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
+ }
}
|