diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs index 5da28edd24..c7bb1e69f8 100644 --- a/crates/ra_ide/src/display/navigation_target.rs +++ b/crates/ra_ide/src/display/navigation_target.rs @@ -92,15 +92,16 @@ impl NavigationTarget { let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); if let Some(src) = module.declaration_source(db) { let frange = original_range(db, src.as_ref().map(|it| it.syntax())); - return NavigationTarget::from_syntax( + let mut res = NavigationTarget::from_syntax( frange.file_id, name, None, frange.range, src.value.syntax().kind(), - src.value.doc_comment_text(), - src.value.short_label(), ); + res.docs = src.value.doc_comment_text(); + res.description = src.value.short_label(); + return res; } module.to_nav(db) } @@ -130,11 +131,9 @@ impl NavigationTarget { } /// Allows `NavigationTarget` to be created from a `NameOwner` - fn from_named( + pub(crate) fn from_named( db: &RootDatabase, node: InFile<&dyn ast::NameOwner>, - docs: Option, - description: Option, ) -> NavigationTarget { //FIXME: use `_` instead of empty string let name = node.value.name().map(|it| it.text().clone()).unwrap_or_default(); @@ -148,8 +147,6 @@ impl NavigationTarget { focus_range, frange.range, node.value.syntax().kind(), - docs, - description, ) } @@ -159,8 +156,6 @@ impl NavigationTarget { focus_range: Option, full_range: TextRange, kind: SyntaxKind, - docs: Option, - description: Option, ) -> NavigationTarget { NavigationTarget { file_id, @@ -169,8 +164,8 @@ impl NavigationTarget { full_range, focus_range, container_name: None, - description, - docs, + description: None, + docs: None, } } } @@ -238,12 +233,11 @@ where { fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { let src = self.source(db); - NavigationTarget::from_named( - db, - src.as_ref().map(|it| it as &dyn ast::NameOwner), - src.value.doc_comment_text(), - src.value.short_label(), - ) + let mut res = + NavigationTarget::from_named(db, src.as_ref().map(|it| it as &dyn ast::NameOwner)); + res.docs = src.value.doc_comment_text(); + res.description = src.value.short_label(); + res } } @@ -258,15 +252,7 @@ impl ToNav for hir::Module { } }; let frange = original_range(db, src.with_value(syntax)); - NavigationTarget::from_syntax( - frange.file_id, - name, - focus, - frange.range, - syntax.kind(), - None, - None, - ) + NavigationTarget::from_syntax(frange.file_id, name, focus, frange.range, syntax.kind()) } } @@ -285,8 +271,6 @@ impl ToNav for hir::ImplDef { None, frange.range, src.value.syntax().kind(), - None, - None, ) } } @@ -296,12 +280,12 @@ impl ToNav for hir::Field { let src = self.source(db); match &src.value { - FieldSource::Named(it) => NavigationTarget::from_named( - db, - src.with_value(it), - it.doc_comment_text(), - it.short_label(), - ), + FieldSource::Named(it) => { + let mut res = NavigationTarget::from_named(db, src.with_value(it)); + res.docs = it.doc_comment_text(); + res.description = it.short_label(); + res + } FieldSource::Pos(it) => { let frange = original_range(db, src.with_value(it.syntax())); NavigationTarget::from_syntax( @@ -310,8 +294,6 @@ impl ToNav for hir::Field { None, frange.range, it.syntax().kind(), - None, - None, ) } } @@ -322,12 +304,10 @@ impl ToNav for hir::MacroDef { fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { let src = self.source(db); log::debug!("nav target {:#?}", src.value.syntax()); - NavigationTarget::from_named( - db, - src.as_ref().map(|it| it as &dyn ast::NameOwner), - src.value.doc_comment_text(), - None, - ) + let mut res = + NavigationTarget::from_named(db, src.as_ref().map(|it| it as &dyn ast::NameOwner)); + res.docs = src.value.doc_comment_text(); + res } } diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs index 286d45eee9..9239ca61bd 100644 --- a/crates/ra_ide/src/runnables.rs +++ b/crates/ra_ide/src/runnables.rs @@ -1,19 +1,19 @@ +use std::fmt; + use hir::{AsAssocItem, Attrs, HirFileId, InFile, Semantics}; use itertools::Itertools; +use ra_cfg::CfgExpr; use ra_ide_db::RootDatabase; use ra_syntax::{ - ast::{self, AstNode, AttrsOwner, ModuleItemOwner, NameOwner}, - match_ast, SyntaxNode, TextRange, + ast::{self, AstNode, AttrsOwner, DocCommentsOwner, ModuleItemOwner, NameOwner}, + match_ast, SyntaxNode, }; -use crate::FileId; -use ast::DocCommentsOwner; -use ra_cfg::CfgExpr; -use std::fmt::Display; +use crate::{display::ToNav, FileId, NavigationTarget}; #[derive(Debug)] pub struct Runnable { - pub range: TextRange, + pub nav: NavigationTarget, pub kind: RunnableKind, pub cfg_exprs: Vec, } @@ -24,8 +24,8 @@ pub enum TestId { Path(String), } -impl Display for TestId { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { +impl fmt::Display for TestId { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { TestId::Name(name) => write!(f, "{}", name), TestId::Path(path) => write!(f, "{}", path), @@ -131,7 +131,8 @@ fn runnable_fn( let cfg_exprs = attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); - Some(Runnable { range: fn_def.syntax().text_range(), kind, cfg_exprs }) + let nav = NavigationTarget::from_named(sema.db, InFile::new(file_id.into(), &fn_def)); + Some(Runnable { nav, kind, cfg_exprs }) } #[derive(Debug)] @@ -183,7 +184,6 @@ fn runnable_mod( if !has_test_function { return None; } - let range = module.syntax().text_range(); let module_def = sema.to_def(&module)?; let path = module_def @@ -197,7 +197,8 @@ fn runnable_mod( let cfg_exprs = attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); - Some(Runnable { range, kind: RunnableKind::TestMod { path }, cfg_exprs }) + let nav = module_def.to_nav(sema.db); + Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg_exprs }) } #[cfg(test)] diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 173c23b9e5..9381f75d39 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -4,7 +4,6 @@ use std::{collections::HashMap, path::PathBuf}; use lsp_types::request::Request; use lsp_types::{Position, Range, TextDocumentIdentifier}; -use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; pub enum AnalyzerStatus {} @@ -121,25 +120,30 @@ pub struct RunnablesParams { pub position: Option, } -// Must strictly correspond to the executable name +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Runnable { + pub label: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub location: Option, + pub kind: RunnableKind, + pub args: CargoRunnable, +} + #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "lowercase")] pub enum RunnableKind { Cargo, - Rustc, - Rustup, } #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] -pub struct Runnable { - pub range: Range, - pub label: String, - pub kind: RunnableKind, - pub args: Vec, - pub extra_args: Vec, - pub env: FxHashMap, - pub cwd: Option, +pub struct CargoRunnable { + pub workspace_root: Option, + // command, --package and --lib stuff + pub cargo_args: Vec, + // stuff after -- + pub executable_args: Vec, } pub enum InlayHints {} diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 410c654abe..7fd6917649 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -23,7 +23,6 @@ use ra_ide::{ use ra_prof::profile; use ra_project_model::TargetKind; use ra_syntax::{AstNode, SyntaxKind, TextRange, TextSize}; -use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; use serde_json::to_value; use stdx::format_to; @@ -401,7 +400,7 @@ pub fn handle_runnables( let cargo_spec = CargoTargetSpec::for_file(&world, file_id)?; for runnable in world.analysis().runnables(file_id)? { if let Some(offset) = offset { - if !runnable.range.contains_inclusive(offset) { + if !runnable.nav.full_range().contains_inclusive(offset) { continue; } } @@ -422,25 +421,31 @@ pub fn handle_runnables( Some(spec) => { for &cmd in ["check", "test"].iter() { res.push(lsp_ext::Runnable { - range: Default::default(), label: format!("cargo {} -p {}", cmd, spec.package), + location: None, kind: lsp_ext::RunnableKind::Cargo, - args: vec![cmd.to_string(), "--package".to_string(), spec.package.clone()], - extra_args: Vec::new(), - env: FxHashMap::default(), - cwd: workspace_root.map(|root| root.to_owned()), + args: lsp_ext::CargoRunnable { + workspace_root: workspace_root.map(|root| root.to_owned()), + cargo_args: vec![ + cmd.to_string(), + "--package".to_string(), + spec.package.clone(), + ], + executable_args: Vec::new(), + }, }) } } None => { res.push(lsp_ext::Runnable { - range: Default::default(), label: "cargo check --workspace".to_string(), + location: None, kind: lsp_ext::RunnableKind::Cargo, - args: vec!["check".to_string(), "--workspace".to_string()], - extra_args: Vec::new(), - env: FxHashMap::default(), - cwd: workspace_root.map(|root| root.to_owned()), + args: lsp_ext::CargoRunnable { + workspace_root: workspace_root.map(|root| root.to_owned()), + cargo_args: vec!["check".to_string(), "--workspace".to_string()], + executable_args: Vec::new(), + }, }); } } @@ -782,10 +787,11 @@ pub fn handle_code_lens( } }; - let mut r = to_proto::runnable(&world, file_id, runnable)?; + let range = to_proto::range(&line_index, runnable.nav.range()); + let r = to_proto::runnable(&world, file_id, runnable)?; if world.config.lens.run { let lens = CodeLens { - range: r.range, + range, command: Some(Command { title: run_title.to_string(), command: "rust-analyzer.runSingle".into(), @@ -797,13 +803,8 @@ pub fn handle_code_lens( } 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, + range, command: Some(Command { title: "Debug".into(), command: "rust-analyzer.debugSingle".into(), diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 66144fe241..85304aa877 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -8,7 +8,6 @@ use ra_ide::{ }; use ra_syntax::{SyntaxKind, TextRange, TextSize}; use ra_vfs::LineEndings; -use rustc_hash::FxHashMap; use crate::{ cargo_target_spec::CargoTargetSpec, lsp_ext, semantic_tokens, world::WorldSnapshot, Result, @@ -638,9 +637,8 @@ pub(crate) fn runnable( ) -> Result { let spec = CargoTargetSpec::for_file(world, file_id)?; let target = spec.as_ref().map(|s| s.target.clone()); - let (args, extra_args) = + let (cargo_args, executable_args) = CargoTargetSpec::runnable_args(spec, &runnable.kind, &runnable.cfg_exprs)?; - let line_index = world.analysis().file_line_index(file_id)?; let label = match &runnable.kind { RunnableKind::Test { test_id, .. } => format!("test {}", test_id), RunnableKind::TestMod { path } => format!("test-mod {}", path), @@ -650,18 +648,16 @@ pub(crate) fn runnable( target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t)) } }; + let location = location_link(world, None, runnable.nav)?; Ok(lsp_ext::Runnable { - range: range(&line_index, runnable.range), label, + location: Some(location), kind: lsp_ext::RunnableKind::Cargo, - args, - extra_args, - env: { - let mut m = FxHashMap::default(); - m.insert("RUST_BACKTRACE".to_string(), "short".to_string()); - m + args: lsp_ext::CargoRunnable { + workspace_root: world.workspace_root_for(file_id).map(|root| root.to_owned()), + cargo_args, + executable_args, }, - cwd: world.workspace_root_for(file_id).map(|root| root.to_owned()), }) } diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts index 1e421d407b..a0c9b3ab2e 100644 --- a/editors/code/src/debug.ts +++ b/editors/code/src/debug.ts @@ -114,8 +114,8 @@ async function getDebugConfiguration(ctx: Ctx, runnable: ra.Runnable): Promise { - const cargo = new Cargo(runnable.cwd || '.', debugOutput); - const executable = await cargo.executableFromArgs(runnable.args); + const cargo = new Cargo(runnable.args.workspaceRoot || '.', debugOutput); + const executable = await cargo.executableFromArgs(runnable.args.cargoArgs); // if we are here, there were no compilation errors. return executable; @@ -127,8 +127,8 @@ function getLldbDebugConfig(runnable: ra.Runnable, executable: string, sourceFil request: "launch", name: runnable.label, program: executable, - args: runnable.extraArgs, - cwd: runnable.cwd, + args: runnable.args.executableArgs, + cwd: runnable.args.workspaceRoot, sourceMap: sourceFileMap, sourceLanguages: ["rust"] }; @@ -140,8 +140,8 @@ function getCppvsDebugConfig(runnable: ra.Runnable, executable: string, sourceFi request: "launch", name: runnable.label, program: executable, - args: runnable.extraArgs, - cwd: runnable.cwd, + args: runnable.args.executableArgs, + cwd: runnable.args.workspaceRoot, sourceFileMap: sourceFileMap, }; } diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts index 3e0b606997..73d5736787 100644 --- a/editors/code/src/lsp_ext.ts +++ b/editors/code/src/lsp_ext.ts @@ -46,16 +46,15 @@ export interface RunnablesParams { position: lc.Position | null; } -export type RunnableKind = "cargo" | "rustc" | "rustup"; - export interface Runnable { - range: lc.Range; label: string; - kind: RunnableKind; - args: string[]; - extraArgs: string[]; - env: { [key: string]: string }; - cwd: string | null; + location?: lc.LocationLink; + kind: "cargo"; + args: { + workspaceRoot?: string; + cargoArgs: string[]; + executableArgs: string[]; + }; } export const runnables = new lc.RequestType("rust-analyzer/runnables"); diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts index 5fc4f8e41b..5c790741f3 100644 --- a/editors/code/src/run.ts +++ b/editors/code/src/run.ts @@ -103,18 +103,27 @@ interface CargoTaskDefinition extends vscode.TaskDefinition { env?: { [key: string]: string }; } -export function createTask(spec: ra.Runnable): vscode.Task { +export function createTask(runnable: ra.Runnable): vscode.Task { const TASK_SOURCE = 'Rust'; + + let command; + switch (runnable.kind) { + case "cargo": command = toolchain.getPathForExecutable("cargo"); + } + const args = runnable.args.cargoArgs; + if (runnable.args.executableArgs.length > 0) { + args.push('--', ...runnable.args.executableArgs); + } const definition: CargoTaskDefinition = { type: 'cargo', - label: spec.label, - command: toolchain.getPathForExecutable(spec.kind), - args: spec.extraArgs ? [...spec.args, '--', ...spec.extraArgs] : spec.args, - env: Object.assign({}, process.env, spec.env), + label: runnable.label, + command, + args, + env: Object.assign({}, process.env as { [key: string]: string }, { "RUST_BACKTRACE": "short" }), }; const execOption: vscode.ShellExecutionOptions = { - cwd: spec.cwd || '.', + cwd: runnable.args.workspaceRoot || '.', env: definition.env, }; const exec = new vscode.ShellExecution(