summary refs log tree commit diff
path: root/src/main.rs
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2026-03-27 09:57:55 -0700
committerIrene Knapp <ireneista@irenes.space>2026-03-27 09:57:55 -0700
commit46b955afbce8997c39bda4e83abcaed2e954e65c (patch)
treed5ea7bee4a5fab465d9d5d65fecb962afb8f778e /src/main.rs
parent916bce453c48f10d42eb3744aa4c62d8ca2c4c69 (diff)
there is now a concept of a scroll-top
scrolling is handled in the most naive possible way, which is way too much redrawing and also doesn't have the desired centering behavior for longer movements

Force-Push: yes
Change-Id: I611b02d25553873a93f2c4c17e303356735581f7
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs66
1 files changed, 57 insertions, 9 deletions
diff --git a/src/main.rs b/src/main.rs
index f21096f..2f93a2e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -41,6 +41,7 @@ struct Window {
    * land in, if it exists in the target row.
    */
   cursor_neutral_column: RwLock<usize>,
+  scroll_top: RwLock<usize>,
 }
 
 
@@ -138,16 +139,19 @@ impl Ivy {
 
     let height = *terminal.height.read().await;
 
+    let window = self.window.read().await;
+    let scroll_top = *window.scroll_top.read().await;
+
     let mut screen_y = 0;
-    for logical_y in 0 .. height - 1 {
-      if let Some(span) = buffer.line_span(logical_y).await {
-        if logical_y > 0 {
+    for i in 0 .. height - 1 {
+      if let Some(span) = buffer.line_span(i + scroll_top).await {
+        if i > 0 {
           terminal.stdout.write_all("\n".as_bytes()).await?;
         }
 
         terminal.stdout.write_all(&buffer.contents.read().await[span]).await?;
 
-        screen_y = logical_y + 1;
+        screen_y += 1;
       } else {
         break;
       }
@@ -161,7 +165,8 @@ impl Ivy {
 
     let window = self.window.read().await;
     terminal.do_cursor_position(*window.cursor_column.read().await,
-                                *window.cursor_row.read().await).await?;
+                                *window.cursor_row.read().await
+                                - *window.scroll_top.read().await).await?;
     terminal.stdout.flush().await?;
 
     Ok(())
@@ -317,7 +322,28 @@ impl Ivy {
      * It does require taking a couple of locks that we might always need, but
      * there's no strong reason to avoid that.
      */
+    self.clamp_cursor_column().await?;
+
+    self.scroll_to_cursor().await?;
+
+    {
+      let window = self.window.read().await;
+      let row = *window.cursor_row.read().await;
+      let column = *window.cursor_column.read().await;
+
+      if old_row != row || old_column != column {
+        let mut terminal = self.terminal.write().await;
+        let scroll_top = *window.scroll_top.read().await;
+
+        terminal.do_cursor_position(column, row - scroll_top).await?;
+        terminal.stdout.flush().await?;
+      }
+    }
+
+    Ok(())
+  }
 
+  async fn clamp_cursor_column(&mut self) -> Result<()> {
     let window = self.window.write().await;
     let row = window.cursor_row.read().await;
     let mut column = window.cursor_column.write().await;
@@ -336,11 +362,32 @@ impl Ivy {
       }
     }
 
-    if old_row != *row || old_column != *column {
-      let mut terminal = self.terminal.write().await;
+    Ok(())
+  }
+
+  async fn scroll_to_cursor(&mut self) -> Result<()> {
+    let old_scroll_top = *self.window.read().await.scroll_top.read().await;
+
+    {
+      let terminal = self.terminal.read().await;
+      let window = self.window.write().await;
+
+      let mut scroll_top = window.scroll_top.write().await;
+      let row = *window.cursor_row.read().await;
+      let height = *terminal.height.read().await;
+      let last_visible = *scroll_top + height - 2;
+
+      if row < *scroll_top {
+        *scroll_top -= *scroll_top - row;
+      } else if row > last_visible {
+        *scroll_top += row - last_visible;
+      }
+    }
 
-      terminal.do_cursor_position(*column, *row).await?;
-      terminal.stdout.flush().await?;
+    let new_scroll_top = *self.window.read().await.scroll_top.read().await;
+    if old_scroll_top != new_scroll_top {
+      self.terminal.write().await.clear().await?;
+      self.draw().await?;
     }
 
     Ok(())
@@ -436,6 +483,7 @@ impl Window {
       cursor_row: RwLock::new(0),
       cursor_column: RwLock::new(0),
       cursor_neutral_column: RwLock::new(0),
+      scroll_top: RwLock::new(0),
     }
   }
 }