aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/rust-analyzer/src/bin/main.rs41
-rw-r--r--crates/rust-analyzer/src/cli/load_cargo.rs3
-rw-r--r--crates/rust-analyzer/src/config.rs25
-rw-r--r--crates/rust-analyzer/src/main_loop.rs29
-rw-r--r--crates/rust-analyzer/tests/heavy_tests/support.rs31
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 @@
4mod args; 4mod args;
5 5
6use lsp_server::Connection; 6use lsp_server::Connection;
7use rust_analyzer::{cli, config::Config, from_json, Result}; 7use rust_analyzer::{
8 cli,
9 config::{Config, LinkedProject},
10 from_json, Result,
11};
8 12
9use crate::args::HelpPrinted; 13use crate::args::HelpPrinted;
14use ra_project_model::ProjectManifest;
10 15
11fn main() -> Result<()> { 16fn 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};
8use ra_db::{ExternSourceId, FileId, SourceRootId}; 8use ra_db::{ExternSourceId, FileId, SourceRootId};
9use ra_ide::{AnalysisChange, AnalysisHost}; 9use ra_ide::{AnalysisChange, AnalysisHost};
10use ra_project_model::{ 10use 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};
13use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; 14use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch};
14use rustc_hash::{FxHashMap, FxHashSet}; 15use 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};
12use lsp_types::ClientCapabilities; 12use lsp_types::ClientCapabilities;
13use ra_flycheck::FlycheckConfig; 13use ra_flycheck::FlycheckConfig;
14use ra_ide::{AssistConfig, CompletionConfig, InlayHintsConfig}; 14use ra_ide::{AssistConfig, CompletionConfig, InlayHintsConfig};
15use ra_project_model::CargoConfig; 15use ra_project_model::{CargoConfig, JsonProject, ProjectManifest};
16use serde::Deserialize; 16use serde::Deserialize;
17 17
18#[derive(Debug, Clone)] 18#[derive(Debug, Clone)]
19pub struct Config { 19pub 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)]
43pub enum LinkedProject {
44 ProjectManifest(ProjectManifest),
45 JsonProject(JsonProject),
46}
47
48impl From<ProjectManifest> for LinkedProject {
49 fn from(v: ProjectManifest) -> Self {
50 LinkedProject::ProjectManifest(v)
51 }
52}
53
54impl 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
20use crossbeam_channel::{never, select, unbounded, RecvError, Sender}; 19use crossbeam_channel::{never, select, unbounded, RecvError, Sender};
21use itertools::Itertools;
22use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; 20use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response};
23use lsp_types::{ 21use lsp_types::{
24 DidChangeTextDocumentParams, NumberOrString, TextDocumentContentChangeEvent, WorkDoneProgress, 22 DidChangeTextDocumentParams, NumberOrString, TextDocumentContentChangeEvent, WorkDoneProgress,
@@ -28,7 +26,7 @@ use lsp_types::{
28use ra_flycheck::{CheckTask, Status}; 26use ra_flycheck::{CheckTask, Status};
29use ra_ide::{Canceled, FileId, LibraryData, LineIndex, SourceRootId}; 27use ra_ide::{Canceled, FileId, LibraryData, LineIndex, SourceRootId};
30use ra_prof::profile; 28use ra_prof::profile;
31use ra_project_model::{PackageRoot, ProjectManifest, ProjectWorkspace}; 29use ra_project_model::{PackageRoot, ProjectWorkspace};
32use ra_vfs::{VfsFile, VfsTask, Watch}; 30use ra_vfs::{VfsFile, VfsTask, Watch};
33use relative_path::RelativePathBuf; 31use relative_path::RelativePathBuf;
34use rustc_hash::FxHashSet; 32use rustc_hash::FxHashSet;
@@ -36,7 +34,7 @@ use serde::{de::DeserializeOwned, Serialize};
36use threadpool::ThreadPool; 34use threadpool::ThreadPool;
37 35
38use crate::{ 36use 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
71impl Error for LspError {} 69impl Error for LspError {}
72 70
73pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection) -> Result<()> { 71pub 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};
19use tempfile::TempDir; 19use tempfile::TempDir;
20use test_utils::{find_mismatch, parse_fixture}; 20use test_utils::{find_mismatch, parse_fixture};
21 21
22use ra_project_model::ProjectManifest;
22use rust_analyzer::{ 23use 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
111impl Server { 122impl 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 =