Skip to content
This repository has been archived by the owner on Dec 29, 2022. It is now read-only.

Commit

Permalink
Merge pull request #1020 from kngwyu/racer-pm-fix
Browse files Browse the repository at this point in the history
Allow project model to download crates
  • Loading branch information
Xanewok authored Aug 28, 2018
2 parents 6bda4d5 + a98c9a0 commit e926d49
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 23 deletions.
57 changes: 35 additions & 22 deletions src/project_model.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/// This module represents the RLS view of the Cargo project model:
/// a graph of interdependent packages.
//! This module represents the RLS view of the Cargo project model:
//! a graph of interdependent packages.
use std::{
collections::HashMap,
sync::Arc,
Expand All @@ -20,6 +20,7 @@ use racer;

#[derive(Debug)]
pub struct ProjectModel {
manifest_to_id: HashMap<PathBuf, Package>,
packages: Vec<PackageData>,
}

Expand All @@ -28,8 +29,7 @@ pub struct Package(usize);

#[derive(Debug)]
struct PackageData {
manifest: PathBuf,
lib: Option<PathBuf>,
lib: Option<(PathBuf, String)>,
deps: Vec<Dep>,
}

Expand All @@ -40,12 +40,12 @@ pub struct Dep {
}

impl ProjectModel {
pub fn load(manifest: &Path, vfs: &Vfs) -> Result<ProjectModel, failure::Error> {
assert!(manifest.ends_with("Cargo.toml"));
pub fn load(ws_manifest: &Path, vfs: &Vfs) -> Result<ProjectModel, failure::Error> {
assert!(ws_manifest.ends_with("Cargo.toml"));
let mut config = Config::default()?;
// frozen=true, locked=true
config.configure(0, Some(true), &None, true, true, &None, &[])?;
let ws = Workspace::new(&manifest, &config)?;
// frozen = false, locked = false
config.configure(0, Some(true), &None, false, false, &None, &[])?;
let ws = Workspace::new(&ws_manifest, &config)?;
// get resolve from lock file
let prev = {
let lock_path = ws.root().to_owned().join("Cargo.lock");
Expand All @@ -55,30 +55,33 @@ impl ProjectModel {
let v: EncodableResolve = resolve.try_into()?;
Some(v.into_resolve(&ws)?)
}
_ => None
_ => None,
}
};
// then resolve precisely and add overrides
let mut registry = PackageRegistry::new(ws.config())?;
let resolve = resolve_with_prev(&mut registry, &ws, prev.as_ref())?;
let cargo_packages = {
let ids: Vec<PackageId> = resolve.iter().cloned().collect();
registry.get(&ids)
};

let mut pkg_id_to_pkg = HashMap::new();
let mut manifest_to_id = HashMap::new();
let mut packages = Vec::new();
for (idx, pkg_id) in resolve.iter().enumerate() {
let pkg = Package(idx);
pkg_id_to_pkg.insert(pkg_id.clone(), pkg);
let cargo_pkg = cargo_packages.get(pkg_id)?;
let manifest = cargo_pkg.manifest_path().to_owned();
packages.push(PackageData {
manifest: cargo_pkg.manifest_path().to_owned(),
lib: cargo_pkg.targets().iter()
lib: cargo_pkg
.targets()
.iter()
.find(|t| t.is_lib())
.map(|t| t.src_path().to_owned()),
// racer expect name 'underscored'(crate) name
.map(|t| (t.src_path().to_owned(), t.name().replace('-', "_"))),
deps: Vec::new(),
})
});
manifest_to_id.insert(manifest, pkg);
}
for pkg_id in resolve.iter() {
for (dep_id, _) in resolve.deps(&pkg_id) {
Expand All @@ -99,28 +102,31 @@ impl ProjectModel {
}
}
}
Ok(ProjectModel { packages })
Ok(ProjectModel {
manifest_to_id,
packages,
})
}

