Detailed changes
@@ -12,7 +12,7 @@ use anyhow::Result;
use editor::{CompletionProvider, Editor, ExcerptId};
use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::{App, Entity, Task, WeakEntity};
-use language::{Buffer, CodeLabel, HighlightId};
+use language::{Buffer, CodeLabel, CodeLabelBuilder, HighlightId};
use lsp::CompletionContext;
use project::lsp_store::{CompletionDocumentation, SymbolLocation};
use project::{
@@ -673,7 +673,7 @@ impl ContextPickerCompletionProvider {
fn build_code_label_for_full_path(file_name: &str, directory: Option<&str>, cx: &App) -> CodeLabel {
let comment_id = cx.theme().syntax().highlight_id("comment").map(HighlightId);
- let mut label = CodeLabel::default();
+ let mut label = CodeLabelBuilder::default();
label.push_str(file_name, None);
label.push_str(" ", None);
@@ -682,9 +682,7 @@ fn build_code_label_for_full_path(file_name: &str, directory: Option<&str>, cx:
label.push_str(directory, comment_id);
}
- label.filter_range = 0..label.text().len();
-
- label
+ label.build()
}
impl CompletionProvider for ContextPickerCompletionProvider {
@@ -11,7 +11,7 @@ use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::{App, Entity, Task, WeakEntity};
use http_client::HttpClientWithUrl;
use itertools::Itertools;
-use language::{Buffer, CodeLabel, HighlightId};
+use language::{Buffer, CodeLabel, CodeLabelBuilder, HighlightId};
use lsp::CompletionContext;
use project::lsp_store::SymbolLocation;
use project::{
@@ -686,7 +686,8 @@ impl ContextPickerCompletionProvider {
};
let comment_id = cx.theme().syntax().highlight_id("comment").map(HighlightId);
- let mut label = CodeLabel::plain(symbol.name.clone(), None);
+ let mut label = CodeLabelBuilder::default();
+ label.push_str(&symbol.name, None);
label.push_str(" ", None);
label.push_str(&file_name, comment_id);
label.push_str(&format!(" L{}", symbol.range.start.0.row + 1), comment_id);
@@ -696,7 +697,7 @@ impl ContextPickerCompletionProvider {
Some(Completion {
replace_range: source_range.clone(),
new_text,
- label,
+ label: label.build(),
documentation: None,
source: project::CompletionSource::Custom,
icon_path: Some(IconName::Code.path().into()),
@@ -729,7 +730,7 @@ impl ContextPickerCompletionProvider {
fn build_code_label_for_full_path(file_name: &str, directory: Option<&str>, cx: &App) -> CodeLabel {
let comment_id = cx.theme().syntax().highlight_id("comment").map(HighlightId);
- let mut label = CodeLabel::default();
+ let mut label = CodeLabelBuilder::default();
label.push_str(file_name, None);
label.push_str(" ", None);
@@ -738,9 +739,7 @@ fn build_code_label_for_full_path(file_name: &str, directory: Option<&str>, cx:
label.push_str(directory, comment_id);
}
- label.filter_range = 0..label.text().len();
-
- label
+ label.build()
}
impl CompletionProvider for ContextPickerCompletionProvider {
@@ -9,6 +9,7 @@ use anyhow::Result;
use futures::StreamExt;
use futures::stream::{self, BoxStream};
use gpui::{App, SharedString, Task, WeakEntity, Window};
+use language::CodeLabelBuilder;
use language::HighlightId;
use language::{BufferSnapshot, CodeLabel, LspAdapterDelegate, OffsetRangeExt};
pub use language_model::Role;
@@ -328,15 +329,15 @@ impl SlashCommandLine {
}
pub fn create_label_for_command(command_name: &str, arguments: &[&str], cx: &App) -> CodeLabel {
- let mut label = CodeLabel::default();
+ let mut label = CodeLabelBuilder::default();
label.push_str(command_name, None);
+ label.respan_filter_range(None);
label.push_str(" ", None);
label.push_str(
&arguments.join(" "),
cx.theme().syntax().highlight_id("comment").map(HighlightId),
);
- label.filter_range = 0..command_name.len();
- label
+ label.build()
}
#[cfg(test)]
@@ -7,7 +7,7 @@ use futures::Stream;
use futures::channel::mpsc;
use fuzzy::PathMatch;
use gpui::{App, Entity, Task, WeakEntity};
-use language::{BufferSnapshot, CodeLabel, HighlightId, LineEnding, LspAdapterDelegate};
+use language::{BufferSnapshot, CodeLabelBuilder, HighlightId, LineEnding, LspAdapterDelegate};
use project::{PathMatchCandidateSet, Project};
use serde::{Deserialize, Serialize};
use smol::stream::StreamExt;
@@ -168,7 +168,7 @@ impl SlashCommand for FileSlashCommand {
.display(path_style)
.to_string();
- let mut label = CodeLabel::default();
+ let mut label = CodeLabelBuilder::default();
let file_name = path_match.path.file_name()?;
let label_text = if path_match.is_dir {
format!("{}/ ", file_name)
@@ -178,10 +178,10 @@ impl SlashCommand for FileSlashCommand {
label.push_str(label_text.as_str(), None);
label.push_str(&text, comment_id);
- label.filter_range = 0..file_name.len();
+ label.respan_filter_range(Some(file_name));
Some(ArgumentCompletion {
- label,
+ label: label.build(),
new_text: text,
after_completion: AfterCompletion::Compose,
replace_previous_arguments: false,
@@ -7,7 +7,7 @@ use collections::{HashMap, HashSet};
use editor::Editor;
use futures::future::join_all;
use gpui::{Task, WeakEntity};
-use language::{BufferSnapshot, CodeLabel, HighlightId, LspAdapterDelegate};
+use language::{BufferSnapshot, CodeLabel, CodeLabelBuilder, HighlightId, LspAdapterDelegate};
use std::sync::{Arc, atomic::AtomicBool};
use ui::{ActiveTheme, App, Window, prelude::*};
use util::{ResultExt, paths::PathStyle};
@@ -308,10 +308,10 @@ fn create_tab_completion_label(
comment_id: Option<HighlightId>,
) -> CodeLabel {
let (parent_path, file_name) = path_style.split(path);
- let mut label = CodeLabel::default();
+ let mut label = CodeLabelBuilder::default();
label.push_str(file_name, None);
label.push_str(" ", None);
label.push_str(parent_path.unwrap_or_default(), comment_id);
- label.filter_range = 0..file_name.len();
- label
+ label.respan_filter_range(Some(file_name));
+ label.build()
}
@@ -669,11 +669,7 @@ impl ConsoleQueryBarCompletionProvider {
&snapshot,
),
new_text: string_match.string.clone(),
- label: CodeLabel {
- filter_range: 0..string_match.string.len(),
- text: string_match.string.clone(),
- runs: Vec::new(),
- },
+ label: CodeLabel::plain(string_match.string.clone(), None),
icon_path: None,
documentation: Some(CompletionDocumentation::MultiLineMarkdown(
variable_value.into(),
@@ -782,11 +778,7 @@ impl ConsoleQueryBarCompletionProvider {
&snapshot,
),
new_text,
- label: CodeLabel {
- filter_range: 0..completion.label.len(),
- text: completion.label,
- runs: Vec::new(),
- },
+ label: CodeLabel::plain(completion.label, None),
icon_path: None,
documentation: completion.detail.map(|detail| {
CompletionDocumentation::MultiLineMarkdown(detail.into())
@@ -328,11 +328,7 @@ impl CompletionsMenu {
.map(|choice| Completion {
replace_range: selection.start.text_anchor..selection.end.text_anchor,
new_text: choice.to_string(),
- label: CodeLabel {
- text: choice.to_string(),
- runs: Default::default(),
- filter_range: Default::default(),
- },
+ label: CodeLabel::plain(choice.to_string(), None),
icon_path: None,
documentation: None,
confirm: None,
@@ -23077,11 +23077,7 @@ fn snippet_completions(
}),
lsp_defaults: None,
},
- label: CodeLabel {
- text: matching_prefix.clone(),
- runs: Vec::new(),
- filter_range: 0..matching_prefix.len(),
- },
+ label: CodeLabel::plain(matching_prefix.clone(), None),
icon_path: None,
documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
single_line: snippet.name.clone().into(),
@@ -14878,12 +14878,7 @@ async fn test_multiline_completion(cx: &mut TestAppContext) {
} else {
item.label.clone()
};
- let len = text.len();
- Some(language::CodeLabel {
- text,
- runs: Vec::new(),
- filter_range: 0..len,
- })
+ Some(language::CodeLabel::plain(text, None))
})),
..FakeLspAdapter::default()
},
@@ -755,7 +755,7 @@ impl PickerDelegate for OpenPathDelegate {
.with_default_highlights(
&window.text_style(),
vec![(
- delta..delta + label_len,
+ delta..label_len,
HighlightStyle::color(Color::Conflict.color(cx)),
)],
)
@@ -765,7 +765,7 @@ impl PickerDelegate for OpenPathDelegate {
.with_default_highlights(
&window.text_style(),
vec![(
- delta..delta + label_len,
+ delta..label_len,
HighlightStyle::color(Color::Created.color(cx)),
)],
)
@@ -180,8 +180,7 @@ impl StyledText {
"Can't use `with_default_highlights` and `with_highlights`"
);
let runs = Self::compute_runs(&self.text, default_style, highlights);
- self.runs = Some(runs);
- self
+ self.with_runs(runs)
}
/// Set the styling attributes for the given text, as well as
@@ -194,7 +193,15 @@ impl StyledText {
self.runs.is_none(),
"Can't use `with_highlights` and `with_default_highlights`"
);
- self.delayed_highlights = Some(highlights.into_iter().collect::<Vec<_>>());
+ self.delayed_highlights = Some(
+ highlights
+ .into_iter()
+ .inspect(|(run, _)| {
+ debug_assert!(self.text.is_char_boundary(run.start));
+ debug_assert!(self.text.is_char_boundary(run.end));
+ })
+ .collect::<Vec<_>>(),
+ );
self
}
@@ -207,8 +214,10 @@ impl StyledText {
let mut ix = 0;
for (range, highlight) in highlights {
if ix < range.start {
+ debug_assert!(text.is_char_boundary(range.start));
runs.push(default_style.clone().to_run(range.start - ix));
}
+ debug_assert!(text.is_char_boundary(range.end));
runs.push(
default_style
.clone()
@@ -225,6 +234,11 @@ impl StyledText {
/// Set the text runs for this piece of text.
pub fn with_runs(mut self, runs: Vec<TextRun>) -> Self {
+ let mut text = &**self.text;
+ for run in &runs {
+ text = text.get(run.len..).expect("invalid text run");
+ }
+ assert!(text.is_empty(), "invalid text run");
self.runs = Some(runs);
self
}
@@ -225,19 +225,15 @@ impl LineWrapper {
fn update_runs_after_truncation(result: &str, ellipsis: &str, runs: &mut Vec<TextRun>) {
let mut truncate_at = result.len() - ellipsis.len();
- let mut run_end = None;
for (run_index, run) in runs.iter_mut().enumerate() {
if run.len <= truncate_at {
truncate_at -= run.len;
} else {
run.len = truncate_at + ellipsis.len();
- run_end = Some(run_index + 1);
+ runs.truncate(run_index + 1);
break;
}
}
- if let Some(run_end) = run_end {
- runs.truncate(run_end);
- }
}
/// A fragment of a line that can be wrapped.
@@ -670,6 +670,16 @@ pub struct CodeLabel {
pub filter_range: Range<usize>,
}
+#[derive(Clone, Debug, Default, PartialEq, Eq)]
+pub struct CodeLabelBuilder {
+ /// The text to display.
+ text: String,
+ /// Syntax highlighting runs.
+ runs: Vec<(Range<usize>, HighlightId)>,
+ /// The portion of the text that should be used in fuzzy filtering.
+ filter_range: Range<usize>,
+}
+
#[derive(Clone, Deserialize, JsonSchema)]
pub struct LanguageConfig {
/// Human-readable name of the language.
@@ -2223,6 +2233,34 @@ impl Grammar {
}
}
+impl CodeLabelBuilder {
+ pub fn respan_filter_range(&mut self, filter_text: Option<&str>) {
+ self.filter_range = filter_text
+ .and_then(|filter| self.text.find(filter).map(|ix| ix..ix + filter.len()))
+ .unwrap_or(0..self.text.len());
+ }
+
+ pub fn push_str(&mut self, text: &str, highlight: Option<HighlightId>) {
+ let start_ix = self.text.len();
+ self.text.push_str(text);
+ if let Some(highlight) = highlight {
+ let end_ix = self.text.len();
+ self.runs.push((start_ix..end_ix, highlight));
+ }
+ }
+
+ pub fn build(mut self) -> CodeLabel {
+ if self.filter_range.end == 0 {
+ self.respan_filter_range(None);
+ }
+ CodeLabel {
+ text: self.text,
+ runs: self.runs,
+ filter_range: self.filter_range,
+ }
+ }
+}
+
impl CodeLabel {
pub fn fallback_for_completion(
item: &lsp::CompletionItem,
@@ -2286,25 +2324,39 @@ impl CodeLabel {
}
pub fn plain(text: String, filter_text: Option<&str>) -> Self {
+ Self::filtered(text, filter_text, Vec::new())
+ }
+
+ pub fn filtered(
+ text: String,
+ filter_text: Option<&str>,
+ runs: Vec<(Range<usize>, HighlightId)>,
+ ) -> Self {
let filter_range = filter_text
.and_then(|filter| text.find(filter).map(|ix| ix..ix + filter.len()))
.unwrap_or(0..text.len());
+ Self::new(text, filter_range, runs)
+ }
+
+ pub fn new(
+ text: String,
+ filter_range: Range<usize>,
+ runs: Vec<(Range<usize>, HighlightId)>,
+ ) -> Self {
+ assert!(
+ text.get(filter_range.clone()).is_some(),
+ "invalid filter range"
+ );
+ runs.iter().for_each(|(range, _)| {
+ assert!(text.get(range.clone()).is_some(), "invalid run range");
+ });
Self {
- runs: Vec::new(),
+ runs,
filter_range,
text,
}
}
- pub fn push_str(&mut self, text: &str, highlight: Option<HighlightId>) {
- let start_ix = self.text.len();
- self.text.push_str(text);
- let end_ix = self.text.len();
- if let Some(highlight) = highlight {
- self.runs.push((start_ix..end_ix, highlight));
- }
- }
-
pub fn text(&self) -> &str {
self.text.as_str()
}
@@ -463,11 +463,7 @@ fn build_code_label(
let filter_range = label.filter_range.clone();
text.get(filter_range.clone())?;
- Some(CodeLabel {
- text,
- runs,
- filter_range,
- })
+ Some(CodeLabel::new(text, filter_range, runs))
}
fn lsp_completion_to_extension(value: lsp::CompletionItem) -> extension::Completion {
@@ -615,11 +611,7 @@ fn test_build_code_label() {
assert_eq!(
label,
- CodeLabel {
- text: label_text,
- runs: label_runs,
- filter_range: label.filter_range.clone()
- }
+ CodeLabel::new(label_text, label.filter_range.clone(), label_runs)
)
}
@@ -188,11 +188,7 @@ impl super::LspAdapter for CLspAdapter {
.map(|start| start..start + filter_text.len())
})
.unwrap_or(detail.len() + 1..text.len());
- return Some(CodeLabel {
- filter_range,
- text,
- runs,
- });
+ return Some(CodeLabel::new(text, filter_range, runs));
}
Some(lsp::CompletionItemKind::CONSTANT | lsp::CompletionItemKind::VARIABLE)
if completion.detail.is_some() =>
@@ -208,11 +204,7 @@ impl super::LspAdapter for CLspAdapter {
.map(|start| start..start + filter_text.len())
})
.unwrap_or(detail.len() + 1..text.len());
- return Some(CodeLabel {
- filter_range,
- text,
- runs,
- });
+ return Some(CodeLabel::new(text, filter_range, runs));
}
Some(lsp::CompletionItemKind::FUNCTION | lsp::CompletionItemKind::METHOD)
if completion.detail.is_some() =>
@@ -236,11 +228,7 @@ impl super::LspAdapter for CLspAdapter {
filter_start..filter_end
});
- return Some(CodeLabel {
- filter_range,
- text,
- runs,
- });
+ return Some(CodeLabel::new(text, filter_range, runs));
}
Some(kind) => {
let highlight_name = match kind {
@@ -324,11 +312,11 @@ impl super::LspAdapter for CLspAdapter {
_ => return None,
};
- Some(CodeLabel {
- runs: language.highlight_text(&text.as_str().into(), display_range.clone()),
- text: text[display_range].to_string(),
+ Some(CodeLabel::new(
+ text[display_range.clone()].to_string(),
filter_range,
- })
+ language.highlight_text(&text.as_str().into(), display_range),
+ ))
}
fn prepare_initialize_params(
@@ -231,11 +231,7 @@ impl LspAdapter for GoLspAdapter {
.map(|start| start..start + filter_text.len())
})
.unwrap_or(0..label.len());
- return Some(CodeLabel {
- text,
- runs,
- filter_range,
- });
+ return Some(CodeLabel::new(text, filter_range, runs));
}
Some((
lsp::CompletionItemKind::CONSTANT | lsp::CompletionItemKind::VARIABLE,
@@ -256,11 +252,7 @@ impl LspAdapter for GoLspAdapter {
.map(|start| start..start + filter_text.len())
})
.unwrap_or(0..label.len());
- return Some(CodeLabel {
- text,
- runs,
- filter_range,
- });
+ return Some(CodeLabel::new(text, filter_range, runs));
}
Some((lsp::CompletionItemKind::STRUCT, _)) => {
let text = format!("{label} struct {{}}");
@@ -277,11 +269,7 @@ impl LspAdapter for GoLspAdapter {
.map(|start| start..start + filter_text.len())
})
.unwrap_or(0..label.len());
- return Some(CodeLabel {
- text,
- runs,
- filter_range,
- });
+ return Some(CodeLabel::new(text, filter_range, runs));
}
Some((lsp::CompletionItemKind::INTERFACE, _)) => {
let text = format!("{label} interface {{}}");
@@ -298,11 +286,7 @@ impl LspAdapter for GoLspAdapter {
.map(|start| start..start + filter_text.len())
})
.unwrap_or(0..label.len());
- return Some(CodeLabel {
- text,
- runs,
- filter_range,
- });
+ return Some(CodeLabel::new(text, filter_range, runs));
}
Some((lsp::CompletionItemKind::FIELD, detail)) => {
let text = format!("{label} {detail}");
@@ -320,11 +304,7 @@ impl LspAdapter for GoLspAdapter {
.map(|start| start..start + filter_text.len())
})
.unwrap_or(0..label.len());
- return Some(CodeLabel {
- text,
- runs,
- filter_range,
- });
+ return Some(CodeLabel::new(text, filter_range, runs));
}
Some((lsp::CompletionItemKind::FUNCTION | lsp::CompletionItemKind::METHOD, detail)) => {
if let Some(signature) = detail.strip_prefix("func") {
@@ -342,11 +322,7 @@ impl LspAdapter for GoLspAdapter {
.map(|start| start..start + filter_text.len())
})
.unwrap_or(0..label.len());
- return Some(CodeLabel {
- filter_range,
- text,
- runs,
- });
+ return Some(CodeLabel::new(text, filter_range, runs));
}
}
_ => {}
@@ -406,11 +382,11 @@ impl LspAdapter for GoLspAdapter {
_ => return None,
};
- Some(CodeLabel {
- runs: language.highlight_text(&text.as_str().into(), display_range.clone()),
- text: text[display_range].to_string(),
+ Some(CodeLabel::new(
+ text[display_range.clone()].to_string(),
filter_range,
- })
+ language.highlight_text(&text.as_str().into(), display_range),
+ ))
}
fn diagnostic_message_to_markdown(&self, message: &str) -> Option<String> {
@@ -810,15 +786,15 @@ mod tests {
&language
)
.await,
- Some(CodeLabel {
- text: "Hello(a B) c.D".to_string(),
- filter_range: 0..5,
- runs: vec![
+ Some(CodeLabel::new(
+ "Hello(a B) c.D".to_string(),
+ 0..5,
+ vec![
(0..5, highlight_function),
(8..9, highlight_type),
(13..14, highlight_type),
- ],
- })
+ ]
+ ))
);
// Nested methods
@@ -834,15 +810,15 @@ mod tests {
&language
)
.await,
- Some(CodeLabel {
- text: "one.two.Three() [3]interface{}".to_string(),
- filter_range: 0..13,
- runs: vec![
+ Some(CodeLabel::new(
+ "one.two.Three() [3]interface{}".to_string(),
+ 0..13,
+ vec![
(8..13, highlight_function),
(17..18, highlight_number),
(19..28, highlight_keyword),
],
- })
+ ))
);
// Nested fields
@@ -858,11 +834,11 @@ mod tests {
&language
)
.await,
- Some(CodeLabel {
- text: "two.Three a.Bcd".to_string(),
- filter_range: 0..9,
- runs: vec![(4..9, highlight_field), (12..15, highlight_type)],
- })
+ Some(CodeLabel::new(
+ "two.Three a.Bcd".to_string(),
+ 0..9,
+ vec![(4..9, highlight_field), (12..15, highlight_type)],
+ ))
);
}
@@ -407,11 +407,6 @@ impl LspAdapter for PyrightLspAdapter {
return None;
}
};
- let filter_range = item
- .filter_text
- .as_deref()
- .and_then(|filter| label.find(filter).map(|ix| ix..ix + filter.len()))
- .unwrap_or(0..label.len());
let mut text = label.clone();
if let Some(completion_details) = item
.label_details
@@ -420,14 +415,14 @@ impl LspAdapter for PyrightLspAdapter {
{
write!(&mut text, " {}", completion_details).ok();
}
- Some(language::CodeLabel {
- runs: highlight_id
+ Some(language::CodeLabel::filtered(
+ text,
+ item.filter_text.as_deref(),
+ highlight_id
.map(|id| (0..label.len(), id))
.into_iter()
.collect(),
- text,
- filter_range,
- })
+ ))
}
async fn label_for_symbol(
@@ -458,11 +453,11 @@ impl LspAdapter for PyrightLspAdapter {
_ => return None,
};
- Some(language::CodeLabel {
- runs: language.highlight_text(&text.as_str().into(), display_range.clone()),
- text: text[display_range].to_string(),
+ Some(language::CodeLabel::new(
+ text[display_range.clone()].to_string(),
filter_range,
- })
+ language.highlight_text(&text.as_str().into(), display_range),
+ ))
}
async fn workspace_configuration(
@@ -1424,16 +1419,11 @@ impl LspAdapter for PyLspAdapter {
lsp::CompletionItemKind::CONSTANT => grammar.highlight_id_for_name("constant")?,
_ => return None,
};
- let filter_range = item
- .filter_text
- .as_deref()
- .and_then(|filter| label.find(filter).map(|ix| ix..ix + filter.len()))
- .unwrap_or(0..label.len());
- Some(language::CodeLabel {
- text: label.clone(),
- runs: vec![(0..label.len(), highlight_id)],
- filter_range,
- })
+ Some(language::CodeLabel::filtered(
+ label.clone(),
+ item.filter_text.as_deref(),
+ vec![(0..label.len(), highlight_id)],
+ ))
}
async fn label_for_symbol(
@@ -1463,12 +1453,11 @@ impl LspAdapter for PyLspAdapter {
}
_ => return None,
};
-
- Some(language::CodeLabel {
- runs: language.highlight_text(&text.as_str().into(), display_range.clone()),
- text: text[display_range].to_string(),
+ Some(language::CodeLabel::new(
+ text[display_range.clone()].to_string(),
filter_range,
- })
+ language.highlight_text(&text.as_str().into(), display_range),
+ ))
}
async fn workspace_configuration(
@@ -1708,11 +1697,6 @@ impl LspAdapter for BasedPyrightLspAdapter {
return None;
}
};
- let filter_range = item
- .filter_text
- .as_deref()
- .and_then(|filter| label.find(filter).map(|ix| ix..ix + filter.len()))
- .unwrap_or(0..label.len());
let mut text = label.clone();
if let Some(completion_details) = item
.label_details
@@ -1721,14 +1705,14 @@ impl LspAdapter for BasedPyrightLspAdapter {
{
write!(&mut text, " {}", completion_details).ok();
}
- Some(language::CodeLabel {
- runs: highlight_id
+ Some(language::CodeLabel::filtered(
+ text,
+ item.filter_text.as_deref(),
+ highlight_id
.map(|id| (0..label.len(), id))
.into_iter()
.collect(),
- text,
- filter_range,
- })
+ ))
}
async fn label_for_symbol(
@@ -1758,12 +1742,11 @@ impl LspAdapter for BasedPyrightLspAdapter {
}
_ => return None,
};
-
- Some(language::CodeLabel {
- runs: language.highlight_text(&text.as_str().into(), display_range.clone()),
- text: text[display_range].to_string(),
+ Some(language::CodeLabel::new(
+ text[display_range.clone()].to_string(),
filter_range,
- })
+ language.highlight_text(&text.as_str().into(), display_range),
+ ))
}
async fn workspace_configuration(
@@ -209,11 +209,7 @@ impl LspAdapter for RustLspAdapter {
})
.unwrap_or_else(filter_range);
- CodeLabel {
- text,
- runs,
- filter_range,
- }
+ CodeLabel::new(text, filter_range, runs)
};
let mut label = match (detail_right, completion.kind) {
(Some(signature), Some(lsp::CompletionItemKind::FIELD)) => {
@@ -364,11 +360,11 @@ impl LspAdapter for RustLspAdapter {
let filter_range = prefix.len()..prefix.len() + name.len();
let display_range = 0..filter_range.end;
- Some(CodeLabel {
- runs: language.highlight_text(&Rope::from_iter([prefix, name, suffix]), display_range),
- text: format!("{prefix}{name}"),
+ Some(CodeLabel::new(
+ format!("{prefix}{name}"),
filter_range,
- })
+ language.highlight_text(&Rope::from_iter([prefix, name, suffix]), display_range),
+ ))
}
fn prepare_initialize_params(
@@ -1166,10 +1162,10 @@ mod tests {
&language
)
.await,
- Some(CodeLabel {
- text: "hello(&mut Option<T>) -> Vec<T> (use crate::foo)".to_string(),
- filter_range: 0..5,
- runs: vec![
+ Some(CodeLabel::new(
+ "hello(&mut Option<T>) -> Vec<T> (use crate::foo)".to_string(),
+ 0..5,
+ vec![
(0..5, highlight_function),
(7..10, highlight_keyword),
(11..17, highlight_type),
@@ -1177,7 +1173,7 @@ mod tests {
(25..28, highlight_type),
(29..30, highlight_type),
],
- })
+ ))
);
assert_eq!(
adapter
@@ -1194,10 +1190,10 @@ mod tests {
&language
)
.await,
- Some(CodeLabel {
- text: "hello(&mut Option<T>) -> Vec<T> (use crate::foo)".to_string(),
- filter_range: 0..5,
- runs: vec![
+ Some(CodeLabel::new(
+ "hello(&mut Option<T>) -> Vec<T> (use crate::foo)".to_string(),
+ 0..5,
+ vec![
(0..5, highlight_function),
(7..10, highlight_keyword),
(11..17, highlight_type),
@@ -1205,7 +1201,7 @@ mod tests {
(25..28, highlight_type),
(29..30, highlight_type),
],
- })
+ ))
);
assert_eq!(
adapter
@@ -1219,11 +1215,11 @@ mod tests {
&language
)
.await,
- Some(CodeLabel {
- text: "len: usize".to_string(),
- filter_range: 0..3,
- runs: vec![(0..3, highlight_field), (5..10, highlight_type),],
- })
+ Some(CodeLabel::new(
+ "len: usize".to_string(),
+ 0..3,
+ vec![(0..3, highlight_field), (5..10, highlight_type),],
+ ))
);
assert_eq!(
@@ -1242,10 +1238,10 @@ mod tests {
&language
)
.await,
- Some(CodeLabel {
- text: "hello(&mut Option<T>) -> Vec<T> (use crate::foo)".to_string(),
- filter_range: 0..5,
- runs: vec![
+ Some(CodeLabel::new(
+ "hello(&mut Option<T>) -> Vec<T> (use crate::foo)".to_string(),
+ 0..5,
+ vec![
(0..5, highlight_function),
(7..10, highlight_keyword),
(11..17, highlight_type),
@@ -1253,7 +1249,7 @@ mod tests {
(25..28, highlight_type),
(29..30, highlight_type),
],
- })
+ ))
);
assert_eq!(
@@ -1271,10 +1267,10 @@ mod tests {
&language
)
.await,
- Some(CodeLabel {
- text: "hello(&mut Option<T>) -> Vec<T> (use crate::foo)".to_string(),
- filter_range: 0..5,
- runs: vec![
+ Some(CodeLabel::new(
+ "hello(&mut Option<T>) -> Vec<T> (use crate::foo)".to_string(),
+ 0..5,
+ vec![
(0..5, highlight_function),
(7..10, highlight_keyword),
(11..17, highlight_type),
@@ -1282,7 +1278,7 @@ mod tests {
(25..28, highlight_type),
(29..30, highlight_type),
],
- })
+ ))
);
assert_eq!(
@@ -1301,16 +1297,16 @@ mod tests {
&language
)
.await,
- Some(CodeLabel {
- text: "await.as_deref_mut(&mut self) -> IterMut<'_, T>".to_string(),
- filter_range: 6..18,
- runs: vec![
+ Some(CodeLabel::new(
+ "await.as_deref_mut(&mut self) -> IterMut<'_, T>".to_string(),
+ 6..18,
+ vec![
(6..18, HighlightId(2)),
(20..23, HighlightId(1)),
(33..40, HighlightId(0)),
(45..46, HighlightId(0))
],
- })
+ ))
);
assert_eq!(
@@ -1331,10 +1327,10 @@ mod tests {
&language
)
.await,
- Some(CodeLabel {
- text: "pub fn as_deref_mut(&mut self) -> IterMut<'_, T>".to_string(),
- filter_range: 7..19,
- runs: vec![
+ Some(CodeLabel::new(
+ "pub fn as_deref_mut(&mut self) -> IterMut<'_, T>".to_string(),
+ 7..19,
+ vec![
(0..3, HighlightId(1)),
(4..6, HighlightId(1)),
(7..19, HighlightId(2)),
@@ -1342,7 +1338,7 @@ mod tests {
(34..41, HighlightId(0)),
(46..47, HighlightId(0))
],
- })
+ ))
);
assert_eq!(
@@ -1358,11 +1354,11 @@ mod tests {
&language,
)
.await,
- Some(CodeLabel {
- text: "inner_value: String".to_string(),
- filter_range: 6..11,
- runs: vec![(0..11, HighlightId(3)), (13..19, HighlightId(0))],
- })
+ Some(CodeLabel::new(
+ "inner_value: String".to_string(),
+ 6..11,
+ vec![(0..11, HighlightId(3)), (13..19, HighlightId(0))],
+ ))
);
}
@@ -1388,22 +1384,22 @@ mod tests {
adapter
.label_for_symbol("hello", lsp::SymbolKind::FUNCTION, &language)
.await,
- Some(CodeLabel {
- text: "fn hello".to_string(),
- filter_range: 3..8,
- runs: vec![(0..2, highlight_keyword), (3..8, highlight_function)],
- })
+ Some(CodeLabel::new(
+ "fn hello".to_string(),
+ 3..8,
+ vec![(0..2, highlight_keyword), (3..8, highlight_function)],
+ ))
);
assert_eq!(
adapter
.label_for_symbol("World", lsp::SymbolKind::TYPE_PARAMETER, &language)
.await,
- Some(CodeLabel {
- text: "type World".to_string(),
- filter_range: 5..10,
- runs: vec![(0..4, highlight_keyword), (5..10, highlight_type)],
- })
+ Some(CodeLabel::new(
+ "type World".to_string(),
+ 5..10,
+ vec![(0..4, highlight_keyword), (5..10, highlight_type)],
+ ))
);
}
@@ -777,16 +777,11 @@ impl LspAdapter for TypeScriptLspAdapter {
} else {
item.label.clone()
};
- let filter_range = item
- .filter_text
- .as_deref()
- .and_then(|filter| text.find(filter).map(|ix| ix..ix + filter.len()))
- .unwrap_or(0..len);
- Some(language::CodeLabel {
+ Some(language::CodeLabel::filtered(
text,
- runs: vec![(0..len, highlight_id)],
- filter_range,
- })
+ item.filter_text.as_deref(),
+ vec![(0..len, highlight_id)],
+ ))
}
async fn initialization_options(
@@ -201,16 +201,11 @@ impl LspAdapter for VtslsLspAdapter {
} else {
item.label.clone()
};
- let filter_range = item
- .filter_text
- .as_deref()
- .and_then(|filter| text.find(filter).map(|ix| ix..ix + filter.len()))
- .unwrap_or(0..len);
- Some(language::CodeLabel {
+ Some(language::CodeLabel::filtered(
text,
- runs: vec![(0..len, highlight_id)],
- filter_range,
- })
+ item.filter_text.as_deref(),
+ vec![(0..len, highlight_id)],
+ ))
}
async fn workspace_configuration(
@@ -9365,11 +9365,7 @@ impl LspStore {
name: symbol.name,
kind: symbol.kind,
range: symbol.range,
- label: CodeLabel {
- text: Default::default(),
- runs: Default::default(),
- filter_range: Default::default(),
- },
+ label: CodeLabel::default(),
},
cx,
)
@@ -9559,11 +9555,7 @@ impl LspStore {
new_text: completion.new_text,
source: completion.source,
documentation: None,
- label: CodeLabel {
- text: Default::default(),
- runs: Default::default(),
- filter_range: Default::default(),
- },
+ label: CodeLabel::default(),
insert_text_mode: None,
icon_path: None,
confirm: None,
@@ -13060,19 +13052,19 @@ mod tests {
#[test]
fn test_multi_len_chars_normalization() {
- let mut label = CodeLabel {
- text: "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
- runs: vec![(0..6, HighlightId(1))],
- filter_range: 0..6,
- };
+ let mut label = CodeLabel::new(
+ "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
+ 0..6,
+ vec![(0..6, HighlightId(1))],
+ );
ensure_uniform_list_compatible_label(&mut label);
assert_eq!(
label,
- CodeLabel {
- text: "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
- runs: vec![(0..6, HighlightId(1))],
- filter_range: 0..6,
- }
+ CodeLabel::new(
+ "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
+ 0..6,
+ vec![(0..6, HighlightId(1))],
+ )
);
}
}