diff --git a/.github/images/graph.drawio.png b/.github/images/graph.drawio.png deleted file mode 100644 index ecc33ce99..000000000 Binary files a/.github/images/graph.drawio.png and /dev/null differ diff --git a/README.md b/README.md index 780d41b2e..4ffacde85 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -
- Developer's Toolbox • - Philosophy • + Quick start • + Why cmd2? • Installation • Documentation • - Tutorials • - Hello World • - Projects using cmd2 • + Projects using cmd2
-[](https://youtu.be/DDU_JH6cFsA) +`cmd2` makes it quick to build powerful, polished command-line applications and REPLs in Python. +Start with a subclass of the standard library's +[`cmd.Cmd`](https://docs.python.org/3/library/cmd.html), then add commands while `cmd2` handles the +details that make an application pleasant to build and use: argument parsing, generated help, tab +completion, command history, scripting, output styling, and much more. -cmd2 is a tool for building interactive command line applications in Python. Its goal is to make it -quick and easy for developers to build feature-rich and user-friendly interactive command line -applications. It provides a simple API which is an extension of Python's built-in -[cmd](https://docs.python.org/3/library/cmd.html) module. cmd2 provides a wealth of features on top -of cmd to make your life easier and eliminates much of the boilerplate code which would be necessary -when using cmd. +You can use `cmd2` for a small internal tool and grow the same application into an extensible, +scriptable interface without replacing the framework or writing the usual CLI boilerplate. -> :warning: **If you are upgrading from an older version of `cmd2`, both `3.x` and `4.x` have some -> significant backwards incompatibilities from previous versions. Please see the -> [CHANGELOG](./CHANGELOG.md) for info on what has changed and the -> [Migration Guide](https://cmd2.readthedocs.io/en/latest/upgrades/) for tips on upgrading from an -> older version of `cmd2` to `4.x`** +## Quick start -## The developers toolbox +Install `cmd2`: - +```bash +pip install cmd2 +``` -When creating solutions developers have no shortage of tools to create rich and smart user -interfaces. System administrators have long been duct taping together brittle workflows based on a -menagerie of simple command line tools created by strangers on github and the guy down the hall. -Unfortunately, when CLIs become significantly complex the ease of command discoverability tends to -fade quickly. On the other hand, Web and traditional desktop GUIs are first in class when it comes -to easily discovering functionality. The price we pay for beautifully colored displays is complexity -required to aggregate disparate applications into larger systems. `cmd2` fills the niche between -high [ease of command discovery](https://clig.dev/#ease-of-discovery) applications and smart -workflow automation systems. +Then create `app.py`: -The `cmd2` framework provides a great mixture of both worlds. Application designers can easily -create complex applications and rely on the cmd2 library to offer effortless user facing help and -extensive tab completion. When users become comfortable with functionality, cmd2 turns into a -feature rich library enabling a smooth transition to full automation. If designed with enough -forethought, a well implemented cmd2 application can serve as a boutique workflow tool. `cmd2` pulls -off this flexibility based on two pillars of philosophy: +```python +from typing import Annotated -- Tab Completion -- Automation Transition +import cmd2 +from cmd2.annotated import Argument, Option -## Philosophy -
+class App(cmd2.Cmd):
+ """A small interactive application."""
-Deep extensive tab completion and help text generation based on the argparse library create the
-first pillar of 'ease of command discovery'. The following is a list of features in this category.
+ @cmd2.with_annotated
+ def do_greet(
+ self,
+ name: Annotated[str, Argument(help_text="person to greet")],
+ count: Annotated[int, Option(help_text="number of greetings")] = 1,
+ ) -> None:
+ """Greet a person."""
+ for _ in range(count):
+ self.poutput(f"Hello, {name}!")
-- Great tab completion of commands, subcommands, file system paths, and shell commands.
-- Custom tab completion for user designed commands via simple function overloading.
-- Tab completion from `persistent_history_file` sources added with very little friction.
-- Automatic tab completion of `argparse` flags and optional arguments.
-- Path completion easily enabled.
-- When all else fails, custom tab completion based on `choices_provider` can fill any gaps.
-
+if __name__ == "__main__":
+ App().cmdloop()
+```
+
+`cmd2` supports [Typer](https://typer.tiangolo.com/)-style syntax for specifying command arguments
+with type annotations. In this example, `@cmd2.with_annotated` turns `name` and `count` into a
+positional argument and an option.
-cmd2 creates the second pillar of 'ease of transition to automation' through alias/macro creation,
-command line argument parsing and execution of cmd2 scripting.
+Run it with `python app.py`. Your new `greet` command already has input validation, generated help,
+and tab completion for its options. The application also includes discoverable help, command
+history, aliases, macros, scripting, shell integration, and other built-in commands.
-- Flexible alias and macro creation for quick abstraction of commands.
-- Text file scripting of your application with `run_script` (`@`) and `_relative_run_script` (`@@`)
-- Powerful and flexible built-in Python scripting of your application using the `run_pyscript`
- command
+```console
+(Cmd) help greet
+Usage: greet [-h] [--count COUNT] name
+
+(Cmd) greet --count 2 Ada
+Hello, Ada!
+Hello, Ada!
+```
+
+[](https://raw.githubusercontent.com/python-cmd2/cmd2/main/docs/assets/cmd2-readme-demo.gif)
+
+See the [getting started tutorial](https://cmd2.readthedocs.io/en/latest/examples/getting_started/)
+to build a more complete application.
+
+## Why cmd2?
+
+### Build more with less code
+
+- Define commands as Python methods and use familiar
+ [`argparse`](https://cmd2.readthedocs.io/en/latest/features/argument_processing/) parsers for
+ arguments and subcommands. A single parser definition drives validation, help, and completion.
+- Render Rich tables and other styled objects, with consistent helpers for
+ [normal output, errors, warnings, and paging](https://cmd2.readthedocs.io/en/latest/features/generating_output/).
+- Organize large applications into independently testable and dynamically loadable
+ [CommandSets](https://cmd2.readthedocs.io/en/latest/features/modular_commands/), and customize the
+ command lifecycle with [hooks](https://cmd2.readthedocs.io/en/latest/features/hooks/).
+- Integrate existing Python code, shell tools, or asynchronous work instead of restructuring your
+ application around the framework.
+- Run on Windows, macOS, and Linux with a pure-Python package and a small dependency footprint.
+
+### Give users a capable interface from day one
+
+- **Tab completion:** provide context-aware completion for commands, subcommands, options, choices,
+ file paths, and custom data sources, with descriptive hints for completion candidates. Learn more
+ about [completion](https://cmd2.readthedocs.io/en/latest/features/completion/).
+- **History:** search, edit, rerun, save, and optionally persist previously entered commands. Users
+ also get familiar navigation and reverse search such as Ctrl+R. Learn more
+ about [history](https://cmd2.readthedocs.io/en/latest/features/history/).
+- **Unicode:** accept Unicode in commands, arguments, file names, and output, and run UTF-8 command
+ scripts for applications used in any language. Learn more about
+ [command scripts](https://cmd2.readthedocs.io/en/latest/features/scripting/#command-scripts).
+- **Shell shortcuts and hotkeys:** use familiar Readline-style keyboard shortcuts for navigating and
+ editing the command line, including Emacs-style bindings provided by `prompt-toolkit`. Learn more
+ about [keyboard shortcuts](https://cmd2.readthedocs.io/en/latest/features/history/#for-users).
+- **Help:** generate discoverable, categorized help for commands, subcommands, and arguments
+ directly from their argument parsers. Learn more about
+ [help](https://cmd2.readthedocs.io/en/latest/features/help/).
+- **Rich UI/UX:** offer syntax highlighting, Fish-style history suggestions, multiline input,
+ configurable prompts, completion menus, themes, and an optional bottom toolbar. Learn more about
+ [prompts and toolbars](https://cmd2.readthedocs.io/en/latest/features/prompt/) and
+ [themes](https://cmd2.readthedocs.io/en/latest/features/theme/).
+
+### Grow from exploration to automation
+
+- **Shell scripting:** automate the same commands users run interactively by passing them as command
+ arguments or standard input from shell scripts. Learn more about
+ [automating cmd2 applications](https://cmd2.readthedocs.io/en/latest/features/os/#automating-cmd2-apps-from-other-cliclu-tools).
+- **Python scripting:** run Python scripts inside the application for loops, branching, complex
+ control flow, and integration with the application's commands and data. Learn more about
+ [Python scripts](https://cmd2.readthedocs.io/en/latest/features/scripting/#python-scripts).
+- **Run shell commands:** execute operating-system commands without leaving the application, using
+ the built-in `shell` command or its `!` shortcut. Learn more about
+ [OS integration](https://cmd2.readthedocs.io/en/latest/features/os/#executing-os-commands-from-within-cmd2).
+- **Redirect output:** send command output to files or the clipboard, or pipe it through one or more
+ shell commands. Learn more about
+ [output redirection and pipes](https://cmd2.readthedocs.io/en/latest/features/redirection/).
+- **Aliases, macros, and shortcuts:** let users customize names, parameterized commands, and terse
+ shortcuts for repetitive workflows without changing the application. Learn more about
+ [aliases, macros, and shortcuts](https://cmd2.readthedocs.io/en/latest/features/shortcuts_aliases_macros/).
+- **Startup scripts:** initialize an application consistently by running saved commands every time
+ it starts. Learn more about
+ [startup commands and scripts](https://cmd2.readthedocs.io/en/latest/features/startup_commands/).
+- **Embedded Python and IPython shells:** drop into an interactive Python or IPython session for
+ experimentation, debugging, object introspection, and access to application state. Learn more
+ about
+ [embedded Python shells](https://cmd2.readthedocs.io/en/latest/features/embedded_python_shells/).
+- **Color, style, and tables:** produce readable output with Rich colors and styles, custom themes,
+ paging, and flexible table layouts. Learn more about
+ [generating output](https://cmd2.readthedocs.io/en/latest/features/generating_output/) and
+ [creating tables](https://cmd2.readthedocs.io/en/latest/features/table_creation/).
## Installation
@@ -94,14 +162,16 @@ For information on other installation options, see
[Installation Instructions](https://cmd2.readthedocs.io/en/latest/overview/installation.html) in the
cmd2 documentation.
-## Documentation
-
-The latest documentation for cmd2 can be read online here: https://cmd2.readthedocs.io/en/latest/
+> [!IMPORTANT] Upgrading from an older release? Versions 3.x and 4.x include significant
+> backwards-incompatible changes. Review the [changelog](./CHANGELOG.md) and
+> [migration guide](https://cmd2.readthedocs.io/en/latest/upgrades/) before upgrading.
-It is available in HTML, PDF, and ePub formats.
+## Documentation
-The best way to learn the cmd2 api is to delve into the example applications located in source under
-examples.
+Read the [latest documentation](https://cmd2.readthedocs.io/en/latest/) online or download it in
+HTML, PDF, and ePub formats. The
+[`examples`](https://github.com/python-cmd2/cmd2/tree/main/examples) directory contains focused,
+runnable demonstrations of individual features.
## Tutorials
@@ -116,29 +186,6 @@ examples.
- Advanced cookiecutter template with external plugin support :
https://github.com/jayrod/cookiecutter-python-cmd2-ext-plug
-## Hello World
-
-```python
-#!/usr/bin/env python
-"""A simple cmd2 application."""
-
-import cmd2
-
-
-class FirstApp(cmd2.Cmd):
- """A simple cmd2 application."""
-
- def do_hello_world(self, _: cmd2.Statement):
- self.poutput("Hello World")
-
-
-if __name__ == "__main__":
- import sys
-
- c = FirstApp()
- sys.exit(c.cmdloop())
-```
-
## Found a bug?
If you think you've found a bug, please first read through the open
diff --git a/cmd2.png b/cmd2.png
deleted file mode 100644
index 31a6e921f..000000000
Binary files a/cmd2.png and /dev/null differ
diff --git a/docs/assets/cmd2-readme-demo.gif b/docs/assets/cmd2-readme-demo.gif
new file mode 100644
index 000000000..74e9d3ef4
Binary files /dev/null and b/docs/assets/cmd2-readme-demo.gif differ
diff --git a/docs/assets/getting-started-demo.gif b/docs/assets/getting-started-demo.gif
new file mode 100644
index 000000000..6a6b71171
Binary files /dev/null and b/docs/assets/getting-started-demo.gif differ
diff --git a/docs/examples/getting_started.md b/docs/examples/getting_started.md
index 3c4c14163..413648665 100644
--- a/docs/examples/getting_started.md
+++ b/docs/examples/getting_started.md
@@ -10,10 +10,13 @@ example application which demonstrates many features of `cmd2`:
- [Generating Output](../features/generating_output.md)
- [Help](../features/help.md)
- [Shortcuts](../features/shortcuts_aliases_macros.md#shortcuts)
-- [Multiline Commands](../features/multiline_commands.md)
- [History](../features/history.md)
- [Bottom Toolbar](../features/prompt.md#bottom-toolbar)
+The following animation shows the `cat`, `echo`, and `intro` commands in action:
+
+
+
If you don't want to type as we go, here is the complete source (you can click to expand and then
click the **Copy** button in the top-right):
@@ -27,146 +30,182 @@ click the **Copy** button in the top-right):
## Basic Application
-First we need to create a new `cmd2` application. Create a new file `getting_started.py` with the
-following contents:
+The example defines `BasicApp` as a subclass of [cmd2.Cmd][]:
```py
-#!/usr/bin/env python
-"""A basic cmd2 application."""
-
-import cmd2
-
-
class BasicApp(cmd2.Cmd):
"""Cmd2 application to demonstrate many common features."""
+```
+At the end of the file, the application creates an instance of that class and passes control to the
+[cmd2.Cmd.cmdloop][] method:
+```py
if __name__ == "__main__":
- import sys
-
app = BasicApp()
sys.exit(app.cmdloop())
```
-We have a new class `BasicApp` which is a subclass of [cmd2.Cmd][]. When we tell Python to run our
-file like this:
+Run the example from the repository root:
```shell
-$ python getting_started.py
+$ uv run python examples/getting_started.py
```
-The application creates an instance of our class, and calls the [cmd2.Cmd.cmdloop][] method. This
-method accepts user input and runs commands based on that input. Because we subclassed `cmd2.Cmd`,
-our new app already has a bunch of built-in features.
-
-Congratulations, you have a working `cmd2` app. You can run it, and then type `quit` to exit.
+The application displays its intro banner and the custom `myapp>` prompt. Because `BasicApp`
+subclasses `cmd2.Cmd`, it also includes `cmd2`'s built-in commands and features. Type `quit` to
+exit.
-## Create a New Setting
+## Create a Setting
-Before we create our first command, we are going to add a new setting to this app. `cmd2` includes
-robust support for [Settings](../features/settings.md). You configure settings during object
-initialization, so we need to add an initializer to our class:
+`cmd2` includes robust support for [Settings](../features/settings.md). The example stores the color
+used by the `echo` command in `foreground_color`, then exposes that attribute as a runtime setting.
+The choices are the color values supported by [cmd2.Color][]:
```py
-def __init__(self):
- super().__init__()
-
- # Make maxrepeats settable at runtime
- self.maxrepeats = 3
- self.add_settable(cmd2.Settable("maxrepeats", int, "max repetitions for speak command", self))
+# Color to output text in with echo command
+self.foreground_color = Color.CYAN.value
+
+# Make echo_fg settable at runtime
+fg_colors = [c.value for c in Color]
+self.add_settable(
+ cmd2.Settable(
+ "foreground_color",
+ str,
+ Text.assemble(
+ "Foreground color to use with echo command ",
+ "(Options: ",
+ Text("Green", Style(color=Color.GREEN)),
+ ", ",
+ Text("Red", Style(color=Color.RED)),
+ ", ",
+ Text("Blue", Style(color=Color.BLUE)),
+ ", ...)",
+ ),
+ self,
+ choices=fg_colors,
+ )
+)
```
-In that initializer, the first thing to do is to make sure we initialize `cmd2`. That's what the
-`super().__init__()` line does. Next create an attribute to hold the setting. Finally, call the
-[cmd2.Cmd.add_settable][] method with a new instance of a [cmd2.utils.Settable][] class. Now if you
-run the script, and enter the `set` command to see the settings, like this:
+The [cmd2.Cmd.add_settable][] method registers a [cmd2.utils.Settable][] that validates new values
+against `fg_colors`. Use the built-in `set` command to inspect or change it:
```shell
-$ python getting_started.py
-(Cmd) set
+myapp> set foreground_color
+myapp> set foreground_color red
```
-you will see our `maxrepeats` setting show up with its default value of `3`.
+The first command displays the current value. The second changes the color used by subsequent `echo`
+output.
+
+## Commands
+
+Methods whose names start with `do_` become commands. `BasicApp` defines three commands: `cat`,
+`echo`, and `intro`. Each one demonstrates a different way to process arguments.
-## Create A Command
+### cat
-Now we will create our first command, called `speak`, which will echo back whatever we tell it to
-say. We are going to use an [argument processor](../features/argument_processing.md) so the `speak`
-command can shout and talk Pig Latin. We will also use some built in methods for
-[generating output](../features/generating_output.md). Add this code to `getting_started.py`, so
-that the `speak_parser` attribute and the `do_speak()` method are part of the `BasicApp()` class:
+The `cat` command uses [cmd2.with_annotated][] to build its argument parser from type annotations.
+The `pathlib.Path` annotation enables path completion, and [cmd2.annotated.Option][] defines the
+optional `-n`/`--number` flag:
```py
-speak_parser = cmd2.Cmd2ArgumentParser()
-speak_parser.add_argument("-p", "--piglatin", action="store_true", help="atinLay")
-speak_parser.add_argument("-s", "--shout", action="store_true", help="N00B EMULATION MODE")
-speak_parser.add_argument("-r", "--repeat", type=int, help="output [n] times")
-speak_parser.add_argument("words", nargs="+", help="words to say")
-
-
-@cmd2.with_argparser(speak_parser)
-def do_speak(self, args):
- """Repeats what you tell me to."""
- words = []
- for word in args.words:
- if args.piglatin:
- word = "%s%say" % (word[1:], word[0])
- if args.shout:
- word = word.upper()
- words.append(word)
- repetitions = args.repeat or 1
- for _ in range(min(repetitions, self.maxrepeats)):
- # .poutput handles newlines, and accommodates output redirection too
- self.poutput(" ".join(words))
+@cmd2.with_annotated
+def do_cat(
+ self,
+ path: pathlib.Path, # Required positional argument with type annotation, tab-completes filesystem paths automatically
+ numbered: Annotated[ # Optional flag argument with type annotation, default value, and help text
+ bool, Option("-n", "--number", help_text="prefix each line with its number")
+ ] = False,
+) -> None:
+ """Print a file's contents. `path` tab-completes filesystem paths automatically.
+
+ Try:
+ cat