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.
Files changed (131) hide show
  1. euporie/console/_commands.py +143 -0
  2. euporie/console/_settings.py +58 -0
  3. euporie/console/app.py +25 -71
  4. euporie/console/tabs/console.py +58 -62
  5. euporie/core/__init__.py +1 -1
  6. euporie/core/__main__.py +28 -11
  7. euporie/core/_settings.py +109 -0
  8. euporie/core/app/__init__.py +3 -0
  9. euporie/core/app/_commands.py +95 -0
  10. euporie/core/app/_settings.py +457 -0
  11. euporie/core/{app.py → app/app.py} +212 -576
  12. euporie/core/app/base.py +51 -0
  13. euporie/core/{current.py → app/current.py} +13 -4
  14. euporie/core/app/cursor.py +35 -0
  15. euporie/core/app/dummy.py +12 -0
  16. euporie/core/app/launch.py +28 -0
  17. euporie/core/bars/__init__.py +11 -0
  18. euporie/core/bars/command.py +205 -0
  19. euporie/core/bars/menu.py +258 -0
  20. euporie/core/{widgets → bars}/search.py +20 -16
  21. euporie/core/{widgets → bars}/status.py +6 -23
  22. euporie/core/clipboard.py +19 -80
  23. euporie/core/comm/base.py +8 -6
  24. euporie/core/comm/ipywidgets.py +16 -7
  25. euporie/core/comm/registry.py +2 -1
  26. euporie/core/commands.py +10 -20
  27. euporie/core/completion.py +3 -2
  28. euporie/core/config.py +368 -341
  29. euporie/core/convert/__init__.py +0 -30
  30. euporie/core/convert/datum.py +116 -53
  31. euporie/core/convert/formats/__init__.py +31 -0
  32. euporie/core/convert/formats/ansi.py +9 -23
  33. euporie/core/convert/formats/common.py +11 -23
  34. euporie/core/convert/formats/html.py +45 -40
  35. euporie/core/convert/formats/pil.py +1 -1
  36. euporie/core/convert/formats/png.py +3 -5
  37. euporie/core/convert/formats/sixel.py +3 -3
  38. euporie/core/convert/registry.py +4 -6
  39. euporie/core/convert/utils.py +41 -4
  40. euporie/core/diagnostics.py +2 -2
  41. euporie/core/filters.py +98 -40
  42. euporie/core/format.py +2 -3
  43. euporie/core/ft/ansi.py +1 -1
  44. euporie/core/ft/html.py +12 -21
  45. euporie/core/ft/table.py +1 -3
  46. euporie/core/ft/utils.py +4 -1
  47. euporie/core/graphics.py +386 -133
  48. euporie/core/history.py +2 -2
  49. euporie/core/inspection.py +3 -2
  50. euporie/core/io.py +207 -28
  51. euporie/core/kernel/__init__.py +1 -0
  52. euporie/core/{kernel.py → kernel/client.py} +45 -108
  53. euporie/core/kernel/manager.py +114 -0
  54. euporie/core/key_binding/bindings/__init__.py +1 -8
  55. euporie/core/key_binding/bindings/basic.py +47 -7
  56. euporie/core/key_binding/bindings/completion.py +3 -8
  57. euporie/core/key_binding/bindings/micro.py +1 -6
  58. euporie/core/key_binding/bindings/mouse.py +2 -2
  59. euporie/core/key_binding/bindings/terminal.py +193 -0
  60. euporie/core/key_binding/key_processor.py +43 -2
  61. euporie/core/key_binding/registry.py +2 -0
  62. euporie/core/key_binding/utils.py +22 -2
  63. euporie/core/keys.py +7156 -93
  64. euporie/core/layout/cache.py +3 -3
  65. euporie/core/layout/containers.py +48 -4
  66. euporie/core/layout/decor.py +2 -2
  67. euporie/core/layout/mouse.py +1 -1
  68. euporie/core/layout/print.py +2 -1
  69. euporie/core/layout/scroll.py +39 -34
  70. euporie/core/log.py +76 -64
  71. euporie/core/lsp.py +118 -24
  72. euporie/core/margins.py +1 -1
  73. euporie/core/path.py +62 -13
  74. euporie/core/renderer.py +58 -17
  75. euporie/core/style.py +57 -39
  76. euporie/core/suggest.py +103 -85
  77. euporie/core/tabs/__init__.py +32 -0
  78. euporie/core/tabs/_settings.py +113 -0
  79. euporie/core/tabs/base.py +80 -470
  80. euporie/core/tabs/kernel.py +419 -0
  81. euporie/core/tabs/notebook.py +24 -101
  82. euporie/core/utils.py +92 -15
  83. euporie/core/validation.py +1 -1
  84. euporie/core/widgets/_settings.py +188 -0
  85. euporie/core/widgets/cell.py +19 -50
  86. euporie/core/widgets/cell_outputs.py +25 -36
  87. euporie/core/widgets/decor.py +11 -41
  88. euporie/core/widgets/dialog.py +62 -27
  89. euporie/core/widgets/display.py +12 -15
  90. euporie/core/widgets/file_browser.py +2 -23
  91. euporie/core/widgets/forms.py +8 -5
  92. euporie/core/widgets/inputs.py +13 -70
  93. euporie/core/widgets/layout.py +2 -1
  94. euporie/core/widgets/logo.py +49 -0
  95. euporie/core/widgets/menu.py +10 -8
  96. euporie/core/widgets/pager.py +6 -10
  97. euporie/core/widgets/palette.py +6 -6
  98. euporie/hub/app.py +52 -35
  99. euporie/notebook/_commands.py +24 -0
  100. euporie/notebook/_settings.py +107 -0
  101. euporie/notebook/app.py +49 -171
  102. euporie/notebook/filters.py +1 -1
  103. euporie/notebook/tabs/__init__.py +46 -7
  104. euporie/notebook/tabs/_commands.py +714 -0
  105. euporie/notebook/tabs/_settings.py +32 -0
  106. euporie/notebook/tabs/display.py +4 -4
  107. euporie/notebook/tabs/edit.py +11 -44
  108. euporie/notebook/tabs/json.py +5 -5
  109. euporie/notebook/tabs/log.py +1 -18
  110. euporie/notebook/tabs/notebook.py +11 -660
  111. euporie/notebook/widgets/_commands.py +11 -0
  112. euporie/notebook/widgets/_settings.py +19 -0
  113. euporie/notebook/widgets/side_bar.py +14 -34
  114. euporie/preview/_settings.py +104 -0
  115. euporie/preview/app.py +6 -31
  116. euporie/preview/tabs/notebook.py +6 -72
  117. euporie/web/__init__.py +1 -0
  118. euporie/web/tabs/__init__.py +14 -0
  119. euporie/web/tabs/web.py +11 -6
  120. euporie/web/widgets/__init__.py +1 -0
  121. euporie/web/widgets/webview.py +5 -15
  122. {euporie-2.8.4.dist-info → euporie-2.8.6.dist-info}/METADATA +10 -8
  123. euporie-2.8.6.dist-info/RECORD +175 -0
  124. {euporie-2.8.4.dist-info → euporie-2.8.6.dist-info}/WHEEL +1 -1
  125. {euporie-2.8.4.dist-info → euporie-2.8.6.dist-info}/entry_points.txt +2 -2
  126. {euporie-2.8.4.dist-info → euporie-2.8.6.dist-info}/licenses/LICENSE +1 -1
  127. euporie/core/launch.py +0 -64
  128. euporie/core/terminal.py +0 -522
  129. euporie-2.8.4.dist-info/RECORD +0 -147
  130. {euporie-2.8.4.data → euporie-2.8.6.data}/data/share/applications/euporie-console.desktop +0 -0
  131. {euporie-2.8.4.data → euporie-2.8.6.data}/data/share/applications/euporie-notebook.desktop +0 -0
