diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs index 203ad12738..3085c4330c 100644 --- a/crates/ra_assists/src/assist_context.rs +++ b/crates/ra_assists/src/assist_context.rs @@ -15,7 +15,7 @@ use ra_syntax::{ }; 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. /// @@ -76,8 +76,7 @@ impl<'a> AssistContext<'a> { find_node_at_offset(self.source_file.syntax(), self.offset()) } pub(crate) fn find_node_at_offset_with_descend(&self) -> Option { - 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) @@ -91,7 +90,7 @@ impl<'a> AssistContext<'a> { pub(crate) struct Assists { resolve: bool, file: FileId, - buf: Vec<(AssistLabel, Option)>, + buf: Vec<(Assist, Option)>, } impl Assists { @@ -102,7 +101,7 @@ impl Assists { Assists { resolve: false, file: ctx.frange.file_id, buf: Vec::new() } } - pub(crate) fn finish_unresolved(self) -> Vec { + pub(crate) fn finish_unresolved(self) -> Vec { assert!(!self.resolve); self.finish() .into_iter() @@ -117,7 +116,7 @@ impl Assists { 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() } @@ -128,7 +127,7 @@ impl Assists { 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( @@ -139,10 +138,10 @@ impl Assists { 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); @@ -156,7 +155,7 @@ impl Assists { Some(()) } - fn finish(mut self) -> Vec<(AssistLabel, Option)> { + fn finish(mut self) -> Vec<(Assist, Option)> { self.buf.sort_by_key(|(label, _edit)| label.target.len()); self.buf } diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs index ccf91797c6..810784ad57 100644 --- a/crates/ra_assists/src/handlers/early_return.rs +++ b/crates/ra_assists/src/handlers/early_return.rs @@ -93,7 +93,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) } 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| { diff --git a/crates/ra_assists/src/handlers/merge_imports.rs b/crates/ra_assists/src/handlers/merge_imports.rs index 8e1d933123..ac3e53c273 100644 --- a/crates/ra_assists/src/handlers/merge_imports.rs +++ b/crates/ra_assists/src/handlers/merge_imports.rs @@ -26,7 +26,7 @@ use crate::{ 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() diff --git a/crates/ra_assists/src/handlers/merge_match_arms.rs b/crates/ra_assists/src/handlers/merge_match_arms.rs index cfe4df47bc..d4e38aa6a5 100644 --- a/crates/ra_assists/src/handlers/merge_match_arms.rs +++ b/crates/ra_assists/src/handlers/merge_match_arms.rs @@ -45,7 +45,7 @@ pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option 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 { diff --git a/crates/ra_assists/src/handlers/split_import.rs b/crates/ra_assists/src/handlers/split_import.rs index 159033731f..b2757e50ce 100644 --- a/crates/ra_assists/src/handlers/split_import.rs +++ b/crates/ra_assists/src/handlers/split_import.rs @@ -26,7 +26,7 @@ pub(crate) fn split_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> 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| { diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 0116137627..b6dc7cb1bf 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs @@ -29,8 +29,11 @@ pub(crate) use crate::assist_context::{AssistContext, Assists}; #[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, @@ -40,56 +43,53 @@ pub struct AssistLabel { 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 { + 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 { + 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, 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 { - 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 { - 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}; diff --git a/crates/ra_assists/src/tests.rs b/crates/ra_assists/src/tests.rs index 45b2d9733e..a3eacb8f11 100644 --- a/crates/ra_assists/src/tests.rs +++ b/crates/ra_assists/src/tests.rs @@ -11,7 +11,7 @@ use test_utils::{ 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); @@ -41,16 +41,16 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) { 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::>() .join(", ") ) @@ -119,7 +119,7 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult) { 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!"), @@ -136,14 +136,14 @@ fn assist_order_field_struct() { 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] @@ -159,9 +159,9 @@ fn assist_order_if_expr() { 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"); } diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index 737f871091..915199bd87 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs @@ -472,12 +472,12 @@ impl Analysis { /// position. pub fn assists(&self, frange: FileRange) -> Cancelable> { 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()