From a3622eb629bf7acea933d956f8cee902ae357fca Mon Sep 17 00:00:00 2001 From: robojumper Date: Fri, 8 Feb 2019 22:43:13 +0100 Subject: Add some assist ranges --- crates/ra_assists/src/add_derive.rs | 1 + crates/ra_assists/src/assist_ctx.rs | 13 ++++++++-- crates/ra_assists/src/change_visibility.rs | 13 ++++++---- crates/ra_assists/src/lib.rs | 40 +++++++++++++++++++++++++++--- crates/ra_assists/src/split_import.rs | 1 + 5 files changed, 58 insertions(+), 10 deletions(-) (limited to 'crates/ra_assists/src') diff --git a/crates/ra_assists/src/add_derive.rs b/crates/ra_assists/src/add_derive.rs index caf21e079..de33b356c 100644 --- a/crates/ra_assists/src/add_derive.rs +++ b/crates/ra_assists/src/add_derive.rs @@ -24,6 +24,7 @@ pub(crate) fn add_derive(ctx: AssistCtx) -> Option { } Some(tt) => tt.syntax().range().end() - TextUnit::of_char(')'), }; + edit.target(nominal.syntax().range()); edit.set_cursor(offset) }) } diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index 0bf640241..41c8ac2f6 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs @@ -16,7 +16,7 @@ pub(crate) enum Assist { /// `AssistCtx` allows to apply an assist or check if it could be applied. /// -/// Assists use a somewhat overengineered approach, given the current needs. The +/// Assists use a somewhat over-engineered approach, given the current needs. The /// assists workflow consists of two phases. In the first phase, a user asks for /// the list of available assists. In the second phase, the user picks a /// particular assist and it gets applied. @@ -106,6 +106,7 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { pub(crate) struct AssistBuilder { edit: TextEditBuilder, cursor_position: Option, + target: Option, } impl AssistBuilder { @@ -138,7 +139,15 @@ impl AssistBuilder { self.cursor_position = Some(offset) } + pub(crate) fn target(&mut self, target: TextRange) { + self.target = Some(target) + } + fn build(self) -> AssistAction { - AssistAction { edit: self.edit.finish(), cursor_position: self.cursor_position } + AssistAction { + edit: self.edit.finish(), + cursor_position: self.cursor_position, + target: self.target, + } } } diff --git a/crates/ra_assists/src/change_visibility.rs b/crates/ra_assists/src/change_visibility.rs index fa5f231c8..73dd8319f 100644 --- a/crates/ra_assists/src/change_visibility.rs +++ b/crates/ra_assists/src/change_visibility.rs @@ -20,7 +20,7 @@ fn add_vis(ctx: AssistCtx) -> Option { _ => false, }); - let offset = if let Some(keyword) = item_keyword { + let (offset, target) = if let Some(keyword) = item_keyword { let parent = keyword.parent()?; let def_kws = vec![FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF]; // Parent is not a definition, can't add visibility @@ -31,17 +31,18 @@ fn add_vis(ctx: AssistCtx) -> Option { if parent.children().any(|child| child.kind() == VISIBILITY) { return None; } - vis_offset(parent) + (vis_offset(parent), parent.range()) } else { let ident = ctx.leaf_at_offset().find(|leaf| leaf.kind() == IDENT)?; let field = ident.ancestors().find_map(ast::NamedFieldDef::cast)?; if field.name()?.syntax().range() != ident.range() && field.visibility().is_some() { return None; } - vis_offset(field.syntax()) + (vis_offset(field.syntax()), field.syntax().range()) }; ctx.build("make pub(crate)", |edit| { + edit.target(target); edit.insert(offset, "pub(crate) "); edit.set_cursor(offset); }) @@ -60,13 +61,15 @@ fn vis_offset(node: &SyntaxNode) -> TextUnit { fn change_vis(ctx: AssistCtx, vis: &ast::Visibility) -> Option { if vis.syntax().text() == "pub" { - return ctx.build("chage to pub(crate)", |edit| { + return ctx.build("change to pub(crate)", |edit| { + edit.target(vis.syntax().range()); edit.replace(vis.syntax().range(), "pub(crate)"); edit.set_cursor(vis.syntax().range().start()); }); } if vis.syntax().text() == "pub(crate)" { - return ctx.build("chage to pub", |edit| { + return ctx.build("change to pub", |edit| { + edit.target(vis.syntax().range()); edit.replace(vis.syntax().range(), "pub"); edit.set_cursor(vis.syntax().range().start()); }); diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 881db6347..fc4e95303 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs @@ -8,7 +8,7 @@ mod assist_ctx; use ra_text_edit::TextEdit; -use ra_syntax::{TextUnit, SyntaxNode, Direction}; +use ra_syntax::{TextRange, TextUnit, SyntaxNode, Direction}; use ra_db::FileRange; use hir::db::HirDatabase; @@ -23,6 +23,7 @@ pub struct AssistLabel { pub struct AssistAction { pub edit: TextEdit, pub cursor_position: Option, + pub target: Option, } /// Return all the assists applicable at the given position. @@ -53,15 +54,26 @@ pub fn assists(db: &H, range: FileRange) -> Vec<(AssistLabel, AssistAction)> where H: HirDatabase + 'static, { + use std::cmp::Ordering; + AssistCtx::with_ctx(db, range, true, |ctx| { - all_assists() + let mut a = all_assists() .iter() .filter_map(|f| f(ctx.clone())) .map(|a| match a { Assist::Resolved(label, action) => (label, action), Assist::Unresolved(..) => unreachable!(), }) - .collect() + .collect::>(); + a.sort_unstable_by(|a, b| match a { + // Some(y) < Some(x) < None for y < x + (_, AssistAction { target: Some(a), .. }) => match b { + (_, AssistAction { target: Some(b), .. }) => a.len().cmp(&b.len()), + _ => Ordering::Less, + }, + _ => Ordering::Greater, + }); + a }) } @@ -162,5 +174,27 @@ mod helpers { let assist = AssistCtx::with_ctx(&db, frange, true, assist); assert!(assist.is_none()); } +} + +#[cfg(test)] +mod tests { + use hir::mock::MockDatabase; + use ra_syntax::TextRange; + use ra_db::FileRange; + use test_utils::extract_offset; + + #[test] + fn assist_order() { + let before = "struct Foo { <|>bar: u32 }"; + let (before_cursor_pos, before) = extract_offset(before); + let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); + let frange = + FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; + let assists = super::assists(&db, frange); + let mut assists = assists.iter(); + + assert_eq!(assists.next().expect("expected assist").0.label, "make pub(crate)"); + assert_eq!(assists.next().expect("expected assist").0.label, "add `#[derive]`"); + } } diff --git a/crates/ra_assists/src/split_import.rs b/crates/ra_assists/src/split_import.rs index fb69cef9c..287c05830 100644 --- a/crates/ra_assists/src/split_import.rs +++ b/crates/ra_assists/src/split_import.rs @@ -24,6 +24,7 @@ pub(crate) fn split_import(ctx: AssistCtx) -> Option { }; ctx.build("split import", |edit| { + edit.target(colon_colon.range()); edit.insert(l_curly, "{"); edit.insert(r_curly, "}"); edit.set_cursor(l_curly + TextUnit::of_str("{")); -- cgit v1.2.3