summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd2/ansi.py16
-rw-r--r--cmd2/cmd2.py2
-rw-r--r--docs/api/ansi.rst5
-rw-r--r--docs/api/cmd.rst17
-rw-r--r--docs/api/index.rst1
-rw-r--r--docs/doc_conventions.rst190
-rw-r--r--docs/features/builtin_commands.rst75
-rw-r--r--docs/features/generating_output.rst196
-rw-r--r--docs/features/index.rst1
-rw-r--r--docs/features/settings.rst170
-rw-r--r--docs/features/startup_commands.rst2
-rw-r--r--docs/migrating/incompatibilities.rst15
-rw-r--r--docs/migrating/next_steps.rst9
-rwxr-xr-xexamples/colors.py26
-rwxr-xr-xexamples/plumbum_colors.py2
15 files changed, 569 insertions, 158 deletions
diff --git a/cmd2/ansi.py b/cmd2/ansi.py
index b3dd7cc1..d3af525a 100644
--- a/cmd2/ansi.py
+++ b/cmd2/ansi.py
@@ -94,7 +94,9 @@ def strip_style(text: str) -> str:
def style_aware_wcswidth(text: str) -> int:
"""
Wrap wcswidth to make it compatible with strings that contains ANSI style sequences
+
:param text: the string being measured
+ :return: the width of the string when printed to the terminal
"""
# Strip ANSI style sequences since they cause wcswidth to return -1
return wcswidth(strip_style(text))
@@ -103,6 +105,7 @@ def style_aware_wcswidth(text: str) -> int:
def style_aware_write(fileobj: IO, msg: str) -> None:
"""
Write a string to a fileobject and strip its ANSI style sequences if required by allow_style setting
+
:param fileobj: the file object being written to
:param msg: the string being written
"""
@@ -115,9 +118,10 @@ def style_aware_write(fileobj: IO, msg: str) -> None:
def fg_lookup(fg_name: str) -> str:
"""
Look up ANSI escape codes based on foreground color name.
+
:param fg_name: foreground color name to look up ANSI escape code(s) for
:return: ANSI escape code(s) associated with this color
- :raises ValueError if the color cannot be found
+ :raises ValueError: if the color cannot be found
"""
try:
ansi_escape = FG_COLORS[fg_name.lower()]
@@ -129,9 +133,10 @@ def fg_lookup(fg_name: str) -> str:
def bg_lookup(bg_name: str) -> str:
"""
Look up ANSI escape codes based on background color name.
+
:param bg_name: background color name to look up ANSI escape code(s) for
:return: ANSI escape code(s) associated with this color
- :raises ValueError if the color cannot be found
+ :raises ValueError: if the color cannot be found
"""
try:
ansi_escape = BG_COLORS[bg_name.lower()]
@@ -193,8 +198,13 @@ def style(text: Any, *, fg: str = '', bg: str = '', bold: bool = False,
# These can be altered to suit an application's needs and only need to be a
# function with the following structure: func(str) -> str
style_success = functools.partial(style, fg='green')
+"""Partial function supplying arguments to :meth:`cmd2.ansi.style()` which colors text to signify success"""
+
style_warning = functools.partial(style, fg='bright_yellow')
+"""Partial function supplying arguments to :meth:`cmd2.ansi.style()` which colors text to signify a warning"""
+
style_error = functools.partial(style, fg='bright_red')
+"""Partial function supplying arguments to :meth:`cmd2.ansi.style()` which colors text to signify an error"""
def async_alert_str(*, terminal_columns: int, prompt: str, line: str, cursor_offset: int, alert_msg: str) -> str:
@@ -255,6 +265,6 @@ def set_title_str(title: str) -> str:
"""Get the required string, including ANSI escape codes, for setting window title for the terminal.
:param title: new title for the window
- :return string to write to sys.stderr in order to set the window title to the desired test
+ :return: string to write to sys.stderr in order to set the window title to the desired test
"""
return colorama.ansi.set_title(title)
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index 434ade5f..cce281b7 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -290,7 +290,7 @@ class Cmd(cmd.Cmd):
# The error that prints when a non-existent command is run
self.default_error = "{} is not a recognized command, alias, or macro"
- # If this string is non-empty, then this warning message will print if a broken pipe error occurs while printing
+ # If non-empty, this string will be displayed if a broken pipe error occurs
self.broken_pipe_warning = ''
# Commands that will run at the beginning of the command loop
diff --git a/docs/api/ansi.rst b/docs/api/ansi.rst
new file mode 100644
index 00000000..e361bd4f
--- /dev/null
+++ b/docs/api/ansi.rst
@@ -0,0 +1,5 @@
+cmd2.ansi
+=========
+
+.. automodule:: cmd2.ansi
+ :members:
diff --git a/docs/api/cmd.rst b/docs/api/cmd.rst
index 4f88101e..ee8d7c67 100644
--- a/docs/api/cmd.rst
+++ b/docs/api/cmd.rst
@@ -3,3 +3,20 @@ cmd2.Cmd
.. autoclass:: cmd2.cmd2.Cmd
:members:
+
+ .. attribute:: help_error
+
+ The error message displayed to the user when they request help for a
+ command with no help defined.
+
+ .. attribute:: default_error
+
+ The error message displayed when a non-existent command is run.
+
+ .. attribute:: settable
+
+ This dictionary contains the name and description of all settings available to users.
+
+ Users use the :ref:`features/builtin_commands:set` command to view and
+ modify settings. Settings are stored in instance attributes with the
+ same name as the setting.
diff --git a/docs/api/index.rst b/docs/api/index.rst
index 94d0fdd4..f0324eab 100644
--- a/docs/api/index.rst
+++ b/docs/api/index.rst
@@ -7,5 +7,6 @@ API Reference
cmd
decorators
exceptions
+ ansi
utility_classes
utility_functions
diff --git a/docs/doc_conventions.rst b/docs/doc_conventions.rst
index 39302fc6..9b714d45 100644
--- a/docs/doc_conventions.rst
+++ b/docs/doc_conventions.rst
@@ -19,61 +19,115 @@ In addition:
documentation, and to the API reference
+Style Checker
+-------------
+
+Use `doc8 <https://pypi.org/project/doc8/>`_ to check the style of the
+documentation. This tool can be invoked using the proper options by typing:
+
+.. code-block:: shell
+
+ $ invoke doc8
+
+
Naming Files
------------
-- all lower case file names
+All source files in the documentation must:
+
+- have all lower case file names
- if the name has multiple words, separate them with an underscore
-- all documentation file names end in '.rst'
+- end in '.rst'
-Heirarchy of headings
----------------------
+Indenting
+---------
-show the heirarchy of sphinx headings we use, and the conventions (underline
-only, no overline)
+In reStructuredText all indenting is significant. Use 2 spaces per indenting
+level.
-Use '=', then '-', then '~'. If your document needs more levels than that,
-break it into separate documents.
-You only have to worry about the heirarchy of headings within a single file.
-Sphinx handles the intra-file heirarchy magically on it's own.
+Wrapping
+--------
-Use two blank lines before every heading unless it's the first heading in the
-file. Use one blank line after every heading
+Hard wrap all text so that line lengths are no greater than 79 characters. It
+makes everything easier when editing documentation, and has no impact on
+reading documentation because we render to html.
-Code
-----
+Titles and Headings
+-------------------
-This documentation declares python as the default Sphinx domain. Python code
-or interactive python sessions can be presented by either:
+reStructuredText allows flexibility in how headings are defined. You only have
+to worry about the heirarchy of headings within a single file. Sphinx magically
+handles the intra-file heirarchy on it's own. This magic means that no matter
+how you style titles and headings in the various files that comprise the
+documentation, Sphinx will render properly structured output. To ensure we have
+a similar consistency when viewing the source files, we use the following
+conventions for titles and headings:
-- finishing the preceding paragraph with a ``::`` and indenting the code
-- use the ``.. code-block::`` directive
+1. When creating a heading for a section, do not use the overline and underline
+syntax. Use the underline syntax only::
+
+ Document Title
+ ==============
+
+2. The string of adornment characters on the line following the heading should
+be the same length as the title.
+
+3. The title of a document should use the '=' adornment character on the next
+line and only one heading of this level should appear in each file.
+
+4. Sections within a document should have their titles adorned with the '-'
+character::
+
+ Section Title
+ -------------
+
+5. Subsections within a section should have their titles adorned with the '~'
+character::
+
+ Subsection Title
+ ~~~~~~~~~~~~~~~~
-If you want to show other code, like shell commands, then use ``.. code-block:
-shell``.
+6. Use two blank lines before every title unless it's the first heading in the
+file. Use one blank line after every heading.
+7. If your document needs more than three levels of sections, break it into
+separate documents.
+
+
+Inline Code
+-----------
+
+This documentation declares ``python`` as the default Sphinx domain. Python
+code or interactive Python sessions can be presented by either:
+
+- finishing the preceding paragraph with a ``::`` and indenting the code
+- use the ``.. code-block::`` directive
-Table of Contents and Captions
-------------------------------
+If you want to show non-Python code, like shell commands, then use ``..
+code-block: shell``.
-Hyperlinks
-----------
+External Hyperlinks
+-------------------
If you want to use an external hyperlink target, define the target at the top
-of the page, not the bottom.
+of the page or the top of the section, not the bottom. The target definition
+should always appear before it is referenced.
+Links To Other Documentation Pages and Sections
+-----------------------------------------------
+
We use the Sphinx `autosectionlabel
<http://www.sphinx-doc.org/en/master/usage/extensions/autosectionlabel.html>`_
extension. This allows you to reference any header in any document by::
See :ref:`features/argument_processing:Help Messages`
-or ::
+or::
See :ref:`custom title<features/argument_processing:Help Messages>`
@@ -85,44 +139,80 @@ and
See :ref:`custom title<features/argument_processing:Help Messages>`
-[TODO what's the right way to link to source code? Can we make it link to the
-tag that the documentation is rendered from?]
+API Documentation
+-----------------
-Autolinking
------------
+The API documentation is mostly pulled from docstrings in the source code using
+the Sphinx `autodoc
+<https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html>`_
+extension. However, Sphinx has issues generating documentation for instance
+attributes (see `cmd2 issue 821
+<https://github.com/python-cmd2/cmd2/issues/821>`_ for the full discussion). We
+have chosen to not use code as the source of instance attribute documentation.
+Instead, it is added manually to the documentation files in ``cmd2/docs/api``.
+See ``cmd2/docs/api/cmd.rst`` to see how to add documentation for an attribute.
+For module data members and class attributes, the ``autodoc`` extension allows
+documentation in a comment with special formatting (using a #: to start the
+comment instead of just #), or in a docstring after the definition. This
+project has standardized on the docstring after the definition approach. Do not
+use the specially formatted comment approach.
-Referencing cmd2 API documentation
-----------------------------------
+Links to API Reference
+----------------------
-Info and Warning Callouts
--------------------------
+To reference a method or function, use one of the following approaches:
+1. Reference the full dotted path of the method::
-Wrapping
---------
+ The :meth:`cmd2.cmd2.Cmd.poutput` method is similar to the Python built-in
+ print function.
-Hard wrap all text with line lengths no greater than 79 characters. It makes
-everything easier when editing documentation, and has no impact on reading
-documentation because we render to html.
+Which renders as: The :meth:`cmd2.cmd2.Cmd.poutput` method is similar to the
+Python built-in print function.
+2. Reference the full dotted path to the method, but only display the method
+name::
-Referencing cmd2
------------------
+ The :meth:`~cmd2.cmd2.Cmd.poutput` method is similar to the Python built-in print function.
-Whenever you reference ``cmd2`` in the documentation, enclose it in double
-backticks. This indicates an inline literal in restructured text, and makes it
-stand out when rendered as html.
+Which renders as: The :meth:`~cmd2.cmd2.Cmd.poutput` method is similar to the
+Python built-in print function.
-Style Checker
--------------
+3. Reference a portion of the dotted path of the method::
-Use `doc8 <https://pypi.org/project/doc8/>`_ to check the style of the
-documentation. This tool can be invoked using the proper options by typing:
+ The :meth:`.cmd2.Cmd.poutput` method is similar to the Python built-in print
+ function.
-.. code-block:: shell
+Which renders as: The :meth:`.cmd2.Cmd.poutput` method is similar to the Python
+built-in print function.
- $ invoke doc8
+Avoid either of these approaches:
+
+1. Reference just the class name without enough dotted path::
+
+ The :meth:`.Cmd.poutput` method is similar to the Python built-in print
+ function.
+
+Because ``cmd2.Cmd`` subclasses ``cmd.Cmd`` from the standard library, this
+approach does not clarify which class it is referring to.
+
+2. Reference just a method name::
+
+ The :meth:`poutput` method is similar to the Python built-in print
+ function.
+
+While Sphinx may be smart enough to generate the correct output, the potential
+for multiple matching references is high, which causes Sphinx to generate
+warnings. The build pipeline that renders the documentation treats warnings as
+fatal errors. It's best to just be specific about what you are referencing.
+
+Referencing cmd2
+-----------------
+
+Whenever you reference ``cmd2`` in the documentation, enclose it in double
+backticks. This indicates an inline literal in restructured text, and makes it
+stand out when rendered as html.
diff --git a/docs/features/builtin_commands.rst b/docs/features/builtin_commands.rst
new file mode 100644
index 00000000..2a857339
--- /dev/null
+++ b/docs/features/builtin_commands.rst
@@ -0,0 +1,75 @@
+Builtin Commands
+================
+
+Applications which subclass :class:`cmd2.cmd2.Cmd` inherit a number of commands
+which may be useful to your users. Developers can
+:ref:`features/builtin_commands:Remove Builtin Commands` if they do not want
+them to be part of the application.
+
+edit
+----
+
+This command launches an editor program and instructs it to open the given file
+name. Here's an example:
+
+.. code-block:: text
+
+ (Cmd) edit ~/.ssh/config
+
+The program to be launched is determined by the value of the
+:ref:`features/settings:editor` setting.
+
+
+set
+---
+
+A list of all user-settable parameters, with brief comments, is viewable from
+within a running application:
+
+.. code-block:: text
+
+ (Cmd) set --long
+ allow_style: Terminal # Allow ANSI text style sequences in output (valid values: Terminal, Always, Never)
+ continuation_prompt: > # On 2nd+ line of input
+ debug: False # Show full error stack on error
+ echo: False # Echo command issued into output
+ editor: vim # Program used by ``edit``
+ feedback_to_output: False # include nonessentials in `|`, `>` results
+ locals_in_py: False # Allow access to your application in py via self
+ max_completion_items: 50 # Maximum number of CompletionItems to display during tab completion
+ prompt: (Cmd) # The prompt issued to solicit input
+ quiet: False # Don't print nonessential feedback
+ timing: False # Report execution times
+
+Any of these user-settable parameters can be set while running your app with
+the ``set`` command like so:
+
+.. code-block:: text
+
+ (Cmd) set allow_style Never
+
+
+shell
+-----
+
+Execute a command as if at the operating system shell prompt:
+
+.. code-block:: text
+
+ (Cmd) shell pwd -P
+ /usr/local/bin
+
+
+Remove Builtin Commands
+-----------------------
+
+Developers may not want to offer the commands builtin to :class:`cmd2.cmd2.Cmd`
+to users of their application. To remove a command you must delete the method
+implementing that command from the :class:`cmd2.cmd2.Cmd` object at runtime.
+For example, if you wanted to remove the :ref:`features/builtin_commands:shell`
+command from your application::
+
+ class NoShellApp(cmd2.Cmd):
+ """A simple cmd2 application."""
+
+ delattr(cmd2.Cmd, 'do_shell')
diff --git a/docs/features/generating_output.rst b/docs/features/generating_output.rst
index e83b5fdf..f3d2a7f4 100644
--- a/docs/features/generating_output.rst
+++ b/docs/features/generating_output.rst
@@ -1,71 +1,169 @@
Generating Output
=================
-how to generate output
+A standard ``cmd`` application can produce output by using either of these
+methods::
-- poutput
-- perror
-- paging
-- exceptions
-- color support
+ print("Greetings, Professor Falken.", file=self.stdout)
+ self.stdout.write("Shall we play a game?\n")
-Standard ``cmd`` applications produce their output with
-``self.stdout.write('output')`` (or with ``print``, but ``print`` decreases
-output flexibility). ``cmd2`` applications can use ``self.poutput('output')``,
-``self.pfeedback('message')``, ``self.perror('errmsg')``, and
-``self.ppaged('text')`` instead. These methods have these advantages:
+While you could send output directly to ``sys.stdout``, :mod:`cmd2.cmd2.Cmd`
+can be initialized with a ``stdin`` and ``stdout`` variables, which it stores
+as ``self.stdin`` and ``self.stdout``. By using these variables every time you
+produce output, you can trivially change where all the output goes by changing
+how you initialize your class.
-- Handle output redirection to file and/or pipe appropriately
-- More concise
- - ``.pfeedback()`` destination is controlled by ``quiet`` parameter.
-- Option to display long output using a pager via ``ppaged()``
+:mod:`cmd2.cmd2.Cmd` extends this approach in a number of convenient ways. See
+:ref:`features/redirection:Output Redirection And Pipes` for information on how
+users can change where the output of a command is sent. In order for those
+features to work, the output you generate must be sent to ``self.stdout``. You
+can use the methods described above, and everything will work fine.
+:mod:`cmd2.cmd2.Cmd` also includes a number of output related methods which you
+may use to enhance the output your application produces.
-.. automethod:: cmd2.cmd2.Cmd.poutput
- :noindex:
-.. automethod:: cmd2.cmd2.Cmd.perror
- :noindex:
-.. automethod:: cmd2.cmd2.Cmd.pfeedback
- :noindex:
-.. automethod:: cmd2.cmd2.Cmd.ppaged
- :noindex:
+Ordinary Output
+---------------
-Suppressing non-essential output
---------------------------------
+The :meth:`~.cmd2.Cmd.poutput` method is similar to the Python
+`built-in print function <https://docs.python.org/3/library/functions.html#print>`_. :meth:`~.cmd2.Cmd.poutput` adds two
+conveniences:
-The ``quiet`` setting controls whether ``self.pfeedback()`` actually produces
-any output. If ``quiet`` is ``False``, then the output will be produced. If
-``quiet`` is ``True``, no output will be produced.
+ 1. Since users can pipe output to a shell command, it catches
+ ``BrokenPipeError`` and outputs the contents of
+ ``self.broken_pipe_warning`` to ``stderr``. ``self.broken_pipe_warning``
+ defaults to an empty string so this method will just swallow the exception.
+ If you want to show an error message, put it in
+ ``self.broken_pipe_warning`` when you initialize :mod:`~cmd2.cmd2.Cmd`.
-This makes ``self.pfeedback()`` useful for non-essential output like status
-messages. Users can control whether they would like to see these messages by
-changing the value of the ``quiet`` setting.
+ 2. It examines and honors the :ref:`features/settings:allow_style` setting.
+ See :ref:`features/generating_output:Colored Output` below for more details.
+
+Here's a simple command that shows this method in action::
+
+ def do_echo(self, args):
+ """A simple command showing how poutput() works"""
+ self.poutput(args)
+
+
+Error Messages
+--------------
+
+When an error occurs in your program, you can display it on ``sys.stderr`` by
+calling the :meth:`~.cmd2.Cmd.perror` method. By default this method applies
+:meth:`cmd2.ansi.style_error` to the output.
+
+
+Warning Messages
+----------------
+
+:meth:`~.cmd2.Cmd.pwarning` is just like :meth:`~.cmd2.Cmd.perror` but applies
+:meth:`cmd2.ansi.style_warning` to the output.
+
+
+Feedback
+--------
+
+You may have the need to display information to the user which is not intended
+to be part of the generated output. This could be debugging information or
+status information about the progress of long running commands. It's not
+output, it's not error messages, it's feedback. If you use the
+:ref:`features/settings:Timing` setting, the output of how long it took the
+command to run will be output as feedback. You can use the
+:meth:`~.cmd2.Cmd.pfeedback` method to produce this type of output, and
+several :ref:`features/settings:Settings` control how it is handled.
+
+If the :ref:`features/settings:quiet` setting is ``True``, then calling
+:meth:`~.cmd2.Cmd.pfeedback` produces no output. If
+:ref:`features/settings:quiet` is ``False``, the
+:ref:`features/settings:feedback_to_output` setting is consulted to determine
+whether to send the output to ``stdout`` or ``stderr``.
+
+
+Exceptions
+----------
+
+If your app catches an exception and you would like to display the exception to
+the user, the :meth:`~.cmd2.Cmd.pexcept` method can help. The default behavior
+is to just display the message contained within the exception. However, if the
+:ref:`features/settings:debug` setting is ``True``, then the entire stack trace
+will be displayed.
+
+
+Paging Output
+-------------
+
+If you know you are going to generate a lot of output, you may want to display
+it in a way that the user can scroll forwards and backwards through it. If you
+pass all of the output to be displayed in a single call to
+:meth:`~.cmd2.Cmd.ppaged`, it will be piped to an operating system appropriate
+shell command to page the output. On Windows, the output is piped to ``more``;
+on Unix-like operating systems like MacOS and Linux, it is piped to ``less``.
Colored Output
--------------
-The output methods in the previous section all honor the ``allow_style``
-setting, which has three possible values:
+You can add your own `ANSI escape sequences
+<https://en.wikipedia.org/wiki/ANSI_escape_code#Colors>`_ to your output which
+tell the terminal to change the foreground and background colors. If you want
+to give yourself a headache, you can generate these by hand. You could also use
+a Python color library like `plumbum.colors
+<https://plumbum.readthedocs.io/en/latest/colors.html>`_, `colored
+<https://gitlab.com/dslackw/colored>`_, or `colorama
+<https://github.com/tartley/colorama>`_. Colorama is unique because when it's
+running on Windows, it wraps ``stdout``, looks for ANSI escape sequences, and
+converts them into the appropriate ``win32`` calls to modify the state of the
+terminal.
+
+``cmd2`` imports and uses Colorama and provides a number of convenience methods
+for generating colorized output, measuring the screen width of colorized
+output, setting the window title in the terminal, and removing ANSI text style
+escape codes from a string. These functions are all documentated in
+:mod:`cmd2.ansi`.
+
+After adding the desired escape sequences to your output, you should use one of
+these methods to present the output to the user:
+
+- :meth:`.cmd2.Cmd.poutput`
+- :meth:`.cmd2.Cmd.perror`
+- :meth:`.cmd2.Cmd.pwarning`
+- :meth:`.cmd2.Cmd.pexcept`
+- :meth:`.cmd2.Cmd.pfeedback`
+- :meth:`.cmd2.Cmd.ppaged`
+
+These methods all honor the :ref:`features/settings:allow_style` setting, which
+users can modify to control whether these escape codes are passed through to
+the terminal or not.
+
+
+Aligning Text
+--------------
+
+If you would like to generate output which is left, center, or right aligned within a
+specified width or the terminal width, the following functions can help:
+
+- :meth:`cmd2.utils.align_left`
+- :meth:`cmd2.utils.align_center`
+- :meth:`cmd2.utils.align_right`
-Never
- poutput(), pfeedback(), and ppaged() strip all ANSI style sequences
- which instruct the terminal to colorize output
+These functions differ from Python's string justifying functions in that they support
+characters with display widths greater than 1. Additionally, ANSI style sequences are safely
+ignored and do not count toward the display width. This means colored text is supported. If
+text has line breaks, then each line is aligned independently.
-Terminal
- (the default value) poutput(), pfeedback(), and ppaged() do not strip any
- ANSI style sequences when the output is a terminal, but if the output is a
- pipe or a file the style sequences are stripped. If you want colorized
- output you must add ANSI style sequences using either cmd2's internal ansi
- module or another color library such as `plumbum.colors`, `colorama`, or
- `colored`.
-Always
- poutput(), pfeedback(), and ppaged() never strip ANSI style sequences,
- regardless of the output destination
-Colored and otherwise styled output can be generated using the `ansi.style()`
-function:
+Columnar Output
+---------------
-.. automethod:: cmd2.ansi.style
+When generating output in multiple columns, you often need to calculate the
+width of each item so you can pad it appropriately with spaces. However, there
+are categories of Unicode characters that occupy 2 cells, and other that occupy
+0. To further complicate matters, you might have included ANSI escape sequences
+in the output to generate colors on the terminal.
+The :meth:`cmd2.ansi.style_aware_wcswidth` function solves both of these
+problems. Pass it a string, and regardless of which Unicode characters and ANSI
+text style escape sequences it contains, it will tell you how many characters on the
+screen that string will consume when printed.
diff --git a/docs/features/index.rst b/docs/features/index.rst
index efeb9e6c..dc64badd 100644
--- a/docs/features/index.rst
+++ b/docs/features/index.rst
@@ -5,6 +5,7 @@ Features
:maxdepth: 1
argument_processing
+ builtin_commands
clipboard
commands
completion
diff --git a/docs/features/settings.rst b/docs/features/settings.rst
index f305a68c..627f61a9 100644
--- a/docs/features/settings.rst
+++ b/docs/features/settings.rst
@@ -1,68 +1,138 @@
Settings
========
-- current settings and what they do
-- how a developer can add their own
-- how to hide built in settings from a user
+Settings provide a mechanism for a user to control the behavior of a ``cmd2``
+based application. A setting is stored in an instance attribute on your
+subclass of :class:`cmd2.cmd2.Cmd` and must also appear in the
+:attr:`cmd2.cmd2.Cmd.settable` dictionary. Developers may set default values
+for these settings and users can modify them at runtime using the
+:ref:`features/builtin_commands:set` command. Developers can
+:ref:`features/settings:Create New Settings` and can also
+:ref:`features/settings:Hide Builtin Settings` from the user.
-Built In Settings
+
+Builtin Settings
-----------------
-``cmd2`` has a number of built in settings, which a developer can set a default
-value, and which users can modify to change the behavior of the application.
+``cmd2`` has a number of builtin settings. These settings control the behavior
+of certain application features and :ref:`features/builtin_commands:Builtin
+Commands`. Users can use the :ref:`features/builtin_commands:set` command to
+show all settings and to modify the value of any setting.
-Timing
-~~~~~~
+allow_style
+~~~~~~~~~~~
+
+Output generated by ``cmd2`` programs may contain ANSI escape seqences which
+instruct the terminal to apply colors or text styling (i.e. bold) to the
+output. The ``allow_style`` setting controls the behavior of these escape
+sequences in output generated with any of the following methods:
+
+- :meth:`.cmd2.Cmd.poutput`
+- :meth:`.cmd2.Cmd.perror`
+- :meth:`.cmd2.Cmd.pwarning`
+- :meth:`.cmd2.Cmd.pexcept`
+- :meth:`.cmd2.Cmd.pfeedback`
+- :meth:`.cmd2.Cmd.ppaged`
+
+This setting can be one of three values:
+
+- ``Never`` - all ANSI escape sequences which instruct the terminal to style
+ output are stripped from the output.
+
+- ``Terminal`` - (the default value) pass through ANSI escape sequences when
+ the output is being sent to the terminal, but if the output is redirected to
+ a pipe or a file the escape sequences are stripped.
+
+- ``Always`` - ANSI escape sequences are always passed through to the output
+
+
+continuation_prompt
+~~~~~~~~~~~~~~~~~~~
-Setting ``App.timing`` to ``True`` outputs timing data after every application
-command is executed. |settable|
+When a user types a :ref:`Multiline Command
+<features/multiline_commands:Multiline Commands>` it may span more than one
+line of input. The prompt for the first line of input is specified by the
+:ref:`features/settings:prompt` setting. The prompt for subsequent lines of
+input is defined by this setting.
-Echo
+debug
+~~~~~
+
+The default value of this setting is ``False``, which causes the
+:meth:`~.cmd2.Cmd.pexcept` method to only display the message from an
+exception. However, if the debug setting is ``True``, then the entire stack
+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.
+it is executed. This is particularly useful when running scripts. This behavior
+does not occur when a running command at the prompt.
-Debug
-~~~~~
+editor
+~~~~~~
+
+Similar to the ``EDITOR`` shell variable, this setting contains the name of the
+program which should be run by the :ref:`features/builtin_commands:edit`
+command.
+
+
+feedback_to_output
+~~~~~~~~~~~~~~~~~~
-Setting ``App.debug`` to ``True`` will produce detailed error stacks whenever
-the application generates an error. |settable|
+Controls whether feedback generated with the :meth:`~cmd2.cmd2.Cmd.pfeedback`
+method is sent to ``sys.stdout`` or ``sys.stderr``. If ``False`` the output
+will be sent to ``sys.stderr``
-.. |settable| replace:: The user can ``set`` this parameter
- during application execution.
- (See :ref:`parameters`)
+If ``True`` the output is sent to ``stdout`` (which is often the screen but may
+be :ref:`redirected <features/redirection:Output Redirection and Pipes>`). The
+feedback output will be mixed in with and indistinguishable from output
+generated with :meth:`~cmd2.cmd2.Cmd.poutput`.
-.. _parameters:
-Other user-settable parameters
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+locals_in_py
+~~~~~~~~~~~~
-A list of all user-settable parameters, with brief
-comments, is viewable from within a running application
-with::
+Allow access to your application in one of the
+:ref:`features/embedded_python_shells:Embedded Python Shells` via ``self``.
- (Cmd) set --long
- allow_style: Terminal # Allow ANSI text style sequences in output (valid values: Terminal, Always, Never)
- continuation_prompt: > # On 2nd+ line of input
- debug: False # Show full error stack on error
- echo: False # Echo command issued into output
- editor: vim # Program used by ``edit``
- feedback_to_output: False # include nonessentials in `|`, `>` results
- locals_in_py: False # Allow access to your application in py via self
- max_completion_items: 50 # Maximum number of CompletionItems to display during tab completion
- prompt: (Cmd) # The prompt issued to solicit input
- quiet: False # Don't print nonessential feedback
- timing: False # Report execution times
-Any of these user-settable parameters can be set while running your app with
-the ``set`` command like so::
+max_completion_items
+~~~~~~~~~~~~~~~~~~~~
- set allow_style Never
+Maximum number of CompletionItems to display during tab completion. A CompletionItem
+is a special kind of tab-completion hint which displays both a value and description
+and uses one line for each hint. Tab complete the ``set`` command for an example.
+If the number of tab-completion hints exceeds ``max_completion_items``, then they will
+be displayed in the typical columnized format and will not include the description text
+of the CompletionItem.
+
+
+prompt
+~~~~~~
+
+This setting contains the string which should be printed as a prompt for user
+input.
+
+
+quiet
+~~~~~
+
+If ``True``, output generated by calling :meth:`~.cmd2.Cmd.pfeedback` is
+suppressed. If ``False``, the :ref:`features/settings:feedback_to_output`
+setting controls where the output is sent.
+
+
+timing
+~~~~~~
+
+If ``True``, the elapsed time is reported for each command executed.
Create New Settings
@@ -100,3 +170,23 @@ changes a setting, and will receive both the old value and the new value.
now: 13
(Cmd) sunbathe
It's 13 C - are you a penguin?
+
+
+Hide Builtin Settings
+----------------------
+
+You may want to prevent a user from modifying a builtin setting. A setting
+must appear in the :attr:`cmd2.cmd2.Cmd.settable` dictionary in order for it
+to be available to the :ref:`features/builtin_commands:set` command.
+
+Let's say your program does not have any
+:ref:`features/multiline_commands:Multiline Commands`. You might want to hide
+the :ref:`features/settings:continuation_prompt` setting from your users since
+it is only applicable to multiline commands. To do so, remove it from the
+:attr:`cmd2.cmd2.Cmd.settable` dictionary after you initialize your object::
+
+ class MyApp(cmd2.Cmd):
+
+ def __init__(self):
+ super().__init__()
+ self.settable.pop('continuation_prompt')
diff --git a/docs/features/startup_commands.rst b/docs/features/startup_commands.rst
index 93984db6..aaaf7722 100644
--- a/docs/features/startup_commands.rst
+++ b/docs/features/startup_commands.rst
@@ -5,7 +5,7 @@ Startup Commands
after your application starts up:
1. Commands at Invocation
-1. Startup Script
+2. Startup Script
Commands run as part of a startup script are always run immediately after the
application finishes initializing so they are guaranteed to run before any
diff --git a/docs/migrating/incompatibilities.rst b/docs/migrating/incompatibilities.rst
index 7526b51b..ba6f2ed1 100644
--- a/docs/migrating/incompatibilities.rst
+++ b/docs/migrating/incompatibilities.rst
@@ -46,15 +46,16 @@ writing a :ref:`Postparsing Hook <features/hooks:Postparsing Hooks>`.
Cmd.cmdqueue
------------
+
In cmd_, the `Cmd.cmdqueue
<https://docs.python.org/3/library/cmd.html#cmd.Cmd.cmdqueue>`_ attribute
-contains A list of queued input lines. The cmdqueue list is checked in
+contains a list of queued input lines. The cmdqueue list is checked in
``cmdloop()`` when new input is needed; if it is nonempty, its elements will be
processed in order, as if entered at the prompt.
-Since version 0.9.13 ``cmd2`` has removed support for ``Cmd.cmdqueue``.
-Because ``cmd2`` supports running commands via the main ``cmdloop()``, text
-scripts, Python scripts, transcripts, and history replays, the only way to
-preserve consistent behavior across these methods was to eliminate the command
-queue. Additionally, reasoning about application behavior is much easier
-without this queue present.
+Since version 0.9.13 ``cmd2`` has removed support for ``Cmd.cmdqueue``. Because
+``cmd2`` supports running commands via the main ``cmdloop()``, text scripts,
+Python scripts, transcripts, and history replays, the only way to preserve
+consistent behavior across these methods was to eliminate the command queue.
+Additionally, reasoning about application behavior is much easier without this
+queue present.
diff --git a/docs/migrating/next_steps.rst b/docs/migrating/next_steps.rst
index f43c69c9..d95473ee 100644
--- a/docs/migrating/next_steps.rst
+++ b/docs/migrating/next_steps.rst
@@ -15,9 +15,8 @@ For all but the simplest of commands, it's probably easier to use `argparse
``cmd2`` provides a ``@with_argparser()`` decorator which associates an
``ArgumentParser`` object with one of your commands. Using this method will:
-1. Pass your command a `Namespace
-<https://docs.python.org/3/library/argparse.html#argparse.Namespace>`_
-containing the arguments instead of a string of text.
+1. Pass your command a `Namespace <https://docs.python.org/3/library/argparse.html#argparse.Namespace>`_
+ containing the arguments instead of a string of text.
2. Properly handle quoted string input from your users.
@@ -52,8 +51,8 @@ Generating Output
-----------------
If your program generates output by printing directly to ``sys.stdout``, you
-should consider switching to :meth:`cmd2.cmd2.Cmd.poutput`,
-:meth:`cmd2.cmd2.Cmd.perror`, and :meth:`cmd2.cmd2.Cmd.pfeedback`. These
+should consider switching to :meth:`~cmd2.cmd2.Cmd.poutput`,
+:meth:`~cmd2.cmd2.Cmd.perror`, and :meth:`~cmd2.cmd2.Cmd.pfeedback`. These
methods work with several of the built in :ref:`features/settings:Settings` to
allow the user to view or suppress feedback (i.e. progress or status output).
They also properly handle ansi colored output according to user preference.
diff --git a/examples/colors.py b/examples/colors.py
index ea8be479..bbb3b2ad 100755
--- a/examples/colors.py
+++ b/examples/colors.py
@@ -24,9 +24,11 @@ Always
regardless of the output destination
"""
import argparse
+from typing import Any
import cmd2
from cmd2 import ansi
+from colorama import Fore, Back, Style
class CmdLineApp(cmd2.Cmd):
@@ -66,9 +68,31 @@ class CmdLineApp(cmd2.Cmd):
repetitions = args.repeat or 1
output_str = ansi.style(' '.join(words), fg=args.fg, bg=args.bg, bold=args.bold, underline=args.underline)
- for i in range(min(repetitions, self.maxrepeats)):
+ for _ in range(min(repetitions, self.maxrepeats)):
# .poutput handles newlines, and accommodates output redirection too
self.poutput(output_str)
+ self.perror('error message at the end')
+
+ @staticmethod
+ def perror(msg: Any, *, end: str = '\n', apply_style: bool = True) -> None:
+ """Override perror() method from `cmd2.Cmd`
+
+ Use colorama native approach for styling the text instead of `cmd2.ansi` methods
+
+ :param msg: message to print (anything convertible to a str with '{}'.format() is OK)
+ :param end: string appended after the end of the message, default a newline
+ :param apply_style: If True, then ansi.style_error will be applied to the message text. Set to False in cases
+ where the message text already has the desired style. Defaults to True.
+ """
+ if apply_style:
+ final_msg = "{}{}{}{}".format(Fore.RED, Back.YELLOW, msg, Style.RESET_ALL)
+ else:
+ final_msg = "{}".format(msg)
+ ansi.ansi_aware_write(sys.stderr, final_msg + end)
+
+ def do_timetravel(self, args):
+ """A command which always generates an error message, to demonstrate custom error colors"""
+ self.perror('Mr. Fusion failed to start. Could not energize flux capacitor.')
if __name__ == '__main__':
diff --git a/examples/plumbum_colors.py b/examples/plumbum_colors.py
index 8eaf3fe8..fe692805 100755
--- a/examples/plumbum_colors.py
+++ b/examples/plumbum_colors.py
@@ -104,7 +104,7 @@ class CmdLineApp(cmd2.Cmd):
repetitions = args.repeat or 1
output_str = ansi.style(' '.join(words), fg=args.fg, bg=args.bg, bold=args.bold, underline=args.underline)
- for i in range(min(repetitions, self.maxrepeats)):
+ for _ in range(min(repetitions, self.maxrepeats)):
# .poutput handles newlines, and accommodates output redirection too
self.poutput(output_str)