@@ -5,24 +5,26 @@ from __future__ import annotations
5
5
  import logging
6
6
  from typing import TYPE_CHECKING
7
7
 
8
+ from prompt_toolkit.buffer import Buffer
8
9
  from prompt_toolkit.document import Document
9
10
  from prompt_toolkit.filters.app import is_searching
10
11
  from prompt_toolkit.filters.base import Condition
12
+ from prompt_toolkit.formatted_text.base import to_formatted_text
11
13
  from prompt_toolkit.key_binding.vi_state import InputMode
12
14
  from prompt_toolkit.layout.controls import BufferControl, SearchBufferControl
13
15
  from prompt_toolkit.search import SearchDirection
14
16
  from prompt_toolkit.selection import SelectionState
15
17
  from prompt_toolkit.widgets import SearchToolbar as PtkSearchToolbar
16
18
 
19
+ from euporie.core.app.current import get_app
20
+ from euporie.core.bars import SEARCH_BAR_BUFFER
17
21
  from euporie.core.commands import add_cmd
18
- from euporie.core.current import get_app
19
22
  from euporie.core.key_binding.registry import (
20
23
  load_registered_bindings,
21
24
  register_bindings,
22
25
  )
23
26
 
24
27
  if TYPE_CHECKING:
25
- from prompt_toolkit.buffer import Buffer
26
28
  from prompt_toolkit.filters import FilterOrBool
