euporie 2.8.6__py3-none-any.whl → 2.8.8__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/app.py +2 -0
- euporie/console/tabs/console.py +27 -17
- euporie/core/__init__.py +2 -2
- euporie/core/app/_commands.py +4 -21
- euporie/core/app/app.py +13 -7
- euporie/core/bars/command.py +9 -6
- euporie/core/bars/search.py +43 -2
- euporie/core/border.py +7 -2
- euporie/core/comm/base.py +2 -2
- euporie/core/comm/ipywidgets.py +3 -3
- euporie/core/commands.py +44 -8
- euporie/core/completion.py +14 -6
- euporie/core/convert/datum.py +7 -7
- euporie/core/data_structures.py +20 -1
- euporie/core/filters.py +8 -0
- euporie/core/ft/html.py +47 -40
- euporie/core/graphics.py +11 -3
- euporie/core/history.py +15 -5
- euporie/core/inspection.py +16 -9
- euporie/core/io.py +1 -1
- euporie/core/kernel/__init__.py +53 -1
- euporie/core/kernel/base.py +571 -0
- euporie/core/kernel/{client.py → jupyter.py} +173 -430
- euporie/core/kernel/{manager.py → jupyter_manager.py} +4 -3
- euporie/core/kernel/local.py +694 -0
- euporie/core/key_binding/bindings/basic.py +6 -3
- euporie/core/keys.py +26 -25
- euporie/core/layout/cache.py +31 -7
- euporie/core/layout/containers.py +88 -13
- euporie/core/layout/scroll.py +45 -148
- euporie/core/log.py +1 -1
- euporie/core/style.py +2 -1
- euporie/core/suggest.py +155 -74
- euporie/core/tabs/__init__.py +10 -0
- euporie/core/tabs/_commands.py +76 -0
- euporie/core/tabs/_settings.py +16 -0
- euporie/core/tabs/base.py +22 -8
- euporie/core/tabs/kernel.py +81 -35
- euporie/core/tabs/notebook.py +14 -22
- euporie/core/utils.py +1 -1
- euporie/core/validation.py +8 -8
- euporie/core/widgets/_settings.py +19 -2
- euporie/core/widgets/cell.py +31 -31
- euporie/core/widgets/cell_outputs.py +10 -1
- euporie/core/widgets/dialog.py +30 -75
- euporie/core/widgets/forms.py +71 -59
- euporie/core/widgets/inputs.py +7 -4
- euporie/core/widgets/layout.py +281 -93
- euporie/core/widgets/menu.py +55 -15
- euporie/core/widgets/palette.py +3 -1
- euporie/core/widgets/tree.py +86 -76
- euporie/notebook/app.py +35 -16
- euporie/notebook/tabs/edit.py +4 -4
- euporie/notebook/tabs/json.py +6 -2
- euporie/notebook/tabs/notebook.py +26 -8
- euporie/preview/tabs/notebook.py +17 -13
- euporie/web/tabs/web.py +22 -3
- euporie/web/widgets/webview.py +3 -0
- {euporie-2.8.6.dist-info → euporie-2.8.8.dist-info}/METADATA +1 -1
- {euporie-2.8.6.dist-info → euporie-2.8.8.dist-info}/RECORD +65 -62
- {euporie-2.8.6.dist-info → euporie-2.8.8.dist-info}/entry_points.txt +1 -1
- {euporie-2.8.6.dist-info → euporie-2.8.8.dist-info}/licenses/LICENSE +1 -1
- {euporie-2.8.6.data → euporie-2.8.8.data}/data/share/applications/euporie-console.desktop +0 -0
- {euporie-2.8.6.data → euporie-2.8.8.data}/data/share/applications/euporie-notebook.desktop +0 -0
- {euporie-2.8.6.dist-info → euporie-2.8.8.dist-info}/WHEEL +0 -0
euporie/core/widgets/tree.py
CHANGED
@@ -2,108 +2,118 @@
|
|
2
2
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
|
-
from
|
5
|
+
from functools import partial
|
6
|
+
from typing import TYPE_CHECKING
|
6
7
|
|
7
|
-
from prompt_toolkit.
|
8
|
-
from prompt_toolkit.layout.containers import ConditionalContainer
|
8
|
+
from prompt_toolkit.layout.containers import Window
|
9
9
|
from prompt_toolkit.layout.controls import FormattedTextControl
|
10
10
|
from prompt_toolkit.mouse_events import MouseButton, MouseEvent, MouseEventType
|
11
11
|
|
12
|
-
from euporie.core.layout.containers import HSplit, VSplit, Window
|
13
|
-
|
14
12
|
if TYPE_CHECKING:
|
15
13
|
from typing import Any
|
16
14
|
|
17
15
|
from prompt_toolkit.formatted_text import StyleAndTextTuples
|
18
16
|
from prompt_toolkit.key_binding.key_bindings import NotImplementedOrNone
|
19
|
-
from prompt_toolkit.layout.containers import AnyContainer
|
20
17
|
|
21
18
|
|
22
19
|
class JsonView:
|
23
20
|
"""A JSON-view container."""
|
24
21
|
|
25
22
|
def __init__(
|
26
|
-
self, data: Any, title: str | None = None, expanded: bool =
|
23
|
+
self, data: Any, title: str | None = None, expanded: bool = False
|
27
24
|
) -> None:
|
28
25
|
"""Create a new instance."""
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
self.
|
34
|
-
|
35
|
-
self.children = []
|
36
|
-
self.value_style = ""
|
37
|
-
self.value = ""
|
38
|
-
|
39
|
-
if isinstance(data, list):
|
40
|
-
data = dict(enumerate(data))
|
41
|
-
self.value = f"[] {len(data)} items"
|
42
|
-
self.value_style = "class:pygments.comment"
|
43
|
-
if isinstance(data, dict):
|
44
|
-
self.value = f"{{}} {len(data)} items"
|
45
|
-
self.value_style = "class:pygments.comment"
|
46
|
-
self.children = [
|
47
|
-
JsonView(data=value, title=key, expanded=expanded)
|
48
|
-
for key, value in data.items()
|
49
|
-
]
|
50
|
-
else:
|
51
|
-
self.value = f"{data!r}"
|
52
|
-
self.value_style = {
|
53
|
-
str: "class:pygments.literal.string",
|
54
|
-
int: "class:pygments.literal.number",
|
55
|
-
float: "class:pygments.literal.number",
|
56
|
-
bool: "class:pygments.keyword.constant",
|
57
|
-
}.get(type(data), "")
|
58
|
-
|
59
|
-
self.container = HSplit(
|
60
|
-
[
|
61
|
-
Window(
|
62
|
-
FormattedTextControl(self.format_title),
|
63
|
-
dont_extend_height=True,
|
64
|
-
),
|
65
|
-
ConditionalContainer(
|
66
|
-
VSplit(
|
67
|
-
[
|
68
|
-
Window(
|
69
|
-
width=2,
|
70
|
-
char=" ",
|
71
|
-
style="",
|
72
|
-
),
|
73
|
-
HSplit(self.children),
|
74
|
-
]
|
75
|
-
),
|
76
|
-
filter=Condition(lambda: self.expanded and bool(self.children)),
|
77
|
-
),
|
78
|
-
],
|
26
|
+
self.data = data
|
27
|
+
self.title = "root" if title is None else title
|
28
|
+
self.start_expanded = expanded
|
29
|
+
self._toggled_paths: set[tuple[str, ...]] = set()
|
30
|
+
self.container = Window(
|
31
|
+
FormattedTextControl(self._get_formatted_text, focusable=True),
|
79
32
|
style="class:tree",
|
80
33
|
)
|
81
34
|
|
82
|
-
def
|
83
|
-
"""
|
35
|
+
def _get_value_style(self, value: Any) -> str:
|
36
|
+
"""Return the style for a given value type."""
|
37
|
+
return {
|
38
|
+
str: "class:pygments.literal.string",
|
39
|
+
int: "class:pygments.literal.number",
|
40
|
+
float: "class:pygments.literal.number",
|
41
|
+
bool: "class:pygments.keyword.constant",
|
42
|
+
}.get(type(value), "")
|
43
|
+
|
44
|
+
def _format_value(self, value: Any) -> tuple[str, str]:
|
45
|
+
"""Return the formatted value and its style."""
|
46
|
+
if isinstance(value, (list, dict)):
|
47
|
+
length = len(value)
|
48
|
+
if isinstance(value, list):
|
49
|
+
return f" [] {length} items", "class:pygments.comment"
|
50
|
+
return f" {{}} {length} items", "class:pygments.comment"
|
51
|
+
return repr(value), self._get_value_style(value)
|
52
|
+
|
53
|
+
def _get_formatted_text(self) -> StyleAndTextTuples:
|
54
|
+
"""Generate the complete tree view as formatted text."""
|
55
|
+
result: StyleAndTextTuples = []
|
56
|
+
toggled_paths = self._toggled_paths
|
57
|
+
start_expanded = self.start_expanded
|
58
|
+
toggle = self._toggle
|
59
|
+
format_value = self._format_value
|
60
|
+
|
61
|
+
def format_node(
|
62
|
+
data: Any, path: tuple[str, ...], indent: int, key: str
|
63
|
+
) -> None:
|
64
|
+
is_expanded = (path in toggled_paths) ^ start_expanded
|
65
|
+
has_children = isinstance(data, (dict, list))
|
66
|
+
mouse_handler = partial(toggle, path=path)
|
67
|
+
|
68
|
+
value, style = format_value(data)
|
69
|
+
row: StyleAndTextTuples = [
|
70
|
+
# Add indentation
|
71
|
+
("", " " * indent),
|
72
|
+
# Add toggle symbol
|
73
|
+
(
|
74
|
+
("class:pygments.operator", "▼" if is_expanded else "▶")
|
75
|
+
if has_children
|
76
|
+
else ("", " ")
|
77
|
+
),
|
78
|
+
("", " "),
|
79
|
+
("class:pygments.keyword", str(key)),
|
80
|
+
("class:pygments.punctuation", ": "),
|
81
|
+
(style, value),
|
82
|
+
("", "\n"),
|
83
|
+
]
|
84
|
+
|
85
|
+
# Apply mouse_handler to rows with children
|
86
|
+
if has_children:
|
87
|
+
row = [(style, text, mouse_handler) for (style, text, *_) in row]
|
88
|
+
|
89
|
+
result.extend(row)
|
90
|
+
|
91
|
+
if is_expanded and has_children:
|
92
|
+
if isinstance(data, list):
|
93
|
+
data = {str(i): v for i, v in enumerate(data)}
|
94
|
+
|
95
|
+
for k, v in data.items():
|
96
|
+
new_path = (*path, str(k)) if path else (str(k),)
|
97
|
+
format_node(v, new_path, indent + 1, k)
|
98
|
+
|
99
|
+
format_node(self.data, (), 0, self.title)
|
100
|
+
return result
|
101
|
+
|
102
|
+
def _toggle(
|
103
|
+
self, mouse_event: MouseEvent, path: tuple[str, ...]
|
104
|
+
) -> NotImplementedOrNone:
|
105
|
+
"""Toggle the expansion state of a node."""
|
84
106
|
if (
|
85
107
|
mouse_event.button == MouseButton.LEFT
|
86
108
|
and mouse_event.event_type == MouseEventType.MOUSE_UP
|
87
109
|
):
|
88
|
-
|
110
|
+
if path in self._toggled_paths:
|
111
|
+
self._toggled_paths.remove(path)
|
112
|
+
else:
|
113
|
+
self._toggled_paths.add(path)
|
89
114
|
return None
|
90
115
|
return NotImplemented
|
91
116
|
|
92
|
-
def
|
93
|
-
"""Return the tree node toggle and title."""
|
94
|
-
return cast(
|
95
|
-
"StyleAndTextTuples",
|
96
|
-
[
|
97
|
-
("class:pygments.operator", "▼" if self.expanded else "▶", self.toggle)
|
98
|
-
if self.children
|
99
|
-
else ("", " ", self.toggle),
|
100
|
-
("", " ", self.toggle),
|
101
|
-
("class:pygments.keyword", f"{self.title}", self.toggle),
|
102
|
-
("class:pygments.punctuation", ": ", self.toggle),
|
103
|
-
(self.value_style, self.value, self.toggle),
|
104
|
-
],
|
105
|
-
)
|
106
|
-
|
107
|
-
def __pt_container__(self) -> AnyContainer:
|
117
|
+
def __pt_container__(self) -> Window:
|
108
118
|
"""Return the tree-view container's content."""
|
109
119
|
return self.container
|
euporie/notebook/app.py
CHANGED
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
5
5
|
import logging
|
6
6
|
from functools import partial
|
7
7
|
from typing import TYPE_CHECKING, cast
|
8
|
+
from weakref import WeakKeyDictionary
|
8
9
|
|
9
10
|
from prompt_toolkit.filters import Condition
|
10
11
|
from prompt_toolkit.formatted_text.base import to_formatted_text
|
@@ -89,6 +90,7 @@ class NotebookApp(BaseApp):
|
|
89
90
|
super().__init__(**kwargs)
|
90
91
|
self.bindings_to_load.append("euporie.notebook.app.NotebookApp")
|
91
92
|
|
93
|
+
self._tab_bar_tabs: dict[int, WeakKeyDictionary[Tab, TabBarTab]] = {}
|
92
94
|
self.on_tabs_change += self.set_tab_container
|
93
95
|
|
94
96
|
# Register config hooks
|
@@ -136,21 +138,36 @@ class NotebookApp(BaseApp):
|
|
136
138
|
|
137
139
|
def set_tab_container(self, app: BaseApp | None = None) -> None:
|
138
140
|
"""Set the container to use to display opened tabs."""
|
141
|
+
tab_mode = TabMode(self.config.tab_mode)
|
139
142
|
if not self.tabs:
|
140
143
|
self._tab_container = Pattern(
|
141
144
|
self.config.background_character,
|
142
145
|
self.config.background_pattern,
|
143
146
|
)
|
144
|
-
elif
|
147
|
+
elif tab_mode == TabMode.TILE_HORIZONTALLY:
|
148
|
+
children = []
|
149
|
+
for tab in self.tabs:
|
150
|
+
|
151
|
+
def _get_tab_container(tab: Tab = tab) -> Tab:
|
152
|
+
return tab
|
153
|
+
|
154
|
+
children.append(DynamicContainer(_get_tab_container))
|
145
155
|
self._tab_container = HSplit(
|
146
|
-
children=
|
156
|
+
children=children,
|
147
157
|
padding=1,
|
148
158
|
padding_style="class:tab-padding",
|
149
159
|
padding_char="─",
|
150
160
|
)
|
151
|
-
elif
|
161
|
+
elif tab_mode == TabMode.TILE_VERTICALLY:
|
162
|
+
children = []
|
163
|
+
for tab in self.tabs:
|
164
|
+
|
165
|
+
def _get_tab_container(tab: Tab = tab) -> Tab:
|
166
|
+
return tab
|
167
|
+
|
168
|
+
children.append(DynamicContainer(_get_tab_container))
|
152
169
|
self._tab_container = VSplit(
|
153
|
-
children=
|
170
|
+
children=children,
|
154
171
|
padding=1,
|
155
172
|
padding_style="class:tab-padding",
|
156
173
|
padding_char="│",
|
@@ -161,9 +178,7 @@ class NotebookApp(BaseApp):
|
|
161
178
|
ConditionalContainer(
|
162
179
|
Window(
|
163
180
|
TabBarControl(
|
164
|
-
tabs=self.tab_bar_tabs,
|
165
|
-
active=lambda: self._tab_idx,
|
166
|
-
closeable=True,
|
181
|
+
tabs=self.tab_bar_tabs, active=lambda: self._tab_idx
|
167
182
|
),
|
168
183
|
height=2,
|
169
184
|
style="class:app-tab-bar",
|
@@ -281,14 +296,18 @@ class NotebookApp(BaseApp):
|
|
281
296
|
|
282
297
|
def tab_bar_tabs(self) -> list[TabBarTab]:
|
283
298
|
"""Return a list of the current tabs for the tab-bar."""
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
299
|
+
result = []
|
300
|
+
for i, tab in enumerate(self.tabs):
|
301
|
+
index_dict = self._tab_bar_tabs.setdefault(i, WeakKeyDictionary())
|
302
|
+
if tab not in index_dict:
|
303
|
+
index_dict[tab] = TabBarTab(
|
304
|
+
title=lambda tab=tab: tab.title, # type: ignore [misc]
|
305
|
+
on_activate=partial(setattr, self, "tab_idx", i),
|
306
|
+
on_close=partial(self.close_tab, tab),
|
307
|
+
closeable=True,
|
308
|
+
)
|
309
|
+
result.append(self._tab_bar_tabs[i][tab])
|
310
|
+
return result
|
292
311
|
|
293
312
|
def _handle_exception(
|
294
313
|
self, loop: AbstractEventLoop, context: dict[str, Any]
|
@@ -474,9 +493,9 @@ class NotebookApp(BaseApp):
|
|
474
493
|
children=[
|
475
494
|
get_cmd("toggle-enable-language-servers").menu,
|
476
495
|
separator,
|
496
|
+
self.config.menus.autosuggest,
|
477
497
|
get_cmd("toggle-autoformat").menu,
|
478
498
|
get_cmd("toggle-autocomplete").menu,
|
479
|
-
get_cmd("toggle-autosuggest").menu,
|
480
499
|
get_cmd("toggle-autoinspect").menu,
|
481
500
|
],
|
482
501
|
description="Turn code assistance tools on or off",
|
euporie/notebook/tabs/edit.py
CHANGED
@@ -3,16 +3,16 @@
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
5
|
import logging
|
6
|
+
from functools import partial
|
6
7
|
from typing import TYPE_CHECKING, ClassVar
|
7
8
|
|
8
9
|
from prompt_toolkit.layout.containers import HSplit
|
9
10
|
from prompt_toolkit.layout.dimension import Dimension
|
10
11
|
|
11
12
|
from euporie.core.filters import insert_mode, replace_mode
|
12
|
-
from euporie.core.kernel.
|
13
|
+
from euporie.core.kernel.jupyter import JupyterKernel, MsgCallbacks
|
13
14
|
from euporie.core.key_binding.registry import load_registered_bindings
|
14
15
|
from euporie.core.lexers import detect_lexer
|
15
|
-
from euporie.core.path import UntitledPath
|
16
16
|
from euporie.core.tabs.kernel import KernelTab
|
17
17
|
from euporie.core.widgets.inputs import KernelInput
|
18
18
|
|
@@ -41,7 +41,7 @@ class EditorTab(KernelTab):
|
|
41
41
|
self,
|
42
42
|
app: BaseApp,
|
43
43
|
path: Path | None = None,
|
44
|
-
kernel:
|
44
|
+
kernel: JupyterKernel | None = None,
|
45
45
|
comms: dict[str, Comm] | None = None,
|
46
46
|
use_kernel_history: bool = False,
|
47
47
|
) -> None:
|
@@ -93,7 +93,7 @@ class EditorTab(KernelTab):
|
|
93
93
|
if self.dirty and (unsaved := self.app.dialogs.get("unsaved")):
|
94
94
|
unsaved.show(
|
95
95
|
tab=self,
|
96
|
-
cb=cb,
|
96
|
+
cb=partial(super().close, cb),
|
97
97
|
)
|
98
98
|
else:
|
99
99
|
super().close(cb)
|
euporie/notebook/tabs/json.py
CHANGED
@@ -10,6 +10,8 @@ from typing import TYPE_CHECKING, ClassVar
|
|
10
10
|
from prompt_toolkit.layout.containers import VSplit
|
11
11
|
from prompt_toolkit.layout.dimension import Dimension
|
12
12
|
|
13
|
+
from euporie.core.layout.scroll import ScrollingContainer
|
14
|
+
from euporie.core.margins import MarginContainer, ScrollbarMargin
|
13
15
|
from euporie.core.tabs.base import Tab
|
14
16
|
from euporie.core.widgets.tree import JsonView
|
15
17
|
|
@@ -65,8 +67,10 @@ class JsonTab(Tab):
|
|
65
67
|
|
66
68
|
return VSplit(
|
67
69
|
[
|
68
|
-
|
69
|
-
|
70
|
+
scroll := ScrollingContainer(
|
71
|
+
children=[JsonView(data, title=self.path.name, expanded=True)]
|
72
|
+
),
|
73
|
+
MarginContainer(ScrollbarMargin(), target=scroll),
|
70
74
|
],
|
71
75
|
width=Dimension(weight=1),
|
72
76
|
height=Dimension(weight=1),
|
@@ -48,7 +48,7 @@ if TYPE_CHECKING:
|
|
48
48
|
from euporie.core.app.app import BaseApp
|
49
49
|
from euporie.core.bars.status import StatusBarFields
|
50
50
|
from euporie.core.comm.base import Comm
|
51
|
-
from euporie.core.kernel.
|
51
|
+
from euporie.core.kernel.base import BaseKernel
|
52
52
|
|
53
53
|
log = logging.getLogger(__name__)
|
54
54
|
|
@@ -77,7 +77,7 @@ class Notebook(BaseNotebook):
|
|
77
77
|
self,
|
78
78
|
app: BaseApp,
|
79
79
|
path: Path | None = None,
|
80
|
-
kernel:
|
80
|
+
kernel: BaseKernel | None = None,
|
81
81
|
comms: dict[str, Comm] | None = None,
|
82
82
|
use_kernel_history: bool = True,
|
83
83
|
json: dict[str, Any] | None = None,
|
@@ -97,7 +97,6 @@ class Notebook(BaseNotebook):
|
|
97
97
|
self.multiple_cells_selected = multiple_cells_selected
|
98
98
|
self.clipboard: list[Cell] = []
|
99
99
|
self.undo_buffer: deque[tuple[int, list[Cell]]] = deque(maxlen=10)
|
100
|
-
|
101
100
|
self.default_callbacks["set_next_input"] = self.set_next_input
|
102
101
|
|
103
102
|
# Tab stuff
|
@@ -117,7 +116,11 @@ class Notebook(BaseNotebook):
|
|
117
116
|
|
118
117
|
def _kernel_name() -> StyleAndTextTuples:
|
119
118
|
ft: StyleAndTextTuples = [
|
120
|
-
(
|
119
|
+
(
|
120
|
+
"",
|
121
|
+
self.kernel_display_name or "No Kernel",
|
122
|
+
self._statusbar_kernel_handler,
|
123
|
+
)
|
121
124
|
]
|
122
125
|
return ft
|
123
126
|
|
@@ -164,13 +167,28 @@ class Notebook(BaseNotebook):
|
|
164
167
|
self.app.dialogs["error"].show(exception=error, when="starting the kernel")
|
165
168
|
|
166
169
|
def load_container(self) -> AnyContainer:
|
167
|
-
"""
|
170
|
+
"""Trigger loading of the main notebook container."""
|
171
|
+
|
172
|
+
async def _load() -> None:
|
173
|
+
# Load notebook file
|
174
|
+
self.load()
|
175
|
+
# Load an focus container
|
176
|
+
prev = self.container
|
177
|
+
self.container = self._load_container()
|
178
|
+
self.loaded = True
|
179
|
+
# Update the focus if the old container had focus
|
180
|
+
if self.app.layout.has_focus(prev):
|
181
|
+
self.focus()
|
182
|
+
|
183
|
+
self.app.create_background_task(_load())
|
184
|
+
|
185
|
+
return self.container
|
186
|
+
|
187
|
+
def _load_container(self) -> AnyContainer:
|
188
|
+
"""Actually load the main notebook container."""
|
168
189
|
self.page = ScrollingContainer(
|
169
190
|
self.rendered_cells, width=self.app.config.max_notebook_width
|
170
191
|
)
|
171
|
-
# Ensure all cells get initialized ASAP to prevent race conditions
|
172
|
-
# creating multiple version of cells across threads
|
173
|
-
self.page.all_children()
|
174
192
|
|
175
193
|
expand = Condition(lambda: self.app.config.expand)
|
176
194
|
|
euporie/preview/tabs/notebook.py
CHANGED
@@ -27,7 +27,7 @@ if TYPE_CHECKING:
|
|
27
27
|
|
28
28
|
from euporie.core.app.app import BaseApp
|
29
29
|
from euporie.core.comm.base import Comm
|
30
|
-
from euporie.core.kernel.
|
30
|
+
from euporie.core.kernel.base import BaseKernel
|
31
31
|
|
32
32
|
log = logging.getLogger(__name__)
|
33
33
|
|
@@ -54,17 +54,6 @@ class PreviewNotebook(BaseNotebook):
|
|
54
54
|
"""Filter cells before kernel is loaded."""
|
55
55
|
super().pre_init_kernel()
|
56
56
|
|
57
|
-
# Filter the cells to be shown
|
58
|
-
n_cells = len(self.json["cells"]) - 1
|
59
|
-
start: int | None = None
|
60
|
-
stop: int | None = None
|
61
|
-
if self.app.config.cell_start is not None:
|
62
|
-
start = min(max(self.app.config.cell_start, -n_cells), n_cells)
|
63
|
-
if self.app.config.cell_stop is not None:
|
64
|
-
stop = min(max(self.app.config.cell_stop, -n_cells), n_cells)
|
65
|
-
log.debug("Showing cells %s to %s", start, stop)
|
66
|
-
self.json["cells"] = self.json["cells"][start:stop]
|
67
|
-
|
68
57
|
def post_init_kernel(self) -> None:
|
69
58
|
"""Optionally start kernel after it is loaded."""
|
70
59
|
super().post_init_kernel()
|
@@ -78,7 +67,7 @@ class PreviewNotebook(BaseNotebook):
|
|
78
67
|
|
79
68
|
def init_kernel(
|
80
69
|
self,
|
81
|
-
kernel:
|
70
|
+
kernel: BaseKernel | None = None,
|
82
71
|
comms: dict[str, Comm] | None = None,
|
83
72
|
use_kernel_history: bool = False,
|
84
73
|
connection_file: Path | None = None,
|
@@ -162,6 +151,21 @@ class PreviewNotebook(BaseNotebook):
|
|
162
151
|
|
163
152
|
def load_container(self) -> AnyContainer:
|
164
153
|
"""Load the notebook's main container."""
|
154
|
+
# Load file
|
155
|
+
self.load()
|
156
|
+
|
157
|
+
# Filter the cells to be shown
|
158
|
+
n_cells = len(self.json["cells"]) - 1
|
159
|
+
start: int | None = None
|
160
|
+
stop: int | None = None
|
161
|
+
if self.app.config.cell_start is not None:
|
162
|
+
start = min(max(self.app.config.cell_start, -n_cells), n_cells)
|
163
|
+
if self.app.config.cell_stop is not None:
|
164
|
+
stop = min(max(self.app.config.cell_stop, -n_cells), n_cells)
|
165
|
+
log.debug("Showing cells %s to %s", start, stop)
|
166
|
+
self.json["cells"] = self.json["cells"][start:stop]
|
167
|
+
|
168
|
+
# Generate container
|
165
169
|
no_expand = ~self.app.config.filters.expand
|
166
170
|
return PrintingContainer(
|
167
171
|
[
|
euporie/web/tabs/web.py
CHANGED
@@ -45,8 +45,6 @@ class WebTab(Tab):
|
|
45
45
|
super().__init__(app, path)
|
46
46
|
self.status: Callable[[], StatusBarFields] | None = None
|
47
47
|
|
48
|
-
# self.container = self.load_container()
|
49
|
-
|
50
48
|
def _load() -> None:
|
51
49
|
old_container = self.container
|
52
50
|
self.container = self.load_container()
|
@@ -73,13 +71,16 @@ class WebTab(Tab):
|
|
73
71
|
def load_url(self, url: str | Path, new_tab: bool = False, **kwargs: Any) -> bool:
|
74
72
|
"""Load a new URL, or the URL in the address-bar."""
|
75
73
|
log.debug("Loading %s", url)
|
74
|
+
self.webview.loading = True
|
75
|
+
self.app.invalidate()
|
76
76
|
if not url:
|
77
77
|
return False
|
78
78
|
if isinstance(url, str):
|
79
|
-
url = UPath(url)
|
79
|
+
url = UPath(url, protocol="https" if ":" not in url else None)
|
80
80
|
if not new_tab and get_mime(url) in self.mime_types:
|
81
81
|
self.webview.load_url(url, **kwargs)
|
82
82
|
else:
|
83
|
+
self.webview.loading = False
|
83
84
|
get_app().open_file(url)
|
84
85
|
return True
|
85
86
|
|
@@ -89,6 +90,8 @@ class WebTab(Tab):
|
|
89
90
|
if url is not None:
|
90
91
|
self.path = UPath(url)
|
91
92
|
self.url_bar.text = str(url)
|
93
|
+
# Focus the webview
|
94
|
+
self.app.layout.current_control = self.webview
|
92
95
|
|
93
96
|
def load_container(self) -> AnyContainer:
|
94
97
|
"""Abcract method for loading the notebook's main container."""
|
@@ -114,10 +117,25 @@ class WebTab(Tab):
|
|
114
117
|
disabled=Condition(lambda: not self.webview.next_stack),
|
115
118
|
on_click=lambda x: self.webview.nav_next(),
|
116
119
|
)
|
120
|
+
button_refresh = Button(
|
121
|
+
"↻",
|
122
|
+
on_click=lambda x: (self.load_url(self.path) and False) or None,
|
123
|
+
)
|
124
|
+
|
125
|
+
def _select_url() -> None:
|
126
|
+
"""Select all in url bar when it gains focus."""
|
127
|
+
from prompt_toolkit.selection import SelectionState
|
128
|
+
|
129
|
+
buffer = self.url_bar.buffer
|
130
|
+
buffer.selection_state = SelectionState(0)
|
131
|
+
buffer.cursor_position = len(buffer.text)
|
132
|
+
buffer.selection_state.enter_shift_mode()
|
133
|
+
|
117
134
|
self.url_bar = Text(
|
118
135
|
text=str(path),
|
119
136
|
show_borders=DiBool(top=True, right=False, bottom=True, left=True),
|
120
137
|
accept_handler=lambda buf: self.load_url(buf.text),
|
138
|
+
on_focus=_select_url,
|
121
139
|
)
|
122
140
|
button_go = Button(
|
123
141
|
"➜",
|
@@ -132,6 +150,7 @@ class WebTab(Tab):
|
|
132
150
|
[
|
133
151
|
FocusedStyle(button_prev),
|
134
152
|
FocusedStyle(button_next),
|
153
|
+
FocusedStyle(button_refresh),
|
135
154
|
FocusedStyle(self.url_bar),
|
136
155
|
FocusedStyle(button_go),
|
137
156
|
],
|
euporie/web/widgets/webview.py
CHANGED
@@ -325,6 +325,7 @@ class WebViewControl(UIControl):
|
|
325
325
|
"""Handle click events."""
|
326
326
|
url = node.attrs.get("_link_path")
|
327
327
|
title = node.attrs.get("title")
|
328
|
+
alt = node.attrs.get("alt")
|
328
329
|
if url:
|
329
330
|
# TODO - Check for #anchor links and scroll accordingly
|
330
331
|
if (
|
@@ -343,6 +344,8 @@ class WebViewControl(UIControl):
|
|
343
344
|
self.status.clear()
|
344
345
|
if title:
|
345
346
|
self.status.append(str(title))
|
347
|
+
if title:
|
348
|
+
self.status.append(str(alt))
|
346
349
|
if url:
|
347
350
|
self.status.append(str(url))
|
348
351
|
return None
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: euporie
|
3
|
-
Version: 2.8.
|
3
|
+
Version: 2.8.8
|
4
4
|
Summary: Euporie is a suite of terminal applications for interacting with Jupyter kernels
|
5
5
|
Project-URL: Documentation, https://euporie.readthedocs.io/en/latest
|
6
6
|
Project-URL: Issues, https://github.com/joouha/euporie/issues
|