euporie 2.8.4__py3-none-any.whl → 2.8.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. euporie/console/_commands.py +143 -0
  2. euporie/console/_settings.py +58 -0
  3. euporie/console/app.py +25 -71
  4. euporie/console/tabs/console.py +58 -62
  5. euporie/core/__init__.py +1 -1
  6. euporie/core/__main__.py +28 -11
  7. euporie/core/_settings.py +109 -0
  8. euporie/core/app/__init__.py +3 -0
  9. euporie/core/app/_commands.py +95 -0
  10. euporie/core/app/_settings.py +457 -0
  11. euporie/core/{app.py → app/app.py} +212 -576
  12. euporie/core/app/base.py +51 -0
  13. euporie/core/{current.py → app/current.py} +13 -4
  14. euporie/core/app/cursor.py +35 -0
  15. euporie/core/app/dummy.py +12 -0
  16. euporie/core/app/launch.py +28 -0
  17. euporie/core/bars/__init__.py +11 -0
  18. euporie/core/bars/command.py +205 -0
  19. euporie/core/bars/menu.py +258 -0
  20. euporie/core/{widgets → bars}/search.py +20 -16
  21. euporie/core/{widgets → bars}/status.py +6 -23
  22. euporie/core/clipboard.py +19 -80
  23. euporie/core/comm/base.py +8 -6
  24. euporie/core/comm/ipywidgets.py +16 -7
  25. euporie/core/comm/registry.py +2 -1
  26. euporie/core/commands.py +10 -20
  27. euporie/core/completion.py +3 -2
  28. euporie/core/config.py +368 -341
  29. euporie/core/convert/__init__.py +0 -30
  30. euporie/core/convert/datum.py +116 -53
  31. euporie/core/convert/formats/__init__.py +31 -0
  32. euporie/core/convert/formats/ansi.py +9 -23
  33. euporie/core/convert/formats/common.py +11 -23
  34. euporie/core/convert/formats/html.py +45 -40
  35. euporie/core/convert/formats/pil.py +1 -1
  36. euporie/core/convert/formats/png.py +3 -5
  37. euporie/core/convert/formats/sixel.py +3 -3
  38. euporie/core/convert/registry.py +4 -6
  39. euporie/core/convert/utils.py +41 -4
  40. euporie/core/diagnostics.py +2 -2
  41. euporie/core/filters.py +98 -40
  42. euporie/core/format.py +2 -3
  43. euporie/core/ft/ansi.py +1 -1
  44. euporie/core/ft/html.py +12 -21
  45. euporie/core/ft/table.py +1 -3
  46. euporie/core/ft/utils.py +4 -1
  47. euporie/core/graphics.py +386 -133
  48. euporie/core/history.py +2 -2
  49. euporie/core/inspection.py +3 -2
  50. euporie/core/io.py +207 -28
  51. euporie/core/kernel/__init__.py +1 -0
  52. euporie/core/{kernel.py → kernel/client.py} +45 -108
  53. euporie/core/kernel/manager.py +114 -0
  54. euporie/core/key_binding/bindings/__init__.py +1 -8
  55. euporie/core/key_binding/bindings/basic.py +47 -7
  56. euporie/core/key_binding/bindings/completion.py +3 -8
  57. euporie/core/key_binding/bindings/micro.py +1 -6
  58. euporie/core/key_binding/bindings/mouse.py +2 -2
  59. euporie/core/key_binding/bindings/terminal.py +193 -0
  60. euporie/core/key_binding/key_processor.py +43 -2
  61. euporie/core/key_binding/registry.py +2 -0
  62. euporie/core/key_binding/utils.py +22 -2
  63. euporie/core/keys.py +7156 -93
  64. euporie/core/layout/cache.py +3 -3
  65. euporie/core/layout/containers.py +48 -4
  66. euporie/core/layout/decor.py +2 -2
  67. euporie/core/layout/mouse.py +1 -1
  68. euporie/core/layout/print.py +2 -1
  69. euporie/core/layout/scroll.py +39 -34
  70. euporie/core/log.py +76 -64
  71. euporie/core/lsp.py +118 -24
  72. euporie/core/margins.py +1 -1
  73. euporie/core/path.py +62 -13
  74. euporie/core/renderer.py +58 -17
  75. euporie/core/style.py +57 -39
  76. euporie/core/suggest.py +103 -85
  77. euporie/core/tabs/__init__.py +32 -0
  78. euporie/core/tabs/_settings.py +113 -0
  79. euporie/core/tabs/base.py +80 -470
  80. euporie/core/tabs/kernel.py +419 -0
  81. euporie/core/tabs/notebook.py +24 -101
  82. euporie/core/utils.py +92 -15
  83. euporie/core/validation.py +1 -1
  84. euporie/core/widgets/_settings.py +188 -0
  85. euporie/core/widgets/cell.py +19 -50
  86. euporie/core/widgets/cell_outputs.py +25 -36
  87. euporie/core/widgets/decor.py +11 -41
  88. euporie/core/widgets/dialog.py +62 -27
  89. euporie/core/widgets/display.py +12 -15
  90. euporie/core/widgets/file_browser.py +2 -23
  91. euporie/core/widgets/forms.py +8 -5
  92. euporie/core/widgets/inputs.py +13 -70
  93. euporie/core/widgets/layout.py +2 -1
  94. euporie/core/widgets/logo.py +49 -0
  95. euporie/core/widgets/menu.py +10 -8
  96. euporie/core/widgets/pager.py +6 -10
  97. euporie/core/widgets/palette.py +6 -6
  98. euporie/hub/app.py +52 -35
  99. euporie/notebook/_commands.py +24 -0
  100. euporie/notebook/_settings.py +107 -0
  101. euporie/notebook/app.py +49 -171
  102. euporie/notebook/filters.py +1 -1
  103. euporie/notebook/tabs/__init__.py +46 -7
  104. euporie/notebook/tabs/_commands.py +714 -0
  105. euporie/notebook/tabs/_settings.py +32 -0
  106. euporie/notebook/tabs/display.py +4 -4
  107. euporie/notebook/tabs/edit.py +11 -44
  108. euporie/notebook/tabs/json.py +5 -5
  109. euporie/notebook/tabs/log.py +1 -18
  110. euporie/notebook/tabs/notebook.py +11 -660
  111. euporie/notebook/widgets/_commands.py +11 -0
  112. euporie/notebook/widgets/_settings.py +19 -0
  113. euporie/notebook/widgets/side_bar.py +14 -34
  114. euporie/preview/_settings.py +104 -0
  115. euporie/preview/app.py +6 -31
  116. euporie/preview/tabs/notebook.py +6 -72
  117. euporie/web/__init__.py +1 -0
  118. euporie/web/tabs/__init__.py +14 -0
  119. euporie/web/tabs/web.py +11 -6
  120. euporie/web/widgets/__init__.py +1 -0
  121. euporie/web/widgets/webview.py +5 -15
  122. {euporie-2.8.4.dist-info → euporie-2.8.6.dist-info}/METADATA +10 -8
  123. euporie-2.8.6.dist-info/RECORD +175 -0
  124. {euporie-2.8.4.dist-info → euporie-2.8.6.dist-info}/WHEEL +1 -1
  125. {euporie-2.8.4.dist-info → euporie-2.8.6.dist-info}/entry_points.txt +2 -2
  126. {euporie-2.8.4.dist-info → euporie-2.8.6.dist-info}/licenses/LICENSE +1 -1
  127. euporie/core/launch.py +0 -64
  128. euporie/core/terminal.py +0 -522
  129. euporie-2.8.4.dist-info/RECORD +0 -147
  130. {euporie-2.8.4.data → euporie-2.8.6.data}/data/share/applications/euporie-console.desktop +0 -0
  131. {euporie-2.8.4.data → euporie-2.8.6.data}/data/share/applications/euporie-notebook.desktop +0 -0
