Skip to content

Commit cc8dce5

Browse files
committed
Make the public api just "here's a list of source roots and a project root"
1 parent 575ebbc commit cc8dce5

File tree

1 file changed

+104
-53
lines changed
  • crates/rust-analyzer/src/config

1 file changed

+104
-53
lines changed

crates/rust-analyzer/src/config/tree.rs

Lines changed: 104 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
use itertools::Itertools;
12
use rustc_hash::{FxHashMap, FxHashSet};
23
use std::sync::Arc;
3-
use vfs::{FileId, Vfs};
4+
use vfs::{AbsPathBuf, FileId, Vfs};
45

56
use super::{ConfigInput, LocalConfigData, RootLocalConfigData};
67

@@ -15,12 +16,23 @@ pub enum ConfigTreeError {
1516

1617
/// Some rust-analyzer.toml files have changed, and/or the LSP client sent a new configuration.
1718
pub struct ConfigChanges {
19+
/// - `None` => no change
20+
/// - `Some(None)` => the client config was removed / reset or something
21+
/// - `Some(Some(...))` => the client config was updated
22+
client_change: Option<Option<Arc<ConfigInput>>>,
23+
set_project_root: Option<AbsPathBuf>,
24+
set_source_roots: Option<FxHashSet<AbsPathBuf>>,
1825
ra_toml_changes: Vec<vfs::ChangedFile>,
26+
}
27+
28+
/// Internal version
29+
struct ConfigChangesInner {
1930
/// - `None` => no change
2031
/// - `Some(None)` => the client config was removed / reset or something
2132
/// - `Some(Some(...))` => the client config was updated
2233
client_change: Option<Option<Arc<ConfigInput>>>,
2334
parent_changes: FxHashMap<FileId, ConfigParent>,
35+
ra_toml_changes: Vec<vfs::ChangedFile>,
2436
}
2537

2638
#[derive(Debug)]
@@ -140,16 +152,20 @@ pub struct ConfigDb {
140152
storage: salsa::Storage<Self>,
141153
known_file_ids: FxHashSet<FileId>,
142154
xdg_config_file_id: FileId,
155+
source_roots: FxHashSet<AbsPathBuf>,
156+
project_root: AbsPathBuf,
143157
}
144158

145159
impl salsa::Database for ConfigDb {}
146160

147161
impl ConfigDb {
148-
pub fn new(xdg_config_file_id: FileId) -> Self {
162+
pub fn new(xdg_config_file_id: FileId, project_root: AbsPathBuf) -> Self {
149163
let mut this = Self {
150164
storage: Default::default(),
151165
known_file_ids: FxHashSet::default(),
152166
xdg_config_file_id,
167+
source_roots: FxHashSet::default(),
168+
project_root,
153169
};
154170
this.set_client_config(None);
155171
this.ensure_node(xdg_config_file_id);
@@ -176,12 +192,68 @@ impl ConfigDb {
176192
}
177193

178194
/// Applies a bunch of [`ConfigChanges`]. The FileIds referred to in `ConfigChanges` do not
179-
/// need to exist. You can generate the `parent_changes` hashmap by iterating ancestors of all
180-
/// of the [`ide::SourceRoot`]s, slapping `.map(|path| path.join("rust-analyzer.toml"))`.
181-
pub fn apply_changes(&mut self, changes: ConfigChanges, vfs: &Vfs) -> Vec<ConfigTreeError> {
195+
/// need to exist.
196+
pub fn apply_changes(&mut self, changes: ConfigChanges, vfs: &mut Vfs) -> Vec<ConfigTreeError> {
197+
if let Some(new_project_root) = &changes.set_project_root {
198+
self.project_root = new_project_root.clone();
199+
}
200+
let source_root_change = changes.set_source_roots.as_ref().or_else(|| {
201+
if changes.set_project_root.is_some() {
202+
Some(&self.source_roots)
203+
} else {
204+
None
205+
}
206+
});
207+
let parent_changes = if let Some(source_roots) = source_root_change {
208+
source_roots
209+
.iter()
210+
.flat_map(|path: &AbsPathBuf| {
211+
path.ancestors()
212+
.take_while(|x| x.starts_with(&self.project_root))
213+
.map(|dir| dir.join("rust-analyzer.toml"))
214+
.map(|path| vfs.alloc_file_id(path.into()))
215+
.collect_vec()
216+
// immediately get tuple_windows before returning from flat_map
217+
.into_iter()
218+
.tuple_windows()
219+
.map(|(a, b)| (a, ConfigParent::Parent(b)))
220+
})
221+
.collect::<FxHashMap<_, _>>()
222+
} else {
223+
Default::default()
224+
};
225+
226+
if tracing::enabled!(tracing::Level::TRACE) {
227+
for (&a, parent) in &parent_changes {
228+
tracing::trace!(
229+
"{a:?} ({:?}): parent = {parent:?} ({:?})",
230+
vfs.file_path(a),
231+
match parent {
232+
ConfigParent::Parent(p) => vfs.file_path(*p).to_string(),
233+
ConfigParent::UserDefault => "xdg".to_string(),
234+
}
235+
);
236+
}
237+
}
238+
239+
// Could delete (self.known_file_ids - parent_changes.keys) here.
240+
241+
let inner = ConfigChangesInner {
242+
ra_toml_changes: changes.ra_toml_changes,
243+
client_change: changes.client_change,
244+
parent_changes,
245+
};
246+
self.apply_changes_inner(inner, vfs)
247+
}
248+
249+
fn apply_changes_inner(
250+
&mut self,
251+
changes: ConfigChangesInner,
252+
vfs: &Vfs,
253+
) -> Vec<ConfigTreeError> {
182254
let mut scratch_errors = Vec::new();
183255
let mut errors = Vec::new();
184-
let ConfigChanges { client_change, ra_toml_changes, parent_changes } = changes;
256+
let ConfigChangesInner { client_change, ra_toml_changes, parent_changes } = changes;
185257

186258
if let Some(change) = client_change {
187259
let current = self.client_config();
@@ -285,7 +357,7 @@ mod tests {
285357
use std::path::{Path, PathBuf};
286358

287359
use itertools::Itertools;
288-
use vfs::{AbsPathBuf, VfsPath};
360+
use vfs::{AbsPath, AbsPathBuf, VfsPath};
289361

290362
fn alloc_file_id(vfs: &mut Vfs, s: &str) -> FileId {
291363
let abs_path = AbsPathBuf::try_from(PathBuf::new().join(s)).unwrap();
@@ -310,11 +382,14 @@ mod tests {
310382
fn basic() {
311383
tracing_subscriber::fmt().try_init().ok();
312384
let mut vfs = Vfs::default();
385+
let project_root = AbsPath::assert(Path::new("/root"));
313386
let xdg_config_file_id =
314387
alloc_file_id(&mut vfs, "/home/username/.config/rust-analyzer/rust-analyzer.toml");
315-
let mut config_tree = ConfigDb::new(xdg_config_file_id);
388+
let mut config_tree = ConfigDb::new(xdg_config_file_id, project_root.to_path_buf());
389+
390+
let source_roots = ["/root/crate_a"].map(Path::new).map(AbsPath::assert);
316391

317-
let root = alloc_config(
392+
let _root = alloc_config(
318393
&mut vfs,
319394
"/root/rust-analyzer.toml",
320395
r#"
@@ -335,13 +410,12 @@ mod tests {
335410
"#,
336411
);
337412

338-
let mut parent_changes = FxHashMap::default();
339-
parent_changes.insert(crate_a, ConfigParent::Parent(root));
340-
413+
let new_source_roots = source_roots.into_iter().map(|abs| abs.to_path_buf()).collect();
341414
let changes = ConfigChanges {
342415
// Normally you will filter these!
343416
ra_toml_changes: vfs.take_changes(),
344-
parent_changes,
417+
set_project_root: None,
418+
set_source_roots: Some(new_source_roots),
345419
client_change: Some(Some(Arc::new(ConfigInput {
346420
local: crate::config::LocalConfigInput {
347421
semanticHighlighting_strings_enable: Some(false),
@@ -351,7 +425,7 @@ mod tests {
351425
}))),
352426
};
353427

354-
dbg!(config_tree.apply_changes(changes, &vfs));
428+
dbg!(config_tree.apply_changes(changes, &mut vfs));
355429

356430
let local = config_tree.local_config(crate_a);
357431
// from root
@@ -384,11 +458,12 @@ mod tests {
384458
);
385459

386460
let changes = ConfigChanges {
387-
ra_toml_changes: dbg!(vfs.take_changes()),
388-
parent_changes: Default::default(),
389461
client_change: None,
462+
set_project_root: None,
463+
set_source_roots: None,
464+
ra_toml_changes: dbg!(vfs.take_changes()),
390465
};
391-
dbg!(config_tree.apply_changes(changes, &vfs));
466+
dbg!(config_tree.apply_changes(changes, &mut vfs));
392467

393468
let prev = local;
394469
let local = config_tree.local_config(crate_a);
@@ -410,67 +485,43 @@ mod tests {
410485
}
411486

412487
#[test]
413-
fn generated_parent_changes() {
488+
fn set_source_roots() {
414489
tracing_subscriber::fmt().try_init().ok();
415490
let mut vfs = Vfs::default();
416491

492+
let project_root = AbsPath::assert(Path::new("/root"));
417493
let xdg =
418494
alloc_file_id(&mut vfs, "/home/username/.config/rust-analyzer/rust-analyzer.toml");
419-
let mut config_tree = ConfigDb::new(xdg);
495+
let mut config_tree = ConfigDb::new(xdg, project_root.to_path_buf());
420496

421-
let project_root = Path::new("/root");
422-
let sourceroots =
423-
[PathBuf::new().join("/root/crate_a"), PathBuf::new().join("/root/crate_a/crate_b")];
424-
let sourceroot_tomls = sourceroots
497+
let source_roots =
498+
["/root/crate_a", "/root/crate_a/crate_b"].map(Path::new).map(AbsPath::assert);
499+
let source_root_tomls = source_roots
425500
.iter()
426501
.map(|dir| dir.join("rust-analyzer.toml"))
427502
.map(|path| AbsPathBuf::try_from(path).unwrap())
428503
.map(|path| vfs.alloc_file_id(path.into()))
429504
.collect_vec();
430-
let &[crate_a, crate_b] = &sourceroot_tomls[..] else {
505+
let &[crate_a, crate_b] = &source_root_tomls[..] else {
431506
panic!();
432507
};
433508

434-
let parent_changes = sourceroots
435-
.iter()
436-
.flat_map(|path| {
437-
path.ancestors()
438-
.take_while(|x| x.starts_with(project_root))
439-
.map(|dir| dir.join("rust-analyzer.toml"))
440-
.map(|path| AbsPathBuf::try_from(path).unwrap())
441-
.map(|path| vfs.alloc_file_id(path.into()))
442-
.collect_vec()
443-
.into_iter()
444-
.tuple_windows()
445-
.map(|(a, b)| (a, ConfigParent::Parent(b)))
446-
})
447-
.collect::<FxHashMap<_, _>>();
448-
449-
for (&a, parent) in &parent_changes {
450-
eprintln!(
451-
"{a:?} ({:?}): parent = {parent:?} ({:?})",
452-
vfs.file_path(a),
453-
match parent {
454-
ConfigParent::Parent(p) => vfs.file_path(*p).to_string(),
455-
ConfigParent::UserDefault => "xdg".to_string(),
456-
}
457-
);
458-
}
459-
460509
vfs.set_file_id_contents(
461510
xdg,
462511
Some(b"[inlayHints.discriminantHints]\nenable = \"always\"".to_vec()),
463512
);
464513
vfs.set_file_id_contents(crate_a, Some(b"[completion.autoself]\nenable = false".to_vec()));
465514
// note that crate_b's rust-analyzer.toml doesn't exist
466515

516+
let new_source_roots = source_roots.into_iter().map(|abs| abs.to_path_buf()).collect();
467517
let changes = ConfigChanges {
468-
ra_toml_changes: dbg!(vfs.take_changes()),
469-
parent_changes,
470518
client_change: None,
519+
set_project_root: None, // already set in ConfigDb::new(...)
520+
set_source_roots: Some(new_source_roots),
521+
ra_toml_changes: dbg!(vfs.take_changes()),
471522
};
472523

473-
dbg!(config_tree.apply_changes(changes, &vfs));
524+
dbg!(config_tree.apply_changes(changes, &mut vfs));
474525
let local = config_tree.local_config(crate_b);
475526

476527
assert_eq!(

0 commit comments

Comments
 (0)