euporie 2.8.6__py3-none-any.whl → 2.8.7__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 (64) hide show
  1. euporie/console/app.py +2 -0
  2. euporie/console/tabs/console.py +27 -17
  3. euporie/core/__init__.py +2 -2
  4. euporie/core/app/_commands.py +4 -21
  5. euporie/core/app/app.py +13 -7
  6. euporie/core/bars/command.py +9 -6
  7. euporie/core/bars/search.py +43 -2
  8. euporie/core/border.py +7 -2
  9. euporie/core/comm/base.py +2 -2
  10. euporie/core/comm/ipywidgets.py +3 -3
  11. euporie/core/commands.py +44 -8
  12. euporie/core/completion.py +14 -6
  13. euporie/core/convert/datum.py +7 -7
  14. euporie/core/data_structures.py +20 -1
  15. euporie/core/filters.py +8 -0
  16. euporie/core/ft/html.py +47 -40
  17. euporie/core/graphics.py +11 -3
  18. euporie/core/history.py +15 -5
  19. euporie/core/inspection.py +16 -9
  20. euporie/core/kernel/__init__.py +53 -1
  21. euporie/core/kernel/base.py +571 -0
  22. euporie/core/kernel/{client.py → jupyter.py} +173 -430
  23. euporie/core/kernel/{manager.py → jupyter_manager.py} +4 -3
  24. euporie/core/kernel/local.py +694 -0
  25. euporie/core/key_binding/bindings/basic.py +6 -3
  26. euporie/core/keys.py +26 -25
  27. euporie/core/layout/cache.py +31 -7
  28. euporie/core/layout/containers.py +88 -13
  29. euporie/core/layout/scroll.py +45 -148
  30. euporie/core/log.py +1 -1
  31. euporie/core/style.py +2 -1
  32. euporie/core/suggest.py +155 -74
  33. euporie/core/tabs/__init__.py +10 -0
  34. euporie/core/tabs/_commands.py +76 -0
  35. euporie/core/tabs/_settings.py +16 -0
  36. euporie/core/tabs/base.py +22 -8
  37. euporie/core/tabs/kernel.py +81 -35
  38. euporie/core/tabs/notebook.py +14 -22
  39. euporie/core/utils.py +1 -1
  40. euporie/core/validation.py +8 -8
  41. euporie/core/widgets/_settings.py +19 -2
  42. euporie/core/widgets/cell.py +31 -31
  43. euporie/core/widgets/cell_outputs.py +10 -1
  44. euporie/core/widgets/dialog.py +30 -75
  45. euporie/core/widgets/forms.py +71 -59
  46. euporie/core/widgets/inputs.py +7 -4
  47. euporie/core/widgets/layout.py +281 -93
  48. euporie/core/widgets/menu.py +55 -15
  49. euporie/core/widgets/palette.py +3 -1
  50. euporie/core/widgets/tree.py +86 -76
  51. euporie/notebook/app.py +35 -16
  52. euporie/notebook/tabs/edit.py +4 -4
  53. euporie/notebook/tabs/json.py +6 -2
  54. euporie/notebook/tabs/notebook.py +26 -8
  55. euporie/preview/tabs/notebook.py +17 -13
  56. euporie/web/tabs/web.py +22 -3
  57. euporie/web/widgets/webview.py +3 -0
  58. {euporie-2.8.6.dist-info → euporie-2.8.7.dist-info}/METADATA +1 -1
  59. {euporie-2.8.6.dist-info → euporie-2.8.7.dist-info}/RECORD +64 -61
  60. {euporie-2.8.6.dist-info → euporie-2.8.7.dist-info}/entry_points.txt +1 -1
  61. {euporie-2.8.6.dist-info → euporie-2.8.7.dist-info}/licenses/LICENSE +1 -1
  62. {euporie-2.8.6.data → euporie-2.8.7.data}/data/share/applications/euporie-console.desktop +0 -0
  63. {euporie-2.8.6.data → euporie-2.8.7.data}/data/share/applications/euporie-notebook.desktop +0 -0
  64. {euporie-2.8.6.dist-info → euporie-2.8.7.dist-info}/WHEEL +0 -0
