diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-24 12:52:44 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-24 12:52:44 +0000 |
commit | 043991662c648d86876be44bc3405ee3a60c37a1 (patch) | |
tree | 45fcbfb58cce8650f67ce4f41e1b5564ef49bfb3 /crates | |
parent | f6f160391db945a0dcc2f73b38926d6919f7c566 (diff) | |
parent | c110e72a115bbec36413bd440812dfe9194c58e2 (diff) |
Merge #889
889: Refactor assits r=matklad a=matklad
* assign unique IDs to assists so that clients could do custom stuff
* specify kinds for assists,
* make introduce_variable a `refactoring.extract` and make it available only when expression is selected
* introduce marks to assists
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_assists/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/add_derive.rs | 4 | ||||
-rw-r--r-- | crates/ra_assists/src/add_impl.rs | 4 | ||||
-rw-r--r-- | crates/ra_assists/src/assist_ctx.rs | 5 | ||||
-rw-r--r-- | crates/ra_assists/src/auto_import.rs | 16 | ||||
-rw-r--r-- | crates/ra_assists/src/change_visibility.rs | 8 | ||||
-rw-r--r-- | crates/ra_assists/src/fill_match_arms.rs | 4 | ||||
-rw-r--r-- | crates/ra_assists/src/flip_comma.rs | 4 | ||||
-rw-r--r-- | crates/ra_assists/src/introduce_variable.rs | 146 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 27 | ||||
-rw-r--r-- | crates/ra_assists/src/marks.rs | 5 | ||||
-rw-r--r-- | crates/ra_assists/src/remove_dbg.rs | 4 | ||||
-rw-r--r-- | crates/ra_assists/src/replace_if_let_with_match.rs | 4 | ||||
-rw-r--r-- | crates/ra_assists/src/split_import.rs | 4 | ||||
-rw-r--r-- | crates/ra_ide_api/src/assists.rs | 16 | ||||
-rw-r--r-- | crates/ra_ide_api/src/lib.rs | 3 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 48 | ||||
-rw-r--r-- | crates/ra_lsp_server/tests/heavy_tests/main.rs | 11 |
18 files changed, 182 insertions, 133 deletions
diff --git a/crates/ra_assists/Cargo.toml b/crates/ra_assists/Cargo.toml index 880bc4b18..d4056a349 100644 --- a/crates/ra_assists/Cargo.toml +++ b/crates/ra_assists/Cargo.toml | |||
@@ -13,6 +13,4 @@ ra_text_edit = { path = "../ra_text_edit" } | |||
13 | ra_fmt = { path = "../ra_fmt" } | 13 | ra_fmt = { path = "../ra_fmt" } |
14 | ra_db = { path = "../ra_db" } | 14 | ra_db = { path = "../ra_db" } |
15 | hir = { path = "../ra_hir", package = "ra_hir" } | 15 | hir = { path = "../ra_hir", package = "ra_hir" } |
16 | |||
17 | [dev-dependencies] | ||
18 | test_utils = { path = "../test_utils" } | 16 | test_utils = { path = "../test_utils" } |
diff --git a/crates/ra_assists/src/add_derive.rs b/crates/ra_assists/src/add_derive.rs index 0556dd69c..e91b5eb8d 100644 --- a/crates/ra_assists/src/add_derive.rs +++ b/crates/ra_assists/src/add_derive.rs | |||
@@ -5,12 +5,12 @@ use ra_syntax::{ | |||
5 | TextUnit, | 5 | TextUnit, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use crate::{AssistCtx, Assist}; | 8 | use crate::{AssistCtx, Assist, AssistId}; |
9 | 9 | ||
10 | pub(crate) fn add_derive(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 10 | pub(crate) fn add_derive(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
11 | let nominal = ctx.node_at_offset::<ast::NominalDef>()?; | 11 | let nominal = ctx.node_at_offset::<ast::NominalDef>()?; |
12 | let node_start = derive_insertion_offset(nominal)?; | 12 | let node_start = derive_insertion_offset(nominal)?; |
13 | ctx.add_action("add `#[derive]`", |edit| { | 13 | ctx.add_action(AssistId("add_derive"), "add `#[derive]`", |edit| { |
14 | let derive_attr = nominal | 14 | let derive_attr = nominal |
15 | .attrs() | 15 | .attrs() |
16 | .filter_map(|x| x.as_call()) | 16 | .filter_map(|x| x.as_call()) |
diff --git a/crates/ra_assists/src/add_impl.rs b/crates/ra_assists/src/add_impl.rs index b40b9cc0c..b292f188d 100644 --- a/crates/ra_assists/src/add_impl.rs +++ b/crates/ra_assists/src/add_impl.rs | |||
@@ -5,12 +5,12 @@ use ra_syntax::{ | |||
5 | TextUnit, | 5 | TextUnit, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use crate::{AssistCtx, Assist}; | 8 | use crate::{AssistCtx, Assist, AssistId}; |
9 | 9 | ||
10 | pub(crate) fn add_impl(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 10 | pub(crate) fn add_impl(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
11 | let nominal = ctx.node_at_offset::<ast::NominalDef>()?; | 11 | let nominal = ctx.node_at_offset::<ast::NominalDef>()?; |
12 | let name = nominal.name()?; | 12 | let name = nominal.name()?; |
13 | ctx.add_action("add impl", |edit| { | 13 | ctx.add_action(AssistId("add_impl"), "add impl", |edit| { |
14 | edit.target(nominal.syntax().range()); | 14 | edit.target(nominal.syntax().range()); |
15 | let type_params = nominal.type_param_list(); | 15 | let type_params = nominal.type_param_list(); |
16 | let start_offset = nominal.syntax().range().end(); | 16 | let start_offset = nominal.syntax().range().end(); |
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index e9c4f0a23..4ad21c74b 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs | |||
@@ -7,7 +7,7 @@ use ra_syntax::{ | |||
7 | }; | 7 | }; |
8 | use ra_fmt::{leading_indent, reindent}; | 8 | use ra_fmt::{leading_indent, reindent}; |
9 | 9 | ||
10 | use crate::{AssistLabel, AssistAction}; | 10 | use crate::{AssistLabel, AssistAction, AssistId}; |
11 | 11 | ||
12 | #[derive(Clone, Debug)] | 12 | #[derive(Clone, Debug)] |
13 | pub(crate) enum Assist { | 13 | pub(crate) enum Assist { |
@@ -81,10 +81,11 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { | |||
81 | 81 | ||
82 | pub(crate) fn add_action( | 82 | pub(crate) fn add_action( |
83 | &mut self, | 83 | &mut self, |
84 | id: AssistId, | ||
84 | label: impl Into<String>, | 85 | label: impl Into<String>, |
85 | f: impl FnOnce(&mut AssistBuilder), | 86 | f: impl FnOnce(&mut AssistBuilder), |
86 | ) -> &mut Self { | 87 | ) -> &mut Self { |
87 | let label = AssistLabel { label: label.into() }; | 88 | let label = AssistLabel { label: label.into(), id }; |
88 | match &mut self.assist { | 89 | match &mut self.assist { |
89 | Assist::Unresolved(labels) => labels.push(label), | 90 | Assist::Unresolved(labels) => labels.push(label), |
90 | Assist::Resolved(labels_actions) => { | 91 | Assist::Resolved(labels_actions) => { |
diff --git a/crates/ra_assists/src/auto_import.rs b/crates/ra_assists/src/auto_import.rs index 105c888d5..685dbed06 100644 --- a/crates/ra_assists/src/auto_import.rs +++ b/crates/ra_assists/src/auto_import.rs | |||
@@ -4,7 +4,10 @@ use ra_syntax::{ | |||
4 | ast::{ self, NameOwner }, AstNode, SyntaxNode, Direction, TextRange, | 4 | ast::{ self, NameOwner }, AstNode, SyntaxNode, Direction, TextRange, |
5 | SyntaxKind::{ PATH, PATH_SEGMENT, COLONCOLON, COMMA } | 5 | SyntaxKind::{ PATH, PATH_SEGMENT, COLONCOLON, COMMA } |
6 | }; | 6 | }; |
7 | use crate::assist_ctx::{AssistCtx, Assist, AssistBuilder}; | 7 | use crate::{ |
8 | AssistId, | ||
9 | assist_ctx::{AssistCtx, Assist, AssistBuilder}, | ||
10 | }; | ||
8 | 11 | ||
9 | fn collect_path_segments(path: &ast::Path) -> Option<Vec<&ast::PathSegment>> { | 12 | fn collect_path_segments(path: &ast::Path) -> Option<Vec<&ast::PathSegment>> { |
10 | let mut v = Vec::new(); | 13 | let mut v = Vec::new(); |
@@ -526,6 +529,7 @@ pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist | |||
526 | if let Some(module) = path.syntax().ancestors().find_map(ast::Module::cast) { | 529 | if let Some(module) = path.syntax().ancestors().find_map(ast::Module::cast) { |
527 | if let (Some(item_list), Some(name)) = (module.item_list(), module.name()) { | 530 | if let (Some(item_list), Some(name)) = (module.item_list(), module.name()) { |
528 | ctx.add_action( | 531 | ctx.add_action( |
532 | AssistId("auto_import"), | ||
529 | format!("import {} in mod {}", fmt_segments(&segments), name.text()), | 533 | format!("import {} in mod {}", fmt_segments(&segments), name.text()), |
530 | |edit| { | 534 | |edit| { |
531 | apply_auto_import(item_list.syntax(), path, &segments, edit); | 535 | apply_auto_import(item_list.syntax(), path, &segments, edit); |
@@ -534,9 +538,13 @@ pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist | |||
534 | } | 538 | } |
535 | } else { | 539 | } else { |
536 | let current_file = node.ancestors().find_map(ast::SourceFile::cast)?; | 540 | let current_file = node.ancestors().find_map(ast::SourceFile::cast)?; |
537 | ctx.add_action(format!("import {} in the current file", fmt_segments(&segments)), |edit| { | 541 | ctx.add_action( |
538 | apply_auto_import(current_file.syntax(), path, &segments, edit); | 542 | AssistId("auto_import"), |
539 | }); | 543 | format!("import {} in the current file", fmt_segments(&segments)), |
544 | |edit| { | ||
545 | apply_auto_import(current_file.syntax(), path, &segments, edit); | ||
546 | }, | ||
547 | ); | ||
540 | } | 548 | } |
541 | 549 | ||
542 | ctx.build() | 550 | ctx.build() |
diff --git a/crates/ra_assists/src/change_visibility.rs b/crates/ra_assists/src/change_visibility.rs index c2ba897a4..50c1be5ae 100644 --- a/crates/ra_assists/src/change_visibility.rs +++ b/crates/ra_assists/src/change_visibility.rs | |||
@@ -5,7 +5,7 @@ use ra_syntax::{ | |||
5 | SyntaxKind::{VISIBILITY, FN_KW, MOD_KW, STRUCT_KW, ENUM_KW, TRAIT_KW, FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF, IDENT, WHITESPACE, COMMENT, ATTR}, | 5 | SyntaxKind::{VISIBILITY, FN_KW, MOD_KW, STRUCT_KW, ENUM_KW, TRAIT_KW, FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF, IDENT, WHITESPACE, COMMENT, ATTR}, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use crate::{AssistCtx, Assist}; | 8 | use crate::{AssistCtx, Assist, AssistId}; |
9 | 9 | ||
10 | pub(crate) fn change_visibility(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 10 | pub(crate) fn change_visibility(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
11 | if let Some(vis) = ctx.node_at_offset::<ast::Visibility>() { | 11 | if let Some(vis) = ctx.node_at_offset::<ast::Visibility>() { |
@@ -41,7 +41,7 @@ fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | |||
41 | (vis_offset(field.syntax()), ident.range()) | 41 | (vis_offset(field.syntax()), ident.range()) |
42 | }; | 42 | }; |
43 | 43 | ||
44 | ctx.add_action("make pub(crate)", |edit| { | 44 | ctx.add_action(AssistId("change_visibility"), "make pub(crate)", |edit| { |
45 | edit.target(target); | 45 | edit.target(target); |
46 | edit.insert(offset, "pub(crate) "); | 46 | edit.insert(offset, "pub(crate) "); |
47 | edit.set_cursor(offset); | 47 | edit.set_cursor(offset); |
@@ -63,7 +63,7 @@ fn vis_offset(node: &SyntaxNode) -> TextUnit { | |||
63 | 63 | ||
64 | fn change_vis(mut ctx: AssistCtx<impl HirDatabase>, vis: &ast::Visibility) -> Option<Assist> { | 64 | fn change_vis(mut ctx: AssistCtx<impl HirDatabase>, vis: &ast::Visibility) -> Option<Assist> { |
65 | if vis.syntax().text() == "pub" { | 65 | if vis.syntax().text() == "pub" { |
66 | ctx.add_action("change to pub(crate)", |edit| { | 66 | ctx.add_action(AssistId("change_visibility"), "change to pub(crate)", |edit| { |
67 | edit.target(vis.syntax().range()); | 67 | edit.target(vis.syntax().range()); |
68 | edit.replace(vis.syntax().range(), "pub(crate)"); | 68 | edit.replace(vis.syntax().range(), "pub(crate)"); |
69 | edit.set_cursor(vis.syntax().range().start()) | 69 | edit.set_cursor(vis.syntax().range().start()) |
@@ -72,7 +72,7 @@ fn change_vis(mut ctx: AssistCtx<impl HirDatabase>, vis: &ast::Visibility) -> Op | |||
72 | return ctx.build(); | 72 | return ctx.build(); |
73 | } | 73 | } |
74 | if vis.syntax().text() == "pub(crate)" { | 74 | if vis.syntax().text() == "pub(crate)" { |
75 | ctx.add_action("change to pub", |edit| { | 75 | ctx.add_action(AssistId("change_visibility"), "change to pub", |edit| { |
76 | edit.target(vis.syntax().range()); | 76 | edit.target(vis.syntax().range()); |
77 | edit.replace(vis.syntax().range(), "pub"); | 77 | edit.replace(vis.syntax().range(), "pub"); |
78 | edit.set_cursor(vis.syntax().range().start()); | 78 | edit.set_cursor(vis.syntax().range().start()); |
diff --git a/crates/ra_assists/src/fill_match_arms.rs b/crates/ra_assists/src/fill_match_arms.rs index 6bf6e7332..30020b56e 100644 --- a/crates/ra_assists/src/fill_match_arms.rs +++ b/crates/ra_assists/src/fill_match_arms.rs | |||
@@ -6,7 +6,7 @@ use hir::{ | |||
6 | }; | 6 | }; |
7 | use ra_syntax::ast::{self, AstNode}; | 7 | use ra_syntax::ast::{self, AstNode}; |
8 | 8 | ||
9 | use crate::{AssistCtx, Assist}; | 9 | use crate::{AssistCtx, Assist, AssistId}; |
10 | 10 | ||
11 | pub(crate) fn fill_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 11 | pub(crate) fn fill_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
12 | let match_expr = ctx.node_at_offset::<ast::MatchExpr>()?; | 12 | let match_expr = ctx.node_at_offset::<ast::MatchExpr>()?; |
@@ -37,7 +37,7 @@ pub(crate) fn fill_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<As | |||
37 | let enum_name = enum_def.name(ctx.db)?; | 37 | let enum_name = enum_def.name(ctx.db)?; |
38 | let db = ctx.db; | 38 | let db = ctx.db; |
39 | 39 | ||
40 | ctx.add_action("fill match arms", |edit| { | 40 | ctx.add_action(AssistId("fill_match_arms"), "fill match arms", |edit| { |
41 | let mut buf = format!("match {} {{\n", expr.syntax().text().to_string()); | 41 | let mut buf = format!("match {} {{\n", expr.syntax().text().to_string()); |
42 | let variants = enum_def.variants(db); | 42 | let variants = enum_def.variants(db); |
43 | for variant in variants { | 43 | for variant in variants { |
diff --git a/crates/ra_assists/src/flip_comma.rs b/crates/ra_assists/src/flip_comma.rs index 0d4a789fc..6b98cac68 100644 --- a/crates/ra_assists/src/flip_comma.rs +++ b/crates/ra_assists/src/flip_comma.rs | |||
@@ -5,13 +5,13 @@ use ra_syntax::{ | |||
5 | algo::non_trivia_sibling, | 5 | algo::non_trivia_sibling, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use crate::{AssistCtx, Assist}; | 8 | use crate::{AssistCtx, Assist, AssistId}; |
9 | 9 | ||
10 | pub(crate) fn flip_comma(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 10 | pub(crate) fn flip_comma(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
11 | let comma = ctx.leaf_at_offset().find(|leaf| leaf.kind() == COMMA)?; | 11 | let comma = ctx.leaf_at_offset().find(|leaf| leaf.kind() == COMMA)?; |
12 | let prev = non_trivia_sibling(comma, Direction::Prev)?; | 12 | let prev = non_trivia_sibling(comma, Direction::Prev)?; |
13 | let next = non_trivia_sibling(comma, Direction::Next)?; | 13 | let next = non_trivia_sibling(comma, Direction::Next)?; |
14 | ctx.add_action("flip comma", |edit| { | 14 | ctx.add_action(AssistId("flip_comma"), "flip comma", |edit| { |
15 | edit.target(comma.range()); | 15 | edit.target(comma.range()); |
16 | edit.replace(prev.range(), next.text()); | 16 | edit.replace(prev.range(), next.text()); |
17 | edit.replace(next.range(), prev.text()); | 17 | edit.replace(next.range(), prev.text()); |
diff --git a/crates/ra_assists/src/introduce_variable.rs b/crates/ra_assists/src/introduce_variable.rs index f0e012105..353bc4105 100644 --- a/crates/ra_assists/src/introduce_variable.rs +++ b/crates/ra_assists/src/introduce_variable.rs | |||
@@ -1,3 +1,4 @@ | |||
1 | use test_utils::tested_by; | ||
1 | use hir::db::HirDatabase; | 2 | use hir::db::HirDatabase; |
2 | use ra_syntax::{ | 3 | use ra_syntax::{ |
3 | ast::{self, AstNode}, | 4 | ast::{self, AstNode}, |
@@ -6,20 +7,24 @@ use ra_syntax::{ | |||
6 | }, SyntaxNode, TextUnit, | 7 | }, SyntaxNode, TextUnit, |
7 | }; | 8 | }; |
8 | 9 | ||
9 | use crate::{AssistCtx, Assist}; | 10 | use crate::{AssistCtx, Assist, AssistId}; |
10 | 11 | ||
11 | pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 12 | pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
13 | if ctx.frange.range.is_empty() { | ||
14 | return None; | ||
15 | } | ||
12 | let node = ctx.covering_node(); | 16 | let node = ctx.covering_node(); |
13 | if !valid_covering_node(node) { | 17 | if node.kind() == COMMENT { |
18 | tested_by!(introduce_var_in_comment_is_not_applicable); | ||
14 | return None; | 19 | return None; |
15 | } | 20 | } |
16 | let expr = node.ancestors().filter_map(valid_target_expr).next()?; | 21 | let expr = node.ancestors().find_map(valid_target_expr)?; |
17 | let (anchor_stmt, wrap_in_block) = anchor_stmt(expr)?; | 22 | let (anchor_stmt, wrap_in_block) = anchor_stmt(expr)?; |
18 | let indent = anchor_stmt.prev_sibling()?; | 23 | let indent = anchor_stmt.prev_sibling()?; |
19 | if indent.kind() != WHITESPACE { | 24 | if indent.kind() != WHITESPACE { |
20 | return None; | 25 | return None; |
21 | } | 26 | } |
22 | ctx.add_action("introduce variable", move |edit| { | 27 | ctx.add_action(AssistId("introduce_variable"), "introduce variable", move |edit| { |
23 | let mut buf = String::new(); | 28 | let mut buf = String::new(); |
24 | 29 | ||
25 | let cursor_offset = if wrap_in_block { | 30 | let cursor_offset = if wrap_in_block { |
@@ -38,6 +43,7 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option | |||
38 | false | 43 | false |
39 | }; | 44 | }; |
40 | if is_full_stmt { | 45 | if is_full_stmt { |
46 | tested_by!(test_introduce_var_expr_stmt); | ||
41 | if !full_stmt.unwrap().has_semi() { | 47 | if !full_stmt.unwrap().has_semi() { |
42 | buf.push_str(";"); | 48 | buf.push_str(";"); |
43 | } | 49 | } |
@@ -73,9 +79,6 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option | |||
73 | ctx.build() | 79 | ctx.build() |
74 | } | 80 | } |
75 | 81 | ||
76 | fn valid_covering_node(node: &SyntaxNode) -> bool { | ||
77 | node.kind() != COMMENT | ||
78 | } | ||
79 | /// Check whether the node is a valid expression which can be extracted to a variable. | 82 | /// Check whether the node is a valid expression which can be extracted to a variable. |
80 | /// In general that's true for any expression, but in some cases that would produce invalid code. | 83 | /// In general that's true for any expression, but in some cases that would produce invalid code. |
81 | fn valid_target_expr(node: &SyntaxNode) -> Option<&ast::Expr> { | 84 | fn valid_target_expr(node: &SyntaxNode) -> Option<&ast::Expr> { |
@@ -101,6 +104,7 @@ fn anchor_stmt(expr: &ast::Expr) -> Option<(&SyntaxNode, bool)> { | |||
101 | 104 | ||
102 | if let Some(expr) = node.parent().and_then(ast::Block::cast).and_then(|it| it.expr()) { | 105 | if let Some(expr) = node.parent().and_then(ast::Block::cast).and_then(|it| it.expr()) { |
103 | if expr.syntax() == node { | 106 | if expr.syntax() == node { |
107 | tested_by!(test_introduce_var_last_expr); | ||
104 | return Some((node, false)); | 108 | return Some((node, false)); |
105 | } | 109 | } |
106 | } | 110 | } |
@@ -117,8 +121,11 @@ fn anchor_stmt(expr: &ast::Expr) -> Option<(&SyntaxNode, bool)> { | |||
117 | 121 | ||
118 | #[cfg(test)] | 122 | #[cfg(test)] |
119 | mod tests { | 123 | mod tests { |
124 | use test_utils::covers; | ||
125 | |||
126 | use crate::helpers::{check_assist_range_not_applicable, check_assist_range, check_assist_range_target}; | ||
127 | |||
120 | use super::*; | 128 | use super::*; |
121 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_range, check_assist_target, check_assist_range_target}; | ||
122 | 129 | ||
123 | #[test] | 130 | #[test] |
124 | fn test_introduce_var_simple() { | 131 | fn test_introduce_var_simple() { |
@@ -137,7 +144,17 @@ fn foo() { | |||
137 | } | 144 | } |
138 | 145 | ||
139 | #[test] | 146 | #[test] |
147 | fn introduce_var_in_comment_is_not_applicable() { | ||
148 | covers!(introduce_var_in_comment_is_not_applicable); | ||
149 | check_assist_range_not_applicable( | ||
150 | introduce_variable, | ||
151 | "fn main() { 1 + /* <|>comment<|> */ 1; }", | ||
152 | ); | ||
153 | } | ||
154 | |||
155 | #[test] | ||
140 | fn test_introduce_var_expr_stmt() { | 156 | fn test_introduce_var_expr_stmt() { |
157 | covers!(test_introduce_var_expr_stmt); | ||
141 | check_assist_range( | 158 | check_assist_range( |
142 | introduce_variable, | 159 | introduce_variable, |
143 | " | 160 | " |
@@ -149,6 +166,19 @@ fn foo() { | |||
149 | let <|>var_name = 1 + 1; | 166 | let <|>var_name = 1 + 1; |
150 | }", | 167 | }", |
151 | ); | 168 | ); |
169 | check_assist_range( | ||
170 | introduce_variable, | ||
171 | " | ||
172 | fn foo() { | ||
173 | <|>{ let x = 0; x }<|> | ||
174 | something_else(); | ||
175 | }", | ||
176 | " | ||
177 | fn foo() { | ||
178 | let <|>var_name = { let x = 0; x }; | ||
179 | something_else(); | ||
180 | }", | ||
181 | ); | ||
152 | } | 182 | } |
153 | 183 | ||
154 | #[test] | 184 | #[test] |
@@ -169,6 +199,7 @@ fn foo() { | |||
169 | 199 | ||
170 | #[test] | 200 | #[test] |
171 | fn test_introduce_var_last_expr() { | 201 | fn test_introduce_var_last_expr() { |
202 | covers!(test_introduce_var_last_expr); | ||
172 | check_assist_range( | 203 | check_assist_range( |
173 | introduce_variable, | 204 | introduce_variable, |
174 | " | 205 | " |
@@ -181,10 +212,6 @@ fn foo() { | |||
181 | bar(var_name) | 212 | bar(var_name) |
182 | }", | 213 | }", |
183 | ); | 214 | ); |
184 | } | ||
185 | |||
186 | #[test] | ||
187 | fn test_introduce_var_last_full_expr() { | ||
188 | check_assist_range( | 215 | check_assist_range( |
189 | introduce_variable, | 216 | introduce_variable, |
190 | " | 217 | " |
@@ -196,24 +223,7 @@ fn foo() { | |||
196 | let <|>var_name = bar(1 + 1); | 223 | let <|>var_name = bar(1 + 1); |
197 | var_name | 224 | var_name |
198 | }", | 225 | }", |
199 | ); | 226 | ) |
200 | } | ||
201 | |||
202 | #[test] | ||
203 | fn test_introduce_var_block_expr_second_to_last() { | ||
204 | check_assist_range( | ||
205 | introduce_variable, | ||
206 | " | ||
207 | fn foo() { | ||
208 | <|>{ let x = 0; x }<|> | ||
209 | something_else(); | ||
210 | }", | ||
211 | " | ||
212 | fn foo() { | ||
213 | let <|>var_name = { let x = 0; x }; | ||
214 | something_else(); | ||
215 | }", | ||
216 | ); | ||
217 | } | 227 | } |
218 | 228 | ||
219 | #[test] | 229 | #[test] |
@@ -309,11 +319,11 @@ fn main() { | |||
309 | 319 | ||
310 | #[test] | 320 | #[test] |
311 | fn test_introduce_var_path_simple() { | 321 | fn test_introduce_var_path_simple() { |
312 | check_assist( | 322 | check_assist_range( |
313 | introduce_variable, | 323 | introduce_variable, |
314 | " | 324 | " |
315 | fn main() { | 325 | fn main() { |
316 | let o = S<|>ome(true); | 326 | let o = <|>Some(true)<|>; |
317 | } | 327 | } |
318 | ", | 328 | ", |
319 | " | 329 | " |
@@ -327,11 +337,11 @@ fn main() { | |||
327 | 337 | ||
328 | #[test] | 338 | #[test] |
329 | fn test_introduce_var_path_method() { | 339 | fn test_introduce_var_path_method() { |
330 | check_assist( | 340 | check_assist_range( |
331 | introduce_variable, | 341 | introduce_variable, |
332 | " | 342 | " |
333 | fn main() { | 343 | fn main() { |
334 | let v = b<|>ar.foo(); | 344 | let v = <|>bar.foo()<|>; |
335 | } | 345 | } |
336 | ", | 346 | ", |
337 | " | 347 | " |
@@ -345,11 +355,11 @@ fn main() { | |||
345 | 355 | ||
346 | #[test] | 356 | #[test] |
347 | fn test_introduce_var_return() { | 357 | fn test_introduce_var_return() { |
348 | check_assist( | 358 | check_assist_range( |
349 | introduce_variable, | 359 | introduce_variable, |
350 | " | 360 | " |
351 | fn foo() -> u32 { | 361 | fn foo() -> u32 { |
352 | r<|>eturn 2 + 2; | 362 | <|>return 2 + 2<|>; |
353 | } | 363 | } |
354 | ", | 364 | ", |
355 | " | 365 | " |
@@ -363,13 +373,13 @@ fn foo() -> u32 { | |||
363 | 373 | ||
364 | #[test] | 374 | #[test] |
365 | fn test_introduce_var_does_not_add_extra_whitespace() { | 375 | fn test_introduce_var_does_not_add_extra_whitespace() { |
366 | check_assist( | 376 | check_assist_range( |
367 | introduce_variable, | 377 | introduce_variable, |
368 | " | 378 | " |
369 | fn foo() -> u32 { | 379 | fn foo() -> u32 { |
370 | 380 | ||
371 | 381 | ||
372 | r<|>eturn 2 + 2; | 382 | <|>return 2 + 2<|>; |
373 | } | 383 | } |
374 | ", | 384 | ", |
375 | " | 385 | " |
@@ -382,12 +392,12 @@ fn foo() -> u32 { | |||
382 | ", | 392 | ", |
383 | ); | 393 | ); |
384 | 394 | ||
385 | check_assist( | 395 | check_assist_range( |
386 | introduce_variable, | 396 | introduce_variable, |
387 | " | 397 | " |
388 | fn foo() -> u32 { | 398 | fn foo() -> u32 { |
389 | 399 | ||
390 | r<|>eturn 2 + 2; | 400 | <|>return 2 + 2<|>; |
391 | } | 401 | } |
392 | ", | 402 | ", |
393 | " | 403 | " |
@@ -399,7 +409,7 @@ fn foo() -> u32 { | |||
399 | ", | 409 | ", |
400 | ); | 410 | ); |
401 | 411 | ||
402 | check_assist( | 412 | check_assist_range( |
403 | introduce_variable, | 413 | introduce_variable, |
404 | " | 414 | " |
405 | fn foo() -> u32 { | 415 | fn foo() -> u32 { |
@@ -408,7 +418,7 @@ fn foo() -> u32 { | |||
408 | // bar | 418 | // bar |
409 | 419 | ||
410 | 420 | ||
411 | r<|>eturn 2 + 2; | 421 | <|>return 2 + 2<|>; |
412 | } | 422 | } |
413 | ", | 423 | ", |
414 | " | 424 | " |
@@ -427,12 +437,12 @@ fn foo() -> u32 { | |||
427 | 437 | ||
428 | #[test] | 438 | #[test] |
429 | fn test_introduce_var_break() { | 439 | fn test_introduce_var_break() { |
430 | check_assist( | 440 | check_assist_range( |
431 | introduce_variable, | 441 | introduce_variable, |
432 | " | 442 | " |
433 | fn main() { | 443 | fn main() { |
434 | let result = loop { | 444 | let result = loop { |
435 | b<|>reak 2 + 2; | 445 | <|>break 2 + 2<|>; |
436 | }; | 446 | }; |
437 | } | 447 | } |
438 | ", | 448 | ", |
@@ -449,11 +459,11 @@ fn main() { | |||
449 | 459 | ||
450 | #[test] | 460 | #[test] |
451 | fn test_introduce_var_for_cast() { | 461 | fn test_introduce_var_for_cast() { |
452 | check_assist( | 462 | check_assist_range( |
453 | introduce_variable, | 463 | introduce_variable, |
454 | " | 464 | " |
455 | fn main() { | 465 | fn main() { |
456 | let v = 0f32 a<|>s u32; | 466 | let v = <|>0f32 as u32<|>; |
457 | } | 467 | } |
458 | ", | 468 | ", |
459 | " | 469 | " |
@@ -467,57 +477,23 @@ fn main() { | |||
467 | 477 | ||
468 | #[test] | 478 | #[test] |
469 | fn test_introduce_var_for_return_not_applicable() { | 479 | fn test_introduce_var_for_return_not_applicable() { |
470 | check_assist_not_applicable( | 480 | check_assist_range_not_applicable(introduce_variable, "fn foo() { <|>return<|>; } "); |
471 | introduce_variable, | ||
472 | " | ||
473 | fn foo() { | ||
474 | r<|>eturn; | ||
475 | } | ||
476 | ", | ||
477 | ); | ||
478 | } | 481 | } |
479 | 482 | ||
480 | #[test] | 483 | #[test] |
481 | fn test_introduce_var_for_break_not_applicable() { | 484 | fn test_introduce_var_for_break_not_applicable() { |
482 | check_assist_not_applicable( | 485 | check_assist_range_not_applicable( |
483 | introduce_variable, | ||
484 | " | ||
485 | fn main() { | ||
486 | loop { | ||
487 | b<|>reak; | ||
488 | }; | ||
489 | } | ||
490 | ", | ||
491 | ); | ||
492 | } | ||
493 | |||
494 | #[test] | ||
495 | fn test_introduce_var_in_comment_not_applicable() { | ||
496 | check_assist_not_applicable( | ||
497 | introduce_variable, | 486 | introduce_variable, |
498 | " | 487 | "fn main() { loop { <|>break<|>; }; }", |
499 | fn main() { | ||
500 | let x = true; | ||
501 | let tuple = match x { | ||
502 | // c<|>omment | ||
503 | true => (2 + 2, true) | ||
504 | _ => (0, false) | ||
505 | }; | ||
506 | } | ||
507 | ", | ||
508 | ); | 488 | ); |
509 | } | 489 | } |
510 | 490 | ||
511 | // FIXME: This is not quite correct, but good enough(tm) for the sorting heuristic | 491 | // FIXME: This is not quite correct, but good enough(tm) for the sorting heuristic |
512 | #[test] | 492 | #[test] |
513 | fn introduce_var_target() { | 493 | fn introduce_var_target() { |
514 | check_assist_target( | 494 | check_assist_range_target( |
515 | introduce_variable, | 495 | introduce_variable, |
516 | " | 496 | "fn foo() -> u32 { <|>return 2 + 2<|>; }", |
517 | fn foo() -> u32 { | ||
518 | r<|>eturn 2 + 2; | ||
519 | } | ||
520 | ", | ||
521 | "2 + 2", | 497 | "2 + 2", |
522 | ); | 498 | ); |
523 | 499 | ||
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index e1e899edc..6c3d75d79 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -6,6 +6,7 @@ | |||
6 | //! becomes available. | 6 | //! becomes available. |
7 | 7 | ||
8 | mod assist_ctx; | 8 | mod assist_ctx; |
9 | mod marks; | ||
9 | 10 | ||
10 | use itertools::Itertools; | 11 | use itertools::Itertools; |
11 | 12 | ||
@@ -16,10 +17,16 @@ use hir::db::HirDatabase; | |||
16 | 17 | ||
17 | pub(crate) use crate::assist_ctx::{AssistCtx, Assist}; | 18 | pub(crate) use crate::assist_ctx::{AssistCtx, Assist}; |
18 | 19 | ||
20 | /// Unique identifier of the assist, should not be shown to the user | ||
21 | /// directly. | ||
22 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
23 | pub struct AssistId(pub &'static str); | ||
24 | |||
19 | #[derive(Debug, Clone)] | 25 | #[derive(Debug, Clone)] |
20 | pub struct AssistLabel { | 26 | pub struct AssistLabel { |
21 | /// Short description of the assist, as shown in the UI. | 27 | /// Short description of the assist, as shown in the UI. |
22 | pub label: String, | 28 | pub label: String, |
29 | pub id: AssistId, | ||
23 | } | 30 | } |
24 | 31 | ||
25 | #[derive(Debug, Clone)] | 32 | #[derive(Debug, Clone)] |
@@ -253,6 +260,17 @@ mod helpers { | |||
253 | let assist = AssistCtx::with_ctx(&db, frange, true, assist); | 260 | let assist = AssistCtx::with_ctx(&db, frange, true, assist); |
254 | assert!(assist.is_none()); | 261 | assert!(assist.is_none()); |
255 | } | 262 | } |
263 | |||
264 | pub(crate) fn check_assist_range_not_applicable( | ||
265 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, | ||
266 | before: &str, | ||
267 | ) { | ||
268 | let (range, before) = extract_range(before); | ||
269 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | ||
270 | let frange = FileRange { file_id, range }; | ||
271 | let assist = AssistCtx::with_ctx(&db, frange, true, assist); | ||
272 | assert!(assist.is_none()); | ||
273 | } | ||
256 | } | 274 | } |
257 | 275 | ||
258 | #[cfg(test)] | 276 | #[cfg(test)] |
@@ -260,7 +278,7 @@ mod tests { | |||
260 | use hir::mock::MockDatabase; | 278 | use hir::mock::MockDatabase; |
261 | use ra_syntax::TextRange; | 279 | use ra_syntax::TextRange; |
262 | use ra_db::FileRange; | 280 | use ra_db::FileRange; |
263 | use test_utils::{extract_offset}; | 281 | use test_utils::{extract_offset, extract_range}; |
264 | 282 | ||
265 | #[test] | 283 | #[test] |
266 | fn assist_order_field_struct() { | 284 | fn assist_order_field_struct() { |
@@ -280,16 +298,15 @@ mod tests { | |||
280 | fn assist_order_if_expr() { | 298 | fn assist_order_if_expr() { |
281 | let before = " | 299 | let before = " |
282 | pub fn test_some_range(a: int) -> bool { | 300 | pub fn test_some_range(a: int) -> bool { |
283 | if let 2..6 = 5<|> { | 301 | if let 2..6 = <|>5<|> { |
284 | true | 302 | true |
285 | } else { | 303 | } else { |
286 | false | 304 | false |
287 | } | 305 | } |
288 | }"; | 306 | }"; |
289 | let (before_cursor_pos, before) = extract_offset(before); | 307 | let (range, before) = extract_range(before); |
290 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 308 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); |
291 | let frange = | 309 | let frange = FileRange { file_id, range }; |
292 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; | ||
293 | let assists = super::assists(&db, frange); | 310 | let assists = super::assists(&db, frange); |
294 | let mut assists = assists.iter(); | 311 | let mut assists = assists.iter(); |
295 | 312 | ||
diff --git a/crates/ra_assists/src/marks.rs b/crates/ra_assists/src/marks.rs new file mode 100644 index 000000000..a29f9f658 --- /dev/null +++ b/crates/ra_assists/src/marks.rs | |||
@@ -0,0 +1,5 @@ | |||
1 | test_utils::marks!( | ||
2 | introduce_var_in_comment_is_not_applicable | ||
3 | test_introduce_var_expr_stmt | ||
4 | test_introduce_var_last_expr | ||
5 | ); | ||
diff --git a/crates/ra_assists/src/remove_dbg.rs b/crates/ra_assists/src/remove_dbg.rs index 2bed270a1..6ea48d909 100644 --- a/crates/ra_assists/src/remove_dbg.rs +++ b/crates/ra_assists/src/remove_dbg.rs | |||
@@ -6,7 +6,7 @@ use ra_syntax::{ | |||
6 | L_PAREN, R_PAREN, L_CURLY, R_CURLY, L_BRACK, R_BRACK, EXCL | 6 | L_PAREN, R_PAREN, L_CURLY, R_CURLY, L_BRACK, R_BRACK, EXCL |
7 | }, | 7 | }, |
8 | }; | 8 | }; |
9 | use crate::{AssistCtx, Assist}; | 9 | use crate::{AssistCtx, Assist, AssistId}; |
10 | 10 | ||
11 | pub(crate) fn remove_dbg(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 11 | pub(crate) fn remove_dbg(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
12 | let macro_call = ctx.node_at_offset::<ast::MacroCall>()?; | 12 | let macro_call = ctx.node_at_offset::<ast::MacroCall>()?; |
@@ -46,7 +46,7 @@ pub(crate) fn remove_dbg(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> | |||
46 | macro_args.text().slice(start..end).to_string() | 46 | macro_args.text().slice(start..end).to_string() |
47 | }; | 47 | }; |
48 | 48 | ||
49 | ctx.add_action("remove dbg!()", |edit| { | 49 | ctx.add_action(AssistId("remove_dbg"), "remove dbg!()", |edit| { |
50 | edit.target(macro_call.syntax().range()); | 50 | edit.target(macro_call.syntax().range()); |
51 | edit.replace(macro_range, macro_content); | 51 | edit.replace(macro_range, macro_content); |
52 | edit.set_cursor(cursor_pos); | 52 | edit.set_cursor(cursor_pos); |
diff --git a/crates/ra_assists/src/replace_if_let_with_match.rs b/crates/ra_assists/src/replace_if_let_with_match.rs index 87a2c1185..230573499 100644 --- a/crates/ra_assists/src/replace_if_let_with_match.rs +++ b/crates/ra_assists/src/replace_if_let_with_match.rs | |||
@@ -2,7 +2,7 @@ use ra_syntax::{AstNode, ast}; | |||
2 | use ra_fmt::extract_trivial_expression; | 2 | use ra_fmt::extract_trivial_expression; |
3 | use hir::db::HirDatabase; | 3 | use hir::db::HirDatabase; |
4 | 4 | ||
5 | use crate::{AssistCtx, Assist}; | 5 | use crate::{AssistCtx, Assist, AssistId}; |
6 | 6 | ||
7 | pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 7 | pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
8 | let if_expr: &ast::IfExpr = ctx.node_at_offset()?; | 8 | let if_expr: &ast::IfExpr = ctx.node_at_offset()?; |
@@ -15,7 +15,7 @@ pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx<impl HirDatabase>) -> | |||
15 | ast::ElseBranchFlavor::IfExpr(_) => return None, | 15 | ast::ElseBranchFlavor::IfExpr(_) => return None, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | ctx.add_action("replace with match", |edit| { | 18 | ctx.add_action(AssistId("replace_if_let_with_match"), "replace with match", |edit| { |
19 | let match_expr = build_match_expr(expr, pat, then_block, else_block); | 19 | let match_expr = build_match_expr(expr, pat, then_block, else_block); |
20 | edit.target(if_expr.syntax().range()); | 20 | edit.target(if_expr.syntax().range()); |
21 | edit.replace_node_and_indent(if_expr.syntax(), match_expr); | 21 | edit.replace_node_and_indent(if_expr.syntax(), match_expr); |
diff --git a/crates/ra_assists/src/split_import.rs b/crates/ra_assists/src/split_import.rs index f043be636..dd5be4e91 100644 --- a/crates/ra_assists/src/split_import.rs +++ b/crates/ra_assists/src/split_import.rs | |||
@@ -5,7 +5,7 @@ use ra_syntax::{ | |||
5 | algo::generate, | 5 | algo::generate, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use crate::{AssistCtx, Assist}; | 8 | use crate::{AssistCtx, Assist, AssistId}; |
9 | 9 | ||
10 | pub(crate) fn split_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 10 | pub(crate) fn split_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
11 | let colon_colon = ctx.leaf_at_offset().find(|leaf| leaf.kind() == COLONCOLON)?; | 11 | let colon_colon = ctx.leaf_at_offset().find(|leaf| leaf.kind() == COLONCOLON)?; |
@@ -23,7 +23,7 @@ pub(crate) fn split_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assis | |||
23 | None => top_path.syntax().range().end(), | 23 | None => top_path.syntax().range().end(), |
24 | }; | 24 | }; |
25 | 25 | ||
26 | ctx.add_action("split import", |edit| { | 26 | ctx.add_action(AssistId("split_import"), "split import", |edit| { |
27 | edit.target(colon_colon.range()); | 27 | edit.target(colon_colon.range()); |
28 | edit.insert(l_curly, "{"); | 28 | edit.insert(l_curly, "{"); |
29 | edit.insert(r_curly, "}"); | 29 | edit.insert(r_curly, "}"); |
diff --git a/crates/ra_ide_api/src/assists.rs b/crates/ra_ide_api/src/assists.rs index 7a9c66681..3c0475a51 100644 --- a/crates/ra_ide_api/src/assists.rs +++ b/crates/ra_ide_api/src/assists.rs | |||
@@ -2,20 +2,30 @@ use ra_db::{FileRange, FilePosition}; | |||
2 | 2 | ||
3 | use crate::{SourceFileEdit, SourceChange, db::RootDatabase}; | 3 | use crate::{SourceFileEdit, SourceChange, db::RootDatabase}; |
4 | 4 | ||
5 | pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<SourceChange> { | 5 | pub use ra_assists::AssistId; |
6 | |||
7 | #[derive(Debug)] | ||
8 | pub struct Assist { | ||
9 | pub id: AssistId, | ||
10 | pub change: SourceChange, | ||
11 | } | ||
12 | |||
13 | pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<Assist> { | ||
6 | ra_assists::assists(db, frange) | 14 | ra_assists::assists(db, frange) |
7 | .into_iter() | 15 | .into_iter() |
8 | .map(|(label, action)| { | 16 | .map(|(label, action)| { |
9 | let file_id = frange.file_id; | 17 | let file_id = frange.file_id; |
10 | let file_edit = SourceFileEdit { file_id, edit: action.edit }; | 18 | let file_edit = SourceFileEdit { file_id, edit: action.edit }; |
11 | SourceChange { | 19 | let id = label.id; |
20 | let change = SourceChange { | ||
12 | label: label.label, | 21 | label: label.label, |
13 | source_file_edits: vec![file_edit], | 22 | source_file_edits: vec![file_edit], |
14 | file_system_edits: vec![], | 23 | file_system_edits: vec![], |
15 | cursor_position: action | 24 | cursor_position: action |
16 | .cursor_position | 25 | .cursor_position |
17 | .map(|offset| FilePosition { offset, file_id }), | 26 | .map(|offset| FilePosition { offset, file_id }), |
18 | } | 27 | }; |
28 | Assist { id, change } | ||
19 | }) | 29 | }) |
20 | .collect() | 30 | .collect() |
21 | } | 31 | } |
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index 4b9fc9372..076a8396c 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs | |||
@@ -57,6 +57,7 @@ pub use crate::{ | |||
57 | runnables::{Runnable, RunnableKind}, | 57 | runnables::{Runnable, RunnableKind}, |
58 | navigation_target::NavigationTarget, | 58 | navigation_target::NavigationTarget, |
59 | references::ReferenceSearchResult, | 59 | references::ReferenceSearchResult, |
60 | assists::{Assist, AssistId}, | ||
60 | }; | 61 | }; |
61 | pub use ra_ide_api_light::{ | 62 | pub use ra_ide_api_light::{ |
62 | Fold, FoldKind, HighlightedRange, Severity, StructureNode, LocalEdit, | 63 | Fold, FoldKind, HighlightedRange, Severity, StructureNode, LocalEdit, |
@@ -368,7 +369,7 @@ impl Analysis { | |||
368 | 369 | ||
369 | /// Computes assists (aks code actons aka intentions) for the given | 370 | /// Computes assists (aks code actons aka intentions) for the given |
370 | /// position. | 371 | /// position. |
371 | pub fn assists(&self, frange: FileRange) -> Cancelable<Vec<SourceChange>> { | 372 | pub fn assists(&self, frange: FileRange) -> Cancelable<Vec<Assist>> { |
372 | self.with_db(|db| assists::assists(db, frange)) | 373 | self.with_db(|db| assists::assists(db, frange)) |
373 | } | 374 | } |
374 | 375 | ||
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 9abd4054e..5da731801 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use gen_lsp_server::ErrorCode; | 1 | use gen_lsp_server::ErrorCode; |
2 | use lsp_types::{ | 2 | use lsp_types::{ |
3 | CodeActionResponse, CodeLens, Command, Diagnostic, DiagnosticSeverity, | 3 | CodeActionResponse, CodeLens, Command, Diagnostic, DiagnosticSeverity, CodeAction, |
4 | DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, | 4 | DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, |
5 | FoldingRangeKind, FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, | 5 | FoldingRangeKind, FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, |
6 | MarkupKind, ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range, | 6 | MarkupKind, ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range, |
@@ -9,6 +9,7 @@ use lsp_types::{ | |||
9 | }; | 9 | }; |
10 | use ra_ide_api::{ | 10 | use ra_ide_api::{ |
11 | FileId, FilePosition, FileRange, FoldKind, Query, RangeInfo, RunnableKind, Severity, Cancelable, | 11 | FileId, FilePosition, FileRange, FoldKind, Query, RangeInfo, RunnableKind, Severity, Cancelable, |
12 | AssistId, | ||
12 | }; | 13 | }; |
13 | use ra_syntax::{AstNode, SyntaxKind, TextUnit}; | 14 | use ra_syntax::{AstNode, SyntaxKind, TextUnit}; |
14 | use rustc_hash::FxHashMap; | 15 | use rustc_hash::FxHashMap; |
@@ -576,28 +577,57 @@ pub fn handle_code_action( | |||
576 | let range = params.range.conv_with(&line_index); | 577 | let range = params.range.conv_with(&line_index); |
577 | 578 | ||
578 | let assists = world.analysis().assists(FileRange { file_id, range })?.into_iter(); | 579 | let assists = world.analysis().assists(FileRange { file_id, range })?.into_iter(); |
579 | let fixes = world | 580 | let diagnostics = world.analysis().diagnostics(file_id)?; |
580 | .analysis() | 581 | let mut res: Vec<CodeAction> = Vec::new(); |
581 | .diagnostics(file_id)? | 582 | |
583 | let fixes_from_diagnostics = diagnostics | ||
582 | .into_iter() | 584 | .into_iter() |
583 | .filter_map(|d| Some((d.range, d.fix?))) | 585 | .filter_map(|d| Some((d.range, d.fix?))) |
584 | .filter(|(diag_range, _fix)| diag_range.intersection(&range).is_some()) | 586 | .filter(|(diag_range, _fix)| diag_range.intersection(&range).is_some()) |
585 | .map(|(_range, fix)| fix); | 587 | .map(|(_range, fix)| fix); |
586 | 588 | ||
587 | let mut res = Vec::new(); | 589 | for source_edit in fixes_from_diagnostics { |
588 | for source_edit in assists.chain(fixes) { | ||
589 | let title = source_edit.label.clone(); | 590 | let title = source_edit.label.clone(); |
590 | let edit = source_edit.try_conv_with(&world)?; | 591 | let edit = source_edit.try_conv_with(&world)?; |
591 | 592 | ||
592 | let cmd = Command { | 593 | let command = Command { |
594 | title, | ||
595 | command: "rust-analyzer.applySourceChange".to_string(), | ||
596 | arguments: Some(vec![to_value(edit).unwrap()]), | ||
597 | }; | ||
598 | let action = CodeAction { | ||
599 | title: command.title.clone(), | ||
600 | kind: None, | ||
601 | diagnostics: None, | ||
602 | edit: None, | ||
603 | command: Some(command), | ||
604 | }; | ||
605 | res.push(action); | ||
606 | } | ||
607 | |||
608 | for assist in assists { | ||
609 | let title = assist.change.label.clone(); | ||
610 | let edit = assist.change.try_conv_with(&world)?; | ||
611 | |||
612 | let command = Command { | ||
593 | title, | 613 | title, |
594 | command: "rust-analyzer.applySourceChange".to_string(), | 614 | command: "rust-analyzer.applySourceChange".to_string(), |
595 | arguments: Some(vec![to_value(edit).unwrap()]), | 615 | arguments: Some(vec![to_value(edit).unwrap()]), |
596 | }; | 616 | }; |
597 | res.push(cmd); | 617 | let action = CodeAction { |
618 | title: command.title.clone(), | ||
619 | kind: match assist.id { | ||
620 | AssistId("introduce_variable") => Some("refactor.extract.variable".to_string()), | ||
621 | _ => None, | ||
622 | }, | ||
623 | diagnostics: None, | ||
624 | edit: None, | ||
625 | command: Some(command), | ||
626 | }; | ||
627 | res.push(action); | ||
598 | } | 628 | } |
599 | 629 | ||
600 | Ok(Some(CodeActionResponse::Commands(res))) | 630 | Ok(Some(CodeActionResponse::Actions(res))) |
601 | } | 631 | } |
602 | 632 | ||
603 | pub fn handle_code_lens( | 633 | pub fn handle_code_lens( |
diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs index e49c87169..996bf8e01 100644 --- a/crates/ra_lsp_server/tests/heavy_tests/main.rs +++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs | |||
@@ -225,10 +225,12 @@ fn main() {} | |||
225 | context: empty_context(), | 225 | context: empty_context(), |
226 | }, | 226 | }, |
227 | json!([ | 227 | json!([ |
228 | { | 228 | { |
229 | "command": { | ||
229 | "arguments": [ | 230 | "arguments": [ |
230 | { | 231 | { |
231 | "cursorPosition": null, | 232 | "cursorPosition": null, |
233 | "label": "create module", | ||
232 | "workspaceEdit": { | 234 | "workspaceEdit": { |
233 | "documentChanges": [ | 235 | "documentChanges": [ |
234 | { | 236 | { |
@@ -236,13 +238,14 @@ fn main() {} | |||
236 | "uri": "file:///[..]/src/bar.rs" | 238 | "uri": "file:///[..]/src/bar.rs" |
237 | } | 239 | } |
238 | ] | 240 | ] |
239 | }, | 241 | } |
240 | "label": "create module" | ||
241 | } | 242 | } |
242 | ], | 243 | ], |
243 | "command": "rust-analyzer.applySourceChange", | 244 | "command": "rust-analyzer.applySourceChange", |
244 | "title": "create module" | 245 | "title": "create module" |
245 | } | 246 | }, |
247 | "title": "create module" | ||
248 | } | ||
246 | ]), | 249 | ]), |
247 | ); | 250 | ); |
248 | 251 | ||