a73x

aac7cbe5

Merge patch b04dcdea: Add auto-generated man pages via clap_mangen

a73x   2026-03-21 09:44


diff --git a/.gitignore b/.gitignore
index ea8c4bf..eaeddaf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
/target
/man
diff --git a/Cargo.lock b/Cargo.lock
index ae81def..950f366 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -245,6 +245,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"

[[package]]
name = "clap_mangen"
version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e30ffc187e2e3aeafcd1c6e2aa416e29739454c0ccaa419226d5ecd181f2d78"
dependencies = [
 "clap",
 "roff",
]

[[package]]
name = "colorchoice"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -687,6 +697,7 @@ dependencies = [
 "base64",
 "chrono",
 "clap",
 "clap_mangen",
 "crossterm",
 "dirs",
 "ed25519-dalek",
@@ -1600,6 +1611,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"

[[package]]
name = "roff"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf2048e0e979efb2ca7b91c4f1a8d77c91853e9b987c94c555668a8994915ad"

[[package]]
name = "rustc_version"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index c59d353..c344663 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -17,5 +17,9 @@ rand_core = { version = "0.6", features = ["getrandom"] }
base64 = "0.22"
dirs = "5"

[build-dependencies]
clap = { version = "4", features = ["derive"] }
clap_mangen = "0.2"

[dev-dependencies]
tempfile = "3"
diff --git a/Makefile b/Makefile
index 11fc2dc..b614f8f 100644
--- a/Makefile
+++ b/Makefile
@@ -30,15 +30,31 @@ ci: lint test build

# --- Install ---
install: PROFILE := release
install: build
install: build install-man
	install -Dm755 target/release/$(BIN) $(PREFIX)/bin/$(BIN)

uninstall:
	rm -f $(PREFIX)/bin/$(BIN)

clean:
clean: clean-man
	$(CARGO) clean

# --- Man pages ---
MAN_DIR := man/man1

.PHONY: man install-man clean-man

man:
	MAN_OUT_DIR=$(MAN_DIR) $(CARGO) build
	@echo "Man pages written to $(MAN_DIR)/"

install-man: man
	install -d $(PREFIX)/share/man/man1
	install -m644 $(MAN_DIR)/*.1 $(PREFIX)/share/man/man1/

clean-man:
	rm -rf man/

# --- Dev helpers ---
.PHONY: run dev dashboard

diff --git a/build.rs b/build.rs
new file mode 100644
index 0000000..5a934da
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,37 @@
use std::env;
use std::fs;
use std::path::PathBuf;

include!("src/cli.rs");

fn main() {
    let out = PathBuf::from(
        env::var("MAN_OUT_DIR").unwrap_or_else(|_| {
            env::var("OUT_DIR").expect("OUT_DIR not set")
        }),
    );

    let cmd = <Cli as clap::CommandFactory>::command();
    generate_manpages(&cmd, &out);
}

fn generate_manpages(cmd: &clap::Command, out: &PathBuf) {
    let man = clap_mangen::Man::new(cmd.clone());
    let name = cmd.get_name().to_string();
    let mut buf = Vec::new();
    man.render(&mut buf).expect("failed to render man page");
    fs::create_dir_all(out).expect("failed to create man output dir");
    fs::write(out.join(format!("{name}.1")), buf)
        .expect("failed to write man page");

    for sub in cmd.get_subcommands() {
        if sub.is_hide_set() {
            continue;
        }
        let sub_name = format!("{}-{}", cmd.get_name(), sub.get_name());
        // Leak is fine: build scripts are short-lived processes. clap requires 'static str for name().
        let sub_name: &'static str = Box::leak(sub_name.into_boxed_str());
        let sub_cmd = sub.clone().name(sub_name);
        generate_manpages(&sub_cmd, out);
    }
}