mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-06 03:00:50 +03:00
Extract a gpui::combine_highlights
function
This commit is contained in:
parent
e5b6b0ee9e
commit
d31b53b912
@ -1276,11 +1276,16 @@ impl CompletionsMenu {
|
||||
&None
|
||||
};
|
||||
|
||||
let highlights = combine_syntax_and_fuzzy_match_highlights(
|
||||
&completion.label.text,
|
||||
&style.text,
|
||||
styled_runs_for_code_label(&completion.label, &style.syntax),
|
||||
&mat.positions,
|
||||
let highlights = gpui::combine_highlights(
|
||||
mat.ranges().map(|range| (range, FontWeight::BOLD.into())),
|
||||
styled_runs_for_code_label(&completion.label, &style.syntax).map(
|
||||
|(range, mut highlight)| {
|
||||
// Ignore font weight for syntax highlighting, as we'll use it
|
||||
// for fuzzy matches.
|
||||
highlight.font_weight = None;
|
||||
(range, highlight)
|
||||
},
|
||||
),
|
||||
);
|
||||
let completion_label = StyledText::new(completion.label.text.clone())
|
||||
.with_runs(text_runs_for_highlights(
|
||||
@ -10056,75 +10061,6 @@ pub fn text_runs_for_highlights(
|
||||
runs
|
||||
}
|
||||
|
||||
pub fn combine_syntax_and_fuzzy_match_highlights(
|
||||
text: &str,
|
||||
default_style: &TextStyle,
|
||||
syntax_ranges: impl Iterator<Item = (Range<usize>, HighlightStyle)>,
|
||||
match_indices: &[usize],
|
||||
) -> Vec<(Range<usize>, HighlightStyle)> {
|
||||
let mut highlights = Vec::new();
|
||||
let mut match_indices = match_indices.iter().copied().peekable();
|
||||
|
||||
for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())])
|
||||
{
|
||||
syntax_highlight.font_weight = None;
|
||||
|
||||
// Add highlights for any fuzzy match characters before the next
|
||||
// syntax highlight range.
|
||||
while let Some(&match_index) = match_indices.peek() {
|
||||
if match_index >= range.start {
|
||||
break;
|
||||
}
|
||||
match_indices.next();
|
||||
let end_index = char_ix_after(match_index, text);
|
||||
highlights.push((match_index..end_index, FontWeight::BOLD.into()));
|
||||
}
|
||||
|
||||
if range.start == usize::MAX {
|
||||
break;
|
||||
}
|
||||
|
||||
// Add highlights for any fuzzy match characters within the
|
||||
// syntax highlight range.
|
||||
let mut offset = range.start;
|
||||
while let Some(&match_index) = match_indices.peek() {
|
||||
if match_index >= range.end {
|
||||
break;
|
||||
}
|
||||
|
||||
match_indices.next();
|
||||
if match_index > offset {
|
||||
highlights.push((offset..match_index, syntax_highlight));
|
||||
}
|
||||
|
||||
let mut end_index = char_ix_after(match_index, text);
|
||||
while let Some(&next_match_index) = match_indices.peek() {
|
||||
if next_match_index == end_index && next_match_index < range.end {
|
||||
end_index = char_ix_after(next_match_index, text);
|
||||
match_indices.next();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let mut match_style = syntax_highlight;
|
||||
match_style.font_weight = Some(FontWeight::BOLD);
|
||||
highlights.push((match_index..end_index, match_style));
|
||||
offset = end_index;
|
||||
}
|
||||
|
||||
if offset < range.end {
|
||||
highlights.push((offset..range.end, syntax_highlight));
|
||||
}
|
||||
}
|
||||
|
||||
fn char_ix_after(ix: usize, text: &str) -> usize {
|
||||
ix + text[ix..].chars().next().unwrap().len_utf8()
|
||||
}
|
||||
|
||||
highlights
|
||||
}
|
||||
|
||||
pub fn styled_runs_for_code_label<'a>(
|
||||
label: &'a CodeLabel,
|
||||
syntax_theme: &'a theme::SyntaxTheme,
|
||||
|
@ -6740,75 +6740,6 @@ async fn test_extra_newline_insertion(cx: &mut gpui::TestAppContext) {
|
||||
// );
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn test_combine_syntax_and_fuzzy_match_highlights() {
|
||||
let string = "abcdefghijklmnop";
|
||||
let syntax_ranges = [
|
||||
(
|
||||
0..3,
|
||||
HighlightStyle {
|
||||
color: Some(Hsla::red()),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
(
|
||||
4..8,
|
||||
HighlightStyle {
|
||||
color: Some(Hsla::green()),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
];
|
||||
let match_indices = [4, 6, 7, 8];
|
||||
assert_eq!(
|
||||
combine_syntax_and_fuzzy_match_highlights(
|
||||
string,
|
||||
&TextStyle::default(),
|
||||
syntax_ranges.into_iter(),
|
||||
&match_indices,
|
||||
),
|
||||
&[
|
||||
(
|
||||
0..3,
|
||||
HighlightStyle {
|
||||
color: Some(Hsla::red()),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
(
|
||||
4..5,
|
||||
HighlightStyle {
|
||||
color: Some(Hsla::green()),
|
||||
font_weight: Some(gpui::FontWeight::BOLD),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
(
|
||||
5..6,
|
||||
HighlightStyle {
|
||||
color: Some(Hsla::green()),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
(
|
||||
6..8,
|
||||
HighlightStyle {
|
||||
color: Some(Hsla::green()),
|
||||
font_weight: Some(gpui::FontWeight::BOLD),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
(
|
||||
8..9,
|
||||
HighlightStyle {
|
||||
font_weight: Some(gpui::FontWeight::BOLD),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn go_to_prev_overlapping_diagnostic(
|
||||
executor: BackgroundExecutor,
|
||||
|
@ -6,6 +6,8 @@ use gpui::BackgroundExecutor;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
cmp::{self, Ordering},
|
||||
iter,
|
||||
ops::Range,
|
||||
sync::atomic::AtomicBool,
|
||||
};
|
||||
|
||||
@ -54,6 +56,30 @@ pub struct StringMatch {
|
||||
pub string: String,
|
||||
}
|
||||
|
||||
impl StringMatch {
|
||||
pub fn ranges<'a>(&'a self) -> impl 'a + Iterator<Item = Range<usize>> {
|
||||
let mut positions = self.positions.iter().peekable();
|
||||
iter::from_fn(move || {
|
||||
while let Some(start) = positions.next().copied() {
|
||||
let mut end = start + self.char_len_at_index(start);
|
||||
while let Some(next_start) = positions.peek() {
|
||||
if end == **next_start {
|
||||
end += self.char_len_at_index(end);
|
||||
positions.next();
|
||||
}
|
||||
}
|
||||
|
||||
return Some(start..end);
|
||||
}
|
||||
None
|
||||
})
|
||||
}
|
||||
|
||||
fn char_len_at_index(&self, ix: usize) -> usize {
|
||||
self.string[ix..].chars().next().unwrap().len_utf8()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for StringMatch {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.cmp(other).is_eq()
|
||||
|
@ -1,9 +1,12 @@
|
||||
use std::{iter, mem, ops::Range};
|
||||
|
||||
use crate::{
|
||||
black, phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask,
|
||||
Corners, CornersRefinement, CursorStyle, DefiniteLength, Edges, EdgesRefinement, Font,
|
||||
FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rgba,
|
||||
SharedString, Size, SizeRefinement, Styled, TextRun, WindowContext,
|
||||
};
|
||||
use collections::HashSet;
|
||||
use refineable::{Cascade, Refineable};
|
||||
use smallvec::SmallVec;
|
||||
pub use taffy::style::{
|
||||
@ -512,6 +515,15 @@ impl From<FontWeight> for HighlightStyle {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FontStyle> for HighlightStyle {
|
||||
fn from(font_style: FontStyle) -> Self {
|
||||
Self {
|
||||
font_style: Some(font_style),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Rgba> for HighlightStyle {
|
||||
fn from(color: Rgba) -> Self {
|
||||
Self {
|
||||
@ -520,3 +532,140 @@ impl From<Rgba> for HighlightStyle {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn combine_highlights(
|
||||
a: impl IntoIterator<Item = (Range<usize>, HighlightStyle)>,
|
||||
b: impl IntoIterator<Item = (Range<usize>, HighlightStyle)>,
|
||||
) -> impl Iterator<Item = (Range<usize>, HighlightStyle)> {
|
||||
let mut endpoints = Vec::new();
|
||||
let mut highlights = Vec::new();
|
||||
for (range, highlight) in a.into_iter().chain(b) {
|
||||
if !range.is_empty() {
|
||||
let highlight_id = highlights.len();
|
||||
endpoints.push((range.start, highlight_id, true));
|
||||
endpoints.push((range.end, highlight_id, false));
|
||||
highlights.push(highlight);
|
||||
}
|
||||
}
|
||||
endpoints.sort_unstable_by_key(|(position, _, _)| *position);
|
||||
let mut endpoints = endpoints.into_iter().peekable();
|
||||
|
||||
let mut active_styles = HashSet::default();
|
||||
let mut ix = 0;
|
||||
iter::from_fn(move || {
|
||||
while let Some((endpoint_ix, highlight_id, is_start)) = endpoints.peek() {
|
||||
let prev_index = mem::replace(&mut ix, *endpoint_ix);
|
||||
if ix > prev_index && !active_styles.is_empty() {
|
||||
let mut current_style = HighlightStyle::default();
|
||||
for highlight_id in &active_styles {
|
||||
current_style.highlight(highlights[*highlight_id]);
|
||||
}
|
||||
return Some((prev_index..ix, current_style));
|
||||
}
|
||||
|
||||
if *is_start {
|
||||
active_styles.insert(*highlight_id);
|
||||
} else {
|
||||
active_styles.remove(highlight_id);
|
||||
}
|
||||
endpoints.next();
|
||||
}
|
||||
None
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{blue, green, red, yellow};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_combine_highlights() {
|
||||
assert_eq!(
|
||||
combine_highlights(
|
||||
[
|
||||
(0..5, green().into()),
|
||||
(4..10, FontWeight::BOLD.into()),
|
||||
(15..20, yellow().into()),
|
||||
],
|
||||
[
|
||||
(2..6, FontStyle::Italic.into()),
|
||||
(1..3, blue().into()),
|
||||
(21..23, red().into()),
|
||||
]
|
||||
)
|
||||
.collect::<Vec<_>>(),
|
||||
[
|
||||
(
|
||||
0..1,
|
||||
HighlightStyle {
|
||||
color: Some(green()),
|
||||
..Default::default()
|
||||
}
|
||||
),
|
||||
(
|
||||
1..2,
|
||||
HighlightStyle {
|
||||
color: Some(blue()),
|
||||
..Default::default()
|
||||
}
|
||||
),
|
||||
(
|
||||
2..3,
|
||||
HighlightStyle {
|
||||
color: Some(blue()),
|
||||
font_style: Some(FontStyle::Italic),
|
||||
..Default::default()
|
||||
}
|
||||
),
|
||||
(
|
||||
3..4,
|
||||
HighlightStyle {
|
||||
color: Some(green()),
|
||||
font_style: Some(FontStyle::Italic),
|
||||
..Default::default()
|
||||
}
|
||||
),
|
||||
(
|
||||
4..5,
|
||||
HighlightStyle {
|
||||
color: Some(green()),
|
||||
font_weight: Some(FontWeight::BOLD),
|
||||
font_style: Some(FontStyle::Italic),
|
||||
..Default::default()
|
||||
}
|
||||
),
|
||||
(
|
||||
5..6,
|
||||
HighlightStyle {
|
||||
font_weight: Some(FontWeight::BOLD),
|
||||
font_style: Some(FontStyle::Italic),
|
||||
..Default::default()
|
||||
}
|
||||
),
|
||||
(
|
||||
6..10,
|
||||
HighlightStyle {
|
||||
font_weight: Some(FontWeight::BOLD),
|
||||
..Default::default()
|
||||
}
|
||||
),
|
||||
(
|
||||
15..20,
|
||||
HighlightStyle {
|
||||
color: Some(yellow()),
|
||||
..Default::default()
|
||||
}
|
||||
),
|
||||
(
|
||||
21..23,
|
||||
HighlightStyle {
|
||||
color: Some(red()),
|
||||
..Default::default()
|
||||
}
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user