euporie 2.8.5__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 (74) 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/__main__.py +2 -2
  5. euporie/core/_settings.py +7 -2
  6. euporie/core/app/_commands.py +20 -12
  7. euporie/core/app/_settings.py +34 -4
  8. euporie/core/app/app.py +31 -18
  9. euporie/core/bars/command.py +53 -27
  10. euporie/core/bars/search.py +43 -2
  11. euporie/core/border.py +7 -2
  12. euporie/core/comm/base.py +2 -2
  13. euporie/core/comm/ipywidgets.py +3 -3
  14. euporie/core/commands.py +44 -24
  15. euporie/core/completion.py +14 -6
  16. euporie/core/convert/datum.py +7 -7
  17. euporie/core/data_structures.py +20 -1
  18. euporie/core/filters.py +40 -9
  19. euporie/core/format.py +2 -3
  20. euporie/core/ft/html.py +47 -40
  21. euporie/core/graphics.py +199 -31
  22. euporie/core/history.py +15 -5
  23. euporie/core/inspection.py +16 -9
  24. euporie/core/kernel/__init__.py +53 -1
  25. euporie/core/kernel/base.py +571 -0
  26. euporie/core/kernel/{client.py → jupyter.py} +173 -430
  27. euporie/core/kernel/{manager.py → jupyter_manager.py} +4 -3
  28. euporie/core/kernel/local.py +694 -0
  29. euporie/core/key_binding/bindings/basic.py +6 -3
  30. euporie/core/keys.py +26 -25
  31. euporie/core/layout/cache.py +31 -7
  32. euporie/core/layout/containers.py +88 -13
  33. euporie/core/layout/scroll.py +69 -170
  34. euporie/core/log.py +2 -5
  35. euporie/core/path.py +61 -13
  36. euporie/core/style.py +2 -1
  37. euporie/core/suggest.py +155 -74
  38. euporie/core/tabs/__init__.py +12 -4
  39. euporie/core/tabs/_commands.py +76 -0
  40. euporie/core/tabs/_settings.py +16 -0
  41. euporie/core/tabs/base.py +89 -9
  42. euporie/core/tabs/kernel.py +83 -38
  43. euporie/core/tabs/notebook.py +28 -76
  44. euporie/core/utils.py +2 -19
  45. euporie/core/validation.py +8 -8
  46. euporie/core/widgets/_settings.py +19 -2
  47. euporie/core/widgets/cell.py +32 -32
  48. euporie/core/widgets/cell_outputs.py +10 -1
  49. euporie/core/widgets/dialog.py +60 -76
  50. euporie/core/widgets/display.py +2 -2
  51. euporie/core/widgets/forms.py +71 -59
  52. euporie/core/widgets/inputs.py +7 -4
  53. euporie/core/widgets/layout.py +281 -93
  54. euporie/core/widgets/menu.py +56 -16
  55. euporie/core/widgets/palette.py +3 -1
  56. euporie/core/widgets/tree.py +86 -76
  57. euporie/notebook/app.py +35 -16
  58. euporie/notebook/tabs/display.py +2 -2
  59. euporie/notebook/tabs/edit.py +11 -46
  60. euporie/notebook/tabs/json.py +8 -4
  61. euporie/notebook/tabs/notebook.py +26 -8
  62. euporie/preview/tabs/notebook.py +17 -13
  63. euporie/web/__init__.py +1 -0
  64. euporie/web/tabs/__init__.py +14 -0
  65. euporie/web/tabs/web.py +30 -5
  66. euporie/web/widgets/__init__.py +1 -0
  67. euporie/web/widgets/webview.py +5 -4
  68. {euporie-2.8.5.dist-info → euporie-2.8.7.dist-info}/METADATA +4 -2
  69. {euporie-2.8.5.dist-info → euporie-2.8.7.dist-info}/RECORD +74 -68
  70. {euporie-2.8.5.dist-info → euporie-2.8.7.dist-info}/entry_points.txt +1 -1
  71. {euporie-2.8.5.dist-info → euporie-2.8.7.dist-info}/licenses/LICENSE +1 -1
  72. {euporie-2.8.5.data → euporie-2.8.7.data}/data/share/applications/euporie-console.desktop +0 -0
  73. {euporie-2.8.5.data → euporie-2.8.7.data}/data/share/applications/euporie-notebook.desktop +0 -0
  74. {euporie-2.8.5.dist-info → euporie-2.8.7.dist-info}/WHEEL +0 -0
