Skip to content

Commit a13d2be

Browse files
list_crate_items appears to work!
1 parent 58b7680 commit a13d2be

File tree

3 files changed

+91
-15
lines changed

3 files changed

+91
-15
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ html2md = "0.2.14"
4949
regex = "1"
5050
syn = { version = "2.0.104", features = ["full"] }
5151
flate2 = "1.1.2"
52+
tar = "0.4.44"
5253

5354
[dev-dependencies]
5455
# Testing utilities

src/tools/item_list.rs

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use std::path::Path;
55
use tar::Archive;
66
use flate2::read::GzDecoder;
77
use syn::{File, Item};
8-
use tokio::fs as tokio_fs;
98

109
/// Represents filters for item listing.
1110
#[derive(Debug)]
@@ -46,24 +45,65 @@ pub async fn list_crate_items(
4645
let crate_path = download_and_cache_crate(crate_name, version).await?;
4746
let mut items = Vec::new();
4847

49-
for entry in fs::read_dir(crate_path)? {
50-
let entry = entry?;
51-
let path = entry.path();
52-
if path.extension().and_then(|ext| ext.to_str()) == Some("rs") {
53-
let content = fs::read_to_string(&path)?;
54-
let parsed_file: File = syn::parse_file(&content)?;
48+
// Most crates have their source in a "src" subdirectory
49+
let src_path = Path::new(&crate_path).join("src");
5550

56-
for item in parsed_file.items {
57-
match item {
58-
Item::Struct(_) if filters.as_ref().map_or(true, |f| f.item_type.as_deref() == Some("struct")) => items.push(format!("{:?}", item)),
59-
Item::Enum(_) if filters.as_ref().map_or(true, |f| f.item_type.as_deref() == Some("enum")) => items.push(format!("{:?}", item)),
60-
Item::Trait(_) if filters.as_ref().map_or(true, |f| f.item_type.as_deref() == Some("trait")) => items.push(format!("{:?}", item)),
61-
Item::Fn(_) if filters.as_ref().map_or(true, |f| f.item_type.as_deref() == Some("fn")) => items.push(format!("{:?}", item)),
62-
_ => {}
51+
fn visit_rs_files<F: FnMut(&Path)>(dir: &Path, cb: &mut F) {
52+
if let Ok(entries) = fs::read_dir(dir) {
53+
for entry in entries.flatten() {
54+
let path = entry.path();
55+
if path.is_dir() {
56+
visit_rs_files(&path, cb);
57+
} else if path.extension().and_then(|ext| ext.to_str()) == Some("rs") {
58+
cb(&path);
6359
}
6460
}
6561
}
6662
}
6763

68-
Ok(items.join("\n"))
64+
visit_rs_files(&src_path, &mut |path: &Path| {
65+
if let Ok(content) = fs::read_to_string(path) {
66+
if let Ok(parsed_file) = syn::parse_file(&content) {
67+
for item in parsed_file.items {
68+
if let Item::Struct(s) = &item {
69+
if filters.as_ref().map_or(true, |f| f.item_type.as_deref().map_or(true, |ty| ty == "struct")) {
70+
items.push(("Structs", format!("{}", s.ident)));
71+
}
72+
}
73+
if let Item::Enum(e) = &item {
74+
if filters.as_ref().map_or(true, |f| f.item_type.as_deref().map_or(true, |ty| ty == "enum")) {
75+
items.push(("Enums", format!("{}", e.ident)));
76+
}
77+
}
78+
if let Item::Trait(t) = &item {
79+
if filters.as_ref().map_or(true, |f| f.item_type.as_deref().map_or(true, |ty| ty == "trait")) {
80+
items.push(("Traits", format!("{}", t.ident)));
81+
}
82+
}
83+
if let Item::Fn(f) = &item {
84+
if filters.as_ref().map_or(true, |f| f.item_type.as_deref().map_or(true, |ty| ty == "fn")) {
85+
items.push(("Functions", format!("{}", f.sig.ident)));
86+
}
87+
}
88+
}
89+
}
90+
}
91+
});
92+
93+
use std::collections::BTreeMap;
94+
let mut grouped: BTreeMap<&str, Vec<String>> = BTreeMap::new();
95+
for (kind, name) in items {
96+
grouped.entry(kind).or_default().push(name);
97+
}
98+
99+
let mut output = String::new();
100+
for (kind, names) in grouped {
101+
output.push_str(&format!("## {}\n", kind));
102+
for name in names {
103+
output.push_str(&format!("- {}\n", name));
104+
}
105+
output.push('\n');
106+
}
107+
108+
Ok(output)
69109
}

0 commit comments

Comments
 (0)