mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 12:33:33 +00:00
New runnables API
This commit is contained in:
parent
f137b3a4e6
commit
0303982119
8 changed files with 108 additions and 118 deletions
|
@ -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<String>,
|
||||
description: Option<String>,
|
||||
) -> 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<TextRange>,
|
||||
full_range: TextRange,
|
||||
kind: SyntaxKind,
|
||||
docs: Option<String>,
|
||||
description: Option<String>,
|
||||
) -> 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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<CfgExpr>,
|
||||
}
|
||||
|
@ -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)]
|
||||
|
|
|
@ -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<Position>,
|
||||
}
|
||||
|
||||
// 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<lsp_types::LocationLink>,
|
||||
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<String>,
|
||||
pub extra_args: Vec<String>,
|
||||
pub env: FxHashMap<String, String>,
|
||||
pub cwd: Option<PathBuf>,
|
||||
pub struct CargoRunnable {
|
||||
pub workspace_root: Option<PathBuf>,
|
||||
// command, --package and --lib stuff
|
||||
pub cargo_args: Vec<String>,
|
||||
// stuff after --
|
||||
pub executable_args: Vec<String>,
|
||||
}
|
||||
|
||||
pub enum InlayHints {}
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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<lsp_ext::Runnable> {
|
||||
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()),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -114,8 +114,8 @@ async function getDebugConfiguration(ctx: Ctx, runnable: ra.Runnable): Promise<v
|
|||
}
|
||||
|
||||
async function getDebugExecutable(runnable: ra.Runnable): Promise<string> {
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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<RunnablesParams, Runnable[], void>("rust-analyzer/runnables");
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in a new issue