};
use ra_text_edit::TextEditBuilder;
-use crate::{AssistId, AssistLabel, GroupLabel, ResolvedAssist};
+use crate::{Assist, AssistId, GroupLabel, ResolvedAssist};
/// `AssistContext` allows to apply an assist or check if it could be applied.
///
find_node_at_offset(self.source_file.syntax(), self.offset())
}
pub(crate) fn find_node_at_offset_with_descend<N: AstNode>(&self) -> Option<N> {
- self.sema
- .find_node_at_offset_with_descend(self.source_file.syntax(), self.frange.range.start())
+ self.sema.find_node_at_offset_with_descend(self.source_file.syntax(), self.offset())
}
pub(crate) fn covering_element(&self) -> SyntaxElement {
find_covering_element(self.source_file.syntax(), self.frange.range)
pub(crate) struct Assists {
resolve: bool,
file: FileId,
- buf: Vec<(AssistLabel, Option<SourceChange>)>,
+ buf: Vec<(Assist, Option<SourceChange>)>,
}
impl Assists {
Assists { resolve: false, file: ctx.frange.file_id, buf: Vec::new() }
}
- pub(crate) fn finish_unresolved(self) -> Vec<AssistLabel> {
+ pub(crate) fn finish_unresolved(self) -> Vec<Assist> {
assert!(!self.resolve);
self.finish()
.into_iter()
assert!(self.resolve);
self.finish()
.into_iter()
- .map(|(label, edit)| ResolvedAssist { label, source_change: edit.unwrap() })
+ .map(|(label, edit)| ResolvedAssist { assist: label, source_change: edit.unwrap() })
.collect()
}
target: TextRange,
f: impl FnOnce(&mut AssistBuilder),
) -> Option<()> {
- let label = AssistLabel::new(id, label.into(), None, target);
+ let label = Assist::new(id, label.into(), None, target);
self.add_impl(label, f)
}
pub(crate) fn add_group(
target: TextRange,
f: impl FnOnce(&mut AssistBuilder),
) -> Option<()> {
- let label = AssistLabel::new(id, label.into(), Some(group.clone()), target);
+ let label = Assist::new(id, label.into(), Some(group.clone()), target);
self.add_impl(label, f)
}
- fn add_impl(&mut self, label: AssistLabel, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> {
+ fn add_impl(&mut self, label: Assist, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> {
let change_label = label.label.clone();
let source_change = if self.resolve {
let mut builder = AssistBuilder::new(self.file);
Some(())
}
- fn finish(mut self) -> Vec<(AssistLabel, Option<SourceChange>)> {
+ fn finish(mut self) -> Vec<(Assist, Option<SourceChange>)> {
self.buf.sort_by_key(|(label, _edit)| label.target.len());
self.buf
}
}
then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?;
- let cursor_position = ctx.frange.range.start();
+ let cursor_position = ctx.offset();
let target = if_expr.syntax().text_range();
acc.add(AssistId("convert_to_guarded_return"), "Convert to guarded return", target, |edit| {
pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
let tree: ast::UseTree = ctx.find_node_at_offset()?;
let mut rewriter = SyntaxRewriter::default();
- let mut offset = ctx.frange.range.start();
+ let mut offset = ctx.offset();
if let Some(use_item) = tree.syntax().parent().and_then(ast::UseItem::cast) {
let (merged, to_delete) = next_prev()
InExpr(TextSize),
InPat(TextSize),
}
- let cursor_pos = ctx.frange.range.start();
+ let cursor_pos = ctx.offset();
let cursor_pos = if current_expr.syntax().text_range().contains(cursor_pos) {
CursorPos::InExpr(current_text_range.end() - cursor_pos)
} else {
if new_tree == use_tree {
return None;
}
- let cursor = ctx.frange.range.start();
+ let cursor = ctx.offset();
let target = colon_colon.text_range();
acc.add(AssistId("split_import"), "Split import", target, |edit| {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AssistId(pub &'static str);
+#[derive(Clone, Debug)]
+pub struct GroupLabel(pub String);
+
#[derive(Debug, Clone)]
-pub struct AssistLabel {
+pub struct Assist {
pub id: AssistId,
/// Short description of the assist, as shown in the UI.
pub label: String,
pub target: TextRange,
}
-#[derive(Clone, Debug)]
-pub struct GroupLabel(pub String);
+#[derive(Debug, Clone)]
+pub struct ResolvedAssist {
+ pub assist: Assist,
+ pub source_change: SourceChange,
+}
+
+impl Assist {
+ /// Return all the assists applicable at the given position.
+ ///
+ /// Assists are returned in the "unresolved" state, that is only labels are
+ /// returned, without actual edits.
+ pub fn unresolved(db: &RootDatabase, range: FileRange) -> Vec<Assist> {
+ let sema = Semantics::new(db);
+ let ctx = AssistContext::new(sema, range);
+ let mut acc = Assists::new_unresolved(&ctx);
+ handlers::all().iter().for_each(|handler| {
+ handler(&mut acc, &ctx);
+ });
+ acc.finish_unresolved()
+ }
+
+ /// Return all the assists applicable at the given position.
+ ///
+ /// Assists are returned in the "resolved" state, that is with edit fully
+ /// computed.
+ pub fn resolved(db: &RootDatabase, range: FileRange) -> Vec<ResolvedAssist> {
+ let sema = Semantics::new(db);
+ let ctx = AssistContext::new(sema, range);
+ let mut acc = Assists::new_resolved(&ctx);
+ handlers::all().iter().for_each(|handler| {
+ handler(&mut acc, &ctx);
+ });
+ acc.finish_resolved()
+ }
-impl AssistLabel {
pub(crate) fn new(
id: AssistId,
label: String,
group: Option<GroupLabel>,
target: TextRange,
- ) -> AssistLabel {
+ ) -> Assist {
// FIXME: make fields private, so that this invariant can't be broken
assert!(label.starts_with(|c: char| c.is_uppercase()));
- AssistLabel { id, label, group, target }
+ Assist { id, label, group, target }
}
}
-#[derive(Debug, Clone)]
-pub struct ResolvedAssist {
- pub label: AssistLabel,
- pub source_change: SourceChange,
-}
-
-/// Return all the assists applicable at the given position.
-///
-/// Assists are returned in the "unresolved" state, that is only labels are
-/// returned, without actual edits.
-pub fn unresolved_assists(db: &RootDatabase, range: FileRange) -> Vec<AssistLabel> {
- let sema = Semantics::new(db);
- let ctx = AssistContext::new(sema, range);
- let mut acc = Assists::new_unresolved(&ctx);
- handlers::all().iter().for_each(|handler| {
- handler(&mut acc, &ctx);
- });
- acc.finish_unresolved()
-}
-
-/// Return all the assists applicable at the given position.
-///
-/// Assists are returned in the "resolved" state, that is with edit fully
-/// computed.
-pub fn resolved_assists(db: &RootDatabase, range: FileRange) -> Vec<ResolvedAssist> {
- let sema = Semantics::new(db);
- let ctx = AssistContext::new(sema, range);
- let mut acc = Assists::new_resolved(&ctx);
- handlers::all().iter().for_each(|handler| {
- handler(&mut acc, &ctx);
- });
- acc.finish_resolved()
-}
-
mod handlers {
use crate::{AssistContext, Assists};
RangeOrOffset,
};
-use crate::{handlers::Handler, resolved_assists, AssistContext, Assists};
+use crate::{handlers::Handler, Assist, AssistContext, Assists};
pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
let (mut db, file_id) = RootDatabase::with_single_file(text);
let (db, file_id) = crate::tests::with_single_file(&before);
let frange = FileRange { file_id, range: selection.into() };
- let mut assist = resolved_assists(&db, frange)
+ let mut assist = Assist::resolved(&db, frange)
.into_iter()
- .find(|assist| assist.label.id.0 == assist_id)
+ .find(|assist| assist.assist.id.0 == assist_id)
.unwrap_or_else(|| {
panic!(
"\n\nAssist is not applicable: {}\nAvailable assists: {}",
assist_id,
- resolved_assists(&db, frange)
+ Assist::resolved(&db, frange)
.into_iter()
- .map(|assist| assist.label.id.0)
+ .map(|assist| assist.assist.id.0)
.collect::<Vec<_>>()
.join(", ")
)
assert_eq_text!(after, &actual);
}
(Some(assist), ExpectedResult::Target(target)) => {
- let range = assist.label.target;
+ let range = assist.assist.target;
assert_eq_text!(&text_without_caret[range], target);
}
(Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"),
let (before_cursor_pos, before) = extract_offset(before);
let (db, file_id) = with_single_file(&before);
let frange = FileRange { file_id, range: TextRange::empty(before_cursor_pos) };
- let assists = resolved_assists(&db, frange);
+ let assists = Assist::resolved(&db, frange);
let mut assists = assists.iter();
assert_eq!(
- assists.next().expect("expected assist").label.label,
+ assists.next().expect("expected assist").assist.label,
"Change visibility to pub(crate)"
);
- assert_eq!(assists.next().expect("expected assist").label.label, "Add `#[derive]`");
+ assert_eq!(assists.next().expect("expected assist").assist.label, "Add `#[derive]`");
}
#[test]
let (range, before) = extract_range(before);
let (db, file_id) = with_single_file(&before);
let frange = FileRange { file_id, range };
- let assists = resolved_assists(&db, frange);
+ let assists = Assist::resolved(&db, frange);
let mut assists = assists.iter();
- assert_eq!(assists.next().expect("expected assist").label.label, "Extract into variable");
- assert_eq!(assists.next().expect("expected assist").label.label, "Replace with match");
+ assert_eq!(assists.next().expect("expected assist").assist.label, "Extract into variable");
+ assert_eq!(assists.next().expect("expected assist").assist.label, "Replace with match");
}
/// position.
pub fn assists(&self, frange: FileRange) -> Cancelable<Vec<Assist>> {
self.with_db(|db| {
- ra_assists::resolved_assists(db, frange)
+ ra_assists::Assist::resolved(db, frange)
.into_iter()
.map(|assist| Assist {
- id: assist.label.id,
- label: assist.label.label,
- group_label: assist.label.group.map(|it| it.0),
+ id: assist.assist.id,
+ label: assist.assist.label,
+ group_label: assist.assist.group.map(|it| it.0),
source_change: assist.source_change,
})
.collect()