diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-02-07 16:28:33 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-02-07 16:28:33 +0000 |
commit | 5397f05bfe7f3b18229a65040c6685e762b2f9a3 (patch) | |
tree | a3c4aab400ffe1c84bd33e094a047798e7136d2d /crates/ra_assists | |
parent | 1996762b1f2b9cb196cc879f0ce26d28a3c450c8 (diff) | |
parent | d00add1f1fec59494c3c1a99c27937ae3891458d (diff) |
Merge #3049
3049: Introduce assists utils r=matklad a=matklad
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_assists')
-rw-r--r-- | crates/ra_assists/src/assist_ctx.rs | 25 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_custom_impl.rs (renamed from crates/ra_assists/src/assists/add_custom_impl.rs) | 0 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_derive.rs (renamed from crates/ra_assists/src/assists/add_derive.rs) | 0 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_explicit_type.rs (renamed from crates/ra_assists/src/assists/add_explicit_type.rs) | 0 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_impl.rs (renamed from crates/ra_assists/src/assists/add_impl.rs) | 0 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_import.rs (renamed from crates/ra_assists/src/assists/add_import.rs) | 0 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_missing_impl_members.rs (renamed from crates/ra_assists/src/assists/add_missing_impl_members.rs) | 0 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_new.rs (renamed from crates/ra_assists/src/assists/add_new.rs) | 0 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/apply_demorgan.rs (renamed from crates/ra_assists/src/assists/apply_demorgan.rs) | 3 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/auto_import.rs (renamed from crates/ra_assists/src/assists/auto_import.rs) | 9 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/change_visibility.rs (renamed from crates/ra_assists/src/assists/change_visibility.rs) | 0 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/early_return.rs (renamed from crates/ra_assists/src/assists/early_return.rs) | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/fill_match_arms.rs (renamed from crates/ra_assists/src/assists/fill_match_arms.rs) | 0 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/flip_binexpr.rs (renamed from crates/ra_assists/src/assists/flip_binexpr.rs) | 0 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/flip_comma.rs (renamed from crates/ra_assists/src/assists/flip_comma.rs) | 0 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/flip_trait_bound.rs (renamed from crates/ra_assists/src/assists/flip_trait_bound.rs) | 0 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/inline_local_variable.rs (renamed from crates/ra_assists/src/assists/inline_local_variable.rs) | 0 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/introduce_variable.rs (renamed from crates/ra_assists/src/assists/introduce_variable.rs) | 0 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/invert_if.rs (renamed from crates/ra_assists/src/assists/invert_if.rs) | 25 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/merge_match_arms.rs (renamed from crates/ra_assists/src/assists/merge_match_arms.rs) | 0 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/move_bounds.rs (renamed from crates/ra_assists/src/assists/move_bounds.rs) | 0 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/move_guard.rs (renamed from crates/ra_assists/src/assists/move_guard.rs) | 0 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/raw_string.rs (renamed from crates/ra_assists/src/assists/raw_string.rs) | 0 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/remove_dbg.rs (renamed from crates/ra_assists/src/assists/remove_dbg.rs) | 0 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/replace_if_let_with_match.rs (renamed from crates/ra_assists/src/assists/replace_if_let_with_match.rs) | 0 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/split_import.rs (renamed from crates/ra_assists/src/assists/split_import.rs) | 0 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 111 | ||||
-rw-r--r-- | crates/ra_assists/src/utils.rs | 27 |
28 files changed, 95 insertions, 107 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index f32072dbd..81f999090 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs | |||
@@ -19,6 +19,8 @@ pub(crate) enum Assist { | |||
19 | Resolved { assist: ResolvedAssist }, | 19 | Resolved { assist: ResolvedAssist }, |
20 | } | 20 | } |
21 | 21 | ||
22 | pub(crate) type AssistHandler = fn(AssistCtx) -> Option<Assist>; | ||
23 | |||
22 | /// `AssistCtx` allows to apply an assist or check if it could be applied. | 24 | /// `AssistCtx` allows to apply an assist or check if it could be applied. |
23 | /// | 25 | /// |
24 | /// Assists use a somewhat over-engineered approach, given the current needs. The | 26 | /// Assists use a somewhat over-engineered approach, given the current needs. The |
@@ -57,7 +59,7 @@ pub(crate) struct AssistCtx<'a> { | |||
57 | should_compute_edit: bool, | 59 | should_compute_edit: bool, |
58 | } | 60 | } |
59 | 61 | ||
60 | impl<'a> Clone for AssistCtx<'a> { | 62 | impl Clone for AssistCtx<'_> { |
61 | fn clone(&self) -> Self { | 63 | fn clone(&self) -> Self { |
62 | AssistCtx { | 64 | AssistCtx { |
63 | db: self.db, | 65 | db: self.db, |
@@ -69,31 +71,18 @@ impl<'a> Clone for AssistCtx<'a> { | |||
69 | } | 71 | } |
70 | 72 | ||
71 | impl<'a> AssistCtx<'a> { | 73 | impl<'a> AssistCtx<'a> { |
72 | pub(crate) fn with_ctx<F, T>( | 74 | pub fn new(db: &RootDatabase, frange: FileRange, should_compute_edit: bool) -> AssistCtx { |
73 | db: &RootDatabase, | ||
74 | frange: FileRange, | ||
75 | should_compute_edit: bool, | ||
76 | f: F, | ||
77 | ) -> T | ||
78 | where | ||
79 | F: FnOnce(AssistCtx) -> T, | ||
80 | { | ||
81 | let parse = db.parse(frange.file_id); | 75 | let parse = db.parse(frange.file_id); |
82 | 76 | AssistCtx { db, frange, source_file: parse.tree(), should_compute_edit } | |
83 | let ctx = AssistCtx { db, frange, source_file: parse.tree(), should_compute_edit }; | ||
84 | f(ctx) | ||
85 | } | 77 | } |
86 | } | ||
87 | 78 | ||
88 | impl<'a> AssistCtx<'a> { | ||
89 | pub(crate) fn add_assist( | 79 | pub(crate) fn add_assist( |
90 | self, | 80 | self, |
91 | id: AssistId, | 81 | id: AssistId, |
92 | label: impl Into<String>, | 82 | label: impl Into<String>, |
93 | f: impl FnOnce(&mut ActionBuilder), | 83 | f: impl FnOnce(&mut ActionBuilder), |
94 | ) -> Option<Assist> { | 84 | ) -> Option<Assist> { |
95 | let label = AssistLabel { label: label.into(), id }; | 85 | let label = AssistLabel::new(label.into(), id); |
96 | assert!(label.label.chars().nth(0).unwrap().is_uppercase()); | ||
97 | 86 | ||
98 | let assist = if self.should_compute_edit { | 87 | let assist = if self.should_compute_edit { |
99 | let action = { | 88 | let action = { |
@@ -115,7 +104,7 @@ impl<'a> AssistCtx<'a> { | |||
115 | label: impl Into<String>, | 104 | label: impl Into<String>, |
116 | f: impl FnOnce() -> Vec<ActionBuilder>, | 105 | f: impl FnOnce() -> Vec<ActionBuilder>, |
117 | ) -> Option<Assist> { | 106 | ) -> Option<Assist> { |
118 | let label = AssistLabel { label: label.into(), id }; | 107 | let label = AssistLabel::new(label.into(), id); |
119 | let assist = if self.should_compute_edit { | 108 | let assist = if self.should_compute_edit { |
120 | let actions = f(); | 109 | let actions = f(); |
121 | assert!(!actions.is_empty(), "Assist cannot have no"); | 110 | assert!(!actions.is_empty(), "Assist cannot have no"); |
diff --git a/crates/ra_assists/src/assists/add_custom_impl.rs b/crates/ra_assists/src/handlers/add_custom_impl.rs index 7fdd816bf..7fdd816bf 100644 --- a/crates/ra_assists/src/assists/add_custom_impl.rs +++ b/crates/ra_assists/src/handlers/add_custom_impl.rs | |||
diff --git a/crates/ra_assists/src/assists/add_derive.rs b/crates/ra_assists/src/handlers/add_derive.rs index b0d1a0a80..b0d1a0a80 100644 --- a/crates/ra_assists/src/assists/add_derive.rs +++ b/crates/ra_assists/src/handlers/add_derive.rs | |||
diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/handlers/add_explicit_type.rs index 2cb9d2f48..2cb9d2f48 100644 --- a/crates/ra_assists/src/assists/add_explicit_type.rs +++ b/crates/ra_assists/src/handlers/add_explicit_type.rs | |||
diff --git a/crates/ra_assists/src/assists/add_impl.rs b/crates/ra_assists/src/handlers/add_impl.rs index 241b085fd..241b085fd 100644 --- a/crates/ra_assists/src/assists/add_impl.rs +++ b/crates/ra_assists/src/handlers/add_impl.rs | |||
diff --git a/crates/ra_assists/src/assists/add_import.rs b/crates/ra_assists/src/handlers/add_import.rs index f03dddac8..f03dddac8 100644 --- a/crates/ra_assists/src/assists/add_import.rs +++ b/crates/ra_assists/src/handlers/add_import.rs | |||
diff --git a/crates/ra_assists/src/assists/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs index 448697d31..448697d31 100644 --- a/crates/ra_assists/src/assists/add_missing_impl_members.rs +++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs | |||
diff --git a/crates/ra_assists/src/assists/add_new.rs b/crates/ra_assists/src/handlers/add_new.rs index a08639311..a08639311 100644 --- a/crates/ra_assists/src/assists/add_new.rs +++ b/crates/ra_assists/src/handlers/add_new.rs | |||
diff --git a/crates/ra_assists/src/assists/apply_demorgan.rs b/crates/ra_assists/src/handlers/apply_demorgan.rs index ba08a8223..239807e24 100644 --- a/crates/ra_assists/src/assists/apply_demorgan.rs +++ b/crates/ra_assists/src/handlers/apply_demorgan.rs | |||
@@ -1,7 +1,6 @@ | |||
1 | use super::invert_if::invert_boolean_expression; | ||
2 | use ra_syntax::ast::{self, AstNode}; | 1 | use ra_syntax::ast::{self, AstNode}; |
3 | 2 | ||
4 | use crate::{Assist, AssistCtx, AssistId}; | 3 | use crate::{utils::invert_boolean_expression, Assist, AssistCtx, AssistId}; |
5 | 4 | ||
6 | // Assist: apply_demorgan | 5 | // Assist: apply_demorgan |
7 | // | 6 | // |
diff --git a/crates/ra_assists/src/assists/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index 10c4b7d7c..84b5474f9 100644 --- a/crates/ra_assists/src/assists/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | use hir::ModPath; | 1 | use hir::ModPath; |
2 | use ra_ide_db::imports_locator::ImportsLocator; | ||
2 | use ra_syntax::{ | 3 | use ra_syntax::{ |
3 | ast::{self, AstNode}, | 4 | ast::{self, AstNode}, |
4 | SyntaxNode, | 5 | SyntaxNode, |
@@ -8,7 +9,7 @@ use crate::{ | |||
8 | assist_ctx::{ActionBuilder, Assist, AssistCtx}, | 9 | assist_ctx::{ActionBuilder, Assist, AssistCtx}, |
9 | auto_import_text_edit, AssistId, | 10 | auto_import_text_edit, AssistId, |
10 | }; | 11 | }; |
11 | use ra_ide_db::imports_locator::ImportsLocator; | 12 | use std::collections::BTreeSet; |
12 | 13 | ||
13 | // Assist: auto_import | 14 | // Assist: auto_import |
14 | // | 15 | // |
@@ -60,7 +61,8 @@ pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> { | |||
60 | .filter_map(|module_def| module_with_name_to_import.find_use_path(ctx.db, module_def)) | 61 | .filter_map(|module_def| module_with_name_to_import.find_use_path(ctx.db, module_def)) |
61 | .filter(|use_path| !use_path.segments.is_empty()) | 62 | .filter(|use_path| !use_path.segments.is_empty()) |
62 | .take(20) | 63 | .take(20) |
63 | .collect::<std::collections::BTreeSet<_>>(); | 64 | .collect::<BTreeSet<_>>(); |
65 | |||
64 | if proposed_imports.is_empty() { | 66 | if proposed_imports.is_empty() { |
65 | return None; | 67 | return None; |
66 | } | 68 | } |
@@ -82,9 +84,10 @@ fn import_to_action(import: ModPath, position: &SyntaxNode, anchor: &SyntaxNode) | |||
82 | 84 | ||
83 | #[cfg(test)] | 85 | #[cfg(test)] |
84 | mod tests { | 86 | mod tests { |
85 | use super::*; | ||
86 | use crate::helpers::{check_assist, check_assist_not_applicable}; | 87 | use crate::helpers::{check_assist, check_assist_not_applicable}; |
87 | 88 | ||
89 | use super::*; | ||
90 | |||
88 | #[test] | 91 | #[test] |
89 | fn applicable_when_found_an_import() { | 92 | fn applicable_when_found_an_import() { |
90 | check_assist( | 93 | check_assist( |
diff --git a/crates/ra_assists/src/assists/change_visibility.rs b/crates/ra_assists/src/handlers/change_visibility.rs index f325b6f92..f325b6f92 100644 --- a/crates/ra_assists/src/assists/change_visibility.rs +++ b/crates/ra_assists/src/handlers/change_visibility.rs | |||
diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs index 8f30dc586..22f88884f 100644 --- a/crates/ra_assists/src/assists/early_return.rs +++ b/crates/ra_assists/src/handlers/early_return.rs | |||
@@ -10,7 +10,7 @@ use ra_syntax::{ | |||
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
12 | assist_ctx::{Assist, AssistCtx}, | 12 | assist_ctx::{Assist, AssistCtx}, |
13 | assists::invert_if::invert_boolean_expression, | 13 | utils::invert_boolean_expression, |
14 | AssistId, | 14 | AssistId, |
15 | }; | 15 | }; |
16 | 16 | ||
diff --git a/crates/ra_assists/src/assists/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs index 0908fc246..0908fc246 100644 --- a/crates/ra_assists/src/assists/fill_match_arms.rs +++ b/crates/ra_assists/src/handlers/fill_match_arms.rs | |||
diff --git a/crates/ra_assists/src/assists/flip_binexpr.rs b/crates/ra_assists/src/handlers/flip_binexpr.rs index bfcc09e90..bfcc09e90 100644 --- a/crates/ra_assists/src/assists/flip_binexpr.rs +++ b/crates/ra_assists/src/handlers/flip_binexpr.rs | |||
diff --git a/crates/ra_assists/src/assists/flip_comma.rs b/crates/ra_assists/src/handlers/flip_comma.rs index 1dacf29f8..1dacf29f8 100644 --- a/crates/ra_assists/src/assists/flip_comma.rs +++ b/crates/ra_assists/src/handlers/flip_comma.rs | |||
diff --git a/crates/ra_assists/src/assists/flip_trait_bound.rs b/crates/ra_assists/src/handlers/flip_trait_bound.rs index f56769624..f56769624 100644 --- a/crates/ra_assists/src/assists/flip_trait_bound.rs +++ b/crates/ra_assists/src/handlers/flip_trait_bound.rs | |||
diff --git a/crates/ra_assists/src/assists/inline_local_variable.rs b/crates/ra_assists/src/handlers/inline_local_variable.rs index 91b588243..91b588243 100644 --- a/crates/ra_assists/src/assists/inline_local_variable.rs +++ b/crates/ra_assists/src/handlers/inline_local_variable.rs | |||
diff --git a/crates/ra_assists/src/assists/introduce_variable.rs b/crates/ra_assists/src/handlers/introduce_variable.rs index 7312ce687..7312ce687 100644 --- a/crates/ra_assists/src/assists/introduce_variable.rs +++ b/crates/ra_assists/src/handlers/introduce_variable.rs | |||
diff --git a/crates/ra_assists/src/assists/invert_if.rs b/crates/ra_assists/src/handlers/invert_if.rs index 983392f21..a594e7e0c 100644 --- a/crates/ra_assists/src/assists/invert_if.rs +++ b/crates/ra_assists/src/handlers/invert_if.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use ra_syntax::ast::{self, make, AstNode}; | 1 | use ra_syntax::ast::{self, AstNode}; |
2 | use ra_syntax::T; | 2 | use ra_syntax::T; |
3 | 3 | ||
4 | use crate::{Assist, AssistCtx, AssistId}; | 4 | use crate::{utils::invert_boolean_expression, Assist, AssistCtx, AssistId}; |
5 | 5 | ||
6 | // Assist: invert_if | 6 | // Assist: invert_if |
7 | // | 7 | // |
@@ -51,27 +51,6 @@ pub(crate) fn invert_if(ctx: AssistCtx) -> Option<Assist> { | |||
51 | None | 51 | None |
52 | } | 52 | } |
53 | 53 | ||
54 | pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr { | ||
55 | if let Some(expr) = invert_special_case(&expr) { | ||
56 | return expr; | ||
57 | } | ||
58 | make::expr_prefix(T![!], expr) | ||
59 | } | ||
60 | |||
61 | pub(crate) fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> { | ||
62 | match expr { | ||
63 | ast::Expr::BinExpr(bin) => match bin.op_kind()? { | ||
64 | ast::BinOp::NegatedEqualityTest => bin.replace_op(T![==]).map(|it| it.into()), | ||
65 | ast::BinOp::EqualityTest => bin.replace_op(T![!=]).map(|it| it.into()), | ||
66 | _ => None, | ||
67 | }, | ||
68 | ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::PrefixOp::Not => pe.expr(), | ||
69 | // FIXME: | ||
70 | // ast::Expr::Literal(true | false ) | ||
71 | _ => None, | ||
72 | } | ||
73 | } | ||
74 | |||
75 | #[cfg(test)] | 54 | #[cfg(test)] |
76 | mod tests { | 55 | mod tests { |
77 | use super::*; | 56 | use super::*; |
diff --git a/crates/ra_assists/src/assists/merge_match_arms.rs b/crates/ra_assists/src/handlers/merge_match_arms.rs index 670614dd8..670614dd8 100644 --- a/crates/ra_assists/src/assists/merge_match_arms.rs +++ b/crates/ra_assists/src/handlers/merge_match_arms.rs | |||
diff --git a/crates/ra_assists/src/assists/move_bounds.rs b/crates/ra_assists/src/handlers/move_bounds.rs index 90793b5fc..90793b5fc 100644 --- a/crates/ra_assists/src/assists/move_bounds.rs +++ b/crates/ra_assists/src/handlers/move_bounds.rs | |||
diff --git a/crates/ra_assists/src/assists/move_guard.rs b/crates/ra_assists/src/handlers/move_guard.rs index 2b91ce7c4..2b91ce7c4 100644 --- a/crates/ra_assists/src/assists/move_guard.rs +++ b/crates/ra_assists/src/handlers/move_guard.rs | |||
diff --git a/crates/ra_assists/src/assists/raw_string.rs b/crates/ra_assists/src/handlers/raw_string.rs index 2c0a1e126..2c0a1e126 100644 --- a/crates/ra_assists/src/assists/raw_string.rs +++ b/crates/ra_assists/src/handlers/raw_string.rs | |||
diff --git a/crates/ra_assists/src/assists/remove_dbg.rs b/crates/ra_assists/src/handlers/remove_dbg.rs index 5085649b4..5085649b4 100644 --- a/crates/ra_assists/src/assists/remove_dbg.rs +++ b/crates/ra_assists/src/handlers/remove_dbg.rs | |||
diff --git a/crates/ra_assists/src/assists/replace_if_let_with_match.rs b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs index e6cd50bc1..e6cd50bc1 100644 --- a/crates/ra_assists/src/assists/replace_if_let_with_match.rs +++ b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs | |||
diff --git a/crates/ra_assists/src/assists/split_import.rs b/crates/ra_assists/src/handlers/split_import.rs index 2c3f07a79..2c3f07a79 100644 --- a/crates/ra_assists/src/assists/split_import.rs +++ b/crates/ra_assists/src/handlers/split_import.rs | |||
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 3f3df3f96..eca6dec4b 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -9,16 +9,19 @@ mod assist_ctx; | |||
9 | mod marks; | 9 | mod marks; |
10 | #[cfg(test)] | 10 | #[cfg(test)] |
11 | mod doc_tests; | 11 | mod doc_tests; |
12 | mod utils; | ||
12 | pub mod ast_transform; | 13 | pub mod ast_transform; |
13 | 14 | ||
15 | use std::cmp::Ordering; | ||
16 | |||
14 | use either::Either; | 17 | use either::Either; |
15 | use ra_db::FileRange; | 18 | use ra_db::FileRange; |
16 | use ra_ide_db::RootDatabase; | 19 | use ra_ide_db::RootDatabase; |
17 | use ra_syntax::{TextRange, TextUnit}; | 20 | use ra_syntax::{TextRange, TextUnit}; |
18 | use ra_text_edit::TextEdit; | 21 | use ra_text_edit::TextEdit; |
19 | 22 | ||
20 | pub(crate) use crate::assist_ctx::{Assist, AssistCtx}; | 23 | pub(crate) use crate::assist_ctx::{Assist, AssistCtx, AssistHandler}; |
21 | pub use crate::assists::add_import::auto_import_text_edit; | 24 | pub use crate::handlers::add_import::auto_import_text_edit; |
22 | 25 | ||
23 | /// Unique identifier of the assist, should not be shown to the user | 26 | /// Unique identifier of the assist, should not be shown to the user |
24 | /// directly. | 27 | /// directly. |
@@ -32,11 +35,20 @@ pub struct AssistLabel { | |||
32 | pub id: AssistId, | 35 | pub id: AssistId, |
33 | } | 36 | } |
34 | 37 | ||
38 | impl AssistLabel { | ||
39 | pub(crate) fn new(label: String, id: AssistId) -> AssistLabel { | ||
40 | // FIXME: make fields private, so that this invariant can't be broken | ||
41 | assert!(label.chars().nth(0).unwrap().is_uppercase()); | ||
42 | AssistLabel { label: label.into(), id } | ||
43 | } | ||
44 | } | ||
45 | |||
35 | #[derive(Debug, Clone)] | 46 | #[derive(Debug, Clone)] |
36 | pub struct AssistAction { | 47 | pub struct AssistAction { |
37 | pub label: Option<String>, | 48 | pub label: Option<String>, |
38 | pub edit: TextEdit, | 49 | pub edit: TextEdit, |
39 | pub cursor_position: Option<TextUnit>, | 50 | pub cursor_position: Option<TextUnit>, |
51 | // FIXME: This belongs to `AssistLabel` | ||
40 | pub target: Option<TextRange>, | 52 | pub target: Option<TextRange>, |
41 | } | 53 | } |
42 | 54 | ||
@@ -60,16 +72,15 @@ impl ResolvedAssist { | |||
60 | /// Assists are returned in the "unresolved" state, that is only labels are | 72 | /// Assists are returned in the "unresolved" state, that is only labels are |
61 | /// returned, without actual edits. | 73 | /// returned, without actual edits. |
62 | pub fn unresolved_assists(db: &RootDatabase, range: FileRange) -> Vec<AssistLabel> { | 74 | pub fn unresolved_assists(db: &RootDatabase, range: FileRange) -> Vec<AssistLabel> { |
63 | AssistCtx::with_ctx(db, range, false, |ctx| { | 75 | let ctx = AssistCtx::new(db, range, false); |
64 | assists::all() | 76 | handlers::all() |
65 | .iter() | 77 | .iter() |
66 | .filter_map(|f| f(ctx.clone())) | 78 | .filter_map(|f| f(ctx.clone())) |
67 | .map(|a| match a { | 79 | .map(|a| match a { |
68 | Assist::Unresolved { label } => label, | 80 | Assist::Unresolved { label } => label, |
69 | Assist::Resolved { .. } => unreachable!(), | 81 | Assist::Resolved { .. } => unreachable!(), |
70 | }) | 82 | }) |
71 | .collect() | 83 | .collect() |
72 | }) | ||
73 | } | 84 | } |
74 | 85 | ||
75 | /// Return all the assists applicable at the given position. | 86 | /// Return all the assists applicable at the given position. |
@@ -77,22 +88,20 @@ pub fn unresolved_assists(db: &RootDatabase, range: FileRange) -> Vec<AssistLabe | |||
77 | /// Assists are returned in the "resolved" state, that is with edit fully | 88 | /// Assists are returned in the "resolved" state, that is with edit fully |
78 | /// computed. | 89 | /// computed. |
79 | pub fn resolved_assists(db: &RootDatabase, range: FileRange) -> Vec<ResolvedAssist> { | 90 | pub fn resolved_assists(db: &RootDatabase, range: FileRange) -> Vec<ResolvedAssist> { |
80 | AssistCtx::with_ctx(db, range, true, |ctx| { | 91 | let ctx = AssistCtx::new(db, range, true); |
81 | let mut a = assists::all() | 92 | let mut a = handlers::all() |
82 | .iter() | 93 | .iter() |
83 | .filter_map(|f| f(ctx.clone())) | 94 | .filter_map(|f| f(ctx.clone())) |
84 | .map(|a| match a { | 95 | .map(|a| match a { |
85 | Assist::Resolved { assist } => assist, | 96 | Assist::Resolved { assist } => assist, |
86 | Assist::Unresolved { .. } => unreachable!(), | 97 | Assist::Unresolved { .. } => unreachable!(), |
87 | }) | 98 | }) |
88 | .collect(); | 99 | .collect::<Vec<_>>(); |
89 | sort_assists(&mut a); | 100 | sort_assists(&mut a); |
90 | a | 101 | a |
91 | }) | ||
92 | } | 102 | } |
93 | 103 | ||
94 | fn sort_assists(assists: &mut Vec<ResolvedAssist>) { | 104 | fn sort_assists(assists: &mut [ResolvedAssist]) { |
95 | use std::cmp::Ordering; | ||
96 | assists.sort_by(|a, b| match (a.get_first_action().target, b.get_first_action().target) { | 105 | assists.sort_by(|a, b| match (a.get_first_action().target, b.get_first_action().target) { |
97 | (Some(a), Some(b)) => a.len().cmp(&b.len()), | 106 | (Some(a), Some(b)) => a.len().cmp(&b.len()), |
98 | (Some(_), None) => Ordering::Less, | 107 | (Some(_), None) => Ordering::Less, |
@@ -101,8 +110,8 @@ fn sort_assists(assists: &mut Vec<ResolvedAssist>) { | |||
101 | }); | 110 | }); |
102 | } | 111 | } |
103 | 112 | ||
104 | mod assists { | 113 | mod handlers { |
105 | use crate::{Assist, AssistCtx}; | 114 | use crate::AssistHandler; |
106 | 115 | ||
107 | mod add_derive; | 116 | mod add_derive; |
108 | mod add_explicit_type; | 117 | mod add_explicit_type; |
@@ -130,7 +139,7 @@ mod assists { | |||
130 | mod move_bounds; | 139 | mod move_bounds; |
131 | mod early_return; | 140 | mod early_return; |
132 | 141 | ||
133 | pub(crate) fn all() -> &'static [fn(AssistCtx) -> Option<Assist>] { | 142 | pub(crate) fn all() -> &'static [AssistHandler] { |
134 | &[ | 143 | &[ |
135 | add_derive::add_derive, | 144 | add_derive::add_derive, |
136 | add_explicit_type::add_explicit_type, | 145 | add_explicit_type::add_explicit_type, |
@@ -175,7 +184,7 @@ mod helpers { | |||
175 | use ra_syntax::TextRange; | 184 | use ra_syntax::TextRange; |
176 | use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range}; | 185 | use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range}; |
177 | 186 | ||
178 | use crate::{Assist, AssistCtx}; | 187 | use crate::{Assist, AssistCtx, AssistHandler}; |
179 | 188 | ||
180 | pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { | 189 | pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { |
181 | let (mut db, file_id) = RootDatabase::with_single_file(text); | 190 | let (mut db, file_id) = RootDatabase::with_single_file(text); |
@@ -186,13 +195,13 @@ mod helpers { | |||
186 | (db, file_id) | 195 | (db, file_id) |
187 | } | 196 | } |
188 | 197 | ||
189 | pub(crate) fn check_assist(assist: fn(AssistCtx) -> Option<Assist>, before: &str, after: &str) { | 198 | pub(crate) fn check_assist(assist: AssistHandler, before: &str, after: &str) { |
190 | let (before_cursor_pos, before) = extract_offset(before); | 199 | let (before_cursor_pos, before) = extract_offset(before); |
191 | let (db, file_id) = with_single_file(&before); | 200 | let (db, file_id) = with_single_file(&before); |
192 | let frange = | 201 | let frange = |
193 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; | 202 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; |
194 | let assist = | 203 | let assist = |
195 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); | 204 | assist(AssistCtx::new(&db, frange, true)).expect("code action is not applicable"); |
196 | let action = match assist { | 205 | let action = match assist { |
197 | Assist::Unresolved { .. } => unreachable!(), | 206 | Assist::Unresolved { .. } => unreachable!(), |
198 | Assist::Resolved { assist } => assist.get_first_action(), | 207 | Assist::Resolved { assist } => assist.get_first_action(), |
@@ -210,16 +219,12 @@ mod helpers { | |||
210 | assert_eq_text!(after, &actual); | 219 | assert_eq_text!(after, &actual); |
211 | } | 220 | } |
212 | 221 | ||
213 | pub(crate) fn check_assist_range( | 222 | pub(crate) fn check_assist_range(assist: AssistHandler, before: &str, after: &str) { |
214 | assist: fn(AssistCtx) -> Option<Assist>, | ||
215 | before: &str, | ||
216 | after: &str, | ||
217 | ) { | ||
218 | let (range, before) = extract_range(before); | 223 | let (range, before) = extract_range(before); |
219 | let (db, file_id) = with_single_file(&before); | 224 | let (db, file_id) = with_single_file(&before); |
220 | let frange = FileRange { file_id, range }; | 225 | let frange = FileRange { file_id, range }; |
221 | let assist = | 226 | let assist = |
222 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); | 227 | assist(AssistCtx::new(&db, frange, true)).expect("code action is not applicable"); |
223 | let action = match assist { | 228 | let action = match assist { |
224 | Assist::Unresolved { .. } => unreachable!(), | 229 | Assist::Unresolved { .. } => unreachable!(), |
225 | Assist::Resolved { assist } => assist.get_first_action(), | 230 | Assist::Resolved { assist } => assist.get_first_action(), |
@@ -232,17 +237,13 @@ mod helpers { | |||
232 | assert_eq_text!(after, &actual); | 237 | assert_eq_text!(after, &actual); |
233 | } | 238 | } |
234 | 239 | ||
235 | pub(crate) fn check_assist_target( | 240 | pub(crate) fn check_assist_target(assist: AssistHandler, before: &str, target: &str) { |
236 | assist: fn(AssistCtx) -> Option<Assist>, | ||
237 | before: &str, | ||
238 | target: &str, | ||
239 | ) { | ||
240 | let (before_cursor_pos, before) = extract_offset(before); | 241 | let (before_cursor_pos, before) = extract_offset(before); |
241 | let (db, file_id) = with_single_file(&before); | 242 | let (db, file_id) = with_single_file(&before); |
242 | let frange = | 243 | let frange = |
243 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; | 244 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; |
244 | let assist = | 245 | let assist = |
245 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); | 246 | assist(AssistCtx::new(&db, frange, true)).expect("code action is not applicable"); |
246 | let action = match assist { | 247 | let action = match assist { |
247 | Assist::Unresolved { .. } => unreachable!(), | 248 | Assist::Unresolved { .. } => unreachable!(), |
248 | Assist::Resolved { assist } => assist.get_first_action(), | 249 | Assist::Resolved { assist } => assist.get_first_action(), |
@@ -252,16 +253,12 @@ mod helpers { | |||
252 | assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target); | 253 | assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target); |
253 | } | 254 | } |
254 | 255 | ||
255 | pub(crate) fn check_assist_range_target( | 256 | pub(crate) fn check_assist_range_target(assist: AssistHandler, before: &str, target: &str) { |
256 | assist: fn(AssistCtx) -> Option<Assist>, | ||
257 | before: &str, | ||
258 | target: &str, | ||
259 | ) { | ||
260 | let (range, before) = extract_range(before); | 257 | let (range, before) = extract_range(before); |
261 | let (db, file_id) = with_single_file(&before); | 258 | let (db, file_id) = with_single_file(&before); |
262 | let frange = FileRange { file_id, range }; | 259 | let frange = FileRange { file_id, range }; |
263 | let assist = | 260 | let assist = |
264 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); | 261 | assist(AssistCtx::new(&db, frange, true)).expect("code action is not applicable"); |
265 | let action = match assist { | 262 | let action = match assist { |
266 | Assist::Unresolved { .. } => unreachable!(), | 263 | Assist::Unresolved { .. } => unreachable!(), |
267 | Assist::Resolved { assist } => assist.get_first_action(), | 264 | Assist::Resolved { assist } => assist.get_first_action(), |
@@ -271,26 +268,20 @@ mod helpers { | |||
271 | assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target); | 268 | assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target); |
272 | } | 269 | } |
273 | 270 | ||
274 | pub(crate) fn check_assist_not_applicable( | 271 | pub(crate) fn check_assist_not_applicable(assist: AssistHandler, before: &str) { |
275 | assist: fn(AssistCtx) -> Option<Assist>, | ||
276 | before: &str, | ||
277 | ) { | ||
278 | let (before_cursor_pos, before) = extract_offset(before); | 272 | let (before_cursor_pos, before) = extract_offset(before); |
279 | let (db, file_id) = with_single_file(&before); | 273 | let (db, file_id) = with_single_file(&before); |
280 | let frange = | 274 | let frange = |
281 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; | 275 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; |
282 | let assist = AssistCtx::with_ctx(&db, frange, true, assist); | 276 | let assist = assist(AssistCtx::new(&db, frange, true)); |
283 | assert!(assist.is_none()); | 277 | assert!(assist.is_none()); |
284 | } | 278 | } |
285 | 279 | ||
286 | pub(crate) fn check_assist_range_not_applicable( | 280 | pub(crate) fn check_assist_range_not_applicable(assist: AssistHandler, before: &str) { |
287 | assist: fn(AssistCtx) -> Option<Assist>, | ||
288 | before: &str, | ||
289 | ) { | ||
290 | let (range, before) = extract_range(before); | 281 | let (range, before) = extract_range(before); |
291 | let (db, file_id) = with_single_file(&before); | 282 | let (db, file_id) = with_single_file(&before); |
292 | let frange = FileRange { file_id, range }; | 283 | let frange = FileRange { file_id, range }; |
293 | let assist = AssistCtx::with_ctx(&db, frange, true, assist); | 284 | let assist = assist(AssistCtx::new(&db, frange, true)); |
294 | assert!(assist.is_none()); | 285 | assert!(assist.is_none()); |
295 | } | 286 | } |
296 | } | 287 | } |
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs new file mode 100644 index 000000000..0d5722295 --- /dev/null +++ b/crates/ra_assists/src/utils.rs | |||
@@ -0,0 +1,27 @@ | |||
1 | //! Assorted functions shared by several assists. | ||
2 | |||
3 | use ra_syntax::{ | ||
4 | ast::{self, make}, | ||
5 | T, | ||
6 | }; | ||
7 | |||
8 | pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr { | ||
9 | if let Some(expr) = invert_special_case(&expr) { | ||
10 | return expr; | ||
11 | } | ||
12 | make::expr_prefix(T![!], expr) | ||
13 | } | ||
14 | |||
15 | fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> { | ||
16 | match expr { | ||
17 | ast::Expr::BinExpr(bin) => match bin.op_kind()? { | ||
18 | ast::BinOp::NegatedEqualityTest => bin.replace_op(T![==]).map(|it| it.into()), | ||
19 | ast::BinOp::EqualityTest => bin.replace_op(T![!=]).map(|it| it.into()), | ||
20 | _ => None, | ||
21 | }, | ||
22 | ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::PrefixOp::Not => pe.expr(), | ||
23 | // FIXME: | ||
24 | // ast::Expr::Literal(true | false ) | ||
25 | _ => None, | ||
26 | } | ||
27 | } | ||