From 00808afe3c215d159574b23e30326379428060bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Mon, 1 Mar 2021 14:23:10 +0900 Subject: [PATCH] ui: Make editor more resilient about being shrunk too small. --- helix-term/src/application.rs | 7 ++++--- helix-term/src/commands.rs | 14 ++++++++------ helix-term/src/compositor.rs | 6 +++--- helix-term/src/terminal.rs | 16 ++++++++-------- helix-term/src/ui/editor.rs | 22 ++++++++++++---------- helix-view/src/view.rs | 2 +- 6 files changed, 36 insertions(+), 31 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index dfa819db..c63e6e57 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -70,10 +70,11 @@ fn render(&mut self) { let area = self.terminal.size().unwrap(); compositor.render(area, self.terminal.current_buffer_mut(), &mut cx); - let pos = compositor.cursor_position(area, &editor); + let pos = compositor + .cursor_position(area, &editor) + .map(|pos| (pos.col as u16, pos.row as u16)); - self.terminal.draw(); - self.terminal.set_cursor(pos.col as u16, pos.row as u16); + self.terminal.draw(pos); } pub async fn event_loop(&mut self) { diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 07e71a70..855a12eb 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1072,9 +1072,10 @@ pub fn completion(cx: &mut Context) { cx.callback = Some(Box::new( move |compositor: &mut Compositor, editor: &mut Editor| { let area = tui::layout::Rect::default(); // TODO: unused remove from cursor_position - let mut pos = compositor.cursor_position(area, editor); - pos.row += 1; // shift down by one row - menu.set_position(pos); + if let Some(mut pos) = compositor.cursor_position(area, editor) { + pos.row += 1; // shift down by one row + menu.set_position(pos); + }; compositor.push(Box::new(menu)); }, @@ -1133,9 +1134,10 @@ pub fn hover(cx: &mut Context) { cx.callback = Some(Box::new( move |compositor: &mut Compositor, editor: &mut Editor| { let area = tui::layout::Rect::default(); // TODO: unused remove from cursor_position - let mut pos = compositor.cursor_position(area, editor); - pos.row += 1; // shift down by one row - popup.set_position(pos); + if let Some(mut pos) = compositor.cursor_position(area, editor) { + pos.row += 1; // shift down by one row + popup.set_position(pos); + }; compositor.push(Box::new(popup)); }, diff --git a/helix-term/src/compositor.rs b/helix-term/src/compositor.rs index 3fee1214..59e93e03 100644 --- a/helix-term/src/compositor.rs +++ b/helix-term/src/compositor.rs @@ -120,12 +120,12 @@ pub fn render(&self, area: Rect, surface: &mut Surface, cx: &mut Context) { } } - pub fn cursor_position(&self, area: Rect, editor: &Editor) -> Position { + pub fn cursor_position(&self, area: Rect, editor: &Editor) -> Option { for layer in self.layers.iter().rev() { if let Some(pos) = layer.cursor_position(area, editor) { - return pos; + return Some(pos); } } - panic!("No layer returned a position!"); + None } } diff --git a/helix-term/src/terminal.rs b/helix-term/src/terminal.rs index e40343bd..fc9bc5ba 100644 --- a/helix-term/src/terminal.rs +++ b/helix-term/src/terminal.rs @@ -154,7 +154,7 @@ pub fn autoresize(&mut self) -> io::Result<()> { /// Synchronizes terminal size, calls the rendering closure, flushes the current internal state /// and prepares for the next draw call. - pub fn draw(&mut self) -> io::Result<()> { + pub fn draw(&mut self, cursor_position: Option<(u16, u16)>) -> io::Result<()> { // // Autoresize - otherwise we get glitches if shrinking or potential desync between widgets // // and the terminal (if growing), which may OOB. // self.autoresize()?; @@ -169,13 +169,13 @@ pub fn draw(&mut self) -> io::Result<()> { // Draw to stdout self.flush()?; - // match cursor_position { - // None => self.hide_cursor()?, - // Some((x, y)) => { - // self.show_cursor()?; - // self.set_cursor(x, y)?; - // } - // } + match cursor_position { + None => self.hide_cursor()?, + Some((x, y)) => { + self.show_cursor()?; + self.set_cursor(x, y)?; + } + } // Swap buffers self.buffers[1 - self.current].reset(); diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 32697a03..499d8021 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -42,7 +42,7 @@ pub fn render_view( viewport.x + OFFSET, viewport.y, viewport.width - OFFSET, - viewport.height - 1, + viewport.height.saturating_sub(1), ); // - 1 for statusline self.render_buffer(view, area, surface, theme, is_focused); @@ -52,7 +52,7 @@ pub fn render_view( let area = Rect::new( viewport.x, - viewport.y + viewport.height - 1, + viewport.y + viewport.height.saturating_sub(1), viewport.width, 1, ); @@ -433,14 +433,16 @@ fn cursor_position(&self, area: Rect, editor: &Editor) -> Option { // Mode::Insert => write!(stdout, "\x1B[6 q"), // mode => write!(stdout, "\x1B[2 q"), // }; - let view = editor.view(); - let cursor = view.doc.selection().cursor(); + // let view = editor.view(); + // let cursor = view.doc.selection().cursor(); - let mut pos = view - .screen_coords_at_pos(view.doc.text().slice(..), cursor) - .expect("Cursor is out of bounds."); - pos.col += view.area.x as usize + area.x as usize + OFFSET as usize; - pos.row += view.area.y as usize + area.y as usize; - Some(pos) + // if let Some(mut pos) = view.screen_coords_at_pos(view.doc.text().slice(..), cursor) { + // pos.col += view.area.x as usize + area.x as usize + OFFSET as usize; + // pos.row += view.area.y as usize + area.y as usize; + // return Some(pos); + // } + + // It's easier to just not render the cursor and use selection rendering instead. + None } } diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index f3d92bfd..1d806da9 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -65,7 +65,7 @@ pub fn ensure_cursor_in_view(&mut self) { /// Calculates the last visible line on screen #[inline] pub fn last_line(&self) -> usize { - let viewport = Rect::new(6, 0, self.area.width, self.area.height - 1); // - 1 for statusline + let viewport = Rect::new(6, 0, self.area.width, self.area.height.saturating_sub(1)); // - 1 for statusline std::cmp::min( self.first_line + (viewport.height as usize), self.doc.text().len_lines() - 1,