Merge pull request #19332 from Veykril/push-trvznlqsvtyq

Make change annotations per text-edit
This commit is contained in:
Lukas Wirth 2025-03-10 11:25:13 +00:00 committed by GitHub
commit f81fcabdf9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 53 additions and 84 deletions

View file

@ -710,24 +710,21 @@ pub fn test_some_range(a: int) -> bool {
Indel {
insert: "let",
delete: 45..47,
annotation: None,
},
Indel {
insert: "var_name",
delete: 48..60,
annotation: None,
},
Indel {
insert: "=",
delete: 61..81,
annotation: None,
},
Indel {
insert: "5;\n if let 2..6 = var_name {\n true\n } else {\n false\n }",
delete: 82..108,
annotation: None,
},
],
annotation: None,
},
Some(
SnippetEdit(
@ -845,24 +842,21 @@ pub fn test_some_range(a: int) -> bool {
Indel {
insert: "let",
delete: 45..47,
annotation: None,
},
Indel {
insert: "var_name",
delete: 48..60,
annotation: None,
},
Indel {
insert: "=",
delete: 61..81,
annotation: None,
},
Indel {
insert: "5;\n if let 2..6 = var_name {\n true\n } else {\n false\n }",
delete: 82..108,
annotation: None,
},
],
annotation: None,
},
Some(
SnippetEdit(
@ -914,29 +908,25 @@ pub fn test_some_range(a: int) -> bool {
Indel {
insert: "const",
delete: 45..47,
annotation: None,
},
Indel {
insert: "VAR_NAME:",
delete: 48..60,
annotation: None,
},
Indel {
insert: "i32",
delete: 61..81,
annotation: None,
},
Indel {
insert: "=",
delete: 82..86,
annotation: None,
},
Indel {
insert: "5;\n if let 2..6 = VAR_NAME {\n true\n } else {\n false\n }",
delete: 87..108,
annotation: None,
},
],
annotation: None,
},
Some(
SnippetEdit(
@ -988,29 +978,25 @@ pub fn test_some_range(a: int) -> bool {
Indel {
insert: "static",
delete: 45..47,
annotation: None,
},
Indel {
insert: "VAR_NAME:",
delete: 48..60,
annotation: None,
},
Indel {
insert: "i32",
delete: 61..81,
annotation: None,
},
Indel {
insert: "=",
delete: 82..86,
annotation: None,
},
Indel {
insert: "5;\n if let 2..6 = VAR_NAME {\n true\n } else {\n false\n }",
delete: 87..108,
annotation: None,
},
],
annotation: None,
},
Some(
SnippetEdit(
@ -1062,14 +1048,13 @@ pub fn test_some_range(a: int) -> bool {
Indel {
insert: "fun_name()",
delete: 59..60,
annotation: None,
},
Indel {
insert: "\n\nfn fun_name() -> i32 {\n 5\n}",
delete: 110..110,
annotation: None,
},
],
annotation: None,
},
Some(
SnippetEdit(

View file

@ -2773,14 +2773,13 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 }
Indel {
insert: "(",
delete: 107..107,
annotation: None,
},
Indel {
insert: "qux)()",
delete: 109..110,
annotation: None,
},
],
annotation: None,
},
kind: SymbolKind(
Field,

View file

@ -367,14 +367,10 @@ fn rename_reference(
)
}));
let mut insert_def_edit = |def| {
let (file_id, edit) = source_edit_from_def(sema, def, new_name, &mut source_change)?;
source_change.insert_source_edit(file_id, edit);
Ok(())
};
// This needs to come after the references edits, because we change the annotation of existing edits
// if a conflict is detected.
insert_def_edit(def)?;
let (file_id, edit) = source_edit_from_def(sema, def, new_name, &mut source_change)?;
source_change.insert_source_edit(file_id, edit);
Ok(source_change)
}

View file

