nail down runnables

This commit is contained in:
Aleksey Kladov 2018-09-02 16:36:03 +03:00
parent 1329dd4e28
commit e98d8cd255
8 changed files with 142 additions and 25 deletions

View File

@ -151,7 +151,7 @@ pub fn parent_module(&self, id: FileId) -> Vec<(FileId, FileSymbol)> {
.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 @@ pub fn crate_root(&self, id: FileId) -> Vec<CrateId> {
}
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,

View File

@ -182,8 +182,11 @@ pub fn approximately_resolve_symbol(&self, file_id: FileId, offset: TextUnit, to
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);

View File

@ -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)],
);
}

View File

@ -16,6 +16,7 @@
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(

View File

@ -56,7 +56,7 @@ pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator<Item=Target> +
}
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 @@ pub fn packages<'a>(&'a self) -> impl Iterator<Item=Package> + 'a {
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()

View File

@ -6,7 +6,7 @@
};
use languageserver_types::Url;
use libanalysis::{FileId, AnalysisHost, Analysis};
use libanalysis::{FileId, AnalysisHost, Analysis, CrateGraph, CrateId};
use {
Result,
@ -95,7 +95,22 @@ pub fn remove_mem_file(&mut self, path: &Path) -> Result<FileId> {
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 {

View File

@ -14,10 +14,10 @@
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#"

View File

@ -134,7 +134,7 @@ pub fn notification<N>(
{
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 @@ fn send_request<R>(&self, id: u64, params: R::Params) -> Value
R::Params: Serialize,
{
let r = RawRequest::new::<R>(id, &params);
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 @@ fn send_request<R>(&self, id: u64, params: R::Params) -> Value
}
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 @@ fn drop(&mut self) {
drop(msg);
}
}
eprintln!("joining server");
self.server.take()
.unwrap()
.join().unwrap().unwrap();