aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/rust-analyzer/src/config.rs41
-rw-r--r--crates/rust-analyzer/src/main_loop/handlers.rs166
-rw-r--r--docs/user/readme.adoc2
-rw-r--r--editors/code/package.json27
-rw-r--r--editors/code/src/commands/runnables.ts17
-rw-r--r--editors/code/src/config.ts13
6 files changed, 187 insertions, 79 deletions
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 53aee833d..b5dc6f0fa 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -33,6 +33,36 @@ pub struct Config {
33 pub inlay_hints: InlayHintsConfig, 33 pub inlay_hints: InlayHintsConfig,
34 pub completion: CompletionConfig, 34 pub completion: CompletionConfig,
35 pub call_info_full: bool, 35 pub call_info_full: bool,
36 pub lens: LensConfig,
37}
38
39#[derive(Clone, Debug, PartialEq, Eq)]
40pub struct LensConfig {
41 pub run: bool,
42 pub debug: bool,
43 pub impementations: bool,
44}
45
46impl Default for LensConfig {
47 fn default() -> Self {
48 Self { run: true, debug: true, impementations: true }
49 }
50}
51
52impl LensConfig {
53 pub const NO_LENS: LensConfig = Self { run: false, debug: false, impementations: false };
54
55 pub fn any(&self) -> bool {
56 self.impementations || self.runnable()
57 }
58
59 pub fn none(&self) -> bool {
60 !self.any()
61 }
62
63 pub fn runnable(&self) -> bool {
64 self.run || self.debug
65 }
36} 66}
37 67
38#[derive(Debug, Clone)] 68#[derive(Debug, Clone)]
@@ -107,6 +137,7 @@ impl Default for Config {
107 ..CompletionConfig::default() 137 ..CompletionConfig::default()
108 }, 138 },
109 call_info_full: true, 139 call_info_full: true,
140 lens: LensConfig::default(),
110 } 141 }
111 } 142 }
112} 143}
@@ -196,6 +227,16 @@ impl Config {
196 set(value, "/completion/addCallArgumentSnippets", &mut self.completion.add_call_argument_snippets); 227 set(value, "/completion/addCallArgumentSnippets", &mut self.completion.add_call_argument_snippets);
197 set(value, "/callInfo/full", &mut self.call_info_full); 228 set(value, "/callInfo/full", &mut self.call_info_full);
198 229
230 let mut lens_enabled = true;
231 set(value, "/lens/enable", &mut lens_enabled);
232 if lens_enabled {
233 set(value, "/lens/run", &mut self.lens.run);
234 set(value, "/lens/debug", &mut self.lens.debug);
235 set(value, "/lens/implementations", &mut self.lens.impementations);
236 } else {
237 self.lens = LensConfig::NO_LENS;
238 }
239
199 log::info!("Config::update() = {:#?}", self); 240 log::info!("Config::update() = {:#?}", self);
200 241
201 fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option<T> { 242 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 6b14830b6..e67556752 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(
812 params: lsp_types::CodeLensParams, 812 params: lsp_types::CodeLensParams,
813) -> Result<Option<Vec<CodeLens>>> { 813) -> Result<Option<Vec<CodeLens>>> {
814 let _p = profile("handle_code_lens"); 814 let _p = profile("handle_code_lens");
815 let file_id = from_proto::file_id(&world, &params.text_document.uri)?;
816 let line_index = world.analysis().file_line_index(file_id)?;
817
818 let mut lenses: Vec<CodeLens> = Default::default(); 815 let mut lenses: Vec<CodeLens> = Default::default();
819 816
817 if world.config.lens.none() {
818 // early return before any db query!
819 return Ok(Some(lenses));
820 }
821
822 let file_id = from_proto::file_id(&world, &params.text_document.uri)?;
823 let line_index = world.analysis().file_line_index(file_id)?;
820 let cargo_spec = CargoTargetSpec::for_file(&world, file_id)?; 824 let cargo_spec = CargoTargetSpec::for_file(&world, file_id)?;
821 // Gather runnables 825
822 for runnable in world.analysis().runnables(file_id)? { 826 if world.config.lens.runnable() {
823 let title = match &runnable.kind { 827 // Gather runnables
824 RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => "▶\u{fe0e} Run Test", 828 for runnable in world.analysis().runnables(file_id)? {
825 RunnableKind::DocTest { .. } => "▶\u{fe0e} Run Doctest", 829 let (run_title, debugee) = match &runnable.kind {
826 RunnableKind::Bench { .. } => "Run Bench", 830 RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => {
827 RunnableKind::Bin => { 831 ("▶️\u{fe0e}Run Test", true)
828 // Do not suggest binary run on other target than binary
829 match &cargo_spec {
830 Some(spec) => match spec.target_kind {
831 TargetKind::Bin => "Run",
832 _ => continue,
833 },
834 None => continue,
835 } 832 }
833 RunnableKind::DocTest { .. } => {
834 // cargo does not support -no-run for doctests
835 ("▶️\u{fe0e}Run Doctest", false)
836 }
837 RunnableKind::Bench { .. } => {
838 // Nothing wrong with bench debugging
839 ("Run Bench", true)
840 }
841 RunnableKind::Bin => {
842 // Do not suggest binary run on other target than binary
843 match &cargo_spec {
844 Some(spec) => match spec.target_kind {
845 TargetKind::Bin => ("Run", true),
846 _ => continue,
847 },
848 None => continue,
849 }
850 }
851 };
852
853 let mut r = to_lsp_runnable(&world, file_id, runnable)?;
854 if world.config.lens.run {
855 let lens = CodeLens {
856 range: r.range,
857 command: Some(Command {
858 title: run_title.to_string(),
859 command: "rust-analyzer.runSingle".into(),
860 arguments: Some(vec![to_value(&r).unwrap()]),
861 }),
862 data: None,
863 };
864 lenses.push(lens);
836 } 865 }
837 }
838 .to_string();
839 let mut r = to_lsp_runnable(&world, file_id, runnable)?;
840 let lens = CodeLens {
841 range: r.range,
842 command: Some(Command {
843 title,
844 command: "rust-analyzer.runSingle".into(),
845 arguments: Some(vec![to_value(&r).unwrap()]),
846 }),
847 data: None,
848 };
849 lenses.push(lens);
850 866
851 if r.args[0] == "run" { 867 if debugee && world.config.lens.debug {
852 r.args[0] = "build".into(); 868 if r.args[0] == "run" {
853 } else { 869 r.args[0] = "build".into();
854 r.args.push("--no-run".into()); 870 } else {
871 r.args.push("--no-run".into());
872 }
873 let debug_lens = CodeLens {
874 range: r.range,
875 command: Some(Command {
876 title: "Debug".into(),
877 command: "rust-analyzer.debugSingle".into(),
878 arguments: Some(vec![to_value(r).unwrap()]),
879 }),
880 data: None,
881 };
882 lenses.push(debug_lens);
883 }
855 } 884 }
856 let debug_lens = CodeLens {
857 range: r.range,
858 command: Some(Command {
859 title: "Debug".into(),
860 command: "rust-analyzer.debugSingle".into(),
861 arguments: Some(vec![to_value(r).unwrap()]),
862 }),
863 data: None,
864 };
865 lenses.push(debug_lens);
866 } 885 }
867 886
868 // Handle impls 887 if world.config.lens.impementations {
869 lenses.extend( 888 // Handle impls
870 world 889 lenses.extend(
871 .analysis() 890 world
872 .file_structure(file_id)? 891 .analysis()
873 .into_iter() 892 .file_structure(file_id)?
874 .filter(|it| match it.kind { 893 .into_iter()
875 SyntaxKind::TRAIT_DEF | SyntaxKind::STRUCT_DEF | SyntaxKind::ENUM_DEF => true, 894 .filter(|it| match it.kind {
876 _ => false, 895 SyntaxKind::TRAIT_DEF | SyntaxKind::STRUCT_DEF | SyntaxKind::ENUM_DEF => true,
877 }) 896 _ => false,
878 .map(|it| { 897 })
879 let range = to_proto::range(&line_index, it.node_range); 898 .map(|it| {
880 let pos = range.start; 899 let range = to_proto::range(&line_index, it.node_range);
881 let lens_params = lsp_types::request::GotoImplementationParams { 900 let pos = range.start;
882 text_document_position_params: lsp_types::TextDocumentPositionParams::new( 901 let lens_params = lsp_types::request::GotoImplementationParams {
883 params.text_document.clone(), 902 text_document_position_params: lsp_types::TextDocumentPositionParams::new(
884 pos, 903 params.text_document.clone(),
885 ), 904 pos,
886 work_done_progress_params: Default::default(), 905 ),
887 partial_result_params: Default::default(), 906 work_done_progress_params: Default::default(),
888 }; 907 partial_result_params: Default::default(),
889 CodeLens { 908 };
890 range, 909 CodeLens {
891 command: None, 910 range,
892 data: Some(to_value(CodeLensResolveData::Impls(lens_params)).unwrap()), 911 command: None,
893 } 912 data: Some(to_value(CodeLensResolveData::Impls(lens_params)).unwrap()),
894 }), 913 }
895 ); 914 }),
896 915 );
916 }
897 Ok(Some(lenses)) 917 Ok(Some(lenses))
898} 918}
899 919
diff --git a/docs/user/readme.adoc b/docs/user/readme.adoc
index d750c7705..03836e6e2 100644
--- a/docs/user/readme.adoc
+++ b/docs/user/readme.adoc
@@ -63,7 +63,7 @@ The server binary is stored in:
63* macOS: `~/Library/Application Support/Code/User/globalStorage/matklad.rust-analyzer` 63* macOS: `~/Library/Application Support/Code/User/globalStorage/matklad.rust-analyzer`
64* Windows: `%APPDATA%\Code\User\globalStorage\matklad.rust-analyzer` 64* Windows: `%APPDATA%\Code\User\globalStorage\matklad.rust-analyzer`
65 65
66Note that we only support the latest version of VS Code. 66Note that we only support two most recent versions of VS Code.
67 67
68==== Updates 68==== Updates
69 69
diff --git a/editors/code/package.json b/editors/code/package.json
index 4e7e3faf7..d899f60e3 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -21,7 +21,7 @@
21 "Programming Languages" 21 "Programming Languages"
22 ], 22 ],
23 "engines": { 23 "engines": {
24 "vscode": "^1.45.0" 24 "vscode": "^1.44.0"
25 }, 25 },
26 "enableProposedApi": true, 26 "enableProposedApi": true,
27 "scripts": { 27 "scripts": {
@@ -41,7 +41,7 @@
41 "@rollup/plugin-node-resolve": "^7.1.3", 41 "@rollup/plugin-node-resolve": "^7.1.3",
42 "@types/node": "^12.12.39", 42 "@types/node": "^12.12.39",
43 "@types/node-fetch": "^2.5.7", 43 "@types/node-fetch": "^2.5.7",
44 "@types/vscode": "^1.45.0", 44 "@types/vscode": "^1.44.0",
45 "@typescript-eslint/eslint-plugin": "^2.33.0", 45 "@typescript-eslint/eslint-plugin": "^2.33.0",
46 "@typescript-eslint/parser": "^2.33.0", 46 "@typescript-eslint/parser": "^2.33.0",
47 "eslint": "^6.8.0", 47 "eslint": "^6.8.0",
@@ -443,6 +443,26 @@
443 "type": "object", 443 "type": "object",
444 "default": {}, 444 "default": {},
445 "description": "Optional settings passed to the debug engine. Example:\n{ \"lldb\": { \"terminal\":\"external\"} }" 445 "description": "Optional settings passed to the debug engine. Example:\n{ \"lldb\": { \"terminal\":\"external\"} }"
446 },
447 "rust-analyzer.lens.enable": {
448 "description": "Whether to show CodeLens in Rust files.",
449 "type": "boolean",
450 "default": true
451 },
452 "rust-analyzer.lens.run": {
453 "markdownDescription": "Whether to show Run lens. Only applies when `#rust-analyzer.lens.enable#` is set.",
454 "type": "boolean",
455 "default": true
456 },
457 "rust-analyzer.lens.debug": {
458 "markdownDescription": "Whether to show Debug lens. Only applies when `#rust-analyzer.lens.enable#` is set.",
459 "type": "boolean",
460 "default": true
461 },
462 "rust-analyzer.lens.implementations": {
463 "markdownDescription": "Whether to show Implementations lens. Only applies when `#rust-analyzer.lens.enable#` is set.",
464 "type": "boolean",
465 "default": true
446 } 466 }
447 } 467 }
448 }, 468 },
@@ -604,6 +624,9 @@
604 { 624 {
605 "language": "rust", 625 "language": "rust",
606 "scopes": { 626 "scopes": {
627 "macro": [
628 "entity.name.function.macro.rust"
629 ],
607 "attribute": [ 630 "attribute": [
608 "meta.attribute.rust" 631 "meta.attribute.rust"
609 ], 632 ],
diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts
index b1d93fc34..0bd30fb07 100644
--- a/editors/code/src/commands/runnables.ts
+++ b/editors/code/src/commands/runnables.ts
@@ -7,7 +7,7 @@ import { startDebugSession, getDebugConfiguration } from '../debug';
7 7
8const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }]; 8const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }];
9 9
10async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, showButtons: boolean = true): Promise<RunnableQuickPick | undefined> { 10async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, debuggeeOnly = false, showButtons: boolean = true): Promise<RunnableQuickPick | undefined> {
11 const editor = ctx.activeRustEditor; 11 const editor = ctx.activeRustEditor;
12 const client = ctx.client; 12 const client = ctx.client;
13 if (!editor || !client) return; 13 if (!editor || !client) return;
@@ -33,9 +33,20 @@ async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, showBu
33 ) { 33 ) {
34 continue; 34 continue;
35 } 35 }
36
37 if (debuggeeOnly && (r.label.startsWith('doctest') || r.label.startsWith('cargo'))) {
38 continue;
39 }
36 items.push(new RunnableQuickPick(r)); 40 items.push(new RunnableQuickPick(r));
37 } 41 }
38 42
43 if (items.length === 0) {
44 // it is the debug case, run always has at least 'cargo check ...'
45 // see crates\rust-analyzer\src\main_loop\handlers.rs, handle_runnables
46 vscode.window.showErrorMessage("There's no debug target!");
47 return;
48 }
49
39 return await new Promise((resolve) => { 50 return await new Promise((resolve) => {
40 const disposables: vscode.Disposable[] = []; 51 const disposables: vscode.Disposable[] = [];
41 const close = (result?: RunnableQuickPick) => { 52 const close = (result?: RunnableQuickPick) => {
@@ -107,7 +118,7 @@ export function debug(ctx: Ctx): Cmd {
107 let prevDebuggee: RunnableQuickPick | undefined; 118 let prevDebuggee: RunnableQuickPick | undefined;
108 119
109 return async () => { 120 return async () => {
110 const item = await selectRunnable(ctx, prevDebuggee); 121 const item = await selectRunnable(ctx, prevDebuggee, true);
111 if (!item) return; 122 if (!item) return;
112 123
113 item.detail = 'restart'; 124 item.detail = 'restart';
@@ -147,7 +158,7 @@ async function makeDebugConfig(ctx: Ctx, item: RunnableQuickPick): Promise<void>
147 158
148export function newDebugConfig(ctx: Ctx): Cmd { 159export function newDebugConfig(ctx: Ctx): Cmd {
149 return async () => { 160 return async () => {
150 const item = await selectRunnable(ctx, undefined, false); 161 const item = await selectRunnable(ctx, undefined, true, false);
151 if (!item) return; 162 if (!item) return;
152 163
153 await makeDebugConfig(ctx, item); 164 await makeDebugConfig(ctx, item);
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 1652827c3..ee294fbe3 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -16,6 +16,10 @@ export class Config {
16 "files", 16 "files",
17 "highlighting", 17 "highlighting",
18 "updates.channel", 18 "updates.channel",
19 "lens.enable",
20 "lens.run",
21 "lens.debug",
22 "lens.implementations",
19 ] 23 ]
20 .map(opt => `${this.rootSection}.${opt}`); 24 .map(opt => `${this.rootSection}.${opt}`);
21 25
@@ -119,4 +123,13 @@ export class Config {
119 sourceFileMap: sourceFileMap 123 sourceFileMap: sourceFileMap
120 }; 124 };
121 } 125 }
126
127 get lens() {
128 return {
129 enable: this.get<boolean>("lens.enable"),
130 run: this.get<boolean>("lens.run"),
131 debug: this.get<boolean>("lens.debug"),
132 implementations: this.get<boolean>("lens.implementations"),
133 };
134 }
122} 135}