@@ -13,6 +13,7 @@ from prompt_toolkit.filters import (
13
13
  from euporie.core.commands import add_cmd
14
14
  from euporie.core.filters import (
15
15
  char_after_cursor,
16
+ cursor_at_end_of_line,
16
17
  has_matching_bracket,
17
18
  insert_mode,
18
19
  replace_mode,
@@ -83,14 +84,16 @@ def _complete_bracket(right: str, event: KeyPressEvent) -> None:
83
84
  event.key_processor.feed(event.key_sequence[0], first=True)
84
85
 
85
86
 
86
- def _close_bracket(right: str, event: KeyPressEvent) -> None:
87
+ def _skip_close_bracket(right: str, event: KeyPressEvent) -> None:
87
88
  event.current_buffer.cursor_position += 1
88
89
 
89
90
 
90
91
  for left, right in [("(", ")"), ("[", "]"), ("{", "}")]:
91
92
  add_cmd(
92
93
  name=f"complete-bracket-{left}{right}",
93
- filter=buffer_has_focus & insert_mode & ~char_after_cursor(right),
94
+ filter=buffer_has_focus
95
+ & insert_mode
96
+ & (char_after_cursor(" ") | cursor_at_end_of_line),
94
97
  save_before=if_no_repeat,
95
98
  hidden=True,
96
99
  )(partial(_complete_bracket, right))
@@ -102,4 +105,4 @@ for left, right in [("(", ")"), ("[", "]"), ("{", "}")]:
102
105
  & has_matching_bracket,
103
106
  save_before=if_no_repeat,
104
107
  hidden=True,
105
- )(partial(_close_bracket, right))
108
+ )(partial(_skip_close_bracket, right))
euporie/core/keys.py CHANGED
@@ -21,7 +21,8 @@ class MoreKeys(str, Enum):
21
21
  SgrPixelStatusResponse = "<sgr-pixel-status-response>"
22
22
  ClipboardDataResponse = "<clipboard-data-response>"
23
23
 
24
- # Regular keys
24
+ # Regular key-presses
25
+
25
26
  AltTab = "A-tab"
26
27
  AltEnter = "A-enter"
27
28
  AltEscape = "A-escape"
@@ -124,15 +125,15 @@ class MoreKeys(str, Enum):
124
125
  Escape = "escape"
125
126
  Insert = "insert"
126
127
  Delete = "delete"
127
- Pageup = "pageUp"
128
- Pagedown = "pageDown"
128
+ Pageup = "pageup"
129
+ Pagedown = "pagedown"
129
130
  Up = "up"
130
131
  Down = "down"
131
132
  Right = "right"
132
133
  Left = "left"
133
134
  Home = "home"
134
135
  End = "end"
135
- Printscreen = "printScreen"
136
+ Printscreen = "printscreen"
136
137
  Pause = "pause"
137
138
  Menu = "menu"
138
139
  F1 = "f1"
@@ -251,15 +252,15 @@ class MoreKeys(str, Enum):
251
252
  ShiftBackspace = "s-backspace"
252
253
  ShiftInsert = "s-insert"
253
254
  ShiftDelete = "s-delete"
254
- ShiftPageup = "s-pageUp"
255
- ShiftPagedown = "s-pageDown"
255
+ ShiftPageup = "s-pageup"
256
+ ShiftPagedown = "s-pagedown"
256
257
  ShiftUp = "s-up"
257
258
  ShiftDown = "s-down"
258
259
  ShiftRight = "s-right"
259
260
  ShiftLeft = "s-left"
260
261
  ShiftHome = "s-home"
261
262
  ShiftEnd = "s-end"
262
- ShiftPrintscreen = "s-printScreen"
263
+ ShiftPrintscreen = "s-printscreen"
263
264
  ShiftPause = "s-pause"
264
265
  ShiftMenu = "s-menu"
265
266
  ShiftF1 = "s-f1"
@@ -276,15 +277,15 @@ class MoreKeys(str, Enum):
276
277
  ShiftF12 = "s-f12"
