Skip to content

Commit e84781a

Browse files
committed
Auto merge of rust-lang#14603 - Veykril:workspaces, r=Veykril
fix: Deduplicate passed workspaces by top level cargo workspace they belong to Fixes rust-lang/rust-analyzer#14571 With this we should be supporting vscode workspaces properly
2 parents 9b835f3 + 9c40897 commit e84781a

File tree

5 files changed

+56
-47
lines changed

5 files changed

+56
-47
lines changed

crates/rust-analyzer/src/config.rs

+28-23
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use project_model::{
2727
};
2828
use rustc_hash::{FxHashMap, FxHashSet};
2929
use serde::{de::DeserializeOwned, Deserialize};
30-
use vfs::AbsPathBuf;
30+
use vfs::{AbsPath, AbsPathBuf};
3131

3232
use crate::{
3333
caps::completion_item_edit_resolve,
@@ -535,8 +535,9 @@ impl Default for ConfigData {
535535

536536
#[derive(Debug, Clone)]
537537
pub struct Config {
538-
pub discovered_projects: Option<Vec<ProjectManifest>>,
539-
pub workspace_roots: Vec<AbsPathBuf>,
538+
discovered_projects: Vec<ProjectManifest>,
539+
/// The workspace roots as registered by the LSP client
540+
workspace_roots: Vec<AbsPathBuf>,
540541
caps: lsp_types::ClientCapabilities,
541542
root_path: AbsPathBuf,
542543
data: ConfigData,
@@ -742,7 +743,7 @@ impl Config {
742743
caps,
743744
data: ConfigData::default(),
744745
detached_files: Vec::new(),
745-
discovered_projects: None,
746+
discovered_projects: Vec::new(),
746747
root_path,
747748
snippets: Default::default(),
748749
workspace_roots,
@@ -755,7 +756,17 @@ impl Config {
755756
if discovered.is_empty() {
756757
tracing::error!("failed to find any projects in {:?}", &self.workspace_roots);
757758
}
758-
self.discovered_projects = Some(discovered);
759+
self.discovered_projects = discovered;
760+
}
761+
762+
pub fn remove_workspace(&mut self, path: &AbsPath) {
763+
if let Some(position) = self.workspace_roots.iter().position(|it| it == path) {
764+
self.workspace_roots.remove(position);
765+
}
766+
}
767+
768+
pub fn add_workspaces(&mut self, paths: impl Iterator<Item = AbsPathBuf>) {
769+
self.workspace_roots.extend(paths);
759770
}
760771

761772
pub fn update(&mut self, mut json: serde_json::Value) -> Result<(), ConfigUpdateError> {
@@ -860,25 +871,19 @@ impl Config {
860871
pub fn linked_projects(&self) -> Vec<LinkedProject> {
861872
match self.data.linkedProjects.as_slice() {
862873
[] => {
863-
match self.discovered_projects.as_ref() {
864-
Some(discovered_projects) => {
865-
let exclude_dirs: Vec<_> = self
866-
.data
867-
.files_excludeDirs
868-
.iter()
869-
.map(|p| self.root_path.join(p))
870-
.collect();
871-
discovered_projects
872-
.iter()
873-
.filter(|(ProjectManifest::ProjectJson(path) | ProjectManifest::CargoToml(path))| {
874+
let exclude_dirs: Vec<_> =
875+
self.data.files_excludeDirs.iter().map(|p| self.root_path.join(p)).collect();
876+
self.discovered_projects
877+
.iter()
878+
.filter(
879+
|(ProjectManifest::ProjectJson(path)
880+
| ProjectManifest::CargoToml(path))| {
874881
!exclude_dirs.iter().any(|p| path.starts_with(p))
875-
})
876-
.cloned()
877-
.map(LinkedProject::from)
878-
.collect()
879-
}
880-
None => Vec::new(),
881-
}
882+
},
883+
)
884+
.cloned()
885+
.map(LinkedProject::from)
886+
.collect()
882887
}
883888
linked_projects => linked_projects
884889
.iter()

crates/rust-analyzer/src/handlers.rs

+1-8
Original file line numberDiff line numberDiff line change
@@ -777,14 +777,7 @@ pub(crate) fn handle_runnables(
777777
}
778778
}
779779
None => {
780-
if !snap.config.linked_projects().is_empty()
781-
|| !snap
782-
.config
783-
.discovered_projects
784-
.as_ref()
785-
.map(|projects| projects.is_empty())
786-
.unwrap_or(true)
787-
{
780+
if !snap.config.linked_projects().is_empty() {
788781
res.push(lsp_ext::Runnable {
789782
label: "cargo check --workspace".to_string(),
790783
location: None,

crates/rust-analyzer/src/main_loop.rs

+11-9
Original file line numberDiff line numberDiff line change
@@ -908,8 +908,10 @@ impl GlobalState {
908908
// Re-fetch workspaces if a workspace related file has changed
909909
if let Some(abs_path) = vfs_path.as_path() {
910910
if reload::should_refresh_for_change(abs_path, ChangeKind::Modify) {
911-
this.fetch_workspaces_queue
912-
.request_op(format!("DidSaveTextDocument {}", abs_path.display()), ());
911+
this.fetch_workspaces_queue.request_op(
912+
format!("DidSaveTextDocument {}", abs_path.display()),
913+
(),
914+
);
913915
}
914916
}
915917

@@ -972,8 +974,7 @@ impl GlobalState {
972974
for workspace in params.event.removed {
973975
let Ok(path) = workspace.uri.to_file_path() else { continue };
974976
let Ok(path) = AbsPathBuf::try_from(path) else { continue };
975-
let Some(position) = config.workspace_roots.iter().position(|it| it == &path) else { continue };
976-
config.workspace_roots.remove(position);
977+
config.remove_workspace(&path);
977978
}
978979

979980
let added = params
@@ -982,11 +983,12 @@ impl GlobalState {
982983
.into_iter()
983984
.filter_map(|it| it.uri.to_file_path().ok())
984985
.filter_map(|it| AbsPathBuf::try_from(it).ok());
985-
config.workspace_roots.extend(added);
986-
if !config.has_linked_projects() && config.detached_files().is_empty() {
987-
config.rediscover_workspaces();
988-
this.fetch_workspaces_queue.request_op("client workspaces changed".to_string(), ())
989-
}
986+
config.add_workspaces(added);
987+
if !config.has_linked_projects() && config.detached_files().is_empty() {
988+
config.rediscover_workspaces();
989+
this.fetch_workspaces_queue
990+
.request_op("client workspaces changed".to_string(), ())
991+
}
990992

991993
Ok(())
992994
})?

crates/rust-analyzer/src/reload.rs

+14
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,20 @@ impl GlobalState {
212212
})
213213
.collect::<Vec<_>>();
214214

215+
let mut i = 0;
216+
while i < workspaces.len() {
217+
if let Ok(w) = &workspaces[i] {
218+
if let Some(dupe) = workspaces[i + 1..]
219+
.iter()
220+
.filter_map(|it| it.as_ref().ok())
221+
.position(|ws| ws.eq_ignore_build_data(w))
222+
{
223+
_ = workspaces.remove(dupe);
224+
}
225+
}
226+
i += 1;
227+
}
228+
215229
if !detached_files.is_empty() {
216230
workspaces.push(project_model::ProjectWorkspace::load_detached_files(
217231
detached_files,

crates/rust-analyzer/tests/slow-tests/support.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use std::{
99
use crossbeam_channel::{after, select, Receiver};
1010
use lsp_server::{Connection, Message, Notification, Request};
1111
use lsp_types::{notification::Exit, request::Shutdown, TextDocumentIdentifier, Url};
12-
use project_model::ProjectManifest;
1312
use rust_analyzer::{config::Config, lsp_ext, main_loop};
1413
use serde::Serialize;
1514
use serde_json::{json, to_string_pretty, Value};
@@ -101,10 +100,6 @@ impl<'a> Project<'a> {
101100
if roots.is_empty() {
102101
roots.push(tmp_dir_path.clone());
103102
}
104-
let discovered_projects = roots
105-
.into_iter()
106-
.map(|it| ProjectManifest::discover_single(&it).unwrap())
107-
.collect::<Vec<_>>();
108103

109104
let mut config = Config::new(
110105
tmp_dir_path,
@@ -144,10 +139,10 @@ impl<'a> Project<'a> {
144139
})),
145140
..Default::default()
146141
},
147-
Vec::new(),
142+
roots,
148143
);
149-
config.discovered_projects = Some(discovered_projects);
150144
config.update(self.config).expect("invalid config");
145+
config.rediscover_workspaces();
151146

152147
Server::new(tmp_dir, config)
153148
}

0 commit comments

Comments
 (0)