euporie 2.6.1__py3-none-any.whl → 2.7.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.
- euporie/console/tabs/console.py +51 -43
- euporie/core/__init__.py +5 -2
- euporie/core/app.py +74 -57
- euporie/core/comm/ipywidgets.py +7 -3
- euporie/core/config.py +51 -27
- euporie/core/convert/__init__.py +2 -0
- euporie/core/convert/datum.py +82 -45
- euporie/core/convert/formats/ansi.py +1 -2
- euporie/core/convert/formats/common.py +7 -11
- euporie/core/convert/formats/ft.py +10 -7
- euporie/core/convert/formats/png.py +7 -6
- euporie/core/convert/formats/sixel.py +1 -1
- euporie/core/convert/formats/svg.py +28 -0
- euporie/core/convert/mime.py +4 -7
- euporie/core/data_structures.py +24 -22
- euporie/core/filters.py +16 -2
- euporie/core/format.py +30 -4
- euporie/core/ft/ansi.py +2 -1
- euporie/core/ft/html.py +155 -42
- euporie/core/{widgets/graphics.py → graphics.py} +225 -227
- euporie/core/io.py +8 -0
- euporie/core/key_binding/bindings/__init__.py +8 -2
- euporie/core/key_binding/bindings/basic.py +9 -14
- euporie/core/key_binding/bindings/micro.py +0 -12
- euporie/core/key_binding/bindings/mouse.py +107 -80
- euporie/core/key_binding/bindings/page_navigation.py +129 -0
- euporie/core/key_binding/key_processor.py +9 -1
- euporie/core/layout/__init__.py +1 -0
- euporie/core/layout/containers.py +1011 -0
- euporie/core/layout/decor.py +381 -0
- euporie/core/layout/print.py +130 -0
- euporie/core/layout/screen.py +75 -0
- euporie/core/{widgets/page.py → layout/scroll.py} +166 -111
- euporie/core/log.py +1 -1
- euporie/core/margins.py +11 -5
- euporie/core/path.py +43 -176
- euporie/core/renderer.py +31 -8
- euporie/core/style.py +2 -0
- euporie/core/tabs/base.py +2 -1
- euporie/core/terminal.py +19 -21
- euporie/core/widgets/cell.py +2 -4
- euporie/core/widgets/cell_outputs.py +2 -2
- euporie/core/widgets/decor.py +3 -359
- euporie/core/widgets/dialog.py +5 -5
- euporie/core/widgets/display.py +32 -12
- euporie/core/widgets/file_browser.py +3 -4
- euporie/core/widgets/forms.py +36 -14
- euporie/core/widgets/inputs.py +171 -99
- euporie/core/widgets/layout.py +80 -5
- euporie/core/widgets/menu.py +1 -3
- euporie/core/widgets/pager.py +3 -3
- euporie/core/widgets/palette.py +3 -2
- euporie/core/widgets/status_bar.py +2 -6
- euporie/core/widgets/tree.py +3 -6
- euporie/notebook/app.py +8 -8
- euporie/notebook/tabs/notebook.py +2 -2
- euporie/notebook/widgets/side_bar.py +1 -1
- euporie/preview/tabs/notebook.py +2 -2
- euporie/web/tabs/web.py +6 -1
- euporie/web/widgets/webview.py +52 -32
- {euporie-2.6.1.dist-info → euporie-2.7.0.dist-info}/METADATA +9 -11
- {euporie-2.6.1.dist-info → euporie-2.7.0.dist-info}/RECORD +67 -60
- {euporie-2.6.1.dist-info → euporie-2.7.0.dist-info}/WHEEL +1 -1
- {euporie-2.6.1.data → euporie-2.7.0.data}/data/share/applications/euporie-console.desktop +0 -0
- {euporie-2.6.1.data → euporie-2.7.0.data}/data/share/applications/euporie-notebook.desktop +0 -0
- {euporie-2.6.1.dist-info → euporie-2.7.0.dist-info}/entry_points.txt +0 -0
- {euporie-2.6.1.dist-info → euporie-2.7.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,5 +1,11 @@
|
|
1
1
|
"""Define collections of generic key-bindings which do not belong to widgets."""
|
2
2
|
|
3
|
-
from euporie.core.key_binding.bindings import
|
3
|
+
from euporie.core.key_binding.bindings import (
|
4
|
+
basic,
|
5
|
+
completion,
|
6
|
+
micro,
|
7
|
+
mouse,
|
8
|
+
page_navigation,
|
9
|
+
)
|
4
10
|
|
5
|
-
__all__ = ["basic", "completion", "micro", "mouse"]
|
11
|
+
__all__ = ["basic", "completion", "micro", "mouse", "page_navigation"]
|
@@ -32,15 +32,14 @@ log = logging.getLogger(__name__)
|
|
32
32
|
class TextEntry:
|
33
33
|
"""Basic key-bindings for text entry."""
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
}
|
42
|
-
|
43
|
-
)
|
35
|
+
# Register default bindings for micro edit mode
|
36
|
+
register_bindings(
|
37
|
+
{
|
38
|
+
"euporie.core.key_binding.bindings.basic.TextEntry": {
|
39
|
+
"type-key": "<any>",
|
40
|
+
},
|
41
|
+
}
|
42
|
+
)
|
44
43
|
|
45
44
|
|
46
45
|
def load_basic_bindings(config: Config | None = None) -> KeyBindingsBase:
|
@@ -56,11 +55,7 @@ def load_basic_bindings(config: Config | None = None) -> KeyBindingsBase:
|
|
56
55
|
# Commands
|
57
56
|
|
58
57
|
|
59
|
-
@add_cmd(
|
60
|
-
filter=buffer_has_focus,
|
61
|
-
save_before=if_no_repeat,
|
62
|
-
hidden=True,
|
63
|
-
)
|
58
|
+
@add_cmd(filter=buffer_has_focus, save_before=if_no_repeat, hidden=True)
|
64
59
|
def type_key(event: KeyPressEvent) -> None:
|
65
60
|
"""Enter a key."""
|
66
61
|
# Do not insert escape sequences
|
@@ -36,8 +36,6 @@ from prompt_toolkit.key_binding.bindings.scroll import (
|
|
36
36
|
scroll_half_page_up,
|
37
37
|
scroll_one_line_down,
|
38
38
|
scroll_one_line_up,
|
39
|
-
scroll_page_down,
|
40
|
-
scroll_page_up,
|
41
39
|
)
|
42
40
|
from prompt_toolkit.keys import Keys
|
43
41
|
from prompt_toolkit.selection import SelectionState, SelectionType
|
@@ -160,8 +158,6 @@ register_bindings(
|
|
160
158
|
"duplicate-selection": "c-d",
|
161
159
|
"paste-clipboard": "c-v",
|
162
160
|
"select-all": "c-a",
|
163
|
-
"scroll-page-up": "pageup",
|
164
|
-
"scroll-page-down": "pagedown",
|
165
161
|
"delete": "delete",
|
166
162
|
"toggle-case": "f4",
|
167
163
|
"toggle-overwrite-mode": "insert",
|
@@ -310,14 +306,6 @@ add_cmd(
|
|
310
306
|
title="Scroll up one line",
|
311
307
|
filter=buffer_has_focus,
|
312
308
|
)(scroll_one_line_up)
|
313
|
-
add_cmd(
|
314
|
-
title="Scroll one one page",
|
315
|
-
filter=buffer_has_focus,
|
316
|
-
)(scroll_page_down)
|
317
|
-
add_cmd(
|
318
|
-
title="Scroll up one page",
|
319
|
-
filter=buffer_has_focus,
|
320
|
-
)(scroll_page_up)
|
321
309
|
|
322
310
|
|
323
311
|
@add_cmd(
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
5
5
|
import logging
|
6
6
|
from typing import TYPE_CHECKING, NamedTuple
|
7
7
|
|
8
|
+
from prompt_toolkit.cache import FastDictCache
|
8
9
|
from prompt_toolkit.data_structures import Point
|
9
10
|
from prompt_toolkit.key_binding.bindings.mouse import (
|
10
11
|
MOUSE_MOVE,
|
@@ -59,99 +60,131 @@ class MouseEvent(PtkMouseEvent):
|
|
59
60
|
self.cell_position = cell_position or RelativePosition(0.5, 0.5)
|
60
61
|
|
61
62
|
|
63
|
+
def _parse_mouse_data(
|
64
|
+
data: str, sgr_pixels: bool, cell_size_xy: tuple[int, int]
|
65
|
+
) -> MouseEvent | None:
|
66
|
+
"""Convert key-press data to a mouse event."""
|
67
|
+
rx = ry = 0.5
|
68
|
+
|
69
|
+
# Parse incoming packet.
|
70
|
+
if data[2] == "M":
|
71
|
+
# Typical.
|
72
|
+
mouse_event, x, y = map(ord, data[3:])
|
73
|
+
|
74
|
+
# TODO: Is it possible to add modifiers here?
|
75
|
+
mouse_button, mouse_event_type, mouse_modifiers = typical_mouse_events[
|
76
|
+
mouse_event
|
77
|
+
]
|
78
|
+
|
79
|
+
# Handle situations where `PosixStdinReader` used surrogateescapes.
|
80
|
+
if x >= 0xDC00:
|
81
|
+
x -= 0xDC00
|
82
|
+
if y >= 0xDC00:
|
83
|
+
y -= 0xDC00
|
84
|
+
|
85
|
+
x -= 32
|
86
|
+
y -= 32
|
87
|
+
else:
|
88
|
+
# Urxvt and Xterm SGR.
|
89
|
+
# When the '<' is not present, we are not using the Xterm SGR mode,
|
90
|
+
# but Urxvt instead.
|
91
|
+
data = data[2:]
|
92
|
+
if data[:1] == "<":
|
93
|
+
sgr = True
|
94
|
+
data = data[1:]
|
95
|
+
else:
|
96
|
+
sgr = False
|
97
|
+
|
98
|
+
# Extract coordinates.
|
99
|
+
mouse_event, x, y = map(int, data[:-1].split(";"))
|
100
|
+
m = data[-1]
|
101
|
+
|
102
|
+
# Parse event type.
|
103
|
+
if sgr:
|
104
|
+
if sgr_pixels:
|
105
|
+
# Calculate cell position
|
106
|
+
cell_x, cell_y = cell_size_xy
|
107
|
+
px, py = x, y
|
108
|
+
fx, fy = px / cell_x + 1, py / cell_y + 1
|
109
|
+
x, y = int(fx), int(fy)
|
110
|
+
rx, ry = fx - x, fy - y
|
111
|
+
|
112
|
+
try:
|
113
|
+
(
|
114
|
+
mouse_button,
|
115
|
+
mouse_event_type,
|
116
|
+
mouse_modifiers,
|
117
|
+
) = xterm_sgr_mouse_events[mouse_event, m]
|
118
|
+
except KeyError:
|
119
|
+
return None
|
120
|
+
|
121
|
+
else:
|
122
|
+
# Some other terminals, like urxvt, Hyper terminal, ...
|
123
|
+
(
|
124
|
+
mouse_button,
|
125
|
+
mouse_event_type,
|
126
|
+
mouse_modifiers,
|
127
|
+
) = urxvt_mouse_events.get(
|
128
|
+
mouse_event, (UNKNOWN_BUTTON, MOUSE_MOVE, UNKNOWN_MODIFIER)
|
129
|
+
)
|
130
|
+
|
131
|
+
x -= 1
|
132
|
+
y -= 1
|
133
|
+
|
134
|
+
return MouseEvent(
|
135
|
+
position=Point(x=x, y=y),
|
136
|
+
event_type=mouse_event_type,
|
137
|
+
button=mouse_button,
|
138
|
+
modifiers=mouse_modifiers,
|
139
|
+
cell_position=RelativePosition(rx, ry),
|
140
|
+
)
|
141
|
+
|
142
|
+
|
143
|
+
_MOUSE_EVENT_CACHE: FastDictCache[
|
144
|
+
tuple[str, bool, tuple[int, int]], MouseEvent | None
|
145
|
+
] = FastDictCache(get_value=_parse_mouse_data)
|
146
|
+
|
147
|
+
|
62
148
|
def load_mouse_bindings() -> KeyBindings:
|
63
149
|
"""Additional key-bindings to deal with SGR-pixel mouse positioning."""
|
64
150
|
key_bindings = load_ptk_mouse_bindings()
|
65
151
|
|
66
|
-
@key_bindings.add(Keys.Vt100MouseEvent)
|
152
|
+
@key_bindings.add(Keys.Vt100MouseEvent, eager=True)
|
67
153
|
def _(event: KeyPressEvent) -> NotImplementedOrNone:
|
68
154
|
"""Handle incoming mouse event, include SGR-pixel mode."""
|
69
|
-
# Ensure mypy knows this would only run in a euporie
|
70
|
-
assert isinstance(event.app, BaseApp)
|
71
|
-
|
72
|
-
rx = ry = 0.5
|
155
|
+
# Ensure mypy knows this would only run in a euporie appo
|
156
|
+
assert isinstance(app := event.app, BaseApp)
|
73
157
|
|
74
|
-
|
75
|
-
|
76
|
-
# Typical.
|
77
|
-
mouse_event, x, y = map(ord, event.data[3:])
|
158
|
+
if not event.app.renderer.height_is_known:
|
159
|
+
return NotImplemented
|
78
160
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
]
|
161
|
+
mouse_event = _MOUSE_EVENT_CACHE[
|
162
|
+
event.data, app.term_info.sgr_pixel_status.value, app.term_info.cell_size_px
|
163
|
+
]
|
83
164
|
|
84
|
-
|
85
|
-
|
86
|
-
x -= 0xDC00
|
87
|
-
if y >= 0xDC00:
|
88
|
-
y -= 0xDC00
|
89
|
-
|
90
|
-
x -= 32
|
91
|
-
y -= 32
|
92
|
-
else:
|
93
|
-
# Urxvt and Xterm SGR.
|
94
|
-
# When the '<' is not present, we are not using the Xterm SGR mode,
|
95
|
-
# but Urxvt instead.
|
96
|
-
data = event.data[2:]
|
97
|
-
if data[:1] == "<":
|
98
|
-
sgr = True
|
99
|
-
data = data[1:]
|
100
|
-
else:
|
101
|
-
sgr = False
|
102
|
-
|
103
|
-
# Extract coordinates.
|
104
|
-
mouse_event, x, y = map(int, data[:-1].split(";"))
|
105
|
-
m = data[-1]
|
106
|
-
|
107
|
-
# Parse event type.
|
108
|
-
if sgr:
|
109
|
-
if event.app.term_info.sgr_pixel_status.value:
|
110
|
-
# Calculate cell position
|
111
|
-
cell_px, cell_py = event.app.term_info.cell_size_px
|
112
|
-
px, py = x, y
|
113
|
-
fx, fy = px / cell_px + 1, py / cell_py + 1
|
114
|
-
x, y = int(fx), int(fy)
|
115
|
-
rx, ry = fx - x, fy - y
|
116
|
-
|
117
|
-
try:
|
118
|
-
(
|
119
|
-
mouse_button,
|
120
|
-
mouse_event_type,
|
121
|
-
mouse_modifiers,
|
122
|
-
) = xterm_sgr_mouse_events[mouse_event, m]
|
123
|
-
except KeyError:
|
124
|
-
return NotImplemented
|
125
|
-
|
126
|
-
else:
|
127
|
-
# Some other terminals, like urxvt, Hyper terminal, ...
|
128
|
-
(
|
129
|
-
mouse_button,
|
130
|
-
mouse_event_type,
|
131
|
-
mouse_modifiers,
|
132
|
-
) = urxvt_mouse_events.get(
|
133
|
-
mouse_event, (UNKNOWN_BUTTON, MOUSE_MOVE, UNKNOWN_MODIFIER)
|
134
|
-
)
|
135
|
-
|
136
|
-
x -= 1
|
137
|
-
y -= 1
|
165
|
+
if mouse_event is None:
|
166
|
+
return NotImplemented
|
138
167
|
|
139
168
|
# Only handle mouse events when we know the window height.
|
140
|
-
if
|
169
|
+
if mouse_event.event_type is not None:
|
141
170
|
# Take region above the layout into account. The reported
|
142
171
|
# coordinates are absolute to the visible part of the terminal.
|
143
172
|
from prompt_toolkit.renderer import HeightIsUnknownError
|
144
173
|
|
174
|
+
x, y = mouse_event.position
|
175
|
+
|
145
176
|
try:
|
146
|
-
|
177
|
+
rows_above = app.renderer.rows_above_layout
|
147
178
|
except HeightIsUnknownError:
|
148
179
|
return NotImplemented
|
180
|
+
else:
|
181
|
+
y -= rows_above
|
149
182
|
|
150
183
|
# Save global mouse position
|
151
|
-
|
184
|
+
app.mouse_position = mouse_event.position
|
152
185
|
|
153
186
|
# Apply limits to mouse position if enabled
|
154
|
-
if (mouse_limits :=
|
187
|
+
if (mouse_limits := app.mouse_limits) is not None:
|
155
188
|
x = max(
|
156
189
|
mouse_limits.xpos,
|
157
190
|
min(x, mouse_limits.xpos + (mouse_limits.width - 1)),
|
@@ -161,6 +194,8 @@ def load_mouse_bindings() -> KeyBindings:
|
|
161
194
|
min(y, mouse_limits.ypos + (mouse_limits.height - 1)),
|
162
195
|
)
|
163
196
|
|
197
|
+
mouse_event.position = Point(x=x, y=y)
|
198
|
+
|
164
199
|
# Call the mouse handler from the renderer.
|
165
200
|
# Note: This can return `NotImplemented` if no mouse handler was
|
166
201
|
# found for this position, or if no repainting needs to
|
@@ -168,15 +203,7 @@ def load_mouse_bindings() -> KeyBindings:
|
|
168
203
|
# movements.
|
169
204
|
handler = event.app.renderer.mouse_handlers.mouse_handlers[y][x]
|
170
205
|
|
171
|
-
return handler(
|
172
|
-
MouseEvent(
|
173
|
-
position=Point(x=x, y=y),
|
174
|
-
event_type=mouse_event_type,
|
175
|
-
button=mouse_button,
|
176
|
-
modifiers=mouse_modifiers,
|
177
|
-
cell_position=RelativePosition(rx, ry),
|
178
|
-
)
|
179
|
-
)
|
206
|
+
return handler(mouse_event)
|
180
207
|
|
181
208
|
return NotImplemented
|
182
209
|
|
@@ -0,0 +1,129 @@
|
|
1
|
+
"""Define page navigation key-bindings for buffers."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
import logging
|
6
|
+
from typing import TYPE_CHECKING
|
7
|
+
|
8
|
+
from prompt_toolkit.application.current import get_app
|
9
|
+
from prompt_toolkit.filters import buffer_has_focus
|
10
|
+
from prompt_toolkit.key_binding.bindings.page_navigation import (
|
11
|
+
load_emacs_page_navigation_bindings,
|
12
|
+
load_vi_page_navigation_bindings,
|
13
|
+
)
|
14
|
+
from prompt_toolkit.key_binding.key_bindings import (
|
15
|
+
ConditionalKeyBindings,
|
16
|
+
merge_key_bindings,
|
17
|
+
)
|
18
|
+
|
19
|
+
from euporie.core.commands import add_cmd
|
20
|
+
from euporie.core.filters import micro_mode
|
21
|
+
from euporie.core.key_binding.registry import (
|
22
|
+
load_registered_bindings,
|
23
|
+
register_bindings,
|
24
|
+
)
|
25
|
+
|
26
|
+
if TYPE_CHECKING:
|
27
|
+
from prompt_toolkit.key_binding import KeyBindingsBase, KeyPressEvent
|
28
|
+
|
29
|
+
from euporie.core.config import Config
|
30
|
+
|
31
|
+
log = logging.getLogger(__name__)
|
32
|
+
|
33
|
+
|
34
|
+
class PageNavigation:
|
35
|
+
"""Key-bindings for page navigation."""
|
36
|
+
|
37
|
+
# Register default bindings for micro edit mode
|
38
|
+
register_bindings(
|
39
|
+
{
|
40
|
+
"euporie.core.key_binding.bindings.page_navigation.PageNavigation": {
|
41
|
+
"scroll-page-up": "pageup",
|
42
|
+
"scroll-page-down": "pagedown",
|
43
|
+
},
|
44
|
+
}
|
45
|
+
)
|
46
|
+
|
47
|
+
|
48
|
+
def load_page_navigation_bindings(config: Config | None = None) -> KeyBindingsBase:
|
49
|
+
"""Load page navigation key-bindings for text entry."""
|
50
|
+
return ConditionalKeyBindings(
|
51
|
+
merge_key_bindings(
|
52
|
+
[
|
53
|
+
load_emacs_page_navigation_bindings(),
|
54
|
+
load_vi_page_navigation_bindings(),
|
55
|
+
ConditionalKeyBindings(
|
56
|
+
load_registered_bindings(
|
57
|
+
"euporie.core.key_binding.bindings.page_navigation.PageNavigation",
|
58
|
+
config=config,
|
59
|
+
),
|
60
|
+
micro_mode,
|
61
|
+
),
|
62
|
+
]
|
63
|
+
),
|
64
|
+
buffer_has_focus,
|
65
|
+
)
|
66
|
+
|
67
|
+
|
68
|
+
# Commands
|
69
|
+
|
70
|
+
|
71
|
+
@add_cmd(filter=buffer_has_focus, hidden=True)
|
72
|
+
def scroll_page_down(event: KeyPressEvent) -> None:
|
73
|
+
"""Scroll page down (prefer the cursor at the top of the page, after scrolling)."""
|
74
|
+
w = event.app.layout.current_window
|
75
|
+
b = event.app.current_buffer
|
76
|
+
|
77
|
+
if w and w.render_info:
|
78
|
+
# Scroll down one page.
|
79
|
+
line_index = b.document.cursor_position_row
|
80
|
+
page = w.render_info.window_height
|
81
|
+
|
82
|
+
if (
|
83
|
+
(screen := get_app().renderer._last_screen)
|
84
|
+
and (wp := screen.visible_windows_to_write_positions.get(w))
|
85
|
+
and (bbox := getattr(wp, "bbox", None))
|
86
|
+
):
|
87
|
+
page -= bbox.top + bbox.bottom
|
88
|
+
|
89
|
+
line_index = max(line_index + page, w.vertical_scroll + 1)
|
90
|
+
w.vertical_scroll = line_index
|
91
|
+
|
92
|
+
b.cursor_position = b.document.translate_row_col_to_index(line_index, 0)
|
93
|
+
b.cursor_position += b.document.get_start_of_line_position(
|
94
|
+
after_whitespace=True
|
95
|
+
)
|
96
|
+
|
97
|
+
|
98
|
+
@add_cmd(filter=buffer_has_focus, hidden=True)
|
99
|
+
def scroll_page_up(event: KeyPressEvent) -> None:
|
100
|
+
"""Scroll page up (prefer the cursor at the bottom of the page, after scrolling)."""
|
101
|
+
w = event.app.layout.current_window
|
102
|
+
b = event.app.current_buffer
|
103
|
+
|
104
|
+
if w and w.render_info:
|
105
|
+
line_index = b.document.cursor_position_row
|
106
|
+
page = w.render_info.window_height
|
107
|
+
|
108
|
+
if (
|
109
|
+
(screen := get_app().renderer._last_screen)
|
110
|
+
and (wp := screen.visible_windows_to_write_positions.get(w))
|
111
|
+
and (bbox := getattr(wp, "bbox", None))
|
112
|
+
):
|
113
|
+
page -= bbox.top + bbox.bottom
|
114
|
+
|
115
|
+
# Put cursor at the first visible line. (But make sure that the cursor
|
116
|
+
# moves at least one line up.)
|
117
|
+
line_index = max(
|
118
|
+
0,
|
119
|
+
min(line_index - page, b.document.cursor_position_row - 1),
|
120
|
+
)
|
121
|
+
|
122
|
+
b.cursor_position = b.document.translate_row_col_to_index(line_index, 0)
|
123
|
+
b.cursor_position += b.document.get_start_of_line_position(
|
124
|
+
after_whitespace=True
|
125
|
+
)
|
126
|
+
|
127
|
+
# Set the scroll offset. We can safely set it to zero; the Window will
|
128
|
+
# make sure that it scrolls at least until the cursor becomes visible.
|
129
|
+
w.vertical_scroll = 0
|
@@ -67,6 +67,7 @@ class KeyProcessor(PtKeyProcessor):
|
|
67
67
|
def process_keys(self) -> None:
|
68
68
|
"""Process all the keys in the input queue."""
|
69
69
|
app = get_app()
|
70
|
+
input_queue = self.input_queue
|
70
71
|
|
71
72
|
def not_empty() -> bool:
|
72
73
|
# When the application result is set, stop processing keys. (E.g.
|
@@ -86,7 +87,14 @@ class KeyProcessor(PtKeyProcessor):
|
|
86
87
|
self.input_queue.remove(cpr)
|
87
88
|
return cpr
|
88
89
|
else:
|
89
|
-
return
|
90
|
+
return input_queue.popleft()
|
91
|
+
|
92
|
+
# Throttle repeated mouse events - limit to 10 per flush
|
93
|
+
if len(input_queue) >= 10 and not any(
|
94
|
+
input_queue[i].key != Keys.Vt100MouseEvent for i in range(10)
|
95
|
+
):
|
96
|
+
for _ in range(len(input_queue) - 10):
|
97
|
+
input_queue.popleft()
|
90
98
|
|
91
99
|
is_flush = False
|
92
100
|
|
@@ -0,0 +1 @@
|
|
1
|
+
"""Contains containers and controls relating to layout."""
|