@@ -0,0 +1,76 @@
1
+ """Contains commands for tabs."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+
7
+ from euporie.core.commands import add_cmd
8
+ from euporie.core.filters import tab_can_save, tab_has_focus
9
+
10
+ log = logging.getLogger(__name__)
11
+
12
+
13
+ @add_cmd(filter=tab_can_save, aliases=["w"])
14
+ def _save_file(path: str = "") -> None:
15
+ """Save the current file."""
16
+ from euporie.core.app.current import get_app
17
+
18
+ if (tab := get_app().tab) is not None:
19
+ from upath import UPath
20
+
21
+ try:
22
+ tab._save(UPath(path) if path else None)
23
+ except NotImplementedError:
24
+ pass
25
+
26
+
27
+ @add_cmd(aliases=["wq", "x"])
28
+ def _save_and_quit(path: str = "") -> None:
29
+ """Save the current tab then quits euporie."""
30
+ from euporie.core.app.current import get_app
31
+
32
+ app = get_app()
33
+ if (tab := app.tab) is not None:
34
+ from upath import UPath
35
+
36
+ try:
37
+ tab.save(UPath(path) if path else None)
38
+ except NotImplementedError:
39
+ pass
40
+
41
+ app.exit()
42
+
43
+
44
+ @add_cmd(
45
+ menu_title="Save As…",
46
+ filter=tab_can_save,
47
+ )
48
+ def _save_as(path: str = "") -> None:
49
+ """Save the current file at a new location."""
50
+ if path:
51
+ _save_file(path)
52
+ else:
53
+ from euporie.core.app.current import get_app
54
+
55
+ app = get_app()
56
+ if dialog := app.dialogs.get("save-as"):
57
+ dialog.show(tab=app.tab)
58
+
59
+
60
+ @add_cmd(filter=tab_has_focus, title="Refresh the current tab")
61
+ def _refresh_tab() -> None:
62
+ """Reload the tab contents and reset the tab."""
63
+ from euporie.core.app.current import get_app
64
+
65
+ if (tab := get_app().tab) is not None:
66
+ tab.reset()
67
+
68
+
69
+ # Depreciated v2.5.0
70
+ @add_cmd(filter=tab_has_focus, title="Reset the current tab")
71
+ def _reset_tab() -> None:
72
+ log.warning(
73
+ "The `reset-tab` command was been renamed to `refresh-tab` in v2.5.0,"
74
+ " and will be removed in a future version"
75
+ )
76
+ _refresh_tab()
@@ -4,6 +4,22 @@ from prompt_toolkit.filters import buffer_has_focus
4
4
 
5
5
  from euporie.core.config import add_setting
6
6
 
7
+ add_setting(
8
+ name="backup_on_save",
9
+ group="euporie.core.tabs.base",
10
+ flags=["--backup-on-save"],
11
+ type_=bool,
12
+ help_="Create backups before saving files",
13
+ default=False,
14
+ description="""
15
+ Determines whether a backup file should be created before saving a file.
16
+
17
+ If set to ``True``, the original file will be copied to a new file with the
18
+ same name but prefixed with ``.`` and suffixed with ``.bak`` before writing the
19
+ updated contents.
20
+ """,
21
+ )
22
+
7
23
  add_setting(
8
24
  name="kernel_name",
9
25
  group="euporie.core.tabs.kernel",
euporie/core/tabs/base.py CHANGED
@@ -22,11 +22,13 @@ from euporie.core.layout.containers import Window
22
22
  from euporie.core.path import UntitledPath, parse_path
23
23
 
24
24
  if TYPE_CHECKING:
25
+ from collections.abc import Sequence
25
26
  from pathlib import Path
26
27
  from typing import Any, Callable
27
28
 
28
29
  from prompt_toolkit.key_binding.key_processor import KeyPressEvent
29
30
  from prompt_toolkit.layout.containers import AnyContainer
31
+ from prompt_toolkit.layout.controls import BufferControl
30
32
 
31
33
  from euporie.core.app.app import BaseApp
32
34
  from euporie.core.bars.status import StatusBarFields
@@ -133,13 +135,14 @@ class Tab(metaclass=ABCMeta):
133
135
  if not name.startswith("."):
134
136
  name = f".{name}"
135
137
  backup_path = parent / name
136
- try:
137
- import shutil
138
+ if self.app.config.backup_on_save:
139
+ try:
140
+ import shutil
138
141
 
139
- shutil.copy2(path, backup_path)
140
- except Exception as e:
141
- log.error("Failed to create backup: %s", e)
142
- raise
142
+ shutil.copy2(path, backup_path)
143
+ except Exception as e:
144
+ log.error("Failed to create backup: %s", e)
145
+ raise
143
146
 
144
147
  # Write new content directly to original file
145
148
  try:
@@ -179,6 +182,17 @@ class Tab(metaclass=ABCMeta):
179
182
  f"File saving not implement for `{self.__class__.__name__}` tab"
180
183
  )
181
184
 
185
+ def __pt_searchables__(self) -> Sequence[BufferControl]:
186
+ """Return a list of searchable buffer controls for this tab.
187
+
188
+ Returns:
189
+ A list of searchable buffer controls
190
+
191
+ Raises:
192
+ NotImplementedError: If the tab does not provide searchable buffers
193
+ """
194
+ raise NotImplementedError()
195
+
182
196
  def __pt_status__(self) -> StatusBarFields | None:
183
197
  """Return a list of statusbar field values shown then this tab is active."""
184
198
  return ([], [])
@@ -208,11 +222,11 @@ class Tab(metaclass=ABCMeta):
208
222
 
209
223
  @staticmethod
210
224
  @add_cmd(filter=tab_can_save, aliases=["w"])
211
- def _save_file(event: KeyPressEvent) -> None:
225
+ def _save_file(event: KeyPressEvent, path: str = "") -> None:
212
226
  """Save the current file."""
213
227
  if (tab := get_app().tab) is not None:
214
228
  try:
215
- tab._save(UPath(event._arg) if event._arg else None)
229
+ tab._save(UPath(path) if path else None)
216
230
  except NotImplementedError:
217
231
  pass
218
232
 
@@ -6,11 +6,11 @@ import asyncio
6
6
  import logging
7
7
  from abc import ABCMeta
8
8
  from collections import deque
9
- from functools import partial
9
+ from functools import lru_cache, partial
10
10
  from typing import TYPE_CHECKING
11
11
  from weakref import WeakKeyDictionary
12
12
 
13
- from prompt_toolkit.auto_suggest import DummyAutoSuggest
13
+ from prompt_toolkit.auto_suggest import DummyAutoSuggest, DynamicAutoSuggest
14
14
  from prompt_toolkit.completion.base import (
15
15
  DynamicCompleter,
16
16
  _MergedCompleter,
@@ -30,8 +30,8 @@ from euporie.core.inspection import (
30
30
  KernelInspector,
31
31
  LspInspector,
32
32
  )
33
- from euporie.core.kernel.client import Kernel, MsgCallbacks
34
- from euporie.core.suggest import HistoryAutoSuggest
33
+ from euporie.core.kernel import list_kernels
34
+ from euporie.core.kernel.base import NoKernel
35
35
  from euporie.core.tabs.base import Tab
36
36
 
37
37
  if TYPE_CHECKING:
@@ -47,16 +47,33 @@ if TYPE_CHECKING:
47
47
  from euporie.core.comm.base import Comm
48
48
  from euporie.core.format import Formatter
49
49
  from euporie.core.inspection import Inspector
50
+ from euporie.core.kernel.base import BaseKernel, KernelFactory, MsgCallbacks
50
51
  from euporie.core.lsp import LspClient
51
52
  from euporie.core.widgets.inputs import KernelInput
52
53
 
53
54
  log = logging.getLogger(__name__)
54
55
 
55
56
 
57
+ @lru_cache
58
+ def autosuggest_factory(kind: str, history: History) -> AutoSuggest:
59
+ """Generate autosuggesters."""
60
+ if kind == "smart":
61
+ from euporie.core.suggest import SmartHistoryAutoSuggest
62
+
63
+ return SmartHistoryAutoSuggest(history)
64
+ elif kind == "simple":
65
+ from euporie.core.suggest import SimpleHistoryAutoSuggest
66
+
67
+ return SimpleHistoryAutoSuggest(history)
68
+ else:
69
+ from prompt_toolkit.auto_suggest import DummyAutoSuggest
70
+
71
+ return DummyAutoSuggest()
72
+
73
+
56
74
  class KernelTab(Tab, metaclass=ABCMeta):
57
75
  """A Tab which connects to a kernel."""
58
76
 
59
- kernel: Kernel
60
77
  kernel_language: str
61
78
  _metadata: dict[str, Any]
62
79
  bg_init = False
@@ -68,7 +85,7 @@ class KernelTab(Tab, metaclass=ABCMeta):
68
85
  self,
69
86
  app: BaseApp,
70
87
  path: Path | None = None,
71
- kernel: Kernel | None = None,
88
+ kernel: BaseKernel | None = None,
72
89
  comms: dict[str, Comm] | None = None,
73
90
  use_kernel_history: bool = False,
74
91
  connection_file: Path | None = None,
@@ -77,6 +94,7 @@ class KernelTab(Tab, metaclass=ABCMeta):
77
94
  # Init tab
78
95
  super().__init__(app, path)
79
96
 
97
+ self.kernel: BaseKernel = NoKernel(self)
80
98
  self.lsps: list[LspClient] = []
81
99
  self.history: History = DummyHistory()
82
100
  self.inspectors: list[Inspector] = []
@@ -182,10 +200,12 @@ class KernelTab(Tab, metaclass=ABCMeta):
182
200
 
183
201
  def post_init_kernel(self) -> None:
184
202
  """Run stuff after the kernel is loaded."""
203
+ if not isinstance(self.kernel, NoKernel):
204
+ self.metadata["kernelspec"] = self.kernel.spec
185
205
 
186
206
  def init_kernel(
187
207
  self,
188
- kernel: Kernel | None = None,
208
+ kernel: BaseKernel | None = None,
189
209
  comms: dict[str, Comm] | None = None,
190
210
  use_kernel_history: bool = False,
191
211
  connection_file: Path | None = None,
@@ -199,20 +219,47 @@ class KernelTab(Tab, metaclass=ABCMeta):
199
219
  self.kernel = kernel
200
220
  self.kernel.default_callbacks = self.default_callbacks
201
221
  else:
202
- self.kernel = Kernel(
222
+ from euporie.core.kernel import list_kernels
223
+
224
+ kernel_infos = list_kernels()
225
+ kernel_name = self.kernel_name or self.app.config.kernel_name
226
+ for info in kernel_infos:
227
+ if info.name == kernel_name:
228
+ factory = info.factory
229
+ break
230
+ else:
231
+ msg = (
232
+ f"Kernel '{self.kernel_display_name}' not found"
233
+ if self.kernel_name
234
+ else "No kernel selected"
235
+ )
236
+ self.change_kernel(msg=msg, startup=True)
237
+ return
238
+ self.kernel = factory(
203
239
  kernel_tab=self,
204
240
  allow_stdin=self.allow_stdin,
205
241
  default_callbacks=self.default_callbacks,
206
- connection_file=connection_file,
242
+ **(
243
+ {"connection_file": connection_file}
244
+ if connection_file is not None
245
+ else {}
246
+ ),
207
247
  )
248
+
208
249
  self.comms = comms or {} # The client-side comm states
209
- self.completers.append(KernelCompleter(self.kernel))
210
- self.inspectors.append(KernelInspector(self.kernel))
250
+ self.completers.append(KernelCompleter(lambda: self.kernel))
251
+ self.inspectors.append(KernelInspector(lambda: self.kernel))
211
252
  self.use_kernel_history = use_kernel_history
212
253
  self.history = (
213
- KernelHistory(self.kernel) if use_kernel_history else InMemoryHistory()
254
+ KernelHistory(lambda: self.kernel)
255
+ if use_kernel_history
256
+ else InMemoryHistory()
214
257
  )
215
- self.suggester = HistoryAutoSuggest(self.history)
258
+
259
+ def _get_suggester() -> AutoSuggest | None:
260
+ return autosuggest_factory(self.app.config.autosuggest, self.history)
261
+
262
+ self.suggester = DynamicAutoSuggest(_get_suggester)
216
263
 
217
264
  self.app.create_background_task(self.load_lsps())
218
265
 
@@ -220,7 +267,7 @@ class KernelTab(Tab, metaclass=ABCMeta):
220
267
 
221
268
  def close(self, cb: Callable | None = None) -> None:
222
269
  """Shut down kernel when tab is closed."""
223
- if hasattr(self, "kernel"):
270
+ if self.kernel is not None:
224
271
  self.kernel.shutdown()
225
272
  super().close(cb)
226
273
 
@@ -232,6 +279,7 @@ class KernelTab(Tab, metaclass=ABCMeta):
232
279
  """Restart the current `Notebook`'s kernel."""
