languages: Correctly calculate ranges in label_for_completion (#44925)

Closes #44825

Release Notes:

- Fixed a case where an incorrect match could be generated in
label_for_completion

---------

Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
This commit is contained in:
NereuxofficialandKirill Bulatov authored and GitHub committed 2025-12-16 14:51:33 +00:00
1 parent 9fcd8f812d
commit c2f72ff38b
2 files changed
+49 -4

No files matched your search

+4 -1
View File
@@ -2425,7 +2425,10 @@ impl CodeLabel {
"invalid filter range"
);
runs.iter().for_each(|(range, _)| {
assert!(text.get(range.clone()).is_some(), "invalid run range");
assert!(
text.get(range.clone()).is_some(),
"invalid run range with inputs. Requested range {range:?} in text '{text}'",
);
});
Self {
runs,
+45 -3
View File
@@ -375,16 +375,20 @@ impl LspAdapter for RustLspAdapter {
let start_pos = range.start as usize;
let end_pos = range.end as usize;
label.push_str(&snippet.text[text_pos..end_pos]);
text_pos = end_pos;
label.push_str(&snippet.text[text_pos..start_pos]);
if start_pos == end_pos {
let caret_start = label.len();
label.push('…');
runs.push((caret_start..label.len(), HighlightId::TABSTOP_INSERT_ID));
} else {
runs.push((start_pos..end_pos, HighlightId::TABSTOP_REPLACE_ID));
let label_start = label.len();
label.push_str(&snippet.text[start_pos..end_pos]);
let label_end = label.len();
runs.push((label_start..label_end, HighlightId::TABSTOP_REPLACE_ID));
}
text_pos = end_pos;
}
label.push_str(&snippet.text[text_pos..]);
@@ -1592,6 +1596,44 @@ mod tests {
],
))
);
// Test for correct range calculation with mixed empty and non-empty tabstops.(See https://github.com/zed-industries/zed/issues/44825)
let res = adapter
.label_for_completion(
&lsp::CompletionItem {
kind: Some(lsp::CompletionItemKind::STRUCT),
label: "Particles".to_string(),
insert_text_format: Some(lsp::InsertTextFormat::SNIPPET),
text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
range: lsp::Range::default(),
new_text: "Particles { pos_x: $1, pos_y: $2, vel_x: $3, vel_y: $4, acc_x: ${5:()}, acc_y: ${6:()}, mass: $7 }$0".to_string(),
})),
..Default::default()
},
&language,
)
.await
.unwrap();
assert_eq!(
res,
CodeLabel::new(
"Particles { pos_x: …, pos_y: …, vel_x: …, vel_y: …, acc_x: (), acc_y: (), mass: … }".to_string(),
0..9,
vec![
(19..22, HighlightId::TABSTOP_INSERT_ID),
(31..34, HighlightId::TABSTOP_INSERT_ID),
(43..46, HighlightId::TABSTOP_INSERT_ID),
(55..58, HighlightId::TABSTOP_INSERT_ID),
(67..69, HighlightId::TABSTOP_REPLACE_ID),
(78..80, HighlightId::TABSTOP_REPLACE_ID),
(88..91, HighlightId::TABSTOP_INSERT_ID),
(0..9, highlight_type),
(60..65, highlight_field),
(71..76, highlight_field),
],
)
);
}
#[gpui::test]