Skip to content

Commit 801bab8

Browse files
committed
Changed allow_ansi to allow_style for accuracy in what types of ANSI escape sequences are handled
1 parent e13fc34 commit 801bab8

File tree

17 files changed

+126
-122
lines changed

17 files changed

+126
-122
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ example/transcript_regex.txt:
317317
# The regex for editor will match whatever program you use.
318318
# regexes on prompts just make the trailing space obvious
319319
(Cmd) set
320-
allow_ansi: Terminal
320+
allow_style: Terminal
321321
continuation_prompt: >/ /
322322
debug: False
323323
echo: False

cmd2/ansi.py

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# coding=utf-8
2-
"""Support for ANSI escape sequences which are used for things like applying style to text"""
2+
"""
3+
Support for ANSI escape sequences which are used for things like applying style to text,
4+
setting the window title, and asynchronous alerts.
5+
"""
36
import functools
47
import re
58
from typing import Any, IO
@@ -11,16 +14,17 @@
1114
# On Windows, filter ANSI escape codes out of text sent to stdout/stderr, and replace them with equivalent Win32 calls
1215
colorama.init(strip=False)
1316

14-
# Values for allow_ansi setting
15-
ANSI_NEVER = 'Never'
16-
ANSI_TERMINAL = 'Terminal'
17-
ANSI_ALWAYS = 'Always'
17+
# Values for allow_style setting
18+
STYLE_NEVER = 'Never'
19+
STYLE_TERMINAL = 'Terminal'
20+
STYLE_ALWAYS = 'Always'
1821

19-
# Controls when ANSI escape sequences are allowed in output
20-
allow_ansi = ANSI_TERMINAL
22+
# Controls when ANSI style style sequences are allowed in output
23+
allow_style = STYLE_TERMINAL
2124

22-
# Regular expression to match ANSI escape sequences
23-
ANSI_ESCAPE_RE = re.compile(r'\x1b[^m]*m')
25+
# Regular expression to match ANSI style sequences
26+
# This matches: colorama.ansi.CSI + digit(s) + m
27+
ANSI_STYLE_RE = re.compile(r'\033\[[0-9]+m')
2428

