Merge #1041
1041: Add convenience functions to SourceChange for creating single edits r=matklad a=vipentti Fixes #1018 Co-authored-by: Ville Penttinen <villem.penttinen@gmail.com>
This commit is contained in:
commit
4132fbf3a0
@ -17,14 +17,9 @@ pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<Assist> {
|
||||
let file_id = frange.file_id;
|
||||
let file_edit = SourceFileEdit { file_id, edit: action.edit };
|
||||
let id = label.id;
|
||||
let change = SourceChange {
|
||||
label: label.label,
|
||||
source_file_edits: vec![file_edit],
|
||||
file_system_edits: vec![],
|
||||
cursor_position: action
|
||||
.cursor_position
|
||||
.map(|offset| FilePosition { offset, file_id }),
|
||||
};
|
||||
let change = SourceChange::source_file_edit(label.label, file_edit).with_cursor_opt(
|
||||
action.cursor_position.map(|offset| FilePosition { offset, file_id }),
|
||||
);
|
||||
Assist { id, change }
|
||||
})
|
||||
.collect()
|
||||
|
@ -71,12 +71,10 @@ fn check_unnecessary_braces_in_use_statement(
|
||||
range,
|
||||
message: format!("Unnecessary braces in use statement"),
|
||||
severity: Severity::WeakWarning,
|
||||
fix: Some(SourceChange {
|
||||
label: "Remove unnecessary braces".to_string(),
|
||||
source_file_edits: vec![SourceFileEdit { file_id, edit }],
|
||||
file_system_edits: Vec::new(),
|
||||
cursor_position: None,
|
||||
}),
|
||||
fix: Some(SourceChange::source_file_edit(
|
||||
"Remove unnecessary braces",
|
||||
SourceFileEdit { file_id, edit },
|
||||
)),
|
||||
});
|
||||
}
|
||||
|
||||
@ -119,12 +117,10 @@ fn check_struct_shorthand_initialization(
|
||||
range: named_field.syntax().range(),
|
||||
message: format!("Shorthand struct initialization"),
|
||||
severity: Severity::WeakWarning,
|
||||
fix: Some(SourceChange {
|
||||
label: "use struct shorthand initialization".to_string(),
|
||||
source_file_edits: vec![SourceFileEdit { file_id, edit }],
|
||||
file_system_edits: Vec::new(),
|
||||
cursor_position: None,
|
||||
}),
|
||||
fix: Some(SourceChange::source_file_edit(
|
||||
"use struct shorthand initialization",
|
||||
SourceFileEdit { file_id, edit },
|
||||
)),
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -144,12 +140,7 @@ fn check_module(
|
||||
Problem::UnresolvedModule { candidate } => {
|
||||
let create_file =
|
||||
FileSystemEdit::CreateFile { source_root, path: candidate.clone() };
|
||||
let fix = SourceChange {
|
||||
label: "create module".to_string(),
|
||||
source_file_edits: Vec::new(),
|
||||
file_system_edits: vec![create_file],
|
||||
cursor_position: None,
|
||||
};
|
||||
let fix = SourceChange::file_system_edit("create module", create_file);
|
||||
Diagnostic {
|
||||
range: name_node.range(),
|
||||
message: "unresolved module".to_string(),
|
||||
|
@ -97,6 +97,79 @@ pub struct SourceChange {
|
||||
pub cursor_position: Option<FilePosition>,
|
||||
}
|
||||
|
||||
impl SourceChange {
|
||||
/// Creates a new SourceChange with the given label
|
||||
/// from the edits.
|
||||
pub(crate) fn from_edits<L: Into<String>>(
|
||||
label: L,
|
||||
source_file_edits: Vec<SourceFileEdit>,
|
||||
file_system_edits: Vec<FileSystemEdit>,
|
||||
) -> Self {
|
||||
SourceChange {
|
||||
label: label.into(),
|
||||
source_file_edits,
|
||||
file_system_edits,
|
||||
cursor_position: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new SourceChange with the given label,
|
||||
/// containing only the given `SourceFileEdits`.
|
||||
pub(crate) fn source_file_edits<L: Into<String>>(label: L, edits: Vec<SourceFileEdit>) -> Self {
|
||||
SourceChange {
|
||||
label: label.into(),
|
||||
source_file_edits: edits,
|
||||
file_system_edits: vec![],
|
||||
cursor_position: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new SourceChange with the given label,
|
||||
/// containing only the given `FileSystemEdits`.
|
||||
pub(crate) fn file_system_edits<L: Into<String>>(label: L, edits: Vec<FileSystemEdit>) -> Self {
|
||||
SourceChange {
|
||||
label: label.into(),
|
||||
source_file_edits: vec![],
|
||||
file_system_edits: edits,
|
||||
cursor_position: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new SourceChange with the given label,
|
||||
/// containing only a single `SourceFileEdit`.
|
||||
pub(crate) fn source_file_edit<L: Into<String>>(label: L, edit: SourceFileEdit) -> Self {
|
||||
SourceChange::source_file_edits(label, vec![edit])
|
||||
}
|
||||
|
||||
/// Creates a new SourceChange with the given label
|
||||
/// from the given `FileId` and `TextEdit`
|
||||
pub(crate) fn source_file_edit_from<L: Into<String>>(
|
||||
label: L,
|
||||
file_id: FileId,
|
||||
edit: TextEdit,
|
||||
) -> Self {
|
||||
SourceChange::source_file_edit(label, SourceFileEdit { file_id, edit })
|
||||
}
|
||||
|
||||
/// Creates a new SourceChange with the given label
|
||||
/// from the given `FileId` and `TextEdit`
|
||||
pub(crate) fn file_system_edit<L: Into<String>>(label: L, edit: FileSystemEdit) -> Self {
|
||||
SourceChange::file_system_edits(label, vec![edit])
|
||||
}
|
||||
|
||||
/// Sets the cursor position to the given `FilePosition`
|
||||
pub(crate) fn with_cursor(mut self, cursor_position: FilePosition) -> Self {
|
||||
self.cursor_position = Some(cursor_position);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the cursor position to the given `FilePosition`
|
||||
pub(crate) fn with_cursor_opt(mut self, cursor_position: Option<FilePosition>) -> Self {
|
||||
self.cursor_position = cursor_position;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SourceFileEdit {
|
||||
pub file_id: FileId,
|
||||
@ -285,12 +358,7 @@ pub fn join_lines(&self, frange: FileRange) -> SourceChange {
|
||||
file_id: frange.file_id,
|
||||
edit: join_lines::join_lines(&file, frange.range),
|
||||
};
|
||||
SourceChange {
|
||||
label: "join lines".to_string(),
|
||||
source_file_edits: vec![file_edit],
|
||||
file_system_edits: vec![],
|
||||
cursor_position: None,
|
||||
}
|
||||
SourceChange::source_file_edit("join lines", file_edit)
|
||||
}
|
||||
|
||||
/// Returns an edit which should be applied when opening a new line, fixing
|
||||
@ -305,12 +373,10 @@ pub fn on_enter(&self, position: FilePosition) -> Option<SourceChange> {
|
||||
pub fn on_eq_typed(&self, position: FilePosition) -> Option<SourceChange> {
|
||||
let file = self.db.parse(position.file_id);
|
||||
let edit = typing::on_eq_typed(&file, position.offset)?;
|
||||
Some(SourceChange {
|
||||
label: "add semicolon".to_string(),
|
||||
source_file_edits: vec![SourceFileEdit { edit, file_id: position.file_id }],
|
||||
file_system_edits: vec![],
|
||||
cursor_position: None,
|
||||
})
|
||||
Some(SourceChange::source_file_edit(
|
||||
"add semicolon",
|
||||
SourceFileEdit { edit, file_id: position.file_id },
|
||||
))
|
||||
}
|
||||
|
||||
/// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately.
|
||||
|
@ -187,12 +187,7 @@ fn rename_mod(
|
||||
};
|
||||
source_file_edits.push(edit);
|
||||
|
||||
Some(SourceChange {
|
||||
label: "rename".to_string(),
|
||||
source_file_edits,
|
||||
file_system_edits,
|
||||
cursor_position: None,
|
||||
})
|
||||
Some(SourceChange::from_edits("rename", source_file_edits, file_system_edits))
|
||||
}
|
||||
|
||||
fn rename_reference(
|
||||
@ -211,12 +206,7 @@ fn rename_reference(
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(SourceChange {
|
||||
label: "rename".to_string(),
|
||||
source_file_edits: edit,
|
||||
file_system_edits: Vec::new(),
|
||||
cursor_position: None,
|
||||
})
|
||||
Some(SourceChange::source_file_edits("rename", edit))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -31,12 +31,14 @@ pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<Sour
|
||||
let cursor_position = position.offset + TextUnit::of_str(&inserted);
|
||||
let mut edit = TextEditBuilder::default();
|
||||
edit.insert(position.offset, inserted);
|
||||
Some(SourceChange {
|
||||
label: "on enter".to_string(),
|
||||
source_file_edits: vec![SourceFileEdit { edit: edit.finish(), file_id: position.file_id }],
|
||||
file_system_edits: vec![],
|
||||
cursor_position: Some(FilePosition { offset: cursor_position, file_id: position.file_id }),
|
||||
})
|
||||
|
||||
Some(
|
||||
SourceChange::source_file_edit(
|
||||
"on enter",
|
||||
SourceFileEdit { edit: edit.finish(), file_id: position.file_id },
|
||||
)
|
||||
.with_cursor(FilePosition { offset: cursor_position, file_id: position.file_id }),
|
||||
)
|
||||
}
|
||||
|
||||
fn node_indent<'a>(file: &'a SourceFile, node: &SyntaxNode) -> Option<&'a str> {
|
||||
@ -110,16 +112,14 @@ pub(crate) fn on_dot_typed(db: &RootDatabase, position: FilePosition) -> Option<
|
||||
TextRange::from_to(position.offset - current_indent_len, position.offset),
|
||||
target_indent.into(),
|
||||
);
|
||||
let res = SourceChange {
|
||||
label: "reindent dot".to_string(),
|
||||
source_file_edits: vec![SourceFileEdit { edit: edit.finish(), file_id: position.file_id }],
|
||||
file_system_edits: vec![],
|
||||
cursor_position: Some(FilePosition {
|
||||
|
||||
let res = SourceChange::source_file_edit_from("reindent dot", position.file_id, edit.finish())
|
||||
.with_cursor(FilePosition {
|
||||
offset: position.offset + target_indent_len - current_indent_len
|
||||
+ TextUnit::of_char('.'),
|
||||
file_id: position.file_id,
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
Some(res)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user