euporie 2.8.4__py3-none-any.whl → 2.8.6__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/_commands.py +143 -0
- euporie/console/_settings.py +58 -0
- euporie/console/app.py +25 -71
- euporie/console/tabs/console.py +58 -62
- euporie/core/__init__.py +1 -1
- euporie/core/__main__.py +28 -11
- euporie/core/_settings.py +109 -0
- euporie/core/app/__init__.py +3 -0
- euporie/core/app/_commands.py +95 -0
- euporie/core/app/_settings.py +457 -0
- euporie/core/{app.py → app/app.py} +212 -576
- euporie/core/app/base.py +51 -0
- euporie/core/{current.py → app/current.py} +13 -4
- euporie/core/app/cursor.py +35 -0
- euporie/core/app/dummy.py +12 -0
- euporie/core/app/launch.py +28 -0
- euporie/core/bars/__init__.py +11 -0
- euporie/core/bars/command.py +205 -0
- euporie/core/bars/menu.py +258 -0
- euporie/core/{widgets → bars}/search.py +20 -16
- euporie/core/{widgets → bars}/status.py +6 -23
- euporie/core/clipboard.py +19 -80
- euporie/core/comm/base.py +8 -6
- euporie/core/comm/ipywidgets.py +16 -7
- euporie/core/comm/registry.py +2 -1
- euporie/core/commands.py +10 -20
- euporie/core/completion.py +3 -2
- euporie/core/config.py +368 -341
- euporie/core/convert/__init__.py +0 -30
- euporie/core/convert/datum.py +116 -53
- euporie/core/convert/formats/__init__.py +31 -0
- euporie/core/convert/formats/ansi.py +9 -23
- euporie/core/convert/formats/common.py +11 -23
- euporie/core/convert/formats/html.py +45 -40
- euporie/core/convert/formats/pil.py +1 -1
- euporie/core/convert/formats/png.py +3 -5
- euporie/core/convert/formats/sixel.py +3 -3
- euporie/core/convert/registry.py +4 -6
- euporie/core/convert/utils.py +41 -4
- euporie/core/diagnostics.py +2 -2
- euporie/core/filters.py +98 -40
- euporie/core/format.py +2 -3
- euporie/core/ft/ansi.py +1 -1
- euporie/core/ft/html.py +12 -21
- euporie/core/ft/table.py +1 -3
- euporie/core/ft/utils.py +4 -1
- euporie/core/graphics.py +386 -133
- euporie/core/history.py +2 -2
- euporie/core/inspection.py +3 -2
- euporie/core/io.py +207 -28
- euporie/core/kernel/__init__.py +1 -0
- euporie/core/{kernel.py → kernel/client.py} +45 -108
- euporie/core/kernel/manager.py +114 -0
- euporie/core/key_binding/bindings/__init__.py +1 -8
- euporie/core/key_binding/bindings/basic.py +47 -7
- euporie/core/key_binding/bindings/completion.py +3 -8
- euporie/core/key_binding/bindings/micro.py +1 -6
- euporie/core/key_binding/bindings/mouse.py +2 -2
- euporie/core/key_binding/bindings/terminal.py +193 -0
- euporie/core/key_binding/key_processor.py +43 -2
- euporie/core/key_binding/registry.py +2 -0
- euporie/core/key_binding/utils.py +22 -2
- euporie/core/keys.py +7156 -93
- euporie/core/layout/cache.py +3 -3
- euporie/core/layout/containers.py +48 -4
- euporie/core/layout/decor.py +2 -2
- euporie/core/layout/mouse.py +1 -1
- euporie/core/layout/print.py +2 -1
- euporie/core/layout/scroll.py +39 -34
- euporie/core/log.py +76 -64
- euporie/core/lsp.py +118 -24
- euporie/core/margins.py +1 -1
- euporie/core/path.py +62 -13
- euporie/core/renderer.py +58 -17
- euporie/core/style.py +57 -39
- euporie/core/suggest.py +103 -85
- euporie/core/tabs/__init__.py +32 -0
- euporie/core/tabs/_settings.py +113 -0
- euporie/core/tabs/base.py +80 -470
- euporie/core/tabs/kernel.py +419 -0
- euporie/core/tabs/notebook.py +24 -101
- euporie/core/utils.py +92 -15
- euporie/core/validation.py +1 -1
- euporie/core/widgets/_settings.py +188 -0
- euporie/core/widgets/cell.py +19 -50
- euporie/core/widgets/cell_outputs.py +25 -36
- euporie/core/widgets/decor.py +11 -41
- euporie/core/widgets/dialog.py +62 -27
- euporie/core/widgets/display.py +12 -15
- euporie/core/widgets/file_browser.py +2 -23
- euporie/core/widgets/forms.py +8 -5
- euporie/core/widgets/inputs.py +13 -70
- euporie/core/widgets/layout.py +2 -1
- euporie/core/widgets/logo.py +49 -0
- euporie/core/widgets/menu.py +10 -8
- euporie/core/widgets/pager.py +6 -10
- euporie/core/widgets/palette.py +6 -6
- euporie/hub/app.py +52 -35
- euporie/notebook/_commands.py +24 -0
- euporie/notebook/_settings.py +107 -0
- euporie/notebook/app.py +49 -171
- euporie/notebook/filters.py +1 -1
- euporie/notebook/tabs/__init__.py +46 -7
- euporie/notebook/tabs/_commands.py +714 -0
- euporie/notebook/tabs/_settings.py +32 -0
- euporie/notebook/tabs/display.py +4 -4
- euporie/notebook/tabs/edit.py +11 -44
- euporie/notebook/tabs/json.py +5 -5
- euporie/notebook/tabs/log.py +1 -18
- euporie/notebook/tabs/notebook.py +11 -660
- euporie/notebook/widgets/_commands.py +11 -0
- euporie/notebook/widgets/_settings.py +19 -0
- euporie/notebook/widgets/side_bar.py +14 -34
- euporie/preview/_settings.py +104 -0
- euporie/preview/app.py +6 -31
- euporie/preview/tabs/notebook.py +6 -72
- euporie/web/__init__.py +1 -0
- euporie/web/tabs/__init__.py +14 -0
- euporie/web/tabs/web.py +11 -6
- euporie/web/widgets/__init__.py +1 -0
- euporie/web/widgets/webview.py +5 -15
- {euporie-2.8.4.dist-info → euporie-2.8.6.dist-info}/METADATA +10 -8
- euporie-2.8.6.dist-info/RECORD +175 -0
- {euporie-2.8.4.dist-info → euporie-2.8.6.dist-info}/WHEEL +1 -1
- {euporie-2.8.4.dist-info → euporie-2.8.6.dist-info}/entry_points.txt +2 -2
- {euporie-2.8.4.dist-info → euporie-2.8.6.dist-info}/licenses/LICENSE +1 -1
- euporie/core/launch.py +0 -64
- euporie/core/terminal.py +0 -522
- euporie-2.8.4.dist-info/RECORD +0 -147
- {euporie-2.8.4.data → euporie-2.8.6.data}/data/share/applications/euporie-console.desktop +0 -0
- {euporie-2.8.4.data → euporie-2.8.6.data}/data/share/applications/euporie-notebook.desktop +0 -0
euporie/core/widgets/dialog.py
CHANGED
@@ -3,7 +3,6 @@
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
5
|
import logging
|
6
|
-
import traceback
|
7
6
|
from abc import ABCMeta, abstractmethod
|
8
7
|
from functools import partial
|
9
8
|
from pathlib import Path
|
@@ -34,26 +33,26 @@ from prompt_toolkit.layout.screen import WritePosition
|
|
34
33
|
from prompt_toolkit.mouse_events import MouseButton, MouseEventType
|
35
34
|
from prompt_toolkit.widgets.base import Label
|
36
35
|
|
37
|
-
from euporie.core.app import get_app
|
36
|
+
from euporie.core.app.current import get_app
|
38
37
|
from euporie.core.border import (
|
39
38
|
FullLine,
|
40
39
|
LowerLeftHalfLine,
|
41
40
|
UpperRightHalfLine,
|
42
41
|
)
|
43
42
|
from euporie.core.commands import add_cmd
|
44
|
-
from euporie.core.filters import
|
43
|
+
from euporie.core.filters import tab_can_save
|
45
44
|
from euporie.core.ft.utils import FormattedTextAlign, align, lex
|
46
45
|
from euporie.core.key_binding.registry import register_bindings
|
47
46
|
from euporie.core.layout.containers import HSplit, VSplit, Window
|
48
47
|
from euporie.core.layout.decor import FocusedStyle
|
49
|
-
from euporie.core.tabs.base import Tab
|
50
48
|
from euporie.core.widgets.decor import Border, Shadow
|
51
49
|
from euporie.core.widgets.file_browser import FileBrowser
|
52
50
|
from euporie.core.widgets.forms import Button, LabelledWidget, Select, Text
|
53
51
|
from euporie.core.widgets.layout import Box
|
54
52
|
|
55
53
|
if TYPE_CHECKING:
|
56
|
-
from
|
54
|
+
from collections.abc import Hashable
|
55
|
+
from typing import Any, Callable
|
57
56
|
|
58
57
|
from prompt_toolkit.buffer import Buffer
|
59
58
|
from prompt_toolkit.data_structures import Point
|
@@ -64,9 +63,9 @@ if TYPE_CHECKING:
|
|
64
63
|
from prompt_toolkit.layout.layout import FocusableElement
|
65
64
|
from prompt_toolkit.mouse_events import MouseEvent
|
66
65
|
|
67
|
-
from euporie.core.app import BaseApp
|
68
|
-
from euporie.core.tabs.base import
|
69
|
-
from euporie.core.
|
66
|
+
from euporie.core.app.app import BaseApp
|
67
|
+
from euporie.core.tabs.base import Tab
|
68
|
+
from euporie.core.tabs.kernel import KernelTab
|
70
69
|
|
71
70
|
log = logging.getLogger(__name__)
|
72
71
|
|
@@ -139,8 +138,12 @@ class DialogTitleControl(UIControl):
|
|
139
138
|
dl_width, max_y
|
140
139
|
).preferred
|
141
140
|
# Calculate new dialog position
|
142
|
-
new_x = max(
|
143
|
-
|
141
|
+
new_x = max(
|
142
|
+
1, min(gx - self.drag_start.x, max_x - dl_width + 1)
|
143
|
+
)
|
144
|
+
new_y = max(
|
145
|
+
1, min(gy - self.drag_start.y, max_y - dl_height + 1)
|
146
|
+
)
|
144
147
|
# Move dialog
|
145
148
|
self.dialog.left = new_x - 1
|
146
149
|
self.dialog.top = new_y - 1
|
@@ -409,7 +412,7 @@ class AboutDialog(Dialog):
|
|
409
412
|
@add_cmd()
|
410
413
|
def _about() -> None:
|
411
414
|
"""Show the about dialog."""
|
412
|
-
from euporie.core.current import get_app
|
415
|
+
from euporie.core.app.current import get_app
|
413
416
|
|
414
417
|
if dialog := get_app().dialogs.get("about"):
|
415
418
|
dialog.toggle()
|
@@ -498,12 +501,13 @@ class OpenFileDialog(FileDialog):
|
|
498
501
|
|
499
502
|
self.tab_dd = tab_dd = Dropdown(options=[])
|
500
503
|
|
501
|
-
def _update_options(
|
502
|
-
tabs = get_app().get_file_tabs(path) if
|
504
|
+
def _update_options(path: Path) -> None:
|
505
|
+
tabs = get_app().get_file_tabs(path) if path.is_file() else []
|
503
506
|
tab_dd.options = tabs
|
504
507
|
tab_dd.labels = [tab.name for tab in tabs]
|
505
508
|
|
506
|
-
self.file_browser.control.on_select += _update_options
|
509
|
+
self.file_browser.control.on_select += lambda fb: _update_options(fb.path)
|
510
|
+
self.filepath.buffer.on_text_changed += lambda b: _update_options(Path(b.text))
|
507
511
|
|
508
512
|
if isinstance(self.body, HSplit):
|
509
513
|
self.body.children.append(
|
@@ -543,7 +547,7 @@ class OpenFileDialog(FileDialog):
|
|
543
547
|
self.file_browser.control.dir = path
|
544
548
|
elif path.is_file():
|
545
549
|
self.hide()
|
546
|
-
self.app.open_file(path, tab_class=self.tab_dd.value)
|
550
|
+
self.app.open_file(path, tab_class=self.tab_dd.value.tab_class)
|
547
551
|
return
|
548
552
|
else:
|
549
553
|
self.show(
|
@@ -556,7 +560,7 @@ class OpenFileDialog(FileDialog):
|
|
556
560
|
@add_cmd(menu_title="Open File…")
|
557
561
|
def _open_file() -> None:
|
558
562
|
"""Open a file."""
|
559
|
-
from euporie.core.current import get_app
|
563
|
+
from euporie.core.app.current import get_app
|
560
564
|
|
561
565
|
if dialog := get_app().dialogs.get("open-file"):
|
562
566
|
dialog.show()
|
@@ -565,7 +569,7 @@ class OpenFileDialog(FileDialog):
|
|
565
569
|
|
566
570
|
register_bindings(
|
567
571
|
{
|
568
|
-
"euporie.core.app.BaseApp": {
|
572
|
+
"euporie.core.app.app:BaseApp": {
|
569
573
|
"open-file": "c-o",
|
570
574
|
}
|
571
575
|
}
|
@@ -598,11 +602,11 @@ class SaveAsDialog(FileDialog):
|
|
598
602
|
@staticmethod
|
599
603
|
@add_cmd(
|
600
604
|
menu_title="Save As…",
|
601
|
-
filter=
|
605
|
+
filter=tab_can_save,
|
602
606
|
)
|
603
607
|
def _save_as() -> None:
|
604
608
|
"""Save the current file at a new location."""
|
605
|
-
from euporie.core.current import get_app
|
609
|
+
from euporie.core.app.current import get_app
|
606
610
|
|
607
611
|
app = get_app()
|
608
612
|
if dialog := app.dialogs.get("save-as"):
|
@@ -612,7 +616,7 @@ class SaveAsDialog(FileDialog):
|
|
612
616
|
|
613
617
|
register_bindings(
|
614
618
|
{
|
615
|
-
"euporie.core.app.BaseApp": {
|
619
|
+
"euporie.core.app.app:BaseApp": {
|
616
620
|
"save-as": ("A-s"),
|
617
621
|
}
|
618
622
|
}
|
@@ -773,6 +777,8 @@ class ErrorDialog(Dialog):
|
|
773
777
|
|
774
778
|
def load(self, exception: Exception | None = None, when: str = "") -> None:
|
775
779
|
"""Load dialog body & buttons."""
|
780
|
+
import traceback
|
781
|
+
|
776
782
|
from euporie.core.margins import MarginContainer, ScrollbarMargin
|
777
783
|
from euporie.core.widgets.formatted_text_area import FormattedTextArea
|
778
784
|
from euporie.core.widgets.forms import Checkbox
|
@@ -798,7 +804,7 @@ class ErrorDialog(Dialog):
|
|
798
804
|
("bold", f" when {when}" if when else ""),
|
799
805
|
("bold", ":"),
|
800
806
|
("", "\n\n"),
|
801
|
-
("fg:ansired", exception
|
807
|
+
("fg:ansired", repr(exception)),
|
802
808
|
("", "\n"),
|
803
809
|
],
|
804
810
|
)
|
@@ -828,7 +834,36 @@ class ErrorDialog(Dialog):
|
|
828
834
|
def _copy_traceback() -> None:
|
829
835
|
self.app.clipboard.set_data(ClipboardData(tb_text))
|
830
836
|
|
831
|
-
|
837
|
+
def _report() -> None:
|
838
|
+
import webbrowser
|
839
|
+
from importlib.metadata import metadata
|
840
|
+
from urllib.parse import urlencode, urlparse, urlunparse
|
841
|
+
|
842
|
+
data = metadata("euporie")
|
843
|
+
if issue_url := dict(
|
844
|
+
x.split(", ", 1) for x in data.json["project_url"]
|
845
|
+
).get("Issues"):
|
846
|
+
parsed_url = urlparse(issue_url)
|
847
|
+
url = urlunparse(
|
848
|
+
parsed_url._replace(
|
849
|
+
path=f"{parsed_url.path.rstrip('/')}/new"
|
850
|
+
)._replace(
|
851
|
+
query=urlencode(
|
852
|
+
{
|
853
|
+
"title": f"Error: {exception!r}",
|
854
|
+
"body": "(Please describe what you did)\n\n"
|
855
|
+
f"## Traceback\n\n```python\n{tb_text}\n```\n",
|
856
|
+
}
|
857
|
+
)
|
858
|
+
)
|
859
|
+
)
|
860
|
+
webbrowser.open(url, new=2, autoraise=True)
|
861
|
+
|
862
|
+
self.buttons = {
|
863
|
+
"Report on GitHub": _report,
|
864
|
+
"Copy Traceback": _copy_traceback,
|
865
|
+
"Close": None,
|
866
|
+
}
|
832
867
|
|
833
868
|
|
834
869
|
class UnsavedDialog(Dialog):
|
@@ -859,6 +894,8 @@ class UnsavedDialog(Dialog):
|
|
859
894
|
tab.save(cb=partial(tab.close, cb))
|
860
895
|
|
861
896
|
def no_cb() -> None:
|
897
|
+
from euporie.core.tabs.base import Tab
|
898
|
+
|
862
899
|
assert tab is not None
|
863
900
|
self.hide()
|
864
901
|
Tab.close(tab, cb)
|
@@ -903,7 +940,7 @@ class ShortcutsDialog(Dialog):
|
|
903
940
|
|
904
941
|
def format_key_info(self) -> StyleAndTextTuples:
|
905
942
|
"""Generate a table with the current key bindings."""
|
906
|
-
import
|
943
|
+
import pkgutil
|
907
944
|
from textwrap import dedent
|
908
945
|
|
909
946
|
from prompt_toolkit.formatted_text.base import to_formatted_text
|
@@ -920,9 +957,7 @@ class ShortcutsDialog(Dialog):
|
|
920
957
|
|
921
958
|
for group, bindings in BINDINGS.items():
|
922
959
|
if any(not get_cmd(cmd_name).hidden() for cmd_name in bindings):
|
923
|
-
|
924
|
-
mod = importlib.import_module(mod_name)
|
925
|
-
app_cls = getattr(mod, cls_name)
|
960
|
+
app_cls = pkgutil.resolve_name(group)
|
926
961
|
section_title = (
|
927
962
|
dedent(app_cls.__doc__).strip().split("\n")[0].rstrip(".")
|
928
963
|
)
|
@@ -965,7 +1000,7 @@ class ShortcutsDialog(Dialog):
|
|
965
1000
|
@add_cmd()
|
966
1001
|
def _keyboard_shortcuts() -> None:
|
967
1002
|
"""Display details of registered key-bindings in a dialog."""
|
968
|
-
from euporie.core.current import get_app
|
1003
|
+
from euporie.core.app.current import get_app
|
969
1004
|
|
970
1005
|
if dialog := get_app().dialogs.get("shortcuts"):
|
971
1006
|
dialog.toggle()
|
euporie/core/widgets/display.py
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
|
+
import asyncio
|
5
6
|
import logging
|
6
7
|
from functools import partial
|
7
8
|
from math import ceil
|
@@ -16,9 +17,9 @@ from prompt_toolkit.layout.controls import GetLinePrefixCallable, UIContent, UIC
|
|
16
17
|
from prompt_toolkit.mouse_events import MouseEvent, MouseEventType
|
17
18
|
from prompt_toolkit.utils import Event, to_str
|
18
19
|
|
20
|
+
from euporie.core.app.current import get_app
|
19
21
|
from euporie.core.commands import add_cmd
|
20
22
|
from euporie.core.convert.datum import Datum
|
21
|
-
from euporie.core.current import get_app
|
22
23
|
from euporie.core.filters import display_has_focus, scrollable
|
23
24
|
from euporie.core.ft.utils import wrap
|
24
25
|
from euporie.core.graphics import GraphicProcessor
|
@@ -28,10 +29,10 @@ from euporie.core.key_binding.registry import (
|
|
28
29
|
)
|
29
30
|
from euporie.core.layout.containers import VSplit, Window
|
30
31
|
from euporie.core.margins import MarginContainer, ScrollbarMargin
|
31
|
-
from euporie.core.utils import run_in_thread_with_context
|
32
32
|
|
33
33
|
if TYPE_CHECKING:
|
34
|
-
from
|
34
|
+
from collections.abc import Iterable
|
35
|
+
from typing import Any, Callable
|
35
36
|
|
36
37
|
from prompt_toolkit.filters import FilterOrBool
|
37
38
|
from prompt_toolkit.formatted_text import StyleAndTextTuples
|
@@ -157,7 +158,7 @@ class DisplayControl(UIControl):
|
|
157
158
|
extend=not self.dont_extend_width(),
|
158
159
|
)
|
159
160
|
if width and height:
|
160
|
-
key = Datum.add_size(datum, Size(
|
161
|
+
key = Datum.add_size(datum, Size(height, width))
|
161
162
|
ft = [(f"[Graphic_{key}]", ""), *ft]
|
162
163
|
lines = list(split_lines(ft))
|
163
164
|
if wrap_lines and width:
|
@@ -194,13 +195,14 @@ class DisplayControl(UIControl):
|
|
194
195
|
)
|
195
196
|
|
196
197
|
def render(self) -> None:
|
197
|
-
"""Render the
|
198
|
+
"""Render the content in a thread."""
|
198
199
|
datum = self.datum
|
199
200
|
wrap_lines = self.wrap_lines()
|
200
201
|
|
201
|
-
|
202
|
-
|
203
|
-
|
202
|
+
cols = self.preferred_width(self.width)
|
203
|
+
rows = self.preferred_height(
|
204
|
+
self.width, self.height, wrap_lines=wrap_lines, get_line_prefix=None
|
205
|
+
)
|
204
206
|
|
205
207
|
def _render() -> None:
|
206
208
|
cp = self.color_palette
|
@@ -215,7 +217,7 @@ class DisplayControl(UIControl):
|
|
215
217
|
if not self.rendering:
|
216
218
|
self.rendering = True
|
217
219
|
if self.threaded:
|
218
|
-
|
220
|
+
get_app().create_background_task(asyncio.to_thread(_render))
|
219
221
|
else:
|
220
222
|
_render()
|
221
223
|
|
@@ -224,12 +226,7 @@ class DisplayControl(UIControl):
|
|
224
226
|
|
225
227
|
def preferred_width(self, max_available_width: int) -> int | None:
|
226
228
|
"""Calculate and return the preferred width of the control."""
|
227
|
-
|
228
|
-
if max_cols:
|
229
|
-
return min(max_cols, max_available_width)
|
230
|
-
return self._max_line_width_cache[
|
231
|
-
self.datum, max_available_width, None, self.wrap_lines()
|
232
|
-
]
|
229
|
+
return max_available_width
|
233
230
|
|
234
231
|
def preferred_height(
|
235
232
|
self,
|
@@ -20,9 +20,8 @@ from prompt_toolkit.mouse_events import MouseButton, MouseEvent, MouseEventType
|
|
20
20
|
from prompt_toolkit.utils import Event
|
21
21
|
from upath import UPath
|
22
22
|
|
23
|
-
from euporie.core.app import get_app
|
23
|
+
from euporie.core.app.current import get_app
|
24
24
|
from euporie.core.border import InsetGrid
|
25
|
-
from euporie.core.config import add_setting
|
26
25
|
from euporie.core.layout.containers import HSplit, VSplit, Window
|
27
26
|
from euporie.core.layout.decor import FocusedStyle
|
28
27
|
from euporie.core.margins import MarginContainer, ScrollbarMargin
|
@@ -41,7 +40,7 @@ if TYPE_CHECKING:
|
|
41
40
|
from prompt_toolkit.layout.dimension import AnyDimension
|
42
41
|
from upath.core import PT
|
43
42
|
|
44
|
-
from euporie.core.
|
43
|
+
from euporie.core.bars.status import StatusBarFields
|
45
44
|
|
46
45
|
log = logging.getLogger(__name__)
|
47
46
|
|
@@ -704,23 +703,3 @@ class FileBrowser:
|
|
704
703
|
def __pt_status__(self) -> StatusBarFields:
|
705
704
|
"""Show the selected or hovered path in the statusbar."""
|
706
705
|
return self.control.__pt_status__()
|
707
|
-
|
708
|
-
# ################################### Settings ####################################
|
709
|
-
|
710
|
-
add_setting(
|
711
|
-
name="show_file_icons",
|
712
|
-
flags=["--show-file-icons"],
|
713
|
-
type_=bool,
|
714
|
-
title="File icons",
|
715
|
-
help_="Show file icons in the file manager",
|
716
|
-
default=False,
|
717
|
-
schema={
|
718
|
-
"type": "boolean",
|
719
|
-
},
|
720
|
-
description="""
|
721
|
-
Whether file icons should be shown in the file manager.
|
722
|
-
|
723
|
-
These icons exist in the unicode private use area, and may require custom
|
724
|
-
fonts such as ``awesome-terminal-fonts`` or ``nerdfonts`` to be installed.
|
725
|
-
""",
|
726
|
-
)
|
euporie/core/widgets/forms.py
CHANGED
@@ -8,7 +8,7 @@ from abc import ABCMeta, abstractmethod
|
|
8
8
|
from collections import deque
|
9
9
|
from functools import partial
|
10
10
|
from math import ceil, floor
|
11
|
-
from typing import TYPE_CHECKING,
|
11
|
+
from typing import TYPE_CHECKING, cast
|
12
12
|
from weakref import finalize
|
13
13
|
|
14
14
|
from prompt_toolkit.buffer import ValidationState
|
@@ -47,8 +47,8 @@ from prompt_toolkit.utils import Event
|
|
47
47
|
from prompt_toolkit.validation import Validator
|
48
48
|
from prompt_toolkit.widgets.base import TextArea
|
49
49
|
|
50
|
+
from euporie.core.app.current import get_app
|
50
51
|
from euporie.core.border import InsetGrid
|
51
|
-
from euporie.core.current import get_app
|
52
52
|
from euporie.core.data_structures import DiBool
|
53
53
|
from euporie.core.ft.utils import FormattedTextAlign, align
|
54
54
|
from euporie.core.margins import MarginContainer, ScrollbarMargin
|
@@ -56,7 +56,8 @@ from euporie.core.widgets.decor import Border, Shadow
|
|
56
56
|
from euporie.core.widgets.layout import Box, ConditionalSplit
|
57
57
|
|
58
58
|
if TYPE_CHECKING:
|
59
|
-
from
|
59
|
+
from collections.abc import Sequence
|
60
|
+
from typing import Any, Callable
|
60
61
|
|
61
62
|
from prompt_toolkit.buffer import Buffer, BufferAcceptHandler
|
62
63
|
from prompt_toolkit.completion.base import Completer
|
@@ -728,9 +729,11 @@ class Label:
|
|
728
729
|
value = self.value
|
729
730
|
data = value() if callable(value) else value
|
730
731
|
if self.html():
|
732
|
+
from prompt_toolkit.formatted_text.utils import to_plain_text
|
733
|
+
|
731
734
|
from euporie.core.ft.html import HTML
|
732
735
|
|
733
|
-
return HTML(data, collapse_root_margin=True, fill=False)
|
736
|
+
return HTML(to_plain_text(data), collapse_root_margin=True, fill=False)
|
734
737
|
return data
|
735
738
|
|
736
739
|
def __pt_container__(self) -> AnyContainer:
|
@@ -956,7 +959,7 @@ class Progress:
|
|
956
959
|
return self.container
|
957
960
|
|
958
961
|
|
959
|
-
class SizedMask(
|
962
|
+
class SizedMask(dict[int, bool]):
|
960
963
|
"""Mask with restricted number of True items."""
|
961
964
|
|
962
965
|
def __init__(self, size: int | None = None) -> None:
|
euporie/core/widgets/inputs.py
CHANGED
@@ -49,9 +49,8 @@ from prompt_toolkit.widgets import TextArea
|
|
49
49
|
from prompt_toolkit.widgets.toolbars import SearchToolbar
|
50
50
|
from pygments.lexers import ClassNotFound, get_lexer_by_name
|
51
51
|
|
52
|
+
from euporie.core.app.current import get_app
|
52
53
|
from euporie.core.commands import add_cmd
|
53
|
-
from euporie.core.config import add_setting
|
54
|
-
from euporie.core.current import get_app
|
55
54
|
from euporie.core.diagnostics import Report
|
56
55
|
from euporie.core.filters import buffer_is_code, scrollable
|
57
56
|
from euporie.core.key_binding.registry import (
|
@@ -71,10 +70,10 @@ from euporie.core.processors import (
|
|
71
70
|
ShowTrailingWhiteSpaceProcessor,
|
72
71
|
)
|
73
72
|
from euporie.core.suggest import ConditionalAutoSuggestAsync
|
74
|
-
from euporie.core.widgets.pager import PagerState
|
75
73
|
|
76
74
|
if TYPE_CHECKING:
|
77
|
-
from
|
75
|
+
from collections.abc import Sequence
|
76
|
+
from typing import Callable
|
78
77
|
|
79
78
|
from prompt_toolkit.buffer import BufferAcceptHandler
|
80
79
|
from prompt_toolkit.filters import Filter, FilterOrBool
|
@@ -89,10 +88,10 @@ if TYPE_CHECKING:
|
|
89
88
|
from prompt_toolkit.layout.margins import Margin
|
90
89
|
from prompt_toolkit.lexers.base import Lexer
|
91
90
|
|
91
|
+
from euporie.core.bars.status import StatusBarFields
|
92
92
|
from euporie.core.format import Formatter
|
93
93
|
from euporie.core.inspection import Inspector
|
94
|
-
from euporie.core.tabs.
|
95
|
-
from euporie.core.widgets.status import StatusBarFields
|
94
|
+
from euporie.core.tabs.kernel import KernelTab
|
96
95
|
|
97
96
|
|
98
97
|
log = logging.getLogger(__name__)
|
@@ -296,7 +295,7 @@ class KernelInput(TextArea):
|
|
296
295
|
diagnostics=_get_diagnostics,
|
297
296
|
show_diagnostics=to_filter(show_diagnostics),
|
298
297
|
),
|
299
|
-
app.config.
|
298
|
+
app.config.filters.line_numbers & self.buffer.multiline,
|
300
299
|
),
|
301
300
|
]
|
302
301
|
right_margins = [OverflowMargin()]
|
@@ -366,6 +365,8 @@ class KernelInput(TextArea):
|
|
366
365
|
|
367
366
|
async def inspect(self, auto: bool = False) -> None:
|
368
367
|
"""Get contextual help for the current cursor position in the current cell."""
|
368
|
+
from euporie.core.widgets.pager import PagerState
|
369
|
+
|
369
370
|
if self.inspector is None:
|
370
371
|
return
|
371
372
|
|
@@ -427,64 +428,6 @@ class KernelInput(TextArea):
|
|
427
428
|
"""Return the widget's container."""
|
428
429
|
return self.container
|
429
430
|
|
430
|
-
# ################################### Settings ####################################
|
431
|
-
|
432
|
-
add_setting(
|
433
|
-
name="line_numbers",
|
434
|
-
flags=["--line-numbers"],
|
435
|
-
type_=bool,
|
436
|
-
help_="Show or hide line numbers",
|
437
|
-
default=True,
|
438
|
-
description="""
|
439
|
-
Whether line numbers are shown by default.
|
440
|
-
""",
|
441
|
-
hooks=[lambda x: get_app().refresh()],
|
442
|
-
)
|
443
|
-
|
444
|
-
add_setting(
|
445
|
-
name="autoformat",
|
446
|
-
flags=["--autoformat"],
|
447
|
-
type_=bool,
|
448
|
-
help_="Automatically re-format code cells when run",
|
449
|
-
default=False,
|
450
|
-
description="""
|
451
|
-
Whether to automatically reformat code cells before they are run.
|
452
|
-
""",
|
453
|
-
)
|
454
|
-
|
455
|
-
add_setting(
|
456
|
-
name="autocomplete",
|
457
|
-
flags=["--autocomplete"],
|
458
|
-
type_=bool,
|
459
|
-
help_="Provide completions suggestions automatically",
|
460
|
-
default=False,
|
461
|
-
description="""
|
462
|
-
Whether to automatically suggestion completions while typing in code cells.
|
463
|
-
""",
|
464
|
-
)
|
465
|
-
|
466
|
-
add_setting(
|
467
|
-
name="autosuggest",
|
468
|
-
flags=["--autosuggest"],
|
469
|
-
type_=bool,
|
470
|
-
help_="Provide line completion suggestions",
|
471
|
-
default=True,
|
472
|
-
description="""
|
473
|
-
Whether to automatically suggestion line content while typing in code cells.
|
474
|
-
""",
|
475
|
-
)
|
476
|
-
|
477
|
-
add_setting(
|
478
|
-
name="autoinspect",
|
479
|
-
flags=["--autoinspect"],
|
480
|
-
type_=bool,
|
481
|
-
help_="Display contextual help automatically",
|
482
|
-
default=False,
|
483
|
-
description="""
|
484
|
-
Whether to automatically display contextual help when navigating through code cells.
|
485
|
-
""",
|
486
|
-
)
|
487
|
-
|
488
431
|
# ################################### Commands ####################################
|
489
432
|
|
490
433
|
@staticmethod
|
@@ -493,7 +436,7 @@ class KernelInput(TextArea):
|
|
493
436
|
)
|
494
437
|
async def _show_contextual_help() -> None:
|
495
438
|
"""Display contextual help."""
|
496
|
-
from euporie.core.tabs.
|
439
|
+
from euporie.core.tabs.kernel import KernelTab
|
497
440
|
|
498
441
|
tab = get_app().tab
|
499
442
|
if isinstance(tab, KernelTab) and (input_box := tab.current_input) is not None:
|
@@ -503,7 +446,7 @@ class KernelInput(TextArea):
|
|
503
446
|
@add_cmd(filter=buffer_is_code & buffer_has_focus)
|
504
447
|
def _history_prev() -> None:
|
505
448
|
"""Get the previous history entry."""
|
506
|
-
from euporie.core.app import get_app
|
449
|
+
from euporie.core.app.current import get_app
|
507
450
|
|
508
451
|
get_app().current_buffer.history_backward()
|
509
452
|
|
@@ -511,7 +454,7 @@ class KernelInput(TextArea):
|
|
511
454
|
@add_cmd(filter=buffer_is_code & buffer_has_focus)
|
512
455
|
def _history_next() -> None:
|
513
456
|
"""Get the next history entry."""
|
514
|
-
from euporie.core.app import get_app
|
457
|
+
from euporie.core.app.current import get_app
|
515
458
|
|
516
459
|
get_app().current_buffer.history_forward()
|
517
460
|
|
@@ -519,8 +462,8 @@ class KernelInput(TextArea):
|
|
519
462
|
@add_cmd()
|
520
463
|
def _reformat_input() -> None:
|
521
464
|
"""Format the contents of the current input field."""
|
522
|
-
from euporie.core.app import get_app
|
523
|
-
from euporie.core.tabs.
|
465
|
+
from euporie.core.app.current import get_app
|
466
|
+
from euporie.core.tabs.kernel import KernelTab
|
524
467
|
|
525
468
|
if (
|
526
469
|
(tab := get_app().tab)
|
euporie/core/widgets/layout.py
CHANGED
@@ -35,7 +35,8 @@ from euporie.core.layout.containers import HSplit, VSplit, Window
|
|
35
35
|
from euporie.core.widgets.decor import Border
|
36
36
|
|
37
37
|
if TYPE_CHECKING:
|
38
|
-
from
|
38
|
+
from collections.abc import Sequence
|
39
|
+
from typing import Any, Callable
|
39
40
|
|
40
41
|
from prompt_toolkit.filters import FilterOrBool
|
41
42
|
from prompt_toolkit.formatted_text.base import AnyFormattedText, StyleAndTextTuples
|
@@ -0,0 +1,49 @@
|
|
1
|
+
"""Defines a logo widget."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
from typing import TYPE_CHECKING, Callable
|
6
|
+
|
7
|
+
from prompt_toolkit.layout.containers import WindowAlign
|
8
|
+
from prompt_toolkit.layout.controls import FormattedTextControl
|
9
|
+
|
10
|
+
from euporie.core import __logo__
|
11
|
+
from euporie.core.filters import has_tabs
|
12
|
+
from euporie.core.layout.containers import Window
|
13
|
+
|
14
|
+
if TYPE_CHECKING:
|
15
|
+
from typing import Any
|
16
|
+
|
17
|
+
from prompt_toolkit.filters import FilterOrBool
|
18
|
+
from prompt_toolkit.layout.controls import UIControl
|
19
|
+
from prompt_toolkit.layout.dimension import AnyDimension
|
20
|
+
|
21
|
+
|
22
|
+
class Logo(Window):
|
23
|
+
"""A widget to display the application's logo."""
|
24
|
+
|
25
|
+
def __init__(
|
26
|
+
self,
|
27
|
+
content: UIControl | None = None,
|
28
|
+
height: AnyDimension = 1,
|
29
|
+
width: AnyDimension = 3,
|
30
|
+
style: str | Callable[[], str] = "class:menu,logo",
|
31
|
+
dont_extend_width: FilterOrBool = True,
|
32
|
+
align: WindowAlign | Callable[[], WindowAlign] = WindowAlign.CENTER,
|
33
|
+
**kwargs: Any,
|
34
|
+
) -> None:
|
35
|
+
"""Create a new window with defaults specified."""
|
36
|
+
if content is None:
|
37
|
+
content = FormattedTextControl(
|
38
|
+
[("", f" {__logo__} ")],
|
39
|
+
focusable=~has_tabs,
|
40
|
+
show_cursor=False,
|
41
|
+
)
|
42
|
+
super().__init__(
|
43
|
+
content=content,
|
44
|
+
height=height,
|
45
|
+
width=width,
|
46
|
+
style=style,
|
47
|
+
dont_extend_width=dont_extend_width,
|
48
|
+
**kwargs,
|
49
|
+
)
|
euporie/core/widgets/menu.py
CHANGED
@@ -37,14 +37,15 @@ from prompt_toolkit.layout.utils import explode_text_fragments
|
|
37
37
|
from prompt_toolkit.mouse_events import MouseEvent, MouseEventType
|
38
38
|
from prompt_toolkit.utils import get_cwidth
|
39
39
|
|
40
|
+
from euporie.core.app.current import get_app
|
41
|
+
from euporie.core.bars.status import StatusContainer
|
40
42
|
from euporie.core.border import OuterHalfGrid
|
41
|
-
from euporie.core.current import get_app
|
42
43
|
from euporie.core.layout.containers import HSplit, VSplit, Window
|
43
44
|
from euporie.core.widgets.decor import Shadow
|
44
|
-
from euporie.core.widgets.status import StatusContainer
|
45
45
|
|
46
46
|
if TYPE_CHECKING:
|
47
|
-
from
|
47
|
+
from collections.abc import Iterable, Sequence
|
48
|
+
from typing import Any, Callable
|
48
49
|
|
49
50
|
from prompt_toolkit.filters import Filter, FilterOrBool
|
50
51
|
from prompt_toolkit.formatted_text.base import (
|
@@ -57,10 +58,10 @@ if TYPE_CHECKING:
|
|
57
58
|
from prompt_toolkit.layout.containers import AnyContainer
|
58
59
|
from prompt_toolkit.layout.controls import UIControl
|
59
60
|
|
60
|
-
from euporie.core.app import BaseApp
|
61
|
+
from euporie.core.app.app import BaseApp
|
62
|
+
from euporie.core.bars.status import StatusBarFields
|
61
63
|
from euporie.core.border import GridStyle
|
62
64
|
from euporie.core.commands import Command
|
63
|
-
from euporie.core.widgets.status import StatusBarFields
|
64
65
|
|
65
66
|
|
66
67
|
log = logging.getLogger(__name__)
|
@@ -149,7 +150,7 @@ class MenuItem:
|
|
149
150
|
"""Create a menu item from a command."""
|
150
151
|
return cls(
|
151
152
|
formatted_text=command.menu_title,
|
152
|
-
handler=command.
|
153
|
+
handler=command.run,
|
153
154
|
shortcut=command.key_str,
|
154
155
|
disabled=~command.filter,
|
155
156
|
hidden=command.hidden,
|
@@ -326,7 +327,6 @@ class MenuBar:
|
|
326
327
|
def _cancel(event: KeyPressEvent) -> None:
|
327
328
|
"""Leave menu."""
|
328
329
|
self.selected_menu = []
|
329
|
-
log.debug(self.last_focused)
|
330
330
|
self.refocus()
|
331
331
|
|
332
332
|
# Sub menu navigation.
|
@@ -521,7 +521,9 @@ class MenuBar:
|
|
521
521
|
def mouse_handler(index: int, mouse_event: MouseEvent) -> NotImplementedOrNone:
|
522
522
|
focused = self.focused()
|
523
523
|
hover = mouse_event.event_type == MouseEventType.MOUSE_MOVE
|
524
|
-
if mouse_event.event_type == MouseEventType.MOUSE_DOWN or
|
524
|
+
if mouse_event.event_type == MouseEventType.MOUSE_DOWN or (
|
525
|
+
hover and focused
|
526
|
+
):
|
525
527
|
# Toggle focus.
|
526
528
|
if not hover and focused and self.selected_menu == [index]:
|
527
529
|
self.selected_menu = []
|