feat: add debug code lens

Refs #3539
This commit is contained in:
Hannes De Valkeneer 2020-03-09 22:06:45 +01:00
parent 05b4fc6d79
commit e903fd0d97
8 changed files with 77 additions and 30 deletions

View file

@ -19,50 +19,48 @@ impl CargoTargetSpec {
pub(crate) fn runnable_args( pub(crate) fn runnable_args(
spec: Option<CargoTargetSpec>, spec: Option<CargoTargetSpec>,
kind: &RunnableKind, kind: &RunnableKind,
) -> Result<Vec<String>> { ) -> Result<(Vec<String>, Vec<String>)> {
let mut res = Vec::new(); let mut args = Vec::new();
let mut extra_args = Vec::new();
match kind { match kind {
RunnableKind::Test { test_id } => { RunnableKind::Test { test_id } => {
res.push("test".to_string()); args.push("test".to_string());
if let Some(spec) = spec { if let Some(spec) = spec {
spec.push_to(&mut res); spec.push_to(&mut args);
} }
res.push("--".to_string()); extra_args.push(test_id.to_string());
res.push(test_id.to_string());
if let TestId::Path(_) = test_id { if let TestId::Path(_) = test_id {
res.push("--exact".to_string()); extra_args.push("--exact".to_string());
} }
res.push("--nocapture".to_string()); extra_args.push("--nocapture".to_string());
} }
RunnableKind::TestMod { path } => { RunnableKind::TestMod { path } => {
res.push("test".to_string()); args.push("test".to_string());
if let Some(spec) = spec { if let Some(spec) = spec {
spec.push_to(&mut res); spec.push_to(&mut args);
} }
res.push("--".to_string()); extra_args.push(path.to_string());
res.push(path.to_string()); extra_args.push("--nocapture".to_string());
res.push("--nocapture".to_string());
} }
RunnableKind::Bench { test_id } => { RunnableKind::Bench { test_id } => {
res.push("bench".to_string()); args.push("bench".to_string());
if let Some(spec) = spec { if let Some(spec) = spec {
spec.push_to(&mut res); spec.push_to(&mut args);
} }
res.push("--".to_string()); extra_args.push(test_id.to_string());
res.push(test_id.to_string());
if let TestId::Path(_) = test_id { if let TestId::Path(_) = test_id {
res.push("--exact".to_string()); extra_args.push("--exact".to_string());
} }
res.push("--nocapture".to_string()); extra_args.push("--nocapture".to_string());
} }
RunnableKind::Bin => { RunnableKind::Bin => {
res.push("run".to_string()); args.push("run".to_string());
if let Some(spec) = spec { if let Some(spec) = spec {
spec.push_to(&mut res); spec.push_to(&mut args);
} }
} }
} }
Ok(res) Ok((args, extra_args))
} }
pub(crate) fn for_file( pub(crate) fn for_file(

View file

@ -381,6 +381,7 @@ pub fn handle_runnables(
label, label,
bin: "cargo".to_string(), bin: "cargo".to_string(),
args: check_args, args: check_args,
extra_args: Vec::with_capacity(0),
env: FxHashMap::default(), env: FxHashMap::default(),
cwd: workspace_root.map(|root| root.to_string_lossy().to_string()), cwd: workspace_root.map(|root| root.to_string_lossy().to_string()),
}); });
@ -795,17 +796,29 @@ pub fn handle_code_lens(
} }
.to_string(); .to_string();
let r = to_lsp_runnable(&world, file_id, runnable)?; let r = to_lsp_runnable(&world, file_id, runnable)?;
let range = r.range;
let arguments = vec![to_value(r).unwrap()];
let lens = CodeLens { let lens = CodeLens {
range: r.range, range: range.clone(),
command: Some(Command { command: Some(Command {
title, title,
command: "rust-analyzer.runSingle".into(), command: "rust-analyzer.runSingle".into(),
arguments: Some(vec![to_value(r).unwrap()]), arguments: Some(arguments.clone()),
}),
data: None,
};
let debug_lens = CodeLens {
range,
command: Some(Command {
title: "Debug".into(),
command: "rust-analyzer.debugSingle".into(),
arguments: Some(arguments.clone()),
}), }),
data: None, data: None,
}; };
lenses.push(lens); lenses.push(lens);
lenses.push(debug_lens);
} }
// Handle impls // Handle impls
@ -952,7 +965,7 @@ fn to_lsp_runnable(
runnable: Runnable, runnable: Runnable,
) -> Result<req::Runnable> { ) -> Result<req::Runnable> {
let spec = CargoTargetSpec::for_file(world, file_id)?; let spec = CargoTargetSpec::for_file(world, file_id)?;
let args = CargoTargetSpec::runnable_args(spec, &runnable.kind)?; let (args, extra_args) = CargoTargetSpec::runnable_args(spec, &runnable.kind)?;
let line_index = world.analysis().file_line_index(file_id)?; let line_index = world.analysis().file_line_index(file_id)?;
let label = match &runnable.kind { let label = match &runnable.kind {
RunnableKind::Test { test_id } => format!("test {}", test_id), RunnableKind::Test { test_id } => format!("test {}", test_id),
@ -965,6 +978,7 @@ fn to_lsp_runnable(
label, label,
bin: "cargo".to_string(), bin: "cargo".to_string(),
args, args,
extra_args,
env: { env: {
let mut m = FxHashMap::default(); let mut m = FxHashMap::default();
m.insert("RUST_BACKTRACE".to_string(), "short".to_string()); m.insert("RUST_BACKTRACE".to_string(), "short".to_string());
@ -973,6 +987,7 @@ fn to_lsp_runnable(
cwd: world.workspace_root_for(file_id).map(|root| root.to_string_lossy().to_string()), cwd: world.workspace_root_for(file_id).map(|root| root.to_string_lossy().to_string()),
}) })
} }
fn highlight(world: &WorldSnapshot, file_id: FileId) -> Result<Vec<Decoration>> { fn highlight(world: &WorldSnapshot, file_id: FileId) -> Result<Vec<Decoration>> {
let line_index = world.analysis().file_line_index(file_id)?; let line_index = world.analysis().file_line_index(file_id)?;
let res = world let res = world

View file

@ -169,6 +169,7 @@ pub struct Runnable {
pub label: String, pub label: String,
pub bin: String, pub bin: String,
pub args: Vec<String>, pub args: Vec<String>,
pub extra_args: Vec<String>,
pub env: FxHashMap<String, String>, pub env: FxHashMap<String, String>,
pub cwd: Option<String>, pub cwd: Option<String>,
} }

View file

@ -75,7 +75,8 @@ fn foo() {
RunnablesParams { text_document: server.doc_id("lib.rs"), position: None }, RunnablesParams { text_document: server.doc_id("lib.rs"), position: None },
json!([ json!([
{ {
"args": [ "test", "--", "foo", "--nocapture" ], "args": [ "test" ],
"extraArgs": [ "foo", "--nocapture" ],
"bin": "cargo", "bin": "cargo",
"env": { "RUST_BACKTRACE": "short" }, "env": { "RUST_BACKTRACE": "short" },
"cwd": null, "cwd": null,
@ -90,6 +91,7 @@ fn foo() {
"check", "check",
"--all" "--all"
], ],
"extraArgs": [],
"bin": "cargo", "bin": "cargo",
"env": {}, "env": {},
"cwd": null, "cwd": null,
@ -147,7 +149,8 @@ fn main() {}
}, },
json!([ json!([
{ {
"args": [ "test", "--package", "foo", "--test", "spam", "--", "test_eggs", "--exact", "--nocapture" ], "args": [ "test", "--package", "foo", "--test", "spam" ],
"extraArgs": [ "test_eggs", "--exact", "--nocapture" ],
"bin": "cargo", "bin": "cargo",
"env": { "RUST_BACKTRACE": "short" }, "env": { "RUST_BACKTRACE": "short" },
"label": "test test_eggs", "label": "test test_eggs",
@ -165,6 +168,7 @@ fn main() {}
"--test", "--test",
"spam" "spam"
], ],
"extraArgs": [],
"bin": "cargo", "bin": "cargo",
"env": {}, "env": {},
"cwd": server.path().join("foo"), "cwd": server.path().join("foo"),

View file

@ -51,6 +51,9 @@
"typescript-formatter": "^7.2.2", "typescript-formatter": "^7.2.2",
"vsce": "^1.74.0" "vsce": "^1.74.0"
}, },
"extensionDependencies": [
"vadimcn.vscode-lldb"
],
"activationEvents": [ "activationEvents": [
"onLanguage:rust", "onLanguage:rust",
"onCommand:rust-analyzer.analyzerStatus", "onCommand:rust-analyzer.analyzerStatus",

View file

@ -3,6 +3,7 @@ import * as lc from 'vscode-languageclient';
import * as ra from '../rust-analyzer-api'; import * as ra from '../rust-analyzer-api';
import { Ctx, Cmd } from '../ctx'; import { Ctx, Cmd } from '../ctx';
import { debug } from 'vscode';
export function run(ctx: Ctx): Cmd { export function run(ctx: Ctx): Cmd {
let prevRunnable: RunnableQuickPick | undefined; let prevRunnable: RunnableQuickPick | undefined;
@ -62,6 +63,31 @@ export function runSingle(ctx: Ctx): Cmd {
}; };
} }
export function debugSingle(ctx: Ctx): Cmd {
return async (config: ra.Runnable) => {
const editor = ctx.activeRustEditor;
if (!editor) return;
if (config.args[0] === 'run') {
config.args[0] = 'build';
} else {
config.args.push('--no-run');
}
const debugConfig = {
type: "lldb",
request: "launch",
name: config.label,
cargo: {
args: config.args,
},
args: config.extraArgs,
cwd: config.cwd
};
return debug.startDebugging(undefined, debugConfig);
};
}
class RunnableQuickPick implements vscode.QuickPickItem { class RunnableQuickPick implements vscode.QuickPickItem {
public label: string; public label: string;
public description?: string | undefined; public description?: string | undefined;
@ -87,7 +113,7 @@ function createTask(spec: ra.Runnable): vscode.Task {
type: 'cargo', type: 'cargo',
label: spec.label, label: spec.label,
command: spec.bin, command: spec.bin,
args: spec.args, args: spec.extraArgs ? [...spec.args, '--', ...spec.extraArgs] : spec.args,
env: spec.env, env: spec.env,
}; };

View file

@ -83,6 +83,7 @@ export async function activate(context: vscode.ExtensionContext) {
// Internal commands which are invoked by the server. // Internal commands which are invoked by the server.
ctx.registerCommand('runSingle', commands.runSingle); ctx.registerCommand('runSingle', commands.runSingle);
ctx.registerCommand('debugSingle', commands.debugSingle);
ctx.registerCommand('showReferences', commands.showReferences); ctx.registerCommand('showReferences', commands.showReferences);
ctx.registerCommand('applySourceChange', commands.applySourceChange); ctx.registerCommand('applySourceChange', commands.applySourceChange);
ctx.registerCommand('selectAndApplySourceChange', commands.selectAndApplySourceChange); ctx.registerCommand('selectAndApplySourceChange', commands.selectAndApplySourceChange);

View file

@ -80,13 +80,12 @@ export interface Runnable {
label: string; label: string;
bin: string; bin: string;
args: Vec<string>; args: Vec<string>;
extraArgs: Vec<string>;
env: FxHashMap<string, string>; env: FxHashMap<string, string>;
cwd: Option<string>; cwd: Option<string>;
} }
export const runnables = request<RunnablesParams, Vec<Runnable>>("runnables"); export const runnables = request<RunnablesParams, Vec<Runnable>>("runnables");
export type InlayHint = InlayHint.TypeHint | InlayHint.ParamHint; export type InlayHint = InlayHint.TypeHint | InlayHint.ParamHint;
export namespace InlayHint { export namespace InlayHint {