Skip to content

Commit 8b9e8fd

Browse files
authored
Fix input line wrapping bug (#6)
On most terminals, line wrapping would not work properly when using the input function with GNU readline and color escape codes. This PR adds special delimiters around the escape codes, signaling to readline that these are non-visible characters and un-confusing its line wrapping functionality.
1 parent 8e89a39 commit 8b9e8fd

1 file changed

Lines changed: 19 additions & 1 deletion

File tree

brainframe/cli/print_utils.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ class Color(Enum):
2020
UNDERLINE = "\033[4m"
2121

2222

23+
# These delimiters tell GNU readline that any characters between them are
24+
# non-visible. These should be put before and after ASCII escape codes. Without
25+
# these, escape codes mess up readline's text wrapping support.
26+
# See: https://superuser.com/a/301355
27+
_NON_VISIBLE_START = "\001"
28+
_NON_VISIBLE_END = "\002"
29+
30+
2331
def ask_yes_no(message_id, **kwargs) -> bool:
2432
"""Prompts the user with a yes or no question. The default value is yes.
2533
@@ -80,7 +88,13 @@ def print_color(message, color: Color, **kwargs) -> None:
8088

8189
def input_color(message, color: Color) -> str:
8290
color = _check_no_color(color)
83-
return input(f"{color.value}{message}{Color.END.value}")
91+
# See https://superuser.com/a/301355 for why these non-visible delimiters
92+
# are necessary for input()
93+
return input(
94+
f"{_NON_VISIBLE_START}{color.value}{_NON_VISIBLE_END}"
95+
f"{message}"
96+
f"{_NON_VISIBLE_START}{Color.END.value}{_NON_VISIBLE_END}"
97+
)
8498

8599

86100
def _check_no_color(color: Color) -> Color:
@@ -108,3 +122,7 @@ def _check_no_color(color: Color) -> Color:
108122
Installer
109123
110124
"""
125+
126+
# Importing readline has the side-effect of augmenting the `input` function
127+
# with GNU readline features.
128+
_ = readline

0 commit comments

Comments
 (0)