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
euporie/core/path.py
CHANGED
@@ -2,14 +2,11 @@
|
|
2
2
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
|
-
import base64
|
6
|
-
import binascii
|
7
5
|
import contextlib
|
8
|
-
import io
|
9
6
|
import logging
|
10
7
|
from pathlib import Path
|
11
|
-
from typing import TYPE_CHECKING
|
12
|
-
from urllib.parse import
|
8
|
+
from typing import TYPE_CHECKING
|
9
|
+
from urllib.parse import urljoin, urlunsplit
|
13
10
|
|
14
11
|
import upath
|
15
12
|
from aiohttp.client_reqrep import ClientResponse
|
@@ -19,39 +16,20 @@ from fsspec.registry import register_implementation as fs_register_implementatio
|
|
19
16
|
from upath import UPath
|
20
17
|
from upath.implementations.http import HTTPPath as _HTTPPath
|
21
18
|
from upath.implementations.http import _HTTPAccessor
|
22
|
-
from upath.registry import
|
19
|
+
from upath.registry import register_implementation
|
23
20
|
|
24
21
|
if TYPE_CHECKING:
|
25
|
-
from io import BufferedRandom, BufferedReader, BufferedWriter, FileIO, TextIOWrapper
|
26
22
|
from os import PathLike
|
27
|
-
from typing import
|
23
|
+
from typing import Any
|
28
24
|
from urllib.parse import SplitResult
|
29
25
|
|
30
|
-
from _typeshed import (
|
31
|
-
OpenBinaryMode,
|
32
|
-
OpenBinaryModeReading,
|
33
|
-
OpenBinaryModeUpdating,
|
34
|
-
OpenBinaryModeWriting,
|
35
|
-
OpenTextMode,
|
36
|
-
)
|
37
26
|
from upath.core import PT
|
38
27
|
|
39
28
|
|
40
29
|
log = logging.getLogger(__name__)
|
41
30
|
|
42
31
|
|
43
|
-
|
44
|
-
"""Parse and resolve a path."""
|
45
|
-
if not isinstance(path, Path):
|
46
|
-
path = UPath(path)
|
47
|
-
with contextlib.suppress(NotImplementedError):
|
48
|
-
path = path.expanduser()
|
49
|
-
if resolve:
|
50
|
-
try:
|
51
|
-
path = path.resolve()
|
52
|
-
except (AttributeError, NotImplementedError, Exception):
|
53
|
-
log.info("Path %s not resolvable", path)
|
54
|
-
return path
|
32
|
+
# Monkey-patch `aiohttp` to not raise exceptions on non-200 responses
|
55
33
|
|
56
34
|
|
57
35
|
def _raise_for_status(self: ClientResponse) -> None:
|
@@ -61,148 +39,21 @@ def _raise_for_status(self: ClientResponse) -> None:
|
|
61
39
|
setattr(ClientResponse, "raise_for_status", _raise_for_status) # noqa B010
|
62
40
|
|
63
41
|
|
64
|
-
|
65
|
-
|
42
|
+
# Define and register non-raising HTTP filesystem implementation for fsspec
|
43
|
+
|
44
|
+
|
45
|
+
class HTTPFileSystem(FsHTTPFileSystem):
|
46
|
+
"""A :py:class:`HTTPFileSystem` which does not raise exceptions on 404 errors."""
|
47
|
+
|
48
|
+
def _raise_not_found_for_status(self, response: ClientResponse, url: str) -> None:
|
49
|
+
"""Do not raise an exception for 404 errors."""
|
50
|
+
|
51
|
+
|
52
|
+
fs_register_implementation("http", HTTPFileSystem, clobber=True)
|
53
|
+
fs_register_implementation("https", HTTPFileSystem, clobber=True)
|
54
|
+
|
66
55
|
|
67
|
-
|
68
|
-
def open(
|
69
|
-
self,
|
70
|
-
mode: OpenTextMode = "r",
|
71
|
-
buffering: int = -1,
|
72
|
-
encoding: str | None = None,
|
73
|
-
errors: str | None = None,
|
74
|
-
newline: str | None = None,
|
75
|
-
) -> TextIOWrapper:
|
76
|
-
...
|
77
|
-
|
78
|
-
# Unbuffered binary mode: returns a FileIO
|
79
|
-
@overload
|
80
|
-
def open(
|
81
|
-
self,
|
82
|
-
mode: OpenBinaryMode,
|
83
|
-
buffering: Literal[0],
|
84
|
-
encoding: None = None,
|
85
|
-
errors: None = None,
|
86
|
-
newline: None = None,
|
87
|
-
) -> FileIO:
|
88
|
-
...
|
89
|
-
|
90
|
-
# Buffering is on: return BufferedRandom, BufferedReader, or BufferedWriter
|
91
|
-
@overload
|
92
|
-
def open(
|
93
|
-
self,
|
94
|
-
mode: OpenBinaryModeUpdating,
|
95
|
-
buffering: Literal[-1, 1] = -1,
|
96
|
-
encoding: None = None,
|
97
|
-
errors: None = None,
|
98
|
-
newline: None = None,
|
99
|
-
) -> BufferedRandom:
|
100
|
-
...
|
101
|
-
|
102
|
-
@overload
|
103
|
-
def open(
|
104
|
-
self,
|
105
|
-
mode: OpenBinaryModeWriting,
|
106
|
-
buffering: Literal[-1, 1] = -1,
|
107
|
-
encoding: None = None,
|
108
|
-
errors: None = None,
|
109
|
-
newline: None = None,
|
110
|
-
) -> BufferedWriter:
|
111
|
-
...
|
112
|
-
|
113
|
-
@overload
|
114
|
-
def open(
|
115
|
-
self,
|
116
|
-
mode: OpenBinaryModeReading,
|
117
|
-
buffering: Literal[-1, 1] = -1,
|
118
|
-
encoding: None = None,
|
119
|
-
errors: None = None,
|
120
|
-
newline: None = None,
|
121
|
-
) -> BufferedReader:
|
122
|
-
...
|
123
|
-
|
124
|
-
# Buffering cannot be determined: fall back to BinaryIO
|
125
|
-
@overload
|
126
|
-
def open(
|
127
|
-
self,
|
128
|
-
mode: OpenBinaryMode,
|
129
|
-
buffering: int = -1,
|
130
|
-
encoding: None = None,
|
131
|
-
errors: None = None,
|
132
|
-
newline: None = None,
|
133
|
-
) -> BinaryIO:
|
134
|
-
...
|
135
|
-
|
136
|
-
# Fallback if mode is not specified
|
137
|
-
@overload
|
138
|
-
def open(
|
139
|
-
self,
|
140
|
-
mode: str,
|
141
|
-
buffering: int = -1,
|
142
|
-
encoding: str | None = None,
|
143
|
-
errors: str | None = None,
|
144
|
-
newline: str | None = None,
|
145
|
-
) -> IO[Any]:
|
146
|
-
...
|
147
|
-
|
148
|
-
def open(
|
149
|
-
self,
|
150
|
-
mode: OpenTextMode
|
151
|
-
| OpenBinaryMode
|
152
|
-
| OpenBinaryModeReading
|
153
|
-
| OpenBinaryModeWriting
|
154
|
-
| OpenBinaryModeUpdating
|
155
|
-
| str = "r",
|
156
|
-
buffering: Literal[-1, 0, 1] | int = -1,
|
157
|
-
encoding: str | None = None,
|
158
|
-
errors: str | None = None,
|
159
|
-
newline: str | None = None,
|
160
|
-
) -> IO[Any]:
|
161
|
-
"""Return an io object for the data in the URI."""
|
162
|
-
assert self._url is not None
|
163
|
-
data_format, _, encoded_data = self._url.path.partition(",")
|
164
|
-
_mime, *params = data_format.split(";")
|
165
|
-
|
166
|
-
data_bytes = None
|
167
|
-
data_str = None
|
168
|
-
|
169
|
-
if "base64" in params:
|
170
|
-
try:
|
171
|
-
data_bytes = base64.b64decode(encoded_data)
|
172
|
-
except binascii.Error:
|
173
|
-
log.warning("Failed to decode base64 encoded data")
|
174
|
-
data_bytes = b""
|
175
|
-
else:
|
176
|
-
data_str = unquote(encoded_data)
|
177
|
-
|
178
|
-
if "b" in mode:
|
179
|
-
if data_bytes is None:
|
180
|
-
assert data_str is not None
|
181
|
-
data_bytes = data_str.encode()
|
182
|
-
return io.BytesIO(data_bytes)
|
183
|
-
else:
|
184
|
-
if data_str is None:
|
185
|
-
assert data_bytes is not None
|
186
|
-
# decode_kwargs: dict[str, str] = {}
|
187
|
-
# if encoding is not None: #:= kwargs.get("encoding"):
|
188
|
-
# decode_kwargs["encoding"] = str(encoding)
|
189
|
-
data_str = data_bytes.decode() # **decode_kwargs)
|
190
|
-
return io.StringIO(data_str)
|
191
|
-
|
192
|
-
def exists(self, **kwargs: Any) -> bool:
|
193
|
-
"""Affirm that data URIs always exist."""
|
194
|
-
return True
|
195
|
-
|
196
|
-
@property
|
197
|
-
def _mime(self) -> str:
|
198
|
-
"""Return the media type of the data URI."""
|
199
|
-
assert self._url is not None
|
200
|
-
data_format, _, _encoded_data = self._url.path.partition(",")
|
201
|
-
mime, *params = data_format.split(";")
|
202
|
-
return mime
|
203
|
-
|
204
|
-
|
205
|
-
_registry.known_implementations["data"] = "euporie.core.path.DataPath"
|
56
|
+
# Define custom universal_pathlib path implementations
|
206
57
|
|
207
58
|
|
208
59
|
class CachingHTTPAccessor(_HTTPAccessor):
|
@@ -256,16 +107,32 @@ class HTTPPath(_HTTPPath):
|
|
256
107
|
return self._hash
|
257
108
|
|
258
109
|
|
259
|
-
|
260
|
-
|
110
|
+
class _DataAccessor(upath.core._FSSpecAccessor):
|
111
|
+
def _format_path(self, path: upath.core.UPath) -> str:
|
112
|
+
"""Return the full URI as a string."""
|
113
|
+
return str(path)
|
261
114
|
|
262
115
|
|
263
|
-
class
|
264
|
-
"""A :py:class:`
|
116
|
+
class DataPath(upath.core.UPath):
|
117
|
+
"""A :py:class:`pathlib` compatible class for reading data URIs."""
|
265
118
|
|
266
|
-
|
267
|
-
"""Do not raise an exception for 404 errors."""
|
119
|
+
_default_accessor = _DataAccessor
|
268
120
|
|
269
121
|
|
270
|
-
|
271
|
-
|
122
|
+
register_implementation("data", DataPath, clobber=True)
|
123
|
+
register_implementation("http", HTTPPath, clobber=True)
|
124
|
+
register_implementation("https", HTTPPath, clobber=True)
|
125
|
+
|
126
|
+
|
127
|
+
def parse_path(path: str | PathLike, resolve: bool = True) -> Path:
|
128
|
+
"""Parse and resolve a path."""
|
129
|
+
if not isinstance(path, Path):
|
130
|
+
path = UPath(path)
|
131
|
+
with contextlib.suppress(NotImplementedError):
|
132
|
+
path = path.expanduser()
|
133
|
+
if resolve:
|
134
|
+
try:
|
135
|
+
path = path.resolve()
|
136
|
+
except (AttributeError, NotImplementedError, Exception):
|
137
|
+
log.info("Path %s not resolvable", path)
|
138
|
+
return path
|
euporie/core/renderer.py
CHANGED
@@ -8,11 +8,11 @@ from typing import TYPE_CHECKING
|
|
8
8
|
from prompt_toolkit.data_structures import Point, Size
|
9
9
|
from prompt_toolkit.filters import to_filter
|
10
10
|
from prompt_toolkit.layout.mouse_handlers import MouseHandlers
|
11
|
-
from prompt_toolkit.layout.screen import Char, Screen, WritePosition
|
12
11
|
from prompt_toolkit.renderer import Renderer as PtkRenderer
|
13
12
|
from prompt_toolkit.renderer import _StyleStringHasStyleCache, _StyleStringToAttrsCache
|
14
13
|
|
15
14
|
from euporie.core.io import Vt100_Output
|
15
|
+
from euporie.core.layout.screen import BoundedWritePosition, Screen
|
16
16
|
|
17
17
|
if TYPE_CHECKING:
|
18
18
|
from typing import Any, Callable
|
@@ -20,6 +20,8 @@ if TYPE_CHECKING:
|
|
20
20
|
from prompt_toolkit.application import Application
|
21
21
|
from prompt_toolkit.filters import FilterOrBool
|
22
22
|
from prompt_toolkit.layout.layout import Layout
|
23
|
+
from prompt_toolkit.layout.screen import Char
|
24
|
+
from prompt_toolkit.layout.screen import Screen as PtkScreen
|
23
25
|
from prompt_toolkit.output import ColorDepth, Output
|
24
26
|
from prompt_toolkit.styles import BaseStyle
|
25
27
|
|
@@ -32,10 +34,10 @@ log = logging.getLogger(__name__)
|
|
32
34
|
def _output_screen_diff(
|
33
35
|
app: Application[Any],
|
34
36
|
output: Output,
|
35
|
-
screen:
|
37
|
+
screen: PtkScreen,
|
36
38
|
current_pos: Point,
|
37
39
|
color_depth: ColorDepth,
|
38
|
-
previous_screen:
|
40
|
+
previous_screen: PtkScreen | None,
|
39
41
|
last_style: str | None,
|
40
42
|
is_done: bool, # XXX: drop is_done
|
41
43
|
full_screen: bool,
|
@@ -123,7 +125,9 @@ def _output_screen_diff(
|
|
123
125
|
for index, cell in row.items()
|
124
126
|
if cell.char != " " or style_string_has_style[cell.style]
|
125
127
|
}
|
126
|
-
|
128
|
+
# Lag ZWE indices by one, as one could exist after the last line character
|
129
|
+
# but we don't want that to count towards the line width
|
130
|
+
| {x - 1 for x in zwe_row}
|
127
131
|
| {0}
|
128
132
|
)
|
129
133
|
|
@@ -148,6 +152,7 @@ def _output_screen_diff(
|
|
148
152
|
output.erase_down()
|
149
153
|
|
150
154
|
previous_screen = Screen()
|
155
|
+
assert previous_screen is not None
|
151
156
|
|
152
157
|
# Get height of the screen.
|
153
158
|
# (height changes as we loop over data_buffer, so remember the current value.)
|
@@ -174,7 +179,8 @@ def _output_screen_diff(
|
|
174
179
|
|
175
180
|
prev_diff_char = False
|
176
181
|
|
177
|
-
#
|
182
|
+
# Loop just beyond the line length to check for ZWE sequences right at the end
|
183
|
+
# of the line
|
178
184
|
while c <= new_max_line_len + 1:
|
179
185
|
new_char = new_row[c]
|
180
186
|
old_char = previous_row[c]
|
@@ -268,16 +274,21 @@ class Renderer(PtkRenderer):
|
|
268
274
|
style, output, full_screen, mouse_support, cpr_not_supported_callback
|
269
275
|
)
|
270
276
|
self._extended_keys_enabled = False
|
277
|
+
self._private_sixel_colors_enabled = False
|
271
278
|
self.extend_height = to_filter(extend_height)
|
272
279
|
self.extend_width = to_filter(extend_width)
|
273
280
|
|
274
281
|
def reset(self, _scroll: bool = False, leave_alternate_screen: bool = True) -> None:
|
275
|
-
"""
|
276
|
-
# Disable extended keys
|
282
|
+
"""Reset the output."""
|
277
283
|
if isinstance(self.output, Vt100_Output):
|
284
|
+
# Disable extended keys before resetting the output
|
278
285
|
self.output.disable_extended_keys()
|
279
286
|
self._extended_keys_enabled = False
|
280
287
|
|
288
|
+
# Disable private sixel colors before resetting the output
|
289
|
+
self.output.disable_private_sixel_colors()
|
290
|
+
self._private_sixel_colors_enabled = False
|
291
|
+
|
281
292
|
super().reset(_scroll, leave_alternate_screen)
|
282
293
|
|
283
294
|
def render(
|
@@ -318,6 +329,13 @@ class Renderer(PtkRenderer):
|
|
318
329
|
self.output.enable_extended_keys()
|
319
330
|
self._extended_keys_enabled = True
|
320
331
|
|
332
|
+
# Ensable private sixel graphic color registers
|
333
|
+
if not self._private_sixel_colors_enabled and isinstance(
|
334
|
+
self.output, Vt100_Output
|
335
|
+
):
|
336
|
+
self.output.enable_private_sixel_colors()
|
337
|
+
self._private_sixel_colors_enabled = True
|
338
|
+
|
321
339
|
# Create screen and write layout to it.
|
322
340
|
size = output.get_size()
|
323
341
|
screen = Screen()
|
@@ -376,7 +394,12 @@ class Renderer(PtkRenderer):
|
|
376
394
|
layout.container.write_to_screen(
|
377
395
|
screen,
|
378
396
|
mouse_handlers,
|
379
|
-
|
397
|
+
BoundedWritePosition(
|
398
|
+
xpos=0,
|
399
|
+
ypos=0,
|
400
|
+
width=size.columns,
|
401
|
+
height=height,
|
402
|
+
),
|
380
403
|
parent_style="",
|
381
404
|
erase_bg=False,
|
382
405
|
z_index=None,
|
euporie/core/style.py
CHANGED
@@ -424,6 +424,8 @@ def build_style(
|
|
424
424
|
# status of cursor-line.
|
425
425
|
**dict(default_ui_style().style_rules),
|
426
426
|
"default": f"fg:{cp.bg.base} bg:{cp.bg.base}",
|
427
|
+
# Remove non-breaking space style from PTK
|
428
|
+
"nbsp": "nounderline fg:default",
|
427
429
|
# Logo
|
428
430
|
"logo": "fg:#dd0000",
|
429
431
|
# Pattern
|
euporie/core/tabs/base.py
CHANGED
@@ -10,7 +10,7 @@ from functools import partial
|
|
10
10
|
from typing import TYPE_CHECKING, ClassVar
|
11
11
|
|
12
12
|
from prompt_toolkit.history import InMemoryHistory
|
13
|
-
from prompt_toolkit.layout.containers import
|
13
|
+
from prompt_toolkit.layout.containers import WindowAlign
|
14
14
|
from prompt_toolkit.layout.controls import FormattedTextControl
|
15
15
|
|
16
16
|
from euporie.core.comm.registry import open_comm
|
@@ -24,6 +24,7 @@ from euporie.core.kernel import Kernel, MsgCallbacks
|
|
24
24
|
from euporie.core.key_binding.registry import (
|
25
25
|
register_bindings,
|
26
26
|
)
|
27
|
+
from euporie.core.layout.containers import Window
|
27
28
|
from euporie.core.suggest import HistoryAutoSuggest
|
28
29
|
from euporie.core.utils import run_in_thread_with_context
|
29
30
|
|
euporie/core/terminal.py
CHANGED
@@ -14,7 +14,6 @@ from functools import lru_cache
|
|
14
14
|
from typing import TYPE_CHECKING, ClassVar
|
15
15
|
|
16
16
|
from aenum import extend_enum
|
17
|
-
from prompt_toolkit.application.current import get_app
|
18
17
|
from prompt_toolkit.application.run_in_terminal import run_in_terminal
|
19
18
|
from prompt_toolkit.key_binding.key_processor import KeyProcessor, _Flush
|
20
19
|
from prompt_toolkit.keys import Keys
|
@@ -22,7 +21,8 @@ from prompt_toolkit.output import ColorDepth
|
|
22
21
|
from prompt_toolkit.utils import Event
|
23
22
|
|
24
23
|
from euporie.core.commands import add_cmd
|
25
|
-
from euporie.core.
|
24
|
+
from euporie.core.current import get_app
|
25
|
+
from euporie.core.filters import in_screen, in_tmux
|
26
26
|
from euporie.core.key_binding.registry import register_bindings
|
27
27
|
from euporie.core.style import DEFAULT_COLORS
|
28
28
|
|
@@ -50,11 +50,17 @@ def _have_termios_tty_fcntl() -> bool:
|
|
50
50
|
return True
|
51
51
|
|
52
52
|
|
53
|
-
def
|
54
|
-
"""Wrap an escape sequence for
|
55
|
-
if
|
56
|
-
|
57
|
-
|
53
|
+
def passthrough(cmd: str) -> str:
|
54
|
+
"""Wrap an escape sequence for terminal passthrough."""
|
55
|
+
if get_app().config.multiplexer_passthrough:
|
56
|
+
if in_tmux():
|
57
|
+
cmd = cmd.replace("\x1b", "\x1b\x1b")
|
58
|
+
cmd = f"\x1bPtmux;{cmd}\x1b\\"
|
59
|
+
elif in_screen():
|
60
|
+
# Screen limits escape sequences to 768 bytes, so we have to chunk it
|
61
|
+
cmd = "".join(
|
62
|
+
f"\x1bP{cmd[i: i+764]}\x1b\\" for i in range(0, len(cmd), 764)
|
63
|
+
)
|
58
64
|
return cmd
|
59
65
|
|
60
66
|
|
@@ -198,7 +204,7 @@ class Colors(TerminalQuery):
|
|
198
204
|
)
|
199
205
|
|
200
206
|
def _cmd(self) -> str:
|
201
|
-
return
|
207
|
+
return passthrough(self.cmd)
|
202
208
|
|
203
209
|
def verify(self, data: str) -> dict[str, str]:
|
204
210
|
"""Verify the response contains a colour."""
|
@@ -247,7 +253,7 @@ class KittyGraphicsStatus(TerminalQuery):
|
|
247
253
|
|
248
254
|
def _cmd(self) -> str:
|
249
255
|
"""Hide the command in case the terminal does not support this sequence."""
|
250
|
-
return "\x1b[s" +
|
256
|
+
return "\x1b[s" + passthrough(self.cmd) + "\x1b[u\x1b[2K"
|
251
257
|
|
252
258
|
def verify(self, data: str) -> bool:
|
253
259
|
"""Verify the terminal response means kitty graphics are supported."""
|
@@ -269,10 +275,7 @@ class SixelGraphicsStatus(TerminalQuery):
|
|
269
275
|
pattern = re.compile(r"^\x1b\[\?(?:\d+;)*(?P<sixel>4)(?:;\d+)*c\Z")
|
270
276
|
|
271
277
|
def _cmd(self) -> str:
|
272
|
-
|
273
|
-
return tmuxify(self.cmd)
|
274
|
-
else:
|
275
|
-
return self.cmd
|
278
|
+
return passthrough(self.cmd)
|
276
279
|
|
277
280
|
def verify(self, data: str) -> bool:
|
278
281
|
"""Verify the terminal response means sixel graphics are supported."""
|
@@ -294,10 +297,7 @@ class ItermGraphicsStatus(TerminalQuery):
|
|
294
297
|
pattern = re.compile(r"^\x1bP>\|(?P<term>[^\x1b]+)\x1b\\")
|
295
298
|
|
296
299
|
def _cmd(self) -> str:
|
297
|
-
|
298
|
-
return tmuxify(self.cmd)
|
299
|
-
else:
|
300
|
-
return self.cmd
|
300
|
+
return passthrough(self.cmd)
|
301
301
|
|
302
302
|
def verify(self, data: str) -> bool:
|
303
303
|
"""Verify iterm graphics are supported by the terminal."""
|
@@ -345,13 +345,11 @@ class SgrPixelStatus(TerminalQuery):
|
|
345
345
|
|
346
346
|
def verify(self, data: str) -> bool:
|
347
347
|
"""Verify the terminal response means SGR pixel-mode is supported."""
|
348
|
-
|
348
|
+
return bool(
|
349
349
|
(match := self.pattern.match(data))
|
350
350
|
and (values := match.groupdict())
|
351
351
|
and (values.get("Pm") in {"1", "3"})
|
352
|
-
)
|
353
|
-
return True
|
354
|
-
return False
|
352
|
+
)
|
355
353
|
|
356
354
|
|
357
355
|
class CsiUStatus(TerminalQuery):
|
euporie/core/widgets/cell.py
CHANGED
@@ -15,9 +15,6 @@ from prompt_toolkit.filters import Condition
|
|
15
15
|
from prompt_toolkit.layout.containers import (
|
16
16
|
ConditionalContainer,
|
17
17
|
Container,
|
18
|
-
HSplit,
|
19
|
-
VSplit,
|
20
|
-
Window,
|
21
18
|
)
|
22
19
|
from prompt_toolkit.layout.controls import FormattedTextControl
|
23
20
|
from prompt_toolkit.layout.dimension import Dimension
|
@@ -30,6 +27,7 @@ from euporie.core.config import add_setting
|
|
30
27
|
from euporie.core.current import get_app
|
31
28
|
from euporie.core.filters import multiple_cells_selected
|
32
29
|
from euporie.core.format import format_code
|
30
|
+
from euporie.core.layout.containers import HSplit, VSplit, Window
|
33
31
|
from euporie.core.utils import on_click
|
34
32
|
from euporie.core.widgets.cell_outputs import CellOutputArea
|
35
33
|
from euporie.core.widgets.inputs import KernelInput, StdInput
|
@@ -442,7 +440,7 @@ class Cell:
|
|
442
440
|
self.rendered = False
|
443
441
|
if position is not None:
|
444
442
|
self.input_box.buffer.cursor_position = position % (
|
445
|
-
len(self.input_box.buffer.text)
|
443
|
+
len(self.input_box.buffer.text) + 1
|
446
444
|
)
|
447
445
|
else:
|
448
446
|
to_focus = self.kernel_tab.cell.control
|
@@ -11,10 +11,8 @@ from prompt_toolkit.cache import SimpleCache
|
|
11
11
|
from prompt_toolkit.filters import buffer_has_focus
|
12
12
|
from prompt_toolkit.layout.containers import (
|
13
13
|
DynamicContainer,
|
14
|
-
HSplit,
|
15
14
|
to_container,
|
16
15
|
)
|
17
|
-
from prompt_toolkit.widgets.base import Box
|
18
16
|
|
19
17
|
from euporie.core.config import add_setting
|
20
18
|
from euporie.core.convert.datum import Datum
|
@@ -22,7 +20,9 @@ from euporie.core.convert.formats import BASE64_FORMATS
|
|
22
20
|
from euporie.core.convert.mime import MIME_FORMATS
|
23
21
|
from euporie.core.convert.registry import find_route
|
24
22
|
from euporie.core.current import get_app
|
23
|
+
from euporie.core.layout.containers import HSplit
|
25
24
|
from euporie.core.widgets.display import Display
|
25
|
+
from euporie.core.widgets.layout import Box
|
26
26
|
from euporie.core.widgets.tree import JsonView
|
27
27
|
|
28
28
|
if TYPE_CHECKING:
|