add sysroot boilerplate

This commit is contained in:
Aleksey Kladov 2019-01-10 20:13:08 +03:00
parent b6bc55f542
commit e8923713c5
6 changed files with 157 additions and 32 deletions

View File

@ -347,11 +347,11 @@ pub fn handle_runnables(
.read() .read()
.file2path(ra_vfs::VfsFile(file_id.0.into())); .file2path(ra_vfs::VfsFile(file_id.0.into()));
let res = world.workspaces.iter().find_map(|ws| { let res = world.workspaces.iter().find_map(|ws| {
let tgt = ws.target_by_root(&path)?; let tgt = ws.cargo.target_by_root(&path)?;
let res = CargoTargetSpec { let res = CargoTargetSpec {
package: tgt.package(ws).name(ws).to_string(), package: tgt.package(&ws.cargo).name(&ws.cargo).to_string(),
target: tgt.name(ws).to_string(), target: tgt.name(&ws.cargo).to_string(),
target_kind: tgt.kind(ws), target_kind: tgt.kind(&ws.cargo),
}; };
Some(res) Some(res)
}); });

View File

@ -1,4 +1,7 @@
use std::path::{Path, PathBuf}; use std::{
path::{Path, PathBuf},
process::Command,
};
use cargo_metadata::{metadata_run, CargoOpt}; use cargo_metadata::{metadata_run, CargoOpt};
use ra_syntax::SmolStr; use ra_syntax::SmolStr;
@ -9,6 +12,36 @@ use thread_worker::{WorkerHandle, Worker};
use crate::Result; use crate::Result;
#[derive(Debug, Clone)]
pub struct ProjectWorkspace {
pub(crate) cargo: CargoWorkspace,
pub(crate) sysroot: Sysroot,
}
impl ProjectWorkspace {
pub fn discover(path: &Path) -> Result<ProjectWorkspace> {
let cargo_toml = find_cargo_toml(path)?;
let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml)?;
let sysroot = sysroot_info(&cargo_toml)?;
let res = ProjectWorkspace { cargo, sysroot };
Ok(res)
}
}
pub fn workspace_loader() -> (Worker<PathBuf, Result<ProjectWorkspace>>, WorkerHandle) {
thread_worker::spawn::<PathBuf, Result<ProjectWorkspace>, _>(
"workspace loader",
1,
|input_receiver, output_sender| {
input_receiver
.into_iter()
.map(|path| ProjectWorkspace::discover(path.as_path()))
.try_for_each(|it| output_sender.send(it))
.unwrap()
},
)
}
/// `CargoWorksapce` represents the logical structure of, well, a Cargo /// `CargoWorksapce` represents the logical structure of, well, a Cargo
/// workspace. It pretty closely mirrors `cargo metadata` output. /// workspace. It pretty closely mirrors `cargo metadata` output.
/// ///
@ -63,6 +96,11 @@ pub enum TargetKind {
Other, Other,
} }
#[derive(Debug, Clone)]
pub(crate) struct Sysroot {
crates: FxHashMap<SmolStr, PathBuf>,
}
impl Package { impl Package {
pub fn name(self, ws: &CargoWorkspace) -> &str { pub fn name(self, ws: &CargoWorkspace) -> &str {
ws.packages[self].name.as_str() ws.packages[self].name.as_str()
@ -160,6 +198,68 @@ impl CargoWorkspace {
} }
} }
fn sysroot_info(cargo_toml: &Path) -> Result<Sysroot> {
let rustc_output = Command::new("rustc")
.current_dir(cargo_toml.parent().unwrap())
.args(&["--print", "sysroot"])
.output()?;
if !rustc_output.status.success() {
failure::bail!("failed to locate sysroot")
}
let stdout = String::from_utf8(rustc_output.stdout)?;
let sysroot_path = Path::new(stdout.trim());
let src = sysroot_path.join("lib/rustlib/src/rust/src");
let crates: &[(&str, &[&str])] = &[
(
"std",
&[
"alloc_jemalloc",
"alloc_system",
"panic_abort",
"rand",
"compiler_builtins",
"unwind",
"rustc_asan",
"rustc_lsan",
"rustc_msan",
"rustc_tsan",
"build_helper",
],
),
("core", &[]),
("alloc", &[]),
("collections", &[]),
("libc", &[]),
("panic_unwind", &[]),
("proc_macro", &[]),
("rustc_unicode", &[]),
("std_unicode", &[]),
("test", &[]),
// Feature gated
("alloc_jemalloc", &[]),
("alloc_system", &[]),
("compiler_builtins", &[]),
("getopts", &[]),
("panic_unwind", &[]),
("panic_abort", &[]),
("rand", &[]),
("term", &[]),
("unwind", &[]),
// Dependencies
("build_helper", &[]),
("rustc_asan", &[]),
("rustc_lsan", &[]),
("rustc_msan", &[]),
("rustc_tsan", &[]),
("syntax", &[]),
];
Ok(Sysroot {
crates: FxHashMap::default(),
})
}
fn find_cargo_toml(path: &Path) -> Result<PathBuf> { fn find_cargo_toml(path: &Path) -> Result<PathBuf> {
if path.ends_with("Cargo.toml") { if path.ends_with("Cargo.toml") {
return Ok(path.to_path_buf()); return Ok(path.to_path_buf());
@ -190,17 +290,3 @@ impl TargetKind {
TargetKind::Other TargetKind::Other
} }
} }
pub fn workspace_loader() -> (Worker<PathBuf, Result<CargoWorkspace>>, WorkerHandle) {
thread_worker::spawn::<PathBuf, Result<CargoWorkspace>, _>(
"workspace loader",
1,
|input_receiver, output_sender| {
input_receiver
.into_iter()
.map(|path| CargoWorkspace::from_cargo_metadata(path.as_path()))
.try_for_each(|it| output_sender.send(it))
.unwrap()
},
)
}

View File

@ -15,7 +15,7 @@ use parking_lot::RwLock;
use failure::format_err; use failure::format_err;
use crate::{ use crate::{
project_model::{CargoWorkspace, TargetKind}, project_model::{ProjectWorkspace, TargetKind},
Result, Result,
}; };
@ -23,26 +23,26 @@ use crate::{
pub struct ServerWorldState { pub struct ServerWorldState {
pub roots_to_scan: usize, pub roots_to_scan: usize,
pub root: PathBuf, pub root: PathBuf,
pub workspaces: Arc<Vec<CargoWorkspace>>, pub workspaces: Arc<Vec<ProjectWorkspace>>,
pub analysis_host: AnalysisHost, pub analysis_host: AnalysisHost,
pub vfs: Arc<RwLock<Vfs>>, pub vfs: Arc<RwLock<Vfs>>,
} }
pub struct ServerWorld { pub struct ServerWorld {
pub workspaces: Arc<Vec<CargoWorkspace>>, pub workspaces: Arc<Vec<ProjectWorkspace>>,
pub analysis: Analysis, pub analysis: Analysis,
pub vfs: Arc<RwLock<Vfs>>, pub vfs: Arc<RwLock<Vfs>>,
} }
impl ServerWorldState { impl ServerWorldState {
pub fn new(root: PathBuf, workspaces: Vec<CargoWorkspace>) -> ServerWorldState { pub fn new(root: PathBuf, workspaces: Vec<ProjectWorkspace>) -> ServerWorldState {
let mut change = AnalysisChange::new(); let mut change = AnalysisChange::new();
let mut roots = Vec::new(); let mut roots = Vec::new();
roots.push(root.clone()); roots.push(root.clone());
for ws in workspaces.iter() { for ws in workspaces.iter() {
for pkg in ws.packages() { for pkg in ws.cargo.packages() {
roots.push(pkg.root(&ws).to_path_buf()); roots.push(pkg.root(&ws.cargo).to_path_buf());
} }
} }
let roots_to_scan = roots.len(); let roots_to_scan = roots.len();
@ -56,13 +56,13 @@ impl ServerWorldState {
let mut pkg_to_lib_crate = FxHashMap::default(); let mut pkg_to_lib_crate = FxHashMap::default();
let mut pkg_crates = FxHashMap::default(); let mut pkg_crates = FxHashMap::default();
for ws in workspaces.iter() { for ws in workspaces.iter() {
for pkg in ws.packages() { for pkg in ws.cargo.packages() {
for tgt in pkg.targets(ws) { for tgt in pkg.targets(&ws.cargo) {
let root = tgt.root(ws); let root = tgt.root(&ws.cargo);
if let Some(file_id) = vfs.load(root) { if let Some(file_id) = vfs.load(root) {
let file_id = FileId(file_id.0.into()); let file_id = FileId(file_id.0.into());
let crate_id = crate_graph.add_crate_root(file_id); let crate_id = crate_graph.add_crate_root(file_id);
if tgt.kind(ws) == TargetKind::Lib { if tgt.kind(&ws.cargo) == TargetKind::Lib {
pkg_to_lib_crate.insert(pkg, crate_id); pkg_to_lib_crate.insert(pkg, crate_id);
} }
pkg_crates pkg_crates
@ -72,8 +72,8 @@ impl ServerWorldState {
} }
} }
} }
for pkg in ws.packages() { for pkg in ws.cargo.packages() {
for dep in pkg.dependencies(ws) { for dep in pkg.dependencies(&ws.cargo) {
if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
for &from in pkg_crates.get(&pkg).into_iter().flatten() { for &from in pkg_crates.get(&pkg).into_iter().flatten() {
crate_graph.add_dep(from, dep.name.clone(), to); crate_graph.add_dep(from, dep.name.clone(), to);

View File

@ -4,7 +4,7 @@ use languageserver_types::{
CodeActionContext, DocumentFormattingParams, FormattingOptions, Position, Range, CodeActionContext, DocumentFormattingParams, FormattingOptions, Position, Range,
}; };
use ra_lsp_server::req::{ use ra_lsp_server::req::{
CodeActionParams, CodeActionRequest, Formatting, Runnables, RunnablesParams, CodeActionParams, CodeActionRequest, Formatting, Runnables, RunnablesParams, CompletionParams, Completion,
}; };
use serde_json::json; use serde_json::json;
@ -12,6 +12,45 @@ use crate::support::project;
const LOG: &'static str = ""; const LOG: &'static str = "";
#[test]
fn completes_items_from_standard_library() {
let server = project(
r#"
//- Cargo.toml
[package]
name = "foo"
version = "0.0.0"
//- src/lib.rs
use std::collections::;
"#,
);
server.wait_for_feedback("workspace loaded");
server.request::<Completion>(
CompletionParams {
text_document: server.doc_id("src/lib.rs"),
context: None,
position: Position::new(0, 22),
},
json!([
{
"filterText": "self",
"insertText": "self",
"insertTextFormat": 1,
"kind": 14,
"label": "self"
},
{
"filterText": "super",
"insertText": "super",
"insertTextFormat": 1,
"kind": 14,
"label": "super"
}
]),
);
}
#[test] #[test]
fn test_runnables_no_project() { fn test_runnables_no_project() {
let server = project( let server = project(