parmacl 0.1.0

A command line text parser. Parses a full command line string which has not already been pre-parsed into arguments by a shell.
Documentation
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
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
#![warn(missing_docs)]
//! A command line parser for Rust
//! 
//! The primary purpose of this library is to parse a full command line. That is, a string containing the complete command line.
//! It can also parse rust environment command line arguments as supplied by Rust (`std::env::Args`) however there are other libraries which
//! specialise in this and may be a better choice.
//! 
//! While the Rust standard library does not give access to the full environment command line, this library could be used to
//! parse internal commands entered within an application.
//! 
//! See [Features](#features).
//! 
//! # Usage
//! 
//! Follow the steps below to parse a command line:
//! 1. Create an enum with one variant for each type of option argument expected in the command line.
//! 1. Create an enum with one variant for each type of parameter argument expected in the command line.
//! 1. Create an instance of [parmacl::Parser](Parser).
//! 1. If necessary, set relevant properties of the Parser instance to reflect the style of the command line.
//! 1. Add a [matcher](Matcher) for all possible arguments to the parser. Tag each matcher with the appropriate enum.
//! 1. Call [Parser.parse_line(command_line)](Parser::parse_line) which will parse the command line and return a result containing
//! either a [vector of parsed arguments](Args) or an error.
//! 1. Loop through returned arguments and process each. The arguments are ordered by appearance in the command line.
//! 
//! ## Example
//! 
//! ```
//!use parmacl::{Parser, Arg, RegexOrText, OptionHasValue};
//!
//!const LINE: &str = r#""binary name" -a "1st ""Param""" -B optValue "param2" -c "C OptValue""#;
//! 
//!#[derive(Default)]
//!enum OptionEnum {
//!    #[default] A,
//!    B,
//!    C,
//!}
//!#[derive(Default)]
//!enum ParamEnum {
//!    #[default] Param1,
//!    Param2,
//!}
//! 
//!let mut parser: Parser<OptionEnum, ParamEnum> = Parser::new();
//! 
//!parser
//!    .push_new_option_matcher("optionA")
//!        .set_option_tag(OptionEnum::A)
//!        .some_option_codes(&[RegexOrText::with_text("a")]);
//! 
//!parser
//!    .push_new_option_matcher("optionB")
//!        .set_option_tag(OptionEnum::B)
//!        .some_option_codes(&[RegexOrText::with_text("b")])
//!        .set_option_has_value(OptionHasValue::IfPossible);
//! 
//!parser
//!    .push_new_option_matcher("optionC")
//!        .set_option_tag(OptionEnum::C)
//!        .some_option_codes(&[RegexOrText::with_text("c")])
//!        .set_option_has_value(OptionHasValue::Always);
//! 
//!parser
//!     .push_new_param_matcher("param1")
//!         .set_param_tag(ParamEnum::Param1)
//!         .some_param_indices(&[0]);
//! 
//!parser
//!    .push_new_param_matcher("param2")
//!        .set_param_tag(ParamEnum::Param2)
//!        .some_param_indices(&[1]);
//! 
//!let args = parser.parse_line(LINE).unwrap();
//! 
//!assert_eq!(args.len(), 6);
//! 
//!for arg in args {
//!    match arg {
//!        Arg::Binary(properties) => {
//!            assert_eq!(properties.arg_index, 0);
//!            assert_eq!(properties.value_text, "binary name");
//!            assert_eq!(properties.char_index, 0);
//!        },
//!        Arg::Option(properties) => {
//!            match properties.matcher.option_tag() {
//!                OptionEnum::A => {
//!                    // Process option A
//!                    assert_eq!(properties.matcher.name(), "optionA");
//!                    assert_eq!(properties.arg_index, 1);
//!                    assert_eq!(properties.option_index, 0);
//!                    assert_eq!(properties.code, "a");
//!                    assert_eq!(properties.value_text, None);
//!                    assert_eq!(properties.char_index, 14);
//!                },
//!                OptionEnum::B => {
//!                    // Process option B
//!                },
//!                OptionEnum::C => {
//!                    // Process option C
//!                },
//!            }
//!        }
//!        Arg::Param(properties) => {
//!            match properties.matcher.param_tag() {
//!                ParamEnum::Param1 => {
//!                    // Process parameter Param1
//!                    assert_eq!(properties.matcher.name(), "param1");
//!                    assert_eq!(properties.arg_index, 2);
//!                    assert_eq!(properties.param_index, 0);
//!                    assert_eq!(properties.value_text, "1st \"Param\"");
//!                    assert_eq!(properties.char_index, 17);
//!                },
//!                ParamEnum::Param2 => {
//!                    // Process parameter Param2
//!                },
//!            }
//!        }
//!    }
//!}
//!```
//! # Parsing environment arguments
//! 
//! Parmacl can also be used to parse the environment command line arguments passed to an application. The above example could be used to parse
//! environment arguments with the following changes.
//! 
//! Instead of using the [new()](Parser::new) constructor function, use the [with_env_args_defaults()](Parser::with_env_args_defaults) constructor.
//! This will create an instance of Parser with defaults suitable for parsing environment arguments.
//!```
//!# use parmacl::{Parser, Arg, RegexOrText, OptionHasValue};
//!#
//!# const LINE: &str = r#""binary name" -a "1st ""Param""" -B optValue "param2" -c "C OptValue""#;
//!#  
//!# #[derive(Default)]
//!# enum OptionEnum {
//!#     #[default] A,
//!#     B,
//!#     C,
//!# }
//!# #[derive(Default)]
//!# enum ParamEnum {
//!#     #[default] Param1,
//!#     Param2,
//!# }
//!#  
//! let mut parser: Parser<OptionEnum, ParamEnum> = Parser::with_env_args_defaults();
//!#  
//!# parser
//!#     .push_new_option_matcher("optionA")
//!#         .set_option_tag(OptionEnum::A)
//!#         .some_option_codes(&[RegexOrText::with_text("a")]);
//!#  
//!# parser
//!#     .push_new_option_matcher("optionB")
//!#         .set_option_tag(OptionEnum::B)
//!#         .some_option_codes(&[RegexOrText::with_text("b")])
//!#         .set_option_has_value(OptionHasValue::IfPossible);
//!#  
//!# parser
//!#     .push_new_option_matcher("optionC")
//!#         .set_option_tag(OptionEnum::C)
//!#         .some_option_codes(&[RegexOrText::with_text("c")])
//!#         .set_option_has_value(OptionHasValue::Always);
//!#  
//!# parser
//!#      .push_new_param_matcher("param1")
//!#          .set_param_tag(ParamEnum::Param1)
//!#          .some_param_indices(&[0]);
//!#  
//!# parser
//!#     .push_new_param_matcher("param2")
//!#         .set_param_tag(ParamEnum::Param2)
//!#         .some_param_indices(&[1]);
//!#  
//!# let args = parser.parse_env().unwrap();
//!#  
//!# // assert_eq!(args.len(), 6); // commented out to allow documentation tests to pass
//!#  
//!# for arg in args {
//!#     match arg {
//!#         Arg::Binary(properties) => {
//!#             assert_eq!(properties.arg_index, 0);
//!#             // assert_eq!(properties.value_text, "binary name"); // commented out to allow documentation tests to pass
//!#             assert_eq!(properties.env_line_approximate_char_index, 0);
//!#         },
//!#         Arg::Option(properties) => {
//!#             match properties.matcher.option_tag() {
//!#                 OptionEnum::A => {
//!#                     // Process option A
//!#                     assert_eq!(properties.matcher.name(), "optionA");
//!#                     assert_eq!(properties.arg_index, 1);
//!#                     assert_eq!(properties.option_index, 0);
//!#                     assert_eq!(properties.code, "a");
//!#                     assert_eq!(properties.value_text, None);
//!#                     assert_eq!(properties.env_line_approximate_char_index, 14);
//!#                 },
//!#                 OptionEnum::B => {
//!#                     // Process option B
//!#                 },
//!#                 OptionEnum::C => {
//!#                     // Process option C
//!#                 },
//!#             }
//!#         }
//!#         Arg::Param(properties) => {
//!#             match properties.matcher.param_tag() {
//!#                 ParamEnum::Param1 => {
//!#                     // Process parameter Param1
//!#                     assert_eq!(properties.matcher.name(), "param1");
//!#                     assert_eq!(properties.arg_index, 2);
//!#                     assert_eq!(properties.param_index, 0);
//!#                     assert_eq!(properties.value_text, "1st \"Param\"");
//!#                     assert_eq!(properties.env_line_approximate_char_index, 17);
//!#                 },
//!#                 ParamEnum::Param2 => {
//!#                     // Process parameter Param2
//!#                 },
//!#             }
//!#         }
//!#     }
//!# }
//!```
//! Use the [parse_env()](Parser::parse_env) function instead of the [parse()](Parser::parse_line) function.
//!```
//!# use parmacl::{Parser, Arg, RegexOrText, OptionHasValue};
//!#
//!# const LINE: &str = r#""binary name" -a "1st ""Param""" -B optValue "param2" -c "C OptValue""#;
//!#  
//!# #[derive(Default)]
//!# enum OptionEnum {
//!#     #[default] A,
//!#     B,
//!#     C,
//!# }
//!# #[derive(Default)]
//!# enum ParamEnum {
//!#     #[default] Param1,
//!#     Param2,
//!# }
//!#  
//!# let mut parser: Parser<OptionEnum, ParamEnum> = Parser::with_env_args_defaults();
//!#  
//!# parser
//!#     .push_new_option_matcher("optionA")
//!#         .set_option_tag(OptionEnum::A)
//!#         .some_option_codes(&[RegexOrText::with_text("a")]);
//!#  
//!# parser
//!#     .push_new_option_matcher("optionB")
//!#         .set_option_tag(OptionEnum::B)
//!#         .some_option_codes(&[RegexOrText::with_text("b")])
//!#         .set_option_has_value(OptionHasValue::IfPossible);
//!#  
//!# parser
//!#     .push_new_option_matcher("optionC")
//!#         .set_option_tag(OptionEnum::C)
//!#         .some_option_codes(&[RegexOrText::with_text("c")])
//!#         .set_option_has_value(OptionHasValue::Always);
//!#  
//!# parser
//!#      .push_new_param_matcher("param1")
//!#          .set_param_tag(ParamEnum::Param1)
//!#          .some_param_indices(&[0]);
//!#  
//!# parser
//!#     .push_new_param_matcher("param2")
//!#         .set_param_tag(ParamEnum::Param2)
//!#         .some_param_indices(&[1]);
//!#  
//! let args = parser.parse_env().unwrap();
//!#  
//!# // assert_eq!(args.len(), 6); // commented out to allow documentation tests to pass
//!#  
//!# for arg in args {
//!#     match arg {
//!#         Arg::Binary(properties) => {
//!#             assert_eq!(properties.arg_index, 0);
//!#             // assert_eq!(properties.value_text, "binary name"); // commented out to allow documentation tests to pass
//!#             assert_eq!(properties.env_line_approximate_char_index, 0);
//!#         },
//!#         Arg::Option(properties) => {
//!#             match properties.matcher.option_tag() {
//!#                 OptionEnum::A => {
//!#                     // Process option A
//!#                     assert_eq!(properties.matcher.name(), "optionA");
//!#                     assert_eq!(properties.arg_index, 1);
//!#                     assert_eq!(properties.option_index, 0);
//!#                     assert_eq!(properties.code, "a");
//!#                     assert_eq!(properties.value_text, None);
//!#                     assert_eq!(properties.env_line_approximate_char_index, 14);
//!#                 },
//!#                 OptionEnum::B => {
//!#                     // Process option B
//!#                 },
//!#                 OptionEnum::C => {
//!#                     // Process option C
//!#                 },
//!#             }
//!#         }
//!#         Arg::Param(properties) => {
//!#             match properties.matcher.param_tag() {
//!#                 ParamEnum::Param1 => {
//!#                     // Process parameter Param1
//!#                     assert_eq!(properties.matcher.name(), "param1");
//!#                     assert_eq!(properties.arg_index, 2);
//!#                     assert_eq!(properties.param_index, 0);
//!#                     assert_eq!(properties.value_text, "1st \"Param\"");
//!#                     assert_eq!(properties.env_line_approximate_char_index, 17);
//!#                 },
//!#                 ParamEnum::Param2 => {
//!#                     // Process parameter Param2
//!#                 },
//!#             }
//!#         }
//!#     }
//!# }
//!```
//! Since the shell will already have parsed the command line, and passed the individual arguments to the application, the parser can
//! only guess the position of each argument in the command line. Use property `env_line_approximate_char_index` instead of `char_index`
//! in [ParamProperties](ParamProperties) or [OptionProperties](OptionProperties) to get the approximate position of a the argument in
//! the command line.
//!```
//!# use parmacl::{Parser, Arg, RegexOrText, OptionHasValue};
//!#
//!# const LINE: &str = r#""binary name" -a "1st ""Param""" -B optValue "param2" -c "C OptValue""#;
//!#  
//!# #[derive(Default)]
//!# enum OptionEnum {
//!#     #[default] A,
//!#     B,
//!#     C,
//!# }
//!# #[derive(Default)]
//!# enum ParamEnum {
//!#     #[default] Param1,
//!#     Param2,
//!# }
//!#  
//!# let mut parser: Parser<OptionEnum, ParamEnum> = Parser::with_env_args_defaults();
//!#  
//!# parser
//!#     .push_new_option_matcher("optionA")
//!#         .set_option_tag(OptionEnum::A)
//!#         .some_option_codes(&[RegexOrText::with_text("a")]);
//!#  
//!# parser
//!#     .push_new_option_matcher("optionB")
//!#         .set_option_tag(OptionEnum::B)
//!#         .some_option_codes(&[RegexOrText::with_text("b")])
//!#         .set_option_has_value(OptionHasValue::IfPossible);
//!#  
//!# parser
//!#     .push_new_option_matcher("optionC")
//!#         .set_option_tag(OptionEnum::C)
//!#         .some_option_codes(&[RegexOrText::with_text("c")])
//!#         .set_option_has_value(OptionHasValue::Always);
//!#  
//!# parser
//!#      .push_new_param_matcher("param1")
//!#          .set_param_tag(ParamEnum::Param1)
//!#          .some_param_indices(&[0]);
//!#  
//!# parser
//!#     .push_new_param_matcher("param2")
//!#         .set_param_tag(ParamEnum::Param2)
//!#         .some_param_indices(&[1]);
//!#  
//!# let args = parser.parse_env().unwrap();
//!#  
//!# // assert_eq!(args.len(), 6); // commented out to allow documentation tests to pass
//!#  
//!# for arg in args {
//!#     match arg {
//!#         Arg::Binary(properties) => {
//!#             assert_eq!(properties.arg_index, 0);
//!#             // assert_eq!(properties.value_text, "binary name"); // commented out to allow documentation tests to pass
//!#             assert_eq!(properties.env_line_approximate_char_index, 0);
//!#         },
//!#         Arg::Option(properties) => {
//!#             match properties.matcher.option_tag() {
//!                 OptionEnum::A => {
//!                     // Process option A
//!                     assert_eq!(properties.matcher.name(), "optionA");
//!                     assert_eq!(properties.arg_index, 1);
//!                     assert_eq!(properties.option_index, 0);
//!                     assert_eq!(properties.code, "a");
//!                     assert_eq!(properties.value_text, None);
//!                     assert_eq!(properties.env_line_approximate_char_index, 14);
//!                 },
//!#                 OptionEnum::B => {
//!#                     // Process option B
//!#                 },
//!#                 OptionEnum::C => {
//!#                     // Process option C
//!#                 },
//!#             }
//!#         }
//!#         Arg::Param(properties) => {
//!#             match properties.matcher.param_tag() {
//!#                 ParamEnum::Param1 => {
//!#                     // Process parameter Param1
//!#                     assert_eq!(properties.matcher.name(), "param1");
//!#                     assert_eq!(properties.arg_index, 2);
//!#                     assert_eq!(properties.param_index, 0);
//!#                     assert_eq!(properties.value_text, "1st \"Param\"");
//!#                     assert_eq!(properties.env_line_approximate_char_index, 17);
//!#                 },
//!#                 ParamEnum::Param2 => {
//!#                     // Process parameter Param2
//!#                 },
//!#             }
//!#         }
//!#     }
//!# }
//!```
//! # Understanding the command line
//! 
//! Parmacl considers a command line to have 3 types of arguments
//! * **Binary name**\
//! This normally is the first argument in the command line and is normally the path to the application's executable file (binary).
//! * **Parameters**\
//! Strings which the application will interpret. Parameters are typically identified by their order in the command line. In the above
//! [example](#example), `"1st ""Param"""` and `"param2"` are parameters.
//! * **Options**\
//! An option is an argument identified by a code.  As such it can be placed anywhere in the command line. It can optionally have a value.
//! If it does not have a value, it behaves like a flag/boolean.  In the above [example](#example), `-a` is an option with code `a` that
//! behaves like a flag. The options `-B optValue` (code `B`) and `-c "C OptValue"` (code `c`) are options with respective values
//! `optValue` and `C OptValue`.
//! 
//! Note that these arguments do not necessarily correspond to environment arguments created by a shell and passed to an application.
//! For example, an option with a value is identified by Parmacl as one argument whereas the shell may identify it as 2 arguments
//! (depending on what character is used to separate option values from the option code).
//! 
//! # Overview of parsing
//! 
//! Before parsing a command line, the parser needs to be configured with the style of the command line.  This includes things like
//! specifying whether parameters and option values can be quoted, whether quotes can be included in quoted parameters and option values,
//! specifying escaping of special characters.
//! 
//! It also needs to be configured with a list of [matchers](Matcher). A matcher is a struct with a set of filters. The filters are used
//! to match arguments identified by the parser. An argument needs to meet all filter conditions in order for it to be 'matched'
//!
//! When a command line is parsed, the parser will identify arguments based on its configured style.  The arguments are identified in order
//! from start to end of the command line.  As each argument is identified, it is matched against one of the [matchers](Matcher) assigned to
//! the parser. It is possible for an argument to match more than one matcher.  The parser will attempt to match each argument to matchers
//! in order of matchers in the parser's matcher list. Accordingly, more specific matchers should be inserted earlier in this list.
//! 
//! When an argument is matched, the parser generates a corresponding [Arg](Arg) variant with details of the argument. For parameter and
//! option arguments, the variant is also assigned a copy of either the respective Matcher's [param_tag](Matcher::param_tag) or
//! [option_tag](Matcher::option_tag) value.
//! 
//! These [Arg](Arg) variants are stored in an array (in same order as the arguments in the command line) which is returned as the success
//! result.
//! 
//! All arguments must be matched. If an argument is not matched, then the user specified an unsupported parameter or option and an
//! [unmatched parameter](ParseErrorTypeId::UnmatchedParam) or [unmatched option](ParseErrorTypeId::UnmatchedOption) will be returned.
//! 
//! If the parser detects an error in the command line, an error result will be returned containing a [ParseError](ParseError) struct.
//! This struct [identifies](ParseErrorTypeId) the reason for the error and where in the line the error occurred.
//! 
//! # Main types
//! 
//! * [Parser](Parser)\
//! The main object. To parse a command line, create an instance of this, set its properties to reflect the style of the command line,
//! assign matchers and then call one its parse functions. The result will either be the array of arguments or an error object.
//! * [Matcher](Matcher)\
//! Each argument must be matched against a matcher.  Typically one matcher is created for each argument however matchers can also
//! be used to match multiple arguments.
//! * [Arg](Arg)\
//! An enum with 3 variants: Binary, Param, Option. The Parser's parse functions return an array of these variants - each of which
//! identify an argument the parser found in the command line.
//! * [ArgProperties](ArgProperties)\
//! A trait shared by structs [BinaryProperties](BinaryProperties), [ParamProperties](ParamProperties) and
//! [OptionProperties](OptionProperties). Instances of these structs are associated with the respective [Arg](Arg) variants returned
//! by the parse function and provide details about each identified argument.
//! * [RegexOrText](RegexOrText)\
//! A struct representing either a Regex or text (string). An instance of RegexOrText can be assigned to the
//! [option_codes](Matcher::option_codes) or [value_text](Matcher::value_text) Matcher filter properties and determines whether the
//! filtering is by text or Regex.
//! * [ParseError](ParseError)\
//! The struct returned with an Error result from a parse function. Specifies the type of error and where in the line the error
//! occurred.
//! 
//! # Features
//! 
//! * Command line parsing
//! * Environment arguments parsing
//! * Command Line Style
//!     * Specify which character(s) can be used to quote parameters and option values
//!     * Specify which character(s) can be used to announce an option
//!     * Specify which character(s) can be used to announce an option value (space character can be included)
//!     * Specify which character(s) will terminate parsing of a command line
//!     * Case sensitivity when matching parameters, option codes and option values
//!     * Whether options with code that have more than one character, require 2 announcer characters (eg --anOpt)
//!     * Use double quotes to embed quote characters within quoted parameters and option values
//!     * Use escaping to include characters with special meaning
//!     * Whether first argument in command line is the binary's name/path
//! * Argument Matching
//!     * Parameter or Option
//!     * Argument indices
//!     * Parameter indices
//!     * Parameter text (string or Regex)
//!     * Option indices
//!     * Option codes (string or Regex)
//!     * Whether option has value (None, IfPossible, Always)
//!     * Option value text (string or Regex)
//!     * Whether option value can start with an option announcer character
//! * Tag parameters and options arguments with with any enum (or any other type) from matcher for easy identification
//! * Parse error result has properties detailing the type of error and where it occurred.