233
280
 
234
281
  def _cb(result: dict[str, Any]) -> None:
282
+ self.kernel_started()
235
283
  if callable(cb):
236
284
  cb()
237
285
 
@@ -245,18 +293,8 @@ class KernelTab(Tab, metaclass=ABCMeta):
245
293
 
246
294
  def kernel_started(self, result: dict[str, Any] | None = None) -> None:
247
295
  """Task to run when the kernel has started."""
248
- # Check kernel has not failed
249
- if not self.kernel_name or self.kernel.missing:
250
- if not self.kernel_name:
251
- msg = "No kernel selected"
252
- else:
253
- msg = f"Kernel '{self.kernel_display_name}' not installed"
254
- self.change_kernel(
255
- msg=msg,
256
- startup=True,
257
- )
258
-
259
- elif self.kernel.status == "error":
296
+ # Set kernel spec in metadata
297
+ if self.kernel.status == "error":
260
298
  self.report_kernel_error(self.kernel.error)
261
299
 
262
300
  else:
@@ -300,9 +338,7 @@ class KernelTab(Tab, metaclass=ABCMeta):
300
338
  @property
301
339
  def kernel_name(self) -> str:
302
340
  """Return the name of the kernel defined in the notebook JSON."""
303
- return self.metadata.get("kernelspec", {}).get(
304
- "name", self.app.config.kernel_name
305
- )
341
+ return self.metadata.get("kernelspec", {}).get("name", "")
306
342
 
