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
@@ -12,26 +12,14 @@ import nbformat
12
12
  from prompt_toolkit.clipboard.base import ClipboardData
13
13
  from prompt_toolkit.filters import (
14
14
  Condition,
15
- buffer_has_focus,
16
- has_completions,
17
- vi_mode,
18
- vi_navigation_mode,
19
15
  )
20
16
  from prompt_toolkit.layout.containers import ConditionalContainer, VSplit
21
17
  from prompt_toolkit.layout.dimension import Dimension
22
18
  from prompt_toolkit.mouse_events import MouseEventType
23
19
 
24
- from euporie.core.commands import add_cmd, get_cmd
25
- from euporie.core.config import add_setting
26
- from euporie.core.current import get_app
20
+ from euporie.core.commands import get_cmd
27
21
  from euporie.core.filters import (
28
- cursor_on_first_line,
29
- cursor_on_last_line,
30
- display_has_focus,
31
- have_formatter,
32
22
  insert_mode,
33
- kernel_is_python,
34
- kernel_tab_has_focus,
35
23
  multiple_cells_selected,
36
24
  replace_mode,
37
25
  )
@@ -44,29 +32,23 @@ from euporie.core.layout.decor import Line, Pattern
44
32
  from euporie.core.layout.scroll import ScrollingContainer
45
33
  from euporie.core.margins import MarginContainer, ScrollbarMargin
46
34
  from euporie.core.style import KERNEL_STATUS_REPR
47
- from euporie.core.tabs.base import KernelTab
48
35
  from euporie.core.tabs.notebook import BaseNotebook
49
36
  from euporie.core.widgets.cell import Cell
50
- from euporie.notebook.filters import (
51
- cell_has_focus,
52
- code_cell_selected,
53
- deleted_cells,
54
- notebook_has_focus,
55
- )
56
37
 
57
38
  if TYPE_CHECKING:
39
+ from collections.abc import MutableSequence, Sequence
58
40
  from pathlib import Path
59
- from typing import Any, MutableSequence, Sequence
41
+ from typing import Any
60
42
 
61
43
  from prompt_toolkit.formatted_text.base import StyleAndTextTuples
62
44
  from prompt_toolkit.key_binding.key_bindings import NotImplementedOrNone
63
45
  from prompt_toolkit.layout.containers import AnyContainer
64
46
  from prompt_toolkit.mouse_events import MouseEvent
65
47
 
66
- from euporie.core.app import BaseApp
48
+ from euporie.core.app.app import BaseApp
49
+ from euporie.core.bars.status import StatusBarFields
67
50
  from euporie.core.comm.base import Comm
68
- from euporie.core.kernel import Kernel
69
- from euporie.core.widgets.status import StatusBarFields
51
+ from euporie.core.kernel.client import Kernel
70
52
 
71
53
  log = logging.getLogger(__name__)
72
54
 
@@ -86,9 +68,10 @@ class Notebook(BaseNotebook):
86
68
  except ModuleNotFoundError:
87
69
  pass
88
70
  else:
89
- file_extensions |= dict.fromkeys(NOTEBOOK_EXTENSIONS)
71
+ file_extensions.update(dict.fromkeys(NOTEBOOK_EXTENSIONS))
90
72
 
91
73
  allow_stdin = True
74
+ bg_init = True
92
75
 
