diff options
Diffstat (limited to 'crates')
26 files changed, 242 insertions, 279 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index c52736679..1908bdec9 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs | |||
@@ -14,8 +14,8 @@ use crate::{AssistAction, AssistId, AssistLabel}; | |||
14 | 14 | ||
15 | #[derive(Clone, Debug)] | 15 | #[derive(Clone, Debug)] |
16 | pub(crate) enum Assist { | 16 | pub(crate) enum Assist { |
17 | Unresolved(Vec<AssistLabel>), | 17 | Unresolved { label: AssistLabel }, |
18 | Resolved(Vec<(AssistLabel, AssistAction)>), | 18 | Resolved { label: AssistLabel, action: AssistAction }, |
19 | } | 19 | } |
20 | 20 | ||
21 | /// `AssistCtx` allows to apply an assist or check if it could be applied. | 21 | /// `AssistCtx` allows to apply an assist or check if it could be applied. |
@@ -54,7 +54,6 @@ pub(crate) struct AssistCtx<'a, DB> { | |||
54 | pub(crate) frange: FileRange, | 54 | pub(crate) frange: FileRange, |
55 | source_file: SourceFile, | 55 | source_file: SourceFile, |
56 | should_compute_edit: bool, | 56 | should_compute_edit: bool, |
57 | assist: Assist, | ||
58 | } | 57 | } |
59 | 58 | ||
60 | impl<'a, DB> Clone for AssistCtx<'a, DB> { | 59 | impl<'a, DB> Clone for AssistCtx<'a, DB> { |
@@ -64,7 +63,6 @@ impl<'a, DB> Clone for AssistCtx<'a, DB> { | |||
64 | frange: self.frange, | 63 | frange: self.frange, |
65 | source_file: self.source_file.clone(), | 64 | source_file: self.source_file.clone(), |
66 | should_compute_edit: self.should_compute_edit, | 65 | should_compute_edit: self.should_compute_edit, |
67 | assist: self.assist.clone(), | ||
68 | } | 66 | } |
69 | } | 67 | } |
70 | } | 68 | } |
@@ -75,36 +73,30 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { | |||
75 | F: FnOnce(AssistCtx<DB>) -> T, | 73 | F: FnOnce(AssistCtx<DB>) -> T, |
76 | { | 74 | { |
77 | let parse = db.parse(frange.file_id); | 75 | let parse = db.parse(frange.file_id); |
78 | let assist = | ||
79 | if should_compute_edit { Assist::Resolved(vec![]) } else { Assist::Unresolved(vec![]) }; | ||
80 | 76 | ||
81 | let ctx = AssistCtx { db, frange, source_file: parse.tree(), should_compute_edit, assist }; | 77 | let ctx = AssistCtx { db, frange, source_file: parse.tree(), should_compute_edit }; |
82 | f(ctx) | 78 | f(ctx) |
83 | } | 79 | } |
84 | 80 | ||
85 | pub(crate) fn add_action( | 81 | pub(crate) fn add_assist( |
86 | &mut self, | 82 | self, |
87 | id: AssistId, | 83 | id: AssistId, |
88 | label: impl Into<String>, | 84 | label: impl Into<String>, |
89 | f: impl FnOnce(&mut AssistBuilder), | 85 | f: impl FnOnce(&mut AssistBuilder), |
90 | ) -> &mut Self { | 86 | ) -> Option<Assist> { |
91 | let label = AssistLabel { label: label.into(), id }; | 87 | let label = AssistLabel { label: label.into(), id }; |
92 | match &mut self.assist { | 88 | let assist = if self.should_compute_edit { |
93 | Assist::Unresolved(labels) => labels.push(label), | 89 | let action = { |
94 | Assist::Resolved(labels_actions) => { | 90 | let mut edit = AssistBuilder::default(); |
95 | let action = { | 91 | f(&mut edit); |
96 | let mut edit = AssistBuilder::default(); | 92 | edit.build() |
97 | f(&mut edit); | 93 | }; |
98 | edit.build() | 94 | Assist::Resolved { label, action } |
99 | }; | 95 | } else { |
100 | labels_actions.push((label, action)); | 96 | Assist::Unresolved { label } |
101 | } | 97 | }; |
102 | } | 98 | |
103 | self | 99 | Some(assist) |
104 | } | ||
105 | |||
106 | pub(crate) fn build(self) -> Option<Assist> { | ||
107 | Some(self.assist) | ||
108 | } | 100 | } |
109 | 101 | ||
110 | pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken> { | 102 | pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken> { |
diff --git a/crates/ra_assists/src/assists/add_derive.rs b/crates/ra_assists/src/assists/add_derive.rs index d1e925b71..764b17bd8 100644 --- a/crates/ra_assists/src/assists/add_derive.rs +++ b/crates/ra_assists/src/assists/add_derive.rs | |||
@@ -25,10 +25,10 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
25 | // y: u32, | 25 | // y: u32, |
26 | // } | 26 | // } |
27 | // ``` | 27 | // ``` |
28 | pub(crate) fn add_derive(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 28 | pub(crate) fn add_derive(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
29 | let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; | 29 | let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; |
30 | let node_start = derive_insertion_offset(&nominal)?; | 30 | let node_start = derive_insertion_offset(&nominal)?; |
31 | ctx.add_action(AssistId("add_derive"), "add `#[derive]`", |edit| { | 31 | ctx.add_assist(AssistId("add_derive"), "add `#[derive]`", |edit| { |
32 | let derive_attr = nominal | 32 | let derive_attr = nominal |
33 | .attrs() | 33 | .attrs() |
34 | .filter_map(|x| x.as_simple_call()) | 34 | .filter_map(|x| x.as_simple_call()) |
@@ -44,9 +44,7 @@ pub(crate) fn add_derive(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> | |||
44 | }; | 44 | }; |
45 | edit.target(nominal.syntax().text_range()); | 45 | edit.target(nominal.syntax().text_range()); |
46 | edit.set_cursor(offset) | 46 | edit.set_cursor(offset) |
47 | }); | 47 | }) |
48 | |||
49 | ctx.build() | ||
50 | } | 48 | } |
51 | 49 | ||
52 | // Insert `derive` after doc comments. | 50 | // Insert `derive` after doc comments. |
diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/assists/add_explicit_type.rs index ffbdc0b62..ddda1a0f2 100644 --- a/crates/ra_assists/src/assists/add_explicit_type.rs +++ b/crates/ra_assists/src/assists/add_explicit_type.rs | |||
@@ -21,7 +21,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
21 | // let x: i32 = 92; | 21 | // let x: i32 = 92; |
22 | // } | 22 | // } |
23 | // ``` | 23 | // ``` |
24 | pub(crate) fn add_explicit_type(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 24 | pub(crate) fn add_explicit_type(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
25 | let stmt = ctx.find_node_at_offset::<LetStmt>()?; | 25 | let stmt = ctx.find_node_at_offset::<LetStmt>()?; |
26 | let expr = stmt.initializer()?; | 26 | let expr = stmt.initializer()?; |
27 | let pat = stmt.pat()?; | 27 | let pat = stmt.pat()?; |
@@ -47,11 +47,10 @@ pub(crate) fn add_explicit_type(mut ctx: AssistCtx<impl HirDatabase>) -> Option< | |||
47 | return None; | 47 | return None; |
48 | } | 48 | } |
49 | 49 | ||
50 | ctx.add_action(AssistId("add_explicit_type"), "add explicit type", |edit| { | 50 | ctx.add_assist(AssistId("add_explicit_type"), "add explicit type", |edit| { |
51 | edit.target(pat_range); | 51 | edit.target(pat_range); |
52 | edit.insert(name_range.end(), format!(": {}", ty.display(db))); | 52 | edit.insert(name_range.end(), format!(": {}", ty.display(db))); |
53 | }); | 53 | }) |
54 | ctx.build() | ||
55 | } | 54 | } |
56 | 55 | ||
57 | /// Returns true if any type parameter is unknown | 56 | /// Returns true if any type parameter is unknown |
diff --git a/crates/ra_assists/src/assists/add_impl.rs b/crates/ra_assists/src/assists/add_impl.rs index fd3588d24..7da0cfd0d 100644 --- a/crates/ra_assists/src/assists/add_impl.rs +++ b/crates/ra_assists/src/assists/add_impl.rs | |||
@@ -27,10 +27,10 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
27 | // | 27 | // |
28 | // } | 28 | // } |
29 | // ``` | 29 | // ``` |
30 | pub(crate) fn add_impl(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 30 | pub(crate) fn add_impl(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
31 | let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; | 31 | let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; |
32 | let name = nominal.name()?; | 32 | let name = nominal.name()?; |
33 | ctx.add_action(AssistId("add_impl"), "add impl", |edit| { | 33 | ctx.add_assist(AssistId("add_impl"), "add impl", |edit| { |
34 | edit.target(nominal.syntax().text_range()); | 34 | edit.target(nominal.syntax().text_range()); |
35 | let type_params = nominal.type_param_list(); | 35 | let type_params = nominal.type_param_list(); |
36 | let start_offset = nominal.syntax().text_range().end(); | 36 | let start_offset = nominal.syntax().text_range().end(); |
@@ -54,9 +54,7 @@ pub(crate) fn add_impl(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | |||
54 | edit.set_cursor(start_offset + TextUnit::of_str(&buf)); | 54 | edit.set_cursor(start_offset + TextUnit::of_str(&buf)); |
55 | buf.push_str("\n}"); | 55 | buf.push_str("\n}"); |
56 | edit.insert(start_offset, buf); | 56 | edit.insert(start_offset, buf); |
57 | }); | 57 | }) |
58 | |||
59 | ctx.build() | ||
60 | } | 58 | } |
61 | 59 | ||
62 | #[cfg(test)] | 60 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/assists/add_import.rs b/crates/ra_assists/src/assists/add_import.rs index 149d1403f..e87fae1af 100644 --- a/crates/ra_assists/src/assists/add_import.rs +++ b/crates/ra_assists/src/assists/add_import.rs | |||
@@ -1,5 +1,3 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use hir::{self, db::HirDatabase}; | 1 | use hir::{self, db::HirDatabase}; |
4 | use ra_syntax::{ | 2 | use ra_syntax::{ |
5 | ast::{self, NameOwner}, | 3 | ast::{self, NameOwner}, |
@@ -14,9 +12,9 @@ use crate::{ | |||
14 | AssistId, | 12 | AssistId, |
15 | }; | 13 | }; |
16 | 14 | ||
17 | // This function produces sequence of text edits into edit | 15 | /// This function produces sequence of text edits into edit |
18 | // to import the target path in the most appropriate scope given | 16 | /// to import the target path in the most appropriate scope given |
19 | // the cursor position | 17 | /// the cursor position |
20 | pub fn auto_import_text_edit( | 18 | pub fn auto_import_text_edit( |
21 | // Ideally the position of the cursor, used to | 19 | // Ideally the position of the cursor, used to |
22 | position: &SyntaxNode, | 20 | position: &SyntaxNode, |
@@ -39,7 +37,20 @@ pub fn auto_import_text_edit( | |||
39 | } | 37 | } |
40 | } | 38 | } |
41 | 39 | ||
42 | pub(crate) fn add_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 40 | // Assist: add_import |
41 | // | ||
42 | // Adds a use statement for a given fully-qualified path. | ||
43 | // | ||
44 | // ``` | ||
45 | // fn process(map: std::collections::<|>HashMap<String, String>) {} | ||
46 | // ``` | ||
47 | // -> | ||
48 | // ``` | ||
49 | // use std::collections::HashMap; | ||
50 | // | ||
51 | // fn process(map: HashMap<String, String>) {} | ||
52 | // ``` | ||
53 | pub(crate) fn add_import(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | ||
43 | let path: ast::Path = ctx.find_node_at_offset()?; | 54 | let path: ast::Path = ctx.find_node_at_offset()?; |
44 | // We don't want to mess with use statements | 55 | // We don't want to mess with use statements |
45 | if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { | 56 | if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { |
@@ -52,38 +63,18 @@ pub(crate) fn add_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> | |||
52 | return None; | 63 | return None; |
53 | } | 64 | } |
54 | 65 | ||
55 | if let Some(module) = path.syntax().ancestors().find_map(ast::Module::cast) { | 66 | let module = path.syntax().ancestors().find_map(ast::Module::cast); |
56 | if let (Some(item_list), Some(name)) = (module.item_list(), module.name()) { | 67 | let position = match module.and_then(|it| it.item_list()) { |
57 | ctx.add_action( | 68 | Some(item_list) => item_list.syntax().clone(), |
58 | AssistId("add_import"), | 69 | None => { |
59 | format!("import {} in mod {}", fmt_segments(&segments), name.text()), | 70 | let current_file = path.syntax().ancestors().find_map(ast::SourceFile::cast)?; |
60 | |edit| { | 71 | current_file.syntax().clone() |
61 | apply_auto_import( | ||
62 | item_list.syntax(), | ||
63 | &path, | ||
64 | &segments, | ||
65 | edit.text_edit_builder(), | ||
66 | ); | ||
67 | }, | ||
68 | ); | ||
69 | } | 72 | } |
70 | } else { | 73 | }; |
71 | let current_file = path.syntax().ancestors().find_map(ast::SourceFile::cast)?; | ||
72 | ctx.add_action( | ||
73 | AssistId("add_import"), | ||
74 | format!("import {} in the current file", fmt_segments(&segments)), | ||
75 | |edit| { | ||
76 | apply_auto_import( | ||
77 | current_file.syntax(), | ||
78 | &path, | ||
79 | &segments, | ||
80 | edit.text_edit_builder(), | ||
81 | ); | ||
82 | }, | ||
83 | ); | ||
84 | } | ||
85 | 74 | ||
86 | ctx.build() | 75 | ctx.add_assist(AssistId("add_import"), format!("import {}", fmt_segments(&segments)), |edit| { |
76 | apply_auto_import(&position, &path, &segments, edit.text_edit_builder()); | ||
77 | }) | ||
87 | } | 78 | } |
88 | 79 | ||
89 | fn collect_path_segments_raw( | 80 | fn collect_path_segments_raw( |
@@ -595,9 +586,10 @@ fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> { | |||
595 | 586 | ||
596 | #[cfg(test)] | 587 | #[cfg(test)] |
597 | mod tests { | 588 | mod tests { |
598 | use super::*; | ||
599 | use crate::helpers::{check_assist, check_assist_not_applicable}; | 589 | use crate::helpers::{check_assist, check_assist_not_applicable}; |
600 | 590 | ||
591 | use super::*; | ||
592 | |||
601 | #[test] | 593 | #[test] |
602 | fn test_auto_import_add_use_no_anchor() { | 594 | fn test_auto_import_add_use_no_anchor() { |
603 | check_assist( | 595 | check_assist( |
diff --git a/crates/ra_assists/src/assists/add_missing_impl_members.rs b/crates/ra_assists/src/assists/add_missing_impl_members.rs index 2585f3045..41de23921 100644 --- a/crates/ra_assists/src/assists/add_missing_impl_members.rs +++ b/crates/ra_assists/src/assists/add_missing_impl_members.rs | |||
@@ -91,7 +91,7 @@ pub(crate) fn add_missing_default_members(ctx: AssistCtx<impl HirDatabase>) -> O | |||
91 | } | 91 | } |
92 | 92 | ||
93 | fn add_missing_impl_members_inner( | 93 | fn add_missing_impl_members_inner( |
94 | mut ctx: AssistCtx<impl HirDatabase>, | 94 | ctx: AssistCtx<impl HirDatabase>, |
95 | mode: AddMissingImplMembersMode, | 95 | mode: AddMissingImplMembersMode, |
96 | assist_id: &'static str, | 96 | assist_id: &'static str, |
97 | label: &'static str, | 97 | label: &'static str, |
@@ -133,7 +133,7 @@ fn add_missing_impl_members_inner( | |||
133 | return None; | 133 | return None; |
134 | } | 134 | } |
135 | 135 | ||
136 | ctx.add_action(AssistId(assist_id), label, |edit| { | 136 | ctx.add_assist(AssistId(assist_id), label, |edit| { |
137 | let n_existing_items = impl_item_list.impl_items().count(); | 137 | let n_existing_items = impl_item_list.impl_items().count(); |
138 | let items = missing_items | 138 | let items = missing_items |
139 | .into_iter() | 139 | .into_iter() |
@@ -150,9 +150,7 @@ fn add_missing_impl_members_inner( | |||
150 | 150 | ||
151 | edit.replace_ast(impl_item_list, new_impl_item_list); | 151 | edit.replace_ast(impl_item_list, new_impl_item_list); |
152 | edit.set_cursor(cursor_position); | 152 | edit.set_cursor(cursor_position); |
153 | }); | 153 | }) |
154 | |||
155 | ctx.build() | ||
156 | } | 154 | } |
157 | 155 | ||
158 | fn add_body(fn_def: ast::FnDef) -> ast::FnDef { | 156 | fn add_body(fn_def: ast::FnDef) -> ast::FnDef { |
diff --git a/crates/ra_assists/src/assists/apply_demorgan.rs b/crates/ra_assists/src/assists/apply_demorgan.rs index 8d5984a58..068da1774 100644 --- a/crates/ra_assists/src/assists/apply_demorgan.rs +++ b/crates/ra_assists/src/assists/apply_demorgan.rs | |||
@@ -23,7 +23,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
23 | // if !(x == 4 && y) {} | 23 | // if !(x == 4 && y) {} |
24 | // } | 24 | // } |
25 | // ``` | 25 | // ``` |
26 | pub(crate) fn apply_demorgan(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 26 | pub(crate) fn apply_demorgan(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
27 | let expr = ctx.find_node_at_offset::<ast::BinExpr>()?; | 27 | let expr = ctx.find_node_at_offset::<ast::BinExpr>()?; |
28 | let op = expr.op_kind()?; | 28 | let op = expr.op_kind()?; |
29 | let op_range = expr.op_token()?.text_range(); | 29 | let op_range = expr.op_token()?.text_range(); |
@@ -39,13 +39,12 @@ pub(crate) fn apply_demorgan(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Ass | |||
39 | let not_lhs = undo_negation(lhs)?; | 39 | let not_lhs = undo_negation(lhs)?; |
40 | let not_rhs = undo_negation(rhs)?; | 40 | let not_rhs = undo_negation(rhs)?; |
41 | 41 | ||
42 | ctx.add_action(AssistId("apply_demorgan"), "apply demorgan's law", |edit| { | 42 | ctx.add_assist(AssistId("apply_demorgan"), "apply demorgan's law", |edit| { |
43 | edit.target(op_range); | 43 | edit.target(op_range); |
44 | edit.replace(op_range, opposite_op); | 44 | edit.replace(op_range, opposite_op); |
45 | edit.replace(lhs_range, format!("!({}", not_lhs)); | 45 | edit.replace(lhs_range, format!("!({}", not_lhs)); |
46 | edit.replace(rhs_range, format!("{})", not_rhs)); | 46 | edit.replace(rhs_range, format!("{})", not_rhs)); |
47 | }); | 47 | }) |
48 | ctx.build() | ||
49 | } | 48 | } |
50 | 49 | ||
51 | // Return the opposite text for a given logical operator, if it makes sense | 50 | // Return the opposite text for a given logical operator, if it makes sense |
diff --git a/crates/ra_assists/src/assists/change_visibility.rs b/crates/ra_assists/src/assists/change_visibility.rs index 770ea04fa..132c9dc1d 100644 --- a/crates/ra_assists/src/assists/change_visibility.rs +++ b/crates/ra_assists/src/assists/change_visibility.rs | |||
@@ -29,7 +29,7 @@ pub(crate) fn change_visibility(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi | |||
29 | add_vis(ctx) | 29 | add_vis(ctx) |
30 | } | 30 | } |
31 | 31 | ||
32 | fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 32 | fn add_vis(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
33 | let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() { | 33 | let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() { |
34 | T![fn] | T![mod] | T![struct] | T![enum] | T![trait] => true, | 34 | T![fn] | T![mod] | T![struct] | T![enum] | T![trait] => true, |
35 | _ => false, | 35 | _ => false, |
@@ -57,13 +57,11 @@ fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | |||
57 | (vis_offset(field.syntax()), ident.text_range()) | 57 | (vis_offset(field.syntax()), ident.text_range()) |
58 | }; | 58 | }; |
59 | 59 | ||
60 | ctx.add_action(AssistId("change_visibility"), "make pub(crate)", |edit| { | 60 | ctx.add_assist(AssistId("change_visibility"), "make pub(crate)", |edit| { |
61 | edit.target(target); | 61 | edit.target(target); |
62 | edit.insert(offset, "pub(crate) "); | 62 | edit.insert(offset, "pub(crate) "); |
63 | edit.set_cursor(offset); | 63 | edit.set_cursor(offset); |
64 | }); | 64 | }) |
65 | |||
66 | ctx.build() | ||
67 | } | 65 | } |
68 | 66 | ||
69 | fn vis_offset(node: &SyntaxNode) -> TextUnit { | 67 | fn vis_offset(node: &SyntaxNode) -> TextUnit { |
@@ -77,24 +75,20 @@ fn vis_offset(node: &SyntaxNode) -> TextUnit { | |||
77 | .unwrap_or_else(|| node.text_range().start()) | 75 | .unwrap_or_else(|| node.text_range().start()) |
78 | } | 76 | } |
79 | 77 | ||
80 | fn change_vis(mut ctx: AssistCtx<impl HirDatabase>, vis: ast::Visibility) -> Option<Assist> { | 78 | fn change_vis(ctx: AssistCtx<impl HirDatabase>, vis: ast::Visibility) -> Option<Assist> { |
81 | if vis.syntax().text() == "pub" { | 79 | if vis.syntax().text() == "pub" { |
82 | ctx.add_action(AssistId("change_visibility"), "change to pub(crate)", |edit| { | 80 | return ctx.add_assist(AssistId("change_visibility"), "change to pub(crate)", |edit| { |
83 | edit.target(vis.syntax().text_range()); | 81 | edit.target(vis.syntax().text_range()); |
84 | edit.replace(vis.syntax().text_range(), "pub(crate)"); | 82 | edit.replace(vis.syntax().text_range(), "pub(crate)"); |
85 | edit.set_cursor(vis.syntax().text_range().start()) | 83 | edit.set_cursor(vis.syntax().text_range().start()) |
86 | }); | 84 | }); |
87 | |||
88 | return ctx.build(); | ||
89 | } | 85 | } |
90 | if vis.syntax().text() == "pub(crate)" { | 86 | if vis.syntax().text() == "pub(crate)" { |
91 | ctx.add_action(AssistId("change_visibility"), "change to pub", |edit| { | 87 | return ctx.add_assist(AssistId("change_visibility"), "change to pub", |edit| { |
92 | edit.target(vis.syntax().text_range()); | 88 | edit.target(vis.syntax().text_range()); |
93 | edit.replace(vis.syntax().text_range(), "pub"); | 89 | edit.replace(vis.syntax().text_range(), "pub"); |
94 | edit.set_cursor(vis.syntax().text_range().start()); | 90 | edit.set_cursor(vis.syntax().text_range().start()); |
95 | }); | 91 | }); |
96 | |||
97 | return ctx.build(); | ||
98 | } | 92 | } |
99 | None | 93 | None |
100 | } | 94 | } |
diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs index 75822dc65..e839d831e 100644 --- a/crates/ra_assists/src/assists/early_return.rs +++ b/crates/ra_assists/src/assists/early_return.rs | |||
@@ -35,7 +35,7 @@ use crate::{ | |||
35 | // bar(); | 35 | // bar(); |
36 | // } | 36 | // } |
37 | // ``` | 37 | // ``` |
38 | pub(crate) fn convert_to_guarded_return(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 38 | pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
39 | let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; | 39 | let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; |
40 | let expr = if_expr.condition()?.expr()?; | 40 | let expr = if_expr.condition()?.expr()?; |
41 | let then_block = if_expr.then_branch()?.block()?; | 41 | let then_block = if_expr.then_branch()?.block()?; |
@@ -75,7 +75,7 @@ pub(crate) fn convert_to_guarded_return(mut ctx: AssistCtx<impl HirDatabase>) -> | |||
75 | then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; | 75 | then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; |
76 | let cursor_position = ctx.frange.range.start(); | 76 | let cursor_position = ctx.frange.range.start(); |
77 | 77 | ||
78 | ctx.add_action(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| { | 78 | ctx.add_assist(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| { |
79 | let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); | 79 | let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); |
80 | let new_if_expr = | 80 | let new_if_expr = |
81 | if_indent_level.increase_indent(make::if_expression(&expr, early_expression)); | 81 | if_indent_level.increase_indent(make::if_expression(&expr, early_expression)); |
@@ -105,8 +105,7 @@ pub(crate) fn convert_to_guarded_return(mut ctx: AssistCtx<impl HirDatabase>) -> | |||
105 | edit.target(if_expr.syntax().text_range()); | 105 | edit.target(if_expr.syntax().text_range()); |
106 | edit.replace_ast(parent_block, ast::Block::cast(new_block).unwrap()); | 106 | edit.replace_ast(parent_block, ast::Block::cast(new_block).unwrap()); |
107 | edit.set_cursor(cursor_position); | 107 | edit.set_cursor(cursor_position); |
108 | }); | 108 | }) |
109 | ctx.build() | ||
110 | } | 109 | } |
111 | 110 | ||
112 | #[cfg(test)] | 111 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/assists/fill_match_arms.rs b/crates/ra_assists/src/assists/fill_match_arms.rs index c62c0efbe..2b74f355c 100644 --- a/crates/ra_assists/src/assists/fill_match_arms.rs +++ b/crates/ra_assists/src/assists/fill_match_arms.rs | |||
@@ -31,7 +31,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
31 | // } | 31 | // } |
32 | // } | 32 | // } |
33 | // ``` | 33 | // ``` |
34 | pub(crate) fn fill_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 34 | pub(crate) fn fill_match_arms(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
35 | let match_expr = ctx.find_node_at_offset::<ast::MatchExpr>()?; | 35 | let match_expr = ctx.find_node_at_offset::<ast::MatchExpr>()?; |
36 | let match_arm_list = match_expr.match_arm_list()?; | 36 | let match_arm_list = match_expr.match_arm_list()?; |
37 | 37 | ||
@@ -53,7 +53,7 @@ pub(crate) fn fill_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<As | |||
53 | }; | 53 | }; |
54 | let variant_list = enum_def.variant_list()?; | 54 | let variant_list = enum_def.variant_list()?; |
55 | 55 | ||
56 | ctx.add_action(AssistId("fill_match_arms"), "fill match arms", |edit| { | 56 | ctx.add_assist(AssistId("fill_match_arms"), "fill match arms", |edit| { |
57 | let indent_level = IndentLevel::from_node(match_arm_list.syntax()); | 57 | let indent_level = IndentLevel::from_node(match_arm_list.syntax()); |
58 | 58 | ||
59 | let new_arm_list = { | 59 | let new_arm_list = { |
@@ -67,9 +67,7 @@ pub(crate) fn fill_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<As | |||
67 | edit.target(match_expr.syntax().text_range()); | 67 | edit.target(match_expr.syntax().text_range()); |
68 | edit.set_cursor(expr.syntax().text_range().start()); | 68 | edit.set_cursor(expr.syntax().text_range().start()); |
69 | edit.replace_ast(match_arm_list, new_arm_list); | 69 | edit.replace_ast(match_arm_list, new_arm_list); |
70 | }); | 70 | }) |
71 | |||
72 | ctx.build() | ||
73 | } | 71 | } |
74 | 72 | ||
75 | fn is_trivial(arm: &ast::MatchArm) -> bool { | 73 | fn is_trivial(arm: &ast::MatchArm) -> bool { |
diff --git a/crates/ra_assists/src/assists/flip_binexpr.rs b/crates/ra_assists/src/assists/flip_binexpr.rs index 9765d5ddd..386045eb0 100644 --- a/crates/ra_assists/src/assists/flip_binexpr.rs +++ b/crates/ra_assists/src/assists/flip_binexpr.rs | |||
@@ -18,7 +18,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
18 | // let _ = 2 + 90; | 18 | // let _ = 2 + 90; |
19 | // } | 19 | // } |
20 | // ``` | 20 | // ``` |
21 | pub(crate) fn flip_binexpr(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 21 | pub(crate) fn flip_binexpr(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
22 | let expr = ctx.find_node_at_offset::<BinExpr>()?; | 22 | let expr = ctx.find_node_at_offset::<BinExpr>()?; |
23 | let lhs = expr.lhs()?.syntax().clone(); | 23 | let lhs = expr.lhs()?.syntax().clone(); |
24 | let rhs = expr.rhs()?.syntax().clone(); | 24 | let rhs = expr.rhs()?.syntax().clone(); |
@@ -34,16 +34,14 @@ pub(crate) fn flip_binexpr(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assis | |||
34 | return None; | 34 | return None; |
35 | } | 35 | } |
36 | 36 | ||
37 | ctx.add_action(AssistId("flip_binexpr"), "flip binary expression", |edit| { | 37 | ctx.add_assist(AssistId("flip_binexpr"), "flip binary expression", |edit| { |
38 | edit.target(op_range); | 38 | edit.target(op_range); |
39 | if let FlipAction::FlipAndReplaceOp(new_op) = action { | 39 | if let FlipAction::FlipAndReplaceOp(new_op) = action { |
40 | edit.replace(op_range, new_op); | 40 | edit.replace(op_range, new_op); |
41 | } | 41 | } |
42 | edit.replace(lhs.text_range(), rhs.text()); | 42 | edit.replace(lhs.text_range(), rhs.text()); |
43 | edit.replace(rhs.text_range(), lhs.text()); | 43 | edit.replace(rhs.text_range(), lhs.text()); |
44 | }); | 44 | }) |
45 | |||
46 | ctx.build() | ||
47 | } | 45 | } |
48 | 46 | ||
49 | enum FlipAction { | 47 | enum FlipAction { |
diff --git a/crates/ra_assists/src/assists/flip_comma.rs b/crates/ra_assists/src/assists/flip_comma.rs index 53ba8011d..9be1c1dc6 100644 --- a/crates/ra_assists/src/assists/flip_comma.rs +++ b/crates/ra_assists/src/assists/flip_comma.rs | |||
@@ -18,7 +18,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
18 | // ((3, 4), (1, 2)); | 18 | // ((3, 4), (1, 2)); |
19 | // } | 19 | // } |
20 | // ``` | 20 | // ``` |
21 | pub(crate) fn flip_comma(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 21 | pub(crate) fn flip_comma(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
22 | let comma = ctx.find_token_at_offset(T![,])?; | 22 | let comma = ctx.find_token_at_offset(T![,])?; |
23 | let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?; | 23 | let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?; |
24 | let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?; | 24 | let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?; |
@@ -29,13 +29,11 @@ pub(crate) fn flip_comma(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> | |||
29 | return None; | 29 | return None; |
30 | } | 30 | } |
31 | 31 | ||
32 | ctx.add_action(AssistId("flip_comma"), "flip comma", |edit| { | 32 | ctx.add_assist(AssistId("flip_comma"), "flip comma", |edit| { |
33 | edit.target(comma.text_range()); | 33 | edit.target(comma.text_range()); |
34 | edit.replace(prev.text_range(), next.to_string()); | 34 | edit.replace(prev.text_range(), next.to_string()); |
35 | edit.replace(next.text_range(), prev.to_string()); | 35 | edit.replace(next.text_range(), prev.to_string()); |
36 | }); | 36 | }) |
37 | |||
38 | ctx.build() | ||
39 | } | 37 | } |
40 | 38 | ||
41 | #[cfg(test)] | 39 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/assists/flip_trait_bound.rs b/crates/ra_assists/src/assists/flip_trait_bound.rs index 1625b241f..6017b39dd 100644 --- a/crates/ra_assists/src/assists/flip_trait_bound.rs +++ b/crates/ra_assists/src/assists/flip_trait_bound.rs | |||
@@ -18,7 +18,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
18 | // ``` | 18 | // ``` |
19 | // fn foo<T: Copy + Clone>() { } | 19 | // fn foo<T: Copy + Clone>() { } |
20 | // ``` | 20 | // ``` |
21 | pub(crate) fn flip_trait_bound(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 21 | pub(crate) fn flip_trait_bound(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
22 | // We want to replicate the behavior of `flip_binexpr` by only suggesting | 22 | // We want to replicate the behavior of `flip_binexpr` by only suggesting |
23 | // the assist when the cursor is on a `+` | 23 | // the assist when the cursor is on a `+` |
24 | let plus = ctx.find_token_at_offset(T![+])?; | 24 | let plus = ctx.find_token_at_offset(T![+])?; |
@@ -33,13 +33,11 @@ pub(crate) fn flip_trait_bound(mut ctx: AssistCtx<impl HirDatabase>) -> Option<A | |||
33 | non_trivia_sibling(plus.clone().into(), Direction::Next)?, | 33 | non_trivia_sibling(plus.clone().into(), Direction::Next)?, |
34 | ); | 34 | ); |
35 | 35 | ||
36 | ctx.add_action(AssistId("flip_trait_bound"), "flip trait bound", |edit| { | 36 | ctx.add_assist(AssistId("flip_trait_bound"), "flip trait bound", |edit| { |
37 | edit.target(plus.text_range()); | 37 | edit.target(plus.text_range()); |
38 | edit.replace(before.text_range(), after.to_string()); | 38 | edit.replace(before.text_range(), after.to_string()); |
39 | edit.replace(after.text_range(), before.to_string()); | 39 | edit.replace(after.text_range(), before.to_string()); |
40 | }); | 40 | }) |
41 | |||
42 | ctx.build() | ||
43 | } | 41 | } |
44 | 42 | ||
45 | #[cfg(test)] | 43 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/assists/inline_local_variable.rs b/crates/ra_assists/src/assists/inline_local_variable.rs index fe8fa2a86..f43910574 100644 --- a/crates/ra_assists/src/assists/inline_local_variable.rs +++ b/crates/ra_assists/src/assists/inline_local_variable.rs | |||
@@ -23,7 +23,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
23 | // (1 + 2) * 4; | 23 | // (1 + 2) * 4; |
24 | // } | 24 | // } |
25 | // ``` | 25 | // ``` |
26 | pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 26 | pub(crate) fn inline_local_varialbe(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
27 | let let_stmt = ctx.find_node_at_offset::<ast::LetStmt>()?; | 27 | let let_stmt = ctx.find_node_at_offset::<ast::LetStmt>()?; |
28 | let bind_pat = match let_stmt.pat()? { | 28 | let bind_pat = match let_stmt.pat()? { |
29 | ast::Pat::BindPat(pat) => pat, | 29 | ast::Pat::BindPat(pat) => pat, |
@@ -93,7 +93,7 @@ pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx<impl HirDatabase>) -> Opt | |||
93 | let init_str = initializer_expr.syntax().text().to_string(); | 93 | let init_str = initializer_expr.syntax().text().to_string(); |
94 | let init_in_paren = format!("({})", &init_str); | 94 | let init_in_paren = format!("({})", &init_str); |
95 | 95 | ||
96 | ctx.add_action( | 96 | ctx.add_assist( |
97 | AssistId("inline_local_variable"), | 97 | AssistId("inline_local_variable"), |
98 | "inline local variable", | 98 | "inline local variable", |
99 | move |edit: &mut AssistBuilder| { | 99 | move |edit: &mut AssistBuilder| { |
@@ -107,9 +107,7 @@ pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx<impl HirDatabase>) -> Opt | |||
107 | } | 107 | } |
108 | edit.set_cursor(delete_range.start()) | 108 | edit.set_cursor(delete_range.start()) |
109 | }, | 109 | }, |
110 | ); | 110 | ) |
111 | |||
112 | ctx.build() | ||
113 | } | 111 | } |
114 | 112 | ||
115 | #[cfg(test)] | 113 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/assists/introduce_variable.rs b/crates/ra_assists/src/assists/introduce_variable.rs index 8245dc99f..0623d4475 100644 --- a/crates/ra_assists/src/assists/introduce_variable.rs +++ b/crates/ra_assists/src/assists/introduce_variable.rs | |||
@@ -28,7 +28,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
28 | // var_name * 4; | 28 | // var_name * 4; |
29 | // } | 29 | // } |
30 | // ``` | 30 | // ``` |
31 | pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 31 | pub(crate) fn introduce_variable(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
32 | if ctx.frange.range.is_empty() { | 32 | if ctx.frange.range.is_empty() { |
33 | return None; | 33 | return None; |
34 | } | 34 | } |
@@ -43,7 +43,7 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option | |||
43 | if indent.kind() != WHITESPACE { | 43 | if indent.kind() != WHITESPACE { |
44 | return None; | 44 | return None; |
45 | } | 45 | } |
46 | ctx.add_action(AssistId("introduce_variable"), "introduce variable", move |edit| { | 46 | ctx.add_assist(AssistId("introduce_variable"), "introduce variable", move |edit| { |
47 | let mut buf = String::new(); | 47 | let mut buf = String::new(); |
48 | 48 | ||
49 | let cursor_offset = if wrap_in_block { | 49 | let cursor_offset = if wrap_in_block { |
@@ -88,9 +88,7 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option | |||
88 | } | 88 | } |
89 | } | 89 | } |
90 | edit.set_cursor(anchor_stmt.text_range().start() + cursor_offset); | 90 | edit.set_cursor(anchor_stmt.text_range().start() + cursor_offset); |
91 | }); | 91 | }) |
92 | |||
93 | ctx.build() | ||
94 | } | 92 | } |
95 | 93 | ||
96 | /// Check whether the node is a valid expression which can be extracted to a variable. | 94 | /// Check whether the node is a valid expression which can be extracted to a variable. |
diff --git a/crates/ra_assists/src/assists/merge_match_arms.rs b/crates/ra_assists/src/assists/merge_match_arms.rs index b0c4ee78b..e9f2cae91 100644 --- a/crates/ra_assists/src/assists/merge_match_arms.rs +++ b/crates/ra_assists/src/assists/merge_match_arms.rs | |||
@@ -26,7 +26,7 @@ use ra_syntax::ast::{AstNode, MatchArm}; | |||
26 | // } | 26 | // } |
27 | // } | 27 | // } |
28 | // ``` | 28 | // ``` |
29 | pub(crate) fn merge_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 29 | pub(crate) fn merge_match_arms(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
30 | let current_arm = ctx.find_node_at_offset::<MatchArm>()?; | 30 | let current_arm = ctx.find_node_at_offset::<MatchArm>()?; |
31 | 31 | ||
32 | // We check if the following match arm matches this one. We could, but don't, | 32 | // We check if the following match arm matches this one. We could, but don't, |
@@ -52,7 +52,7 @@ pub(crate) fn merge_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<A | |||
52 | 52 | ||
53 | let cursor_to_end = current_arm.syntax().text_range().end() - ctx.frange.range.start(); | 53 | let cursor_to_end = current_arm.syntax().text_range().end() - ctx.frange.range.start(); |
54 | 54 | ||
55 | ctx.add_action(AssistId("merge_match_arms"), "merge match arms", |edit| { | 55 | ctx.add_assist(AssistId("merge_match_arms"), "merge match arms", |edit| { |
56 | fn contains_placeholder(a: &MatchArm) -> bool { | 56 | fn contains_placeholder(a: &MatchArm) -> bool { |
57 | a.pats().any(|x| match x { | 57 | a.pats().any(|x| match x { |
58 | ra_syntax::ast::Pat::PlaceholderPat(..) => true, | 58 | ra_syntax::ast::Pat::PlaceholderPat(..) => true, |
@@ -80,9 +80,7 @@ pub(crate) fn merge_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<A | |||
80 | edit.target(current_arm.syntax().text_range()); | 80 | edit.target(current_arm.syntax().text_range()); |
81 | edit.replace(TextRange::from_to(start, end), arm); | 81 | edit.replace(TextRange::from_to(start, end), arm); |
82 | edit.set_cursor(start + offset); | 82 | edit.set_cursor(start + offset); |
83 | }); | 83 | }) |
84 | |||
85 | ctx.build() | ||
86 | } | 84 | } |
87 | 85 | ||
88 | #[cfg(test)] | 86 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/assists/move_bounds.rs b/crates/ra_assists/src/assists/move_bounds.rs index edf2897c6..3145d7625 100644 --- a/crates/ra_assists/src/assists/move_bounds.rs +++ b/crates/ra_assists/src/assists/move_bounds.rs | |||
@@ -22,7 +22,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
22 | // f(x) | 22 | // f(x) |
23 | // } | 23 | // } |
24 | // ``` | 24 | // ``` |
25 | pub(crate) fn move_bounds_to_where_clause(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 25 | pub(crate) fn move_bounds_to_where_clause(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
26 | let type_param_list = ctx.find_node_at_offset::<ast::TypeParamList>()?; | 26 | let type_param_list = ctx.find_node_at_offset::<ast::TypeParamList>()?; |
27 | 27 | ||
28 | let mut type_params = type_param_list.type_params(); | 28 | let mut type_params = type_param_list.type_params(); |
@@ -46,38 +46,30 @@ pub(crate) fn move_bounds_to_where_clause(mut ctx: AssistCtx<impl HirDatabase>) | |||
46 | _ => return None, | 46 | _ => return None, |
47 | }; | 47 | }; |
48 | 48 | ||
49 | ctx.add_action( | 49 | ctx.add_assist(AssistId("move_bounds_to_where_clause"), "move_bounds_to_where_clause", |edit| { |
50 | AssistId("move_bounds_to_where_clause"), | 50 | let new_params = type_param_list |
51 | "move_bounds_to_where_clause", | 51 | .type_params() |
52 | |edit| { | 52 | .filter(|it| it.type_bound_list().is_some()) |
53 | let new_params = type_param_list | 53 | .map(|type_param| { |
54 | .type_params() | 54 | let without_bounds = type_param.remove_bounds(); |
55 | .filter(|it| it.type_bound_list().is_some()) | 55 | (type_param, without_bounds) |
56 | .map(|type_param| { | 56 | }); |
57 | let without_bounds = type_param.remove_bounds(); | 57 | |
58 | (type_param, without_bounds) | 58 | let new_type_param_list = edit::replace_descendants(&type_param_list, new_params); |
59 | }); | 59 | edit.replace_ast(type_param_list.clone(), new_type_param_list); |
60 | 60 | ||
61 | let new_type_param_list = edit::replace_descendants(&type_param_list, new_params); | 61 | let where_clause = { |
62 | edit.replace_ast(type_param_list.clone(), new_type_param_list); | 62 | let predicates = type_param_list.type_params().filter_map(build_predicate); |
63 | 63 | make::where_clause(predicates) | |
64 | let where_clause = { | 64 | }; |
65 | let predicates = type_param_list.type_params().filter_map(build_predicate); | 65 | |
66 | make::where_clause(predicates) | 66 | let to_insert = match anchor.prev_sibling_or_token() { |
67 | }; | 67 | Some(ref elem) if elem.kind() == WHITESPACE => format!("{} ", where_clause.syntax()), |
68 | 68 | _ => format!(" {}", where_clause.syntax()), | |
69 | let to_insert = match anchor.prev_sibling_or_token() { | 69 | }; |
70 | Some(ref elem) if elem.kind() == WHITESPACE => { | 70 | edit.insert(anchor.text_range().start(), to_insert); |
71 | format!("{} ", where_clause.syntax()) | 71 | edit.target(type_param_list.syntax().text_range()); |
72 | } | 72 | }) |
73 | _ => format!(" {}", where_clause.syntax()), | ||
74 | }; | ||
75 | edit.insert(anchor.text_range().start(), to_insert); | ||
76 | edit.target(type_param_list.syntax().text_range()); | ||
77 | }, | ||
78 | ); | ||
79 | |||
80 | ctx.build() | ||
81 | } | 73 | } |
82 | 74 | ||
83 | fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> { | 75 | fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> { |
diff --git a/crates/ra_assists/src/assists/move_guard.rs b/crates/ra_assists/src/assists/move_guard.rs index e820a73c8..b49ec6172 100644 --- a/crates/ra_assists/src/assists/move_guard.rs +++ b/crates/ra_assists/src/assists/move_guard.rs | |||
@@ -32,7 +32,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
32 | // } | 32 | // } |
33 | // } | 33 | // } |
34 | // ``` | 34 | // ``` |
35 | pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 35 | pub(crate) fn move_guard_to_arm_body(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
36 | let match_arm = ctx.find_node_at_offset::<MatchArm>()?; | 36 | let match_arm = ctx.find_node_at_offset::<MatchArm>()?; |
37 | let guard = match_arm.guard()?; | 37 | let guard = match_arm.guard()?; |
38 | let space_before_guard = guard.syntax().prev_sibling_or_token(); | 38 | let space_before_guard = guard.syntax().prev_sibling_or_token(); |
@@ -41,7 +41,7 @@ pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx<impl HirDatabase>) -> Op | |||
41 | let arm_expr = match_arm.expr()?; | 41 | let arm_expr = match_arm.expr()?; |
42 | let buf = format!("if {} {{ {} }}", guard_conditions.syntax().text(), arm_expr.syntax().text()); | 42 | let buf = format!("if {} {{ {} }}", guard_conditions.syntax().text(), arm_expr.syntax().text()); |
43 | 43 | ||
44 | ctx.add_action(AssistId("move_guard_to_arm_body"), "move guard to arm body", |edit| { | 44 | ctx.add_assist(AssistId("move_guard_to_arm_body"), "move guard to arm body", |edit| { |
45 | edit.target(guard.syntax().text_range()); | 45 | edit.target(guard.syntax().text_range()); |
46 | let offseting_amount = match space_before_guard.and_then(|it| it.into_token()) { | 46 | let offseting_amount = match space_before_guard.and_then(|it| it.into_token()) { |
47 | Some(tok) => { | 47 | Some(tok) => { |
@@ -61,8 +61,7 @@ pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx<impl HirDatabase>) -> Op | |||
61 | edit.set_cursor( | 61 | edit.set_cursor( |
62 | arm_expr.syntax().text_range().start() + TextUnit::from(3) - offseting_amount, | 62 | arm_expr.syntax().text_range().start() + TextUnit::from(3) - offseting_amount, |
63 | ); | 63 | ); |
64 | }); | 64 | }) |
65 | ctx.build() | ||
66 | } | 65 | } |
67 | 66 | ||
68 | // Assist: move_arm_cond_to_match_guard | 67 | // Assist: move_arm_cond_to_match_guard |
@@ -90,7 +89,7 @@ pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx<impl HirDatabase>) -> Op | |||
90 | // } | 89 | // } |
91 | // } | 90 | // } |
92 | // ``` | 91 | // ``` |
93 | pub(crate) fn move_arm_cond_to_match_guard(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 92 | pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
94 | let match_arm: MatchArm = ctx.find_node_at_offset::<MatchArm>()?; | 93 | let match_arm: MatchArm = ctx.find_node_at_offset::<MatchArm>()?; |
95 | let last_match_pat = match_arm.pats().last()?; | 94 | let last_match_pat = match_arm.pats().last()?; |
96 | 95 | ||
@@ -110,7 +109,7 @@ pub(crate) fn move_arm_cond_to_match_guard(mut ctx: AssistCtx<impl HirDatabase>) | |||
110 | 109 | ||
111 | let buf = format!(" if {}", cond.syntax().text()); | 110 | let buf = format!(" if {}", cond.syntax().text()); |
112 | 111 | ||
113 | ctx.add_action( | 112 | ctx.add_assist( |
114 | AssistId("move_arm_cond_to_match_guard"), | 113 | AssistId("move_arm_cond_to_match_guard"), |
115 | "move condition to match guard", | 114 | "move condition to match guard", |
116 | |edit| { | 115 | |edit| { |
@@ -127,8 +126,7 @@ pub(crate) fn move_arm_cond_to_match_guard(mut ctx: AssistCtx<impl HirDatabase>) | |||
127 | edit.insert(last_match_pat.syntax().text_range().end(), buf); | 126 | edit.insert(last_match_pat.syntax().text_range().end(), buf); |
128 | edit.set_cursor(last_match_pat.syntax().text_range().end() + TextUnit::from(1)); | 127 | edit.set_cursor(last_match_pat.syntax().text_range().end() + TextUnit::from(1)); |
129 | }, | 128 | }, |
130 | ); | 129 | ) |
131 | ctx.build() | ||
132 | } | 130 | } |
133 | 131 | ||
134 | #[cfg(test)] | 132 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/assists/raw_string.rs b/crates/ra_assists/src/assists/raw_string.rs index 2df48a838..6f4b66c31 100644 --- a/crates/ra_assists/src/assists/raw_string.rs +++ b/crates/ra_assists/src/assists/raw_string.rs | |||
@@ -22,7 +22,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
22 | // r#"Hello, World!"#; | 22 | // r#"Hello, World!"#; |
23 | // } | 23 | // } |
24 | // ``` | 24 | // ``` |
25 | pub(crate) fn make_raw_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 25 | pub(crate) fn make_raw_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
26 | let token = ctx.find_token_at_offset(STRING)?; | 26 | let token = ctx.find_token_at_offset(STRING)?; |
27 | let text = token.text().as_str(); | 27 | let text = token.text().as_str(); |
28 | let usual_string_range = find_usual_string_range(text)?; | 28 | let usual_string_range = find_usual_string_range(text)?; |
@@ -41,7 +41,7 @@ pub(crate) fn make_raw_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<As | |||
41 | if error.is_err() { | 41 | if error.is_err() { |
42 | return None; | 42 | return None; |
43 | } | 43 | } |
44 | ctx.add_action(AssistId("make_raw_string"), "make raw string", |edit| { | 44 | ctx.add_assist(AssistId("make_raw_string"), "make raw string", |edit| { |
45 | edit.target(token.text_range()); | 45 | edit.target(token.text_range()); |
46 | let max_hash_streak = count_hashes(&unescaped); | 46 | let max_hash_streak = count_hashes(&unescaped); |
47 | let mut hashes = String::with_capacity(max_hash_streak + 1); | 47 | let mut hashes = String::with_capacity(max_hash_streak + 1); |
@@ -49,8 +49,7 @@ pub(crate) fn make_raw_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<As | |||
49 | hashes.push('#'); | 49 | hashes.push('#'); |
50 | } | 50 | } |
51 | edit.replace(token.text_range(), format!("r{}\"{}\"{}", hashes, unescaped, hashes)); | 51 | edit.replace(token.text_range(), format!("r{}\"{}\"{}", hashes, unescaped, hashes)); |
52 | }); | 52 | }) |
53 | ctx.build() | ||
54 | } | 53 | } |
55 | 54 | ||
56 | // Assist: make_usual_string | 55 | // Assist: make_usual_string |
@@ -68,11 +67,11 @@ pub(crate) fn make_raw_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<As | |||
68 | // "Hello, \"World!\""; | 67 | // "Hello, \"World!\""; |
69 | // } | 68 | // } |
70 | // ``` | 69 | // ``` |
71 | pub(crate) fn make_usual_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 70 | pub(crate) fn make_usual_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
72 | let token = ctx.find_token_at_offset(RAW_STRING)?; | 71 | let token = ctx.find_token_at_offset(RAW_STRING)?; |
73 | let text = token.text().as_str(); | 72 | let text = token.text().as_str(); |
74 | let usual_string_range = find_usual_string_range(text)?; | 73 | let usual_string_range = find_usual_string_range(text)?; |
75 | ctx.add_action(AssistId("make_usual_string"), "make usual string", |edit| { | 74 | ctx.add_assist(AssistId("make_usual_string"), "make usual string", |edit| { |
76 | edit.target(token.text_range()); | 75 | edit.target(token.text_range()); |
77 | // parse inside string to escape `"` | 76 | // parse inside string to escape `"` |
78 | let start_of_inside = usual_string_range.start().to_usize() + 1; | 77 | let start_of_inside = usual_string_range.start().to_usize() + 1; |
@@ -80,8 +79,7 @@ pub(crate) fn make_usual_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option< | |||
80 | let inside_str = &text[start_of_inside..end_of_inside]; | 79 | let inside_str = &text[start_of_inside..end_of_inside]; |
81 | let escaped = inside_str.escape_default().to_string(); | 80 | let escaped = inside_str.escape_default().to_string(); |
82 | edit.replace(token.text_range(), format!("\"{}\"", escaped)); | 81 | edit.replace(token.text_range(), format!("\"{}\"", escaped)); |
83 | }); | 82 | }) |
84 | ctx.build() | ||
85 | } | 83 | } |
86 | 84 | ||
87 | // Assist: add_hash | 85 | // Assist: add_hash |
@@ -99,14 +97,13 @@ pub(crate) fn make_usual_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option< | |||
99 | // r##"Hello, World!"##; | 97 | // r##"Hello, World!"##; |
100 | // } | 98 | // } |
101 | // ``` | 99 | // ``` |
102 | pub(crate) fn add_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 100 | pub(crate) fn add_hash(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
103 | let token = ctx.find_token_at_offset(RAW_STRING)?; | 101 | let token = ctx.find_token_at_offset(RAW_STRING)?; |
104 | ctx.add_action(AssistId("add_hash"), "add hash to raw string", |edit| { | 102 | ctx.add_assist(AssistId("add_hash"), "add hash to raw string", |edit| { |
105 | edit.target(token.text_range()); | 103 | edit.target(token.text_range()); |
106 | edit.insert(token.text_range().start() + TextUnit::of_char('r'), "#"); | 104 | edit.insert(token.text_range().start() + TextUnit::of_char('r'), "#"); |
107 | edit.insert(token.text_range().end(), "#"); | 105 | edit.insert(token.text_range().end(), "#"); |
108 | }); | 106 | }) |
109 | ctx.build() | ||
110 | } | 107 | } |
111 | 108 | ||
112 | // Assist: remove_hash | 109 | // Assist: remove_hash |
@@ -124,14 +121,14 @@ pub(crate) fn add_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | |||
124 | // r"Hello, World!"; | 121 | // r"Hello, World!"; |
125 | // } | 122 | // } |
126 | // ``` | 123 | // ``` |
127 | pub(crate) fn remove_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 124 | pub(crate) fn remove_hash(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
128 | let token = ctx.find_token_at_offset(RAW_STRING)?; | 125 | let token = ctx.find_token_at_offset(RAW_STRING)?; |
129 | let text = token.text().as_str(); | 126 | let text = token.text().as_str(); |
130 | if text.starts_with("r\"") { | 127 | if text.starts_with("r\"") { |
131 | // no hash to remove | 128 | // no hash to remove |
132 | return None; | 129 | return None; |
133 | } | 130 | } |
134 | ctx.add_action(AssistId("remove_hash"), "remove hash from raw string", |edit| { | 131 | ctx.add_assist(AssistId("remove_hash"), "remove hash from raw string", |edit| { |
135 | edit.target(token.text_range()); | 132 | edit.target(token.text_range()); |
136 | let result = &text[2..text.len() - 1]; | 133 | let result = &text[2..text.len() - 1]; |
137 | let result = if result.starts_with("\"") { | 134 | let result = if result.starts_with("\"") { |
@@ -142,8 +139,7 @@ pub(crate) fn remove_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist | |||
142 | result.to_owned() | 139 | result.to_owned() |
143 | }; | 140 | }; |
144 | edit.replace(token.text_range(), format!("r{}", result)); | 141 | edit.replace(token.text_range(), format!("r{}", result)); |
145 | }); | 142 | }) |
146 | ctx.build() | ||
147 | } | 143 | } |
148 | 144 | ||
149 | fn count_hashes(s: &str) -> usize { | 145 | fn count_hashes(s: &str) -> usize { |
@@ -159,10 +155,17 @@ fn count_hashes(s: &str) -> usize { | |||
159 | } | 155 | } |
160 | 156 | ||
161 | fn find_usual_string_range(s: &str) -> Option<TextRange> { | 157 | fn find_usual_string_range(s: &str) -> Option<TextRange> { |
162 | Some(TextRange::from_to( | 158 | let left_quote = s.find('"')?; |
163 | TextUnit::from(s.find('"')? as u32), | 159 | let right_quote = s.rfind('"')?; |
164 | TextUnit::from(s.rfind('"')? as u32), | 160 | if left_quote == right_quote { |
165 | )) | 161 | // `s` only contains one quote |
162 | None | ||
163 | } else { | ||
164 | Some(TextRange::from_to( | ||
165 | TextUnit::from(left_quote as u32), | ||
166 | TextUnit::from(right_quote as u32), | ||
167 | )) | ||
168 | } | ||
166 | } | 169 | } |
167 | 170 | ||
168 | #[cfg(test)] | 171 | #[cfg(test)] |
@@ -272,6 +275,30 @@ string"###; | |||
272 | } | 275 | } |
273 | 276 | ||
274 | #[test] | 277 | #[test] |
278 | fn make_raw_string_not_works_on_partial_string() { | ||
279 | check_assist_not_applicable( | ||
280 | make_raw_string, | ||
281 | r#" | ||
282 | fn f() { | ||
283 | let s = "foo<|> | ||
284 | } | ||
285 | "#, | ||
286 | ) | ||
287 | } | ||
288 | |||
289 | #[test] | ||
290 | fn make_usual_string_not_works_on_partial_string() { | ||
291 | check_assist_not_applicable( | ||
292 | make_usual_string, | ||
293 | r#" | ||
294 | fn main() { | ||
295 | let s = r#"bar<|> | ||
296 | } | ||
297 | "#, | ||
298 | ) | ||
299 | } | ||
300 | |||
301 | #[test] | ||
275 | fn add_hash_target() { | 302 | fn add_hash_target() { |
276 | check_assist_target( | 303 | check_assist_target( |
277 | add_hash, | 304 | add_hash, |
diff --git a/crates/ra_assists/src/assists/remove_dbg.rs b/crates/ra_assists/src/assists/remove_dbg.rs index 44b8de814..aedf8747f 100644 --- a/crates/ra_assists/src/assists/remove_dbg.rs +++ b/crates/ra_assists/src/assists/remove_dbg.rs | |||
@@ -21,7 +21,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
21 | // 92; | 21 | // 92; |
22 | // } | 22 | // } |
23 | // ``` | 23 | // ``` |
24 | pub(crate) fn remove_dbg(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 24 | pub(crate) fn remove_dbg(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
25 | let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?; | 25 | let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?; |
26 | 26 | ||
27 | if !is_valid_macrocall(¯o_call, "dbg")? { | 27 | if !is_valid_macrocall(¯o_call, "dbg")? { |
@@ -58,13 +58,11 @@ pub(crate) fn remove_dbg(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> | |||
58 | text.slice(without_parens).to_string() | 58 | text.slice(without_parens).to_string() |
59 | }; | 59 | }; |
60 | 60 | ||
61 | ctx.add_action(AssistId("remove_dbg"), "remove dbg!()", |edit| { | 61 | ctx.add_assist(AssistId("remove_dbg"), "remove dbg!()", |edit| { |
62 | edit.target(macro_call.syntax().text_range()); | 62 | edit.target(macro_call.syntax().text_range()); |
63 | edit.replace(macro_range, macro_content); | 63 | edit.replace(macro_range, macro_content); |
64 | edit.set_cursor(cursor_pos); | 64 | edit.set_cursor(cursor_pos); |
65 | }); | 65 | }) |
66 | |||
67 | ctx.build() | ||
68 | } | 66 | } |
69 | 67 | ||
70 | /// Verifies that the given macro_call actually matches the given name | 68 | /// Verifies that the given macro_call actually matches the given name |
diff --git a/crates/ra_assists/src/assists/replace_if_let_with_match.rs b/crates/ra_assists/src/assists/replace_if_let_with_match.rs index 58ef2ff20..dff84d865 100644 --- a/crates/ra_assists/src/assists/replace_if_let_with_match.rs +++ b/crates/ra_assists/src/assists/replace_if_let_with_match.rs | |||
@@ -31,7 +31,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
31 | // } | 31 | // } |
32 | // } | 32 | // } |
33 | // ``` | 33 | // ``` |
34 | pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 34 | pub(crate) fn replace_if_let_with_match(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
35 | let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; | 35 | let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; |
36 | let cond = if_expr.condition()?; | 36 | let cond = if_expr.condition()?; |
37 | let pat = cond.pat()?; | 37 | let pat = cond.pat()?; |
@@ -42,14 +42,12 @@ pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx<impl HirDatabase>) -> | |||
42 | ast::ElseBranch::IfExpr(_) => return None, | 42 | ast::ElseBranch::IfExpr(_) => return None, |
43 | }; | 43 | }; |
44 | 44 | ||
45 | ctx.add_action(AssistId("replace_if_let_with_match"), "replace with match", |edit| { | 45 | ctx.add_assist(AssistId("replace_if_let_with_match"), "replace with match", |edit| { |
46 | let match_expr = build_match_expr(expr, pat, then_block, else_block); | 46 | let match_expr = build_match_expr(expr, pat, then_block, else_block); |
47 | edit.target(if_expr.syntax().text_range()); | 47 | edit.target(if_expr.syntax().text_range()); |
48 | edit.replace_node_and_indent(if_expr.syntax(), match_expr); | 48 | edit.replace_node_and_indent(if_expr.syntax(), match_expr); |
49 | edit.set_cursor(if_expr.syntax().text_range().start()) | 49 | edit.set_cursor(if_expr.syntax().text_range().start()) |
50 | }); | 50 | }) |
51 | |||
52 | ctx.build() | ||
53 | } | 51 | } |
54 | 52 | ||
55 | fn build_match_expr( | 53 | fn build_match_expr( |
diff --git a/crates/ra_assists/src/assists/split_import.rs b/crates/ra_assists/src/assists/split_import.rs index 8d8a28987..5f8d6b0be 100644 --- a/crates/ra_assists/src/assists/split_import.rs +++ b/crates/ra_assists/src/assists/split_import.rs | |||
@@ -16,7 +16,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
16 | // ``` | 16 | // ``` |
17 | // use std::{collections::HashMap}; | 17 | // use std::{collections::HashMap}; |
18 | // ``` | 18 | // ``` |
19 | pub(crate) fn split_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 19 | pub(crate) fn split_import(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
20 | let colon_colon = ctx.find_token_at_offset(T![::])?; | 20 | let colon_colon = ctx.find_token_at_offset(T![::])?; |
21 | let path = ast::Path::cast(colon_colon.parent())?; | 21 | let path = ast::Path::cast(colon_colon.parent())?; |
22 | let top_path = successors(Some(path), |it| it.parent_path()).last()?; | 22 | let top_path = successors(Some(path), |it| it.parent_path()).last()?; |
@@ -32,14 +32,12 @@ pub(crate) fn split_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assis | |||
32 | None => top_path.syntax().text_range().end(), | 32 | None => top_path.syntax().text_range().end(), |
33 | }; | 33 | }; |
34 | 34 | ||
35 | ctx.add_action(AssistId("split_import"), "split import", |edit| { | 35 | ctx.add_assist(AssistId("split_import"), "split import", |edit| { |
36 | edit.target(colon_colon.text_range()); | 36 | edit.target(colon_colon.text_range()); |
37 | edit.insert(l_curly, "{"); | 37 | edit.insert(l_curly, "{"); |
38 | edit.insert(r_curly, "}"); | 38 | edit.insert(r_curly, "}"); |
39 | edit.set_cursor(l_curly + TextUnit::of_str("{")); | 39 | edit.set_cursor(l_curly + TextUnit::of_str("{")); |
40 | }); | 40 | }) |
41 | |||
42 | ctx.build() | ||
43 | } | 41 | } |
44 | 42 | ||
45 | #[cfg(test)] | 43 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs index ebe49aecf..1bee76f59 100644 --- a/crates/ra_assists/src/doc_tests/generated.rs +++ b/crates/ra_assists/src/doc_tests/generated.rs | |||
@@ -142,6 +142,21 @@ impl T for () { | |||
142 | } | 142 | } |
143 | 143 | ||
144 | #[test] | 144 | #[test] |
145 | fn doctest_add_import() { | ||
146 | check( | ||
147 | "add_import", | ||
148 | r#####" | ||
149 | fn process(map: std::collections::<|>HashMap<String, String>) {} | ||
150 | "#####, | ||
151 | r#####" | ||
152 | use std::collections::HashMap; | ||
153 | |||
154 | fn process(map: HashMap<String, String>) {} | ||
155 | "#####, | ||
156 | ) | ||
157 | } | ||
158 | |||
159 | #[test] | ||
145 | fn doctest_apply_demorgan() { | 160 | fn doctest_apply_demorgan() { |
146 | check( | 161 | check( |
147 | "apply_demorgan", | 162 | "apply_demorgan", |
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 7a1657d87..38599d4f1 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -11,7 +11,6 @@ mod marks; | |||
11 | mod doc_tests; | 11 | mod doc_tests; |
12 | 12 | ||
13 | use hir::db::HirDatabase; | 13 | use hir::db::HirDatabase; |
14 | use itertools::Itertools; | ||
15 | use ra_db::FileRange; | 14 | use ra_db::FileRange; |
16 | use ra_syntax::{TextRange, TextUnit}; | 15 | use ra_syntax::{TextRange, TextUnit}; |
17 | use ra_text_edit::TextEdit; | 16 | use ra_text_edit::TextEdit; |
@@ -51,10 +50,10 @@ where | |||
51 | .iter() | 50 | .iter() |
52 | .filter_map(|f| f(ctx.clone())) | 51 | .filter_map(|f| f(ctx.clone())) |
53 | .map(|a| match a { | 52 | .map(|a| match a { |
54 | Assist::Unresolved(labels) => labels, | 53 | Assist::Unresolved { label } => label, |
55 | Assist::Resolved(..) => unreachable!(), | 54 | Assist::Resolved { .. } => unreachable!(), |
56 | }) | 55 | }) |
57 | .concat() | 56 | .collect() |
58 | }) | 57 | }) |
59 | } | 58 | } |
60 | 59 | ||
@@ -73,10 +72,10 @@ where | |||
73 | .iter() | 72 | .iter() |
74 | .filter_map(|f| f(ctx.clone())) | 73 | .filter_map(|f| f(ctx.clone())) |
75 | .map(|a| match a { | 74 | .map(|a| match a { |
76 | Assist::Resolved(labels_actions) => labels_actions, | 75 | Assist::Resolved { label, action } => (label, action), |
77 | Assist::Unresolved(..) => unreachable!(), | 76 | Assist::Unresolved { .. } => unreachable!(), |
78 | }) | 77 | }) |
79 | .concat(); | 78 | .collect::<Vec<_>>(); |
80 | a.sort_by(|a, b| match (a.1.target, b.1.target) { | 79 | a.sort_by(|a, b| match (a.1.target, b.1.target) { |
81 | (Some(a), Some(b)) => a.len().cmp(&b.len()), | 80 | (Some(a), Some(b)) => a.len().cmp(&b.len()), |
82 | (Some(_), None) => Ordering::Less, | 81 | (Some(_), None) => Ordering::Less, |
@@ -159,51 +158,17 @@ mod helpers { | |||
159 | before: &str, | 158 | before: &str, |
160 | after: &str, | 159 | after: &str, |
161 | ) { | 160 | ) { |
162 | check_assist_nth_action(assist, before, after, 0) | ||
163 | } | ||
164 | |||
165 | pub(crate) fn check_assist_range( | ||
166 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, | ||
167 | before: &str, | ||
168 | after: &str, | ||
169 | ) { | ||
170 | check_assist_range_nth_action(assist, before, after, 0) | ||
171 | } | ||
172 | |||
173 | pub(crate) fn check_assist_target( | ||
174 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, | ||
175 | before: &str, | ||
176 | target: &str, | ||
177 | ) { | ||
178 | check_assist_target_nth_action(assist, before, target, 0) | ||
179 | } | ||
180 | |||
181 | pub(crate) fn check_assist_range_target( | ||
182 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, | ||
183 | before: &str, | ||
184 | target: &str, | ||
185 | ) { | ||
186 | check_assist_range_target_nth_action(assist, before, target, 0) | ||
187 | } | ||
188 | |||
189 | pub(crate) fn check_assist_nth_action( | ||
190 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, | ||
191 | before: &str, | ||
192 | after: &str, | ||
193 | index: usize, | ||
194 | ) { | ||
195 | let (before_cursor_pos, before) = extract_offset(before); | 161 | let (before_cursor_pos, before) = extract_offset(before); |
196 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 162 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); |
197 | let frange = | 163 | let frange = |
198 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; | 164 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; |
199 | let assist = | 165 | let assist = |
200 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); | 166 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); |
201 | let labels_actions = match assist { | 167 | let action = match assist { |
202 | Assist::Unresolved(_) => unreachable!(), | 168 | Assist::Unresolved { .. } => unreachable!(), |
203 | Assist::Resolved(labels_actions) => labels_actions, | 169 | Assist::Resolved { action, .. } => action, |
204 | }; | 170 | }; |
205 | 171 | ||
206 | let (_, action) = labels_actions.get(index).expect("expect assist action at index"); | ||
207 | let actual = action.edit.apply(&before); | 172 | let actual = action.edit.apply(&before); |
208 | let actual_cursor_pos = match action.cursor_position { | 173 | let actual_cursor_pos = match action.cursor_position { |
209 | None => action | 174 | None => action |
@@ -216,23 +181,21 @@ mod helpers { | |||
216 | assert_eq_text!(after, &actual); | 181 | assert_eq_text!(after, &actual); |
217 | } | 182 | } |
218 | 183 | ||
219 | pub(crate) fn check_assist_range_nth_action( | 184 | pub(crate) fn check_assist_range( |
220 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, | 185 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, |
221 | before: &str, | 186 | before: &str, |
222 | after: &str, | 187 | after: &str, |
223 | index: usize, | ||
224 | ) { | 188 | ) { |
225 | let (range, before) = extract_range(before); | 189 | let (range, before) = extract_range(before); |
226 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 190 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); |
227 | let frange = FileRange { file_id, range }; | 191 | let frange = FileRange { file_id, range }; |
228 | let assist = | 192 | let assist = |
229 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); | 193 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); |
230 | let labels_actions = match assist { | 194 | let action = match assist { |
231 | Assist::Unresolved(_) => unreachable!(), | 195 | Assist::Unresolved { .. } => unreachable!(), |
232 | Assist::Resolved(labels_actions) => labels_actions, | 196 | Assist::Resolved { action, .. } => action, |
233 | }; | 197 | }; |
234 | 198 | ||
235 | let (_, action) = labels_actions.get(index).expect("expect assist action at index"); | ||
236 | let mut actual = action.edit.apply(&before); | 199 | let mut actual = action.edit.apply(&before); |
237 | if let Some(pos) = action.cursor_position { | 200 | if let Some(pos) = action.cursor_position { |
238 | actual = add_cursor(&actual, pos); | 201 | actual = add_cursor(&actual, pos); |
@@ -240,11 +203,10 @@ mod helpers { | |||
240 | assert_eq_text!(after, &actual); | 203 | assert_eq_text!(after, &actual); |
241 | } | 204 | } |
242 | 205 | ||
243 | pub(crate) fn check_assist_target_nth_action( | 206 | pub(crate) fn check_assist_target( |
244 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, | 207 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, |
245 | before: &str, | 208 | before: &str, |
246 | target: &str, | 209 | target: &str, |
247 | index: usize, | ||
248 | ) { | 210 | ) { |
249 | let (before_cursor_pos, before) = extract_offset(before); | 211 | let (before_cursor_pos, before) = extract_offset(before); |
250 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 212 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); |
@@ -252,33 +214,30 @@ mod helpers { | |||
252 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; | 214 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; |
253 | let assist = | 215 | let assist = |
254 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); | 216 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); |
255 | let labels_actions = match assist { | 217 | let action = match assist { |
256 | Assist::Unresolved(_) => unreachable!(), | 218 | Assist::Unresolved { .. } => unreachable!(), |
257 | Assist::Resolved(labels_actions) => labels_actions, | 219 | Assist::Resolved { action, .. } => action, |
258 | }; | 220 | }; |
259 | 221 | ||
260 | let (_, action) = labels_actions.get(index).expect("expect assist action at index"); | ||
261 | let range = action.target.expect("expected target on action"); | 222 | let range = action.target.expect("expected target on action"); |
262 | assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target); | 223 | assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target); |
263 | } | 224 | } |
264 | 225 | ||
265 | pub(crate) fn check_assist_range_target_nth_action( | 226 | pub(crate) fn check_assist_range_target( |
266 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, | 227 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, |
267 | before: &str, | 228 | before: &str, |
268 | target: &str, | 229 | target: &str, |
269 | index: usize, | ||
270 | ) { | 230 | ) { |
271 | let (range, before) = extract_range(before); | 231 | let (range, before) = extract_range(before); |
272 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 232 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); |
273 | let frange = FileRange { file_id, range }; | 233 | let frange = FileRange { file_id, range }; |
274 | let assist = | 234 | let assist = |
275 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); | 235 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); |
276 | let labels_actions = match assist { | 236 | let action = match assist { |
277 | Assist::Unresolved(_) => unreachable!(), | 237 | Assist::Unresolved { .. } => unreachable!(), |
278 | Assist::Resolved(labels_actions) => labels_actions, | 238 | Assist::Resolved { action, .. } => action, |
279 | }; | 239 | }; |
280 | 240 | ||
281 | let (_, action) = labels_actions.get(index).expect("expect assist action at index"); | ||
282 | let range = action.target.expect("expected target on action"); | 241 | let range = action.target.expect("expected target on action"); |
283 | assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target); | 242 | assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target); |
284 | } | 243 | } |
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index 1b2ce921a..a12da5be2 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs | |||
@@ -173,7 +173,7 @@ fn test_doc_comment_single_line_block_strips_suffix_whitespace() { | |||
173 | .ok() | 173 | .ok() |
174 | .unwrap(); | 174 | .unwrap(); |
175 | let module = file.syntax().descendants().find_map(Module::cast).unwrap(); | 175 | let module = file.syntax().descendants().find_map(Module::cast).unwrap(); |
176 | assert_eq!("this is mod foo", module.doc_comment_text().unwrap()); | 176 | assert_eq!("this is mod foo ", module.doc_comment_text().unwrap()); |
177 | } | 177 | } |
178 | 178 | ||
179 | #[test] | 179 | #[test] |
@@ -191,7 +191,27 @@ fn test_doc_comment_multi_line_block_strips_suffix() { | |||
191 | .ok() | 191 | .ok() |
192 | .unwrap(); | 192 | .unwrap(); |
193 | let module = file.syntax().descendants().find_map(Module::cast).unwrap(); | 193 | let module = file.syntax().descendants().find_map(Module::cast).unwrap(); |
194 | assert_eq!(" this\n is\n mod foo", module.doc_comment_text().unwrap()); | 194 | assert_eq!( |
195 | " this\n is\n mod foo\n ", | ||
196 | module.doc_comment_text().unwrap() | ||
197 | ); | ||
198 | } | ||
199 | |||
200 | #[test] | ||
201 | fn test_comments_preserve_trailing_whitespace() { | ||
202 | let file = SourceFile::parse( | ||
203 | r#" | ||
204 | /// Representation of a Realm. | ||
205 | /// In the specification these are called Realm Records. | ||
206 | struct Realm {}"#, | ||
207 | ) | ||
208 | .ok() | ||
209 | .unwrap(); | ||
210 | let def = file.syntax().descendants().find_map(StructDef::cast).unwrap(); | ||
211 | assert_eq!( | ||
212 | "Representation of a Realm. \nIn the specification these are called Realm Records.", | ||
213 | def.doc_comment_text().unwrap() | ||
214 | ); | ||
195 | } | 215 | } |
196 | 216 | ||
197 | #[test] | 217 | #[test] |
diff --git a/crates/ra_syntax/src/ast/traits.rs b/crates/ra_syntax/src/ast/traits.rs index f275a4955..76313684e 100644 --- a/crates/ra_syntax/src/ast/traits.rs +++ b/crates/ra_syntax/src/ast/traits.rs | |||
@@ -120,7 +120,7 @@ pub trait DocCommentsOwner: AstNode { | |||
120 | has_comments = true; | 120 | has_comments = true; |
121 | let prefix_len = comment.prefix().len(); | 121 | let prefix_len = comment.prefix().len(); |
122 | 122 | ||
123 | let line = comment.text().as_str(); | 123 | let line: &str = comment.text().as_str(); |
124 | 124 | ||
125 | // Determine if the prefix or prefix + 1 char is stripped | 125 | // Determine if the prefix or prefix + 1 char is stripped |
126 | let pos = | 126 | let pos = |
@@ -136,7 +136,10 @@ pub trait DocCommentsOwner: AstNode { | |||
136 | line.len() | 136 | line.len() |
137 | }; | 137 | }; |
138 | 138 | ||
139 | line[pos..end].trim_end().to_owned() | 139 | // Note that we do not trim the end of the line here |
140 | // since whitespace can have special meaning at the end | ||
141 | // of a line in markdown. | ||
142 | line[pos..end].to_owned() | ||
140 | }) | 143 | }) |
141 | .join("\n"); | 144 | .join("\n"); |
142 | 145 | ||