wizlib 3.3.9__py3-none-any.whl → 3.3.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of wizlib might be problematic. Click here for more details.
wizlib/ui/shell_ui.py
CHANGED
|
@@ -4,6 +4,7 @@ import sys
|
|
|
4
4
|
from wizlib.ui import UI, Chooser, Emphasis
|
|
5
5
|
from wizlib.ui.shell.line_editor import ShellLineEditor
|
|
6
6
|
from wizlib.ui.shell import S
|
|
7
|
+
from wizlib.ui.text_wrapper import StreamingTextWrapper
|
|
7
8
|
import wizlib.io
|
|
8
9
|
|
|
9
10
|
COLOR = {
|
|
@@ -23,12 +24,35 @@ class ShellUI(UI):
|
|
|
23
24
|
|
|
24
25
|
name = "shell"
|
|
25
26
|
|
|
27
|
+
def __init__(self):
|
|
28
|
+
super().__init__()
|
|
29
|
+
self._wrapper = None
|
|
30
|
+
|
|
26
31
|
def send(self, value: str = '', emphasis: Emphasis = Emphasis.GENERAL,
|
|
27
|
-
newline: bool = True):
|
|
28
|
-
"""Output some text
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
newline: bool = True, wrap: int = 0):
|
|
33
|
+
"""Output some text
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
value: Text to output
|
|
37
|
+
emphasis: Color/emphasis style
|
|
38
|
+
newline: Whether to append a newline
|
|
39
|
+
wrap: Column width to wrap at (0 = no wrapping)
|
|
40
|
+
"""
|
|
41
|
+
if wrap > 0:
|
|
42
|
+
# Initialize wrapper if needed or if width changed
|
|
43
|
+
if self._wrapper is None or self._wrapper.width != wrap:
|
|
44
|
+
self._wrapper = StreamingTextWrapper(
|
|
45
|
+
width=wrap, output_stream=sys.stderr)
|
|
46
|
+
|
|
47
|
+
# Use streaming wrapper
|
|
48
|
+
self._wrapper.write_streaming(value, COLOR[emphasis])
|
|
49
|
+
if newline:
|
|
50
|
+
self._wrapper.write_newline()
|
|
51
|
+
else:
|
|
52
|
+
# Original behavior - no wrapping
|
|
53
|
+
end = '\n' if newline else ''
|
|
54
|
+
sys.stderr.write(COLOR[emphasis] + value + S.RESET + end)
|
|
55
|
+
sys.stderr.flush()
|
|
32
56
|
|
|
33
57
|
def ask(self, value: str):
|
|
34
58
|
"""Prompt for input"""
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Streaming text wrapper that provides word wrapping with backspace correction
|
|
3
|
+
for a typewriter-like streaming experience.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import sys
|
|
7
|
+
from enum import Enum
|
|
8
|
+
from wizlib.ui import Emphasis
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class StreamingTextWrapper:
|
|
12
|
+
"""Handles streaming text output with word wrapping that uses backspace
|
|
13
|
+
to correct words that would overflow the line boundary.
|
|
14
|
+
|
|
15
|
+
Provides a typewriter-like streaming experience where characters are
|
|
16
|
+
written immediately, but words are moved to the next line if they
|
|
17
|
+
would overflow.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, width: int = 80, output_stream=None):
|
|
21
|
+
"""Initialize the wrapper.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
width: Column width to wrap at
|
|
25
|
+
output_stream: Stream to write to (defaults to sys.stderr)
|
|
26
|
+
"""
|
|
27
|
+
self.width = width
|
|
28
|
+
self.output_stream = output_stream or sys.stderr
|
|
29
|
+
self._current_col = 0
|
|
30
|
+
self._word_buffer = [] # Buffer for current word being streamed
|
|
31
|
+
|
|
32
|
+
def _write_char(self, char: str, color_code: str = ''):
|
|
33
|
+
"""Write a single character with optional color."""
|
|
34
|
+
if color_code:
|
|
35
|
+
self.output_stream.write(color_code + char + '\033[0m')
|
|
36
|
+
else:
|
|
37
|
+
self.output_stream.write(char)
|
|
38
|
+
self.output_stream.flush()
|
|
39
|
+
|
|
40
|
+
def _backspace_buffer(self):
|
|
41
|
+
"""Backspace over the current word buffer."""
|
|
42
|
+
for _ in range(len(self._word_buffer)):
|
|
43
|
+
self.output_stream.write('\b \b') # backspace, space, backspace
|
|
44
|
+
self.output_stream.flush()
|
|
45
|
+
|
|
46
|
+
def write_streaming(self, text: str, color_code: str = ''):
|
|
47
|
+
"""Write text with streaming word wrapping.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
text: Text to output
|
|
51
|
+
color_code: ANSI color code to apply
|
|
52
|
+
"""
|
|
53
|
+
for char in text:
|
|
54
|
+
if char == '\n':
|
|
55
|
+
# Explicit newline - flush buffer and reset
|
|
56
|
+
self._word_buffer = []
|
|
57
|
+
self._write_char(char)
|
|
58
|
+
self._current_col = 0
|
|
59
|
+
elif char in ' \t':
|
|
60
|
+
# Word boundary - write the space and clear buffer
|
|
61
|
+
self._word_buffer = []
|
|
62
|
+
self._write_char(char, color_code)
|
|
63
|
+
self._current_col += 1
|
|
64
|
+
else:
|
|
65
|
+
# Regular character - add to buffer and write immediately
|
|
66
|
+
self._word_buffer.append(char)
|
|
67
|
+
self._write_char(char, color_code)
|
|
68
|
+
self._current_col += 1
|
|
69
|
+
|
|
70
|
+
# Check if this character pushed us over the width
|
|
71
|
+
if self._current_col > self.width:
|
|
72
|
+
# Only backspace and wrap if the word can fit on a new line
|
|
73
|
+
# If the word itself is longer than width, let it continue
|
|
74
|
+
if len(self._word_buffer) <= self.width:
|
|
75
|
+
# We've gone over - backspace the whole current word
|
|
76
|
+
self._backspace_buffer()
|
|
77
|
+
self._current_col -= len(self._word_buffer)
|
|
78
|
+
|
|
79
|
+
# Write newline
|
|
80
|
+
self._write_char('\n')
|
|
81
|
+
self._current_col = 0
|
|
82
|
+
|
|
83
|
+
# Rewrite word on new line
|
|
84
|
+
for c in self._word_buffer:
|
|
85
|
+
self._write_char(c, color_code)
|
|
86
|
+
self._current_col += 1
|
|
87
|
+
|
|
88
|
+
def write_newline(self):
|
|
89
|
+
"""Write a newline and reset position."""
|
|
90
|
+
self.output_stream.write('\n')
|
|
91
|
+
self.output_stream.flush()
|
|
92
|
+
self._current_col = 0
|
|
93
|
+
self._word_buffer = []
|
|
94
|
+
|
|
95
|
+
def reset_position(self):
|
|
96
|
+
"""Reset the column position (useful for explicit positioning)."""
|
|
97
|
+
self._current_col = 0
|
|
98
|
+
self._word_buffer = []
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def current_column(self):
|
|
102
|
+
"""Get the current column position."""
|
|
103
|
+
return self._current_col
|
|
@@ -13,8 +13,9 @@ wizlib/test_case.py,sha256=T5cX7yWy94hf8JuherDeBCH9Gve5tx2x_PZOte4udC0,1017
|
|
|
13
13
|
wizlib/ui/__init__.py,sha256=ve_p_g4aBujh4jIJMgKkJ6cE5PT0aeY5AgRlneDswGg,4241
|
|
14
14
|
wizlib/ui/shell/__init__.py,sha256=VFtxcvTh5Mhyx6JHbR1C8yIDHlOsrNjdqSVfH5ZPAtQ,1154
|
|
15
15
|
wizlib/ui/shell/line_editor.py,sha256=OXOgHBhp7EfheZK1mdOykYqB_aXDn2bHA12dvHN9kFg,8087
|
|
16
|
-
wizlib/ui/shell_ui.py,sha256=
|
|
16
|
+
wizlib/ui/shell_ui.py,sha256=zsqmfL5LTnH_yqfqHUmBKhkZdb5cjRWL96vmfTrAn3U,2855
|
|
17
|
+
wizlib/ui/text_wrapper.py,sha256=WYL59E9cMRv0gI2Yhrc5GJTvstRZO86uYUD7lmDiwjM,3812
|
|
17
18
|
wizlib/ui_handler.py,sha256=JoZadtw9DKAtGvHKP3_BJF2NaYqmcQYNdsY4PeRnOjg,634
|
|
18
|
-
wizlib-3.3.
|
|
19
|
-
wizlib-3.3.
|
|
20
|
-
wizlib-3.3.
|
|
19
|
+
wizlib-3.3.10.dist-info/METADATA,sha256=s7L0Q0x7p3Wi0-hTGlD0z2cz0XqcyAbe14YNzErmUJs,996
|
|
20
|
+
wizlib-3.3.10.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
21
|
+
wizlib-3.3.10.dist-info/RECORD,,
|
|
File without changes
|