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)
}
pub(crate) fn add_assist_group(
self,
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 add_assist_group(self, group_name: impl Into<String>) -> AssistGroup<'a> {
AssistGroup { ctx: self, group_name: group_name.into(), assists: Vec::new() }
}
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)]
pub(crate) struct ActionBuilder {
edit: TextEditBuilder,
@ -164,11 +203,6 @@ pub(crate) struct 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.
pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) {
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_syntax::{
ast::{self, AstNode},
SyntaxNode,
};
use ra_syntax::ast::{self, AstNode};
use crate::{
assist_ctx::{ActionBuilder, Assist, AssistCtx},
assist_ctx::{Assist, AssistCtx},
insert_use_statement, AssistId,
};
use std::collections::BTreeSet;
@ -67,19 +63,18 @@ pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> {
return None;
}
ctx.add_assist_group(AssistId("auto_import"), format!("Import {}", name_to_import), || {
proposed_imports
.into_iter()
.map(|import| import_to_action(import, &position, &path_to_import_syntax))
.collect()
})
}
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
let mut group = ctx.add_assist_group(format!("Import {}", name_to_import));
for import in proposed_imports {
group.add_assist(AssistId("auto_import"), format!("Import `{}`", &import), |edit| {
insert_use_statement(
&position,
path_to_import_syntax,
&import,
edit.text_edit_builder(),
);
});
}
group.finish()
}
#[cfg(test)]