fix small terminal size panic with info popup (#563)

* fix small terminal size panic with info popup

* remove unused enumerator

* fix subtraction overflow panic
imgbot
Kirawi 3 years ago committed by GitHub
parent b5223618ed
commit 815ee9e334
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -699,7 +699,8 @@ impl Component for EditorView {
match event { match event {
Event::Resize(width, height) => { Event::Resize(width, height) => {
// HAXX: offset the render area height by 1 to account for prompt/commandline // HAXX: offset the render area height by 1 to account for prompt/commandline
cx.editor.resize(Rect::new(0, 0, width, height - 1)); cx.editor
.resize(Rect::new(0, 0, width, height.saturating_sub(1)));
EventResult::Consumed(None) EventResult::Consumed(None)
} }
Event::Key(key) => { Event::Key(key) => {

@ -7,24 +7,32 @@ use tui::widgets::{Block, Borders, Widget};
impl Component for Info { impl Component for Info {
fn render(&self, viewport: Rect, surface: &mut Surface, cx: &mut Context) { fn render(&self, viewport: Rect, surface: &mut Surface, cx: &mut Context) {
let style = cx.editor.theme.get("ui.popup"); let style = cx.editor.theme.get("ui.popup");
// Calculate the area of the terminal to modify. Because we want to
// render at the bottom right, we use the viewport's width and height
// which evaluate to the most bottom right coordinate.
let (width, height) = (self.width + 2, self.height + 2);
let area = viewport.intersection(Rect::new(
viewport.width.saturating_sub(width),
viewport.height.saturating_sub(height + 2),
width,
height,
));
surface.clear_with(area, style);
let block = Block::default() let block = Block::default()
.title(self.title.as_str()) .title(self.title.as_str())
.borders(Borders::ALL) .borders(Borders::ALL)
.border_style(style); .border_style(style);
let Info { width, height, .. } = self; let inner = block.inner(area);
let (w, h) = (*width + 2, *height + 2);
// -2 to subtract command line + statusline. a bit of a hack, because of splits.
let area = viewport.intersection(Rect::new(
viewport.width.saturating_sub(w),
viewport.height.saturating_sub(h + 2),
w,
h,
));
surface.clear_with(area, style);
let Rect { x, y, .. } = block.inner(area);
for (y, line) in (y..).zip(self.text.lines()) {
surface.set_string(x, y, line, style);
}
block.render(area, surface); block.render(area, surface);
// Only write as many lines as there are rows available.
for (y, line) in (inner.y..)
.zip(self.text.lines())
.take(inner.height as usize)
{
surface.set_string(inner.x, y, line, style);
}
} }
} }

@ -64,22 +64,27 @@ impl Rect {
} }
} }
#[inline]
pub fn area(self) -> u16 { pub fn area(self) -> u16 {
self.width * self.height self.width * self.height
} }
#[inline]
pub fn left(self) -> u16 { pub fn left(self) -> u16 {
self.x self.x
} }
#[inline]
pub fn right(self) -> u16 { pub fn right(self) -> u16 {
self.x.saturating_add(self.width) self.x.saturating_add(self.width)
} }
#[inline]
pub fn top(self) -> u16 { pub fn top(self) -> u16 {
self.y self.y
} }
#[inline]
pub fn bottom(self) -> u16 { pub fn bottom(self) -> u16 {
self.y.saturating_add(self.height) self.y.saturating_add(self.height)
} }
@ -97,7 +102,18 @@ impl Rect {
} }
} }
/// Calculate the union between two [`Rect`]s.
pub fn union(self, other: Rect) -> Rect { pub fn union(self, other: Rect) -> Rect {
// Example:
//
// If `Rect` A is positioned at `(0, 0)` with a width and height of `5`,
// and `Rect` B is positioned at `(5, 0)` with a width and height of `2`,
// then this is the resulting union:
//
// x1 = min(0, 5) => x1 = 0
// y1 = min(0, 0) => y1 = 0
// x2 = max(0 + 5, 5 + 2) => x2 = 7
// y2 = max(0 + 5, 0 + 2) => y2 = 5
let x1 = min(self.x, other.x); let x1 = min(self.x, other.x);
let y1 = min(self.y, other.y); let y1 = min(self.y, other.y);
let x2 = max(self.x + self.width, other.x + other.width); let x2 = max(self.x + self.width, other.x + other.width);
@ -110,7 +126,18 @@ impl Rect {
} }
} }
/// Calculate the intersection between two [`Rect`]s.
pub fn intersection(self, other: Rect) -> Rect { pub fn intersection(self, other: Rect) -> Rect {
// Example:
//
// If `Rect` A is positioned at `(0, 0)` with a width and height of `5`,
// and `Rect` B is positioned at `(5, 0)` with a width and height of `2`,
// then this is the resulting intersection:
//
// x1 = max(0, 5) => x1 = 5
// y1 = max(0, 0) => y1 = 0
// x2 = min(0 + 5, 5 + 2) => x2 = 5
// y2 = min(0 + 5, 0 + 2) => y2 = 2
let x1 = max(self.x, other.x); let x1 = max(self.x, other.x);
let y1 = max(self.y, other.y); let y1 = max(self.y, other.y);
let x2 = min(self.x + self.width, other.x + other.width); let x2 = min(self.x + self.width, other.x + other.width);

Loading…
Cancel
Save