on master help sign in
ui: Make editor more resilient about being shrunk too small.
00808afBlaž Hrastnik
helix-term/src/application.rs+4−3
@@ -70,10 +70,11 @@ impl Application {
70 let area = self.terminal.size().unwrap();
70 let area = self.terminal.size().unwrap();
71
71
72 compositor.render(area, self.terminal.current_buffer_mut(), &mut cx);
72 compositor.render(area, self.terminal.current_buffer_mut(), &mut cx);
73+ let pos = compositor
73− let pos = compositor.cursor_position(area, &editor);
74+ .cursor_position(area, &editor)
75+ .map(|pos| (pos.col as u16, pos.row as u16));
74
76
75− self.terminal.draw();
77+ self.terminal.draw(pos);
76− self.terminal.set_cursor(pos.col as u16, pos.row as u16);
77 }
78 }
78
79
79 pub async fn event_loop(&mut self) {
80 pub async fn event_loop(&mut self) {
helix-term/src/commands.rs+8−6
@@ -1072,9 +1072,10 @@ pub fn completion(cx: &mut Context) {
1072 cx.callback = Some(Box::new(
1072 cx.callback = Some(Box::new(
1073 move |compositor: &mut Compositor, editor: &mut Editor| {
1073 move |compositor: &mut Compositor, editor: &mut Editor| {
1074 let area = tui::layout::Rect::default(); // TODO: unused remove from cursor_position
1074 let area = tui::layout::Rect::default(); // TODO: unused remove from cursor_position
1075− let mut pos = compositor.cursor_position(area, editor);
1075+ if let Some(mut pos) = compositor.cursor_position(area, editor) {
1076− pos.row += 1; // shift down by one row
1076+ pos.row += 1; // shift down by one row
1077− menu.set_position(pos);
1077+ menu.set_position(pos);
1078+ };
1078
1079
1079 compositor.push(Box::new(menu));
1080 compositor.push(Box::new(menu));
1080 },
1081 },
@@ -1133,9 +1134,10 @@ pub fn hover(cx: &mut Context) {
1133 cx.callback = Some(Box::new(
1134 cx.callback = Some(Box::new(
1134 move |compositor: &mut Compositor, editor: &mut Editor| {
1135 move |compositor: &mut Compositor, editor: &mut Editor| {
1135 let area = tui::layout::Rect::default(); // TODO: unused remove from cursor_position
1136 let area = tui::layout::Rect::default(); // TODO: unused remove from cursor_position
1136− let mut pos = compositor.cursor_position(area, editor);
1137+ if let Some(mut pos) = compositor.cursor_position(area, editor) {
1137− pos.row += 1; // shift down by one row
1138+ pos.row += 1; // shift down by one row
1138− popup.set_position(pos);
1139+ popup.set_position(pos);
1140+ };
1139
1141
1140 compositor.push(Box::new(popup));
1142 compositor.push(Box::new(popup));
1141 },
1143 },
helix-term/src/compositor.rs+3−3
@@ -120,12 +120,12 @@ impl Compositor {
120 }
120 }
121 }
121 }
122
122
123− pub fn cursor_position(&self, area: Rect, editor: &Editor) -> Position {
123+ pub fn cursor_position(&self, area: Rect, editor: &Editor) -> Option<Position> {
124 for layer in self.layers.iter().rev() {
124 for layer in self.layers.iter().rev() {
125 if let Some(pos) = layer.cursor_position(area, editor) {
125 if let Some(pos) = layer.cursor_position(area, editor) {
126− return pos;
126+ return Some(pos);
127 }
127 }
128 }
128 }
129− panic!("No layer returned a position!");
129+ None
130 }
130 }
131}
131}
helix-term/src/terminal.rs+8−8
@@ -154,7 +154,7 @@ where
154
154
155 /// Synchronizes terminal size, calls the rendering closure, flushes the current internal state
155 /// Synchronizes terminal size, calls the rendering closure, flushes the current internal state
156 /// and prepares for the next draw call.
156 /// and prepares for the next draw call.
157− pub fn draw(&mut self) -> io::Result<()> {
157+ pub fn draw(&mut self, cursor_position: Option<(u16, u16)>) -> io::Result<()> {
158 // // Autoresize - otherwise we get glitches if shrinking or potential desync between widgets
158 // // Autoresize - otherwise we get glitches if shrinking or potential desync between widgets
159 // // and the terminal (if growing), which may OOB.
159 // // and the terminal (if growing), which may OOB.
160 // self.autoresize()?;
160 // self.autoresize()?;
@@ -169,13 +169,13 @@ where
169 // Draw to stdout
169 // Draw to stdout
170 self.flush()?;
170 self.flush()?;
171
171
172− // match cursor_position {
172+ match cursor_position {
173− // None => self.hide_cursor()?,
173+ None => self.hide_cursor()?,
174− // Some((x, y)) => {
174+ Some((x, y)) => {
175− // self.show_cursor()?;
175+ self.show_cursor()?;
176− // self.set_cursor(x, y)?;
176+ self.set_cursor(x, y)?;
177− // }
177+ }
178− // }
178+ }
179
179
180 // Swap buffers
180 // Swap buffers
181 self.buffers[1 - self.current].reset();
181 self.buffers[1 - self.current].reset();
helix-term/src/ui/editor.rs+13−11
@@ -42,7 +42,7 @@ impl EditorView {
42 viewport.x + OFFSET,
42 viewport.x + OFFSET,
43 viewport.y,
43 viewport.y,
44 viewport.width - OFFSET,
44 viewport.width - OFFSET,
45− viewport.height - 1,
45+ viewport.height.saturating_sub(1),
46 ); // - 1 for statusline
46 ); // - 1 for statusline
47 self.render_buffer(view, area, surface, theme, is_focused);
47 self.render_buffer(view, area, surface, theme, is_focused);
48
48
@@ -52,7 +52,7 @@ impl EditorView {
52
52
53 let area = Rect::new(
53 let area = Rect::new(
54 viewport.x,
54 viewport.x,
55− viewport.y + viewport.height - 1,
55+ viewport.y + viewport.height.saturating_sub(1),
56 viewport.width,
56 viewport.width,
57 1,
57 1,
58 );
58 );
@@ -433,14 +433,16 @@ impl Component for EditorView {
433 // Mode::Insert => write!(stdout, "\x1B[6 q"),
433 // Mode::Insert => write!(stdout, "\x1B[6 q"),
434 // mode => write!(stdout, "\x1B[2 q"),
434 // mode => write!(stdout, "\x1B[2 q"),
435 // };
435 // };
436− let view = editor.view();
436+ // let view = editor.view();
437− let cursor = view.doc.selection().cursor();
437+ // let cursor = view.doc.selection().cursor();
438−
438+
439− let mut pos = view
440− .screen_coords_at_pos(view.doc.text().slice(..), cursor)
439+ // if let Some(mut pos) = view.screen_coords_at_pos(view.doc.text().slice(..), cursor) {
441− .expect("Cursor is out of bounds.");
442− pos.col += view.area.x as usize + area.x as usize + OFFSET as usize;
440+ // pos.col += view.area.x as usize + area.x as usize + OFFSET as usize;
443− pos.row += view.area.y as usize + area.y as usize;
441+ // pos.row += view.area.y as usize + area.y as usize;
444− Some(pos)
442+ // return Some(pos);
443+ // }
444+
445+ // It's easier to just not render the cursor and use selection rendering instead.
446+ None
445 }
447 }
446}
448}
helix-view/src/view.rs+1−1
@@ -65,7 +65,7 @@ impl View {
65 /// Calculates the last visible line on screen
65 /// Calculates the last visible line on screen
66 #[inline]
66 #[inline]
67 pub fn last_line(&self) -> usize {
67 pub fn last_line(&self) -> usize {
68− let viewport = Rect::new(6, 0, self.area.width, self.area.height - 1); // - 1 for statusline
68+ let viewport = Rect::new(6, 0, self.area.width, self.area.height.saturating_sub(1)); // - 1 for statusline
69 std::cmp::min(
69 std::cmp::min(
70 self.first_line + (viewport.height as usize),
70 self.first_line + (viewport.height as usize),
71 self.doc.text().len_lines() - 1,
71 self.doc.text().len_lines() - 1,