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.
Files changed (129) 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 +267 -147
  5. euporie/core/__init__.py +1 -9
  6. euporie/core/__main__.py +31 -5
  7. euporie/core/_settings.py +104 -0
  8. euporie/core/app/__init__.py +3 -0
  9. euporie/core/app/_commands.py +70 -0
  10. euporie/core/app/_settings.py +427 -0
  11. euporie/core/{app.py → app/app.py} +214 -572
  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 +182 -0
  19. euporie/core/bars/menu.py +258 -0
  20. euporie/core/{widgets → bars}/search.py +154 -57
  21. euporie/core/{widgets → bars}/status.py +9 -26
  22. euporie/core/clipboard.py +19 -80
  23. euporie/core/comm/base.py +8 -6
  24. euporie/core/comm/ipywidgets.py +21 -12
  25. euporie/core/comm/registry.py +2 -1
  26. euporie/core/commands.py +11 -5
  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 +131 -60
  31. euporie/core/convert/formats/__init__.py +31 -0
  32. euporie/core/convert/formats/ansi.py +46 -30
  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 +11 -8
  39. euporie/core/convert/utils.py +50 -23
  40. euporie/core/diagnostics.py +2 -2
  41. euporie/core/filters.py +72 -82
  42. euporie/core/format.py +13 -2
  43. euporie/core/ft/ansi.py +1 -1
  44. euporie/core/ft/html.py +36 -36
  45. euporie/core/ft/table.py +1 -3
  46. euporie/core/ft/utils.py +4 -1
  47. euporie/core/graphics.py +216 -124
  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} +100 -139
  53. euporie/core/kernel/manager.py +114 -0
  54. euporie/core/key_binding/bindings/__init__.py +2 -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 +5 -7
  58. euporie/core/key_binding/bindings/mouse.py +26 -24
  59. euporie/core/key_binding/bindings/terminal.py +193 -0
  60. euporie/core/key_binding/bindings/vi.py +46 -0
  61. euporie/core/key_binding/key_processor.py +43 -2
  62. euporie/core/key_binding/registry.py +2 -0
  63. euporie/core/key_binding/utils.py +22 -2
  64. euporie/core/keys.py +7156 -93
  65. euporie/core/layout/cache.py +35 -25
  66. euporie/core/layout/containers.py +280 -74
  67. euporie/core/layout/decor.py +5 -5
  68. euporie/core/layout/mouse.py +1 -1
  69. euporie/core/layout/print.py +16 -3
  70. euporie/core/layout/scroll.py +26 -28
  71. euporie/core/log.py +75 -60
  72. euporie/core/lsp.py +118 -24
  73. euporie/core/margins.py +60 -31
  74. euporie/core/path.py +2 -1
  75. euporie/core/renderer.py +58 -17
  76. euporie/core/style.py +60 -40
  77. euporie/core/suggest.py +103 -85
  78. euporie/core/tabs/__init__.py +34 -0
  79. euporie/core/tabs/_settings.py +113 -0
  80. euporie/core/tabs/base.py +11 -435
  81. euporie/core/tabs/kernel.py +420 -0
  82. euporie/core/tabs/notebook.py +20 -54
  83. euporie/core/utils.py +98 -6
  84. euporie/core/validation.py +1 -1
  85. euporie/core/widgets/_settings.py +188 -0
  86. euporie/core/widgets/cell.py +90 -158
  87. euporie/core/widgets/cell_outputs.py +25 -36
  88. euporie/core/widgets/decor.py +11 -41
  89. euporie/core/widgets/dialog.py +55 -44
  90. euporie/core/widgets/display.py +27 -24
  91. euporie/core/widgets/file_browser.py +5 -26
  92. euporie/core/widgets/forms.py +16 -12
  93. euporie/core/widgets/inputs.py +37 -81
  94. euporie/core/widgets/layout.py +7 -6
  95. euporie/core/widgets/logo.py +49 -0
  96. euporie/core/widgets/menu.py +13 -11
  97. euporie/core/widgets/pager.py +8 -11
  98. euporie/core/widgets/palette.py +6 -6
  99. euporie/hub/app.py +52 -31
  100. euporie/notebook/_commands.py +24 -0
  101. euporie/notebook/_settings.py +107 -0
  102. euporie/notebook/app.py +109 -210
  103. euporie/notebook/filters.py +1 -1
  104. euporie/notebook/tabs/__init__.py +46 -7
  105. euporie/notebook/tabs/_commands.py +714 -0
  106. euporie/notebook/tabs/_settings.py +32 -0
  107. euporie/notebook/tabs/display.py +2 -2
  108. euporie/notebook/tabs/edit.py +12 -7
  109. euporie/notebook/tabs/json.py +3 -3
  110. euporie/notebook/tabs/log.py +1 -18
  111. euporie/notebook/tabs/notebook.py +21 -674
  112. euporie/notebook/widgets/_commands.py +11 -0
  113. euporie/notebook/widgets/_settings.py +19 -0
  114. euporie/notebook/widgets/side_bar.py +14 -34
  115. euporie/preview/_settings.py +104 -0
  116. euporie/preview/app.py +8 -30
  117. euporie/preview/tabs/notebook.py +15 -86
  118. euporie/web/tabs/web.py +4 -6
  119. euporie/web/widgets/webview.py +5 -12
  120. {euporie-2.8.1.dist-info → euporie-2.8.5.dist-info}/METADATA +11 -15
  121. euporie-2.8.5.dist-info/RECORD +172 -0
  122. {euporie-2.8.1.dist-info → euporie-2.8.5.dist-info}/WHEEL +1 -1
  123. {euporie-2.8.1.dist-info → euporie-2.8.5.dist-info}/entry_points.txt +2 -2
  124. {euporie-2.8.1.dist-info → euporie-2.8.5.dist-info}/licenses/LICENSE +1 -1
  125. euporie/core/launch.py +0 -59
  126. euporie/core/terminal.py +0 -527
  127. euporie-2.8.1.dist-info/RECORD +0 -146
  128. {euporie-2.8.1.data → euporie-2.8.5.data}/data/share/applications/euporie-console.desktop +0 -0
  129. {euporie-2.8.1.data → euporie-2.8.5.data}/data/share/applications/euporie-notebook.desktop +0 -0
