Skip to content

Commit c6ed089

Browse files
bors[bot]vsrs
andauthored
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 <[email protected]>
2 parents 31611da + 78817a3 commit c6ed089

File tree

5 files changed

+181
-76
lines changed

5 files changed

+181
-76
lines changed

crates/rust-analyzer/src/config.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,36 @@ pub struct Config {
3333
pub inlay_hints: InlayHintsConfig,
3434
pub completion: CompletionConfig,
3535
pub call_info_full: bool,
36+
pub lens: LensConfig,
37+
}
38+
39+
#[derive(Clone, Debug, PartialEq, Eq)]
40+
pub struct LensConfig {
41+
pub run: bool,
42+
pub debug: bool,
43+
pub impementations: bool,
44+
}
45+
46+
impl Default for LensConfig {
47+
fn default() -> Self {
48+
Self { run: true, debug: true, impementations: true }
49+
}
50+
}
51+
52+
impl 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+
}
3666
}
3767

3868
#[derive(Debug, Clone)]
@@ -107,6 +137,7 @@ impl Default for Config {
107137
..CompletionConfig::default()
108138
},
109139
call_info_full: true,
140+
lens: LensConfig::default(),
110141
}
111142
}
112143
}
@@ -196,6 +227,16 @@ impl Config {
196227
set(value, "/completion/addCallArgumentSnippets", &mut self.completion.add_call_argument_snippets);
197228
set(value, "/callInfo/full", &mut self.call_info_full);
198229

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+
199240
log::info!("Config::update() = {:#?}", self);
200241

201242
fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option<T> {

crates/rust-analyzer/src/main_loop/handlers.rs

Lines changed: 93 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -812,88 +812,108 @@ pub fn handle_code_lens(
812812
params: lsp_types::CodeLensParams,
813813
) -> Result<Option<Vec<CodeLens>>> {
814814
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-
818815
let mut lenses: Vec<CodeLens> = Default::default();
819816

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)?;
820824
let cargo_spec = CargoTargetSpec::for_file(&world, file_id)?;
821-
// Gather runnables
822-
for runnable in world.analysis().runnables(file_id)? {
823-
let title = match &runnable.kind {
824-
RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => "▶\u{fe0e} Run Test",
825-
RunnableKind::DocTest { .. } => "▶\u{fe0e} Run Doctest",
826-
RunnableKind::Bench { .. } => "Run Bench",
827-
RunnableKind::Bin => {
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,
825+
826+
if world.config.lens.runnable() {
827+
// Gather runnables
828+
for runnable in world.analysis().runnables(file_id)? {
829+
let (run_title, debugee) = match &runnable.kind {
830+
RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => {
831+
("▶️\u{fe0e}Run Test", true)
835832
}
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);
836865
}
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);
850866

851-
if r.args[0] == "run" {
852-
r.args[0] = "build".into();
853-
} else {
854-
r.args.push("--no-run".into());
867+
if debugee && world.config.lens.debug {
868+
if r.args[0] == "run" {
869+
r.args[0] = "build".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+
}
855884
}
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);
866885
}
867886

868-
// Handle impls
869-
lenses.extend(
870-
world
871-
.analysis()
872-
.file_structure(file_id)?
873-
.into_iter()
874-
.filter(|it| match it.kind {
875-
SyntaxKind::TRAIT_DEF | SyntaxKind::STRUCT_DEF | SyntaxKind::ENUM_DEF => true,
876-
_ => false,
877-
})
878-
.map(|it| {
879-
let range = to_proto::range(&line_index, it.node_range);
880-
let pos = range.start;
881-
let lens_params = lsp_types::request::GotoImplementationParams {
882-
text_document_position_params: lsp_types::TextDocumentPositionParams::new(
883-
params.text_document.clone(),
884-
pos,
885-
),
886-
work_done_progress_params: Default::default(),
887-
partial_result_params: Default::default(),
888-
};
889-
CodeLens {
890-
range,
891-
command: None,
892-
data: Some(to_value(CodeLensResolveData::Impls(lens_params)).unwrap()),
893-
}
894-
}),
895-
);
896-
887+
if world.config.lens.impementations {
888+
// Handle impls
889+
lenses.extend(
890+
world
891+
.analysis()
892+
.file_structure(file_id)?
893+
.into_iter()
894+
.filter(|it| match it.kind {
895+
SyntaxKind::TRAIT_DEF | SyntaxKind::STRUCT_DEF | SyntaxKind::ENUM_DEF => true,
896+
_ => false,
897+
})
898+
.map(|it| {
899+
let range = to_proto::range(&line_index, it.node_range);
900+
let pos = range.start;
901+
let lens_params = lsp_types::request::GotoImplementationParams {
902+
text_document_position_params: lsp_types::TextDocumentPositionParams::new(
903+
params.text_document.clone(),
904+
pos,
905+
),
906+
work_done_progress_params: Default::default(),
907+
partial_result_params: Default::default(),
908+
};
909+
CodeLens {
910+
range,
911+
command: None,
912+
data: Some(to_value(CodeLensResolveData::Impls(lens_params)).unwrap()),
913+
}
914+
}),
915+
);
916+
}
897917
Ok(Some(lenses))
898918
}
899919

editors/code/package.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,26 @@
443443
"type": "object",
444444
"default": {},
445445
"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
446466
}
447467
}
448468
},

editors/code/src/commands/runnables.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { startDebugSession, getDebugConfiguration } from '../debug';
77

88
const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }];
99

10-
async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, showButtons: boolean = true): Promise<RunnableQuickPick | undefined> {
10+
async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, debuggeeOnly = false, showButtons: boolean = true): Promise<RunnableQuickPick | undefined> {
1111
const editor = ctx.activeRustEditor;
1212
const client = ctx.client;
1313
if (!editor || !client) return;
@@ -33,9 +33,20 @@ async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, showBu
3333
) {
3434
continue;
3535
}
36+
37+
if (debuggeeOnly && (r.label.startsWith('doctest') || r.label.startsWith('cargo'))) {
38+
continue;
39+
}
3640
items.push(new RunnableQuickPick(r));
3741
}
3842

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+
3950
return await new Promise((resolve) => {
4051
const disposables: vscode.Disposable[] = [];
4152
const close = (result?: RunnableQuickPick) => {
@@ -107,7 +118,7 @@ export function debug(ctx: Ctx): Cmd {
107118
let prevDebuggee: RunnableQuickPick | undefined;
108119

109120
return async () => {
110-
const item = await selectRunnable(ctx, prevDebuggee);
121+
const item = await selectRunnable(ctx, prevDebuggee, true);
111122
if (!item) return;
112123

113124
item.detail = 'restart';
@@ -147,7 +158,7 @@ async function makeDebugConfig(ctx: Ctx, item: RunnableQuickPick): Promise<void>
147158

148159
export function newDebugConfig(ctx: Ctx): Cmd {
149160
return async () => {
150-
const item = await selectRunnable(ctx, undefined, false);
161+
const item = await selectRunnable(ctx, undefined, true, false);
151162
if (!item) return;
152163

153164
await makeDebugConfig(ctx, item);

editors/code/src/config.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ export class Config {
1616
"files",
1717
"highlighting",
1818
"updates.channel",
19+
"lens.enable",
20+
"lens.run",
21+
"lens.debug",
22+
"lens.implementations",
1923
]
2024
.map(opt => `${this.rootSection}.${opt}`);
2125

@@ -119,4 +123,13 @@ export class Config {
119123
sourceFileMap: sourceFileMap
120124
};
121125
}
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+
}
122135
}

0 commit comments

Comments
 (0)