Skip to content

Commit ad028f2

Browse files
committed
feature: move linked_projects discovery to the rust-analyzer server
1 parent d4da3f9 commit ad028f2

File tree

19 files changed

+289
-72
lines changed

19 files changed

+289
-72
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/flycheck/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ command-group.workspace = true
2424
paths.workspace = true
2525
stdx.workspace = true
2626
toolchain.workspace = true
27+
project-model.workspace = true
2728

2829
[lints]
2930
workspace = true

crates/flycheck/src/json_workspace.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//! A `cargo-metadata`-equivalent for non-Cargo build systems.
2+
use std::{io, process::Command};
3+
4+
use crossbeam_channel::Sender;
5+
use paths::AbsPathBuf;
6+
use project_model::ProjectJsonData;
7+
use serde::{Deserialize, Serialize};
8+
9+
use crate::command::{CommandHandle, ParseFromLine};
10+
11+
/// A command wrapper for getting a `rust-project.json`.
12+
///
13+
/// This is analogous to `cargo-metadata`, but for non-Cargo build systems.
14+
pub struct JsonWorkspace {
15+
command: Vec<String>,
16+
sender: Sender<DiscoverProjectMessage>,
17+
}
18+
19+
impl JsonWorkspace {
20+
/// Create a new [JsonWorkspace].
21+
pub fn new(sender: Sender<DiscoverProjectMessage>, command: Vec<String>) -> Self {
22+
Self { sender, command }
23+
}
24+
25+
/// Spawn the command inside [JsonWorkspace] and report progress, if any.
26+
pub fn spawn(&self, files: Vec<AbsPathBuf>) -> io::Result<JsonWorkspaceHandle> {
27+
let command = &self.command[0];
28+
let args = &self.command[1..];
29+
let first_file: &AbsPathBuf = &files[0];
30+
31+
let mut cmd = Command::new(command);
32+
cmd.args(args);
33+
cmd.arg(first_file);
34+
35+
Ok(JsonWorkspaceHandle { _handle: CommandHandle::spawn(cmd, self.sender.clone())? })
36+
}
37+
}
38+
39+
/// A handle to a spawned [JsonWorkspace].
40+
#[derive(Debug)]
41+
pub struct JsonWorkspaceHandle {
42+
_handle: CommandHandle<DiscoverProjectMessage>,
43+
}
44+
45+
/// An enum containing either progress messages or the materialized rust-project.
46+
#[derive(Debug, Clone, Deserialize, Serialize)]
47+
#[serde(tag = "type")]
48+
pub enum DiscoverProjectMessage {
49+
Progress { message: String },
50+
Finished { project_json: Vec<ProjectJsonData> },
51+
}
52+
53+
impl ParseFromLine for DiscoverProjectMessage {
54+
fn from_line(line: &str, _error: &mut String) -> Option<Self> {
55+
let value = serde_json::from_str::<serde_json::Value>(&line).unwrap();
56+
57+
// let mut deserializer = serde_json::Deserializer::from_str(line);
58+
// deserializer.disable_recursion_limit();
59+
60+
if let Ok(project) = serde_json::from_value::<ProjectJsonData>(value.clone()) {
61+
return Some(DiscoverProjectMessage::Finished { project_json: vec![project] });
62+
}
63+
64+
if let Some(message) = value.pointer("/fields/message") {
65+
return Some(DiscoverProjectMessage::Progress {
66+
message: message.as_str().unwrap().to_owned(),
67+
});
68+
}
69+
70+
None
71+
}
72+
73+
fn from_eof() -> Option<Self> {
74+
None
75+
}
76+
}

