Skip to content

Commit

Permalink
feat: Make rust-analyzer work partially when missing an internet conn…
Browse files Browse the repository at this point in the history
…ection
  • Loading branch information
Veykril committed Aug 17, 2024
1 parent 0765978 commit b2abbf8
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 13 deletions.
35 changes: 33 additions & 2 deletions crates/project-model/src/cargo_workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,18 @@ impl CargoWorkspace {
sysroot: &Sysroot,
locked: bool,
progress: &dyn Fn(String),
) -> anyhow::Result<cargo_metadata::Metadata> {
Self::fetch_metadata_(cargo_toml, current_dir, config, sysroot, locked, false, progress)
}

fn fetch_metadata_(
cargo_toml: &ManifestPath,
current_dir: &AbsPath,
config: &CargoConfig,
sysroot: &Sysroot,
locked: bool,
no_deps: bool,
progress: &dyn Fn(String),
) -> anyhow::Result<cargo_metadata::Metadata> {
let targets = find_list_of_build_targets(config, cargo_toml, sysroot);

Expand Down Expand Up @@ -314,6 +326,9 @@ impl CargoWorkspace {
if locked {
other_options.push("--locked".to_owned());
}
if no_deps {
other_options.push("--no-deps".to_owned());
}
meta.other_options(other_options);

// FIXME: Fetching metadata is a slow process, as it might require
Expand All @@ -324,6 +339,22 @@ impl CargoWorkspace {
(|| -> Result<cargo_metadata::Metadata, cargo_metadata::Error> {
let output = meta.cargo_command().output()?;
if !output.status.success() {
if !no_deps {
// If we failed to fetch metadata with deps, try again without them.
// This makes r-a still work partially when offline.
if let Ok(metadata) = Self::fetch_metadata_(
cargo_toml,
current_dir,
config,
sysroot,
locked,
true,
progress,
) {
return Ok(metadata);
}
}

return Err(cargo_metadata::Error::CargoMetadata {
stderr: String::from_utf8(output.stderr)?,
});
Expand Down Expand Up @@ -431,8 +462,8 @@ impl CargoWorkspace {
pkg_data.targets.push(tgt);
}
}
let resolve = meta.resolve.expect("metadata executed with deps");
for mut node in resolve.nodes {
let nodes = meta.resolve.map_or_else(Vec::new, |it| it.nodes);
for mut node in nodes {
let &source = pkg_by_id.get(&node.id).unwrap();
node.deps.sort_by(|a, b| a.pkg.cmp(&b.pkg));
let dependencies = node
Expand Down
23 changes: 12 additions & 11 deletions crates/project-model/src/sysroot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,18 +372,19 @@ impl Sysroot {
.flatten()
};

let resolve = res.resolve.as_mut().expect("metadata executed with deps");
resolve.nodes.retain_mut(|node| {
// Replace `rustc-std-workspace` crate with the actual one in the dependency list
node.deps.iter_mut().for_each(|dep| {
let real_pkg = patches.clone().find(|((_, fake_id), _)| *fake_id == dep.pkg);
if let Some((_, real)) = real_pkg {
dep.pkg = real;
}
if let Some(resolve) = res.resolve.as_mut() {
resolve.nodes.retain_mut(|node| {
// Replace `rustc-std-workspace` crate with the actual one in the dependency list
node.deps.iter_mut().for_each(|dep| {
let real_pkg = patches.clone().find(|((_, fake_id), _)| *fake_id == dep.pkg);
if let Some((_, real)) = real_pkg {
dep.pkg = real;
}
});
// Remove this node if it's a fake one
!patches.clone().any(|((_, fake), _)| fake == node.id)
});
// Remove this node if it's a fake one
!patches.clone().any(|((_, fake), _)| fake == node.id)
});
}
// Remove the fake ones from the package list
patches.map(|((idx, _), _)| idx).sorted().rev().for_each(|idx| {
res.packages.remove(idx);
Expand Down

0 comments on commit b2abbf8

Please sign in to comment.