euporie 2.8.1__py3-none-any.whl → 2.8.5__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 +267 -147
- euporie/core/__init__.py +1 -9
- euporie/core/__main__.py +31 -5
- euporie/core/_settings.py +104 -0
- euporie/core/app/__init__.py +3 -0
- euporie/core/app/_commands.py +70 -0
- euporie/core/app/_settings.py +427 -0
- euporie/core/{app.py → app/app.py} +214 -572
- 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 +182 -0
- euporie/core/bars/menu.py +258 -0
- euporie/core/{widgets → bars}/search.py +154 -57
- euporie/core/{widgets → bars}/status.py +9 -26
- euporie/core/clipboard.py +19 -80
- euporie/core/comm/base.py +8 -6
- euporie/core/comm/ipywidgets.py +21 -12
- euporie/core/comm/registry.py +2 -1
- euporie/core/commands.py +11 -5
- euporie/core/completion.py +3 -2
- euporie/core/config.py +368 -341
- euporie/core/convert/__init__.py +0 -30
- euporie/core/convert/datum.py +131 -60
- euporie/core/convert/formats/__init__.py +31 -0
- euporie/core/convert/formats/ansi.py +46 -30
- 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 +11 -8
- euporie/core/convert/utils.py +50 -23
- euporie/core/diagnostics.py +2 -2
- euporie/core/filters.py +72 -82
- euporie/core/format.py +13 -2
- euporie/core/ft/ansi.py +1 -1
- euporie/core/ft/html.py +36 -36
- euporie/core/ft/table.py +1 -3
- euporie/core/ft/utils.py +4 -1
- euporie/core/graphics.py +216 -124
- 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} +100 -139
- euporie/core/kernel/manager.py +114 -0
- euporie/core/key_binding/bindings/__init__.py +2 -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 +5 -7
- euporie/core/key_binding/bindings/mouse.py +26 -24
- euporie/core/key_binding/bindings/terminal.py +193 -0
- euporie/core/key_binding/bindings/vi.py +46 -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 +35 -25
- euporie/core/layout/containers.py +280 -74
- euporie/core/layout/decor.py +5 -5
- euporie/core/layout/mouse.py +1 -1
- euporie/core/layout/print.py +16 -3
- euporie/core/layout/scroll.py +26 -28
- euporie/core/log.py +75 -60
- euporie/core/lsp.py +118 -24
- euporie/core/margins.py +60 -31
- euporie/core/path.py +2 -1
- euporie/core/renderer.py +58 -17
- euporie/core/style.py +60 -40
- euporie/core/suggest.py +103 -85
- euporie/core/tabs/__init__.py +34 -0
- euporie/core/tabs/_settings.py +113 -0
- euporie/core/tabs/base.py +11 -435
- euporie/core/tabs/kernel.py +420 -0
- euporie/core/tabs/notebook.py +20 -54
- euporie/core/utils.py +98 -6
- euporie/core/validation.py +1 -1
- euporie/core/widgets/_settings.py +188 -0
- euporie/core/widgets/cell.py +90 -158
- euporie/core/widgets/cell_outputs.py +25 -36
- euporie/core/widgets/decor.py +11 -41
- euporie/core/widgets/dialog.py +55 -44
- euporie/core/widgets/display.py +27 -24
- euporie/core/widgets/file_browser.py +5 -26
- euporie/core/widgets/forms.py +16 -12
- euporie/core/widgets/inputs.py +37 -81
- euporie/core/widgets/layout.py +7 -6
- euporie/core/widgets/logo.py +49 -0
- euporie/core/widgets/menu.py +13 -11
- euporie/core/widgets/pager.py +8 -11
- euporie/core/widgets/palette.py +6 -6
- euporie/hub/app.py +52 -31
- euporie/notebook/_commands.py +24 -0
- euporie/notebook/_settings.py +107 -0
- euporie/notebook/app.py +109 -210
- 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 +2 -2
- euporie/notebook/tabs/edit.py +12 -7
- euporie/notebook/tabs/json.py +3 -3
- euporie/notebook/tabs/log.py +1 -18
- euporie/notebook/tabs/notebook.py +21 -674
- 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 +8 -30
- euporie/preview/tabs/notebook.py +15 -86
- euporie/web/tabs/web.py +4 -6
- euporie/web/widgets/webview.py +5 -12
- {euporie-2.8.1.dist-info → euporie-2.8.5.dist-info}/METADATA +11 -15
- euporie-2.8.5.dist-info/RECORD +172 -0
- {euporie-2.8.1.dist-info → euporie-2.8.5.dist-info}/WHEEL +1 -1
- {euporie-2.8.1.dist-info → euporie-2.8.5.dist-info}/entry_points.txt +2 -2
- {euporie-2.8.1.dist-info → euporie-2.8.5.dist-info}/licenses/LICENSE +1 -1
- euporie/core/launch.py +0 -59
- euporie/core/terminal.py +0 -527
- euporie-2.8.1.dist-info/RECORD +0 -146
- {euporie-2.8.1.data → euporie-2.8.5.data}/data/share/applications/euporie-console.desktop +0 -0
- {euporie-2.8.1.data → euporie-2.8.5.data}/data/share/applications/euporie-notebook.desktop +0 -0
euporie/core/suggest.py
CHANGED
@@ -3,7 +3,9 @@
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
5
|
import logging
|
6
|
-
from collections import
|
6
|
+
from collections import defaultdict
|
7
|
+
from difflib import SequenceMatcher
|
8
|
+
from functools import lru_cache
|
7
9
|
from typing import TYPE_CHECKING
|
8
10
|
|
9
11
|
from prompt_toolkit.auto_suggest import AutoSuggest, ConditionalAutoSuggest, Suggestion
|
@@ -15,7 +17,6 @@ if TYPE_CHECKING:
|
|
15
17
|
from prompt_toolkit.filters import Filter
|
16
18
|
from prompt_toolkit.history import History
|
17
19
|
|
18
|
-
from euporie.core.kernel import Kernel
|
19
20
|
|
20
21
|
log = logging.getLogger(__name__)
|
21
22
|
|
@@ -23,99 +24,116 @@ log = logging.getLogger(__name__)
|
|
23
24
|
class HistoryAutoSuggest(AutoSuggest):
|
24
25
|
"""Suggest line completions from a :class:`History` object."""
|
25
26
|
|
26
|
-
def __init__(self, history: History
|
27
|
+
def __init__(self, history: History) -> None:
|
27
28
|
"""Set the kernel instance in initialization."""
|
28
29
|
self.history = history
|
30
|
+
self.calculate_similarity = lru_cache(maxsize=1024)(self._calculate_similarity)
|
29
31
|
|
30
|
-
self.
|
31
|
-
self.
|
32
|
-
self.
|
32
|
+
self.n_texts = 0
|
33
|
+
self.n_lines = 0
|
34
|
+
self.prefix_dict: dict[str, dict[str, list[dict[str, int]]]] = defaultdict(
|
35
|
+
lambda: defaultdict(list)
|
36
|
+
)
|
37
|
+
|
38
|
+
def process_history(self) -> None:
|
39
|
+
"""Process the entire history and store in prefix_dict."""
|
40
|
+
texts = self.history._loaded_strings
|
41
|
+
if texts := texts[: len(texts) - self.n_texts]:
|
42
|
+
n_lines = self.n_lines
|
43
|
+
prefix_dict = self.prefix_dict
|
44
|
+
for i, text in enumerate(reversed(texts)):
|
45
|
+
for line in text.strip().splitlines():
|
46
|
+
n_lines += 1
|
47
|
+
line = line.strip()
|
48
|
+
for j in range(1, len(line)):
|
49
|
+
prefix, suffix = line[:j], line[j:]
|
50
|
+
prefix_dict[prefix][suffix].append(
|
51
|
+
{"index": -1 - i, "line": n_lines}
|
52
|
+
)
|
53
|
+
# for k in range(1, len(prefix)):
|
54
|
+
# prefix_dict[prefix[-k:]] = prefix_dict[prefix]
|
55
|
+
self.n_lines = n_lines
|
56
|
+
self.n_texts += len(texts)
|
57
|
+
|
58
|
+
def _calculate_similarity(self, text_1: str, text_2: str) -> float:
|
59
|
+
"""Calculate and cache the similarity between two texts."""
|
60
|
+
return SequenceMatcher(None, text_1, text_2).quick_ratio()
|
33
61
|
|
34
62
|
def get_suggestion(self, buffer: Buffer, document: Document) -> Suggestion | None:
|
35
63
|
"""Get a line completion suggestion."""
|
36
|
-
|
64
|
+
self.process_history()
|
65
|
+
|
37
66
|
line = document.current_line.lstrip()
|
38
|
-
if line:
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
67
|
+
if not line:
|
68
|
+
return None
|
69
|
+
|
70
|
+
suffixes = self.prefix_dict[line]
|
71
|
+
|
72
|
+
texts = self.history._loaded_strings
|
73
|
+
n_lines = self.n_lines
|
74
|
+
|
75
|
+
best_score = 0.0
|
76
|
+
best_suffix = ""
|
77
|
+
|
78
|
+
# Rank candidates
|
79
|
+
max_count = max([1, *(len(x) for x in suffixes.values())])
|
80
|
+
for suffix, instances in suffixes.items():
|
81
|
+
count = len(instances)
|
82
|
+
for instance in instances:
|
83
|
+
text = texts[instance["index"]]
|
84
|
+
context_similarity = self.calculate_similarity(document.text, text)
|
85
|
+
score = (
|
86
|
+
0
|
87
|
+
# Similarity of prefix to line
|
88
|
+
# 0.333 * len(line) / len(match.group("prefix"))
|
89
|
+
# NUmber of instances in history
|
90
|
+
+ 0.3 * count / max_count
|
91
|
+
# Recentness
|
92
|
+
+ 0.3 * instance["line"] / n_lines
|
93
|
+
# Similarity of context to document
|
94
|
+
+ 0.4 * context_similarity
|
95
|
+
)
|
96
|
+
# log.debug("%s %r", score, suffix)
|
97
|
+
if score > 0.95:
|
98
|
+
return Suggestion(suffix)
|
99
|
+
if score > best_score:
|
100
|
+
best_score = score
|
101
|
+
best_suffix = suffix
|
102
|
+
if best_suffix:
|
103
|
+
return Suggestion(best_suffix)
|
65
104
|
return None
|
66
105
|
|
67
|
-
'''
|
68
|
-
def lookup_suggestion(self, line: "str") -> "Optional[Suggestion]":
|
69
|
-
""Suggest most commonly used line."""
|
70
|
-
results = {}
|
71
|
-
pat = re.compile(f"^\\s*{re.escape(line)}(.*)$", re.MULTILINE)
|
72
|
-
for text in self.history.get_strings():
|
73
|
-
if line in text:
|
74
|
-
for hist_line in text.splitlines()[::-1]:
|
75
|
-
hist_line = hist_line.strip()
|
76
|
-
if hist_line.startswith(line):
|
77
|
-
# Return from the match to end from the history line
|
78
|
-
suggestion = hist_line[len(line) :]
|
79
|
-
if suggestion not in results:
|
80
|
-
results[suggestion] = 1
|
81
|
-
else:
|
82
|
-
results[suggestion] += 1
|
83
|
-
return Suggestion(
|
84
|
-
{b: a for a, b in results.items()}[max(results.values())]
|
85
|
-
)
|
86
|
-
'''
|
87
|
-
|
88
|
-
|
89
|
-
class KernelAutoSuggest(AutoSuggest):
|
90
|
-
"""Suggest line completions from kernel history."""
|
91
|
-
|
92
|
-
def __init__(self, kernel: Kernel) -> None:
|
93
|
-
"""Set the kernel instance in initialization."""
|
94
|
-
self.kernel = kernel
|
95
|
-
|
96
|
-
def get_suggestion(self, buffer: Buffer, document: Document) -> Suggestion | None:
|
97
|
-
"""Doe nothing."""
|
98
|
-
return None
|
99
106
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
107
|
+
# class KernelAutoSuggest(AutoSuggest):
|
108
|
+
# """Suggest line completions from kernel history."""
|
109
|
+
|
110
|
+
# def __init__(self, kernel: Kernel) -> None:
|
111
|
+
# """Set the kernel instance in initialization."""
|
112
|
+
# self.kernel = kernel
|
113
|
+
|
114
|
+
# def get_suggestion(self, buffer: Buffer, document: Document) -> Suggestion | None:
|
115
|
+
# """Doe nothing."""
|
116
|
+
# return None
|
117
|
+
|
118
|
+
# async def get_suggestion_async(
|
119
|
+
# self, buff: Buffer, document: Document
|
120
|
+
# ) -> Suggestion | None:
|
121
|
+
# """Return suggestions based on matching kernel history."""
|
122
|
+
# line = document.current_line.strip()
|
123
|
+
# if line:
|
124
|
+
# suggestions = await self.kernel.history_(f"*{line}*")
|
125
|
+
# log.debug("Suggestor got suggestions %s", suggestions)
|
126
|
+
# if suggestions:
|
127
|
+
# _, _, text = suggestions[0]
|
128
|
+
# # Find matching line
|
129
|
+
# for hist_line in text.split("\n"):
|
130
|
+
# hist_line = hist_line.strip()
|
131
|
+
# if hist_line.startswith(line):
|
132
|
+
# # Return from the match to end from the history line
|
133
|
+
# suggestion = hist_line[len(line) :]
|
134
|
+
# log.debug("Suggesting %s", suggestion)
|
135
|
+
# return Suggestion(suggestion)
|
136
|
+
# return None
|
119
137
|
|
120
138
|
|
121
139
|
class ConditionalAutoSuggestAsync(ConditionalAutoSuggest):
|
euporie/core/tabs/__init__.py
CHANGED
@@ -1 +1,35 @@
|
|
1
1
|
"""Contain various application tab implementations."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
from dataclasses import dataclass, field
|
6
|
+
from importlib import import_module
|
7
|
+
from typing import TYPE_CHECKING
|
8
|
+
|
9
|
+
if TYPE_CHECKING:
|
10
|
+
from euporie.core.tabs.base import Tab
|
11
|
+
|
12
|
+
|
13
|
+
@dataclass
|
14
|
+
class TabRegistryEntry:
|
15
|
+
"""Class to store tab information."""
|
16
|
+
|
17
|
+
path: str
|
18
|
+
name: str
|
19
|
+
mime_types: set = field(default_factory=set)
|
20
|
+
file_extensions: dict[str, None] = field(default_factory=dict)
|
21
|
+
weight: int = 0
|
22
|
+
|
23
|
+
@property
|
24
|
+
def tab_class(self) -> type[Tab]:
|
25
|
+
"""Import and return the tab class."""
|
26
|
+
module_path, _, attribute = self.path.partition(":")
|
27
|
+
module = import_module(module_path)
|
28
|
+
return getattr(module, attribute)
|
29
|
+
|
30
|
+
def __lt__(self, other: TabRegistryEntry) -> bool:
|
31
|
+
"""Sort by weight."""
|
32
|
+
return self.weight < other.weight
|
33
|
+
|
34
|
+
|
35
|
+
_TAB_REGISTRY: list[TabRegistryEntry] = []
|
@@ -0,0 +1,113 @@
|
|
1
|
+
"""Defines tab settings."""
|
2
|
+
|
3
|
+
from prompt_toolkit.filters import buffer_has_focus
|
4
|
+
|
5
|
+
from euporie.core.config import add_setting
|
6
|
+
|
7
|
+
add_setting(
|
8
|
+
name="kernel_name",
|
9
|
+
group="euporie.core.tabs.kernel",
|
10
|
+
flags=["--kernel-name", "--kernel"],
|
11
|
+
type_=str,
|
12
|
+
help_="The name of the kernel to start by default",
|
13
|
+
default="python3",
|
14
|
+
description="""
|
15
|
+
The name of the kernel selected automatically by the console app or in new
|
16
|
+
notebooks. If set to an empty string, the user will be asked which kernel
|
17
|
+
to launch.
|
18
|
+
""",
|
19
|
+
)
|
20
|
+
|
21
|
+
add_setting(
|
22
|
+
name="record_cell_timing",
|
23
|
+
group="euporie.core.tabs.kernel",
|
24
|
+
title="cell timing recording",
|
25
|
+
flags=["--record-cell-timing"],
|
26
|
+
type_=bool,
|
27
|
+
help_="Should timing data be recorded in cell metadata.",
|
28
|
+
default=False,
|
29
|
+
schema={
|
30
|
+
"type": "boolean",
|
31
|
+
},
|
32
|
+
description="""
|
33
|
+
When set, execution timing data will be recorded in cell metadata.
|
34
|
+
""",
|
35
|
+
)
|
36
|
+
|
37
|
+
add_setting(
|
38
|
+
name="show_remote_inputs",
|
39
|
+
group="euporie.core.tabs.kernel",
|
40
|
+
flags=["--show-remote-inputs"],
|
41
|
+
type_=bool,
|
42
|
+
help_="Display inputs sent to the kernel by other clients",
|
43
|
+
default=True,
|
44
|
+
description="""
|
45
|
+
If set to `True`, all code input sent to the kernel by any client will be
|
46
|
+
displayed.
|
47
|
+
|
48
|
+
If set to `False`, only inputs sent to the kernel by the current instance
|
49
|
+
of euporie will be displayed, and all other inputs will be ignored.
|
50
|
+
|
51
|
+
""",
|
52
|
+
)
|
53
|
+
|
54
|
+
add_setting(
|
55
|
+
name="show_remote_outputs",
|
56
|
+
group="euporie.core.tabs.kernel",
|
57
|
+
flags=["--show-remote-outputs"],
|
58
|
+
type_=bool,
|
59
|
+
help_="Display kernel outputs triggered by other clients",
|
60
|
+
default=True,
|
61
|
+
description="""
|
62
|
+
If set to `False`, only outputs generated by code input from the current
|
63
|
+
instance of euporie will be displayed, and all other outputs will be
|
64
|
+
ignored.
|
65
|
+
|
66
|
+
If set to `True`, all outputs generated by the kernel will be
|
67
|
+
displayed.
|
68
|
+
""",
|
69
|
+
)
|
70
|
+
|
71
|
+
# euporie.core.tabs.notebook
|
72
|
+
|
73
|
+
add_setting(
|
74
|
+
name="save_widget_state",
|
75
|
+
group="euporie.core.tabs.notebook",
|
76
|
+
flags=["--save-widget-state"],
|
77
|
+
type_=bool,
|
78
|
+
help_="Save a notebook's widget state in the notebook metadata",
|
79
|
+
default=True,
|
80
|
+
description="""
|
81
|
+
When set to ``True``, the state of any widgets in the current notebook will
|
82
|
+
be saves in the notebook's metadata. This enables widgets to be displayed
|
83
|
+
when the notebook is re-opened without having to re-run the notebook.
|
84
|
+
""",
|
85
|
+
)
|
86
|
+
|
87
|
+
add_setting(
|
88
|
+
name="max_notebook_width",
|
89
|
+
group="euporie.core.tabs.notebook",
|
90
|
+
flags=["--max-notebook-width"],
|
91
|
+
type_=int,
|
92
|
+
help_="Maximum width of notebooks",
|
93
|
+
default=120,
|
94
|
+
schema={
|
95
|
+
"minimum": 1,
|
96
|
+
},
|
97
|
+
description="""
|
98
|
+
The maximum width at which to display a notebook.
|
99
|
+
""",
|
100
|
+
)
|
101
|
+
|
102
|
+
add_setting(
|
103
|
+
name="expand",
|
104
|
+
group="euporie.core.tabs.notebook",
|
105
|
+
flags=["--expand"],
|
106
|
+
type_=bool,
|
107
|
+
help_="Use the full width to display notebooks",
|
108
|
+
default=False,
|
109
|
+
description="""
|
110
|
+
Whether the notebook page should expand to fill the available width
|
111
|
+
""",
|
112
|
+
cmd_filter=~buffer_has_focus,
|
113
|
+
)
|