euporie/core/tabs/base.py CHANGED
@@ -1,65 +1,35 @@
1
- """Contain tab base classes."""
1
+ """Contain tab base class."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import asyncio
6
5
  import logging
7
6
  from abc import ABCMeta
8
- from collections import deque
9
- from functools import partial
10
7
  from typing import TYPE_CHECKING, ClassVar
11
- from weakref import WeakKeyDictionary
12
8
 
13
- from prompt_toolkit.auto_suggest import DummyAutoSuggest
14
- from prompt_toolkit.completion.base import (
15
- DynamicCompleter,
16
- _MergedCompleter,
17
- )
18
- from prompt_toolkit.history import DummyHistory, InMemoryHistory
19
9
  from prompt_toolkit.layout.containers import WindowAlign
20
10
  from prompt_toolkit.layout.controls import FormattedTextControl
21
11
  from prompt_toolkit.utils import Event
22
12
  from upath import UPath
23
13
 
24
- from euporie.core.comm.registry import open_comm
14
+ from euporie.core.app.current import get_app
25
15
  from euporie.core.commands import add_cmd
26
- from euporie.core.completion import DeduplicateCompleter, KernelCompleter, LspCompleter
27
- from euporie.core.config import add_setting
28
- from euporie.core.current import get_app
29
- from euporie.core.diagnostics import Report
30
- from euporie.core.filters import kernel_tab_has_focus, tab_has_focus
31
- from euporie.core.format import LspFormatter
32
- from euporie.core.history import KernelHistory
33
- from euporie.core.inspection import (
34
- FirstInspector,
35
- KernelInspector,
36
- LspInspector,
37
- )
38
- from euporie.core.kernel import Kernel, MsgCallbacks
16
+ from euporie.core.filters import tab_has_focus
39
17
  from euporie.core.key_binding.registry import (
40
18
  register_bindings,
41
19
  )
42
20
  from euporie.core.layout.containers import Window
43
21
  from euporie.core.path import parse_path
44
- from euporie.core.suggest import HistoryAutoSuggest
45
22
  from euporie.core.utils import run_in_thread_with_context
46
- from euporie.core.widgets.inputs import KernelInput
47
23
 
48
24
  if TYPE_CHECKING:
49
25
  from pathlib import Path
50
- from typing import Any, Callable, Sequence
26
+ from typing import Any, Callable
51
27
 
52
- from prompt_toolkit.auto_suggest import AutoSuggest
53
- from prompt_toolkit.completion.base import Completer
54
- from prompt_toolkit.history import History
28
+ from prompt_toolkit.key_binding.key_processor import KeyPressEvent
55
29
  from prompt_toolkit.layout.containers import AnyContainer
56
30
 
57
- from euporie.core.app import BaseApp
58
- from euporie.core.comm.base import Comm
59
- from euporie.core.format import Formatter
60
- from euporie.core.inspection import Inspector
61
- from euporie.core.lsp import LspClient
62
- from euporie.core.widgets.status import StatusBarFields
31
+ from euporie.core.app.app import BaseApp
32
+ from euporie.core.bars.status import StatusBarFields
63
33
 
64
34
  log = logging.getLogger(__name__)
65
35
 
@@ -140,7 +110,7 @@ class Tab(metaclass=ABCMeta):
140
110
  run_in_thread_with_context(self.save, path, _wrapped_cb)
141
111
 
142
112
  def save(self, path: Path | None = None, cb: Callable | None = None) -> None:
143
- """Save the current notebook."""
113
+ """Save the current tab."""
144
114
  raise NotImplementedError
145
115
 
146
116
  def __pt_status__(self) -> StatusBarFields | None:
@@ -171,12 +141,12 @@ class Tab(metaclass=ABCMeta):
171
141
  Tab._refresh_tab()
172
142
 
173
143
  @staticmethod
174
- @add_cmd(filter=tab_has_focus)
175
- def _save_file() -> None:
144
+ @add_cmd(filter=tab_has_focus, aliases=["w"])
145
+ def _save_file(event: KeyPressEvent) -> None:
176
146
  """Save the current file."""
177
147
  if (tab := get_app().tab) is not None:
178
148
  try:
179
- tab._save()
149
+ tab._save(UPath(event._arg) if event._arg else None)
180
150
  except NotImplementedError:
181
151
  pass
182
152
 
@@ -190,397 +160,3 @@ class Tab(metaclass=ABCMeta):
190
160
  }
191
161
  }
192
162
  )
193
-
194
-
195
- class KernelTab(Tab, metaclass=ABCMeta):
196
- """A Tab which connects to a kernel."""
197
-
198
- kernel: Kernel
199
- kernel_language: str
200
- _metadata: dict[str, Any]
201
- bg_init = True
202
-
203
- default_callbacks: MsgCallbacks
204
- allow_stdin: bool
205
-
206
- def __init__(
207
- self,
208
- app: BaseApp,
209
- path: Path | None = None,
210
- kernel: Kernel | None = None,
211
- comms: dict[str, Comm] | None = None,
212
- use_kernel_history: bool = False,
213
- connection_file: Path | None = None,
214
- ) -> None:
215
- """Create a new instance of a tab with a kernel."""
216
- # Init tab
217
- super().__init__(app, path)
218
-
219
- self.lsps: list[LspClient] = []
220
- self.history: History = DummyHistory()
221
- self.inspectors: list[Inspector] = []
222
- self.inspector = FirstInspector(lambda: self.inspectors)
223
- self.suggester: AutoSuggest = DummyAutoSuggest()
224
- self.completers: list[Completer] = []
225
- self.completer = DeduplicateCompleter(
226
- DynamicCompleter(lambda: _MergedCompleter(self.completers))
227
- )
228
- self.formatters: list[Formatter] = self.app.formatters
229
- self.reports: WeakKeyDictionary[LspClient, Report] = WeakKeyDictionary()
230
-
231
- # The client-side comm states
232
- self.comms: dict[str, Comm] = {}
233
- # The current kernel input
234
- self._current_input: KernelInput | None = None
235
-
236
- if self.bg_init:
237
- # Load kernel in a background thread
238
- run_in_thread_with_context(
239
- partial(
240
- self.init_kernel, kernel, comms, use_kernel_history, connection_file
241
- )
242
- )
243
- else:
244
- self.init_kernel(kernel, comms, use_kernel_history, connection_file)
245
-
246
- async def load_lsps(self) -> None:
247
- """Load the LSP clients."""
248
- path = self.path
249
-
250
- # Load list of LSP clients for the tab's language
251
- self.lsps.extend(self.app.get_language_lsps(self.language))
252
-
253
- # Wait for all lsps to be initialized, and setup hooks as they become ready
254
- async def _await_load(lsp: LspClient) -> LspClient:
255
- await lsp.initialized.wait()
256
- return lsp
257
-
258
- for ready in asyncio.as_completed([_await_load(lsp) for lsp in self.lsps]):
259
- lsp = await ready
260
- # Apply open, save, and close hooks to the tab
261
- change_handler = partial(lambda lsp, tab: self.lsp_change_handler(lsp), lsp)
262
- close_handler = partial(lambda lsp, tab: self.lsp_close_handler(lsp), lsp)
263
- before_save_handler = partial(
264
- lambda lsp, tab: self.lsp_before_save_handler(lsp), lsp
265
- )
266
- after_save_handler = partial(
267
- lambda lsp, tab: self.lsp_after_save_handler(lsp), lsp
268
- )
269
-
270
- self.on_close += close_handler
271
- self.on_change += change_handler
272
- self.before_save += before_save_handler
273
- self.after_save += after_save_handler
274
-
275
- # Listen for LSP diagnostics
276
- lsp.on_diagnostics += self.lsp_update_diagnostics
277
-
278
- # Add completer
279
- completer = LspCompleter(lsp=lsp, path=path)
280
- self.completers.append(completer)
281
-
282
- # Add inspector
283
- inspector = LspInspector(lsp, path)
284
- self.inspectors.append(inspector)
285
-
286
- # Add formatter
287
- formatter = LspFormatter(lsp, path)
288
- self.formatters.append(formatter)
289
-
290
- # Remove hooks if the LSP exits
291
- def lsp_unload(lsp: LspClient) -> None:
292
- self.on_change -= change_handler # noqa: B023
293
- self.before_save -= before_save_handler # noqa: B023
294
- self.after_save -= after_save_handler # noqa: B023
295
- self.on_close -= close_handler # noqa: B023
296
- if completer in self.completers: # noqa: B023
297
- self.completers.remove(completer) # noqa: B023
298
- if inspector in self.completers: # noqa: B023
299
- self.inspectors.remove(inspector) # noqa: B023
300
- if formatter in self.completers: # noqa: B023
301
- self.formatters.remove(formatter) # noqa: B023
302
- if completer in self.completers: # noqa: B023
303
- self.completers.remove(completer) # noqa: B023
304
- if inspector in self.inspectors: # noqa: B023
305
- self.inspectors.remove(inspector) # noqa: B023
306
- if formatter in self.formatters: # noqa: B023
307
- self.formatters.remove(formatter) # noqa: B023
308
-
309
- lsp.on_exit += lsp_unload
310
-
311
- # Remove the lsp exit handler if this tab closes
312
- self.on_close += lambda tab: (
313
- (lsp.on_exit.__isub__(lsp_unload) and None) or None # noqa: B023
314
- ) # Magical typing
315
-
316
- # Tell the LSP we have an open file
317
- self.lsp_open_handler(lsp)
318
-
319
- def pre_init_kernel(self) -> None:
320
- """Run stuff before the kernel is loaded."""
321
-
322
- def post_init_kernel(self) -> None:
323
- """Run stuff after the kernel is loaded."""
324
-
325
- def init_kernel(
326
- self,
327
- kernel: Kernel | None = None,
328
- comms: dict[str, Comm] | None = None,
329
- use_kernel_history: bool = False,
330
- connection_file: Path | None = None,
331
- ) -> None:
332
- """Set up the tab's kernel and related components."""
333
- self.pre_init_kernel()
334
-
335
- self.kernel_queue: deque[Callable] = deque()
336
-
337
- if kernel:
338
- self.kernel = kernel
339
- self.kernel.default_callbacks = self.default_callbacks
340
- else:
341
- self.kernel = Kernel(
342
- kernel_tab=self,
343
- allow_stdin=self.allow_stdin,
344
- default_callbacks=self.default_callbacks,
345
- connection_file=connection_file,
346
- )
347
- self.comms = comms or {} # The client-side comm states
348
- self.completers.append(KernelCompleter(self.kernel))
349
- self.inspectors.append(KernelInspector(self.kernel))
350
- self.use_kernel_history = use_kernel_history
351
- self.history = (
352
- KernelHistory(self.kernel) if use_kernel_history else InMemoryHistory()
353
- )
354
- self.suggester = HistoryAutoSuggest(self.history)
355
-
356
- self.app.create_background_task(self.load_lsps())
357
-
358
- self.post_init_kernel()
359
-
360
- def close(self, cb: Callable | None = None) -> None:
361
- """Shut down kernel when tab is closed."""
362
- if hasattr(self, "kernel"):
363
- self.kernel.shutdown()
364
- super().close(cb)
365
-
366
- def interrupt_kernel(self) -> None:
367
- """Interrupt the current `Notebook`'s kernel."""
368
- self.kernel.interrupt()
369
-
370
- def restart_kernel(self, cb: Callable | None = None) -> None:
371
- """Restart the current `Notebook`'s kernel."""
372
-
373
- def _cb(result: dict[str, Any]) -> None:
374
- if callable(cb):
375
- cb()
376
-
377
- if confirm := self.app.dialogs.get("confirm"):
378
- confirm.show(
379
- message="Are you sure you want to restart the kernel?",
380
- cb=partial(self.kernel.restart, cb=_cb),
381
- )
382
- else:
383
- self.kernel.restart(cb=_cb)
384
-
385
- def kernel_started(self, result: dict[str, Any] | None = None) -> None:
386
- """Task to run when the kernel has started."""
387
- # Check kernel has not failed
388
- if not self.kernel_name or self.kernel.missing:
389
- if not self.kernel_name:
390
- msg = "No kernel selected"
391
- else:
392
- msg = f"Kernel '{self.kernel_display_name}' not installed"
393
- self.change_kernel(
394
- msg=msg,
395
- startup=True,
396
- )
397
-
398
- elif self.kernel.status == "error":
399
- self.report_kernel_error(self.kernel.error)
400
-
401
- else:
402
- # Wait for an idle kernel
403
- if self.kernel.status != "idle":
404
- self.kernel.wait_for_status("idle")
405
-
406
- # Load widget comm info
407
- # self.kernel.comm_info(target_name="jupyter.widget")
408
-
409
- # Load kernel info
410
- self.kernel.info(set_kernel_info=self.set_kernel_info)
411
-
412
- # Load kernel history
413
- if self.use_kernel_history:
414
- self.app.create_background_task(self.load_history())
415
-
416
- # Run queued kernel tasks when the kernel is idle
417
- log.debug("Running %d kernel tasks", len(self.kernel_queue))
418
- while self.kernel_queue:
419
- self.kernel_queue.popleft()()
420
-
421
- self.app.invalidate()
422
-
423
- def report_kernel_error(self, error: Exception | None) -> None:
424
- """Report a kernel error to the user."""
425
- log.debug("Kernel error", exc_info=error)
426
-
427
- async def load_history(self) -> None:
428
- """Load kernel history."""
429
- try:
430
- await self.history.load().__anext__()
431
- except StopAsyncIteration:
432
- pass
433
-
434
- @property
435
- def metadata(self) -> dict[str, Any]:
436
- """Return a dictionary to hold notebook / kernel metadata."""
437
- return self._metadata
438
-
439
- @property
440
- def kernel_name(self) -> str:
441
- """Return the name of the kernel defined in the notebook JSON."""
442
- return self.metadata.get("kernelspec", {}).get(
443
- "name", self.app.config.kernel_name
444
- )
445
-
446
- @kernel_name.setter
447
- def kernel_name(self, value: str) -> None:
448
- """Return the name of the kernel defined in the notebook JSON."""
449
- self.metadata.setdefault("kernelspec", {})["name"] = value
450
-
451
- @property
452
- def language(self) -> str:
453
- """Return the name of the kernel defined in the notebook JSON."""
454
- return self.metadata.get("kernelspec", {}).get("language")
455
-
456
- @property
457
- def kernel_display_name(self) -> str:
458
- """Return the display name of the kernel defined in the notebook JSON."""
459
- return self.metadata.get("kernelspec", {}).get("display_name", self.kernel_name)
460
-
461
- @property
462
- def kernel_lang_file_ext(self) -> str:
463
- """Return the display name of the kernel defined in the notebook JSON."""
464
- return self.metadata.get("language_info", {}).get("file_extension", ".py")
465
-
466
- @property
467
- def current_input(self) -> KernelInput:
468
- """Return the currently active kernel input, if any."""
469
- return self._current_input or KernelInput(self)
470
-
471
- def set_kernel_info(self, info: dict) -> None:
472
- """Handle kernel info requests."""
473
- self.metadata["language_info"] = info.get("language_info", {})
474
-
475
- def change_kernel(self, msg: str | None = None, startup: bool = False) -> None:
476
- """Prompt the user to select a new kernel."""
477
- kernel_specs = self.kernel.specs
478
-
479
- # Warn the user if no kernels are installed
480
- if not kernel_specs:
481
- if startup and "no-kernels" in self.app.dialogs:
482
- self.app.dialogs["no-kernels"].show()
483
- return
484
-
485
- # Automatically select the only kernel if there is only one
486
- if startup and len(kernel_specs) == 1:
487
- self.kernel.change(next(iter(kernel_specs)))
488
- return
489
-
490
- self.app.dialogs["change-kernel"].show(
491
- tab=self, message=msg, kernel_specs=kernel_specs
492
- )
493
-
494
- def comm_open(self, content: dict, buffers: Sequence[bytes]) -> None:
495
- """Register a new kernel Comm object in the notebook."""
496
- comm_id = str(content.get("comm_id"))
497
- self.comms[comm_id] = open_comm(
498
- comm_container=self, content=content, buffers=buffers
499
- )
500
-
501
- def comm_msg(self, content: dict, buffers: Sequence[bytes]) -> None:
502
- """Respond to a Comm message from the kernel."""
503
- comm_id = str(content.get("comm_id"))
504
- if comm := self.comms.get(comm_id):
505
- comm.process_data(content.get("data", {}), buffers)
506
-
507
- def comm_close(self, content: dict, buffers: Sequence[bytes]) -> None:
508
- """Close a notebook Comm."""
509
- comm_id = content.get("comm_id")
510
- if comm_id in self.comms:
511
- del self.comms[comm_id]
512
-
513
- def lsp_open_handler(self, lsp: LspClient) -> None:
514
- """Tell the LSP we opened a file."""
515
- lsp.open_doc(
516
- path=self.path, language=self.language, text=self.current_input.buffer.text
517
- )
518
-
519
- def lsp_change_handler(self, lsp: LspClient) -> None:
520
- """Tell the LSP server a file has changed."""
521
- lsp.change_doc(
522
- path=self.path,
523
- language=self.language,
524
- text=self.current_input.buffer.text,
525
- )
526
-
527
- def lsp_before_save_handler(self, lsp: LspClient) -> None:
528
- """Tell the the LSP we are about to save a document."""
529
- lsp.will_save_doc(self.path)
530
-
531
- def lsp_after_save_handler(self, lsp: LspClient) -> None:
532
- """Tell the the LSP we saved a document."""
533
- lsp.save_doc(self.path, text=self.current_input.buffer.text)
534
-
535
- def lsp_close_handler(self, lsp: LspClient) -> None:
536
- """Tell the LSP we opened a file."""
537
- lsp.close_doc(path=self.path)
538
-
539
- def lsp_update_diagnostics(self, lsp: LspClient) -> None:
540
- """Process a new diagnostic report from the LSP."""
541
- if (diagnostics := lsp.reports.pop(self.path.as_uri(), None)) is not None:
542
- self.reports[lsp] = Report.from_lsp(self.current_input.text, diagnostics)
543
- self.app.invalidate()
544
-
545
- def report(self) -> Report:
546
- """Return the current diagnostic reports."""
547
- return Report.from_reports(*self.reports.values())
548
-
549
- # ################################### Commands ####################################
550
-
551
- @staticmethod
552
- @add_cmd(filter=kernel_tab_has_focus)
553
- def _change_kernel() -> None:
554
- """Change the notebook's kernel."""
555
- if isinstance(kt := get_app().tab, KernelTab):
556
- kt.change_kernel()
557
-
558
- # ################################### Settings ####################################
559
-
560
- add_setting(
561
- name="kernel_name",
562
- flags=["--kernel-name", "--kernel"],
563
- type_=str,
564
- help_="The name of the kernel to start by default",
565
- default="python3",
566
- description="""
567
- The name of the kernel selected automatically by the console app or in new
568
- notebooks. If set to an empty string, the user will be asked which kernel
569
- to launch.
570
- """,
571
- )
572
-
573
- add_setting(
574
- name="record_cell_timing",
575
- title="cell timing recording",
576
- flags=["--record-cell-timing"],
577
- type_=bool,
578
- help_="Should timing data be recorded in cell metadata.",
579
- default=False,
580
- schema={
581
- "type": "boolean",
582
- },
583
- description="""
584
- When set, execution timing data will be recorded in cell metadata.
585
- """,
586
- )