@ -18,18 +18,19 @@ pub struct Indel {
pub insert: String,
/// Refers to offsets in the original text
pub delete: TextRange,
pub annotation: Option<ChangeAnnotationId>,
}
#[derive(Default, Debug, Clone)]
pub struct TextEdit {
/// Invariant: disjoint and sorted by `delete`.
indels: Vec<Indel>,
annotation: Option<ChangeAnnotationId>,
}
#[derive(Debug, Default, Clone)]
pub struct TextEditBuilder {
indels: Vec<Indel>,
annotation: Option<ChangeAnnotationId>,
}
impl Indel {
@ -40,7 +41,7 @@ impl Indel {
Indel::replace(range, String::new())
}
pub fn replace(range: TextRange, replace_with: String) -> Indel {
Indel { delete: range, insert: replace_with, annotation: None }
Indel { delete: range, insert: replace_with }
}
pub fn apply(&self, text: &mut String) {
@ -142,12 +143,12 @@ impl TextEdit {
Some(res)
}
pub fn set_annotation(&mut self, annotation: Option<ChangeAnnotationId>) {
if annotation.is_some() {
for indel in &mut self.indels {
indel.annotation = annotation;
}
}
pub(crate) fn set_annotation(&mut self, conflict_annotation: Option<ChangeAnnotationId>) {
self.annotation = conflict_annotation;
}
pub fn change_annotation(&self) -> Option<ChangeAnnotationId> {
self.annotation
}
}
@ -183,10 +184,10 @@ impl TextEditBuilder {
self.indel(Indel::insert(offset, text));
}
pub fn finish(self) -> TextEdit {
let mut indels = self.indels;
let TextEditBuilder { mut indels, annotation } = self;
assert_disjoint_or_equal(&mut indels);
indels = coalesce_indels(indels);
TextEdit { indels }
TextEdit { indels, annotation }
}
pub fn invalidates_offset(&self, offset: TextSize) -> bool {
self.indels.iter().any(|indel| indel.delete.contains_inclusive(offset))

View file

@ -509,10 +509,9 @@ mod tests {
let found_conflicts = source_change
.source_file_edits
.iter()
.filter(|(_, (edit, _))| edit.change_annotation().is_some())
.flat_map(|(file_id, (edit, _))| {
edit.into_iter()
.filter(|edit| edit.annotation.is_some())
.map(move |edit| (*file_id, edit.delete))
edit.into_iter().map(move |edit| (*file_id, edit.delete))
})
.sorted_unstable_by_key(|(file_id, range)| (*file_id, range.start()))
.collect_vec();
@ -1081,7 +1080,6 @@ mod foo$0;
Indel {
insert: "foo2",
delete: 4..7,
annotation: None,
},
],
),
@ -1129,7 +1127,6 @@ use crate::foo$0::FooContent;
Indel {
insert: "quux",
delete: 8..11,
annotation: None,
},
],
),
@ -1141,7 +1138,6 @@ use crate::foo$0::FooContent;
Indel {
insert: "quux",
delete: 11..14,
annotation: None,
},
],
),
@ -1183,7 +1179,6 @@ mod fo$0o;
Indel {
insert: "foo2",
delete: 4..7,
annotation: None,
},
],
),
@ -1232,7 +1227,6 @@ mod outer { mod fo$0o; }
Indel {
insert: "bar",
delete: 16..19,
annotation: None,
},
],
),
@ -1304,7 +1298,6 @@ pub mod foo$0;
Indel {
insert: "foo2",
delete: 27..30,
annotation: None,
},
],
),
@ -1316,7 +1309,6 @@ pub mod foo$0;
Indel {
insert: "foo2",
delete: 8..11,
annotation: None,
},
],
),
@ -1372,7 +1364,6 @@ mod quux;
Indel {
insert: "foo2",
delete: 4..7,
annotation: None,
},
],
),
@ -1506,12 +1497,10 @@ pub fn baz() {}
Indel {
insert: "r#fn",
delete: 4..7,
annotation: None,
},
Indel {
insert: "r#fn",
delete: 22..25,
annotation: None,
},
],
),
@ -1576,12 +1565,10 @@ pub fn baz() {}
Indel {
insert: "foo",
delete: 4..8,
annotation: None,
},
Indel {
insert: "foo",
delete: 23..27,
annotation: None,
},
],
),
@ -1643,7 +1630,6 @@ fn bar() {
Indel {
insert: "dyn",
delete: 7..10,
annotation: None,
},
],
),
@ -1655,7 +1641,6 @@ fn bar() {
Indel {
insert: "r#dyn",
delete: 18..21,
annotation: None,
},
],
),
@ -1685,7 +1670,6 @@ fn bar() {
Indel {
insert: "r#dyn",
delete: 7..10,
annotation: None,
},
],
),
@ -1697,7 +1681,6 @@ fn bar() {
Indel {
insert: "dyn",
delete: 18..21,
annotation: None,
},
],
),
@ -1727,7 +1710,6 @@ fn bar() {
Indel {
insert: "r#dyn",
delete: 7..10,
annotation: None,
},
],
),
@ -1739,7 +1721,6 @@ fn bar() {
Indel {
insert: "dyn",
delete: 18..21,
annotation: None,
},
],
),
@ -1776,12 +1757,10 @@ fn bar() {
Indel {
insert: "abc",
delete: 7..10,
annotation: None,
},
Indel {
insert: "abc",
delete: 32..35,
annotation: None,
},
],
),
@ -1793,7 +1772,6 @@ fn bar() {
Indel {
insert: "abc",
delete: 18..23,
annotation: None,
},
],
),
@ -1827,12 +1805,10 @@ fn bar() {
Indel {
insert: "abc",
delete: 7..12,
annotation: None,
},
Indel {
insert: "abc",
delete: 34..39,
annotation: None,
},
],
),
@ -1844,7 +1820,6 @@ fn bar() {
Indel {
insert: "abc",
delete: 18..21,
annotation: None,
},
],
),

