Skip to content

Commit

Permalink
load stdlib crates!
Browse files Browse the repository at this point in the history
  • Loading branch information
wfraser committed Nov 28, 2023
1 parent f5934ea commit 95403bd
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 13 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rsbrowse"
version = "0.2.1"
version = "0.2.2"
authors = ["William R. Fraser <wfraser@codewise.org>"]
description = "an interactive browser for the contents of Rust crates"
edition = "2021"
Expand Down
73 changes: 65 additions & 8 deletions src/analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ impl Analysis {
cmd.arg(format!("+{toolchain}"));
}

let workspace_path = workspace_path.as_ref();

let cargo_status = cmd
.arg("doc")
.arg("--target-dir")
Expand All @@ -59,15 +61,14 @@ impl Analysis {
anyhow::bail!("'cargo build' killed by signal");
}
}

copy_stdlib_json(workspace_path, toolchain).context("copying stdlib analysis")?;

Ok(())
}

pub fn load(workspace_path: impl Into<PathBuf>) -> anyhow::Result<Self> {
let root: PathBuf = workspace_path
.into()
.join("target")
.join(SUBDIR)
.join("doc");
let root = json_root(&workspace_path.into());
let mut paths = vec![];
for res in fs::read_dir(root)? {
let entry = res?;
Expand Down Expand Up @@ -241,11 +242,20 @@ impl Analysis {
}
}

pub fn get_path<'a>(&'a self, id: ItemId<'a>) -> &'a [String] {
pub fn get_path<'a>(&'a self, id: ItemId<'a>, name_hint: &str) -> Option<&'a [String]> {
if id == EMPTY_ITEM_ID {
return &[];
return None;
}
&self.crates[id.0.name].paths[id.1].path[..]
Some(
&self.crates[id.0.name]
.paths
.get(id.1)
.or_else(|| {
eprintln!("missing path for {id:?} ({name_hint})");
None
})?
.path[..],
)
}
}

Expand Down Expand Up @@ -289,6 +299,53 @@ pub fn type_ids(ty: &rustdoc_types::Type) -> Vec<&rustdoc_types::Id> {
}
}

fn json_root(workspace_path: &Path) -> PathBuf {
workspace_path.join("target").join(SUBDIR).join("doc")
}

fn get_stdlib_analysis_path(toolchain: Option<&str>) -> anyhow::Result<PathBuf> {
let mut cmd = Command::new("rustc");
if let Some(toolchain) = toolchain {
cmd.arg(format!("+{toolchain}"));
}

let out = cmd
.arg("--print")
.arg("sysroot")
.output()
.context("Error running 'rustc --print sysroot'")?;

if !out.status.success() {
let mut msg = format!("Error running 'rustc --print sysroot': {}", out.status).into_bytes();
msg.extend(b"\nCommand stderr: ");
msg.extend(&out.stderr);
anyhow::bail!(String::from_utf8_lossy(&msg).into_owned());
}

let path = String::from_utf8(out.stdout).context("'rustc --print sysroot' output")?;

Ok(PathBuf::from(path.trim())
.join("share")
.join("doc")
.join("rust")
.join("json"))
}

fn copy_stdlib_json(workspace_path: &Path, toolchain: Option<&str>) -> anyhow::Result<()> {
let src = get_stdlib_analysis_path(toolchain)?;
let dst = json_root(workspace_path);
for res in fs::read_dir(&src).with_context(|| src.display().to_string())? {
let entry = res?;
if entry.file_name().as_encoded_bytes().ends_with(b".json") {
let src_path = entry.path();
println!("copying {:?}", entry.file_name());
fs::copy(&src_path, dst.join(entry.file_name()))
.with_context(|| format!("copy {src_path:?}"))?;
}
}
Ok(())
}

#[derive(Debug, Clone, PartialEq)]
pub struct CrateId<'a> {
pub name: &'a String,
Expand Down
17 changes: 14 additions & 3 deletions src/browser_rustdoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,25 @@ impl RustdocBrowser {
TraitAlias(_) => "trait alias",
Impl(i) => {
return if let Some(trait_) = &i.trait_ {
let full_path = self.analysis.get_path(id.crate_sibling(&trait_.id));
let mut trait_name = if full_path[0] == id.crate_name() {
let path = self
.analysis
.get_path(id.crate_sibling(&trait_.id), &trait_.name);

/* requires #![feature(let_chains)]
let mut trait_name = if let Some(path) = path && path[0] != id.crate_name() {
path.join("::")
} else {
trait_.name.clone()
};*/
#[allow(clippy::unnecessary_unwrap)] // until if-let chains are stabilized
let mut trait_name = if path.is_none() || path.unwrap()[0] == id.crate_name() {
// trait in local crate, use trait name
trait_.name.clone()
} else {
// trait in foreign crate, use full path
full_path.join("::")
path.unwrap().join("::")
};

if let Some(g) = &trait_.args {
trait_name.push_str(&generic_label(g));
}
Expand Down

0 comments on commit 95403bd

Please sign in to comment.