midenc_session/flags/
mod.rs1mod arg_matches;
2mod flag;
3
4#[cfg(not(feature = "std"))]
5use alloc::borrow::Cow;
6use alloc::vec::Vec;
7use core::fmt;
8
9pub use self::{
10 arg_matches::ArgMatches,
11 flag::{CompileFlag, FlagAction},
12};
13use crate::diagnostics::Report;
14
15#[derive(Clone)]
16pub struct CompileFlags {
17 flags: Vec<CompileFlag>,
18 arg_matches: ArgMatches,
19}
20
21#[cfg(feature = "std")]
22impl Default for CompileFlags {
23 fn default() -> Self {
24 Self::new(None::<std::ffi::OsString>).unwrap()
25 }
26}
27
28#[cfg(not(feature = "std"))]
29impl Default for CompileFlags {
30 fn default() -> Self {
31 Self::new(None::<alloc::string::String>).unwrap()
32 }
33}
34
35impl From<ArgMatches> for CompileFlags {
36 fn from(arg_matches: ArgMatches) -> Self {
37 let flags = inventory::iter::<CompileFlag>.into_iter().cloned().collect();
38 Self { flags, arg_matches }
39 }
40}
41
42impl CompileFlags {
43 #[cfg(feature = "std")]
45 pub fn new<I, V>(argv: I) -> Result<Self, Report>
46 where
47 I: IntoIterator<Item = V>,
48 V: Into<std::ffi::OsString> + Clone,
49 {
50 use crate::diagnostics::IntoDiagnostic;
51
52 let flags = inventory::iter::<CompileFlag>.into_iter().cloned().collect();
53 fake_compile_command()
54 .try_get_matches_from(argv)
55 .into_diagnostic()
56 .map(|arg_matches| Self { flags, arg_matches })
57 }
58
59 #[cfg(not(feature = "std"))]
61 pub fn new<I, V>(argv: I) -> Result<Self, Report>
62 where
63 I: IntoIterator<Item = V>,
64 V: Into<Cow<'static, str>> + Clone,
65 {
66 use alloc::collections::{BTreeMap, VecDeque};
67
68 let argv = argv.into_iter().map(|arg| arg.into()).collect::<VecDeque<_>>();
69 let flags = inventory::iter::<CompileFlag>
70 .into_iter()
71 .map(|flag| (flag.name, flag))
72 .collect::<BTreeMap<_, _>>();
73
74 let arg_matches = ArgMatches::parse(argv, &flags)?;
75 let this = Self {
76 flags: flags.values().copied().cloned().collect(),
77 arg_matches,
78 };
79
80 Ok(this)
81 }
82
83 pub fn flags(&self) -> &[CompileFlag] {
84 self.flags.as_slice()
85 }
86
87 pub fn get_flag(&self, name: &str) -> bool {
89 self.arg_matches.get_flag(name)
90 }
91
92 pub fn get_flag_count(&self, name: &str) -> usize {
94 self.arg_matches.get_count(name) as usize
95 }
96
97 pub fn matches(&self) -> &ArgMatches {
99 &self.arg_matches
100 }
101}
102
103impl fmt::Debug for CompileFlags {
104 #[cfg(feature = "std")]
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 let mut map = f.debug_map();
107 for id in self.arg_matches.ids() {
108 use clap::parser::ValueSource;
109 if id.as_str() == "CompilerOptions" {
111 continue;
112 }
113 if matches!(self.arg_matches.value_source(id.as_str()), Some(ValueSource::DefaultValue))
115 {
116 continue;
117 }
118 map.key(&id.as_str()).value_with(|f| {
119 let mut list = f.debug_list();
120 if let Some(occurs) =
121 self.arg_matches.try_get_raw_occurrences(id.as_str()).expect("expected flag")
122 {
123 list.entries(occurs.flatten());
124 }
125 list.finish()
126 });
127 }
128 map.finish()
129 }
130
131 #[cfg(not(feature = "std"))]
132 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133 let mut map = f.debug_map();
134 for (name, raw_values) in self.arg_matches.iter() {
135 map.key(&name)
136 .value_with(|f| f.debug_list().entries(raw_values.iter()).finish());
137 }
138 map.finish()
139 }
140}
141
142#[cfg(feature = "std")]
144fn fake_compile_command() -> clap::Command {
145 let cmd = clap::Command::new("compile")
146 .no_binary_name(true)
147 .disable_help_flag(true)
148 .disable_version_flag(true)
149 .disable_help_subcommand(true);
150 register_flags(cmd)
151}
152
153#[cfg(feature = "std")]
155pub fn register_flags(cmd: clap::Command) -> clap::Command {
156 inventory::iter::<CompileFlag>.into_iter().fold(cmd, |cmd, flag| {
157 let arg = clap::Arg::new(flag.name)
158 .long(flag.long.unwrap_or(flag.name))
159 .action(clap::ArgAction::from(flag.action));
160 let arg = if let Some(help) = flag.help {
161 arg.help(help)
162 } else {
163 arg
164 };
165 let arg = if let Some(help_heading) = flag.help_heading {
166 arg.help_heading(help_heading)
167 } else {
168 arg
169 };
170 let arg = if let Some(short) = flag.short {
171 arg.short(short)
172 } else {
173 arg
174 };
175 let arg = if let Some(env) = flag.env {
176 arg.env(env)
177 } else {
178 arg
179 };
180 let arg = if let Some(value) = flag.default_missing_value {
181 arg.default_missing_value(value)
182 } else {
183 arg
184 };
185 let arg = if let Some(value) = flag.default_value {
186 arg.default_value(value)
187 } else {
188 arg
189 };
190 let arg = if let Some(value) = flag.hide {
191 arg.hide(value)
192 } else {
193 arg
194 };
195 cmd.arg(arg)
196 })
197}