git-lfs 0.7.0

Large file storage for git, implemented in Rust
Documentation
//! Per-subcommand documentation extras (man pages + mdbook).
//!
//! The clap derive in [`crate::args`] is the source of truth for the
//! NAME, SYNOPSIS, and OPTIONS surface; xtask renders that
//! automatically into both groff (man pages) and markdown (mdbook).
//! This module owns everything richer: DESCRIPTION prose, EXAMPLES,
//! NOTES, FILES, SEE ALSO.
//!
//! **Bodies are authored in markdown.** xtask passes them through
//! verbatim for the markdown output and converts them to groff for
//! the man pages, so a single source feeds both formats. The
//! supported markdown vocabulary is intentionally small: paragraphs,
//! bold and italic, code spans and fenced code blocks, bulleted and
//! numbered lists. Stick to that and the groff conversion stays
//! predictable.
//!
//! Each subcommand exposes its extras here as a [`ManContent`] entry
//! in [`extras_for`]. Bodies live under `cli/man/<sub>/*.md` and are
//! pulled in via [`include_str!`], keeping prose out of `man.rs`.
//!
//! Onboarding a new section is two-step:
//! 1. Drop one or more `.md` files into `cli/man/<subcommand>/`.
//! 2. Add a match arm in [`extras_for`] referencing them.
//!
//! Subcommands without an entry get the auto-generated page with no
//! extras: still useful, just shorter.

/// Hand-authored extras for a single command's documentation.
///
/// Returned by [`extras_for`] keyed on the subcommand name (or `""`
/// for the top-level `git-lfs` page). Both fields are markdown; xtask
/// renders them to either groff or markdown depending on output
/// format.
#[derive(Debug)]
pub struct ManContent {
    /// Replaces the auto-generated DESCRIPTION (which is just the short
    /// `about` from the clap derive). Markdown.
    pub description: Option<&'static str>,

    /// Sections appended after OPTIONS, in order. Each entry is
    /// `(title, markdown body)`. Conventional titles: `EXAMPLES`,
    /// `FILES`, `ENVIRONMENT`, `NOTES`, `BUGS`, `SEE ALSO`. The title
    /// becomes a `.SH` in groff and a top-level `##` in markdown.
    pub extra_sections: &'static [(&'static str, &'static str)],
}

impl ManContent {
    /// A [`ManContent`] with no description and no extra sections.
    ///
    /// Returned by [`extras_for`] for subcommands that don't have
    /// hand-authored extras; the caller splices in the empty result
    /// unconditionally.
    pub const fn empty() -> Self {
        Self {
            description: None,
            extra_sections: &[],
        }
    }
}

const EMPTY: ManContent = ManContent::empty();

const ROOT: ManContent = ManContent {
    description: None,
    extra_sections: &[("EXAMPLES", include_str!("../man/root/examples.md"))],
};

/// Markdown body for the `REPORTING BUGS` section.
///
/// xtask appends this to every generated man page and mdbook page, so
/// the project URL and the "this is the Rust implementation" framing
/// have a single source of truth. Change here and every page picks it
/// up on the next regen.
pub const REPORTING_BUGS: &str = include_str!("../man/reporting_bugs.md");

const SMUDGE: ManContent = ManContent {
    description: None,
    extra_sections: &[
        ("ENVIRONMENT", include_str!("../man/smudge/environment.md")),
        ("KNOWN BUGS", include_str!("../man/smudge/known_bugs.md")),
        ("SEE ALSO", include_str!("../man/smudge/see_also.md")),
    ],
};

const CHECKOUT: ManContent = ManContent {
    description: None,
    extra_sections: &[("EXAMPLES", include_str!("../man/checkout/examples.md"))],
};

const FETCH: ManContent = ManContent {
    description: None,
    extra_sections: &[
        (
            "INCLUDE AND EXCLUDE",
            include_str!("../man/fetch/include_and_exclude.md"),
        ),
        (
            "DEFAULT REMOTE",
            include_str!("../man/fetch/default_remote.md"),
        ),
        ("DEFAULT REFS", include_str!("../man/fetch/default_refs.md")),
        (
            "RECENT CHANGES",
            include_str!("../man/fetch/recent_changes.md"),
        ),
        ("EXAMPLES", include_str!("../man/fetch/examples.md")),
        ("SEE ALSO", include_str!("../man/fetch/see_also.md")),
    ],
};

