Merge #4553
4553: Cleanup r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
ba6cf638fb
@ -63,8 +63,8 @@ impl fmt::Debug for CompletionItem {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let mut s = f.debug_struct("CompletionItem");
|
let mut s = f.debug_struct("CompletionItem");
|
||||||
s.field("label", &self.label()).field("source_range", &self.source_range());
|
s.field("label", &self.label()).field("source_range", &self.source_range());
|
||||||
if self.text_edit().as_indels().len() == 1 {
|
if self.text_edit().len() == 1 {
|
||||||
let atom = &self.text_edit().as_indels()[0];
|
let atom = &self.text_edit().iter().next().unwrap();
|
||||||
s.field("delete", &atom.delete);
|
s.field("delete", &atom.delete);
|
||||||
s.field("insert", &atom.insert);
|
s.field("insert", &atom.insert);
|
||||||
} else {
|
} else {
|
||||||
|
@ -166,16 +166,28 @@ fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::test_utils::{assert_eq_text, check_action, extract_range};
|
use ra_syntax::SourceFile;
|
||||||
|
use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn check_join_lines(before: &str, after: &str) {
|
fn check_join_lines(before: &str, after: &str) {
|
||||||
check_action(before, after, |file, offset| {
|
let (before_cursor_pos, before) = extract_offset(before);
|
||||||
let range = TextRange::empty(offset);
|
let file = SourceFile::parse(&before).ok().unwrap();
|
||||||
let res = join_lines(file, range);
|
|
||||||
Some(res)
|
let range = TextRange::empty(before_cursor_pos);
|
||||||
})
|
let result = join_lines(&file, range);
|
||||||
|
|
||||||
|
let actual = {
|
||||||
|
let mut actual = before.to_string();
|
||||||
|
result.apply(&mut actual);
|
||||||
|
actual
|
||||||
|
};
|
||||||
|
let actual_cursor_pos = result
|
||||||
|
.apply_to_offset(before_cursor_pos)
|
||||||
|
.expect("cursor position is affected by the edit");
|
||||||
|
let actual = add_cursor(&actual, actual_cursor_pos);
|
||||||
|
assert_eq_text!(after, &actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -42,9 +42,6 @@ macro_rules! eprintln {
|
|||||||
mod expand_macro;
|
mod expand_macro;
|
||||||
mod ssr;
|
mod ssr;
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test_utils;
|
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ra_cfg::CfgOptions;
|
use ra_cfg::CfgOptions;
|
||||||
|
@ -983,8 +983,8 @@ fn test_rename(text: &str, new_name: &str, expected: &str) {
|
|||||||
if let Some(change) = source_change {
|
if let Some(change) = source_change {
|
||||||
for edit in change.info.source_file_edits {
|
for edit in change.info.source_file_edits {
|
||||||
file_id = Some(edit.file_id);
|
file_id = Some(edit.file_id);
|
||||||
for indel in edit.edit.as_indels() {
|
for indel in edit.edit.into_iter() {
|
||||||
text_edit_builder.replace(indel.delete, indel.insert.clone());
|
text_edit_builder.replace(indel.delete, indel.insert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
//! FIXME: write short doc here
|
|
||||||
|
|
||||||
use ra_syntax::{SourceFile, TextSize};
|
|
||||||
use ra_text_edit::TextEdit;
|
|
||||||
|
|
||||||
pub use test_utils::*;
|
|
||||||
|
|
||||||
pub fn check_action<F: Fn(&SourceFile, TextSize) -> Option<TextEdit>>(
|
|
||||||
before: &str,
|
|
||||||
after: &str,
|
|
||||||
f: F,
|
|
||||||
) {
|
|
||||||
let (before_cursor_pos, before) = extract_offset(before);
|
|
||||||
let file = SourceFile::parse(&before).ok().unwrap();
|
|
||||||
let result = f(&file, before_cursor_pos).expect("code action is not applicable");
|
|
||||||
let actual = {
|
|
||||||
let mut actual = before.to_string();
|
|
||||||
result.apply(&mut actual);
|
|
||||||
actual
|
|
||||||
};
|
|
||||||
let actual_cursor_pos =
|
|
||||||
result.apply_to_offset(before_cursor_pos).expect("cursor position is affected by the edit");
|
|
||||||
let actual = add_cursor(&actual, actual_cursor_pos);
|
|
||||||
assert_eq_text!(after, &actual);
|
|
||||||
}
|
|
@ -3,6 +3,7 @@
|
|||||||
//! `rust-analyzer` never mutates text itself and only sends diffs to clients,
|
//! `rust-analyzer` never mutates text itself and only sends diffs to clients,
|
||||||
//! so `TextEdit` is the ultimate representation of the work done by
|
//! so `TextEdit` is the ultimate representation of the work done by
|
||||||
//! rust-analyzer.
|
//! rust-analyzer.
|
||||||
|
use std::{slice, vec};
|
||||||
|
|
||||||
pub use text_size::{TextRange, TextSize};
|
pub use text_size::{TextRange, TextSize};
|
||||||
|
|
||||||
@ -71,17 +72,24 @@ pub(crate) fn from_indels(mut indels: Vec<Indel>) -> TextEdit {
|
|||||||
TextEdit { indels }
|
TextEdit { indels }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.indels.len()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.indels.is_empty()
|
self.indels.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
// FXME: impl IntoIter instead
|
pub fn iter(&self) -> slice::Iter<'_, Indel> {
|
||||||
pub fn as_indels(&self) -> &[Indel] {
|
self.indels.iter()
|
||||||
&self.indels
|
}
|
||||||
|
|
||||||
|
pub fn into_iter(self) -> vec::IntoIter<Indel> {
|
||||||
|
self.indels.into_iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply(&self, text: &mut String) {
|
pub fn apply(&self, text: &mut String) {
|
||||||
match self.indels.len() {
|
match self.len() {
|
||||||
0 => return,
|
0 => return,
|
||||||
1 => {
|
1 => {
|
||||||
self.indels[0].apply(text);
|
self.indels[0].apply(text);
|
||||||
|
@ -133,11 +133,7 @@ pub(crate) fn text_edit_vec(
|
|||||||
line_endings: LineEndings,
|
line_endings: LineEndings,
|
||||||
text_edit: TextEdit,
|
text_edit: TextEdit,
|
||||||
) -> Vec<lsp_types::TextEdit> {
|
) -> Vec<lsp_types::TextEdit> {
|
||||||
text_edit
|
text_edit.into_iter().map(|indel| self::text_edit(line_index, line_endings, indel)).collect()
|
||||||
.as_indels()
|
|
||||||
.iter()
|
|
||||||
.map(|it| self::text_edit(line_index, line_endings, it.clone()))
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn completion_item(
|
pub(crate) fn completion_item(
|
||||||
@ -150,7 +146,7 @@ pub(crate) fn completion_item(
|
|||||||
// LSP does not allow arbitrary edits in completion, so we have to do a
|
// LSP does not allow arbitrary edits in completion, so we have to do a
|
||||||
// non-trivial mapping here.
|
// non-trivial mapping here.
|
||||||
let source_range = completion_item.source_range();
|
let source_range = completion_item.source_range();
|
||||||
for indel in completion_item.text_edit().as_indels() {
|
for indel in completion_item.text_edit().iter() {
|
||||||
if indel.delete.contains_range(source_range) {
|
if indel.delete.contains_range(source_range) {
|
||||||
text_edit = Some(if indel.delete == source_range {
|
text_edit = Some(if indel.delete == source_range {
|
||||||
self::text_edit(line_index, line_endings, indel.clone())
|
self::text_edit(line_index, line_endings, indel.clone())
|
||||||
@ -459,8 +455,7 @@ pub(crate) fn snippet_text_document_edit(
|
|||||||
let line_endings = world.file_line_endings(source_file_edit.file_id);
|
let line_endings = world.file_line_endings(source_file_edit.file_id);
|
||||||
let edits = source_file_edit
|
let edits = source_file_edit
|
||||||
.edit
|
.edit
|
||||||
.as_indels()
|
.into_iter()
|
||||||
.iter()
|
|
||||||
.map(|it| snippet_text_edit(&line_index, line_endings, is_snippet, it.clone()))
|
.map(|it| snippet_text_edit(&line_index, line_endings, is_snippet, it.clone()))
|
||||||
.collect();
|
.collect();
|
||||||
Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits })
|
Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits })
|
||||||
|
Loading…
Reference in New Issue
Block a user