Skip to content

Commit

Permalink
New method: Terminal.formatter() (#172)
Browse files Browse the repository at this point in the history
  • Loading branch information
avylove authored Jun 7, 2020
1 parent 37260bb commit f9039a6
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 4 deletions.
2 changes: 1 addition & 1 deletion blessed/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@
'support due to http://bugs.python.org/issue10570.')

__all__ = ('Terminal',)
__version__ = '1.17.6'
__version__ = '1.17.7'
4 changes: 2 additions & 2 deletions blessed/formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ def resolve_attribute(term, attr):
:arg Terminal term: :class:`~.Terminal` instance.
:arg str attr: Sugary, ordinary, or compound formatted terminal
capability, such as "red_on_white", "normal", "red", or
"bold_on_black", respectively.
"bold_on_black".
:returns: a string class instance which emits the terminal sequence
for the given terminal capability, or may be used as a callable to
wrap the given string with such sequence.
Expand All @@ -478,7 +478,7 @@ def resolve_attribute(term, attr):
# call for each compounding section, joined and returned as
# a completed completed FormattingString.
formatters = split_compound(attr)
if all(fmt in (COLORS | COMPOUNDABLES) for fmt in formatters):
if all((fmt in COLORS or fmt in COMPOUNDABLES) for fmt in formatters):
resolution = (resolve_attribute(term, fmt) for fmt in formatters)
return FormattingString(u''.join(resolution), term.normal)

Expand Down
22 changes: 22 additions & 0 deletions blessed/terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@
from .sequences import Termcap, Sequence, SequenceTextWrapper
from .colorspace import RGB_256TABLE
from .formatters import (COLORS,
COMPOUNDABLES,
FormattingString,
NullCallableString,
ParameterizingString,
FormattingOtherString,
split_compound,
resolve_attribute,
resolve_capability)
from ._capabilities import CAPABILITY_DATABASE, CAPABILITIES_ADDITIVES, CAPABILITIES_RAW_MIXIN
Expand Down Expand Up @@ -824,6 +826,26 @@ def on_color_rgb(self, red, green, blue):
color_idx = self.rgb_downconvert(red, green, blue)
return FormattingString(self._background_color(color_idx), self.normal)

def formatter(self, value):
"""
Provides callable formatting string to set color and other text formatting options.
:arg str value: Sugary, ordinary, or compound formatted terminal capability,
such as "red_on_white", "normal", "red", or "bold_on_black".
:rtype: :class:`FormattingString` or :class:`NullCallableString`
:returns: Callable string that sets color and other text formatting options
Calling ``term.formatter('bold_on_red')`` is equivalent to ``term.bold_on_red``, but a
string that is not a valid text formatter will return a :class:`NullCallableString`.
This is intended to allow validation of text formatters without the possibility of
inadvertently returning another terminal capability.
"""
formatters = split_compound(value)
if all((fmt in COLORS or fmt in COMPOUNDABLES) for fmt in formatters):
return getattr(self, value)

return NullCallableString()

def rgb_downconvert(self, red, green, blue):
"""
Translate an RGB color to a color code of the terminal's color depth.
Expand Down
3 changes: 3 additions & 0 deletions docs/history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ Version History
``term.move_right(9)``.
* introduced: :attr:`~Terminal.pixel_width` and :attr:`~Terminal.pixel_height` for libsixel
support or general curiosity.
* introduced: :meth:`~.Terminal.formatter` which returns callable formatters for valid text
formatters such as 'red' or 'bold_on_red', returning a
:class:`~blessed.formatters.NullCallableString` if passed an invalid text formatter.
* bugfix: prevent ``ValueError: I/O operation on closed file`` on ``sys.stdin`` in multiprocessing
environments, where the keyboard wouldn't work, anyway.
* bugfix: prevent error condition, ``ValueError: underlying buffer has been detached`` in rare
Expand Down
38 changes: 38 additions & 0 deletions tests/test_color.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
# local
from blessed.color import COLOR_DISTANCE_ALGORITHMS
from blessed.colorspace import RGBColor
from blessed.formatters import FormattingString, NullCallableString
# local
from .accessories import TestTerminal, as_subprocess

Expand Down Expand Up @@ -115,3 +116,40 @@ def test_RGBColor():
"""Ensure string is hex color representation"""
color = RGBColor(0x5a, 0x05, 0xcb)
assert str(color) == '#5a05cb'


def test_formatter():
"""Ensure return values match terminal attributes"""
@as_subprocess
def child():
t = TestTerminal(force_styling=True)
t.number_of_colors = 1 << 24
bold_on_seagreen = t.formatter('bold_on_seagreen')
assert isinstance(bold_on_seagreen, FormattingString)
assert bold_on_seagreen == t.bold_on_seagreen

t.number_of_colors = 0
bold_on_seagreen = t.formatter('bold_on_seagreen')
assert isinstance(bold_on_seagreen, FormattingString)
assert bold_on_seagreen == t.bold_on_seagreen

bold = t.formatter('bold')
assert isinstance(bold, FormattingString)
assert bold == t.bold

t = TestTerminal()
t._does_styling = False
t.number_of_colors = 0
bold_on_seagreen = t.formatter('bold_on_seagreen')
assert isinstance(bold_on_seagreen, NullCallableString)
assert bold_on_seagreen == t.bold_on_seagreen
child()


def test_formatter_invalid():
"""Ensure NullCallableString for invalid formatters"""
@as_subprocess
def child():
t = TestTerminal(force_styling=True)
assert isinstance(t.formatter('csr'), NullCallableString)
child()
2 changes: 1 addition & 1 deletion version.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version": "1.17.6"}
{"version": "1.17.7"}

0 comments on commit f9039a6

Please sign in to comment.