1 /** 2 * Parsed arguments module. 3 * 4 * This module contains functionality for handling the parsed command line arguments. 5 * 6 * `ProgramArgs` instance is created and returned by `parse` function. It contains values of flags, 7 * options and arguments, which can be read with `.flag`, `.option` and `.arg` functions respectively. 8 * Those functions work on _unique names_, not on option full/short names such as `-l` or `--help`. 9 * 10 * For repeating options and arguments, plural form functions can be used: `.options`, `.args`, 11 * which return all values rather than last one. 12 * 13 * When a command or program has sub-commands returned `ProgramArgs` object forms a hierarchy, 14 * where every subcommand is another instance of `ProgramArgs`, starting from root which is program args, going down 15 * to selected sub-command. 16 * 17 * To simplify working with subcommands, you can use `on` command that allows to register command handlers 18 * with a simple interface. E.g. consider git-like tool: 19 * 20 * --- 21 * auto program = new Program("grit") 22 * .add(new Flag("v", "verbose", "verbosity")) 23 * .add(new Command("branch", "branch management") 24 * .add(new Command("add", "adds branch") 25 * .add(new Argument("name")) 26 * ) 27 * .add(new Command("rm", "removes branch") 28 * .add(new Argument("name")) 29 * ) 30 * ) 31 * ; 32 * auto programArgs = program.parse(args); 33 * programArgs 34 * .on("branch", (args) { 35 * writeln("verbosity: ", args.flag("verbose")); 36 * args.on("rm", (args) { writeln("removing branch ", args.arg("name")); }) 37 * .on("add", (args) { writeln("adding branch", args.arg("name")); }) 38 * }) 39 * --- 40 * 41 * See_Also: 42 * ProgramArgs 43 */ 44 module commandr.args; 45 46 import commandr.program; 47 48 49 /** 50 * Parsed program/command arguments. 51 * 52 * Note: All functions here work on flag/option/argument names, not short or long names. 53 * option -> options multi 54 * names 55 * commands 56 */ 57 public class ProgramArgs { 58 /// Program or command name 59 public string name; 60 61 package { 62 int[string] _flags; 63 string[][string] _options; 64 string[][string] _args; 65 ProgramArgs _parent; 66 ProgramArgs _command; 67 } 68 69 package ProgramArgs copy() { 70 ProgramArgs a = new ProgramArgs(); 71 a._flags = _flags.dup; 72 a._options = _options.dup; 73 a._args = _args.dup; 74 return a; 75 } 76 77 /** 78 * Checks for flag value. 79 * 80 * Params: 81 * name - flag name to check 82 * 83 * Returns: 84 * true if flag has been passed at least once, false otherwise. 85 * 86 * See_Also: 87 * occurencesOf 88 */ 89 public bool hasFlag(string name) { 90 return ((name in _flags) != null && _flags[name] > 0); 91 } 92 93 /// ditto 94 public alias flag = hasFlag; 95 96 /** 97 * Gets number of flag occurences. 98 * 99 * For non-repeating flags, returns either 0 or 1. 100 * 101 * Params: 102 * name - flag name to check 103 * 104 * Returns: 105 * Number of flag occurences, 0 on none. 106 * 107 * See_Also: 108 * hasFlag, flag 109 */ 110 public int occurencesOf(string name) { 111 if (!hasFlag(name)) { 112 return 0; 113 } 114 return _flags[name]; 115 } 116 117 /** 118 * Gets option value. 119 * 120 * In case of repeating option, returns last value. 121 * 122 * Params: 123 * name - name of option to get 124 * defaultValue - default value if option is not set 125 * 126 * Returns: 127 * Last option specified, or defaultValue if none 128 * 129 * See_Also: 130 * options, optionAll 131 */ 132 public string option(string name, string defaultValue = null) { 133 string[]* entryPtr = name in _options; 134 if (!entryPtr) { 135 return defaultValue; 136 } 137 138 if ((*entryPtr).length == 0) { 139 return defaultValue; 140 } 141 142 return (*entryPtr)[$-1]; 143 } 144 145 /** 146 * Gets all option values. 147 * 148 * In case of non-repeating option, returns array with one value. 149 * 150 * Params: 151 * name - name of option to get 152 * defaultValue - default value if option is not set 153 * 154 * Returns: 155 * Option values, or defaultValue if none 156 * 157 * See_Also: 158 * option 159 */ 160 public string[] optionAll(string name, string[] defaultValue = null) { 161 string[]* entryPtr = name in _options; 162 if (!entryPtr) { 163 return defaultValue; 164 } 165 return *entryPtr; 166 } 167 168 /// ditto 169 alias options = optionAll; 170 171 /** 172 * Gets argument value. 173 * 174 * In case of repeating arguments, returns last value. 175 * 176 * Params: 177 * name - name of argument to get 178 * defaultValue - default value if argument is missing 179 * 180 * Returns: 181 * Argument values, or defaultValue if none 182 * 183 * See_Also: 184 * args, argAll 185 */ 186 public string arg(string name, string defaultValue = null) { 187 string[]* entryPtr = name in _args; 188 if (!entryPtr) { 189 return defaultValue; 190 } 191 192 if ((*entryPtr).length == 0) { 193 return defaultValue; 194 } 195 196 return (*entryPtr)[$-1]; 197 } 198 199 /** 200 * Gets all argument values. 201 * 202 * In case of non-repeating arguments, returns array with one value. 203 * 204 * Params: 205 * name - name of argument to get 206 * defaultValue - default value if argument is missing 207 * 208 * Returns: 209 * Argument values, or defaultValue if none 210 * 211 * See_Also: 212 * arg 213 */ 214 public string[] argAll(string name, string[] defaultValue = null) { 215 string[]* entryPtr = name in _args; 216 if (!entryPtr) { 217 return defaultValue; 218 } 219 return *entryPtr; 220 } 221 222 /// ditto 223 alias args = argAll; 224 225 226 /** 227 * Gets subcommand arguments. 228 * 229 * See_Also: 230 * on, parent 231 */ 232 public ProgramArgs command() { 233 return _command; 234 } 235 236 /** 237 * Gets parent `ProgramArgs`, if any. 238 * 239 * See_Also: 240 * command 241 */ 242 public ProgramArgs parent() { 243 return _parent; 244 } 245 246 /** 247 * Calls `handler` if user specified `command` subcommand. 248 * 249 * Example: 250 * --- 251 * auto a = new Program() 252 * .add(new Command("test")) 253 * .parse(args); 254 * 255 * a.on("test", (a) { 256 * writeln("Test!"); 257 * }); 258 * --- 259 */ 260 public typeof(this) on(string command, scope void delegate(ProgramArgs args) handler) { 261 if (_command !is null && _command.name == command) { 262 handler(_command); 263 } 264 265 return this; 266 } 267 }