crates/flycheck/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ pub use cargo_metadata::diagnostic::{
2222
use toolchain::Tool;
2323

2424
mod command;
25+
mod json_workspace;
2526
mod test_runner;
2627

2728
use command::{CommandHandle, ParseFromLine};
29+
pub use json_workspace::{DiscoverProjectMessage, JsonWorkspace, JsonWorkspaceHandle};
2830
pub use test_runner::{CargoTestHandle, CargoTestMessage, TestState};
2931

3032
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
@@ -227,7 +229,7 @@ enum Event {
227229
CheckEvent(Option<CargoCheckMessage>),
228230
}
229231

230-
const SAVED_FILE_PLACEHOLDER: &str = "$saved_file";
232+
pub const SAVED_FILE_PLACEHOLDER: &str = "$saved_file";
231233

232234
impl FlycheckActor {
233235
fn new(

crates/load-cargo/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use itertools::Itertools;
1717
use proc_macro_api::{MacroDylib, ProcMacroServer};
1818
use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace};
1919
use span::Span;
20-
use tracing::{instrument, Level};
20+
use tracing::Level;
2121
use vfs::{file_set::FileSetConfig, loader::Handle, AbsPath, AbsPathBuf, VfsPath};
2222

2323
pub struct LoadCargoConfig {
@@ -51,7 +51,6 @@ pub fn load_workspace_at(
5151
load_workspace(workspace, &cargo_config.extra_env, load_config)
5252
}
5353

54-
#[instrument(skip_all)]
5554
pub fn load_workspace(
5655
ws: ProjectWorkspace,
5756
extra_env: &FxHashMap<String, String>,

crates/project-model/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ doctest = false
1414
[dependencies]
1515
anyhow.workspace = true
1616
cargo_metadata.workspace = true
17+
crossbeam-channel.workspace = true
1718
rustc-hash.workspace = true
1819
semver.workspace = true
1920
serde_json.workspace = true

crates/project-model/src/project_json.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ impl ProjectJson {
175175

176176
#[derive(Serialize, Deserialize, Debug, Clone)]
177177
pub struct ProjectJsonData {
178-
sysroot: Option<Utf8PathBuf>,
178+
pub sysroot: Option<Utf8PathBuf>,
179179
sysroot_src: Option<Utf8PathBuf>,
180180
crates: Vec<CrateData>,
181181
}

crates/project-model/src/workspace.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use crate::{
3030
utf8_stdout, CargoConfig, CargoWorkspace, InvocationStrategy, ManifestPath, Package,
3131
ProjectJson, ProjectManifest, Sysroot, TargetData, TargetKind, WorkspaceBuildScripts,
3232
};
33+
use tracing::{info, Level, error, debug};
3334

3435
pub type FileLoader<'a> = &'a mut dyn for<'b> FnMut(&'b AbsPath) -> Option<FileId>;
3536

@@ -240,7 +241,7 @@ impl ProjectWorkspace {
240241
let sysroot_ref = sysroot.as_ref().ok();
241242

242243
if let Ok(sysroot) = &sysroot {
243-
tracing::info!(workspace = %cargo_toml, src_root = ?sysroot.src_root(), root = %sysroot.root(), "Using sysroot");
244+
info!(workspace = %cargo_toml, src_root = ?sysroot.src_root(), root = %sysroot.root(), "Using sysroot");
244245
}
245246

246247
let rustc_dir = match &config.rustc_source {
@@ -255,7 +256,7 @@ impl ProjectWorkspace {
255256
};
256257

257258
let rustc = rustc_dir.and_then(|rustc_dir| {
258-
tracing::info!(workspace = %cargo_toml, rustc_dir = %rustc_dir, "Using rustc source");
259+
info!(workspace = %cargo_toml, rustc_dir = %rustc_dir, "Using rustc source");
259260
match CargoWorkspace::fetch_metadata(
260261
&rustc_dir,
261262
cargo_toml.parent(),
@@ -356,6 +357,7 @@ impl ProjectWorkspace {
356357
) -> ProjectWorkspace {
357358
let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) {
358359
(Some(sysroot), Some(sysroot_src)) => {
360+
359361
Ok(Sysroot::load(sysroot, Some(Ok(sysroot_src)), false))
360362
}
361363
(Some(sysroot), None) => {
@@ -755,7 +757,7 @@ impl ProjectWorkspace {
755757
load: FileLoader<'_>,
756758
extra_env: &FxHashMap<String, String>,
757759
) -> (CrateGraph, ProcMacroPaths) {
758-
let _p = tracing::span!(tracing::Level::INFO, "ProjectWorkspace::to_crate_graph").entered();
760+
let _p = tracing::span!(tracing::Level::INFO, "to_crate_graph").entered();
759761

760762
let Self { kind, sysroot, cfg_overrides, rustc_cfg, .. } = self;
761763
let ((mut crate_graph, proc_macros), sysroot) = match kind {
@@ -814,9 +816,9 @@ impl ProjectWorkspace {
814816
if matches!(sysroot.as_ref().map(|it| it.mode()), Ok(SysrootMode::Stitched(_)))
815817
&& crate_graph.patch_cfg_if()
816818
{
817-
tracing::debug!("Patched std to depend on cfg-if")
819+
debug!("Patched std to depend on cfg-if")
818820
} else {
819-
tracing::debug!("Did not patch std to depend on cfg-if")
821+
debug!("Did not patch std to depend on cfg-if")
820822
}
821823
(crate_graph, proc_macros)
822824
}
@@ -962,6 +964,11 @@ fn project_json_to_crate_graph(
962964
CrateOrigin::Local { repo: None, name: None }
963965
},
964966
);
967+
debug!(
968+
?crate_graph_crate_id,
969+
crate = display_name.as_ref().map(|name| name.canonical_name()),
970+
"added root to crate graph"
971+
);
965972
if *is_proc_macro {
966973
if let Some(path) = proc_macro_dylib_path.clone() {
967974
let node = Ok((
@@ -976,6 +983,7 @@ fn project_json_to_crate_graph(
976983
)
977984
.collect();
978985

986+
debug!(map = ?idx_to_crate_id);
979987
for (from_idx, krate) in project.crates() {
980988
if let Some(&from) = idx_to_crate_id.get(&from_idx) {
981989
if let Some((public_deps, libproc_macro)) = &sysroot_deps {
@@ -1004,7 +1012,7 @@ fn cargo_to_crate_graph(
10041012
override_cfg: &CfgOverrides,
10051013
build_scripts: &WorkspaceBuildScripts,
10061014
) -> (CrateGraph, ProcMacroPaths) {
1007-
let _p = tracing::span!(tracing::Level::INFO, "cargo_to_crate_graph").entered();
1015+
let _p = tracing::span!(Level::INFO, "cargo_to_crate_graph").entered();
10081016
let mut res = (CrateGraph::default(), ProcMacroPaths::default());
10091017
let crate_graph = &mut res.0;
10101018
let proc_macros = &mut res.1;
@@ -1191,7 +1199,7 @@ fn detached_file_to_crate_graph(
11911199
sysroot: Option<&Sysroot>,
11921200
override_cfg: &CfgOverrides,
11931201
) -> (CrateGraph, ProcMacroPaths) {
1194-
let _p = tracing::span!(tracing::Level::INFO, "detached_file_to_crate_graph").entered();
1202+
let _p = tracing::span!(Level::INFO, "detached_file_to_crate_graph").entered();
11951203
let mut crate_graph = CrateGraph::default();
11961204
let (public_deps, _libproc_macro) = match sysroot {
11971205
Some(sysroot) => sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load),
@@ -1207,7 +1215,7 @@ fn detached_file_to_crate_graph(
12071215
let file_id = match load(detached_file) {
12081216
Some(file_id) => file_id,
12091217
None => {
1210-
tracing::error!("Failed to load detached file {:?}", detached_file);
1218+
error!("Failed to load detached file {:?}", detached_file);
12111219
return (crate_graph, FxHashMap::default());
12121220
}
12131221
};
@@ -1404,7 +1412,7 @@ fn add_target_crate_root(
14041412
crate_id
14051413
}
14061414

1407-
#[derive(Default)]
1415+
#[derive(Default, Debug)]
14081416
struct SysrootPublicDeps {
14091417
deps: Vec<(CrateName, CrateId, bool)>,
14101418
}

crates/rust-analyzer/src/bin/main.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ fn run_server() -> anyhow::Result<()> {
172172
return Err(e.into());
173173
}
174174
};
175+
175176
tracing::info!("InitializeParams: {}", initialize_params);
176177
let lsp_types::InitializeParams {
177178
root_uri,
@@ -221,6 +222,7 @@ fn run_server() -> anyhow::Result<()> {
221222
.unwrap_or_else(|| vec![root_path.clone()]);
222223
let mut config =
223224
Config::new(root_path, capabilities, workspace_roots, visual_studio_code_version);
225+
224226
if let Some(json) = initialization_options {
225227
if let Err(e) = config.update(json) {
226228
use lsp_types::{
@@ -255,8 +257,10 @@ fn run_server() -> anyhow::Result<()> {
255257
return Err(e.into());
256258
}
257259

258-
if !config.has_linked_projects() && config.detached_files().is_empty() {
259-
config.rediscover_workspaces();
260+
if config.discover_command().is_none() {
261+
if !config.has_linked_projects() && config.detached_files().is_empty() {
262+
config.rediscover_workspaces();
263+
}
260264
}
261265

262266
// If the io_threads have an error, there's usually an error on the main

0 commit comments

Comments
 (0)