@@ -8,19 +8,15 @@ from typing import TYPE_CHECKING, NamedTuple
8
8
  from prompt_toolkit.cache import FastDictCache, SimpleCache
9
9
  from prompt_toolkit.filters import to_filter
10
10
 
11
- # from euporie.core.cache import cache
12
-
13
11
  if TYPE_CHECKING:
14
- from typing import Callable, Iterable
12
+ from collections.abc import Iterable
13
+ from typing import Callable
15
14
 
16
15
  from prompt_toolkit.filters import Filter, FilterOrBool
17
16
 
18
17
  log = logging.getLogger(__name__)
19
18
 
20
19
 
21
- BASE64_FORMATS = {"png", "jpeg", "pdf", "gif"}
22
-
23
-
24
20
  class Converter(NamedTuple):
25
21
  """Hold a conversion function and its weight."""
26
22
 
@@ -60,6 +56,8 @@ def register(
60
56
 
61
57
  def _find_route(from_: str, to: str) -> list | None:
62
58
  """Find the shortest conversion path between two formats."""
59
+ from euporie.core.convert import formats # noqa: F401
60
+
63
61
  if from_ == to:
64
62
  return [from_]
65
63
 
@@ -6,15 +6,49 @@ import asyncio
6
6
  import logging
7
7
  import subprocess # S404 - Security implications have been considered
8
8
  import tempfile
9
+ from math import ceil
9
10
  from pathlib import Path
10
11
  from typing import TYPE_CHECKING
11
12
 
13
+ from euporie.core.app.current import get_app
14
+
12
15
  if TYPE_CHECKING:
13
16
  from typing import Any
14
17
 
18
+ from euporie.core.convert.datum import Datum
19
+
15
20
  log = logging.getLogger(__name__)
16
21
 
17
22
 
23
+ async def scale_to_fit(
24
+ datum: Datum, cols: int | None, rows: int | None
25
+ ) -> tuple[int, int]:
26
+ """Calculate image size based on aspect ratio, and scale to fit."""
27
+ data = datum.data
28
+ px, py = get_app().cell_size_px
29
+
30
+ # Calculate rows based on image aspect ratio
31
+ w, h = data.size
32
+ if rows is None and cols is not None:
33
+ rows = ceil(cols / w * h)
34
+ elif cols is None and rows is not None:
35
+ cols = ceil(rows / h * w)
36
+ elif rows is None and cols is None:
37
+ cols = ceil(w / px)
38
+ rows = ceil(h / py)
39
+ assert rows is not None
40
+ assert cols is not None
41
+
42
+ # Scale to fit while maintaining aspect ratio
43
+ _width, aspect = await datum.cell_size_async()
44
+ if cols * aspect < rows:
45
+ rows = ceil(cols * aspect)
46
+ else:
47
+ cols = ceil(rows / aspect)
48
+
49
+ return cols, rows
50
+
51
+
18
52
  async def call_subproc(
19
53
  data: str | bytes,
20
54
  cmd: list[Any],
@@ -43,15 +77,18 @@ async def call_subproc(
43
77
  if use_tempfile:
44
78
  # If the command cannot read from stdin, create a temporary file to pass to
45
79
  # the command
46
- tfile = tempfile.NamedTemporaryFile(delete=False, suffix=suffix)
47
- tfile.write(data)
48
- tfile.close()
80
+ with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as tfile:
81
+ tfile.write(data)
49
82
  cmd.append(tfile.name)
50
83
  stdinput = None
51
84
  else:
52
85
  stdinput = data
53
86
 
54
- log.debug("Running external command `%s`", cmd)
87
+ if log.level <= 0:
88
+ import shlex
89
+
90
+ log.debug("Running external command `%s`", shlex.join(cmd))
91
+
55
92
  error: Exception | None = None
56
93
  try:
57
94
  proc = await asyncio.create_subprocess_exec(
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import logging
6
6
  from abc import ABCMeta
7
- from typing import TYPE_CHECKING, List, NamedTuple
7
+ from typing import TYPE_CHECKING, NamedTuple
8
8
 
9
9
  if TYPE_CHECKING:
10
10
  from typing import Literal
@@ -23,7 +23,7 @@ class Diagnostic(NamedTuple):
23
23
  chars: slice
24
24
 
25
25
 
26
- class Report(List[Diagnostic], metaclass=ABCMeta):
26
+ class Report(list[Diagnostic], metaclass=ABCMeta):
27
27
  """Class for storing a diagnostic report."""
28
28
 
29
29
  @classmethod
euporie/core/filters.py CHANGED
@@ -3,12 +3,12 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import os
6
- from functools import lru_cache, partial, reduce
7
- from importlib import import_module
6
+ from functools import cache, partial, reduce
7
+ from importlib.util import find_spec
8
8
  from shutil import which
9
9
  from typing import TYPE_CHECKING
10
10
 
11
- from prompt_toolkit.enums import EditingMode
11
+ # from prompt_toolkit.enums import EditingMode
12
12
  from prompt_toolkit.filters import (
13
13
  Condition,
14
14
  emacs_insert_mode,
@@ -27,7 +27,7 @@ if TYPE_CHECKING:
27
27
  from prompt_toolkit.layout.containers import Window
28
28
 
29
29
 
30
- @lru_cache(maxsize=None)
30
+ @cache
31
31
  def command_exists(*cmds: str) -> Filter:
32
32
  """Verify a list of external commands exist on the system."""
33
33
  filters = [
@@ -37,17 +37,13 @@ def command_exists(*cmds: str) -> Filter:
37
37
  return reduce(lambda a, b: a & b, filters, to_filter(True))
38
38
 
39
39
 
40
- @lru_cache(maxsize=None)
40
+ @cache
41
41
  def have_modules(*modules: str) -> Filter:
42
42
  """Verify a list of python modules are importable."""
43
43
 
44
44
  def try_import(module: str) -> bool:
45
- try:
46
- import_module(module)
47
- except ModuleNotFoundError:
48
- return False
49
- else:
50
- return True
45
+ loader = find_spec(module)
46
+ return loader is not None
51
47
 
52
48
  filters = [Condition(partial(try_import, module)) for module in modules]
53
49
  return reduce(lambda a, b: a & b, filters, to_filter(True))
@@ -81,12 +77,20 @@ def has_suggestion() -> bool:
81
77
  )
82
78
 
83
79
 
80
+ @Condition
81
+ def has_tabs() -> bool:
82
+ """Filter to show if any tabs are open in an app."""
83
+ from euporie.core.app.current import get_app
84
+
85
+ return bool(get_app().tabs)
86
+
87
+
84
88
  @Condition
85
89
  def has_dialog() -> bool:
86
90
  """Determine if a dialog is being displayed."""
87
91
  from prompt_toolkit.layout.containers import ConditionalContainer
88
92
 
89
- from euporie.core.current import get_app
93
+ from euporie.core.app.current import get_app
90
94
 
91
95
  app = get_app()
92
96
  for dialog in app.dialogs.values():
@@ -112,18 +116,59 @@ def has_menus() -> bool:
112
116
  has_float = has_dialog | has_menus | has_completions
113
117
 
114
118
 
119
+ @Condition
120
+ def has_toolbar() -> bool:
121
+ """Is there an active toolbar?"""
122
+ from euporie.core.app.current import get_app
123
+ from euporie.core.bars import BAR_BUFFERS
124
+
125
+ return get_app().current_buffer.name in BAR_BUFFERS
126
+
127
+
115
128
  @Condition
116
129
  def tab_has_focus() -> bool:
117
130
  """Determine if there is a currently focused tab."""
118
- from euporie.core.current import get_app
131
+ from euporie.core.app.current import get_app
119
132
 
120
133
  return get_app().tab is not None
121
134
 
122
135
 
136
+ @Condition
137
+ def kernel_tab_has_focus() -> bool:
138
+ """Determine if there is a focused kernel tab."""
139
+ from euporie.core.app.current import get_app
140
+ from euporie.core.tabs.kernel import KernelTab
141
+
142
+ return isinstance(get_app().tab, KernelTab)
143
+
144
+
145
+ @cache
146
+ def tab_type_has_focus(tab_class_path: str) -> Condition:
147
+ """Determine if the focused tab is of a particular type."""
148
+ from pkgutil import resolve_name
149
+
150
+ from euporie.core.app.current import get_app
151
+
152
+ tab_class = cache(resolve_name)
153
+
154
+ return Condition(lambda: isinstance(get_app().tab, tab_class(tab_class_path)))
155
+
156
+
157
+ @Condition
158
+ def tab_can_save() -> bool:
159
+ """Determine if the current tab can save it's contents."""
160
+ from euporie.core.app.current import get_app
161
+ from euporie.core.tabs.base import Tab
162
+
163
+ return (
164
+ tab := get_app().tab
165
+ ) is not None and tab.__class__.write_file != Tab.write_file
166
+
167
+
123
168
  @Condition
124
169
  def pager_has_focus() -> bool:
125
170
  """Determine if there is a currently focused notebook."""
126
- from euporie.core.current import get_app
171
+ from euporie.core.app.current import get_app
127
172
 
128
173
  app = get_app()
129
174
  pager = app.pager
@@ -135,7 +180,7 @@ def pager_has_focus() -> bool:
135
180
  @Condition
136
181
  def display_has_focus() -> bool:
137
182
  """Determine if there is a currently focused cell."""
138
- from euporie.core.current import get_app
183
+ from euporie.core.app.current import get_app
139
184
  from euporie.core.widgets.display import DisplayControl
140
185
 
141
186
  return isinstance(get_app().layout.current_control, DisplayControl)
@@ -144,7 +189,7 @@ def display_has_focus() -> bool:
144
189
  @Condition
145
190
  def buffer_is_empty() -> bool:
146
191
  """Determine if the current buffer contains nothing."""
147
- from euporie.core.current import get_app
192
+ from euporie.core.app.current import get_app
148
193
 
149
194
  return not get_app().current_buffer.text
150
195
 
@@ -152,7 +197,7 @@ def buffer_is_empty() -> bool:
152
197
  @Condition
153
198
  def buffer_is_code() -> bool:
154
199
  """Determine if the current buffer contains code."""
155
- from euporie.core.current import get_app
200
+ from euporie.core.app.current import get_app
156
201
 
157
202
  return get_app().current_buffer.name == "code"
158
203
 
@@ -160,7 +205,7 @@ def buffer_is_code() -> bool:
160
205
  @Condition
161
206
  def buffer_is_markdown() -> bool:
162
207
  """Determine if the current buffer contains markdown."""
163
- from euporie.core.current import get_app
208
+ from euporie.core.app.current import get_app
164
209
 
165
210
  return get_app().current_buffer.name == "markdown"
166
211
 
@@ -168,15 +213,16 @@ def buffer_is_markdown() -> bool:
168
213
  @Condition
169
214
  def micro_mode() -> bool:
170
215
  """When the micro key-bindings are active."""
171
- from euporie.core.current import get_app
216
+ from euporie.core.app.app import ExtraEditingMode
217
+ from euporie.core.app.current import get_app
172
218
 
173
- return get_app().editing_mode == EditingMode.MICRO # type: ignore
219
+ return get_app().editing_mode == ExtraEditingMode.MICRO
174
220
 
175
221
 
176
222
  @Condition
177
223
  def micro_replace_mode() -> bool:
178
224
  """Determine if the editor is in overwrite mode."""
179
- from euporie.core.current import get_app
225
+ from euporie.core.app.current import get_app
180
226
 
181
227
  app = get_app()
182
228
  return app.micro_state.input_mode == MicroInputMode.REPLACE
@@ -185,7 +231,7 @@ def micro_replace_mode() -> bool:
185
231
  @Condition
186
232
  def micro_insert_mode() -> bool:
187
233
  """Determine if the editor is in insert mode."""
188
- from euporie.core.current import get_app
234
+ from euporie.core.app.current import get_app
189
235
 
190
236
  app = get_app()
191
237
  return app.micro_state.input_mode == MicroInputMode.INSERT
@@ -194,7 +240,7 @@ def micro_insert_mode() -> bool:
194
240
  @Condition
195
241
  def micro_recording_macro() -> bool:
196
242
  """Determine if a micro macro is being recorded."""
197
- from euporie.core.current import get_app
243
+ from euporie.core.app.current import get_app
198
244
 
199
245
  return get_app().micro_state.current_recording is not None
200
246
 
@@ -202,7 +248,7 @@ def micro_recording_macro() -> bool:
202
248
  @Condition
203
249
  def is_returnable() -> bool:
204
250
  """Determine if the current buffer has an accept handler."""
205
- from euporie.core.current import get_app
251
+ from euporie.core.app.current import get_app
206
252
 
207
253
  return get_app().current_buffer.is_returnable
208
254
 
@@ -210,7 +256,7 @@ def is_returnable() -> bool:
210
256
  @Condition
211
257
  def cursor_at_start_of_line() -> bool:
212
258
  """Determine if the cursor is at the start of a line."""
213
- from euporie.core.current import get_app
259
+ from euporie.core.app.current import get_app
214
260
 
215
261
  return get_app().current_buffer.document.cursor_position_col == 0
216
262
 
@@ -218,7 +264,7 @@ def cursor_at_start_of_line() -> bool:
218
264
  @Condition
219
265
  def cursor_on_first_line() -> bool:
220
266
  """Determine if the cursor is on the first line of a buffer."""
221
- from euporie.core.current import get_app
267
+ from euporie.core.app.current import get_app
222
268
 
223
269
  return get_app().current_buffer.document.on_first_line
224
270
 
@@ -226,11 +272,32 @@ def cursor_on_first_line() -> bool:
226
272
  @Condition
227
273
  def cursor_on_last_line() -> bool:
228
274
  """Determine if the cursor is on the last line of a buffer."""
229
- from euporie.core.current import get_app
275
+ from euporie.core.app.current import get_app
230
276
 
231
277
  return get_app().current_buffer.document.on_last_line
232
278
 
233
279
 
280
+ @cache
281
+ def char_after_cursor(char: str) -> Condition:
282
+ """Generate a condition to check for a character after the cursor."""
283
+ from euporie.core.app.current import get_app
284
+
285
+ return Condition(
286
+ lambda: bool(
287
+ (post := get_app().current_buffer.document.text_after_cursor)
288
+ and post[0] == char
289
+ )
290
+ )
291
+
292
+
293
+ @Condition
294
+ def has_matching_bracket() -> bool:
295
+ """Determine if the bracket at the cursor has a matching pair."""
296
+ from euporie.core.app.current import get_app
297
+
298
+ return bool(get_app().current_buffer.document.find_matching_bracket_position())
299
+
300
+
234
301
  """Determine if any binding style is in insert mode."""
235
302
  insert_mode = (
236
303
  (vi_mode & vi_insert_mode)
@@ -245,7 +312,7 @@ replace_mode = micro_replace_mode | vi_replace_mode
245
312
  @Condition
246
313
  def is_searching() -> bool:
247
314
  """Determine if the app is in search mode."""
248
- from euporie.core.current import get_app
315
+ from euporie.core.app.current import get_app
249
316
 
250
317
  app = get_app()
251
318
  return (
@@ -265,8 +332,8 @@ def at_end_of_buffer() -> bool:
265
332
  @Condition
266
333
  def kernel_is_python() -> bool:
267
334
  """Determine if the current notebook has a python kernel."""
268
- from euporie.core.current import get_app
269
- from euporie.core.tabs.base import KernelTab
335
+ from euporie.core.app.current import get_app
336
+ from euporie.core.tabs.kernel import KernelTab
270
337
 
271
338
  kernel_tab = get_app().tab
272
339
  if isinstance(kernel_tab, KernelTab):
@@ -277,7 +344,7 @@ def kernel_is_python() -> bool:
277
344
  @Condition
278
345
  def multiple_cells_selected() -> bool:
279
346
  """Determine if there is more than one selected cell."""
280
- from euporie.core.current import get_app
347
+ from euporie.core.app.current import get_app
281
348
  from euporie.core.tabs.notebook import BaseNotebook
282
349
 
283
350
  nb = get_app().tab
@@ -286,15 +353,6 @@ def multiple_cells_selected() -> bool:
286
353
  return False
287
354
 
288
355
 
289
- @Condition
290
- def kernel_tab_has_focus() -> bool:
291
- """Determine if there is a focused kernel tab."""
292
- from euporie.core.current import get_app
293
- from euporie.core.tabs.base import KernelTab
294
-
295
- return isinstance(get_app().tab, KernelTab)
296
-
297
-
298
356
  def scrollable(window: Window) -> Filter:
299
357
  """Return a filter which indicates if a window is scrollable."""
300
358
  return Condition(
euporie/core/format.py CHANGED
@@ -110,11 +110,10 @@ class LspFormatter(Formatter):
110
110
  range_ = change.get("range", {})
111
111
  start = range_.get("start", {})
112
112
  start_line = start.get("line", 0)
113
- start_char = start.get("char", 0)
113
+ start_char = start.get("character", 0)
114
114
  end = range_.get("end", {})
115
115
  end_line = end.get("line", 0)
116
- end_char = end.get("char", 0)
117
-
116
+ end_char = end.get("character", 0)
118
117
  segment = range_to_slice(
119
118
  start_line, start_char, end_line, end_char, text
120
119
  )
euporie/core/ft/ansi.py CHANGED
@@ -9,7 +9,7 @@ from typing import TYPE_CHECKING
9
9
  from prompt_toolkit.formatted_text import ANSI as PTANSI
10
10
 
11
11
  if TYPE_CHECKING:
12
- from typing import Generator
12
+ from collections.abc import Generator
13
13
 
14
14
  log = logging.getLogger(__name__)
15
15
 
euporie/core/ft/html.py CHANGED
@@ -27,6 +27,7 @@ from prompt_toolkit.layout.dimension import Dimension
27
27
  from prompt_toolkit.utils import Event
28
28
  from upath import UPath
29
29
 
30
+ from euporie.core.app.current import get_app
30
31
  from euporie.core.border import (
31
32
  DiLineStyle,
32
33
  DoubleLine,
@@ -50,7 +51,6 @@ from euporie.core.border import (
50
51
  )
51
52
  from euporie.core.convert.datum import Datum, get_loop
52
53
  from euporie.core.convert.mime import get_format
53
- from euporie.core.current import get_app
54
54
  from euporie.core.data_structures import DiBool, DiInt, DiStr
55
55
  from euporie.core.ft.table import Cell, Table, compute_padding
56
56
  from euporie.core.ft.utils import (
@@ -102,8 +102,9 @@ class CssSelector(NamedTuple):
102
102
 
103
103
 
104
104
  if TYPE_CHECKING:
105
+ from collections.abc import Generator, Iterator
105
106
  from pathlib import Path
106
- from typing import Any, Callable, Generator, Iterator
107
+ from typing import Any, Callable
107
108
 
108
109
  from fsspec.spec import AbstractFileSystem
109
110
  from prompt_toolkit.filters.base import Filter
@@ -595,8 +596,8 @@ def css_dimension(
595
596
 
596
597
  # Get cell pixel dimensions
597
598
  app = get_app()
598
- if hasattr(app, "term_info"):
599
- cell_px, cell_py = get_app().term_info.cell_size_px
599
+ if hasattr(app, "cell_size_px"):
600
+ cell_px, cell_py = get_app().cell_size_px
600
601
  else:
601
602
  cell_px, cell_py = 10, 20
602
603
 
@@ -1149,8 +1150,7 @@ class Theme(Mapping):
1149
1150
  and parent_theme["flex_direction"].startswith("col")
1150
1151
  )
1151
1152
  )
1152
- or (parent_theme is not None and parent_theme.d_grid)
1153
- )
1153
+ ) or (parent_theme is not None and parent_theme.d_grid)
1154
1154
 
1155
1155
  @cached_property
1156
1156
  def d_inline(self) -> bool:
@@ -2892,7 +2892,7 @@ class Node:
2892
2892
  s += ">"
2893
2893
  if self.contents:
2894
2894
  for child in self.contents:
2895
- s += f"\n{dd} {child._outer_html(d+1, attrs=attrs)}"
2895
+ s += f"\n{dd} {child._outer_html(d + 1, attrs=attrs)}"
2896
2896
  s += f"\n{dd}{dd}"
2897
2897
  s += f"</{self.name}>"
2898
2898
  else:
@@ -3263,15 +3263,6 @@ class CustomHTMLParser(HTMLParser):
3263
3263
  Node(dom=self.dom, name="::text", text=data, parent=self.curr, attrs=[])
3264
3264
  )
3265
3265
 
3266
- # def handle_endtag(self, tag: str) -> None:
3267
- # """Handle end tags: close the currently opened element."""
3268
- # if tag == self.curr.name:
3269
- # self.curr.closed = True
3270
- # if self.curr.parent:
3271
- # self.curr = self.curr.parent
3272
- # else:
3273
- # self.autoclose()
3274
-
3275
3266
  def handle_endtag(self, tag: str) -> None:
3276
3267
  """Handle end tags: close the currently opened element."""
3277
3268
  if tag != self.curr.name:
@@ -3285,7 +3276,6 @@ def parse_style_sheet(css_str: str, dom: HTML, condition: Filter = always) -> No
3285
3276
  """Collect all CSS styles from style tags."""
3286
3277
  dom_css = dom.css
3287
3278
  # Remove whitespace and newlines
3288
- # css_str = css_str.strip().replace("\n", "")
3289
3279
  css_str = re.sub(r"\s*\n\s*", " ", css_str)
3290
3280
  # Remove comments
3291
3281
  css_str = re.sub(r"\/\*[^\*]+\*\/", "", css_str)
@@ -4992,15 +4982,16 @@ if __name__ == "__main__":
4992
4982
  from prompt_toolkit.shortcuts.utils import print_formatted_text
4993
4983
  from prompt_toolkit.styles.style import Style
4994
4984
 
4995
- from euporie.core.app import BaseApp
4985
+ from euporie.core.app.dummy import DummyApp
4996
4986
  from euporie.core.path import parse_path
4997
4987
  from euporie.core.style import HTML_STYLE
4998
4988
 
4999
4989
  path = parse_path(sys.argv[1])
5000
4990
 
5001
- with create_app_session(
5002
- input=BaseApp.load_input(), output=BaseApp.load_output()
5003
- ), set_app(BaseApp()):
4991
+ with (
4992
+ create_app_session(input=DummyApp.load_input(), output=DummyApp.load_output()),
4993
+ set_app(DummyApp()),
4994
+ ):
5004
4995
  print_formatted_text(
5005
4996
  HTML(
5006
4997
  path.read_text(),
euporie/core/ft/table.py CHANGED
@@ -36,11 +36,9 @@ from euporie.core.ft.utils import (
36
36
  )
37
37
 
38
38
  if TYPE_CHECKING:
39
+ from collections.abc import Iterable, Iterator, Sequence
39
40
  from typing import (
40
41
  Any,
41
- Iterable,
42
- Iterator,
43
- Sequence,
44
42
  TypeVar,
45
43
  )
46
44
 
euporie/core/ft/utils.py CHANGED
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import re
6
6
  from enum import Enum
7
- from typing import Iterable, cast
7
+ from typing import TYPE_CHECKING, cast
8
8
 
9
9
  from prompt_toolkit.formatted_text.base import OneStyleAndTextTuple, StyleAndTextTuples
10
10
  from prompt_toolkit.formatted_text.utils import (
@@ -20,6 +20,9 @@ from pygments.util import ClassNotFound
20
20
  from euporie.core.border import GridStyle, ThinGrid
21
21
  from euporie.core.data_structures import DiBool, DiInt, DiStr
22
22
 
23
+ if TYPE_CHECKING:
24
+ from collections.abc import Iterable
25
+
23
26
  _ZERO_WIDTH_FRAGMENTS = ("[ZeroWidthEscape]", "[ReverseOverwrite]")
24
27
 
25
28