27
29
  from prompt_toolkit.formatted_text.base import AnyFormattedText
28
30
 
@@ -40,24 +42,26 @@ class SearchBar(PtkSearchToolbar):
40
42
  search_buffer: Buffer | None = None,
41
43
  vi_mode: bool = False,
42
44
  text_if_not_searching: AnyFormattedText = "",
43
- forward_search_prompt: AnyFormattedText = "I-search: ",
44
- backward_search_prompt: AnyFormattedText = "I-search backward: ",
45
+ forward_search_prompt: AnyFormattedText = " Find: ",
46
+ backward_search_prompt: AnyFormattedText = " Find (up): ",
45
47
  ignore_case: FilterOrBool = False,
46
48
  ) -> None:
47
49
  """Create a new search bar instance."""
50
+ if search_buffer is None:
51
+ search_buffer = Buffer(name=SEARCH_BAR_BUFFER)
48
52
  super().__init__(
49
- text_if_not_searching="",
50
- forward_search_prompt=[
51
- ("class:search-toolbar.title", " Find: "),
52
- ("", " "),
53
- ],
54
- backward_search_prompt=[
55
- ("class:search-toolbar.title", " Find (up): "),
56
- ("", " "),
57
- ],
53
+ search_buffer=search_buffer,
54
+ vi_mode=vi_mode,
55
+ text_if_not_searching=text_if_not_searching,
56
+ forward_search_prompt=to_formatted_text(
57
+ forward_search_prompt, "class:status-field"
58
+ ),
59
+ backward_search_prompt=to_formatted_text(
60
+ backward_search_prompt, "class:status-field"
61
+ ),
58
62
  )
59
63
  self.control.key_bindings = load_registered_bindings(
60
- "euporie.core.widgets.search.SearchBar",
64
+ "euporie.core.bars.search.SearchBar",
61
65
  config=get_app().config,
62
66
  )
63
67
  search_state = self.control.searcher_search_state
@@ -67,12 +71,12 @@ class SearchBar(PtkSearchToolbar):
67
71
 
