From 4f9bce07bd3352ce5e54b544496c3ba80e5bf782 Mon Sep 17 00:00:00 2001 From: Sondre Wold Date: Sat, 27 Apr 2024 08:03:25 +0200 Subject: [PATCH] Display file, scrolling --- octo/src/document.rs | 29 +++++++++++++++++++++++ octo/src/editor.rs | 55 ++++++++++++++++++++++++++++++++++++++------ octo/src/main.rs | 6 ++++- octo/src/row.rs | 21 +++++++++++++++++ 4 files changed, 103 insertions(+), 8 deletions(-) create mode 100644 octo/src/document.rs create mode 100644 octo/src/row.rs diff --git a/octo/src/document.rs b/octo/src/document.rs new file mode 100644 index 0000000..71e5ea6 --- /dev/null +++ b/octo/src/document.rs @@ -0,0 +1,29 @@ +use crate::Row; +use std::fs; + +#[derive(Default)] +pub struct Document { + rows: Vec, +} + +impl Document { + pub fn open(filename: &str) -> Result { + let contents = fs::read_to_string(filename)?; + let mut rows = Vec::new(); + for value in contents.lines() { + rows.push(Row::from(value)); + } + Ok(Self { rows }) + } + pub fn row(&self, index: usize) -> Option<&Row> { + self.rows.get(index) + } + + pub fn is_empty(&self) -> bool { + self.rows.is_empty() + } + + pub fn len(&self) -> usize { + self.rows.len() + } +} diff --git a/octo/src/editor.rs b/octo/src/editor.rs index dc87d89..17793ed 100644 --- a/octo/src/editor.rs +++ b/octo/src/editor.rs @@ -1,13 +1,15 @@ -use crate::Terminal; +use crate::{Document, Row, Terminal}; +use std::env; use termion::event::Key; const VERSION: &str = env!("CARGO_PKG_VERSION"); fn die(e: std::io::Error) { Terminal::clear_screen(); - panic!("{:?}", e); + panic!("{e:?}"); } +#[derive(Default)] pub struct Position { pub x: usize, pub y: usize, @@ -17,6 +19,8 @@ pub struct Editor { should_quit: bool, terminal: Terminal, current_position: Position, + offset: Position, + document: Document, } impl Editor { @@ -34,16 +38,25 @@ impl Editor { } } pub fn default() -> Self { + let args: Vec = env::args().collect(); + let document = if args.len() > 1 { + let file_name = &args[1]; + Document::open(&file_name).unwrap_or_default() + } else { + Document::default() + }; Self { should_quit: false, terminal: Terminal::default().expect("Failed to create terminal"), - current_position: Position { x: 0, y: 0 }, + document, + current_position: Position::default(), + offset: Position::default(), } } fn refresh_screen(&self) -> Result<(), std::io::Error> { Terminal::cursor_hide(); - Terminal::cursor_position(&Position { x: 0, y: 0 }); + Terminal::cursor_position(&Position::default()); if self.should_quit { Terminal::clear_screen(); println!("Goodbye.\r"); @@ -69,14 +82,32 @@ impl Editor { | Key::End => self.move_cursor(pressed_key), _ => (), }; + self.scroll(); Ok(()) } + fn scroll(&mut self) { + let Position { x, y } = self.current_position; + let width = self.terminal.size().width as usize; + let height = self.terminal.size().height as usize; + let mut offset = &mut self.offset; + if y < offset.y { + offset.y = y + } else if y >= offset.y.saturating_add(height) { + offset.y = y.saturating_sub(height).saturating_add(1); + } + if x < offset.x { + offset.x = x; + } else if x >= offset.x.saturating_add(width) { + offset.x = x.saturating_sub(width).saturating_add(1); + } + } + fn move_cursor(&mut self, key: Key) { let Position { mut x, mut y } = self.current_position; let size = self.terminal.size(); let width = size.width.saturating_sub(1) as usize; - let height = size.height.saturating_sub(1) as usize; + let height = self.document.len(); match key { Key::Up => y = y.saturating_sub(1), Key::Down => { @@ -110,11 +141,21 @@ impl Editor { println!("{}\r", welcome_message); } + fn draw_row(&self, row: &Row) { + let width = self.terminal.size().width as usize; + let start = self.offset.x; + let end = self.offset.x + width; + let row = row.render(start, end); + println!("{}\r", row); + } + fn draw_rows(&self) { let height = self.terminal.size().height; - for row in 0..height - 1 { + for terminal_row in 0..height - 1 { Terminal::clear_current_line(); - if row == height / 3 { + if let Some(row) = self.document.row(terminal_row as usize + self.offset.y) { + self.draw_row(row); + } else if self.document.is_empty() && terminal_row == height / 3 { self.draw_welcome_message(); } else { println!("~\r"); diff --git a/octo/src/main.rs b/octo/src/main.rs index 4bc5c57..4fe15bc 100644 --- a/octo/src/main.rs +++ b/octo/src/main.rs @@ -1,9 +1,13 @@ #![warn(clippy::all, clippy::pedantic)] +mod document; mod editor; +mod row; mod terminal; +pub use document::Document; use editor::Editor; -pub use terminal::Terminal; pub use editor::Position; +pub use row::Row; +pub use terminal::Terminal; fn main() { Editor::default().run(); diff --git a/octo/src/row.rs b/octo/src/row.rs new file mode 100644 index 0000000..665c109 --- /dev/null +++ b/octo/src/row.rs @@ -0,0 +1,21 @@ +use std::cmp; + +pub struct Row { + string: String, +} + +impl From<&str> for Row { + fn from(slice: &str) -> Self { + Self { + string: String::from(slice), + } + } +} + +impl Row { + pub fn render(&self, start: usize, end: usize) -> String { + let end = cmp::min(end, self.string.len()); + let start = cmp::min(start, end); + self.string.get(start..end).unwrap_or_default().to_string() + } +} -- 2.39.5