mirror of
https://github.com/zed-industries/zed.git
synced 2026-06-01 03:14:56 +07:00
language: Assert CodeLabel text ranges are correct (#40242)
Release Notes: - N/A *or* Added/Fixed/Improved ...
This commit is contained in:
parent
b0b83ef5aa
commit
3882323f79
21 changed files with 246 additions and 290 deletions
|
|
@ -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,22 +2324,36 @@ 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 {
|
||||
runs: Vec::new(),
|
||||
filter_range,
|
||||
text,
|
||||
}
|
||||
Self::new(text, filter_range, runs)
|
||||
}
|
||||
|
||||
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 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,
|
||||
filter_range,
|
||||
text,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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))],
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue