urwid 2.6.15__py3-none-any.whl → 3.0.0__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 urwid might be problematic. Click here for more details.
- urwid/__init__.py +1 -4
- urwid/canvas.py +27 -46
- urwid/command_map.py +6 -4
- urwid/container.py +1 -1
- urwid/decoration.py +1 -1
- urwid/display/_posix_raw_display.py +16 -4
- urwid/display/_raw_display_base.py +8 -5
- urwid/display/_win32_raw_display.py +16 -17
- urwid/display/common.py +26 -55
- urwid/display/curses.py +1 -1
- urwid/display/escape.py +15 -12
- urwid/display/lcd.py +4 -6
- urwid/display/web.py +7 -12
- urwid/event_loop/asyncio_loop.py +1 -2
- urwid/event_loop/main_loop.py +13 -18
- urwid/event_loop/tornado_loop.py +4 -5
- urwid/event_loop/trio_loop.py +1 -1
- urwid/font.py +13 -18
- urwid/signals.py +2 -1
- urwid/str_util.py +15 -18
- urwid/text_layout.py +6 -7
- urwid/util.py +7 -18
- urwid/version.py +9 -4
- urwid/vterm.py +18 -45
- urwid/widget/__init__.py +0 -6
- urwid/widget/attr_wrap.py +8 -10
- urwid/widget/bar_graph.py +3 -8
- urwid/widget/big_text.py +9 -7
- urwid/widget/box_adapter.py +4 -4
- urwid/widget/columns.py +52 -83
- urwid/widget/container.py +29 -75
- urwid/widget/edit.py +8 -8
- urwid/widget/filler.py +6 -6
- urwid/widget/frame.py +28 -37
- urwid/widget/grid_flow.py +25 -110
- urwid/widget/line_box.py +13 -0
- urwid/widget/listbox.py +12 -50
- urwid/widget/monitored_list.py +6 -4
- urwid/widget/overlay.py +4 -37
- urwid/widget/padding.py +11 -48
- urwid/widget/pile.py +179 -158
- urwid/widget/popup.py +2 -2
- urwid/widget/progress_bar.py +10 -11
- urwid/widget/scrollable.py +25 -33
- urwid/widget/treetools.py +27 -48
- urwid/widget/widget.py +7 -124
- urwid/widget/widget_decoration.py +4 -33
- urwid/wimp.py +1 -1
- {urwid-2.6.15.dist-info → urwid-3.0.0.dist-info}/METADATA +18 -18
- urwid-3.0.0.dist-info/RECORD +74 -0
- {urwid-2.6.15.dist-info → urwid-3.0.0.dist-info}/WHEEL +1 -1
- urwid-2.6.15.dist-info/RECORD +0 -74
- {urwid-2.6.15.dist-info → urwid-3.0.0.dist-info/licenses}/COPYING +0 -0
- {urwid-2.6.15.dist-info → urwid-3.0.0.dist-info}/top_level.txt +0 -0
urwid/__init__.py
CHANGED
|
@@ -150,7 +150,6 @@ from .widget import (
|
|
|
150
150
|
BigText,
|
|
151
151
|
BoxAdapter,
|
|
152
152
|
BoxAdapterError,
|
|
153
|
-
BoxWidget,
|
|
154
153
|
Button,
|
|
155
154
|
CheckBox,
|
|
156
155
|
CheckBoxError,
|
|
@@ -161,8 +160,6 @@ from .widget import (
|
|
|
161
160
|
EditError,
|
|
162
161
|
Filler,
|
|
163
162
|
FillerError,
|
|
164
|
-
FixedWidget,
|
|
165
|
-
FlowWidget,
|
|
166
163
|
Frame,
|
|
167
164
|
FrameError,
|
|
168
165
|
GraphVScale,
|
|
@@ -242,7 +239,7 @@ except ImportError:
|
|
|
242
239
|
|
|
243
240
|
# OS Specific
|
|
244
241
|
if sys.platform != "win32":
|
|
245
|
-
from .vterm import TermCanvas, TermCharset, Terminal, TermModes
|
|
242
|
+
from .vterm import TermCanvas, TermCharset, Terminal, TermModes
|
|
246
243
|
|
|
247
244
|
# ZMQEventLoop cause interpreter crash on windows
|
|
248
245
|
try:
|
urwid/canvas.py
CHANGED
|
@@ -23,7 +23,6 @@ from __future__ import annotations
|
|
|
23
23
|
import contextlib
|
|
24
24
|
import dataclasses
|
|
25
25
|
import typing
|
|
26
|
-
import warnings
|
|
27
26
|
import weakref
|
|
28
27
|
from contextlib import suppress
|
|
29
28
|
|
|
@@ -40,7 +39,7 @@ from urwid.util import (
|
|
|
40
39
|
)
|
|
41
40
|
|
|
42
41
|
if typing.TYPE_CHECKING:
|
|
43
|
-
from collections.abc import Hashable, Iterable, Sequence
|
|
42
|
+
from collections.abc import Hashable, Iterable, Iterator, Sequence
|
|
44
43
|
|
|
45
44
|
from typing_extensions import Literal
|
|
46
45
|
|
|
@@ -126,7 +125,7 @@ class CanvasCache:
|
|
|
126
125
|
|
|
127
126
|
ref = weakref.ref(canvas, cls.cleanup)
|
|
128
127
|
cls._refs[ref] = (widget, wcls, size, focus)
|
|
129
|
-
cls._widgets.setdefault(widget, {})[
|
|
128
|
+
cls._widgets.setdefault(widget, {})[wcls, size, focus] = ref
|
|
130
129
|
|
|
131
130
|
@classmethod
|
|
132
131
|
def fetch(cls, widget, wcls, size, focus) -> Canvas | None:
|
|
@@ -182,7 +181,7 @@ class CanvasCache:
|
|
|
182
181
|
if not sizes:
|
|
183
182
|
return
|
|
184
183
|
with suppress(KeyError):
|
|
185
|
-
del sizes[
|
|
184
|
+
del sizes[wcls, size, focus]
|
|
186
185
|
if not sizes:
|
|
187
186
|
with contextlib.suppress(KeyError):
|
|
188
187
|
del cls._widgets[widget]
|
|
@@ -244,15 +243,6 @@ class Canvas:
|
|
|
244
243
|
def widget_info(self):
|
|
245
244
|
return self._widget_info
|
|
246
245
|
|
|
247
|
-
def _get_widget_info(self):
|
|
248
|
-
warnings.warn(
|
|
249
|
-
f"Method `{self.__class__.__name__}._get_widget_info` is deprecated, "
|
|
250
|
-
f"please use property `{self.__class__.__name__}.widget_info`",
|
|
251
|
-
DeprecationWarning,
|
|
252
|
-
stacklevel=2,
|
|
253
|
-
)
|
|
254
|
-
return self.widget_info
|
|
255
|
-
|
|
256
246
|
@property
|
|
257
247
|
def text(self) -> list[bytes]:
|
|
258
248
|
"""
|
|
@@ -266,15 +256,6 @@ class Canvas:
|
|
|
266
256
|
encoding = get_encoding()
|
|
267
257
|
return tuple(line.decode(encoding) for line in self.text)
|
|
268
258
|
|
|
269
|
-
def _text_content(self):
|
|
270
|
-
warnings.warn(
|
|
271
|
-
f"Method `{self.__class__.__name__}._text_content` is deprecated, "
|
|
272
|
-
f"please use property `{self.__class__.__name__}.text`",
|
|
273
|
-
DeprecationWarning,
|
|
274
|
-
stacklevel=2,
|
|
275
|
-
)
|
|
276
|
-
return self.text
|
|
277
|
-
|
|
278
259
|
def content(
|
|
279
260
|
self,
|
|
280
261
|
trim_left: int = 0,
|
|
@@ -282,7 +263,7 @@ class Canvas:
|
|
|
282
263
|
cols: int | None = None,
|
|
283
264
|
rows: int | None = None,
|
|
284
265
|
attr=None,
|
|
285
|
-
) ->
|
|
266
|
+
) -> Iterator[list[tuple[object, Literal["0", "U"] | None, bytes]]]:
|
|
286
267
|
raise NotImplementedError()
|
|
287
268
|
|
|
288
269
|
def cols(self) -> int:
|
|
@@ -295,10 +276,10 @@ class Canvas:
|
|
|
295
276
|
raise NotImplementedError()
|
|
296
277
|
|
|
297
278
|
def get_cursor(self) -> tuple[int, int] | None:
|
|
298
|
-
c
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
return
|
|
279
|
+
if c := self.coords.get("cursor", None):
|
|
280
|
+
return c[:2] # trim off data part
|
|
281
|
+
|
|
282
|
+
return None
|
|
302
283
|
|
|
303
284
|
def set_cursor(self, c: tuple[int, int] | None) -> None:
|
|
304
285
|
if self.widget_info and self.cacheable:
|
|
@@ -312,10 +293,10 @@ class Canvas:
|
|
|
312
293
|
cursor = property(get_cursor, set_cursor)
|
|
313
294
|
|
|
314
295
|
def get_pop_up(self) -> tuple[int, int, tuple[Widget, int, int]] | None:
|
|
315
|
-
c
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
return
|
|
296
|
+
if c := self.coords.get("pop up", None):
|
|
297
|
+
return c
|
|
298
|
+
|
|
299
|
+
return None
|
|
319
300
|
|
|
320
301
|
def set_pop_up(self, w: Widget, left: int, top: int, overlay_width: int, overlay_height: int) -> None:
|
|
321
302
|
"""
|
|
@@ -376,7 +357,7 @@ class TextCanvas(Canvas):
|
|
|
376
357
|
|
|
377
358
|
def __init__(
|
|
378
359
|
self,
|
|
379
|
-
text:
|
|
360
|
+
text: list[bytes] | None = None,
|
|
380
361
|
attr: list[list[tuple[Hashable | None, int]]] | None = None,
|
|
381
362
|
cs: list[list[tuple[Literal["0", "U"] | None, int]]] | None = None,
|
|
382
363
|
cursor: tuple[int, int] | None = None,
|
|
@@ -477,7 +458,7 @@ class TextCanvas(Canvas):
|
|
|
477
458
|
cols: int | None = 0,
|
|
478
459
|
rows: int | None = 0,
|
|
479
460
|
attr=None,
|
|
480
|
-
) ->
|
|
461
|
+
) -> Iterator[tuple[object, Literal["0", "U"] | None, bytes]]:
|
|
481
462
|
"""
|
|
482
463
|
Return the canvas content as a list of rows where each row
|
|
483
464
|
is a list of (attr, cs, text) tuples.
|
|
@@ -551,7 +532,7 @@ class BlankCanvas(Canvas):
|
|
|
551
532
|
cols: int | None = 0,
|
|
552
533
|
rows: int | None = 0,
|
|
553
534
|
attr=None,
|
|
554
|
-
) ->
|
|
535
|
+
) -> Iterator[list[tuple[object, Literal["0", "U"] | None, bytes]]]:
|
|
555
536
|
"""
|
|
556
537
|
return (cols, rows) of spaces with default attributes.
|
|
557
538
|
"""
|
|
@@ -603,7 +584,7 @@ class SolidCanvas(Canvas):
|
|
|
603
584
|
cols: int | None = None,
|
|
604
585
|
rows: int | None = None,
|
|
605
586
|
attr=None,
|
|
606
|
-
) ->
|
|
587
|
+
) -> Iterator[list[tuple[object, Literal["0", "U"] | None, bytes]]]:
|
|
607
588
|
if cols is None:
|
|
608
589
|
cols = self.size[0]
|
|
609
590
|
if rows is None:
|
|
@@ -704,7 +685,7 @@ class CompositeCanvas(Canvas):
|
|
|
704
685
|
cols: int | None = None,
|
|
705
686
|
rows: int | None = None,
|
|
706
687
|
attr=None,
|
|
707
|
-
) ->
|
|
688
|
+
) -> Iterator[list[tuple[object, Literal["0", "U"] | None, bytes]]]:
|
|
708
689
|
"""
|
|
709
690
|
Return the canvas content as a list of rows where each row
|
|
710
691
|
is a list of (attr, cs, text) tuples.
|
|
@@ -808,7 +789,7 @@ class CompositeCanvas(Canvas):
|
|
|
808
789
|
|
|
809
790
|
if right > 0:
|
|
810
791
|
new_top_cviews.append((0, 0, right, rows, None, blank_canvas))
|
|
811
|
-
shards = [(top_rows, new_top_cviews)
|
|
792
|
+
shards = [(top_rows, new_top_cviews), *shards[1:]]
|
|
812
793
|
|
|
813
794
|
self.coords = self.translate_coords(left, 0)
|
|
814
795
|
self.shards = shards
|
|
@@ -833,7 +814,7 @@ class CompositeCanvas(Canvas):
|
|
|
833
814
|
|
|
834
815
|
if bottom > 0:
|
|
835
816
|
if orig_shards is self.shards:
|
|
836
|
-
self.shards = self.shards
|
|
817
|
+
self.shards = self.shards.copy()
|
|
837
818
|
self.shards.append((bottom, [(0, 0, cols, bottom, None, blank_canvas)]))
|
|
838
819
|
|
|
839
820
|
def overlay(self, other: CompositeCanvas, left: int, top: int) -> None:
|
|
@@ -902,11 +883,11 @@ class CompositeCanvas(Canvas):
|
|
|
902
883
|
for cv in original_cviews:
|
|
903
884
|
# cv[4] == attr_map
|
|
904
885
|
if cv[4] is None:
|
|
905
|
-
new_cviews.append(cv[:4]
|
|
886
|
+
new_cviews.append((*cv[:4], mapping, *cv[5:]))
|
|
906
887
|
else:
|
|
907
888
|
combined = mapping.copy()
|
|
908
889
|
combined.update([(k, mapping.get(v, v)) for k, v in cv[4].items()])
|
|
909
|
-
new_cviews.append(cv[:4]
|
|
890
|
+
new_cviews.append((*cv[:4], combined, *cv[5:]))
|
|
910
891
|
shards.append((num_rows, new_cviews))
|
|
911
892
|
self.shards = shards
|
|
912
893
|
|
|
@@ -1002,7 +983,7 @@ def shard_cviews_delta(cviews, other_cviews):
|
|
|
1002
983
|
continue
|
|
1003
984
|
# top-left-aligned cviews, compare them
|
|
1004
985
|
if cv[5] is other_cv[5] and cv[:5] == other_cv[:5]:
|
|
1005
|
-
yield cv[:5]
|
|
986
|
+
yield (*cv[:5], None, *cv[6:])
|
|
1006
987
|
else:
|
|
1007
988
|
yield cv
|
|
1008
989
|
other_cols += other_cv[2]
|
|
@@ -1185,7 +1166,7 @@ def shards_join(shard_lists):
|
|
|
1185
1166
|
|
|
1186
1167
|
|
|
1187
1168
|
def cview_trim_rows(cv, rows: int):
|
|
1188
|
-
return cv[:3]
|
|
1169
|
+
return (*cv[:3], rows, *cv[4:])
|
|
1189
1170
|
|
|
1190
1171
|
|
|
1191
1172
|
def cview_trim_top(cv, trim: int):
|
|
@@ -1193,11 +1174,11 @@ def cview_trim_top(cv, trim: int):
|
|
|
1193
1174
|
|
|
1194
1175
|
|
|
1195
1176
|
def cview_trim_left(cv, trim: int):
|
|
1196
|
-
return (cv[0] + trim, cv[1], cv[2] - trim
|
|
1177
|
+
return (cv[0] + trim, cv[1], cv[2] - trim, *cv[3:])
|
|
1197
1178
|
|
|
1198
1179
|
|
|
1199
1180
|
def cview_trim_cols(cv, cols: int):
|
|
1200
|
-
return cv[:2]
|
|
1181
|
+
return (*cv[:2], cols, *cv[3:])
|
|
1201
1182
|
|
|
1202
1183
|
|
|
1203
1184
|
def CanvasCombine(canvas_info: Iterable[tuple[Canvas, typing.Any, bool]]) -> CompositeCanvas:
|
|
@@ -1229,7 +1210,7 @@ def CanvasCombine(canvas_info: Iterable[tuple[Canvas, typing.Any, bool]]) -> Com
|
|
|
1229
1210
|
row += canv.rows()
|
|
1230
1211
|
|
|
1231
1212
|
if focus_index:
|
|
1232
|
-
children = [children[focus_index]
|
|
1213
|
+
children = [children[focus_index], *children[:focus_index], *children[focus_index + 1 :]]
|
|
1233
1214
|
|
|
1234
1215
|
combined_canvas.shards = shards
|
|
1235
1216
|
combined_canvas.children = children
|
|
@@ -1295,7 +1276,7 @@ def CanvasJoin(canvas_info: Iterable[tuple[Canvas, typing.Any, bool, int]]) -> C
|
|
|
1295
1276
|
col += composite_canvas.cols()
|
|
1296
1277
|
|
|
1297
1278
|
if focus_item:
|
|
1298
|
-
children = [children[focus_item]
|
|
1279
|
+
children = [children[focus_item], *children[:focus_item], *children[focus_item + 1 :]]
|
|
1299
1280
|
|
|
1300
1281
|
joined_canvas.shards = shards_join(shard_lists)
|
|
1301
1282
|
joined_canvas.children = children
|
urwid/command_map.py
CHANGED
|
@@ -21,9 +21,11 @@ from __future__ import annotations
|
|
|
21
21
|
|
|
22
22
|
import enum
|
|
23
23
|
import typing
|
|
24
|
-
from
|
|
24
|
+
from collections.abc import MutableMapping
|
|
25
25
|
|
|
26
26
|
if typing.TYPE_CHECKING:
|
|
27
|
+
from collections.abc import Iterator
|
|
28
|
+
|
|
27
29
|
from typing_extensions import Self
|
|
28
30
|
|
|
29
31
|
|
|
@@ -55,7 +57,7 @@ CURSOR_MAX_RIGHT = Command.MAX_RIGHT
|
|
|
55
57
|
ACTIVATE = Command.ACTIVATE
|
|
56
58
|
|
|
57
59
|
|
|
58
|
-
class CommandMap(
|
|
60
|
+
class CommandMap(MutableMapping[str, typing.Union[str, Command, None]]):
|
|
59
61
|
"""
|
|
60
62
|
dict-like object for looking up commands from keystrokes
|
|
61
63
|
|
|
@@ -105,10 +107,10 @@ class CommandMap(typing.Mapping[str, typing.Union[str, Command, None]]):
|
|
|
105
107
|
}
|
|
106
108
|
|
|
107
109
|
def __init__(self) -> None:
|
|
108
|
-
self._command =
|
|
110
|
+
self._command = self._command_defaults.copy()
|
|
109
111
|
|
|
110
112
|
def restore_defaults(self) -> None:
|
|
111
|
-
self._command =
|
|
113
|
+
self._command = self._command_defaults.copy()
|
|
112
114
|
|
|
113
115
|
def __getitem__(self, key: str) -> str | Command | None:
|
|
114
116
|
return self._command.get(key, None)
|
urwid/container.py
CHANGED
|
@@ -53,7 +53,7 @@ __all__ = (
|
|
|
53
53
|
warnings.warn(
|
|
54
54
|
f"{__name__!r} is not expected to be imported directly. "
|
|
55
55
|
'Please use public access from "urwid" package. '
|
|
56
|
-
f"Module {__name__!r} is deprecated and will be removed in the
|
|
56
|
+
f"Module {__name__!r} is deprecated and will be removed in the version 4.0.",
|
|
57
57
|
DeprecationWarning,
|
|
58
58
|
stacklevel=3,
|
|
59
59
|
)
|
urwid/decoration.py
CHANGED
|
@@ -59,7 +59,7 @@ __all__ = (
|
|
|
59
59
|
warnings.warn(
|
|
60
60
|
f"{__name__!r} is not expected to be imported directly. "
|
|
61
61
|
'Please use public access from "urwid" package. '
|
|
62
|
-
f"Module {__name__!r} is deprecated and will be removed in the
|
|
62
|
+
f"Module {__name__!r} is deprecated and will be removed in the version 4.0.",
|
|
63
63
|
DeprecationWarning,
|
|
64
64
|
stacklevel=3,
|
|
65
65
|
)
|
|
@@ -56,6 +56,7 @@ class Screen(_raw_display_base.Screen):
|
|
|
56
56
|
input: typing.TextIO = sys.stdin, # noqa: A002 # pylint: disable=redefined-builtin
|
|
57
57
|
output: typing.TextIO = sys.stdout,
|
|
58
58
|
bracketed_paste_mode=False,
|
|
59
|
+
focus_reporting=False,
|
|
59
60
|
) -> None:
|
|
60
61
|
"""Initialize a screen that directly prints escape codes to an output
|
|
61
62
|
terminal.
|
|
@@ -63,11 +64,15 @@ class Screen(_raw_display_base.Screen):
|
|
|
63
64
|
bracketed_paste_mode -- enable bracketed paste mode in the host terminal.
|
|
64
65
|
If the host terminal supports it, the application will receive `begin paste`
|
|
65
66
|
and `end paste` keystrokes when the user pastes text.
|
|
67
|
+
focus_reporting -- enable focus reporting in the host terminal.
|
|
68
|
+
If the host terminal supports it, the application will receive `focus in`
|
|
69
|
+
and `focus out` keystrokes when the application gains and loses focus.
|
|
66
70
|
"""
|
|
67
71
|
super().__init__(input, output)
|
|
68
72
|
self.gpm_mev: Popen | None = None
|
|
69
73
|
self.gpm_event_pending: bool = False
|
|
70
74
|
self.bracketed_paste_mode = bracketed_paste_mode
|
|
75
|
+
self.focus_reporting = focus_reporting
|
|
71
76
|
|
|
72
77
|
# These store the previous signal handlers after setting ours
|
|
73
78
|
self._prev_sigcont_handler = None
|
|
@@ -79,7 +84,8 @@ class Screen(_raw_display_base.Screen):
|
|
|
79
84
|
f"<{self.__class__.__name__}("
|
|
80
85
|
f"input={self._term_input_file}, "
|
|
81
86
|
f"output={self._term_output_file}, "
|
|
82
|
-
f"bracketed_paste_mode={self.bracketed_paste_mode}
|
|
87
|
+
f"bracketed_paste_mode={self.bracketed_paste_mode}, "
|
|
88
|
+
f"focus_reporting={self.focus_reporting})>"
|
|
83
89
|
)
|
|
84
90
|
|
|
85
91
|
def _sigwinch_handler(self, signum: int = 28, frame: FrameType | None = None) -> None:
|
|
@@ -180,6 +186,9 @@ class Screen(_raw_display_base.Screen):
|
|
|
180
186
|
if self.bracketed_paste_mode:
|
|
181
187
|
self.write(escape.ENABLE_BRACKETED_PASTE_MODE)
|
|
182
188
|
|
|
189
|
+
if self.focus_reporting:
|
|
190
|
+
self.write(escape.ENABLE_FOCUS_REPORTING)
|
|
191
|
+
|
|
183
192
|
fd = self._input_fileno()
|
|
184
193
|
if fd is not None and os.isatty(fd):
|
|
185
194
|
self._old_termios_settings = termios.tcgetattr(fd)
|
|
@@ -207,15 +216,18 @@ class Screen(_raw_display_base.Screen):
|
|
|
207
216
|
if self.bracketed_paste_mode:
|
|
208
217
|
self.write(escape.DISABLE_BRACKETED_PASTE_MODE)
|
|
209
218
|
|
|
219
|
+
if self.focus_reporting:
|
|
220
|
+
self.write(escape.DISABLE_FOCUS_REPORTING)
|
|
221
|
+
|
|
210
222
|
signals.emit_signal(self, INPUT_DESCRIPTORS_CHANGED)
|
|
211
223
|
|
|
212
224
|
self.signal_restore()
|
|
213
225
|
|
|
226
|
+
self._stop_mouse_restore_buffer()
|
|
227
|
+
|
|
214
228
|
fd = self._input_fileno()
|
|
215
229
|
if fd is not None and os.isatty(fd):
|
|
216
|
-
termios.tcsetattr(fd, termios.
|
|
217
|
-
|
|
218
|
-
self._stop_mouse_restore_buffer()
|
|
230
|
+
termios.tcsetattr(fd, termios.TCSAFLUSH, self._old_termios_settings)
|
|
219
231
|
|
|
220
232
|
if self._old_signal_keys:
|
|
221
233
|
self.tty_signal_keys(*self._old_signal_keys, fd)
|
|
@@ -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
|
|
|
@@ -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
|
|
|
@@ -641,7 +641,7 @@ class Screen(BaseScreen, RealTerminal):
|
|
|
641
641
|
a, cs, run = row[-1]
|
|
642
642
|
if run[-1:] == b" " and self.back_color_erase and not using_standout_or_underline(a):
|
|
643
643
|
whitespace_at_end = True
|
|
644
|
-
row = row[:-1]
|
|
644
|
+
row = [*row[:-1], (a, cs, run.rstrip(b" "))] # noqa: PLW2901
|
|
645
645
|
elif y == maxrow - 1 and maxcol > 1:
|
|
646
646
|
row, back, ins = self._last_row(row) # noqa: PLW2901
|
|
647
647
|
|
|
@@ -727,7 +727,10 @@ class Screen(BaseScreen, RealTerminal):
|
|
|
727
727
|
self.screen_buf = sb
|
|
728
728
|
self._screen_buf_canvas = canvas
|
|
729
729
|
|
|
730
|
-
def _last_row(
|
|
730
|
+
def _last_row(
|
|
731
|
+
self,
|
|
732
|
+
row: list[tuple[object, Literal["0", "U"] | None, bytes]],
|
|
733
|
+
) -> tuple[
|
|
731
734
|
list[tuple[object, Literal["0", "U"] | None, bytes]],
|
|
732
735
|
int,
|
|
733
736
|
tuple[object, Literal["0", "U"] | None, bytes],
|
|
@@ -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
|
|
|
@@ -409,16 +411,16 @@ 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#"):
|
|
@@ -489,16 +491,16 @@ 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#"):
|
|
@@ -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
|
|
@@ -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
|
|
@@ -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]
|
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
|
|