From 1e73d1f0b55d3d2a1f66fde5b1f5ee8596d78ee2 Mon Sep 17 00:00:00 2001 From: mcc Date: Sun, 8 Dec 2024 20:36:48 -0500 Subject: [PATCH 1/2] Capability to add an arbitrary number of custom highlight ranges to the text area. External API is pub fn custom_highlight(&mut self, range:((usize, usize), (usize, usize)), style:Style, priority:u8) --- src/highlight.rs | 39 ++++++++++++++++++++++++++++++++++----- src/textarea.rs | 23 ++++++++++++++++++++++- 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/src/highlight.rs b/src/highlight.rs index 70490ac..ee42d1e 100644 --- a/src/highlight.rs +++ b/src/highlight.rs @@ -15,6 +15,7 @@ enum Boundary { Select(Style), #[cfg(feature = "search")] Search(Style), + Custom(Style, u8), // style, priority End, } @@ -22,10 +23,11 @@ impl Boundary { fn cmp(&self, other: &Boundary) -> Ordering { fn rank(b: &Boundary) -> u8 { match b { - Boundary::Cursor(_) => 3, + Boundary::Cursor(_) => 30, #[cfg(feature = "search")] - Boundary::Search(_) => 2, - Boundary::Select(_) => 1, + Boundary::Search(_) => 20, + Boundary::Select(_) => 10, + Boundary::Custom(_, p) => *p, Boundary::End => 0, } } @@ -38,6 +40,7 @@ impl Boundary { Boundary::Select(s) => Some(*s), #[cfg(feature = "search")] Boundary::Search(s) => Some(*s), + Boundary::Custom(s, _) => Some(*s), Boundary::End => None, } } @@ -156,13 +159,15 @@ impl<'a> LineHighlighter<'a> { } } - pub fn selection( + // Shared code for selection and custom highlights + fn multiline_highlight( &mut self, current_row: usize, start_row: usize, start_off: usize, end_row: usize, end_off: usize, + boundary: Boundary ) { let (start, end) = if current_row == start_row { if start_row == end_row { @@ -181,11 +186,35 @@ impl<'a> LineHighlighter<'a> { }; if start != end { self.boundaries - .push((Boundary::Select(self.select_style), start)); + .push((boundary, start)); self.boundaries.push((Boundary::End, end)); } } + pub fn selection( + &mut self, + current_row: usize, + start_row: usize, + start_off: usize, + end_row: usize, + end_off: usize, + ) { + self.multiline_highlight(current_row, start_row, start_off, end_row, end_off, Boundary::Select(self.select_style)); + } + + pub fn custom( + &mut self, + current_row: usize, + start_row: usize, + start_off: usize, + end_row: usize, + end_off: usize, + style: Style, + priority: u8 + ) { + self.multiline_highlight(current_row, start_row, start_off, end_row, end_off, Boundary::Custom(style, priority)); + } + pub fn into_spans(self) -> Line<'a> { let Self { line, diff --git a/src/textarea.rs b/src/textarea.rs index 059354b..6db3650 100644 --- a/src/textarea.rs +++ b/src/textarea.rs @@ -55,6 +55,13 @@ impl fmt::Display for YankText { } } +#[derive(Clone, Debug)] +struct CustomHighlight { + range: ((usize, usize), (usize, usize)), + style: Style, + priority: u8 +} + /// A type to manage state of textarea. These are some important methods: /// /// - [`TextArea::default`] creates an empty textarea. @@ -125,6 +132,7 @@ pub struct TextArea<'a> { mask: Option, selection_start: Option<(usize, usize)>, select_style: Style, + custom_highlights: Vec } /// Convert any iterator whose elements can be converted into [`String`] into [`TextArea`]. Each [`String`] element is @@ -230,6 +238,7 @@ impl<'a> TextArea<'a> { mask: None, selection_start: None, select_style: Style::default().bg(Color::LightBlue), + custom_highlights: Default::default() } } @@ -1355,6 +1364,14 @@ impl<'a> TextArea<'a> { self.selection_start = None; } + pub fn custom_highlight(&mut self, range:((usize, usize), (usize, usize)), style:Style, priority:u8) { + self.custom_highlights.push(CustomHighlight { range, style, priority }); + } + + pub fn clear_custom_highlight(&mut self) { + self.custom_highlights.clear(); + } + /// Select the entire text. Cursor moves to the end of the text buffer. When text selection is already ongoing, /// it is canceled. /// ``` @@ -1592,7 +1609,7 @@ impl<'a> TextArea<'a> { self.cursor_style, self.tab_len, self.mask, - self.select_style, + self.select_style ); if let Some(style) = self.line_number_style { @@ -1612,6 +1629,10 @@ impl<'a> TextArea<'a> { hl.selection(row, start.row, start.offset, end.row, end.offset); } + for CustomHighlight { range:((start_row, start_offset), (end_row, end_offset)), style, priority } in &self.custom_highlights { + hl.custom(row, *start_row, *start_offset, *end_row, *end_offset, *style, *priority); + } + hl.into_spans() } From 4b0c5bb32d010ff9aab055690cf97f77d11b0eac Mon Sep 17 00:00:00 2001 From: mcc Date: Sun, 8 Dec 2024 20:40:11 -0500 Subject: [PATCH 2/2] rustfmt on custom highlight patch --- src/highlight.rs | 27 ++++++++++++++++++++------- src/textarea.rs | 38 ++++++++++++++++++++++++++++++-------- 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/src/highlight.rs b/src/highlight.rs index ee42d1e..3a29677 100644 --- a/src/highlight.rs +++ b/src/highlight.rs @@ -167,7 +167,7 @@ impl<'a> LineHighlighter<'a> { start_off: usize, end_row: usize, end_off: usize, - boundary: Boundary + boundary: Boundary, ) { let (start, end) = if current_row == start_row { if start_row == end_row { @@ -185,8 +185,7 @@ impl<'a> LineHighlighter<'a> { return; }; if start != end { - self.boundaries - .push((boundary, start)); + self.boundaries.push((boundary, start)); self.boundaries.push((Boundary::End, end)); } } @@ -199,7 +198,14 @@ impl<'a> LineHighlighter<'a> { end_row: usize, end_off: usize, ) { - self.multiline_highlight(current_row, start_row, start_off, end_row, end_off, Boundary::Select(self.select_style)); + self.multiline_highlight( + current_row, + start_row, + start_off, + end_row, + end_off, + Boundary::Select(self.select_style), + ); } pub fn custom( @@ -210,9 +216,16 @@ impl<'a> LineHighlighter<'a> { end_row: usize, end_off: usize, style: Style, - priority: u8 - ) { - self.multiline_highlight(current_row, start_row, start_off, end_row, end_off, Boundary::Custom(style, priority)); + priority: u8, + ) { + self.multiline_highlight( + current_row, + start_row, + start_off, + end_row, + end_off, + Boundary::Custom(style, priority), + ); } pub fn into_spans(self) -> Line<'a> { diff --git a/src/textarea.rs b/src/textarea.rs index 6db3650..29cc0c8 100644 --- a/src/textarea.rs +++ b/src/textarea.rs @@ -59,7 +59,7 @@ impl fmt::Display for YankText { struct CustomHighlight { range: ((usize, usize), (usize, usize)), style: Style, - priority: u8 + priority: u8, } /// A type to manage state of textarea. These are some important methods: @@ -132,7 +132,7 @@ pub struct TextArea<'a> { mask: Option, selection_start: Option<(usize, usize)>, select_style: Style, - custom_highlights: Vec + custom_highlights: Vec, } /// Convert any iterator whose elements can be converted into [`String`] into [`TextArea`]. Each [`String`] element is @@ -238,7 +238,7 @@ impl<'a> TextArea<'a> { mask: None, selection_start: None, select_style: Style::default().bg(Color::LightBlue), - custom_highlights: Default::default() + custom_highlights: Default::default(), } } @@ -1364,8 +1364,17 @@ impl<'a> TextArea<'a> { self.selection_start = None; } - pub fn custom_highlight(&mut self, range:((usize, usize), (usize, usize)), style:Style, priority:u8) { - self.custom_highlights.push(CustomHighlight { range, style, priority }); + pub fn custom_highlight( + &mut self, + range: ((usize, usize), (usize, usize)), + style: Style, + priority: u8, + ) { + self.custom_highlights.push(CustomHighlight { + range, + style, + priority, + }); } pub fn clear_custom_highlight(&mut self) { @@ -1609,7 +1618,7 @@ impl<'a> TextArea<'a> { self.cursor_style, self.tab_len, self.mask, - self.select_style + self.select_style, ); if let Some(style) = self.line_number_style { @@ -1629,8 +1638,21 @@ impl<'a> TextArea<'a> { hl.selection(row, start.row, start.offset, end.row, end.offset); } - for CustomHighlight { range:((start_row, start_offset), (end_row, end_offset)), style, priority } in &self.custom_highlights { - hl.custom(row, *start_row, *start_offset, *end_row, *end_offset, *style, *priority); + for CustomHighlight { + range: ((start_row, start_offset), (end_row, end_offset)), + style, + priority, + } in &self.custom_highlights + { + hl.custom( + row, + *start_row, + *start_offset, + *end_row, + *end_offset, + *style, + *priority, + ); } hl.into_spans()