mirror of
https://github.com/zed-industries/zed.git
synced 2026-10-19 11:04:06 +00:00
Highlight strings without building ropes
This commit is contained in:
parent
d5be3d8bec
commit
eb70b3fe85
14 changed files with 148 additions and 97 deletions
|
|
@ -33,7 +33,7 @@ use gpui::{
|
|||
TextStyle, WeakEntity, Window, WindowHandle, div, ease_in_out, img, linear_color_stop,
|
||||
linear_gradient, list, pulsating_between,
|
||||
};
|
||||
use language::{Buffer, Language, Rope};
|
||||
use language::{Buffer, Language};
|
||||
use language_model::{
|
||||
LanguageModelCompletionError, ProviderErrorCategory, ZED_CLOUD_PROVIDER_NAME,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -454,7 +454,7 @@ fn highlight_code_runs(
|
|||
|
||||
let mut runs = Vec::new();
|
||||
let mut offset = 0;
|
||||
let highlights = language.highlight_text_resolved(&Rope::from(code), 0..code.len());
|
||||
let highlights = language.highlight_text_resolved(code, 0..code.len());
|
||||
for (range, highlight_id) in highlights.runs.iter() {
|
||||
if range.start > offset {
|
||||
runs.push(code_text_style.to_run(range.start - offset));
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ impl RenderedPreview {
|
|||
let highlights = match (preview, language) {
|
||||
(InlineInputPreview::Text(_), Some(language)) => {
|
||||
language
|
||||
.highlight_text_resolved(&Rope::from(text.as_str()), 0..text.len())
|
||||
.highlight_text_resolved(text.as_str(), 0..text.len())
|
||||
.runs
|
||||
}
|
||||
_ => Arc::default(),
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use multi_buffer::{Anchor, MultiBufferOffset, ToOffset};
|
|||
use settings::Settings;
|
||||
use std::ops::Range;
|
||||
use std::time::Duration;
|
||||
use text::Rope;
|
||||
|
||||
use theme_settings::ThemeSettings;
|
||||
use ui::{
|
||||
ActiveTheme, AnyElement, ButtonCommon, ButtonStyle, Clickable, FluentBuilder, IconButton,
|
||||
|
|
@ -232,9 +232,10 @@ impl Editor {
|
|||
|
||||
if let Some(language) = language {
|
||||
for signature in &mut signature_help.signatures {
|
||||
let text = Rope::from(signature.label.as_ref());
|
||||
let resolved = language
|
||||
.highlight_text_resolved(&text, 0..signature.label.len());
|
||||
let resolved = language.highlight_text_resolved(
|
||||
signature.label.as_str(),
|
||||
0..signature.label.len(),
|
||||
);
|
||||
let highlights =
|
||||
resolved.runs.iter().flat_map(|(range, highlight_id)| {
|
||||
Some((
|
||||
|
|
|
|||
|
|
@ -2427,7 +2427,7 @@ impl RenderOnce for SyntaxHighlightedText {
|
|||
|
||||
let highlights = self
|
||||
.language
|
||||
.highlight_text_resolved(&text.as_ref().into(), 0..text.len());
|
||||
.highlight_text_resolved(text.as_str(), 0..text.len());
|
||||
let mut runs = Vec::with_capacity(highlights.runs.len());
|
||||
let mut offset = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ pub use language_core::{
|
|||
|
||||
use futures::future::FutureExt as _;
|
||||
use language_core::highlight_cache::{MAX_TEXT_HIGHLIGHT_ENTRY_BYTES, TextHighlightKey};
|
||||
use language_core::highlight_map::HighlightCaptureRef;
|
||||
pub use language_core::{
|
||||
BlockCommentConfig, BracketPair, BracketPairConfig, BracketPairContent, BracketsConfig,
|
||||
BracketsPatternConfig, CodeLabel, CodeLabelBuilder, DebugVariablesConfig, DebuggerTextObject,
|
||||
|
|
@ -78,13 +79,14 @@ use std::{
|
|||
ffi::OsStr,
|
||||
fmt::Debug,
|
||||
hash::Hash,
|
||||
mem,
|
||||
iter, mem,
|
||||
ops::{DerefMut, Range},
|
||||
path::{Path, PathBuf},
|
||||
str,
|
||||
sync::{Arc, LazyLock},
|
||||
};
|
||||
use syntax_map::{QueryCursorHandle, SyntaxSnapshot, flattened_highlight_regions};
|
||||
use streaming_iterator::StreamingIterator as _;
|
||||
use syntax_map::{QueryCursorHandle, TextProvider, flatten_capture_regions};
|
||||
use task::RunnableTag;
|
||||
pub use task_context::{ContextLocation, ContextProvider};
|
||||
pub use text_diff::{
|
||||
|
|
@ -1130,18 +1132,18 @@ impl Language {
|
|||
self.toolchain.clone()
|
||||
}
|
||||
|
||||
pub fn highlight_text<'a>(
|
||||
self: &'a Arc<Self>,
|
||||
text: &'a Rope,
|
||||
pub fn highlight_text(
|
||||
self: &Arc<Self>,
|
||||
text: &(impl HighlightSource + ?Sized),
|
||||
range: Range<usize>,
|
||||
) -> Vec<(Range<usize>, HighlightId)> {
|
||||
let highlights = self.highlight_text_resolved(text, 0..text.len());
|
||||
let highlights = self.highlight_text_resolved(text, 0..text.source_len());
|
||||
highlight_runs_in_range(&highlights.runs, range).collect()
|
||||
}
|
||||
|
||||
pub fn highlight_text_resolved(
|
||||
self: &Arc<Self>,
|
||||
text: &Rope,
|
||||
text: &(impl HighlightSource + ?Sized),
|
||||
range: Range<usize>,
|
||||
) -> ResolvedHighlights {
|
||||
let Some(grammar) = &self.grammar else {
|
||||
|
|
@ -1150,27 +1152,28 @@ impl Language {
|
|||
let Some(highlights_config) = &grammar.highlights_config else {
|
||||
return ResolvedHighlights::default();
|
||||
};
|
||||
let highlights = if text.len() > MAX_TEXT_HIGHLIGHT_ENTRY_BYTES {
|
||||
self.compute_resolved_highlights(grammar, text)
|
||||
let text_len = text.source_len();
|
||||
let highlights = if text_len > MAX_TEXT_HIGHLIGHT_ENTRY_BYTES {
|
||||
Self::compute_resolved_highlights(grammar, &highlights_config.query, text)
|
||||
} else {
|
||||
let key = TextHighlightKey::new(text.chunks(), text.len());
|
||||
let key = TextHighlightKey::new(text.source_chunks(), text_len);
|
||||
match highlights_config
|
||||
.text_highlight_cache
|
||||
.get(&key, text.chunks())
|
||||
.get(&key, text.source_chunks())
|
||||
{
|
||||
Some(highlights) => highlights,
|
||||
None => {
|
||||
let mut cached_text = String::with_capacity(text.len());
|
||||
cached_text.extend(text.chunks());
|
||||
let mut cached_text = String::with_capacity(text_len);
|
||||
cached_text.extend(text.source_chunks());
|
||||
highlights_config.text_highlight_cache.insert(
|
||||
key,
|
||||
cached_text,
|
||||
self.compute_resolved_highlights(grammar, text),
|
||||
Self::compute_resolved_highlights(grammar, &highlights_config.query, text),
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
if range.start == 0 && range.end >= text.len() {
|
||||
if range.start == 0 && range.end >= text_len {
|
||||
return highlights;
|
||||
}
|
||||
ResolvedHighlights {
|
||||
|
|
@ -1180,21 +1183,31 @@ impl Language {
|
|||
}
|
||||
|
||||
fn compute_resolved_highlights(
|
||||
self: &Arc<Self>,
|
||||
grammar: &Arc<Grammar>,
|
||||
text: &Rope,
|
||||
query: &tree_sitter::Query,
|
||||
text: &(impl HighlightSource + ?Sized),
|
||||
) -> ResolvedHighlights {
|
||||
let highlight_map = grammar.highlight_map();
|
||||
let tree = parse_text(grammar, text, None);
|
||||
let captures =
|
||||
SyntaxSnapshot::single_tree_captures(0..text.len(), text, &tree, self, |grammar| {
|
||||
grammar
|
||||
.highlights_config
|
||||
.as_ref()
|
||||
.map(|config| &config.query)
|
||||
let text_len = text.source_len();
|
||||
let tree = text.parse(grammar);
|
||||
let regions = with_query_cursor(|cursor| {
|
||||
cursor.set_byte_range(0..text_len);
|
||||
let mut captures = cursor.captures(query, tree.root_node(), text.text_provider());
|
||||
let capture_refs = iter::from_fn(move || {
|
||||
let (query_match, capture_index) = captures.next()?;
|
||||
let capture = query_match.captures[*capture_index];
|
||||
Some((
|
||||
capture.node.byte_range(),
|
||||
HighlightCaptureRef {
|
||||
grammar_index: 0,
|
||||
capture_id: CaptureId(capture.index),
|
||||
},
|
||||
))
|
||||
});
|
||||
flatten_capture_regions(0..text_len, capture_refs)
|
||||
});
|
||||
let mut runs = Vec::<(Range<usize>, HighlightId)>::new();
|
||||
for region in flattened_highlight_regions(captures, 0..text.len()) {
|
||||
for region in regions {
|
||||
let highlight_id = region
|
||||
.stack
|
||||
.iter()
|
||||
|
|
@ -1454,6 +1467,54 @@ impl Debug for Language {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait HighlightSource {
|
||||
fn source_len(&self) -> usize;
|
||||
fn source_chunks(&self) -> impl Iterator<Item = &str>;
|
||||
fn parse(&self, grammar: &Grammar) -> Tree;
|
||||
fn text_provider<'a>(&'a self) -> impl tree_sitter::TextProvider<&'a [u8]> + 'a;
|
||||
}
|
||||
|
||||
impl HighlightSource for str {
|
||||
fn source_len(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
||||
fn source_chunks(&self) -> impl Iterator<Item = &str> {
|
||||
iter::once(self)
|
||||
}
|
||||
|
||||
fn parse(&self, grammar: &Grammar) -> Tree {
|
||||
with_parser(|parser| {
|
||||
parser
|
||||
.set_language(&grammar.ts_language)
|
||||
.expect("incompatible grammar");
|
||||
parser.parse(self, None).unwrap()
|
||||
})
|
||||
}
|
||||
|
||||
fn text_provider<'a>(&'a self) -> impl tree_sitter::TextProvider<&'a [u8]> + 'a {
|
||||
self.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl HighlightSource for Rope {
|
||||
fn source_len(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
||||
fn source_chunks(&self) -> impl Iterator<Item = &str> {
|
||||
self.chunks()
|
||||
}
|
||||
|
||||
fn parse(&self, grammar: &Grammar) -> Tree {
|
||||
parse_text(grammar, self, None)
|
||||
}
|
||||
|
||||
fn text_provider<'a>(&'a self) -> impl tree_sitter::TextProvider<&'a [u8]> + 'a {
|
||||
TextProvider(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parse_text(grammar: &Grammar, text: &Rope, old_tree: Option<Tree>) -> Tree {
|
||||
with_parser(|parser| {
|
||||
parser
|
||||
|
|
@ -1847,6 +1908,11 @@ mod tests {
|
|||
Arc::ptr_eq(&highlights.runs, &memoized.runs),
|
||||
"repeated highlighting of the same text must be memoized"
|
||||
);
|
||||
let memoized_str = language.highlight_text_resolved(code, 0..code.len());
|
||||
assert!(
|
||||
Arc::ptr_eq(&highlights.runs, &memoized_str.runs),
|
||||
"str and rope sources of the same text must share memoized highlights"
|
||||
);
|
||||
let partial = language.highlight_text_resolved(&Rope::from(code), 0..2);
|
||||
assert!(
|
||||
!Arc::ptr_eq(&highlights.runs, &partial.runs),
|
||||
|
|
@ -1925,6 +1991,14 @@ mod tests {
|
|||
small_highlights.runs.as_ref(),
|
||||
"texts over the cache entry cap must still be highlighted"
|
||||
);
|
||||
assert_eq!(
|
||||
language
|
||||
.highlight_text_resolved(oversized_code.as_str(), 0..oversized_code.len())
|
||||
.runs
|
||||
.as_ref(),
|
||||
first_highlights.runs.as_ref(),
|
||||
"str and rope sources must be highlighted identically"
|
||||
);
|
||||
let second_highlights =
|
||||
language.highlight_text_resolved(&oversized_rope, 0..oversized_code.len());
|
||||
assert_eq!(
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::{BufferSnapshot, Language, Point, ToPoint, ToTreeSitterPoint};
|
|||
use fuzzy_nucleo::{Case, LengthPenalty, StringMatch, StringMatchCandidate};
|
||||
use gpui::{BackgroundExecutor, HighlightStyle, SharedString};
|
||||
use std::{ops::Range, sync::Arc};
|
||||
use text::Rope;
|
||||
|
||||
use theme::SyntaxTheme;
|
||||
|
||||
/// An outline of all the symbols contained in a buffer.
|
||||
|
|
@ -269,8 +269,7 @@ pub fn highlight_ranges_from_text(
|
|||
language: &Arc<Language>,
|
||||
syntax_theme: &SyntaxTheme,
|
||||
) -> Vec<(Range<usize>, HighlightStyle)> {
|
||||
let rope = Rope::from(text);
|
||||
let highlights = language.highlight_text_resolved(&rope, 0..text.len());
|
||||
let highlights = language.highlight_text_resolved(text, 0..text.len());
|
||||
syntax_theme.resolve_runs(highlights.runs.iter()).collect()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ pub(crate) fn flattened_highlight_regions(
|
|||
flatten_capture_regions(range, capture_refs)
|
||||
}
|
||||
|
||||
fn flatten_capture_regions(
|
||||
pub(crate) fn flatten_capture_regions(
|
||||
range: Range<usize>,
|
||||
mut captures: impl Iterator<Item = (Range<usize>, HighlightCaptureRef)>,
|
||||
) -> Vec<HighlightCaptureRegion> {
|
||||
|
|
@ -347,7 +347,7 @@ struct ChangedRegion {
|
|||
#[derive(Default)]
|
||||
struct ChangeRegionSet(Vec<ChangedRegion>);
|
||||
|
||||
struct TextProvider<'a>(&'a Rope);
|
||||
pub(crate) struct TextProvider<'a>(pub(crate) &'a Rope);
|
||||
|
||||
pub(crate) struct QueryCursorHandle(Option<QueryCursor>);
|
||||
|
||||
|
|
@ -1044,28 +1044,6 @@ impl SyntaxSnapshot {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn single_tree_captures<'a>(
|
||||
range: Range<usize>,
|
||||
text: &'a Rope,
|
||||
tree: &'a tree_sitter::Tree,
|
||||
language: &'a Arc<Language>,
|
||||
query: fn(&Grammar) -> Option<&Query>,
|
||||
) -> SyntaxMapCaptures<'a> {
|
||||
SyntaxMapCaptures::new(
|
||||
range,
|
||||
text,
|
||||
[SyntaxLayer {
|
||||
language,
|
||||
tree,
|
||||
included_sub_ranges: None,
|
||||
depth: 0,
|
||||
offset: (0, tree_sitter::Point::new(0, 0)),
|
||||
}]
|
||||
.into_iter(),
|
||||
query,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn captures<'a>(
|
||||
&'a self,
|
||||
range: Range<usize>,
|
||||
|
|
|
|||
|
|
@ -514,7 +514,7 @@ fn labels_from_extension(
|
|||
Arc::default()
|
||||
} else {
|
||||
language
|
||||
.highlight_text_resolved(&label.code.as_str().into(), 0..label.code.len())
|
||||
.highlight_text_resolved(label.code.as_str(), 0..label.code.len())
|
||||
.runs
|
||||
};
|
||||
build_code_label(&label, &runs, language)
|
||||
|
|
|
|||
|
|
@ -211,8 +211,8 @@ impl super::LspAdapter for CLspAdapter {
|
|||
Some(lsp::CompletionItemKind::FIELD) if completion.detail.is_some() => {
|
||||
let detail = completion.detail.as_ref().unwrap();
|
||||
let text = format!("{} {}", detail, label);
|
||||
let source = Rope::from(format!("struct S {{ {} }}", text).as_str());
|
||||
let runs = language.highlight_text(&source, 11..11 + text.len());
|
||||
let source = format!("struct S {{ {} }}", text);
|
||||
let runs = language.highlight_text(source.as_str(), 11..11 + text.len());
|
||||
let filter_range = completion
|
||||
.filter_text
|
||||
.as_deref()
|
||||
|
|
@ -228,7 +228,7 @@ impl super::LspAdapter for CLspAdapter {
|
|||
{
|
||||
let detail = completion.detail.as_ref().unwrap();
|
||||
let text = format!("{} {}", detail, label);
|
||||
let runs = language.highlight_text(&Rope::from(text.as_str()), 0..text.len());
|
||||
let runs = language.highlight_text(text.as_str(), 0..text.len());
|
||||
let filter_range = completion
|
||||
.filter_text
|
||||
.as_deref()
|
||||
|
|
@ -244,7 +244,7 @@ impl super::LspAdapter for CLspAdapter {
|
|||
{
|
||||
let detail = completion.detail.as_ref().unwrap();
|
||||
let text = format!("{} {}", detail, label);
|
||||
let runs = language.highlight_text(&Rope::from(text.as_str()), 0..text.len());
|
||||
let runs = language.highlight_text(text.as_str(), 0..text.len());
|
||||
let filter_range = completion
|
||||
.filter_text
|
||||
.as_deref()
|
||||
|
|
@ -348,7 +348,7 @@ impl super::LspAdapter for CLspAdapter {
|
|||
Some(CodeLabel::new(
|
||||
text[display_range.clone()].to_string(),
|
||||
filter_range,
|
||||
language.highlight_text(&text.as_str().into(), display_range),
|
||||
language.highlight_text(text.as_str(), display_range),
|
||||
))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -278,8 +278,9 @@ impl LspAdapter for GoLspAdapter {
|
|||
match completion.kind.zip(completion.detail.as_ref()) {
|
||||
Some((lsp::CompletionItemKind::MODULE, detail)) => {
|
||||
let text = format!("{label} {detail}");
|
||||
let source = Rope::from(format!("import {text}").as_str());
|
||||
let runs = language.highlight_text(&source, 7..7 + text[name_offset..].len());
|
||||
let source = format!("import {text}");
|
||||
let runs =
|
||||
language.highlight_text(source.as_str(), 7..7 + text[name_offset..].len());
|
||||
let filter_range = completion
|
||||
.filter_text
|
||||
.as_deref()
|
||||
|
|
@ -295,11 +296,10 @@ impl LspAdapter for GoLspAdapter {
|
|||
detail,
|
||||
)) => {
|
||||
let text = format!("{label} {detail}");
|
||||
let source =
|
||||
Rope::from(format!("var {} {}", &text[name_offset..], detail).as_str());
|
||||
let source = format!("var {} {}", &text[name_offset..], detail);
|
||||
let runs = adjust_runs(
|
||||
name_offset,
|
||||
language.highlight_text(&source, 4..4 + text[name_offset..].len()),
|
||||
language.highlight_text(source.as_str(), 4..4 + text[name_offset..].len()),
|
||||
);
|
||||
let filter_range = completion
|
||||
.filter_text
|
||||
|
|
@ -313,10 +313,10 @@ impl LspAdapter for GoLspAdapter {
|
|||
}
|
||||
Some((lsp::CompletionItemKind::STRUCT, _)) => {
|
||||
let text = format!("{label} struct {{}}");
|
||||
let source = Rope::from(format!("type {}", &text[name_offset..]).as_str());
|
||||
let source = format!("type {}", &text[name_offset..]);
|
||||
let runs = adjust_runs(
|
||||
name_offset,
|
||||
language.highlight_text(&source, 5..5 + text[name_offset..].len()),
|
||||
language.highlight_text(source.as_str(), 5..5 + text[name_offset..].len()),
|
||||
);
|
||||
let filter_range = completion
|
||||
.filter_text
|
||||
|
|
@ -330,10 +330,10 @@ impl LspAdapter for GoLspAdapter {
|
|||
}
|
||||
Some((lsp::CompletionItemKind::INTERFACE, _)) => {
|
||||
let text = format!("{label} interface {{}}");
|
||||
let source = Rope::from(format!("type {}", &text[name_offset..]).as_str());
|
||||
let source = format!("type {}", &text[name_offset..]);
|
||||
let runs = adjust_runs(
|
||||
name_offset,
|
||||
language.highlight_text(&source, 5..5 + text[name_offset..].len()),
|
||||
language.highlight_text(source.as_str(), 5..5 + text[name_offset..].len()),
|
||||
);
|
||||
let filter_range = completion
|
||||
.filter_text
|
||||
|
|
@ -347,11 +347,10 @@ impl LspAdapter for GoLspAdapter {
|
|||
}
|
||||
Some((lsp::CompletionItemKind::FIELD, detail)) => {
|
||||
let text = format!("{label} {detail}");
|
||||
let source =
|
||||
Rope::from(format!("type T struct {{ {} }}", &text[name_offset..]).as_str());
|
||||
let source = format!("type T struct {{ {} }}", &text[name_offset..]);
|
||||
let runs = adjust_runs(
|
||||
name_offset,
|
||||
language.highlight_text(&source, 16..16 + text[name_offset..].len()),
|
||||
language.highlight_text(source.as_str(), 16..16 + text[name_offset..].len()),
|
||||
);
|
||||
let filter_range = completion
|
||||
.filter_text
|
||||
|
|
@ -366,10 +365,10 @@ impl LspAdapter for GoLspAdapter {
|
|||
Some((lsp::CompletionItemKind::FUNCTION | lsp::CompletionItemKind::METHOD, detail)) => {
|
||||
if let Some(signature) = detail.strip_prefix("func") {
|
||||
let text = format!("{label}{signature}");
|
||||
let source = Rope::from(format!("func {} {{}}", &text[name_offset..]).as_str());
|
||||
let source = format!("func {} {{}}", &text[name_offset..]);
|
||||
let runs = adjust_runs(
|
||||
name_offset,
|
||||
language.highlight_text(&source, 5..5 + text[name_offset..].len()),
|
||||
language.highlight_text(source.as_str(), 5..5 + text[name_offset..].len()),
|
||||
);
|
||||
let filter_range = completion
|
||||
.filter_text
|
||||
|
|
@ -442,7 +441,7 @@ impl LspAdapter for GoLspAdapter {
|
|||
Some(CodeLabel::new(
|
||||
text[display_range.clone()].to_string(),
|
||||
filter_range,
|
||||
language.highlight_text(&text.as_str().into(), display_range),
|
||||
language.highlight_text(text.as_str(), display_range),
|
||||
))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ fn label_for_python_symbol(
|
|||
Some(language::CodeLabel::new(
|
||||
text[display_range.clone()].to_string(),
|
||||
filter_range,
|
||||
language.highlight_text(&text.as_str().into(), display_range),
|
||||
language.highlight_text(text.as_str(), display_range),
|
||||
))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -430,8 +430,8 @@ impl LspAdapter for RustLspAdapter {
|
|||
.filter(|it| it.contains(&label))
|
||||
.and_then(|it| Some((it, FULL_SIGNATURE_REGEX.find(it)?)))
|
||||
{
|
||||
let source = Rope::from(function_signature);
|
||||
let runs = language.highlight_text(&source, 0..function_signature.len());
|
||||
let runs =
|
||||
language.highlight_text(function_signature, 0..function_signature.len());
|
||||
mk_label(
|
||||
function_signature.to_owned(),
|
||||
&|| match_.range().start + 3..match_.range().end - 1,
|
||||
|
|
@ -446,8 +446,7 @@ impl LspAdapter for RustLspAdapter {
|
|||
} else if detail_right.is_some_and(|detail| detail.starts_with("macro_rules! ")) {
|
||||
let text = completion.label.clone();
|
||||
let len = text.len();
|
||||
let source = Rope::from(text.as_str());
|
||||
let runs = language.highlight_text(&source, 0..len);
|
||||
let runs = language.highlight_text(text.as_str(), 0..len);
|
||||
mk_label(text, &|| 0..completion.label.len(), runs)
|
||||
} else if detail_left.is_none() {
|
||||
return None;
|
||||
|
|
@ -544,7 +543,7 @@ impl LspAdapter for RustLspAdapter {
|
|||
detail_left.take();
|
||||
}
|
||||
|
||||
runs.extend(language.highlight_text(&Rope::from(&label), 0..label.len()));
|
||||
runs.extend(language.highlight_text(label.as_str(), 0..label.len()));
|
||||
} else {
|
||||
let highlight_name = kind.and_then(|kind| match kind {
|
||||
lsp::CompletionItemKind::STRUCT
|
||||
|
|
|
|||
|
|
@ -1674,22 +1674,25 @@ fn compute_code_block_highlights(parsed: &ParsedMarkdown) -> CodeBlockHighlights
|
|||
}
|
||||
|
||||
fn highlight_code_block(block: PendingCodeBlock, code_block_highlights: &mut CodeBlockHighlights) {
|
||||
let mut combined = Rope::new();
|
||||
if let [(event_index, text)] = block.texts.as_slice() {
|
||||
let resolved = block.language.highlight_text_resolved(*text, 0..text.len());
|
||||
if !resolved.runs.is_empty() {
|
||||
code_block_highlights.insert(*event_index, resolved);
|
||||
}
|
||||
return;
|
||||
}
|
||||
let mut combined = String::new();
|
||||
let mut text_offsets = Vec::with_capacity(block.texts.len());
|
||||
for (_, text) in &block.texts {
|
||||
text_offsets.push(combined.len());
|
||||
combined.push(text);
|
||||
combined.push_str(text);
|
||||
}
|
||||
let resolved = block
|
||||
.language
|
||||
.highlight_text_resolved(&combined, 0..combined.len());
|
||||
.highlight_text_resolved(combined.as_str(), 0..combined.len());
|
||||
if resolved.runs.is_empty() {
|
||||
return;
|
||||
}
|
||||
if let [(event_index, _)] = block.texts.as_slice() {
|
||||
code_block_highlights.insert(*event_index, resolved);
|
||||
return;
|
||||
}
|
||||
let mut runs = resolved.runs.iter().peekable();
|
||||
for ((event_index, text), text_offset) in block.texts.iter().zip(text_offsets) {
|
||||
let text_end = text_offset + text.len();
|
||||
|
|
@ -4169,9 +4172,7 @@ impl MarkdownElementBuilder {
|
|||
let runs = if resolved.is_current() {
|
||||
resolved.runs.clone()
|
||||
} else {
|
||||
language
|
||||
.highlight_text_resolved(&Rope::from(text), 0..text.len())
|
||||
.runs
|
||||
language.highlight_text_resolved(text, 0..text.len()).runs
|
||||
};
|
||||
let mut offset = 0;
|
||||
for (run_range, highlight_id) in runs.iter() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue