diff options
-rw-r--r-- | cmd2/cmd2.py | 72 | ||||
-rw-r--r-- | docs/features/initialization.rst | 119 | ||||
-rw-r--r-- | docs/features/settings.rst | 6 | ||||
-rwxr-xr-x | examples/initialization.py | 60 |
4 files changed, 207 insertions, 50 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 900a2451..648aadb1 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -272,9 +272,6 @@ class Cmd(cmd.Cmd): # Otherwise it will be None. Its used to know when a pipe process can be killed and/or waited upon. self._cur_pipe_proc_reader = None - # Used by complete() for readline tab completion - self.completion_matches = [] - # Used to keep track of whether we are redirecting or piping output self._redirecting = False @@ -321,6 +318,38 @@ class Cmd(cmd.Cmd): elif transcript_files: self._transcript_files = transcript_files + # Set the pager(s) for use with the ppaged() method for displaying output using a pager + if sys.platform.startswith('win'): + self.pager = self.pager_chop = 'more' + else: + # Here is the meaning of the various flags we are using with the less command: + # -S causes lines longer than the screen width to be chopped (truncated) rather than wrapped + # -R causes ANSI "style" escape sequences to be output in raw form (i.e. colors are displayed) + # -X disables sending the termcap initialization and deinitialization strings to the terminal + # -F causes less to automatically exit if the entire file can be displayed on the first screen + self.pager = 'less -RXF' + self.pager_chop = 'less -SRXF' + + # This boolean flag determines whether or not the cmd2 application can interact with the clipboard + self._can_clip = can_clip + + # This determines the value returned by cmdloop() when exiting the application + self.exit_code = 0 + + # This lock should be acquired before doing any asynchronous changes to the terminal to + # ensure the updates to the terminal don't interfere with the input being typed or output + # being printed by a command. + self.terminal_lock = threading.RLock() + + # Commands that have been disabled from use. This is to support commands that are only available + # during specific states of the application. This dictionary's keys are the command names and its + # values are DisabledCommand objects. + self.disabled_commands = dict() + + # If any command has been categorized, then all other commands that haven't been categorized + # will display under this section in the help output. + self.default_category = 'Uncategorized' + # The default key for sorting string results. Its default value performs a case-insensitive alphabetical sort. # If natural sorting is preferred, then set this to NATURAL_SORT_KEY. # cmd2 uses this key for sorting: @@ -331,7 +360,7 @@ class Cmd(cmd.Cmd): ############################################################################################################ # The following variables are used by tab-completion functions. They are reset each time complete() is run - # in reset_completion_defaults() and it is up to completer functions to set them before returning results. + # in _reset_completion_defaults() and it is up to completer functions to set them before returning results. ############################################################################################################ # If True and a single match is returned to complete(), then a space will be appended @@ -345,6 +374,9 @@ class Cmd(cmd.Cmd): # An optional header that prints above the tab-completion suggestions self.completion_header = '' + # Used by complete() for readline tab completion + self.completion_matches = [] + # Use this list if you are completing strings that contain a common delimiter and you only want to # display the final portion of the matches as the tab-completion suggestions. The full matches # still must be returned from your completer function. For an example, look at path_complete() @@ -360,38 +392,6 @@ class Cmd(cmd.Cmd): # If False, then complete() will sort the matches using self.default_sort_key before they are displayed. self.matches_sorted = False - # Set the pager(s) for use with the ppaged() method for displaying output using a pager - if sys.platform.startswith('win'): - self.pager = self.pager_chop = 'more' - else: - # Here is the meaning of the various flags we are using with the less command: - # -S causes lines longer than the screen width to be chopped (truncated) rather than wrapped - # -R causes ANSI "style" escape sequences to be output in raw form (i.e. colors are displayed) - # -X disables sending the termcap initialization and deinitialization strings to the terminal - # -F causes less to automatically exit if the entire file can be displayed on the first screen - self.pager = 'less -RXF' - self.pager_chop = 'less -SRXF' - - # This boolean flag determines whether or not the cmd2 application can interact with the clipboard - self._can_clip = can_clip - - # This determines the value returned by cmdloop() when exiting the application - self.exit_code = 0 - - # This lock should be acquired before doing any asynchronous changes to the terminal to - # ensure the updates to the terminal don't interfere with the input being typed or output - # being printed by a command. - self.terminal_lock = threading.RLock() - - # Commands that have been disabled from use. This is to support commands that are only available - # during specific states of the application. This dictionary's keys are the command names and its - # values are DisabledCommand objects. - self.disabled_commands = dict() - - # If any command has been categorized, then all other commands that haven't been categorized - # will display under this section in the help output. - self.default_category = 'Uncategorized' - # ----- Methods related to presenting output to the user ----- @property diff --git a/docs/features/initialization.rst b/docs/features/initialization.rst index 936208f1..39e36428 100644 --- a/docs/features/initialization.rst +++ b/docs/features/initialization.rst @@ -6,16 +6,17 @@ capabilities which you may wish to utilize while initializing the app:: #!/usr/bin/env python3 # coding=utf-8 - """A simple example cmd2 appliction demonstrating the following: - 1) Colorizing/stylizing output - 2) Using multiline commands - 3) Persistent history - 4) How to run an initialization script at startup - 5) How to group and categorize commands when displaying them in help - 6) Opting-in to using the ipy command to run an IPython shell - 7) Allowing access to your application in py and ipy - 8) Displaying an intro banner upon starting your application - 9) Using a custom prompt + """A simple example cmd2 application demonstrating the following: + 1) Colorizing/stylizing output + 2) Using multiline commands + 3) Persistent history + 4) How to run an initialization script at startup + 5) How to group and categorize commands when displaying them in help + 6) Opting-in to using the ipy command to run an IPython shell + 7) Allowing access to your application in py and ipy + 8) Displaying an intro banner upon starting your application + 9) Using a custom prompt + 10) How to make custom attributes settable at runtime """ import cmd2 from cmd2 import style @@ -28,15 +29,27 @@ capabilities which you may wish to utilize while initializing the app:: super().__init__(multiline_commands=['echo'], persistent_history_file='cmd2_history.dat', startup_script='scripts/startup.txt', use_ipython=True) + # Prints an intro banner once upon application startup self.intro = style('Welcome to cmd2!', fg='red', bg='white', bold=True) + + # Show this as the prompt when asking for input self.prompt = 'myapp> ' + # Used as prompt for multiline commands after the first line + self.continuation_prompt = '... ' + # Allow access to your application in py and ipy via self self.locals_in_py = True # Set the default category name self.default_category = 'cmd2 Built-in Commands' + # Color to output text in with echo command + self.foreground_color = 'cyan' + + # Make echo_fg settable at runtime + self.settable['foreground_color'] = 'Foreground color to use with echo command' + @cmd2.with_category(CUSTOM_CATEGORY) def do_intro(self, _): """Display the intro banner""" @@ -45,9 +58,93 @@ capabilities which you may wish to utilize while initializing the app:: @cmd2.with_category(CUSTOM_CATEGORY) def do_echo(self, arg): """Example of a multiline command""" - self.poutput(arg) + self.poutput(style(arg, fg=self.foreground_color)) if __name__ == '__main__': app = BasicApp() app.cmdloop() + + +Cmd class initializer +--------------------- + +A ``cmd2.Cmd`` instance or subclass instance is an interactive CLI application +framework. There is no good reason to instantiate ``Cmd`` itself; rather, it’s +useful as a superclass of a class you define yourself in order to inherit +``Cmd``’s methods and encapsulate action methods. + +Certain things must be initialized within the ``__init__()`` method of your +class derived from ``cmd2.Cmd``(all arguments to ``__init__()`` are optional): + +.. automethod:: cmd2.cmd2.Cmd.__init__ + :noindex: + +Cmd instance attributes +----------------------- + +The ``cmd2.Cmd`` class provides a large number of public instance attributes +which allow developers to customize a ``cmd2`` application further beyond the +options provided by the ``__init__()`` method. + +Public instance attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~ +Here are instance attributes of ``cmd2.Cmd`` which developers might wish +override: + +- **broken_pipe_warning**: if non-empty, this string will be displayed if a + broken pipe error occurs +- **continuation_prompt**: used for multiline commands on 2nd+ line of input +- **debug**: if ``True`` show full stack trace on error (Default: ``False``) +- **default_category**: if any command has been categorized, then all other + commands that haven't been categorized will display under this section in the + help output. +- **default_error**: the error that prints when a non-existent command is run +- **default_sort_key**: the default key for sorting string results. Its default + value performs a case-insensitive alphabetical sort. +- **default_to_shell**: if ``True`` attempt to run unrecognized commands as + shell commands (Default: ``False``) +- **disabled_commands**: commands that have been disabled from use. This is to + support commands that are only available during specific states of the + application. This dictionary's keys are the command names and its values are + DisabledCommand objects. +- **echo**: if ``True``, each command the user issues will be repeated to the + screen before it is executed. This is particularly useful when running + scripts. This behavior does not occur when a running command at the prompt. + (Default: ``False``) +- **editor**: text editor program to use with *edit* command (e.g. ``vim``) +- **exclude_from_history**: commands to exclude from the *history* command +- **exit_code**: this determines the value returned by ``cmdloop()`` when + exiting the application +- **feedback_to_output**: if ``True`` send nonessential output to stdout, if + ``False`` send them to stderr (Default: ``False``) +- **help_error**: the error that prints when no help information can be found +- **hidden_commands**: commands to exclude from the help menu and tab + completion +- **last_result**: stores results from the last command run to enable usage + of results in a Python script or interactive console. Built-in commands don't + make use of this. It is purely there for user-defined commands and + convenience. +- **locals_in_py**: if ``True`` allow access to your application in *py* + command via ``self`` (Default: ``False``) +- **macros**: dictionary of macro names and their values +- **max_completion_items**: max number of CompletionItems to display during + tab-completion (Default: 50) +- **pager**: sets the pager command used by the ``Cmd.ppaged()`` method for + displaying wrapped output using a pager +- **pager_chop**: sets the pager command used by the ``Cmd.ppaged()`` method + for displaying chopped/truncated output using a pager +- **py_bridge_name**: name by which embedded Python environments and scripts + refer to the ``cmd2`` application by in order to call commands (Default: + ``app``) +- **py_locals**: dictionary that defines specific variables/functions available + in Python shells and scripts (provides more fine-grained control than making + everything available with **locals_in_py**) +- **quiet**: if ``True`` then completely suppress nonessential output (Default: + ``False``) +- **quit_on_sigint**: if ``True`` quit the main loop on interrupt instead of + just resetting prompt +- **settable**: dictionary that controls which of these instance attributes + are settable at runtime using the *set* command +- **timing**: if ``True`` display execution time for each command (Default: + ``False``) diff --git a/docs/features/settings.rst b/docs/features/settings.rst index 697c68a7..b8f75934 100644 --- a/docs/features/settings.rst +++ b/docs/features/settings.rst @@ -69,9 +69,9 @@ trace will be printed. echo ~~~~ -If ``True``, each command the user issues will be repeated to the screen before -it is executed. This is particularly useful when running scripts. This -behavior does not occur when a running command at the prompt. +If ``True``, each command the user issues will be repeated to the screen +before it is executed. This is particularly useful when running scripts. +This behavior does not occur when a running command at the prompt. editor diff --git a/examples/initialization.py b/examples/initialization.py new file mode 100755 index 00000000..e26aac9f --- /dev/null +++ b/examples/initialization.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +# coding=utf-8 +"""A simple example cmd2 application demonstrating the following: + 1) Colorizing/stylizing output + 2) Using multiline commands + 3) Persistent history + 4) How to run an initialization script at startup + 5) How to group and categorize commands when displaying them in help + 6) Opting-in to using the ipy command to run an IPython shell + 7) Allowing access to your application in py and ipy + 8) Displaying an intro banner upon starting your application + 9) Using a custom prompt + 10) How to make custom attributes settable at runtime +""" +import cmd2 +from cmd2 import style + + +class BasicApp(cmd2.Cmd): + CUSTOM_CATEGORY = 'My Custom Commands' + + def __init__(self): + super().__init__(multiline_commands=['echo'], persistent_history_file='cmd2_history.dat', + startup_script='scripts/startup.txt', use_ipython=True) + + # Prints an intro banner once upon application startup + self.intro = style('Welcome to cmd2!', fg='red', bg='white', bold=True) + + # Show this as the prompt when asking for input + self.prompt = 'myapp> ' + + # Used as prompt for multiline commands after the first line + self.continuation_prompt = '... ' + + # Allow access to your application in py and ipy via self + self.locals_in_py = True + + # Set the default category name + self.default_category = 'cmd2 Built-in Commands' + + # Color to output text in with echo command + self.foreground_color = 'cyan' + + # Make echo_fg settable at runtime + self.settable['foreground_color'] = 'Foreground color to use with echo command' + + @cmd2.with_category(CUSTOM_CATEGORY) + def do_intro(self, _): + """Display the intro banner""" + self.poutput(self.intro) + + @cmd2.with_category(CUSTOM_CATEGORY) + def do_echo(self, arg): + """Example of a multiline command""" + self.poutput(style(arg, fg=self.foreground_color)) + + +if __name__ == '__main__': + app = BasicApp() + app.cmdloop() |