urwid 2.6.15__py3-none-any.whl → 3.0.5__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.
- urwid/__init__.py +30 -20
- urwid/canvas.py +34 -53
- urwid/command_map.py +6 -4
- urwid/container.py +1 -1
- urwid/decoration.py +1 -1
- urwid/display/__init__.py +53 -48
- urwid/display/_posix_raw_display.py +20 -8
- urwid/display/_raw_display_base.py +21 -16
- urwid/display/_win32_raw_display.py +16 -17
- urwid/display/common.py +45 -74
- urwid/display/curses.py +3 -5
- urwid/display/escape.py +28 -13
- urwid/display/lcd.py +8 -10
- urwid/display/web.py +11 -16
- urwid/event_loop/asyncio_loop.py +35 -15
- urwid/event_loop/main_loop.py +18 -23
- urwid/event_loop/tornado_loop.py +4 -5
- urwid/event_loop/trio_loop.py +1 -1
- urwid/font.py +19 -22
- urwid/numedit.py +65 -65
- urwid/signals.py +19 -27
- urwid/split_repr.py +9 -3
- urwid/str_util.py +105 -60
- urwid/text_layout.py +14 -13
- urwid/util.py +8 -19
- urwid/version.py +22 -4
- urwid/vterm.py +20 -47
- urwid/widget/__init__.py +0 -6
- urwid/widget/attr_map.py +10 -10
- urwid/widget/attr_wrap.py +11 -13
- urwid/widget/bar_graph.py +3 -8
- urwid/widget/big_text.py +8 -9
- urwid/widget/box_adapter.py +6 -6
- urwid/widget/columns.py +52 -83
- urwid/widget/container.py +29 -75
- urwid/widget/divider.py +6 -6
- urwid/widget/edit.py +50 -50
- urwid/widget/filler.py +14 -14
- urwid/widget/frame.py +31 -40
- urwid/widget/grid_flow.py +25 -110
- urwid/widget/line_box.py +31 -18
- urwid/widget/listbox.py +16 -51
- urwid/widget/monitored_list.py +75 -49
- urwid/widget/overlay.py +4 -37
- urwid/widget/padding.py +31 -68
- urwid/widget/pile.py +179 -158
- urwid/widget/popup.py +2 -2
- urwid/widget/progress_bar.py +17 -18
- urwid/widget/scrollable.py +26 -34
- urwid/widget/solid_fill.py +3 -3
- urwid/widget/text.py +44 -30
- urwid/widget/treetools.py +27 -48
- urwid/widget/widget.py +13 -130
- urwid/widget/widget_decoration.py +6 -35
- urwid/widget/wimp.py +61 -61
- urwid/wimp.py +1 -1
- {urwid-2.6.15.dist-info → urwid-3.0.5.dist-info}/METADATA +24 -24
- urwid-3.0.5.dist-info/RECORD +74 -0
- {urwid-2.6.15.dist-info → urwid-3.0.5.dist-info}/WHEEL +1 -1
- urwid-2.6.15.dist-info/RECORD +0 -74
- {urwid-2.6.15.dist-info → urwid-3.0.5.dist-info/licenses}/COPYING +0 -0
- {urwid-2.6.15.dist-info → urwid-3.0.5.dist-info}/top_level.txt +0 -0
|
@@ -172,7 +172,7 @@ class Screen(BaseScreen, RealTerminal):
|
|
|
172
172
|
After calling this function get_input will include mouse
|
|
173
173
|
click events along with keystrokes.
|
|
174
174
|
"""
|
|
175
|
-
enable = bool(enable)
|
|
175
|
+
enable = bool(enable)
|
|
176
176
|
if enable == self._mouse_tracking_enabled:
|
|
177
177
|
return
|
|
178
178
|
|
|
@@ -211,7 +211,7 @@ class Screen(BaseScreen, RealTerminal):
|
|
|
211
211
|
Restore the screen.
|
|
212
212
|
"""
|
|
213
213
|
|
|
214
|
-
def write(self, data):
|
|
214
|
+
def write(self, data: str) -> None:
|
|
215
215
|
"""Write some data to the terminal.
|
|
216
216
|
|
|
217
217
|
You may wish to override this if you're using something other than
|
|
@@ -219,7 +219,7 @@ class Screen(BaseScreen, RealTerminal):
|
|
|
219
219
|
"""
|
|
220
220
|
self._term_output_file.write(data)
|
|
221
221
|
|
|
222
|
-
def flush(self):
|
|
222
|
+
def flush(self) -> None:
|
|
223
223
|
"""Flush the output buffer.
|
|
224
224
|
|
|
225
225
|
You may wish to override this if you're using something other than
|
|
@@ -323,8 +323,8 @@ class Screen(BaseScreen, RealTerminal):
|
|
|
323
323
|
return []
|
|
324
324
|
|
|
325
325
|
fd_list: list[socket.socket | typing.IO | int] = [self._resize_pipe_rd]
|
|
326
|
-
|
|
327
|
-
if input_io is not None:
|
|
326
|
+
|
|
327
|
+
if (input_io := self._term_input_io) is not None:
|
|
328
328
|
fd_list.append(input_io)
|
|
329
329
|
return fd_list
|
|
330
330
|
|
|
@@ -352,7 +352,11 @@ class Screen(BaseScreen, RealTerminal):
|
|
|
352
352
|
|
|
353
353
|
_input_timeout = None
|
|
354
354
|
|
|
355
|
-
def _make_legacy_input_wrapper(
|
|
355
|
+
def _make_legacy_input_wrapper(
|
|
356
|
+
self,
|
|
357
|
+
event_loop: EventLoop,
|
|
358
|
+
callback: Callable[[list[str], list[int]], typing.Any],
|
|
359
|
+
) -> Callable[[], None]:
|
|
356
360
|
"""
|
|
357
361
|
Support old Screen classes that still have a get_input_nonblocking and expect it to work.
|
|
358
362
|
"""
|
|
@@ -641,7 +645,7 @@ class Screen(BaseScreen, RealTerminal):
|
|
|
641
645
|
a, cs, run = row[-1]
|
|
642
646
|
if run[-1:] == b" " and self.back_color_erase and not using_standout_or_underline(a):
|
|
643
647
|
whitespace_at_end = True
|
|
644
|
-
row = row[:-1]
|
|
648
|
+
row = [*row[:-1], (a, cs, run.rstrip(b" "))] # noqa: PLW2901
|
|
645
649
|
elif y == maxrow - 1 and maxcol > 1:
|
|
646
650
|
row, back, ins = self._last_row(row) # noqa: PLW2901
|
|
647
651
|
|
|
@@ -727,7 +731,10 @@ class Screen(BaseScreen, RealTerminal):
|
|
|
727
731
|
self.screen_buf = sb
|
|
728
732
|
self._screen_buf_canvas = canvas
|
|
729
733
|
|
|
730
|
-
def _last_row(
|
|
734
|
+
def _last_row(
|
|
735
|
+
self,
|
|
736
|
+
row: list[tuple[object, Literal["0", "U"] | None, bytes]],
|
|
737
|
+
) -> tuple[
|
|
731
738
|
list[tuple[object, Literal["0", "U"] | None, bytes]],
|
|
732
739
|
int,
|
|
733
740
|
tuple[object, Literal["0", "U"] | None, bytes],
|
|
@@ -783,9 +790,9 @@ class Screen(BaseScreen, RealTerminal):
|
|
|
783
790
|
>>> s = Screen()
|
|
784
791
|
>>> s.set_terminal_properties(colors=256)
|
|
785
792
|
>>> a2e = s._attrspec_to_escape
|
|
786
|
-
>>> a2e(s.AttrSpec(
|
|
793
|
+
>>> a2e(s.AttrSpec("brown", "dark green"))
|
|
787
794
|
'\\x1b[0;33;42m'
|
|
788
|
-
>>> a2e(s.AttrSpec(
|
|
795
|
+
>>> a2e(s.AttrSpec("#fea,underline", "#d0d"))
|
|
789
796
|
'\\x1b[0;38;5;229;4;48;5;164m'
|
|
790
797
|
"""
|
|
791
798
|
if self.term == "fbterm":
|
|
@@ -870,9 +877,8 @@ class Screen(BaseScreen, RealTerminal):
|
|
|
870
877
|
|
|
871
878
|
def reset_default_terminal_palette(self) -> None:
|
|
872
879
|
"""
|
|
873
|
-
Attempt to set the terminal palette to default values as taken
|
|
874
|
-
|
|
875
|
-
set_terminal_properties() screen setting.
|
|
880
|
+
Attempt to set the terminal palette to default values as taken from xterm.
|
|
881
|
+
Uses a number of colors from the current set_terminal_properties() screen setting.
|
|
876
882
|
"""
|
|
877
883
|
if self.colors == 1:
|
|
878
884
|
return
|
|
@@ -895,9 +901,8 @@ class Screen(BaseScreen, RealTerminal):
|
|
|
895
901
|
"""
|
|
896
902
|
entries - list of (index, red, green, blue) tuples.
|
|
897
903
|
|
|
898
|
-
Attempt to set part of the terminal palette (this does not work
|
|
899
|
-
|
|
900
|
-
sequence so they should all take effect at the same time.
|
|
904
|
+
Attempt to set part of the terminal palette (this does not work on all terminals.)
|
|
905
|
+
The changes are sent as a single escape sequence so they should all take effect at the same time.
|
|
901
906
|
|
|
902
907
|
0 <= index < 256 (some terminals will only have 16 or 88 colors)
|
|
903
908
|
0 <= red, green, blue < 256
|
|
@@ -94,11 +94,10 @@ class Screen(_raw_display_base.Screen):
|
|
|
94
94
|
self._dwOriginalInMode.value | _win32.ENABLE_WINDOW_INPUT | _win32.ENABLE_VIRTUAL_TERMINAL_INPUT
|
|
95
95
|
)
|
|
96
96
|
|
|
97
|
-
ok
|
|
98
|
-
if not ok:
|
|
97
|
+
if not (ok := _win32.SetConsoleMode(handle_out, dword_out_mode)):
|
|
99
98
|
raise RuntimeError(f"ConsoleMode set failed for output. Err: {ok!r}")
|
|
100
|
-
|
|
101
|
-
if not ok:
|
|
99
|
+
|
|
100
|
+
if not (ok := _win32.SetConsoleMode(handle_in, dword_in_mode)):
|
|
102
101
|
raise RuntimeError(f"ConsoleMode set failed for input. Err: {ok!r}")
|
|
103
102
|
self._alternate_buffer = alternate_buffer
|
|
104
103
|
self._next_timeout = self.max_wait
|
|
@@ -121,11 +120,11 @@ class Screen(_raw_display_base.Screen):
|
|
|
121
120
|
|
|
122
121
|
handle_out = _win32.GetStdHandle(_win32.STD_OUTPUT_HANDLE)
|
|
123
122
|
handle_in = _win32.GetStdHandle(_win32.STD_INPUT_HANDLE)
|
|
124
|
-
|
|
125
|
-
if not ok:
|
|
123
|
+
|
|
124
|
+
if not (ok := _win32.SetConsoleMode(handle_out, self._dwOriginalOutMode)):
|
|
126
125
|
raise RuntimeError(f"ConsoleMode set failed for output. Err: {ok!r}")
|
|
127
|
-
|
|
128
|
-
if not ok:
|
|
126
|
+
|
|
127
|
+
if not (ok := _win32.SetConsoleMode(handle_in, self._dwOriginalInMode)):
|
|
129
128
|
raise RuntimeError(f"ConsoleMode set failed for input. Err: {ok!r}")
|
|
130
129
|
|
|
131
130
|
super()._stop()
|
|
@@ -188,10 +187,9 @@ class Screen(_raw_display_base.Screen):
|
|
|
188
187
|
|
|
189
188
|
with selectors.DefaultSelector() as selector:
|
|
190
189
|
selector.register(fd, selectors.EVENT_READ)
|
|
191
|
-
|
|
192
|
-
while
|
|
190
|
+
|
|
191
|
+
while selector.select(0):
|
|
193
192
|
chars.extend(self._term_input_file.recv(1024))
|
|
194
|
-
input_ready = selector.select(0)
|
|
195
193
|
|
|
196
194
|
return chars
|
|
197
195
|
|
|
@@ -204,8 +202,8 @@ class Screen(_raw_display_base.Screen):
|
|
|
204
202
|
raise RuntimeError("Unexpected terminal output file")
|
|
205
203
|
handle = _win32.GetStdHandle(_win32.STD_OUTPUT_HANDLE)
|
|
206
204
|
info = _win32.CONSOLE_SCREEN_BUFFER_INFO()
|
|
207
|
-
|
|
208
|
-
if
|
|
205
|
+
|
|
206
|
+
if _win32.GetConsoleScreenBufferInfo(handle, byref(info)):
|
|
209
207
|
# Fallback will be used in case of term size could not be determined
|
|
210
208
|
y, x = info.dwSize.Y, info.dwSize.X
|
|
211
209
|
|
|
@@ -246,11 +244,12 @@ class ReadInputThread(threading.Thread):
|
|
|
246
244
|
if not inp.Event.KeyEvent.bKeyDown:
|
|
247
245
|
continue
|
|
248
246
|
|
|
249
|
-
input_data = inp.Event.KeyEvent.uChar.
|
|
250
|
-
# On Windows atomic press/release of modifier keys produce phantom input with code NULL
|
|
247
|
+
input_data = inp.Event.KeyEvent.uChar.UnicodeChar
|
|
248
|
+
# On Windows atomic press/release of modifier keys produce phantom input with code NULL.
|
|
251
249
|
# This input cannot be decoded and should be handled as garbage.
|
|
252
|
-
|
|
253
|
-
|
|
250
|
+
input_bytes = input_data.encode("utf-8")
|
|
251
|
+
if input_bytes != b"\x00":
|
|
252
|
+
self._input.send(input_bytes)
|
|
254
253
|
|
|
255
254
|
elif inp.EventType == _win32.EventType.WINDOW_BUFFER_SIZE_EVENT:
|
|
256
255
|
self._resize()
|
urwid/display/common.py
CHANGED
|
@@ -361,19 +361,21 @@ def _color_desc_88(num: int) -> str:
|
|
|
361
361
|
|
|
362
362
|
|
|
363
363
|
def _parse_color_true(desc: str) -> int | None:
|
|
364
|
-
c
|
|
365
|
-
if c is not None:
|
|
364
|
+
if (c := _parse_color_256(desc)) is not None:
|
|
366
365
|
(r, g, b) = _COLOR_VALUES_256[c]
|
|
367
366
|
return (r << 16) + (g << 8) + b
|
|
368
367
|
|
|
369
368
|
if not desc.startswith("#"):
|
|
370
369
|
return None
|
|
370
|
+
|
|
371
371
|
if len(desc) == 7:
|
|
372
372
|
h = desc[1:]
|
|
373
373
|
return int(h, 16)
|
|
374
|
+
|
|
374
375
|
if len(desc) == 4:
|
|
375
376
|
h = f"0x{desc[1]}0{desc[2]}0{desc[3]}"
|
|
376
377
|
return int(h, 16)
|
|
378
|
+
|
|
377
379
|
return None
|
|
378
380
|
|
|
379
381
|
|
|
@@ -387,13 +389,13 @@ def _parse_color_256(desc: str) -> int | None:
|
|
|
387
389
|
|
|
388
390
|
Returns None if desc is invalid.
|
|
389
391
|
|
|
390
|
-
>>> _parse_color_256(
|
|
392
|
+
>>> _parse_color_256("h142")
|
|
391
393
|
142
|
|
392
|
-
>>> _parse_color_256(
|
|
394
|
+
>>> _parse_color_256("#f00")
|
|
393
395
|
196
|
|
394
|
-
>>> _parse_color_256(
|
|
396
|
+
>>> _parse_color_256("g100")
|
|
395
397
|
231
|
|
396
|
-
>>> _parse_color_256(
|
|
398
|
+
>>> _parse_color_256("g#80")
|
|
397
399
|
244
|
|
398
400
|
"""
|
|
399
401
|
if len(desc) > 4:
|
|
@@ -409,21 +411,21 @@ def _parse_color_256(desc: str) -> int | None:
|
|
|
409
411
|
|
|
410
412
|
if desc.startswith("#") and len(desc) == 4:
|
|
411
413
|
# color-cube coordinates
|
|
412
|
-
rgb
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
return
|
|
414
|
+
if (rgb := int(desc[1:], 16)) >= 0:
|
|
415
|
+
b, rgb = rgb % 16, rgb // 16
|
|
416
|
+
g, r = rgb % 16, rgb // 16
|
|
417
|
+
# find the closest rgb values
|
|
418
|
+
r = _CUBE_256_LOOKUP_16[r]
|
|
419
|
+
g = _CUBE_256_LOOKUP_16[g]
|
|
420
|
+
b = _CUBE_256_LOOKUP_16[b]
|
|
421
|
+
return _CUBE_START + (r * _CUBE_SIZE_256 + g) * _CUBE_SIZE_256 + b
|
|
422
|
+
|
|
423
|
+
return None
|
|
422
424
|
|
|
423
425
|
# Only remaining possibility is gray value
|
|
424
426
|
if desc.startswith("g#"):
|
|
425
427
|
# hex value 00..ff
|
|
426
|
-
gray = int(desc[2:], 16)
|
|
428
|
+
gray = int(desc[2:], 16) # noqa: FURB166
|
|
427
429
|
if gray < 0 or gray > 255:
|
|
428
430
|
return None
|
|
429
431
|
gray = _GRAY_256_LOOKUP[gray]
|
|
@@ -464,14 +466,14 @@ def _parse_color_88(desc: str) -> int | None:
|
|
|
464
466
|
|
|
465
467
|
Returns None if desc is invalid.
|
|
466
468
|
|
|
467
|
-
>>> _parse_color_88(
|
|
468
|
-
>>> _parse_color_88(
|
|
469
|
+
>>> _parse_color_88("h142")
|
|
470
|
+
>>> _parse_color_88("h42")
|
|
469
471
|
42
|
|
470
|
-
>>> _parse_color_88(
|
|
472
|
+
>>> _parse_color_88("#f00")
|
|
471
473
|
64
|
|
472
|
-
>>> _parse_color_88(
|
|
474
|
+
>>> _parse_color_88("g100")
|
|
473
475
|
79
|
|
474
|
-
>>> _parse_color_88(
|
|
476
|
+
>>> _parse_color_88("g#80")
|
|
475
477
|
83
|
|
476
478
|
"""
|
|
477
479
|
if len(desc) == 7:
|
|
@@ -489,21 +491,21 @@ def _parse_color_88(desc: str) -> int | None:
|
|
|
489
491
|
|
|
490
492
|
if desc.startswith("#") and len(desc) == 4:
|
|
491
493
|
# color-cube coordinates
|
|
492
|
-
rgb
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
return
|
|
494
|
+
if (rgb := int(desc[1:], 16)) >= 0:
|
|
495
|
+
b, rgb = rgb % 16, rgb // 16
|
|
496
|
+
g, r = rgb % 16, rgb // 16
|
|
497
|
+
# find the closest rgb values
|
|
498
|
+
r = _CUBE_88_LOOKUP_16[r]
|
|
499
|
+
g = _CUBE_88_LOOKUP_16[g]
|
|
500
|
+
b = _CUBE_88_LOOKUP_16[b]
|
|
501
|
+
return _CUBE_START + (r * _CUBE_SIZE_88 + g) * _CUBE_SIZE_88 + b
|
|
502
|
+
|
|
503
|
+
return None
|
|
502
504
|
|
|
503
505
|
# Only remaining possibility is gray value
|
|
504
506
|
if desc.startswith("g#"):
|
|
505
507
|
# hex value 00..ff
|
|
506
|
-
gray = int(desc[2:], 16)
|
|
508
|
+
gray = int(desc[2:], 16) # noqa: FURB166
|
|
507
509
|
if gray < 0 or gray > 255:
|
|
508
510
|
return None
|
|
509
511
|
gray = _GRAY_88_LOOKUP[gray]
|
|
@@ -580,13 +582,13 @@ class AttrSpec:
|
|
|
580
582
|
values are only usable with 88, 256, or 2**24 colors. With
|
|
581
583
|
1 color only the foreground settings may be used.
|
|
582
584
|
|
|
583
|
-
>>> AttrSpec(
|
|
585
|
+
>>> AttrSpec("dark red", "light gray", 16)
|
|
584
586
|
AttrSpec('dark red', 'light gray')
|
|
585
|
-
>>> AttrSpec(
|
|
587
|
+
>>> AttrSpec("yellow, underline, bold", "dark blue")
|
|
586
588
|
AttrSpec('yellow,bold,underline', 'dark blue')
|
|
587
|
-
>>> AttrSpec(
|
|
589
|
+
>>> AttrSpec("#ddb", "#004", 256) # closest colors will be found
|
|
588
590
|
AttrSpec('#dda', '#006')
|
|
589
|
-
>>> AttrSpec(
|
|
591
|
+
>>> AttrSpec("#ddb", "#004", 88)
|
|
590
592
|
AttrSpec('#ccc', '#000', colors=88)
|
|
591
593
|
"""
|
|
592
594
|
if colors not in {1, 16, 88, 256, 2**24}:
|
|
@@ -704,15 +706,6 @@ class AttrSpec:
|
|
|
704
706
|
return 16
|
|
705
707
|
return 1
|
|
706
708
|
|
|
707
|
-
def _colors(self) -> int:
|
|
708
|
-
warnings.warn(
|
|
709
|
-
f"Method `{self.__class__.__name__}._colors` is deprecated, "
|
|
710
|
-
f"please use property `{self.__class__.__name__}.colors`",
|
|
711
|
-
DeprecationWarning,
|
|
712
|
-
stacklevel=2,
|
|
713
|
-
)
|
|
714
|
-
return self.colors
|
|
715
|
-
|
|
716
709
|
def __repr__(self) -> str:
|
|
717
710
|
"""
|
|
718
711
|
Return an executable python representation of the AttrSpec
|
|
@@ -775,7 +768,7 @@ class AttrSpec:
|
|
|
775
768
|
else:
|
|
776
769
|
scolor = _parse_color_256(_true_to_256(part) or part)
|
|
777
770
|
flags |= _FG_HIGH_COLOR
|
|
778
|
-
# _parse_color_*() return None for
|
|
771
|
+
# _parse_color_*() return None for unrecognized colors
|
|
779
772
|
if scolor is None:
|
|
780
773
|
raise AttrSpecError(f"Unrecognised color specification {part!r} in foreground ({foreground!r})")
|
|
781
774
|
if color is not None:
|
|
@@ -785,15 +778,6 @@ class AttrSpec:
|
|
|
785
778
|
color = 0
|
|
786
779
|
self.__value = (self.__value & ~_FG_MASK) | color | flags
|
|
787
780
|
|
|
788
|
-
def _foreground(self) -> str:
|
|
789
|
-
warnings.warn(
|
|
790
|
-
f"Method `{self.__class__.__name__}._foreground` is deprecated, "
|
|
791
|
-
f"please use property `{self.__class__.__name__}.foreground`",
|
|
792
|
-
DeprecationWarning,
|
|
793
|
-
stacklevel=2,
|
|
794
|
-
)
|
|
795
|
-
return self.foreground
|
|
796
|
-
|
|
797
781
|
@property
|
|
798
782
|
def background(self) -> str:
|
|
799
783
|
"""Return the background color."""
|
|
@@ -827,15 +811,6 @@ class AttrSpec:
|
|
|
827
811
|
raise AttrSpecError(f"Unrecognised color specification in background ({background!r})")
|
|
828
812
|
self.__value = (self.__value & ~_BG_MASK) | (color << _BG_SHIFT) | flags
|
|
829
813
|
|
|
830
|
-
def _background(self) -> str:
|
|
831
|
-
warnings.warn(
|
|
832
|
-
f"Method `{self.__class__.__name__}._background` is deprecated, "
|
|
833
|
-
f"please use property `{self.__class__.__name__}.background`",
|
|
834
|
-
DeprecationWarning,
|
|
835
|
-
stacklevel=2,
|
|
836
|
-
)
|
|
837
|
-
return self.background
|
|
838
|
-
|
|
839
814
|
def get_rgb_values(self) -> tuple[int | None, int | None, int | None, int | None, int | None, int | None]:
|
|
840
815
|
"""
|
|
841
816
|
Return (fg_red, fg_green, fg_blue, bg_red, bg_green, bg_blue) color
|
|
@@ -845,9 +820,9 @@ class AttrSpec:
|
|
|
845
820
|
If the foreground or background is 'default' then all their compenents
|
|
846
821
|
will be returned as None.
|
|
847
822
|
|
|
848
|
-
>>> AttrSpec(
|
|
823
|
+
>>> AttrSpec("yellow", "#ccf", colors=88).get_rgb_values()
|
|
849
824
|
(255, 255, 0, 205, 205, 255)
|
|
850
|
-
>>> AttrSpec(
|
|
825
|
+
>>> AttrSpec("default", "g92").get_rgb_values()
|
|
851
826
|
(None, None, None, 238, 238, 238)
|
|
852
827
|
"""
|
|
853
828
|
if not (self.foreground_basic or self.foreground_high or self.foreground_true):
|
|
@@ -988,13 +963,9 @@ class ScreenError(Exception):
|
|
|
988
963
|
pass
|
|
989
964
|
|
|
990
965
|
|
|
991
|
-
class
|
|
992
|
-
"""Base metaclass for abstra"""
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
class BaseScreen(metaclass=BaseMeta):
|
|
966
|
+
class BaseScreen(abc.ABC, metaclass=signals.MetaSignals):
|
|
996
967
|
"""
|
|
997
|
-
Base class for Screen classes (raw_display.Screen,
|
|
968
|
+
Base class for Screen classes (raw_display.Screen, ..., etc.)
|
|
998
969
|
"""
|
|
999
970
|
|
|
1000
971
|
signals: typing.ClassVar[list[str]] = [UPDATE_PALETTE_ENTRY, INPUT_DESCRIPTORS_CHANGED]
|
|
@@ -1040,7 +1011,7 @@ class BaseScreen(metaclass=BaseMeta):
|
|
|
1040
1011
|
def _stop(self) -> None:
|
|
1041
1012
|
pass
|
|
1042
1013
|
|
|
1043
|
-
def run_wrapper(self, fn, *args, **kwargs):
|
|
1014
|
+
def run_wrapper(self, fn, *args, **kwargs) -> None:
|
|
1044
1015
|
"""Start the screen, call a function, then stop the screen. Extra
|
|
1045
1016
|
arguments are passed to `start`.
|
|
1046
1017
|
|
urwid/display/curses.py
CHANGED
|
@@ -124,7 +124,7 @@ class Screen(BaseScreen, RealTerminal):
|
|
|
124
124
|
After calling this function get_input will include mouse
|
|
125
125
|
click events along with keystrokes.
|
|
126
126
|
"""
|
|
127
|
-
enable = bool(enable)
|
|
127
|
+
enable = bool(enable)
|
|
128
128
|
if enable == self._mouse_tracking_enabled:
|
|
129
129
|
return
|
|
130
130
|
|
|
@@ -563,9 +563,7 @@ class Screen(BaseScreen, RealTerminal):
|
|
|
563
563
|
|
|
564
564
|
logger.debug(f"Drawing screen with size {size!r}")
|
|
565
565
|
|
|
566
|
-
y
|
|
567
|
-
for row in canvas.content():
|
|
568
|
-
y += 1
|
|
566
|
+
for y, row in enumerate(canvas.content()):
|
|
569
567
|
try:
|
|
570
568
|
self.s.move(y, 0)
|
|
571
569
|
except curses.error:
|
|
@@ -596,7 +594,7 @@ class Screen(BaseScreen, RealTerminal):
|
|
|
596
594
|
raise TypeError(seg)
|
|
597
595
|
self.s.addstr(seg.decode(util.get_encoding()))
|
|
598
596
|
except curses.error:
|
|
599
|
-
# it's
|
|
597
|
+
# it's OK to get out of the
|
|
600
598
|
# screen on the lower right
|
|
601
599
|
if y != rows - 1 or nr != len(row) - 1:
|
|
602
600
|
# perhaps screen size changed
|
urwid/display/escape.py
CHANGED
|
@@ -32,7 +32,7 @@ from collections.abc import MutableMapping, Sequence
|
|
|
32
32
|
from urwid import str_util
|
|
33
33
|
|
|
34
34
|
if typing.TYPE_CHECKING:
|
|
35
|
-
from collections.abc import
|
|
35
|
+
from collections.abc import Iterable
|
|
36
36
|
|
|
37
37
|
# NOTE: because of circular imports (urwid.util -> urwid.escape -> urwid.util)
|
|
38
38
|
# from urwid.util import is_mouse_event -- will not work here
|
|
@@ -85,6 +85,8 @@ input_sequences = [
|
|
|
85
85
|
("[F", "end"),
|
|
86
86
|
("[G", "5"),
|
|
87
87
|
("[H", "home"),
|
|
88
|
+
("[I", "focus in"),
|
|
89
|
+
("[O", "focus out"),
|
|
88
90
|
("[1~", "home"),
|
|
89
91
|
("[2~", "insert"),
|
|
90
92
|
("[3~", "delete"),
|
|
@@ -214,10 +216,10 @@ class KeyqueueTrie:
|
|
|
214
216
|
root[ord(s)] = result
|
|
215
217
|
|
|
216
218
|
def get(self, keys, more_available: bool):
|
|
217
|
-
result
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
return
|
|
219
|
+
if result := self.get_recurse(self.data, keys, more_available):
|
|
220
|
+
return result
|
|
221
|
+
|
|
222
|
+
return self.read_cursor_position(keys, more_available)
|
|
221
223
|
|
|
222
224
|
def get_recurse(
|
|
223
225
|
self,
|
|
@@ -225,7 +227,7 @@ class KeyqueueTrie:
|
|
|
225
227
|
MutableMapping[int, str | MutableMapping[int, str | MutableMapping[int, str]]]
|
|
226
228
|
| typing.Literal["mouse", "sgrmouse"]
|
|
227
229
|
),
|
|
228
|
-
keys:
|
|
230
|
+
keys: Sequence[int],
|
|
229
231
|
more_available: bool,
|
|
230
232
|
):
|
|
231
233
|
if not isinstance(root, MutableMapping):
|
|
@@ -245,7 +247,11 @@ class KeyqueueTrie:
|
|
|
245
247
|
return None
|
|
246
248
|
return self.get_recurse(root[keys[0]], keys[1:], more_available)
|
|
247
249
|
|
|
248
|
-
def read_mouse_info(
|
|
250
|
+
def read_mouse_info(
|
|
251
|
+
self,
|
|
252
|
+
keys: Sequence[int],
|
|
253
|
+
more_available: bool,
|
|
254
|
+
) -> tuple[tuple[str, int, int, int], Sequence[int]] | None:
|
|
249
255
|
if len(keys) < 3:
|
|
250
256
|
if more_available:
|
|
251
257
|
raise MoreInputRequired()
|
|
@@ -284,7 +290,11 @@ class KeyqueueTrie:
|
|
|
284
290
|
|
|
285
291
|
return ((f"{prefix}mouse {action}", button, x, y), keys[3:])
|
|
286
292
|
|
|
287
|
-
def read_sgrmouse_info(
|
|
293
|
+
def read_sgrmouse_info(
|
|
294
|
+
self,
|
|
295
|
+
keys: Sequence[int],
|
|
296
|
+
more_available: bool,
|
|
297
|
+
) -> tuple[tuple[str, int, int, int], Sequence[int]] | None:
|
|
288
298
|
# Helpful links:
|
|
289
299
|
# https://stackoverflow.com/questions/5966903/how-to-get-mousemove-and-mouseclick-in-bash
|
|
290
300
|
# http://invisible-island.net/xterm/ctlseqs/ctlseqs.pdf
|
|
@@ -343,7 +353,11 @@ class KeyqueueTrie:
|
|
|
343
353
|
|
|
344
354
|
return ((f"{prefix}mouse {action}", button, x, y), keys[pos_m + 1 :])
|
|
345
355
|
|
|
346
|
-
def read_cursor_position(
|
|
356
|
+
def read_cursor_position(
|
|
357
|
+
self,
|
|
358
|
+
keys: Sequence[int],
|
|
359
|
+
more_available: bool,
|
|
360
|
+
) -> tuple[tuple[str, int, int], Sequence[int]] | None:
|
|
347
361
|
"""
|
|
348
362
|
Interpret cursor position information being sent by the
|
|
349
363
|
user's terminal. Returned as ('cursor position', x, y)
|
|
@@ -538,9 +552,7 @@ def process_keyqueue(codes: Sequence[int], more_available: bool) -> tuple[list[s
|
|
|
538
552
|
if code != 27:
|
|
539
553
|
return [f"<{code:d}>"], codes[1:]
|
|
540
554
|
|
|
541
|
-
result
|
|
542
|
-
|
|
543
|
-
if result is not None:
|
|
555
|
+
if (result := input_trie.get(codes[1:], more_available)) is not None:
|
|
544
556
|
result, remaining_codes = result
|
|
545
557
|
return [result], remaining_codes
|
|
546
558
|
|
|
@@ -551,7 +563,7 @@ def process_keyqueue(codes: Sequence[int], more_available: bool) -> tuple[list[s
|
|
|
551
563
|
return ["esc", *run], remaining_codes
|
|
552
564
|
if run[0] == "esc" or run[0].find("meta ") >= 0:
|
|
553
565
|
return ["esc", *run], remaining_codes
|
|
554
|
-
return [f"meta {run[0]}"
|
|
566
|
+
return [f"meta {run[0]}", *run[1:]], remaining_codes
|
|
555
567
|
|
|
556
568
|
return ["esc"], codes[1:]
|
|
557
569
|
|
|
@@ -574,6 +586,9 @@ RESTORE_NORMAL_BUFFER = f"{ESC}[?1049l"
|
|
|
574
586
|
ENABLE_BRACKETED_PASTE_MODE = f"{ESC}[?2004h"
|
|
575
587
|
DISABLE_BRACKETED_PASTE_MODE = f"{ESC}[?2004l"
|
|
576
588
|
|
|
589
|
+
ENABLE_FOCUS_REPORTING = f"{ESC}[?1004h"
|
|
590
|
+
DISABLE_FOCUS_REPORTING = f"{ESC}[?1004l"
|
|
591
|
+
|
|
577
592
|
# RESET_SCROLL_REGION = ESC+"[;r"
|
|
578
593
|
# RESET = ESC+"c"
|
|
579
594
|
|
urwid/display/lcd.py
CHANGED
|
@@ -125,8 +125,8 @@ class CFLCDScreen(LCDScreen, abc.ABC):
|
|
|
125
125
|
|
|
126
126
|
@classmethod
|
|
127
127
|
def get_crc(cls, buf: Iterable[int]) -> bytes:
|
|
128
|
-
# This seed makes the output of this shift
|
|
129
|
-
# the table
|
|
128
|
+
# This seed makes the output of this shift-based algorithm match
|
|
129
|
+
# the table-based algorithm. The center 16 bits of the 32-bit
|
|
130
130
|
# "newCRC" are used for the CRC. The MSB of the lower byte is used
|
|
131
131
|
# to see what bit was shifted out of the center 16 bit CRC
|
|
132
132
|
# accumulator ("carry flag analog");
|
|
@@ -218,10 +218,9 @@ class CFLCDScreen(LCDScreen, abc.ABC):
|
|
|
218
218
|
raise cls.MoreDataRequired
|
|
219
219
|
|
|
220
220
|
data_end = 2 + packet_len
|
|
221
|
-
crc
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
raise cls.InvalidPacket("CRC doesn't match")
|
|
221
|
+
if (crc := cls.get_crc(data[:data_end])) != (packet_crc := data[data_end : data_end + 2]):
|
|
222
|
+
raise cls.InvalidPacket(f"CRC doesn't match ({crc=}, {packet_crc=})")
|
|
223
|
+
|
|
225
224
|
return command, data[2:data_end], data[data_end + 2 :]
|
|
226
225
|
|
|
227
226
|
|
|
@@ -230,7 +229,7 @@ class KeyRepeatSimulator:
|
|
|
230
229
|
Provide simulated repeat key events when given press and
|
|
231
230
|
release events.
|
|
232
231
|
|
|
233
|
-
If two or more keys are pressed disable repeating until all
|
|
232
|
+
If two or more keys are pressed, disable repeating until all
|
|
234
233
|
keys are released.
|
|
235
234
|
"""
|
|
236
235
|
|
|
@@ -287,7 +286,7 @@ class CF635Screen(CFLCDScreen):
|
|
|
287
286
|
20x4 character display + cursor
|
|
288
287
|
no foreground/background colors or settings supported
|
|
289
288
|
|
|
290
|
-
see CGROM for list of close
|
|
289
|
+
see CGROM for a list of close Unicode matches to characters available
|
|
291
290
|
|
|
292
291
|
6 button input
|
|
293
292
|
up, down, left, right, enter (check mark), exit (cross)
|
|
@@ -401,8 +400,7 @@ class CF635Screen(CFLCDScreen):
|
|
|
401
400
|
|
|
402
401
|
packet = self._read_packet()
|
|
403
402
|
|
|
404
|
-
next_repeat
|
|
405
|
-
if next_repeat:
|
|
403
|
+
if next_repeat := self.key_repeat.next_event():
|
|
406
404
|
timeout, key = next_repeat
|
|
407
405
|
if not timeout:
|
|
408
406
|
data_input.append(key)
|