summaryrefslogtreecommitdiff
path: root/src/widgets
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets')
-rw-r--r--src/widgets/sheetview/mod.rs110
-rw-r--r--src/widgets/statusbar.rs85
2 files changed, 174 insertions, 21 deletions
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::<Vec<_>>();
+
+ 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<String>,
+ 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()