From a807d4e6fb96c4d8b8585b7dbb862e53486562ec Mon Sep 17 00:00:00 2001 From: Nathan Reiner Date: Thu, 1 Aug 2024 20:13:55 +0200 Subject: add evalsto --- src/widgets/sheetview/mod.rs | 110 +++++++++++++++++++++++++++++++++++++------ src/widgets/statusbar.rs | 85 ++++++++++++++++++++++++++++++--- 2 files changed, 174 insertions(+), 21 deletions(-) (limited to 'src/widgets') diff --git a/src/widgets/sheetview/mod.rs b/src/widgets/sheetview/mod.rs index 40adfc7..fd0919d 100644 --- a/src/widgets/sheetview/mod.rs +++ b/src/widgets/sheetview/mod.rs @@ -9,7 +9,8 @@ use ratatui::{ }; use crate::{ - config::GlobalConfig, + config::{theme::style, GlobalConfig}, + lua, sheet::{ eval::EvalFunction, register::{Register, SheetId}, @@ -144,7 +145,7 @@ impl SheetView { } pub fn handle_key_event(&mut self, event: KeyEvent) { - match self.mode { + match &self.mode { SheetViewMode::Normal => match event.code { KeyCode::Char('j') => self.move_cursor_by((1, 0)), KeyCode::Char('k') => self.move_cursor_by((-1, 0)), @@ -153,11 +154,15 @@ impl SheetView { KeyCode::Char('v') => { self.selection_anchor = Some(self.cursor.clone()); self.mode = SheetViewMode::Visual - }, + } KeyCode::Char('s') => { self.editor.set_text("function(cell)\n\treturn \"\"\nend"); self.mode = SheetViewMode::Script; } + KeyCode::Char(':') => { + self.mode = SheetViewMode::Command; + self.bar.set_input_mode(true) + } _ => {} }, SheetViewMode::Insert => {} @@ -169,16 +174,42 @@ impl SheetView { KeyCode::Esc | KeyCode::Char('v') => { self.selection_anchor = None; self.mode = SheetViewMode::Normal; - }, + } KeyCode::Char('s') => { self.editor.set_text("function(cell)\n\treturn \"\"\nend"); self.mode = SheetViewMode::Script; } + KeyCode::Char(':') => { + self.mode = SheetViewMode::Command; + self.bar.set_input_mode(true) + } _ => {} }, - SheetViewMode::Command => {} + SheetViewMode::Command => match event.code { + KeyCode::Enter => { + if let Err(error) = lua::get().load(self.bar.input().unwrap_or("")).exec() { + self.mode = SheetViewMode::CommandError(error.to_string()) + } else { + if self.selection_anchor.is_some() { + self.mode = SheetViewMode::Visual; + } else { + self.mode = SheetViewMode::Normal; + } + } + + self.bar.set_input_mode(false); + } + KeyCode::Esc => { + if self.selection_anchor.is_some() { + self.mode = SheetViewMode::Visual; + } else { + self.mode = SheetViewMode::Normal; + } + } + _ => self.bar.handle_keyevent(event), + }, SheetViewMode::CommandError(_) => match event.code { - KeyCode::Esc => self.mode = SheetViewMode::Normal, + KeyCode::Esc | KeyCode::Enter => self.mode = SheetViewMode::Normal, _ => {} }, SheetViewMode::Script => match event.code { @@ -226,7 +257,7 @@ impl SheetView { self.join_process_handle_on_finished(); } SheetViewMode::EditorError(_) => match event.code { - KeyCode::Esc => self.mode = SheetViewMode::Script, + KeyCode::Esc | KeyCode::Enter => self.mode = SheetViewMode::Script, _ => {} }, } @@ -255,11 +286,22 @@ impl SheetView { } } - fn areas(&self, area: Rect) -> (Rect, Rect, Rect, Rect) { + fn areas(&self, area: Rect) -> (Rect, Rect, Rect, Rect, Rect) { let mut sheet = area; let mut editor = Rect::default(); let mut error = Rect::default(); let mut progress = Rect::default(); + let mut command_error = Rect::default(); + + if let SheetViewMode::CommandError(message) = &self.mode { + let layout = Layout::vertical([ + Constraint::Min(1), + Constraint::Length(message.lines().count().min(15) as u16 + 1), + ]) + .split(sheet); + sheet = layout[0]; + command_error = layout[1]; + } if self.is_editor_visible() { let layout = @@ -282,7 +324,7 @@ impl SheetView { } } - (sheet, editor, error, progress) + (sheet, editor, error, progress, command_error) } } @@ -293,7 +335,7 @@ impl Widget for &mut SheetView { { let theme = GlobalConfig::instance().theme.sheetview.clone(); let progress; - let (sheet_area, editor_area, error_area, progress_area) = self.areas(area); + let (sheet_area, editor_area, error_area, progress_area, cmd_error_area) = self.areas(area); let separator = Block::default().borders(Borders::RIGHT).border_style( Style::default() .bg(Color::Rgb(29, 32, 33)) @@ -331,17 +373,20 @@ impl Widget for &mut SheetView { for column in 0..(viewport_columns + 1) as u16 { let (cell_pos_y, cell_pos_x) = (row + self.scroll.0, column + self.scroll.1); - if let Some(cell) = sheet.get_cell(cell_pos_y as usize, cell_pos_x as usize) { - let cell = cell.to_string() + " "; + if let Some(cell_ref) = sheet.get_ref(cell_pos_y as usize, cell_pos_x as usize) + { + let cell = cell_ref.value().to_string() + " "; let line = if (cell_pos_y, cell_pos_x) == self.cursor { theme.cursor.apply(cell.to_line()) } else if self.is_in_selection(cell_pos_y, cell_pos_x) { theme.selection.apply(cell.to_line()) - } else if (row + column) % 2 == 0 { - theme.cell.0.apply(cell.to_line()) } else { - theme.cell.1.apply(cell.to_line()) + theme + .cell + .get(cell_ref, &lua::get()) + .unwrap_or(style::Style::new()) + .apply(cell.to_line()) }; let rect = Rect::new( @@ -357,6 +402,22 @@ impl Widget for &mut SheetView { } } + match &self.mode { + SheetViewMode::Command => { + self.bar.set_left(" COMMAND "); + } + + _ => { + if self.selection_anchor.is_some() { + self.bar.set_left(" VISUAL "); + } else { + self.bar.set_left(" NORMAL "); + self.bar.set_middle_alignment(Alignment::Center); + self.bar.set_middle("Sheet"); + } + } + } + self.bar.render(sheet_area, buf); if self.is_editor_visible() { @@ -383,6 +444,25 @@ impl Widget for &mut SheetView { .render(error_inner, buf); } + if let SheetViewMode::CommandError(message) = &self.mode { + let lines = message.lines().collect::>(); + + let block = Block::default() + .title_bottom(" Error ") + .title_style(Style::default().on_red()) + .border_style(Style::default().black().on_black()) + .borders(Borders::BOTTOM); + let error_inner = block.inner(cmd_error_area); + block.render(cmd_error_area, buf); + + let text = Text::from_iter(lines.iter().map(|s| s.to_line().white())); + + Paragraph::new(text) + .wrap(Wrap { trim: true }) + .bg(Color::Rgb(70, 25, 25)) + .render(error_inner, buf); + } + progress = sheet.progress(); } diff --git a/src/widgets/statusbar.rs b/src/widgets/statusbar.rs index 97b514d..60b58a6 100644 --- a/src/widgets/statusbar.rs +++ b/src/widgets/statusbar.rs @@ -1,4 +1,10 @@ -use ratatui::{layout::{Alignment, Rect}, style::Style, text::ToLine, widgets::Widget}; +use ratatui::{ + crossterm::event::{KeyCode, KeyEvent}, + layout::{Alignment, Rect}, + style::{Style, Stylize}, + text::{ToLine, ToSpan}, + widgets::Widget, +}; #[derive(Clone)] pub struct StatusBar { @@ -9,6 +15,8 @@ pub struct StatusBar { middle_alignment: Alignment, right: String, right_style: Style, + input: Option, + cursor: u16, } impl StatusBar { @@ -21,6 +29,8 @@ impl StatusBar { middle_alignment: Alignment::Center, right: String::new(), right_style: Style::default(), + input: None, + cursor: 0, } } @@ -105,12 +115,49 @@ impl StatusBar { self.middle_alignment = alignment; } + pub fn set_input_mode(&mut self, input: bool) { + if input { + self.input = Some(String::new()); + self.cursor = 0; + } else { + self.input = None; + } + } + + pub fn input(&self) -> Option<&str> { + self.input.as_ref().map(|s| s.as_str()) + } + pub fn area(&self, rect: Rect) -> Rect { let mut inner = rect.clone(); inner.height -= 1; inner } + pub fn handle_keyevent(&mut self, event: KeyEvent) { + if let Some(input) = &mut self.input { + match event.code { + KeyCode::Char(c) => { + input.insert(self.cursor as usize, c); + self.cursor += 1; + } + KeyCode::Backspace => { + if self.cursor > 0 { + self.cursor -= 1; + input.remove(self.cursor as usize).to_string(); + } + } + KeyCode::Left => { + self.cursor = (self.cursor as i32 - 1).max(0) as u16; + } + KeyCode::Right => { + self.cursor = (self.cursor + 1).min(input.len() as u16); + } + _ => {} + } + } + } + fn layout(&self, mut area: Rect) -> (Rect, Rect, Rect) { area.y += area.height - 1; area.height = 1; @@ -142,11 +189,37 @@ impl Widget for &mut StatusBar { .left_aligned() .style(self.left_style) .render(left, buf); - self.middle - .to_line() - .alignment(self.middle_alignment) - .style(self.middle_style) - .render(middle, buf); + + if let Some(input) = &self.input { + (":".to_owned() + input) + .to_line() + .alignment(Alignment::Left) + .style(self.middle_style) + .render(middle, buf); + + input + .chars() + .nth(self.cursor as usize) + .unwrap_or(' ') + .to_span() + .reversed() + .render( + Rect::new( + middle.x + 1 + self.cursor, + middle.y, + middle.width, + middle.height, + ), + buf, + ); + } else { + self.middle + .to_line() + .alignment(self.middle_alignment) + .style(self.middle_style) + .render(middle, buf); + } + self.right .to_line() .right_aligned() -- cgit v1.2.3-70-g09d2