aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src
diff options
context:
space:
mode:
authorrobojumper <[email protected]>2019-02-08 21:43:13 +0000
committerrobojumper <[email protected]>2019-02-08 21:43:13 +0000
commita3622eb629bf7acea933d956f8cee902ae357fca (patch)
treee09c517a22f7cf4229c8d4a306f68d9f3940adec /crates/ra_assists/src
parent12e3b4c70b5ef23b2fdfc197296d483680e125f9 (diff)
Add some assist ranges
Diffstat (limited to 'crates/ra_assists/src')
-rw-r--r--crates/ra_assists/src/add_derive.rs1
-rw-r--r--crates/ra_assists/src/assist_ctx.rs13
-rw-r--r--crates/ra_assists/src/change_visibility.rs13
-rw-r--r--crates/ra_assists/src/lib.rs40
-rw-r--r--crates/ra_assists/src/split_import.rs1
5 files changed, 58 insertions, 10 deletions
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<impl HirDatabase>) -> Option<Assist> {
24 } 24 }
25 Some(tt) => tt.syntax().range().end() - TextUnit::of_char(')'), 25 Some(tt) => tt.syntax().range().end() - TextUnit::of_char(')'),
26 }; 26 };
27 edit.target(nominal.syntax().range());
27 edit.set_cursor(offset) 28 edit.set_cursor(offset)
28 }) 29 })
29} 30}
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 {
16 16
17/// `AssistCtx` allows to apply an assist or check if it could be applied. 17/// `AssistCtx` allows to apply an assist or check if it could be applied.
18/// 18///
19/// Assists use a somewhat overengineered approach, given the current needs. The 19/// Assists use a somewhat over-engineered approach, given the current needs. The
20/// assists workflow consists of two phases. In the first phase, a user asks for 20/// assists workflow consists of two phases. In the first phase, a user asks for
21/// the list of available assists. In the second phase, the user picks a 21/// the list of available assists. In the second phase, the user picks a
22/// particular assist and it gets applied. 22/// particular assist and it gets applied.
@@ -106,6 +106,7 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
106pub(crate) struct AssistBuilder { 106pub(crate) struct AssistBuilder {
107 edit: TextEditBuilder, 107 edit: TextEditBuilder,
108 cursor_position: Option<TextUnit>, 108 cursor_position: Option<TextUnit>,
109 target: Option<TextRange>,
109} 110}
110 111
111impl AssistBuilder { 112impl AssistBuilder {
@@ -138,7 +139,15 @@ impl AssistBuilder {
138 self.cursor_position = Some(offset) 139 self.cursor_position = Some(offset)
139 } 140 }
140 141
142 pub(crate) fn target(&mut self, target: TextRange) {
143 self.target = Some(target)
144 }
145
141 fn build(self) -> AssistAction { 146 fn build(self) -> AssistAction {
142 AssistAction { edit: self.edit.finish(), cursor_position: self.cursor_position } 147 AssistAction {
148 edit: self.edit.finish(),
149 cursor_position: self.cursor_position,
150 target: self.target,
151 }
143 } 152 }
144} 153}
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<impl HirDatabase>) -> Option<Assist> {
20 _ => false, 20 _ => false,
21 }); 21 });
22 22
23 let offset = if let Some(keyword) = item_keyword { 23 let (offset, target) = if let Some(keyword) = item_keyword {
24 let parent = keyword.parent()?; 24 let parent = keyword.parent()?;
25 let def_kws = vec![FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF]; 25 let def_kws = vec![FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF];
26 // Parent is not a definition, can't add visibility 26 // Parent is not a definition, can't add visibility
@@ -31,17 +31,18 @@ fn add_vis(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
31 if parent.children().any(|child| child.kind() == VISIBILITY) { 31 if parent.children().any(|child| child.kind() == VISIBILITY) {
32 return None; 32 return None;
33 } 33 }
34 vis_offset(parent) 34 (vis_offset(parent), parent.range())
35 } else { 35 } else {
36 let ident = ctx.leaf_at_offset().find(|leaf| leaf.kind() == IDENT)?; 36 let ident = ctx.leaf_at_offset().find(|leaf| leaf.kind() == IDENT)?;
37 let field = ident.ancestors().find_map(ast::NamedFieldDef::cast)?; 37 let field = ident.ancestors().find_map(ast::NamedFieldDef::cast)?;
38 if field.name()?.syntax().range() != ident.range() && field.visibility().is_some() { 38 if field.name()?.syntax().range() != ident.range() && field.visibility().is_some() {
39 return None; 39 return None;
40 } 40 }
41 vis_offset(field.syntax()) 41 (vis_offset(field.syntax()), field.syntax().range())
42 }; 42 };
43 43
44 ctx.build("make pub(crate)", |edit| { 44 ctx.build("make pub(crate)", |edit| {
45 edit.target(target);
45 edit.insert(offset, "pub(crate) "); 46 edit.insert(offset, "pub(crate) ");
46 edit.set_cursor(offset); 47 edit.set_cursor(offset);
47 }) 48 })
@@ -60,13 +61,15 @@ fn vis_offset(node: &SyntaxNode) -> TextUnit {
60 61
61fn change_vis(ctx: AssistCtx<impl HirDatabase>, vis: &ast::Visibility) -> Option<Assist> { 62fn change_vis(ctx: AssistCtx<impl HirDatabase>, vis: &ast::Visibility) -> Option<Assist> {
62 if vis.syntax().text() == "pub" { 63 if vis.syntax().text() == "pub" {
63 return ctx.build("chage to pub(crate)", |edit| { 64 return ctx.build("change to pub(crate)", |edit| {
65 edit.target(vis.syntax().range());
64 edit.replace(vis.syntax().range(), "pub(crate)"); 66 edit.replace(vis.syntax().range(), "pub(crate)");
65 edit.set_cursor(vis.syntax().range().start()); 67 edit.set_cursor(vis.syntax().range().start());
66 }); 68 });
67 } 69 }
68 if vis.syntax().text() == "pub(crate)" { 70 if vis.syntax().text() == "pub(crate)" {
69 return ctx.build("chage to pub", |edit| { 71 return ctx.build("change to pub", |edit| {
72 edit.target(vis.syntax().range());
70 edit.replace(vis.syntax().range(), "pub"); 73 edit.replace(vis.syntax().range(), "pub");
71 edit.set_cursor(vis.syntax().range().start()); 74 edit.set_cursor(vis.syntax().range().start());
72 }); 75 });
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 @@
8mod assist_ctx; 8mod assist_ctx;
9 9
10use ra_text_edit::TextEdit; 10use ra_text_edit::TextEdit;
11use ra_syntax::{TextUnit, SyntaxNode, Direction}; 11use ra_syntax::{TextRange, TextUnit, SyntaxNode, Direction};
12use ra_db::FileRange; 12use ra_db::FileRange;
13use hir::db::HirDatabase; 13use hir::db::HirDatabase;
14 14
@@ -23,6 +23,7 @@ pub struct AssistLabel {
23pub struct AssistAction { 23pub struct AssistAction {
24 pub edit: TextEdit, 24 pub edit: TextEdit,
25 pub cursor_position: Option<TextUnit>, 25 pub cursor_position: Option<TextUnit>,
26 pub target: Option<TextRange>,
26} 27}
27 28
28/// Return all the assists applicable at the given position. 29/// Return all the assists applicable at the given position.
@@ -53,15 +54,26 @@ pub fn assists<H>(db: &H, range: FileRange) -> Vec<(AssistLabel, AssistAction)>
53where 54where
54 H: HirDatabase + 'static, 55 H: HirDatabase + 'static,
55{ 56{
57 use std::cmp::Ordering;
58
56 AssistCtx::with_ctx(db, range, true, |ctx| { 59 AssistCtx::with_ctx(db, range, true, |ctx| {
57 all_assists() 60 let mut a = all_assists()
58 .iter() 61 .iter()
59 .filter_map(|f| f(ctx.clone())) 62 .filter_map(|f| f(ctx.clone()))
60 .map(|a| match a { 63 .map(|a| match a {
61 Assist::Resolved(label, action) => (label, action), 64 Assist::Resolved(label, action) => (label, action),
62 Assist::Unresolved(..) => unreachable!(), 65 Assist::Unresolved(..) => unreachable!(),
63 }) 66 })
64 .collect() 67 .collect::<Vec<(AssistLabel, AssistAction)>>();
68 a.sort_unstable_by(|a, b| match a {
69 // Some(y) < Some(x) < None for y < x
70 (_, AssistAction { target: Some(a), .. }) => match b {
71 (_, AssistAction { target: Some(b), .. }) => a.len().cmp(&b.len()),
72 _ => Ordering::Less,
73 },
74 _ => Ordering::Greater,
75 });
76 a
65 }) 77 })
66} 78}
67 79
@@ -162,5 +174,27 @@ mod helpers {
162 let assist = AssistCtx::with_ctx(&db, frange, true, assist); 174 let assist = AssistCtx::with_ctx(&db, frange, true, assist);
163 assert!(assist.is_none()); 175 assert!(assist.is_none());
164 } 176 }
177}
178
179#[cfg(test)]
180mod tests {
181 use hir::mock::MockDatabase;
182 use ra_syntax::TextRange;
183 use ra_db::FileRange;
184 use test_utils::extract_offset;
185
186 #[test]
187 fn assist_order() {
188 let before = "struct Foo { <|>bar: u32 }";
189 let (before_cursor_pos, before) = extract_offset(before);
190 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
191 let frange =
192 FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
193 let assists = super::assists(&db, frange);
194 let mut assists = assists.iter();
195
196 assert_eq!(assists.next().expect("expected assist").0.label, "make pub(crate)");
197 assert_eq!(assists.next().expect("expected assist").0.label, "add `#[derive]`");
198 }
165 199
166} 200}
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<impl HirDatabase>) -> Option<Assist> {
24 }; 24 };
25 25
26 ctx.build("split import", |edit| { 26 ctx.build("split import", |edit| {
27 edit.target(colon_colon.range());
27 edit.insert(l_curly, "{"); 28 edit.insert(l_curly, "{");
28 edit.insert(r_curly, "}"); 29 edit.insert(r_curly, "}");
29 edit.set_cursor(l_curly + TextUnit::of_str("{")); 30 edit.set_cursor(l_curly + TextUnit::of_str("{"));