diff --git a/src/app.rs b/src/app.rs index cae4768..9dedd7a 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,5 +1,7 @@ use std::error; +use ratatui::layout::Rect; + pub type AppResult = std::result::Result>; #[derive(Debug)] @@ -21,6 +23,7 @@ pub struct App { pub cursor_position: Position, pub cursor_offset: Position, pub opened_filename: String, + pub window_size: Rect, } impl Default for App { @@ -31,6 +34,7 @@ impl Default for App { cursor_position: Position { x: 0, y: 0 }, cursor_offset: Position { x: 0, y: 0 }, opened_filename: String::new(), + window_size: Rect::new(0, 0, 0, 0), } } } @@ -50,11 +54,14 @@ impl App { while self.cursor_position.y >= self.content.len() { self.content.push(String::new()); } - self.content[self.cursor_position.y].insert(self.cursor_position.x, c); + self.content[self.cursor_position.y + self.cursor_offset.y] + .insert(self.cursor_position.x + self.cursor_offset.x, c); self.cursor_position.x += 1; } pub fn add_new_line(&mut self) { + self.content + .insert(self.cursor_position.y + self.cursor_offset.y, String::new()); self.cursor_position.y += 1; self.cursor_position.x = 0; } @@ -68,23 +75,43 @@ impl App { } pub fn move_cursor(&mut self, direction: Direction) { - if direction.x < 0 && self.cursor_position.x > 0 { - self.cursor_position.x -= 1; + if direction.x < 0 && self.cursor_position.x + self.cursor_offset.x > 0 { + if self.cursor_position.x == 0 { + self.cursor_offset.x -= 1; + } else { + self.cursor_position.x -= 1; + } } else if direction.x > 0 { if let Some(line) = self.content.get(self.cursor_position.y) { - if line.len() > self.cursor_position.x { - self.cursor_position.x += 1; + if line.len() > self.cursor_position.x + self.cursor_offset.x { + if self.window_size.width.saturating_sub(1) > self.cursor_position.x as u16 { + self.cursor_position.x += 1; + } else { + self.cursor_offset.x += 1; + } } } } - if direction.y > 0 && self.cursor_position.y > 0 { - self.cursor_position.y -= 1; + if direction.y > 0 && self.cursor_position.y + self.cursor_offset.y > 0 { + if self.cursor_position.y == 0 { + self.cursor_offset.y -= 1; + } else { + self.cursor_position.y -= 1; + } + if self.cursor_position.x > self.content[self.cursor_position.y].len() { self.cursor_position.x = self.content[self.cursor_position.y].len(); } - } else if direction.y < 0 && self.cursor_position.y < self.content.len().saturating_sub(1) { - self.cursor_position.y += 1; + } else if direction.y < 0 + && self.cursor_position.y + self.cursor_offset.y < self.content.len().saturating_sub(1) + { + if self.window_size.height.saturating_sub(4) > self.cursor_position.y as u16 { + self.cursor_position.y += 1; + } else { + self.cursor_offset.y += 1; + } + if self.cursor_position.x > self.content[self.cursor_position.y].len() { self.cursor_position.x = self.content[self.cursor_position.y].len(); } diff --git a/src/main.rs b/src/main.rs index 5ed1d54..6b521f8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,7 @@ async fn main() -> AppResult<()> { let events = EventHandler::new(250); let mut tui = Tui::new(terminal, events); tui.init()?; + app.window_size = tui.get_terminal_size()?; tui.draw(&mut app)?; while app.running { @@ -24,7 +25,10 @@ async fn main() -> AppResult<()> { tui.draw(&mut app)?; } Event::Mouse(_) => tui.draw(&mut app)?, - Event::Resize(_, _) => tui.draw(&mut app)?, + Event::Resize(_, _) => { + app.window_size = tui.get_terminal_size()?; + tui.draw(&mut app)?; + } } } diff --git a/src/tui.rs b/src/tui.rs index da69d06..16c451e 100644 --- a/src/tui.rs +++ b/src/tui.rs @@ -4,8 +4,9 @@ use crate::ui; use crossterm::event::{DisableMouseCapture, EnableMouseCapture}; use crossterm::terminal::{self, EnterAlternateScreen, LeaveAlternateScreen}; use ratatui::backend::Backend; +use ratatui::layout::Rect; use ratatui::Terminal; -use std::io; +use std::io::{self, Error}; use std::panic; #[derive(Debug)] @@ -52,4 +53,8 @@ impl Tui { self.terminal.show_cursor()?; Ok(()) } + + pub fn get_terminal_size(&self) -> Result { + self.terminal.size() + } } diff --git a/src/ui.rs b/src/ui.rs index a824403..7f91857 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -18,7 +18,7 @@ pub fn render(app: &mut App, frame: &mut Frame) { let cursor_position_status = Line::from(format!( " {:>2}:{:<2} ", app.cursor_position.y + 1, - app.cursor_position.x + 1 + app.cursor_position.x + 1, )) .right_aligned() .style(Style::default().bg(Color::Rgb(128, 192, 255)).bold()); @@ -29,6 +29,7 @@ pub fn render(app: &mut App, frame: &mut Frame) { Constraint::Length(1), Constraint::Min(0), Constraint::Length(1), + Constraint::Length(1), ]) .split(frame.size()); @@ -52,11 +53,13 @@ pub fn render(app: &mut App, frame: &mut Frame) { ); frame.render_widget( - Paragraph::new(content_lines).style( - Style::default() - .fg(Color::Rgb(128, 192, 255)) - .bg(Color::Rgb(32, 32, 64)), - ), + Paragraph::new(content_lines) + .style( + Style::default() + .fg(Color::Rgb(128, 192, 255)) + .bg(Color::Rgb(32, 32, 64)), + ) + .scroll((app.cursor_offset.y as u16, app.cursor_offset.x as u16)), layout[1], ); @@ -78,6 +81,8 @@ pub fn render(app: &mut App, frame: &mut Frame) { status_bar_layout[1], ); + frame.render_widget(Line::from("Press Ctrl + C to quit").centered(), layout[3]); + frame.set_cursor( app.cursor_position.x as u16, app.cursor_position.y as u16 + 1,