euporie 2.3.2__py3-none-any.whl → 2.4.1__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/__main__.py +3 -1
- euporie/console/app.py +6 -4
- euporie/console/tabs/console.py +34 -9
- euporie/core/__init__.py +6 -1
- euporie/core/__main__.py +1 -1
- euporie/core/app.py +79 -109
- euporie/core/border.py +44 -14
- euporie/core/comm/base.py +5 -4
- euporie/core/comm/ipywidgets.py +11 -11
- euporie/core/comm/registry.py +12 -6
- euporie/core/commands.py +30 -23
- euporie/core/completion.py +1 -4
- euporie/core/config.py +15 -5
- euporie/core/convert/{base.py → core.py} +117 -53
- euporie/core/convert/formats/ansi.py +46 -25
- euporie/core/convert/formats/base64.py +3 -3
- euporie/core/convert/formats/common.py +38 -13
- euporie/core/convert/formats/formatted_text.py +54 -12
- euporie/core/convert/formats/html.py +5 -5
- euporie/core/convert/formats/jpeg.py +1 -1
- euporie/core/convert/formats/markdown.py +4 -4
- euporie/core/convert/formats/pdf.py +1 -1
- euporie/core/convert/formats/pil.py +5 -3
- euporie/core/convert/formats/png.py +7 -6
- euporie/core/convert/formats/rich.py +4 -3
- euporie/core/convert/formats/sixel.py +5 -5
- euporie/core/convert/utils.py +1 -1
- euporie/core/current.py +11 -5
- euporie/core/formatted_text/ansi.py +4 -8
- euporie/core/formatted_text/html.py +1630 -856
- euporie/core/formatted_text/markdown.py +177 -166
- euporie/core/formatted_text/table.py +20 -14
- euporie/core/formatted_text/utils.py +21 -10
- euporie/core/io.py +14 -14
- euporie/core/kernel.py +48 -37
- euporie/core/key_binding/bindings/micro.py +5 -1
- euporie/core/key_binding/bindings/mouse.py +2 -2
- euporie/core/keys.py +3 -0
- euporie/core/launch.py +5 -2
- euporie/core/lexers.py +13 -2
- euporie/core/log.py +135 -139
- euporie/core/margins.py +32 -14
- euporie/core/path.py +273 -0
- euporie/core/processors.py +35 -0
- euporie/core/renderer.py +21 -5
- euporie/core/style.py +34 -19
- euporie/core/tabs/base.py +101 -17
- euporie/core/tabs/notebook.py +72 -30
- euporie/core/terminal.py +56 -48
- euporie/core/utils.py +12 -16
- euporie/core/widgets/cell.py +6 -5
- euporie/core/widgets/cell_outputs.py +2 -2
- euporie/core/widgets/decor.py +74 -82
- euporie/core/widgets/dialog.py +132 -28
- euporie/core/widgets/display.py +76 -24
- euporie/core/widgets/file_browser.py +87 -31
- euporie/core/widgets/formatted_text_area.py +1 -3
- euporie/core/widgets/forms.py +79 -40
- euporie/core/widgets/inputs.py +23 -13
- euporie/core/widgets/layout.py +4 -3
- euporie/core/widgets/menu.py +368 -216
- euporie/core/widgets/page.py +99 -58
- euporie/core/widgets/pager.py +1 -1
- euporie/core/widgets/palette.py +30 -27
- euporie/core/widgets/search_bar.py +38 -25
- euporie/core/widgets/status_bar.py +103 -5
- euporie/data/desktop/euporie-console.desktop +7 -0
- euporie/data/desktop/euporie-notebook.desktop +7 -0
- euporie/hub/__main__.py +3 -1
- euporie/hub/app.py +9 -7
- euporie/notebook/__main__.py +3 -1
- euporie/notebook/app.py +7 -30
- euporie/notebook/tabs/__init__.py +7 -3
- euporie/notebook/tabs/display.py +18 -9
- euporie/notebook/tabs/edit.py +106 -23
- euporie/notebook/tabs/json.py +73 -0
- euporie/notebook/tabs/log.py +18 -8
- euporie/notebook/tabs/notebook.py +60 -41
- euporie/preview/__main__.py +3 -1
- euporie/preview/app.py +2 -1
- euporie/preview/tabs/notebook.py +23 -10
- euporie/web/tabs/web.py +149 -0
- euporie/web/widgets/webview.py +563 -0
- euporie-2.4.1.data/data/share/applications/euporie-console.desktop +7 -0
- euporie-2.4.1.data/data/share/applications/euporie-notebook.desktop +7 -0
- {euporie-2.3.2.dist-info → euporie-2.4.1.dist-info}/METADATA +6 -5
- euporie-2.4.1.dist-info/RECORD +129 -0
- {euporie-2.3.2.dist-info → euporie-2.4.1.dist-info}/WHEEL +1 -1
- euporie/core/url.py +0 -64
- euporie-2.3.2.dist-info/RECORD +0 -122
- {euporie-2.3.2.dist-info → euporie-2.4.1.dist-info}/entry_points.txt +0 -0
- {euporie-2.3.2.dist-info → euporie-2.4.1.dist-info}/licenses/LICENSE +0 -0
euporie/core/widgets/display.py
CHANGED
@@ -16,16 +16,15 @@ from prompt_toolkit.filters.base import Condition
|
|
16
16
|
from prompt_toolkit.filters.utils import to_filter
|
17
17
|
from prompt_toolkit.formatted_text.base import to_formatted_text
|
18
18
|
from prompt_toolkit.formatted_text.utils import fragment_list_width, split_lines
|
19
|
-
from prompt_toolkit.layout.containers import Float, Window
|
19
|
+
from prompt_toolkit.layout.containers import ConditionalContainer, Float, VSplit, Window
|
20
20
|
from prompt_toolkit.layout.controls import GetLinePrefixCallable, UIContent, UIControl
|
21
|
-
from prompt_toolkit.layout.margins import ConditionalMargin
|
22
21
|
from prompt_toolkit.layout.mouse_handlers import MouseHandlers
|
23
22
|
from prompt_toolkit.layout.screen import Char, WritePosition
|
24
23
|
from prompt_toolkit.mouse_events import MouseEvent, MouseEventType
|
25
24
|
from prompt_toolkit.utils import Event
|
26
25
|
|
27
26
|
from euporie.core.commands import add_cmd
|
28
|
-
from euporie.core.convert.
|
27
|
+
from euporie.core.convert.core import convert, find_route
|
29
28
|
from euporie.core.convert.utils import data_pixel_size, pixels_to_cell_size
|
30
29
|
from euporie.core.current import get_app
|
31
30
|
from euporie.core.data_structures import DiInt
|
@@ -40,21 +39,21 @@ from euporie.core.key_binding.registry import (
|
|
40
39
|
load_registered_bindings,
|
41
40
|
register_bindings,
|
42
41
|
)
|
43
|
-
from euporie.core.margins import ScrollbarMargin
|
42
|
+
from euporie.core.margins import MarginContainer, ScrollbarMargin
|
44
43
|
from euporie.core.terminal import tmuxify
|
45
44
|
from euporie.core.widgets.page import BoundedWritePosition
|
46
45
|
|
47
46
|
if TYPE_CHECKING:
|
47
|
+
from pathlib import Path
|
48
48
|
from typing import Any, Callable, Iterable
|
49
49
|
|
50
50
|
from prompt_toolkit.filters import FilterOrBool
|
51
51
|
from prompt_toolkit.formatted_text import StyleAndTextTuples
|
52
52
|
from prompt_toolkit.key_binding import KeyBindingsBase
|
53
53
|
from prompt_toolkit.key_binding.key_bindings import NotImplementedOrNone
|
54
|
-
from prompt_toolkit.layout.containers import AnyContainer
|
54
|
+
from prompt_toolkit.layout.containers import AnyContainer
|
55
55
|
from prompt_toolkit.layout.dimension import AnyDimension
|
56
56
|
from prompt_toolkit.layout.screen import Screen
|
57
|
-
from upath import UPath
|
58
57
|
|
59
58
|
|
60
59
|
log = logging.getLogger(__name__)
|
@@ -71,7 +70,7 @@ class DisplayControl(UIControl):
|
|
71
70
|
self,
|
72
71
|
data: Any,
|
73
72
|
format_: str,
|
74
|
-
path:
|
73
|
+
path: Path | None = None,
|
75
74
|
fg_color: str | None = None,
|
76
75
|
bg_color: str | None = None,
|
77
76
|
sizing_func: Callable[[], tuple[int, float]] | None = None,
|
@@ -102,11 +101,12 @@ class DisplayControl(UIControl):
|
|
102
101
|
self.key_bindings = load_registered_bindings(
|
103
102
|
"euporie.core.widgets.display.Display"
|
104
103
|
)
|
104
|
+
self._cursor_position = Point(x=0, y=0)
|
105
|
+
self.dy = 0
|
105
106
|
self.app = get_app()
|
106
107
|
|
108
|
+
self.on_data_changed = Event(self)
|
107
109
|
self.on_cursor_position_changed = Event(self)
|
108
|
-
self._cursor_position = Point(x=0, y=0)
|
109
|
-
self.dy = 0
|
110
110
|
|
111
111
|
self.sizing_func = sizing_func or (lambda: (0, 0))
|
112
112
|
self._max_cols = 0
|
@@ -133,6 +133,7 @@ class DisplayControl(UIControl):
|
|
133
133
|
"""Set the control's data."""
|
134
134
|
self._data = value
|
135
135
|
self.reset()
|
136
|
+
self.on_data_changed.fire()
|
136
137
|
|
137
138
|
def get_key_bindings(self) -> KeyBindingsBase | None:
|
138
139
|
"""Return the control's key bindings."""
|
@@ -276,6 +277,7 @@ class DisplayControl(UIControl):
|
|
276
277
|
def get_invalidate_events(self) -> Iterable[Event[object]]:
|
277
278
|
"""Return the Window invalidate events."""
|
278
279
|
# Whenever the cursor position changes, the UI has to be updated.
|
280
|
+
yield self.on_data_changed
|
279
281
|
yield self.on_cursor_position_changed
|
280
282
|
|
281
283
|
@property
|
@@ -293,7 +295,6 @@ class DisplayWindow(Window):
|
|
293
295
|
"""A window sub-class which can scroll left and right."""
|
294
296
|
|
295
297
|
content: DisplayControl
|
296
|
-
render_info: WindowRenderInfo
|
297
298
|
vertical_scroll: int
|
298
299
|
|
299
300
|
def _write_to_screen_at_index(
|
@@ -388,7 +389,7 @@ class GraphicControl(DisplayControl, metaclass=ABCMeta):
|
|
388
389
|
self,
|
389
390
|
data: Any,
|
390
391
|
format_: str,
|
391
|
-
path:
|
392
|
+
path: Path | None = None,
|
392
393
|
fg_color: str | None = None,
|
393
394
|
bg_color: str | None = None,
|
394
395
|
sizing_func: Callable[[], tuple[int, float]] | None = None,
|
@@ -632,7 +633,7 @@ class KittyGraphicControl(GraphicControl):
|
|
632
633
|
self,
|
633
634
|
data: Any,
|
634
635
|
format_: str,
|
635
|
-
path:
|
636
|
+
path: Path | None = None,
|
636
637
|
fg_color: str | None = None,
|
637
638
|
bg_color: str | None = None,
|
638
639
|
sizing_func: Callable[[], tuple[int, float]] | None = None,
|
@@ -957,7 +958,7 @@ class GraphicFloat(Float):
|
|
957
958
|
target_window: Window,
|
958
959
|
data: Any,
|
959
960
|
format_: str,
|
960
|
-
path:
|
961
|
+
path: Path | None = None,
|
961
962
|
fg_color: str | None = None,
|
962
963
|
bg_color: str | None = None,
|
963
964
|
sizing_func: Callable[[], tuple[int, float]] | None = None,
|
@@ -1053,6 +1054,32 @@ class GraphicFloat(Float):
|
|
1053
1054
|
self.control.data = value
|
1054
1055
|
self.control.reset()
|
1055
1056
|
|
1057
|
+
@property
|
1058
|
+
def format_(self) -> str:
|
1059
|
+
"""Return the graphic's current data format."""
|
1060
|
+
if self.control is not None:
|
1061
|
+
return self.control.format_
|
1062
|
+
return ""
|
1063
|
+
|
1064
|
+
@format_.setter
|
1065
|
+
def format_(self, value: str) -> None:
|
1066
|
+
"""Set the graphic float's data format."""
|
1067
|
+
if self.control is not None:
|
1068
|
+
self.control.format_ = value
|
1069
|
+
|
1070
|
+
@property
|
1071
|
+
def path(self) -> Path | None:
|
1072
|
+
"""Return the graphic's current data path."""
|
1073
|
+
if self.control is not None:
|
1074
|
+
return self.control.path
|
1075
|
+
return None
|
1076
|
+
|
1077
|
+
@path.setter
|
1078
|
+
def path(self, value: Path | None) -> None:
|
1079
|
+
"""Set the graphic float's data path."""
|
1080
|
+
if self.control is not None:
|
1081
|
+
self.control.path = value
|
1082
|
+
|
1056
1083
|
|
1057
1084
|
class Display:
|
1058
1085
|
"""Rich output displays.
|
@@ -1065,7 +1092,7 @@ class Display:
|
|
1065
1092
|
self,
|
1066
1093
|
data: Any,
|
1067
1094
|
format_: str,
|
1068
|
-
path:
|
1095
|
+
path: Path | None = None,
|
1069
1096
|
fg_color: str | None = None,
|
1070
1097
|
bg_color: str | None = None,
|
1071
1098
|
height: AnyDimension = None,
|
@@ -1138,16 +1165,19 @@ class Display:
|
|
1138
1165
|
char=" ",
|
1139
1166
|
)
|
1140
1167
|
|
1141
|
-
self.
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1168
|
+
self.container = VSplit(
|
1169
|
+
[
|
1170
|
+
self.window,
|
1171
|
+
ConditionalContainer(
|
1172
|
+
MarginContainer(ScrollbarMargin(), target=self.window),
|
1173
|
+
filter=to_filter(scrollbar)
|
1174
|
+
& (
|
1175
|
+
~to_filter(scrollbar_autohide)
|
1176
|
+
| (to_filter(scrollbar_autohide) & scrollable(self.window))
|
1177
|
+
),
|
1148
1178
|
),
|
1149
|
-
|
1150
|
-
|
1179
|
+
]
|
1180
|
+
)
|
1151
1181
|
|
1152
1182
|
# Add graphic
|
1153
1183
|
app = get_app()
|
@@ -1175,6 +1205,28 @@ class Display:
|
|
1175
1205
|
self.control.data = value
|
1176
1206
|
self.graphic_float.data = value
|
1177
1207
|
|
1208
|
+
@property
|
1209
|
+
def format_(self) -> str:
|
1210
|
+
"""Return the display's current data format."""
|
1211
|
+
return self.control.format_
|
1212
|
+
|
1213
|
+
@format_.setter
|
1214
|
+
def format_(self, value: str) -> None:
|
1215
|
+
"""Set the display container's data format."""
|
1216
|
+
self.control.format_ = value
|
1217
|
+
self.graphic_float.format_ = value
|
1218
|
+
|
1219
|
+
@property
|
1220
|
+
def path(self) -> Path | None:
|
1221
|
+
"""Return the display's current data path."""
|
1222
|
+
return self.control.path
|
1223
|
+
|
1224
|
+
@path.setter
|
1225
|
+
def path(self, value: Path | None) -> None:
|
1226
|
+
"""Set the display container's data path."""
|
1227
|
+
self.control.path = value
|
1228
|
+
self.graphic_float.path = value
|
1229
|
+
|
1178
1230
|
def make_sizing_func(
|
1179
1231
|
self, data: Any, format_: str, fg: str | None, bg: str | None
|
1180
1232
|
) -> Callable[[], tuple[int, float]]:
|
@@ -1222,7 +1274,7 @@ class Display:
|
|
1222
1274
|
|
1223
1275
|
def __pt_container__(self) -> AnyContainer:
|
1224
1276
|
"""Return the content of this output."""
|
1225
|
-
return self.
|
1277
|
+
return self.container
|
1226
1278
|
|
1227
1279
|
# ################################### Commands ####################################
|
1228
1280
|
|
@@ -5,7 +5,6 @@ from __future__ import annotations
|
|
5
5
|
import logging
|
6
6
|
from typing import TYPE_CHECKING
|
7
7
|
|
8
|
-
from prompt_toolkit.application.current import get_app
|
9
8
|
from prompt_toolkit.buffer import Buffer
|
10
9
|
from prompt_toolkit.cache import FastDictCache
|
11
10
|
from prompt_toolkit.completion import PathCompleter
|
@@ -20,16 +19,19 @@ from prompt_toolkit.layout.containers import (
|
|
20
19
|
Window,
|
21
20
|
)
|
22
21
|
from prompt_toolkit.layout.controls import UIContent, UIControl
|
23
|
-
from prompt_toolkit.
|
22
|
+
from prompt_toolkit.layout.screen import WritePosition
|
23
|
+
from prompt_toolkit.mouse_events import MouseButton, MouseEvent, MouseEventType
|
24
24
|
from prompt_toolkit.utils import Event
|
25
25
|
from upath import UPath
|
26
26
|
|
27
|
-
from euporie.core.
|
28
|
-
from euporie.core.
|
27
|
+
from euporie.core.app import get_app
|
28
|
+
from euporie.core.border import InsetGrid
|
29
|
+
from euporie.core.margins import MarginContainer, ScrollbarMargin
|
29
30
|
from euporie.core.widgets.decor import Border, FocusedStyle
|
30
31
|
from euporie.core.widgets.forms import Button, Text
|
31
32
|
|
32
33
|
if TYPE_CHECKING:
|
34
|
+
from pathlib import Path
|
33
35
|
from typing import Callable
|
34
36
|
|
35
37
|
from prompt_toolkit.filters.base import FilterOrBool
|
@@ -39,6 +41,8 @@ if TYPE_CHECKING:
|
|
39
41
|
from prompt_toolkit.layout.dimension import AnyDimension
|
40
42
|
from upath.core import PT
|
41
43
|
|
44
|
+
from euporie.core.widgets.status_bar import StatusBarFields
|
45
|
+
|
42
46
|
log = logging.getLogger(__name__)
|
43
47
|
|
44
48
|
|
@@ -349,7 +353,7 @@ FILE_ICONS = {
|
|
349
353
|
}
|
350
354
|
|
351
355
|
|
352
|
-
def is_dir(path: str |
|
356
|
+
def is_dir(path: str | Path) -> bool | None:
|
353
357
|
"""Check if a path is a directory."""
|
354
358
|
test_path = UPath(path)
|
355
359
|
try:
|
@@ -363,22 +367,25 @@ class FileBrowserControl(UIControl):
|
|
363
367
|
|
364
368
|
def __init__(
|
365
369
|
self,
|
366
|
-
path:
|
370
|
+
path: Path | None = None,
|
367
371
|
on_chdir: Callable[[FileBrowserControl], None] | None = None,
|
368
372
|
on_select: Callable[[FileBrowserControl], None] | None = None,
|
369
373
|
on_open: Callable[[FileBrowserControl], None] | None = None,
|
374
|
+
window: Window | None = None,
|
370
375
|
) -> None:
|
371
376
|
"""Initialize a new file browser instance."""
|
372
377
|
self.dir = path or UPath(".")
|
373
|
-
self.hovered: int =
|
378
|
+
self.hovered: int | None = None
|
374
379
|
self.selected: int | None = None
|
375
380
|
self._dir_cache: FastDictCache[
|
376
|
-
tuple[
|
381
|
+
tuple[Path], list[tuple[bool, Path]]
|
377
382
|
] = FastDictCache(get_value=self.load_path, size=1)
|
378
383
|
self.on_select = Event(self, on_select)
|
379
384
|
self.on_chdir = Event(self, on_chdir)
|
380
385
|
self.on_open = Event(self, on_open)
|
381
386
|
|
387
|
+
self.window = window
|
388
|
+
|
382
389
|
self.on_chdir.fire()
|
383
390
|
|
384
391
|
self.key_bindings = kb = KeyBindings()
|
@@ -412,12 +419,12 @@ class FileBrowserControl(UIControl):
|
|
412
419
|
return self.open_path()
|
413
420
|
|
414
421
|
@property
|
415
|
-
def contents(self) -> list[tuple[bool,
|
422
|
+
def contents(self) -> list[tuple[bool, Path]]:
|
416
423
|
"""Return the contents of the current folder."""
|
417
424
|
return self._dir_cache[(self.dir,)]
|
418
425
|
|
419
426
|
@property
|
420
|
-
def dir(self) ->
|
427
|
+
def dir(self) -> Path:
|
421
428
|
"""Return the current folder path."""
|
422
429
|
return self._dir
|
423
430
|
|
@@ -435,12 +442,12 @@ class FileBrowserControl(UIControl):
|
|
435
442
|
log.warning("'%s' is not a directory, not changing directory", value)
|
436
443
|
|
437
444
|
@property
|
438
|
-
def path(self) ->
|
445
|
+
def path(self) -> Path:
|
439
446
|
"""Return the current selected path."""
|
440
447
|
return self.contents[self.selected or 0][1]
|
441
448
|
|
442
449
|
@staticmethod
|
443
|
-
def load_path(path:
|
450
|
+
def load_path(path: Path) -> list[tuple[bool, Path]]:
|
444
451
|
"""Return the contents of a folder."""
|
445
452
|
paths = [] if path.parent == path else [path / ".."]
|
446
453
|
try:
|
@@ -489,11 +496,42 @@ class FileBrowserControl(UIControl):
|
|
489
496
|
def mouse_handler(self, mouse_event: MouseEvent) -> NotImplementedOrNone:
|
490
497
|
"""Handle mouse events."""
|
491
498
|
row = mouse_event.position.y
|
492
|
-
|
493
|
-
|
499
|
+
app = get_app()
|
500
|
+
if (
|
501
|
+
mouse_event.button == MouseButton.LEFT
|
502
|
+
and mouse_event.event_type == MouseEventType.MOUSE_DOWN
|
503
|
+
):
|
504
|
+
app.layout.current_control = self
|
505
|
+
app.mouse_limits = None
|
506
|
+
self.hovered = None
|
494
507
|
return self.select(row, open_file=True)
|
495
508
|
elif mouse_event.event_type == MouseEventType.MOUSE_MOVE:
|
496
|
-
|
509
|
+
# Mark item as hovered if mouse is over the control
|
510
|
+
if (
|
511
|
+
self.window is not None
|
512
|
+
and (info := self.window.render_info) is not None
|
513
|
+
):
|
514
|
+
rowcol_to_yx = info._rowcol_to_yx
|
515
|
+
abs_mouse_pos = (
|
516
|
+
mouse_event.position.x + info._x_offset,
|
517
|
+
mouse_event.position.y + info._y_offset - info.vertical_scroll,
|
518
|
+
)
|
519
|
+
if abs_mouse_pos == app.mouse_position:
|
520
|
+
row_col_vals = rowcol_to_yx.values()
|
521
|
+
y_min, x_min = min(row_col_vals)
|
522
|
+
y_max, x_max = max(row_col_vals)
|
523
|
+
app.mouse_limits = WritePosition(
|
524
|
+
xpos=x_min,
|
525
|
+
ypos=y_min,
|
526
|
+
width=x_max - x_min + 1,
|
527
|
+
height=y_max - y_min + 1,
|
528
|
+
)
|
529
|
+
return self.hover(row)
|
530
|
+
else:
|
531
|
+
# Clear mouse limits if mouse is outside control
|
532
|
+
app.mouse_limits = None
|
533
|
+
self.hovered = None
|
534
|
+
return None
|
497
535
|
|
498
536
|
return NotImplemented
|
499
537
|
|
@@ -509,12 +547,13 @@ class FileBrowserControl(UIControl):
|
|
509
547
|
self.open_path()
|
510
548
|
return None
|
511
549
|
|
512
|
-
def hover(self, row: int) -> NotImplementedOrNone:
|
550
|
+
def hover(self, row: int | None) -> NotImplementedOrNone:
|
513
551
|
"""Hover a file in the browser."""
|
514
|
-
|
515
|
-
|
516
|
-
self.hovered
|
517
|
-
|
552
|
+
if row is not None:
|
553
|
+
row = min(max(0, row), len(self.contents) - 1)
|
554
|
+
if self.hovered != row:
|
555
|
+
self.hovered = row
|
556
|
+
return None
|
518
557
|
return NotImplemented
|
519
558
|
|
520
559
|
def open_path(self) -> None:
|
@@ -555,6 +594,14 @@ class FileBrowserControl(UIControl):
|
|
555
594
|
"""Determine that the file_browser is focusable."""
|
556
595
|
return True
|
557
596
|
|
597
|
+
def __pt_status__(self) -> StatusBarFields:
|
598
|
+
"""Show the selected or hovered path in the statusbar."""
|
599
|
+
if self.hovered is not None:
|
600
|
+
return [[("", str(self.contents[self.hovered][1]))]], []
|
601
|
+
elif self.selected is not None:
|
602
|
+
return [[("", str(self.contents[self.selected][1]))]], []
|
603
|
+
return [], []
|
604
|
+
|
558
605
|
|
559
606
|
class FileBrowser:
|
560
607
|
"""A file browser."""
|
@@ -563,10 +610,10 @@ class FileBrowser:
|
|
563
610
|
|
564
611
|
def __init__(
|
565
612
|
self,
|
566
|
-
path:
|
567
|
-
on_select: Callable[[
|
568
|
-
on_open: Callable[[
|
569
|
-
on_chdir: Callable[[
|
613
|
+
path: Path | None = None,
|
614
|
+
on_select: Callable[[Path], None] | None = None,
|
615
|
+
on_open: Callable[[Path], None] | None = None,
|
616
|
+
on_chdir: Callable[[Path], None] | None = None,
|
570
617
|
width: AnyDimension = None,
|
571
618
|
height: AnyDimension = None,
|
572
619
|
style: str = "",
|
@@ -575,7 +622,7 @@ class FileBrowser:
|
|
575
622
|
"""Create a new instance."""
|
576
623
|
|
577
624
|
def _accept_path(buffer: Buffer) -> bool:
|
578
|
-
control.dir =
|
625
|
+
control.dir = Path(buffer.text)
|
579
626
|
return True
|
580
627
|
|
581
628
|
def _validate_path(path: str) -> bool:
|
@@ -588,7 +635,6 @@ class FileBrowser:
|
|
588
635
|
)
|
589
636
|
self.control = control = FileBrowserControl(
|
590
637
|
path=path,
|
591
|
-
on_open=lambda x: log.debug(x.path),
|
592
638
|
on_chdir=lambda x: setattr(text, "text", str(x.dir)),
|
593
639
|
)
|
594
640
|
if on_select is not None:
|
@@ -622,12 +668,16 @@ class FileBrowser:
|
|
622
668
|
),
|
623
669
|
FocusedStyle(
|
624
670
|
Border(
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
671
|
+
VSplit(
|
672
|
+
[
|
673
|
+
window := Window(
|
674
|
+
control,
|
675
|
+
style="class:face",
|
676
|
+
),
|
677
|
+
MarginContainer(ScrollbarMargin(), target=window),
|
678
|
+
]
|
629
679
|
),
|
630
|
-
border=
|
680
|
+
border=InsetGrid,
|
631
681
|
style="class:input,inset,border",
|
632
682
|
),
|
633
683
|
style_hover="",
|
@@ -637,7 +687,13 @@ class FileBrowser:
|
|
637
687
|
width=width,
|
638
688
|
height=height,
|
639
689
|
)
|
690
|
+
# Set control's window so it can determine it's position for mouse-over
|
691
|
+
control.window = window
|
640
692
|
|
641
693
|
def __pt_container__(self) -> AnyContainer:
|
642
694
|
"""Return the tree-view container's content."""
|
643
695
|
return self.container
|
696
|
+
|
697
|
+
def __pt_status__(self) -> StatusBarFields:
|
698
|
+
"""Show the selected or hovered path in the statusbar."""
|
699
|
+
return self.control.__pt_status__()
|
@@ -15,7 +15,7 @@ from prompt_toolkit.layout.margins import ConditionalMargin
|
|
15
15
|
from prompt_toolkit.layout.processors import DynamicProcessor, Processor, Transformation
|
16
16
|
from prompt_toolkit.widgets import TextArea
|
17
17
|
|
18
|
-
from euporie.core.margins import NumberedDiffMargin
|
18
|
+
from euporie.core.margins import NumberedDiffMargin
|
19
19
|
|
20
20
|
if TYPE_CHECKING:
|
21
21
|
from typing import Any
|
@@ -98,8 +98,6 @@ class FormattedTextArea(TextArea):
|
|
98
98
|
self.line_numbers,
|
99
99
|
)
|
100
100
|
]
|
101
|
-
# Add auto scrollbar
|
102
|
-
self.window.right_margins = [ScrollbarMargin(display_arrows=False)]
|
103
101
|
# Set the formatted text to display
|
104
102
|
self._set_formatted_text(formatted_text)
|
105
103
|
|