#![allow(clippy::collapsible_else_if)]

mod env_char;
mod parse_error_type_id;
mod parse_error;
mod regex_or_text;
mod matcher;
mod arg;
mod parser;

mod parse_state;

pub use parse_error_type_id::{
    ParseErrorTypeId,
};

pub use parse_error::{
    ParseError,
};

pub use regex_or_text::{
    RegexOrText,
};

pub use matcher:: {
    Matcher,
    Matchers,
    DefaultTagType,
    OptionHasValue,
    MatchArgTypeId,
    DEFAULT_OPTION_HAS_VALUE,
};

pub use arg::{
    ArgProperties,
    BinaryProperties,
    OptionProperties,
    ParamProperties,
    Arg,
    Args,
};

pub use parser::{
    Parser,
    EscapeableLogicalChar,
    DEFAULT_LINE_QUOTE_CHARS,
    DEFAULT_LINE_OPTION_ANNOUNCER_CHARS,
    DEFAULT_LINE_OPTION_CODES_CASE_SENSITIVE,
    DEFAULT_LINE_MULTI_CHAR_OPTION_CODE_REQUIRES_DOUBLE_ANNOUNCER,
    DEFAULT_LINE_OPTION_VALUE_ANNOUNCER_CHARS,
    DEFAULT_LINE_OPTION_VALUES_CASE_SENSITIVE,
    DEFAULT_LINE_PARAMS_CASE_SENSITIVE,
    DEFAULT_LINE_EMBED_QUOTE_CHAR_WITH_DOUBLE,
    DEFAULT_LINE_ESCAPE_CHAR,
    DEFAULT_LINE_ESCAPEABLE_LOGICAL_CHARS,
    DEFAULT_LINE_ESCAPEABLE_CHARS,
    DEFAULT_LINE_PARSE_TERMINATE_CHARS,
    DEFAULT_LINE_FIRST_ARG_IS_BINARY,
    DEFAULT_ENV_ARGS_QUOTE_CHARS,
    DEFAULT_ENV_ARGS_OPTION_ANNOUNCER_CHARS,
    DEFAULT_ENV_ARGS_OPTION_CODES_CASE_SENSITIVE,
    DEFAULT_ENV_ARGS_OPTION_CODE_CAN_BE_EMPTY,
    DEFAULT_ENV_ARGS_MULTI_CHAR_OPTION_CODE_REQUIRES_DOUBLE_ANNOUNCER,
    DEFAULT_ENV_ARGS_OPTION_VALUE_ANNOUNCER_CHARS,
    DEFAULT_ENV_ARGS_OPTION_VALUES_CASE_SENSITIVE,
    DEFAULT_ENV_ARGS_PARAMS_CASE_SENSITIVE,
    DEFAULT_ENV_ARGS_EMBED_QUOTE_CHAR_WITH_DOUBLE,
    DEFAULT_ENV_ARGS_ESCAPE_CHAR,
    DEFAULT_ENV_ARGS_ESCAPEABLE_LOGICAL_CHARS,
    DEFAULT_ENV_ARGS_ESCAPEABLE_CHARS,
    DEFAULT_ENV_ARGS_PARSE_TERMINATE_CHARS,
    DEFAULT_ENV_ARGS_FIRST_ARG_IS_BINARY,
};