python/blessings/README.rst

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/python/blessings/README.rst	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,399 @@
     1.4 +=========
     1.5 +Blessings
     1.6 +=========
     1.7 +
     1.8 +Coding with Blessings looks like this... ::
     1.9 +
    1.10 +    from blessings import Terminal
    1.11 +
    1.12 +    t = Terminal()
    1.13 +
    1.14 +    print t.bold('Hi there!')
    1.15 +    print t.bold_red_on_bright_green('It hurts my eyes!')
    1.16 +
    1.17 +    with t.location(0, t.height - 1):
    1.18 +        print 'This is at the bottom.'
    1.19 +
    1.20 +Or, for byte-level control, you can drop down and play with raw terminal
    1.21 +capabilities::
    1.22 +
    1.23 +    print '{t.bold}All your {t.red}bold and red base{t.normal}'.format(t=t)
    1.24 +    print t.wingo(2)
    1.25 +
    1.26 +The Pitch
    1.27 +=========
    1.28 +
    1.29 +Blessings lifts several of curses_' limiting assumptions, and it makes your
    1.30 +code pretty, too:
    1.31 +
    1.32 +* Use styles, color, and maybe a little positioning without clearing the whole
    1.33 +  screen first.
    1.34 +* Leave more than one screenful of scrollback in the buffer after your program
    1.35 +  exits, like a well-behaved command-line app should.
    1.36 +* Get rid of all those noisy, C-like calls to ``tigetstr`` and ``tparm``, so
    1.37 +  your code doesn't get crowded out by terminal bookkeeping.
    1.38 +* Act intelligently when somebody redirects your output to a file, omitting the
    1.39 +  terminal control codes the user doesn't want to see (optional).
    1.40 +
    1.41 +.. _curses: http://docs.python.org/library/curses.html
    1.42 +
    1.43 +Before And After
    1.44 +----------------
    1.45 +
    1.46 +Without Blessings, this is how you'd print some underlined text at the bottom
    1.47 +of the screen::
    1.48 +
    1.49 +    from curses import tigetstr, setupterm, tparm
    1.50 +    from fcntl import ioctl
    1.51 +    from os import isatty
    1.52 +    import struct
    1.53 +    import sys
    1.54 +    from termios import TIOCGWINSZ
    1.55 +
    1.56 +    # If we want to tolerate having our output piped to other commands or
    1.57 +    # files without crashing, we need to do all this branching:
    1.58 +    if hasattr(sys.stdout, 'fileno') and isatty(sys.stdout.fileno()):
    1.59 +        setupterm()
    1.60 +        sc = tigetstr('sc')
    1.61 +        cup = tigetstr('cup')
    1.62 +        rc = tigetstr('rc')
    1.63 +        underline = tigetstr('smul')
    1.64 +        normal = tigetstr('sgr0')
    1.65 +    else:
    1.66 +        sc = cup = rc = underline = normal = ''
    1.67 +    print sc  # Save cursor position.
    1.68 +    if cup:
    1.69 +        # tigetnum('lines') doesn't always update promptly, hence this:
    1.70 +        height = struct.unpack('hhhh', ioctl(0, TIOCGWINSZ, '\000' * 8))[0]
    1.71 +        print tparm(cup, height - 1, 0)  # Move cursor to bottom.
    1.72 +    print 'This is {under}underlined{normal}!'.format(under=underline,
    1.73 +                                                      normal=normal)
    1.74 +    print rc  # Restore cursor position.
    1.75 +
    1.76 +Phew! That was long and full of incomprehensible trash! Let's try it again,
    1.77 +this time with Blessings::
    1.78 +
    1.79 +    from blessings import Terminal
    1.80 +
    1.81 +    term = Terminal()
    1.82 +    with term.location(0, term.height - 1):
    1.83 +        print 'This is', term.underline('pretty!')
    1.84 +
    1.85 +Much better.
    1.86 +
    1.87 +What It Provides
    1.88 +================
    1.89 +
    1.90 +Blessings provides just one top-level object: ``Terminal``. Instantiating a
    1.91 +``Terminal`` figures out whether you're on a terminal at all and, if so, does
    1.92 +any necessary terminal setup. After that, you can proceed to ask it all sorts
    1.93 +of things about the terminal. Terminal terminal terminal.
    1.94 +
    1.95 +Simple Formatting
    1.96 +-----------------
    1.97 +
    1.98 +Lots of handy formatting codes ("capabilities" in low-level parlance) are
    1.99 +available as attributes on a ``Terminal``. For example::
   1.100 +
   1.101 +    from blessings import Terminal
   1.102 +
   1.103 +    term = Terminal()
   1.104 +    print 'I am ' + term.bold + 'bold' + term.normal + '!'
   1.105 +
   1.106 +You can also use them as wrappers so you don't have to say ``normal``
   1.107 +afterward::
   1.108 +
   1.109 +    print 'I am', term.bold('bold') + '!'
   1.110 +
   1.111 +Or, if you want fine-grained control while maintaining some semblance of
   1.112 +brevity, you can combine it with Python's string formatting, which makes
   1.113 +attributes easy to access::
   1.114 +
   1.115 +    print 'All your {t.red}base {t.underline}are belong to us{t.normal}'.format(t=term)
   1.116 +
   1.117 +Simple capabilities of interest include...
   1.118 +
   1.119 +* ``bold``
   1.120 +* ``reverse``
   1.121 +* ``underline``
   1.122 +* ``no_underline`` (which turns off underlining)
   1.123 +* ``blink``
   1.124 +* ``normal`` (which turns off everything, even colors)
   1.125 +* ``clear_eol`` (clear to the end of the line)
   1.126 +* ``clear_bol`` (clear to beginning of line)
   1.127 +* ``clear_eos`` (clear to end of screen)
   1.128 +
   1.129 +Here are a few more which are less likely to work on all terminals:
   1.130 +
   1.131 +* ``dim``
   1.132 +* ``italic`` and ``no_italic``
   1.133 +* ``shadow`` and ``no_shadow``
   1.134 +* ``standout`` and ``no_standout``
   1.135 +* ``subscript`` and ``no_subscript``
   1.136 +* ``superscript`` and ``no_superscript``
   1.137 +* ``flash`` (which flashes the screen once)
   1.138 +
   1.139 +Note that, while the inverse of ``underline`` is ``no_underline``, the only way
   1.140 +to turn off ``bold`` or ``reverse`` is ``normal``, which also cancels any
   1.141 +custom colors. This is because there's no way to tell the terminal to undo
   1.142 +certain pieces of formatting, even at the lowest level.
   1.143 +
   1.144 +You might notice that the above aren't the typical incomprehensible terminfo
   1.145 +capability names; we alias a few of the harder-to-remember ones for
   1.146 +readability. However, you aren't limited to these: you can reference any
   1.147 +string-returning capability listed on the `terminfo man page`_ by the name
   1.148 +under the "Cap-name" column: for example, ``term.rum``.
   1.149 +
   1.150 +.. _`terminfo man page`: http://www.manpagez.com/man/5/terminfo/
   1.151 +
   1.152 +Color
   1.153 +-----
   1.154 +
   1.155 +16 colors, both foreground and background, are available as easy-to-remember
   1.156 +attributes::
   1.157 +
   1.158 +    from blessings import Terminal
   1.159 +
   1.160 +    term = Terminal()
   1.161 +    print term.red + term.on_green + 'Red on green? Ick!' + term.normal
   1.162 +    print term.bright_red + term.on_bright_blue + 'This is even worse!' + term.normal
   1.163 +
   1.164 +You can also call them as wrappers, which sets everything back to normal at the
   1.165 +end::
   1.166 +
   1.167 +    print term.red_on_green('Red on green? Ick!')
   1.168 +    print term.yellow('I can barely see it.')
   1.169 +
   1.170 +The available colors are...
   1.171 +
   1.172 +* ``black``
   1.173 +* ``red``
   1.174 +* ``green``
   1.175 +* ``yellow``
   1.176 +* ``blue``
   1.177 +* ``magenta``
   1.178 +* ``cyan``
   1.179 +* ``white``
   1.180 +
   1.181 +You can set the background color instead of the foreground by prepending
   1.182 +``on_``, as in ``on_blue``. There is also a ``bright`` version of each color:
   1.183 +for example, ``on_bright_blue``.
   1.184 +
   1.185 +There is also a numerical interface to colors, which takes an integer from
   1.186 +0-15::
   1.187 +
   1.188 +    term.color(5) + 'Hello' + term.normal
   1.189 +    term.on_color(3) + 'Hello' + term.normal
   1.190 +
   1.191 +    term.color(5)('Hello')
   1.192 +    term.on_color(3)('Hello')
   1.193 +
   1.194 +If some color is unsupported (for instance, if only the normal colors are
   1.195 +available, not the bright ones), trying to use it will, on most terminals, have
   1.196 +no effect: the foreground and background colors will stay as they were. You can
   1.197 +get fancy and do different things depending on the supported colors by checking
   1.198 +`number_of_colors`_.
   1.199 +
   1.200 +.. _`number_of_colors`: http://packages.python.org/blessings/#blessings.Terminal.number_of_colors
   1.201 +
   1.202 +Compound Formatting
   1.203 +-------------------
   1.204 +
   1.205 +If you want to do lots of crazy formatting all at once, you can just mash it
   1.206 +all together::
   1.207 +
   1.208 +    from blessings import Terminal
   1.209 +
   1.210 +    term = Terminal()
   1.211 +    print term.bold_underline_green_on_yellow + 'Woo' + term.normal
   1.212 +
   1.213 +Or you can use your newly coined attribute as a wrapper, which implicitly sets
   1.214 +everything back to normal afterward::
   1.215 +
   1.216 +    print term.bold_underline_green_on_yellow('Woo')
   1.217 +
   1.218 +This compound notation comes in handy if you want to allow users to customize
   1.219 +the formatting of your app: just have them pass in a format specifier like
   1.220 +"bold_green" on the command line, and do a quick ``getattr(term,
   1.221 +that_option)('Your text')`` when you do your formatting.
   1.222 +
   1.223 +I'd be remiss if I didn't credit couleur_, where I probably got the idea for
   1.224 +all this mashing.
   1.225 +
   1.226 +.. _couleur: http://pypi.python.org/pypi/couleur
   1.227 +
   1.228 +Parametrized Capabilities
   1.229 +-------------------------
   1.230 +
   1.231 +Some capabilities take parameters. Rather than making you dig up ``tparm()``
   1.232 +all the time, we simply make such capabilities into callable strings. You can
   1.233 +pass the parameters right in::
   1.234 +
   1.235 +    from blessings import Terminal
   1.236 +
   1.237 +    term = Terminal()
   1.238 +    print term.move(10, 1)
   1.239 +
   1.240 +Here are some of interest:
   1.241 +
   1.242 +``move``
   1.243 +  Position the cursor elsewhere. Parameters are y coordinate, then x
   1.244 +  coordinate.
   1.245 +``move_x``
   1.246 +  Move the cursor to the given column.
   1.247 +``move_y``
   1.248 +  Move the cursor to the given row.
   1.249 +
   1.250 +You can also reference any other string-returning capability listed on the
   1.251 +`terminfo man page`_ by its name under the "Cap-name" column.
   1.252 +
   1.253 +.. _`terminfo man page`: http://www.manpagez.com/man/5/terminfo/
   1.254 +
   1.255 +Height and Width
   1.256 +----------------
   1.257 +
   1.258 +It's simple to get the height and width of the terminal, in characters::
   1.259 +
   1.260 +    from blessings import Terminal
   1.261 +
   1.262 +    term = Terminal()
   1.263 +    height = term.height
   1.264 +    width = term.width
   1.265 +
   1.266 +These are newly updated each time you ask for them, so they're safe to use from
   1.267 +SIGWINCH handlers.
   1.268 +
   1.269 +Temporary Repositioning
   1.270 +-----------------------
   1.271 +
   1.272 +Sometimes you need to flit to a certain location, print something, and then
   1.273 +return: for example, when updating a progress bar at the bottom of the screen.
   1.274 +``Terminal`` provides a context manager for doing this concisely::
   1.275 +
   1.276 +    from blessings import Terminal
   1.277 +
   1.278 +    term = Terminal()
   1.279 +    with term.location(0, term.height - 1):
   1.280 +        print 'Here is the bottom.'
   1.281 +    print 'This is back where I came from.'
   1.282 +
   1.283 +Parameters to ``location()`` are ``x`` and then ``y``, but you can also pass
   1.284 +just one of them, leaving the other alone. For example... ::
   1.285 +
   1.286 +    with term.location(y=10):
   1.287 +        print 'We changed just the row.'
   1.288 +
   1.289 +If you want to reposition permanently, see ``move``, in an example above.
   1.290 +
   1.291 +Pipe Savvy
   1.292 +----------
   1.293 +
   1.294 +If your program isn't attached to a terminal, like if it's being piped to
   1.295 +another command or redirected to a file, all the capability attributes on
   1.296 +``Terminal`` will return empty strings. You'll get a nice-looking file without
   1.297 +any formatting codes gumming up the works.
   1.298 +
   1.299 +If you want to override this--like if you anticipate your program being piped
   1.300 +through ``less -r``, which handles terminal escapes just fine--pass
   1.301 +``force_styling=True`` to the ``Terminal`` constructor.
   1.302 +
   1.303 +In any case, there is an ``is_a_tty`` attribute on ``Terminal`` that lets you
   1.304 +see whether the attached stream seems to be a terminal. If it's false, you
   1.305 +might refrain from drawing progress bars and other frippery, since you're
   1.306 +apparently headed into a pipe::
   1.307 +
   1.308 +    from blessings import Terminal
   1.309 +
   1.310 +    term = Terminal()
   1.311 +    if term.is_a_tty:
   1.312 +        with term.location(0, term.height - 1):
   1.313 +            print 'Progress: [=======>   ]'
   1.314 +    print term.bold('Important stuff')
   1.315 +
   1.316 +Shopping List
   1.317 +=============
   1.318 +
   1.319 +There are decades of legacy tied up in terminal interaction, so attention to
   1.320 +detail and behavior in edge cases make a difference. Here are some ways
   1.321 +Blessings has your back:
   1.322 +
   1.323 +* Uses the terminfo database so it works with any terminal type
   1.324 +* Provides up-to-the-moment terminal height and width, so you can respond to
   1.325 +  terminal size changes (SIGWINCH signals). (Most other libraries query the
   1.326 +  ``COLUMNS`` and ``LINES`` environment variables or the ``cols`` or ``lines``
   1.327 +  terminal capabilities, which don't update promptly, if at all.)
   1.328 +* Avoids making a mess if the output gets piped to a non-terminal
   1.329 +* Works great with standard Python string templating
   1.330 +* Provides convenient access to all terminal capabilities, not just a sugared
   1.331 +  few
   1.332 +* Outputs to any file-like object, not just stdout
   1.333 +* Keeps a minimum of internal state, so you can feel free to mix and match with
   1.334 +  calls to curses or whatever other terminal libraries you like
   1.335 +
   1.336 +Blessings does not provide...
   1.337 +
   1.338 +* Native color support on the Windows command prompt. However, it should work
   1.339 +  when used in concert with colorama_.
   1.340 +
   1.341 +.. _colorama: http://pypi.python.org/pypi/colorama/0.2.4
   1.342 +
   1.343 +Bugs
   1.344 +====
   1.345 +
   1.346 +Bugs or suggestions? Visit the `issue tracker`_.
   1.347 +
   1.348 +.. _`issue tracker`: https://github.com/erikrose/blessings/issues/new
   1.349 +
   1.350 +License
   1.351 +=======
   1.352 +
   1.353 +Blessings is under the MIT License. See the LICENSE file.
   1.354 +
   1.355 +Version History
   1.356 +===============
   1.357 +
   1.358 +1.3
   1.359 +  * Add ``number_of_colors``, which tells you how many colors the terminal
   1.360 +    supports.
   1.361 +  * Made ``color(n)`` and ``on_color(n)`` callable to wrap a string, like the
   1.362 +    named colors can. Also, make them both fall back to the ``setf`` and
   1.363 +    ``setb`` capabilities (like the named colors do) if the ANSI ``setaf`` and
   1.364 +    ``setab`` aren't available.
   1.365 +  * Allow ``color`` attr to act as an unparametrized string, not just a
   1.366 +    callable.
   1.367 +  * Make ``height`` and ``width`` examine any passed-in stream before falling
   1.368 +    back to stdout. (This rarely if ever affects actual behavior; it's mostly
   1.369 +    philosophical.)
   1.370 +  * Make caching simpler and slightly more efficient.
   1.371 +  * Get rid of a reference cycle between Terminals and FormattingStrings.
   1.372 +  * Update docs to reflect that terminal addressing (as in ``location()``) is
   1.373 +    0-based.
   1.374 +
   1.375 +1.2
   1.376 +  * Added support for Python 3! We need 3.2.3 or greater, because the curses
   1.377 +    library couldn't decide whether to accept strs or bytes before that
   1.378 +    (http://bugs.python.org/issue10570).
   1.379 +  * Everything that comes out of the library is now unicode. This lets us
   1.380 +    support Python 3 without making a mess of the code, and Python 2 should
   1.381 +    continue to work unless you were testing types (and badly). Please file a
   1.382 +    bug if this causes trouble for you.
   1.383 +  * Changed to the MIT License for better world domination.
   1.384 +  * Added Sphinx docs.
   1.385 +
   1.386 +1.1
   1.387 +  * Added nicely named attributes for colors.
   1.388 +  * Introduced compound formatting.
   1.389 +  * Added wrapper behavior for styling and colors.
   1.390 +  * Let you force capabilities to be non-empty, even if the output stream is
   1.391 +    not a terminal.
   1.392 +  * Added the ``is_a_tty`` attribute for telling whether the output stream is a
   1.393 +    terminal.
   1.394 +  * Sugared the remaining interesting string capabilities.
   1.395 +  * Let ``location()`` operate on just an x *or* y coordinate.
   1.396 +
   1.397 +1.0
   1.398 +  * Extracted Blessings from nose-progressive, my `progress-bar-having,
   1.399 +    traceback-shortcutting, rootin', tootin' testrunner`_. It provided the
   1.400 +    tootin' functionality.
   1.401 +
   1.402 +.. _`progress-bar-having, traceback-shortcutting, rootin', tootin' testrunner`: http://pypi.python.org/pypi/nose-progressive/

mercurial