const PULL: ManContent = ManContent {
    description: None,
    extra_sections: &[
        (
            "INCLUDE AND EXCLUDE",
            include_str!("../man/pull/include_and_exclude.md"),
        ),
        (
            "DEFAULT REMOTE",
            include_str!("../man/pull/default_remote.md"),
        ),
        ("EXAMPLES", include_str!("../man/pull/examples.md")),
        ("SEE ALSO", include_str!("../man/pull/see_also.md")),
    ],
};

const PUSH: ManContent = ManContent {
    description: None,
    extra_sections: &[("SEE ALSO", include_str!("../man/push/see_also.md"))],
};

const INSTALL: ManContent = ManContent {
    description: None,
    extra_sections: &[("SEE ALSO", include_str!("../man/install/see_also.md"))],
};

const UNINSTALL: ManContent = ManContent {
    description: None,
    extra_sections: &[("SEE ALSO", include_str!("../man/uninstall/see_also.md"))],
};

const TRACK: ManContent = ManContent {
    description: None,
    extra_sections: &[
        ("EXAMPLES", include_str!("../man/track/examples.md")),
        ("SEE ALSO", include_str!("../man/track/see_also.md")),
    ],
};

const UNTRACK: ManContent = ManContent {
    description: None,
    extra_sections: &[
        ("EXAMPLES", include_str!("../man/untrack/examples.md")),
        ("SEE ALSO", include_str!("../man/untrack/see_also.md")),
    ],
};

const LOCK: ManContent = ManContent {
    description: None,
    extra_sections: &[("SEE ALSO", include_str!("../man/lock/see_also.md"))],
};

const LOCKS: ManContent = ManContent {
    description: None,
    extra_sections: &[("SEE ALSO", include_str!("../man/locks/see_also.md"))],
};

const UNLOCK: ManContent = ManContent {
    description: None,
    extra_sections: &[("SEE ALSO", include_str!("../man/unlock/see_also.md"))],
};

const STATUS: ManContent = ManContent {
    description: None,
    extra_sections: &[("SEE ALSO", include_str!("../man/status/see_also.md"))],
};

const LS_FILES: ManContent = ManContent {
    description: None,
    extra_sections: &[("SEE ALSO", include_str!("../man/ls-files/see_also.md"))],
};

const PRUNE: ManContent = ManContent {
    description: Some(include_str!("../man/prune/description.md")),
    extra_sections: &[
        ("RECENT FILES", include_str!("../man/prune/recent_files.md")),
        (
            "UNPUSHED LFS FILES",
            include_str!("../man/prune/unpushed.md"),
        ),
        (
            "VERIFY REMOTE",
            include_str!("../man/prune/verify_remote.md"),
        ),
        (
            "DEFAULT REMOTE",
            include_str!("../man/prune/default_remote.md"),
        ),
        ("SEE ALSO", include_str!("../man/prune/see_also.md")),
    ],
};

const FSCK: ManContent = ManContent {
    description: None,
    extra_sections: &[("SEE ALSO", include_str!("../man/fsck/see_also.md"))],
};

const CLEAN: ManContent = ManContent {
    description: None,
    extra_sections: &[("SEE ALSO", include_str!("../man/clean/see_also.md"))],
};

const FILTER_PROCESS: ManContent = ManContent {
    description: None,
    extra_sections: &[(
        "SEE ALSO",
        include_str!("../man/filter-process/see_also.md"),
    )],
};

const CLONE: ManContent = ManContent {
    description: None,
    extra_sections: &[("SEE ALSO", include_str!("../man/clone/see_also.md"))],
};

const PRE_PUSH: ManContent = ManContent {
    description: None,
    extra_sections: &[("SEE ALSO", include_str!("../man/pre-push/see_also.md"))],
};

const POST_CHECKOUT: ManContent = ManContent {
    description: None,
    extra_sections: &[("SEE ALSO", include_str!("../man/post-checkout/see_also.md"))],
};

const POST_COMMIT: ManContent = ManContent {
    description: None,
    extra_sections: &[("SEE ALSO", include_str!("../man/post-commit/see_also.md"))],
};

const POST_MERGE: ManContent = ManContent {
    description: None,
    extra_sections: &[("SEE ALSO", include_str!("../man/post-merge/see_also.md"))],
};

const MIGRATE: ManContent = ManContent {
    description: None,
    extra_sections: &[
        (
            "INCLUDE AND EXCLUDE",
            include_str!("../man/migrate/include_and_exclude.md"),
        ),
        (
            "INCLUDE AND EXCLUDE REFERENCES",
            include_str!("../man/migrate/include_and_exclude_references.md"),
        ),
        ("EXAMPLES", include_str!("../man/migrate/examples.md")),
        ("SEE ALSO", include_str!("../man/migrate/see_also.md")),
    ],
};