pub fn package_for_manifest(&self, manifest_path: &Path) -> Option<Package> {
self.packages.iter()
.enumerate()
.find(|(_idx, p)| p.manifest == manifest_path)
.map(|(idx, _p)| Package(idx))
self.manifest_to_id.get(manifest_path).map(|&x| x)
}

fn get(&self, pkg: Package) -> &PackageData {
&self.packages[pkg.0]
}

fn get_lib(&self, pkg: Package) -> Option<&(PathBuf, String)> {
self.packages[pkg.0].lib.as_ref()
}
}

impl Package {
pub fn deps(self, project: &ProjectModel) -> &[Dep] {
&project.get(self).deps
}
pub fn lib_root(self, project: &ProjectModel) -> Option<&Path> {
project.get(self).lib.as_ref().map(|p| p.as_path())
project.get(self).lib.as_ref().map(|p| p.0.as_path())
}
}

Expand All @@ -141,6 +147,13 @@ impl racer::ProjectModelProvider for RacerProjectModel {
}
fn resolve_dependency(&self, manifest: &Path, libname: &str) -> Option<PathBuf> {
let pkg = self.0.package_for_manifest(manifest)?;
// if current package has a library target, we have to provide its own name
// in examples/tests/benches directory
if let Some(lib) = self.0.get_lib(pkg) {
if lib.1 == libname {
return Some(lib.0.clone());
}
}
let dep = pkg.deps(&self.0)
.iter()
.find(|dep| dep.crate_name == libname)?
Expand Down
67 changes: 66 additions & 1 deletion tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,4 +311,69 @@ fn changing_workspace_lib_retains_bin_diagnostics() {

rls.shutdown_exit();
});
}
}

#[test]
fn cmd_test_complete_self_crate_name() {
timeout(Duration::from_secs(TIME_LIMIT_SECS), ||{
let p = project("ws_with_test_dir")
.file("Cargo.toml", r#"
[workspace]
members = ["library"]
"#)
.file("library/Cargo.toml", r#"
[package]
name = "library"
version = "0.1.0"
authors = ["Example <[email protected]>"]
"#)
.file("library/src/lib.rs", r#"
pub fn function() -> usize { 5 }
"#)
.file("library/tests/test.rs", r#"
extern crate library;
use library::~
"#)
.build();

let root_path = p.root();
let rls_child = p.rls().spawn().unwrap();
let mut rls = RlsHandle::new(rls_child);

rls.request(0, "initialize", Some(json!({
"rootPath": root_path,
"capabilities": {}
}))).unwrap();

rls.expect_messages(&[
ExpectedMessage::new(Some(0)).expect_contains("capabilities"),
ExpectedMessage::new(None).expect_contains("progress").expect_contains(r#"title":"Building""#),
ExpectedMessage::new(None).expect_contains("progress").expect_contains("library"),
ExpectedMessage::new(None).expect_contains("progress").expect_contains("library"),
ExpectedMessage::new(None).expect_contains("progress").expect_contains(r#"title":"Building""#),
ExpectedMessage::new(None).expect_contains("progress").expect_contains(r#""done":true"#),
ExpectedMessage::new(None).expect_contains("progress").expect_contains(r#"title":"Indexing""#),
ExpectedMessage::new(None).expect_contains("expected identifier, found"),
ExpectedMessage::new(None).expect_contains("progress").expect_contains(r#""done":true"#),
]);
rls.request(0, "textDocument/completion", Some(json!({
"context": {
"triggerCharacter": ":",
"triggerKind": 2
},
"position": {
"character": 32,
"line": 2
},
"textDocument": {
"uri": format!("file://{}/library/tests/test.rs", root_path.as_path().display()),
"version": 1
}
}))).unwrap();
rls.expect_messages(&[
ExpectedMessage::new(Some(0)).expect_contains("result").expect_contains("pub fn function() -> usize"),
]);

rls.shutdown_exit();
});
}

0 comments on commit e926d49

Please sign in to comment.