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
euporie/core/terminal.py DELETED
@@ -1,522 +0,0 @@
1
- """Contain classes related to querying terminal features."""
2
-
3
- from __future__ import annotations
4
-
5
- import logging
6
- import os
7
- import re
8
- import shlex
9
- import subprocess
10
- import time
11
- from base64 import b64decode
12
- from datetime import datetime as dt
13
- from functools import lru_cache
14
- from typing import TYPE_CHECKING, ClassVar
15
-
16
- from aenum import extend_enum
17
- from prompt_toolkit.application.run_in_terminal import run_in_terminal
18
- from prompt_toolkit.key_binding.key_processor import KeyProcessor, _Flush
19
- from prompt_toolkit.keys import Keys
20
- from prompt_toolkit.output import ColorDepth
21
- from prompt_toolkit.utils import Event
22
-
23
- from euporie.core.commands import add_cmd
24
- from euporie.core.current import get_app
25
- from euporie.core.filters import in_screen, in_tmux
26
- from euporie.core.key_binding.registry import register_bindings
27
- from euporie.core.style import DEFAULT_COLORS
28
-
29
- if TYPE_CHECKING:
30
- from typing import Any
31
-
32
- from prompt_toolkit.input import Input
33
- from prompt_toolkit.key_binding import KeyPressEvent
34
- from prompt_toolkit.output import Output
35
-
36
- from euporie.core.config import Config
37
-
38
- log = logging.getLogger(__name__)
39
-
40
-
41
- @lru_cache
42
- def _have_termios_tty_fcntl() -> bool:
43
- try:
44
- import fcntl # noqa F401
45
- import termios # noqa F401
46
- import tty # noqa F401
47
- except ModuleNotFoundError:
48
- return False
49
- else:
50
- return True
51
-
52
-
53
- def passthrough(cmd: str) -> str:
54
- """Wrap an escape sequence for terminal passthrough."""
55
- if get_app().config.multiplexer_passthrough:
56
- if in_tmux():
57
- cmd = cmd.replace("\x1b", "\x1b\x1b")
58
- cmd = f"\x1bPtmux;{cmd}\x1b\\"
59
- elif in_screen():
60
- # Screen limits escape sequences to 768 bytes, so we have to chunk it
61
- cmd = "".join(
62
- f"\x1bP{cmd[i: i+764]}\x1b\\" for i in range(0, len(cmd), 764)
63
- )
64
- return cmd
65
-
66
-
67
- class TerminalQuery:
68
- """A class representing a terminal query.
69
-
70
- This allows a control sequence to sent to the terminal, the response interpreted,
71
- and the received value processed and stored.
72
- """
73
-
74
- default: Any | None = None
75
- cache = False
76
- cmd = ""
77
- pattern: re.Pattern | None = None
78
- run_at_startup: bool = True
79
-
80
- def __init__(self, input_: Input, output: Output, config: Config) -> None:
81
- """Create a new instance of the terminal query."""
82
- self.input = input_
83
- self.output = output
84
- self.config = config
85
- self.key: Keys | None = None
86
- self.waiting = False
87
- self._value: Any | None = None
88
- self.event = Event(self)
89
- self.queryable = self.output.stdout and (
90
- self.output.stdout.isatty()
91
- # Don't send escape codes if this is not a real TTY.
92
- # We create pseudo-ttys to get colored output, but don't want
93
- # any terminal queries to be sent
94
- and not getattr(self.output.stdout, "fake_tty", False)
95
- )
96
- if not self.queryable:
97
- self.cmd = ""
98
-
99
- def verify(self, data: str) -> Any | None:
100
- """Verify the response from the terminal."""
101
- return None
102
-
103
- def await_response(self, timeout: float = 0.2) -> bool:
104
- """Wait for a response from the terminal."""
105
- app = get_app()
106
- start = dt.now()
107
- while (dt.now() - start).total_seconds() < timeout:
108
- time.sleep(0.05)
109
- for press in self.input.read_keys():
110
- if press.key == self.key:
111
- # If we find the key we're after, process it immediately
112
- tkp = KeyProcessor(key_bindings=app.key_processor._bindings)
113
- tkp.feed_multiple([press, _Flush])
114
- tkp.process_keys()
115
- return True
116
- else:
117
- # If we get other keys, add them to the input queue
118
- app.key_processor.feed(press)
119
- return False
120
-
121
- def _handle_response(self, event: KeyPressEvent) -> object:
122
- """Run when the terminal receives the response from the terminal.
123
-
124
- Args:
125
- event: The key press event received when the termina sends a response
126
-
127
- Returns:
128
- :py:obj:`NotImplemented`, so the application is not invalidated when a
129
- response from the terminal is received
130
-
131
- """
132
- log.debug("Got terminal response for '%s'", self.__class__.__name__)
133
- self.waiting = False
134
- new_value = self.verify(event.data)
135
- # Only fire the event if the value has changed
136
- if self._value != new_value:
137
- self._value = new_value
138
- self.event.fire()
139
- return NotImplemented
140
-
141
- def _cmd(self) -> str:
142
- """Return the query's command."""
143
- return self.cmd
144
-
145
- def send(self, flush: bool = True) -> None:
146
- """Send the terminal query command to the output."""
147
- if self.queryable and self.cmd and not self.waiting:
148
- cmd = self._cmd()
149
- log.debug(
150
- "Sending query %s for %s",
151
- cmd.__repr__(),
152
- self.__class__.__name__,
153
- )
154
- self.output.write_raw(cmd)
155
- if flush:
156
- self.output.flush()
157
- self.waiting = True
158
-
159
- @property
160
- def value(self) -> Any:
161
- """Return the last known value for the query.
162
-
163
- Returns:
164
- The last value received, or the default value.
165
-
166
- """
167
- return self._value or self.default
168
-
169
-
170
- class Colors(TerminalQuery):
171
- """A terminal query to retrieve colours as hex codes."""
172
-
173
- _color_names: ClassVar[dict[str, str]] = {
174
- "10": "fg",
175
- "11": "bg",
176
- "4;0": "ansiblack",
177
- "4;1": "ansired",
178
- "4;2": "ansigreen",
179
- "4;3": "ansiyellow",
180
- "4;4": "ansiblue",
181
- "4;5": "ansipurple",
182
- "4;6": "ansicyan",
183
- "4;7": "ansiwhite",
184
- "4;8": "ansirbightblack",
185
- "4;9": "ansirbightred",
186
- "4;10": "ansirbightgreen",
187
- "4;11": "ansirbightyellow",
188
- "4;12": "ansirbightblue",
189
- "4;13": "ansirbightpurple",
190
- "4;14": "ansirbightcyan",
191
- "4;15": "ansirbightwhite",
192
- }
193
- default = DEFAULT_COLORS
194
- cache = True
195
- cmd = ("\x1b]10;?\x1b\\" "\x1b]11;?\x1b\\") + "".join(
196
- f"\x1b]4;{i};?\x1b\\" for i in range(16)
197
- )
198
- pattern = re.compile(
199
- r"^\x1b\](?P<c>(\d+;)?\d+)+;rgb:"
200
- r"(?P<r>[0-9A-Fa-f]{2,4})\/"
201
- r"(?P<g>[0-9A-Fa-f]{2,4})\/"
202
- r"(?P<b>[0-9A-Fa-f]{2,4})"
203
- # Allow BEL or ST as terminator
204
- r"(\x1b\\\Z|\0x7)"
205
- )
206
-
207
- def _cmd(self) -> str:
208
- return passthrough(self.cmd)
209
-
210
- def verify(self, data: str) -> dict[str, str]:
211
- """Verify the response contains a colour."""
212
- if (match := self.pattern.match(data)) and (colors := match.groupdict()):
213
- c = colors["c"]
214
- r, g, b = (
215
- colors.get("r", "00"),
216
- colors.get("g", "00"),
217
- colors.get("b", "00"),
218
- )
219
- return {
220
- **self.value,
221
- self._color_names.get(c, c): f"#{r[:2]}{g[:2]}{b[:2]}",
222
- }
223
- return self.value
224
-
225
-
226
- class PixelDimensions(TerminalQuery):
227
- """A terminal query to check the terminal's dimensions in pixels."""
228
-
229
- default = (0, 0)
230
- cmd = "\x1b[14t"
231
- cache = True
232
- pattern = re.compile(r"^\x1b\[4;(?P<y>\d+);(?P<x>\d+)t")
233
-
234
- def verify(self, data: str) -> tuple[int, int] | None:
235
- """Verify the terminal responded with pixel dimensions."""
236
- if (
237
- (match := self.pattern.match(data))
238
- and (values := match.groupdict())
239
- and (x := values.get("x")) is not None
240
- and (y := values.get("y")) is not None
241
- ):
242
- return int(x), int(y)
243
- return None
244
-
245
-
246
- class KittyGraphicsStatus(TerminalQuery):
247
- """A terminal query to check for kitty graphics support."""
248
-
249
- default = False
250
- cache = True
251
- cmd = "\x1b_Gi=4294967295,s=1,v=1,a=q,t=d,f=24;AAAA\x1b\\"
252
- # Konsole responds with 'i=0' - I'll allow it
253
- pattern = re.compile(r"^\x1b_Gi=(4294967295|0);(?P<status>OK)\x1b\\\Z")
254
-
255
- def _cmd(self) -> str:
256
- """Hide the command in case the terminal does not support this sequence."""
257
- return "\x1b[s" + passthrough(self.cmd) + "\x1b[u\x1b[2K"
258
-
259
- def verify(self, data: str) -> bool:
260
- """Verify the terminal response means kitty graphics are supported."""
261
- return bool(
262
- (match := self.pattern.match(data))
263
- and (values := match.groupdict())
264
- and values.get("status") == "OK"
265
- )
266
-
267
-
268
- class SixelGraphicsStatus(TerminalQuery):
269
- """A terminal query to check for sixel graphics support."""
270
-
271
- default = False
272
- cache = True
273
- cmd = "\x1b[c"
274
- pattern = re.compile(r"^\x1b\[\?(?:\d+;)*(?P<sixel>4)(?:;\d+)*c\Z")
275
-
276
- def _cmd(self) -> str:
277
- return passthrough(self.cmd)
278
-
279
- def verify(self, data: str) -> bool:
280
- """Verify the terminal response means sixel graphics are supported."""
281
- return bool(
282
- (match := self.pattern.match(data))
283
- and (values := match.groupdict())
284
- and values.get("sixel")
285
- )
286
-
287
-
288
- class ItermGraphicsStatus(TerminalQuery):
289
- """A terminal query to check for iTerm graphics support."""
290
-
291
- default = False
292
- cache = True
293
- cmd = "\x1b[>q"
294
- pattern = re.compile(r"^\x1bP>\|(?P<term>[^\x1b]+)\x1b\\")
295
-
296
- def _cmd(self) -> str:
297
- return passthrough(self.cmd)
298
-
299
- def verify(self, data: str) -> bool:
300
- """Verify iterm graphics are supported by the terminal."""
301
- return bool(
302
- (match := self.pattern.match(data))
303
- and (values := match.groupdict())
304
- and (term := values.get("term"))
305
- and term.startswith(("WezTerm", "Konsole", "mlterm"))
306
- )
307
-
308
-
309
- class DepthOfColor(TerminalQuery):
310
- """Determine the suspected color depth of the terminal."""
311
-
312
- # TODO - detect 24bit color support with escape sequence
313
- # "\x1b[48:2:1:2:3m\eP$qm\x1b\\"
314
-
315
- default = ColorDepth.DEPTH_24_BIT
316
-
317
- def __init__(self, input_: Input, output: Output, config: Config) -> None:
318
- """Detect the terminal's colour support based on environment variables."""
319
- super().__init__(input_, output, config)
320
- self._value: ColorDepth | None = None
321
- if os.environ.get("NO_COLOR", "") or os.environ.get("TERM", "") == "dumb":
322
- self._value = ColorDepth.DEPTH_1_BIT
323
- return
324
- colorterm = os.environ.get("COLORTERM", "")
325
- if "truecolor" in colorterm or "24bit" in colorterm:
326
- self._value = ColorDepth.DEPTH_24_BIT
327
- return
328
- if "256" in os.environ.get("TERM", ""):
329
- self._value = ColorDepth.DEPTH_8_BIT
330
- return
331
-
332
-
333
- class SgrPixelStatus(TerminalQuery):
334
- """A terminal query to check for Pixel SGR support."""
335
-
336
- default = False
337
- cache = True
338
- cmd = "\x1b[?1016h\x1b[?1016$p\x1b[?1016l" # Enable, check, disable
339
- pattern = re.compile(r"^\x1b\[\?1016;(?P<Pm>\d)\$\Z")
340
-
341
- def verify(self, data: str) -> bool:
342
- """Verify the terminal response means SGR pixel-mode is supported."""
343
- return bool(
344
- (match := self.pattern.match(data))
345
- and (values := match.groupdict())
346
- and (values.get("Pm") in {"1", "3"})
347
- )
348
-
349
-
350
- class CsiUStatus(TerminalQuery):
351
- """A terminal query to check for CSI-u support."""
352
-
353
- default = False
354
- cache = True
355
- cmd = "\x1b[?u"
356
- pattern = re.compile(r"^\x1b\[\?\d+u")
357
-
358
- def verify(self, data: str) -> bool:
359
- """Verify the terminal responds."""
360
- return bool((match := self.pattern.match(data)) and match)
361
-
362
-
363
- class ClipboardData(TerminalQuery):
364
- """A terminal query to retrieve clipboard contents."""
365
-
366
- default = ""
367
- cache = False
368
- cmd = "\x1b]52;c;?\x1b\\"
369
- pattern = re.compile(r"^\x1b\]52;(?:c|p)?;(?P<data>[A-Za-z0-9+/=]+)\x1b\\\Z")
370
- run_at_startup = False
371
-
372
- def verify(self, data: str) -> str:
373
- """Verify the terminal responds."""
374
- if (match := self.pattern.match(data)) and (values := match.groupdict()):
375
- value = values.get("data", "")
376
- return b64decode(value).decode()
377
- return ""
378
-
379
-
380
- class TerminalInfo:
381
- """A class to gather and hold information about the terminal."""
382
-
383
- input: Input
384
- output: Output
385
-
386
- _queries: ClassVar[dict[type[TerminalQuery], TerminalQuery]] = {}
387
-
388
- def __init__(self, input_: Input, output: Output, config: Config) -> None:
389
- """Instantiate the terminal information class."""
390
- self.input = input_
391
- self.output = output
392
- self.config = config
393
-
394
- self.colors = self.register(Colors)
395
- self.pixel_dimensions = self.register(PixelDimensions)
396
- self.sixel_graphics_status = self.register(SixelGraphicsStatus)
397
- self.kitty_graphics_status = self.register(KittyGraphicsStatus)
398
- self.iterm_graphics_status = self.register(ItermGraphicsStatus)
399
- self.depth_of_color = self.register(DepthOfColor)
400
- self.sgr_pixel_status = self.register(SgrPixelStatus)
401
- # self.csiu_status = self.register(CsiUStatus)
402
- self.clipboard_data = self.register(ClipboardData)
403
-
404
- def register(self, query: type[TerminalQuery]) -> TerminalQuery:
405
- """Instantiate and registers a query's response with the input parser."""
406
- # Create an instance of this query
407
- query_inst: TerminalQuery | None
408
-
409
- if (query_inst := self._queries.get(query)) is None:
410
- query_inst = query(self.input, self.output, config=self.config)
411
- self._queries[query] = query_inst
412
-
413
- # If the query expects a response from the terminal, we need to add a
414
- # key-binding for it and register it with the input parser
415
- if query.pattern:
416
- name = re.sub(r"(?<!^)(?=[A-Z])", "-", query.__name__).lower()
417
- title = name.replace("-", " ")
418
-
419
- # Add a "key" definition for this query
420
- key_name = f"{query.__name__}Response"
421
- key_code = f"<{name}-response>"
422
- # Do not register the same key multiple times
423
- if not hasattr(Keys, key_name):
424
- extend_enum(Keys, key_name, key_code)
425
- key = getattr(Keys, key_name)
426
- # Attach the key to the query instance
427
- query_inst.key = key
428
-
429
- # Register this key with the parser if supported
430
- if (parser := getattr(self.input, "vt100_parser", None)) and hasattr(
431
- parser, "queries"
432
- ):
433
- # Register the key
434
- parser.queries[key] = query.pattern
435
-
436
- # Add a command for the query's key-binding
437
- add_cmd(name=name, title=title, hidden=True)(
438
- query_inst._handle_response
439
- )
440
- # Add key-binding
441
- register_bindings({"euporie.core.terminal.TerminalInfo": {name: key}})
442
-
443
- return query_inst
444
-
445
- def send_all(self) -> None:
446
- """Send the command for all queries."""
447
- # Ensure line wrapping is off before sending queries
448
- self.output.disable_autowrap()
449
- for query in self._queries.values():
450
- if query.run_at_startup:
451
- query.send(flush=False)
452
- self.output.flush()
453
-
454
- def _tiocgwnsz(self) -> tuple[int, int, int, int]:
455
- """Get the size and pixel dimensions of the terminal with `termios`."""
456
- import array
457
-
458
- output = array.array("H", [0, 0, 0, 0])
459
- if _have_termios_tty_fcntl():
460
- import fcntl
461
- import termios
462
-
463
- try:
464
- fcntl.ioctl(1, termios.TIOCGWINSZ, output)
465
- except OSError:
466
- pass
467
- rows, cols, xpixels, ypixels = output
468
- return rows, cols, xpixels, ypixels
469
-
470
- @property
471
- def terminal_size_px(self) -> tuple[int, int]:
472
- """Get the pixel dimensions of the terminal."""
473
- # Prefer using escape codes as this works over SSH
474
- px, py = self.pixel_dimensions.value
475
- if px == 0:
476
- # If unsuccessful, try requesting info with tiocgwnsz
477
- _rows, _cols, px, py = self._tiocgwnsz()
478
- return px, py
479
-
480
- @property
481
- def cell_size_px(self) -> tuple[int, int]:
482
- """Get the pixel size of a single terminal cell."""
483
- px, py = self.terminal_size_px
484
- rows, cols = self.output.get_size()
485
- # If we can't get the pixel size, just guess wildly
486
- return px // cols or 10, py // rows or 20
487
-
488
-
489
- def edit_in_editor(filename: str, line_number: int = 0) -> None:
490
- """Suspend the current app and edit a file in an external editor."""
491
-
492
- def _open_file_in_editor(filename: str) -> None:
493
- """Call editor executable."""
494
- # If the 'VISUAL' or 'EDITOR' environment variable has been set, use that.
495
- # Otherwise, fall back to the first available editor that we can find.
496
- for editor in [
497
- os.environ.get("VISUAL"),
498
- os.environ.get("EDITOR"),
499
- "editor",
500
- "micro",
501
- "nano",
502
- "pico",
503
- "vi",
504
- "emacs",
505
- ]:
506
- if editor:
507
- try:
508
- # Use 'shlex.split()' because $VISUAL can contain spaces and quotes
509
- subprocess.call([*shlex.split(editor), filename])
510
- return
511
- except OSError:
512
- # Executable does not exist, try the next one.
513
- pass
514
-
515
- async def run() -> None:
516
- # Open in editor
517
- # (We need to use `run_in_terminal`, because not all editors go to
518
- # the alternate screen buffer, and some could influence the cursor
519
- # position)
520
- await run_in_terminal(lambda: _open_file_in_editor(filename), in_executor=True)
521
-
522
- get_app().create_background_task(run())
@@ -1,147 +0,0 @@
1
- euporie/console/__init__.py,sha256=Xgd2sBDyLKQ3_kiRmkRIVNHw6MGB-f-mB1YOxhta0Oc,55
2
- euporie/console/__main__.py,sha256=m2EnzIDLO4dHlDt41JNKpUvAUSw6wD-X0V3YhymXqxc,289
3
- euporie/console/app.py,sha256=Icu-q-qTOuap873-s0ONcrtluD6EH5DPlbxX8ue6Zqo,7379
4
- euporie/console/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- euporie/console/tabs/__init__.py,sha256=Grm9EO1gnBO1o-k6Nqnlzo8XLIgFZSXNAdz49Vvh4zY,55
6
- euporie/console/tabs/console.py,sha256=JsKslgnHHUtDLItpC6Dxcql29v4GICn2raln4DpnBjc,31021
7
- euporie/core/__init__.py,sha256=ZWQhL70IXhO4R_0h0HVYNq-CUCqRB1axpm6fSZMS6OQ,313
8
- euporie/core/__main__.py,sha256=xeDgX2wOce0SBnojquayfidznlnn8QU8edGEXYrDSBM,817
9
- euporie/core/app.py,sha256=xy8LMugJZNbUB7STXHQozu4eRY4H1VAN0-e8VyR75Gk,46401
10
- euporie/core/border.py,sha256=kJbpyxwJBtIRpFOpXhDtaCT1_oyVRjRiYKG4lXn3-iA,48507
11
- euporie/core/clipboard.py,sha256=FzMk6uAFTcgNW-beaQ9Jyrpvd3JG9aBP-5S_gMy6Xak,4470
12
- euporie/core/commands.py,sha256=4L-8UV9ejz2HG_U2-dzbybXLdn1SKfruOjgga5XiIX0,8254
13
- euporie/core/completion.py,sha256=97pe7PdeUsahbgYLwvKhmik5aDAdZFZFOuOmhi9I8d8,5478
14
- euporie/core/config.py,sha256=JCoBmGVGegDWfnQItmcGCHn_Plv-6dwQjZpoBRrezkM,22811
15
- euporie/core/current.py,sha256=BdSVCLngNpZdtYJaxdijuu8N9yRcoU_wr0jI6RGRSms,557
16
- euporie/core/data_structures.py,sha256=eA54Cg305R1mVX6YGTRPIvTN4piEFKrltehif49l92o,1800
17
- euporie/core/diagnostics.py,sha256=5rS3DbJqNiPVfOb3tU4RKyq2rIMoS3O3_0-a62zknPE,1686
18
- euporie/core/filters.py,sha256=R41Yf18znfTQQEagpLicZC-1HEdOxWbL2K6zgdCyt6M,8314
19
- euporie/core/format.py,sha256=oFlD3aX_uVeLhqxo2n-zaUBsiNKpWqhx6W-5arFY5C4,4154
20
- euporie/core/graphics.py,sha256=zc4Vff851i6E_fy0vJ-GbMHk1VvMZNFIXvY4kBBOH8Y,32655
21
- euporie/core/history.py,sha256=uO14q8keGEtH1R9loaZrBfy66GfXcJhxyXW95-35niA,2542
22
- euporie/core/inspection.py,sha256=JhUttlOqvcYOLTSqrn49zSACbaeGLwbwK-BVOLllh6Y,2563
23
- euporie/core/io.py,sha256=ipl11Uo3mOmbqTjqC9k1Z8nwXmgNWgY-7ROI3WG4FwY,4469
24
- euporie/core/kernel.py,sha256=lqc7fbiZdeHBVDWtOdztsXWENUWQyi887Vbj8Fq_uSw,47360
25
- euporie/core/keys.py,sha256=hfxzZjh4dbDdEkel1YXu8p5RgGwD44oZ9mptHZ0TcfA,3309
26
- euporie/core/launch.py,sha256=drtCrvVmGS19nMjL21Q0YwB7zZ0EK0E-0Wa_rRS0N70,1540
27
- euporie/core/lexers.py,sha256=AXNDYOR0BZf0sYj9o8YSb0oF4AGYZdKygwFIUKJ3XFM,1083
28
- euporie/core/log.py,sha256=6d8Dk5SA2fYr2QL1BqATmMtTU_BQ_DuONqNSQAYiOek,16323
29
- euporie/core/lsp.py,sha256=LU-sPEl-jeGA-nqlJMoFl0SzcTS9cY9KDKVmU3bDXdk,49204
30
- euporie/core/margins.py,sha256=QDWboU3K5YriRmahe1ZJsitZtfpLkWqKrt6dS0jsnyo,24942
31
- euporie/core/path.py,sha256=tm1mAtPlwwvXO7YdN5ZD1HG2x5i3tMT83v80N_V4Rk8,2275
32
- euporie/core/processors.py,sha256=63vwLEuSdp5B_PuQ-zv--qtC05GTlbhXVojISzHUnIk,5478
33
- euporie/core/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
- euporie/core/pygments.py,sha256=TE3VrZ-QKe4n6hmoYuNmt0l0XR6qmko7JvO5YHSt_rU,2588
35
- euporie/core/reference.py,sha256=x8-7405xgTEcK7ImqikQtVAXXqFanz61UQ3mn7v_4-o,65039
36
- euporie/core/renderer.py,sha256=XhjSsNFiHBZigtBy7Bp942jfs0iz1Il2GIwNNKOZp00,17264
37
- euporie/core/style.py,sha256=vmh2otvH2ZAcmgrvbibHJosDRy-5n5RzDi3FY5DiGOc,33606
38
- euporie/core/suggest.py,sha256=T86TsEY1_Z7XnW9ncUDKwP4utJc-wYFDV5U8MY78Q7A,5512
39
- euporie/core/terminal.py,sha256=hlbjlIEo6YkMujobwppPsu7bIeSrO6maeeLP9IwLxcY,17906
40
- euporie/core/utils.py,sha256=0p_Kmcsx77H8zvTCAJ6S6Aag3z1l611dst2reB2FZpw,2686
41
- euporie/core/validation.py,sha256=cA40YnpWdB1Wpi-B4DeyQ541IEFNh2q6ypCqbVT0aXU,1180
42
- euporie/core/comm/__init__.py,sha256=jTf9gPhonyl-UOEC7lc8RwLGJiNhFSuDZqm8rpZRnnI,52
43
- euporie/core/comm/base.py,sha256=72PF6upybtBnNB3M8oNkR8WDzC2vptRS9TmIKJkNRq4,4047
44
- euporie/core/comm/ipywidgets.py,sha256=O37QczvaDksi6f-xoaVuAekKAJE3K7EnW27ZMPIDpY8,52738
45
- euporie/core/comm/registry.py,sha256=cxH5r6BZe-NUy0zFqxTriAnP0_spMY3m9r1Na688i7o,1353
46
- euporie/core/convert/__init__.py,sha256=SdXTdFh5Exb7NLtiY7pDuv4AcQdP5b1syQSoZeanJco,391
47
- euporie/core/convert/datum.py,sha256=6EtBAagMUOJAgpCKAUqKdPeJfKc2pCLLbB7fTGAEB3w,14410
48
- euporie/core/convert/mime.py,sha256=uQwXw2hUsfS_dMeR4Ci6Zv4fORIBnEa9rdRa-nVT-Ls,3142
49
- euporie/core/convert/registry.py,sha256=vVBM78Rf778wDFGdnmxc9mkDPGczeLUVsehZv6u9w0s,2902
50
- euporie/core/convert/utils.py,sha256=h1qlZBQ0YqV-EgdIDZcO14KJwIqA5FfDOW_nd4ZtIDA,2438
51
- euporie/core/convert/formats/__init__.py,sha256=sPJqKh1aA0V2jJs5cXUBmAEadsozUsGxv55irlrVr68,164
52
- euporie/core/convert/formats/ansi.py,sha256=SqkwtKqo-7wD2_tCgsJYwsCcM4vBgXPA5tGB7oVqtcM,14327
53
- euporie/core/convert/formats/base64.py,sha256=8tP29nX_patgOG9lYr-HIn0I_6VyV_SyfDi-ZZBTp6Q,878
54
- euporie/core/convert/formats/common.py,sha256=bDfVSBrMYCM1yAuKO254R2JBO-viZHB0MArezti5txM,4959
55
- euporie/core/convert/formats/ft.py,sha256=6RKWq0y3kbJ96kbMjfazGeBg3uha8CWoseRPa4WLWHE,2810
56
- euporie/core/convert/formats/html.py,sha256=i9RDnNXD8vZ-zvfOWQqyZHRFGALeyrZkhewq4Pdrxnc,2188
57
- euporie/core/convert/formats/jpeg.py,sha256=c38IZEd6HVAmKBXnDE0qmqwfWtjcwVL5ugXffV0wCpA,287
58
- euporie/core/convert/formats/markdown.py,sha256=vKTyS-HGz_smvvNxo0cJoRNgBjbRWU2Bf1sM1_bwWAM,2377
59
- euporie/core/convert/formats/pdf.py,sha256=6d8e5tjV1j6QXMr7KBNmQ2hQzVY9Il19xg4a8E_0I0I,283
60
- euporie/core/convert/formats/pil.py,sha256=9muJJYXEGm_SSJfwSqqoCRq_DxnyXZ-HBNNgiKMeVDE,2504
61
- euporie/core/convert/formats/png.py,sha256=wWFHMaZm0vbQy-obgujex8_UMSjaCH1-C4XAG47jjj4,5025
62
- euporie/core/convert/formats/rich.py,sha256=lh12hxMWvWMJ2Y3cMZBKcX8UQ4huWRWyi0H7LgpNqZE,939
63
- euporie/core/convert/formats/sixel.py,sha256=gsBDwXowN5eg-X-khzUjhYcNUsNl2up3zQVnEnYmd1w,2511
64
- euporie/core/convert/formats/svg.py,sha256=SY-rioXSm5lK6LLp3mu3YeFYTFOJ-jCvEwH-wusfU1s,805
65
- euporie/core/ft/__init__.py,sha256=Ib-pswos3RiOM2Vn8GCZ4rwuoTNPeBJ0jhgRpwu7BKE,55
66
- euporie/core/ft/ansi.py,sha256=ICUBohoOVtbkf96T3EsFcHf-oSsWMxD7uyRoEFnhS1I,5796
67
- euporie/core/ft/html.py,sha256=ncmpObJQWaNYCqzqqXmDyk4hCm60tfvvz8epnoEjcDQ,179401
68
- euporie/core/ft/table.py,sha256=L6rtT1XHArydL7gYX1m98MPoKCDYk8L7jibKRiayaGc,53325
69
- euporie/core/ft/utils.py,sha256=Or3eZwoJi2NbYQg0M2mk815RlKcDmGXr7K5-7JJcT1k,27773
70
- euporie/core/key_binding/__init__.py,sha256=zFKrJrZARNht6Tl4TT5Fw3fk-IrD8SBYk5mBJ5K_F1A,47
71
- euporie/core/key_binding/key_processor.py,sha256=NDCzCYh2DszilELl6giGoxAlnWy40wAUOUiQqBL5GXU,4329
72
- euporie/core/key_binding/micro_state.py,sha256=h_CBBiIUa4mHf70ZZDNbXreC0p0H3boNVzHnHVuIAp8,1276
73
- euporie/core/key_binding/registry.py,sha256=UBT_dPpndgzgrKoI7AdbL4PmZUGvZ4hBC7YGkGNTIXA,1348
74
- euporie/core/key_binding/utils.py,sha256=UZ0ymB4vLPFaxbx9jhqR_cKaSt08efrlvFtb1KZixcU,2407
75
- euporie/core/key_binding/vi_state.py,sha256=ek3Wxsckihsr5x9ULiDtNnVkOEiCBzoF4m4qY6wAB9Q,702
76
- euporie/core/key_binding/bindings/__init__.py,sha256=qbDXRvt21fwd-esuCU5ljYwoYSK_AGVDjJ_SijdCnsg,288
77
- euporie/core/key_binding/bindings/basic.py,sha256=djhGhPC6yDPfgXcNXfh14wLhFdraUBQH8VMfkZnLZvI,1648
78
- euporie/core/key_binding/bindings/completion.py,sha256=npf61P0NvmrYMG8qT-1AYDReLcoMHsgdG5gzBloSTWk,2081
79
- euporie/core/key_binding/bindings/micro.py,sha256=NZSeYZIlN2kA-nNRC8_0ECqT4jRbGOfcTllKnpRrXh8,28020
80
- euporie/core/key_binding/bindings/mouse.py,sha256=UGzOFMA-3FaN_Fag_4LigBQ7Gk2pn5_s7PAj_myCRTo,6949
81
- euporie/core/key_binding/bindings/page_navigation.py,sha256=FWIv4iqWUCMjFHLu-I5Z08NIULXuTIjrn9fC25XImYg,4142
82
- euporie/core/key_binding/bindings/vi.py,sha256=XutOsbBI8ywyWR5XY2pUN14Vga6R0vrDK27q7ZhE8pM,1567
83
- euporie/core/layout/__init__.py,sha256=T5iGOnMGfNwVffJlfFMwGTFBLV7RkOuKw5gVp6cl4wA,59
84
- euporie/core/layout/cache.py,sha256=i4yDyFWM9zxnB1CCW7oV9kJvp5D_IJMoVOfs53QXgrU,15144
85
- euporie/core/layout/containers.py,sha256=ECzq_Q8XQKuG5v51JP90QJLvlDJ796bpOdl5PVuVz6w,44637
86
- euporie/core/layout/controls.py,sha256=iFklysBxk_roWKfNN4Hdjqf4sFdEBzNWZq2OavlpJHY,825
87
- euporie/core/layout/decor.py,sha256=8EuHM4cDr4njagA2SuPeXMmj5tpK7q609r2w8o9BUoI,14108
88
- euporie/core/layout/mouse.py,sha256=GJvFwOCZ8x-CppW8rGmJ6kV6JdW0Ndjihf8IwkuBI6Q,5165
89
- euporie/core/layout/print.py,sha256=cVOD2BYciQKC9-mWFz9dw6Ttc60MUnDjjBI7jT7Zxco,5154
90
- euporie/core/layout/screen.py,sha256=0xP9ZErMcw51nPgBbrm-DSQqFq5WNvsh9fw1amz2Z28,2224
91
- euporie/core/layout/scroll.py,sha256=aluts7jUkzIXqJKyOhNr27eI3miTh27dOYcpmaJsV_w,32824
92
- euporie/core/tabs/__init__.py,sha256=Grm9EO1gnBO1o-k6Nqnlzo8XLIgFZSXNAdz49Vvh4zY,55
93
- euporie/core/tabs/base.py,sha256=69KU5ZN73aPIBswllXwrSEUa-A1CoCmXD1_E1TGWGP8,21989
94
- euporie/core/tabs/notebook.py,sha256=-g5wuKdH6iWL69ti9hKpdPJrndTvuAfp5Rl8f_sm18M,18152
95
- euporie/core/widgets/__init__.py,sha256=ektso_Ea1-pZB04alUujQsa2r-kv8xAF0SmQOv_bvHQ,52
96
- euporie/core/widgets/cell.py,sha256=cP0yU-7drPvyloPMvxRe73nZg732pAo-XEh4V5ScTq0,34697
97
- euporie/core/widgets/cell_outputs.py,sha256=FSTvEYvwqNiHvj1UgbDYyQnW8pZpfdz2sKodxysqFsE,17334
98
- euporie/core/widgets/decor.py,sha256=GPZG7-h3MKynQIXJ_YoR6tPpYxtmrXi0uoyVCovSjBQ,8770
99
- euporie/core/widgets/dialog.py,sha256=pnF1uyTkovXb-6bhB9LWZU_XkV9L6h5G1NDe-GN2i28,32951
100
- euporie/core/widgets/display.py,sha256=UicJq9iSzHrrYXdXTXWPvBsC69ttZU8GHJ7xRK5Fbmo,21767
101
- euporie/core/widgets/file_browser.py,sha256=kH1bIap6zkB6KV_1GoA34yd95LIZ3b20cgqJWQlWMik,20733
102
- euporie/core/widgets/formatted_text_area.py,sha256=J7P_TNXPZKZkiBdjAVkPvkfRY1veXe4tzXU241k4b-Q,4037
103
- euporie/core/widgets/forms.py,sha256=rrLbgMo4YQRTeG0sLd45PCaL2ztckd99RIeZQvnhDmo,85475
104
- euporie/core/widgets/inputs.py,sha256=Rpsy-kouiDeoSWPs89l1pSTXGnyAV0_tufQ3EqZp1P8,21826
105
- euporie/core/widgets/layout.py,sha256=G1Tgy0bQbJfpnnlAQx0NzJ6gzaOnrPiXuXZov20dhQo,23507
106
- euporie/core/widgets/menu.py,sha256=K5Zkv_wKs7-2ZgMDygLDTKj5Vkh7MPLwc9ZWIhXa_xM,32856
107
- euporie/core/widgets/pager.py,sha256=mbqB2-mX8bORUKM5492s5K9rpoGrvrBN1qY7uYE9o0g,6527
108
- euporie/core/widgets/palette.py,sha256=e15dnPAg7VYjjahae-XsWViCjUA63jR5fdS3Oyof3MY,10847
109
- euporie/core/widgets/search.py,sha256=szGAC19LYhAnMvQGLRWrjPoUjQa9Q3nhyugQ3uFshaU,11816
110
- euporie/core/widgets/status.py,sha256=LphylR8zFVs5Oq3s_Pd-1B0BfPd8UAR5BvsjEG4ggxo,5560
111
- euporie/core/widgets/tree.py,sha256=BG7QRsI2GzSJPReNQu9zWFjO0iy8TeJwrmCmP5dc2ek,3760
112
- euporie/data/desktop/euporie-console.desktop,sha256=DI08G0Dl2s5asM6afWUfkKvO5YmcBm-pWQZzUHiNnqc,153
113
- euporie/data/desktop/euporie-notebook.desktop,sha256=RtpJzvizTDuOp0BLa2bLgVHx11LG6L7PL-oF-wHTsgU,155
114
- euporie/hub/__init__.py,sha256=NcrOlSFgI4y5gEbD4lFY-Ryd1K79EeMoeAp41A6tDT0,44
115
- euporie/hub/__main__.py,sha256=m2EnzIDLO4dHlDt41JNKpUvAUSw6wD-X0V3YhymXqxc,289
116
- euporie/hub/app.py,sha256=nsihRIlimet6HoFNCZwmY8iyBUPSdoRxTwRw9iwC_iQ,6285
117
- euporie/hub/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
118
- euporie/notebook/__init__.py,sha256=rOE71d95pym_ILYVg07NO9oDYbSB0AskxbC8cr4htiU,44
119
- euporie/notebook/__main__.py,sha256=m2EnzIDLO4dHlDt41JNKpUvAUSw6wD-X0V3YhymXqxc,289
120
- euporie/notebook/app.py,sha256=QQFvWorsxTxzcUdVVmc4d0FpbC88neTTbxbsLQu5xKw,22481
121
- euporie/notebook/current.py,sha256=rQ_R9B0b8JmWILxEyGzGfuVY2iVkHTghq4qRiC-MYSU,387
122
- euporie/notebook/enums.py,sha256=g7quMch8KAlaaYJS0UppWqx6tx-ZFt7HxFcmEfam5OM,221
123
- euporie/notebook/filters.py,sha256=c2PncF-n4dE67cFmVmhsMhFVWCfxePAaCW6mb6zm0Yo,1502
124
- euporie/notebook/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
125
- euporie/notebook/tabs/__init__.py,sha256=CnHrMzmr4tKEd8Rs8swFvNDWj0fCiLChdqha0AtDNqY,417
126
- euporie/notebook/tabs/display.py,sha256=y8wMa-MsQZky_JgJEwUtMUGIbLnFiAZMfrX1u-km6VM,2595
127
- euporie/notebook/tabs/edit.py,sha256=Hop0AIvIaXJ9SaWtgxpocjGN0JEcsNuPkBsZPcJ76UE,6529
128
- euporie/notebook/tabs/json.py,sha256=xKDHYkA59aleBpm6qLuic5GNPNQU6qApLuIT1vZzJrg,2179
129
- euporie/notebook/tabs/log.py,sha256=qGyjx4Cz9WZ7QP6blh4lCJaJpSDBWnFMpCLRR90aE6U,3546
130
- euporie/notebook/tabs/notebook.py,sha256=pho5gJZFV5un8hQ5wBc-_JwsRVy6r1YE3wuTJTSKn80,43120
131
- euporie/notebook/widgets/__init__.py,sha256=74tOl0bYuWkaKT-4pgD5zmdiIkoFYx8uGj4SxcLHLtQ,48
132
- euporie/notebook/widgets/side_bar.py,sha256=EDFAulshV7YqA50w84RRl88UI60AehIXYYA2exlFh0M,7243
133
- euporie/preview/__init__.py,sha256=B6RsBuuT0JJk1v6U5n95VuFXcOeFLq6UGgt4w-n_nEI,51
134
- euporie/preview/__main__.py,sha256=m2EnzIDLO4dHlDt41JNKpUvAUSw6wD-X0V3YhymXqxc,289
135
- euporie/preview/app.py,sha256=qbDKbSvE_D2_OMU20atVXkWNT8nRjb_BtSRxYzDgsEI,8272
136
- euporie/preview/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
137
- euporie/preview/tabs/__init__.py,sha256=rY6DfQ-8qRo_AiICCD-zTyhJBnuMjawWDd8tRxR6q58,43
138
- euporie/preview/tabs/notebook.py,sha256=KcKB84cUwqB9mbUC7ZfLSDlmhIjYhfSD6uiYX334uEc,8339
139
- euporie/web/tabs/web.py,sha256=LAVjWdGkTRHT2rtmnU0ITbQzV5aIOAhH5am0kKuynC4,5227
140
- euporie/web/widgets/webview.py,sha256=PA8hWqJs8FLMEFNAHYKz4Zt2fJTg-BSyuCji6isxz3o,20800
141
- euporie-2.8.4.data/data/share/applications/euporie-console.desktop,sha256=DI08G0Dl2s5asM6afWUfkKvO5YmcBm-pWQZzUHiNnqc,153
142
- euporie-2.8.4.data/data/share/applications/euporie-notebook.desktop,sha256=RtpJzvizTDuOp0BLa2bLgVHx11LG6L7PL-oF-wHTsgU,155
143
- euporie-2.8.4.dist-info/METADATA,sha256=QbvlH35_CH8vp3NcF3AKGBpjOaKHfD-UpX26uucjzf0,6415
144
- euporie-2.8.4.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
145
- euporie-2.8.4.dist-info/entry_points.txt,sha256=iHdjwf9iCAipy7w3tXCH2W_SavHVCSHpJk_84--b7rE,776
146
- euporie-2.8.4.dist-info/licenses/LICENSE,sha256=rI0bfSsCfCVw6d8vk7WokRxd3t8yx5xV4fC5fwaMgCg,1079
147
- euporie-2.8.4.dist-info/RECORD,,