about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-05-18 07:37:04 +0000
committerGitHub <noreply@github.com>2020-05-18 07:37:04 +0000
commitc6ed08967193cadc927dfaf422601bcd160a6fc9 (patch)
treeaaccb210353786d000a3455264e368b76f61ff98
parent31611da2538e66027ea67482235f6b8659bedf09 (diff)
parent78817a319476d8af40c4f78e8c47dc958781f88f (diff)
downloadrust-c6ed08967193cadc927dfaf422601bcd160a6fc9.tar.gz
rust-c6ed08967193cadc927dfaf422601bcd160a6fc9.zip
Merge #4499
4499: CodeLens configuration options r=vsrs a=vsrs

This PR
- adds an option to granularly enable\disable all CodeLens, just like the TypeScript extension.
- fixes a minor bug for doctests. It makes no sense to show `Debug` lens for them as cargo `Can't skip running doc tests with --no-run`.

Co-authored-by: vsrs <vit@conrlab.com>
-rw-r--r--crates/rust-analyzer/src/config.rs41
-rw-r--r--crates/rust-analyzer/src/main_loop/handlers.rs166
-rw-r--r--editors/code/package.json20
-rw-r--r--editors/code/src/commands/runnables.ts17
-rw-r--r--editors/code/src/config.ts13
5 files changed, 181 insertions, 76 deletions
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 53aee833d62..b5dc6f0fa98 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -33,6 +33,36 @@ 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 const NO_LENS: LensConfig = Self { run: false, debug: false, impementations: false };
+
+    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 +137,7 @@ impl Default for Config {
                 ..CompletionConfig::default()
             },
             call_info_full: true,
+            lens: LensConfig::default(),
         }
     }
 }
@@ -196,6 +227,16 @@ impl Config {
         set(value, "/completion/addCallArgumentSnippets", &mut self.completion.add_call_argument_snippets);
         set(value, "/callInfo/full", &mut self.call_info_full);
 
+        let mut lens_enabled = true;
+        set(value, "/lens/enable", &mut lens_enabled);
+        if lens_enabled {
+            set(value, "/lens/run", &mut self.lens.run);
+            set(value, "/lens/debug", &mut self.lens.debug);
+            set(value, "/lens/implementations", &mut self.lens.impementations);
+        } else {
+            self.lens = LensConfig::NO_LENS;
+        }
+
         log::info!("Config::update() = {:#?}", self);
 
         fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option<T> {
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs
index 6b14830b6df..e6755675285 100644
--- a/crates/rust-analyzer/src/main_loop/handlers.rs
+++ b/crates/rust-analyzer/src/main_loop/handlers.rs
@@ -812,88 +812,108 @@ pub fn handle_code_lens(
     params: lsp_types::CodeLensParams,
 ) -> Result<Option<Vec<CodeLens>>> {
     let _p = profile("handle_code_lens");
-    let file_id = from_proto::file_id(&world, &params.text_document.uri)?;
-    let line_index = world.analysis().file_line_index(file_id)?;
-
     let mut lenses: Vec<CodeLens> = Default::default();
 
+    if world.config.lens.none() {
+        // early return before any db query!
+        return Ok(Some(lenses));
+    }
+
+    let file_id = from_proto::file_id(&world, &params.text_document.uri)?;
+    let line_index = world.analysis().file_line_index(file_id)?;
     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,
+
+    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);
             }
-        }
-        .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());
+            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);
+            }
         }
-        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);
     }
 
-    // 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()),
-                }
-            }),
-    );
-
+    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 4045ab3d275..d899f60e333 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -443,6 +443,26 @@
                     "type": "object",
                     "default": {},
                     "description": "Optional settings passed to the debug engine. Example:\n{ \"lldb\": { \"terminal\":\"external\"} }"
+                },
+                "rust-analyzer.lens.enable": {
+                    "description": "Whether to show CodeLens in Rust files.",
+                    "type": "boolean",
+                    "default": true
+                },
+                "rust-analyzer.lens.run": {
+                    "markdownDescription": "Whether to show Run lens. Only applies when `#rust-analyzer.lens.enable#` is set.",
+                    "type": "boolean",
+                    "default": true
+                },
+                "rust-analyzer.lens.debug": {
+                    "markdownDescription": "Whether to show Debug lens. Only applies when `#rust-analyzer.lens.enable#` is set.",
+                    "type": "boolean",
+                    "default": true
+                },
+                "rust-analyzer.lens.implementations": {
+                    "markdownDescription": "Whether to show Implementations lens. Only applies when `#rust-analyzer.lens.enable#` is set.",
+                    "type": "boolean",
+                    "default": true
                 }
             }
         },
diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts
index b1d93fc34eb..0bd30fb077d 100644
--- a/editors/code/src/commands/runnables.ts
+++ b/editors/code/src/commands/runnables.ts
@@ -7,7 +7,7 @@ import { startDebugSession, getDebugConfiguration } from '../debug';
 
 const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }];
 
-async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, showButtons: boolean = true): Promise<RunnableQuickPick | undefined> {
+async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, debuggeeOnly = false, showButtons: boolean = true): Promise<RunnableQuickPick | undefined> {
     const editor = ctx.activeRustEditor;
     const client = ctx.client;
     if (!editor || !client) return;
@@ -33,9 +33,20 @@ async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, showBu
         ) {
             continue;
         }
+
+        if (debuggeeOnly && (r.label.startsWith('doctest') || r.label.startsWith('cargo'))) {
+            continue;
+        }
         items.push(new RunnableQuickPick(r));
     }
 
+    if (items.length === 0) {
+        // it is the debug case, run always has at least 'cargo check ...'
+        // see crates\rust-analyzer\src\main_loop\handlers.rs, handle_runnables
+        vscode.window.showErrorMessage("There's no debug target!");
+        return;
+    }
+
     return await new Promise((resolve) => {
         const disposables: vscode.Disposable[] = [];
         const close = (result?: RunnableQuickPick) => {
@@ -107,7 +118,7 @@ export function debug(ctx: Ctx): Cmd {
     let prevDebuggee: RunnableQuickPick | undefined;
 
     return async () => {
-        const item = await selectRunnable(ctx, prevDebuggee);
+        const item = await selectRunnable(ctx, prevDebuggee, true);
         if (!item) return;
 
         item.detail = 'restart';
@@ -147,7 +158,7 @@ async function makeDebugConfig(ctx: Ctx, item: RunnableQuickPick): Promise<void>
 
 export function newDebugConfig(ctx: Ctx): Cmd {
     return async () => {
-        const item = await selectRunnable(ctx, undefined, false);
+        const item = await selectRunnable(ctx, undefined, true, false);
         if (!item) return;
 
         await makeDebugConfig(ctx, item);
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 1652827c32a..ee294fbe312 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -16,6 +16,10 @@ export class Config {
         "files",
         "highlighting",
         "updates.channel",
+        "lens.enable",
+        "lens.run",
+        "lens.debug",
+        "lens.implementations",
     ]
         .map(opt => `${this.rootSection}.${opt}`);
 
@@ -119,4 +123,13 @@ export class Config {
             sourceFileMap: sourceFileMap
         };
     }
+
+    get lens() {
+        return {
+            enable: this.get<boolean>("lens.enable"),
+            run: this.get<boolean>("lens.run"),
+            debug: this.get<boolean>("lens.debug"),
+            implementations: this.get<boolean>("lens.implementations"),
+        };
+    }
 }