mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 12:33:33 +00:00
nail down runnables
This commit is contained in:
parent
1329dd4e28
commit
e98d8cd255
8 changed files with 142 additions and 25 deletions
|
@ -151,7 +151,7 @@ impl AnalysisImpl {
|
|||
.collect()
|
||||
}
|
||||
|
||||
pub fn crate_root(&self, id: FileId) -> Vec<CrateId> {
|
||||
pub fn crate_for(&self, id: FileId) -> Vec<CrateId> {
|
||||
let module_map = &self.data.module_map;
|
||||
let crate_graph = &self.data.crate_graph;
|
||||
let mut res = Vec::new();
|
||||
|
@ -177,7 +177,9 @@ impl AnalysisImpl {
|
|||
}
|
||||
res
|
||||
}
|
||||
|
||||
pub fn crate_root(&self, crate_id: CrateId) -> FileId {
|
||||
self.data.crate_graph.crate_roots[&crate_id]
|
||||
}
|
||||
pub fn approximately_resolve_symbol(
|
||||
&self,
|
||||
id: FileId,
|
||||
|
|
|
@ -182,8 +182,11 @@ impl Analysis {
|
|||
pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> {
|
||||
self.imp.parent_module(file_id)
|
||||
}
|
||||
pub fn crate_root(&self, file_id: FileId) -> Vec<CrateId> {
|
||||
self.imp.crate_root(file_id)
|
||||
pub fn crate_for(&self, file_id: FileId) -> Vec<CrateId> {
|
||||
self.imp.crate_for(file_id)
|
||||
}
|
||||
pub fn crate_root(&self, crate_id: CrateId) -> FileId {
|
||||
self.imp.crate_root(crate_id)
|
||||
}
|
||||
pub fn runnables(&self, file_id: FileId) -> Vec<Runnable> {
|
||||
let file = self.file_syntax(file_id);
|
||||
|
|
|
@ -126,7 +126,7 @@ fn test_resolve_crate_root() {
|
|||
(1, "/lib.rs"),
|
||||
(2, "/foo.rs"),
|
||||
]));
|
||||
assert!(snap.crate_root(FileId(2)).is_empty());
|
||||
assert!(snap.crate_for(FileId(2)).is_empty());
|
||||
|
||||
let crate_graph = CrateGraph {
|
||||
crate_roots: {
|
||||
|
@ -142,7 +142,7 @@ fn test_resolve_crate_root() {
|
|||
(2, "/foo.rs"),
|
||||
]));
|
||||
assert_eq!(
|
||||
snap.crate_root(FileId(2)),
|
||||
snap.crate_for(FileId(2)),
|
||||
vec![CrateId(1)],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ use ::{
|
|||
req::{self, Decoration}, Result,
|
||||
conv::{Conv, ConvWith, TryConvWith, MapConvWith, to_location},
|
||||
server_world::ServerWorld,
|
||||
project_model::TargetKind,
|
||||
};
|
||||
|
||||
pub fn handle_syntax_tree(
|
||||
|
@ -233,6 +234,8 @@ pub fn handle_runnables(
|
|||
}
|
||||
}
|
||||
|
||||
let args = runnable_args(&world, file_id, &runnable.kind);
|
||||
|
||||
let r = req::Runnable {
|
||||
range: runnable.range.conv_with(&line_index),
|
||||
label: match &runnable.kind {
|
||||
|
@ -242,17 +245,7 @@ pub fn handle_runnables(
|
|||
"run binary".to_string(),
|
||||
},
|
||||
bin: "cargo".to_string(),
|
||||
args: match runnable.kind {
|
||||
RunnableKind::Test { name } => {
|
||||
vec![
|
||||
"test".to_string(),
|
||||
"--".to_string(),
|
||||
name,
|
||||
"--nocapture".to_string(),
|
||||
]
|
||||
}
|
||||
RunnableKind::Bin => vec!["run".to_string()]
|
||||
},
|
||||
args,
|
||||
env: {
|
||||
let mut m = HashMap::new();
|
||||
m.insert(
|
||||
|
@ -265,6 +258,67 @@ pub fn handle_runnables(
|
|||
res.push(r);
|
||||
}
|
||||
return Ok(res);
|
||||
|
||||
fn runnable_args(world: &ServerWorld, file_id: FileId, kind: &RunnableKind) -> Vec<String> {
|
||||
let spec = if let Some(&crate_id) = world.analysis().crate_for(file_id).first() {
|
||||
let file_id = world.analysis().crate_root(crate_id);
|
||||
let path = world.path_map.get_path(file_id);
|
||||
world.workspaces.iter()
|
||||
.filter_map(|ws| {
|
||||
let tgt = ws.target_by_root(path)?;
|
||||
Some((tgt.package(ws).name(ws).clone(), tgt.name(ws).clone(), tgt.kind(ws)))
|
||||
})
|
||||
.next()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mut res = Vec::new();
|
||||
match kind {
|
||||
RunnableKind::Test { name } => {
|
||||
res.push("test".to_string());
|
||||
if let Some((pkg_name, tgt_name, tgt_kind)) = spec {
|
||||
spec_args(pkg_name, tgt_name, tgt_kind, &mut res);
|
||||
}
|
||||
res.push("--".to_string());
|
||||
res.push(name.to_string());
|
||||
res.push("--nocapture".to_string());
|
||||
}
|
||||
RunnableKind::Bin => {
|
||||
res.push("run".to_string());
|
||||
if let Some((pkg_name, tgt_name, tgt_kind)) = spec {
|
||||
spec_args(pkg_name, tgt_name, tgt_kind, &mut res);
|
||||
}
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
fn spec_args(pkg_name: &str, tgt_name: &str, tgt_kind: TargetKind, buf: &mut Vec<String>) {
|
||||
buf.push("--package".to_string());
|
||||
buf.push(pkg_name.to_string());
|
||||
match tgt_kind {
|
||||
TargetKind::Bin => {
|
||||
buf.push("--bin".to_string());
|
||||
buf.push(tgt_name.to_string());
|
||||
}
|
||||
TargetKind::Test => {
|
||||
buf.push("--test".to_string());
|
||||
buf.push(tgt_name.to_string());
|
||||
}
|
||||
TargetKind::Bench => {
|
||||
buf.push("--bench".to_string());
|
||||
buf.push(tgt_name.to_string());
|
||||
}
|
||||
TargetKind::Example => {
|
||||
buf.push("--example".to_string());
|
||||
buf.push(tgt_name.to_string());
|
||||
}
|
||||
TargetKind::Lib => {
|
||||
buf.push("--lib".to_string());
|
||||
}
|
||||
TargetKind::Other => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_decorations(
|
||||
|
|
|
@ -56,7 +56,7 @@ impl Package {
|
|||
}
|
||||
|
||||
impl Target {
|
||||
pub fn pkg(self, ws: &CargoWorkspace) -> Package {
|
||||
pub fn package(self, ws: &CargoWorkspace) -> Package {
|
||||
ws.tgt(self).pkg
|
||||
}
|
||||
pub fn name(self, ws: &CargoWorkspace) -> &str {
|
||||
|
@ -114,7 +114,7 @@ impl CargoWorkspace {
|
|||
pub fn ws_members<'a>(&'a self) -> impl Iterator<Item=Package> + 'a {
|
||||
self.ws_members.iter().cloned()
|
||||
}
|
||||
pub fn target_by_roo(&self, root: &Path) -> Option<Target> {
|
||||
pub fn target_by_root(&self, root: &Path) -> Option<Target> {
|
||||
self.packages()
|
||||
.filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root))
|
||||
.next()
|
||||
|
|
|
@ -6,7 +6,7 @@ use std::{
|
|||
};
|
||||
|
||||
use languageserver_types::Url;
|
||||
use libanalysis::{FileId, AnalysisHost, Analysis};
|
||||
use libanalysis::{FileId, AnalysisHost, Analysis, CrateGraph, CrateId};
|
||||
|
||||
use {
|
||||
Result,
|
||||
|
@ -95,7 +95,22 @@ impl ServerWorldState {
|
|||
Ok(file_id)
|
||||
}
|
||||
pub fn set_workspaces(&mut self, ws: Vec<CargoWorkspace>) {
|
||||
let mut crate_roots = HashMap::new();
|
||||
ws.iter()
|
||||
.flat_map(|ws| {
|
||||
ws.packages()
|
||||
.flat_map(move |pkg| pkg.targets(ws))
|
||||
.map(move |tgt| tgt.root(ws))
|
||||
})
|
||||
.for_each(|root| {
|
||||
if let Some(file_id) = self.path_map.get_id(root) {
|
||||
let crate_id = CrateId(crate_roots.len() as u32);
|
||||
crate_roots.insert(crate_id, file_id);
|
||||
}
|
||||
});
|
||||
let crate_graph = CrateGraph { crate_roots };
|
||||
self.workspaces = Arc::new(ws);
|
||||
self.analysis_host.set_crate_graph(crate_graph);
|
||||
}
|
||||
pub fn snapshot(&self) -> ServerWorld {
|
||||
ServerWorld {
|
||||
|
|
|
@ -14,10 +14,10 @@ use m::req::{Runnables, RunnablesParams, DidReloadWorkspace};
|
|||
|
||||
use support::project;
|
||||
|
||||
const LOG: &'static str = "WARN";
|
||||
const LOG: &'static str = "";
|
||||
|
||||
#[test]
|
||||
fn test_runnables() {
|
||||
fn test_runnables_no_project() {
|
||||
let server = project(r"
|
||||
//- lib.rs
|
||||
#[test]
|
||||
|
@ -44,6 +44,42 @@ fn foo() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_runnables_project() {
|
||||
let server = project(r#"
|
||||
//- Cargo.toml
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.0.0"
|
||||
|
||||
//- src/lib.rs
|
||||
pub fn foo() {}
|
||||
|
||||
//- tests/spam.rs
|
||||
#[test]
|
||||
fn test_eggs() {}
|
||||
"#);
|
||||
server.wait_for_notification::<DidReloadWorkspace>();
|
||||
server.request::<Runnables>(
|
||||
RunnablesParams {
|
||||
text_document: server.doc_id("tests/spam.rs"),
|
||||
position: None,
|
||||
},
|
||||
r#"[
|
||||
{
|
||||
"args": [ "test", "--package", "foo", "--test", "spam", "--", "test_eggs", "--nocapture" ],
|
||||
"bin": "cargo",
|
||||
"env": { "RUST_BACKTRACE": "short" },
|
||||
"label": "test test_eggs",
|
||||
"range": {
|
||||
"end": { "character": 17, "line": 1 },
|
||||
"start": { "character": 0, "line": 0 }
|
||||
}
|
||||
}
|
||||
]"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_project_model() {
|
||||
let server = project(r#"
|
||||
|
|
|
@ -134,7 +134,7 @@ impl Server {
|
|||
{
|
||||
let expected = expected.replace("$PROJECT_ROOT$", &self.dir.path().display().to_string());
|
||||
let expected: Value = from_str(&expected).unwrap();
|
||||
let actual = self.wait_for_notification(N::METHOD);
|
||||
let actual = self.wait_for_notification::<N>();
|
||||
assert_eq!(
|
||||
expected, actual,
|
||||
"Expected:\n{}\n\
|
||||
|
@ -150,6 +150,11 @@ impl Server {
|
|||
R::Params: Serialize,
|
||||
{
|
||||
let r = RawRequest::new::<R>(id, ¶ms);
|
||||
self.send_request_(r)
|
||||
}
|
||||
fn send_request_(&self, r: RawRequest) -> Value
|
||||
{
|
||||
let id = r.id;
|
||||
self.sender.as_ref()
|
||||
.unwrap()
|
||||
.send(RawMessage::Request(r));
|
||||
|
@ -168,7 +173,10 @@ impl Server {
|
|||
}
|
||||
panic!("no response");
|
||||
}
|
||||
fn wait_for_notification(&self, method: &str) -> Value {
|
||||
pub fn wait_for_notification<N: Notification>(&self) -> Value {
|
||||
self.wait_for_notification_(N::METHOD)
|
||||
}
|
||||
fn wait_for_notification_(&self, method: &str) -> Value {
|
||||
let f = |msg: &RawMessage| match msg {
|
||||
RawMessage::Notification(n) if n.method == method => {
|
||||
Some(n.params.clone())
|
||||
|
@ -215,7 +223,6 @@ impl Drop for Server {
|
|||
drop(msg);
|
||||
}
|
||||
}
|
||||
eprintln!("joining server");
|
||||
self.server.take()
|
||||
.unwrap()
|
||||
.join().unwrap().unwrap();
|
||||
|
|
Loading…
Reference in a new issue