diff --git a/README.md b/README.md index 72f66ab..33f23da 100644 --- a/README.md +++ b/README.md @@ -34,9 +34,9 @@ fn print_information(command: CommandArc, args: List[String]) -> None: fn get_cat_fact(command: CommandArc, args: List[String]) -> Error: - var flags = command[].get_all_flags()[] + var flags = command[].flags[] var lover = flags.get_as_bool("lover") - if lover and lover.value(): + if lover and lover.value()[]: print("Hello fellow cat lover!") try: @@ -54,7 +54,7 @@ fn get_cat_fact(command: CommandArc, args: List[String]) -> Error: if not count: return Error("Count flag was not found.") var body = response.json() - for i in range(count.value()): + for i in range(count.value()[]): print(body[i]["text"]) else: return Error("Request failed!") @@ -98,8 +98,8 @@ fn init() -> None: description="Get some cat facts!", erroring_run=get_cat_fact, ) - cat_command.flags.add_int_flag[name="count", shorthand="c", usage="Number of facts to get."]() - cat_command.flags.add_bool_flag[name="lover", shorthand="l", usage="Are you a cat lover?"]() + cat_command.add_int_flag(name="count", shorthand="c", usage="Number of facts to get.") + cat_command.add_bool_flag(name="lover", shorthand="l", usage="Are you a cat lover?") var dog_command = Command( name="dog", @@ -116,7 +116,6 @@ fn init() -> None: fn main() -> None: init() - ``` Start by navigating to the `nested` example directory. @@ -201,7 +200,11 @@ Usage information will be printed the console by passing the `--help` flag. - Add find suggestion logic to `Command` struct. - Enable required flags. +- Add flag groups and mutually exclusive flags. +- Add subcommand groups. +- Enable usage function to return the results of a usage function upon calling wrong functions or commands. - Replace print usage with writers to enable stdout/stderr/file writing. +- Update default help command to improve available commands and flags section. ### Improvements diff --git a/examples/aliases/__init__.mojo b/examples/aliases/__init__.mojo new file mode 100644 index 0000000..e69de29 diff --git a/examples/aliases/root.mojo b/examples/aliases/root.mojo new file mode 100644 index 0000000..800d203 --- /dev/null +++ b/examples/aliases/root.mojo @@ -0,0 +1,30 @@ +from memory._arc import Arc +from prism import Flag, Command, CommandArc +from prism.vector import to_string + + +fn test(command: CommandArc, args: List[String]) -> None: + print("Pass tool, object, or thing as a subcommand!") + + +fn tool_func(command: CommandArc, args: List[String]) -> None: + print("My tool!") + + +fn init() -> None: + var root_command = Command( + name="my", + description="This is a dummy command!", + run=test, + ) + + var tool_command = Command( + name="tool", description="This is a dummy command!", run=tool_func, aliases=List[String]("object", "thing") + ) + + root_command.add_command(tool_command) + root_command.execute() + + +fn main() -> None: + init() diff --git a/prism/command.mojo b/prism/command.mojo index 6148ec3..f2daab9 100644 --- a/prism/command.mojo +++ b/prism/command.mojo @@ -24,28 +24,32 @@ fn get_args_as_list() -> List[String]: fn default_help(command: Arc[Command]) -> String: """Prints the help information for the command.""" - var cmd = command[] var builder = StringBuilder() - _ = builder.write_string(cmd.description) - _ = builder.write_string("\n\n") + _ = builder.write_string(command[].description) + + if command[].aliases: + _ = builder.write_string("\n\nAliases:") + _ = builder.write_string(sprintf("\n %s", to_string(command[].aliases))) # Build usage statement arguments depending on the command's children and flags. - var full_command = cmd._full_command() - _ = builder.write_string(sprintf("Usage:\n %s%s", full_command, String(" [args]"))) - if len(cmd.children) > 0: + var full_command = command[]._full_command() + _ = builder.write_string(sprintf("\n\nUsage:\n %s%s", full_command, String(" [args]"))) + if len(command[].children) > 0: _ = builder.write_string(" [command]") - if len(cmd.flags[]) > 0: + if len(command[].flags[]) > 0: _ = builder.write_string(" [flags]") - _ = builder.write_string("\n\nAvailable commands:\n") - for child in cmd.children: - _ = builder.write_string(sprintf(" %s\n", str(child[][]))) + if command[].children: + _ = builder.write_string("\n\nAvailable commands:\n") + for child in command[].children: + _ = builder.write_string(sprintf(" %s\n", str(child[][]))) - _ = builder.write_string("\nAvailable flags:\n") - for flag in cmd.flag_list(): - _ = builder.write_string(sprintf(" -%s, --%s %s\n", flag[][].shorthand, flag[][].name, flag[][].usage)) + if command[].flag_list(): + _ = builder.write_string("\n\nAvailable flags:\n") + for flag in command[].flag_list(): + _ = builder.write_string(sprintf(" -%s, --%s %s\n", flag[][].shorthand, flag[][].name, flag[][].usage)) - _ = builder.write_string(sprintf('Use "%s [command] --help" for more information about a command.', full_command)) + _ = builder.write_string(sprintf('\nUse "%s [command] --help" for more information about a command.', full_command)) return str(builder) @@ -70,7 +74,7 @@ fn parse_command_from_args(start: Command) -> (Command, List[String]): for arg in args: for command_ref in children: - if command_ref[][].name == arg[]: + if command_ref[][].name == arg[] or contains(command_ref[][].aliases, arg[]): command = command_ref[][] children = command.children leftover_args_start_index += 1 @@ -100,12 +104,19 @@ struct Command(CollectionElement): erroring_run: The function to run when the command is executed that returns an error. erroring_pre_run: The function to run before the command is executed that returns an error. erroring_post_run: The function to run after the command is executed that returns an error. + persisting_pre_run: The function to run before the command is executed. This persists to children. + persisting_post_run: The function to run after the command is executed. This persists to children. + persisting_erroring_pre_run: The function to run before the command is executed that returns an error. This persists to children. + persisting_erroring_post_run: The function to run after the command is executed that returns an error. This persists to children. help: The function to generate help text for the command. """ var name: String var description: String + # Aliases that can be used instead of the first word in name. + var aliases: List[String] + # Generates help text. var help: HelpFunction @@ -145,6 +156,7 @@ struct Command(CollectionElement): inout self, name: String, description: String, + aliases: List[String] = List[String](), valid_args: List[String] = List[String](), run: Optional[CommandFunction] = None, pre_run: Optional[CommandFunction] = None, @@ -163,6 +175,7 @@ struct Command(CollectionElement): self.name = name self.description = description + self.aliases = aliases self.help = help @@ -200,6 +213,7 @@ struct Command(CollectionElement): name: String, description: String, arg_validator: ArgValidator, + aliases: List[String] = List[String](), valid_args: List[String] = List[String](), run: Optional[CommandFunction] = None, pre_run: Optional[CommandFunction] = None, @@ -218,6 +232,7 @@ struct Command(CollectionElement): self.name = name self.description = description + self.aliases = aliases self.help = help @@ -250,6 +265,7 @@ struct Command(CollectionElement): fn __copyinit__(inout self, existing: Self): self.name = existing.name self.description = existing.description + self.aliases = existing.aliases self.help = existing.help @@ -279,6 +295,7 @@ struct Command(CollectionElement): fn __moveinit__(inout self, owned existing: Self): self.name = existing.name^ self.description = existing.description^ + self.aliases = existing.aliases^ self.help = existing.help @@ -306,7 +323,7 @@ struct Command(CollectionElement): self.parent = existing.parent^ fn __str__(self) -> String: - return "(Name: " + self.name + ", Description: " + self.description + ")" + return sprintf("(Name: %s, Description: %s)", self.name, self.description) fn __repr__(inout self) -> String: var parent_name: String = "" diff --git a/run_examples.sh b/run_examples.sh index ae5fafe..083ee84 100644 --- a/run_examples.sh +++ b/run_examples.sh @@ -5,6 +5,7 @@ mkdir ./temp mojo package prism -I ./external -o ./temp/prism.mojopkg echo -e "Building binaries for all examples...\n" +mojo build examples/aliases/root.mojo -o temp/aliases mojo build examples/hello_world/root.mojo -o temp/hello_world mojo build examples/nested/nested.mojo -o temp/nested mojo build examples/printer/printer.mojo -o temp/printer @@ -15,6 +16,7 @@ mkdir -p temp/examples/read_csv/ && cp examples/read_csv/file.csv temp/examples/ echo -e "Executing examples...\n" cd temp +./aliases my thing ./hello_world say hello ./nested get cat --count 5 -l ./printer "sample-text" --formatting=underline