diff --git a/src/components/mail/listing/compact.rs b/src/components/mail/listing/compact.rs index f32d63c84..b05e1a8e7 100644 --- a/src/components/mail/listing/compact.rs +++ b/src/components/mail/listing/compact.rs @@ -1167,14 +1167,8 @@ impl CompactListing { debug!(crate::conf::text_format_regexps(context, "listing.from")) { let t = self.data_columns.columns[2].insert_tag(text_formatter.tag); - for _match in text_formatter.regexp.0.find_iter(strings.from.as_bytes()) { - if let Ok(_match) = _match { - self.data_columns.columns[2].set_tag( - t, - (_match.start(), idx), - (_match.end(), idx), - ); - } + for (start, end) in text_formatter.regexp.find_iter(strings.from.as_str()) { + self.data_columns.columns[2].set_tag(t, (start, idx), (end, idx)); } } } @@ -1212,18 +1206,8 @@ impl CompactListing { debug!(crate::conf::text_format_regexps(context, "listing.subject")) { let t = self.data_columns.columns[4].insert_tag(text_formatter.tag); - for _match in text_formatter - .regexp - .0 - .find_iter(strings.subject.as_bytes()) - { - if let Ok(_match) = _match { - self.data_columns.columns[4].set_tag( - t, - (_match.start(), idx), - (_match.end(), idx), - ); - } + for (start, end) in text_formatter.regexp.find_iter(strings.subject.as_str()) { + self.data_columns.columns[4].set_tag(t, (start, idx), (end, idx)); } } } diff --git a/src/components/utilities.rs b/src/components/utilities.rs index aff984a61..a0918a284 100644 --- a/src/components/utilities.rs +++ b/src/components/utilities.rs @@ -571,10 +571,8 @@ impl Component for Pager { { let t = content.insert_tag(text_formatter.tag); for (i, l) in lines.iter().enumerate() { - for _match in text_formatter.regexp.0.find_iter(l.as_bytes()) { - if let Ok(_match) = _match { - content.set_tag(t, (_match.start(), i), (_match.end(), i)); - } + for (start, end) in text_formatter.regexp.find_iter(l) { + content.set_tag(t, (start, i), (end, i)); } } } diff --git a/src/conf/themes.rs b/src/conf/themes.rs index 935e38e6b..5ccf59733 100644 --- a/src/conf/themes.rs +++ b/src/conf/themes.rs @@ -516,6 +516,7 @@ mod regexp { pub(super) fg: Option>, pub(super) bg: Option>, pub(super) attrs: Option>, + pub(super) priority: u8, } #[derive(Debug, Clone)] @@ -572,6 +573,57 @@ mod regexp { .build(pattern)? })) } + + pub fn find_iter<'w, 's>(&'w self, s: &'s str) -> FindIter<'w, 's> { + FindIter { + pcre_iter: self.0.find_iter(s.as_bytes()), + char_indices: s.char_indices(), + char_offset: 0, + } + } + } + + pub struct FindIter<'r, 's> { + pcre_iter: pcre2::bytes::Matches<'r, 's>, + char_indices: std::str::CharIndices<'s>, + char_offset: usize, + } + + impl<'r, 's> Iterator for FindIter<'r, 's> { + type Item = (usize, usize); + + fn next(&mut self) -> Option { + loop { + let next_byte_offset = self.pcre_iter.next(); + if next_byte_offset.is_none() { + return None; + } + let next_byte_offset = next_byte_offset.unwrap(); + if next_byte_offset.is_err() { + continue; + } + let next_byte_offset = next_byte_offset.unwrap(); + + while next_byte_offset.start() < self.char_indices.next().unwrap().0 { + self.char_offset += 1; + } + let start = self.char_offset; + + while next_byte_offset.end() + >= self + .char_indices + .next() + .map(|(v, _)| v) + .unwrap_or(next_byte_offset.end()) + + 1 + { + self.char_offset += 1; + } + let end = self.char_offset + 1; + + return Some((start, end)); + } + } } #[inline(always)] @@ -669,7 +721,7 @@ mod regexp { } ThemeValue::Value(val) => *val, }), - priority: 0, + priority: v.priority, }, }) .collect() @@ -739,6 +791,8 @@ impl<'de> Deserialize<'de> for Themes { ucp: bool, #[serde(default = "false_val")] jit_if_available: bool, + #[serde(default)] + priority: u8, #[serde(flatten)] rest: ThemeAttributeInnerOptions, } @@ -804,6 +858,7 @@ impl<'de> Deserialize<'de> for Themes { fg: v.rest.fg, bg: v.rest.bg, attrs: v.rest.attrs, + priority: v.priority, }); } Err(err) => { @@ -859,6 +914,7 @@ impl<'de> Deserialize<'de> for Themes { fg: v.rest.fg, bg: v.rest.bg, attrs: v.rest.attrs, + priority: v.priority, }); } Err(err) => { @@ -917,6 +973,7 @@ impl<'de> Deserialize<'de> for Themes { fg: v.rest.fg, bg: v.rest.bg, attrs: v.rest.attrs, + priority: v.priority, }); } Err(err) => { diff --git a/src/terminal/cells.rs b/src/terminal/cells.rs index d75f3859f..73ec778b0 100644 --- a/src/terminal/cells.rs +++ b/src/terminal/cells.rs @@ -1717,9 +1717,11 @@ pub fn copy_area(grid_dest: &mut CellBuffer, grid_src: &CellBuffer, dest: Area, .binary_search_by(|probe| probe.0.cmp(&start_idx)) .unwrap_or_else(|i| i); let mut stack: HashSet = HashSet::default(); + let mut sorted_stack: SmallVec<[u64; 64]> = SmallVec::new(); for y in get_y(upper_left!(dest))..=get_y(bottom_right!(dest)) { 'for_x: for x in get_x(upper_left!(dest))..=get_x(bottom_right!(dest)) { let idx = grid_src.pos_to_index(src_x, src_y).unwrap(); + let resort_stack = tag_offset < tag_associations.len() && tag_associations[tag_offset].0 <= idx; while tag_offset < tag_associations.len() && tag_associations[tag_offset].0 <= idx { if tag_associations[tag_offset].2 { stack.insert(tag_associations[tag_offset].1); @@ -1728,8 +1730,13 @@ pub fn copy_area(grid_dest: &mut CellBuffer, grid_src: &CellBuffer, dest: Area, } tag_offset += 1; } + if resort_stack { + sorted_stack.clear(); + sorted_stack.extend(stack.iter().cloned()); + sorted_stack.sort_by_key(|h| grid_src.tag_table()[h].priority); + } grid_dest[(x, y)] = grid_src[(src_x, src_y)]; - for t in &stack { + for t in &sorted_stack { if let Some(fg) = grid_src.tag_table()[&t].fg { grid_dest[(x, y)].set_fg(fg).set_keep_fg(true); }