277
278
  AltInsert = "A-insert"
278
279
  AltDelete = "A-delete"
279
- AltPageup = "A-pageUp"
280
- AltPagedown = "A-pageDown"
280
+ AltPageup = "A-pageup"
281
+ AltPagedown = "A-pagedown"
281
282
  AltUp = "A-up"
282
283
  AltDown = "A-down"
283
284
  AltRight = "A-right"
284
285
  AltLeft = "A-left"
285
286
  AltHome = "A-home"
286
287
  AltEnd = "A-end"
287
- AltPrintscreen = "A-printScreen"
288
+ AltPrintscreen = "A-printscreen"
288
289
  AltPause = "A-pause"
289
290
  AltMenu = "A-menu"
290
291
  AltF1 = "A-f1"
@@ -400,15 +401,15 @@ class MoreKeys(str, Enum):
400
401
  ControlBackspace = "c-backspace"
401
402
  ControlInsert = "c-insert"
402
403
  ControlDelete = "c-delete"
403
- ControlPageup = "c-pageUp"
404
- ControlPagedown = "c-pageDown"
404
+ ControlPageup = "c-pageup"
405
+ ControlPagedown = "c-pagedown"
405
406
  ControlUp = "c-up"
406
407
  ControlDown = "c-down"
407
408
  ControlRight = "c-right"
408
409
  ControlLeft = "c-left"
409
410
  ControlHome = "c-home"
410
411
  ControlEnd = "c-end"
411
- ControlPrintscreen = "c-printScreen"
412
+ ControlPrintscreen = "c-printscreen"
412
413
  ControlPause = "c-pause"
413
414
  ControlMenu = "c-menu"
414
415
  ControlF1 = "c-f1"
@@ -524,15 +525,15 @@ class MoreKeys(str, Enum):
524
525
  AltShiftBackspace = "A-s-backspace"
525
526
  AltShiftInsert = "A-s-insert"
526
527
  AltShiftDelete = "A-s-delete"
527
- AltShiftPageup = "A-s-pageUp"
528
- AltShiftPagedown = "A-s-pageDown"
528
+ AltShiftPageup = "A-s-pageup"
529
+ AltShiftPagedown = "A-s-pagedown"
529
530
  AltShiftUp = "A-s-up"
530
531
  AltShiftDown = "A-s-down"
531
532
  AltShiftRight = "A-s-right"
532
533
  AltShiftLeft = "A-s-left"
533
534
  AltShiftHome = "A-s-home"
534
535
  AltShiftEnd = "A-s-end"
535
- AltShiftPrintscreen = "A-s-printScreen"
536
+ AltShiftPrintscreen = "A-s-printscreen"
536
537
  AltShiftPause = "A-s-pause"
537
538
  AltShiftMenu = "A-s-menu"
538
539
  AltShiftF1 = "A-s-f1"
@@ -648,15 +649,15 @@ class MoreKeys(str, Enum):
648
649
  ControlShiftBackspace = "c-s-backspace"
649
650
  ControlShiftInsert = "c-s-insert"
650
651
  ControlShiftDelete = "c-s-delete"
651
- ControlShiftPageup = "c-s-pageUp"
652
- ControlShiftPagedown = "c-s-pageDown"
652
+ ControlShiftPageup = "c-s-pageup"
653
+ ControlShiftPagedown = "c-s-pagedown"
653
654
  ControlShiftUp = "c-s-up"
654
655
  ControlShiftDown = "c-s-down"
655
656
  ControlShiftRight = "c-s-right"
656
657
  ControlShiftLeft = "c-s-left"
657
658
  ControlShiftHome = "c-s-home"
658
659
  ControlShiftEnd = "c-s-end"
659
- ControlShiftPrintscreen = "c-s-printScreen"
660
+ ControlShiftPrintscreen = "c-s-printscreen"
660
661
  ControlShiftPause = "c-s-pause"
661
662
  ControlShiftMenu = "c-s-menu"
662
663
  ControlShiftF1 = "c-s-f1"
@@ -772,15 +773,15 @@ class MoreKeys(str, Enum):
772
773
  ControlAltBackspace = "c-A-backspace"
