diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 53aee833d6..b99b95bfca 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -33,6 +33,34 @@ pub struct Config { pub inlay_hints: InlayHintsConfig, pub completion: CompletionConfig, pub call_info_full: bool, + pub lens: LensConfig, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct LensConfig { + pub run: bool, + pub debug: bool, + pub impementations: bool, +} + +impl Default for LensConfig { + fn default() -> Self { + Self { run: true, debug: true, impementations: true } + } +} + +impl LensConfig { + pub fn any(&self) -> bool { + self.impementations || self.runnable() + } + + pub fn none(&self) -> bool { + !self.any() + } + + pub fn runnable(&self) -> bool { + self.run || self.debug + } } #[derive(Debug, Clone)] @@ -107,6 +135,7 @@ impl Default for Config { ..CompletionConfig::default() }, call_info_full: true, + lens: LensConfig::default(), } } } @@ -195,6 +224,9 @@ impl Config { set(value, "/completion/addCallParenthesis", &mut self.completion.add_call_parenthesis); set(value, "/completion/addCallArgumentSnippets", &mut self.completion.add_call_argument_snippets); set(value, "/callInfo/full", &mut self.call_info_full); + set(value, "/lens/run", &mut self.lens.run); + set(value, "/lens/debug", &mut self.lens.debug); + set(value, "/lens/implementations", &mut self.lens.impementations); log::info!("Config::update() = {:#?}", self); @@ -212,35 +244,35 @@ impl Config { pub fn update_caps(&mut self, caps: &ClientCapabilities) { if let Some(doc_caps) = caps.text_document.as_ref() { if let Some(value) = doc_caps.definition.as_ref().and_then(|it| it.link_support) { - self.client_caps.location_link = value; - } + self.client_caps.location_link = value; + } if let Some(value) = doc_caps.folding_range.as_ref().and_then(|it| it.line_folding_only) { - self.client_caps.line_folding_only = value - } + self.client_caps.line_folding_only = value + } if let Some(value) = doc_caps .document_symbol .as_ref() .and_then(|it| it.hierarchical_document_symbol_support) - { - self.client_caps.hierarchical_symbols = value - } + { + self.client_caps.hierarchical_symbols = value + } if let Some(value) = doc_caps .code_action .as_ref() .and_then(|it| Some(it.code_action_literal_support.is_some())) - { - self.client_caps.code_action_literals = value; - } - self.completion.allow_snippets(false); + { + self.client_caps.code_action_literals = value; + } + self.completion.allow_snippets(false); if let Some(completion) = &doc_caps.completion { - if let Some(completion_item) = &completion.completion_item { - if let Some(value) = completion_item.snippet_support { - self.completion.allow_snippets(value); - } + if let Some(completion_item) = &completion.completion_item { + if let Some(value) = completion_item.snippet_support { + self.completion.allow_snippets(value); } } } + } if let Some(window_caps) = caps.window.as_ref() { if let Some(value) = window_caps.work_done_progress { diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 6b14830b6d..808532d237 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -812,88 +812,106 @@ pub fn handle_code_lens( params: lsp_types::CodeLensParams, ) -> Result>> { let _p = profile("handle_code_lens"); - let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; - let line_index = world.analysis().file_line_index(file_id)?; - let mut lenses: Vec = Default::default(); - let cargo_spec = CargoTargetSpec::for_file(&world, file_id)?; - // Gather runnables - for runnable in world.analysis().runnables(file_id)? { - let title = match &runnable.kind { - RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => "▶\u{fe0e} Run Test", - RunnableKind::DocTest { .. } => "▶\u{fe0e} Run Doctest", - RunnableKind::Bench { .. } => "Run Bench", - RunnableKind::Bin => { - // Do not suggest binary run on other target than binary - match &cargo_spec { - Some(spec) => match spec.target_kind { - TargetKind::Bin => "Run", - _ => continue, - }, - None => continue, - } - } - } - .to_string(); - let mut r = to_lsp_runnable(&world, file_id, runnable)?; - let lens = CodeLens { - range: r.range, - command: Some(Command { - title, - command: "rust-analyzer.runSingle".into(), - arguments: Some(vec![to_value(&r).unwrap()]), - }), - data: None, - }; - lenses.push(lens); - - if r.args[0] == "run" { - r.args[0] = "build".into(); - } else { - r.args.push("--no-run".into()); - } - let debug_lens = CodeLens { - range: r.range, - command: Some(Command { - title: "Debug".into(), - command: "rust-analyzer.debugSingle".into(), - arguments: Some(vec![to_value(r).unwrap()]), - }), - data: None, - }; - lenses.push(debug_lens); + if world.config.lens.none() { + // early return before any db query! + return Ok(Some(lenses)); } - // Handle impls - lenses.extend( - world - .analysis() - .file_structure(file_id)? - .into_iter() - .filter(|it| match it.kind { - SyntaxKind::TRAIT_DEF | SyntaxKind::STRUCT_DEF | SyntaxKind::ENUM_DEF => true, - _ => false, - }) - .map(|it| { - let range = to_proto::range(&line_index, it.node_range); - let pos = range.start; - let lens_params = lsp_types::request::GotoImplementationParams { - text_document_position_params: lsp_types::TextDocumentPositionParams::new( - params.text_document.clone(), - pos, - ), - work_done_progress_params: Default::default(), - partial_result_params: Default::default(), - }; - CodeLens { - range, - command: None, - data: Some(to_value(CodeLensResolveData::Impls(lens_params)).unwrap()), - } - }), - ); + let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; + let line_index = world.analysis().file_line_index(file_id)?; + let cargo_spec = CargoTargetSpec::for_file(&world, file_id)?; + if world.config.lens.runnable() { + // Gather runnables + for runnable in world.analysis().runnables(file_id)? { + let (run_title, debugee ) = match &runnable.kind { + RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => ("▶️\u{fe0e}Run Test", true), + RunnableKind::DocTest { .. } => { + // cargo does not support -no-run for doctests + ("▶️\u{fe0e}Run Doctest", false) + } + RunnableKind::Bench { .. } => { + // Nothing wrong with bench debugging + ("Run Bench", true) + }, + RunnableKind::Bin => { + // Do not suggest binary run on other target than binary + match &cargo_spec { + Some(spec) => match spec.target_kind { + TargetKind::Bin => ("Run", true), + _ => continue, + }, + None => continue, + } + } + }; + + let mut r = to_lsp_runnable(&world, file_id, runnable)?; + if world.config.lens.run { + let lens = CodeLens { + range: r.range, + command: Some(Command { + title: run_title.to_string(), + command: "rust-analyzer.runSingle".into(), + arguments: Some(vec![to_value(&r).unwrap()]), + }), + data: None, + }; + lenses.push(lens); + } + + if debugee && world.config.lens.debug { + if r.args[0] == "run" { + r.args[0] = "build".into(); + } else { + r.args.push("--no-run".into()); + } + let debug_lens = CodeLens { + range: r.range, + command: Some(Command { + title: "Debug".into(), + command: "rust-analyzer.debugSingle".into(), + arguments: Some(vec![to_value(r).unwrap()]), + }), + data: None, + }; + lenses.push(debug_lens); + } + } + } + + if world.config.lens.impementations { + // Handle impls + lenses.extend( + world + .analysis() + .file_structure(file_id)? + .into_iter() + .filter(|it| match it.kind { + SyntaxKind::TRAIT_DEF | SyntaxKind::STRUCT_DEF | SyntaxKind::ENUM_DEF => true, + _ => false, + }) + .map(|it| { + let range = to_proto::range(&line_index, it.node_range); + let pos = range.start; + let lens_params = lsp_types::request::GotoImplementationParams { + text_document_position_params: lsp_types::TextDocumentPositionParams::new( + params.text_document.clone(), + pos, + ), + work_done_progress_params: Default::default(), + partial_result_params: Default::default(), + }; + CodeLens { + range, + command: None, + data: Some(to_value(CodeLensResolveData::Impls(lens_params)).unwrap()), + } + }), + ); + } Ok(Some(lenses)) } diff --git a/editors/code/package.json b/editors/code/package.json index 2dbbde8527..efed4c7f2f 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -443,6 +443,21 @@ "type": "object", "default": {}, "description": "Optional settings passed to the debug engine. Example:\n{ \"lldb\": { \"terminal\":\"external\"} }" + }, + "rust-analyzer.lens.run": { + "description": "Whether to show Run lens.", + "type": "boolean", + "default": true + }, + "rust-analyzer.lens.debug": { + "description": "Whether to show Debug lens.", + "type": "boolean", + "default": true + }, + "rust-analyzer.lens.implementations": { + "description": "Whether to show Implementations lens.", + "type": "boolean", + "default": true } } }, diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 1652827c32..93d9aa1607 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -16,6 +16,9 @@ export class Config { "files", "highlighting", "updates.channel", + "lens.run", + "lens.debug", + "lens.implementations", ] .map(opt => `${this.rootSection}.${opt}`); @@ -119,4 +122,12 @@ export class Config { sourceFileMap: sourceFileMap }; } + + get lens() { + return { + run: this.get("lens.run"), + debug: this.get("lens.debug"), + implementations: this.get("lens.implementations"), + }; + } }