From 04a5a938994ddb95cfaa9a74b180e457d3a2b5d0 Mon Sep 17 00:00:00 2001 From: Nathan Reiner Date: Fri, 2 Aug 2024 11:38:19 +0200 Subject: implement new lua interface --- src/widgets/logview.rs | 4 +- src/widgets/luaeditor/buffer.rs | 180 ------------- src/widgets/luaeditor/mod.rs | 96 +++---- src/widgets/sheetview/mod.rs | 577 ++++++++++------------------------------ 4 files changed, 197 insertions(+), 660 deletions(-) delete mode 100644 src/widgets/luaeditor/buffer.rs (limited to 'src/widgets') diff --git a/src/widgets/logview.rs b/src/widgets/logview.rs index 35c7bed..5d30b17 100644 --- a/src/widgets/logview.rs +++ b/src/widgets/logview.rs @@ -1,4 +1,4 @@ -use ratatui::{style::{Style, Stylize}, text::ToSpan, widgets::Widget}; +use ratatui::{crossterm::event::KeyEvent, style::{Style, Stylize}, text::ToSpan, widgets::Widget}; use crate::lua::iobuffer::iobuffer; @@ -15,6 +15,8 @@ impl LogView { bar: StatusBar::new().left(" Log ").left_style(Style::default().on_magenta()), } } + + pub fn handle_key_event(&mut self, _event: KeyEvent) {} } impl Widget for &mut LogView { diff --git a/src/widgets/luaeditor/buffer.rs b/src/widgets/luaeditor/buffer.rs deleted file mode 100644 index 1427bdb..0000000 --- a/src/widgets/luaeditor/buffer.rs +++ /dev/null @@ -1,180 +0,0 @@ -use std::str::FromStr; - -use crate::cursor::{Cursor, CursorMove}; - -#[derive(Default, Debug, Clone)] -pub struct Buffer { - lines: Vec, - cursor: Cursor, -} - -impl Buffer { - pub fn new() -> Self { - Self { - lines: Vec::new(), - cursor: Cursor::new().with_position(0, 0).with_max(0, 0), - } - } - - fn refresh_line_max(&mut self) { - self.cursor.set_x_max(self.lines[self.cursor.y()].len()) - } - - fn refresh_buffer_max(&mut self) { - self.cursor.set_y_max(self.lines.len() - 1); - } - - fn refresh_max(&mut self) { - self.refresh_line_max(); - self.refresh_buffer_max(); - } - - fn end_balance(&self, level: usize) -> isize { - let str = "\t".repeat(level); - let start_count = self - .lines - .iter() - .filter(|s| { - s.starts_with(&(str.clone() + "if ")) - || s.starts_with(&(str.clone() + "for ")) - || s.starts_with(&(str.clone() + "while ")) - || (s.starts_with(&str) && s.contains("function(") && s.ends_with(')')) - }) - .count(); - - let end_count = self - .lines - .iter() - .filter(|s| s.starts_with(&(str.clone() + "end ")) || **s == (str.clone() + "end")) - .count(); - - (end_count as isize) - (start_count as isize) - } - - pub fn insert(&mut self, c: char) { - match c { - '\n' => { - let (a, b) = { - let line = self.current_line(); - let (a, b) = line.split_at(self.cursor.x()); - (a.to_string(), b.to_string()) - }; - - let indent_normalized = a.replace(" ", "\t"); - let indent = indent_normalized.len() - indent_normalized.trim_start().len(); - let l = a.trim(); - let insert_end = (l.starts_with("if ") && l.ends_with(" then")) - || ((l.starts_with("for ") || l.starts_with("while ")) && l.ends_with(" do")) - || (l.contains("function(") && l.ends_with(')')); - - let extra_indent = if insert_end { 1 } else { 0 }; - - { - *self.current_line_mut() = a; - } - self.cursor.move_unchecked(CursorMove::Down(1)); - self.cursor.move_unchecked(CursorMove::Begin); - self.lines - .insert(self.cursor().y(), "\t".repeat(indent + extra_indent) + &b); - - if insert_end && self.end_balance(indent) < 0 { - self.lines - .insert(self.cursor().y() + 1, "\t".repeat(indent) + "end"); - } - - self.refresh_max(); - self.cursor - .move_checked(CursorMove::Right(indent + extra_indent)); - } - _ => { - let x = self.cursor().x(); - self.current_line_mut().insert(x, c); - self.refresh_line_max(); - self.cursor.move_checked(CursorMove::Right(1)); - } - } - } - - pub fn delete(&mut self) { - if self.cursor.is_at_start() && !self.cursor.is_at_top() { - let old_line = self.current_line_mut().clone(); - self.lines.remove(self.cursor.y()); - self.cursor.move_checked(CursorMove::Up(1)); - self.refresh_line_max(); - - let new_x = self.current_line().len(); - self.current_line_mut().push_str(&old_line); - self.cursor - .move_checked(CursorMove::Jump((new_x, self.cursor.y()))); - - self.refresh_buffer_max() - } else { - let x = self.cursor.x() - 1; - self.current_line_mut().remove(x); - self.refresh_line_max(); - self.cursor.move_checked(CursorMove::Left(1)); - } - } - - pub fn line(&self, index: usize) -> Option<&String> { - self.lines.get(index) - } - - fn line_mut(&mut self, index: usize) -> Option<&mut String> { - self.lines.get_mut(index) - } - - pub fn current_line(&self) -> &String { - self.line(self.cursor.y()).unwrap() - } - - fn current_line_mut(&mut self) -> &mut String { - self.line_mut(self.cursor.y()).unwrap() - } - - pub fn cursor(&self) -> &Cursor { - &self.cursor - } - - pub fn move_cursor(&mut self, m: CursorMove) { - match m { - CursorMove::Up(_) - | CursorMove::Down(_) - | CursorMove::Top - | CursorMove::Bottom - | CursorMove::Relative(_) - | CursorMove::Jump(_) => { - self.cursor.move_checked(m); - self.cursor.set_x_max(self.current_line().len()); - self.cursor.correct_cursor_position(); - } - CursorMove::Left(_) | CursorMove::Right(_) | CursorMove::Begin | CursorMove::End => { - self.cursor.move_checked(m) - } - } - } - - pub fn lines(&self) -> &Vec { - &self.lines - } - - pub fn set_lines(&mut self, lines: Vec) { - self.lines = lines; - self.cursor.move_checked(CursorMove::Jump((0, 0))); - self.refresh_max(); - } -} - -impl FromStr for Buffer { - type Err = (); - - fn from_str(s: &str) -> Result { - let lines: Vec<_> = s.lines().map(|s| s.to_string()).collect(); - let mut buffer = Self::new(); - buffer.lines = lines; - - buffer.refresh_max(); - - Ok(buffer) - } -} diff --git a/src/widgets/luaeditor/mod.rs b/src/widgets/luaeditor/mod.rs index 6fc8436..de35c3d 100644 --- a/src/widgets/luaeditor/mod.rs +++ b/src/widgets/luaeditor/mod.rs @@ -1,25 +1,22 @@ use ratatui::{ - crossterm::event::{KeyCode, KeyEvent}, + crossterm::event::{KeyCode, KeyEvent, KeyModifiers}, style::{Style, Stylize}, text::{ToLine, ToSpan}, widgets::Widget, }; - -pub mod buffer; -pub mod theme; -pub mod treesitter; - -use buffer::Buffer; use tree_sitter_highlight::HighlightConfiguration; -use crate::cursor::CursorMove; +use crate::state::{editor::EditorState, window::Window, GlobalState}; +use crate::{cursor::CursorMove, lua}; use super::statusbar::StatusBar; +pub mod theme; +pub mod treesitter; + pub struct LuaEditor { bar: StatusBar, scroll: usize, - buffer: Buffer, highlight_config: HighlightConfiguration, } @@ -30,35 +27,53 @@ impl LuaEditor { .left(" [No Name] ") .left_style(Style::default().on_magenta()), scroll: 0, - buffer: Buffer::new(), highlight_config: treesitter::new_highlight_configuration(), } } pub fn handle_key_event(&mut self, event: KeyEvent) { match event.code { - KeyCode::Char(c) => self.buffer.insert(c), + KeyCode::Char('r') if event.modifiers == KeyModifiers::CONTROL => { + EditorState::run(&lua::get()) + } + KeyCode::Char(c) => GlobalState::instance_mut().editor.buffer.insert(c), KeyCode::Backspace => { - self.buffer.delete(); + GlobalState::instance_mut().editor.buffer.delete(); } KeyCode::Enter => { - self.buffer.insert('\n'); + GlobalState::instance_mut().editor.buffer.insert('\n'); } - KeyCode::Left => self.buffer.move_cursor(CursorMove::Left(1)), - KeyCode::Right => self.buffer.move_cursor(CursorMove::Right(1)), - KeyCode::Up => self.buffer.move_cursor(CursorMove::Up(1)), - KeyCode::Down => self.buffer.move_cursor(CursorMove::Down(1)), + KeyCode::Left => GlobalState::instance_mut() + .editor + .buffer + .move_cursor(CursorMove::Left(1)), + KeyCode::Right => GlobalState::instance_mut() + .editor + .buffer + .move_cursor(CursorMove::Right(1)), + KeyCode::Up => GlobalState::instance_mut() + .editor + .buffer + .move_cursor(CursorMove::Up(1)), + KeyCode::Down => GlobalState::instance_mut() + .editor + .buffer + .move_cursor(CursorMove::Down(1)), KeyCode::Home => {} KeyCode::End => {} KeyCode::PageUp => {} KeyCode::PageDown => {} - KeyCode::Tab => self.buffer.insert('\t'), + KeyCode::Tab => GlobalState::instance_mut().editor.buffer.insert('\t'), KeyCode::BackTab => {} KeyCode::Delete => {} KeyCode::Insert => {} KeyCode::F(_) => {} KeyCode::Null => {} - KeyCode::Esc => {} + KeyCode::Esc => { + let mut state = GlobalState::instance_mut(); + state.editor.visible = false; + state.set_focus(Window::View) + } KeyCode::CapsLock => {} KeyCode::ScrollLock => {} KeyCode::NumLock => {} @@ -70,18 +85,6 @@ impl LuaEditor { KeyCode::Modifier(_) => {} } } - - pub fn set_text(&mut self, content: S) - where - S: AsRef, - { - self.buffer - .set_lines(content.as_ref().lines().map(|s| s.to_string()).collect()) - } - - pub fn text(&self) -> String { - self.buffer.lines().join("\n") - } } impl Widget for &mut LuaEditor { @@ -89,13 +92,16 @@ impl Widget for &mut LuaEditor { where Self: Sized, { + let state = GlobalState::instance(); + let buffer = &state.editor.buffer; + self.bar.render(area, buf); let inner_area = self.bar.area(area); - let text = self.text(); + let text = buffer.as_string(); let highlights = treesitter::highlighter_split(text.as_bytes(), &self.highlight_config); - let nr_width = (self.buffer.lines().len().to_string().len() + 1).max(4) as u16; + let nr_width = (buffer.lines().len().to_string().len() + 1).max(4) as u16; let mut text_area = inner_area; text_area.x += nr_width; @@ -122,7 +128,7 @@ impl Widget for &mut LuaEditor { } } - for i in self.scroll..self.buffer.lines().len() { + for i in self.scroll..buffer.lines().len() { let mut nr_area = span_area; nr_area.x = inner_area.x; nr_area.width = nr_width - 1; @@ -139,13 +145,10 @@ impl Widget for &mut LuaEditor { let mut cursor_area = text_area; cursor_area.width = 1; cursor_area.height = 1; - cursor_area.y += self.buffer.cursor().y() as u16; - cursor_area.x += self.buffer.cursor().x() as u16; + cursor_area.y += buffer.cursor().y() as u16; + cursor_area.x += buffer.cursor().x() as u16; - let (first, _) = self - .buffer - .current_line() - .split_at(self.buffer.cursor().x()); + let (first, _) = buffer.current_line().split_at(buffer.cursor().x()); for c in first.chars() { if c == '\t' { @@ -153,19 +156,19 @@ impl Widget for &mut LuaEditor { } } - if self.scroll > self.buffer.cursor().y() { - self.scroll = self.buffer.cursor().y(); - } else if inner_area.height as usize + self.scroll - 1 < self.buffer.cursor().y() { - self.scroll = self.buffer.cursor().y() - inner_area.height as usize + 1; + if self.scroll > buffer.cursor().y() { + self.scroll = buffer.cursor().y(); + } else if inner_area.height as usize + self.scroll - 1 < buffer.cursor().y() { + self.scroll = buffer.cursor().y() - inner_area.height as usize + 1; } cursor_area.y -= self.scroll as u16; if inner_area.contains(cursor_area.into()) { - self.buffer + buffer .current_line() .chars() - .nth(self.buffer.cursor().x()) + .nth(buffer.cursor().x()) .map(|c| if c == '\t' { ' ' } else { c }) .unwrap_or(' ') .to_span() @@ -181,7 +184,6 @@ impl Default for LuaEditor { highlight_config: treesitter::new_highlight_configuration(), bar: StatusBar::default(), scroll: 0, - buffer: Buffer::default(), } } } diff --git a/src/widgets/sheetview/mod.rs b/src/widgets/sheetview/mod.rs index 4ae37f0..aac2080 100644 --- a/src/widgets/sheetview/mod.rs +++ b/src/widgets/sheetview/mod.rs @@ -1,49 +1,27 @@ -use std::thread::JoinHandle; - use ratatui::{ - crossterm::event::{KeyCode, KeyEvent, KeyModifiers}, + crossterm::event::{KeyCode, KeyEvent}, prelude::*, style::Stylize, text::ToLine, - widgets::{Block, Borders, Clear, Gauge, Paragraph, Widget, Wrap}, + widgets::Widget, }; use crate::{ config::GlobalConfig, cursor::CursorMove, lua, - sheet::{ - cell::Cell, - eval::EvalFunction, - Sheet, - }, - state::GlobalState, + sheet::cell::Cell, + state::{view::mode::Mode, window::Window, GlobalState}, }; -use super::{luaeditor::LuaEditor, statusbar::StatusBar}; +use super::statusbar::StatusBar; const DEFAULT_COLUMN_WIDTH: u16 = 10; -#[derive(Default)] -enum SheetViewMode { - #[default] - Normal, - Insert, - Visual, - Command, - CommandError(String), - Script, - Processing(Option>>), - EditorError(String), -} - #[derive(Default)] pub struct SheetView { bar: StatusBar, - scroll: (u16, u16), - selection_anchor: Option<(u16, u16)>, - mode: SheetViewMode, - editor: LuaEditor, + scroll: (usize, usize), } impl SheetView { @@ -56,315 +34,127 @@ impl SheetView { .right("") .right_style(Style::default().on_red()), scroll: (0, 0), - mode: SheetViewMode::Normal, - selection_anchor: None, - editor: LuaEditor::new(), } } - pub fn move_cursor_by(&mut self, delta: (isize, isize)) { - let mut state = GlobalState::instance_mut(); - state - .sheetview - .cursor - .move_checked(CursorMove::Relative(delta)); + fn set_mode(&self, mode: Mode) { + GlobalState::instance_mut().sheetview.mode = mode; } - pub fn selection(&self) -> Vec<(u16, u16)> { - let mut selection = Vec::new(); - - if let Some((row, column)) = self.selection_range() { - for i in row.0..=row.1 { - for j in column.0..=column.1 { - selection.push((i, j)) - } - } - } - - selection - } - - fn is_in_selection(&mut self, row: u16, column: u16) -> bool { - if let Some((row_range, column_range)) = self.selection_range() { - row >= row_range.0 - && row <= row_range.1 - && column >= column_range.0 - && column <= column_range.1 - } else { - false - } + fn move_cursor(&self, cm: CursorMove) { + GlobalState::instance_mut() + .sheetview + .cursor + .move_checked(cm) } - fn selection_range(&self) -> Option<((u16, u16), (u16, u16))> { + fn cursor(&self) -> (usize, usize) { let state = GlobalState::instance(); - let cursor = &state.sheetview.cursor; - if let Some(selection) = self.selection_anchor { - let row = if selection.0 as usize > cursor.y() { - (cursor.y() as u16, selection.0) - } else { - (selection.0, cursor.y() as u16) - }; - - let column = if selection.1 as usize > cursor.x() { - (cursor.x() as u16, selection.1) - } else { - (selection.1, cursor.x() as u16) - }; + (state.sheetview.cursor.y(), state.sheetview.cursor.x()) + } - Some((row, column)) - } else { - None - } + fn start_selection(&self) { + let mut state = GlobalState::instance_mut(); + state.sheetview.selection_anchor = Some(self.cursor()); + state.sheetview.mode = Mode::Visual; } - fn join_process_handle_on_finished(&mut self) { - if let SheetViewMode::Processing(opt) = &mut self.mode { - let handle = opt.take().unwrap(); - if handle.is_finished() { - match handle.join().unwrap() { - Ok(sheet) => { - GlobalState::instance() - .sheetview - .active_sheet() - .unwrap() - .write() - .unwrap() - .apply(sheet); - self.mode = SheetViewMode::Script; - } - Err(message) => self.mode = SheetViewMode::EditorError(message), - }; - } else { - self.mode = SheetViewMode::Processing(Some(handle)); - } - } + fn open_editor(&self) { + let mut state = GlobalState::instance_mut(); + state.editor.buffer.set_lines_from_string( +r#"require('neosheet') + .state + .view + .active:foreach(function(cell) + return "" +end)"#, + ); + state.set_focus(Window::Editor) } pub fn handle_key_event(&mut self, event: KeyEvent) { - match &self.mode { - SheetViewMode::Normal => match event.code { - KeyCode::Char('j') => self.move_cursor_by((0, 1)), - KeyCode::Char('k') => self.move_cursor_by((0, -1)), - KeyCode::Char('h') => self.move_cursor_by((-1, 0)), - KeyCode::Char('l') => self.move_cursor_by((1, 0)), - KeyCode::Char('v') => { - let state = GlobalState::instance(); - let cursor = &state.sheetview.cursor; - self.selection_anchor = Some((cursor.y() as u16, cursor.x() as u16)); - self.mode = SheetViewMode::Visual - } - KeyCode::Char('s') => { - self.editor.set_text("function(cell)\n\treturn \"\"\nend"); - self.mode = SheetViewMode::Script; - } + let mode = { GlobalState::instance().sheetview.mode }; + match mode { + Mode::Normal => match event.code { + KeyCode::Char('j') => self.move_cursor(CursorMove::Down(1)), + KeyCode::Char('k') => self.move_cursor(CursorMove::Up(1)), + KeyCode::Char('h') => self.move_cursor(CursorMove::Left(1)), + KeyCode::Char('l') => self.move_cursor(CursorMove::Right(1)), + KeyCode::Char('v') => self.start_selection(), + KeyCode::Char('s') => self.open_editor(), KeyCode::Char(':') => { - self.mode = SheetViewMode::Command; - self.bar.set_input_mode(true) + self.set_mode(Mode::Command); + self.bar.set_input_mode(true); } KeyCode::Enter => { - self.mode = SheetViewMode::Insert; + self.set_mode(Mode::Insert); self.bar.set_input_mode(true); } _ => {} }, - SheetViewMode::Insert => match event.code { + Mode::Insert => match event.code { KeyCode::Enter => { - let lock = GlobalState::instance().sheetview.active_sheet().unwrap(); + let mut state = GlobalState::instance_mut(); + let lock = state.sheetview.active_sheet().unwrap(); let mut sheet = lock.write().unwrap(); - let state = GlobalState::instance(); - let cursor = &state.sheetview.cursor; - - if self.selection_anchor.is_some() { - self.selection().iter().map(|(r, c)| (*r, *c)).collect() - } else { - vec![(cursor.y() as u16, cursor.x() as u16)] - } - .into_iter() - .for_each(|(r, c)| { - sheet.set_cell(r as usize, c as usize, { - let s = self.bar.input().unwrap(); - match s.parse() { - Ok(n) => Cell::Number(n), - Err(_) => Cell::String(s.to_string()), - } - }) - }); - + state + .sheetview + .selection_or_cursor() + .into_iter() + .for_each(|(r, c)| { + sheet.set_cell(r as usize, c as usize, { + let s = self.bar.input().unwrap(); + match s.parse() { + Ok(n) => Cell::Number(n), + Err(_) => Cell::String(s.to_string()), + } + }) + }); + + state.sheetview.cancel_mode(); self.bar.set_input_mode(false); - if self.selection_anchor.is_some() { - self.mode = SheetViewMode::Visual; - } else { - self.mode = SheetViewMode::Normal; - } } KeyCode::Esc => { - if self.selection_anchor.is_some() { - self.mode = SheetViewMode::Visual; - } else { - self.mode = SheetViewMode::Normal; - } + GlobalState::instance_mut().sheetview.cancel_mode(); self.bar.set_input_mode(false); } _ => self.bar.handle_keyevent(event), }, - SheetViewMode::Visual => match event.code { - KeyCode::Char('j') => self.move_cursor_by((0, 1)), - KeyCode::Char('k') => self.move_cursor_by((0, -1)), - KeyCode::Char('h') => self.move_cursor_by((-1, 0)), - KeyCode::Char('l') => self.move_cursor_by((1, 0)), - 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; - } + Mode::Visual => match event.code { + KeyCode::Char('j') => self.move_cursor(CursorMove::Down(1)), + KeyCode::Char('k') => self.move_cursor(CursorMove::Up(1)), + KeyCode::Char('h') => self.move_cursor(CursorMove::Left(1)), + KeyCode::Char('l') => self.move_cursor(CursorMove::Right(1)), + KeyCode::Char('v') => self.start_selection(), + KeyCode::Char('s') => self.open_editor(), KeyCode::Char(':') => { - self.mode = SheetViewMode::Command; - self.bar.set_input_mode(true) + self.set_mode(Mode::Command); + self.bar.set_input_mode(true); } KeyCode::Enter => { - self.mode = SheetViewMode::Insert; + self.set_mode(Mode::Insert); self.bar.set_input_mode(true); } _ => {} }, - SheetViewMode::Command => match event.code { + Mode::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; + if let Err(_error) = lua::get().load(self.bar.input().unwrap_or("")).exec() { + // TODO: push errors to buffer } + GlobalState::instance_mut().sheetview.cancel_mode(); self.bar.set_input_mode(false); } KeyCode::Esc => { - if self.selection_anchor.is_some() { - self.mode = SheetViewMode::Visual; - } else { - self.mode = SheetViewMode::Normal; - } + GlobalState::instance_mut().sheetview.cancel_mode(); self.bar.set_input_mode(false); } _ => self.bar.handle_keyevent(event), }, - SheetViewMode::CommandError(_) => match event.code { - KeyCode::Esc | KeyCode::Enter => self.mode = SheetViewMode::Normal, - _ => {} - }, - SheetViewMode::Script => match event.code { - KeyCode::Char('r') if event.modifiers == KeyModifiers::CONTROL => { - let script = self.editor.text(); - - let (width, height) = { - let lock = GlobalState::instance().sheetview.active_sheet().unwrap(); - let sheet = lock.read().unwrap(); - (sheet.width(), sheet.height()) - }; - - let mut cells = Vec::new(); - - if self.selection_anchor.is_some() { - cells = self - .selection() - .iter() - .map(|(r, c)| (*r as usize, *c as usize)) - .collect() - } else { - for row in 0..height { - for column in 0..width { - cells.push((row, column)); - } - } - } - - self.mode = SheetViewMode::Processing(Some( - GlobalState::instance() - .sheetview - .active_sheet() - .unwrap() - .eval_function(script, cells), - )); - } - KeyCode::Esc => { - if self.selection_anchor.is_some() { - self.mode = SheetViewMode::Visual; - } else { - self.mode = SheetViewMode::Normal; - } - } - _ => self.editor.handle_key_event(event), - }, - SheetViewMode::Processing(_) => { - self.join_process_handle_on_finished(); - } - SheetViewMode::EditorError(_) => match event.code { - KeyCode::Esc | KeyCode::Enter => self.mode = SheetViewMode::Script, - _ => {} - }, } } - - fn is_editor_visible(&self) -> bool { - matches!( - self.mode, - SheetViewMode::Script | SheetViewMode::Processing(_) | SheetViewMode::EditorError(_), - ) - } - - fn is_error_window_visible(&self) -> bool { - matches!(self.mode, SheetViewMode::EditorError(_)) - } - - fn is_progress_visible(&self) -> bool { - matches!(self.mode, SheetViewMode::Processing(_)) - } - - 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 = - Layout::horizontal([Constraint::Min(1), Constraint::Length(50)]).split(sheet); - sheet = layout[0]; - editor = layout[1]; - - if self.is_error_window_visible() { - let layout = - Layout::vertical([Constraint::Min(1), Constraint::Length(10)]).split(editor); - editor = layout[0]; - error = layout[1]; - } - - if self.is_progress_visible() { - let layout = - Layout::vertical([Constraint::Min(1), Constraint::Length(1)]).split(editor); - editor = layout[0]; - progress = layout[1]; - } - } - - (sheet, editor, error, progress, command_error) - } } impl Widget for &mut SheetView { @@ -373,168 +163,91 @@ impl Widget for &mut SheetView { Self: Sized, { let theme = GlobalConfig::instance().theme.sheetview.clone(); - let progress; - 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)) - .fg(Color::Rgb(29, 32, 33)), - ); - - { - let lock = GlobalState::instance().sheetview.active_sheet().unwrap(); - let sheet = lock.read().unwrap(); - - let state = GlobalState::instance(); - let cursor = &state.sheetview.cursor; - - let mut sheet_area_inner = self.bar.area(sheet_area); - - if self.is_editor_visible() { - sheet_area_inner = separator.inner(sheet_area_inner); - } - - let viewport_rows = sheet.height().min(sheet_area_inner.height as usize); - let viewport_columns = sheet - .width() - .min((sheet_area_inner.width / DEFAULT_COLUMN_WIDTH) as usize); - - if cursor.y() >= viewport_rows + self.scroll.0 as usize { - self.scroll.0 = (cursor.y() - viewport_rows) as u16 + 1; - } else if cursor.y() < self.scroll.0 as usize { - self.scroll.0 = cursor.y() as u16; - } - if cursor.x() >= viewport_columns + self.scroll.1 as usize { - self.scroll.1 = (cursor.x() - viewport_columns) as u16 + 1; - } else if cursor.x() < self.scroll.1 as usize { - self.scroll.1 = cursor.x() as u16; - } + let state = GlobalState::instance(); + let lock = state.sheetview.active_sheet().unwrap(); + let sheet = lock.read().unwrap(); + let cursor = &state.sheetview.cursor; - for row in 0..viewport_rows as u16 { - for column in 0..(viewport_columns + 1) as u16 { - let (cell_pos_y, cell_pos_x) = (row + self.scroll.0, column + self.scroll.1); + let sheet_area_inner = self.bar.area(area); - 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 viewport_rows = sheet.height().min(sheet_area_inner.height as usize); + let viewport_columns = sheet + .width() + .min((sheet_area_inner.width / DEFAULT_COLUMN_WIDTH) as usize); - let line = - if (cell_pos_y, cell_pos_x) == (cursor.y() as u16, cursor.x() as u16) { - theme - .cursor - .get(cell_ref, &lua::get()) - .unwrap_or_default() - .apply(cell.to_line()) - } else if self.is_in_selection(cell_pos_y, cell_pos_x) { - theme - .selection - .get(cell_ref, &lua::get()) - .unwrap_or_default() - .apply(cell.to_line()) - } else { - theme - .cell - .get(cell_ref, &lua::get()) - .unwrap_or_default() - .apply(cell.to_line()) - }; + if cursor.y() >= viewport_rows + self.scroll.0 { + self.scroll.0 = (cursor.y() - viewport_rows) + 1; + } else if cursor.y() < self.scroll.0 { + self.scroll.0 = cursor.y(); + } - let rect = Rect::new( - sheet_area_inner.x + column * DEFAULT_COLUMN_WIDTH, - sheet_area_inner.y + row, - (sheet_area_inner.width - column * DEFAULT_COLUMN_WIDTH) - .min(DEFAULT_COLUMN_WIDTH), - 1, - ); + if cursor.x() >= viewport_columns + self.scroll.1 as usize { + self.scroll.1 = (cursor.x() - viewport_columns) + 1; + } else if cursor.x() < self.scroll.1 { + self.scroll.1 = cursor.x(); + } - line.render(rect, buf); - } - } - } + for row in 0..viewport_rows { + for column in 0..(viewport_columns + 1) { + let (cell_pos_y, cell_pos_x) = (row + self.scroll.0, column + self.scroll.1); + + 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) == (cursor.y(), cursor.x()) { + theme + .cursor + .get(cell_ref, &lua::get()) + .unwrap_or_default() + .apply(cell.to_line()) + } else if state.sheetview.selection_contains(cell_pos_y, cell_pos_x) { + theme + .selection + .get(cell_ref, &lua::get()) + .unwrap_or_default() + .apply(cell.to_line()) + } else { + theme + .cell + .get(cell_ref, &lua::get()) + .unwrap_or_default() + .apply(cell.to_line()) + }; - match &self.mode { - SheetViewMode::Command => { - self.bar.set_left(" COMMAND "); - } + let rect = Rect::new( + sheet_area_inner.x + (column as u16) * DEFAULT_COLUMN_WIDTH, + sheet_area_inner.y + (row as u16), + (sheet_area_inner.width - (column as u16) * DEFAULT_COLUMN_WIDTH) + .min(DEFAULT_COLUMN_WIDTH), + 1, + ); - SheetViewMode::Insert => { - self.bar.set_left(" INSERT "); - } - - _ => { - 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"); - } + line.render(rect, buf); } } + } - self.bar.render(sheet_area, buf); - - if self.is_editor_visible() { - separator.render(sheet_area, buf); - self.editor.render(editor_area, buf) + match state.sheetview.mode { + Mode::Command => { + self.bar.set_left(" COMMAND "); } - if let SheetViewMode::EditorError(error_msg) = &self.mode { - let lines = error_msg.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(error_area); - block.render(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); + Mode::Insert => { + self.bar.set_left(" INSERT "); } - 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); + _ => { + if state.sheetview.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"); + } } - - progress = sheet.progress(); } - self.join_process_handle_on_finished(); - - if self.is_progress_visible() { - let gauge = Gauge::default() - .gauge_style( - Style::default() - .fg(Color::White) - .bg(Color::DarkGray) - .add_modifier(Modifier::ITALIC), - ) - .percent(progress as u16); - - Clear.render(progress_area, buf); - gauge.render(progress_area, buf); - } + self.bar.render(area, buf); } } -- cgit v1.2.3-70-g09d2