mirror of
https://github.com/zed-industries/zed.git
synced 2026-05-31 19:05:00 +07:00
Merge 935d4059d1 into 09165c15dc
This commit is contained in:
commit
c557685ebe
3 changed files with 232 additions and 72 deletions
|
|
@ -1,10 +1,12 @@
|
|||
use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
|
||||
use editor::MultiBuffer;
|
||||
use gpui::TestDispatcher;
|
||||
use criterion::{BenchmarkId, Criterion, black_box, criterion_group, criterion_main};
|
||||
use editor::{MultiBuffer, display_map::*};
|
||||
use gpui::{AppContext as _, HighlightStyle, Hsla, TestDispatcher, font, px};
|
||||
use itertools::Itertools;
|
||||
use multi_buffer::MultiBufferOffset;
|
||||
use project::project_settings::DiagnosticSeverity;
|
||||
use rand::{Rng, SeedableRng, rngs::StdRng};
|
||||
use std::num::NonZeroU32;
|
||||
use settings::SettingsStore;
|
||||
use std::{num::NonZeroU32, time::Duration};
|
||||
use text::Bias;
|
||||
use util::RandomCharIter;
|
||||
|
||||
|
|
@ -101,5 +103,112 @@ fn to_fold_point_benchmark(c: &mut Criterion) {
|
|||
group.finish();
|
||||
}
|
||||
|
||||
criterion_group!(benches, to_tab_point_benchmark, to_fold_point_benchmark);
|
||||
fn create_highlight_endpoints_benchmark(c: &mut Criterion) {
|
||||
const LINE_COUNT: usize = 20_000;
|
||||
const LINE_VIEW_PORT_COUNT: usize = 100;
|
||||
const HIGHLIGHTS_PER_LINE: usize = 4;
|
||||
|
||||
let dispatcher = TestDispatcher::new(1);
|
||||
let mut cx = gpui::TestAppContext::build(dispatcher, None);
|
||||
cx.update(|cx| {
|
||||
let store = SettingsStore::test(cx);
|
||||
cx.set_global(store);
|
||||
editor::init(cx);
|
||||
});
|
||||
|
||||
let mut text = String::new();
|
||||
let mut highlight_ranges = Vec::with_capacity(LINE_COUNT * HIGHLIGHTS_PER_LINE);
|
||||
for line in 0..LINE_COUNT {
|
||||
text.push_str("fn item_");
|
||||
text.push_str(&format!("{line:05}"));
|
||||
text.push_str("() { ");
|
||||
|
||||
let start = text.len();
|
||||
text.push_str("alpha_highlight");
|
||||
highlight_ranges.push(MultiBufferOffset(start)..MultiBufferOffset(text.len()));
|
||||
|
||||
text.push_str(" + ");
|
||||
let start = text.len();
|
||||
text.push_str("beta_highlight");
|
||||
highlight_ranges.push(MultiBufferOffset(start)..MultiBufferOffset(text.len()));
|
||||
|
||||
text.push_str(" + ");
|
||||
let start = text.len();
|
||||
text.push_str("gamma_highlight");
|
||||
highlight_ranges.push(MultiBufferOffset(start)..MultiBufferOffset(text.len()));
|
||||
|
||||
text.push_str(" + ");
|
||||
let start = text.len();
|
||||
text.push_str("delta_highlight");
|
||||
highlight_ranges.push(MultiBufferOffset(start)..MultiBufferOffset(text.len()));
|
||||
|
||||
text.push_str("; }\n");
|
||||
}
|
||||
|
||||
let buffer = cx.update(|cx| MultiBuffer::build_simple(&text, cx));
|
||||
let buffer_snapshot = cx.read(|cx| buffer.read(cx).snapshot(cx));
|
||||
let highlight_ranges = highlight_ranges
|
||||
.into_iter()
|
||||
.map(|range| {
|
||||
buffer_snapshot.anchor_before(range.start)..buffer_snapshot.anchor_before(range.end)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let map = cx.new(|cx| {
|
||||
DisplayMap::new(
|
||||
buffer,
|
||||
font("Courier"),
|
||||
px(16.0),
|
||||
None,
|
||||
1,
|
||||
1,
|
||||
FoldPlaceholder::default(),
|
||||
DiagnosticSeverity::Warning,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
cx.update(|cx| {
|
||||
map.update(cx, |map, cx| {
|
||||
map.highlight_text(
|
||||
HighlightKey::Editor,
|
||||
highlight_ranges,
|
||||
HighlightStyle {
|
||||
color: Some(Hsla::blue()),
|
||||
..Default::default()
|
||||
},
|
||||
false,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
});
|
||||
let snapshot = cx.update(|cx| map.update(cx, |map, cx| map.snapshot(cx)));
|
||||
|
||||
let mut group = c.benchmark_group("Create highlight endpoints");
|
||||
group.sample_size(10);
|
||||
group.measurement_time(Duration::from_secs(10));
|
||||
group.bench_with_input(
|
||||
BenchmarkId::new("text_highlights", LINE_VIEW_PORT_COUNT),
|
||||
&snapshot,
|
||||
|bench, snapshot| {
|
||||
bench.iter(|| {
|
||||
black_box(snapshot.chunks(
|
||||
DisplayRow(400)..DisplayRow(400 + LINE_VIEW_PORT_COUNT as u32),
|
||||
language::LanguageAwareStyling {
|
||||
tree_sitter: false,
|
||||
diagnostics: false,
|
||||
},
|
||||
Default::default(),
|
||||
));
|
||||
});
|
||||
},
|
||||
);
|
||||
group.finish();
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
benches,
|
||||
to_tab_point_benchmark,
|
||||
to_fold_point_benchmark,
|
||||
create_highlight_endpoints_benchmark
|
||||
);
|
||||
criterion_main!(benches);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,8 @@
|
|||
use collections::BTreeMap;
|
||||
use gpui::HighlightStyle;
|
||||
use language::{Chunk, LanguageAwareStyling};
|
||||
use multi_buffer::{MultiBufferChunks, MultiBufferOffset, MultiBufferSnapshot, ToOffset as _};
|
||||
use std::{
|
||||
cmp,
|
||||
iter::{self, Peekable},
|
||||
ops::Range,
|
||||
vec,
|
||||
};
|
||||
use multi_buffer::{MultiBufferChunks, MultiBufferOffset, MultiBufferSnapshot};
|
||||
use std::{cmp, ops::Range};
|
||||
|
||||
use crate::display_map::{HighlightKey, SemanticTokensHighlights, TextHighlights};
|
||||
|
||||
|
|
@ -17,7 +12,7 @@ pub struct CustomHighlightsChunks<'a> {
|
|||
offset: MultiBufferOffset,
|
||||
multibuffer_snapshot: &'a MultiBufferSnapshot,
|
||||
|
||||
highlight_endpoints: Peekable<vec::IntoIter<HighlightEndpoint>>,
|
||||
highlight_endpoints: Vec<HighlightEndpoint>,
|
||||
active_highlights: BTreeMap<HighlightKey, HighlightStyle>,
|
||||
text_highlights: Option<&'a TextHighlights>,
|
||||
semantic_token_highlights: Option<&'a SemanticTokensHighlights>,
|
||||
|
|
@ -39,17 +34,20 @@ impl<'a> CustomHighlightsChunks<'a> {
|
|||
semantic_token_highlights: Option<&'a SemanticTokensHighlights>,
|
||||
multibuffer_snapshot: &'a MultiBufferSnapshot,
|
||||
) -> Self {
|
||||
let mut highlight_endpoints = Vec::new();
|
||||
create_highlight_endpoints(
|
||||
&range,
|
||||
text_highlights,
|
||||
semantic_token_highlights,
|
||||
multibuffer_snapshot,
|
||||
&mut highlight_endpoints,
|
||||
);
|
||||
Self {
|
||||
buffer_chunks: multibuffer_snapshot.chunks(range.clone(), language_aware),
|
||||
buffer_chunk: None,
|
||||
offset: range.start,
|
||||
text_highlights,
|
||||
highlight_endpoints: create_highlight_endpoints(
|
||||
&range,
|
||||
text_highlights,
|
||||
semantic_token_highlights,
|
||||
multibuffer_snapshot,
|
||||
),
|
||||
highlight_endpoints,
|
||||
active_highlights: Default::default(),
|
||||
multibuffer_snapshot,
|
||||
semantic_token_highlights,
|
||||
|
|
@ -58,11 +56,12 @@ impl<'a> CustomHighlightsChunks<'a> {
|
|||
|
||||
#[ztracing::instrument(skip_all)]
|
||||
pub fn seek(&mut self, new_range: Range<MultiBufferOffset>) {
|
||||
self.highlight_endpoints = create_highlight_endpoints(
|
||||
create_highlight_endpoints(
|
||||
&new_range,
|
||||
self.text_highlights,
|
||||
self.semantic_token_highlights,
|
||||
self.multibuffer_snapshot,
|
||||
&mut self.highlight_endpoints,
|
||||
);
|
||||
self.offset = new_range.start;
|
||||
self.buffer_chunks.seek(new_range);
|
||||
|
|
@ -76,11 +75,14 @@ fn create_highlight_endpoints(
|
|||
text_highlights: Option<&TextHighlights>,
|
||||
semantic_token_highlights: Option<&SemanticTokensHighlights>,
|
||||
buffer: &MultiBufferSnapshot,
|
||||
) -> iter::Peekable<vec::IntoIter<HighlightEndpoint>> {
|
||||
let mut highlight_endpoints = Vec::new();
|
||||
highlight_endpoints: &mut Vec<HighlightEndpoint>,
|
||||
) {
|
||||
highlight_endpoints.clear();
|
||||
if let Some(text_highlights) = text_highlights {
|
||||
let start = buffer.anchor_after(range.start);
|
||||
let end = buffer.anchor_after(range.end);
|
||||
let mut text_highlights_scratch = Vec::new();
|
||||
|
||||
for (&tag, text_highlights) in text_highlights.iter() {
|
||||
let style = text_highlights.0;
|
||||
let ranges = &text_highlights.1;
|
||||
|
|
@ -94,13 +96,26 @@ fn create_highlight_endpoints(
|
|||
})
|
||||
.unwrap_or_else(|i| i);
|
||||
|
||||
highlight_endpoints.reserve(2 * end_ix);
|
||||
let ranges_ = &ranges[start_ix..][..end_ix];
|
||||
text_highlights_scratch.clear();
|
||||
text_highlights_scratch.reserve(ranges_.len());
|
||||
highlight_endpoints.reserve(2 * ranges_.len());
|
||||
|
||||
for range in &ranges[start_ix..][..end_ix] {
|
||||
let start = range.start.to_offset(buffer);
|
||||
let end = range.end.to_offset(buffer);
|
||||
let mut iter = ranges_.iter();
|
||||
buffer.summaries_for_anchors_cb(
|
||||
ranges_.iter().map(|r| &r.start),
|
||||
|start: MultiBufferOffset| {
|
||||
text_highlights_scratch.push((start, iter.next().unwrap().end));
|
||||
},
|
||||
);
|
||||
text_highlights_scratch.sort_by(|a, b| a.1.cmp(&b.1, buffer));
|
||||
let mut iter = text_highlights_scratch.iter();
|
||||
buffer.summaries_for_anchors_cb(
|
||||
text_highlights_scratch.iter().map(|(_, end)| end),
|
||||
|end: MultiBufferOffset| {
|
||||
let start = iter.next().unwrap().0;
|
||||
if start == end {
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
highlight_endpoints.push(HighlightEndpoint {
|
||||
offset: start,
|
||||
|
|
@ -112,12 +127,14 @@ fn create_highlight_endpoints(
|
|||
tag,
|
||||
style: None,
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
if let Some(semantic_token_highlights) = semantic_token_highlights {
|
||||
let start = buffer.anchor_after(range.start);
|
||||
let end = buffer.anchor_after(range.end);
|
||||
let mut semantic_highlights_scratch = Vec::new();
|
||||
for buffer_id in buffer.buffer_ids_for_range(range.clone()) {
|
||||
let Some((semantic_token_highlights, interner)) =
|
||||
semantic_token_highlights.get(&buffer_id)
|
||||
|
|
@ -133,18 +150,41 @@ fn create_highlight_endpoints(
|
|||
.then(cmp::Ordering::Less)
|
||||
})
|
||||
.unwrap_or_else(|i| i);
|
||||
for token in &semantic_token_highlights[start_ix..] {
|
||||
if token.range.start.cmp(&end, buffer).is_ge() {
|
||||
break;
|
||||
}
|
||||
let end_ix = semantic_token_highlights[start_ix..]
|
||||
.binary_search_by(|probe| {
|
||||
probe
|
||||
.range
|
||||
.start
|
||||
.cmp(&end, buffer)
|
||||
.then(cmp::Ordering::Greater)
|
||||
})
|
||||
.unwrap_or_else(|i| i);
|
||||
|
||||
let start = token.range.start.to_offset(buffer);
|
||||
let end = token.range.end.to_offset(buffer);
|
||||
if start == end {
|
||||
continue;
|
||||
let ranges_ = &semantic_token_highlights[start_ix..][..end_ix];
|
||||
semantic_highlights_scratch.clear();
|
||||
semantic_highlights_scratch.reserve(ranges_.len());
|
||||
highlight_endpoints.reserve(2 * ranges_.len());
|
||||
|
||||
let mut iter = ranges_.iter();
|
||||
buffer.summaries_for_anchors_cb(
|
||||
ranges_.iter().map(|token| &token.range.start),
|
||||
|start: MultiBufferOffset| {
|
||||
semantic_highlights_scratch.push((start, iter.next().unwrap()));
|
||||
},
|
||||
);
|
||||
semantic_highlights_scratch.sort_by(|a, b| a.1.range.end.cmp(&b.1.range.end, buffer));
|
||||
let mut iter = semantic_highlights_scratch.iter();
|
||||
buffer.summaries_for_anchors_cb(
|
||||
semantic_highlights_scratch
|
||||
.iter()
|
||||
.map(|(_, token)| &token.range.end),
|
||||
|end: MultiBufferOffset| {
|
||||
let (start, token) = iter.next().unwrap();
|
||||
if *start == end {
|
||||
return;
|
||||
}
|
||||
highlight_endpoints.push(HighlightEndpoint {
|
||||
offset: start,
|
||||
offset: *start,
|
||||
tag: HighlightKey::SemanticToken,
|
||||
style: Some(interner[token.style]),
|
||||
});
|
||||
|
|
@ -153,11 +193,11 @@ fn create_highlight_endpoints(
|
|||
tag: HighlightKey::SemanticToken,
|
||||
style: None,
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
highlight_endpoints.sort();
|
||||
highlight_endpoints.into_iter().peekable()
|
||||
highlight_endpoints.sort_by(|a, b| a.cmp(b).reverse());
|
||||
}
|
||||
|
||||
impl<'a> Iterator for CustomHighlightsChunks<'a> {
|
||||
|
|
@ -166,14 +206,14 @@ impl<'a> Iterator for CustomHighlightsChunks<'a> {
|
|||
#[ztracing::instrument(skip_all)]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut next_highlight_endpoint = MultiBufferOffset(usize::MAX);
|
||||
while let Some(endpoint) = self.highlight_endpoints.peek().copied() {
|
||||
while let Some(endpoint) = self.highlight_endpoints.last().copied() {
|
||||
if endpoint.offset <= self.offset {
|
||||
if let Some(style) = endpoint.style {
|
||||
self.active_highlights.insert(endpoint.tag, style);
|
||||
} else {
|
||||
self.active_highlights.remove(&endpoint.tag);
|
||||
}
|
||||
self.highlight_endpoints.next();
|
||||
self.highlight_endpoints.pop();
|
||||
} else {
|
||||
next_highlight_endpoint = endpoint.offset;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -5003,6 +5003,20 @@ impl MultiBufferSnapshot {
|
|||
}
|
||||
|
||||
pub fn summaries_for_anchors<'a, MBD, I>(&'a self, anchors: I) -> Vec<MBD>
|
||||
where
|
||||
MBD: MultiBufferDimension
|
||||
+ Ord
|
||||
+ Sub<Output = MBD::TextDimension>
|
||||
+ AddAssign<MBD::TextDimension>,
|
||||
MBD::TextDimension: Sub<Output = MBD::TextDimension> + Ord,
|
||||
I: 'a + IntoIterator<Item = &'a Anchor>,
|
||||
{
|
||||
let mut summaries = Vec::new();
|
||||
self.summaries_for_anchors_cb(anchors, |summary| summaries.push(summary));
|
||||
summaries
|
||||
}
|
||||
|
||||
pub fn summaries_for_anchors_cb<'a, MBD, I>(&'a self, anchors: I, mut cb: impl FnMut(MBD))
|
||||
where
|
||||
MBD: MultiBufferDimension
|
||||
+ Ord
|
||||
|
|
@ -5018,18 +5032,17 @@ impl MultiBufferSnapshot {
|
|||
.cursor::<Dimensions<ExcerptDimension<MBD>, OutputDimension<MBD>>>(());
|
||||
diff_transforms_cursor.next();
|
||||
|
||||
let mut summaries = Vec::new();
|
||||
while let Some(anchor) = anchors.peek() {
|
||||
let target = anchor.seek_target(self);
|
||||
let excerpt_anchor = match anchor {
|
||||
Anchor::Min => {
|
||||
summaries.push(MBD::default());
|
||||
cb(MBD::default());
|
||||
anchors.next();
|
||||
continue;
|
||||
}
|
||||
Anchor::Excerpt(excerpt_anchor) => excerpt_anchor,
|
||||
Anchor::Max => {
|
||||
summaries.push(MBD::from_summary(&self.text_summary()));
|
||||
cb(MBD::from_summary(&self.text_summary()));
|
||||
anchors.next();
|
||||
continue;
|
||||
}
|
||||
|
|
@ -5047,7 +5060,7 @@ impl MultiBufferSnapshot {
|
|||
excerpt_start_position,
|
||||
&mut diff_transforms_cursor,
|
||||
);
|
||||
summaries.push(position);
|
||||
cb(position);
|
||||
anchors.next();
|
||||
continue;
|
||||
}
|
||||
|
|
@ -5083,7 +5096,7 @@ impl MultiBufferSnapshot {
|
|||
diff_transforms_cursor.seek_forward(&position, Bias::Left);
|
||||
}
|
||||
|
||||
summaries.push(self.summary_for_anchor_with_excerpt_position(
|
||||
cb(self.summary_for_anchor_with_excerpt_position(
|
||||
excerpt_anchor,
|
||||
position,
|
||||
&mut diff_transforms_cursor,
|
||||
|
|
@ -5097,12 +5110,10 @@ impl MultiBufferSnapshot {
|
|||
excerpt_start_position,
|
||||
&mut diff_transforms_cursor,
|
||||
);
|
||||
summaries.push(position);
|
||||
cb(position);
|
||||
anchors.next();
|
||||
}
|
||||
}
|
||||
|
||||
summaries
|
||||
}
|
||||
|
||||
pub fn dimensions_from_points<'a, MBD>(
|
||||
|
|
|
|||
Loading…
Reference in a new issue