Skip to main content

cargo_ff/
cli.rs

1use crate::types::Config;
2use clap::{Args, Parser};
3use std::num::NonZeroUsize;
4use std::path::PathBuf;
5
6#[derive(Debug, Parser)]
7#[command(
8    name = "cargo-ff",
9    bin_name = "cargo ff",
10    about = "Fast Format is a fast drop-in replacement for cargo fmt",
11    version
12)]
13#[non_exhaustive]
14pub struct Cli {
15    /// Run rustfmt in --check mode (exit non-zero if any file would change).
16    #[arg(long)]
17    pub check: bool,
18
19    /// Format every workspace member, regardless of which package
20    /// `--manifest-path` (or the current directory) implicitly selects.
21    /// Mirrors `cargo fmt --all`.
22    #[arg(long)]
23    pub all: bool,
24
25    /// Format only the given workspace member(s). Can be repeated.
26    #[arg(short = 'p', long = "package")]
27    pub packages: Vec<String>,
28
29    /// Path to the workspace's Cargo.toml (forwarded to `cargo metadata`).
30    #[arg(long)]
31    pub manifest_path: Option<PathBuf>,
32
33    /// Extra arguments forwarded to rustfmt (after `--`).
34    #[arg(last = true)]
35    pub rustfmt_args: Vec<String>,
36
37    #[command(flatten)]
38    pub ff: FfArgs,
39}
40
41/// cargo-ff-specific flags. All long names are prefixed `--ff-*` so they
42/// can never collide with a flag added upstream by `cargo fmt`.
43#[derive(Debug, Args)]
44#[non_exhaustive]
45pub struct FfArgs {
46    /// Number of worker threads. Defaults to `available_parallelism()`.
47    #[arg(long = "ff-workers")]
48    pub workers: Option<NonZeroUsize>,
49
50    /// Bounded-channel capacity. Default 512. Hidden — benchmarking knob.
51    #[arg(long = "ff-channel-capacity", hide = true)]
52    pub channel_capacity: Option<usize>,
53
54    /// Crates per rustfmt invocation. Higher amortizes spawn cost; lower
55    /// gives finer scheduling granularity. Hidden — benchmarking knob.
56    #[arg(long = "ff-batch-size", hide = true)]
57    pub batch_size: Option<usize>,
58
59    /// Experimental: skip rustfmt for crates whose `*.rs` mtimes match
60    /// the prior successful run. May produce stale results if files
61    /// outside `manifest_dir` are pulled in via `#[path]`.
62    #[arg(long = "ff-experimental-cache", hide = true)]
63    pub experimental_cache: bool,
64
65    /// Emit advisory warnings to stderr (off by default).
66    #[arg(long = "ff-warnings")]
67    pub warnings: bool,
68}
69
70impl Cli {
71    /// Parse argv, stripping the cargo-subcommand `argv[1] == "ff"` if present.
72    #[must_use]
73    pub fn parse_argv() -> Self {
74        let mut args: Vec<std::ffi::OsString> = std::env::args_os().collect();
75        if args.len() >= 2 && args[1] == "ff" {
76            args.remove(1);
77        }
78        Self::parse_from(args)
79    }
80
81    pub fn into_config(self) -> Config {
82        Config {
83            manifest_path: self.manifest_path,
84            packages: self.packages,
85            all: self.all,
86            check: self.check,
87            rustfmt_args: self.rustfmt_args,
88            workers: self.ff.workers.map(NonZeroUsize::get),
89            channel_capacity: self.ff.channel_capacity,
90            batch_size: self.ff.batch_size,
91            experimental_cache: self.ff.experimental_cache,
92            warnings: self.ff.warnings,
93        }
94    }
95}