307
343
  @kernel_name.setter
308
344
  def kernel_name(self, value: str) -> None:
@@ -337,22 +373,32 @@ class KernelTab(Tab, metaclass=ABCMeta):
337
373
 
338
374
  def change_kernel(self, msg: str | None = None, startup: bool = False) -> None:
339
375
  """Prompt the user to select a new kernel."""
340
- kernel_specs = self.kernel.specs
376
+ kernel_infos = list_kernels()
341
377
 
342
378
  # Warn the user if no kernels are installed
343
- if not kernel_specs:
379
+ if not kernel_infos:
344
380
  if startup and "no-kernels" in self.app.dialogs:
345
381
  self.app.dialogs["no-kernels"].show()
346
382
  return
347
383
 
348
384
  # Automatically select the only kernel if there is only one
349
- if startup and len(kernel_specs) == 1:
350
- self.kernel.change(next(iter(kernel_specs)))
385
+ if startup and len(kernel_infos) == 1:
386
+ self.switch_kernel(next(iter(kernel_infos)).factory)
351
387
  return
352
388
 
353
- self.app.dialogs["change-kernel"].show(
354
- tab=self, message=msg, kernel_specs=kernel_specs
389
+ # Prompt user to select a kernel
390
+ self.app.dialogs["change-kernel"].show(tab=self, message=msg)
391
+
392
+ def switch_kernel(self, factory: KernelFactory) -> None:
393
+ """Shut down the current kernel and change to another."""
394
+ if (old_kernel := self.kernel) is not None:
395
+ old_kernel.shutdown(wait=True)
396
+ kernel = factory(
397
+ kernel_tab=self,
398
+ default_callbacks=self.default_callbacks,
399
+ allow_stdin=self.allow_stdin,
355
400
  )
401
+ self.init_kernel(kernel)
356
402
 
357
403
  def comm_open(self, content: dict, buffers: Sequence[bytes]) -> None:
358
404
  """Register a new kernel Comm object in the notebook."""
@@ -12,10 +12,8 @@ import nbformat
12
12
  from prompt_toolkit.filters import Never
13
13
 
14
14
  from euporie.core.comm.registry import open_comm
15
- from euporie.core.commands import get_cmd
16
15
  from euporie.core.io import edit_in_editor
17
- from euporie.core.kernel.client import MsgCallbacks
18
- from euporie.core.path import UntitledPath
16
+ from euporie.core.kernel.base import MsgCallbacks
19
17
  from euporie.core.tabs.kernel import KernelTab
20
18
  from euporie.core.widgets.cell import Cell, get_cell_id
21
19
 
@@ -27,15 +25,17 @@ except ModuleNotFoundError:
27
25
  from nbformat import write as write_nb
28
26
 
29
27
  if TYPE_CHECKING:
28
+ from collections.abc import Sequence
30
29
  from pathlib import Path
31
30
  from typing import Any, Callable
32
31
 
33
32
  from prompt_toolkit.filters import Filter
34
33
  from prompt_toolkit.layout.containers import AnyContainer
34
+ from prompt_toolkit.layout.controls import BufferControl
35
35
 
36
36
  from euporie.core.app.app import BaseApp
37
37
  from euporie.core.comm.base import Comm
38
- from euporie.core.kernel.client import Kernel
38
+ from euporie.core.kernel.base import BaseKernel
39
39
  from euporie.core.lsp import LspClient
40
40
  from euporie.core.widgets.inputs import KernelInput
41
41
 
@@ -52,7 +52,7 @@ class BaseNotebook(KernelTab, metaclass=ABCMeta):
52
52
  self,
53
53
  app: BaseApp,
54
54
  path: Path | None = None,
55
- kernel: Kernel | None = None,
55
+ kernel: BaseKernel | None = None,
56
56
  comms: dict[str, Comm] | None = None,
57
57
  use_kernel_history: bool = False,
58
58
  json: dict[str, Any] | None = None,
@@ -92,6 +92,9 @@ class BaseNotebook(KernelTab, metaclass=ABCMeta):
92
92
  app, path, kernel=kernel, comms=comms, use_kernel_history=use_kernel_history
93
93
  )
