on master help sign in
fix small terminal size panic with info popup (#563)
815ee9eKirawi
helix-term/src/ui/editor.rs+2−1
@@ -699,7 +699,8 @@ impl Component for EditorView {
699 match event {
699 match event {
700 Event::Resize(width, height) => {
700 Event::Resize(width, height) => {
701 // HAXX: offset the render area height by 1 to account for prompt/commandline
701 // HAXX: offset the render area height by 1 to account for prompt/commandline
702+ cx.editor
702− cx.editor.resize(Rect::new(0, 0, width, height - 1));
703+ .resize(Rect::new(0, 0, width, height.saturating_sub(1)));
703 EventResult::Consumed(None)
704 EventResult::Consumed(None)
704 }
705 }
705 Event::Key(key) => {
706 Event::Key(key) => {
helix-term/src/ui/info.rs+22−14
@@ -7,24 +7,32 @@ use tui::widgets::{Block, Borders, Widget};
7impl Component for Info {
7impl Component for Info {
8 fn render(&self, viewport: Rect, surface: &mut Surface, cx: &mut Context) {
8 fn render(&self, viewport: Rect, surface: &mut Surface, cx: &mut Context) {
9 let style = cx.editor.theme.get("ui.popup");
9 let style = cx.editor.theme.get("ui.popup");
10+
11+ // Calculate the area of the terminal to modify. Because we want to
12+ // render at the bottom right, we use the viewport's width and height
13+ // which evaluate to the most bottom right coordinate.
14+ let (width, height) = (self.width + 2, self.height + 2);
15+ let area = viewport.intersection(Rect::new(
16+ viewport.width.saturating_sub(width),
17+ viewport.height.saturating_sub(height + 2),
18+ width,
19+ height,
20+ ));
21+ surface.clear_with(area, style);
22+
10 let block = Block::default()
23 let block = Block::default()
11 .title(self.title.as_str())
24 .title(self.title.as_str())
12 .borders(Borders::ALL)
25 .borders(Borders::ALL)
13 .border_style(style);
26 .border_style(style);
14− let Info { width, height, .. } = self;
15− let (w, h) = (*width + 2, *height + 2);
16− // -2 to subtract command line + statusline. a bit of a hack, because of splits.
17− let area = viewport.intersection(Rect::new(
18− viewport.width.saturating_sub(w),
19− viewport.height.saturating_sub(h + 2),
20− w,
21− h,
22− ));
23− surface.clear_with(area, style);
24− let Rect { x, y, .. } = block.inner(area);
27+ let inner = block.inner(area);
25− for (y, line) in (y..).zip(self.text.lines()) {
26− surface.set_string(x, y, line, style);
27− }
28 block.render(area, surface);
28 block.render(area, surface);
29+
30+ // Only write as many lines as there are rows available.
31+ for (y, line) in (inner.y..)
32+ .zip(self.text.lines())
33+ .take(inner.height as usize)
34+ {
35+ surface.set_string(inner.x, y, line, style);
36+ }
29 }
37 }
30}
38}
helix-view/src/graphics.rs+27
@@ -64,22 +64,27 @@ impl Rect {
64 }
64 }
65 }
65 }
66
66
67+ #[inline]
67 pub fn area(self) -> u16 {
68 pub fn area(self) -> u16 {
68 self.width * self.height
69 self.width * self.height
69 }
70 }
70
71
72+ #[inline]
71 pub fn left(self) -> u16 {
73 pub fn left(self) -> u16 {
72 self.x
74 self.x
73 }
75 }
74
76
77+ #[inline]
75 pub fn right(self) -> u16 {
78 pub fn right(self) -> u16 {
76 self.x.saturating_add(self.width)
79 self.x.saturating_add(self.width)
77 }
80 }
78
81
82+ #[inline]
79 pub fn top(self) -> u16 {
83 pub fn top(self) -> u16 {
80 self.y
84 self.y
81 }
85 }
82
86
87+ #[inline]
83 pub fn bottom(self) -> u16 {
88 pub fn bottom(self) -> u16 {
84 self.y.saturating_add(self.height)
89 self.y.saturating_add(self.height)
85 }
90 }
@@ -97,7 +102,18 @@ impl Rect {
97 }
102 }
98 }
103 }
99
104
105+ /// Calculate the union between two [`Rect`]s.
100 pub fn union(self, other: Rect) -> Rect {
106 pub fn union(self, other: Rect) -> Rect {
107+ // Example:
108+ //
109+ // If `Rect` A is positioned at `(0, 0)` with a width and height of `5`,
110+ // and `Rect` B is positioned at `(5, 0)` with a width and height of `2`,
111+ // then this is the resulting union:
112+ //
113+ // x1 = min(0, 5) => x1 = 0
114+ // y1 = min(0, 0) => y1 = 0
115+ // x2 = max(0 + 5, 5 + 2) => x2 = 7
116+ // y2 = max(0 + 5, 0 + 2) => y2 = 5
101 let x1 = min(self.x, other.x);
117 let x1 = min(self.x, other.x);
102 let y1 = min(self.y, other.y);
118 let y1 = min(self.y, other.y);
103 let x2 = max(self.x + self.width, other.x + other.width);
119 let x2 = max(self.x + self.width, other.x + other.width);
@@ -110,7 +126,18 @@ impl Rect {
110 }
126 }
111 }
127 }
112
128
129+ /// Calculate the intersection between two [`Rect`]s.
113 pub fn intersection(self, other: Rect) -> Rect {
130 pub fn intersection(self, other: Rect) -> Rect {
131+ // Example:
132+ //
133+ // If `Rect` A is positioned at `(0, 0)` with a width and height of `5`,
134+ // and `Rect` B is positioned at `(5, 0)` with a width and height of `2`,
135+ // then this is the resulting intersection:
136+ //
137+ // x1 = max(0, 5) => x1 = 5
138+ // y1 = max(0, 0) => y1 = 0
139+ // x2 = min(0 + 5, 5 + 2) => x2 = 5
140+ // y2 = min(0 + 5, 0 + 2) => y2 = 2
114 let x1 = max(self.x, other.x);
141 let x1 = max(self.x, other.x);
115 let y1 = max(self.y, other.y);
142 let y1 = max(self.y, other.y);
116 let x2 = min(self.x + self.width, other.x + other.width);
143 let x2 = min(self.x + self.width, other.x + other.width);