aopt_help/
cmd.rs

1use std::borrow::Cow;
2use std::ops::Deref;
3use std::ops::DerefMut;
4
5use crate::block::Block;
6use crate::error::Error;
7use crate::format::HelpDisplay;
8use crate::format::HelpPolicy;
9use crate::store::Store;
10
11#[derive(Debug, Default, Clone)]
12pub struct Command<'a> {
13    name: Cow<'a, str>,
14
15    hint: Cow<'a, str>,
16
17    help: Cow<'a, str>,
18
19    foot: Cow<'a, str>,
20
21    head: Cow<'a, str>,
22
23    blocks: Vec<Block<'a, Cow<'a, str>>>,
24
25    stores: Vec<Store<'a>>,
26}
27
28impl<'a> Command<'a> {
29    pub fn new<S: Into<Cow<'a, str>>>(name: S, hint: S, help: S, head: S, foot: S) -> Self {
30        Self {
31            name: name.into(),
32            foot: foot.into(),
33            head: head.into(),
34            hint: hint.into(),
35            help: help.into(),
36            blocks: vec![],
37            stores: vec![],
38        }
39    }
40
41    pub fn name(&self) -> Cow<'a, str> {
42        self.name.clone()
43    }
44
45    pub fn hint(&self) -> Cow<'a, str> {
46        self.hint.clone()
47    }
48
49    pub fn help(&self) -> Cow<'a, str> {
50        self.help.clone()
51    }
52
53    pub fn head(&self) -> Cow<'a, str> {
54        self.head.clone()
55    }
56
57    pub fn foot(&self) -> Cow<'a, str> {
58        self.foot.clone()
59    }
60
61    pub fn block(&self) -> &Vec<Block<'a, Cow<'a, str>>> {
62        &self.blocks
63    }
64
65    pub fn block_mut(&mut self) -> &mut Vec<Block<'a, Cow<'a, str>>> {
66        &mut self.blocks
67    }
68
69    pub fn has_position(&self) -> bool {
70        self.stores.iter().any(|store| store.position())
71    }
72
73    pub fn find_store<S: Into<Cow<'a, str>>>(&self, name: S) -> Option<&Store<'a>> {
74        let name = name.into();
75        self.stores.iter().find(|v| v.name() == name)
76    }
77
78    pub fn find_store_mut<S: Into<Cow<'a, str>>>(&mut self, name: S) -> Option<&mut Store<'a>> {
79        let name = name.into();
80        self.stores.iter_mut().find(|v| v.name() == name)
81    }
82
83    pub fn find_block<S: Into<Cow<'a, str>>>(&self, name: S) -> Option<&Block<'a, Cow<'a, str>>> {
84        let name = name.into();
85        self.blocks.iter().find(|v| v.name() == name)
86    }
87
88    pub fn find_block_mut<S: Into<Cow<'a, str>>>(
89        &mut self,
90        name: S,
91    ) -> Option<&mut Block<'a, Cow<'a, str>>> {
92        let name = name.into();
93        self.blocks.iter_mut().find(|v| v.name() == name)
94    }
95
96    pub fn set_name<S: Into<Cow<'a, str>>>(&mut self, name: S) -> &mut Self {
97        self.name = name.into();
98        self
99    }
100
101    pub fn set_hint<S: Into<Cow<'a, str>>>(&mut self, hint: S) -> &mut Self {
102        self.hint = hint.into();
103        self
104    }
105
106    pub fn set_help<S: Into<Cow<'a, str>>>(&mut self, help: S) -> &mut Self {
107        self.help = help.into();
108        self
109    }
110
111    pub fn set_foot<S: Into<Cow<'a, str>>>(&mut self, help: S) -> &mut Self {
112        self.foot = help.into();
113        self
114    }
115
116    pub fn set_head<S: Into<Cow<'a, str>>>(&mut self, help: S) -> &mut Self {
117        self.head = help.into();
118        self
119    }
120
121    pub fn add_store<S: Into<Cow<'a, str>>>(
122        &mut self,
123        block: S,
124        store: Store<'a>,
125    ) -> Result<&mut Self, Error> {
126        let name: Cow<'a, str> = block.into();
127
128        if self.find_store(name.clone()).is_some() {
129            Err(Error::DuplicatedStoreName(store.name().to_string()))
130        } else {
131            let block = self
132                .find_block_mut(name.clone())
133                .ok_or_else(|| Error::InvalidBlockName(name.to_string()))?;
134
135            block.attach(store.name());
136            self.stores.push(store);
137            Ok(self)
138        }
139    }
140
141    pub fn add_block(&mut self, block: Block<'a, Cow<'a, str>>) -> Result<&mut Self, Error> {
142        let name = block.name();
143
144        if self.find_block(name.clone()).is_some() {
145            Err(Error::DuplicatedBlockName(name.to_string()))
146        } else {
147            self.blocks.push(block);
148            Ok(self)
149        }
150    }
151
152    pub fn new_store<S: Into<Cow<'a, str>>>(
153        &mut self,
154        block: S,
155        name: S,
156    ) -> Result<AddStore2Block<'a, '_>, Error> {
157        let name = name.into();
158
159        if self.find_store(name.clone()).is_some() {
160            Err(Error::DuplicatedStoreName(name.to_string()))
161        } else {
162            let block = block.into();
163            let block = self
164                .blocks
165                .iter_mut()
166                .find(|v| v.name() == block)
167                .ok_or_else(|| Error::InvalidBlockName(block.to_string()))?;
168            let stores = &mut self.stores;
169
170            Ok(AddStore2Block::new(block, stores, name))
171        }
172    }
173
174    pub fn new_block<S: Into<Cow<'a, str>>>(&mut self, name: S) -> Result<BlockMut<'a, '_>, Error> {
175        let name = name.into();
176
177        if self.find_block(name.clone()).is_some() {
178            Err(Error::DuplicatedBlockName(name.to_string()))
179        } else {
180            Ok(BlockMut::new(self, name))
181        }
182    }
183}
184
185impl<'a> Deref for Command<'a> {
186    type Target = Vec<Store<'a>>;
187
188    fn deref(&self) -> &Self::Target {
189        &self.stores
190    }
191}
192
193impl DerefMut for Command<'_> {
194    fn deref_mut(&mut self) -> &mut Self::Target {
195        &mut self.stores
196    }
197}
198
199impl HelpDisplay for Command<'_> {
200    fn gen_help<'a, P>(&self, policy: &P) -> Option<Cow<'a, str>>
201    where
202        Self: 'a,
203        P: HelpPolicy<'a, Self>,
204    {
205        policy.format(self)
206    }
207}
208
209pub struct AddStore2Block<'a, 'b> {
210    store: Store<'a>,
211
212    block: &'b mut Block<'a, Cow<'a, str>>,
213
214    stores: &'b mut Vec<Store<'a>>,
215
216    added: bool,
217}
218
219impl<'a, 'b> AddStore2Block<'a, 'b> {
220    pub fn new<S: Into<Cow<'a, str>>>(
221        block: &'b mut Block<'a, Cow<'a, str>>,
222        stores: &'b mut Vec<Store<'a>>,
223        name: S,
224    ) -> Self {
225        let mut store = Store::default();
226
227        store.set_optional(true);
228        store.set_name(name);
229        Self {
230            block,
231            store,
232            stores,
233            added: false,
234        }
235    }
236
237    pub fn set_optional(&mut self, optional: bool) -> &mut Self {
238        self.store.set_optional(optional);
239        self
240    }
241
242    pub fn set_position(&mut self, position: bool) -> &mut Self {
243        self.store.set_position(position);
244        self
245    }
246
247    pub fn set_hint<S: Into<Cow<'a, str>>>(&mut self, hint: S) -> &mut Self {
248        self.store.set_hint(hint);
249        self
250    }
251
252    pub fn set_help<S: Into<Cow<'a, str>>>(&mut self, help: S) -> &mut Self {
253        self.store.set_help(help);
254        self
255    }
256
257    pub fn set_name<S: Into<Cow<'a, str>>>(&mut self, name: S) -> &mut Self {
258        self.store.set_name(name);
259        self
260    }
261
262    pub fn set_type<S: Into<Cow<'a, str>>>(&mut self, type_name: S) -> &mut Self {
263        self.store.set_type(type_name);
264        self
265    }
266
267    pub fn submit(mut self) {
268        if !self.added {
269            let store = std::mem::take(&mut self.store);
270
271            self.block.attach(store.name());
272            self.stores.push(store);
273            self.added = true;
274        }
275    }
276}
277
278impl Drop for AddStore2Block<'_, '_> {
279    fn drop(&mut self) {
280        if !self.added {
281            let store = std::mem::take(&mut self.store);
282
283            self.block.attach(store.name());
284            self.stores.push(store);
285            self.added = true;
286        }
287    }
288}
289
290pub struct BlockMut<'a, 'b> {
291    block: Block<'a, Cow<'a, str>>,
292
293    cmd: &'b mut Command<'a>,
294
295    added: bool,
296}
297
298impl<'a, 'b> BlockMut<'a, 'b> {
299    pub fn new<S: Into<Cow<'a, str>>>(cmd: &'b mut Command<'a>, name: S) -> Self {
300        let mut opt = Block::default();
301
302        opt.set_name(name);
303        Self {
304            cmd,
305            block: opt,
306            added: false,
307        }
308    }
309
310    pub fn attach<S: Into<Cow<'a, str>>>(&mut self, name: S) -> Result<&mut Self, Error> {
311        let name = name.into();
312
313        if self.cmd.find_store(name.clone()).is_none() {
314            Err(Error::InvalidStoreName(name.to_string()))
315        } else if self.block.iter().any(|v| v == &name) {
316            Err(Error::DuplicatedStoreName(name.to_string()))
317        } else {
318            self.block.attach(name);
319            Ok(self)
320        }
321    }
322
323    pub fn set_hint<S: Into<Cow<'a, str>>>(&mut self, hint: S) -> &mut Self {
324        self.block.set_hint(hint);
325        self
326    }
327
328    pub fn set_help<S: Into<Cow<'a, str>>>(&mut self, help: S) -> &mut Self {
329        self.block.set_help(help);
330        self
331    }
332
333    pub fn set_foot<S: Into<Cow<'a, str>>>(&mut self, footer: S) -> &mut Self {
334        self.block.set_foot(footer);
335        self
336    }
337
338    pub fn set_head<S: Into<Cow<'a, str>>>(&mut self, header: S) -> &mut Self {
339        self.block.set_head(header);
340        self
341    }
342
343    pub fn set_name<S: Into<Cow<'a, str>>>(&mut self, name: S) -> &mut Self {
344        self.block.set_name(name);
345        self
346    }
347
348    pub fn new_store<S: Into<Cow<'a, str>>>(&mut self, store: S) -> AddStore2Block<'a, '_> {
349        let block = &mut self.block;
350        let stores = &mut self.cmd.stores;
351
352        AddStore2Block::new(block, stores, store)
353    }
354
355    pub fn submit(mut self) {
356        if !self.added {
357            let block = std::mem::take(&mut self.block);
358
359            self.cmd.add_block(block).unwrap();
360            self.added = true;
361        }
362    }
363}
364
365impl Drop for BlockMut<'_, '_> {
366    fn drop(&mut self) {
367        if !self.added {
368            let block = std::mem::take(&mut self.block);
369            let cmd_name = self.cmd.name();
370
371            self.cmd
372                .add_block(block)
373                .unwrap_or_else(|_| panic!("Can not add block to Command {cmd_name}"));
374        }
375    }
376}