4804: Simplify API r=matklad a=matklad



bors r+
🤖

Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2020-06-08 22:03:20 +00:00 committed by GitHub
commit 733ef3163c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 60 additions and 111 deletions

View file

@ -1,5 +1,7 @@
//! See `AssistContext` //! See `AssistContext`
use std::mem;
use algo::find_covering_element; use algo::find_covering_element;
use hir::Semantics; use hir::Semantics;
use ra_db::{FileId, FileRange}; use ra_db::{FileId, FileRange};
@ -19,7 +21,6 @@ use crate::{
assist_config::{AssistConfig, SnippetCap}, assist_config::{AssistConfig, SnippetCap},
Assist, AssistId, GroupLabel, ResolvedAssist, Assist, AssistId, GroupLabel, ResolvedAssist,
}; };
use rustc_hash::FxHashMap;
/// `AssistContext` allows to apply an assist or check if it could be applied. /// `AssistContext` allows to apply an assist or check if it could be applied.
/// ///
@ -139,16 +140,6 @@ impl Assists {
let label = Assist::new(id, label.into(), None, target); let label = Assist::new(id, label.into(), None, target);
self.add_impl(label, f) self.add_impl(label, f)
} }
pub(crate) fn add_in_multiple_files(
&mut self,
id: AssistId,
label: impl Into<String>,
target: TextRange,
f: impl FnOnce(&mut AssistDirector),
) -> Option<()> {
let label = Assist::new(id, label.into(), None, target);
self.add_impl_multiple_files(label, f)
}
pub(crate) fn add_group( pub(crate) fn add_group(
&mut self, &mut self,
group: &GroupLabel, group: &GroupLabel,
@ -173,31 +164,6 @@ impl Assists {
Some(()) Some(())
} }
fn add_impl_multiple_files(
&mut self,
label: Assist,
f: impl FnOnce(&mut AssistDirector),
) -> Option<()> {
if !self.resolve {
self.buf.push((label, None));
return None;
}
let mut director = AssistDirector::default();
f(&mut director);
let changes = director.finish();
let file_edits: Vec<SourceFileEdit> =
changes.into_iter().map(|mut change| change.source_file_edits.pop().unwrap()).collect();
let source_change = SourceChange {
source_file_edits: file_edits,
file_system_edits: vec![],
is_snippet: false,
};
self.buf.push((label, Some(source_change)));
Some(())
}
fn finish(mut self) -> Vec<(Assist, Option<SourceChange>)> { fn finish(mut self) -> Vec<(Assist, Option<SourceChange>)> {
self.buf.sort_by_key(|(label, _edit)| label.target.len()); self.buf.sort_by_key(|(label, _edit)| label.target.len());
self.buf self.buf
@ -206,13 +172,32 @@ impl Assists {
pub(crate) struct AssistBuilder { pub(crate) struct AssistBuilder {
edit: TextEditBuilder, edit: TextEditBuilder,
file: FileId, file_id: FileId,
is_snippet: bool, is_snippet: bool,
edits: Vec<SourceFileEdit>,
} }
impl AssistBuilder { impl AssistBuilder {
pub(crate) fn new(file: FileId) -> AssistBuilder { pub(crate) fn new(file_id: FileId) -> AssistBuilder {
AssistBuilder { edit: TextEditBuilder::default(), file, is_snippet: false } AssistBuilder {
edit: TextEditBuilder::default(),
file_id,
is_snippet: false,
edits: Vec::new(),
}
}
pub(crate) fn edit_file(&mut self, file_id: FileId) {
self.file_id = file_id;
}
fn commit(&mut self) {
let edit = mem::take(&mut self.edit).finish();
if !edit.is_empty() {
let new_edit = SourceFileEdit { file_id: self.file_id, edit };
assert!(!self.edits.iter().any(|it| it.file_id == new_edit.file_id));
self.edits.push(new_edit);
}
} }
/// Remove specified `range` of text. /// Remove specified `range` of text.
@ -270,48 +255,18 @@ impl AssistBuilder {
algo::diff(&node, &new).into_text_edit(&mut self.edit) algo::diff(&node, &new).into_text_edit(&mut self.edit)
} }
// FIXME: better API
pub(crate) fn set_file(&mut self, assist_file: FileId) {
self.file = assist_file;
}
// FIXME: kill this API // FIXME: kill this API
/// Get access to the raw `TextEditBuilder`. /// Get access to the raw `TextEditBuilder`.
pub(crate) fn text_edit_builder(&mut self) -> &mut TextEditBuilder { pub(crate) fn text_edit_builder(&mut self) -> &mut TextEditBuilder {
&mut self.edit &mut self.edit
} }
fn finish(self) -> SourceChange { fn finish(mut self) -> SourceChange {
let edit = self.edit.finish(); self.commit();
let source_file_edit = SourceFileEdit { file_id: self.file, edit }; let mut res: SourceChange = mem::take(&mut self.edits).into();
let mut res: SourceChange = source_file_edit.into();
if self.is_snippet { if self.is_snippet {
res.is_snippet = true; res.is_snippet = true;
} }
res res
} }
} }
pub(crate) struct AssistDirector {
builders: FxHashMap<FileId, AssistBuilder>,
}
impl AssistDirector {
pub(crate) fn perform(&mut self, file_id: FileId, f: impl FnOnce(&mut AssistBuilder)) {
let mut builder = self.builders.entry(file_id).or_insert(AssistBuilder::new(file_id));
f(&mut builder);
}
fn finish(self) -> Vec<SourceChange> {
self.builders
.into_iter()
.map(|(_, builder)| builder.finish())
.collect::<Vec<SourceChange>>()
}
}
impl Default for AssistDirector {
fn default() -> Self {
AssistDirector { builders: FxHashMap::default() }
}
}

View file

@ -64,7 +64,7 @@ pub(crate) fn add_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
let target = call.syntax().text_range(); let target = call.syntax().text_range();
acc.add(AssistId("add_function"), "Add function", target, |builder| { acc.add(AssistId("add_function"), "Add function", target, |builder| {
let function_template = function_builder.render(); let function_template = function_builder.render();
builder.set_file(function_template.file); builder.edit_file(function_template.file);
let new_fn = function_template.to_string(ctx.config.snippet_cap); let new_fn = function_template.to_string(ctx.config.snippet_cap);
match ctx.config.snippet_cap { match ctx.config.snippet_cap {
Some(cap) => builder.insert_snippet(cap, function_template.insert_offset, new_fn), Some(cap) => builder.insert_snippet(cap, function_template.insert_offset, new_fn),

View file

@ -1,21 +1,18 @@
use ra_ide_db::{defs::Definition, search::Reference, RootDatabase};
use ra_syntax::{
algo::find_node_at_offset,
ast::{self, AstNode, NameOwner},
SourceFile, SyntaxNode, TextRange, TextSize,
};
use crate::{
assist_context::{AssistBuilder, AssistDirector},
utils::insert_use_statement,
AssistContext, AssistId, Assists,
};
use ast::{ArgListOwner, VisibilityOwner};
use hir::{EnumVariant, Module, ModuleDef, Name}; use hir::{EnumVariant, Module, ModuleDef, Name};
use ra_db::FileId; use ra_db::FileId;
use ra_fmt::leading_indent; use ra_fmt::leading_indent;
use ra_ide_db::{defs::Definition, search::Reference, RootDatabase};
use ra_syntax::{
algo::find_node_at_offset,
ast::{self, ArgListOwner, AstNode, NameOwner, VisibilityOwner},
SourceFile, SyntaxNode, TextRange, TextSize,
};
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use crate::{
assist_context::AssistBuilder, utils::insert_use_statement, AssistContext, AssistId, Assists,
};
// Assist: extract_struct_from_enum_variant // Assist: extract_struct_from_enum_variant
// //
// Extracts a struct from enum variant. // Extracts a struct from enum variant.
@ -50,11 +47,11 @@ pub(crate) fn extract_struct_from_enum_variant(
let enum_module_def = ModuleDef::from(enum_hir); let enum_module_def = ModuleDef::from(enum_hir);
let current_module = enum_hir.module(ctx.db); let current_module = enum_hir.module(ctx.db);
let target = variant.syntax().text_range(); let target = variant.syntax().text_range();
acc.add_in_multiple_files( acc.add(
AssistId("extract_struct_from_enum_variant"), AssistId("extract_struct_from_enum_variant"),
"Extract struct from enum variant", "Extract struct from enum variant",
target, target,
|edit| { |builder| {
let definition = Definition::ModuleDef(ModuleDef::EnumVariant(variant_hir)); let definition = Definition::ModuleDef(ModuleDef::EnumVariant(variant_hir));
let res = definition.find_usages(&ctx.db, None); let res = definition.find_usages(&ctx.db, None);
let start_offset = variant.parent_enum().syntax().text_range().start(); let start_offset = variant.parent_enum().syntax().text_range().start();
@ -64,7 +61,7 @@ pub(crate) fn extract_struct_from_enum_variant(
let source_file = ctx.sema.parse(reference.file_range.file_id); let source_file = ctx.sema.parse(reference.file_range.file_id);
update_reference( update_reference(
ctx, ctx,
edit, builder,
reference, reference,
&source_file, &source_file,
&enum_module_def, &enum_module_def,
@ -73,7 +70,7 @@ pub(crate) fn extract_struct_from_enum_variant(
); );
} }
extract_struct_def( extract_struct_def(
edit, builder,
enum_ast.syntax(), enum_ast.syntax(),
&variant_name, &variant_name,
&field_list.to_string(), &field_list.to_string(),
@ -82,7 +79,7 @@ pub(crate) fn extract_struct_from_enum_variant(
&visibility, &visibility,
); );
let list_range = field_list.syntax().text_range(); let list_range = field_list.syntax().text_range();
update_variant(edit, &variant_name, ctx.frange.file_id, list_range); update_variant(builder, &variant_name, ctx.frange.file_id, list_range);
}, },
) )
} }
@ -115,7 +112,7 @@ fn insert_import(
} }
fn extract_struct_def( fn extract_struct_def(
edit: &mut AssistDirector, builder: &mut AssistBuilder,
enum_ast: &SyntaxNode, enum_ast: &SyntaxNode,
variant_name: &str, variant_name: &str,
variant_list: &str, variant_list: &str,
@ -142,14 +139,13 @@ fn extract_struct_def(
list_with_visibility(variant_list), list_with_visibility(variant_list),
indent indent
); );
edit.perform(file_id, |builder| { builder.edit_file(file_id);
builder.insert(start_offset, struct_def); builder.insert(start_offset, struct_def);
});
Some(()) Some(())
} }
fn update_variant( fn update_variant(
edit: &mut AssistDirector, builder: &mut AssistBuilder,
variant_name: &str, variant_name: &str,
file_id: FileId, file_id: FileId,
list_range: TextRange, list_range: TextRange,
@ -158,15 +154,14 @@ fn update_variant(
list_range.start().checked_add(TextSize::from(1))?, list_range.start().checked_add(TextSize::from(1))?,
list_range.end().checked_sub(TextSize::from(1))?, list_range.end().checked_sub(TextSize::from(1))?,
); );
edit.perform(file_id, |builder| { builder.edit_file(file_id);
builder.replace(inside_variant_range, variant_name); builder.replace(inside_variant_range, variant_name);
});
Some(()) Some(())
} }
fn update_reference( fn update_reference(
ctx: &AssistContext, ctx: &AssistContext,
edit: &mut AssistDirector, builder: &mut AssistBuilder,
reference: Reference, reference: Reference,
source_file: &SourceFile, source_file: &SourceFile,
enum_module_def: &ModuleDef, enum_module_def: &ModuleDef,
@ -186,16 +181,15 @@ fn update_reference(
list_range.start().checked_add(TextSize::from(1))?, list_range.start().checked_add(TextSize::from(1))?,
list_range.end().checked_sub(TextSize::from(1))?, list_range.end().checked_sub(TextSize::from(1))?,
); );
edit.perform(reference.file_range.file_id, |builder| { builder.edit_file(reference.file_range.file_id);
if !visited_modules_set.contains(&module) { if !visited_modules_set.contains(&module) {
if insert_import(ctx, builder, &path_expr, &module, enum_module_def, variant_hir_name) if insert_import(ctx, builder, &path_expr, &module, enum_module_def, variant_hir_name)
.is_some() .is_some()
{ {
visited_modules_set.insert(module); visited_modules_set.insert(module);
}
} }
builder.replace(inside_list_range, format!("{}{}", segment, list)); }
}); builder.replace(inside_list_range, format!("{}{}", segment, list));
Some(()) Some(())
} }

View file

@ -63,7 +63,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext) -> O
}; };
acc.add(AssistId("fix_visibility"), assist_label, target, |builder| { acc.add(AssistId("fix_visibility"), assist_label, target, |builder| {
builder.set_file(target_file); builder.edit_file(target_file);
match ctx.config.snippet_cap { match ctx.config.snippet_cap {
Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)),
None => builder.insert(offset, format!("{} ", missing_visibility)), None => builder.insert(offset, format!("{} ", missing_visibility)),
@ -106,7 +106,7 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) ->
format!("Change visibility of {}.{} to {}", parent_name, target_name, missing_visibility); format!("Change visibility of {}.{} to {}", parent_name, target_name, missing_visibility);
acc.add(AssistId("fix_visibility"), assist_label, target, |builder| { acc.add(AssistId("fix_visibility"), assist_label, target, |builder| {
builder.set_file(target_file); builder.edit_file(target_file);
match ctx.config.snippet_cap { match ctx.config.snippet_cap {
Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)),
None => builder.insert(offset, format!("{} ", missing_visibility)), None => builder.insert(offset, format!("{} ", missing_visibility)),