1#[cfg(feature = "cli")]
6use clap::Parser;
7
8use crate::presets::Preset;
9use crate::process::CommentPattern;
10use crate::Format;
11use regex::Regex;
12
13#[derive(Debug)]
15#[cfg_attr(feature = "cli", derive(Parser))]
16#[cfg_attr(
17 feature = "cli",
18 command(
19 bin_name = "codump",
20 about,
21 version,
22 author,
23 arg_required_else_help = true
24 )
25)]
26pub struct CliArgs {
27 #[cfg_attr(feature = "cli", arg(required = true))]
29 pub file: String,
30
31 #[cfg_attr(feature = "cli", arg(required = true))]
36 pub search_path: Vec<String>,
37
38 #[cfg_attr(feature = "cli", arg(long))]
40 outer: Option<String>,
41
42 #[cfg_attr(feature = "cli", arg(long))]
44 outer_start: Option<String>,
45
46 #[cfg_attr(feature = "cli", arg(long))]
48 outer_end: Option<String>,
49
50 #[cfg_attr(feature = "cli", arg(long))]
52 inner: Option<String>,
53
54 #[cfg_attr(feature = "cli", arg(long))]
56 inner_start: Option<String>,
57
58 #[cfg_attr(feature = "cli", arg(long))]
60 inner_end: Option<String>,
61
62 #[cfg_attr(feature = "cli", arg(long, short))]
64 ignore: Vec<String>,
65
66 #[cfg_attr(feature = "cli", arg(long, short, default_value = "summary"))]
68 format: Format,
69
70 #[cfg_attr(feature = "cli", arg(long, short))]
76 preset: Option<Preset>,
77
78 #[cfg_attr(feature = "cli", arg(long, short))]
82 context: bool,
83
84 #[cfg_attr(feature = "cli", arg(long, short = 'C'))]
88 context_comments: bool,
89}
90
91#[derive(Debug, Clone)]
93pub struct Config {
94 pub outer_comments: CommentPattern,
96 pub inner_comments: CommentPattern,
98 pub ignore_lines: Vec<Regex>,
100 pub include_context: bool,
102 pub context_include_comments: bool,
104 pub format: Format,
106}
107
108impl TryFrom<CliArgs> for Config {
109 type Error = String;
110
111 fn try_from(args: CliArgs) -> Result<Self, Self::Error> {
112 let (outer_comments, inner_comments) = match args.preset {
113 Some(preset) => {
114 let (mut outer, mut inner) = preset.get_patterns();
115 if let Some(v) = args.outer {
116 outer.single_line = parse_regex(&v)?;
117 }
118 if let Some(v) = args.outer_start {
119 outer.multi_start = Some(parse_regex(&v)?);
120 }
121 if let Some(v) = args.outer_end {
122 outer.multi_end = parse_regex(&v)?;
123 }
124 if let Some(v) = args.inner {
125 inner.single_line = parse_regex(&v)?;
126 }
127 if let Some(v) = args.inner_start {
128 inner.multi_start = Some(parse_regex(&v)?);
129 }
130 if let Some(v) = args.inner_end {
131 inner.multi_end = parse_regex(&v)?;
132 }
133 (outer, inner)
134 }
135 None => parse_comment_pattern_from_args(&args)?,
136 };
137 let mut ignore_lines = vec![];
138 for line in args.ignore {
139 ignore_lines.push(parse_regex(&line)?);
140 }
141
142 Ok(Config {
143 outer_comments,
144 inner_comments,
145 ignore_lines,
146 include_context: args.context || args.context_comments,
147 context_include_comments: args.context_comments,
148 format: args.format,
149 })
150 }
151}
152
153fn parse_comment_pattern_from_args(
154 args: &CliArgs,
155) -> Result<(CommentPattern, CommentPattern), String> {
156 Ok((
157 CommentPattern {
158 single_line: parse_comment_pattern(args.outer.as_ref())?,
159 multi_start: Some(parse_comment_pattern(args.outer_start.as_ref())?),
160 multi_end: parse_comment_pattern(args.outer_end.as_ref())?,
161 },
162 CommentPattern {
163 single_line: parse_comment_pattern(args.inner.as_ref())?,
164 multi_start: Some(parse_comment_pattern(args.inner_start.as_ref())?),
165 multi_end: parse_comment_pattern(args.inner_end.as_ref())?,
166 },
167 ))
168}
169
170fn parse_comment_pattern(pattern: Option<&String>) -> Result<Regex, String> {
171 match pattern {
172 Some(s) => parse_regex(s),
173 None => Err("Comment pattern missing. Either use a --preset or specify all the --outer* and --inner* arguments. See --help for more.".to_string()),
174 }
175}
176
177fn parse_regex(s: &str) -> Result<Regex, String> {
178 Regex::new(s).map_err(|_| format!("Invalid regex \"{}\". See --help for more.", s))
179}