Slightly simpler API for groups

This commit is contained in:
Aleksey Kladov 2020-02-09 14:30:27 +01:00
parent aa5f80aed1
commit fb99831cb0
2 changed files with 77 additions and 48 deletions

View File

@ -98,30 +98,8 @@ impl<'a> AssistCtx<'a> {
Some(assist) Some(assist)
} }
pub(crate) fn add_assist_group( pub(crate) fn add_assist_group(self, group_name: impl Into<String>) -> AssistGroup<'a> {
self, AssistGroup { ctx: self, group_name: group_name.into(), assists: Vec::new() }
id: AssistId,
label: impl Into<String>,
f: impl FnOnce() -> Vec<ActionBuilder>,
) -> Option<Assist> {
let label = AssistLabel::new(label.into(), id);
let assist = if self.should_compute_edit {
let actions = f();
assert!(!actions.is_empty(), "Assist cannot have no");
Assist::Resolved {
assist: ResolvedAssist {
label,
action_data: Either::Right(
actions.into_iter().map(ActionBuilder::build).collect(),
),
},
}
} else {
Assist::Unresolved { label }
};
Some(assist)
} }
pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken> { pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken> {
@ -155,6 +133,67 @@ impl<'a> AssistCtx<'a> {
} }
} }
pub(crate) struct AssistGroup<'a> {
ctx: AssistCtx<'a>,
group_name: String,
assists: Vec<Assist>,
}
impl<'a> AssistGroup<'a> {
pub(crate) fn add_assist(
&mut self,
id: AssistId,
label: impl Into<String>,
f: impl FnOnce(&mut ActionBuilder),
) {
let label = AssistLabel::new(label.into(), id);
let assist = if self.ctx.should_compute_edit {
let action = {
let mut edit = ActionBuilder::default();
f(&mut edit);
edit.build()
};
Assist::Resolved { assist: ResolvedAssist { label, action_data: Either::Left(action) } }
} else {
Assist::Unresolved { label }
};
self.assists.push(assist)
}
pub(crate) fn finish(self) -> Option<Assist> {
assert!(!self.assists.is_empty());
let mut label = match &self.assists[0] {
Assist::Unresolved { label } => label.clone(),
Assist::Resolved { assist } => assist.label.clone(),
};
label.label = self.group_name;
let assist = if self.ctx.should_compute_edit {
Assist::Resolved {
assist: ResolvedAssist {
label,
action_data: Either::Right(
self.assists
.into_iter()
.map(|assist| match assist {
Assist::Resolved {
assist:
ResolvedAssist { label: _, action_data: Either::Left(it) },
} => it,
_ => unreachable!(),
})
.collect(),
),
},
}
} else {
Assist::Unresolved { label }
};
Some(assist)
}
}
#[derive(Default)] #[derive(Default)]
pub(crate) struct ActionBuilder { pub(crate) struct ActionBuilder {
edit: TextEditBuilder, edit: TextEditBuilder,
@ -164,11 +203,6 @@ pub(crate) struct ActionBuilder {
} }
impl ActionBuilder { impl ActionBuilder {
/// Adds a custom label to the action, if it needs to be different from the assist label
pub(crate) fn label(&mut self, label: impl Into<String>) {
self.label = Some(label.into())
}
/// Replaces specified `range` of text with a given string. /// Replaces specified `range` of text with a given string.
pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) { pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) {
self.edit.replace(range, replace_with.into()) self.edit.replace(range, replace_with.into())

View File

@ -1,12 +1,8 @@
use hir::ModPath;
use ra_ide_db::imports_locator::ImportsLocator; use ra_ide_db::imports_locator::ImportsLocator;
use ra_syntax::{ use ra_syntax::ast::{self, AstNode};
ast::{self, AstNode},
SyntaxNode,
};
use crate::{ use crate::{
assist_ctx::{ActionBuilder, Assist, AssistCtx}, assist_ctx::{Assist, AssistCtx},
insert_use_statement, AssistId, insert_use_statement, AssistId,
}; };
use std::collections::BTreeSet; use std::collections::BTreeSet;
@ -67,19 +63,18 @@ pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> {
return None; return None;
} }
ctx.add_assist_group(AssistId("auto_import"), format!("Import {}", name_to_import), || { let mut group = ctx.add_assist_group(format!("Import {}", name_to_import));
proposed_imports for import in proposed_imports {
.into_iter() group.add_assist(AssistId("auto_import"), format!("Import `{}`", &import), |edit| {
.map(|import| import_to_action(import, &position, &path_to_import_syntax)) insert_use_statement(
.collect() &position,
}) path_to_import_syntax,
&import,
edit.text_edit_builder(),
);
});
} }
group.finish()
fn import_to_action(import: ModPath, position: &SyntaxNode, anchor: &SyntaxNode) -> ActionBuilder {
let mut action_builder = ActionBuilder::default();
action_builder.label(format!("Import `{}`", &import));
insert_use_statement(position, anchor, &import, action_builder.text_edit_builder());
action_builder
} }
#[cfg(test)] #[cfg(test)]