94
94
 
95
+ # Load notebook file
96
+ self.container = self.load_container()
97
+
95
98
  # Tab stuff
96
99
 
97
100
  def reset(self) -> None:
@@ -104,24 +107,10 @@ class BaseNotebook(KernelTab, metaclass=ABCMeta):
104
107
 
105
108
  # KernelTab stuff
106
109
 
107
- def pre_init_kernel(self) -> None:
108
- """Run stuff before the kernel is loaded."""
109
- super().pre_init_kernel()
110
- # Load notebook file
111
- self.load()
112
-
113
110
  def post_init_kernel(self) -> None:
114
111
  """Load the notebook container after the kernel has been loaded."""
115
112
  super().post_init_kernel()
116
113
 
117
- # Replace the tab's container
118
- prev = self.container
119
- self.container = self.load_container()
120
- self.loaded = True
121
- # Update the focus if the old container had focus
122
- if self.app.layout.has_focus(prev):
123
- self.focus()
124
-
125
114
  # Load widgets
126
115
  self.load_widgets_from_metadata()
127
116
 
@@ -179,8 +168,7 @@ class BaseNotebook(KernelTab, metaclass=ABCMeta):
179
168
 
180
169
  @abstractmethod
181
170
  def load_container(self) -> AnyContainer:
