// Copyright (C) 2026 Leandro Lisboa Penz <lpenz@lpenz.org>
// This file is subject to the terms and conditions defined in
// file 'LICENSE', which is part of this source code package.

#![deny(future_incompatible)]
#![deny(nonstandard_style)]
#![deny(missing_docs)]
#![deny(rustdoc::broken_intra_doc_links)]
#![allow(rustdoc::private_intra_doc_links)]

//! Converts a [clap](https://crates.io/crates/clap) cli into a
//! [man](https://crates.io/crates/man) manpage that can be further
//! customized.
//!
//! ## Usage
//!
//! In your `Cargo.toml`:
//!
//! ```toml
//! [build-dependencies]
//! clap2man = "0.1.0"
//! clap = "4.6.0"
//! ```
//!
//! In your `build.rs`:
//!
//! ```rust
//! use clap::{Arg, Command};
//! use clap2man::Manual;
//! use std::env;
//! use std::fs;
//! use std::path::Path;
//!
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # if false {
//!     // Usually you would import your Command definition from your main crate
//!     // (e.g., include!("src/cli.rs")) instead of defining it here.
//!     let cmd = Command::new("test-app")
//!         .version("1.2.3")
//!         .author("John Doe <john@doe.com>")
//!         .about("A test application for clap2man")
//!         .arg(
//!             Arg::new("verbose")
//!                 .short('v')
//!                 .long("verbose")
//!                 .help("Enable verbose mode")
//!                 .action(clap::ArgAction::SetTrue),
//!         );
//!
//!     let manual = Manual::try_from(&cmd)?;
//!     let manpage: man::Manual = manual.into();
//!     let rendered = manpage.render();
//!
//!     // Find the target directory (e.g. target/debug or target/release)
//!     // OUT_DIR is usually target/.../build/crate-hash/out
//!     let out_dir = env::var_os("OUT_DIR").ok_or("OUT_DIR not set")?;
//!     let target_dir = Path::new(&out_dir)
//!         .ancestors()
//!         .nth(3)
//!         .ok_or("Could not find target directory")?;
//!
//!     let out_path = target_dir.join("test-app.1");
//!     fs::write(out_path, rendered).expect("Failed to write manpage");
//! # }
//!     Ok(())
//! }
//! ```
//!
//! ## Features
//!
//! - Converts basic information from a `clap::Command`:
//!   - Name
//!   - About
//!   - Description (long_about)
//!   - Author
//!   - Flags/Options (automatically adds standard help and version flags)
//!   - Positional Arguments
//!   - Subcommands
//! - Returns a `man::Manual` object that can be further customized.
//!
//! ## Customization
//!
//! Since `Manual::into()` returns a `man::Manual` from the
//! [man](https://crates.io/crates/man) crate, you can use all its
//! methods to further customize the manpage:
//!
//! ```rust
//! # use clap::Command;
//! # use clap2man::Manual;
//! # let cmd = Command::new("test-app").about("about").author("author");
//! let manual = Manual::try_from(&cmd)?;
//! let mut manpage: man::Manual = manual.into();
//!
//! // Add a custom section
//! manpage = manpage.custom(
//!     man::Section::new("extra section")
//!         .paragraph("This is some extra information.")
//! );
//!
//! let rendered = manpage.render();
//! # Ok::<(), clap2man::Error>(())
//! ```
//!
//! ## Fine-grained control
//!
//! If you don't want to convert everything, you can use the functions
//! in the `fill` module directly:
//!
//! ```rust
//! # use clap::Command;
//! use clap2man::fill;
//!
//! # let cmd = Command::new("test-app").about("about");
//! let mut manpage = man::Manual::new("my-app");
//! manpage = fill::fill_about(&cmd, manpage)?;
//! manpage = fill::fill_flags(&cmd, manpage)?;
//! // Only about and flags are filled; the rest is omitted or manual.
//! # Ok::<(), clap2man::Error>(())
//! ```
//!
//! ## Comparison with alternatives
//!
//! - **[clap_mangen](https://crates.io/crates/clap_mangen)**:
//!   The official `clap` manpage generator. It is more mature and
//!   generates complete manpages directly from `clap`. However, it
//!   doesn't return a `man::Manual` object, which makes it harder to
//!   further customize the output using the `man` crate's API if you
//!   need to add complex custom sections or change the formatting in
//!   ways not supported by `clap`'s metadata.

pub mod fill;

mod wrapper;
pub use wrapper::Manual;

/// Error type for clap2man
#[derive(thiserror::Error, Debug)]
pub enum Error {
    /// Command about is missing
    #[error("command about is missing")]
    MissingAbout,
    /// Command author is missing
    #[error("command author is missing")]
    MissingAuthor,
    /// Duplicate flag
    #[error("duplicate flag --{0}")]
    DuplicateFlag(String),
    /// Duplicate short flag
    #[error("duplicate short flag -{0}")]
    DuplicateShortFlag(char),
}

/// Result type for clap2man
pub type Result<T> = std::result::Result<T, Error>;
