aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-06-02 16:22:23 +0100
committerAleksey Kladov <[email protected]>2020-06-02 16:22:42 +0100
commit03039821195c9d9c4bbc1e4cbddb6378c43a6c52 (patch)
tree2fb425ca0ed235ae051d9ea0547ebf8664c3295d
parentf137b3a4e626bdef165e0ad7c61c88c44797798e (diff)
New runnables API
-rw-r--r--crates/ra_ide/src/display/navigation_target.rs66
-rw-r--r--crates/ra_ide/src/runnables.rs25
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs28
-rw-r--r--crates/rust-analyzer/src/main_loop/handlers.rs41
-rw-r--r--crates/rust-analyzer/src/to_proto.rs18
-rw-r--r--editors/code/src/debug.ts12
-rw-r--r--editors/code/src/lsp_ext.ts15
-rw-r--r--editors/code/src/run.ts21
8 files changed, 108 insertions, 118 deletions
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs
index 5da28edd2..c7bb1e69f 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 {
92 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); 92 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
93 if let Some(src) = module.declaration_source(db) { 93 if let Some(src) = module.declaration_source(db) {
94 let frange = original_range(db, src.as_ref().map(|it| it.syntax())); 94 let frange = original_range(db, src.as_ref().map(|it| it.syntax()));
95 return NavigationTarget::from_syntax( 95 let mut res = NavigationTarget::from_syntax(
96 frange.file_id, 96 frange.file_id,
97 name, 97 name,
98 None, 98 None,
99 frange.range, 99 frange.range,
100 src.value.syntax().kind(), 100 src.value.syntax().kind(),
101 src.value.doc_comment_text(),
102 src.value.short_label(),
103 ); 101 );
102 res.docs = src.value.doc_comment_text();
103 res.description = src.value.short_label();
104 return res;
104 } 105 }
105 module.to_nav(db) 106 module.to_nav(db)
106 } 107 }
@@ -130,11 +131,9 @@ impl NavigationTarget {
130 } 131 }
131 132
132 /// Allows `NavigationTarget` to be created from a `NameOwner` 133 /// Allows `NavigationTarget` to be created from a `NameOwner`
133 fn from_named( 134 pub(crate) fn from_named(
134 db: &RootDatabase, 135 db: &RootDatabase,
135 node: InFile<&dyn ast::NameOwner>, 136 node: InFile<&dyn ast::NameOwner>,
136 docs: Option<String>,
137 description: Option<String>,
138 ) -> NavigationTarget { 137 ) -> NavigationTarget {
139 //FIXME: use `_` instead of empty string 138 //FIXME: use `_` instead of empty string
140 let name = node.value.name().map(|it| it.text().clone()).unwrap_or_default(); 139 let name = node.value.name().map(|it| it.text().clone()).unwrap_or_default();
@@ -148,8 +147,6 @@ impl NavigationTarget {
148 focus_range, 147 focus_range,
149 frange.range, 148 frange.range,
150 node.value.syntax().kind(), 149 node.value.syntax().kind(),
151 docs,
152 description,
153 ) 150 )
154 } 151 }
155 152
@@ -159,8 +156,6 @@ impl NavigationTarget {
159 focus_range: Option<TextRange>, 156 focus_range: Option<TextRange>,
160 full_range: TextRange, 157 full_range: TextRange,
161 kind: SyntaxKind, 158 kind: SyntaxKind,
162 docs: Option<String>,
163 description: Option<String>,
164 ) -> NavigationTarget { 159 ) -> NavigationTarget {
165 NavigationTarget { 160 NavigationTarget {
166 file_id, 161 file_id,
@@ -169,8 +164,8 @@ impl NavigationTarget {
169 full_range, 164 full_range,
170 focus_range, 165 focus_range,
171 container_name: None, 166 container_name: None,
172 description, 167 description: None,
173 docs, 168 docs: None,
174 } 169 }
175 } 170 }
176} 171}
@@ -238,12 +233,11 @@ where
238{ 233{
239 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 234 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
240 let src = self.source(db); 235 let src = self.source(db);
241 NavigationTarget::from_named( 236 let mut res =
242 db, 237 NavigationTarget::from_named(db, src.as_ref().map(|it| it as &dyn ast::NameOwner));
243 src.as_ref().map(|it| it as &dyn ast::NameOwner), 238 res.docs = src.value.doc_comment_text();
244 src.value.doc_comment_text(), 239 res.description = src.value.short_label();
245 src.value.short_label(), 240 res
246 )
247 } 241 }
248} 242}
249 243
@@ -258,15 +252,7 @@ impl ToNav for hir::Module {
258 } 252 }
259 }; 253 };
260 let frange = original_range(db, src.with_value(syntax)); 254 let frange = original_range(db, src.with_value(syntax));
261 NavigationTarget::from_syntax( 255 NavigationTarget::from_syntax(frange.file_id, name, focus, frange.range, syntax.kind())
262 frange.file_id,
263 name,
264 focus,
265 frange.range,
266 syntax.kind(),
267 None,
268 None,
269 )
270 } 256 }
271} 257}
272 258
@@ -285,8 +271,6 @@ impl ToNav for hir::ImplDef {
285 None, 271 None,
286 frange.range, 272 frange.range,
287 src.value.syntax().kind(), 273 src.value.syntax().kind(),
288 None,
289 None,
290 ) 274 )
291 } 275 }
292} 276}
@@ -296,12 +280,12 @@ impl ToNav for hir::Field {
296 let src = self.source(db); 280 let src = self.source(db);
297 281
298 match &src.value { 282 match &src.value {
299 FieldSource::Named(it) => NavigationTarget::from_named( 283 FieldSource::Named(it) => {
300 db, 284 let mut res = NavigationTarget::from_named(db, src.with_value(it));
301 src.with_value(it), 285 res.docs = it.doc_comment_text();
302 it.doc_comment_text(), 286 res.description = it.short_label();
303 it.short_label(), 287 res
304 ), 288 }
305 FieldSource::Pos(it) => { 289 FieldSource::Pos(it) => {
306 let frange = original_range(db, src.with_value(it.syntax())); 290 let frange = original_range(db, src.with_value(it.syntax()));
307 NavigationTarget::from_syntax( 291 NavigationTarget::from_syntax(
@@ -310,8 +294,6 @@ impl ToNav for hir::Field {
310 None, 294 None,
311 frange.range, 295 frange.range,
312 it.syntax().kind(), 296 it.syntax().kind(),
313 None,
314 None,
315 ) 297 )
316 } 298 }
317 } 299 }
@@ -322,12 +304,10 @@ impl ToNav for hir::MacroDef {
322 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 304 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
323 let src = self.source(db); 305 let src = self.source(db);
324 log::debug!("nav target {:#?}", src.value.syntax()); 306 log::debug!("nav target {:#?}", src.value.syntax());
325 NavigationTarget::from_named( 307 let mut res =
326 db, 308 NavigationTarget::from_named(db, src.as_ref().map(|it| it as &dyn ast::NameOwner));
327 src.as_ref().map(|it| it as &dyn ast::NameOwner), 309 res.docs = src.value.doc_comment_text();
328 src.value.doc_comment_text(), 310 res
329 None,
330 )
331 } 311 }
332} 312}
333 313
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs
index 286d45eee..9239ca61b 100644
--- a/crates/ra_ide/src/runnables.rs
+++ b/crates/ra_ide/src/runnables.rs
@@ -1,19 +1,19 @@
1use std::fmt;
2
1use hir::{AsAssocItem, Attrs, HirFileId, InFile, Semantics}; 3use hir::{AsAssocItem, Attrs, HirFileId, InFile, Semantics};
2use itertools::Itertools; 4use itertools::Itertools;
5use ra_cfg::CfgExpr;
3use ra_ide_db::RootDatabase; 6use ra_ide_db::RootDatabase;
4use ra_syntax::{ 7use ra_syntax::{
5 ast::{self, AstNode, AttrsOwner, ModuleItemOwner, NameOwner}, 8 ast::{self, AstNode, AttrsOwner, DocCommentsOwner, ModuleItemOwner, NameOwner},
6 match_ast, SyntaxNode, TextRange, 9 match_ast, SyntaxNode,
7}; 10};
8 11
9use crate::FileId; 12use crate::{display::ToNav, FileId, NavigationTarget};
10use ast::DocCommentsOwner;
11use ra_cfg::CfgExpr;
12use std::fmt::Display;
13 13
14#[derive(Debug)] 14#[derive(Debug)]
15pub struct Runnable { 15pub struct Runnable {
16 pub range: TextRange, 16 pub nav: NavigationTarget,
17 pub kind: RunnableKind, 17 pub kind: RunnableKind,
18 pub cfg_exprs: Vec<CfgExpr>, 18 pub cfg_exprs: Vec<CfgExpr>,
19} 19}
@@ -24,8 +24,8 @@ pub enum TestId {
24 Path(String), 24 Path(String),
25} 25}
26 26
27impl Display for TestId { 27impl fmt::Display for TestId {
28 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 28 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
29 match self { 29 match self {
30 TestId::Name(name) => write!(f, "{}", name), 30 TestId::Name(name) => write!(f, "{}", name),
31 TestId::Path(path) => write!(f, "{}", path), 31 TestId::Path(path) => write!(f, "{}", path),
@@ -131,7 +131,8 @@ fn runnable_fn(
131 let cfg_exprs = 131 let cfg_exprs =
132 attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); 132 attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect();
133 133
134 Some(Runnable { range: fn_def.syntax().text_range(), kind, cfg_exprs }) 134 let nav = NavigationTarget::from_named(sema.db, InFile::new(file_id.into(), &fn_def));
135 Some(Runnable { nav, kind, cfg_exprs })
135} 136}
136 137
137#[derive(Debug)] 138#[derive(Debug)]
@@ -183,7 +184,6 @@ fn runnable_mod(
183 if !has_test_function { 184 if !has_test_function {
184 return None; 185 return None;
185 } 186 }
186 let range = module.syntax().text_range();
187 let module_def = sema.to_def(&module)?; 187 let module_def = sema.to_def(&module)?;
188 188
189 let path = module_def 189 let path = module_def
@@ -197,7 +197,8 @@ fn runnable_mod(
197 let cfg_exprs = 197 let cfg_exprs =
198 attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); 198 attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect();
199 199
200 Some(Runnable { range, kind: RunnableKind::TestMod { path }, cfg_exprs }) 200 let nav = module_def.to_nav(sema.db);
201 Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg_exprs })
201} 202}
202 203
203#[cfg(test)] 204#[cfg(test)]
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index 173c23b9e..9381f75d3 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};
4 4
5use lsp_types::request::Request; 5use lsp_types::request::Request;
6use lsp_types::{Position, Range, TextDocumentIdentifier}; 6use lsp_types::{Position, Range, TextDocumentIdentifier};
7use rustc_hash::FxHashMap;
8use serde::{Deserialize, Serialize}; 7use serde::{Deserialize, Serialize};
9 8
10pub enum AnalyzerStatus {} 9pub enum AnalyzerStatus {}
@@ -121,25 +120,30 @@ pub struct RunnablesParams {
121 pub position: Option<Position>, 120 pub position: Option<Position>,
122} 121}
123 122
124// Must strictly correspond to the executable name 123#[derive(Deserialize, Serialize, Debug)]
124#[serde(rename_all = "camelCase")]
125pub struct Runnable {
126 pub label: String,
127 #[serde(skip_serializing_if = "Option::is_none")]
128 pub location: Option<lsp_types::LocationLink>,
129 pub kind: RunnableKind,
130 pub args: CargoRunnable,
131}
132
125#[derive(Serialize, Deserialize, Debug)] 133#[derive(Serialize, Deserialize, Debug)]
126#[serde(rename_all = "lowercase")] 134#[serde(rename_all = "lowercase")]
127pub enum RunnableKind { 135pub enum RunnableKind {
128 Cargo, 136 Cargo,
129 Rustc,
130 Rustup,
131} 137}
132 138
133#[derive(Deserialize, Serialize, Debug)] 139#[derive(Deserialize, Serialize, Debug)]
134#[serde(rename_all = "camelCase")] 140#[serde(rename_all = "camelCase")]
135pub struct Runnable { 141pub struct CargoRunnable {
136 pub range: Range, 142 pub workspace_root: Option<PathBuf>,
137 pub label: String, 143 // command, --package and --lib stuff
138 pub kind: RunnableKind, 144 pub cargo_args: Vec<String>,
139 pub args: Vec<String>, 145 // stuff after --
140 pub extra_args: Vec<String>, 146 pub executable_args: Vec<String>,
141 pub env: FxHashMap<String, String>,
142 pub cwd: Option<PathBuf>,
143} 147}
144 148
145pub enum InlayHints {} 149pub enum InlayHints {}
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs
index 410c654ab..7fd691764 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::{
23use ra_prof::profile; 23use ra_prof::profile;
24use ra_project_model::TargetKind; 24use ra_project_model::TargetKind;
25use ra_syntax::{AstNode, SyntaxKind, TextRange, TextSize}; 25use ra_syntax::{AstNode, SyntaxKind, TextRange, TextSize};
26use rustc_hash::FxHashMap;
27use serde::{Deserialize, Serialize}; 26use serde::{Deserialize, Serialize};
28use serde_json::to_value; 27use serde_json::to_value;
29use stdx::format_to; 28use stdx::format_to;
@@ -401,7 +400,7 @@ pub fn handle_runnables(
401 let cargo_spec = CargoTargetSpec::for_file(&world, file_id)?; 400 let cargo_spec = CargoTargetSpec::for_file(&world, file_id)?;
402 for runnable in world.analysis().runnables(file_id)? { 401 for runnable in world.analysis().runnables(file_id)? {
403 if let Some(offset) = offset { 402 if let Some(offset) = offset {
404 if !runnable.range.contains_inclusive(offset) { 403 if !runnable.nav.full_range().contains_inclusive(offset) {
405 continue; 404 continue;
406 } 405 }
407 } 406 }
@@ -422,25 +421,31 @@ pub fn handle_runnables(
422 Some(spec) => { 421 Some(spec) => {
423 for &cmd in ["check", "test"].iter() { 422 for &cmd in ["check", "test"].iter() {
424 res.push(lsp_ext::Runnable { 423 res.push(lsp_ext::Runnable {
425 range: Default::default(),
426 label: format!("cargo {} -p {}", cmd, spec.package), 424 label: format!("cargo {} -p {}", cmd, spec.package),
425 location: None,
427 kind: lsp_ext::RunnableKind::Cargo, 426 kind: lsp_ext::RunnableKind::Cargo,
428 args: vec![cmd.to_string(), "--package".to_string(), spec.package.clone()], 427 args: lsp_ext::CargoRunnable {
429 extra_args: Vec::new(), 428 workspace_root: workspace_root.map(|root| root.to_owned()),
430 env: FxHashMap::default(), 429 cargo_args: vec![
431 cwd: workspace_root.map(|root| root.to_owned()), 430 cmd.to_string(),
431 "--package".to_string(),
432 spec.package.clone(),
433 ],
434 executable_args: Vec::new(),
435 },
432 }) 436 })
433 } 437 }
434 } 438 }
435 None => { 439 None => {
436 res.push(lsp_ext::Runnable { 440 res.push(lsp_ext::Runnable {
437 range: Default::default(),
438 label: "cargo check --workspace".to_string(), 441 label: "cargo check --workspace".to_string(),
442 location: None,
439 kind: lsp_ext::RunnableKind::Cargo, 443 kind: lsp_ext::RunnableKind::Cargo,
440 args: vec!["check".to_string(), "--workspace".to_string()], 444 args: lsp_ext::CargoRunnable {
441 extra_args: Vec::new(), 445 workspace_root: workspace_root.map(|root| root.to_owned()),
442 env: FxHashMap::default(), 446 cargo_args: vec!["check".to_string(), "--workspace".to_string()],
443 cwd: workspace_root.map(|root| root.to_owned()), 447 executable_args: Vec::new(),
448 },
444 }); 449 });
445 } 450 }
446 } 451 }
@@ -782,10 +787,11 @@ pub fn handle_code_lens(
782 } 787 }
783 }; 788 };
784 789
785 let mut r = to_proto::runnable(&world, file_id, runnable)?; 790 let range = to_proto::range(&line_index, runnable.nav.range());
791 let r = to_proto::runnable(&world, file_id, runnable)?;
786 if world.config.lens.run { 792 if world.config.lens.run {
787 let lens = CodeLens { 793 let lens = CodeLens {
788 range: r.range, 794 range,
789 command: Some(Command { 795 command: Some(Command {
790 title: run_title.to_string(), 796 title: run_title.to_string(),
791 command: "rust-analyzer.runSingle".into(), 797 command: "rust-analyzer.runSingle".into(),
@@ -797,13 +803,8 @@ pub fn handle_code_lens(
797 } 803 }
798 804
799 if debugee && world.config.lens.debug { 805 if debugee && world.config.lens.debug {
800 if r.args[0] == "run" {
801 r.args[0] = "build".into();
802 } else {
803 r.args.push("--no-run".into());
804 }
805 let debug_lens = CodeLens { 806 let debug_lens = CodeLens {
806 range: r.range, 807 range,
807 command: Some(Command { 808 command: Some(Command {
808 title: "Debug".into(), 809 title: "Debug".into(),
809 command: "rust-analyzer.debugSingle".into(), 810 command: "rust-analyzer.debugSingle".into(),
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 66144fe24..85304aa87 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -8,7 +8,6 @@ use ra_ide::{
8}; 8};
9use ra_syntax::{SyntaxKind, TextRange, TextSize}; 9use ra_syntax::{SyntaxKind, TextRange, TextSize};
10use ra_vfs::LineEndings; 10use ra_vfs::LineEndings;
11use rustc_hash::FxHashMap;
12 11
13use crate::{ 12use crate::{
14 cargo_target_spec::CargoTargetSpec, lsp_ext, semantic_tokens, world::WorldSnapshot, Result, 13 cargo_target_spec::CargoTargetSpec, lsp_ext, semantic_tokens, world::WorldSnapshot, Result,
@@ -638,9 +637,8 @@ pub(crate) fn runnable(
638) -> Result<lsp_ext::Runnable> { 637) -> Result<lsp_ext::Runnable> {
639 let spec = CargoTargetSpec::for_file(world, file_id)?; 638 let spec = CargoTargetSpec::for_file(world, file_id)?;
640 let target = spec.as_ref().map(|s| s.target.clone()); 639 let target = spec.as_ref().map(|s| s.target.clone());
641 let (args, extra_args) = 640 let (cargo_args, executable_args) =
642 CargoTargetSpec::runnable_args(spec, &runnable.kind, &runnable.cfg_exprs)?; 641 CargoTargetSpec::runnable_args(spec, &runnable.kind, &runnable.cfg_exprs)?;
643 let line_index = world.analysis().file_line_index(file_id)?;
644 let label = match &runnable.kind { 642 let label = match &runnable.kind {
645 RunnableKind::Test { test_id, .. } => format!("test {}", test_id), 643 RunnableKind::Test { test_id, .. } => format!("test {}", test_id),
646 RunnableKind::TestMod { path } => format!("test-mod {}", path), 644 RunnableKind::TestMod { path } => format!("test-mod {}", path),
@@ -650,18 +648,16 @@ pub(crate) fn runnable(
650 target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t)) 648 target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t))
651 } 649 }
652 }; 650 };
651 let location = location_link(world, None, runnable.nav)?;
653 652
654 Ok(lsp_ext::Runnable { 653 Ok(lsp_ext::Runnable {
655 range: range(&line_index, runnable.range),
656 label, 654 label,
655 location: Some(location),
657 kind: lsp_ext::RunnableKind::Cargo, 656 kind: lsp_ext::RunnableKind::Cargo,
658 args, 657 args: lsp_ext::CargoRunnable {
659 extra_args, 658 workspace_root: world.workspace_root_for(file_id).map(|root| root.to_owned()),
660 env: { 659 cargo_args,
661 let mut m = FxHashMap::default(); 660 executable_args,
662 m.insert("RUST_BACKTRACE".to_string(), "short".to_string());
663 m
664 }, 661 },
665 cwd: world.workspace_root_for(file_id).map(|root| root.to_owned()),
666 }) 662 })
667} 663}
diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts
index 1e421d407..a0c9b3ab2 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<v
114} 114}
115 115
116async function getDebugExecutable(runnable: ra.Runnable): Promise<string> { 116async function getDebugExecutable(runnable: ra.Runnable): Promise<string> {
117 const cargo = new Cargo(runnable.cwd || '.', debugOutput); 117 const cargo = new Cargo(runnable.args.workspaceRoot || '.', debugOutput);
118 const executable = await cargo.executableFromArgs(runnable.args); 118 const executable = await cargo.executableFromArgs(runnable.args.cargoArgs);
119 119
120 // if we are here, there were no compilation errors. 120 // if we are here, there were no compilation errors.
121 return executable; 121 return executable;
@@ -127,8 +127,8 @@ function getLldbDebugConfig(runnable: ra.Runnable, executable: string, sourceFil
127 request: "launch", 127 request: "launch",
128 name: runnable.label, 128 name: runnable.label,
129 program: executable, 129 program: executable,
130 args: runnable.extraArgs, 130 args: runnable.args.executableArgs,
131 cwd: runnable.cwd, 131 cwd: runnable.args.workspaceRoot,
132 sourceMap: sourceFileMap, 132 sourceMap: sourceFileMap,
133 sourceLanguages: ["rust"] 133 sourceLanguages: ["rust"]
134 }; 134 };
@@ -140,8 +140,8 @@ function getCppvsDebugConfig(runnable: ra.Runnable, executable: string, sourceFi
140 request: "launch", 140 request: "launch",
141 name: runnable.label, 141 name: runnable.label,
142 program: executable, 142 program: executable,
143 args: runnable.extraArgs, 143 args: runnable.args.executableArgs,
144 cwd: runnable.cwd, 144 cwd: runnable.args.workspaceRoot,
145 sourceFileMap: sourceFileMap, 145 sourceFileMap: sourceFileMap,
146 }; 146 };
147} 147}
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts
index 3e0b60699..73d573678 100644
--- a/editors/code/src/lsp_ext.ts
+++ b/editors/code/src/lsp_ext.ts
@@ -46,16 +46,15 @@ export interface RunnablesParams {
46 position: lc.Position | null; 46 position: lc.Position | null;
47} 47}
48 48
49export type RunnableKind = "cargo" | "rustc" | "rustup";
50
51export interface Runnable { 49export interface Runnable {
52 range: lc.Range;
53 label: string; 50 label: string;
54 kind: RunnableKind; 51 location?: lc.LocationLink;
55 args: string[]; 52 kind: "cargo";
56 extraArgs: string[]; 53 args: {
57 env: { [key: string]: string }; 54 workspaceRoot?: string;
58 cwd: string | null; 55 cargoArgs: string[];
56 executableArgs: string[];
57 };
59} 58}
60export const runnables = new lc.RequestType<RunnablesParams, Runnable[], void>("rust-analyzer/runnables"); 59export const runnables = new lc.RequestType<RunnablesParams, Runnable[], void>("rust-analyzer/runnables");
61 60
diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts
index 5fc4f8e41..5c790741f 100644
--- a/editors/code/src/run.ts
+++ b/editors/code/src/run.ts
@@ -103,18 +103,27 @@ interface CargoTaskDefinition extends vscode.TaskDefinition {
103 env?: { [key: string]: string }; 103 env?: { [key: string]: string };
104} 104}
105 105
106export function createTask(spec: ra.Runnable): vscode.Task { 106export function createTask(runnable: ra.Runnable): vscode.Task {
107 const TASK_SOURCE = 'Rust'; 107 const TASK_SOURCE = 'Rust';
108
109 let command;
110 switch (runnable.kind) {
111 case "cargo": command = toolchain.getPathForExecutable("cargo");
112 }
113 const args = runnable.args.cargoArgs;
114 if (runnable.args.executableArgs.length > 0) {
115 args.push('--', ...runnable.args.executableArgs);
116 }
108 const definition: CargoTaskDefinition = { 117 const definition: CargoTaskDefinition = {
109 type: 'cargo', 118 type: 'cargo',
110 label: spec.label, 119 label: runnable.label,
111 command: toolchain.getPathForExecutable(spec.kind), 120 command,
112 args: spec.extraArgs ? [...spec.args, '--', ...spec.extraArgs] : spec.args, 121 args,
113 env: Object.assign({}, process.env, spec.env), 122 env: Object.assign({}, process.env as { [key: string]: string }, { "RUST_BACKTRACE": "short" }),
114 }; 123 };
115 124
116 const execOption: vscode.ShellExecutionOptions = { 125 const execOption: vscode.ShellExecutionOptions = {
117 cwd: spec.cwd || '.', 126 cwd: runnable.args.workspaceRoot || '.',
118 env: definition.env, 127 env: definition.env,
119 }; 128 };
120 const exec = new vscode.ShellExecution( 129 const exec = new vscode.ShellExecution(