aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_assists/src/add_derive.rs4
-rw-r--r--crates/ra_assists/src/add_impl.rs4
-rw-r--r--crates/ra_assists/src/assist_ctx.rs5
-rw-r--r--crates/ra_assists/src/auto_import.rs16
-rw-r--r--crates/ra_assists/src/change_visibility.rs8
-rw-r--r--crates/ra_assists/src/fill_match_arms.rs4
-rw-r--r--crates/ra_assists/src/flip_comma.rs4
-rw-r--r--crates/ra_assists/src/introduce_variable.rs4
-rw-r--r--crates/ra_assists/src/lib.rs6
-rw-r--r--crates/ra_assists/src/remove_dbg.rs4
-rw-r--r--crates/ra_assists/src/replace_if_let_with_match.rs4
-rw-r--r--crates/ra_assists/src/split_import.rs4
-rw-r--r--crates/ra_ide_api/src/assists.rs16
-rw-r--r--crates/ra_ide_api/src/lib.rs3
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs48
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/main.rs11
16 files changed, 102 insertions, 43 deletions
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
8use crate::{AssistCtx, Assist}; 8use crate::{AssistCtx, Assist, AssistId};
9 9
10pub(crate) fn add_derive(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 10pub(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
8use crate::{AssistCtx, Assist}; 8use crate::{AssistCtx, Assist, AssistId};
9 9
10pub(crate) fn add_impl(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 10pub(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};
8use ra_fmt::{leading_indent, reindent}; 8use ra_fmt::{leading_indent, reindent};
9 9
10use crate::{AssistLabel, AssistAction}; 10use crate::{AssistLabel, AssistAction, AssistId};
11 11
12#[derive(Clone, Debug)] 12#[derive(Clone, Debug)]
13pub(crate) enum Assist { 13pub(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};
7use crate::assist_ctx::{AssistCtx, Assist, AssistBuilder}; 7use crate::{
8 AssistId,
9 assist_ctx::{AssistCtx, Assist, AssistBuilder},
10};
8 11
9fn collect_path_segments(path: &ast::Path) -> Option<Vec<&ast::PathSegment>> { 12fn 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
8use crate::{AssistCtx, Assist}; 8use crate::{AssistCtx, Assist, AssistId};
9 9
10pub(crate) fn change_visibility(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 10pub(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
64fn change_vis(mut ctx: AssistCtx<impl HirDatabase>, vis: &ast::Visibility) -> Option<Assist> { 64fn 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};
7use ra_syntax::ast::{self, AstNode}; 7use ra_syntax::ast::{self, AstNode};
8 8
9use crate::{AssistCtx, Assist}; 9use crate::{AssistCtx, Assist, AssistId};
10 10
11pub(crate) fn fill_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 11pub(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
8use crate::{AssistCtx, Assist}; 8use crate::{AssistCtx, Assist, AssistId};
9 9
10pub(crate) fn flip_comma(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 10pub(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..3d708ebb2 100644
--- a/crates/ra_assists/src/introduce_variable.rs
+++ b/crates/ra_assists/src/introduce_variable.rs
@@ -6,7 +6,7 @@ use ra_syntax::{
6 }, SyntaxNode, TextUnit, 6 }, SyntaxNode, TextUnit,
7}; 7};
8 8
9use crate::{AssistCtx, Assist}; 9use crate::{AssistCtx, Assist, AssistId};
10 10
11pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 11pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
12 let node = ctx.covering_node(); 12 let node = ctx.covering_node();
@@ -19,7 +19,7 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option
19 if indent.kind() != WHITESPACE { 19 if indent.kind() != WHITESPACE {
20 return None; 20 return None;
21 } 21 }
22 ctx.add_action("introduce variable", move |edit| { 22 ctx.add_action(AssistId("introduce_variable"), "introduce variable", move |edit| {
23 let mut buf = String::new(); 23 let mut buf = String::new();
24 24
25 let cursor_offset = if wrap_in_block { 25 let cursor_offset = if wrap_in_block {
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index e1e899edc..56d276867 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -16,10 +16,16 @@ use hir::db::HirDatabase;
16 16
17pub(crate) use crate::assist_ctx::{AssistCtx, Assist}; 17pub(crate) use crate::assist_ctx::{AssistCtx, Assist};
18 18
19/// Unique identifier of the assist, should not be shown to the user
20/// directly.
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub struct AssistId(pub &'static str);
23
19#[derive(Debug, Clone)] 24#[derive(Debug, Clone)]
20pub struct AssistLabel { 25pub struct AssistLabel {
21 /// Short description of the assist, as shown in the UI. 26 /// Short description of the assist, as shown in the UI.
22 pub label: String, 27 pub label: String,
28 pub id: AssistId,
23} 29}
24 30
25#[derive(Debug, Clone)] 31#[derive(Debug, Clone)]
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};
9use crate::{AssistCtx, Assist}; 9use crate::{AssistCtx, Assist, AssistId};
10 10
11pub(crate) fn remove_dbg(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 11pub(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};
2use ra_fmt::extract_trivial_expression; 2use ra_fmt::extract_trivial_expression;
3use hir::db::HirDatabase; 3use hir::db::HirDatabase;
4 4
5use crate::{AssistCtx, Assist}; 5use crate::{AssistCtx, Assist, AssistId};
6 6
7pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 7pub(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
8use crate::{AssistCtx, Assist}; 8use crate::{AssistCtx, Assist, AssistId};
9 9
10pub(crate) fn split_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 10pub(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
3use crate::{SourceFileEdit, SourceChange, db::RootDatabase}; 3use crate::{SourceFileEdit, SourceChange, db::RootDatabase};
4 4
5pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<SourceChange> { 5pub use ra_assists::AssistId;
6
7#[derive(Debug)]
8pub struct Assist {
9 pub id: AssistId,
10 pub change: SourceChange,
11}
12
13pub(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};
61pub use ra_ide_api_light::{ 62pub 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 @@
1use gen_lsp_server::ErrorCode; 1use gen_lsp_server::ErrorCode;
2use lsp_types::{ 2use 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};
10use ra_ide_api::{ 10use 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};
13use ra_syntax::{AstNode, SyntaxKind, TextUnit}; 14use ra_syntax::{AstNode, SyntaxKind, TextUnit};
14use rustc_hash::FxHashMap; 15use 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
603pub fn handle_code_lens( 633pub 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