Skip to content

Commit e903fd0

Browse files
committed
feat: add debug code lens
Refs #3539
1 parent 05b4fc6 commit e903fd0

File tree

8 files changed

+77
-30
lines changed

8 files changed

+77
-30
lines changed

crates/rust-analyzer/src/cargo_target_spec.rs

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,50 +19,48 @@ impl CargoTargetSpec {
1919
pub(crate) fn runnable_args(
2020
spec: Option<CargoTargetSpec>,
2121
kind: &RunnableKind,
22-
) -> Result<Vec<String>> {
23-
let mut res = Vec::new();
22+
) -> Result<(Vec<String>, Vec<String>)> {
23+
let mut args = Vec::new();
24+
let mut extra_args = Vec::new();
2425
match kind {
2526
RunnableKind::Test { test_id } => {
26-
res.push("test".to_string());
27+
args.push("test".to_string());
2728
if let Some(spec) = spec {
28-
spec.push_to(&mut res);
29+
spec.push_to(&mut args);
2930
}
30-
res.push("--".to_string());
31-
res.push(test_id.to_string());
31+
extra_args.push(test_id.to_string());
3232
if let TestId::Path(_) = test_id {
33-
res.push("--exact".to_string());
33+
extra_args.push("--exact".to_string());
3434
}
35-
res.push("--nocapture".to_string());
35+
extra_args.push("--nocapture".to_string());
3636
}
3737
RunnableKind::TestMod { path } => {
38-
res.push("test".to_string());
38+
args.push("test".to_string());
3939
if let Some(spec) = spec {
40-
spec.push_to(&mut res);
40+
spec.push_to(&mut args);
4141
}
42-
res.push("--".to_string());
43-
res.push(path.to_string());
44-
res.push("--nocapture".to_string());
42+
extra_args.push(path.to_string());
43+
extra_args.push("--nocapture".to_string());
4544
}
4645
RunnableKind::Bench { test_id } => {
47-
res.push("bench".to_string());
46+
args.push("bench".to_string());
4847
if let Some(spec) = spec {
49-
spec.push_to(&mut res);
48+
spec.push_to(&mut args);
5049
}
51-
res.push("--".to_string());
52-
res.push(test_id.to_string());
50+
extra_args.push(test_id.to_string());
5351
if let TestId::Path(_) = test_id {
54-
res.push("--exact".to_string());
52+
extra_args.push("--exact".to_string());
5553
}
56-
res.push("--nocapture".to_string());
54+
extra_args.push("--nocapture".to_string());
5755
}
5856
RunnableKind::Bin => {
59-
res.push("run".to_string());
57+
args.push("run".to_string());
6058
if let Some(spec) = spec {
61-
spec.push_to(&mut res);
59+
spec.push_to(&mut args);
6260
}
6361
}
6462
}
65-
Ok(res)
63+
Ok((args, extra_args))
6664
}
6765

6866
pub(crate) fn for_file(

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

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,7 @@ pub fn handle_runnables(
381381
label,
382382
bin: "cargo".to_string(),
383383
args: check_args,
384+
extra_args: Vec::with_capacity(0),
384385
env: FxHashMap::default(),
385386
cwd: workspace_root.map(|root| root.to_string_lossy().to_string()),
386387
});
@@ -795,17 +796,29 @@ pub fn handle_code_lens(
795796
}
796797
.to_string();
797798
let r = to_lsp_runnable(&world, file_id, runnable)?;
799+
let range = r.range;
800+
let arguments = vec![to_value(r).unwrap()];
798801
let lens = CodeLens {
799-
range: r.range,
802+
range: range.clone(),
800803
command: Some(Command {
801804
title,
802805
command: "rust-analyzer.runSingle".into(),
803-
arguments: Some(vec![to_value(r).unwrap()]),
806+
arguments: Some(arguments.clone()),
807+
}),
808+
data: None,
809+
};
810+
let debug_lens = CodeLens {
811+
range,
812+
command: Some(Command {
813+
title: "Debug".into(),
814+
command: "rust-analyzer.debugSingle".into(),
815+
arguments: Some(arguments.clone()),
804816
}),
805817
data: None,
806818
};
807819

808820
lenses.push(lens);
821+
lenses.push(debug_lens);
809822
}
810823

