diff options
| author | Nathan Reiner <nathan@nathanreiner.xyz> | 2024-08-02 18:09:23 +0200 |
|---|---|---|
| committer | Nathan Reiner <nathan@nathanreiner.xyz> | 2024-08-02 18:09:23 +0200 |
| commit | de9ad07b2a4737713f1473641fe195d7e3023928 (patch) | |
| tree | 38f3bdb122b6e94fe45dbfa2264314c7a7f26be8 | |
| parent | 29ab8b40dc6976687ffb8bfbf663314b0ec3c46e (diff) | |
add tui-cursor handling
| -rw-r--r-- | src/app.rs | 41 | ||||
| -rw-r--r-- | src/main.rs | 1 | ||||
| -rw-r--r-- | src/tui.rs | 10 | ||||
| -rw-r--r-- | src/tuicursor.rs | 15 | ||||
| -rw-r--r-- | src/widgets/luaeditor/mod.rs | 52 |
5 files changed, 67 insertions, 52 deletions
@@ -5,11 +5,15 @@ use crate::{ sheet::register::Register, state::{window::Window, GlobalState}, tui, + tuicursor::TuiCursor, widgets::{logview::LogView, luaeditor::LuaEditor, sheetview::SheetView}, }; use ratatui::{ - crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers}, + crossterm::{ + event::{self, Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers}, + ExecutableCommand, + }, prelude::*, }; @@ -19,6 +23,7 @@ pub struct App { view: SheetView, editor: LuaEditor, logview: LogView, + cursor: Option<TuiCursor>, } impl App { @@ -33,10 +38,11 @@ impl App { view: SheetView::new(), editor: LuaEditor::new(), logview: LogView::new(), + cursor: None, } } - pub fn run(&mut self, terminal: &mut tui::Tui) -> io::Result<()> { + pub fn run(mut self, terminal: &mut tui::Tui) -> io::Result<()> { if let Err(e) = lua::source(&config::constants::USER_RC_PATH) { self.exit = true; tui::restore()?; @@ -44,7 +50,18 @@ impl App { } while !self.exit { - terminal.draw(|frame| self.render_frame(frame))?; + terminal.draw(|frame| { + self.render_frame(frame); + + if let Some(cursor) = &self.cursor { + frame.set_cursor(cursor.position.1, cursor.position.0); + } + })?; + + if let Some(cursor) = &self.cursor { + terminal.backend_mut().execute(cursor.style)?; + } + self.handle_events()?; } @@ -75,13 +92,11 @@ impl App { let mut state = GlobalState::instance_mut(); state.log.visible = !state.log.visible; } - _ => { - match focus { - Window::View => self.view.handle_key_event(key_event), - Window::Editor => self.editor.handle_key_event(key_event), - Window::Log => self.logview.handle_key_event(key_event), - Window::Error => {}, - } + _ => match focus { + Window::View => self.view.handle_key_event(key_event), + Window::Editor => self.editor.handle_key_event(key_event), + Window::Log => self.logview.handle_key_event(key_event), + Window::Error => {} }, } } @@ -103,7 +118,8 @@ impl App { } if state.editor.visible { - let layout = Layout::horizontal([Constraint::Min(1), Constraint::Length(80)]).split(view); + let layout = + Layout::horizontal([Constraint::Min(1), Constraint::Length(80)]).split(view); view = layout[0]; editor = Some(layout[1]); } @@ -121,8 +137,11 @@ impl Widget for &mut App { self.view.render(view, buf); + self.cursor = None; + if let Some(editor) = editor { self.editor.render(editor, buf); + self.cursor = self.editor.render_cursor().map(|c| c.relative_to(editor)); } if let Some(log) = log { diff --git a/src/main.rs b/src/main.rs index 9228eaf..1a465ca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ pub mod lua; pub mod config; pub mod state; pub mod cursor; +pub mod tuicursor; fn run() -> io::Result<()> { let mut terminal = tui::init()?; @@ -1,7 +1,12 @@ use std::io::{self, stdout, Stdout}; -use ratatui::{backend::CrosstermBackend, crossterm::{terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, ExecutableCommand}, Terminal}; - +use ratatui::{ + backend::CrosstermBackend, + crossterm::{ + cursor::SetCursorStyle, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, ExecutableCommand + }, + Terminal, +}; pub type Tui = Terminal<CrosstermBackend<Stdout>>; @@ -17,6 +22,7 @@ pub fn init() -> io::Result<Tui> { pub fn restore() -> io::Result<()> { stdout().execute(LeaveAlternateScreen)?; + stdout().execute(SetCursorStyle::DefaultUserShape)?; disable_raw_mode()?; Ok(()) } diff --git a/src/tuicursor.rs b/src/tuicursor.rs new file mode 100644 index 0000000..fbb7531 --- /dev/null +++ b/src/tuicursor.rs @@ -0,0 +1,15 @@ +use ratatui::{crossterm::cursor::SetCursorStyle, layout::Rect}; + +pub struct TuiCursor { + pub position: (u16, u16), + pub style: SetCursorStyle, +} + +impl TuiCursor { + pub fn relative_to(self, rect: Rect) -> Self { + Self { + position: (rect.y + self.position.0, rect.x + self.position.1), + style: self.style, + } + } +} diff --git a/src/widgets/luaeditor/mod.rs b/src/widgets/luaeditor/mod.rs index 3ce9ab5..0bcffc8 100644 --- a/src/widgets/luaeditor/mod.rs +++ b/src/widgets/luaeditor/mod.rs @@ -1,12 +1,9 @@ use ratatui::{ - crossterm::event::{KeyCode, KeyEvent, KeyModifiers}, - style::Stylize, - text::{ToLine, ToSpan}, - widgets::Widget, + crossterm::event::{KeyCode, KeyEvent, KeyModifiers}, text::{ToLine, ToSpan}, widgets::Widget }; use tree_sitter_highlight::HighlightConfiguration; -use crate::state::{editor::EditorState, window::Window, GlobalState}; +use crate::{state::{editor::EditorState, window::Window, GlobalState}, tuicursor::TuiCursor}; use crate::{cursor::CursorMove, lua}; use super::statusbar::StatusBar; @@ -83,6 +80,17 @@ impl LuaEditor { KeyCode::Modifier(_) => {} } } + + pub fn render_cursor(&self) -> Option<TuiCursor> { + let state = GlobalState::instance(); + let buffer = &state.editor.buffer; + let nr_width = (buffer.lines().len().to_string().len() + 1).max(4) as u16; + + Some(TuiCursor { + position: (buffer.cursor().y() as u16, buffer.cursor().x() as u16 + nr_width), + style: ratatui::crossterm::cursor::SetCursorStyle::SteadyBar, + }) + } } impl Widget for &mut LuaEditor { @@ -139,40 +147,6 @@ impl Widget for &mut LuaEditor { (i + 1).to_line().right_aligned().render(nr_area, buf); } - - let mut cursor_area = text_area; - cursor_area.width = 1; - cursor_area.height = 1; - cursor_area.y += buffer.cursor().y() as u16; - cursor_area.x += buffer.cursor().x() as u16; - - let (first, _) = buffer.current_line().split_at(buffer.cursor().x()); - - for c in first.chars() { - if c == '\t' { - cursor_area.x += 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()) { - buffer - .current_line() - .chars() - .nth(buffer.cursor().x()) - .map(|c| if c == '\t' { ' ' } else { c }) - .unwrap_or(' ') - .to_span() - .reversed() - .render(cursor_area, buf); - } } } |