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.
- euporie/console/_commands.py +143 -0
- euporie/console/_settings.py +58 -0
- euporie/console/app.py +25 -71
- euporie/console/tabs/console.py +58 -62
- euporie/core/__init__.py +1 -1
- euporie/core/__main__.py +28 -11
- euporie/core/_settings.py +109 -0
- euporie/core/app/__init__.py +3 -0
- euporie/core/app/_commands.py +95 -0
- euporie/core/app/_settings.py +457 -0
- euporie/core/{app.py → app/app.py} +212 -576
- euporie/core/app/base.py +51 -0
- euporie/core/{current.py → app/current.py} +13 -4
- euporie/core/app/cursor.py +35 -0
- euporie/core/app/dummy.py +12 -0
- euporie/core/app/launch.py +28 -0
- euporie/core/bars/__init__.py +11 -0
- euporie/core/bars/command.py +205 -0
- euporie/core/bars/menu.py +258 -0
- euporie/core/{widgets → bars}/search.py +20 -16
- euporie/core/{widgets → bars}/status.py +6 -23
- euporie/core/clipboard.py +19 -80
- euporie/core/comm/base.py +8 -6
- euporie/core/comm/ipywidgets.py +16 -7
- euporie/core/comm/registry.py +2 -1
- euporie/core/commands.py +10 -20
- euporie/core/completion.py +3 -2
- euporie/core/config.py +368 -341
- euporie/core/convert/__init__.py +0 -30
- euporie/core/convert/datum.py +116 -53
- euporie/core/convert/formats/__init__.py +31 -0
- euporie/core/convert/formats/ansi.py +9 -23
- euporie/core/convert/formats/common.py +11 -23
- euporie/core/convert/formats/html.py +45 -40
- euporie/core/convert/formats/pil.py +1 -1
- euporie/core/convert/formats/png.py +3 -5
- euporie/core/convert/formats/sixel.py +3 -3
- euporie/core/convert/registry.py +4 -6
- euporie/core/convert/utils.py +41 -4
- euporie/core/diagnostics.py +2 -2
- euporie/core/filters.py +98 -40
- euporie/core/format.py +2 -3
- euporie/core/ft/ansi.py +1 -1
- euporie/core/ft/html.py +12 -21
- euporie/core/ft/table.py +1 -3
- euporie/core/ft/utils.py +4 -1
- euporie/core/graphics.py +386 -133
- euporie/core/history.py +2 -2
- euporie/core/inspection.py +3 -2
- euporie/core/io.py +207 -28
- euporie/core/kernel/__init__.py +1 -0
- euporie/core/{kernel.py → kernel/client.py} +45 -108
- euporie/core/kernel/manager.py +114 -0
- euporie/core/key_binding/bindings/__init__.py +1 -8
- euporie/core/key_binding/bindings/basic.py +47 -7
- euporie/core/key_binding/bindings/completion.py +3 -8
- euporie/core/key_binding/bindings/micro.py +1 -6
- euporie/core/key_binding/bindings/mouse.py +2 -2
- euporie/core/key_binding/bindings/terminal.py +193 -0
- euporie/core/key_binding/key_processor.py +43 -2
- euporie/core/key_binding/registry.py +2 -0
- euporie/core/key_binding/utils.py +22 -2
- euporie/core/keys.py +7156 -93
- euporie/core/layout/cache.py +3 -3
- euporie/core/layout/containers.py +48 -4
- euporie/core/layout/decor.py +2 -2
- euporie/core/layout/mouse.py +1 -1
- euporie/core/layout/print.py +2 -1
- euporie/core/layout/scroll.py +39 -34
- euporie/core/log.py +76 -64
- euporie/core/lsp.py +118 -24
- euporie/core/margins.py +1 -1
- euporie/core/path.py +62 -13
- euporie/core/renderer.py +58 -17
- euporie/core/style.py +57 -39
- euporie/core/suggest.py +103 -85
- euporie/core/tabs/__init__.py +32 -0
- euporie/core/tabs/_settings.py +113 -0
- euporie/core/tabs/base.py +80 -470
- euporie/core/tabs/kernel.py +419 -0
- euporie/core/tabs/notebook.py +24 -101
- euporie/core/utils.py +92 -15
- euporie/core/validation.py +1 -1
- euporie/core/widgets/_settings.py +188 -0
- euporie/core/widgets/cell.py +19 -50
- euporie/core/widgets/cell_outputs.py +25 -36
- euporie/core/widgets/decor.py +11 -41
- euporie/core/widgets/dialog.py +62 -27
- euporie/core/widgets/display.py +12 -15
- euporie/core/widgets/file_browser.py +2 -23
- euporie/core/widgets/forms.py +8 -5
- euporie/core/widgets/inputs.py +13 -70
- euporie/core/widgets/layout.py +2 -1
- euporie/core/widgets/logo.py +49 -0
- euporie/core/widgets/menu.py +10 -8
- euporie/core/widgets/pager.py +6 -10
- euporie/core/widgets/palette.py +6 -6
- euporie/hub/app.py +52 -35
- euporie/notebook/_commands.py +24 -0
- euporie/notebook/_settings.py +107 -0
- euporie/notebook/app.py +49 -171
- euporie/notebook/filters.py +1 -1
- euporie/notebook/tabs/__init__.py +46 -7
- euporie/notebook/tabs/_commands.py +714 -0
- euporie/notebook/tabs/_settings.py +32 -0
- euporie/notebook/tabs/display.py +4 -4
- euporie/notebook/tabs/edit.py +11 -44
- euporie/notebook/tabs/json.py +5 -5
- euporie/notebook/tabs/log.py +1 -18
- euporie/notebook/tabs/notebook.py +11 -660
- euporie/notebook/widgets/_commands.py +11 -0
- euporie/notebook/widgets/_settings.py +19 -0
- euporie/notebook/widgets/side_bar.py +14 -34
- euporie/preview/_settings.py +104 -0
- euporie/preview/app.py +6 -31
- euporie/preview/tabs/notebook.py +6 -72
- euporie/web/__init__.py +1 -0
- euporie/web/tabs/__init__.py +14 -0
- euporie/web/tabs/web.py +11 -6
- euporie/web/widgets/__init__.py +1 -0
- euporie/web/widgets/webview.py +5 -15
- {euporie-2.8.4.dist-info → euporie-2.8.6.dist-info}/METADATA +10 -8
- euporie-2.8.6.dist-info/RECORD +175 -0
- {euporie-2.8.4.dist-info → euporie-2.8.6.dist-info}/WHEEL +1 -1
- {euporie-2.8.4.dist-info → euporie-2.8.6.dist-info}/entry_points.txt +2 -2
- {euporie-2.8.4.dist-info → euporie-2.8.6.dist-info}/licenses/LICENSE +1 -1
- euporie/core/launch.py +0 -64
- euporie/core/terminal.py +0 -522
- euporie-2.8.4.dist-info/RECORD +0 -147
- {euporie-2.8.4.data → euporie-2.8.6.data}/data/share/applications/euporie-console.desktop +0 -0
- {euporie-2.8.4.data → euporie-2.8.6.data}/data/share/applications/euporie-notebook.desktop +0 -0
@@ -3,10 +3,12 @@
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
5
|
import asyncio
|
6
|
-
import json
|
7
6
|
import logging
|
7
|
+
import os
|
8
8
|
import signal
|
9
9
|
import sys
|
10
|
+
from abc import ABC, abstractmethod
|
11
|
+
from enum import Enum
|
10
12
|
from functools import partial
|
11
13
|
from pathlib import PurePath
|
12
14
|
from typing import TYPE_CHECKING, cast
|
@@ -14,8 +16,8 @@ from weakref import WeakSet, WeakValueDictionary
|
|
14
16
|
|
15
17
|
from prompt_toolkit.application.application import Application, _CombinedRegistry
|
16
18
|
from prompt_toolkit.application.current import create_app_session, set_app
|
17
|
-
from prompt_toolkit.cursor_shapes import CursorShape, CursorShapeConfig
|
18
19
|
from prompt_toolkit.data_structures import Point
|
20
|
+
from prompt_toolkit.enums import EditingMode
|
19
21
|
from prompt_toolkit.filters import Condition, buffer_has_focus, to_filter
|
20
22
|
from prompt_toolkit.input.defaults import create_input
|
21
23
|
from prompt_toolkit.key_binding.bindings.basic import (
|
@@ -52,18 +54,14 @@ from prompt_toolkit.styles import (
|
|
52
54
|
style_from_pygments_cls,
|
53
55
|
)
|
54
56
|
from prompt_toolkit.utils import Event
|
55
|
-
from pygments.styles import STYLE_MAP as pygments_styles
|
56
|
-
from pygments.styles import get_style_by_name
|
57
|
-
from upath import UPath
|
58
57
|
|
59
|
-
from euporie.core.
|
60
|
-
from euporie.core.
|
61
|
-
from euporie.core.
|
58
|
+
from euporie.core.app.base import ConfigurableApp
|
59
|
+
from euporie.core.app.cursor import CursorConfig
|
60
|
+
from euporie.core.clipboard import CONFIGURED_CLIPBOARDS
|
62
61
|
from euporie.core.convert.mime import get_mime
|
63
|
-
from euporie.core.
|
64
|
-
from euporie.core.filters import in_mplex, insert_mode, replace_mode, tab_has_focus
|
62
|
+
from euporie.core.filters import has_toolbar
|
65
63
|
from euporie.core.format import CliFormatter
|
66
|
-
from euporie.core.io import Vt100_Output, Vt100Parser
|
64
|
+
from euporie.core.io import COLOR_DEPTHS, Vt100_Output, Vt100Parser
|
67
65
|
from euporie.core.key_binding.key_processor import KeyProcessor
|
68
66
|
from euporie.core.key_binding.micro_state import MicroState
|
69
67
|
from euporie.core.key_binding.registry import (
|
@@ -84,8 +82,8 @@ from euporie.core.style import (
|
|
84
82
|
MIME_STYLE,
|
85
83
|
ColorPalette,
|
86
84
|
build_style,
|
85
|
+
get_style_by_name,
|
87
86
|
)
|
88
|
-
from euporie.core.terminal import TerminalInfo
|
89
87
|
from euporie.core.utils import ChainedList
|
90
88
|
from euporie.core.widgets.decor import Shadow
|
91
89
|
from euporie.core.widgets.menu import CompletionsMenu
|
@@ -94,84 +92,38 @@ if TYPE_CHECKING:
|
|
94
92
|
from asyncio import AbstractEventLoop
|
95
93
|
from pathlib import Path
|
96
94
|
from types import FrameType
|
97
|
-
from typing import Any, Callable, TypeVar
|
95
|
+
from typing import Any, Callable, ClassVar, TypeVar
|
98
96
|
|
99
97
|
# from prompt_toolkit.application import _AppResult
|
100
|
-
from prompt_toolkit.clipboard import Clipboard
|
101
98
|
from prompt_toolkit.contrib.ssh import PromptToolkitSSHSession
|
102
|
-
from prompt_toolkit.enums import EditingMode
|
103
99
|
from prompt_toolkit.filters import Filter, FilterOrBool
|
104
100
|
from prompt_toolkit.input import Input
|
101
|
+
from prompt_toolkit.layout.containers import AnyContainer
|
105
102
|
from prompt_toolkit.layout.layout import FocusableElement
|
106
103
|
from prompt_toolkit.layout.screen import WritePosition
|
107
104
|
from prompt_toolkit.output import Output
|
108
105
|
|
106
|
+
from euporie.core.bars.command import CommandBar
|
107
|
+
from euporie.core.bars.search import SearchBar
|
109
108
|
from euporie.core.config import Setting
|
110
109
|
from euporie.core.format import Formatter
|
110
|
+
from euporie.core.tabs import TabRegistryEntry
|
111
111
|
from euporie.core.tabs.base import Tab
|
112
|
-
from euporie.core.terminal import TerminalQuery
|
113
112
|
from euporie.core.widgets.dialog import Dialog
|
114
113
|
from euporie.core.widgets.pager import Pager
|
115
|
-
from euporie.core.widgets.search import SearchBar
|
116
114
|
|
117
115
|
_AppResult = TypeVar("_AppResult")
|
118
116
|
|
119
117
|
log = logging.getLogger(__name__)
|
120
118
|
|
121
119
|
|
122
|
-
|
123
|
-
|
124
|
-
4: ColorDepth.DEPTH_4_BIT,
|
125
|
-
8: ColorDepth.DEPTH_8_BIT,
|
126
|
-
24: ColorDepth.DEPTH_24_BIT,
|
127
|
-
}
|
128
|
-
|
129
|
-
|
130
|
-
class CursorConfig(CursorShapeConfig):
|
131
|
-
"""Determine which cursor mode to use."""
|
132
|
-
|
133
|
-
def get_cursor_shape(self, app: Application[Any]) -> CursorShape:
|
134
|
-
"""Return the cursor shape to be used in the current state."""
|
135
|
-
if isinstance(app, BaseApp) and app.config.set_cursor_shape:
|
136
|
-
if insert_mode():
|
137
|
-
if app.config.cursor_blink:
|
138
|
-
return CursorShape.BLINKING_BEAM
|
139
|
-
else:
|
140
|
-
return CursorShape.BEAM
|
141
|
-
elif replace_mode():
|
142
|
-
if app.config.cursor_blink:
|
143
|
-
return CursorShape.BLINKING_UNDERLINE
|
144
|
-
else:
|
145
|
-
return CursorShape.UNDERLINE
|
146
|
-
return CursorShape.BLOCK
|
147
|
-
|
148
|
-
# ################################### Settings ####################################w
|
149
|
-
|
150
|
-
add_setting(
|
151
|
-
name="set_cursor_shape",
|
152
|
-
flags=["--set-cursor-shape"],
|
153
|
-
type_=bool,
|
154
|
-
default=True,
|
155
|
-
menu_title="Change cursor shape",
|
156
|
-
help_="Whether to set the shape of the cursor depending on the editing mode",
|
157
|
-
description="""
|
158
|
-
When set to True, the euporie will set the shape of the terminal's cursor
|
159
|
-
to a beam in insert mode and and underline in replace mode when editing.
|
160
|
-
""",
|
161
|
-
)
|
162
|
-
add_setting(
|
163
|
-
name="cursor_blink",
|
164
|
-
flags=["--cursor-blink"],
|
165
|
-
type_=bool,
|
166
|
-
default=False,
|
167
|
-
help_="Whether to blink the cursor",
|
168
|
-
description="""
|
169
|
-
When set to True, the cursor will blink.
|
170
|
-
""",
|
171
|
-
)
|
120
|
+
class ExtraEditingMode(str, Enum):
|
121
|
+
"""Additional editing modes."""
|
172
122
|
|
123
|
+
MICRO = "MICRO"
|
173
124
|
|
174
|
-
|
125
|
+
|
126
|
+
class BaseApp(ConfigurableApp, Application, ABC):
|
175
127
|
"""All euporie apps.
|
176
128
|
|
177
129
|
The base euporie application class.
|
@@ -180,12 +132,10 @@ class BaseApp(Application):
|
|
180
132
|
wide methods can be easily added.
|
181
133
|
"""
|
182
134
|
|
183
|
-
name: str
|
184
135
|
color_palette: ColorPalette
|
185
136
|
mouse_position: Point
|
186
137
|
|
187
|
-
|
188
|
-
log_stdout_level: str = "CRITICAL"
|
138
|
+
_config_defaults: ClassVar[dict[str, Any]] = {"log_level_stdout": "critical"}
|
189
139
|
|
190
140
|
def __init__(
|
191
141
|
self,
|
@@ -219,7 +169,10 @@ class BaseApp(Application):
|
|
219
169
|
# Initialise the application
|
220
170
|
super().__init__(
|
221
171
|
**{
|
222
|
-
"
|
172
|
+
"clipboard": CONFIGURED_CLIPBOARDS.get(
|
173
|
+
self.config.clipboard, lambda: None
|
174
|
+
)(),
|
175
|
+
"color_depth": COLOR_DEPTHS.get(self.config.color_depth),
|
223
176
|
"editing_mode": self.get_edit_mode(),
|
224
177
|
"mouse_support": True,
|
225
178
|
"cursor": CursorConfig(),
|
@@ -240,14 +193,20 @@ class BaseApp(Application):
|
|
240
193
|
# Contains the opened tab containers
|
241
194
|
self.tabs: list[Tab] = []
|
242
195
|
self.on_tabs_change = Event(self)
|
243
|
-
# Holds the
|
196
|
+
# Holds the optional toolbars
|
244
197
|
self.search_bar: SearchBar | None = None
|
198
|
+
self.command_bar: CommandBar | None = None
|
245
199
|
# Holds the index of the current tab
|
246
200
|
self._tab_idx = 0
|
247
201
|
# Add state for micro key-bindings
|
248
202
|
self.micro_state = MicroState()
|
249
|
-
#
|
250
|
-
self.
|
203
|
+
# Default terminal info values
|
204
|
+
self.term_colors = dict(DEFAULT_COLORS)
|
205
|
+
self.term_graphics_sixel = False
|
206
|
+
self.term_graphics_iterm = False
|
207
|
+
self.term_graphics_kitty = False
|
208
|
+
self.term_sgr_pixel = False
|
209
|
+
self._term_size_px: tuple[int, int]
|
251
210
|
# Floats at the app level
|
252
211
|
self.leave_graphics = to_filter(leave_graphics)
|
253
212
|
self.graphics: WeakSet[Float] = WeakSet()
|
@@ -272,15 +231,16 @@ class BaseApp(Application):
|
|
272
231
|
self.key_processor = KeyProcessor(_CombinedRegistry(self))
|
273
232
|
# List of key-bindings groups to load
|
274
233
|
self.bindings_to_load = [
|
275
|
-
"euporie.core.app.BaseApp",
|
276
|
-
"euporie.core.
|
234
|
+
"euporie.core.app.app:BaseApp",
|
235
|
+
"euporie.core.io.TerminalInfo",
|
277
236
|
]
|
278
237
|
|
279
|
-
|
280
|
-
|
281
|
-
|
238
|
+
if enable_page_navigation_bindings:
|
239
|
+
from euporie.core.key_binding.bindings.page_navigation import (
|
240
|
+
load_page_navigation_bindings,
|
241
|
+
)
|
282
242
|
|
283
|
-
|
243
|
+
self._page_navigation_bindings = load_page_navigation_bindings(self.config)
|
284
244
|
# Allow hiding element when manually redrawing app
|
285
245
|
self._redrawing = False
|
286
246
|
self.redrawing = Condition(lambda: self._redrawing)
|
@@ -292,14 +252,17 @@ class BaseApp(Application):
|
|
292
252
|
self.set_title = to_filter(set_title)
|
293
253
|
self.title = title or self.__class__.__name__
|
294
254
|
# Register config hooks
|
295
|
-
self.config.
|
296
|
-
self.config.
|
297
|
-
self.config.
|
298
|
-
self.config.
|
299
|
-
self.config.
|
300
|
-
self.config.
|
301
|
-
self.config.
|
302
|
-
self, "_color_depth",
|
255
|
+
self.config.events.edit_mode += self.update_edit_mode
|
256
|
+
self.config.events.syntax_theme += self.update_style
|
257
|
+
self.config.events.color_scheme += self.update_style
|
258
|
+
self.config.events.log_level += lambda x: setup_logs(self.config)
|
259
|
+
self.config.events.log_file += lambda x: setup_logs(self.config)
|
260
|
+
self.config.events.log_config += lambda x: setup_logs(self.config)
|
261
|
+
self.config.events.color_depth += lambda x: setattr(
|
262
|
+
self, "_color_depth", COLOR_DEPTHS[self.config.color_depth]
|
263
|
+
)
|
264
|
+
self.config.events.clipboard += lambda x: setattr(
|
265
|
+
self, "clipboard", CONFIGURED_CLIPBOARDS[self.config.clipboard]
|
303
266
|
)
|
304
267
|
# Set up the color palette
|
305
268
|
self.color_palette = ColorPalette()
|
@@ -317,6 +280,30 @@ class BaseApp(Application):
|
|
317
280
|
CliFormatter(**info) for info in self.config.formatters
|
318
281
|
]
|
319
282
|
|
283
|
+
@property
|
284
|
+
def term_size_px(self) -> tuple[int, int]:
|
285
|
+
"""The dimensions of the terminal in pixels."""
|
286
|
+
try:
|
287
|
+
return self._term_size_px
|
288
|
+
except AttributeError:
|
289
|
+
from euporie.core.io import _tiocgwinsz
|
290
|
+
|
291
|
+
_rows, _cols, px, py = _tiocgwinsz()
|
292
|
+
self._term_size_px = (px, py)
|
293
|
+
return self._term_size_px
|
294
|
+
|
295
|
+
@term_size_px.setter
|
296
|
+
def term_size_px(self, value: tuple[int, int]) -> None:
|
297
|
+
self._term_size_px = value
|
298
|
+
|
299
|
+
@property
|
300
|
+
def cell_size_px(self) -> tuple[int, int]:
|
301
|
+
"""Get the pixel size of a single terminal cell."""
|
302
|
+
px, py = self.term_size_px
|
303
|
+
rows, cols = self.output.get_size()
|
304
|
+
# If we can't get the pixel size, just guess wildly
|
305
|
+
return px // cols or 10, py // rows or 20
|
306
|
+
|
320
307
|
@property
|
321
308
|
def title(self) -> str:
|
322
309
|
"""The application's title."""
|
@@ -350,19 +337,11 @@ class BaseApp(Application):
|
|
350
337
|
|
351
338
|
def pre_run(self, app: Application | None = None) -> None:
|
352
339
|
"""Call during the 'pre-run' stage of application loading."""
|
353
|
-
#
|
354
|
-
self.clipboard: Clipboard = ConfiguredClipboard(self)
|
355
|
-
# Determine what color depth to use
|
356
|
-
self._color_depth = _COLOR_DEPTHS.get(
|
357
|
-
self.config.color_depth, self.term_info.depth_of_color.value
|
358
|
-
)
|
359
|
-
# Set the application's style, and update it when the terminal responds
|
340
|
+
# Set the application's style
|
360
341
|
self.update_style()
|
361
|
-
|
362
|
-
# Load completions menu. This must be done after the app is set, because
|
363
|
-
# :py:func:`get_app` is needed to access the config
|
342
|
+
# Load completions menu.
|
364
343
|
self.menus["completions"] = Float(
|
365
|
-
content=Shadow(CompletionsMenu()),
|
344
|
+
content=Shadow(CompletionsMenu(extra_filter=~has_toolbar)),
|
366
345
|
xcursor=True,
|
367
346
|
ycursor=True,
|
368
347
|
)
|
@@ -372,6 +351,18 @@ class BaseApp(Application):
|
|
372
351
|
self.layout = Layout(self.load_container(), self.focused_element)
|
373
352
|
# Open any files we need to
|
374
353
|
self.open_files()
|
354
|
+
# Start polling terminal style if configured
|
355
|
+
if self.config.terminal_polling_interval and hasattr(
|
356
|
+
self.input, "vt100_parser"
|
357
|
+
):
|
358
|
+
self.create_background_task(self._poll_terminal_colors())
|
359
|
+
|
360
|
+
async def _poll_terminal_colors(self) -> None:
|
361
|
+
"""Repeatedly query the terminal for its background and foreground colours."""
|
362
|
+
if isinstance(output := self.output, Vt100_Output):
|
363
|
+
while self.config.terminal_polling_interval:
|
364
|
+
await asyncio.sleep(self.config.terminal_polling_interval)
|
365
|
+
output.get_colors()
|
375
366
|
|
376
367
|
async def run_async(
|
377
368
|
self,
|
@@ -382,26 +373,50 @@ class BaseApp(Application):
|
|
382
373
|
) -> _AppResult:
|
383
374
|
"""Run the application."""
|
384
375
|
with set_app(self):
|
376
|
+
# Use a custom vt100 parser to allow querying the terminal
|
377
|
+
if parser := getattr(self.input, "vt100_parser", None):
|
378
|
+
setattr( # noqa B010
|
379
|
+
self.input, "vt100_parser", Vt100Parser(parser.feed_key_callback)
|
380
|
+
)
|
381
|
+
|
385
382
|
# Load key bindings
|
386
383
|
self.load_key_bindings()
|
387
|
-
# Send queries to the terminal
|
388
|
-
self.term_info.send_all()
|
389
|
-
# Read responses
|
390
|
-
kp = self.key_processor
|
391
|
-
|
392
|
-
def read_from_input() -> None:
|
393
|
-
kp.feed_multiple(self.input.read_keys())
|
394
384
|
|
395
|
-
|
396
|
-
#
|
397
|
-
|
398
|
-
|
399
|
-
|
385
|
+
if isinstance(self.output, Vt100_Output):
|
386
|
+
# Send terminal queries
|
387
|
+
self.output.get_colors()
|
388
|
+
self.output.get_pixel_size()
|
389
|
+
self.output.get_kitty_graphics_status()
|
390
|
+
self.output.get_sixel_graphics_status()
|
391
|
+
self.output.get_iterm_graphics_status()
|
392
|
+
self.output.get_sgr_pixel_status()
|
393
|
+
self.output.get_csiu_status()
|
394
|
+
self.output.flush()
|
395
|
+
|
396
|
+
# Read responses
|
397
|
+
kp = self.key_processor
|
398
|
+
|
399
|
+
def read_from_input() -> None:
|
400
|
+
kp.feed_multiple(self.input.read_keys())
|
401
|
+
|
402
|
+
with self.input.raw_mode(), self.input.attach(read_from_input):
|
403
|
+
# Give the terminal time to respond and allow the event loop to read
|
404
|
+
# the terminal responses from the input
|
405
|
+
await asyncio.sleep(0.1)
|
406
|
+
kp.process_keys()
|
400
407
|
|
401
408
|
return await super().run_async(
|
402
409
|
pre_run, set_exception_handler, handle_sigint, slow_callback_duration
|
403
410
|
)
|
404
411
|
|
412
|
+
@classmethod
|
413
|
+
async def interact(cls, ssh_session: PromptToolkitSSHSession) -> None:
|
414
|
+
"""Run the app asynchronously for the hub SSH server."""
|
415
|
+
try:
|
416
|
+
await cls().run_async()
|
417
|
+
except EOFError:
|
418
|
+
pass
|
419
|
+
|
405
420
|
@classmethod
|
406
421
|
def load_input(cls) -> Input:
|
407
422
|
"""Create the input for this application to use.
|
@@ -419,12 +434,6 @@ class BaseApp(Application):
|
|
419
434
|
|
420
435
|
input_ = IgnoredInput()
|
421
436
|
|
422
|
-
# Use a custom vt100 parser to allow querying the terminal
|
423
|
-
if parser := getattr(input_, "vt100_parser", None):
|
424
|
-
setattr( # noqa B010
|
425
|
-
input_, "vt100_parser", Vt100Parser(parser.feed_key_callback)
|
426
|
-
)
|
427
|
-
|
428
437
|
return input_
|
429
438
|
|
430
439
|
@classmethod
|
@@ -461,6 +470,7 @@ class BaseApp(Application):
|
|
461
470
|
from euporie.core.key_binding.bindings.basic import load_basic_bindings
|
462
471
|
from euporie.core.key_binding.bindings.micro import load_micro_bindings
|
463
472
|
from euporie.core.key_binding.bindings.mouse import load_mouse_bindings
|
473
|
+
from euporie.core.key_binding.bindings.terminal import load_terminal_bindings
|
464
474
|
from euporie.core.key_binding.bindings.vi import load_vi_bindings
|
465
475
|
|
466
476
|
self._default_bindings = merge_key_bindings(
|
@@ -494,7 +504,7 @@ class BaseApp(Application):
|
|
494
504
|
# Load extra mouse bindings
|
495
505
|
load_mouse_bindings(),
|
496
506
|
# Load terminal query response key bindings
|
497
|
-
|
507
|
+
load_terminal_bindings(),
|
498
508
|
]
|
499
509
|
)
|
500
510
|
self.key_bindings = load_registered_bindings(
|
@@ -503,40 +513,39 @@ class BaseApp(Application):
|
|
503
513
|
|
504
514
|
def _on_resize(self) -> None:
|
505
515
|
"""Query the terminal dimensions on a resize event."""
|
506
|
-
self.
|
516
|
+
if isinstance(output := self.output, Vt100_Output):
|
517
|
+
output.get_pixel_size()
|
507
518
|
super()._on_resize()
|
508
519
|
|
509
520
|
@classmethod
|
510
521
|
def launch(cls) -> None:
|
511
522
|
"""Launch the app."""
|
512
|
-
|
513
|
-
setup_logs()
|
514
|
-
# Load the app's configuration
|
515
|
-
cls.config.load(cls)
|
523
|
+
super().launch()
|
516
524
|
# Run the application
|
517
525
|
with create_app_session(input=cls.load_input(), output=cls.load_output()):
|
518
526
|
# Create an instance of the app and run it
|
519
527
|
app = cls()
|
520
|
-
|
521
528
|
# Handle SIGTERM while the app is running
|
522
529
|
original_sigterm = signal.getsignal(signal.SIGTERM)
|
523
530
|
signal.signal(signal.SIGTERM, app.cleanup)
|
524
|
-
#
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
531
|
+
# Set and run the app
|
532
|
+
with set_app(app):
|
533
|
+
try:
|
534
|
+
result = app.run()
|
535
|
+
except (EOFError, KeyboardInterrupt):
|
536
|
+
result = None
|
537
|
+
finally:
|
538
|
+
signal.signal(signal.SIGTERM, original_sigterm)
|
539
|
+
# Shut down any remaining LSP clients at exit
|
540
|
+
app.shutdown_lsps()
|
533
541
|
return result
|
534
542
|
|
535
543
|
def cleanup(self, signum: int, frame: FrameType | None) -> None:
|
536
544
|
"""Restore the state of the terminal on unexpected exit."""
|
537
545
|
log.critical("Unexpected exit signal, restoring terminal")
|
538
546
|
output = self.output
|
539
|
-
self.
|
547
|
+
if self.is_running:
|
548
|
+
self.exit()
|
540
549
|
self.shutdown_lsps()
|
541
550
|
# Reset terminal state
|
542
551
|
output.reset_cursor_key_mode()
|
@@ -548,12 +557,8 @@ class BaseApp(Application):
|
|
548
557
|
# Exit the main thread
|
549
558
|
sys.exit(1)
|
550
559
|
|
551
|
-
@
|
552
|
-
|
553
|
-
"""Run the app asynchronously for the hub SSH server."""
|
554
|
-
await cls().run_async()
|
555
|
-
|
556
|
-
def load_container(self) -> FloatContainer:
|
560
|
+
@abstractmethod
|
561
|
+
def load_container(self) -> AnyContainer:
|
557
562
|
"""Load the root container for this application.
|
558
563
|
|
559
564
|
Returns:
|
@@ -565,27 +570,32 @@ class BaseApp(Application):
|
|
565
570
|
floats=cast("list[Float]", self.floats),
|
566
571
|
)
|
567
572
|
|
568
|
-
|
569
|
-
|
570
|
-
|
573
|
+
@property
|
574
|
+
def tab_registry(self) -> list[TabRegistryEntry]:
|
575
|
+
"""Return the tab registry."""
|
576
|
+
from euporie.core.tabs import _TAB_REGISTRY
|
577
|
+
|
578
|
+
return _TAB_REGISTRY
|
571
579
|
|
580
|
+
def get_file_tabs(self, path: Path) -> list[TabRegistryEntry]:
|
581
|
+
"""Return the tab to use for a file path."""
|
572
582
|
path_mime = get_mime(path) or "text/plain"
|
573
583
|
log.debug("File %s has mime type: %s", path, path_mime)
|
574
584
|
|
575
|
-
tab_options =
|
576
|
-
for
|
577
|
-
for mime_type in
|
585
|
+
tab_options: list[TabRegistryEntry] = []
|
586
|
+
for entry in self.tab_registry:
|
587
|
+
for mime_type in entry.mime_types:
|
578
588
|
if PurePath(path_mime).match(mime_type):
|
579
|
-
tab_options.
|
580
|
-
if path.suffix in
|
581
|
-
tab_options.
|
589
|
+
tab_options.append(entry)
|
590
|
+
if path.suffix in entry.file_extensions:
|
591
|
+
tab_options.append(entry)
|
582
592
|
|
583
|
-
return sorted(tab_options,
|
593
|
+
return sorted(tab_options, reverse=True)
|
584
594
|
|
585
595
|
def get_file_tab(self, path: Path) -> type[Tab] | None:
|
586
596
|
"""Return the tab to use for a file path."""
|
587
597
|
if tabs := self.get_file_tabs(path):
|
588
|
-
return tabs[0]
|
598
|
+
return tabs[0].tab_class
|
589
599
|
return None
|
590
600
|
|
591
601
|
def get_language_lsps(self, language: str) -> list[LspClient]:
|
@@ -735,30 +745,59 @@ class BaseApp(Application):
|
|
735
745
|
|
736
746
|
def get_edit_mode(self) -> EditingMode:
|
737
747
|
"""Return the editing mode enum defined in the configuration."""
|
738
|
-
|
748
|
+
micro_mode = cast("EditingMode", ExtraEditingMode.MICRO)
|
739
749
|
|
740
750
|
return {
|
741
|
-
"micro":
|
751
|
+
"micro": micro_mode,
|
742
752
|
"vi": EditingMode.VI,
|
743
753
|
"emacs": EditingMode.EMACS,
|
744
|
-
}.get(
|
745
|
-
str(self.config.edit_mode),
|
746
|
-
EditingMode.MICRO, # type: ignore
|
747
|
-
)
|
754
|
+
}.get(str(self.config.edit_mode), micro_mode)
|
748
755
|
|
749
756
|
def update_edit_mode(self, setting: Setting | None = None) -> None:
|
750
757
|
"""Set the keybindings for editing mode."""
|
751
758
|
self.editing_mode = self.get_edit_mode()
|
752
759
|
log.debug("Editing mode set to: %s", self.editing_mode)
|
753
760
|
|
761
|
+
@property
|
762
|
+
def color_depth(self) -> ColorDepth:
|
763
|
+
"""The active :class:`.ColorDepth`.
|
764
|
+
|
765
|
+
The current value is determined as follows:
|
766
|
+
|
767
|
+
- If a color depth was given explicitly to this application, use that
|
768
|
+
value.
|
769
|
+
- Otherwise, fall back to the color depth that is reported by the
|
770
|
+
:class:`.Output` implementation. If the :class:`.Output` class was
|
771
|
+
created using `output.defaults.create_output`, then this value is
|
772
|
+
coming from the $PROMPT_TOOLKIT_COLOR_DEPTH environment variable.
|
773
|
+
"""
|
774
|
+
# Detect terminal color depth
|
775
|
+
if self._color_depth is None:
|
776
|
+
if os.environ.get("NO_COLOR", "") or os.environ.get("TERM", "") == "dumb":
|
777
|
+
self._color_depth = ColorDepth.DEPTH_1_BIT
|
778
|
+
colorterm = os.environ.get("COLORTERM", "")
|
779
|
+
if "truecolor" in colorterm or "24bit" in colorterm:
|
780
|
+
self._color_depth = ColorDepth.DEPTH_24_BIT
|
781
|
+
elif "256" in os.environ.get("TERM", ""):
|
782
|
+
self._color_depth = ColorDepth.DEPTH_8_BIT
|
783
|
+
|
784
|
+
return super().color_depth
|
785
|
+
|
754
786
|
@property
|
755
787
|
def syntax_theme(self) -> str:
|
756
788
|
"""Calculate the current syntax theme."""
|
757
789
|
syntax_theme = self.config.syntax_theme
|
758
|
-
if syntax_theme == self.config.
|
790
|
+
if syntax_theme == self.config.defaults.syntax_theme:
|
759
791
|
syntax_theme = "tango" if self.color_palette.bg.is_light else "euporie"
|
760
792
|
return syntax_theme
|
761
793
|
|
794
|
+
base_styles = (
|
795
|
+
Style(MIME_STYLE),
|
796
|
+
Style(HTML_STYLE),
|
797
|
+
Style(LOG_STYLE),
|
798
|
+
Style(IPYWIDGET_STYLE),
|
799
|
+
)
|
800
|
+
|
762
801
|
def create_merged_style(self) -> BaseStyle:
|
763
802
|
"""Generate a new merged style for the application.
|
764
803
|
|
@@ -769,6 +808,11 @@ class BaseApp(Application):
|
|
769
808
|
Return a combined style to use for the application
|
770
809
|
|
771
810
|
"""
|
811
|
+
styles: list[BaseStyle] = [
|
812
|
+
style_from_pygments_cls(get_style_by_name(self.syntax_theme)),
|
813
|
+
*self.base_styles,
|
814
|
+
]
|
815
|
+
|
772
816
|
# Get foreground and background colors based on the configured colour scheme
|
773
817
|
theme_colors: dict[str, dict[str, str]] = {
|
774
818
|
"default": {},
|
@@ -784,7 +828,7 @@ class BaseApp(Application):
|
|
784
828
|
}
|
785
829
|
base_colors: dict[str, str] = {
|
786
830
|
**DEFAULT_COLORS,
|
787
|
-
**self.
|
831
|
+
**self.term_colors,
|
788
832
|
**theme_colors.get(self.config.color_scheme, theme_colors["default"]),
|
789
833
|
}
|
790
834
|
|
@@ -812,7 +856,7 @@ class BaseApp(Application):
|
|
812
856
|
)
|
813
857
|
|
814
858
|
# Build app style
|
815
|
-
|
859
|
+
styles.append(build_style(cp))
|
816
860
|
|
817
861
|
# Apply style transformations based on the configured color scheme
|
818
862
|
self.style_transformation = merge_style_transformations(
|
@@ -830,21 +874,13 @@ class BaseApp(Application):
|
|
830
874
|
]
|
831
875
|
)
|
832
876
|
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
Style(MIME_STYLE),
|
837
|
-
Style(HTML_STYLE),
|
838
|
-
Style(LOG_STYLE),
|
839
|
-
Style(IPYWIDGET_STYLE),
|
840
|
-
app_style,
|
841
|
-
]
|
842
|
-
)
|
877
|
+
# Add user style customizations
|
878
|
+
if custom_style_dict := self.config.custom_styles:
|
879
|
+
styles.append(Style.from_dict(custom_style_dict))
|
843
880
|
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
) -> None:
|
881
|
+
return merge_styles(styles)
|
882
|
+
|
883
|
+
def update_style(self, query: Setting | None = None) -> None:
|
848
884
|
"""Update the application's style when the syntax theme is changed."""
|
849
885
|
self.renderer.style = self.create_merged_style()
|
850
886
|
|
@@ -895,411 +931,11 @@ class BaseApp(Application):
|
|
895
931
|
# print(task.get_loop())
|
896
932
|
# await asyncio.wait([task])
|
897
933
|
|
898
|
-
# ################################### Commands ####################################
|
899
|
-
|
900
|
-
@staticmethod
|
901
|
-
@add_cmd()
|
902
|
-
def _quit() -> None:
|
903
|
-
"""Quit euporie."""
|
904
|
-
get_app().exit()
|
905
|
-
|
906
|
-
@staticmethod
|
907
|
-
@add_cmd(
|
908
|
-
name="close-tab",
|
909
|
-
filter=tab_has_focus,
|
910
|
-
menu_title="Close File",
|
911
|
-
)
|
912
|
-
def _close_tab() -> None:
|
913
|
-
"""Close the current tab."""
|
914
|
-
get_app().close_tab()
|
915
|
-
|
916
|
-
@staticmethod
|
917
|
-
@add_cmd(
|
918
|
-
filter=tab_has_focus,
|
919
|
-
)
|
920
|
-
def _next_tab() -> None:
|
921
|
-
"""Switch to the next tab."""
|
922
|
-
get_app().tab_idx += 1
|
923
|
-
|
924
|
-
@staticmethod
|
925
|
-
@add_cmd(
|
926
|
-
filter=tab_has_focus,
|
927
|
-
)
|
928
|
-
def _previous_tab() -> None:
|
929
|
-
"""Switch to the previous tab."""
|
930
|
-
get_app().tab_idx -= 1
|
931
|
-
|
932
|
-
@staticmethod
|
933
|
-
@add_cmd(
|
934
|
-
filter=~buffer_has_focus,
|
935
|
-
)
|
936
|
-
def _focus_next() -> None:
|
937
|
-
"""Focus the next control."""
|
938
|
-
get_app().layout.focus_next()
|
939
|
-
|
940
|
-
@staticmethod
|
941
|
-
@add_cmd(
|
942
|
-
filter=~buffer_has_focus,
|
943
|
-
)
|
944
|
-
def _focus_previous() -> None:
|
945
|
-
"""Focus the previous control."""
|
946
|
-
get_app().layout.focus_previous()
|
947
|
-
|
948
|
-
@staticmethod
|
949
|
-
@add_cmd()
|
950
|
-
def _clear_screen() -> None:
|
951
|
-
"""Clear the screen."""
|
952
|
-
get_app().renderer.clear()
|
953
|
-
|
954
|
-
# ################################### Settings ####################################w
|
955
|
-
|
956
|
-
add_setting(
|
957
|
-
name="files",
|
958
|
-
default=[],
|
959
|
-
flags=["files"],
|
960
|
-
nargs="*",
|
961
|
-
type_=UPath,
|
962
|
-
help_="List of file names to open",
|
963
|
-
schema={
|
964
|
-
"type": "array",
|
965
|
-
"items": {
|
966
|
-
"description": "File path",
|
967
|
-
"type": "string",
|
968
|
-
},
|
969
|
-
},
|
970
|
-
description="""
|
971
|
-
A list of file paths to open when euporie is launched.
|
972
|
-
""",
|
973
|
-
)
|
974
|
-
|
975
|
-
add_setting(
|
976
|
-
name="edit_mode",
|
977
|
-
flags=["--edit-mode"],
|
978
|
-
type_=str,
|
979
|
-
choices=["micro", "emacs", "vi"],
|
980
|
-
title="Editor key bindings",
|
981
|
-
help_="Key-binding mode for text editing",
|
982
|
-
default="micro",
|
983
|
-
description="""
|
984
|
-
Key binding style to use when editing cells.
|
985
|
-
""",
|
986
|
-
)
|
987
|
-
|
988
|
-
add_setting(
|
989
|
-
name="tab_size",
|
990
|
-
flags=["--tab-size"],
|
991
|
-
type_=int,
|
992
|
-
help_="Spaces per indentation level",
|
993
|
-
default=4,
|
994
|
-
schema={
|
995
|
-
"minimum": 1,
|
996
|
-
},
|
997
|
-
description="""
|
998
|
-
The number of spaces to use per indentation level. Should be set to 4.
|
999
|
-
""",
|
1000
|
-
)
|
1001
|
-
|
1002
|
-
add_setting(
|
1003
|
-
name="terminal_polling_interval",
|
1004
|
-
flags=["--terminal-polling-interval"],
|
1005
|
-
type_=float,
|
1006
|
-
help_="Time between terminal colour queries",
|
1007
|
-
default=0.0,
|
1008
|
-
schema={
|
1009
|
-
"min": 0.0,
|
1010
|
-
},
|
1011
|
-
description="""
|
1012
|
-
Determine how frequently the terminal should be polled for changes to the
|
1013
|
-
background / foreground colours. Set to zero to disable terminal polling.
|
1014
|
-
""",
|
1015
|
-
)
|
1016
|
-
|
1017
|
-
add_setting(
|
1018
|
-
name="formatters",
|
1019
|
-
flags=["--formatters"],
|
1020
|
-
type_=json.loads,
|
1021
|
-
help_="List of external code formatters",
|
1022
|
-
default=[
|
1023
|
-
# {"command": ["ruff", "format", "-"], "languages": ["python"]},
|
1024
|
-
# {"command": ["black", "-"], "languages": ["python"]},
|
1025
|
-
# {"command": ["isort", "-"], "languages": ["python"]},
|
1026
|
-
],
|
1027
|
-
action="append",
|
1028
|
-
schema={
|
1029
|
-
"type": "array",
|
1030
|
-
"items": {
|
1031
|
-
"type": "object",
|
1032
|
-
"properties": {
|
1033
|
-
"command": {
|
1034
|
-
"type": "array",
|
1035
|
-
"items": [{"type": "string"}],
|
1036
|
-
},
|
1037
|
-
"languages": {
|
1038
|
-
"type": "array",
|
1039
|
-
"items": [{"type": "string", "unique": True}],
|
1040
|
-
},
|
1041
|
-
},
|
1042
|
-
"required": ["command", "languages"],
|
1043
|
-
},
|
1044
|
-
},
|
1045
|
-
description="""
|
1046
|
-
An array listing languages and commands of formatters to use for
|
1047
|
-
reformatting code cells. The command is an array of the command any any
|
1048
|
-
arguments. Code to be formatted is pass in via the standard input, and
|
1049
|
-
replaced with the standard output.
|
1050
|
-
|
1051
|
-
e.g.
|
1052
|
-
|
1053
|
-
[
|
1054
|
-
{"command": ["ruff", "format", "-"], "languages": ["python"]},
|
1055
|
-
{"command": ["black", "-"], "languages": ["python"]},
|
1056
|
-
{"command": ["isort", "-"], "languages": ["python"]}
|
1057
|
-
]
|
1058
|
-
""",
|
1059
|
-
)
|
1060
|
-
|
1061
|
-
add_setting(
|
1062
|
-
name="syntax_highlighting",
|
1063
|
-
flags=["--syntax-highlighting"],
|
1064
|
-
type_=bool,
|
1065
|
-
help_="Syntax highlighting",
|
1066
|
-
default=True,
|
1067
|
-
description="""
|
1068
|
-
Enable or disable syntax highlighting in code input fields.
|
1069
|
-
""",
|
1070
|
-
)
|
1071
|
-
|
1072
|
-
add_setting(
|
1073
|
-
name="syntax_theme",
|
1074
|
-
flags=["--syntax-theme"],
|
1075
|
-
type_=str,
|
1076
|
-
help_="Syntax highlighting theme",
|
1077
|
-
default="euporie",
|
1078
|
-
schema={
|
1079
|
-
# Do not want to print all theme names in `--help` screen as it looks messy
|
1080
|
-
# so we only add them in the scheme, not as setting choices
|
1081
|
-
"enum": list(pygments_styles.keys()),
|
1082
|
-
},
|
1083
|
-
description="""
|
1084
|
-
The name of the pygments style to use for syntax highlighting.
|
1085
|
-
""",
|
1086
|
-
)
|
1087
|
-
|
1088
|
-
add_setting(
|
1089
|
-
name="color_depth",
|
1090
|
-
flags=["--color-depth"],
|
1091
|
-
type_=int,
|
1092
|
-
choices=[1, 4, 8, 24],
|
1093
|
-
default=None,
|
1094
|
-
help_="The color depth to use",
|
1095
|
-
description="""
|
1096
|
-
The number of bits to use to represent colors displayable on the screen.
|
1097
|
-
If set to None, the supported color depth of the terminal will be detected
|
1098
|
-
automatically.
|
1099
|
-
""",
|
1100
|
-
)
|
1101
|
-
|
1102
|
-
add_setting(
|
1103
|
-
name="multiplexer_passthrough",
|
1104
|
-
flags=["--multiplexer-passthrough"],
|
1105
|
-
type_=bool,
|
1106
|
-
help_="Use passthrough from within terminal multiplexers",
|
1107
|
-
default=False,
|
1108
|
-
hidden=~in_mplex,
|
1109
|
-
description="""
|
1110
|
-
If set and euporie is running inside a terminal multiplexer
|
1111
|
-
(:program:`screen` or :program:`tmux`), then certain escape sequences
|
1112
|
-
will be passed-through the multiplexer directly to the terminal.
|
1113
|
-
|
1114
|
-
This affects things such as terminal color detection and graphics display.
|
1115
|
-
|
1116
|
-
for tmux, you will also need to ensure that ``allow-passthrough`` is set to
|
1117
|
-
``on`` in your :program:`tmux` configuration.
|
1118
|
-
|
1119
|
-
.. warning::
|
1120
|
-
|
1121
|
-
Terminal graphics in :program:`tmux` is experimental, and is not
|
1122
|
-
guaranteed to work. Use at your own risk!
|
1123
|
-
|
1124
|
-
.. note::
|
1125
|
-
As of version :command:`tmux` version ``3.4`` sixel graphics are
|
1126
|
-
supported, which may result in better terminal graphics then using
|
1127
|
-
multiplexer passthrough.
|
1128
|
-
""",
|
1129
|
-
)
|
1130
|
-
|
1131
|
-
add_setting(
|
1132
|
-
name="color_scheme",
|
1133
|
-
flags=["--color-scheme"],
|
1134
|
-
type_=str,
|
1135
|
-
choices=["default", "inverse", "light", "dark", "black", "white", "custom"],
|
1136
|
-
help_="The color scheme to use",
|
1137
|
-
default="default",
|
1138
|
-
description="""
|
1139
|
-
The color scheme to use: `auto` means euporie will try to use your
|
1140
|
-
terminal's color scheme, `light` means black text on a white background,
|
1141
|
-
and `dark` means white text on a black background.
|
1142
|
-
""",
|
1143
|
-
)
|
1144
|
-
|
1145
|
-
add_setting(
|
1146
|
-
name="custom_background_color",
|
1147
|
-
flags=["--custom-background-color", "--custom-bg-color", "--bg"],
|
1148
|
-
type_=str,
|
1149
|
-
help_='Background color for "Custom" color theme',
|
1150
|
-
default="#073642",
|
1151
|
-
schema={
|
1152
|
-
"maxLength": 7,
|
1153
|
-
},
|
1154
|
-
description="""
|
1155
|
-
The hex code of the color to use for the background in the "Custom" color
|
1156
|
-
scheme.
|
1157
|
-
""",
|
1158
|
-
)
|
1159
|
-
|
1160
|
-
add_setting(
|
1161
|
-
name="custom_foreground_color",
|
1162
|
-
flags=["--custom-foreground-color", "--custom-fg-color", "--fg"],
|
1163
|
-
type_=str,
|
1164
|
-
help_='Foreground color for "Custom" color theme',
|
1165
|
-
default="#839496",
|
1166
|
-
schema={
|
1167
|
-
"maxLength": 7,
|
1168
|
-
},
|
1169
|
-
description="""
|
1170
|
-
The hex code of the color to use for the foreground in the "Custom" color
|
1171
|
-
scheme.
|
1172
|
-
""",
|
1173
|
-
)
|
1174
|
-
|
1175
|
-
add_setting(
|
1176
|
-
name="accent_color",
|
1177
|
-
flags=["--accent-color"],
|
1178
|
-
type_=str,
|
1179
|
-
help_="Accent color to use in the app",
|
1180
|
-
default="ansiblue",
|
1181
|
-
description="""
|
1182
|
-
The hex code of a color to use for the accent color in the application.
|
1183
|
-
""",
|
1184
|
-
)
|
1185
|
-
|
1186
|
-
add_setting(
|
1187
|
-
name="key_bindings",
|
1188
|
-
flags=["--key-bindings"],
|
1189
|
-
type_=json.loads,
|
1190
|
-
help_="Additional key binding definitions",
|
1191
|
-
default={},
|
1192
|
-
description="""
|
1193
|
-
A mapping of component names to mappings of command name to key-binding lists.
|
1194
|
-
""",
|
1195
|
-
schema={
|
1196
|
-
"type": "object",
|
1197
|
-
},
|
1198
|
-
)
|
1199
|
-
|
1200
|
-
add_setting(
|
1201
|
-
name="graphics",
|
1202
|
-
flags=["--graphics"],
|
1203
|
-
choices=["none", "sixel", "kitty", "iterm"],
|
1204
|
-
type_=str,
|
1205
|
-
default=None,
|
1206
|
-
help_="The preferred graphics protocol",
|
1207
|
-
description="""
|
1208
|
-
The graphics protocol to use, if supported by the terminal.
|
1209
|
-
If set to "none", terminal graphics will not be used.
|
1210
|
-
""",
|
1211
|
-
)
|
1212
|
-
|
1213
|
-
add_setting(
|
1214
|
-
name="force_graphics",
|
1215
|
-
flags=["--force-graphics"],
|
1216
|
-
type_=bool,
|
1217
|
-
default=False,
|
1218
|
-
help_="Force use of specified graphics protocol",
|
1219
|
-
description="""
|
1220
|
-
When set to :py:const:`True`, the graphics protocol specified by the
|
1221
|
-
:option:`graphics` configuration option will be used even if the terminal
|
1222
|
-
does not support it.
|
1223
|
-
|
1224
|
-
This is also useful if you want to use graphics in :command:`euporie-hub`.
|
1225
|
-
""",
|
1226
|
-
)
|
1227
|
-
|
1228
|
-
add_setting(
|
1229
|
-
name="enable_language_servers",
|
1230
|
-
flags=["--enable-language-servers", "--lsp"],
|
1231
|
-
menu_title="Language servers",
|
1232
|
-
type_=bool,
|
1233
|
-
default=False,
|
1234
|
-
help_="Enable language server support",
|
1235
|
-
description="""
|
1236
|
-
When set to :py:const:`True`, language servers will be used for liniting,
|
1237
|
-
code inspection, and code formatting.
|
1238
|
-
|
1239
|
-
Additional language servers can be added using the
|
1240
|
-
:option:`language-servers` option.
|
1241
|
-
""",
|
1242
|
-
)
|
1243
|
-
|
1244
|
-
add_setting(
|
1245
|
-
name="language_servers",
|
1246
|
-
flags=["--language-servers"],
|
1247
|
-
type_=json.loads,
|
1248
|
-
help_="Language server configurations",
|
1249
|
-
default={},
|
1250
|
-
schema={
|
1251
|
-
"type": "object",
|
1252
|
-
"items": {
|
1253
|
-
"type": "object",
|
1254
|
-
"patternProperties": {
|
1255
|
-
"^[0-9]+$": {
|
1256
|
-
"type": "object",
|
1257
|
-
"properties": {
|
1258
|
-
"command": {
|
1259
|
-
"type": "array",
|
1260
|
-
"items": [{"type": "string"}],
|
1261
|
-
},
|
1262
|
-
"language": {
|
1263
|
-
"type": "array",
|
1264
|
-
"items": [{"type": "string", "unique": True}],
|
1265
|
-
},
|
1266
|
-
},
|
1267
|
-
"required": ["command"],
|
1268
|
-
}
|
1269
|
-
},
|
1270
|
-
},
|
1271
|
-
},
|
1272
|
-
description="""
|
1273
|
-
Additional language servers can be defined here, e.g.:
|
1274
|
-
|
1275
|
-
{
|
1276
|
-
"ruff": {"command": ["ruff-lsp"], "languages": ["python"]},
|
1277
|
-
"pylsp": {"command": ["pylsp"], "languages": ["python"]},
|
1278
|
-
"typos": {"command": ["typos-lsp"], "languages": []}
|
1279
|
-
}
|
1280
|
-
|
1281
|
-
The following properties are required:
|
1282
|
-
- The name to be given to the the language server, must be unique
|
1283
|
-
- The command list consists of the process to launch, followed by any
|
1284
|
-
command line arguments
|
1285
|
-
- A list of language the language server supports. If no languages are
|
1286
|
-
given, the language server will be used for documents of any language.
|
1287
|
-
|
1288
|
-
To disable one of the default language servers, its name can be set to an
|
1289
|
-
empty dictionary. For example, the following would disable the awk language
|
1290
|
-
server:
|
1291
|
-
|
1292
|
-
{
|
1293
|
-
"awk-language-server": {},
|
1294
|
-
}
|
1295
|
-
""",
|
1296
|
-
)
|
1297
|
-
|
1298
934
|
# ################################# Key Bindings ##################################
|
1299
935
|
|
1300
936
|
register_bindings(
|
1301
937
|
{
|
1302
|
-
"euporie.core.app.BaseApp": {
|
938
|
+
"euporie.core.app.app:BaseApp": {
|
1303
939
|
"quit": ["c-q", "<sigint>"],
|
1304
940
|
"close-tab": "c-w",
|
1305
941
|
"next-tab": "c-pagedown",
|