1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
//! A simple, lighweight crate to parse command line arguments. Inspired by its javascript equivalent, commander.js.
//!
//! This crate is relatively similar in syntax to the said library and is easy to get started with. It presents a builder interface to work with and can easily be extended to suit your needs.
//! The crate only offers a builder interface, no derive features, if you're looking such features or something more powerful, you should probably check out `clap`.
//!
//! There are three main constructs you need to be aware of when using this crate. `Program`, `Event` and `Cmd`. A program is what you actually create. An instance of your, well program, It contains a few fields, some for metadata such as `version`, `author` and `about` and the most important field, the `cmds` field which is a vector of `Cmds`
//! .
//! Cmds on the other hand are exactly what they sound like. They contain all the functionality for a given command.
//! Events are a construct that can be used to extend the program. As will be demonstrated below.
//!
//! There are other constructs such as `Themes` and `Patterns` that can also be ussed to extend and customize the default program behavior.
//!
//! The following is a full-fleged example of how the crate can be used:
//!
//!
//! ```should_panic
//!
//!
//! use cmder::{Program, Event, Pattern, PredefinedThemes};
//!
//! let mut program = Program::new();
//!
//! program.version("0.20").description("Some awesome cli");
//!
//! program
//!     .command("test <app-name> [optional-val]")
//!     .alias("-t")
//!     .description("A test command")
//!     .option("-a --all", "Test everything in the app")
//!     .option(
//!         "-p --priority-level <priority-value>",
//!         "Set the priority level when testing",
//!     )
//!     .action(|vals, config| {
//!         dbg!(vals);
//!         dbg!(config);
//!     })
//!     .build(&mut program);
//!
//! program
//!     .command("new <app-name>")
//!     .alias("n")
//!     .description("A command for creating new projects.")
//!     .option("-g --git", " Whether to initialized the project with git.")
//!     .option("-s  --skip ", " Skips installing the dependencies")
//!      .action(|vals, config| {
//!          dbg!(vals);
//!          dbg!(config);
//!      })
//!      .build(&mut program);
//!
//!
//!  program.on(Event::MissingArgument, |p, v| {
//!     let params: Vec<_> = v.split(',').collect();
//!     let msg = format!("You are missing a required argument: {}", params[1]);
//!     let cmd = p.get_cmd(params[0]).unwrap();
//!     cmd.output_command_help(p, &msg);
//!  });
//!
//!
//!  program.on(Event::OutputHelp, |_p, _v| {
//!      println!("The help listener acts differently, help still gets printed out")
//!  });
//!
//!
//!  program.on(Event::OutputVersion, |p, v| {
//!      println!("You are using version {} of my program", v);
//!      println!("This program was authored by: {}", p.get_author());
//!  });
//!
//!
//!  program.on(Event::OutputVersion, |_p, _v| {
//!      println!("A single event can have multiple callbacks, this will get invoked after the one above it.");
//!  });
//!
//!
//!  program.on(Event::UnknownCommand, |_p, v| {
//!      println!("Your command was not recognized {}", v);
//!  });
//!
//!  program.set_pattern(Pattern::Standard);
//!
//!  program.set_theme(PredefinedThemes::Plain);
//!
//!  program.parse();
//! ```
//! The program.parse() method should be the very last thing to call. It doesn't take any args. If any custom event listeners are called after the parse method, they will be ignored.
//!
//! Assuming we have a binary crate called `bolt` with the above code in its main function and we run the following command:
//! ```bash
//! bolt test appOne -a -p 1
//! ```
//!
//! When the program gets executed, the closure in the action method gets invoked and we get the following output:
//!
//! ```bash
//! [src\bin\bolt.rs:19] vals = {  
//!     "app_name": "appOne",       
//! }
//! [src\bin\bolt.rs:20] config = {
//!    "priority_value": "1",      
//!    "all": "true",
//! }
//! ```
//!
//! Any parameters starting with angle brackets < > are marked as required and one with [ ] are not. Hence, in the above snippets, we did not include the optional-val and the code worked well without throwing any errors. However, we can include the optional val as shown below and the code will still work.
//!
//! ```bash
//! bolt test appOne optionalName -a -p 1
//! ```
//!
//! And we get the following output:
//!
//! ```bash
//! [src\bin\bolt.rs:19] vals = {  
//!     "app_name": "appOne",       
//!     "optional_val": "optionalName",
//! }
//! [src\bin\bolt.rs:20] config = {
//!     "all": "true",
//!     "priority_value": "1",      
//! }
//! ```
//!
//! There are a few important things to note:
//! - For any flags that receive a parameter, the name of the param will be returned in the hashmap containing flags metadata, while flags that dont have any input will simply have the value true.
//! - The names of the values and the flag params get transformed into a rust-friendly manner(snake_cased)
//! - Required parameters are enclosed in angle brackets while optional ones in square brackets
//!
//! The crate can also be easily extended, to override or modify the default behavior. This is done by the use of `Event Listeners` which are simply closures of the type Listener where:
//! `type Listener = fn(&Program, String) -> ();`
//!
//! As shown, these listeners take in a ref to the program and a string which is a different value depending on the event being referred to.
//! These listeners are set by invoking the .on() method on the instance of the program.
//!
//! For instance, when the -v flag is passed to the program, the program simply prints the version and exits. This can easily be modified in the following way:
//!
//! ```
//! use cmder::{Event, Program};
//!
//! let mut program = Program::new();
//!
//! //...
//!
//! program.on(Event::OutputVersion, |p, v| {
//!     println!("You are using version {} of my program", v);
//!     println!("This program was authored by: {}", p.get_author());
//! });
//!
//! //...
//!
//! ```
//!
//! In the above event, the string that gets passed to the callback closure is the actual version of the program. Do note that when you set a custom listener, the default behavior is overriden and you have to perform all the desired actions. This is true for all events apart from the `Event::OutputHelp`. In this special case, the help informartion first gets printed out, then your callbacks are invoked.
//!
//! All available events are found in the `Event` enum in the `program.rs` module.
//!
//! Here are some more examples of using event listeners:
//!
//! ```
//! use cmder::{Event, Program};
//!
//! let mut program = Program::new();
//!
//! //...
//!
//! program.on(Event::MissingArgument, |p, v| {
//!     // the value returned contains the name of the resolved command, and the name of the missing argument
//!     let params: Vec<_> = v.split(',').collect();
//!
//!     // the missing argument name is the second value
//!     let msg = format!("You are missing a required argument: {}", params[1]);
//!
//!     // you can use the `get_cmd` method to get a ref to the command and invoke the `output_command_help`
//!     // this is equivalent to the default behavior
//!     let cmd = p.get_cmd(params[0]).unwrap();
//!     cmd.output_command_help(p, &msg);
//! });
//!
//! //...
//!
//!
//! program.on(Event::OutputHelp, |_p, _v| {
//!     // Here v is an empty string since there's nothing to pass
//!     // The help listener acts differently, your callbacks are invoked after the help info is printed out
//!     println!("This line gets printed out after all the help information")
//! });
//!
//!
//! //...
//!
//! program.on(Event::UnknownCommand, |_p, v| {
//!     // The value of v is the unrecognized command
//!
//!     // If the command is unrecognized, you can redirect the command elsewhere
//!     let args: Vec<String> = std::env::args().collect();
//!     custom_handler(&args);
//!
//!     // Alternatively, you can define a custom function to suggest commands:
//!     suggest_commands(&v);
//!
//!     // Or you could simply print out a warning, as is the default behavior:
//!     println!("Unknown Command: {}", v);
//!
//! });
//!
//! fn custom_handler(args: &Vec<String>) {
//!     // custom handling
//! }
//!
//! fn suggest_commands(_cmd: &String) {
//!     // suggest commands logic
//! }
//!
//! //...
//!
//! ```
//!
//! Apart from customizing the default behavior of the program, you can also customize the look and feel by using Patterns and Themes.
//!
//! Patterns refer to how your program presents and outputs help information. The default pattern is the `Legacy` pattern which is how most CLI's are presented
//!
//! The legacy pattern looks as shown below:
//!
//! ```bash
//! Some awesome prog
//!
//! USAGE:
//!    bolt <COMMAND> [options]
//!
//! OPTIONS:
//!    -h, --help           Output help for the program
//!    -v, --version        Output the version info for the program
//!
//! COMMANDS:
//!    test | -t            A test command
//!    new | n              A command for creating new projects.
//! ```
//!
//! The `Standard` pattern appears as shown below:
//!
//! ```bash
//! Some awesome prog
//!
//! USAGE:
//!    bolt <COMMAND> [options]
//!
//! OPTIONS:
//!    -h, --help
//!    Output help for the program
//!
//!    -v, --version
//!    Output the version info for the program
//!
//! COMMANDS:
//!    test | -t, <app-name> [optional-val]   
//!    A test command
//!
//!    new | n, <app-name>
//!    A command for creating new projects.
//! ```
//!
//! Themes can also be customized by defining your own color palette to be used when printing out information.

/// The parser modules contains all functionality for parsing arguments at the command level. It contains some submodules all involved in parsing arguments and flags.
pub mod parser;

/// The program module houses the the program struct and all its associated methods for manipulating and adjusting the program settings to customize the look and feel of your cli. It contains multiple `getters` and `setters` that can be used to get any desired values in the program.
///
/// The program module contains all functionality for parsing arguments at the program level. It resolves the target command then passes the cleaned argument to the cmd.parse() method.
pub mod program;

/// The events module contains the EventEmitter functionality and an enum containing all the possible events that can be emitted. It also contains associative methods to `emit` and `listen` to events in the Event enum. When a new instance of a program is created, the program contains an event_emitter instance.
pub mod events;

/// A module to house some utilities used by the crate itself.
pub mod utils;

/// The UI module houses the formatter module that is used to print to stdout and the themes module used to construct and define new themes.
pub mod ui;

pub use events::{Event, EventEmitter};
pub use program::Program;
pub use termcolor::Color;
pub use ui::{Designation, Formatter, FormatterRules, Pattern, PredefinedThemes, Theme};