diff options
Diffstat (limited to 'crates/ra_assists')
-rw-r--r-- | crates/ra_assists/src/assist_context.rs | 19 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/early_return.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/merge_imports.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/merge_match_arms.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/split_import.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 80 | ||||
-rw-r--r-- | crates/ra_assists/src/tests.rs | 24 |
7 files changed, 65 insertions, 66 deletions
diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs index 203ad1273..3085c4330 100644 --- a/crates/ra_assists/src/assist_context.rs +++ b/crates/ra_assists/src/assist_context.rs | |||
@@ -15,7 +15,7 @@ use ra_syntax::{ | |||
15 | }; | 15 | }; |
16 | use ra_text_edit::TextEditBuilder; | 16 | use ra_text_edit::TextEditBuilder; |
17 | 17 | ||
18 | use crate::{AssistId, AssistLabel, GroupLabel, ResolvedAssist}; | 18 | use crate::{Assist, AssistId, GroupLabel, ResolvedAssist}; |
19 | 19 | ||
20 | /// `AssistContext` allows to apply an assist or check if it could be applied. | 20 | /// `AssistContext` allows to apply an assist or check if it could be applied. |
21 | /// | 21 | /// |
@@ -76,8 +76,7 @@ impl<'a> AssistContext<'a> { | |||
76 | find_node_at_offset(self.source_file.syntax(), self.offset()) | 76 | find_node_at_offset(self.source_file.syntax(), self.offset()) |
77 | } | 77 | } |
78 | pub(crate) fn find_node_at_offset_with_descend<N: AstNode>(&self) -> Option<N> { | 78 | pub(crate) fn find_node_at_offset_with_descend<N: AstNode>(&self) -> Option<N> { |
79 | self.sema | 79 | self.sema.find_node_at_offset_with_descend(self.source_file.syntax(), self.offset()) |
80 | .find_node_at_offset_with_descend(self.source_file.syntax(), self.frange.range.start()) | ||
81 | } | 80 | } |
82 | pub(crate) fn covering_element(&self) -> SyntaxElement { | 81 | pub(crate) fn covering_element(&self) -> SyntaxElement { |
83 | find_covering_element(self.source_file.syntax(), self.frange.range) | 82 | find_covering_element(self.source_file.syntax(), self.frange.range) |
@@ -91,7 +90,7 @@ impl<'a> AssistContext<'a> { | |||
91 | pub(crate) struct Assists { | 90 | pub(crate) struct Assists { |
92 | resolve: bool, | 91 | resolve: bool, |
93 | file: FileId, | 92 | file: FileId, |
94 | buf: Vec<(AssistLabel, Option<SourceChange>)>, | 93 | buf: Vec<(Assist, Option<SourceChange>)>, |
95 | } | 94 | } |
96 | 95 | ||
97 | impl Assists { | 96 | impl Assists { |
@@ -102,7 +101,7 @@ impl Assists { | |||
102 | Assists { resolve: false, file: ctx.frange.file_id, buf: Vec::new() } | 101 | Assists { resolve: false, file: ctx.frange.file_id, buf: Vec::new() } |
103 | } | 102 | } |
104 | 103 | ||
105 | pub(crate) fn finish_unresolved(self) -> Vec<AssistLabel> { | 104 | pub(crate) fn finish_unresolved(self) -> Vec<Assist> { |
106 | assert!(!self.resolve); | 105 | assert!(!self.resolve); |
107 | self.finish() | 106 | self.finish() |
108 | .into_iter() | 107 | .into_iter() |
@@ -117,7 +116,7 @@ impl Assists { | |||
117 | assert!(self.resolve); | 116 | assert!(self.resolve); |
118 | self.finish() | 117 | self.finish() |
119 | .into_iter() | 118 | .into_iter() |
120 | .map(|(label, edit)| ResolvedAssist { label, source_change: edit.unwrap() }) | 119 | .map(|(label, edit)| ResolvedAssist { assist: label, source_change: edit.unwrap() }) |
121 | .collect() | 120 | .collect() |
122 | } | 121 | } |
123 | 122 | ||
@@ -128,7 +127,7 @@ impl Assists { | |||
128 | target: TextRange, | 127 | target: TextRange, |
129 | f: impl FnOnce(&mut AssistBuilder), | 128 | f: impl FnOnce(&mut AssistBuilder), |
130 | ) -> Option<()> { | 129 | ) -> Option<()> { |
131 | let label = AssistLabel::new(id, label.into(), None, target); | 130 | let label = Assist::new(id, label.into(), None, target); |
132 | self.add_impl(label, f) | 131 | self.add_impl(label, f) |
133 | } | 132 | } |
134 | pub(crate) fn add_group( | 133 | pub(crate) fn add_group( |
@@ -139,10 +138,10 @@ impl Assists { | |||
139 | target: TextRange, | 138 | target: TextRange, |
140 | f: impl FnOnce(&mut AssistBuilder), | 139 | f: impl FnOnce(&mut AssistBuilder), |
141 | ) -> Option<()> { | 140 | ) -> Option<()> { |
142 | let label = AssistLabel::new(id, label.into(), Some(group.clone()), target); | 141 | let label = Assist::new(id, label.into(), Some(group.clone()), target); |
143 | self.add_impl(label, f) | 142 | self.add_impl(label, f) |
144 | } | 143 | } |
145 | fn add_impl(&mut self, label: AssistLabel, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> { | 144 | fn add_impl(&mut self, label: Assist, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> { |
146 | let change_label = label.label.clone(); | 145 | let change_label = label.label.clone(); |
147 | let source_change = if self.resolve { | 146 | let source_change = if self.resolve { |
148 | let mut builder = AssistBuilder::new(self.file); | 147 | let mut builder = AssistBuilder::new(self.file); |
@@ -156,7 +155,7 @@ impl Assists { | |||
156 | Some(()) | 155 | Some(()) |
157 | } | 156 | } |
158 | 157 | ||
159 | fn finish(mut self) -> Vec<(AssistLabel, Option<SourceChange>)> { | 158 | fn finish(mut self) -> Vec<(Assist, Option<SourceChange>)> { |
160 | self.buf.sort_by_key(|(label, _edit)| label.target.len()); | 159 | self.buf.sort_by_key(|(label, _edit)| label.target.len()); |
161 | self.buf | 160 | self.buf |
162 | } | 161 | } |
diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs index ccf91797c..810784ad5 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) | |||
93 | } | 93 | } |
94 | 94 | ||
95 | then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; | 95 | then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; |
96 | let cursor_position = ctx.frange.range.start(); | 96 | let cursor_position = ctx.offset(); |
97 | 97 | ||
98 | let target = if_expr.syntax().text_range(); | 98 | let target = if_expr.syntax().text_range(); |
99 | acc.add(AssistId("convert_to_guarded_return"), "Convert to guarded return", target, |edit| { | 99 | 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 8e1d93312..ac3e53c27 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::{ | |||
26 | pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 26 | pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
27 | let tree: ast::UseTree = ctx.find_node_at_offset()?; | 27 | let tree: ast::UseTree = ctx.find_node_at_offset()?; |
28 | let mut rewriter = SyntaxRewriter::default(); | 28 | let mut rewriter = SyntaxRewriter::default(); |
29 | let mut offset = ctx.frange.range.start(); | 29 | let mut offset = ctx.offset(); |
30 | 30 | ||
31 | if let Some(use_item) = tree.syntax().parent().and_then(ast::UseItem::cast) { | 31 | if let Some(use_item) = tree.syntax().parent().and_then(ast::UseItem::cast) { |
32 | let (merged, to_delete) = next_prev() | 32 | 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 cfe4df47b..d4e38aa6a 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 | |||
45 | InExpr(TextSize), | 45 | InExpr(TextSize), |
46 | InPat(TextSize), | 46 | InPat(TextSize), |
47 | } | 47 | } |
48 | let cursor_pos = ctx.frange.range.start(); | 48 | let cursor_pos = ctx.offset(); |
49 | let cursor_pos = if current_expr.syntax().text_range().contains(cursor_pos) { | 49 | let cursor_pos = if current_expr.syntax().text_range().contains(cursor_pos) { |
50 | CursorPos::InExpr(current_text_range.end() - cursor_pos) | 50 | CursorPos::InExpr(current_text_range.end() - cursor_pos) |
51 | } else { | 51 | } else { |
diff --git a/crates/ra_assists/src/handlers/split_import.rs b/crates/ra_assists/src/handlers/split_import.rs index 159033731..b2757e50c 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<()> | |||
26 | if new_tree == use_tree { | 26 | if new_tree == use_tree { |
27 | return None; | 27 | return None; |
28 | } | 28 | } |
29 | let cursor = ctx.frange.range.start(); | 29 | let cursor = ctx.offset(); |
30 | 30 | ||
31 | let target = colon_colon.text_range(); | 31 | let target = colon_colon.text_range(); |
32 | acc.add(AssistId("split_import"), "Split import", target, |edit| { | 32 | 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 011613762..b6dc7cb1b 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}; | |||
29 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 29 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
30 | pub struct AssistId(pub &'static str); | 30 | pub struct AssistId(pub &'static str); |
31 | 31 | ||
32 | #[derive(Clone, Debug)] | ||
33 | pub struct GroupLabel(pub String); | ||
34 | |||
32 | #[derive(Debug, Clone)] | 35 | #[derive(Debug, Clone)] |
33 | pub struct AssistLabel { | 36 | pub struct Assist { |
34 | pub id: AssistId, | 37 | pub id: AssistId, |
35 | /// Short description of the assist, as shown in the UI. | 38 | /// Short description of the assist, as shown in the UI. |
36 | pub label: String, | 39 | pub label: String, |
@@ -40,56 +43,53 @@ pub struct AssistLabel { | |||
40 | pub target: TextRange, | 43 | pub target: TextRange, |
41 | } | 44 | } |
42 | 45 | ||
43 | #[derive(Clone, Debug)] | 46 | #[derive(Debug, Clone)] |
44 | pub struct GroupLabel(pub String); | 47 | pub struct ResolvedAssist { |
48 | pub assist: Assist, | ||
49 | pub source_change: SourceChange, | ||
50 | } | ||
51 | |||
52 | impl Assist { | ||
53 | /// Return all the assists applicable at the given position. | ||
54 | /// | ||
55 | /// Assists are returned in the "unresolved" state, that is only labels are | ||
56 | /// returned, without actual edits. | ||
57 | pub fn unresolved(db: &RootDatabase, range: FileRange) -> Vec<Assist> { | ||
58 | let sema = Semantics::new(db); | ||
59 | let ctx = AssistContext::new(sema, range); | ||
60 | let mut acc = Assists::new_unresolved(&ctx); | ||
61 | handlers::all().iter().for_each(|handler| { | ||
62 | handler(&mut acc, &ctx); | ||
63 | }); | ||
64 | acc.finish_unresolved() | ||
65 | } | ||
66 | |||
67 | /// Return all the assists applicable at the given position. | ||
68 | /// | ||
69 | /// Assists are returned in the "resolved" state, that is with edit fully | ||
70 | /// computed. | ||
71 | pub fn resolved(db: &RootDatabase, range: FileRange) -> Vec<ResolvedAssist> { | ||
72 | let sema = Semantics::new(db); | ||
73 | let ctx = AssistContext::new(sema, range); | ||
74 | let mut acc = Assists::new_resolved(&ctx); | ||
75 | handlers::all().iter().for_each(|handler| { | ||
76 | handler(&mut acc, &ctx); | ||
77 | }); | ||
78 | acc.finish_resolved() | ||
79 | } | ||
45 | 80 | ||
46 | impl AssistLabel { | ||
47 | pub(crate) fn new( | 81 | pub(crate) fn new( |
48 | id: AssistId, | 82 | id: AssistId, |
49 | label: String, | 83 | label: String, |
50 | group: Option<GroupLabel>, | 84 | group: Option<GroupLabel>, |
51 | target: TextRange, | 85 | target: TextRange, |
52 | ) -> AssistLabel { | 86 | ) -> Assist { |
53 | // FIXME: make fields private, so that this invariant can't be broken | 87 | // FIXME: make fields private, so that this invariant can't be broken |
54 | assert!(label.starts_with(|c: char| c.is_uppercase())); | 88 | assert!(label.starts_with(|c: char| c.is_uppercase())); |
55 | AssistLabel { id, label, group, target } | 89 | Assist { id, label, group, target } |
56 | } | 90 | } |
57 | } | 91 | } |
58 | 92 | ||
59 | #[derive(Debug, Clone)] | ||
60 | pub struct ResolvedAssist { | ||
61 | pub label: AssistLabel, | ||
62 | pub source_change: SourceChange, | ||
63 | } | ||
64 | |||
65 | /// Return all the assists applicable at the given position. | ||
66 | /// | ||
67 | /// Assists are returned in the "unresolved" state, that is only labels are | ||
68 | /// returned, without actual edits. | ||
69 | pub fn unresolved_assists(db: &RootDatabase, range: FileRange) -> Vec<AssistLabel> { | ||
70 | let sema = Semantics::new(db); | ||
71 | let ctx = AssistContext::new(sema, range); | ||
72 | let mut acc = Assists::new_unresolved(&ctx); | ||
73 | handlers::all().iter().for_each(|handler| { | ||
74 | handler(&mut acc, &ctx); | ||
75 | }); | ||
76 | acc.finish_unresolved() | ||
77 | } | ||
78 | |||
79 | /// Return all the assists applicable at the given position. | ||
80 | /// | ||
81 | /// Assists are returned in the "resolved" state, that is with edit fully | ||
82 | /// computed. | ||
83 | pub fn resolved_assists(db: &RootDatabase, range: FileRange) -> Vec<ResolvedAssist> { | ||
84 | let sema = Semantics::new(db); | ||
85 | let ctx = AssistContext::new(sema, range); | ||
86 | let mut acc = Assists::new_resolved(&ctx); | ||
87 | handlers::all().iter().for_each(|handler| { | ||
88 | handler(&mut acc, &ctx); | ||
89 | }); | ||
90 | acc.finish_resolved() | ||
91 | } | ||
92 | |||
93 | mod handlers { | 93 | mod handlers { |
94 | use crate::{AssistContext, Assists}; | 94 | use crate::{AssistContext, Assists}; |
95 | 95 | ||
diff --git a/crates/ra_assists/src/tests.rs b/crates/ra_assists/src/tests.rs index 45b2d9733..a3eacb8f1 100644 --- a/crates/ra_assists/src/tests.rs +++ b/crates/ra_assists/src/tests.rs | |||
@@ -11,7 +11,7 @@ use test_utils::{ | |||
11 | RangeOrOffset, | 11 | RangeOrOffset, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | use crate::{handlers::Handler, resolved_assists, AssistContext, Assists}; | 14 | use crate::{handlers::Handler, Assist, AssistContext, Assists}; |
15 | 15 | ||
16 | pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { | 16 | pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { |
17 | let (mut db, file_id) = RootDatabase::with_single_file(text); | 17 | 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) { | |||
41 | let (db, file_id) = crate::tests::with_single_file(&before); | 41 | let (db, file_id) = crate::tests::with_single_file(&before); |
42 | let frange = FileRange { file_id, range: selection.into() }; | 42 | let frange = FileRange { file_id, range: selection.into() }; |
43 | 43 | ||
44 | let mut assist = resolved_assists(&db, frange) | 44 | let mut assist = Assist::resolved(&db, frange) |
45 | .into_iter() | 45 | .into_iter() |
46 | .find(|assist| assist.label.id.0 == assist_id) | 46 | .find(|assist| assist.assist.id.0 == assist_id) |
47 | .unwrap_or_else(|| { | 47 | .unwrap_or_else(|| { |
48 | panic!( | 48 | panic!( |
49 | "\n\nAssist is not applicable: {}\nAvailable assists: {}", | 49 | "\n\nAssist is not applicable: {}\nAvailable assists: {}", |
50 | assist_id, | 50 | assist_id, |
51 | resolved_assists(&db, frange) | 51 | Assist::resolved(&db, frange) |
52 | .into_iter() | 52 | .into_iter() |
53 | .map(|assist| assist.label.id.0) | 53 | .map(|assist| assist.assist.id.0) |
54 | .collect::<Vec<_>>() | 54 | .collect::<Vec<_>>() |
55 | .join(", ") | 55 | .join(", ") |
56 | ) | 56 | ) |
@@ -119,7 +119,7 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult) { | |||
119 | assert_eq_text!(after, &actual); | 119 | assert_eq_text!(after, &actual); |
120 | } | 120 | } |
121 | (Some(assist), ExpectedResult::Target(target)) => { | 121 | (Some(assist), ExpectedResult::Target(target)) => { |
122 | let range = assist.label.target; | 122 | let range = assist.assist.target; |
123 | assert_eq_text!(&text_without_caret[range], target); | 123 | assert_eq_text!(&text_without_caret[range], target); |
124 | } | 124 | } |
125 | (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"), | 125 | (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"), |
@@ -136,14 +136,14 @@ fn assist_order_field_struct() { | |||
136 | let (before_cursor_pos, before) = extract_offset(before); | 136 | let (before_cursor_pos, before) = extract_offset(before); |
137 | let (db, file_id) = with_single_file(&before); | 137 | let (db, file_id) = with_single_file(&before); |
138 | let frange = FileRange { file_id, range: TextRange::empty(before_cursor_pos) }; | 138 | let frange = FileRange { file_id, range: TextRange::empty(before_cursor_pos) }; |
139 | let assists = resolved_assists(&db, frange); | 139 | let assists = Assist::resolved(&db, frange); |
140 | let mut assists = assists.iter(); | 140 | let mut assists = assists.iter(); |
141 | 141 | ||
142 | assert_eq!( | 142 | assert_eq!( |
143 | assists.next().expect("expected assist").label.label, | 143 | assists.next().expect("expected assist").assist.label, |
144 | "Change visibility to pub(crate)" | 144 | "Change visibility to pub(crate)" |
145 | ); | 145 | ); |
146 | assert_eq!(assists.next().expect("expected assist").label.label, "Add `#[derive]`"); | 146 | assert_eq!(assists.next().expect("expected assist").assist.label, "Add `#[derive]`"); |
147 | } | 147 | } |
148 | 148 | ||
149 | #[test] | 149 | #[test] |
@@ -159,9 +159,9 @@ fn assist_order_if_expr() { | |||
159 | let (range, before) = extract_range(before); | 159 | let (range, before) = extract_range(before); |
160 | let (db, file_id) = with_single_file(&before); | 160 | let (db, file_id) = with_single_file(&before); |
161 | let frange = FileRange { file_id, range }; | 161 | let frange = FileRange { file_id, range }; |
162 | let assists = resolved_assists(&db, frange); | 162 | let assists = Assist::resolved(&db, frange); |
163 | let mut assists = assists.iter(); | 163 | let mut assists = assists.iter(); |
164 | 164 | ||
165 | assert_eq!(assists.next().expect("expected assist").label.label, "Extract into variable"); | 165 | assert_eq!(assists.next().expect("expected assist").assist.label, "Extract into variable"); |
166 | assert_eq!(assists.next().expect("expected assist").label.label, "Replace with match"); | 166 | assert_eq!(assists.next().expect("expected assist").assist.label, "Replace with match"); |
167 | } | 167 | } |