euporie 2.8.0__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 -92
  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 +26 -37
  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 +9 -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.0.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.0.dist-info → euporie-2.8.5.dist-info}/WHEEL +1 -1
  123. {euporie-2.8.0.dist-info → euporie-2.8.5.dist-info}/entry_points.txt +2 -2
  124. {euporie-2.8.0.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.0.dist-info/RECORD +0 -146
  128. {euporie-2.8.0.data → euporie-2.8.5.data}/data/share/applications/euporie-console.desktop +0 -0
  129. {euporie-2.8.0.data → euporie-2.8.5.data}/data/share/applications/euporie-notebook.desktop +0 -0
euporie/core/terminal.py DELETED
@@ -1,527 +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
-
79
- def __init__(self, input_: Input, output: Output, config: Config) -> None:
80
- """Create a new instance of the terminal query."""
81
- self.input = input_
82
- self.output = output
83
- self.config = config
84
- self.key: Keys | None = None
85
- self.waiting = False
86
- self._value: Any | None = None
87
- self.event = Event(self)
88
- self.queryable = self.output.stdout and (
89
- self.output.stdout.isatty()
90
- # Don't send escape codes if this is not a real TTY.
91
- # We create pseudo-ttys to get colored output, but don't want
92
- # any terminal queries to be sent
93
- and not getattr(self.output.stdout, "fake_tty", False)
94
- )
95
- if not self.queryable:
96
- self.cmd = ""
97
-
98
- def verify(self, data: str) -> Any | None:
99
- """Verify the response from the terminal."""
100
- return None
101
-
102
- def await_response(self, timeout: float = 0.2) -> bool:
103
- """Wait for a response from the terminal."""
104
- app = get_app()
105
- start = dt.now()
106
- while (dt.now() - start).total_seconds() < timeout:
107
- time.sleep(0.05)
108
- for press in self.input.read_keys():
109
- if press.key == self.key:
110
- # If we find the key we're after, process it immediately
111
- tkp = KeyProcessor(key_bindings=app.key_processor._bindings)
112
- tkp.feed_multiple([press, _Flush])
113
- tkp.process_keys()
114
- return True
115
- else:
116
- # If we get other keys, add them to the input queue
117
- app.key_processor.feed(press)
118
- return False
119
-
120
- def _handle_response(self, event: KeyPressEvent) -> object:
121
- """Run when the terminal receives the response from the terminal.
122
-
123
- Args:
124
- event: The key press event received when the termina sends a response
125
-
126
- Returns:
127
- :py:obj:`NotImplemented`, so the application is not invalidated when a
128
- response from the terminal is received
129
-
130
- """
131
- log.debug("Got terminal response for '%s'", self.__class__.__name__)
132
- self.waiting = False
133
- new_value = self.verify(event.data)
134
- # Only fire the event if the value has changed
135
- if self._value != new_value:
136
- self._value = new_value
137
- self.event.fire()
138
- return NotImplemented
139
-
140
- def _cmd(self) -> str:
141
- """Return the query's command."""
142
- return self.cmd
143
-
144
- def send(self, flush: bool = True) -> None:
145
- """Send the terminal query command to the output."""
146
- if self.queryable and self.cmd and not self.waiting:
147
- cmd = self._cmd()
148
- log.debug(
149
- "Sending query %s for %s",
150
- cmd.__repr__(),
151
- self.__class__.__name__,
152
- )
153
- self.output.write_raw(cmd)
154
- if flush:
155
- self.output.flush()
156
- self.waiting = True
157
-
158
- @property
159
- def value(self) -> Any:
160
- """Return the last known value for the query.
161
-
162
- Returns:
163
- The last value received, or the default value.
164
-
165
- """
166
- return self._value or self.default
167
-
168
-
169
- class Colors(TerminalQuery):
170
- """A terminal query to retrieve colours as hex codes."""
171
-
172
- _color_names: ClassVar[dict[str, str]] = {
173
- "10": "fg",
174
- "11": "bg",
175
- "4;0": "ansiblack",
176
- "4;1": "ansired",
177
- "4;2": "ansigreen",
178
- "4;3": "ansiyellow",
179
- "4;4": "ansiblue",
180
- "4;5": "ansipurple",
181
- "4;6": "ansicyan",
182
- "4;7": "ansiwhite",
183
- "4;8": "ansirbightblack",
184
- "4;9": "ansirbightred",
185
- "4;10": "ansirbightgreen",
186
- "4;11": "ansirbightyellow",
187
- "4;12": "ansirbightblue",
188
- "4;13": "ansirbightpurple",
189
- "4;14": "ansirbightcyan",
190
- "4;15": "ansirbightwhite",
191
- }
192
- default = DEFAULT_COLORS
193
- cache = True
194
- cmd = ("\x1b]10;?\x1b\\" "\x1b]11;?\x1b\\") + "".join(
195
- f"\x1b]4;{i};?\x1b\\" for i in range(16)
196
- )
197
- pattern = re.compile(
198
- r"^\x1b\](?P<c>(\d+;)?\d+)+;rgb:"
199
- r"(?P<r>[0-9A-Fa-f]{2,4})\/"
200
- r"(?P<g>[0-9A-Fa-f]{2,4})\/"
201
- r"(?P<b>[0-9A-Fa-f]{2,4})"
202
- # Allow BEL or ST as terminator
203
- r"(\x1b\\\Z|\0x7)"
204
- )
205
-
206
- def _cmd(self) -> str:
207
- return passthrough(self.cmd)
208
-
209
- def verify(self, data: str) -> dict[str, str]:
210
- """Verify the response contains a colour."""
211
- if (match := self.pattern.match(data)) and (colors := match.groupdict()):
212
- c = colors["c"]
213
- r, g, b = (
214
- colors.get("r", "00"),
215
- colors.get("g", "00"),
216
- colors.get("b", "00"),
217
- )
218
- return {
219
- **self.value,
220
- self._color_names.get(c, c): f"#{r[:2]}{g[:2]}{b[:2]}",
221
- }
222
- return self.value
223
-
224
-
225
- class PixelDimensions(TerminalQuery):
226
- """A terminal query to check the terminal's dimensions in pixels."""
227
-
228
- default = (0, 0)
229
- cmd = "\x1b[14t"
230
- cache = True
231
- pattern = re.compile(r"^\x1b\[4;(?P<y>\d+);(?P<x>\d+)t")
232
-
233
- def verify(self, data: str) -> tuple[int, int] | None:
234
- """Verify the terminal responded with pixel dimensions."""
235
- if (
236
- (match := self.pattern.match(data))
237
- and (values := match.groupdict())
238
- and (x := values.get("x")) is not None
239
- and (y := values.get("y")) is not None
240
- ):
241
- return int(x), int(y)
242
- return None
243
-
244
-
245
- class KittyGraphicsStatus(TerminalQuery):
246
- """A terminal query to check for kitty graphics support."""
247
-
248
- default = False
249
- cache = True
250
- cmd = "\x1b_Gi=4294967295,s=1,v=1,a=q,t=d,f=24;AAAA\x1b\\"
251
- # Konsole responds with 'i=0' - I'll allow it
252
- pattern = re.compile(r"^\x1b_Gi=(4294967295|0);(?P<status>OK)\x1b\\\Z")
253
-
254
- def _cmd(self) -> str:
255
- """Hide the command in case the terminal does not support this sequence."""
256
- return "\x1b[s" + passthrough(self.cmd) + "\x1b[u\x1b[2K"
257
-
258
- def verify(self, data: str) -> bool:
259
- """Verify the terminal response means kitty graphics are supported."""
260
- if (
261
- (match := self.pattern.match(data))
262
- and (values := match.groupdict())
263
- and values.get("status") == "OK"
264
- ):
265
- return True
266
- return False
267
-
268
-
269
- class SixelGraphicsStatus(TerminalQuery):
270
- """A terminal query to check for sixel graphics support."""
271
-
272
- default = False
273
- cache = True
274
- cmd = "\x1b[c"
275
- pattern = re.compile(r"^\x1b\[\?(?:\d+;)*(?P<sixel>4)(?:;\d+)*c\Z")
276
-
277
- def _cmd(self) -> str:
278
- return passthrough(self.cmd)
279
-
280
- def verify(self, data: str) -> bool:
281
- """Verify the terminal response means sixel graphics are supported."""
282
- if (
283
- (match := self.pattern.match(data))
284
- and (values := match.groupdict())
285
- and values.get("sixel")
286
- ):
287
- return True
288
- return False
289
-
290
-
291
- class ItermGraphicsStatus(TerminalQuery):
292
- """A terminal query to check for iTerm graphics support."""
293
-
294
- default = False
295
- cache = True
296
- cmd = "\x1b[>q"
297
- pattern = re.compile(r"^\x1bP>\|(?P<term>[^\x1b]+)\x1b\\")
298
-
299
- def _cmd(self) -> str:
300
- return passthrough(self.cmd)
301
-
302
- def verify(self, data: str) -> bool:
303
- """Verify iterm graphics are supported by the terminal."""
304
- if (
305
- (match := self.pattern.match(data))
306
- and (values := match.groupdict())
307
- and (term := values.get("term"))
308
- and (term.startswith(("WezTerm", "Konsole", "mlterm")))
309
- ):
310
- return True
311
- return False
312
-
313
-
314
- class DepthOfColor(TerminalQuery):
315
- """Determine the suspected color depth of the terminal."""
316
-
317
- # TODO - detect 24bit color support with escape sequence
318
- # "\x1b[48:2:1:2:3m\eP$qm\x1b\\"
319
-
320
- default = ColorDepth.DEPTH_24_BIT
321
-
322
- def __init__(self, input_: Input, output: Output, config: Config) -> None:
323
- """Detect the terminal's colour support based on environment variables."""
324
- super().__init__(input_, output, config)
325
- self._value: ColorDepth | None = None
326
- if os.environ.get("NO_COLOR", "") or os.environ.get("TERM", "") == "dumb":
327
- self._value = ColorDepth.DEPTH_1_BIT
328
- return
329
- colorterm = os.environ.get("COLORTERM", "")
330
- if "truecolor" in colorterm or "24bit" in colorterm:
331
- self._value = ColorDepth.DEPTH_24_BIT
332
- return
333
- if "256" in os.environ.get("TERM", ""):
334
- self._value = ColorDepth.DEPTH_8_BIT
335
- return
336
-
337
-
338
- class SgrPixelStatus(TerminalQuery):
339
- """A terminal query to check for Pixel SGR support."""
340
-
341
- default = False
342
- cache = True
343
- cmd = "\x1b[?1016h\x1b[?1016$p\x1b[?1016l" # Enable, check, disable
344
- pattern = re.compile(r"^\x1b\[\?1016;(?P<Pm>\d)\$\Z")
345
-
346
- def verify(self, data: str) -> bool:
347
- """Verify the terminal response means SGR pixel-mode is supported."""
348
- return bool(
349
- (match := self.pattern.match(data))
350
- and (values := match.groupdict())
351
- and (values.get("Pm") in {"1", "3"})
352
- )
353
-
354
-
355
- class CsiUStatus(TerminalQuery):
356
- """A terminal query to check for CSI-u support."""
357
-
358
- default = False
359
- cache = True
360
- cmd = "\x1b[?u"
361
- pattern = re.compile(r"^\x1b\[\?\d+u")
362
-
363
- def verify(self, data: str) -> bool:
364
- """Verify the terminal responds."""
365
- if (match := self.pattern.match(data)) and match:
366
- return True
367
- return False
368
-
369
-
370
- class ClipboardData(TerminalQuery):
371
- """A terminal query to retrieve clipboard contents."""
372
-
373
- default = ""
374
- cache = False
375
- cmd = "\x1b]52;c;?\x1b\\"
376
- pattern = re.compile(r"^\x1b\]52;(?:c|p)?;(?P<data>[A-Za-z0-9+/=]+)\x1b\\\Z")
377
-
378
- def verify(self, data: str) -> str:
379
- """Verify the terminal responds."""
380
- if (match := self.pattern.match(data)) and (values := match.groupdict()):
381
- value = values.get("data", "")
382
- return b64decode(value).decode()
383
- return ""
384
-
385
-
386
- class TerminalInfo:
387
- """A class to gather and hold information about the terminal."""
388
-
389
- input: Input
390
- output: Output
391
-
392
- _queries: ClassVar[dict[type[TerminalQuery], TerminalQuery]] = {}
393
-
394
- def __init__(self, input_: Input, output: Output, config: Config) -> None:
395
- """Instantiate the terminal information class."""
396
- self.input = input_
397
- self.output = output
398
- self.config = config
399
-
400
- self.colors = self.register(Colors)
401
- self.pixel_dimensions = self.register(PixelDimensions)
402
- self.sixel_graphics_status = self.register(SixelGraphicsStatus)
403
- self.kitty_graphics_status = self.register(KittyGraphicsStatus)
404
- self.iterm_graphics_status = self.register(ItermGraphicsStatus)
405
- self.depth_of_color = self.register(DepthOfColor)
406
- self.sgr_pixel_status = self.register(SgrPixelStatus)
407
- # self.csiu_status = self.register(CsiUStatus)
408
- self.clipboard_data = self.register(ClipboardData)
409
-
410
- def register(self, query: type[TerminalQuery]) -> TerminalQuery:
411
- """Instantiate and registers a query's response with the input parser."""
412
- # Create an instance of this query
413
- query_inst: TerminalQuery | None
414
-
415
- if (query_inst := self._queries.get(query)) is None:
416
- query_inst = query(self.input, self.output, config=self.config)
417
- self._queries[query] = query_inst
418
-
419
- # If the query expects a response from the terminal, we need to add a
420
- # key-binding for it and register it with the input parser
421
- if query.pattern:
422
- name = re.sub(r"(?<!^)(?=[A-Z])", "-", query.__name__).lower()
423
- title = name.replace("-", " ")
424
-
425
- # Add a "key" definition for this query
426
- key_name = f"{query.__name__}Response"
427
- key_code = f"<{name}-response>"
428
- # Do not register the same key multiple times
429
- if not hasattr(Keys, key_name):
430
- extend_enum(Keys, key_name, key_code)
431
- key = getattr(Keys, key_name)
432
- # Attach the key to the query instance
433
- query_inst.key = key
434
-
435
- # Register this key with the parser if supported
436
- if (parser := getattr(self.input, "vt100_parser", None)) and hasattr(
437
- parser, "queries"
438
- ):
439
- # Register the key
440
- parser.queries[key] = query.pattern
441
-
442
- # Add a command for the query's key-binding
443
- add_cmd(name=name, title=title, hidden=True)(
444
- query_inst._handle_response
445
- )
446
- # Add key-binding
447
- register_bindings({"euporie.core.terminal.TerminalInfo": {name: key}})
448
-
449
- return query_inst
450
-
451
- def send_all(self) -> None:
452
- """Send the command for all queries."""
453
- # Ensure line wrapping is off before sending queries
454
- self.output.disable_autowrap()
455
- for query in self._queries.values():
456
- query.send(flush=False)
457
- self.output.flush()
458
-
459
- def _tiocgwnsz(self) -> tuple[int, int, int, int]:
460
- """Get the size and pixel dimensions of the terminal with `termios`."""
461
- import array
462
-
463
- output = array.array("H", [0, 0, 0, 0])
464
- if _have_termios_tty_fcntl():
465
- import fcntl
466
- import termios
467
-
468
- try:
469
- fcntl.ioctl(1, termios.TIOCGWINSZ, output)
470
- except OSError:
471
- pass
472
- rows, cols, xpixels, ypixels = output
473
- return rows, cols, xpixels, ypixels
474
-
475
- @property
476
- def terminal_size_px(self) -> tuple[int, int]:
477
- """Get the pixel dimensions of the terminal."""
478
- # Prefer using escape codes as this works over SSH
479
- px, py = self.pixel_dimensions.value
480
- if px == 0:
481
- # If unsuccessful, try requesting info with tiocgwnsz
482
- _rows, _cols, px, py = self._tiocgwnsz()
483
- return px, py
484
-
485
- @property
486
- def cell_size_px(self) -> tuple[int, int]:
487
- """Get the pixel size of a single terminal cell."""
488
- px, py = self.terminal_size_px
489
- rows, cols = self.output.get_size()
490
- # If we can't get the pixel size, just guess wildly
491
- return px // cols or 10, py // rows or 20
492
-
493
-
494
- def edit_in_editor(filename: str, line_number: int = 0) -> None:
495
- """Suspend the current app and edit a file in an external editor."""
496
-
497
- def _open_file_in_editor(filename: str) -> None:
498
- """Call editor executable."""
499
- # If the 'VISUAL' or 'EDITOR' environment variable has been set, use that.
500
- # Otherwise, fall back to the first available editor that we can find.
501
- for editor in [
502
- os.environ.get("VISUAL"),
503
- os.environ.get("EDITOR"),
504
- "editor",
505
- "micro",
506
- "nano",
507
- "pico",
508
- "vi",
509
- "emacs",
510
- ]:
511
- if editor:
512
- try:
513
- # Use 'shlex.split()' because $VISUAL can contain spaces and quotes
514
- subprocess.call([*shlex.split(editor), filename])
515
- return
516
- except OSError:
517
- # Executable does not exist, try the next one.
518
- pass
519
-
520
- async def run() -> None:
521
- # Open in editor
522
- # (We need to use `run_in_terminal`, because not all editors go to
523
- # the alternate screen buffer, and some could influence the cursor
524
- # position)
525
- await run_in_terminal(lambda: _open_file_in_editor(filename), in_executor=True)
526
-
527
- get_app().create_background_task(run())
@@ -1,146 +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=GR-sGiOMnVigOYWqBMuzAnrfImUPDhnS5lWFIuUCcbk,26068
7
- euporie/core/__init__.py,sha256=jxseVjT-dxbt7sKWcD4hEFUMp2b-iYpKAwdavMolIvI,536
8
- euporie/core/__main__.py,sha256=8sHP02sjS29QZzOwPF7hSzOR9UwPEvsMCbuGuOlxVu4,603
9
- euporie/core/app.py,sha256=MVGQJbXb30LbDgETCLbHTnpFD_zRhn8vSE0mWQzNw2o,46040
10
- euporie/core/border.py,sha256=kJbpyxwJBtIRpFOpXhDtaCT1_oyVRjRiYKG4lXn3-iA,48507
11
- euporie/core/clipboard.py,sha256=Ps1wTcIV2B1PKfXiNKITR8nee2bo5qVfdCuhobiCNms,4461
12
- euporie/core/commands.py,sha256=uOS4cJTzxSv8jEMComMDAqaAUrsPjaB_AY4tTeZFGfY,8256
13
- euporie/core/completion.py,sha256=97pe7PdeUsahbgYLwvKhmik5aDAdZFZFOuOmhi9I8d8,5478
14
- euporie/core/config.py,sha256=ka6wloVH2hLhe7ga3w0nKLtuYsMenXcumdIC4eNSqM8,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=OSyOzp-7LuBsfQoJQqD3aKpMayeJOAT5eYSa-RGoYWk,9180
19
- euporie/core/format.py,sha256=jFt-GgLDId6Wzz88cA6spkDM6Hix_ihRx9fV_feBENw,3764
20
- euporie/core/graphics.py,sha256=JxBIpa0gL8iT_GH_Zk0RhwetMk1683KaQCCueemrTvY,32728
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=9bKFeE41Hrr241scVSnIjTFwKVSEk3yDc9HGK2rLXMs,46223
25
- euporie/core/keys.py,sha256=AZQI9e1l7OpUTEdH1r2feYAC2lyFPqkZw8-BYDjnbbI,3288
26
- euporie/core/launch.py,sha256=a51t67xWCGXVPRfzQMeHSJHaMBC5SDkGsjBGUqNSX_w,1405
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=Y8_YFTo7CBGgyJfaj7JRSx_7dwGz2tdMikBxSckxFuY,23637
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=08uO1695j-8LDQOwhfgOcUesXB1xhJpCfI_xosTiPtI,33407
38
- euporie/core/suggest.py,sha256=T86TsEY1_Z7XnW9ncUDKwP4utJc-wYFDV5U8MY78Q7A,5512
39
- euporie/core/terminal.py,sha256=BVwdgpBHYPNA9nht-9uS2Oy79T4wWt6y9wnlzSyKt9Q,17958
40
- euporie/core/utils.py,sha256=ZzaLogLbZw_c8-wdk2XS6dwpgIpQotKwhN2nzalHL8Y,2702
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=obOKgcYc8OBB1PfKfNRB59ppZbnVA2eCDokSTUucZ7Q,52725
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=VRkaVVVHHpfVxWY6zhBXgHD2qmPXfQAM9IfeMxJW1bE,14029
48
- euporie/core/convert/mime.py,sha256=uQwXw2hUsfS_dMeR4Ci6Zv4fORIBnEa9rdRa-nVT-Ls,3142
49
- euporie/core/convert/registry.py,sha256=IP43FE1edE2WDpjlKNylWhQV88WULpzWCIddBOQxxk8,2757
50
- euporie/core/convert/utils.py,sha256=aB1QdbfAvRJ0RRllhgI-knsX9eJQEU9Ygp26549n7Rk,2782
51
- euporie/core/convert/formats/__init__.py,sha256=sPJqKh1aA0V2jJs5cXUBmAEadsozUsGxv55irlrVr68,164
52
- euporie/core/convert/formats/ansi.py,sha256=fN2VJPYZ4D0fY77mbeW2hrT-JfnU7vqDEyPt8kl-HPo,13613
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=qZAwXikisfiUKfirtPVOlsrTDdOyRKGtW8HNon8z9YU,179010
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=vzrTyqaHWRxLDdiLStPQ-AprURIie76-i3cibELIDsA,274
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=04ByQ-7N5YNPOouHZiYcBIFIuHX2KuLW3XUZ1wzSBBo,27847
80
- euporie/core/key_binding/bindings/mouse.py,sha256=xbsBFSF2zLtK-f_Aj2NQ5kFaWaR1fimvs7dXhBpiFFM,6545
81
- euporie/core/key_binding/bindings/page_navigation.py,sha256=FWIv4iqWUCMjFHLu-I5Z08NIULXuTIjrn9fC25XImYg,4142
82
- euporie/core/layout/__init__.py,sha256=T5iGOnMGfNwVffJlfFMwGTFBLV7RkOuKw5gVp6cl4wA,59
83
- euporie/core/layout/cache.py,sha256=5jCF_Y-1vx4D5i9-iRDea3jD5F0Nvn14eKHLZl6TW6k,15057
84
- euporie/core/layout/containers.py,sha256=y6m5P-4_Ng49CCJuR5ghtumf7VwE7dOqeNEgEPDAPZ4,38831
85
- euporie/core/layout/controls.py,sha256=iFklysBxk_roWKfNN4Hdjqf4sFdEBzNWZq2OavlpJHY,825
86
- euporie/core/layout/decor.py,sha256=qMCgkrjokpqH9gaBXLe_rGLx9AwzfJ7rtyVhSAVh45w,14106
87
- euporie/core/layout/mouse.py,sha256=GJvFwOCZ8x-CppW8rGmJ6kV6JdW0Ndjihf8IwkuBI6Q,5165
88
- euporie/core/layout/print.py,sha256=YNDafjVTcI8GwOjueLBuqWMY72alxV9HE0BQaka9sgA,4645
89
- euporie/core/layout/screen.py,sha256=0xP9ZErMcw51nPgBbrm-DSQqFq5WNvsh9fw1amz2Z28,2224
90
- euporie/core/layout/scroll.py,sha256=DMBoVNNfahMDbq_vKezT3qDfQm2EwBGwOv2qy5QYkDc,33093
91
- euporie/core/tabs/__init__.py,sha256=Grm9EO1gnBO1o-k6Nqnlzo8XLIgFZSXNAdz49Vvh4zY,55
92
- euporie/core/tabs/base.py,sha256=Gdydp8Km9p6Hdqs-pdHvxGAKyWhvE_76zdE4ywcZF-g,20934
93
- euporie/core/tabs/notebook.py,sha256=4EdMMVvHzIAMAVkIZyDeToz5ad-emse5g5l2sMluTDU,17953
94
- euporie/core/widgets/__init__.py,sha256=ektso_Ea1-pZB04alUujQsa2r-kv8xAF0SmQOv_bvHQ,52
95
- euporie/core/widgets/cell.py,sha256=PMx_XHhnIXuqd0BcVmZPIDt1SaLlpnbTJuiB5-3yK64,35650
96
- euporie/core/widgets/cell_outputs.py,sha256=bVDbnf8KvZIsmUojopOn2iXjUCwP2rHuP1Q7r2_Z5eI,17322
97
- euporie/core/widgets/decor.py,sha256=GPZG7-h3MKynQIXJ_YoR6tPpYxtmrXi0uoyVCovSjBQ,8770
98
- euporie/core/widgets/dialog.py,sha256=Dj6CAHtHlSPmk2F30FXZZ2kYrEFYGkPAKzbWHUfaw-c,32675
99
- euporie/core/widgets/display.py,sha256=iGq5UTE_q3TS9fg1IIZ7dHDMyCMCDPqj0ue5kEwH4dw,21558
100
- euporie/core/widgets/file_browser.py,sha256=SmoQnngytD8-NgiRCKNLeFSdrqSCWRUUaGu8Tq295TQ,20731
101
- euporie/core/widgets/formatted_text_area.py,sha256=J7P_TNXPZKZkiBdjAVkPvkfRY1veXe4tzXU241k4b-Q,4037
102
- euporie/core/widgets/forms.py,sha256=iZj09v9I91ByuwUpGvf1FZrH2LF8FDIE-2MuAGIbLeA,85459
103
- euporie/core/widgets/inputs.py,sha256=BEYyP8SIH7h5yLkzY8NZExcc8-yL9z1feOCS_o1Q_78,21476
104
- euporie/core/widgets/layout.py,sha256=GAmWCUIhyhFvk0RBx8L7VeQpudKaFgkoyTk1tRKDJ94,23490
105
- euporie/core/widgets/menu.py,sha256=r5fdg63V3_VbZsd4EsAp2OBwaaGNnJemVFju8VyvM6E,32916
106
- euporie/core/widgets/pager.py,sha256=NX4cXP6T0dPVCcjeO7w4ebf-mdmjq-69Qc9I0I0AUdc,6446
107
- euporie/core/widgets/palette.py,sha256=e15dnPAg7VYjjahae-XsWViCjUA63jR5fdS3Oyof3MY,10847
108
- euporie/core/widgets/search.py,sha256=vz747icOZtwcEL1nH7p1hvrRtd-0W4LtSvXddO3y-hU,8227
109
- euporie/core/widgets/status.py,sha256=WnS9PzlfPyyVXLTaswLHV1tgbvmYCSWqs1re-DOTxXQ,5558
110
- euporie/core/widgets/tree.py,sha256=BG7QRsI2GzSJPReNQu9zWFjO0iy8TeJwrmCmP5dc2ek,3760
111
- euporie/data/desktop/euporie-console.desktop,sha256=DI08G0Dl2s5asM6afWUfkKvO5YmcBm-pWQZzUHiNnqc,153
112
- euporie/data/desktop/euporie-notebook.desktop,sha256=RtpJzvizTDuOp0BLa2bLgVHx11LG6L7PL-oF-wHTsgU,155
113
- euporie/hub/__init__.py,sha256=NcrOlSFgI4y5gEbD4lFY-Ryd1K79EeMoeAp41A6tDT0,44
114
- euporie/hub/__main__.py,sha256=m2EnzIDLO4dHlDt41JNKpUvAUSw6wD-X0V3YhymXqxc,289
115
- euporie/hub/app.py,sha256=w1J4A0X-W8Tr_rlRm13jMDjn35ggTOggDDVhCSIvitE,6129
116
- euporie/hub/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
117
- euporie/notebook/__init__.py,sha256=rOE71d95pym_ILYVg07NO9oDYbSB0AskxbC8cr4htiU,44
118
- euporie/notebook/__main__.py,sha256=m2EnzIDLO4dHlDt41JNKpUvAUSw6wD-X0V3YhymXqxc,289
119
- euporie/notebook/app.py,sha256=KvsSwjttvSuJgBsXa2eT0cUJVLOIdqzUM2lxuf2VneE,21320
120
- euporie/notebook/current.py,sha256=rQ_R9B0b8JmWILxEyGzGfuVY2iVkHTghq4qRiC-MYSU,387
121
- euporie/notebook/enums.py,sha256=g7quMch8KAlaaYJS0UppWqx6tx-ZFt7HxFcmEfam5OM,221
122
- euporie/notebook/filters.py,sha256=c2PncF-n4dE67cFmVmhsMhFVWCfxePAaCW6mb6zm0Yo,1502
123
- euporie/notebook/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
124
- euporie/notebook/tabs/__init__.py,sha256=CnHrMzmr4tKEd8Rs8swFvNDWj0fCiLChdqha0AtDNqY,417
125
- euporie/notebook/tabs/display.py,sha256=y8wMa-MsQZky_JgJEwUtMUGIbLnFiAZMfrX1u-km6VM,2595
126
- euporie/notebook/tabs/edit.py,sha256=_X7pnBLyXTAziblT4F_behiB4awE_GOR7bB-cRTHrKw,6458
127
- euporie/notebook/tabs/json.py,sha256=xKDHYkA59aleBpm6qLuic5GNPNQU6qApLuIT1vZzJrg,2179
128
- euporie/notebook/tabs/log.py,sha256=VJQRC_4SB4aZ4tVELm6ldkFCON_A_rqxBfi-sZzGBOw,3550
129
- euporie/notebook/tabs/notebook.py,sha256=gg-lLlVWZOivJTD6JMFaw73ca307mkqYe7ALZKdkKsw,43052
130
- euporie/notebook/widgets/__init__.py,sha256=74tOl0bYuWkaKT-4pgD5zmdiIkoFYx8uGj4SxcLHLtQ,48
131
- euporie/notebook/widgets/side_bar.py,sha256=EDFAulshV7YqA50w84RRl88UI60AehIXYYA2exlFh0M,7243
132
- euporie/preview/__init__.py,sha256=B6RsBuuT0JJk1v6U5n95VuFXcOeFLq6UGgt4w-n_nEI,51
133
- euporie/preview/__main__.py,sha256=m2EnzIDLO4dHlDt41JNKpUvAUSw6wD-X0V3YhymXqxc,289
134
- euporie/preview/app.py,sha256=XyZ3HpngCg_jCpDeVPMAUkZjHB3ZnNXdNPPjHuAtegI,8138
135
- euporie/preview/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
136
- euporie/preview/tabs/__init__.py,sha256=rY6DfQ-8qRo_AiICCD-zTyhJBnuMjawWDd8tRxR6q58,43
137
- euporie/preview/tabs/notebook.py,sha256=IHY-cAWo5UmehmXpSSLyuTJvjN9jBeD5BsSoa86zrUw,8504
138
- euporie/web/tabs/web.py,sha256=6wTB7ZLRqG79eQwKwsPIw03gHDUalmMVROSS9Z9j3YM,5228
139
- euporie/web/widgets/webview.py,sha256=jjJhZfujzyPCCz6t7bfgdPQ3ud20-1YhT-Lod5x-rrI,20762
140
- euporie-2.8.0.data/data/share/applications/euporie-console.desktop,sha256=DI08G0Dl2s5asM6afWUfkKvO5YmcBm-pWQZzUHiNnqc,153
141
- euporie-2.8.0.data/data/share/applications/euporie-notebook.desktop,sha256=RtpJzvizTDuOp0BLa2bLgVHx11LG6L7PL-oF-wHTsgU,155
142
- euporie-2.8.0.dist-info/METADATA,sha256=erYYRif6Bjt-WPHUGQagcXY5eSzCxI96ISkAiRwpy5c,6583
143
- euporie-2.8.0.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
144
- euporie-2.8.0.dist-info/entry_points.txt,sha256=iHdjwf9iCAipy7w3tXCH2W_SavHVCSHpJk_84--b7rE,776
145
- euporie-2.8.0.dist-info/licenses/LICENSE,sha256=rI0bfSsCfCVw6d8vk7WokRxd3t8yx5xV4fC5fwaMgCg,1079
146
- euporie-2.8.0.dist-info/RECORD,,