Skip to main content

paper_age/
cli.rs

1//! Command line arguments
2use std::path::PathBuf;
3
4use clap::Parser;
5use clap_verbosity_flag::Verbosity;
6
7use crate::page::PageSize;
8
9/// Command line arguments
10#[derive(Parser, Debug)]
11#[command(author, version, about, long_about = None)]
12pub struct Args {
13    /// Page title (max. 64 characters)
14    #[arg(short, long, default_value = "PaperAge")]
15    pub title: String,
16
17    /// Notes label below the QR code (max. 32 characters)
18    #[arg(short, long, default_value = "Passphrase:")]
19    pub notes_label: String,
20
21    /// Skip the notes placeholder line (e.g. Passphrase: ________)
22    #[arg(long, default_value_t = false)]
23    pub skip_notes_line: bool,
24
25    /// Output file name. Use - for STDOUT.
26    #[arg(short, long, default_value = "out.pdf")]
27    pub output: PathBuf,
28
29    /// Paper size
30    #[arg(short = 's', long, default_value_t = PageSize::A4)]
31    pub page_size: PageSize,
32
33    /// Overwrite the output file if it already exists
34    #[arg(short, long, default_value_t = false)]
35    pub force: bool,
36
37    /// Draw a grid pattern for debugging layout issues
38    #[arg(short, long, default_value_t = false)]
39    pub grid: bool,
40
41    /// Print out the license for the embedded fonts
42    #[arg(long, default_value_t = false, exclusive = true)]
43    pub fonts_license: bool,
44
45    /// Verbose output for debugging
46    #[clap(flatten)]
47    pub verbose: Verbosity,
48
49    /// The path to the file to read. Defaults to standard input. Max. ~1.9KB.
50    pub input: Option<PathBuf>,
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn verify_args() {
59        use clap::CommandFactory;
60        super::Args::command().debug_assert()
61    }
62
63    #[test]
64    fn test_args() {
65        let args = Args::parse_from([
66            "paper-age",
67            "-f",
68            "-g",
69            "--title",
70            "Hello",
71            "--notes-label",
72            "Notes:",
73            "--skip-notes-line",
74            "--output",
75            "test.pdf",
76            "input.txt",
77        ]);
78        assert!(args.force);
79        assert!(args.grid);
80        assert_eq!(args.title, "Hello");
81        assert_eq!(args.notes_label, "Notes:");
82        assert!(args.skip_notes_line);
83        assert_eq!(args.output.to_str().unwrap(), "test.pdf");
84        assert_eq!(args.input.unwrap().to_str().unwrap(), "input.txt");
85    }
86
87    #[test]
88    fn test_defaults() {
89        let args = Args::parse_from(["paper-age"]);
90        assert_eq!(args.title, "PaperAge");
91        assert_eq!(args.notes_label, "Passphrase:");
92        assert!(!args.skip_notes_line);
93        assert_eq!(args.output.to_str().unwrap(), "out.pdf");
94        assert_eq!(args.input, None);
95        assert!(!args.force);
96    }
97
98    #[test]
99    fn test_fonts_license() {
100        let args = Args::parse_from(["paper-age", "--fonts-license"]);
101        assert!(args.fonts_license);
102    }
103
104    #[test]
105    fn test_fonts_license_conflict() -> Result<(), Box<dyn std::error::Error>> {
106        let result = Args::try_parse_from(["paper-age", "--fonts-license", "--grid"]);
107
108        assert!(result.is_err());
109
110        Ok(())
111    }
112}