182
- """Abcract method for loading the notebook's main container."""
183
- ...
171
+ """Absract method for loading the notebook's main container."""
184
172
 
185
173
  @abstractproperty
186
174
  def cell(self) -> Cell:
@@ -270,7 +258,7 @@ class BaseNotebook(KernelTab, metaclass=ABCMeta):
270
258
  if self.dirty and (unsaved := self.app.dialogs.get("unsaved")):
271
259
  unsaved.show(
272
260
  tab=self,
273
- cb=cb,
261
+ cb=partial(super().close, cb),
274
262
  )
275
263
  else:
276
264
  super().close(cb)
@@ -422,3 +410,7 @@ class BaseNotebook(KernelTab, metaclass=ABCMeta):
422
410
  def lsp_update_diagnostics(self, lsp: LspClient) -> None:
423
411
  """Process a new diagnostic report from the LSP."""
424
412
  # Do nothing, these are handled by cells
413
+
414
+ def __pt_searchables__(self) -> Sequence[BufferControl]:
415
+ """Return list of cell input buffer controls for searching."""
416
+ return [cell.input_box.control for cell in self.rendered_cells()]
euporie/core/utils.py CHANGED
@@ -1,4 +1,4 @@
1
- """Miscellaneou utility classes."""
1
+ """Miscellaneous utility classes."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -9,29 +9,29 @@ 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.client import Kernel
12
+ from euporie.core.kernel.base import BaseKernel
13
13
 
14
14
 
15
15
  class KernelValidator(Validator):
16
16
  """Validate kernel input using a kernel code completeness call."""
17
17
 
18
- def __init__(self, kernel: Kernel) -> None:
18
+ def __init__(self, kernel: BaseKernel) -> None:
19
19
  """Initialize the validator."""
20
20
  self.kernel = kernel
21
21
 
22
22
  def validate(self, document: Document) -> None:
23
23
  """Validate the input synchronously."""
24
- completeness_status = self.kernel.is_complete(
25
- code=document.text, wait=True
26
- ).get("status", "unknown")
24
+ completeness_status = self.kernel.is_complete(source=document.text).get(
25
+ "status", "unknown"
26
+ )
27
27
  if completeness_status == "incomplete":
28
28
  raise ValidationError
29
29
 
30
30
  async def validate_async(self, document: Document) -> None:
31
31
  """Return a `Future` which is set when the validation is ready."""
32
- completeness_status = (await self.kernel.is_complete_(code=document.text)).get(
33
- "status", "unknown"
34
- )
32
+ completeness_status = (
33
+ await self.kernel.is_complete_async(source=document.text)
34
+ ).get("status", "unknown")
35
35
  if completeness_status == "incomplete":
36
36
  raise ValidationError
37
37
  return
@@ -22,6 +22,22 @@ add_setting(
22
22
  cmd_filter=~buffer_has_focus,
23
23
  )
24
24
 
25
+ add_setting(
26
+ name="text_output_limit",
27
+ group="euporie.core.widgets.cell_outputs",
28
+ flags=["--text-output-limit"],
29
+ type_=int,
30
+ help_="Limit the amount of cell text output",
31
+ default=1_000_000,
32
+ schema={
33
+ "minimum": 0,
34
+ },
35
+ description="""
36
+ Limit the number of text characters in interactive cell text output to this value.
37
+ Use ``0`` to allow any amount of characters.
38
+ """,
39
+ )
40
+
25
41
  # euporie,core.widgets.file_browser:FileBrowser
26
42
 
27
43
  add_setting(
@@ -86,9 +102,10 @@ add_setting(
86
102
  name="autosuggest",
87
103
  group="euporie.core.widgets.inputs",
88
104
  flags=["--autosuggest"],
89
- type_=bool,
105
+ type_=str,
106
+ choices=["smart", "simple", "none"],
90
107
  help_="Provide line completion suggestions",
91
- default=True,
108
+ default="smart",
92
109
  description="""
93
110
  Whether to automatically suggestion line content while typing in code cells.
94
111
  """,