From ef442b8682909f2ab758f55507d4c2e81673cfa1 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 24 Feb 2019 13:53:35 +0300 Subject: Assign IDs to assists --- crates/ra_assists/src/add_derive.rs | 4 +- crates/ra_assists/src/add_impl.rs | 4 +- crates/ra_assists/src/assist_ctx.rs | 5 ++- crates/ra_assists/src/auto_import.rs | 16 ++++++-- crates/ra_assists/src/change_visibility.rs | 8 ++-- crates/ra_assists/src/fill_match_arms.rs | 4 +- crates/ra_assists/src/flip_comma.rs | 4 +- crates/ra_assists/src/introduce_variable.rs | 4 +- crates/ra_assists/src/lib.rs | 6 +++ crates/ra_assists/src/remove_dbg.rs | 4 +- crates/ra_assists/src/replace_if_let_with_match.rs | 4 +- crates/ra_assists/src/split_import.rs | 4 +- crates/ra_ide_api/src/assists.rs | 16 ++++++-- crates/ra_ide_api/src/lib.rs | 3 +- crates/ra_lsp_server/src/main_loop/handlers.rs | 48 ++++++++++++++++++---- crates/ra_lsp_server/tests/heavy_tests/main.rs | 11 +++-- 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::{ TextUnit, }; -use crate::{AssistCtx, Assist}; +use crate::{AssistCtx, Assist, AssistId}; pub(crate) fn add_derive(mut ctx: AssistCtx) -> Option { let nominal = ctx.node_at_offset::()?; let node_start = derive_insertion_offset(nominal)?; - ctx.add_action("add `#[derive]`", |edit| { + ctx.add_action(AssistId("add_derive"), "add `#[derive]`", |edit| { let derive_attr = nominal .attrs() .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::{ TextUnit, }; -use crate::{AssistCtx, Assist}; +use crate::{AssistCtx, Assist, AssistId}; pub(crate) fn add_impl(mut ctx: AssistCtx) -> Option { let nominal = ctx.node_at_offset::()?; let name = nominal.name()?; - ctx.add_action("add impl", |edit| { + ctx.add_action(AssistId("add_impl"), "add impl", |edit| { edit.target(nominal.syntax().range()); let type_params = nominal.type_param_list(); 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::{ }; use ra_fmt::{leading_indent, reindent}; -use crate::{AssistLabel, AssistAction}; +use crate::{AssistLabel, AssistAction, AssistId}; #[derive(Clone, Debug)] pub(crate) enum Assist { @@ -81,10 +81,11 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { pub(crate) fn add_action( &mut self, + id: AssistId, label: impl Into, f: impl FnOnce(&mut AssistBuilder), ) -> &mut Self { - let label = AssistLabel { label: label.into() }; + let label = AssistLabel { label: label.into(), id }; match &mut self.assist { Assist::Unresolved(labels) => labels.push(label), 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::{ ast::{ self, NameOwner }, AstNode, SyntaxNode, Direction, TextRange, SyntaxKind::{ PATH, PATH_SEGMENT, COLONCOLON, COMMA } }; -use crate::assist_ctx::{AssistCtx, Assist, AssistBuilder}; +use crate::{ + AssistId, + assist_ctx::{AssistCtx, Assist, AssistBuilder}, +}; fn collect_path_segments(path: &ast::Path) -> Option> { let mut v = Vec::new(); @@ -526,6 +529,7 @@ pub(crate) fn auto_import(mut ctx: AssistCtx) -> Option) -> Option) -> Option { if let Some(vis) = ctx.node_at_offset::() { @@ -41,7 +41,7 @@ fn add_vis(mut ctx: AssistCtx) -> Option { (vis_offset(field.syntax()), ident.range()) }; - ctx.add_action("make pub(crate)", |edit| { + ctx.add_action(AssistId("change_visibility"), "make pub(crate)", |edit| { edit.target(target); edit.insert(offset, "pub(crate) "); edit.set_cursor(offset); @@ -63,7 +63,7 @@ fn vis_offset(node: &SyntaxNode) -> TextUnit { fn change_vis(mut ctx: AssistCtx, vis: &ast::Visibility) -> Option { if vis.syntax().text() == "pub" { - ctx.add_action("change to pub(crate)", |edit| { + ctx.add_action(AssistId("change_visibility"), "change to pub(crate)", |edit| { edit.target(vis.syntax().range()); edit.replace(vis.syntax().range(), "pub(crate)"); edit.set_cursor(vis.syntax().range().start()) @@ -72,7 +72,7 @@ fn change_vis(mut ctx: AssistCtx, vis: &ast::Visibility) -> Op return ctx.build(); } if vis.syntax().text() == "pub(crate)" { - ctx.add_action("change to pub", |edit| { + ctx.add_action(AssistId("change_visibility"), "change to pub", |edit| { edit.target(vis.syntax().range()); edit.replace(vis.syntax().range(), "pub"); 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::{ }; use ra_syntax::ast::{self, AstNode}; -use crate::{AssistCtx, Assist}; +use crate::{AssistCtx, Assist, AssistId}; pub(crate) fn fill_match_arms(mut ctx: AssistCtx) -> Option { let match_expr = ctx.node_at_offset::()?; @@ -37,7 +37,7 @@ pub(crate) fn fill_match_arms(mut ctx: AssistCtx) -> Option) -> Option { let comma = ctx.leaf_at_offset().find(|leaf| leaf.kind() == COMMA)?; let prev = non_trivia_sibling(comma, Direction::Prev)?; let next = non_trivia_sibling(comma, Direction::Next)?; - ctx.add_action("flip comma", |edit| { + ctx.add_action(AssistId("flip_comma"), "flip comma", |edit| { edit.target(comma.range()); edit.replace(prev.range(), next.text()); 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::{ }, SyntaxNode, TextUnit, }; -use crate::{AssistCtx, Assist}; +use crate::{AssistCtx, Assist, AssistId}; pub(crate) fn introduce_variable(mut ctx: AssistCtx) -> Option { let node = ctx.covering_node(); @@ -19,7 +19,7 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx) -> Option if indent.kind() != WHITESPACE { return None; } - ctx.add_action("introduce variable", move |edit| { + ctx.add_action(AssistId("introduce_variable"), "introduce variable", move |edit| { let mut buf = String::new(); 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; pub(crate) use crate::assist_ctx::{AssistCtx, Assist}; +/// Unique identifier of the assist, should not be shown to the user +/// directly. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AssistId(pub &'static str); + #[derive(Debug, Clone)] pub struct AssistLabel { /// Short description of the assist, as shown in the UI. pub label: String, + pub id: AssistId, } #[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::{ L_PAREN, R_PAREN, L_CURLY, R_CURLY, L_BRACK, R_BRACK, EXCL }, }; -use crate::{AssistCtx, Assist}; +use crate::{AssistCtx, Assist, AssistId}; pub(crate) fn remove_dbg(mut ctx: AssistCtx) -> Option { let macro_call = ctx.node_at_offset::()?; @@ -46,7 +46,7 @@ pub(crate) fn remove_dbg(mut ctx: AssistCtx) -> Option macro_args.text().slice(start..end).to_string() }; - ctx.add_action("remove dbg!()", |edit| { + ctx.add_action(AssistId("remove_dbg"), "remove dbg!()", |edit| { edit.target(macro_call.syntax().range()); edit.replace(macro_range, macro_content); 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}; use ra_fmt::extract_trivial_expression; use hir::db::HirDatabase; -use crate::{AssistCtx, Assist}; +use crate::{AssistCtx, Assist, AssistId}; pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx) -> Option { let if_expr: &ast::IfExpr = ctx.node_at_offset()?; @@ -15,7 +15,7 @@ pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx) -> ast::ElseBranchFlavor::IfExpr(_) => return None, }; - ctx.add_action("replace with match", |edit| { + ctx.add_action(AssistId("replace_if_let_with_match"), "replace with match", |edit| { let match_expr = build_match_expr(expr, pat, then_block, else_block); edit.target(if_expr.syntax().range()); 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::{ algo::generate, }; -use crate::{AssistCtx, Assist}; +use crate::{AssistCtx, Assist, AssistId}; pub(crate) fn split_import(mut ctx: AssistCtx) -> Option { let colon_colon = ctx.leaf_at_offset().find(|leaf| leaf.kind() == COLONCOLON)?; @@ -23,7 +23,7 @@ pub(crate) fn split_import(mut ctx: AssistCtx) -> Option top_path.syntax().range().end(), }; - ctx.add_action("split import", |edit| { + ctx.add_action(AssistId("split_import"), "split import", |edit| { edit.target(colon_colon.range()); edit.insert(l_curly, "{"); 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}; use crate::{SourceFileEdit, SourceChange, db::RootDatabase}; -pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec { +pub use ra_assists::AssistId; + +#[derive(Debug)] +pub struct Assist { + pub id: AssistId, + pub change: SourceChange, +} + +pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec { ra_assists::assists(db, frange) .into_iter() .map(|(label, action)| { let file_id = frange.file_id; let file_edit = SourceFileEdit { file_id, edit: action.edit }; - SourceChange { + let id = label.id; + let change = SourceChange { label: label.label, source_file_edits: vec![file_edit], file_system_edits: vec![], cursor_position: action .cursor_position .map(|offset| FilePosition { offset, file_id }), - } + }; + Assist { id, change } }) .collect() } 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::{ runnables::{Runnable, RunnableKind}, navigation_target::NavigationTarget, references::ReferenceSearchResult, + assists::{Assist, AssistId}, }; pub use ra_ide_api_light::{ Fold, FoldKind, HighlightedRange, Severity, StructureNode, LocalEdit, @@ -368,7 +369,7 @@ impl Analysis { /// Computes assists (aks code actons aka intentions) for the given /// position. - pub fn assists(&self, frange: FileRange) -> Cancelable> { + pub fn assists(&self, frange: FileRange) -> Cancelable> { self.with_db(|db| assists::assists(db, frange)) } 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 @@ use gen_lsp_server::ErrorCode; use lsp_types::{ - CodeActionResponse, CodeLens, Command, Diagnostic, DiagnosticSeverity, + CodeActionResponse, CodeLens, Command, Diagnostic, DiagnosticSeverity, CodeAction, DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeKind, FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, MarkupKind, ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range, @@ -9,6 +9,7 @@ use lsp_types::{ }; use ra_ide_api::{ FileId, FilePosition, FileRange, FoldKind, Query, RangeInfo, RunnableKind, Severity, Cancelable, + AssistId, }; use ra_syntax::{AstNode, SyntaxKind, TextUnit}; use rustc_hash::FxHashMap; @@ -576,28 +577,57 @@ pub fn handle_code_action( let range = params.range.conv_with(&line_index); let assists = world.analysis().assists(FileRange { file_id, range })?.into_iter(); - let fixes = world - .analysis() - .diagnostics(file_id)? + let diagnostics = world.analysis().diagnostics(file_id)?; + let mut res: Vec = Vec::new(); + + let fixes_from_diagnostics = diagnostics .into_iter() .filter_map(|d| Some((d.range, d.fix?))) .filter(|(diag_range, _fix)| diag_range.intersection(&range).is_some()) .map(|(_range, fix)| fix); - let mut res = Vec::new(); - for source_edit in assists.chain(fixes) { + for source_edit in fixes_from_diagnostics { let title = source_edit.label.clone(); let edit = source_edit.try_conv_with(&world)?; - let cmd = Command { + let command = Command { + title, + command: "rust-analyzer.applySourceChange".to_string(), + arguments: Some(vec![to_value(edit).unwrap()]), + }; + let action = CodeAction { + title: command.title.clone(), + kind: None, + diagnostics: None, + edit: None, + command: Some(command), + }; + res.push(action); + } + + for assist in assists { + let title = assist.change.label.clone(); + let edit = assist.change.try_conv_with(&world)?; + + let command = Command { title, command: "rust-analyzer.applySourceChange".to_string(), arguments: Some(vec![to_value(edit).unwrap()]), }; - res.push(cmd); + let action = CodeAction { + title: command.title.clone(), + kind: match assist.id { + AssistId("introduce_variable") => Some("refactor.extract.variable".to_string()), + _ => None, + }, + diagnostics: None, + edit: None, + command: Some(command), + }; + res.push(action); } - Ok(Some(CodeActionResponse::Commands(res))) + Ok(Some(CodeActionResponse::Actions(res))) } 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() {} context: empty_context(), }, json!([ - { + { + "command": { "arguments": [ { "cursorPosition": null, + "label": "create module", "workspaceEdit": { "documentChanges": [ { @@ -236,13 +238,14 @@ fn main() {} "uri": "file:///[..]/src/bar.rs" } ] - }, - "label": "create module" + } } ], "command": "rust-analyzer.applySourceChange", "title": "create module" - } + }, + "title": "create module" + } ]), ); -- cgit v1.2.3