]> git.sondrewold.no Git - octo.git/commitdiff
Display file, scrolling
authorSondre Wold <[email protected]>
Sat, 27 Apr 2024 06:03:25 +0000 (08:03 +0200)
committerSondre Wold <[email protected]>
Sat, 27 Apr 2024 06:03:25 +0000 (08:03 +0200)
octo/src/document.rs [new file with mode: 0644]
octo/src/editor.rs
octo/src/main.rs
octo/src/row.rs [new file with mode: 0644]

diff --git a/octo/src/document.rs b/octo/src/document.rs
new file mode 100644 (file)
index 0000000..71e5ea6
--- /dev/null
@@ -0,0 +1,29 @@
+use crate::Row;
+use std::fs;
+
+#[derive(Default)]
+pub struct Document {
+    rows: Vec<Row>,
+}
+
+impl Document {
+    pub fn open(filename: &str) -> Result<Self, std::io::Error> {
+        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()
+    }
+}
index dc87d899d8bf86cc8a212ec0280aa694766dc280..17793ed83dd5dc4cbe4e9e83d8d27425011e7d6b 100644 (file)
@@ -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<String> = 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");
index 4bc5c579f2e12111cd6ce802108cb04d68f6a141..4fe15bc3628762a0204d1ec3c063f7697bde3032 100644 (file)
@@ -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 (file)
index 0000000..665c109
--- /dev/null
@@ -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()
+    }
+}