Skip to content

Commit

Permalink
feat(doxygen): use custom parser
Browse files Browse the repository at this point in the history
  • Loading branch information
oberrich committed Jan 2, 2025
1 parent 2282614 commit fa26853
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 80 deletions.
80 changes: 7 additions & 73 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ build = "src/build.rs"
description = "Rust bindings to the System Informer's (formerly known as Process Hacker) `phnt` native Windows headers"

[features]
regenerate = ["dep:regex", "dep:bindgen", "dep:chrono", "dep:doxygen-rs"]
regenerate = ["dep:regex", "dep:bindgen", "dep:chrono", "dep:yap"]

[package.metadata.docs.rs]
default-target = "x86_64-pc-windows-msvc"
Expand All @@ -22,7 +22,7 @@ rustc-args = ["--cfg", "docsrs"]
regex = { version = "1.11.1", optional = true }
bindgen = { version = "0.71.1", optional = true }
chrono = { version = "0.4.39", optional = true }
doxygen-rs = { version = "0.4.2", optional = true }
yap = { version = "0.12.0", optional = true }

[dependencies.windows-sys]
version = "0.59.0"
Expand Down
104 changes: 99 additions & 5 deletions src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,107 @@

#[cfg_attr(docsrs, doc(cfg(feature = "regenerate")))]
#[cfg(feature = "regenerate")]
pub use regen::main;
use regen::main;

#[cfg_attr(docsrs, doc(cfg(not(feature = "regenerate"))))]
#[cfg(not(feature = "regenerate"))]
fn main() {
println!("Using vsendored bindings, build script skipped.");
}

#[cfg_attr(docsrs, doc(cfg(feature = "regenerate")))]
#[cfg(feature = "regenerate")]
mod doxygen {
use yap::{IntoTokens, Tokens};
static SEPS: [char; 5] = [' ', '\t', '\r', '\n', '['];

fn format_ref(str: String) -> String {
assert!(!str.contains(' '));
// Don't turn URIs into code refs
if !str.contains("://") {
format!("[`{}`]", str)
} else {
str
}
}

fn take_word(toks: &mut impl Tokens<Item = char>) -> String {
toks
.take_while(|&c| !SEPS.into_iter().any(|s| c == s))
.collect::<String>()
}

fn skip_whitespace(toks: &mut impl Tokens<Item = char>) {
toks.skip_while(|c| c.is_ascii_whitespace());
}

pub fn transform(str: &str) -> String {
let mut res: Vec<String> = vec![];
let mut toks = str.into_tokens();
let mut first_param = true;
let mut first_see_also = true;

skip_whitespace(&mut toks);
while let Some(tok) = toks.next() {
if "@\\".chars().any(|c| c == tok) {
let tag = take_word(&mut toks);
skip_whitespace(&mut toks);
match tag.as_str() {
"param" => {
if first_param {
res.push("# Arguments\n\n".to_owned());
first_param = false;
}

let (mut argument, mut attributes) = (take_word(&mut toks), "".to_owned());
if argument.is_empty() {
assert_eq!(toks.next().expect("has more input"), '[');
attributes = toks.take_while(|&c| c != ']').collect::<String>();
assert_eq!(toks.next().expect("has more input"), ']');
attributes = format!(" [{}] ", attributes);
skip_whitespace(&mut toks);
argument = take_word(&mut toks);
}

res.push(format!("* `{}`{} -", argument, attributes));
}
"c" | "p" => res.push(format!("`{}`", take_word(&mut toks))),
"ref" => res.push(format_ref(take_word(&mut toks))),
"see" | "sa" => {
if first_see_also {
res.push("# See also\n\n".to_owned());
first_see_also = false;
}

res.push(format!("\t{}", format_ref(take_word(&mut toks))));
}
"a" | "e" | "em" => res.push(format!("_{}_", take_word(&mut toks))),
"b" => res.push(format!("**{}**", take_word(&mut toks))),
"note" => res.push("> **Note:** ".to_owned()),
"since" => res.push("> Available since: ".to_owned()),
"deprecated" => res.push("> **Deprecated** ".to_owned()),
"remark" | "remarks" => res.push("> ".to_owned()),
"li" => res.push("- ".to_owned()),
"par" => res.push("# ".to_owned()),
"returns" | "return" | "result" => res.push("# Returns\n\n".to_owned()),
"{" => { /* group start, not implemented */ }
"}" => { /* group end, not implemented */ }
"brief" | "short" => {}
_ => {
res.push(format!("{tok}{tag} "));
}
}
} else if tok == '\n' {
skip_whitespace(&mut toks);
res.push(format!("{tok}"));
} else {
res.push(format!("{tok}"));
}
}
res.join("")
}
}

#[cfg_attr(docsrs, doc(cfg(feature = "regenerate")))]
#[cfg(feature = "regenerate")]
mod regen {
Expand All @@ -48,20 +141,21 @@ mod regen {

impl ParseCallbacks for ProcessComments {
fn process_comment(&self, comment: &str) -> Option<String> {
match std::panic::catch_unwind(|| doxygen_rs::transform(comment)) {
match std::panic::catch_unwind(|| crate::doxygen::transform(comment)) {
Ok(res) => Some(res),
Err(err) => {
println!(
"cargo:warning=Problem processing comment: {}",
"cargo:warning=Problem processing comment: {}\n{}",
comment,
if let Some(msg) = err.downcast_ref::<String>() {
msg
msg.as_str()
} else if let Some(msg) = err.downcast_ref::<&str>() {
msg
} else {
"Unknown panic type"
}
);
None
Some(comment.to_owned())
}
}
}
Expand Down

0 comments on commit fa26853

Please sign in to comment.