diff --git a/docs/docs/standard-lib/argparse.md b/docs/docs/standard-lib/argparse.md index a88f9dd5..89f3feee 100644 --- a/docs/docs/standard-lib/argparse.md +++ b/docs/docs/standard-lib/argparse.md @@ -24,12 +24,16 @@ To make use of the Argparse module an import is required. from Argparse import Parser; ``` -### New Parser(String, String, String) -> Parser +### New Parser(String, String, String -> Optional) -> Parser -To create a new parser instance, call the `Parser` class with the 3 required string arguments; name, description, and user provided usage. +To create a new parser instance, call the `Parser` class with the 2 required string arguments; name, description. + +You can optionally pass in a user generated usage for the Parser ```cs -var parser = Parser("prog_name", "Program to do all the things", ""); +const parser = Parser("prog_name", "Program to do all the things"); +// +const parser = Parser("prog_name", "Program to do all the things", "User defined usage string"); ``` ### Parse.addString(String, String, Bool, string -> Optional) @@ -64,7 +68,24 @@ To add a new list argument, call the method below with at least the 3 required a parser.addList("-u", "active users", true, "users"); ``` -### Parser.parse() -> Result\ +### Parser.usage() -> String + +The Parser class will create a helpful output based on the arguments added to the parser class for you, this can be used to populate a `--help` argument. + +```cs +const parser = Parser("Code!", "Some code"); +parser.addBool("--myOption", "Some useful boolean option", false); +print(parser.usage()); + +// Output +usage: Code! + Some code + + --myOption Some useful boolean option + +``` + +### Parser.parse() -> Result\ The `parse` method needs to be called to process the given flags against the configured flags. `parse` returns a `Result` value that, on success, will need to be unwrapped to access an instance of the `Args` class. @@ -78,8 +99,23 @@ const args = parser.parse().match( ); ``` -The value of type `Args` will be instantiated with fields matching the configured flags or the given metavar names. Below is an example using the list argument example from above. +The value of type `Args` will be instantiated with fields matching the configured flags or the given metavar names. + +If the option was not marked as required and a value for that given argument was not passed then it will have a `nil` value. ```cs -print("Users: {}".format(args.users)); +const parser = Parser("Code!", "Some code"); +parser.addString("--option", "Some useful string option", false); +parser.addString("--option1", "Some useful string option", false); +const args = parser.parse().unwrap(); + +print(args.option, args.option1); +``` + +CLI Input / Output: + +``` +$ dictu argparse.du --option "Hello" +hello +nil ``` diff --git a/src/optionals/argparse/argparse-source.h b/src/optionals/argparse/argparse-source.h index df5e9264..3fab8cca 100644 --- a/src/optionals/argparse/argparse-source.h +++ b/src/optionals/argparse/argparse-source.h @@ -1,5 +1,4 @@ -#define DICTU_ARGPARSE_SOURCE "import Argparse;\n" \ -"import System;\n" \ +#define DICTU_ARGPARSE_SOURCE "import System;\n" \ "\n" \ "class Args {\n" \ " init(private name, private desc) {}\n" \ @@ -7,12 +6,13 @@ "\n" \ "class Parser {\n" \ " private args;\n" \ +" private preArgs;\n" \ +" private required;\n" \ "\n" \ -" var preArgs = [];\n" \ -" var required = [];\n" \ -"\n" \ -" init(private name, private desc, private userUsage) {\n" \ +" init(private name, private desc, private userUsage = '') {\n" \ " this.args = Args(name, desc);\n" \ +" this.preArgs = [];\n" \ +" this.required = [];\n" \ " }\n" \ "\n" \ " private flagExists(flag) {\n" \ @@ -67,7 +67,11 @@ " var u = 'usage: {}\n {}\n\n'.format(this.name, this.desc);\n" \ "\n" \ " for (var i = 0; i < this.preArgs.len(); i+=1) {\n" \ -" u += ' {} {}\n'.format(this.preArgs[i]['flag'], this.preArgs[i]['desc']);\n" \ +" u += ' {} {}{}\n'.format(\n" \ +" this.preArgs[i]['flag'],\n" \ +" this.preArgs[i]['desc'],\n" \ +" this.preArgs[i]['required'] ? ' Required' : ''\n" \ +" );\n" \ " }\n" \ "\n" \ " return u;\n" \ @@ -93,6 +97,23 @@ " return false;\n" \ " }\n" \ "\n" \ +" private fillEmpty() {\n" \ +" for (var i = 0; i < this.preArgs.len(); i += 1) {\n" \ +" const arg = this.preArgs[i];\n" \ +"\n" \ +" if (arg.get('metavar') and not this.args.getAttribute(arg['metavar'])) {\n" \ +" this.args.setAttribute(arg['metavar'], nil);\n" \ +"\n" \ +" continue;\n" \ +" }\n" \ +"\n" \ +" const flag = arg['flag'].replace('-', '');\n" \ +" if (not this.args.getAttribute(flag)) {\n" \ +" this.args.setAttribute(flag, nil);\n" \ +" }\n" \ +" }\n" \ +" }\n" \ +"\n" \ " parse() {\n" \ " for (var i = 0; i < System.argv.len(); i+=1) {\n" \ " for (var j = 0; j < this.preArgs.len(); j+=1) {\n" \ @@ -115,7 +136,7 @@ " this.args.setAttribute(this.preArgs[j]['flag'].replace('-', ''), System.argv[i+1].split(','));\n" \ " }\n" \ " } else if (this.preArgs[j]['type'] == 'number') {\n" \ -" if (i == (System.argv.len() - 1) or System.argv[i+1][0] == '-') {\n" \ +" if (i == (System.argv.len() - 1)) {\n" \ " return Error('{} requires an argument'.format(System.argv[i]));\n" \ " }\n" \ "\n" \ @@ -149,6 +170,8 @@ " return Error('1 or more required flags missing');\n" \ " }\n" \ "\n" \ +" this.fillEmpty();\n" \ +"\n" \ " return Success(this.args);\n" \ " }\n" \ "}\n" \ diff --git a/src/optionals/argparse/argparse.c b/src/optionals/argparse/argparse.c index ae8098e0..e2bd18fe 100644 --- a/src/optionals/argparse/argparse.c +++ b/src/optionals/argparse/argparse.c @@ -9,8 +9,5 @@ Value createArgParseModule(DictuVM *vm) { return EMPTY_VAL; } - push(vm, OBJ_VAL(closure)); - pop(vm); - return OBJ_VAL(closure); } diff --git a/src/optionals/argparse/argparse.du b/src/optionals/argparse/argparse.du index 79912887..e9fbc747 100644 --- a/src/optionals/argparse/argparse.du +++ b/src/optionals/argparse/argparse.du @@ -1,4 +1,3 @@ -import Argparse; import System; class Args { @@ -7,12 +6,13 @@ class Args { class Parser { private args; + private preArgs; + private required; - var preArgs = []; - var required = []; - - init(private name, private desc, private userUsage) { + init(private name, private desc, private userUsage = '') { this.args = Args(name, desc); + this.preArgs = []; + this.required = []; } private flagExists(flag) { @@ -67,7 +67,11 @@ class Parser { var u = 'usage: {}\n {}\n\n'.format(this.name, this.desc); for (var i = 0; i < this.preArgs.len(); i+=1) { - u += ' {} {}\n'.format(this.preArgs[i]['flag'], this.preArgs[i]['desc']); + u += ' {} {}{}\n'.format( + this.preArgs[i]['flag'], + this.preArgs[i]['desc'], + this.preArgs[i]['required'] ? ' Required' : '' + ); } return u; @@ -93,6 +97,23 @@ class Parser { return false; } + private fillEmpty() { + for (var i = 0; i < this.preArgs.len(); i += 1) { + const arg = this.preArgs[i]; + + if (arg.get('metavar') and not this.args.getAttribute(arg['metavar'])) { + this.args.setAttribute(arg['metavar'], nil); + + continue; + } + + const flag = arg['flag'].replace('-', ''); + if (not this.args.getAttribute(flag)) { + this.args.setAttribute(flag, nil); + } + } + } + parse() { for (var i = 0; i < System.argv.len(); i+=1) { for (var j = 0; j < this.preArgs.len(); j+=1) { @@ -115,7 +136,7 @@ class Parser { this.args.setAttribute(this.preArgs[j]['flag'].replace('-', ''), System.argv[i+1].split(',')); } } else if (this.preArgs[j]['type'] == 'number') { - if (i == (System.argv.len() - 1) or System.argv[i+1][0] == '-') { + if (i == (System.argv.len() - 1)) { return Error('{} requires an argument'.format(System.argv[i])); } @@ -149,6 +170,8 @@ class Parser { return Error('1 or more required flags missing'); } + this.fillEmpty(); + return Success(this.args); } }