93
76
  def __init__(
94
77
  self,
@@ -141,7 +124,7 @@ class Notebook(BaseNotebook):
141
124
  return (
142
125
  [
143
126
  self.mode(),
144
- f"Cell {self.page.selected_slice.start+1}",
127
+ f"Cell {self.page.selected_slice.start + 1}",
145
128
  f"Rendering… ({rendered:.0%})" if rendered and rendered < 1 else "",
146
129
  "Saving…" if self.saving else "",
147
130
  ],
@@ -157,13 +140,13 @@ class Notebook(BaseNotebook):
157
140
 
158
141
  def post_init_kernel(self) -> None:
159
142
  """Start the kernel after if has been loaded."""
143
+ # Load container
144
+ super().post_init_kernel()
145
+
160
146
  # Start kernel
161
147
  if self.kernel._status == "stopped":
162
148
  self.kernel.start(cb=self.kernel_started, wait=False)
163
149
 
164
- # Load container
165
- super().post_init_kernel()
166
-
167
150
  @property
168
151
  def selected_indices(self) -> list[int]:
169
152
  """Return a list of the currently selected cell indices."""
@@ -185,6 +168,9 @@ class Notebook(BaseNotebook):
185
168
  self.page = ScrollingContainer(
186
169
  self.rendered_cells, width=self.app.config.max_notebook_width
187
170
  )
171
+ # Ensure all cells get initialized ASAP to prevent race conditions
172
+ # creating multiple version of cells across threads
173
+ self.page.all_children()
188
174
 
189
175
  expand = Condition(lambda: self.app.config.expand)
190
176
 
@@ -246,15 +232,16 @@ class Notebook(BaseNotebook):
246
232
  key_bindings=load_registered_bindings(
247
233
  "euporie.core.tabs.base.Tab",
248
234
  "euporie.notebook.tabs.notebook.Notebook",
235
+ config=self.app.config,
249
236
  ),
250
237
  )
251
238
 
252
239
  @property
253
240
  def cell(self) -> Cell:
254
241
  """Return the currently selected `Cell` in this `Notebook`."""
255
- cell = self.page.get_child().content
256
- assert isinstance(cell, Cell)
257
- return cell
242
+ if isinstance(cell := self.page.get_child().content, Cell):
243
+ return cell
244
+ return Cell(0, {}, self)
258
245
 
259
246
  # Editing specific stuff
260
247
 
@@ -275,6 +262,8 @@ class Notebook(BaseNotebook):
275
262
 
276
263
  def enter_edit_mode(self) -> None:
277
264
  """Enter cell edit mode."""
265
+ # Signal the page to scroll so the cursor is visible on next render
266
+ self.page.scroll_to_cursor = True
278
267
  self.edit_mode = True
279
268
  # Only one cell can be selected in edit mode
280
269
  self.select(self.cell.index)
@@ -591,648 +580,6 @@ class Notebook(BaseNotebook):
591
580
  cell.run_or_render(wait=wait)
592
581
  log.debug("All cells run")
593
582
 
594
- # ################################### Settings ####################################
595
-
596
- add_setting(
597
- name="show_scroll_bar",
598
- title="scroll bar",
599
- flags=["--show-scroll-bar"],
600
- type_=bool,
601
- help_="Show the scroll bar",
602
- default=True,
603
- description="""
604
- Whether the scroll bar should be shown on the right of the screen.
605
- """,
606
- )
607
-
608
- # ################################### Commands ####################################
609
-
610
- @staticmethod
611
- @add_cmd(
612
- filter=cell_has_focus & ~buffer_has_focus,
613
- )
614
- def _enter_cell_edit_mode() -> None:
615
- """Enter cell edit mode."""
616
- nb = get_app().tab
617
- if isinstance(nb, Notebook):
618
- nb.enter_edit_mode()
619
-
620
- @staticmethod
621
- @add_cmd(
622
- filter=cell_has_focus
623
- & buffer_has_focus
624
- & (~vi_mode | (vi_mode & vi_navigation_mode)),
625
- )
626
- def _exit_edit_mode() -> None:
627
- """Exit cell edit mode."""
628
- nb = get_app().tab
629
- if isinstance(nb, Notebook):
630
- nb.exit_edit_mode()
631
-
632
- @staticmethod
633
- @add_cmd(
634
- filter=cell_has_focus,
635
- )
636
- def _run_selected_cells() -> None:
637
- """Run or render the current cells."""
638
- nb = get_app().tab
639
- if isinstance(nb, Notebook):
640
- nb.run_selected_cells()
641
-
642
- @staticmethod
643
- @add_cmd(
644
- title="Run selected cells and select next cell",
645
- filter=cell_has_focus,
646
- )
647
- def _run_and_select_next() -> None:
648
- """Run or render the current cells and select the next cell."""
649
- nb = get_app().tab
650
- if isinstance(nb, Notebook):
651
- nb.run_selected_cells(advance=True)
652
-
653
- @staticmethod
654
- @add_cmd(
655
- filter=cell_has_focus,
656
- )
657
- def _run_cell_and_insert_below() -> None:
658
- """Run or render the current cells and insert a new cell below."""
659
- nb = get_app().tab
660
- if isinstance(nb, Notebook):
661
- nb.run_selected_cells(insert=True)
662
-
663
- @staticmethod
664
- @add_cmd(
665
- filter=notebook_has_focus,
666
- )
667
- def _run_all_cells() -> None:
668
- """Run or render all the cells in the current notebook."""
669
- nb = get_app().tab
670
- if isinstance(nb, Notebook):
671
- nb.run_all()
672
-
673
- @staticmethod
674
- @add_cmd(
675
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
676
- )
677
- def _add_cell_above() -> None:
678
- """Add a new cell above the current."""
679
- nb = get_app().tab
680
- if isinstance(nb, Notebook):
681
- nb.add_cell_above()
682
-
683
- @staticmethod
684
- @add_cmd(
685
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
686
- )
687
- def _add_cell_below() -> None:
688
- """Add a new cell below the current."""
689
- nb = get_app().tab
690
- if isinstance(nb, Notebook):
691
- nb.add_cell_below()
692
-
693
- @staticmethod
694
- @add_cmd(
695
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
696
- )
697
- def _delete_cells() -> None:
698
- """Delete the current cells."""
699
- nb = get_app().tab
700
- if isinstance(nb, Notebook):
701
- nb.delete()
702
-
703
- @staticmethod
704
- @add_cmd(
705
- menu_title="Undo delete cell",
706
- filter=notebook_has_focus
707
- & ~buffer_has_focus
708
- & ~display_has_focus
709
- & deleted_cells,
710
- )
711
- def _undelete_cells() -> None:
712
- """Undelete the last deleted cells."""
713
- nb = get_app().tab
714
- if isinstance(nb, Notebook):
715
- nb.undelete()
716
-
717
- @staticmethod
718
- @add_cmd(
719
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
720
- )
721
- def _cut_cells() -> None:
722
- """Cut the current cells."""
723
- nb = get_app().tab
724
- if isinstance(nb, Notebook):
725
- nb.cut()
726
-
727
- @staticmethod
728
- @add_cmd(
729
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
730
- )
731
- def _copy_cells() -> None:
732
- """Copy the current cells."""
733
- nb = get_app().tab
734
- if isinstance(nb, Notebook):
735
- nb.copy()
736
-
737
- @staticmethod
738
- @add_cmd(
739
- menu_title="Copy cell outputs",
740
- filter=cell_has_focus & ~buffer_has_focus,
741
- )
742
- def _copy_outputs() -> None:
743
- """Copy the cell's output to the clipboard."""
744
- nb = get_app().tab
745
- if isinstance(nb, Notebook):
746
- nb.copy_outputs()
747
-
748
- @staticmethod
749
- @add_cmd(
750
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
751
- )
752
- def _paste_cells() -> None:
753
- """Pate the previously copied cells."""
754
- nb = get_app().tab
755
- if isinstance(nb, Notebook):
756
- nb.paste()
757
-
758
- @staticmethod
759
- @add_cmd(
760
- filter=notebook_has_focus
761
- & ~buffer_has_focus
762
- & ~display_has_focus
763
- & multiple_cells_selected,
764
- )
765
- def _merge_cells() -> None:
766
- """Merge the selected cells."""
767
- nb = get_app().tab
768
- if isinstance(nb, Notebook):
769
- nb.merge()
770
-
771
- @staticmethod
772
- @add_cmd(
773
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
774
- )
775
- @add_cmd(
776
- filter=notebook_has_focus,
777
- )
778
- def _scroll_up() -> NotImplementedOrNone:
779
- """Scroll the page up a line."""
780
- nb = get_app().tab
781
- if isinstance(nb, Notebook):
782
- return nb.page.scroll(1)
783
- return None
784
-
785
- @staticmethod
786
- @add_cmd(
787
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
788
- )
789
- @add_cmd(
790
- filter=notebook_has_focus,
791
- )
792
- def _scroll_down() -> NotImplementedOrNone:
793
- """Scroll the page down a line."""
794
- nb = get_app().tab
795
- if isinstance(nb, Notebook):
796
- return nb.page.scroll(-1)
797
- return None
798
-
799
- @staticmethod
800
- @add_cmd(
801
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
802
- )
803
- def _scroll_up_5_lines() -> None:
804
- """Scroll the page up 5 lines."""
805
- nb = get_app().tab
806
- if isinstance(nb, Notebook):
807
- nb.page.scroll(5)
808
-
809
- @staticmethod
810
- @add_cmd(
811
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
812
- )
813
- def _scroll_down_5_lines() -> None:
814
- """Scroll the page down 5 lines."""
815
- nb = get_app().tab
816
- if isinstance(nb, Notebook):
817
- nb.page.scroll(-5)
818
-
819
- @staticmethod
820
- @add_cmd(
821
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
822
- )
823
- def _select_first_cell() -> None:
824
- """Select the first cell in the notebook."""
825
- nb = get_app().tab
826
- if isinstance(nb, Notebook):
827
- nb.select(0)
828
-
829
- @staticmethod
830
- @add_cmd(
831
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
832
- )
833
- def _select_5th_previous_cell() -> None:
834
- """Go up 5 cells."""
835
- nb = get_app().tab
836
- if isinstance(nb, Notebook):
837
- nb.select(nb.page.selected_slice.start - 5)
838
-
839
- @staticmethod
840
- @add_cmd(
841
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
842
- )
843
- def _select_previous_cell() -> None:
844
- """Go up one cell."""
845
- nb = get_app().tab
846
- if isinstance(nb, Notebook):
847
- nb.select(nb.page.selected_slice.start - 1)
848
-
849
- @staticmethod
850
- @add_cmd(
851
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
852
- )
853
- def _select_next_cell() -> None:
854
- """Select the next cell."""
855
- nb = get_app().tab
856
- if isinstance(nb, Notebook):
857
- nb.select(nb.page.selected_slice.start + 1)
858
-
859
- @staticmethod
860
- @add_cmd(
861
- filter=~buffer_has_focus,
862
- )
863
- def _select_5th_next_cell() -> None:
864
- """Go down 5 cells."""
865
- nb = get_app().tab
866
- if isinstance(nb, Notebook):
867
- nb.select(nb.page.selected_slice.start + 5)
868
-
869
- @staticmethod
870
- @add_cmd(
871
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
872
- )
873
- def _select_last_cell() -> None:
874
- """Select the last cell in the notebook."""
875
- nb = get_app().tab
876
- if isinstance(nb, Notebook):
877
- nb.select(len(nb.page.all_children()) - 1)
878
-
879
- @staticmethod
880
- @add_cmd(
881
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
882
- )
883
- def _select_all_cells() -> None:
884
- """Select all cells in the notebook."""
885
- nb = get_app().tab
886
- if isinstance(nb, Notebook):
887
- nb.page.selected_slice = slice(
888
- 0,
889
- len(nb.page.all_children()) + 1,
890
- )
891
-
892
- @staticmethod
893
- @add_cmd(
894
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
895
- )
896
- def _extend_cell_selection_to_top() -> None:
897
- """Extend the cell selection to the top of the notebook."""
898
- nb = get_app().tab
899
- if isinstance(nb, Notebook):
900
- nb.select(0, extend=True)
901
-
902
- @staticmethod
903
- @add_cmd(
904
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
905
- )
906
- def _extend_cell_selection_up() -> None:
907
- """Extend the cell selection up a cell."""
908
- nb = get_app().tab
909
- if isinstance(nb, Notebook):
910
- nb.select(nb.page._selected_slice.start - 1, extend=True)
911
-
912
- @staticmethod
913
- @add_cmd(
914
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
915
- )
916
- def _extend_cell_selection_down() -> None:
917
- """Extend the cell selection down a cell."""
918
- nb = get_app().tab
919
- if isinstance(nb, Notebook):
920
- nb.select(nb.page._selected_slice.start + 1, extend=True)
921
-
922
- @staticmethod
923
- @add_cmd(
924
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
925
- )
926
- def _extend_cell_selection_to_bottom() -> None:
927
- """Extend the cell selection to the bottom of the notebook."""
928
- nb = get_app().tab
929
- if isinstance(nb, Notebook):
930
- nb.select(len(nb.json["cells"]) - 1, extend=True)
931
-
932
- @staticmethod
933
- @add_cmd(
934
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
935
- )
936
- def _move_cells_up() -> None:
937
- """Move selected cells up."""
938
- nb = get_app().tab
939
- if isinstance(nb, Notebook):
940
- nb.move(-1)
941
-
942
- @staticmethod
943
- @add_cmd(
944
- filter=notebook_has_focus & ~buffer_has_focus & ~display_has_focus,
945
- )
946
- def _move_cells_down() -> None:
947
- """Move selected cells down."""
948
- nb = get_app().tab
949
- if isinstance(nb, Notebook):
950
- nb.move(1)
951
-
952
- @staticmethod
953
- @add_cmd(
954
- filter=cell_has_focus & ~buffer_has_focus,
955
- )
956
- def _cells_to_markdown() -> None:
957
- """Change selected cells to markdown cells."""
958
- nb = get_app().tab
959
- if isinstance(nb, Notebook):
960
- for cell in nb.cells:
961
- cell.set_cell_type("markdown", clear=True)
962
- # Remove unallowed additional properties
963
- json = cell.json
964
- json.pop("execution_count", None)
965
- json.pop("outputs", None)
966
- cell.run_or_render()
967
-
968
- @staticmethod
969
- @add_cmd(
970
- filter=cell_has_focus & ~buffer_has_focus,
971
- )
972
- def _cells_to_code() -> None:
973
- """Change selected cells to code cells."""
974
- nb = get_app().tab
975
- if isinstance(nb, Notebook):
976
- for cell in nb.cells:
977
- cell.set_cell_type("code", clear=False)
978
-
979
- @staticmethod
980
- @add_cmd(
981
- filter=cell_has_focus & ~buffer_has_focus,
982
- )
983
- def _cells_to_raw() -> None:
984
- """Change selected cells to raw cells."""
985
- nb = get_app().tab
986
- if isinstance(nb, Notebook):
987
- for cell in nb.cells:
988
- cell.set_cell_type("raw", clear=True)
989
-
990
- @staticmethod
991
- @add_cmd(
992
- filter=cell_has_focus & ~buffer_has_focus,
993
- )
994
- def _clear_cell_outputs() -> None:
995
- """Clear the outputs of the selected cells."""
996
- nb = get_app().tab
997
- if isinstance(nb, Notebook):
998
- for cell in nb.cells:
999
- cell.remove_outputs()
1000
-
1001
- @staticmethod
1002
- @add_cmd(
1003
- filter=cell_has_focus & ~buffer_has_focus,
1004
- )
1005
- def _clear_all_outputs() -> None:
1006
- """Clear the outputs of the selected cells."""
1007
- nb = get_app().tab
1008
- if isinstance(nb, Notebook):
1009
- for cell in nb._rendered_cells.values():
1010
- cell.remove_outputs()
1011
-
1012
- @staticmethod
1013
- @add_cmd(
1014
- filter=cell_has_focus & ~buffer_has_focus,
1015
- title="Expand cell inputs",
1016
- )
1017
- def _show_cell_inputs() -> None:
1018
- """Expand the selected cells' inputs."""
1019
- nb = get_app().tab
1020
- if isinstance(nb, Notebook):
1021
- for cell in nb.cells:
1022
- cell.show_input()
1023
-
1024
- @staticmethod
1025
- @add_cmd(
1026
- filter=cell_has_focus & ~buffer_has_focus,
1027
- title="Collapse cell inputs",
1028
- )
1029
- def _hide_cell_inputs() -> None:
1030
- """Collapse the selected cells' inputs."""
1031
- nb = get_app().tab
1032
- if isinstance(nb, Notebook):
1033
- for cell in nb.cells:
1034
- cell.hide_input()
1035
-
1036
- @staticmethod
1037
- @add_cmd(
1038
- filter=cell_has_focus & ~buffer_has_focus,
1039
- )
1040
- def _toggle_cell_inputs() -> None:
1041
- """Toggle the visibility of the selected cells' inputs."""
1042
- nb = get_app().tab
1043
- if isinstance(nb, Notebook):
1044
- for cell in nb.cells:
1045
- cell.toggle_input()
1046
-
1047
- @staticmethod
1048
- @add_cmd(
1049
- filter=cell_has_focus & ~buffer_has_focus,
1050
- title="Expand cell outputs",
1051
- )
1052
- def _show_cell_outputs() -> None:
1053
- """Expand the selected cells' outputs."""
1054
- nb = get_app().tab
1055
- if isinstance(nb, Notebook):
1056
- for cell in nb.cells:
1057
- cell.show_output()
1058
-
1059
- @staticmethod
1060
- @add_cmd(
1061
- filter=cell_has_focus & ~buffer_has_focus,
1062
- title="Collapse cell outputs",
1063
- )
1064
- def _hide_cell_outputs() -> None:
1065
- """Collapse the selected cells' outputs."""
1066
- nb = get_app().tab
1067
- if isinstance(nb, Notebook):
1068
- for cell in nb.cells:
1069
- cell.hide_output()
1070
-
1071
- @staticmethod
1072
- @add_cmd(
1073
- filter=cell_has_focus & ~buffer_has_focus,
1074
- )
1075
- def _toggle_cell_outputs() -> None:
1076
- """Toggle the visibility of the selected cells' outputs."""
1077
- nb = get_app().tab
1078
- if isinstance(nb, Notebook):
1079
- for cell in nb.cells:
1080
- cell.toggle_output()
1081
-
1082
- @staticmethod
1083
- @add_cmd(
1084
- title="Reformat cells",
1085
- filter=code_cell_selected
1086
- & cell_has_focus
1087
- & ~buffer_has_focus
1088
- & notebook_has_focus,
1089
- )
1090
- def _reformat_cells() -> None:
1091
- """Format the selected code cells."""
1092
- nb = get_app().tab
1093
- if isinstance(nb, Notebook):
1094
- for cell in nb.cells:
1095
- if cell.cell_type == "code":
1096
- cell.input_box.reformat()
1097
-
1098
- @staticmethod
1099
- @add_cmd(
1100
- filter=have_formatter
1101
- & kernel_is_python
1102
- & notebook_has_focus
1103
- & ~buffer_has_focus,
1104
- )
1105
- def _reformat_notebook() -> None:
1106
- """Automatically reformat all code cells in the notebook."""
1107
- nb = get_app().tab
1108
- if isinstance(nb, Notebook):
1109
- nb.reformat()
1110
-
1111
- @staticmethod
1112
- @add_cmd(
1113
- filter=cell_has_focus & ~buffer_has_focus,
1114
- )
1115
- async def _edit_in_external_editor() -> None:
1116
- """Edit cell in $EDITOR."""
1117
- nb = get_app().tab
1118
- if isinstance(nb, Notebook):
1119
- await nb.cell.edit_in_editor()
1120
-
1121
- @staticmethod
1122
- @add_cmd(
1123
- filter=cell_has_focus & buffer_has_focus,
1124
- )
1125
- def _split_cell() -> None:
1126
- """Split the current cell at the cursor position."""
1127
- nb = get_app().tab
1128
- if isinstance(nb, Notebook):
1129
- nb.split_cell()
1130
-
1131
- @staticmethod
1132
- @add_cmd(
1133
- name="edit-previous-cell-vi",
1134
- filter=cell_has_focus
1135
- & buffer_has_focus
1136
- & cursor_on_first_line
1137
- & ~has_completions
1138
- & vi_mode
1139
- & vi_navigation_mode,
1140
- )
1141
- @add_cmd(
1142
- filter=cell_has_focus
1143
- & buffer_has_focus
1144
- & cursor_on_first_line
1145
- & ~has_completions
1146
- )
1147
- def _edit_previous_cell() -> None:
1148
- """Move the cursor up to the previous cell."""
1149
- nb = get_app().tab
1150
- if isinstance(nb, Notebook):
1151
- new_index = nb.cell.index - 1
1152
- cells = nb.rendered_cells()
1153
- if 0 <= new_index < len(cells):
1154
- nb.select(index=new_index, position=-1, scroll=True)
1155
-
1156
- @staticmethod
1157
- @add_cmd(
1158
- name="edit-next-cell-vi",
1159
- filter=cell_has_focus
1160
- & buffer_has_focus
1161
- & cursor_on_last_line
1162
- & ~has_completions
1163
- & vi_mode
1164
- & vi_navigation_mode,
1165
- )
1166
- @add_cmd(
1167
- filter=cell_has_focus
1168
- & buffer_has_focus
1169
- & cursor_on_last_line
1170
- & ~has_completions
1171
- )
1172
- def _edit_next_cell() -> None:
1173
- """Move the cursor down to the next cell."""
1174
- nb = get_app().tab
1175
- if isinstance(nb, Notebook):
1176
- new_index = nb.cell.index + 1
1177
- cells = nb.rendered_cells()
1178
- if 0 <= new_index < len(cells):
1179
- nb.select(index=new_index, position=0, scroll=True)
1180
-
1181
- @staticmethod
1182
- @add_cmd(
1183
- filter=cell_has_focus & ~buffer_has_focus,
1184
- )
1185
- def _scroll_output_left() -> None:
1186
- """Scroll the cell output to the left."""
1187
- nb = get_app().tab
1188
- if isinstance(nb, Notebook):
1189
- nb.cell.output_area.scroll_left()
1190
-
1191
- @staticmethod
1192
- @add_cmd(
1193
- filter=cell_has_focus & ~buffer_has_focus,
1194
- )
1195
- def _scroll_output_right() -> None:
1196
- """Scroll the cell output to the right."""
1197
- nb = get_app().tab
1198
- if isinstance(nb, Notebook):
1199
- nb.cell.output_area.scroll_right()
1200
-
1201
- @staticmethod
1202
- @add_cmd(
1203
- filter=kernel_tab_has_focus & ~buffer_has_focus & ~display_has_focus,
1204
- )
1205
- def _interrupt_kernel() -> None:
1206
- """Interrupt the notebook's kernel."""
1207
- if isinstance(kt := get_app().tab, KernelTab):
1208
- kt.interrupt_kernel()
1209
-
1210
- @staticmethod
1211
- @add_cmd(
1212
- filter=kernel_tab_has_focus & ~buffer_has_focus & ~display_has_focus,
1213
- )
1214
- def _restart_kernel() -> None:
1215
- """Restart the notebook's kernel."""
1216
- if isinstance(kt := get_app().tab, KernelTab):
1217
- kt.restart_kernel()
1218
-
1219
- @staticmethod
1220
- @add_cmd(
1221
- filter=kernel_tab_has_focus & ~buffer_has_focus & ~display_has_focus,
1222
- )
1223
- def _restart_kernel_and_clear_all_outputs() -> None:
1224
- """Restart the notebook's kernel and clear all cell output."""
1225
- if isinstance(nb := get_app().tab, Notebook):
1226
- nb.restart_kernel(cb=Notebook._clear_all_outputs)
1227
-
1228
- @staticmethod
1229
- @add_cmd(
1230
- filter=~buffer_has_focus,
1231
- )
1232
- def _notebook_toggle_line_numbers() -> None:
1233
- """Toggle line numbers when a buffer does not have focus."""
1234
- get_cmd("toggle-line-numbers").run()
1235
-
1236
583
  # ################################# Key Bindings ##################################
1237
584
 
1238
585
  register_bindings(