1use clap::Parser;
2
3#[derive(Parser, Debug, Clone)]
5#[clap(author, version, about)]
6pub struct Args {
7 #[clap(short = 'd', long, default_value = ".")]
9 pub input: String,
10
11 #[clap(short, long, default_value = "output.md")]
13 pub output: String,
14
15 #[clap(short = 'f', long, value_delimiter = ',')]
17 pub filter: Vec<String>,
18
19 #[clap(short = 'i', long)]
21 pub ignore: Vec<String>,
22
23 #[clap(long)]
25 pub preview: bool,
26
27 #[clap(long)]
29 pub token_count: bool,
30
31 #[clap(long)]
33 pub line_numbers: bool,
34
35 #[clap(short = 'y', long)]
37 pub yes: bool,
38
39 #[clap(long)]
41 pub max_tokens: Option<usize>,
42
43 #[clap(long, default_value_t = false)]
45 pub diff_only: bool,
46
47 #[clap(long)]
49 pub clear_cache: bool,
50
51 #[clap(long)]
53 pub init: bool,
54}
55
56#[cfg(test)]
57mod tests {
58 use super::Args;
59 use clap::Parser;
60
61 #[test]
62 fn parses_with_no_args() {
63 let res = Args::try_parse_from(["context-builder"]);
64 assert!(res.is_ok(), "Expected success when no args are provided");
65 }
66
67 #[test]
68 fn parses_all_flags_and_options() {
69 let args = Args::try_parse_from([
70 "context-builder",
71 "--input",
72 "some/dir",
73 "--output",
74 "ctx.md",
75 "--filter",
76 "rs",
77 "--filter",
78 "toml",
79 "--ignore",
80 "target",
81 "--ignore",
82 "node_modules",
83 "--preview",
84 "--token-count",
85 "--line-numbers",
86 "--diff-only",
87 "--clear-cache",
88 ])
89 .expect("should parse");
90
91 assert_eq!(args.input, "some/dir");
92 assert_eq!(args.output, "ctx.md");
93 assert_eq!(args.filter, vec!["rs".to_string(), "toml".to_string()]);
94 assert_eq!(
95 args.ignore,
96 vec!["target".to_string(), "node_modules".to_string()]
97 );
98 assert!(args.preview);
99 assert!(args.token_count);
100 assert!(args.line_numbers);
101 assert!(args.diff_only);
102 assert!(args.clear_cache);
103 }
104
105 #[test]
106 fn short_flags_parse_correctly() {
107 let args = Args::try_parse_from([
108 "context-builder",
109 "-d",
110 ".",
111 "-o",
112 "out.md",
113 "-f",
114 "md",
115 "-f",
116 "rs",
117 "-i",
118 "target",
119 "-i",
120 ".git",
121 ])
122 .expect("should parse");
123
124 assert_eq!(args.input, ".");
125 assert_eq!(args.output, "out.md");
126 assert_eq!(args.filter, vec!["md".to_string(), "rs".to_string()]);
127 assert_eq!(args.ignore, vec!["target".to_string(), ".git".to_string()]);
128 assert!(!args.preview);
129 assert!(!args.line_numbers);
130 assert!(!args.clear_cache);
131 }
132
133 #[test]
134 fn defaults_for_options_when_not_provided() {
135 let args = Args::try_parse_from(["context-builder", "-d", "proj"]).expect("should parse");
136
137 assert_eq!(args.input, "proj");
138 assert_eq!(args.output, "output.md");
139 assert!(args.filter.is_empty());
140 assert!(args.ignore.is_empty());
141 assert!(!args.preview);
142 assert!(!args.line_numbers);
143 assert!(!args.diff_only);
144 assert!(!args.clear_cache);
145 }
146
147 #[test]
148 fn parses_diff_only_flag() {
149 let args = Args::try_parse_from(["context-builder", "--diff-only"])
150 .expect("should parse diff-only flag");
151 assert!(args.diff_only);
152 assert!(!args.clear_cache);
153 }
154
155 #[test]
156 fn parses_clear_cache_flag() {
157 let args = Args::try_parse_from(["context-builder", "--clear-cache"])
158 .expect("should parse clear-cache flag");
159 assert!(args.clear_cache);
160 assert!(!args.diff_only);
161 }
162}