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/utils.py
CHANGED
@@ -2,15 +2,17 @@
|
|
2
2
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
|
-
import
|
5
|
+
from collections.abc import Sequence
|
6
|
+
from functools import cache
|
6
7
|
from itertools import chain
|
7
|
-
from
|
8
|
-
from typing import TYPE_CHECKING, Sequence, TypeVar, overload
|
8
|
+
from typing import TYPE_CHECKING, TypeVar, overload
|
9
9
|
|
10
10
|
from prompt_toolkit.mouse_events import MouseButton, MouseEventType
|
11
11
|
|
12
12
|
if TYPE_CHECKING:
|
13
|
-
from
|
13
|
+
from collections.abc import Iterable
|
14
|
+
from types import ModuleType
|
15
|
+
from typing import Callable
|
14
16
|
|
15
17
|
from prompt_toolkit.key_binding.key_bindings import NotImplementedOrNone
|
16
18
|
from prompt_toolkit.layout.mouse_handlers import MouseHandler
|
@@ -74,16 +76,91 @@ def on_click(func: Callable) -> MouseHandler:
|
|
74
76
|
return _mouse_handler
|
75
77
|
|
76
78
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
"""Run a function in an thread, but make sure it uses the same contextvars.
|
79
|
+
@cache
|
80
|
+
def root_module(name: str) -> ModuleType:
|
81
|
+
"""Find and load the root module of a given module name by traversing up the module hierarchy.
|
81
82
|
|
82
|
-
This
|
83
|
+
This function walks up the module hierarchy until it finds the topmost parent module
|
84
|
+
that has a valid location. It uses Python's importlib machinery to inspect module
|
85
|
+
specifications and load modules.
|
86
|
+
|
87
|
+
Args:
|
88
|
+
name: The name of the module to find the root for (e.g., 'package.subpackage.module')
|
89
|
+
|
90
|
+
Returns:
|
91
|
+
The loaded root module object
|
92
|
+
|
93
|
+
Example:
|
94
|
+
>>> root = root_module("django.contrib.admin")
|
95
|
+
>>> print(root.__name__)
|
96
|
+
'django'
|
97
|
+
|
98
|
+
Note:
|
99
|
+
The function is cached using lru_cache to improve performance for repeated lookups.
|
100
|
+
The function handles both regular packages and frozen modules.
|
101
|
+
"""
|
102
|
+
from importlib.util import find_spec, module_from_spec
|
103
|
+
|
104
|
+
if spec := find_spec(name):
|
105
|
+
while True:
|
106
|
+
if spec.name == spec.parent:
|
107
|
+
try:
|
108
|
+
parent = find_spec("..", spec.parent)
|
109
|
+
except ImportError:
|
110
|
+
break
|
111
|
+
elif spec.parent is not None:
|
112
|
+
parent = find_spec(spec.parent)
|
113
|
+
if (spec and not spec.parent) or (parent and not parent.has_location):
|
114
|
+
break
|
115
|
+
if parent:
|
116
|
+
spec = parent
|
117
|
+
if spec.loader:
|
118
|
+
module = module_from_spec(spec)
|
119
|
+
spec.loader.exec_module(module)
|
120
|
+
return module
|
121
|
+
raise ModuleNotFoundError(name=name)
|
122
|
+
|
123
|
+
|
124
|
+
@cache
|
125
|
+
def import_submodules(root: ModuleType, names: tuple[str]) -> list[ModuleType]:
|
126
|
+
"""Import all submodules with a specific name within a root module's package hierarchy.
|
127
|
+
|
128
|
+
This function walks through all packages under the given root module and imports
|
129
|
+
any submodules that match the specified name. It handles various module types
|
130
|
+
including regular packages, single file modules, and frozen modules.
|
131
|
+
|
132
|
+
Args:
|
133
|
+
root: The root module object to search within
|
134
|
+
names: The specific submodule name to search for
|
135
|
+
|
136
|
+
Returns:
|
137
|
+
A list of imported module objects matching the specified name
|
138
|
+
|
139
|
+
Example:
|
140
|
+
>>> root = import_module("django")
|
141
|
+
>>> admin_modules = import_submodules(root, "admin")
|
142
|
+
>>> print([m.__name__ for m in admin_modules])
|
143
|
+
['django.contrib.admin', 'django.contrib.gis.admin']
|
144
|
+
|
145
|
+
Note:
|
146
|
+
- The function is cached using lru_cache to improve performance for repeated imports
|
147
|
+
- For packages, it searches through __path__
|
148
|
+
- For single file modules, it uses __file__
|
149
|
+
- For frozen modules, it uses the module specification's origin
|
83
150
|
"""
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
151
|
+
from importlib import import_module
|
152
|
+
from pkgutil import walk_packages
|
153
|
+
|
154
|
+
if hasattr(root, "__path__"):
|
155
|
+
path = root.__path__
|
156
|
+
elif hasattr(root, "__file__"):
|
157
|
+
path = [root.__file__] if root.__file__ else []
|
158
|
+
else:
|
159
|
+
# For frozen modules, we need to create a special path
|
160
|
+
spec = root.__spec__
|
161
|
+
path = [spec.origin] if spec and spec.origin else []
|
162
|
+
return [
|
163
|
+
import_module(module_name)
|
164
|
+
for _loader, module_name, _is_pkg in walk_packages(path, f"{root.__name__}.")
|
165
|
+
if module_name.rpartition(".")[2] in names
|
166
|
+
]
|
euporie/core/validation.py
CHANGED
@@ -9,7 +9,7 @@ from prompt_toolkit.validation import ValidationError, Validator
|
|
9
9
|
if TYPE_CHECKING:
|
10
10
|
from prompt_toolkit.document import Document
|
11
11
|
|
12
|
-
from euporie.core.kernel import Kernel
|
12
|
+
from euporie.core.kernel.client import Kernel
|
13
13
|
|
14
14
|
|
15
15
|
class KernelValidator(Validator):
|
@@ -0,0 +1,188 @@
|
|
1
|
+
"""Defines widget settings."""
|
2
|
+
|
3
|
+
from prompt_toolkit.filters import buffer_has_focus
|
4
|
+
|
5
|
+
from euporie.core.app.current import get_app
|
6
|
+
from euporie.core.config import add_setting
|
7
|
+
|
8
|
+
# euporie.core.widgets.cell_outputs:CellOutputArea
|
9
|
+
|
10
|
+
add_setting(
|
11
|
+
name="wrap_cell_outputs",
|
12
|
+
group="euporie.core.widgets.cell_outputs",
|
13
|
+
title="wrap cell outputs",
|
14
|
+
flags=["--wrap-cell-outputs"],
|
15
|
+
type_=bool,
|
16
|
+
help_="Wrap cell output text.",
|
17
|
+
default=False,
|
18
|
+
schema={"type": "boolean"},
|
19
|
+
description="""
|
20
|
+
Whether text-based cell outputs should be wrapped.
|
21
|
+
""",
|
22
|
+
cmd_filter=~buffer_has_focus,
|
23
|
+
)
|
24
|
+
|
25
|
+
# euporie,core.widgets.file_browser:FileBrowser
|
26
|
+
|
27
|
+
add_setting(
|
28
|
+
name="show_file_icons",
|
29
|
+
group="euporie.core.widgets.file_browser",
|
30
|
+
flags=["--show-file-icons"],
|
31
|
+
type_=bool,
|
32
|
+
title="File icons",
|
33
|
+
help_="Show file icons in the file manager",
|
34
|
+
default=False,
|
35
|
+
schema={
|
36
|
+
"type": "boolean",
|
37
|
+
},
|
38
|
+
description="""
|
39
|
+
Whether file icons should be shown in the file manager.
|
40
|
+
|
41
|
+
These icons exist in the unicode private use area, and may require custom
|
42
|
+
fonts such as ``awesome-terminal-fonts`` or ``nerdfonts`` to be installed.
|
43
|
+
""",
|
44
|
+
)
|
45
|
+
|
46
|
+
# euporie.core.widgets.inputs:KernelInput
|
47
|
+
|
48
|
+
add_setting(
|
49
|
+
name="line_numbers",
|
50
|
+
group="euporie.core.widgets.inputs",
|
51
|
+
flags=["--line-numbers"],
|
52
|
+
type_=bool,
|
53
|
+
help_="Show or hide line numbers",
|
54
|
+
default=True,
|
55
|
+
description="""
|
56
|
+
Whether line numbers are shown by default.
|
57
|
+
""",
|
58
|
+
hooks=[lambda x: get_app().refresh()],
|
59
|
+
)
|
60
|
+
|
61
|
+
add_setting(
|
62
|
+
name="autoformat",
|
63
|
+
group="euporie.core.widgets.inputs",
|
64
|
+
flags=["--autoformat"],
|
65
|
+
type_=bool,
|
66
|
+
help_="Automatically re-format code cells when run",
|
67
|
+
default=False,
|
68
|
+
description="""
|
69
|
+
Whether to automatically reformat code cells before they are run.
|
70
|
+
""",
|
71
|
+
)
|
72
|
+
|
73
|
+
add_setting(
|
74
|
+
name="autocomplete",
|
75
|
+
group="euporie.core.widgets.inputs",
|
76
|
+
flags=["--autocomplete"],
|
77
|
+
type_=bool,
|
78
|
+
help_="Provide completions suggestions automatically",
|
79
|
+
default=False,
|
80
|
+
description="""
|
81
|
+
Whether to automatically suggestion completions while typing in code cells.
|
82
|
+
""",
|
83
|
+
)
|
84
|
+
|
85
|
+
add_setting(
|
86
|
+
name="autosuggest",
|
87
|
+
group="euporie.core.widgets.inputs",
|
88
|
+
flags=["--autosuggest"],
|
89
|
+
type_=bool,
|
90
|
+
help_="Provide line completion suggestions",
|
91
|
+
default=True,
|
92
|
+
description="""
|
93
|
+
Whether to automatically suggestion line content while typing in code cells.
|
94
|
+
""",
|
95
|
+
)
|
96
|
+
|
97
|
+
add_setting(
|
98
|
+
name="autoinspect",
|
99
|
+
group="euporie.core.widgets.inputs",
|
100
|
+
flags=["--autoinspect"],
|
101
|
+
type_=bool,
|
102
|
+
help_="Display contextual help automatically",
|
103
|
+
default=False,
|
104
|
+
description="""
|
105
|
+
Whether to automatically display contextual help when navigating through code cells.
|
106
|
+
""",
|
107
|
+
)
|
108
|
+
|
109
|
+
|
110
|
+
# euporie.core.bars.status:StatusBar
|
111
|
+
|
112
|
+
add_setting(
|
113
|
+
name="show_status_bar",
|
114
|
+
group="euporie.core.bars.status",
|
115
|
+
flags=["--show-status-bar"],
|
116
|
+
type_=bool,
|
117
|
+
title="status bar",
|
118
|
+
help_="Show the status bar",
|
119
|
+
default=True,
|
120
|
+
schema={
|
121
|
+
"type": "boolean",
|
122
|
+
},
|
123
|
+
description="""
|
124
|
+
Whether the status bar should be shown at the bottom of the screen.
|
125
|
+
""",
|
126
|
+
)
|
127
|
+
|
128
|
+
# euporie.core.widgets.decor:
|
129
|
+
|
130
|
+
add_setting(
|
131
|
+
name="show_shadows",
|
132
|
+
group="euporie.core.widgets.decor",
|
133
|
+
flags=["--show-shadows"],
|
134
|
+
type_=bool,
|
135
|
+
help_="Show or hide shadows under menus and dialogs",
|
136
|
+
default=True,
|
137
|
+
description="""
|
138
|
+
Sets whether shadows are shown under dialogs and popup-menus.
|
139
|
+
""",
|
140
|
+
)
|
141
|
+
|
142
|
+
# euporie.core.widgets.cell
|
143
|
+
|
144
|
+
add_setting(
|
145
|
+
name="show_cell_borders",
|
146
|
+
group="euporie.core.widgets.cell",
|
147
|
+
title="cell borders",
|
148
|
+
flags=["--show-cell-borders"],
|
149
|
+
type_=bool,
|
150
|
+
help_="Show or hide cell borders.",
|
151
|
+
default=False,
|
152
|
+
schema={
|
153
|
+
"type": "boolean",
|
154
|
+
},
|
155
|
+
description="""
|
156
|
+
Whether cell borders should be drawn for unselected cells.
|
157
|
+
""",
|
158
|
+
)
|
159
|
+
|
160
|
+
add_setting(
|
161
|
+
name="external_editor",
|
162
|
+
group="euporie.core.widgets.cell",
|
163
|
+
flags=["--external-editor"],
|
164
|
+
type_=str,
|
165
|
+
help_="Set the external editor to use.",
|
166
|
+
default=None,
|
167
|
+
description="""
|
168
|
+
A command to run when editing cells externally. The following strings in
|
169
|
+
the command will be replaced with values which locate the cell being
|
170
|
+
edited:
|
171
|
+
|
172
|
+
* ``{top}``
|
173
|
+
* ``{left}``
|
174
|
+
* ``{bottom}``
|
175
|
+
* ``{right}``
|
176
|
+
* ``{width}``
|
177
|
+
* ``{height}``
|
178
|
+
|
179
|
+
This is useful if you run euporie inside a tmux session, and wish to launch
|
180
|
+
your editor in a pop-up pane. This can be achieved by setting this parameter
|
181
|
+
to something like the following:
|
182
|
+
|
183
|
+
.. code-block::
|
184
|
+
|
185
|
+
"tmux display-popup -x {left} -y {bottom} -w {width} -h {height} -B -E micro"
|
186
|
+
|
187
|
+
""",
|
188
|
+
)
|
euporie/core/widgets/cell.py
CHANGED
@@ -27,10 +27,9 @@ from prompt_toolkit.layout.controls import FormattedTextControl
|
|
27
27
|
from prompt_toolkit.layout.dimension import Dimension
|
28
28
|
from prompt_toolkit.utils import Event
|
29
29
|
|
30
|
+
from euporie.core.app.current import get_app
|
30
31
|
from euporie.core.border import NoLine, ThickLine, ThinLine
|
31
32
|
from euporie.core.completion import DeduplicateCompleter, LspCompleter
|
32
|
-
from euporie.core.config import add_setting
|
33
|
-
from euporie.core.current import get_app
|
34
33
|
from euporie.core.diagnostics import Report
|
35
34
|
from euporie.core.filters import multiple_cells_selected
|
36
35
|
from euporie.core.format import LspFormatter
|
@@ -173,7 +172,7 @@ class Cell:
|
|
173
172
|
# Now we generate the main container used to represent a kernel_tab cell
|
174
173
|
|
175
174
|
source_hidden = Condition(
|
176
|
-
lambda: weak_self.json
|
175
|
+
lambda: weak_self.json.get("metadata", {})
|
177
176
|
.get("jupyter", {})
|
178
177
|
.get("source_hidden", False)
|
179
178
|
)
|
@@ -219,6 +218,23 @@ class Cell:
|
|
219
218
|
|
220
219
|
return _inner
|
221
220
|
|
221
|
+
# @lru_cache(maxsize=None)
|
222
|
+
# def _cell_border_char(
|
223
|
+
# name: str,
|
224
|
+
# show_cell_borders: bool,
|
225
|
+
# focused: bool,
|
226
|
+
# selected: bool,
|
227
|
+
# multiple_cells_selected: bool,
|
228
|
+
# ) -> str:
|
229
|
+
# if show_cell_borders or selected:
|
230
|
+
# if focused and multiple_cells_selected:
|
231
|
+
# grid = ThickLine.outer
|
232
|
+
# else:
|
233
|
+
# grid = ThinLine.outer
|
234
|
+
# else:
|
235
|
+
# grid = NoLine.grid
|
236
|
+
# return getattr(grid, name.upper())
|
237
|
+
|
222
238
|
self.control = Window(
|
223
239
|
FormattedTextControl(
|
224
240
|
border_char("TOP_LEFT"),
|
@@ -565,7 +581,6 @@ class Cell:
|
|
565
581
|
"""Determine the current cell type."""
|
566
582
|
return self.json.get("cell_type", "code")
|
567
583
|
|
568
|
-
@property
|
569
584
|
def suffix(self) -> str:
|
570
585
|
"""Return the file suffix matching the current cell type."""
|
571
586
|
cell_type = self.cell_type
|
@@ -910,49 +925,3 @@ class Cell:
|
|
910
925
|
def close(self) -> None:
|
911
926
|
"""Signal that the cell is no longer present in the notebook."""
|
912
927
|
self.on_close()
|
913
|
-
|
914
|
-
# ################################### Settings ####################################
|
915
|
-
|
916
|
-
add_setting(
|
917
|
-
name="show_cell_borders",
|
918
|
-
title="cell borders",
|
919
|
-
flags=["--show-cell-borders"],
|
920
|
-
type_=bool,
|
921
|
-
help_="Show or hide cell borders.",
|
922
|
-
default=False,
|
923
|
-
schema={
|
924
|
-
"type": "boolean",
|
925
|
-
},
|
926
|
-
description="""
|
927
|
-
Whether cell borders should be drawn for unselected cells.
|
928
|
-
""",
|
929
|
-
)
|
930
|
-
|
931
|
-
add_setting(
|
932
|
-
name="external_editor",
|
933
|
-
flags=["--external-editor"],
|
934
|
-
type_=str,
|
935
|
-
help_="Set the external editor to use.",
|
936
|
-
default=None,
|
937
|
-
description="""
|
938
|
-
A command to run when editing cells externally. The following strings in
|
939
|
-
the command will be replaced with values which locate the cell being
|
940
|
-
edited:
|
941
|
-
|
942
|
-
* ``{top}``
|
943
|
-
* ``{left}``
|
944
|
-
* ``{bottom}``
|
945
|
-
* ``{right}``
|
946
|
-
* ``{width}``
|
947
|
-
* ``{height}``
|
948
|
-
|
949
|
-
This is useful if you run euporie inside a tmux session, and wish to launch
|
950
|
-
your editor in a pop-up pane. This can be achieved by setting this parameter
|
951
|
-
to something like the following:
|
952
|
-
|
953
|
-
.. code-block::
|
954
|
-
|
955
|
-
"tmux display-popup -x {left} -y {bottom} -w {width} -h {height} -B -E micro"
|
956
|
-
|
957
|
-
""",
|
958
|
-
)
|
@@ -4,22 +4,18 @@ from __future__ import annotations
|
|
4
4
|
|
5
5
|
import logging
|
6
6
|
from abc import ABCMeta, abstractmethod
|
7
|
+
from functools import cache
|
7
8
|
from pathlib import PurePath
|
8
9
|
from typing import TYPE_CHECKING
|
9
10
|
|
10
11
|
from prompt_toolkit.cache import SimpleCache
|
11
|
-
from prompt_toolkit.filters import buffer_has_focus
|
12
12
|
from prompt_toolkit.layout.containers import (
|
13
13
|
DynamicContainer,
|
14
14
|
to_container,
|
15
15
|
)
|
16
16
|
|
17
|
-
from euporie.core.
|
18
|
-
from euporie.core.convert.datum import Datum
|
19
|
-
from euporie.core.convert.formats import BASE64_FORMATS
|
20
|
-
from euporie.core.convert.mime import MIME_FORMATS
|
17
|
+
from euporie.core.app.current import get_app
|
21
18
|
from euporie.core.convert.registry import find_route
|
22
|
-
from euporie.core.current import get_app
|
23
19
|
from euporie.core.layout.containers import HSplit
|
24
20
|
from euporie.core.widgets.display import Display
|
25
21
|
from euporie.core.widgets.layout import Box
|
@@ -30,7 +26,7 @@ if TYPE_CHECKING:
|
|
30
26
|
|
31
27
|
from prompt_toolkit.layout.containers import AnyContainer
|
32
28
|
|
33
|
-
from euporie.core.
|
29
|
+
from euporie.core.tabs.kernel import KernelTab
|
34
30
|
|
35
31
|
KTParent = TypeVar("KTParent", bound=KernelTab)
|
36
32
|
|
@@ -98,6 +94,10 @@ class CellOutputDataElement(CellOutputElement):
|
|
98
94
|
metadata: Any metadata relating to the data
|
99
95
|
parent: The cell the output-element is attached to
|
100
96
|
"""
|
97
|
+
from euporie.core.convert.datum import Datum
|
98
|
+
from euporie.core.convert.formats import BASE64_FORMATS
|
99
|
+
from euporie.core.convert.mime import MIME_FORMATS
|
100
|
+
|
101
101
|
self.parent = parent
|
102
102
|
|
103
103
|
# Get foreground and background colors
|
@@ -129,16 +129,14 @@ class CellOutputDataElement(CellOutputElement):
|
|
129
129
|
self._datum,
|
130
130
|
focusable=False,
|
131
131
|
focus_on_click=False,
|
132
|
-
wrap_lines=config.
|
132
|
+
wrap_lines=config.filters.wrap_cell_outputs,
|
133
133
|
always_hide_cursor=True,
|
134
|
-
style=f"class:mime-{mime.replace('/','-')}",
|
134
|
+
style=f"class:mime-{mime.replace('/', '-')}",
|
135
135
|
scrollbar=False,
|
136
136
|
)
|
137
137
|
|
138
138
|
# Ensure container gets invalidated if `wrap_cell_output` changes
|
139
|
-
self.container.control.invalidate_events.append(
|
140
|
-
config.settings["wrap_cell_outputs"].event
|
141
|
-
)
|
139
|
+
self.container.control.invalidate_events.append(config.events.wrap_cell_outputs)
|
142
140
|
|
143
141
|
@property
|
144
142
|
def data(self) -> Any:
|
@@ -148,6 +146,8 @@ class CellOutputDataElement(CellOutputElement):
|
|
148
146
|
@data.setter
|
149
147
|
def data(self, value: Any) -> None:
|
150
148
|
"""Set the cell output's data."""
|
149
|
+
from euporie.core.convert.datum import Datum
|
150
|
+
|
151
151
|
self._datum = Datum(
|
152
152
|
value,
|
153
153
|
self._datum.format,
|
@@ -260,12 +260,12 @@ MIME_ORDER = [
|
|
260
260
|
]
|
261
261
|
|
262
262
|
|
263
|
-
|
263
|
+
@cache
|
264
|
+
def _calculate_mime_rank(mime: str, have_escapes: bool) -> int:
|
264
265
|
"""Score the richness of mime output types."""
|
265
|
-
mime, data = mime_data
|
266
266
|
for i, ranked_mime in enumerate(MIME_ORDER):
|
267
267
|
# Uprank plain text with escape sequences
|
268
|
-
if mime == "text/plain" and
|
268
|
+
if mime == "text/plain" and have_escapes:
|
269
269
|
i -= 7
|
270
270
|
if PurePath(mime).match(ranked_mime):
|
271
271
|
return i
|
@@ -273,6 +273,12 @@ def _calculate_mime_rank(mime_data: tuple[str, Any]) -> int:
|
|
273
273
|
return 999
|
274
274
|
|
275
275
|
|
276
|
+
def _mime_ranker(mime_data: tuple[str, Any]) -> int:
|
277
|
+
"""Score the richness of mime output types."""
|
278
|
+
mime, data = mime_data
|
279
|
+
return _calculate_mime_rank(mime, isinstance(data, str) and "\x1b[" in data)
|
280
|
+
|
281
|
+
|
276
282
|
class CellOutput:
|
277
283
|
"""Represent a single cell output.
|
278
284
|
|
@@ -319,7 +325,7 @@ class CellOutput:
|
|
319
325
|
data = {}
|
320
326
|
output_type = self.json.get("output_type", "unknown")
|
321
327
|
if output_type == "stream":
|
322
|
-
data = {f
|
328
|
+
data = {f"stream/{self.json.get('name')}": self.json.get("text", "")}
|
323
329
|
elif output_type == "error":
|
324
330
|
ename = self.json.get("ename", "")
|
325
331
|
evalue = self.json.get("evalue", "")
|
@@ -327,7 +333,7 @@ class CellOutput:
|
|
327
333
|
data = {"text/x-python-traceback": f"{ename}: {evalue}\n{traceback}"}
|
328
334
|
else:
|
329
335
|
data = self.json.get("data", {"text/plain": ""})
|
330
|
-
return dict(sorted(data.items(), key=
|
336
|
+
return dict(sorted(data.items(), key=_mime_ranker))
|
331
337
|
|
332
338
|
def update(self) -> None:
|
333
339
|
"""Update the output by updating all child containers."""
|
@@ -372,9 +378,8 @@ class CellOutput:
|
|
372
378
|
if mime not in self._elements:
|
373
379
|
element = self.make_element(mime)
|
374
380
|
self._elements[mime] = element
|
375
|
-
|
376
|
-
|
377
|
-
return element
|
381
|
+
return element
|
382
|
+
return self._elements[mime]
|
378
383
|
|
379
384
|
@property
|
380
385
|
def element(self) -> CellOutputElement:
|
@@ -511,19 +516,3 @@ class CellOutputArea:
|
|
511
516
|
):
|
512
517
|
outputs.append(to_plain_text(line))
|
513
518
|
return "\n".join(outputs)
|
514
|
-
|
515
|
-
# ################################### Settings ####################################
|
516
|
-
|
517
|
-
add_setting(
|
518
|
-
name="wrap_cell_outputs",
|
519
|
-
title="wrap cell outputs",
|
520
|
-
flags=["--wrap-cell-outputs"],
|
521
|
-
type_=bool,
|
522
|
-
help_="Wrap cell output text.",
|
523
|
-
default=False,
|
524
|
-
schema={"type": "boolean"},
|
525
|
-
description="""
|
526
|
-
Whether text-based cell outputs should be wrapped.
|
527
|
-
""",
|
528
|
-
cmd_filter=~buffer_has_focus,
|
529
|
-
)
|
euporie/core/widgets/decor.py
CHANGED
@@ -9,15 +9,12 @@ from prompt_toolkit.filters import to_filter
|
|
9
9
|
from prompt_toolkit.layout.containers import (
|
10
10
|
ConditionalContainer,
|
11
11
|
DynamicContainer,
|
12
|
-
Float,
|
13
|
-
FloatContainer,
|
14
12
|
)
|
15
13
|
|
14
|
+
from euporie.core.app.current import get_app
|
16
15
|
from euporie.core.border import ThinLine
|
17
|
-
from euporie.core.config import add_setting
|
18
|
-
from euporie.core.current import get_app
|
19
16
|
from euporie.core.data_structures import DiBool
|
20
|
-
from euporie.core.layout.containers import HSplit, VSplit, Window
|
17
|
+
from euporie.core.layout.containers import DummyContainer, HSplit, VSplit, Window
|
21
18
|
from euporie.core.layout.decor import DropShadow
|
22
19
|
|
23
20
|
if TYPE_CHECKING:
|
@@ -183,8 +180,7 @@ class Border:
|
|
183
180
|
class Shadow:
|
184
181
|
"""Draw a shadow underneath/behind this container.
|
185
182
|
|
186
|
-
|
187
|
-
:py:class:`prompt_toolkit.widows.base.Shadow` class.
|
183
|
+
The container must be in a float.
|
188
184
|
"""
|
189
185
|
|
190
186
|
def __init__(self, body: AnyContainer) -> None:
|
@@ -193,27 +189,14 @@ class Shadow:
|
|
193
189
|
Args:
|
194
190
|
body: Another container object.
|
195
191
|
"""
|
196
|
-
filter_ = get_app().config.
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
right=0,
|
205
|
-
transparent=True,
|
206
|
-
content=DropShadow(),
|
207
|
-
),
|
208
|
-
Float(
|
209
|
-
bottom=-1,
|
210
|
-
top=1,
|
211
|
-
width=1,
|
212
|
-
right=-1,
|
213
|
-
transparent=True,
|
214
|
-
content=DropShadow(),
|
215
|
-
),
|
216
|
-
],
|
192
|
+
filter_ = get_app().config.filters.show_shadows
|
193
|
+
|
194
|
+
spacer = DummyContainer(width=1, height=1)
|
195
|
+
shadow = VSplit(
|
196
|
+
[
|
197
|
+
HSplit([body, VSplit([spacer, DropShadow()])]),
|
198
|
+
HSplit([spacer, DropShadow()]),
|
199
|
+
]
|
217
200
|
)
|
218
201
|
|
219
202
|
def get_contents() -> AnyContainer:
|
@@ -227,16 +210,3 @@ class Shadow:
|
|
227
210
|
def __pt_container__(self) -> AnyContainer:
|
228
211
|
"""Return the container's content."""
|
229
212
|
return self.container
|
230
|
-
|
231
|
-
# ################################### Settings ####################################
|
232
|
-
|
233
|
-
add_setting(
|
234
|
-
name="show_shadows",
|
235
|
-
flags=["--show-shadows"],
|
236
|
-
type_=bool,
|
237
|
-
help_="Show or hide shadows under menus and dialogs",
|
238
|
-
default=True,
|
239
|
-
description="""
|
240
|
-
Sets whether shadows are shown under dialogs and popup-menus.
|
241
|
-
""",
|
242
|
-
)
|