diff options
| author | Irene Knapp <ireneista@irenes.space> | 2026-03-27 09:57:55 -0700 |
|---|---|---|
| committer | Irene Knapp <ireneista@irenes.space> | 2026-03-27 09:57:55 -0700 |
| commit | 46b955afbce8997c39bda4e83abcaed2e954e65c (patch) | |
| tree | d5ea7bee4a5fab465d9d5d65fecb962afb8f778e /src | |
| parent | 916bce453c48f10d42eb3744aa4c62d8ca2c4c69 (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')
| -rw-r--r-- | src/main.rs | 66 | ||||
| -rw-r--r-- | src/terminal.rs | 5 |
2 files changed, 62 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), } } } diff --git a/src/terminal.rs b/src/terminal.rs index 28e83b3..9188c43 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -205,6 +205,11 @@ impl Terminal { Err(std::io::Error::other("Couldn't read terminal size.")) } } + + // vt100 + pub async fn clear(&mut self) -> Result<()> { + self.do_escape(EscapeType::CSI, "J", &[2]).await + } } |