diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/rust-analyzer/src/bin/main.rs | 41 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cli/load_cargo.rs | 3 | ||||
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 25 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 29 | ||||
-rw-r--r-- | crates/rust-analyzer/tests/heavy_tests/support.rs | 31 |
5 files changed, 83 insertions, 46 deletions
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index e82fd57de..8d071ab1c 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs | |||
@@ -4,9 +4,14 @@ | |||
4 | mod args; | 4 | mod args; |
5 | 5 | ||
6 | use lsp_server::Connection; | 6 | use lsp_server::Connection; |
7 | use rust_analyzer::{cli, config::Config, from_json, Result}; | 7 | use rust_analyzer::{ |
8 | cli, | ||
9 | config::{Config, LinkedProject}, | ||
10 | from_json, Result, | ||
11 | }; | ||
8 | 12 | ||
9 | use crate::args::HelpPrinted; | 13 | use crate::args::HelpPrinted; |
14 | use ra_project_model::ProjectManifest; | ||
10 | 15 | ||
11 | fn main() -> Result<()> { | 16 | fn main() -> Result<()> { |
12 | setup_logging()?; | 17 | setup_logging()?; |
@@ -97,17 +102,6 @@ fn run_server() -> Result<()> { | |||
97 | log::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default()); | 102 | log::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default()); |
98 | } | 103 | } |
99 | 104 | ||
100 | let cwd = std::env::current_dir()?; | ||
101 | let root = initialize_params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd); | ||
102 | |||
103 | let workspace_roots = initialize_params | ||
104 | .workspace_folders | ||
105 | .map(|workspaces| { | ||
106 | workspaces.into_iter().filter_map(|it| it.uri.to_file_path().ok()).collect::<Vec<_>>() | ||
107 | }) | ||
108 | .filter(|workspaces| !workspaces.is_empty()) | ||
109 | .unwrap_or_else(|| vec![root]); | ||
110 | |||
111 | let config = { | 105 | let config = { |
112 | let mut config = Config::default(); | 106 | let mut config = Config::default(); |
113 | if let Some(value) = &initialize_params.initialization_options { | 107 | if let Some(value) = &initialize_params.initialization_options { |
@@ -115,10 +109,31 @@ fn run_server() -> Result<()> { | |||
115 | } | 109 | } |
116 | config.update_caps(&initialize_params.capabilities); | 110 | config.update_caps(&initialize_params.capabilities); |
117 | 111 | ||
112 | if config.linked_projects.is_empty() { | ||
113 | let cwd = std::env::current_dir()?; | ||
114 | let root = | ||
115 | initialize_params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd); | ||
116 | let workspace_roots = initialize_params | ||
117 | .workspace_folders | ||
118 | .map(|workspaces| { | ||
119 | workspaces | ||
120 | .into_iter() | ||
121 | .filter_map(|it| it.uri.to_file_path().ok()) | ||
122 | .collect::<Vec<_>>() | ||
123 | }) | ||
124 | .filter(|workspaces| !workspaces.is_empty()) | ||
125 | .unwrap_or_else(|| vec![root]); | ||
126 | |||
127 | config.linked_projects = ProjectManifest::discover_all(&workspace_roots) | ||
128 | .into_iter() | ||
129 | .map(LinkedProject::from) | ||
130 | .collect(); | ||
131 | } | ||
132 | |||
118 | config | 133 | config |
119 | }; | 134 | }; |
120 | 135 | ||
121 | rust_analyzer::main_loop(workspace_roots, config, connection)?; | 136 | rust_analyzer::main_loop(config, connection)?; |
122 | 137 | ||
123 | log::info!("shutting down IO..."); | 138 | log::info!("shutting down IO..."); |
124 | io_threads.join()?; | 139 | io_threads.join()?; |
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 67491b42a..c7e86fe0c 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs | |||
@@ -8,7 +8,8 @@ use crossbeam_channel::{unbounded, Receiver}; | |||
8 | use ra_db::{ExternSourceId, FileId, SourceRootId}; | 8 | use ra_db::{ExternSourceId, FileId, SourceRootId}; |
9 | use ra_ide::{AnalysisChange, AnalysisHost}; | 9 | use ra_ide::{AnalysisChange, AnalysisHost}; |
10 | use ra_project_model::{ | 10 | use ra_project_model::{ |
11 | get_rustc_cfg_options, CargoConfig, PackageRoot, ProcMacroClient, ProjectManifest, ProjectWorkspace, | 11 | get_rustc_cfg_options, CargoConfig, PackageRoot, ProcMacroClient, ProjectManifest, |
12 | ProjectWorkspace, | ||
12 | }; | 13 | }; |
13 | use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; | 14 | use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; |
14 | use rustc_hash::{FxHashMap, FxHashSet}; | 15 | use rustc_hash::{FxHashMap, FxHashSet}; |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 9c6e369d2..761bc9c2d 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -12,14 +12,13 @@ use std::{ffi::OsString, path::PathBuf}; | |||
12 | use lsp_types::ClientCapabilities; | 12 | use lsp_types::ClientCapabilities; |
13 | use ra_flycheck::FlycheckConfig; | 13 | use ra_flycheck::FlycheckConfig; |
14 | use ra_ide::{AssistConfig, CompletionConfig, InlayHintsConfig}; | 14 | use ra_ide::{AssistConfig, CompletionConfig, InlayHintsConfig}; |
15 | use ra_project_model::CargoConfig; | 15 | use ra_project_model::{CargoConfig, JsonProject, ProjectManifest}; |
16 | use serde::Deserialize; | 16 | use serde::Deserialize; |
17 | 17 | ||
18 | #[derive(Debug, Clone)] | 18 | #[derive(Debug, Clone)] |
19 | pub struct Config { | 19 | pub struct Config { |
20 | pub client_caps: ClientCapsConfig, | 20 | pub client_caps: ClientCapsConfig, |
21 | 21 | ||
22 | pub with_sysroot: bool, | ||
23 | pub publish_diagnostics: bool, | 22 | pub publish_diagnostics: bool, |
24 | pub lru_capacity: Option<usize>, | 23 | pub lru_capacity: Option<usize>, |
25 | pub proc_macro_srv: Option<(PathBuf, Vec<OsString>)>, | 24 | pub proc_macro_srv: Option<(PathBuf, Vec<OsString>)>, |
@@ -35,6 +34,27 @@ pub struct Config { | |||
35 | pub assist: AssistConfig, | 34 | pub assist: AssistConfig, |
36 | pub call_info_full: bool, | 35 | pub call_info_full: bool, |
37 | pub lens: LensConfig, | 36 | pub lens: LensConfig, |
37 | |||
38 | pub with_sysroot: bool, | ||
39 | pub linked_projects: Vec<LinkedProject>, | ||
40 | } | ||
41 | |||
42 | #[derive(Debug, Clone)] | ||
43 | pub enum LinkedProject { | ||
44 | ProjectManifest(ProjectManifest), | ||
45 | JsonProject(JsonProject), | ||
46 | } | ||
47 | |||
48 | impl From<ProjectManifest> for LinkedProject { | ||
49 | fn from(v: ProjectManifest) -> Self { | ||
50 | LinkedProject::ProjectManifest(v) | ||
51 | } | ||
52 | } | ||
53 | |||
54 | impl From<JsonProject> for LinkedProject { | ||
55 | fn from(v: JsonProject) -> Self { | ||
56 | LinkedProject::JsonProject(v) | ||
57 | } | ||
38 | } | 58 | } |
39 | 59 | ||
40 | #[derive(Clone, Debug, PartialEq, Eq)] | 60 | #[derive(Clone, Debug, PartialEq, Eq)] |
@@ -141,6 +161,7 @@ impl Default for Config { | |||
141 | assist: AssistConfig::default(), | 161 | assist: AssistConfig::default(), |
142 | call_info_full: true, | 162 | call_info_full: true, |
143 | lens: LensConfig::default(), | 163 | lens: LensConfig::default(), |
164 | linked_projects: Vec::new(), | ||
144 | } | 165 | } |
145 | } | 166 | } |
146 | } | 167 | } |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index ea5b4c91c..d901f21d7 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -12,13 +12,11 @@ use std::{ | |||
12 | fmt, | 12 | fmt, |
13 | ops::Range, | 13 | ops::Range, |
14 | panic, | 14 | panic, |
15 | path::PathBuf, | ||
16 | sync::Arc, | 15 | sync::Arc, |
17 | time::{Duration, Instant}, | 16 | time::{Duration, Instant}, |
18 | }; | 17 | }; |
19 | 18 | ||
20 | use crossbeam_channel::{never, select, unbounded, RecvError, Sender}; | 19 | use crossbeam_channel::{never, select, unbounded, RecvError, Sender}; |
21 | use itertools::Itertools; | ||
22 | use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; | 20 | use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; |
23 | use lsp_types::{ | 21 | use lsp_types::{ |
24 | DidChangeTextDocumentParams, NumberOrString, TextDocumentContentChangeEvent, WorkDoneProgress, | 22 | DidChangeTextDocumentParams, NumberOrString, TextDocumentContentChangeEvent, WorkDoneProgress, |
@@ -28,7 +26,7 @@ use lsp_types::{ | |||
28 | use ra_flycheck::{CheckTask, Status}; | 26 | use ra_flycheck::{CheckTask, Status}; |
29 | use ra_ide::{Canceled, FileId, LibraryData, LineIndex, SourceRootId}; | 27 | use ra_ide::{Canceled, FileId, LibraryData, LineIndex, SourceRootId}; |
30 | use ra_prof::profile; | 28 | use ra_prof::profile; |
31 | use ra_project_model::{PackageRoot, ProjectManifest, ProjectWorkspace}; | 29 | use ra_project_model::{PackageRoot, ProjectWorkspace}; |
32 | use ra_vfs::{VfsFile, VfsTask, Watch}; | 30 | use ra_vfs::{VfsFile, VfsTask, Watch}; |
33 | use relative_path::RelativePathBuf; | 31 | use relative_path::RelativePathBuf; |
34 | use rustc_hash::FxHashSet; | 32 | use rustc_hash::FxHashSet; |
@@ -36,7 +34,7 @@ use serde::{de::DeserializeOwned, Serialize}; | |||
36 | use threadpool::ThreadPool; | 34 | use threadpool::ThreadPool; |
37 | 35 | ||
38 | use crate::{ | 36 | use crate::{ |
39 | config::{Config, FilesWatcher}, | 37 | config::{Config, FilesWatcher, LinkedProject}, |
40 | diagnostics::{to_proto::url_from_path_with_drive_lowercasing, DiagnosticTask}, | 38 | diagnostics::{to_proto::url_from_path_with_drive_lowercasing, DiagnosticTask}, |
41 | from_proto, | 39 | from_proto, |
42 | global_state::{GlobalState, GlobalStateSnapshot}, | 40 | global_state::{GlobalState, GlobalStateSnapshot}, |
@@ -70,7 +68,7 @@ impl fmt::Display for LspError { | |||
70 | 68 | ||
71 | impl Error for LspError {} | 69 | impl Error for LspError {} |
72 | 70 | ||
73 | pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection) -> Result<()> { | 71 | pub fn main_loop(config: Config, connection: Connection) -> Result<()> { |
74 | log::info!("initial config: {:#?}", config); | 72 | log::info!("initial config: {:#?}", config); |
75 | 73 | ||
76 | // Windows scheduler implements priority boosts: if thread waits for an | 74 | // Windows scheduler implements priority boosts: if thread waits for an |
@@ -95,25 +93,24 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection) | |||
95 | let mut loop_state = LoopState::default(); | 93 | let mut loop_state = LoopState::default(); |
96 | let mut global_state = { | 94 | let mut global_state = { |
97 | let workspaces = { | 95 | let workspaces = { |
98 | // FIXME: support dynamic workspace loading. | 96 | if config.linked_projects.is_empty() && config.notifications.cargo_toml_not_found { |
99 | let project_roots = ProjectManifest::discover_all(&ws_roots); | ||
100 | |||
101 | if project_roots.is_empty() && config.notifications.cargo_toml_not_found { | ||
102 | show_message( | 97 | show_message( |
103 | lsp_types::MessageType::Error, | 98 | lsp_types::MessageType::Error, |
104 | format!( | 99 | "rust-analyzer failed to discover workspace".to_string(), |
105 | "rust-analyzer failed to discover workspace, no Cargo.toml found, dirs searched: {}", | ||
106 | ws_roots.iter().format_with(", ", |it, f| f(&it.display())) | ||
107 | ), | ||
108 | &connection.sender, | 100 | &connection.sender, |
109 | ); | 101 | ); |
110 | }; | 102 | }; |
111 | 103 | ||
112 | project_roots | 104 | config |
113 | .into_iter() | 105 | .linked_projects |
106 | .iter() | ||
107 | .filter_map(|project| match project { | ||
108 | LinkedProject::ProjectManifest(it) => Some(it), | ||
109 | LinkedProject::JsonProject(_) => None, | ||
110 | }) | ||
114 | .filter_map(|root| { | 111 | .filter_map(|root| { |
115 | ra_project_model::ProjectWorkspace::load( | 112 | ra_project_model::ProjectWorkspace::load( |
116 | root, | 113 | root.clone(), |
117 | &config.cargo, | 114 | &config.cargo, |
118 | config.with_sysroot, | 115 | config.with_sysroot, |
119 | ) | 116 | ) |
diff --git a/crates/rust-analyzer/tests/heavy_tests/support.rs b/crates/rust-analyzer/tests/heavy_tests/support.rs index 66a6f4d54..30d03b622 100644 --- a/crates/rust-analyzer/tests/heavy_tests/support.rs +++ b/crates/rust-analyzer/tests/heavy_tests/support.rs | |||
@@ -19,8 +19,9 @@ use serde_json::{to_string_pretty, Value}; | |||
19 | use tempfile::TempDir; | 19 | use tempfile::TempDir; |
20 | use test_utils::{find_mismatch, parse_fixture}; | 20 | use test_utils::{find_mismatch, parse_fixture}; |
21 | 21 | ||
22 | use ra_project_model::ProjectManifest; | ||
22 | use rust_analyzer::{ | 23 | use rust_analyzer::{ |
23 | config::{ClientCapsConfig, Config}, | 24 | config::{ClientCapsConfig, Config, LinkedProject}, |
24 | main_loop, | 25 | main_loop, |
25 | }; | 26 | }; |
26 | 27 | ||
@@ -42,7 +43,7 @@ impl<'a> Project<'a> { | |||
42 | self | 43 | self |
43 | } | 44 | } |
44 | 45 | ||
45 | pub fn root(mut self, path: &str) -> Project<'a> { | 46 | pub(crate) fn root(mut self, path: &str) -> Project<'a> { |
46 | self.roots.push(path.into()); | 47 | self.roots.push(path.into()); |
47 | self | 48 | self |
48 | } | 49 | } |
@@ -74,7 +75,16 @@ impl<'a> Project<'a> { | |||
74 | paths.push((path, entry.text)); | 75 | paths.push((path, entry.text)); |
75 | } | 76 | } |
76 | 77 | ||
77 | let roots = self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect(); | 78 | let mut roots = |
79 | self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect::<Vec<_>>(); | ||
80 | if roots.is_empty() { | ||
81 | roots.push(tmp_dir.path().to_path_buf()); | ||
82 | } | ||
83 | let linked_projects = roots | ||
84 | .into_iter() | ||
85 | .map(|it| ProjectManifest::discover_single(&it).unwrap()) | ||
86 | .map(LinkedProject::from) | ||
87 | .collect::<Vec<_>>(); | ||
78 | 88 | ||
79 | let mut config = Config { | 89 | let mut config = Config { |
80 | client_caps: ClientCapsConfig { | 90 | client_caps: ClientCapsConfig { |
@@ -84,6 +94,7 @@ impl<'a> Project<'a> { | |||
84 | ..Default::default() | 94 | ..Default::default() |
85 | }, | 95 | }, |
86 | with_sysroot: self.with_sysroot, | 96 | with_sysroot: self.with_sysroot, |
97 | linked_projects, | ||
87 | ..Config::default() | 98 | ..Config::default() |
88 | }; | 99 | }; |
89 | 100 | ||
@@ -91,7 +102,7 @@ impl<'a> Project<'a> { | |||
91 | f(&mut config) | 102 | f(&mut config) |
92 | } | 103 | } |
93 | 104 | ||
94 | Server::new(tmp_dir, config, roots, paths) | 105 | Server::new(tmp_dir, config, paths) |
95 | } | 106 | } |
96 | } | 107 | } |
97 | 108 | ||
@@ -109,20 +120,12 @@ pub struct Server { | |||
109 | } | 120 | } |
110 | 121 | ||
111 | impl Server { | 122 | impl Server { |
112 | fn new( | 123 | fn new(dir: TempDir, config: Config, files: Vec<(PathBuf, String)>) -> Server { |
113 | dir: TempDir, | ||
114 | config: Config, | ||
115 | roots: Vec<PathBuf>, | ||
116 | files: Vec<(PathBuf, String)>, | ||
117 | ) -> Server { | ||
118 | let path = dir.path().to_path_buf(); | ||
119 | |||
120 | let roots = if roots.is_empty() { vec![path] } else { roots }; | ||
121 | let (connection, client) = Connection::memory(); | 124 | let (connection, client) = Connection::memory(); |
122 | 125 | ||
123 | let _thread = jod_thread::Builder::new() | 126 | let _thread = jod_thread::Builder::new() |
124 | .name("test server".to_string()) | 127 | .name("test server".to_string()) |
125 | .spawn(move || main_loop(roots, config, connection).unwrap()) | 128 | .spawn(move || main_loop(config, connection).unwrap()) |
126 | .expect("failed to spawn a thread"); | 129 | .expect("failed to spawn a thread"); |
127 | 130 | ||
128 | let res = | 131 | let res = |