811824
// Handle impls
@@ -952,7 +965,7 @@ fn to_lsp_runnable(
952965
runnable: Runnable,
953966
) -> Result<req::Runnable> {
954967
let spec = CargoTargetSpec::for_file(world, file_id)?;
955-
let args = CargoTargetSpec::runnable_args(spec, &runnable.kind)?;
968+
let (args, extra_args) = CargoTargetSpec::runnable_args(spec, &runnable.kind)?;
956969
let line_index = world.analysis().file_line_index(file_id)?;
957970
let label = match &runnable.kind {
958971
RunnableKind::Test { test_id } => format!("test {}", test_id),
@@ -965,6 +978,7 @@ fn to_lsp_runnable(
965978
label,
966979
bin: "cargo".to_string(),
967980
args,
981+
extra_args,
968982
env: {
969983
let mut m = FxHashMap::default();
970984
m.insert("RUST_BACKTRACE".to_string(), "short".to_string());
@@ -973,6 +987,7 @@ fn to_lsp_runnable(
973987
cwd: world.workspace_root_for(file_id).map(|root| root.to_string_lossy().to_string()),
974988
})
975989
}
990+
976991
fn highlight(world: &WorldSnapshot, file_id: FileId) -> Result<Vec<Decoration>> {
977992
let line_index = world.analysis().file_line_index(file_id)?;
978993
let res = world

crates/rust-analyzer/src/req.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ pub struct Runnable {
169169
pub label: String,
170170
pub bin: String,
171171
pub args: Vec<String>,
172+
pub extra_args: Vec<String>,
172173
pub env: FxHashMap<String, String>,
173174
pub cwd: Option<String>,
174175
}

crates/rust-analyzer/tests/heavy_tests/main.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ fn foo() {
7575
RunnablesParams { text_document: server.doc_id("lib.rs"), position: None },
7676
json!([
7777
{
78-
"args": [ "test", "--", "foo", "--nocapture" ],
78+
"args": [ "test" ],
79+
"extraArgs": [ "foo", "--nocapture" ],
7980
"bin": "cargo",
8081
"env": { "RUST_BACKTRACE": "short" },
8182
"cwd": null,
@@ -90,6 +91,7 @@ fn foo() {
9091
"check",
9192
"--all"
9293
],
94+
"extraArgs": [],
9395
"bin": "cargo",
9496
"env": {},
9597
"cwd": null,
@@ -147,7 +149,8 @@ fn main() {}
147149
},
148150
json!([
149151
{
150-
"args": [ "test", "--package", "foo", "--test", "spam", "--", "test_eggs", "--exact", "--nocapture" ],
152+
"args": [ "test", "--package", "foo", "--test", "spam" ],
153+
"extraArgs": [ "test_eggs", "--exact", "--nocapture" ],
151154
"bin": "cargo",
152155
"env": { "RUST_BACKTRACE": "short" },
153156
"label": "test test_eggs",
@@ -165,6 +168,7 @@ fn main() {}
165168
"--test",
166169
"spam"
167170
],
171+
"extraArgs": [],
168172
"bin": "cargo",
169173
"env": {},
170174
"cwd": server.path().join("foo"),

editors/code/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@
5151
"typescript-formatter": "^7.2.2",
5252
"vsce": "^1.74.0"
5353
},
54+
"extensionDependencies": [
55+
"vadimcn.vscode-lldb"
56+
],
5457
"activationEvents": [
5558
"onLanguage:rust",
5659
"onCommand:rust-analyzer.analyzerStatus",

editors/code/src/commands/runnables.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as lc from 'vscode-languageclient';
33
import * as ra from '../rust-analyzer-api';
44

55
import { Ctx, Cmd } from '../ctx';
6+
import { debug } from 'vscode';
67

78
export function run(ctx: Ctx): Cmd {
89
let prevRunnable: RunnableQuickPick | undefined;
@@ -62,6 +63,31 @@ export function runSingle(ctx: Ctx): Cmd {
6263
};
6364
}
6465

66+
export function debugSingle(ctx: Ctx): Cmd {
67+
return async (config: ra.Runnable) => {
68+
const editor = ctx.activeRustEditor;
69+
if (!editor) return;
70+
71+
if (config.args[0] === 'run') {
72+
config.args[0] = 'build';
73+
} else {
74+
config.args.push('--no-run');
75+
}
76+
77+
const debugConfig = {
78+
type: "lldb",
79+
request: "launch",
80+
name: config.label,
81+
cargo: {
82+
args: config.args,
83+
},
84+
args: config.extraArgs,
85+
cwd: config.cwd
86+
};
87+
return debug.startDebugging(undefined, debugConfig);
88+
};
89+
}
90+
6591
class RunnableQuickPick implements vscode.QuickPickItem {
6692
public label: string;
6793
public description?: string | undefined;
@@ -87,7 +113,7 @@ function createTask(spec: ra.Runnable): vscode.Task {
87113
type: 'cargo',
88114
label: spec.label,
89115
command: spec.bin,
90-
args: spec.args,
116+
args: spec.extraArgs ? [...spec.args, '--', ...spec.extraArgs] : spec.args,
91117
env: spec.env,
92118
};
93119

editors/code/src/main.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ export async function activate(context: vscode.ExtensionContext) {
8383

8484
// Internal commands which are invoked by the server.
8585
ctx.registerCommand('runSingle', commands.runSingle);
86+
ctx.registerCommand('debugSingle', commands.debugSingle);
8687
ctx.registerCommand('showReferences', commands.showReferences);
8788
ctx.registerCommand('applySourceChange', commands.applySourceChange);
8889
ctx.registerCommand('selectAndApplySourceChange', commands.selectAndApplySourceChange);

editors/code/src/rust-analyzer-api.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,12 @@ export interface Runnable {
8080
label: string;
8181
bin: string;
8282
args: Vec<string>;
83+
extraArgs: Vec<string>;
8384
env: FxHashMap<string, string>;
8485
cwd: Option<string>;
8586
}
8687
export const runnables = request<RunnablesParams, Vec<Runnable>>("runnables");
8788

88-
89-
9089
export type InlayHint = InlayHint.TypeHint | InlayHint.ParamHint;
9190

9291
export namespace InlayHint {

0 commit comments

Comments
 (0)