From 34f46e7502a562ffb1a3f681046c6cb7e86f7286 Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Fri, 3 Dec 2021 12:48:07 +0900 Subject: Bump rust to 1.57, fix new lint failures --- helix-tui/src/widgets/table.rs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'helix-tui/src/widgets') diff --git a/helix-tui/src/widgets/table.rs b/helix-tui/src/widgets/table.rs index d7caa0b0..6aee5988 100644 --- a/helix-tui/src/widgets/table.rs +++ b/helix-tui/src/widgets/table.rs @@ -363,21 +363,12 @@ impl<'a> Table<'a> { } } -#[derive(Debug, Clone)] +#[derive(Debug, Default, Clone)] pub struct TableState { pub offset: usize, pub selected: Option, } -impl Default for TableState { - fn default() -> TableState { - TableState { - offset: 0, - selected: None, - } - } -} - impl TableState { pub fn selected(&self) -> Option { self.selected -- cgit v1.2.3-70-g09d2 From f5b0821860940782567a0baa17280aef04f845e3 Mon Sep 17 00:00:00 2001 From: Mathis Brossier Date: Sun, 16 Jan 2022 02:55:28 +0100 Subject: Fix panics when resizing (#1408) * Change buffer.get & buffer.get_mut to return Option, Implement Trait Index & IndexMut to panic * Prevent FilePicker from drawing outside buffer (rust panics) * apply suggestion * add function in_bounds to avoid useless calculations Co-authored-by: mathis --- helix-term/src/ui/editor.rs | 6 +-- helix-term/src/ui/menu.rs | 2 +- helix-term/src/ui/picker.rs | 12 ++--- helix-term/src/ui/prompt.rs | 2 +- helix-tui/src/backend/test.rs | 3 +- helix-tui/src/buffer.rs | 91 +++++++++++++++++++++++++++++--------- helix-tui/src/widgets/block.rs | 16 +++---- helix-tui/src/widgets/paragraph.rs | 2 +- helix-view/src/graphics.rs | 8 ++-- 9 files changed, 95 insertions(+), 47 deletions(-) (limited to 'helix-tui/src/widgets') diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 8d811ed2..c8c94e14 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -97,8 +97,7 @@ impl EditorView { let x = area.right(); let border_style = theme.get("ui.window"); for y in area.top()..area.bottom() { - surface - .get_mut(x, y) + surface[(x, y)] .set_symbol(tui::symbols::line::VERTICAL) //.set_symbol(" ") .set_style(border_style); @@ -393,8 +392,7 @@ impl EditorView { .add_modifier(Modifier::DIM) }); - surface - .get_mut(viewport.x + pos.col as u16, viewport.y + pos.row as u16) + surface[(viewport.x + pos.col as u16, viewport.y + pos.row as u16)] .set_style(style); } } diff --git a/helix-term/src/ui/menu.rs b/helix-term/src/ui/menu.rs index 69053db3..9758732c 100644 --- a/helix-term/src/ui/menu.rs +++ b/helix-term/src/ui/menu.rs @@ -301,7 +301,7 @@ impl Component for Menu { let is_marked = i >= scroll_line && i < scroll_line + scroll_height; if is_marked { - let cell = surface.get_mut(area.x + area.width - 2, area.y + i as u16); + let cell = &mut surface[(area.x + area.width - 2, area.y + i as u16)]; cell.set_symbol("▐ "); // cell.set_style(selected); // cell.set_style(if is_marked { selected } else { style }); diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 1ef94df0..a061513c 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -159,6 +159,7 @@ impl Component for FilePicker { // |picker | | | // | | | | // +---------+ +---------+ + let render_preview = area.width > MIN_SCREEN_WIDTH_FOR_PREVIEW; let area = inner_rect(area); // -- Render the frame: @@ -492,10 +493,9 @@ impl Component for Picker { let sep_style = Style::default().fg(Color::Rgb(90, 89, 119)); let borders = BorderType::line_symbols(BorderType::Plain); for x in inner.left()..inner.right() { - surface - .get_mut(x, inner.y + 1) - .set_symbol(borders.horizontal) - .set_style(sep_style); + if let Some(cell) = surface.get_mut(x, inner.y + 1) { + cell.set_symbol(borders.horizontal).set_style(sep_style); + } } // -- Render the contents: @@ -505,7 +505,7 @@ impl Component for Picker { let selected = cx.editor.theme.get("ui.text.focus"); let rows = inner.height; - let offset = self.cursor / (rows as usize) * (rows as usize); + let offset = self.cursor / std::cmp::max(1, (rows as usize) * (rows as usize)); let files = self.matches.iter().skip(offset).map(|(index, _score)| { (index, self.options.get(*index).unwrap()) // get_unchecked @@ -513,7 +513,7 @@ impl Component for Picker { for (i, (_index, option)) in files.take(rows as usize).enumerate() { if i == (self.cursor - offset) { - surface.set_string(inner.x - 2, inner.y + i as u16, ">", selected); + surface.set_string(inner.x.saturating_sub(2), inner.y + i as u16, ">", selected); } surface.set_string_truncated( diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index 0202de23..4c4fef26 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -330,7 +330,7 @@ impl Prompt { .max(BASE_WIDTH); let cols = std::cmp::max(1, area.width / max_len); - let col_width = (area.width - (cols)) / cols; + let col_width = (area.width.saturating_sub(cols)) / cols; let height = ((self.completion.len() as u16 + cols - 1) / cols) .min(10) // at most 10 rows (or less) diff --git a/helix-tui/src/backend/test.rs b/helix-tui/src/backend/test.rs index 3f56b49c..52474148 100644 --- a/helix-tui/src/backend/test.rs +++ b/helix-tui/src/backend/test.rs @@ -111,8 +111,7 @@ impl Backend for TestBackend { I: Iterator, { for (x, y, c) in content { - let cell = self.buffer.get_mut(x, y); - *cell = c.clone(); + self.buffer[(x, y)] = c.clone(); } Ok(()) } diff --git a/helix-tui/src/buffer.rs b/helix-tui/src/buffer.rs index c49a0200..3c5e09ac 100644 --- a/helix-tui/src/buffer.rs +++ b/helix-tui/src/buffer.rs @@ -90,17 +90,17 @@ impl Default for Cell { /// use helix_view::graphics::{Rect, Color, Style, Modifier}; /// /// let mut buf = Buffer::empty(Rect{x: 0, y: 0, width: 10, height: 5}); -/// buf.get_mut(0, 2).set_symbol("x"); -/// assert_eq!(buf.get(0, 2).symbol, "x"); +/// buf[(0, 2)].set_symbol("x"); +/// assert_eq!(buf[(0, 2)].symbol, "x"); /// buf.set_string(3, 0, "string", Style::default().fg(Color::Red).bg(Color::White)); -/// assert_eq!(buf.get(5, 0), &Cell{ +/// assert_eq!(buf[(5, 0)], Cell{ /// symbol: String::from("r"), /// fg: Color::Red, /// bg: Color::White, /// modifier: Modifier::empty() /// }); -/// buf.get_mut(5, 0).set_char('x'); -/// assert_eq!(buf.get(5, 0).symbol, "x"); +/// buf[(5, 0)].set_char('x'); +/// assert_eq!(buf[(5, 0)].symbol, "x"); /// ``` #[derive(Debug, Default, Clone, PartialEq)] pub struct Buffer { @@ -162,15 +162,38 @@ impl Buffer { } /// Returns a reference to Cell at the given coordinates - pub fn get(&self, x: u16, y: u16) -> &Cell { - let i = self.index_of(x, y); - &self.content[i] + pub fn get(&self, x: u16, y: u16) -> Option<&Cell> { + self.index_of_opt(x, y).map(|i| &self.content[i]) } /// Returns a mutable reference to Cell at the given coordinates - pub fn get_mut(&mut self, x: u16, y: u16) -> &mut Cell { - let i = self.index_of(x, y); - &mut self.content[i] + pub fn get_mut(&mut self, x: u16, y: u16) -> Option<&mut Cell> { + self.index_of_opt(x, y).map(|i| &mut self.content[i]) + } + + /// Tells whether the global (x, y) coordinates are inside the Buffer's area. + /// + /// Global coordinates are offset by the Buffer's area offset (`x`/`y`). + /// + /// # Examples + /// + /// ``` + /// # use helix_tui::buffer::Buffer; + /// # use helix_view::graphics::Rect; + /// let rect = Rect::new(200, 100, 10, 10); + /// let buffer = Buffer::empty(rect); + /// // Global coordinates inside the Buffer's area + /// assert!(buffer.in_bounds(209, 100)); + /// // Global coordinates outside the Buffer's area + /// assert!(!buffer.in_bounds(210, 100)); + /// ``` + /// + /// Global coordinates are offset by the Buffer's area offset (`x`/`y`). + pub fn in_bounds(&self, x: u16, y: u16) -> bool { + x >= self.area.left() + && x < self.area.right() + && y >= self.area.top() + && y < self.area.bottom() } /// Returns the index in the Vec for the given global (x, y) coordinates. @@ -184,7 +207,7 @@ impl Buffer { /// # use helix_view::graphics::Rect; /// let rect = Rect::new(200, 100, 10, 10); /// let buffer = Buffer::empty(rect); - /// // Global coordinates to the top corner of this buffer's area + /// // Global coordinates to the top corner of this Buffer's area /// assert_eq!(buffer.index_of(200, 100), 0); /// ``` /// @@ -193,10 +216,7 @@ impl Buffer { /// Panics when given an coordinate that is outside of this Buffer's area. pub fn index_of(&self, x: u16, y: u16) -> usize { debug_assert!( - x >= self.area.left() - && x < self.area.right() - && y >= self.area.top() - && y < self.area.bottom(), + self.in_bounds(x, y), "Trying to access position outside the buffer: x={}, y={}, area={:?}", x, y, @@ -205,6 +225,16 @@ impl Buffer { ((y - self.area.y) * self.area.width + (x - self.area.x)) as usize } + /// Returns the index in the Vec for the given global (x, y) coordinates, + /// or `None` if the coordinates are outside the buffer's area. + fn index_of_opt(&self, x: u16, y: u16) -> Option { + if self.in_bounds(x, y) { + Some(self.index_of(x, y)) + } else { + None + } + } + /// Returns the (global) coordinates of a cell given its index /// /// Global coordinates are offset by the Buffer's area offset (`x`/`y`). @@ -278,6 +308,11 @@ impl Buffer { where S: AsRef, { + // prevent panic if out of range + if !self.in_bounds(x, y) || width == 0 { + return (x, y); + } + let mut index = self.index_of(x, y); let mut x_offset = x as usize; let width = if ellipsis { width - 1 } else { width }; @@ -372,7 +407,7 @@ impl Buffer { pub fn set_background(&mut self, area: Rect, color: Color) { for y in area.top()..area.bottom() { for x in area.left()..area.right() { - self.get_mut(x, y).set_bg(color); + self[(x, y)].set_bg(color); } } } @@ -380,7 +415,7 @@ impl Buffer { pub fn set_style(&mut self, area: Rect, style: Style) { for y in area.top()..area.bottom() { for x in area.left()..area.right() { - self.get_mut(x, y).set_style(style); + self[(x, y)].set_style(style); } } } @@ -408,7 +443,7 @@ impl Buffer { pub fn clear(&mut self, area: Rect) { for x in area.left()..area.right() { for y in area.top()..area.bottom() { - self.get_mut(x, y).reset(); + self[(x, y)].reset(); } } } @@ -417,7 +452,7 @@ impl Buffer { pub fn clear_with(&mut self, area: Rect, style: Style) { for x in area.left()..area.right() { for y in area.top()..area.bottom() { - let cell = self.get_mut(x, y); + let cell = &mut self[(x, y)]; cell.reset(); cell.set_style(style); } @@ -509,6 +544,22 @@ impl Buffer { } } +impl std::ops::Index<(u16, u16)> for Buffer { + type Output = Cell; + + fn index(&self, (x, y): (u16, u16)) -> &Self::Output { + let i = self.index_of(x, y); + &self.content[i] + } +} + +impl std::ops::IndexMut<(u16, u16)> for Buffer { + fn index_mut(&mut self, (x, y): (u16, u16)) -> &mut Self::Output { + let i = self.index_of(x, y); + &mut self.content[i] + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/helix-tui/src/widgets/block.rs b/helix-tui/src/widgets/block.rs index 648c2d7e..d43ad41d 100644 --- a/helix-tui/src/widgets/block.rs +++ b/helix-tui/src/widgets/block.rs @@ -140,14 +140,14 @@ impl<'a> Widget for Block<'a> { // Sides if self.borders.intersects(Borders::LEFT) { for y in area.top()..area.bottom() { - buf.get_mut(area.left(), y) + buf[(area.left(), y)] .set_symbol(symbols.vertical) .set_style(self.border_style); } } if self.borders.intersects(Borders::TOP) { for x in area.left()..area.right() { - buf.get_mut(x, area.top()) + buf[(x, area.top())] .set_symbol(symbols.horizontal) .set_style(self.border_style); } @@ -155,7 +155,7 @@ impl<'a> Widget for Block<'a> { if self.borders.intersects(Borders::RIGHT) { let x = area.right() - 1; for y in area.top()..area.bottom() { - buf.get_mut(x, y) + buf[(x, y)] .set_symbol(symbols.vertical) .set_style(self.border_style); } @@ -163,7 +163,7 @@ impl<'a> Widget for Block<'a> { if self.borders.intersects(Borders::BOTTOM) { let y = area.bottom() - 1; for x in area.left()..area.right() { - buf.get_mut(x, y) + buf[(x, y)] .set_symbol(symbols.horizontal) .set_style(self.border_style); } @@ -171,22 +171,22 @@ impl<'a> Widget for Block<'a> { // Corners if self.borders.contains(Borders::RIGHT | Borders::BOTTOM) { - buf.get_mut(area.right() - 1, area.bottom() - 1) + buf[(area.right() - 1, area.bottom() - 1)] .set_symbol(symbols.bottom_right) .set_style(self.border_style); } if self.borders.contains(Borders::RIGHT | Borders::TOP) { - buf.get_mut(area.right() - 1, area.top()) + buf[(area.right() - 1, area.top())] .set_symbol(symbols.top_right) .set_style(self.border_style); } if self.borders.contains(Borders::LEFT | Borders::BOTTOM) { - buf.get_mut(area.left(), area.bottom() - 1) + buf[(area.left(), area.bottom() - 1)] .set_symbol(symbols.bottom_left) .set_style(self.border_style); } if self.borders.contains(Borders::LEFT | Borders::TOP) { - buf.get_mut(area.left(), area.top()) + buf[(area.left(), area.top())] .set_symbol(symbols.top_left) .set_style(self.border_style); } diff --git a/helix-tui/src/widgets/paragraph.rs b/helix-tui/src/widgets/paragraph.rs index fee35d25..8bafbb9a 100644 --- a/helix-tui/src/widgets/paragraph.rs +++ b/helix-tui/src/widgets/paragraph.rs @@ -176,7 +176,7 @@ impl<'a> Widget for Paragraph<'a> { if y >= self.scroll.0 { let mut x = get_line_offset(current_line_width, text_area.width, self.alignment); for StyledGrapheme { symbol, style } in current_line { - buf.get_mut(text_area.left() + x, text_area.top() + y - self.scroll.0) + buf[(text_area.left() + x, text_area.top() + y - self.scroll.0)] .set_symbol(if symbol.is_empty() { // If the symbol is empty, the last char which rendered last time will // leave on the line. It's a quick fix. diff --git a/helix-view/src/graphics.rs b/helix-view/src/graphics.rs index b8e43ba5..5fd54c8c 100644 --- a/helix-view/src/graphics.rs +++ b/helix-view/src/graphics.rs @@ -323,7 +323,7 @@ impl FromStr for Modifier { /// ]; /// let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1)); /// for style in &styles { -/// buffer.get_mut(0, 0).set_style(*style); +/// buffer[(0, 0)].set_style(*style); /// } /// assert_eq!( /// Style { @@ -332,7 +332,7 @@ impl FromStr for Modifier { /// add_modifier: Modifier::BOLD, /// sub_modifier: Modifier::empty(), /// }, -/// buffer.get(0, 0).style(), +/// buffer[(0, 0)].style(), /// ); /// ``` /// @@ -348,7 +348,7 @@ impl FromStr for Modifier { /// ]; /// let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1)); /// for style in &styles { -/// buffer.get_mut(0, 0).set_style(*style); +/// buffer[(0, 0)].set_style(*style); /// } /// assert_eq!( /// Style { @@ -357,7 +357,7 @@ impl FromStr for Modifier { /// add_modifier: Modifier::empty(), /// sub_modifier: Modifier::empty(), /// }, -/// buffer.get(0, 0).style(), +/// buffer[(0, 0)].style(), /// ); /// ``` #[derive(Debug, Clone, Copy, PartialEq)] -- cgit v1.2.3-70-g09d2 From e7eab95b943ff15396c5d512a9c95650ab98a902 Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Fri, 14 Jan 2022 12:25:59 +0900 Subject: Update to rust 1.58, fix a bunch of optional lints --- flake.lock | 24 ++++++++++++------------ helix-core/src/increment/date_time.rs | 32 ++++++++++++++++---------------- helix-term/src/commands.rs | 35 ++++++++++++++++------------------- helix-term/src/job.rs | 14 +++++++------- helix-term/src/keymap.rs | 8 ++++---- helix-term/src/ui/completion.rs | 2 +- helix-tui/src/widgets/block.rs | 10 +++++----- helix-tui/src/widgets/paragraph.rs | 2 +- helix-view/src/info.rs | 4 ++-- 9 files changed, 64 insertions(+), 67 deletions(-) (limited to 'helix-tui/src/widgets') diff --git a/flake.lock b/flake.lock index 606a72f3..94e443e3 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "devshell": { "locked": { - "lastModified": 1640301433, - "narHash": "sha256-eplae8ZNiEmxbOgwUn9IihaJfEUxoUilkwciRPGskYE=", + "lastModified": 1641980203, + "narHash": "sha256-RiWJ3+6V267Ji+P54K1Xrj1Nsah9BfG/aLfIhqgVyBY=", "owner": "numtide", "repo": "devshell", - "rev": "f87fb932740abe1c1b46f6edd8a36ade17881666", + "rev": "d897c1ddb4eab66cc2b783c7868d78555b9880ad", "type": "github" }, "original": { @@ -41,11 +41,11 @@ ] }, "locked": { - "lastModified": 1641449444, - "narHash": "sha256-InqsyCVafPqXmK7YqUfFVpb6eVYJWUWbYXEvey0J+3c=", + "lastModified": 1642054253, + "narHash": "sha256-kHh9VmaB7gbS6pheheC4x0uT84LEmhfbsbWEQJgU2E4=", "owner": "yusdacra", "repo": "nix-cargo-integration", - "rev": "d1aa15a832db331a97082b7f8c7da737a6789c77", + "rev": "f8fa9af990195a3f63fe2dde84aa187e193da793", "type": "github" }, "original": { @@ -56,11 +56,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1639699734, - "narHash": "sha256-tlX6WebGmiHb2Hmniff+ltYp+7dRfdsBxw9YczLsP60=", + "lastModified": 1641887635, + "narHash": "sha256-kDGpufwzVaiGe5e1sBUBPo9f1YN+nYHJlYqCaVpZTQQ=", "owner": "nixos", "repo": "nixpkgs", - "rev": "03ec468b14067729a285c2c7cfa7b9434a04816c", + "rev": "b2737d4980a17cc2b7d600d7d0b32fd7333aca88", "type": "github" }, "original": { @@ -99,11 +99,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1639880499, - "narHash": "sha256-/BibDmFwgWuuTUkNVO6YlvuTSWM9dpBvlZoTAPs7ORI=", + "lastModified": 1642128126, + "narHash": "sha256-av8JUACdrTfQYl/ftZJvKpZEmZfa0avCq7tt5Usdoq0=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "c6c83589ae048af20d93d01eb07a4176012093d0", + "rev": "ce4ef6f2d74f2b68f7547df1de22d1b0037ce4ad", "type": "github" }, "original": { diff --git a/helix-core/src/increment/date_time.rs b/helix-core/src/increment/date_time.rs index e3cfe107..1703c3ba 100644 --- a/helix-core/src/increment/date_time.rs +++ b/helix-core/src/increment/date_time.rs @@ -195,82 +195,82 @@ struct DateField { impl DateField { fn from_specifier(specifier: &str) -> Option { match specifier { - "Y" => Some(DateField { + "Y" => Some(Self { regex: r"\d{4}", unit: DateUnit::Years, max_len: 5, }), - "y" => Some(DateField { + "y" => Some(Self { regex: r"\d\d", unit: DateUnit::Years, max_len: 2, }), - "m" => Some(DateField { + "m" => Some(Self { regex: r"[0-1]\d", unit: DateUnit::Months, max_len: 2, }), - "d" => Some(DateField { + "d" => Some(Self { regex: r"[0-3]\d", unit: DateUnit::Days, max_len: 2, }), - "-d" => Some(DateField { + "-d" => Some(Self { regex: r"[1-3]?\d", unit: DateUnit::Days, max_len: 2, }), - "a" => Some(DateField { + "a" => Some(Self { regex: r"Sun|Mon|Tue|Wed|Thu|Fri|Sat", unit: DateUnit::Days, max_len: 3, }), - "A" => Some(DateField { + "A" => Some(Self { regex: r"Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday", unit: DateUnit::Days, max_len: 9, }), - "b" | "h" => Some(DateField { + "b" | "h" => Some(Self { regex: r"Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec", unit: DateUnit::Months, max_len: 3, }), - "B" => Some(DateField { + "B" => Some(Self { regex: r"January|February|March|April|May|June|July|August|September|October|November|December", unit: DateUnit::Months, max_len: 9, }), - "H" => Some(DateField { + "H" => Some(Self { regex: r"[0-2]\d", unit: DateUnit::Hours, max_len: 2, }), - "M" => Some(DateField { + "M" => Some(Self { regex: r"[0-5]\d", unit: DateUnit::Minutes, max_len: 2, }), - "S" => Some(DateField { + "S" => Some(Self { regex: r"[0-5]\d", unit: DateUnit::Seconds, max_len: 2, }), - "I" => Some(DateField { + "I" => Some(Self { regex: r"[0-1]\d", unit: DateUnit::Hours, max_len: 2, }), - "-I" => Some(DateField { + "-I" => Some(Self { regex: r"1?\d", unit: DateUnit::Hours, max_len: 2, }), - "P" => Some(DateField { + "P" => Some(Self { regex: r"am|pm", unit: DateUnit::AmPm, max_len: 2, }), - "p" => Some(DateField { + "p" => Some(Self { regex: r"AM|PM", unit: DateUnit::AmPm, max_len: 2, diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index c14216c0..9ac12931 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -173,7 +173,7 @@ macro_rules! static_commands { impl MappableCommand { pub fn execute(&self, cx: &mut Context) { match &self { - MappableCommand::Typable { name, args, doc: _ } => { + Self::Typable { name, args, doc: _ } => { let args: Vec> = args.iter().map(Cow::from).collect(); if let Some(command) = cmd::TYPABLE_COMMAND_MAP.get(name.as_str()) { let mut cx = compositor::Context { @@ -186,21 +186,21 @@ impl MappableCommand { } } } - MappableCommand::Static { fun, .. } => (fun)(cx), + Self::Static { fun, .. } => (fun)(cx), } } pub fn name(&self) -> &str { match &self { - MappableCommand::Typable { name, .. } => name, - MappableCommand::Static { name, .. } => name, + Self::Typable { name, .. } => name, + Self::Static { name, .. } => name, } } pub fn doc(&self) -> &str { match &self { - MappableCommand::Typable { doc, .. } => doc, - MappableCommand::Static { doc, .. } => doc, + Self::Typable { doc, .. } => doc, + Self::Static { doc, .. } => doc, } } @@ -3494,11 +3494,9 @@ pub fn apply_document_resource_op(op: &lsp::ResourceOp) -> std::io::Result<()> { match op { ResourceOp::Create(op) => { let path = op.uri.to_file_path().unwrap(); - let ignore_if_exists = if let Some(options) = &op.options { + let ignore_if_exists = op.options.as_ref().map_or(false, |options| { !options.overwrite.unwrap_or(false) && options.ignore_if_exists.unwrap_or(false) - } else { - false - }; + }); if ignore_if_exists && path.exists() { Ok(()) } else { @@ -3508,11 +3506,12 @@ pub fn apply_document_resource_op(op: &lsp::ResourceOp) -> std::io::Result<()> { ResourceOp::Delete(op) => { let path = op.uri.to_file_path().unwrap(); if path.is_dir() { - let recursive = if let Some(options) = &op.options { - options.recursive.unwrap_or(false) - } else { - false - }; + let recursive = op + .options + .as_ref() + .and_then(|options| options.recursive) + .unwrap_or(false); + if recursive { fs::remove_dir_all(&path) } else { @@ -3527,11 +3526,9 @@ pub fn apply_document_resource_op(op: &lsp::ResourceOp) -> std::io::Result<()> { ResourceOp::Rename(op) => { let from = op.old_uri.to_file_path().unwrap(); let to = op.new_uri.to_file_path().unwrap(); - let ignore_if_exists = if let Some(options) = &op.options { + let ignore_if_exists = op.options.as_ref().map_or(false, |options| { !options.overwrite.unwrap_or(false) && options.ignore_if_exists.unwrap_or(false) - } else { - false - }; + }); if ignore_if_exists && to.exists() { Ok(()) } else { diff --git a/helix-term/src/job.rs b/helix-term/src/job.rs index 4fa38174..f5a0a425 100644 --- a/helix-term/src/job.rs +++ b/helix-term/src/job.rs @@ -22,8 +22,8 @@ pub struct Jobs { } impl Job { - pub fn new> + Send + 'static>(f: F) -> Job { - Job { + pub fn new> + Send + 'static>(f: F) -> Self { + Self { future: f.map(|r| r.map(|()| None)).boxed(), wait: false, } @@ -31,22 +31,22 @@ impl Job { pub fn with_callback> + Send + 'static>( f: F, - ) -> Job { - Job { + ) -> Self { + Self { future: f.map(|r| r.map(Some)).boxed(), wait: false, } } - pub fn wait_before_exiting(mut self) -> Job { + pub fn wait_before_exiting(mut self) -> Self { self.wait = true; self } } impl Jobs { - pub fn new() -> Jobs { - Jobs::default() + pub fn new() -> Self { + Self::default() } pub fn spawn> + Send + 'static>(&mut self, f: F) { diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index c4bd25ed..79a06206 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -344,7 +344,7 @@ pub struct Keymap { impl Keymap { pub fn new(root: KeyTrie) -> Self { - Keymap { + Self { root, state: Vec::new(), sticky: None, @@ -368,7 +368,7 @@ impl Keymap { /// key cancels pending keystrokes. If there are no pending keystrokes but a /// sticky node is in use, it will be cleared. pub fn get(&mut self, key: KeyEvent) -> KeymapResult { - if let key!(Esc) = key { + if key!(Esc) == key { if !self.state.is_empty() { return KeymapResult::new( // Note that Esc is not included here @@ -477,7 +477,7 @@ impl DerefMut for Keymaps { } impl Default for Keymaps { - fn default() -> Keymaps { + fn default() -> Self { let normal = keymap!({ "Normal mode" "h" | "left" => move_char_left, "j" | "down" => move_line_down, @@ -784,7 +784,7 @@ impl Default for Keymaps { "C-x" => completion, "C-r" => insert_register, }); - Keymaps(hashmap!( + Self(hashmap!( Mode::Normal => Keymap::new(normal), Mode::Select => Keymap::new(select), Mode::Insert => Keymap::new(insert), diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index 274330c0..c9ed3b4a 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -158,7 +158,7 @@ impl Completion { let resolved_additional_text_edits = if item.additional_text_edits.is_some() { None } else { - Completion::resolve_completion_item(doc, item.clone()) + Self::resolve_completion_item(doc, item.clone()) .and_then(|item| item.additional_text_edits) }; diff --git a/helix-tui/src/widgets/block.rs b/helix-tui/src/widgets/block.rs index d43ad41d..26223c3e 100644 --- a/helix-tui/src/widgets/block.rs +++ b/helix-tui/src/widgets/block.rs @@ -15,12 +15,12 @@ pub enum BorderType { } impl BorderType { - pub fn line_symbols(border_type: BorderType) -> line::Set { + pub fn line_symbols(border_type: Self) -> line::Set { match border_type { - BorderType::Plain => line::NORMAL, - BorderType::Rounded => line::ROUNDED, - BorderType::Double => line::DOUBLE, - BorderType::Thick => line::THICK, + Self::Plain => line::NORMAL, + Self::Rounded => line::ROUNDED, + Self::Double => line::DOUBLE, + Self::Thick => line::THICK, } } } diff --git a/helix-tui/src/widgets/paragraph.rs b/helix-tui/src/widgets/paragraph.rs index 8bafbb9a..4e839162 100644 --- a/helix-tui/src/widgets/paragraph.rs +++ b/helix-tui/src/widgets/paragraph.rs @@ -166,7 +166,7 @@ impl<'a> Widget for Paragraph<'a> { Box::new(WordWrapper::new(&mut styled, text_area.width, trim)) } else { let mut line_composer = Box::new(LineTruncator::new(&mut styled, text_area.width)); - if let Alignment::Left = self.alignment { + if self.alignment == Alignment::Left { line_composer.set_horizontal_offset(self.scroll.1); } line_composer diff --git a/helix-view/src/info.rs b/helix-view/src/info.rs index b5a002fa..73856154 100644 --- a/helix-view/src/info.rs +++ b/helix-view/src/info.rs @@ -16,7 +16,7 @@ pub struct Info { } impl Info { - pub fn new(title: &str, body: Vec<(&str, BTreeSet)>) -> Info { + pub fn new(title: &str, body: Vec<(&str, BTreeSet)>) -> Self { let body = body .into_iter() .map(|(desc, events)| { @@ -38,7 +38,7 @@ impl Info { ); } - Info { + Self { title: title.to_string(), width: text.lines().map(|l| l.width()).max().unwrap() as u16, height: body.len() as u16, -- cgit v1.2.3-70-g09d2 From f064894e5778071ef8cc563380f48cfdd9acba59 Mon Sep 17 00:00:00 2001 From: Omnikar Date: Sun, 23 Jan 2022 02:37:23 -0500 Subject: Fix Clippy lints in tests (#1563) Co-authored-by: Blaž Hrastnik --- helix-core/src/auto_pairs.rs | 4 ++-- helix-core/src/chars.rs | 9 ++++----- helix-core/src/diff.rs | 2 +- helix-core/src/history.rs | 4 ++-- helix-core/src/indent.rs | 4 ++-- helix-core/src/line_ending.rs | 2 +- helix-core/src/selection.rs | 16 ++++++++-------- helix-core/src/surround.rs | 1 + helix-core/src/transaction.rs | 2 +- helix-tui/src/widgets/reflow.rs | 4 ++-- helix-view/src/view.rs | 4 ++-- 11 files changed, 26 insertions(+), 26 deletions(-) (limited to 'helix-tui/src/widgets') diff --git a/helix-core/src/auto_pairs.rs b/helix-core/src/auto_pairs.rs index 9d1152bc..40802680 100644 --- a/helix-core/src/auto_pairs.rs +++ b/helix-core/src/auto_pairs.rs @@ -322,7 +322,7 @@ mod test { use super::*; use smallvec::smallvec; - const LINE_END: &'static str = crate::DEFAULT_LINE_ENDING.as_str(); + const LINE_END: &str = crate::DEFAULT_LINE_ENDING.as_str(); fn differing_pairs() -> impl Iterator { PAIRS.iter().filter(|(open, close)| open != close) @@ -339,7 +339,7 @@ mod test { expected_doc: &Rope, expected_sel: &Selection, ) { - let trans = hook(&in_doc, &in_sel, ch).unwrap(); + let trans = hook(in_doc, in_sel, ch).unwrap(); let mut actual_doc = in_doc.clone(); assert!(trans.apply(&mut actual_doc)); assert_eq!(expected_doc, &actual_doc); diff --git a/helix-core/src/chars.rs b/helix-core/src/chars.rs index c8e5efbd..54991574 100644 --- a/helix-core/src/chars.rs +++ b/helix-core/src/chars.rs @@ -91,12 +91,11 @@ mod test { #[test] fn test_categorize() { - const EOL_TEST_CASE: &'static str = "\n\r\u{000B}\u{000C}\u{0085}\u{2028}\u{2029}"; - const WORD_TEST_CASE: &'static str = - "_hello_world_あいうえおー12345678901234567890"; - const PUNCTUATION_TEST_CASE: &'static str = + const EOL_TEST_CASE: &str = "\n\r\u{000B}\u{000C}\u{0085}\u{2028}\u{2029}"; + const WORD_TEST_CASE: &str = "_hello_world_あいうえおー12345678901234567890"; + const PUNCTUATION_TEST_CASE: &str = "!\"#$%&\'()*+,-./:;<=>?@[\\]^`{|}~!”#$%&’()*+、。:;<=>?@「」^`{|}~"; - const WHITESPACE_TEST_CASE: &'static str = "      "; + const WHITESPACE_TEST_CASE: &str = "      "; for ch in EOL_TEST_CASE.chars() { assert_eq!(CharCategory::Eol, categorize_char(ch)); diff --git a/helix-core/src/diff.rs b/helix-core/src/diff.rs index 3349213d..6960c679 100644 --- a/helix-core/src/diff.rs +++ b/helix-core/src/diff.rs @@ -58,7 +58,7 @@ mod tests { let mut old = Rope::from(a); let new = Rope::from(b); compare_ropes(&old, &new).apply(&mut old); - old.to_string() == new.to_string() + old == new } } } diff --git a/helix-core/src/history.rs b/helix-core/src/history.rs index 4b1c8d3b..bb95213c 100644 --- a/helix-core/src/history.rs +++ b/helix-core/src/history.rs @@ -448,8 +448,8 @@ mod test { change: crate::transaction::Change, instant: Instant, ) { - let txn = Transaction::change(&state.doc, vec![change.clone()].into_iter()); - history.commit_revision_at_timestamp(&txn, &state, instant); + let txn = Transaction::change(&state.doc, vec![change].into_iter()); + history.commit_revision_at_timestamp(&txn, state, instant); txn.apply(&mut state.doc); } diff --git a/helix-core/src/indent.rs b/helix-core/src/indent.rs index ac2a1208..a8ea3012 100644 --- a/helix-core/src/indent.rs +++ b/helix-core/src/indent.rs @@ -416,7 +416,7 @@ where ", ); - let doc = Rope::from(doc); + let doc = doc; use crate::diagnostic::Severity; use crate::syntax::{ Configuration, IndentationConfiguration, LanguageConfiguration, Loader, @@ -454,7 +454,7 @@ where let language_config = loader.language_config_for_scope("source.rust").unwrap(); let highlight_config = language_config.highlight_config(&[]).unwrap(); - let syntax = Syntax::new(&doc, highlight_config.clone(), std::sync::Arc::new(loader)); + let syntax = Syntax::new(&doc, highlight_config, std::sync::Arc::new(loader)); let text = doc.slice(..); let tab_width = 4; diff --git a/helix-core/src/line_ending.rs b/helix-core/src/line_ending.rs index 3541305c..8eb426e1 100644 --- a/helix-core/src/line_ending.rs +++ b/helix-core/src/line_ending.rs @@ -250,7 +250,7 @@ mod line_ending_tests { assert_eq!(get_line_ending_of_str(&text[..6]), Some(LineEnding::CR)); assert_eq!(get_line_ending_of_str(&text[..12]), Some(LineEnding::LF)); assert_eq!(get_line_ending_of_str(&text[..17]), Some(LineEnding::Crlf)); - assert_eq!(get_line_ending_of_str(&text[..]), None); + assert_eq!(get_line_ending_of_str(text), None); } #[test] diff --git a/helix-core/src/selection.rs b/helix-core/src/selection.rs index 1515c4fc..c6eceb4b 100644 --- a/helix-core/src/selection.rs +++ b/helix-core/src/selection.rs @@ -766,16 +766,16 @@ mod test { fn test_contains() { let range = Range::new(10, 12); - assert_eq!(range.contains(9), false); - assert_eq!(range.contains(10), true); - assert_eq!(range.contains(11), true); - assert_eq!(range.contains(12), false); - assert_eq!(range.contains(13), false); + assert!(!range.contains(9)); + assert!(range.contains(10)); + assert!(range.contains(11)); + assert!(!range.contains(12)); + assert!(!range.contains(13)); let range = Range::new(9, 6); - assert_eq!(range.contains(9), false); - assert_eq!(range.contains(7), true); - assert_eq!(range.contains(6), true); + assert!(!range.contains(9)); + assert!(range.contains(7)); + assert!(range.contains(6)); } #[test] diff --git a/helix-core/src/surround.rs b/helix-core/src/surround.rs index b53b0a78..58eb23cf 100644 --- a/helix-core/src/surround.rs +++ b/helix-core/src/surround.rs @@ -172,6 +172,7 @@ mod test { use ropey::Rope; use smallvec::SmallVec; + #[allow(clippy::type_complexity)] fn check_find_nth_pair_pos( text: &str, cases: Vec<(usize, char, usize, Option<(usize, usize)>)>, diff --git a/helix-core/src/transaction.rs b/helix-core/src/transaction.rs index d8d389f3..30995e8c 100644 --- a/helix-core/src/transaction.rs +++ b/helix-core/src/transaction.rs @@ -761,7 +761,7 @@ mod test { #[test] fn combine_with_utf8() { - const TEST_CASE: &'static str = "Hello, これはヘリックスエディターです!"; + const TEST_CASE: &str = "Hello, これはヘリックスエディターです!"; let empty = Rope::from(""); let a = ChangeSet::new(&empty); diff --git a/helix-tui/src/widgets/reflow.rs b/helix-tui/src/widgets/reflow.rs index 21847783..33e52bb4 100644 --- a/helix-tui/src/widgets/reflow.rs +++ b/helix-tui/src/widgets/reflow.rs @@ -404,8 +404,8 @@ mod test { let text = "コンピュータ上で文字を扱う場合、典型的には文字による通信を行う場合にその両端点\ では、"; let (word_wrapper, word_wrapper_width) = - run_composer(Composer::WordWrapper { trim: true }, &text, width); - let (line_truncator, _) = run_composer(Composer::LineTruncator, &text, width); + run_composer(Composer::WordWrapper { trim: true }, text, width); + let (line_truncator, _) = run_composer(Composer::LineTruncator, text, width); assert_eq!(line_truncator, vec!["コンピュータ上で文字"]); let wrapped = vec![ "コンピュータ上で文字", diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index 89a6c196..adfcd071 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -356,7 +356,7 @@ mod tests { let text = rope.slice(..); assert_eq!( - view.text_pos_at_screen_coords(&text, 40, 40 + OFFSET + 0, 4), + view.text_pos_at_screen_coords(&text, 40, 40 + OFFSET, 4), Some(0) ); @@ -389,7 +389,7 @@ mod tests { let text = rope.slice(..); assert_eq!( - view.text_pos_at_screen_coords(&text, 40, 40 + OFFSET + 0, 4), + view.text_pos_at_screen_coords(&text, 40, 40 + OFFSET, 4), Some(0) ); -- cgit v1.2.3-70-g09d2 From 094a0aa3f9877e3b1049f262e65c8efea2b7b73e Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Mon, 31 Jan 2022 13:42:32 +0900 Subject: Render code actions as a menu, allow adding padding to popup --- helix-term/src/commands.rs | 40 ++++++++++++++++++++++++++-------------- helix-term/src/ui/menu.rs | 15 +++++++++++---- helix-term/src/ui/mod.rs | 2 +- helix-term/src/ui/popup.rs | 24 ++++++++++++++++++++---- helix-tui/src/widgets/block.rs | 2 +- 5 files changed, 59 insertions(+), 24 deletions(-) (limited to 'helix-tui/src/widgets') diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 96acb424..6bc2b9b6 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -39,7 +39,7 @@ use movement::Movement; use crate::{ args, compositor::{self, Component, Compositor}, - ui::{self, FilePicker, Picker, Popup, Prompt, PromptEvent}, + ui::{self, FilePicker, Popup, Prompt, PromptEvent}, }; use crate::job::{self, Job, Jobs}; @@ -3463,6 +3463,15 @@ fn workspace_symbol_picker(cx: &mut Context) { ) } +impl ui::menu::Item for lsp::CodeActionOrCommand { + fn label(&self) -> &str { + match self { + lsp::CodeActionOrCommand::CodeAction(action) => action.title.as_str(), + lsp::CodeActionOrCommand::Command(command) => command.title.as_str(), + } + } +} + pub fn code_action(cx: &mut Context) { let (view, doc) = current!(cx.editor); @@ -3491,16 +3500,15 @@ pub fn code_action(cx: &mut Context) { return; } - let picker = Picker::new( - false, - actions, - |action| match action { - lsp::CodeActionOrCommand::CodeAction(action) => { - action.title.as_str().into() - } - lsp::CodeActionOrCommand::Command(command) => command.title.as_str().into(), - }, - move |editor, code_action, _action| match code_action { + let picker = ui::Menu::new(actions, move |editor, code_action, event| { + if event != PromptEvent::Validate { + return; + } + + // always present here + let code_action = code_action.unwrap(); + + match code_action { lsp::CodeActionOrCommand::Command(command) => { log::debug!("code action command: {:?}", command); execute_lsp_command(editor, command.clone()); @@ -3518,9 +3526,13 @@ pub fn code_action(cx: &mut Context) { execute_lsp_command(editor, command.clone()); } } - }, - ); - let popup = Popup::new("code-action", picker); + } + }); + let popup = + Popup::new("code-action", picker).margin(helix_view::graphics::Margin { + vertical: 1, + horizontal: 1, + }); compositor.push(Box::new(popup)) } }, diff --git a/helix-term/src/ui/menu.rs b/helix-term/src/ui/menu.rs index 9758732c..e127e09b 100644 --- a/helix-term/src/ui/menu.rs +++ b/helix-term/src/ui/menu.rs @@ -14,11 +14,18 @@ use helix_view::{graphics::Rect, Editor}; use tui::layout::Constraint; pub trait Item { - fn sort_text(&self) -> &str; - fn filter_text(&self) -> &str; - fn label(&self) -> &str; - fn row(&self) -> Row; + + fn sort_text(&self) -> &str { + self.label() + } + fn filter_text(&self) -> &str { + self.label() + } + + fn row(&self) -> Row { + Row::new(vec![Cell::from(self.label())]) + } } pub struct Menu { diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 9ff9118f..5d650c65 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -2,7 +2,7 @@ mod completion; pub(crate) mod editor; mod info; mod markdown; -mod menu; +pub mod menu; mod picker; mod popup; mod prompt; diff --git a/helix-term/src/ui/popup.rs b/helix-term/src/ui/popup.rs index bf7510a2..4d319423 100644 --- a/helix-term/src/ui/popup.rs +++ b/helix-term/src/ui/popup.rs @@ -6,7 +6,7 @@ use crossterm::event::Event; use tui::buffer::Buffer as Surface; use helix_core::Position; -use helix_view::graphics::Rect; +use helix_view::graphics::{Margin, Rect}; // TODO: share logic with Menu, it's essentially Popup(render_fn), but render fn needs to return // a width/height hint. maybe Popup(Box) @@ -14,6 +14,7 @@ use helix_view::graphics::Rect; pub struct Popup { contents: T, position: Option, + margin: Margin, size: (u16, u16), child_size: (u16, u16), scroll: usize, @@ -25,6 +26,10 @@ impl Popup { Self { contents, position: None, + margin: Margin { + vertical: 0, + horizontal: 0, + }, size: (0, 0), child_size: (0, 0), scroll: 0, @@ -36,6 +41,11 @@ impl Popup { self.position = pos; } + pub fn margin(mut self, margin: Margin) -> Self { + self.margin = margin; + self + } + pub fn get_rel_position(&mut self, viewport: Rect, cx: &Context) -> (u16, u16) { let position = self .position @@ -126,13 +136,18 @@ impl Component for Popup { let max_width = 120.min(viewport.0); let max_height = 26.min(viewport.1.saturating_sub(2)); // add some spacing in the viewport + let inner = Rect::new(0, 0, max_width, max_height).inner(&self.margin); + let (width, height) = self .contents - .required_size((max_width, max_height)) + .required_size((inner.width, inner.height)) .expect("Component needs required_size implemented in order to be embedded in a popup"); self.child_size = (width, height); - self.size = (width.min(max_width), height.min(max_height)); + self.size = ( + (width + self.margin.horizontal * 2).min(max_width), + (height + self.margin.vertical * 2).min(max_height), + ); // re-clamp scroll offset let max_offset = self.child_size.1.saturating_sub(self.size.1); @@ -156,7 +171,8 @@ impl Component for Popup { let background = cx.editor.theme.get("ui.popup"); surface.clear_with(area, background); - self.contents.render(area, surface, cx); + let inner = area.inner(&self.margin); + self.contents.render(inner, surface, cx); } fn id(&self) -> Option<&'static str> { diff --git a/helix-tui/src/widgets/block.rs b/helix-tui/src/widgets/block.rs index 26223c3e..f084a324 100644 --- a/helix-tui/src/widgets/block.rs +++ b/helix-tui/src/widgets/block.rs @@ -134,7 +134,7 @@ impl<'a> Widget for Block<'a> { if area.area() == 0 { return; } - buf.set_style(area, self.style); + buf.clear_with(area, self.style); let symbols = BorderType::line_symbols(self.border_type); // Sides -- cgit v1.2.3-70-g09d2 From ad62e1e129c84c285b6c4f47d8d5e1a94fd6947b Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Mon, 7 Feb 2022 10:29:43 +0900 Subject: fix: Revert Block widget change that broke autoinfo background --- helix-tui/src/widgets/block.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'helix-tui/src/widgets') diff --git a/helix-tui/src/widgets/block.rs b/helix-tui/src/widgets/block.rs index f084a324..26223c3e 100644 --- a/helix-tui/src/widgets/block.rs +++ b/helix-tui/src/widgets/block.rs @@ -134,7 +134,7 @@ impl<'a> Widget for Block<'a> { if area.area() == 0 { return; } - buf.clear_with(area, self.style); + buf.set_style(area, self.style); let symbols = BorderType::line_symbols(self.border_type); // Sides -- cgit v1.2.3-70-g09d2