773
774
  ControlAltInsert = "c-A-insert"
774
775
  ControlAltDelete = "c-A-delete"
775
- ControlAltPageup = "c-A-pageUp"
776
- ControlAltPagedown = "c-A-pageDown"
776
+ ControlAltPageup = "c-A-pageup"
777
+ ControlAltPagedown = "c-A-pagedown"
777
778
  ControlAltUp = "c-A-up"
778
779
  ControlAltDown = "c-A-down"
779
780
  ControlAltRight = "c-A-right"
780
781
  ControlAltLeft = "c-A-left"
781
782
  ControlAltHome = "c-A-home"
782
783
  ControlAltEnd = "c-A-end"
783
- ControlAltPrintscreen = "c-A-printScreen"
784
+ ControlAltPrintscreen = "c-A-printscreen"
784
785
  ControlAltPause = "c-A-pause"
785
786
  ControlAltMenu = "c-A-menu"
786
787
  ControlAltF1 = "c-A-f1"
@@ -896,15 +897,15 @@ class MoreKeys(str, Enum):
896
897
  ControlAltShiftBackspace = "c-A-s-backspace"
897
898
  ControlAltShiftInsert = "c-A-s-insert"
898
899
  ControlAltShiftDelete = "c-A-s-delete"
899
- ControlAltShiftPageup = "c-A-s-pageUp"
900
- ControlAltShiftPagedown = "c-A-s-pageDown"
900
+ ControlAltShiftPageup = "c-A-s-pageup"
901
+ ControlAltShiftPagedown = "c-A-s-pagedown"
901
902
  ControlAltShiftUp = "c-A-s-up"
902
903
  ControlAltShiftDown = "c-A-s-down"
903
904
  ControlAltShiftRight = "c-A-s-right"
904
905
  ControlAltShiftLeft = "c-A-s-left"
905
906
  ControlAltShiftHome = "c-A-s-home"
906
907
  ControlAltShiftEnd = "c-A-s-end"
907
- ControlAltShiftPrintscreen = "c-A-s-printScreen"
908
+ ControlAltShiftPrintscreen = "c-A-s-printscreen"
908
909
  ControlAltShiftPause = "c-A-s-pause"
909
910
  ControlAltShiftMenu = "c-A-s-menu"
910
911
  ControlAltShiftF1 = "c-A-s-f1"
@@ -6,6 +6,7 @@ import logging
6
6
  from functools import cache
7
7
  from typing import TYPE_CHECKING
8
8
 
9
+ from prompt_toolkit.cache import FastDictCache
9
10
  from prompt_toolkit.data_structures import Point
