This commit is contained in:
2025-11-10 16:21:23 -07:00
parent 6ed6cbfd62
commit 7c453f5d6a
2 changed files with 131 additions and 81 deletions

View File

@@ -5,10 +5,10 @@ use ratatui::{DefaultTerminal, Frame, crossterm::event, layout::{self, Constrain
use crate::app::{calc::{Grid, LEN}, mode::Mode}; use crate::app::{calc::{Grid, LEN}, mode::Mode};
pub struct App { pub struct App {
exit: bool, pub exit: bool,
pub grid: Grid, pub grid: Grid,
pub mode: Mode, pub mode: Mode,
file: Option<PathBuf>, pub file: Option<PathBuf>,
} }
impl Widget for &App { impl Widget for &App {
@@ -18,7 +18,6 @@ impl Widget for &App {
let cell_height = 1; let cell_height = 1;
let cell_length = 5; let cell_length = 5;
let x_max = if area.width / cell_length > len { let x_max = if area.width / cell_length > len {
len - 1 len - 1
} else { } else {
@@ -30,14 +29,41 @@ impl Widget for &App {
area.height / cell_height area.height / cell_height
}; };
let is_selected = |x: usize, y: usize| -> bool {
if let Mode::Visual((mut x1, mut y1)) = self.mode {
let (mut x2, mut y2) = self.grid.selected_cell;
x1 += 1;
y1 += 1;
x2 += 1;
y2 += 1;
if x >= x1 && x <= x2{
// in-between the Xs
if y >= y1 && y <= y2 {
// in-between the Ys
return true
}
}
}
false
};
for x in 0..x_max { for x in 0..x_max {
for y in 0..y_max { for y in 0..y_max {
let mut display = String::new(); let mut display = String::new();
let mut style = Style::new().fg(Color::White); let mut style = Style::new().fg(Color::White);
if is_selected(x.into(),y.into()) {
style = style.fg(Color::LightMagenta).bg(Color::Blue);
}
const ORANGE1: Color = Color::Rgb(200, 160, 0); const ORANGE1: Color = Color::Rgb(200, 160, 0);
const ORANGE2: Color = Color::Rgb(180, 130, 0); const ORANGE2: Color = Color::Rgb(180, 130, 0);
match (x == 0, y == 0) { match (x == 0, y == 0) {
(true, true) => { (true, true) => {
let (x,y) = self.grid.selected_cell; let (x,y) = self.grid.selected_cell;
@@ -159,7 +185,7 @@ impl App {
}), }),
layout[0], layout[0],
), ),
Mode::Visual(start_pos) => {} Mode::Visual(_) => {}
} }
frame.render_widget(self, layout[1]); frame.render_widget(self, layout[1]);
@@ -172,32 +198,7 @@ impl App {
event::Event::Key(key) => match key.code { event::Event::Key(key) => match key.code {
event::KeyCode::Esc => self.mode = Mode::Normal, event::KeyCode::Esc => self.mode = Mode::Normal,
event::KeyCode::Char(c) => { event::KeyCode::Char(c) => {
chord.add_char(c); Mode::process_key(self, c);
match chord.as_string()[0..chord.as_string().len() - 1].parse::<usize>() {
Ok(num) => match c {
'G' => {
let sel = self.grid.selected_cell;
self.grid.selected_cell = (sel.0, num);
self.mode = Mode::Normal;
}
_ => {
if c.is_alphabetic() {
self.mode = Mode::Normal;
for _ in 0..num {
Mode::process_key(self, c);
}
}
}
},
Err(_) => match chord.as_string().as_str() {
"d " | "dw" => {
let loc = self.grid.selected_cell;
self.grid.set_cell_raw(loc, String::new());
self.mode = Mode::Normal;
}
_ => {}
},
}
} }
event::KeyCode::Backspace => { event::KeyCode::Backspace => {
chord.backspace(); chord.backspace();
@@ -243,12 +244,11 @@ impl App {
}, },
_ => todo!(), _ => todo!(),
}, },
Mode::Visual(start_pos) => { Mode::Visual(_start_pos) => {
if let event::Event::Key(key) = event::read()? { if let event::Event::Key(key) = event::read()? {
match key.code { match key.code {
event::KeyCode::Char(c) => { event::KeyCode::Char(c) => {
Mode::process_key(self, c); Mode::process_key(self, c);
todo!();
} }
event::KeyCode::Esc => self.mode = Mode::Normal, event::KeyCode::Esc => self.mode = Mode::Normal,
_ => {} _ => {}
@@ -262,12 +262,7 @@ impl App {
self.mode = Mode::Normal; self.mode = Mode::Normal;
} }
event::KeyCode::Enter => { event::KeyCode::Enter => {
// [':', 'q'] Mode::process_cmd(self);
match editor.as_string().as_bytes()[1] as char {
'w' => {}
'q' => self.exit = true,
_ => {}
}
self.mode = Mode::Normal; self.mode = Mode::Normal;
} }
event::KeyCode::Backspace => { event::KeyCode::Backspace => {

View File

@@ -6,7 +6,7 @@ use ratatui::{
widgets::{Paragraph, Widget}, widgets::{Paragraph, Widget},
}; };
use crate::app::app::App; use crate::app::{self, app::App};
pub enum Mode { pub enum Mode {
Insert(Editor), Insert(Editor),
@@ -35,52 +35,107 @@ impl Display for Mode {
} }
impl Mode { impl Mode {
pub fn process_key(app: &mut App, key: char) { pub fn process_cmd(app: &mut App) {
match key { if let Mode::Command(editor) = &mut app.mode {
// < // [':', 'q']
'h' => { match editor.as_string().as_bytes()[1] as char {
app.grid.selected_cell.0 = app.grid.selected_cell.0.saturating_sub(1); 'w' => {
return; if let Some(file) = &app.file {
} unimplemented!("Figure out how we want to save Grid to a csv or something")
// v } else {
'j' => { // TODO figure out how to get an error message to the user
app.grid.selected_cell.1 = app.grid.selected_cell.1.saturating_add(1); }
return;
}
// ^
'k' => {
app.grid.selected_cell.1 = app.grid.selected_cell.1.saturating_sub(1);
return;
}
// >
'l' => {
app.grid.selected_cell.0 = app.grid.selected_cell.0.saturating_add(1);
return;
}
_ => {}
}
if let Mode::Normal = app.mode {
match key {
// edit cell
'i' | 'a' => {
let (x, y) = app.grid.selected_cell;
let val = app.grid.get_cell_raw(x, y).as_ref().map(|f| f.as_raw_string()).unwrap_or(String::new());
app.mode = Mode::Insert(Editor::new(val, (x, y)));
} }
'I' => { /* insert col before */ } 'q' => app.exit = true,
'A' => { /* insert col after */ } _ => {}
'o' => { /* insert row below */ }
'O' => { /* insert row above */ }
'v' => app.mode = Mode::Visual(app.grid.selected_cell),
':' => app.mode = Mode::Command(Chord::new(':')),
// loose chars will put you into chord mode
c => app.mode = Mode::Chord(Chord::new(c)),
} }
} }
} }
pub fn process_key(app: &mut App, key: char) {
match &mut app.mode {
// FIXME this will break visual movement
Mode::Normal => {
match key {
// <
'h' => {
app.grid.selected_cell.0 = app.grid.selected_cell.0.saturating_sub(1);
return;
}
// v
'j' => {
app.grid.selected_cell.1 = app.grid.selected_cell.1.saturating_add(1);
return;
}
// ^
'k' => {
app.grid.selected_cell.1 = app.grid.selected_cell.1.saturating_sub(1);
return;
}
// >
'l' => {
app.grid.selected_cell.0 = app.grid.selected_cell.0.saturating_add(1);
return;
}
'0' => {
app.grid.selected_cell.0 = 0;
return;
}
// edit cell
'i' | 'a' => {
let (x, y) = app.grid.selected_cell;
let val =
app.grid.get_cell_raw(x, y).as_ref().map(|f| f.as_raw_string()).unwrap_or(String::new());
app.mode = Mode::Insert(Editor::new(val, (x, y)));
}
'I' => { /* insert col before */ }
'A' => { /* insert col after */ }
'o' => { /* insert row below */ }
'O' => { /* insert row above */ }
'v' => app.mode = Mode::Visual(app.grid.selected_cell),
':' => app.mode = Mode::Command(Chord::new(':')),
// loose chars will put you into chord mode
c => app.mode = Mode::Chord(Chord::new(c)),
}
}
Mode::Chord(chord) => {
chord.add_char(key);
match chord.as_string()[0..chord.as_string().len() - 1].parse::<usize>() {
// For chords that can take a numeric input
Ok(num) => match key {
'G' => {
let sel = app.grid.selected_cell;
app.grid.selected_cell = (sel.0, num);
app.mode = Mode::Normal;
}
_ => {
if key.is_alphabetic() {
app.mode = Mode::Normal;
for _ in 0..num {
Mode::process_key(app, key);
}
}
}
},
Err(_) => match chord.as_string().as_str() {
"d " | "dw" => {
let loc = app.grid.selected_cell;
app.grid.set_cell_raw(loc, String::new());
app.mode = Mode::Normal;
}
"gg" => {
app.grid.selected_cell.1 = 0;
app.mode = Mode::Normal;
}
_ => {}
},
}
}
_ => todo!(),
}
}
} }
pub struct Editor { pub struct Editor {