aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/server/Cargo.toml1
-rw-r--r--crates/server/src/lib.rs9
-rw-r--r--crates/server/src/project_model.rs138
3 files changed, 145 insertions, 3 deletions
diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml
index 2a9374e98..c3e7a6238 100644
--- a/crates/server/Cargo.toml
+++ b/crates/server/Cargo.toml
@@ -19,6 +19,7 @@ languageserver-types = "0.49.0"
19walkdir = "2.2.0" 19walkdir = "2.2.0"
20im = { version = "11.0.1", features = ["arc"] } 20im = { version = "11.0.1", features = ["arc"] }
21text_unit = { version = "0.1.2", features = ["serde"] } 21text_unit = { version = "0.1.2", features = ["serde"] }
22cargo_metadata = "0.6.0"
22 23
23libsyntax2 = { path = "../libsyntax2" } 24libsyntax2 = { path = "../libsyntax2" }
24libeditor = { path = "../libeditor" } 25libeditor = { path = "../libeditor" }
diff --git a/crates/server/src/lib.rs b/crates/server/src/lib.rs
index bfa4bc41e..096b94a6d 100644
--- a/crates/server/src/lib.rs
+++ b/crates/server/src/lib.rs
@@ -13,12 +13,14 @@ extern crate log;
13extern crate drop_bomb; 13extern crate drop_bomb;
14extern crate url_serde; 14extern crate url_serde;
15extern crate walkdir; 15extern crate walkdir;
16extern crate im;
17extern crate relative_path;
18extern crate cargo_metadata;
19
20extern crate gen_lsp_server;
16extern crate libeditor; 21extern crate libeditor;
17extern crate libanalysis; 22extern crate libanalysis;
18extern crate libsyntax2; 23extern crate libsyntax2;
19extern crate gen_lsp_server;
20extern crate im;
21extern crate relative_path;
22 24
23mod caps; 25mod caps;
24pub mod req; 26pub mod req;
@@ -27,6 +29,7 @@ mod main_loop;
27mod vfs; 29mod vfs;
28mod path_map; 30mod path_map;
29mod server_world; 31mod server_world;
32mod project_model;
30 33
31pub type Result<T> = ::std::result::Result<T, ::failure::Error>; 34pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
32pub use caps::server_capabilities; 35pub use caps::server_capabilities;
diff --git a/crates/server/src/project_model.rs b/crates/server/src/project_model.rs
new file mode 100644
index 000000000..a33b34dd0
--- /dev/null
+++ b/crates/server/src/project_model.rs
@@ -0,0 +1,138 @@
1use std::{
2 collections::HashMap,
3 path::{Path, PathBuf},
4};
5use libsyntax2::SmolStr;
6use cargo_metadata::{metadata_run, CargoOpt};
7use Result;
8
9#[derive(Debug)]
10pub struct CargoWorkspace {
11 ws_members: Vec<Package>,
12 packages: Vec<PackageData>,
13 targets: Vec<TargetData>,
14}
15
16#[derive(Clone, Copy, Debug)]
17pub struct Package(usize);
18#[derive(Clone, Copy, Debug)]
19pub struct Target(usize);
20
21#[derive(Debug)]
22struct PackageData {
23 name: SmolStr,
24 manifest: PathBuf,
25 targets: Vec<Target>
26}
27
28#[derive(Debug)]
29struct TargetData {
30 pkg: Package,
31 name: SmolStr,
32 root: PathBuf,
33 kind: TargetKind,
34}
35
36#[derive(Clone, Copy, PartialEq, Eq, Debug)]
37pub enum TargetKind {
38 Bin, Lib, Example, Test, Bench, Other,
39}
40
41impl Package {
42 pub fn name(self, ws: &CargoWorkspace) -> &str {
43 ws.pkg(self).name.as_str()
44 }
45 pub fn manifest(self, ws: &CargoWorkspace) -> &Path {
46 ws.pkg(self).manifest.as_path()
47 }
48 pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator<Item=Target> + 'a {
49 ws.pkg(self).targets.iter().cloned()
50 }
51}
52
53impl Target {
54 pub fn pkg(self, ws: &CargoWorkspace) -> Package {
55 ws.tgt(self).pkg
56 }
57 pub fn name(self, ws: &CargoWorkspace) -> &str {
58 ws.tgt(self).name.as_str()
59 }
60 pub fn root(self, ws: &CargoWorkspace) -> &Path {
61 ws.tgt(self).root.as_path()
62 }
63 pub fn kind(self, ws: &CargoWorkspace) -> TargetKind {
64 ws.tgt(self).kind
65 }
66}
67
68impl CargoWorkspace {
69 pub fn from_path(path: &Path) -> Result<CargoWorkspace> {
70 let meta = metadata_run(
71 Some(path),
72 true,
73 Some(CargoOpt::AllFeatures)
74 ).map_err(|e| format_err!("cargo metadata failed: {}", e))?;
75 let mut pkg_by_id = HashMap::new();
76 let mut packages = Vec::new();
77 let mut targets = Vec::new();
78 for meta_pkg in meta.packages {
79 let pkg = Package(packages.len());
80 pkg_by_id.insert(meta_pkg.id.clone(), pkg);
81 let mut pkg_data = PackageData {
82 name: meta_pkg.name.into(),
83 manifest: PathBuf::from(meta_pkg.manifest_path),
84 targets: Vec::new(),
85 };
86 for meta_tgt in meta_pkg.targets {
87 let tgt = Target(targets.len());
88 targets.push(TargetData {
89 pkg,
90 name: meta_tgt.name.into(),
91 root: PathBuf::from(meta_tgt.src_path),
92 kind: TargetKind::new(meta_tgt.kind.as_slice()),
93 });
94 pkg_data.targets.push(tgt);
95 }
96 packages.push(pkg_data)
97 }
98 let ws_members = meta.workspace_members
99 .iter()
100 .map(|it| pkg_by_id[&it.raw])
101 .collect();
102
103 Ok(CargoWorkspace { packages, targets, ws_members })
104 }
105 pub fn packages<'a>(&'a self) -> impl Iterator<Item=Package> + 'a {
106 (0..self.packages.len()).map(Package)
107 }
108 pub fn ws_members<'a>(&'a self) -> impl Iterator<Item=Package> + 'a {
109 self.ws_members.iter().cloned()
110 }
111 pub fn target_by_roo(&self, root: &Path) -> Option<Target> {
112 self.packages()
113 .filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root))
114 .next()
115 }
116 fn pkg(&self, pkg: Package) -> &PackageData {
117 &self.packages[pkg.0]
118 }
119 fn tgt(&self, tgt: Target) -> &TargetData {
120 &self.targets[tgt.0]
121 }
122}
123
124impl TargetKind {
125 fn new(kinds: &[String]) -> TargetKind {
126 for kind in kinds {
127 return match kind.as_str() {
128 "bin" => TargetKind::Bin,
129 "test" => TargetKind::Test,
130 "bench" => TargetKind::Bench,
131 "example" => TargetKind::Example,
132 _ if kind.contains("lib") => TargetKind::Lib,
133 _ => continue,
134 }
135 }
136 TargetKind::Other
137 }
138}