10
11
  from prompt_toolkit.layout.containers import (
11
12
  Container,
@@ -56,11 +57,26 @@ class CachedContainer(Container):
56
57
  self._invalid = True
57
58
  self._invalidate_events: set[Event[object]] = set()
58
59
  self._layout_hash = 0
60
+ self.render_counter = 0
59
61
  self.height = 0
60
62
  self.width = 0
61
63
  self._rendered_lines: set[int] = set()
62
64
  self._rowcols_to_yx: dict[Window, dict[tuple[int, int], tuple[int, int]]] = {}
63
65
 
66
+ self._width_cache: FastDictCache[tuple[int, int], Dimension] = FastDictCache(
67
+ get_value=lambda _render_count,
68
+ max_available_width: self.container.preferred_width(max_available_width)
69
+ )
70
+ self._height_cache: FastDictCache[tuple[int, int, int], Dimension] = (
71
+ FastDictCache(
72
+ get_value=lambda _render_count,
73
+ width,
74
+ max_available_height: self.container.preferred_height(
75
+ width, max_available_height
76
+ )
77
+ )
78
+ )
79
+
64
80
  @property
65
81
  def layout_hash(self) -> int:
66
82
  """Return a hash of the child's current layout."""
@@ -80,11 +96,11 @@ class CachedContainer(Container):
80
96
 
81
97
  def preferred_width(self, max_available_width: int) -> Dimension:
82
98
  """Return the desired width for this container."""
83
- return self.container.preferred_width(max_available_width)
99
+ return self._width_cache[self.render_counter, max_available_width]
84
100
 
85
101
  def preferred_height(self, width: int, max_available_height: int) -> Dimension:
86
102
  """Return the desired height for this container."""
87
- return self.container.preferred_height(width, max_available_height)
103
+ return self._height_cache[self.render_counter, width, max_available_height]
88
104
 
89
105
  def render(
90
106
  self,
@@ -115,6 +131,7 @@ class CachedContainer(Container):
115
131
  self._rendered_lines.clear()
116
132
  self.mouse_handlers.mouse_handlers.clear()
117
133
  self.screen = Screen()
134
+ self.render_counter += 1
118
135
 
119
136
  # Recalculate child height if this child has been invalidated
120
137
  height = self.height = self.container.preferred_height(
@@ -278,10 +295,16 @@ class CachedContainer(Container):
278
295
  # Modify render info
279
296
  info = win.render_info
280
297
  if info is not None:
298
+ xpos = new_wp.xpos + info._x_offset
299
+ y_start = new_wp.ypos + info._y_offset
300
+ # Only include visible lines according to the bounding box
281
301
  visible_line_to_row_col = {
282
- line: (y + info._y_offset, new_wp.xpos + info._x_offset)
283
- for line, y in enumerate(
284
- range(new_wp.ypos, new_wp.ypos + new_wp.height)
302
+ i: (y, xpos)
303
+ for i, y in enumerate(
304
+ range(
305
+ y_start + new_wp.bbox.top,
306
+ y_start + new_wp.height - new_wp.bbox.bottom,
307
+ )
285
308
  )
286
309
  }
287
310
  win.render_info = WindowRenderInfo(
@@ -295,8 +318,8 @@ class CachedContainer(Container):
295
318
  visible_line_to_row_col=visible_line_to_row_col,
296
319
  # The following is needed to calculate absolute cursor positions
297
320
  rowcol_to_yx={
298
- (row, col): (y + top, x + left)
299
- for (row, col), (y, x) in info._rowcol_to_yx.items()
321
+ k: (y + top, x + left)
322
+ for k, (y, x) in info._rowcol_to_yx.items()
300
323
  },
301
324
  x_offset=info._x_offset + left,
302
325
  y_offset=info._y_offset + top,
@@ -342,6 +365,7 @@ class CachedContainer(Container):
342
365
 
343
366
  rows_range = range(max(0, rows.start), rows.stop)
344
367
  cols_range = range(max(0, cols.start), cols.stop)
368
+
345
369
  for y in rows_range:
346
370
  input_db_row = input_db[y]
347
371
  input_zwes_row = input_zwes[y]
@@ -4,10 +4,9 @@ from __future__ import annotations
4
4
 
5
5
  import logging
6
6
  from functools import lru_cache, partial
7
- from typing import TYPE_CHECKING
7
+ from typing import TYPE_CHECKING, NamedTuple
8
8
 
9
9
  from prompt_toolkit.application.current import get_app
10
- from prompt_toolkit.cache import FastDictCache
11
10
  from prompt_toolkit.data_structures import Point
12
11
  from prompt_toolkit.layout import containers as ptk_containers
13
12
  from prompt_toolkit.layout.containers import (
@@ -28,7 +27,7 @@ from prompt_toolkit.layout.dimension import Dimension
28
27
  from prompt_toolkit.layout.screen import _CHAR_CACHE
29
28
  from prompt_toolkit.layout.utils import explode_text_fragments
30
29
  from prompt_toolkit.mouse_events import MouseEvent, MouseEventType
31
- from prompt_toolkit.utils import get_cwidth, to_str
30
+ from prompt_toolkit.utils import get_cwidth, take_using_weights, to_str
32
31
 
33
32
  from euporie.core.data_structures import DiInt
34
33
  from euporie.core.layout.controls import DummyControl
@@ -56,6 +55,67 @@ if TYPE_CHECKING:
56
55
  log = logging.getLogger(__name__)
57
56
 
58
57
 
58
+ class DimensionTuple(NamedTuple):
59
+ """A hashable representation of a PTK :py:class:`Dimension`."""
60
+
61
+ min: int
62
+ max: int
63
+ preferred: int
64
+ weight: int = 1
65
+
66
+
67
+ @lru_cache
68
+ def distribute_dimensions(
69
+ size: int, dimensions: tuple[DimensionTuple, ...]
70
+ ) -> list[int] | None:
71
+ """Return the heights for all rows, or None when there is not enough space."""
72
+ if not dimensions:
73
+ return []
74
+
75
+ # Sum dimensions
76
+ sum_dimensions = DimensionTuple(
77
+ min=sum(d.min for d in dimensions),
78
+ max=sum(d.max for d in dimensions),
79
+ preferred=sum(d.preferred for d in dimensions),
80
+ )
81
+
82
+ # If there is not enough space for both.
83
+ # Don't do anything.
84
+ if sum_dimensions.min > size:
85
+ return None
86
+
87
+ # Find optimal sizes. (Start with minimal size, increase until we cover
88
+ # the whole size.)
89
+ sizes = [d.min for d in dimensions]
90
+
91
+ child_generator = take_using_weights(
92
+ items=list(range(len(dimensions))), weights=[d.weight for d in dimensions]
93
+ )
94
+
95
+ i = next(child_generator)
96
+
97
+ # Increase until we meet at least the 'preferred' size.
98
+ preferred_stop = min(size, sum_dimensions.preferred)
99
+ preferred_dimensions = [d.preferred for d in dimensions]
100
+
101
+ while sum(sizes) < preferred_stop:
102
+ if sizes[i] < preferred_dimensions[i]:
103
+ sizes[i] += 1
104
+ i = next(child_generator)
105
+
106
+ # Increase until we use all the available space. (or until "max")
107
+ if not get_app().is_done:
108
+ max_stop = min(size, sum_dimensions.max)
109
+ max_dimensions = [d.max for d in dimensions]
110
+
111
+ while sum(sizes) < max_stop:
112
+ if sizes[i] < max_dimensions[i]:
113
+ sizes[i] += 1
114
+ i = next(child_generator)
115
+
116
+ return sizes
117
+
118
+
59
119
  @lru_cache(maxsize=None)
60
120
  class DummyContainer(Container):
61
121
  """Base class for user interface layout."""
@@ -129,13 +189,22 @@ class HSplit(ptk_containers.HSplit):
129
189
  key_bindings=key_bindings,
130
190
  style=style,
131
191
  )
132
- _split_cache_getter = super()._divide_heights
133
- self._split_cache: FastDictCache[
134
- tuple[int, WritePosition], list[int] | None
135
- ] = FastDictCache(lambda rc, wp: _split_cache_getter(wp), size=100)
136
192
 
137
193
  def _divide_heights(self, write_position: WritePosition) -> list[int] | None:
138
- return self._split_cache[get_app().render_counter, write_position]
194
+ """Calculate and cache heights for all rows."""
195
+ width = write_position.width
196
+ height = write_position.height
197
+ dimensions = [c.preferred_height(width, height) for c in self._all_children]
198
+ result = distribute_dimensions(
199
+ height,
200
+ tuple(
201
+ DimensionTuple(
202
+ min=d.min, max=d.max, preferred=d.preferred, weight=d.weight
203
+ )
204
+ for d in dimensions
205
+ ),
206
+ )
207
+ return result
139
208
 
140
209
  def write_to_screen(
141
210
  self,
@@ -299,14 +368,20 @@ class VSplit(ptk_containers.VSplit):
299
368
  key_bindings=key_bindings,
300
369
  style=style,
301
370
  )
302
- _split_cache_getter = super()._divide_widths
303
- self._split_cache: FastDictCache[tuple[int, int], list[int] | None] = (
304
- FastDictCache(lambda rc, w: _split_cache_getter(w), size=100)
305
- )
306
371
 
307
372
  def _divide_widths(self, width: int) -> list[int] | None:
308
373
  """Calculate and cache widths for all columns."""
309
- return self._split_cache[get_app().render_counter, width]
374
+ dimensions = [c.preferred_width(width) for c in self._all_children]
375
+ result = distribute_dimensions(
376
+ width,
377
+ tuple(
378
+ DimensionTuple(
379
+ min=d.min, max=d.max, preferred=d.preferred, weight=d.weight
380
+ )
381
+ for d in dimensions
382
+ ),
383
+ )
384
+ return result
310
385
 
311
386
  def write_to_screen(
312
387
  self,