const MIGRATE_INFO: ManContent = ManContent {
    description: None,
    extra_sections: &[
        ("EXAMPLES", include_str!("../man/migrate-info/examples.md")),
        ("SEE ALSO", include_str!("../man/migrate-info/see_also.md")),
    ],
};

const MIGRATE_IMPORT: ManContent = ManContent {
    description: None,
    extra_sections: &[
        (
            "EXAMPLES",
            include_str!("../man/migrate-import/examples.md"),
        ),
        (
            "SEE ALSO",
            include_str!("../man/migrate-import/see_also.md"),
        ),
    ],
};

const MIGRATE_EXPORT: ManContent = ManContent {
    description: None,
    extra_sections: &[
        (
            "EXAMPLES",
            include_str!("../man/migrate-export/examples.md"),
        ),
        (
            "SEE ALSO",
            include_str!("../man/migrate-export/see_also.md"),
        ),
    ],
};

const EXT: ManContent = ManContent {
    description: None,
    extra_sections: &[("EXAMPLES", include_str!("../man/ext/examples.md"))],
};

// git-lfs-config(5) is a synthetic page: no clap-derived OPTIONS or
// DESCRIPTION, everything lives in the extras. The OPTIONS section is
// built up across several commits; the framing sections
// (CONFIGURATION FILES, LFSCONFIG, EXAMPLES, SEE ALSO) bracket
// whatever lands in between.
const CONFIG: ManContent = ManContent {
    description: None,
    extra_sections: &[
        (
            "CONFIGURATION FILES",
            include_str!("../man/config/configuration_files.md"),
        ),
        (
            "GENERAL SETTINGS",
            include_str!("../man/config/general_settings.md"),
        ),
        (
            "UPLOAD AND DOWNLOAD TRANSFER SETTINGS",
            include_str!("../man/config/transfer_settings.md"),
        ),
        (
            "PUSH SETTINGS",
            include_str!("../man/config/push_settings.md"),
        ),
        (
            "FETCH SETTINGS",
            include_str!("../man/config/fetch_settings.md"),
        ),
        (
            "PRUNE SETTINGS",
            include_str!("../man/config/prune_settings.md"),
        ),
        ("EXTENSIONS", include_str!("../man/config/extensions.md")),
        (
            "OTHER SETTINGS",
            include_str!("../man/config/other_settings.md"),
        ),
        ("LFSCONFIG", include_str!("../man/config/lfsconfig.md")),
        ("EXAMPLES", include_str!("../man/config/examples.md")),
        ("SEE ALSO", include_str!("../man/config/see_also.md")),
    ],
};

/// Look up the doc extras for `subcommand`.
///
/// `subcommand` is the clap subcommand name (e.g. `"fetch"`,
/// `"checkout"`); pass `""` for the top-level `git-lfs` page. Returns
/// a reference to [`ManContent::empty`] when there's no entry, so the
/// caller can always splice unconditionally.
pub fn extras_for(subcommand: &str) -> &'static ManContent {
    match subcommand {
        "smudge" => &SMUDGE,
        "ext" => &EXT,
        "config" => &CONFIG,
        "checkout" => &CHECKOUT,
        "fetch" => &FETCH,
        "pull" => &PULL,
        "push" => &PUSH,
        "install" => &INSTALL,
        "uninstall" => &UNINSTALL,
        "track" => &TRACK,
        "untrack" => &UNTRACK,
        "lock" => &LOCK,
        "locks" => &LOCKS,
        "unlock" => &UNLOCK,
        "status" => &STATUS,
        "ls-files" => &LS_FILES,
        "prune" => &PRUNE,
        "fsck" => &FSCK,
        "clean" => &CLEAN,
        "filter-process" => &FILTER_PROCESS,
        "clone" => &CLONE,
        "pre-push" => &PRE_PUSH,
        "post-checkout" => &POST_CHECKOUT,
        "post-commit" => &POST_COMMIT,
        "post-merge" => &POST_MERGE,
        "migrate" => &MIGRATE,
        "migrate-info" => &MIGRATE_INFO,
        "migrate-import" => &MIGRATE_IMPORT,
        "migrate-export" => &MIGRATE_EXPORT,
        "" => &ROOT,
        _ => &EMPTY,
    }
}