Skip to content

Commit

Permalink
use cargo to run rustdoc for all crates in workspace, use RUSTDOCFLAG…
Browse files Browse the repository at this point in the history
…S instead of running cargo rustdoc
  • Loading branch information
wfraser committed Nov 25, 2023
1 parent 85c994e commit 79e94d9
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 68 deletions.
119 changes: 65 additions & 54 deletions src/analysis.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::collections::HashMap;
use std::fs::{self, File};
use std::iter;
use std::path::{Path, PathBuf};
use std::process::Command;

Expand All @@ -11,21 +11,22 @@ pub type Id = rustdoc_types::Id;
const SUBDIR: &str = "rsbrowse";

pub struct Analysis {
pub krate: rustdoc_types::Crate,
pub crates: HashMap<String, rustdoc_types::Crate>,
}

impl Analysis {
pub fn generate(workspace_path: impl AsRef<Path>, compiler: &str) -> anyhow::Result<()> {
let cargo_status = Command::new("cargo")
.arg(format!("+{compiler}"))
.arg("rustdoc")
.arg("doc")
.arg("--target-dir")
.arg(Path::new("target").join(SUBDIR))
.arg("--")
.arg("-Zunstable-options")
.arg("--output-format=json")
.arg("--document-private-items")
.arg("--document-hidden-items")
.arg("--workspace")
.env("RUSTDOCFLAGS", "-Zunstable-options \
--output-format=json \
--document-private-items \
--document-hidden-items \
")
.current_dir(workspace_path)
.status()
.context("failed to run 'cargo rustdoc'")?;
Expand All @@ -42,62 +43,61 @@ impl Analysis {

pub fn load(workspace_path: impl Into<PathBuf>) -> anyhow::Result<Self> {
let root: PathBuf = workspace_path.into().join("target").join(SUBDIR).join("doc");
let json_path = fs::read_dir(&root)?
/*.try_find(|entry| {
Ok(entry?.file_name().as_encoded_bytes().ends_with(b".json"))
})?*/
.find_map(|r| {
let entry = match r {
Ok(v) => v,
Err(e) => return Some(Err(e)),
};
if entry.file_name().as_encoded_bytes().ends_with(b".json") {
Some(Ok(entry))
} else {
None
}
})
.transpose()?
.ok_or_else(|| anyhow::anyhow!("no json files found"))?
.path();
let krate = parse_json(&json_path)
.with_context(|| json_path.display().to_string())?;
Ok(Self { krate })
let mut crates = HashMap::new();
for res in fs::read_dir(&root)? {
let entry = res?;
if entry.file_name().as_encoded_bytes().ends_with(b".json") {
let path = entry.path();
let crate_name = path.file_stem().unwrap().to_str()
.ok_or_else(|| anyhow::anyhow!("{path:?} isn't utf-8"))?
.to_owned();
println!("reading {path:?}");
let data = parse_json(&path)
.with_context(|| path.display().to_string())?;
crates.insert(crate_name, data);
}
}
Ok(Self { crates })
}

pub fn crate_ids(&self) -> impl Iterator<Item=CrateId> + '_ {
let my_name = self.krate.index.iter()
.find_map(|(_id, item)| {
/*let mut ids = vec![];
for c in self.crates.values() {
let name = c.index.iter()
.find_map(|(_id, item)| {
match &item.inner {
rustdoc_types::ItemEnum::Module(m) if m.is_crate && item.crate_id == 0 => {
Some(item.name.clone().expect("crate module should have a name"))
}
_ => None
}
})
.expect("should have an index item for the local crate");
ids.push(CrateId { name });
}*/

self.crates.values()
.flat_map(|crate_| &crate_.index)
.filter_map(|(_id, item)| {
match &item.inner {
rustdoc_types::ItemEnum::Module(m) if m.is_crate && item.crate_id == 0 => {
Some(item.name.clone().expect("crate module should have a name"))
let name = item.name.clone().expect("crate module should have a name");
Some(CrateId { name })
}
_ => None
}
})
.expect("should have an index item for the local crate");

let myself = CrateId {
name: my_name,
id: 0,
};

let others = self.krate.external_crates.iter()
.map(|(&id, ext)| {
CrateId {
name: ext.name.clone(),
id,
}
});

iter::once(myself).chain(others)
//ids.into_iter()
}

pub fn items<'a>(&'a self, crate_id: &'a CrateId, parent_id: Option<Id>)
-> impl Iterator<Item = &'a rustdoc_types::Item> + 'a
{
let parent_id = parent_id.unwrap_or(self.krate.root.clone());
let parent = &self.krate.index[&parent_id];
let parent_id = parent_id.unwrap_or(self.crates[&crate_id.name].root.clone());
let parent = &self.crates[&crate_id.name].index[&parent_id];

use rustdoc_types::ItemEnum::*;
let children = match &parent.inner {
Expand All @@ -115,14 +115,25 @@ impl Analysis {
}
StructField(_) => vec![],
Enum(e) => [&e.variants[..], &e.impls[..]].concat(),
Variant(_) => vec![],
Variant(v) => match &v.kind {
rustdoc_types::VariantKind::Plain => vec![],
rustdoc_types::VariantKind::Tuple(t) => t.iter().filter_map(|id| id.clone()).collect(),
rustdoc_types::VariantKind::Struct { fields, .. } => fields.clone(),
},
Function(_) => vec![],
Trait(t) => {
// TODO: also include impls?
// TODO: also find impls?
t.items.clone()
}
TraitAlias(_) => vec![],
Impl(i) => i.items.clone(),
Impl(i) => {
let mut items = i.items.clone();
// Add a reference to the trait itself too if it's not an inherent impl:
if let Some(trait_) = &i.trait_ {
items.push(trait_.id.clone());
}
items
},
TypeAlias(_) => vec![],
OpaqueTy(_) => vec![],
Constant(_) => vec![],
Expand All @@ -135,7 +146,7 @@ impl Analysis {
AssocType { .. } => vec![],
};

self.krate.index.iter()
self.crates[&crate_id.name].index.iter()
.filter_map(move |(id, item)| {
if children.contains(id) {
Some(item)
Expand All @@ -155,7 +166,7 @@ fn parse_json(p: &Path) -> anyhow::Result<rustdoc_types::Crate> {
#[derive(Debug, Clone)]
pub struct CrateId {
pub name: String,
pub id: u32,
//pub id: u32,
}

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
Expand Down
21 changes: 7 additions & 14 deletions src/browser_rustdoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ impl Browser for RustdocBrowser {
fn get_info(&self, crate_id: &CrateId, item: &Item) -> String {
let mut txt = String::new();
match item {
Item::Item(item) /*| Item::ExternalDef(_, def)*/ => {
Item::Item(item) => {
if let Some(docs) = &item.docs {
txt += &docs;
txt.push('\n');
Expand All @@ -70,14 +70,10 @@ impl Browser for RustdocBrowser {

fn get_source(&self, item: &Item) -> (String, Option<usize>) {
match item {
Item::Item(item) /*| Item::ExternalDef(_, def)*/ => {
Item::Item(item) => {
let (txt, line) = get_source_for_item(item);
(txt, Some(line))
}
/*Item::Impl(imp) => {
let id = imp.trait_id.unwrap_or(imp.impl_on);
(format!("source listing unimplemented for impls. impl ID = {id:?}"), None)
}*/
Item::Root => (String::new(), None),
}
}
Expand Down Expand Up @@ -139,10 +135,10 @@ fn item_label(item: &rustdoc_types::Item) -> String {
Struct(_) => "struct",
StructField(f) => return format!("{}: {}", name, type_label(&f)),
Enum(_) => "enum",
Variant(_) => todo!(),
Function(_) => "fn", // TODO: include signature
Variant(_) => "enum variant",
Function(_) => "fn", // TODO: include signature?
Trait(_) => "trait",
TraitAlias(_) => todo!(),
TraitAlias(_) => "trait alias",
Impl(i) => {
let name = type_label(&i.for_);
return if let Some(trait_) = &i.trait_ {
Expand All @@ -152,7 +148,7 @@ fn item_label(item: &rustdoc_types::Item) -> String {
};
}
TypeAlias(_) => "type",
OpaqueTy(_) => todo!(),
OpaqueTy(_) => "opaque type",
Constant(c) => return format!("const {}: {}", name, c.expr),
Static(s) => return format!("static {}: {}", name, s.expr),
ForeignType => "extern type",
Expand Down Expand Up @@ -217,10 +213,7 @@ fn type_label(ty: &rustdoc_types::Type) -> String {
#[derive(Debug, Clone)]
pub enum Item {
Root,
//Def(rls_data::Def),
Item(rustdoc_types::Item)
//ExternalDef(CrateId, rls_data::Def),
//Impl(ImplDetails),
Item(rustdoc_types::Item),
}

impl browser_trait::Item for Item {
Expand Down

0 comments on commit 79e94d9

Please sign in to comment.