68
72
  register_bindings(
69
73
  {
70
- "euporie.core.app.BaseApp": {
74
+ "euporie.core.app.app:BaseApp": {
71
75
  "find": ["c-f", "f3", "f7"],
72
76
  "find-next": "c-g",
73
77
  "find-previous": "c-p",
74
78
  },
75
- "euporie.core.widgets.search.SearchBar": {
79
+ "euporie.core.bars.search.SearchBar": {
76
80
  "accept-search": "enter",
77
81
  "stop-search": "escape",
78
82
  },
@@ -16,13 +16,13 @@ from prompt_toolkit.layout.containers import (
16
16
  )
17
17
  from prompt_toolkit.layout.controls import FormattedTextControl
18
18
 
19
- from euporie.core.config import add_setting
20
- from euporie.core.current import get_app
21
- from euporie.core.filters import is_searching
19
+ from euporie.core.app.current import get_app
20
+ from euporie.core.filters import has_toolbar
22
21
  from euporie.core.layout.containers import VSplit, Window
23
22
 
24
23
  if TYPE_CHECKING:
25
- from typing import Callable, Sequence
24
+ from collections.abc import Sequence
25
+ from typing import Callable
26
26
 
27
27
  from prompt_toolkit.filters.base import FilterOrBool
28
28
  from prompt_toolkit.formatted_text import StyleAndTextTuples
@@ -99,8 +99,8 @@ class StatusBar:
99
99
  ],
100
100
  height=1,
101
101
  ),
102
- filter=get_app().config.filter("show_status_bar")
103
- & ~is_searching
102
+ filter=get_app().config.filters.show_status_bar
103
+ & ~has_toolbar
104
104
  & to_filter(extra_filter),
105
105
  )
106
106
 
@@ -144,20 +144,3 @@ class StatusBar:
144
144
  def __pt_container__(self) -> AnyContainer:
145
145
  """Return the widget's container."""
146
146
  return self.container
147
-
148
- # ################################### Settings ####################################
149
-
150
- add_setting(
151
- name="show_status_bar",
152
- flags=["--show-status-bar"],
153
- type_=bool,
154
- title="status bar",
155
- help_="Show the status bar",
156
- default=True,
157
- schema={
158
- "type": "boolean",
159
- },
160
- description="""
161
- Whether the status bar should be shown at the bottom of the screen.
162
- """,
163
- )
euporie/core/clipboard.py CHANGED
@@ -3,21 +3,15 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import logging
6
- from typing import TYPE_CHECKING
7
6
 
8
7
  from prompt_toolkit.clipboard.base import Clipboard, ClipboardData
9
8
  from prompt_toolkit.clipboard.in_memory import InMemoryClipboard
10
9
  from prompt_toolkit.clipboard.pyperclip import PyperclipClipboard
11
10
  from prompt_toolkit.selection import SelectionType
12
- from pyperclip import determine_clipboard
13
11
 
14
- from euporie.core.config import add_setting
12
+ from euporie.core.app.current import get_app
15
13
  from euporie.core.io import Vt100_Output
16
-
17
- if TYPE_CHECKING:
18
- from euporie.core.app import BaseApp
19
- from euporie.core.config import Setting
20
- from euporie.core.terminal import TerminalQuery
14
+ from euporie.core.key_binding.key_processor import KeyProcessor
21
15
 
22
16
  log = logging.getLogger(__name__)
23
17
 
@@ -25,16 +19,13 @@ log = logging.getLogger(__name__)
25
19
  class Osc52Clipboard(Clipboard):
26
20
  """Clipboard that syncs with the system clipboard using OSC52 escape codes."""
27
21
 
28
- def __init__(self, app: BaseApp) -> None:
22
+ def __init__(self) -> None:
29
23
  """Create a new instance of the clipboard."""
30
- self.app = app
31
- term_clipboard_data = app.term_info.clipboard_data
32
- term_clipboard_data.event += self._update_clipboard
33
- self._data = ClipboardData(text=term_clipboard_data.value)
24
+ self._data = ClipboardData()
34
25
 
35
26
  def set_data(self, data: ClipboardData) -> None:
36
27
  """Set clipboard data."""
37
- output = self.app.output
28
+ output = get_app().output
38
29
  if isinstance(output, Vt100_Output):
39
30
  output.set_clipboard(data.text)
40
31
  output.flush()
@@ -43,16 +34,21 @@ class Osc52Clipboard(Clipboard):
43
34
  def get_data(self) -> ClipboardData:
44
35
  """Retrieve clipboard data."""
45
36
  # Send clipboard query
46
- output = self.app.output
37
+ app = get_app()
38
+ output = app.output
39
+ # Request clipboard contents from terminal
47
40
  if isinstance(output, Vt100_Output):
41
+ from euporie.core.keys import MoreKeys
42
+
48
43
  output.get_clipboard()
49
44
  output.flush()
50
- self.app.term_info.clipboard_data.await_response(timeout=5)
45
+ # Wait for terminal response
46
+ if isinstance(app.key_processor, KeyProcessor):
47
+ app.key_processor.await_key(MoreKeys.ClipboardDataResponse)
51
48
  return self._data
52
49
 
53
- def _update_clipboard(self, query: TerminalQuery) -> None:
50
+ def sync(self, text: str) -> None:
54
51
  """Update the last known clipboard data."""
55
- text = query.value
56
52
  if text != self._data.text:
57
53
  self._data = ClipboardData(
58
54
  text=text,
@@ -60,65 +56,8 @@ class Osc52Clipboard(Clipboard):
60
56
  )
61
57
 
62
58
 
63
- class ConfiguredClipboard(Clipboard):
64
- """Use a clipboard determined by euporie's configuration."""
65
-
66
- _clipboard: Clipboard
67
-
68
- def __init__(self, app: BaseApp) -> None:
69
- """Create a new clipboard instance."""
70
- self.app = app
71
- clipboard_config = app.config.settings["clipboard"]
72
- self.get_clipboard(clipboard_config)
73
- clipboard_config.event += self.get_clipboard
74
-
75
- def get_clipboard(self, setting: Setting) -> None:
76
- """Determine which clipboard to use."""
77
- clipboard: Clipboard | None = None
78
- if setting.value == "external" and determine_clipboard()[0]:
79
- log.debug("Using pyperclip clipboard")
80
- clipboard = PyperclipClipboard()
81
- if not clipboard:
82
- if setting.value == "terminal":
83
- log.debug("Using terminal clipboard")
84
- clipboard = Osc52Clipboard(self.app)
85
- else:
86
- log.debug("Using in-memory clipboard")
87
- clipboard = InMemoryClipboard()
88
- self._clipboard = clipboard
89
-
90
- def set_data(self, data: ClipboardData) -> None:
91
- """Set data to the clipboard."""
92
- self._clipboard.set_data(data)
93
-
94
- def set_text(self, text: str) -> None:
95
- """Shortcut for setting plain text on clipboard."""
96
- self._clipboard.set_text(text)
97
-
98
- def rotate(self) -> None:
99
- """For Emacs mode, rotate the kill ring."""
100
- self._clipboard.rotate()
101
-
102
- def get_data(self) -> ClipboardData:
103
- """Return clipboard data."""
104
- return self._clipboard.get_data()
105
-
106
- # ################################### Settings ####################################w
107
-
108
- add_setting(
109
- name="clipboard",
110
- flags=["--clipboard"],
111
- choices=["external", "internal", "terminal"],
112
- type_=str,
113
- default="external",
114
- help_="The preferred clipboard access method",
115
- description="""
116
- The clipboard access method to use.
117
- - ``external``: Data is saved to the system clipboard using OS native tooling.
118
- - ``internal``: Clipboard data is only stored and usable inside euporie - it is
119
- not saved to the system clipboard.
120
- - ``terminal``: uses OSC52 escape sequences to retrieve and set the clipboard
121
- contents. Requires your terminal emulator to support OSC52. Works over SSH.
122
-
123
- """,
124
- )
59
+ CONFIGURED_CLIPBOARDS = {
60
+ "internal": InMemoryClipboard,
61
+ "external": PyperclipClipboard,
62
+ "terminal": Osc52Clipboard,
63
+ }
euporie/core/comm/base.py CHANGED
@@ -7,17 +7,16 @@ from abc import ABCMeta, abstractmethod
7
7
  from typing import TYPE_CHECKING
8
8
  from weakref import WeakKeyDictionary
9
9
 
10
- from euporie.core.convert.datum import Datum
11
- from euporie.core.current import get_app
12
- from euporie.core.widgets.display import Display
10
+ from euporie.core.app.current import get_app
13
11
 
14
12
  if TYPE_CHECKING:
15
- from typing import Any, Callable, Mapping, Sequence
13
+ from collections.abc import Mapping, Sequence
14
+ from typing import Any, Callable
16
15
 
17
16
  from prompt_toolkit.layout.containers import AnyContainer
18
17
 
19
- from euporie.core.kernel import Kernel
20
- from euporie.core.tabs.base import KernelTab
18
+ from euporie.core.kernel.client import Kernel
19
+ from euporie.core.tabs.kernel import KernelTab
21
20
  from euporie.core.widgets.cell_outputs import OutputParent
22
21
 
23
22
 
@@ -97,6 +96,9 @@ class Comm(metaclass=ABCMeta):
97
96
 
98
97
  def create_view(self, parent: OutputParent) -> CommView:
99
98
  """Create a new :class:`CommView` for this Comm."""
99
+ from euporie.core.convert.datum import Datum
100
+ from euporie.core.widgets.display import Display
101
+
100
102
  return CommView(Display(Datum("[Object cannot be rendered]", format="ansi")))
101
103
 
102
104
  def new_view(self, parent: OutputParent) -> CommView:
@@ -18,12 +18,9 @@ from prompt_toolkit.layout.containers import HSplit, VSplit
18
18
  from prompt_toolkit.layout.processors import BeforeInput
19
19
 
20
20
  from euporie.core.comm.base import Comm, CommView
21
- from euporie.core.convert.datum import Datum
22
21
  from euporie.core.data_structures import DiBool
23
- from euporie.core.kernel import MsgCallbacks
22
+ from euporie.core.kernel.client import MsgCallbacks
24
23
  from euporie.core.layout.decor import FocusedStyle
25
- from euporie.core.widgets.cell_outputs import CellOutputArea
26
- from euporie.core.widgets.display import Display
27
24
  from euporie.core.widgets.forms import (
28
25
  Button,
29
26
  Checkbox,
@@ -46,13 +43,14 @@ from euporie.core.widgets.layout import (
46
43
  )
47
44
 
48
45
  if TYPE_CHECKING:
49
- from typing import Any, Iterable, MutableSequence, Sequence
46
+ from collections.abc import Iterable, MutableSequence, Sequence
47
+ from typing import Any
50
48
 
51
49
  from prompt_toolkit.buffer import Buffer
52
50
  from prompt_toolkit.formatted_text.base import AnyFormattedText
53
51
  from prompt_toolkit.layout.containers import AnyContainer, _Split
54
52
 
55
- from euporie.core.comm.base import KernelTab
53
+ from euporie.core.tabs.kernel import KernelTab
56
54
  from euporie.core.widgets.cell_outputs import OutputParent
57
55
  from euporie.core.widgets.forms import SelectableWidget, ToggleableWidget
58
56
  from euporie.core.widgets.layout import StackedSplit
@@ -213,6 +211,9 @@ class UnimplementedModel(IpyWidgetComm):
213
211
 
214
212
  def create_view(self, parent: OutputParent) -> CommView:
215
213
  """Create a new view."""
214
+ from euporie.core.convert.datum import Datum
215
+ from euporie.core.widgets.display import Display
216
+
216
217
  return CommView(Display(Datum("[Widget not implemented]", format="ansi")))
217
218
 
218
219
 
@@ -242,6 +243,8 @@ class OutputModel(IpyWidgetComm):
242
243
 
243
244
  def create_view(self, parent: OutputParent) -> CommView:
244
245
  """Create a new view of this output ipywidget."""
246
+ from euporie.core.widgets.cell_outputs import CellOutputArea
247
+
245
248
  container = CellOutputArea(
246
249
  self.data.get("state", {}).get("outputs", []), parent
247
250
  )
@@ -1258,6 +1261,9 @@ class HTMLModel(IpyWidgetComm):
1258
1261
 
1259
1262
  def create_view(self, parent: OutputParent) -> CommView:
1260
1263
  """Create a new view of the HTML widget."""
1264
+ from euporie.core.convert.datum import Datum
1265
+ from euporie.core.widgets.display import Display
1266
+
1261
1267
  html = Display(
1262
1268
  Datum(data=self.data["state"].get("value", ""), format="html"),
1263
1269
  dont_extend_width=True,
@@ -1285,6 +1291,9 @@ class ImageModel(IpyWidgetComm):
1285
1291
 
1286
1292
  def create_view(self, parent: OutputParent) -> CommView:
1287
1293
  """Create a new view of the image widget."""
1294
+ from euporie.core.convert.datum import Datum
1295
+ from euporie.core.widgets.display import Display
1296
+
1288
1297
  display = Display(
1289
1298
  Datum(
1290
1299
  data=self.data["state"].get("value", b""),
@@ -1408,7 +1417,7 @@ class ColorPickerModel(TextBoxIpyWidgetComm):
1408
1417
  if value in NAMED_COLORS:
1409
1418
  value = NAMED_COLORS[value]
1410
1419
  elif 4 <= len(value) < 7:
1411
- value = f"#{value[1]*2}{value[2]*2}{value[3]*2}"
1420
+ value = f"#{value[1] * 2}{value[2] * 2}{value[3] * 2}"
1412
1421
  else:
1413
1422
  value = value[:7]
1414
1423
  return value
@@ -8,7 +8,8 @@ from euporie.core.comm.base import UnimplementedComm
8
8
  from euporie.core.comm.ipywidgets import open_comm_ipywidgets
9
9
 
10
10
  if TYPE_CHECKING:
11
- from typing import Any, Callable, Sequence
11
+ from collections.abc import Sequence
12
+ from typing import Any, Callable
12
13
 
13
14
  from euporie.core.comm.base import Comm, KernelTab
14
15
 
euporie/core/commands.py CHANGED
@@ -15,7 +15,8 @@ from prompt_toolkit.key_binding.key_processor import KeyPressEvent
15
15
  from euporie.core.key_binding.utils import parse_keys
16
16
 
17
17
  if TYPE_CHECKING:
18
- from typing import Any, Callable, Coroutine
18
+ from collections.abc import Coroutine
19
+ from typing import Any, Callable
19
20
 
20
21
  from prompt_toolkit.filters import Filter, FilterOrBool
21
22
  from prompt_toolkit.key_binding.key_bindings import (
@@ -50,6 +51,7 @@ class Command:
50
51
  filter: FilterOrBool = True,
51
52
  hidden: FilterOrBool = False,
52
53
  name: str | None = None,
54
+ aliases: list[str] | None = None,
53
55
  title: str | None = None,
54
56
  menu_title: str | None = None,
55
57
  description: str | None = None,
@@ -66,6 +68,7 @@ class Command:
66
68
  filter: The condition under which the command is allowed to run
67
69
  hidden: The condition under the command is visible to the user
68
70
  name: The name of the command, for accessing the command from the registry
71
+ aliases: List of additional names for the command
69
72
  title: The title of the command for display
70
73
  menu_title: The title to display in menus if different
71
74
  description: The description of the command to explain it's function
@@ -77,6 +80,7 @@ class Command:
77
80
 
78
81
  """
79
82
  self.handler = handler
83
+ self.aliases = aliases or []
80
84
  self.filter = to_filter(filter)
81
85
  self.hidden = to_filter(hidden)
82
86
  if name is None:
@@ -106,18 +110,18 @@ class Command:
106
110
 
107
111
  self.keys: list[tuple[str | Keys, ...]] = []
108
112
 
109
- def run(self) -> None:
113
+ def run(self, arg: str | None = None) -> None:
110
114
  """Run the command's handler."""
111
115
  if self.filter():
112
116
  app = get_app()
113
117
  result = self.key_handler(
114
118
  KeyPressEvent(
115
119
  key_processor_ref=weakref.ref(app.key_processor),
116
- arg=None,
120
+ arg=arg,
117
121
  key_sequence=[],
118
122
  previous_key_sequence=[],
119
123
  is_repeat=False,
120
- )
124
+ ),
121
125
  )
122
126
  if isawaitable(result):
123
127
 
@@ -187,22 +191,6 @@ class Command:
187
191
  return format_keys([self.keys[0]])[0]
188
192
  return ""
189
193
 
190
- @property
191
- def menu_handler(self) -> Callable[[], None]:
192
- """Return a menu handler for the command."""
193
- handler = self.handler
194
- if isawaitable(handler):
195
-
196
- def _menu_handler() -> None:
197
- task = cast("CommandHandlerNoArgs", handler)()
198
- task = cast("Coroutine[Any, Any, None]", task)
199
- if task is not None:
200
- get_app().create_background_task(task)
201
-
202
- return _menu_handler
203
- else:
204
- return cast("Callable[[], None]", handler)
205
-
206
194
  @property
207
195
  def menu(self) -> MenuItem:
208
196
  """Return a menu item for the command."""
@@ -222,6 +210,8 @@ def add_cmd(**kwargs: Any) -> Callable:
222
210
  def decorator(handler: Callable) -> Callable:
223
211
  cmd = Command(handler, **kwargs)
224
212
  commands[cmd.name] = cmd
213
+ for alias in cmd.aliases:
214
+ commands[alias] = cmd
225
215
  return handler
226
216
 
227
217
  return decorator
@@ -3,16 +3,17 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import logging
6
- from typing import TYPE_CHECKING, AsyncGenerator, Iterable
6
+ from typing import TYPE_CHECKING
7
7
 
8
8
  from prompt_toolkit.completion.base import CompleteEvent, Completer, Completion
9
9
 
10
10
  if TYPE_CHECKING:
11
+ from collections.abc import AsyncGenerator, Iterable
11
12
  from pathlib import Path
12
13
 
13
14
  from prompt_toolkit.document import Document
14
15
 
15
- from euporie.core.kernel import Kernel
16
+ from euporie.core.kernel.client import Kernel
16
17
  from euporie.core.lsp import LspClient
17
18
 
18
19
  log = logging.getLogger(__name__)