View file

@ -139,9 +139,9 @@ mod tests {
Indel {
insert: "3",
delete: 33..34,
annotation: None,
},
],
annotation: None,
},
None,
),
@ -182,9 +182,9 @@ mod tests {
Indel {
insert: "3",
delete: 33..34,
annotation: None,
},
],
annotation: None,
},
None,
),
@ -196,9 +196,9 @@ mod tests {
Indel {
insert: "3",
delete: 11..12,
annotation: None,
},
],
annotation: None,
},
None,
),

View file

@ -16,7 +16,7 @@ use ide::{
SnippetEdit, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
UpdateTest,
};
use ide_db::{assists, rust_doc::format_docs, FxHasher};
use ide_db::{assists, rust_doc::format_docs, source_change::ChangeAnnotationId, FxHasher};
use itertools::Itertools;
use paths::{Utf8Component, Utf8Prefix};
use semver::VersionReq;
@ -200,10 +200,10 @@ pub(crate) fn snippet_text_edit(
line_index: &LineIndex,
is_snippet: bool,
indel: Indel,
annotation: Option<ChangeAnnotationId>,
client_supports_annotations: bool,
) -> lsp_ext::SnippetTextEdit {
let annotation_id =
indel.annotation.filter(|_| client_supports_annotations).map(|it| it.to_string());
let annotation_id = annotation.filter(|_| client_supports_annotations).map(|it| it.to_string());
let text_edit = text_edit(line_index, indel);
let insert_text_format =
if is_snippet { Some(lsp_types::InsertTextFormat::SNIPPET) } else { None };
@ -228,10 +228,17 @@ pub(crate) fn snippet_text_edit_vec(
text_edit: TextEdit,
clients_support_annotations: bool,
) -> Vec<lsp_ext::SnippetTextEdit> {
let annotation = text_edit.change_annotation();
text_edit
.into_iter()
.map(|indel| {
self::snippet_text_edit(line_index, is_snippet, indel, clients_support_annotations)
self::snippet_text_edit(
line_index,
is_snippet,
indel,
annotation,
clients_support_annotations,
)
})
.collect()
}
@ -1082,6 +1089,7 @@ fn merge_text_and_snippet_edits(
) -> Vec<SnippetTextEdit> {
let mut edits: Vec<SnippetTextEdit> = vec![];
let mut snippets = snippet_edit.into_edit_ranges().into_iter().peekable();
let annotation = edit.change_annotation();
let text_edits = edit.into_iter();
// offset to go from the final source location to the original source location
let mut source_text_offset = 0i32;
@ -1127,11 +1135,8 @@ fn merge_text_and_snippet_edits(
edits.push(snippet_text_edit(
line_index,
true,
Indel {
insert: format!("${snippet_index}"),
delete: snippet_range,
annotation: None,
},
Indel { insert: format!("${snippet_index}"), delete: snippet_range },
annotation,
client_supports_annotations,
))
}
@ -1190,11 +1195,8 @@ fn merge_text_and_snippet_edits(
edits.push(snippet_text_edit(
line_index,
true,
Indel {
insert: new_text,
delete: current_indel.delete,
annotation: current_indel.annotation,
},
Indel { insert: new_text, delete: current_indel.delete },
annotation,
client_supports_annotations,
))
} else {
@ -1204,6 +1206,7 @@ fn merge_text_and_snippet_edits(
line_index,
false,
current_indel,
annotation,
client_supports_annotations,
));
}
@ -1230,7 +1233,8 @@ fn merge_text_and_snippet_edits(
snippet_text_edit(
line_index,
true,
Indel { insert: format!("${snippet_index}"), delete: snippet_range, annotation: None },
Indel { insert: format!("${snippet_index}"), delete: snippet_range },
annotation,
client_supports_annotations,
)
}));
@ -1251,8 +1255,17 @@ pub(crate) fn snippet_text_document_edit(
let mut edits = if let Some(snippet_edit) = snippet_edit {
merge_text_and_snippet_edits(&line_index, edit, snippet_edit, client_supports_annotations)
} else {
let annotation = edit.change_annotation();
edit.into_iter()
.map(|it| snippet_text_edit(&line_index, is_snippet, it, client_supports_annotations))
.map(|it| {
snippet_text_edit(
&line_index,
is_snippet,
it,
annotation,
client_supports_annotations,
)
})
.collect()
};