2529
# Foreground color presets
2630
FG_COLORS = {
@@ -71,41 +75,41 @@
7175
BRIGHT = Style.BRIGHT
7276
NORMAL = Style.NORMAL
7377

74-
# ANSI escape sequences not provided by colorama
78+
# ANSI style sequences not provided by colorama
7579
UNDERLINE_ENABLE = colorama.ansi.code_to_chars(4)
7680
UNDERLINE_DISABLE = colorama.ansi.code_to_chars(24)
7781

7882

79-
def strip_ansi(text: str) -> str:
83+
def strip_style(text: str) -> str:
8084
"""
81-
Strip ANSI escape sequences from a string.
85+
Strip ANSI style sequences from a string.
8286
83-
:param text: string which may contain ANSI escape sequences
84-
:return: the same string with any ANSI escape sequences removed
87+
:param text: string which may contain ANSI style sequences
88+
:return: the same string with any ANSI style sequences removed
8589
"""
86-
return ANSI_ESCAPE_RE.sub('', text)
90+
return ANSI_STYLE_RE.sub('', text)
8791

8892

8993
def ansi_safe_wcswidth(text: str) -> int:
9094
"""
91-
Wrap wcswidth to make it compatible with strings that contains ANSI escape sequences
95+
Wrap wcswidth to make it compatible with strings that contains ANSI style sequences
9296
9397
:param text: the string being measured
9498
"""
95-
# Strip ANSI escape sequences since they cause wcswidth to return -1
96-
return wcswidth(strip_ansi(text))
99+
# Strip ANSI style sequences since they cause wcswidth to return -1
100+
return wcswidth(strip_style(text))
97101

98102

99103
def ansi_aware_write(fileobj: IO, msg: str) -> None:
100104
"""
101-
Write a string to a fileobject and strip its ANSI escape sequences if required by allow_ansi setting
105+
Write a string to a fileobject and strip its ANSI style sequences if required by allow_style setting
102106
103107
:param fileobj: the file object being written to
104108
:param msg: the string being written
105109
"""
106-
if allow_ansi.lower() == ANSI_NEVER.lower() or \
107-
(allow_ansi.lower() == ANSI_TERMINAL.lower() and not fileobj.isatty()):
108-
msg = strip_ansi(msg)
110+
if allow_style.lower() == STYLE_NEVER.lower() or \
111+
(allow_style.lower() == STYLE_TERMINAL.lower() and not fileobj.isatty()):
112+
msg = strip_style(msg)
109113
fileobj.write(msg)
110114

111115

@@ -176,7 +180,7 @@ def style(text: Any, *, fg: str = '', bg: str = '', bold: bool = False, underlin
176180
additions.append(UNDERLINE_ENABLE)
177181
removals.append(UNDERLINE_DISABLE)
178182

179-
# Combine the ANSI escape sequences with the text
183+
# Combine the ANSI style sequences with the text
180184
return "".join(additions) + text + "".join(removals)
181185

182186

cmd2/cmd2.py

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -206,11 +206,11 @@ def __init__(self, completekey: str = 'tab', stdin=None, stdout=None, *,
206206
# To make an attribute settable with the "do_set" command, add it to this ...
207207
self.settable = \
208208
{
209-
# allow_ansi is a special case in which it's an application-wide setting defined in ansi.py
210-
'allow_ansi': ('Allow ANSI escape sequences in output '
211-
'(valid values: {}, {}, {})'.format(ansi.ANSI_TERMINAL,
212-
ansi.ANSI_ALWAYS,
213-
ansi.ANSI_NEVER)),
209+
# allow_style is a special case in which it's an application-wide setting defined in ansi.py
210+
'allow_style': ('Allow ANSI style sequences in output '
211+
'(valid values: {}, {}, {})'.format(ansi.STYLE_TERMINAL,
212+
ansi.STYLE_ALWAYS,
213+
ansi.STYLE_NEVER)),
214214
'continuation_prompt': 'On 2nd+ line of input',
215215
'debug': 'Show full error stack on error',
216216
'echo': 'Echo command issued into output',
@@ -366,7 +366,7 @@ def __init__(self, completekey: str = 'tab', stdin=None, stdout=None, *,
366366
else:
367367
# Here is the meaning of the various flags we are using with the less command:
368368
# -S causes lines longer than the screen width to be chopped (truncated) rather than wrapped
369-
# -R causes ANSI "color" escape sequences to be output in raw form (i.e. colors are displayed)
369+
# -R causes ANSI "style" escape sequences to be output in raw form (i.e. colors are displayed)
370370
# -X disables sending the termcap initialization and deinitialization strings to the terminal
371371
# -F causes less to automatically exit if the entire file can be displayed on the first screen
372372
self.pager = 'less -RXF'
@@ -395,38 +395,38 @@ def __init__(self, completekey: str = 'tab', stdin=None, stdout=None, *,
395395
# ----- Methods related to presenting output to the user -----
396396

397397
@property
398-
def allow_ansi(self) -> str:
399-
"""Read-only property needed to support do_set when it reads allow_ansi"""
400-
return ansi.allow_ansi
398+
def allow_style(self) -> str:
399+
"""Read-only property needed to support do_set when it reads allow_style"""
400+
return ansi.allow_style
401401

402-
@allow_ansi.setter
403-
def allow_ansi(self, new_val: str) -> None:
404-
"""Setter property needed to support do_set when it updates allow_ansi"""
402+
@allow_style.setter
403+
def allow_style(self, new_val: str) -> None:
404+
"""Setter property needed to support do_set when it updates allow_style"""
405405
new_val = new_val.lower()
406-
if new_val == ansi.ANSI_TERMINAL.lower():
407-
ansi.allow_ansi = ansi.ANSI_TERMINAL
408-
elif new_val == ansi.ANSI_ALWAYS.lower():
409-
ansi.allow_ansi = ansi.ANSI_ALWAYS
410-
elif new_val == ansi.ANSI_NEVER.lower():
411-
ansi.allow_ansi = ansi.ANSI_NEVER
406+
if new_val == ansi.STYLE_TERMINAL.lower():
407+
ansi.allow_style = ansi.STYLE_TERMINAL
408+
elif new_val == ansi.STYLE_ALWAYS.lower():
409+
ansi.allow_style = ansi.STYLE_ALWAYS
410+
elif new_val == ansi.STYLE_NEVER.lower():
411+
ansi.allow_style = ansi.STYLE_NEVER
412412
else:
413-
self.perror('Invalid value: {} (valid values: {}, {}, {})'.format(new_val, ansi.ANSI_TERMINAL,
414-
ansi.ANSI_ALWAYS, ansi.ANSI_NEVER))
413+
self.perror('Invalid value: {} (valid values: {}, {}, {})'.format(new_val, ansi.STYLE_TERMINAL,
414+
ansi.STYLE_ALWAYS, ansi.STYLE_NEVER))
415415

416416
def _completion_supported(self) -> bool:
417417
"""Return whether tab completion is supported"""
418418
return self.use_rawinput and self.completekey and rl_type != RlType.NONE
419419

420420
@property
421421
def visible_prompt(self) -> str:
422-
"""Read-only property to get the visible prompt with any ANSI escape codes stripped.
422+
"""Read-only property to get the visible prompt with any ANSI style escape codes stripped.
423423
424424
Used by transcript testing to make it easier and more reliable when users are doing things like coloring the
425425
prompt using ANSI color codes.
426426
427427
:return: prompt stripped of any ANSI escape codes
428428
"""
429-
return ansi.strip_ansi(self.prompt)
429+
return ansi.strip_style(self.prompt)
430430

431431
def poutput(self, msg: Any = '', *, end: str = '\n') -> None:
432432
"""Print message to self.stdout and appends a newline by default
@@ -551,8 +551,8 @@ def ppaged(self, msg: Any, *, end: str = '\n', chop: bool = False) -> None:
551551
# Don't attempt to use a pager that can block if redirecting or running a script (either text or Python)
552552
# Also only attempt to use a pager if actually running in a real fully functional terminal
553553
if functional_terminal and not self._redirecting and not self.in_pyscript() and not self.in_script():
554-
if ansi.allow_ansi.lower() == ansi.ANSI_NEVER.lower():
555-
msg_str = ansi.strip_ansi(msg_str)
554+
if ansi.allow_style.lower() == ansi.STYLE_NEVER.lower():
555+
msg_str = ansi.strip_style(msg_str)
556556
msg_str += end
557557

558558
pager = self.pager

cmd2/transcript.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,13 @@ def _fetchTranscripts(self):
5656
def _test_transcript(self, fname: str, transcript):
5757
line_num = 0
5858
finished = False
59-
line = ansi.strip_ansi(next(transcript))
59+
line = ansi.strip_style(next(transcript))
6060
line_num += 1
6161
while not finished:
6262
# Scroll forward to where actual commands begin
6363
while not line.startswith(self.cmdapp.visible_prompt):
6464
try:
65-
line = ansi.strip_ansi(next(transcript))
65+
line = ansi.strip_style(next(transcript))
6666
except StopIteration:
6767
finished = True
6868
break
@@ -89,15 +89,15 @@ def _test_transcript(self, fname: str, transcript):
8989
result = self.cmdapp.stdout.read()
9090
stop_msg = 'Command indicated application should quit, but more commands in transcript'
9191
# Read the expected result from transcript
92-
if ansi.strip_ansi(line).startswith(self.cmdapp.visible_prompt):
92+
if ansi.strip_style(line).startswith(self.cmdapp.visible_prompt):
9393
message = '\nFile {}, line {}\nCommand was:\n{}\nExpected: (nothing)\nGot:\n{}\n'.format(
9494
fname, line_num, command, result)
9595
self.assertTrue(not (result.strip()), message)
9696
# If the command signaled the application to quit there should be no more commands
9797
self.assertFalse(stop, stop_msg)
9898
continue
9999
expected = []
100-
while not ansi.strip_ansi(line).startswith(self.cmdapp.visible_prompt):
100+
while not ansi.strip_style(line).startswith(self.cmdapp.visible_prompt):
101101
expected.append(line)
102102
try:
103103
line = next(transcript)

cmd2/utils.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,7 @@ def align_text(text: str, alignment: TextAlignment, *, fill_char: str = ' ',
641641
width: Optional[int] = None, tab_width: int = 4) -> str:
642642
"""
643643
Align text for display within a given width. Supports characters with display widths greater than 1.
644-
ANSI escape sequences are safely ignored and do not count toward the display width. This means colored text is
644+
ANSI style sequences are safely ignored and do not count toward the display width. This means colored text is
645645
supported. If text has line breaks, then each line is aligned independently.
646646
647647
There are convenience wrappers around this function: align_left(), align_center(), and align_right()
@@ -688,7 +688,7 @@ def align_text(text: str, alignment: TextAlignment, *, fill_char: str = ' ',
688688
text_buf.write('\n')
689689

690690
# Use ansi_safe_wcswidth to support characters with display widths
691-
# greater than 1 as well as ANSI escape sequences
691+
# greater than 1 as well as ANSI style sequences
692692
line_width = ansi.ansi_safe_wcswidth(line)
693693
if line_width == -1:
694694
raise(ValueError("Text to align contains an unprintable character"))
@@ -728,7 +728,7 @@ def align_text(text: str, alignment: TextAlignment, *, fill_char: str = ' ',
728728
def align_left(text: str, *, fill_char: str = ' ', width: Optional[int] = None, tab_width: int = 4) -> str:
729729
"""
730730
Left align text for display within a given width. Supports characters with display widths greater than 1.
731-
ANSI escape sequences are safely ignored and do not count toward the display width. This means colored text is
731+
ANSI style sequences are safely ignored and do not count toward the display width. This means colored text is
732732
supported. If text has line breaks, then each line is aligned independently.
733733
734734
:param text: text to left align (can contain multiple lines)
@@ -746,7 +746,7 @@ def align_left(text: str, *, fill_char: str = ' ', width: Optional[int] = None,
746746
def align_center(text: str, *, fill_char: str = ' ', width: Optional[int] = None, tab_width: int = 4) -> str:
747747
"""
748748
Center text for display within a given width. Supports characters with display widths greater than 1.
749-
ANSI escape sequences are safely ignored and do not count toward the display width. This means colored text is
749+
ANSI style sequences are safely ignored and do not count toward the display width. This means colored text is
750750
supported. If text has line breaks, then each line is aligned independently.
751751
752752
:param text: text to center (can contain multiple lines)
@@ -764,7 +764,7 @@ def align_center(text: str, *, fill_char: str = ' ', width: Optional[int] = None
764764
def align_right(text: str, *, fill_char: str = ' ', width: Optional[int] = None, tab_width: int = 4) -> str:
765765
"""
766766
Right align text for display within a given width. Supports characters with display widths greater than 1.
767-
ANSI escape sequences are safely ignored and do not count toward the display width. This means colored text is
767+
ANSI style sequences are safely ignored and do not count toward the display width. This means colored text is
768768
supported. If text has line breaks, then each line is aligned independently.
769769
770770
:param text: text to right align (can contain multiple lines)

docs/features/generating_output.rst

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,23 +45,23 @@ changing the value of the ``quiet`` setting.
4545
Colored Output
4646
--------------
4747

48-
The output methods in the previous section all honor the ``allow_ansi``
48+
The output methods in the previous section all honor the ``allow_style``
4949
setting, which has three possible values:
5050

5151
Never
52-
poutput(), pfeedback(), and ppaged() strip all ANSI escape sequences
52+
poutput(), pfeedback(), and ppaged() strip all ANSI style sequences
5353
which instruct the terminal to colorize output
5454

5555
Terminal
5656
(the default value) poutput(), pfeedback(), and ppaged() do not strip any
57-
ANSI escape sequences when the output is a terminal, but if the output is a
58-
pipe or a file the escape sequences are stripped. If you want colorized
59-
output you must add ANSI escape sequences using either cmd2's internal ansi
57+
ANSI style sequences when the output is a terminal, but if the output is a
58+
pipe or a file the style sequences are stripped. If you want colorized
59+
output you must add ANSI style sequences using either cmd2's internal ansi
6060
module or another color library such as `plumbum.colors`, `colorama`, or
6161
`colored`.
6262

6363
Always
64-
poutput(), pfeedback(), and ppaged() never strip ANSI escape sequences,
64+
poutput(), pfeedback(), and ppaged() never strip ANSI style sequences,
6565
regardless of the output destination
6666

6767
Colored and otherwise styled output can be generated using the `ansi.style()`

docs/features/settings.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ comments, is viewable from within a running application
4646
with::
4747

4848
(Cmd) set --long
49-
allow_ansi: Terminal # Allow ANSI escape sequences in output (valid values: Terminal, Always, Never)
49+
allow_style: Terminal # Allow ANSI style sequences in output (valid values: Terminal, Always, Never)
5050
continuation_prompt: > # On 2nd+ line of input
5151
debug: False # Show full error stack on error
5252
echo: False # Echo command issued into output
@@ -61,7 +61,7 @@ with::
6161
Any of these user-settable parameters can be set while running your app with
6262
the ``set`` command like so::
6363

64-
set allow_ansi Never
64+
set allow_style Never
6565

6666

6767

examples/colors.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,21 @@
66
Experiment with the command line options on the `speak` command to see how
77
different output colors ca
88
9-
The allow_ansi setting has three possible values:
9+
The allow_style setting has three possible values:
1010
1111
Never
12-
poutput(), pfeedback(), and ppaged() strip all ANSI escape sequences
12+
poutput(), pfeedback(), and ppaged() strip all ANSI style sequences
1313
which instruct the terminal to colorize output
1414
1515
Terminal
1616
(the default value) poutput(), pfeedback(), and ppaged() do not strip any
17-
ANSI escape sequences when the output is a terminal, but if the output is
18-
a pipe or a file the escape sequences are stripped. If you want colorized
19-
output you must add ANSI escape sequences using either cmd2's internal ansi
17+
ANSI style sequences when the output is a terminal, but if the output is
18+
a pipe or a file the style sequences are stripped. If you want colorized
19+
output you must add ANSI style sequences using either cmd2's internal ansi
2020
module or another color library such as `plumbum.colors` or `colorama`.
2121
2222
Always
23-
poutput(), pfeedback(), and ppaged() never strip ANSI escape sequences,
23+
poutput(), pfeedback(), and ppaged() never strip ANSI style sequences,
2424
regardless of the output destination
2525
"""
2626
import argparse
@@ -40,7 +40,7 @@ def __init__(self):
4040
self.settable['maxrepeats'] = 'max repetitions for speak command'
4141

4242
# Should ANSI color output be allowed
43-
self.allow_ansi = ansi.ANSI_TERMINAL
43+
self.allow_style = ansi.STYLE_TERMINAL
4444

4545
speak_parser = argparse.ArgumentParser()
4646
speak_parser.add_argument('-p', '--piglatin', action='store_true', help='atinLay')

0 commit comments

Comments
 (0)