summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErik Rose <erik@mozilla.com>2011-11-30 23:44:47 -0800
committerErik Rose <erik@mozilla.com>2011-11-30 23:44:47 -0800
commit15293bc24d35d4c60dbce75528bde571c1a60b63 (patch)
tree5c237f796aec172aff38564da09a3f496e6a1e12
parent3c711a9ce95856239a451f6c8dae2a2865979ffc (diff)
downloadblessings-15293bc24d35d4c60dbce75528bde571c1a60b63.tar.gz
Allow `color` attr to act as an unparametrized string, not just a callable.
Also have FormattingString stop reaching into the Terminal to pull out `normal`.
-rw-r--r--blessings/__init__.py63
-rw-r--r--blessings/tests.py6
-rw-r--r--docs/index.rst2
3 files changed, 45 insertions, 26 deletions
diff --git a/blessings/__init__.py b/blessings/__init__.py
index b4b2ecb..f46ee66 100644
--- a/blessings/__init__.py
+++ b/blessings/__init__.py
@@ -185,27 +185,28 @@ class Terminal(object):
"""
return Location(self, x, y)
- def color(self, num):
+ @property
+ def color(self):
"""Return a capability that sets the foreground color.
- :arg num: The number, 0-15, of the color
+ The capability is unparametrized until called and passed a number
+ (0-15), at which point it returns another string which represents a
+ specific color change. This second string can further be called to
+ color a piece of text and set everything back to normal afterward.
- The returned string can also be called on another string to wrap it in
- the color and set the formatting to normal afterward.
+ :arg num: The number, 0-15, of the color
"""
- return self._resolve_numeric_color(num, self._foreground_color)
+ return ParametrizingString(self._foreground_color, self.normal)
- def on_color(self, num):
+ @property
+ def on_color(self):
"""Return a capability that sets the background color.
- :arg num: The number, 0-15, of the color
-
- The returned string can also be called on another string to wrap it in
- the color and set the formatting to normal afterward.
+ See ``color()``.
"""
- return self._resolve_numeric_color(num, self._background_color)
+ return ParametrizingString(self._background_color, self.normal)
def _resolve_formatter(self, attr):
"""Resolve a sugary or plain capability name, color, or compound formatting function name into a callable capability."""
@@ -213,16 +214,15 @@ class Terminal(object):
return self._resolve_color(attr)
elif attr in COMPOUNDABLES:
# Bold, underline, or something that takes no parameters
- return FormattingString(self._resolve_capability(attr), self)
+ return self._formatting_string(self._resolve_capability(attr))
else:
formatters = split_into_formatters(attr)
if all(f in COMPOUNDABLES for f in formatters):
# It's a compound formatter, like "bold_green_on_red". Future
# optimization: combine all formatting into a single escape
# sequence.
- return FormattingString(
- u''.join(self._resolve_formatter(s) for s in formatters),
- self)
+ return self._formatting_string(
+ u''.join(self._resolve_formatter(s) for s in formatters))
else:
return ParametrizingString(self._resolve_capability(attr))
@@ -253,13 +253,8 @@ class Terminal(object):
# bright colors at 8-15:
offset = 8 if 'bright_' in color else 0
base_color = color.rsplit('_', 1)[-1]
- return self._resolve_numeric_color(
- getattr(curses, 'COLOR_' + base_color.upper()) + offset,
- color_cap)
-
- def _resolve_numeric_color(self, num, cap):
- """Resolve a numeric base color to a ``FormattingString``."""
- return FormattingString(cap(num), self)
+ return self._formatting_string(
+ color_cap(getattr(curses, 'COLOR_' + base_color.upper()) + offset))
@property
def _foreground_color(self):
@@ -269,6 +264,10 @@ class Terminal(object):
def _background_color(self):
return self.setab or self.setb
+ def _formatting_string(self, formatting):
+ """Return a new ``FormattingString`` which implicitly receives my notion of "normal"."""
+ return FormattingString(formatting, self.normal)
+
def derivative_colors(colors):
"""Return the names of valid color variants, given the base colors."""
@@ -286,12 +285,26 @@ COMPOUNDABLES = (COLORS |
class ParametrizingString(unicode):
"""A Unicode string which can be called to parametrize it as a terminal capability"""
+ def __new__(cls, formatting, normal=None):
+ """Instantiate.
+
+ :arg normal: If non-None, indicates that, once parametrized, this can
+ be used as a ``FormattingString``. The value is used as the
+ "normal" capability.
+
+ """
+ new = unicode.__new__(cls, formatting)
+ new._normal = normal
+ return new
+
def __call__(self, *args):
try:
# Re-encode the cap, because tparm() takes a bytestring in Python
# 3. However, appear to be a plain Unicode string otherwise so
# concats work.
- return tparm(self.encode('utf-8'), *args).decode('utf-8')
+ parametrized = tparm(self.encode('utf-8'), *args).decode('utf-8')
+ return (parametrized if self._normal is None else
+ FormattingString(parametrized, self._normal))
except curses.error:
# Catch "must call (at least) setupterm() first" errors, as when
# running simply `nosetests` (without progressive) on nose-
@@ -314,9 +327,9 @@ class ParametrizingString(unicode):
class FormattingString(unicode):
"""A Unicode string which can be called upon a piece of text to wrap it in formatting"""
- def __new__(cls, formatting, term):
+ def __new__(cls, formatting, normal):
new = unicode.__new__(cls, formatting)
- new._normal = term.normal
+ new._normal = normal
return new
def __call__(self, text):
diff --git a/blessings/tests.py b/blessings/tests.py
index beca0f8..aa8d5d8 100644
--- a/blessings/tests.py
+++ b/blessings/tests.py
@@ -150,6 +150,12 @@ def test_null_callable_numeric_colors():
eq_(t.on_color(6)('smoo'), 'smoo')
+def test_naked_color_cap():
+ """``term.color`` should return a stringlike capability."""
+ t = TestTerminal()
+ eq_(t.color + '', t.setaf + '')
+
+
def test_formatting_functions():
"""Test crazy-ass formatting wrappers, both simple and compound."""
t = TestTerminal()
diff --git a/docs/index.rst b/docs/index.rst
index 02d07d6..8cad9ca 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -17,4 +17,4 @@ Then Read This If You Want
==========================
.. autoclass:: blessings.Terminal
- :members: __init__, __getattr__, location, height, width
+ :members: __init__, __getattr__, location, height, width, color, on_color