summaryrefslogtreecommitdiff
path: root/docs/features/generating_output.rst
blob: 78ff76578e595e5f1a2dafe6f9eaf9e8eed3e4b2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
Generating Output
=================

A standard ``cmd`` application can produce output by using either of these
methods::

  print("Greetings, Professor Falken.", file=self.stdout)
  self.stdout.write("Shall we play a game?\n")

While you could send output directly to ``sys.stdout``, ``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.

``cmd2`` 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. ``cmd2``
also adds a number of output related methods to ``Cmd2.Cmd`` which you may use
to enhance the output your application produces.


Ordinary 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.cmd2.Cmd.poutput` adds two
conveniences.

  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 ``Cmd2.cmd``.

  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)


Colored Output
--------------
The output methods in the previous section all honor the ``allow_style``
setting, which has three possible values:

Never
    poutput(), pfeedback(), and ppaged() strip all ANSI style sequences
    which instruct the terminal to colorize output

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:

.. automethod:: cmd2.ansi.style
   :noindex:

You may want to generate output in different colors, which is typically done by
adding `ANSI escape sequences
<https://en.wikipedia.org/wiki/ANSI_escape_code#Colors>`_ 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 another
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 escape
codes from a string. These functions are all documentated in
:mod:`cmd2.ansi`.

:mod:`cmd2.cmd2.Cmd` includes an :ref:`features/settings:allow_style` setting,
which controls whether ANSI escape sequences that instruct the terminal to
colorize output are stripped from the output. The recommended approach is to
construct your application so that it generates colorized output, and then
allow your users to use this setting to remove the colorization if they do not
want it.

Output generated by any of these
methods will honor the :ref:`features/settings:allow_style` setting:

- :meth:`~.cmd2.Cmd.poutput`
- :meth:`~.cmd2.Cmd.perror`
- :meth:`~.cmd2.Cmd.pwarning`
- :meth:`~.cmd2.Cmd.pexcept`
- :meth:`~.cmd2.Cmd.pfeedback`
- :meth:`~.cmd2.Cmd.ppaged`


Error Messages
--------------

When an error occurs in your program, you can display it on ``sys.stderr`` by
calling the :meth:`~.cmd2.Cmd.perror` method.


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``.


Centering Text
--------------

If you would like to generate output which is centered in the user's terminal,
the :meth:`cmd2.utils.align_center` method can help. Pass it a string and it
will figure out the width of the terminal and return you a new string,
appropriately padded so it will be centered.


Columnar Output
---------------

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
escape sequences it contains, it will tell you how many characters on the
screen that string will consume when printed.