]> git.sondrewold.no Git - octo.git/commitdiff
More navigation
authorSondre Wold <[email protected]>
Wed, 1 May 2024 12:04:07 +0000 (14:04 +0200)
committerSondre Wold <[email protected]>
Wed, 1 May 2024 12:04:07 +0000 (14:04 +0200)
octo/Cargo.toml
octo/src/editor.rs
octo/src/row.rs

index bc088c14a3dff29e3cdf5810f2f33d42b191e5d1..160e7511b602fcf9d0ec19c9c469ae4827f103e0 100644 (file)
@@ -8,3 +8,4 @@ edition = "2021"
 [dependencies]
 crossterm = "0.27.0"
 termion = "3.0.0"
+unicode-segmentation = "1"
index 17793ed83dd5dc4cbe4e9e83d8d27425011e7d6b..458b0e2047a9e7eb5ce84988d519a56c2eedceb1 100644 (file)
@@ -62,7 +62,10 @@ impl Editor {
             println!("Goodbye.\r");
         } else {
             self.draw_rows();
-            Terminal::cursor_position(&self.current_position);
+            Terminal::cursor_position(&Position {
+                x: self.current_position.x.saturating_sub(self.offset.x),
+                y: self.current_position.y.saturating_sub(self.offset.y),
+            });
         }
         Terminal::cursor_show();
         Terminal::flush()
@@ -98,15 +101,20 @@ impl Editor {
         }
         if x < offset.x {
             offset.x = x;
-        } else if x >= offset.x.saturating_add(width) { 
+        } 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 terminal_height = self.terminal.size().height as usize;
         let Position { mut x, mut y } = self.current_position;
         let size = self.terminal.size();
-        let width = size.width.saturating_sub(1) as usize;
+        let mut width = if let Some(row) = self.document.row(y) {
+            row.len()
+        } else {
+            0
+        };
         let height = self.document.len();
         match key {
             Key::Up => y = y.saturating_sub(1),
@@ -115,18 +123,52 @@ impl Editor {
                     y = y.saturating_add(1);
                 }
             }
-            Key::Left => x = x.saturating_sub(1),
+            Key::Left => {
+                if x > 0 {
+                    x -= 1;
+                } else if y > 0 {
+                    y -= 1;
+                    if let Some(row) = self.document.row(y) {
+                        x = row.len();
+                    } else {
+                        x = 0;
+                    }
+                }
+            }
             Key::Right => {
                 if x < width {
-                    x = x.saturating_add(1);
+                    x += 1;
+                } else if y < height {
+                    y += 1;
+                    x = 0;
+                }
+            }
+            Key::PageUp => {
+                y = if y > terminal_height {
+                    y - terminal_height
+                } else {
+                    0
+                }
+            }
+            Key::PageDown => {
+                y = if y.saturating_add(terminal_height) < height {
+                    y + terminal_height as usize
+                } else {
+                    height
                 }
             }
-            Key::PageUp => y = 0,
-            Key::PageDown => y = height,
             Key::Home => x = 0,
             Key::End => x = width,
             _ => (),
         }
+        width = if let Some(row) = self.document.row(y) {
+            row.len()
+        } else {
+            0
+        };
+        if x > width {
+            x = width;
+        }
         self.current_position = Position { x, y };
     }
 
index 665c109e50ad8678d90a00351a399215e6e4025d..44ed3953d8a93fda83c2b11dd97365867fa809ef 100644 (file)
@@ -1,14 +1,19 @@
 use std::cmp;
+use unicode_segmentation::UnicodeSegmentation;
 
 pub struct Row {
     string: String,
+    len: usize,
 }
 
 impl From<&str> for Row {
     fn from(slice: &str) -> Self {
-        Self {
+        let mut row = Self {
             string: String::from(slice),
-        }
+            len: 0,
+        };
+        row.update_len();
+        row
     }
 }
 
@@ -16,6 +21,30 @@ 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()
+        let mut result = String::new();
+        for grapheme in self.string[..]
+            .graphemes(true)
+            .skip(start)
+            .take(end - start)
+        {
+            if grapheme == "\t" {
+                result.push_str(" ");
+            } else {
+                result.push_str(grapheme);
+            }
+        }
+        result
+    }
+
+    pub fn len(&self) -> usize {
+        self.len
+    }
+
+    pub fn is_empty(&self) -> bool {
+        self.len == 0
+    }
+
+    fn update_len(&mut self) {
+        self.len = self.string[..].graphemes(true).count()
     }
 }