M src/app.rs => src/app.rs +39 -4
@@ 97,10 97,43 @@ impl InputBuffer {
// adjust viewspan to match current terminal width (less the prompt)
if self.span_len() > width_with_prompt {
// shrink the view span
- self.end -= self.span_len() - width_with_prompt;
+ let delta = self.span_len() - width_with_prompt;
+
+ let trailing_width = self.buffer.len() - self.pos;
+
+ if self.pos + trailing_width > width_with_prompt {
+ let start_to_pos = self.pos - self.start;
+ self.start = self.pos;
+
+ if start_to_pos < delta {
+ self.end -= delta - start_to_pos;
+ }
+ } else {
+ self.end -= delta;
+ }
} else if self.span_len() < width_with_prompt {
// grow the view span
- self.end += width_with_prompt - self.span_len();
+ let mut delta = width_with_prompt - self.span_len();
+
+ // consume delta to display tail of the buffer outside the viewport.
+ if self.buffer.len() > self.end {
+ let overhang = cmp::min(delta, self.buffer.len() - self.end);
+ self.end += overhang;
+ delta -= overhang;
+ }
+
+ // repeat the same for the head of the buffer outside the viewport.
+ if self.start > 0 {
+ let overhang = cmp::min(delta, self.start);
+ self.start -= overhang;
+ delta -= overhang;
+ }
+
+ // if we still have new columns place them on the end.
+ //
+ // this should only be the case if the input span is larger than
+ // the current buffer.
+ self.end += delta;
}
// draw status info on line 2
@@ 123,10 156,12 @@ impl InputBuffer {
.queue(Clear(ClearType::CurrentLine))?
.queue(Print(prompt.to_string()))?;
- // draw the current viewport
+ // render the current viewport & update the cursor
+ let beg = self.start;
+ let end = cmp::min(self.buffer.len(), self.end);
let relative_cursor_pos = (self.pos - self.start) + prompt.len() + 1;
stdout
- .queue(Print(&self.buffer[self.start..]))?
+ .queue(Print(&self.buffer[beg..end]))?
.queue(cursor::MoveToColumn(relative_cursor_pos as u16))?;
Ok(stdout.flush()?)
M src/main.rs => src/main.rs +14 -7
@@ 16,8 16,19 @@ mod app;
fn main() -> anyhow::Result<()> {
-
crossterm::terminal::enable_raw_mode()?;
+
+ let res = std::panic::catch_unwind(|| {
+ ui_thread()
+ });
+
+ crossterm::terminal::disable_raw_mode()?;
+ println!("panic: {:?}", res);
+
+ Ok(())
+}
+
+fn ui_thread() -> anyhow::Result<()> {
let mut shell = app::Shell::new()?;
let poll_hz = Duration::from_millis(1000 / 120);
@@ 47,10 58,6 @@ fn main() -> anyhow::Result<()> {
.execute(LeaveAlternateScreen)?
.execute(cursor::Show)?;
crossterm::terminal::disable_raw_mode()?;
- Ok(())
-}
-
-
-
-
+ Ok(())
+}<
\ No newline at end of file