# argparse.nas # 2023/12/7 by ValKmjolnir use std.padding; var new = func(description) { var _arg = globals.arg; var parser = { description: description, subparser: [], command_list: [], add_command: func(long, short, help, need_arg = false, need_nargs = false) { return _add_command(parser, long, short, help, need_arg, need_nargs); }, add_subparser: func(name, help) { return _add_subparser(parser, name, help); }, parse_args: func() { var result_hash = {}; _parse(parser, _arg, result_hash); return result_hash; } }; parser.add_command("--help", "-h", "Get help info and exit"); return parser; } var _new_sub_parser = func(description) { var parser = { description: description, subparser: [], command_list: [], add_command: func(long, short, help, need_arg = false, need_nargs = false) { return _add_command(parser, long, short, help, need_arg, need_nargs); }, add_subparser: func(name, help) { return _add_subparser(parser, name, help); } }; parser.add_command("--help", "-h", "Get help info and exit"); return parser; } var _help = func(parser) { println(parser.description, "\n"); if (size(parser.subparser)>0) { println("Subcommand:"); var max_pad_length = 0; var info_pairs = []; foreach(var cmd; parser.subparser) { var info = " "~cmd.name; append(info_pairs, {info: info, help: cmd.parser.description}); info_length = size(info); max_pad_length = max_pad_length>info_length? max_pad_length:info_length; } foreach(var pair; info_pairs) { println(padding.rightpad(pair.info, max_pad_length), " ", pair.help); } println(); } if (size(parser.command_list)>0) { println("Options:"); var max_pad_length = 0; var info_pairs = []; foreach(var cmd; parser.command_list) { if (cmd.need_nargs) { var info = " "~cmd.full_name~" [args...] "~cmd.short_name~" [args...]"; append(info_pairs, {info: info, help: cmd.help}); } elsif (cmd.need_arg) { var info = " "~cmd.full_name~" arg "~cmd.short_name~" arg"; append(info_pairs, {info: info, help: cmd.help}); } else { var info = " "~cmd.full_name~" "~cmd.short_name; append(info_pairs, {info: info, help: cmd.help}); } var info_length = size(info); max_pad_length = max_pad_length>info_length? max_pad_length:info_length; } foreach(var pair; info_pairs) { println(padding.rightpad(pair.info, max_pad_length), " ", pair.help); } } } var _in_list = func(arginfo, command_list) { foreach(var cmd; command_list) { if (arginfo==cmd.full_name or arginfo==cmd.short_name) { return true; } } return false; } var _parse = func(parser, args, result_hash) { if (size(args)==0) { println("Require more command, use \"--help\" to get help.\n"); _help(parser); exit(0); } foreach(var subparser; parser.subparser) { if (subparser.name==args[0]) { result_hash[subparser.name] = true; _parse(subparser.parser, size(args)>1? args[1:]:[], result_hash); return; } } for(var i = 0; i<size(args); i += 1) { var this_arg = args[i]; var find_command_flag = false; foreach(var cmd; parser.command_list) { if (this_arg=="--help" or this_arg=="-h") { _help(parser); exit(0); } if (this_arg==cmd.full_name or this_arg==cmd.short_name) { find_command_flag = true; if (cmd.need_nargs) { i += 1; var args_collect = []; while (i<size(args) and !_in_list(args[i], parser.command_list)) { append(args_collect, args[i]); i += 1; } i -= 1; if (!size(args_collect)) { println("Require argument(s) after command `", this_arg, "`.\n"); _help(parser); exit(0); } result_hash[cmd.full_name] = args_collect; } elsif (cmd.need_arg) { i += 1; if (i<size(args) and !_in_list(args[i], parser.command_list)) { result_hash[cmd.full_name] = args[i]; } else { println("Require argument after command `", this_arg, "`.\n"); _help(parser); exit(0); } } else { result_hash[cmd.full_name] = true; } } } if (!find_command_flag) { println("Invalid command `", this_arg, "`.\n"); _help(parser); exit(0); } } return; } var _add_command = func(parser, long, short, help, need_arg , need_nargs) { var new_command = { full_name: long, short_name: short, help: help, need_arg: need_arg, need_nargs: need_nargs }; append(parser.command_list, new_command); } var _add_subparser = func(parser, name, help) { var new_subparser = { name: name, parser: _new_sub_parser(help) }; append(parser.subparser, new_subparser); return new_subparser.parser; }