mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-26 18:22:09 +02:00
Update codebase to Python 3.10 using pyupgrade
This commit is contained in:
@@ -2,10 +2,6 @@
|
||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import sys
|
||||
from typing import (
|
||||
List,
|
||||
Optional,
|
||||
)
|
||||
|
||||
from kitty.typing import BossType, TypedDict
|
||||
|
||||
@@ -69,15 +65,15 @@ The text in the message to be replaced by hidden text. The hidden text is read v
|
||||
|
||||
|
||||
class Response(TypedDict):
|
||||
items: List[str]
|
||||
response: Optional[str]
|
||||
items: list[str]
|
||||
response: str | None
|
||||
|
||||
def main(args: List[str]) -> Response:
|
||||
def main(args: list[str]) -> Response:
|
||||
raise SystemExit('This must be run as kitten ask')
|
||||
|
||||
|
||||
@result_handler()
|
||||
def handle_result(args: List[str], data: Response, target_window_id: int, boss: BossType) -> None:
|
||||
def handle_result(args: list[str], data: Response, target_window_id: int, boss: BossType) -> None:
|
||||
if data['response'] is not None:
|
||||
func, *args = data['items']
|
||||
getattr(boss, func)(data['response'], *args)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import sys
|
||||
from base64 import standard_b64encode
|
||||
from gettext import gettext as _
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
from typing import Any
|
||||
|
||||
from kitty.cli import parse_args
|
||||
from kitty.cli_stub import BroadcastCLIOptions
|
||||
@@ -20,7 +20,7 @@ from ..tui.loop import Loop
|
||||
from ..tui.operations import RESTORE_CURSOR, SAVE_CURSOR, styled
|
||||
|
||||
|
||||
def session_command(payload: Dict[str, Any], start: bool = True) -> bytes:
|
||||
def session_command(payload: dict[str, Any], start: bool = True) -> bytes:
|
||||
payload = payload.copy()
|
||||
payload['data'] = 'session:' + ('start' if start else 'end')
|
||||
send = create_basic_command('send-text', payload, no_response=True)
|
||||
@@ -29,7 +29,7 @@ def session_command(payload: Dict[str, Any], start: bool = True) -> bytes:
|
||||
|
||||
class Broadcast(Handler):
|
||||
|
||||
def __init__(self, opts: BroadcastCLIOptions, initial_strings: List[str]) -> None:
|
||||
def __init__(self, opts: BroadcastCLIOptions, initial_strings: list[str]) -> None:
|
||||
self.opts = opts
|
||||
self.hide_input = False
|
||||
self.initial_strings = initial_strings
|
||||
@@ -128,11 +128,11 @@ help_text = 'Broadcast typed text to kitty windows. By default text is sent to a
|
||||
usage = '[initial text to send ...]'
|
||||
|
||||
|
||||
def parse_broadcast_args(args: List[str]) -> Tuple[BroadcastCLIOptions, List[str]]:
|
||||
def parse_broadcast_args(args: list[str]) -> tuple[BroadcastCLIOptions, list[str]]:
|
||||
return parse_args(args, OPTIONS, usage, help_text, 'kitty +kitten broadcast', result_class=BroadcastCLIOptions)
|
||||
|
||||
|
||||
def main(args: List[str]) -> Optional[Dict[str, Any]]:
|
||||
def main(args: list[str]) -> dict[str, Any] | None:
|
||||
try:
|
||||
opts, items = parse_broadcast_args(args[1:])
|
||||
except SystemExit as e:
|
||||
|
||||
@@ -6,7 +6,7 @@ import os
|
||||
import string
|
||||
import sys
|
||||
import tempfile
|
||||
from typing import TYPE_CHECKING, Any, Dict, Literal, Optional, Tuple, TypedDict
|
||||
from typing import TYPE_CHECKING, Any, Literal, Optional, TypedDict
|
||||
|
||||
from kitty.cli import create_default_opts
|
||||
from kitty.conf.utils import to_color
|
||||
@@ -67,10 +67,10 @@ class TextStyle(TypedDict):
|
||||
|
||||
|
||||
OptNames = Literal['font_family', 'bold_font', 'italic_font', 'bold_italic_font']
|
||||
FamilyKey = Tuple[OptNames, ...]
|
||||
FamilyKey = tuple[OptNames, ...]
|
||||
|
||||
|
||||
def opts_from_cmd(cmd: Dict[str, Any]) -> Tuple[Options, FamilyKey, float, float]:
|
||||
def opts_from_cmd(cmd: dict[str, Any]) -> tuple[Options, FamilyKey, float, float]:
|
||||
opts = Options()
|
||||
ts: TextStyle = cmd['text_style']
|
||||
opts.font_size = ts['font_size']
|
||||
@@ -88,10 +88,10 @@ def opts_from_cmd(cmd: Dict[str, Any]) -> Tuple[Options, FamilyKey, float, float
|
||||
return opts, tuple(family_key), ts['dpi_x'], ts['dpi_y']
|
||||
|
||||
|
||||
BaseKey = Tuple[str, int, int]
|
||||
FaceKey = Tuple[str, BaseKey]
|
||||
RenderedSample = Tuple[bytes, Dict[str, Any]]
|
||||
RenderedSampleTransmit = Dict[str, Any]
|
||||
BaseKey = tuple[str, int, int]
|
||||
FaceKey = tuple[str, BaseKey]
|
||||
RenderedSample = tuple[bytes, dict[str, Any]]
|
||||
RenderedSampleTransmit = dict[str, Any]
|
||||
SAMPLE_TEXT = string.ascii_lowercase + ' ' + string.digits + ' ' + string.ascii_uppercase + ' ' + string.punctuation
|
||||
|
||||
|
||||
@@ -100,11 +100,11 @@ class FD(TypedDict):
|
||||
name: NotRequired[str]
|
||||
tooltip: NotRequired[str]
|
||||
sample: NotRequired[str]
|
||||
params: NotRequired[Tuple[str, ...]]
|
||||
params: NotRequired[tuple[str, ...]]
|
||||
|
||||
|
||||
|
||||
def get_features(features: Dict[str, Optional['FeatureData']]) -> Dict[str, FD]:
|
||||
def get_features(features: dict[str, Optional['FeatureData']]) -> dict[str, FD]:
|
||||
ans = {}
|
||||
for tag, data in features.items():
|
||||
kf = known_features.get(tag)
|
||||
@@ -150,10 +150,10 @@ def render_face_sample(font: Descriptor, opts: Options, dpi_x: float, dpi_y: flo
|
||||
|
||||
def render_family_sample(
|
||||
opts: Options, family_key: FamilyKey, dpi_x: float, dpi_y: float, width: int, height: int, output_dir: str,
|
||||
cache: Dict[FaceKey, RenderedSampleTransmit]
|
||||
) -> Dict[str, RenderedSampleTransmit]:
|
||||
cache: dict[FaceKey, RenderedSampleTransmit]
|
||||
) -> dict[str, RenderedSampleTransmit]:
|
||||
base_key: BaseKey = opts.font_family.created_from_string, width, height
|
||||
ans: Dict[str, RenderedSampleTransmit] = {}
|
||||
ans: dict[str, RenderedSampleTransmit] = {}
|
||||
font_files = get_font_files(opts)
|
||||
for x in family_key:
|
||||
key: FaceKey = x + ': ' + str(getattr(opts, x)), base_key
|
||||
@@ -177,7 +177,7 @@ def render_family_sample(
|
||||
return ans
|
||||
|
||||
|
||||
ResolvedFace = Dict[Literal['family', 'spec', 'setting'], str]
|
||||
ResolvedFace = dict[Literal['family', 'spec', 'setting'], str]
|
||||
|
||||
|
||||
def spec_for_descriptor(d: Descriptor, font_size: float) -> str:
|
||||
@@ -185,9 +185,9 @@ def spec_for_descriptor(d: Descriptor, font_size: float) -> str:
|
||||
return spec_for_face(d['family'], face).as_setting
|
||||
|
||||
|
||||
def resolved_faces(opts: Options) -> Dict[OptNames, ResolvedFace]:
|
||||
def resolved_faces(opts: Options) -> dict[OptNames, ResolvedFace]:
|
||||
font_files = get_font_files(opts)
|
||||
ans: Dict[OptNames, ResolvedFace] = {}
|
||||
ans: dict[OptNames, ResolvedFace] = {}
|
||||
def d(key: Literal['medium', 'bold', 'italic', 'bi'], opt_name: OptNames) -> None:
|
||||
descriptor = font_files[key]
|
||||
ans[opt_name] = {
|
||||
@@ -203,7 +203,7 @@ def resolved_faces(opts: Options) -> Dict[OptNames, ResolvedFace]:
|
||||
|
||||
def main() -> None:
|
||||
setup_debug_print()
|
||||
cache: Dict[FaceKey, RenderedSampleTransmit] = {}
|
||||
cache: dict[FaceKey, RenderedSampleTransmit] = {}
|
||||
for line in sys.stdin.buffer:
|
||||
cmd = json.loads(line)
|
||||
action = cmd.get('action', '')
|
||||
@@ -222,7 +222,7 @@ def main() -> None:
|
||||
raise SystemExit(f'Unknown action: {action}')
|
||||
|
||||
|
||||
def query_kitty() -> Dict[str, str]:
|
||||
def query_kitty() -> dict[str, str]:
|
||||
import subprocess
|
||||
ans = {}
|
||||
for line in subprocess.check_output([kitten_exe(), 'query-terminal']).decode().splitlines():
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
from typing import Dict
|
||||
|
||||
|
||||
def syntax_aliases(x: str) -> Dict[str, str]:
|
||||
def syntax_aliases(x: str) -> dict[str, str]:
|
||||
ans = {}
|
||||
for x in x.split():
|
||||
k, _, v = x.partition(':')
|
||||
|
||||
@@ -3,14 +3,13 @@
|
||||
|
||||
import sys
|
||||
from functools import partial
|
||||
from typing import List
|
||||
|
||||
from kitty.cli import CONFIG_HELP, CompletionSpec
|
||||
from kitty.conf.types import Definition
|
||||
from kitty.constants import appname
|
||||
|
||||
|
||||
def main(args: List[str]) -> None:
|
||||
def main(args: list[str]) -> None:
|
||||
raise SystemExit('Must be run as kitten diff')
|
||||
|
||||
definition = Definition(
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import sys
|
||||
from collections.abc import Sequence
|
||||
from functools import lru_cache
|
||||
from typing import Any, Dict, List, Optional, Sequence, Tuple
|
||||
from typing import Any
|
||||
|
||||
from kitty.cli_stub import HintsCLIOptions
|
||||
from kitty.clipboard import set_clipboard_string, set_primary_selection
|
||||
@@ -37,7 +38,7 @@ class Mark:
|
||||
text: str,
|
||||
groupdict: Any,
|
||||
is_hyperlink: bool = False,
|
||||
group_id: Optional[str] = None
|
||||
group_id: str | None = None
|
||||
):
|
||||
self.index, self.start, self.end = index, start, end
|
||||
self.text = text
|
||||
@@ -45,7 +46,7 @@ class Mark:
|
||||
self.is_hyperlink = is_hyperlink
|
||||
self.group_id = group_id
|
||||
|
||||
def as_dict(self) -> Dict[str, Any]:
|
||||
def as_dict(self) -> dict[str, Any]:
|
||||
return {
|
||||
'index': self.index, 'start': self.start, 'end': self.end,
|
||||
'text': self.text, 'groupdict': {str(k):v for k, v in (self.groupdict or {}).items()},
|
||||
@@ -53,7 +54,7 @@ class Mark:
|
||||
}
|
||||
|
||||
|
||||
def parse_hints_args(args: List[str]) -> Tuple[HintsCLIOptions, List[str]]:
|
||||
def parse_hints_args(args: list[str]) -> tuple[HintsCLIOptions, list[str]]:
|
||||
from kitty.cli import parse_args
|
||||
return parse_args(args, OPTIONS, usage, help_text, 'kitty +kitten hints', result_class=HintsCLIOptions)
|
||||
|
||||
@@ -255,11 +256,11 @@ help_text = 'Select text from the screen using the keyboard. Defaults to searchi
|
||||
usage = ''
|
||||
|
||||
|
||||
def main(args: List[str]) -> Optional[Dict[str, Any]]:
|
||||
def main(args: list[str]) -> dict[str, Any] | None:
|
||||
raise SystemExit('Should be run as kitten hints')
|
||||
|
||||
|
||||
def linenum_process_result(data: Dict[str, Any]) -> Tuple[str, int]:
|
||||
def linenum_process_result(data: dict[str, Any]) -> tuple[str, int]:
|
||||
for match, g in zip(data['match'], data['groupdicts']):
|
||||
path, line = g['path'], g['line']
|
||||
if path and line:
|
||||
@@ -267,7 +268,7 @@ def linenum_process_result(data: Dict[str, Any]) -> Tuple[str, int]:
|
||||
return '', -1
|
||||
|
||||
|
||||
def linenum_handle_result(args: List[str], data: Dict[str, Any], target_window_id: int, boss: BossType, extra_cli_args: Sequence[str], *a: Any) -> None:
|
||||
def linenum_handle_result(args: list[str], data: dict[str, Any], target_window_id: int, boss: BossType, extra_cli_args: Sequence[str], *a: Any) -> None:
|
||||
path, line = linenum_process_result(data)
|
||||
if not path:
|
||||
return
|
||||
@@ -301,7 +302,7 @@ def linenum_handle_result(args: List[str], data: Dict[str, Any], target_window_i
|
||||
boss.set_clipboard_buffer(program[1:], text)
|
||||
else:
|
||||
import shlex
|
||||
text = ' '.join(shlex.quote(arg) for arg in cmd)
|
||||
text = shlex.join(cmd)
|
||||
w.paste_bytes(f'{text}\r')
|
||||
elif action == 'background':
|
||||
import subprocess
|
||||
@@ -320,7 +321,7 @@ def on_mark_clicked(boss: BossType, window: WindowType, url: str, hyperlink_id:
|
||||
|
||||
|
||||
@result_handler(type_of_input='screen-ansi', has_ready_notification=True, open_url_handler=on_mark_clicked)
|
||||
def handle_result(args: List[str], data: Dict[str, Any], target_window_id: int, boss: BossType) -> None:
|
||||
def handle_result(args: list[str], data: dict[str, Any], target_window_id: int, boss: BossType) -> None:
|
||||
cp = data['customize_processing']
|
||||
if data['type'] == 'linenum':
|
||||
cp = '::linenum::'
|
||||
@@ -331,7 +332,7 @@ def handle_result(args: List[str], data: Dict[str, Any], target_window_id: int,
|
||||
return None
|
||||
|
||||
programs = data['programs'] or ('default',)
|
||||
matches: List[str] = []
|
||||
matches: list[str] = []
|
||||
groupdicts = []
|
||||
for m, g in zip(data['match'], data['groupdicts']):
|
||||
if m:
|
||||
@@ -339,12 +340,12 @@ def handle_result(args: List[str], data: Dict[str, Any], target_window_id: int,
|
||||
groupdicts.append(g)
|
||||
joiner = data['multiple_joiner']
|
||||
try:
|
||||
is_int: Optional[int] = int(joiner)
|
||||
is_int: int | None = int(joiner)
|
||||
except Exception:
|
||||
is_int = None
|
||||
text_type = data['type']
|
||||
|
||||
@lru_cache()
|
||||
@lru_cache
|
||||
def joined_text() -> str:
|
||||
if is_int is not None:
|
||||
try:
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
|
||||
import sys
|
||||
from typing import List
|
||||
|
||||
from kitty.cli import CompletionSpec
|
||||
|
||||
@@ -27,7 +26,7 @@ and STDIN is not a TTY, it is used.
|
||||
usage = '[filename]'
|
||||
|
||||
|
||||
def main(args: List[str]) -> None:
|
||||
def main(args: list[str]) -> None:
|
||||
raise SystemExit('Must be run as kitten pager')
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import sys
|
||||
from typing import Any, Callable, Dict, List, Tuple
|
||||
from collections.abc import Callable
|
||||
from typing import Any
|
||||
|
||||
from kitty.cli import parse_args
|
||||
from kitty.cli_stub import PanelCLIOptions
|
||||
@@ -152,11 +153,11 @@ help_text = 'Use a command line program to draw a GPU accelerated panel on your
|
||||
usage = 'program-to-run'
|
||||
|
||||
|
||||
def parse_panel_args(args: List[str]) -> Tuple[PanelCLIOptions, List[str]]:
|
||||
def parse_panel_args(args: list[str]) -> tuple[PanelCLIOptions, list[str]]:
|
||||
return parse_args(args, OPTIONS, usage, help_text, 'kitty +kitten panel', result_class=PanelCLIOptions)
|
||||
|
||||
|
||||
Strut = Tuple[int, int, int, int, int, int, int, int, int, int, int, int]
|
||||
Strut = tuple[int, int, int, int, int, int, int, int, int, int, int, int]
|
||||
|
||||
|
||||
def create_strut(
|
||||
@@ -195,12 +196,12 @@ def setup_x11_window(win_id: int) -> None:
|
||||
make_x11_window_a_dock_window(win_id, strut)
|
||||
|
||||
|
||||
def initial_window_size_func(opts: WindowSizeData, cached_values: Dict[str, Any]) -> Callable[[int, int, float, float, float, float], Tuple[int, int]]:
|
||||
def initial_window_size_func(opts: WindowSizeData, cached_values: dict[str, Any]) -> Callable[[int, int, float, float, float, float], tuple[int, int]]:
|
||||
|
||||
def es(which: EdgeLiteral) -> float:
|
||||
return edge_spacing(which, opts)
|
||||
|
||||
def initial_window_size(cell_width: int, cell_height: int, dpi_x: float, dpi_y: float, xscale: float, yscale: float) -> Tuple[int, int]:
|
||||
def initial_window_size(cell_width: int, cell_height: int, dpi_x: float, dpi_y: float, xscale: float, yscale: float) -> tuple[int, int]:
|
||||
if not is_macos and not is_wayland():
|
||||
# Not sure what the deal with scaling on X11 is
|
||||
xscale = yscale = 1
|
||||
@@ -248,7 +249,7 @@ def layer_shell_config(opts: PanelCLIOptions) -> LayerShellConfig:
|
||||
output_name=opts.output_name or '')
|
||||
|
||||
|
||||
def main(sys_args: List[str]) -> None:
|
||||
def main(sys_args: list[str]) -> None:
|
||||
global args
|
||||
if is_macos:
|
||||
raise SystemExit('Currently the panel kitten is not supported on macOS')
|
||||
|
||||
@@ -5,7 +5,7 @@ import re
|
||||
import sys
|
||||
from binascii import hexlify, unhexlify
|
||||
from contextlib import suppress
|
||||
from typing import Dict, Optional, Type, get_args
|
||||
from typing import get_args
|
||||
|
||||
from kitty.conf.utils import OSNames, os_name
|
||||
from kitty.constants import appname, str_version
|
||||
@@ -52,10 +52,10 @@ class Query:
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
all_queries: Dict[str, Type[Query]] = {}
|
||||
all_queries: dict[str, type[Query]] = {}
|
||||
|
||||
|
||||
def query(cls: Type[Query]) -> Type[Query]:
|
||||
def query(cls: type[Query]) -> type[Query]:
|
||||
all_queries[cls.name] = cls
|
||||
return cls
|
||||
|
||||
@@ -237,7 +237,7 @@ class OSName(Query):
|
||||
return os_name()
|
||||
|
||||
|
||||
def get_result(name: str, window_id: int, os_window_id: int) -> Optional[str]:
|
||||
def get_result(name: str, window_id: int, os_window_id: int) -> str | None:
|
||||
from kitty.fast_data_types import get_options
|
||||
q = all_queries.get(name)
|
||||
if q is None:
|
||||
|
||||
@@ -10,7 +10,7 @@ import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
from typing import Any, List, Optional
|
||||
from typing import Any, Optional
|
||||
|
||||
from kitty.cli import parse_args
|
||||
from kitty.cli_stub import RemoteFileCLIOptions
|
||||
@@ -129,7 +129,7 @@ class ControlMaster:
|
||||
cmd.extend(['-i', conn_data.identity_file])
|
||||
self.batch_cmd_prefix = cmd + ['-o', 'BatchMode=yes']
|
||||
|
||||
def check_call(self, cmd: List[str]) -> None:
|
||||
def check_call(self, cmd: list[str]) -> None:
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.DEVNULL)
|
||||
stdout = p.communicate()[0]
|
||||
if p.wait() != 0:
|
||||
@@ -228,7 +228,7 @@ class ControlMaster:
|
||||
Result = Optional[str]
|
||||
|
||||
|
||||
def main(args: List[str]) -> Result:
|
||||
def main(args: list[str]) -> Result:
|
||||
msg = 'Ask the user what to do with the remote file. For internal use by kitty, do not run it directly.'
|
||||
try:
|
||||
cli_opts, items = parse_args(args[1:], option_text, '', msg, 'kitty +kitten remote_file', result_class=RemoteFileCLIOptions)
|
||||
@@ -355,7 +355,7 @@ def handle_action(action: str, cli_opts: RemoteFileCLIOptions) -> Result:
|
||||
|
||||
|
||||
@result_handler()
|
||||
def handle_result(args: List[str], data: Result, target_window_id: int, boss: BossType) -> None:
|
||||
def handle_result(args: list[str], data: Result, target_window_id: int, boss: BossType) -> None:
|
||||
if data:
|
||||
from kitty.fast_data_types import get_options
|
||||
cmd = command_for_open(get_options().open_url_with)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
|
||||
import sys
|
||||
from typing import Any, Dict, List, Optional
|
||||
from typing import Any
|
||||
|
||||
from kitty.cli import parse_args
|
||||
from kitty.cli_stub import RCOptions, ResizeCLIOptions
|
||||
@@ -22,7 +22,7 @@ global_opts = RCOptions()
|
||||
|
||||
class Resize(Handler):
|
||||
|
||||
print_on_fail: Optional[str] = None
|
||||
print_on_fail: str | None = None
|
||||
|
||||
def __init__(self, opts: ResizeCLIOptions):
|
||||
self.opts = opts
|
||||
@@ -48,7 +48,7 @@ class Resize(Handler):
|
||||
send = {'cmd': resize_window.name, 'version': version, 'payload': payload, 'no_response': False}
|
||||
self.write(encode_send(send))
|
||||
|
||||
def on_kitty_cmd_response(self, response: Dict[str, Any]) -> None:
|
||||
def on_kitty_cmd_response(self, response: dict[str, Any]) -> None:
|
||||
if not response.get('ok'):
|
||||
err = response['error']
|
||||
if response.get('tb'):
|
||||
@@ -114,7 +114,7 @@ The base vertical increment.
|
||||
'''.format
|
||||
|
||||
|
||||
def main(args: List[str]) -> None:
|
||||
def main(args: list[str]) -> None:
|
||||
msg = 'Resize the current window'
|
||||
try:
|
||||
cli_opts, items = parse_args(args[1:], OPTIONS, '', msg, 'resize_window', result_class=ResizeCLIOptions)
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
import importlib
|
||||
import os
|
||||
import sys
|
||||
from collections.abc import Callable, Generator
|
||||
from contextlib import contextmanager
|
||||
from functools import partial
|
||||
from typing import TYPE_CHECKING, Any, Callable, Dict, FrozenSet, Generator, List, NamedTuple, Optional, Union, cast
|
||||
from typing import TYPE_CHECKING, Any, NamedTuple, cast
|
||||
|
||||
from kitty.constants import list_kitty_resources
|
||||
from kitty.types import run_once
|
||||
@@ -49,7 +50,7 @@ class CLIOnlyKitten(TypeError):
|
||||
super().__init__(f'The {kitten} kitten must be run only at the commandline, as: kitten {kitten}')
|
||||
|
||||
|
||||
def import_kitten_main_module(config_dir: str, kitten: str) -> Dict[str, Any]:
|
||||
def import_kitten_main_module(config_dir: str, kitten: str) -> dict[str, Any]:
|
||||
if kitten.endswith('.py'):
|
||||
with preserve_sys_path():
|
||||
path = path_to_custom_kitten(config_dir, kitten)
|
||||
@@ -76,15 +77,15 @@ def import_kitten_main_module(config_dir: str, kitten: str) -> Dict[str, Any]:
|
||||
class KittenMetadata(NamedTuple):
|
||||
handle_result: Callable[[Any, int, BossType], None] = lambda *a: None
|
||||
|
||||
type_of_input: Optional[str] = None
|
||||
type_of_input: str | None = None
|
||||
no_ui: bool = False
|
||||
has_ready_notification: bool = False
|
||||
open_url_handler: Optional[Callable[[BossType, WindowType, str, int, str], bool]] = None
|
||||
open_url_handler: Callable[[BossType, WindowType, str, int, str], bool] | None = None
|
||||
allow_remote_control: bool = False
|
||||
remote_control_password: Union[str, bool] = False
|
||||
remote_control_password: str | bool = False
|
||||
|
||||
|
||||
def create_kitten_handler(kitten: str, orig_args: List[str]) -> KittenMetadata:
|
||||
def create_kitten_handler(kitten: str, orig_args: list[str]) -> KittenMetadata:
|
||||
from kitty.constants import config_dir
|
||||
kitten = resolved_kitten(kitten)
|
||||
m = import_kitten_main_module(config_dir, kitten)
|
||||
@@ -107,7 +108,7 @@ def set_debug(kitten: str) -> None:
|
||||
setattr(builtins, 'debug', debug)
|
||||
|
||||
|
||||
def launch(args: List[str]) -> None:
|
||||
def launch(args: list[str]) -> None:
|
||||
config_dir, kitten = args[:2]
|
||||
kitten = resolved_kitten(kitten)
|
||||
del args[:2]
|
||||
@@ -157,7 +158,7 @@ def run_kitten(kitten: str, run_name: str = '__main__') -> None:
|
||||
|
||||
|
||||
@run_once
|
||||
def all_kitten_names() -> FrozenSet[str]:
|
||||
def all_kitten_names() -> frozenset[str]:
|
||||
ans = []
|
||||
for name in list_kitty_resources('kittens'):
|
||||
if '__' not in name and '.' not in name and name != 'tui':
|
||||
@@ -198,7 +199,7 @@ def get_kitten_completer(kitten: str) -> Any:
|
||||
return ans
|
||||
|
||||
|
||||
def get_kitten_conf_docs(kitten: str) -> Optional[Definition]:
|
||||
def get_kitten_conf_docs(kitten: str) -> Definition | None:
|
||||
setattr(sys, 'options_definition', None)
|
||||
run_kitten(kitten, run_name='__conf__')
|
||||
ans = getattr(sys, 'options_definition')
|
||||
@@ -206,12 +207,12 @@ def get_kitten_conf_docs(kitten: str) -> Optional[Definition]:
|
||||
return cast(Definition, ans)
|
||||
|
||||
|
||||
def get_kitten_extra_cli_parsers(kitten: str) -> Dict[str,str]:
|
||||
def get_kitten_extra_cli_parsers(kitten: str) -> dict[str,str]:
|
||||
setattr(sys, 'extra_cli_parsers', {})
|
||||
run_kitten(kitten, run_name='__extra_cli_parsers__')
|
||||
ans = getattr(sys, 'extra_cli_parsers')
|
||||
delattr(sys, 'extra_cli_parsers')
|
||||
return cast(Dict[str, str], ans)
|
||||
return cast(dict[str, str], ans)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
|
||||
import sys
|
||||
from typing import List
|
||||
|
||||
OPTIONS = r'''
|
||||
--key-mode -m
|
||||
@@ -18,7 +17,7 @@ help_text = 'Show the codes generated by the terminal for key presses in various
|
||||
usage = ''
|
||||
|
||||
|
||||
def main(args: List[str]) -> None:
|
||||
def main(args: list[str]) -> None:
|
||||
raise SystemExit('This should be reun as kitten show_key')
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import sys
|
||||
from typing import List, Optional
|
||||
|
||||
from kitty.conf.types import Definition
|
||||
from kitty.types import run_once
|
||||
@@ -222,7 +221,7 @@ environment variable.
|
||||
egr() # }}}
|
||||
|
||||
|
||||
def main(args: List[str]) -> Optional[str]:
|
||||
def main(args: list[str]) -> str | None:
|
||||
raise SystemExit('This should be run as kitten ssh')
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -5,15 +5,16 @@
|
||||
import os
|
||||
import subprocess
|
||||
import traceback
|
||||
from collections.abc import Iterator, Sequence
|
||||
from contextlib import suppress
|
||||
from typing import Any, Dict, Iterator, List, Optional, Sequence, Set, Tuple
|
||||
from typing import Any
|
||||
|
||||
from kitty.types import run_once
|
||||
from kitty.utils import SSHConnectionData
|
||||
|
||||
|
||||
@run_once
|
||||
def ssh_options() -> Dict[str, str]:
|
||||
def ssh_options() -> dict[str, str]:
|
||||
try:
|
||||
p = subprocess.run(['ssh'], stderr=subprocess.PIPE, encoding='utf-8')
|
||||
raw = p.stderr or ''
|
||||
@@ -28,7 +29,7 @@ def ssh_options() -> Dict[str, str]:
|
||||
'S': 'ctl_path', 'W': 'host:port', 'w': 'local_tun[:remote_tun]'
|
||||
}
|
||||
|
||||
ans: Dict[str, str] = {}
|
||||
ans: dict[str, str] = {}
|
||||
pos = 0
|
||||
while True:
|
||||
pos = raw.find('[', pos)
|
||||
@@ -68,7 +69,7 @@ def is_kitten_cmdline(q: Sequence[str]) -> bool:
|
||||
return q[1:3] == ['+runpy', 'from kittens.runner import main; main()'] and len(q) >= 6 and q[5] == 'ssh'
|
||||
|
||||
|
||||
def patch_cmdline(key: str, val: str, argv: List[str]) -> None:
|
||||
def patch_cmdline(key: str, val: str, argv: list[str]) -> None:
|
||||
for i, arg in enumerate(tuple(argv)):
|
||||
if arg.startswith(f'--kitten={key}='):
|
||||
argv[i] = f'--kitten={key}={val}'
|
||||
@@ -80,7 +81,7 @@ def patch_cmdline(key: str, val: str, argv: List[str]) -> None:
|
||||
argv.insert(idx + 1, f'--kitten={key}={val}')
|
||||
|
||||
|
||||
def set_cwd_in_cmdline(cwd: str, argv: List[str]) -> None:
|
||||
def set_cwd_in_cmdline(cwd: str, argv: list[str]) -> None:
|
||||
patch_cmdline('cwd', cwd, argv)
|
||||
|
||||
|
||||
@@ -135,7 +136,7 @@ def get_ssh_data(msgb: memoryview, request_id: str) -> Iterator[bytes]:
|
||||
raise ValueError(f'Incorrect request id: {rq_id!r} expecting the KITTY_PID-KITTY_WINDOW_ID for the current kitty window')
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
yield f'{e}\n'.encode('utf-8')
|
||||
yield f'{e}\n'.encode()
|
||||
else:
|
||||
yield b'OK\n'
|
||||
encoded_data = memoryview(env_data['tarfile'].encode('ascii'))
|
||||
@@ -150,7 +151,7 @@ def get_ssh_data(msgb: memoryview, request_id: str) -> Iterator[bytes]:
|
||||
yield b'KITTY_DATA_END\n'
|
||||
|
||||
|
||||
def set_env_in_cmdline(env: Dict[str, str], argv: List[str], clone: bool = True) -> None:
|
||||
def set_env_in_cmdline(env: dict[str, str], argv: list[str], clone: bool = True) -> None:
|
||||
from kitty.options.utils import DELETE_ENV_VAR
|
||||
if clone:
|
||||
patch_cmdline('clone_env', create_shared_memory(env, 'ksse-'), argv)
|
||||
@@ -171,9 +172,9 @@ def set_env_in_cmdline(env: Dict[str, str], argv: List[str], clone: bool = True)
|
||||
argv[idx+1:idx+1] = env_dirs
|
||||
|
||||
|
||||
def get_ssh_cli() -> Tuple[Set[str], Set[str]]:
|
||||
other_ssh_args: Set[str] = set()
|
||||
boolean_ssh_args: Set[str] = set()
|
||||
def get_ssh_cli() -> tuple[set[str], set[str]]:
|
||||
other_ssh_args: set[str] = set()
|
||||
boolean_ssh_args: set[str] = set()
|
||||
for k, v in ssh_options().items():
|
||||
k = f'-{k}'
|
||||
if v:
|
||||
@@ -183,7 +184,7 @@ def get_ssh_cli() -> Tuple[Set[str], Set[str]]:
|
||||
return boolean_ssh_args, other_ssh_args
|
||||
|
||||
|
||||
def is_extra_arg(arg: str, extra_args: Tuple[str, ...]) -> str:
|
||||
def is_extra_arg(arg: str, extra_args: tuple[str, ...]) -> str:
|
||||
for x in extra_args:
|
||||
if arg == x or arg.startswith(f'{x}='):
|
||||
return x
|
||||
@@ -194,14 +195,14 @@ passthrough_args = {f'-{x}' for x in 'NnfGT'}
|
||||
|
||||
|
||||
def set_server_args_in_cmdline(
|
||||
server_args: List[str], argv: List[str],
|
||||
extra_args: Tuple[str, ...] = ('--kitten',),
|
||||
server_args: list[str], argv: list[str],
|
||||
extra_args: tuple[str, ...] = ('--kitten',),
|
||||
allocate_tty: bool = False
|
||||
) -> None:
|
||||
boolean_ssh_args, other_ssh_args = get_ssh_cli()
|
||||
ssh_args = []
|
||||
expecting_option_val = False
|
||||
found_extra_args: List[str] = []
|
||||
found_extra_args: list[str] = []
|
||||
expecting_extra_val = ''
|
||||
ans = list(argv)
|
||||
found_ssh = False
|
||||
@@ -257,15 +258,15 @@ def set_server_args_in_cmdline(
|
||||
argv[:] = ans + server_args
|
||||
|
||||
|
||||
def get_connection_data(args: List[str], cwd: str = '', extra_args: Tuple[str, ...] = ()) -> Optional[SSHConnectionData]:
|
||||
def get_connection_data(args: list[str], cwd: str = '', extra_args: tuple[str, ...] = ()) -> SSHConnectionData | None:
|
||||
boolean_ssh_args, other_ssh_args = get_ssh_cli()
|
||||
port: Optional[int] = None
|
||||
port: int | None = None
|
||||
expecting_port = expecting_identity = False
|
||||
expecting_option_val = False
|
||||
expecting_hostname = False
|
||||
expecting_extra_val = ''
|
||||
host_name = identity_file = found_ssh = ''
|
||||
found_extra_args: List[Tuple[str, str]] = []
|
||||
found_extra_args: list[tuple[str, str]] = []
|
||||
|
||||
for i, arg in enumerate(args):
|
||||
if not found_ssh:
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import sys
|
||||
from typing import List
|
||||
|
||||
from kitty.cli import CompletionSpec
|
||||
|
||||
@@ -46,7 +45,7 @@ to your kitty.conf and then have the kitten operate only on :file:`themes.conf`,
|
||||
allowing :code:`kitty.conf` to remain unchanged.
|
||||
'''.format
|
||||
|
||||
def main(args: List[str]) -> None:
|
||||
def main(args: list[str]) -> None:
|
||||
raise SystemExit('This must be run as kitten themes')
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
|
||||
import sys
|
||||
from typing import List
|
||||
|
||||
usage = 'source_files_or_directories destination_path'
|
||||
help_text = '''\
|
||||
@@ -121,7 +120,7 @@ actually degrade performance on fast links or with small files, so use with care
|
||||
'''
|
||||
|
||||
|
||||
def main(args: List[str]) -> None:
|
||||
def main(args: list[str]) -> None:
|
||||
raise SystemExit('This should be run as kitten transfer')
|
||||
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import os
|
||||
from collections.abc import Generator
|
||||
from contextlib import contextmanager
|
||||
from typing import Generator
|
||||
|
||||
_cwd = _home = ''
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
import os
|
||||
import stat
|
||||
from collections.abc import Generator
|
||||
from contextlib import suppress
|
||||
from typing import Dict, Generator, Optional, Tuple, Union
|
||||
|
||||
DEFAULT_DIRCOLORS = r"""# {{{
|
||||
# Configuration file for dircolors, a utility to help you set the
|
||||
@@ -236,8 +236,8 @@ CODE_MAP = {
|
||||
}
|
||||
|
||||
|
||||
def stat_at(file: str, cwd: Optional[Union[int, str]] = None, follow_symlinks: bool = False) -> os.stat_result:
|
||||
dirfd: Optional[int] = None
|
||||
def stat_at(file: str, cwd: int | str | None = None, follow_symlinks: bool = False) -> os.stat_result:
|
||||
dirfd: int | None = None
|
||||
need_to_close = False
|
||||
if isinstance(cwd, str):
|
||||
dirfd = os.open(cwd, os.O_RDONLY | getattr(os, 'O_CLOEXEC', 0))
|
||||
@@ -255,8 +255,8 @@ def stat_at(file: str, cwd: Optional[Union[int, str]] = None, follow_symlinks: b
|
||||
class Dircolors:
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.codes: Dict[str, str] = {}
|
||||
self.extensions: Dict[str, str] = {}
|
||||
self.codes: dict[str, str] = {}
|
||||
self.extensions: dict[str, str] = {}
|
||||
if not self.load_from_environ() and not self.load_from_file():
|
||||
self.load_defaults()
|
||||
|
||||
@@ -324,7 +324,7 @@ class Dircolors:
|
||||
def generate_lscolors(self) -> str:
|
||||
""" Output the database in the format used by the LS_COLORS environment variable. """
|
||||
|
||||
def gen_pairs() -> Generator[Tuple[str, str], None, None]:
|
||||
def gen_pairs() -> Generator[tuple[str, str], None, None]:
|
||||
for pair in self.codes.items():
|
||||
yield pair
|
||||
for pair in self.extensions.items():
|
||||
@@ -370,7 +370,7 @@ class Dircolors:
|
||||
return self._format_ext(text, ext)
|
||||
return text
|
||||
|
||||
def __call__(self, path: str, text: str, cwd: Optional[Union[int, str]] = None) -> str:
|
||||
def __call__(self, path: str, text: str, cwd: int | str | None = None) -> str:
|
||||
follow_symlinks = self.codes.get('ln') == 'target'
|
||||
try:
|
||||
sr = stat_at(path, cwd, follow_symlinks)
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
|
||||
import os
|
||||
from collections import deque
|
||||
from collections.abc import Callable, Sequence
|
||||
from contextlib import suppress
|
||||
from types import TracebackType
|
||||
from typing import TYPE_CHECKING, Any, Callable, ContextManager, Deque, Dict, NamedTuple, Optional, Sequence, Type, Union, cast
|
||||
from typing import TYPE_CHECKING, Any, ContextManager, Deque, NamedTuple, Optional, cast
|
||||
|
||||
from kitty.constants import kitten_exe, running_in_kitty
|
||||
from kitty.fast_data_types import monotonic, safe_pipe
|
||||
@@ -51,9 +52,9 @@ def is_click(a: ButtonEvent, b: ButtonEvent) -> bool:
|
||||
|
||||
class KittenUI:
|
||||
allow_remote_control: bool = False
|
||||
remote_control_password: Union[bool, str] = False
|
||||
remote_control_password: bool | str = False
|
||||
|
||||
def __init__(self, func: Callable[[list[str]], str], allow_remote_control: bool, remote_control_password: Union[bool, str]):
|
||||
def __init__(self, func: Callable[[list[str]], str], allow_remote_control: bool, remote_control_password: bool | str):
|
||||
self.func = func
|
||||
self.allow_remote_control = allow_remote_control
|
||||
self.remote_control_password = remote_control_password
|
||||
@@ -94,7 +95,7 @@ class KittenUI:
|
||||
if self.password:
|
||||
os.environ.pop('KITTY_RC_PASSWORD', None)
|
||||
|
||||
def remote_control(self, cmd: Union[str, Sequence[str]], **kw: Any) -> Any:
|
||||
def remote_control(self, cmd: str | Sequence[str], **kw: Any) -> Any:
|
||||
if not self.allow_remote_control:
|
||||
raise ValueError('Remote control is not enabled, remember to use allow_remote_control=True')
|
||||
prefix = [kitten_exe(), '@']
|
||||
@@ -132,7 +133,7 @@ class KittenUI:
|
||||
|
||||
def kitten_ui(
|
||||
allow_remote_control: bool = KittenUI.allow_remote_control,
|
||||
remote_control_password: Union[bool, str] = KittenUI.allow_remote_control,
|
||||
remote_control_password: bool | str = KittenUI.allow_remote_control,
|
||||
) -> Callable[[Callable[[list[str]], str]], KittenUI]:
|
||||
|
||||
def wrapper(impl: Callable[..., Any]) -> KittenUI:
|
||||
@@ -143,7 +144,7 @@ def kitten_ui(
|
||||
|
||||
class Handler:
|
||||
|
||||
image_manager_class: Optional[Type[ImageManagerType]] = None
|
||||
image_manager_class: type[ImageManagerType] | None = None
|
||||
use_alternate_screen = True
|
||||
mouse_tracking = MouseTracking.none
|
||||
terminal_io_ended = False
|
||||
@@ -156,7 +157,7 @@ class Handler:
|
||||
schedule_write: Callable[[bytes], None],
|
||||
tui_loop: LoopType,
|
||||
debug: Debug,
|
||||
image_manager: Optional[ImageManagerType] = None
|
||||
image_manager: ImageManagerType | None = None
|
||||
) -> None:
|
||||
from .operations import commander
|
||||
self.screen_size = screen_size
|
||||
@@ -166,7 +167,7 @@ class Handler:
|
||||
self.debug = debug
|
||||
self.cmd = commander(self)
|
||||
self._image_manager = image_manager
|
||||
self._button_events: Dict[MouseButton, Deque[ButtonEvent]] = {}
|
||||
self._button_events: dict[MouseButton, Deque[ButtonEvent]] = {}
|
||||
|
||||
@property
|
||||
def image_manager(self) -> ImageManagerType:
|
||||
@@ -177,15 +178,15 @@ class Handler:
|
||||
def asyncio_loop(self) -> AbstractEventLoop:
|
||||
return self._tui_loop.asyncio_loop
|
||||
|
||||
def add_shortcut(self, action: KeyActionType, spec: Union[str, ParsedShortcut]) -> None:
|
||||
def add_shortcut(self, action: KeyActionType, spec: str | ParsedShortcut) -> None:
|
||||
if not hasattr(self, '_key_shortcuts'):
|
||||
self._key_shortcuts: Dict[ParsedShortcut, KeyActionType] = {}
|
||||
self._key_shortcuts: dict[ParsedShortcut, KeyActionType] = {}
|
||||
if isinstance(spec, str):
|
||||
from kitty.key_encoding import parse_shortcut
|
||||
spec = parse_shortcut(spec)
|
||||
self._key_shortcuts[spec] = action
|
||||
|
||||
def shortcut_action(self, key_event: KeyEventType) -> Optional[KeyActionType]:
|
||||
def shortcut_action(self, key_event: KeyEventType) -> KeyActionType | None:
|
||||
for sc, action in self._key_shortcuts.items():
|
||||
if key_event.matches(sc):
|
||||
return action
|
||||
@@ -213,7 +214,7 @@ class Handler:
|
||||
def on_resize(self, screen_size: ScreenSize) -> None:
|
||||
self.screen_size = screen_size
|
||||
|
||||
def quit_loop(self, return_code: Optional[int] = None) -> None:
|
||||
def quit_loop(self, return_code: int | None = None) -> None:
|
||||
self._tui_loop.quit(return_code)
|
||||
|
||||
def on_term(self) -> None:
|
||||
@@ -278,7 +279,7 @@ class Handler:
|
||||
def on_writing_finished(self) -> None:
|
||||
pass
|
||||
|
||||
def on_kitty_cmd_response(self, response: Dict[str, Any]) -> None:
|
||||
def on_kitty_cmd_response(self, response: dict[str, Any]) -> None:
|
||||
pass
|
||||
|
||||
def on_clipboard_response(self, text: str, from_primary: bool = False) -> None:
|
||||
@@ -290,7 +291,7 @@ class Handler:
|
||||
def on_capability_response(self, name: str, val: str) -> None:
|
||||
pass
|
||||
|
||||
def write(self, data: Union[bytes, str]) -> None:
|
||||
def write(self, data: bytes | str) -> None:
|
||||
if isinstance(data, str):
|
||||
data = data.encode('utf-8')
|
||||
self._schedule_write(data)
|
||||
@@ -318,10 +319,10 @@ class Handler:
|
||||
|
||||
class HandleResult:
|
||||
|
||||
type_of_input: Optional[str] = None
|
||||
type_of_input: str | None = None
|
||||
no_ui: bool = False
|
||||
|
||||
def __init__(self, impl: Callable[..., Any], type_of_input: Optional[str], no_ui: bool, has_ready_notification: bool, open_url_handler: OpenUrlHandler):
|
||||
def __init__(self, impl: Callable[..., Any], type_of_input: str | None, no_ui: bool, has_ready_notification: bool, open_url_handler: OpenUrlHandler):
|
||||
self.impl = impl
|
||||
self.no_ui = no_ui
|
||||
self.type_of_input = type_of_input
|
||||
@@ -334,7 +335,7 @@ class HandleResult:
|
||||
|
||||
|
||||
def result_handler(
|
||||
type_of_input: Optional[str] = None,
|
||||
type_of_input: str | None = None,
|
||||
no_ui: bool = False,
|
||||
has_ready_notification: bool = Handler.overlay_ready_report_needed,
|
||||
open_url_handler: OpenUrlHandler = None,
|
||||
|
||||
@@ -6,10 +6,11 @@ import os
|
||||
import sys
|
||||
from base64 import standard_b64encode
|
||||
from collections import defaultdict, deque
|
||||
from collections.abc import Callable, Iterator, Sequence
|
||||
from contextlib import suppress
|
||||
from enum import IntEnum
|
||||
from itertools import count
|
||||
from typing import Any, Callable, ClassVar, DefaultDict, Deque, Dict, Generic, Iterator, List, Optional, Sequence, Tuple, Type, TypeVar, Union, cast
|
||||
from typing import Any, ClassVar, DefaultDict, Deque, Generic, Optional, TypeVar, Union, cast
|
||||
|
||||
from kitty.conf.utils import positive_float, positive_int
|
||||
from kitty.fast_data_types import create_canvas
|
||||
@@ -49,7 +50,7 @@ class Frame:
|
||||
dispose: Dispose
|
||||
path: str = ''
|
||||
|
||||
def __init__(self, identify_data: Union['Frame', Dict[str, str]]):
|
||||
def __init__(self, identify_data: Union['Frame', dict[str, str]]):
|
||||
if isinstance(identify_data, Frame):
|
||||
for k in Frame.__annotations__:
|
||||
setattr(self, k, getattr(identify_data, k))
|
||||
@@ -78,7 +79,7 @@ class Frame:
|
||||
|
||||
class ImageData:
|
||||
|
||||
def __init__(self, fmt: str, width: int, height: int, mode: str, frames: List[Frame]):
|
||||
def __init__(self, fmt: str, width: int, height: int, mode: str, frames: list[Frame]):
|
||||
self.width, self.height, self.fmt, self.mode = width, height, fmt, mode
|
||||
self.transmit_fmt: GRT_f = (24 if self.mode == 'rgb' else 32)
|
||||
self.frames = frames
|
||||
@@ -291,9 +292,9 @@ def render_as_single_image(
|
||||
path: str, m: ImageData,
|
||||
available_width: int, available_height: int,
|
||||
scale_up: bool,
|
||||
tdir: Optional[str] = None,
|
||||
tdir: str | None = None,
|
||||
remove_alpha: str = '', flip: bool = False, flop: bool = False,
|
||||
) -> Tuple[str, int, int]:
|
||||
) -> tuple[str, int, int]:
|
||||
import tempfile
|
||||
fd, output = tempfile.mkstemp(prefix='tty-graphics-protocol-', suffix=f'.{m.mode}', dir=tdir)
|
||||
os.close(fd)
|
||||
@@ -305,15 +306,15 @@ def render_as_single_image(
|
||||
|
||||
|
||||
def can_display_images() -> bool:
|
||||
ans: Optional[bool] = getattr(can_display_images, 'ans', None)
|
||||
ans: bool | None = getattr(can_display_images, 'ans', None)
|
||||
if ans is None:
|
||||
ans = which('convert') is not None
|
||||
setattr(can_display_images, 'ans', ans)
|
||||
return ans
|
||||
|
||||
|
||||
ImageKey = Tuple[str, int, int]
|
||||
SentImageKey = Tuple[int, int, int]
|
||||
ImageKey = tuple[str, int, int]
|
||||
SentImageKey = tuple[int, int, int]
|
||||
T = TypeVar('T')
|
||||
|
||||
|
||||
@@ -325,7 +326,7 @@ class Alias(Generic[T]):
|
||||
self.name = ''
|
||||
self.defval = defval
|
||||
|
||||
def __get__(self, instance: Optional['GraphicsCommand'], cls: Optional[Type['GraphicsCommand']] = None) -> T:
|
||||
def __get__(self, instance: Optional['GraphicsCommand'], cls: type['GraphicsCommand'] | None = None) -> T:
|
||||
if instance is None:
|
||||
return self.defval
|
||||
return cast(T, instance._actual_values.get(self.name, self.defval))
|
||||
@@ -336,7 +337,7 @@ class Alias(Generic[T]):
|
||||
else:
|
||||
instance._actual_values[self.name] = val
|
||||
|
||||
def __set_name__(self, owner: Type['GraphicsCommand'], name: str) -> None:
|
||||
def __set_name__(self, owner: type['GraphicsCommand'], name: str) -> None:
|
||||
if len(name) == 1:
|
||||
Alias.currently_processing = name
|
||||
self.name = Alias.currently_processing
|
||||
@@ -369,7 +370,7 @@ class GraphicsCommand:
|
||||
d = delete_action = Alias(cast(GRT_d, 'a'))
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._actual_values: Dict[str, Any] = {}
|
||||
self._actual_values: dict[str, Any] = {}
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return self.serialize().decode('ascii').replace('\033', '^]')
|
||||
@@ -379,12 +380,12 @@ class GraphicsCommand:
|
||||
ans._actual_values = self._actual_values.copy()
|
||||
return ans
|
||||
|
||||
def serialize(self, payload: Union[bytes, str] = b'') -> bytes:
|
||||
def serialize(self, payload: bytes | str = b'') -> bytes:
|
||||
items = []
|
||||
for k, val in self._actual_values.items():
|
||||
items.append(f'{k}={val}')
|
||||
|
||||
ans: List[bytes] = []
|
||||
ans: list[bytes] = []
|
||||
w = ans.append
|
||||
w(b'\033_G')
|
||||
w(','.join(items).encode('ascii'))
|
||||
@@ -399,7 +400,7 @@ class GraphicsCommand:
|
||||
def clear(self) -> None:
|
||||
self._actual_values = {}
|
||||
|
||||
def iter_transmission_chunks(self, data: Optional[bytes] = None, level: int = -1, compression_threshold: int = 1024) -> Iterator[bytes]:
|
||||
def iter_transmission_chunks(self, data: bytes | None = None, level: int = -1, compression_threshold: int = 1024) -> Iterator[bytes]:
|
||||
if data is None:
|
||||
yield self.serialize()
|
||||
return
|
||||
@@ -436,16 +437,16 @@ class ImageManager:
|
||||
def __init__(self, handler: HandlerType):
|
||||
self.image_id_counter = count()
|
||||
self.handler = handler
|
||||
self.filesystem_ok: Optional[bool] = None
|
||||
self.image_data: Dict[str, ImageData] = {}
|
||||
self.failed_images: Dict[str, Exception] = {}
|
||||
self.converted_images: Dict[ImageKey, ImageKey] = {}
|
||||
self.sent_images: Dict[ImageKey, int] = {}
|
||||
self.image_id_to_image_data: Dict[int, ImageData] = {}
|
||||
self.image_id_to_converted_data: Dict[int, ImageKey] = {}
|
||||
self.transmission_status: Dict[int, Union[str, int]] = {}
|
||||
self.filesystem_ok: bool | None = None
|
||||
self.image_data: dict[str, ImageData] = {}
|
||||
self.failed_images: dict[str, Exception] = {}
|
||||
self.converted_images: dict[ImageKey, ImageKey] = {}
|
||||
self.sent_images: dict[ImageKey, int] = {}
|
||||
self.image_id_to_image_data: dict[int, ImageData] = {}
|
||||
self.image_id_to_converted_data: dict[int, ImageKey] = {}
|
||||
self.transmission_status: dict[int, str | int] = {}
|
||||
self.placements_in_flight: DefaultDict[int, Deque[Placement]] = defaultdict(deque)
|
||||
self.update_image_placement_for_resend: Optional[Callable[[int, Placement], bool]]
|
||||
self.update_image_placement_for_resend: Callable[[int, Placement], bool] | None
|
||||
|
||||
@property
|
||||
def next_image_id(self) -> int:
|
||||
@@ -518,7 +519,7 @@ class ImageManager:
|
||||
self.handler.cmd.set_cursor_position(pl.x, pl.y)
|
||||
self.handler.cmd.gr_command(pl.cmd)
|
||||
|
||||
def send_image(self, path: str, max_cols: Optional[int] = None, max_rows: Optional[int] = None, scale_up: bool = False) -> SentImageKey:
|
||||
def send_image(self, path: str, max_cols: int | None = None, max_rows: int | None = None, scale_up: bool = False) -> SentImageKey:
|
||||
path = os.path.abspath(path)
|
||||
if path in self.failed_images:
|
||||
raise self.failed_images[path]
|
||||
@@ -562,7 +563,7 @@ class ImageManager:
|
||||
gc.i = image_id
|
||||
self.handler.cmd.gr_command(gc)
|
||||
|
||||
def show_image(self, image_id: int, x: int, y: int, src_rect: Optional[Tuple[int, int, int, int]] = None) -> None:
|
||||
def show_image(self, image_id: int, x: int, y: int, src_rect: tuple[int, int, int, int] | None = None) -> None:
|
||||
gc = GraphicsCommand()
|
||||
gc.a = 'p'
|
||||
gc.i = image_id
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
from typing import Callable, Tuple
|
||||
from collections.abc import Callable
|
||||
|
||||
from kitty.fast_data_types import truncate_point_for_length, wcswidth
|
||||
from kitty.key_encoding import EventType, KeyEvent
|
||||
@@ -20,7 +20,7 @@ class LineEdit:
|
||||
self.cursor_pos = 0
|
||||
self.pending_bell = False
|
||||
|
||||
def split_at_cursor(self, delta: int = 0) -> Tuple[str, str]:
|
||||
def split_at_cursor(self, delta: int = 0) -> tuple[str, str]:
|
||||
pos = max(0, self.cursor_pos + delta)
|
||||
x = truncate_point_for_length(self.current_input, pos) if pos else 0
|
||||
before, after = self.current_input[:x], self.current_input[x:]
|
||||
|
||||
@@ -10,10 +10,11 @@ import selectors
|
||||
import signal
|
||||
import sys
|
||||
import termios
|
||||
from collections.abc import Callable, Generator
|
||||
from contextlib import contextmanager, suppress
|
||||
from enum import Enum, IntFlag, auto
|
||||
from functools import partial
|
||||
from typing import Any, Callable, Dict, Generator, List, NamedTuple, Optional
|
||||
from typing import Any, NamedTuple
|
||||
|
||||
from kitty.constants import is_macos
|
||||
from kitty.fast_data_types import FILE_TRANSFER_CODE, close_tty, normal_tty, open_tty, parse_input_from_terminal, raw_tty
|
||||
@@ -50,7 +51,7 @@ def debug_write(*a: Any, **kw: Any) -> None:
|
||||
|
||||
class Debug:
|
||||
|
||||
fobj: Optional[BinaryWrite] = None
|
||||
fobj: BinaryWrite | None = None
|
||||
|
||||
def __call__(self, *a: Any, **kw: Any) -> None:
|
||||
kw['file'] = self.fobj or sys.stdout.buffer
|
||||
@@ -67,7 +68,7 @@ class TermManager:
|
||||
self, optional_actions: int = termios.TCSANOW, use_alternate_screen: bool = True,
|
||||
mouse_tracking: MouseTracking = MouseTracking.none
|
||||
) -> None:
|
||||
self.extra_finalize: Optional[str] = None
|
||||
self.extra_finalize: str | None = None
|
||||
self.optional_actions = optional_actions
|
||||
self.use_alternate_screen = use_alternate_screen
|
||||
self.mouse_tracking = mouse_tracking
|
||||
@@ -377,7 +378,7 @@ class Loop:
|
||||
else:
|
||||
written = 0
|
||||
if written >= total_size:
|
||||
self.write_buf: List[bytes] = []
|
||||
self.write_buf: list[bytes] = []
|
||||
self.asyncio_loop.remove_writer(fd)
|
||||
self.waiting_for_writes = False
|
||||
handler.on_writing_finished()
|
||||
@@ -394,12 +395,12 @@ class Loop:
|
||||
break
|
||||
del self.write_buf[:consumed]
|
||||
|
||||
def quit(self, return_code: Optional[int] = None) -> None:
|
||||
def quit(self, return_code: int | None = None) -> None:
|
||||
if return_code is not None:
|
||||
self.return_code = return_code
|
||||
self.asyncio_loop.stop()
|
||||
|
||||
def loop_impl(self, handler: Handler, term_manager: TermManager, image_manager: Optional[ImageManagerType] = None) -> Optional[str]:
|
||||
def loop_impl(self, handler: Handler, term_manager: TermManager, image_manager: ImageManagerType | None = None) -> str | None:
|
||||
self.write_buf = []
|
||||
tty_fd = term_manager.tty_fd
|
||||
tb = None
|
||||
@@ -411,7 +412,7 @@ class Loop:
|
||||
self.asyncio_loop.add_writer(tty_fd, self._write_ready, handler, tty_fd)
|
||||
self.waiting_for_writes = True
|
||||
|
||||
def handle_exception(loop: asyncio.AbstractEventLoop, context: Dict[str, Any]) -> None:
|
||||
def handle_exception(loop: asyncio.AbstractEventLoop, context: dict[str, Any]) -> None:
|
||||
nonlocal tb
|
||||
loop.stop()
|
||||
tb = context['message']
|
||||
@@ -436,7 +437,7 @@ class Loop:
|
||||
return tb
|
||||
|
||||
def loop(self, handler: Handler) -> None:
|
||||
tb: Optional[str] = None
|
||||
tb: str | None = None
|
||||
|
||||
def _on_sigwinch() -> None:
|
||||
self._get_screen_size.changed = True
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
|
||||
import os
|
||||
import sys
|
||||
from collections.abc import Callable, Generator
|
||||
from contextlib import contextmanager
|
||||
from enum import Enum, auto
|
||||
from functools import wraps
|
||||
from typing import Any, Callable, Dict, Generator, Optional, TypeVar, Union
|
||||
from typing import Any, Optional, TypeVar, Union
|
||||
|
||||
from kitty.fast_data_types import Color
|
||||
from kitty.rgb import color_as_sharp, to_color
|
||||
@@ -22,7 +23,7 @@ RESTORE_PRIVATE_MODE_VALUES = '\033[?r'
|
||||
SAVE_COLORS = '\033[#P'
|
||||
RESTORE_COLORS = '\033[#Q'
|
||||
F = TypeVar('F')
|
||||
all_cmds: Dict[str, Callable[..., Any]] = {}
|
||||
all_cmds: dict[str, Callable[..., Any]] = {}
|
||||
|
||||
|
||||
class Mode(Enum):
|
||||
@@ -146,7 +147,7 @@ def set_cursor_shape(shape: str = 'block', blink: bool = True) -> str:
|
||||
|
||||
|
||||
@cmd
|
||||
def set_scrolling_region(screen_size: Optional['ScreenSize'] = None, top: Optional[int] = None, bottom: Optional[int] = None) -> str:
|
||||
def set_scrolling_region(screen_size: Optional['ScreenSize'] = None, top: int | None = None, bottom: int | None = None) -> str:
|
||||
if screen_size is None:
|
||||
return '\033[r'
|
||||
if top is None:
|
||||
@@ -192,7 +193,7 @@ def colored(
|
||||
text: str,
|
||||
color: ColorSpec,
|
||||
intense: bool = False,
|
||||
reset_to: Optional[ColorSpec] = None,
|
||||
reset_to: ColorSpec | None = None,
|
||||
reset_to_intense: bool = False
|
||||
) -> str:
|
||||
e = color_code(color, intense)
|
||||
@@ -207,16 +208,16 @@ def faint(text: str) -> str:
|
||||
@cmd
|
||||
def styled(
|
||||
text: str,
|
||||
fg: Optional[ColorSpec] = None,
|
||||
bg: Optional[ColorSpec] = None,
|
||||
fg: ColorSpec | None = None,
|
||||
bg: ColorSpec | None = None,
|
||||
fg_intense: bool = False,
|
||||
bg_intense: bool = False,
|
||||
italic: Optional[bool] = None,
|
||||
bold: Optional[bool] = None,
|
||||
underline: Optional[UnderlineLiteral] = None,
|
||||
underline_color: Optional[ColorSpec] = None,
|
||||
reverse: Optional[bool] = None,
|
||||
dim: Optional[bool] = None,
|
||||
italic: bool | None = None,
|
||||
bold: bool | None = None,
|
||||
underline: UnderlineLiteral | None = None,
|
||||
underline_color: ColorSpec | None = None,
|
||||
reverse: bool | None = None,
|
||||
dim: bool | None = None,
|
||||
) -> str:
|
||||
start, end = [], []
|
||||
if fg is not None:
|
||||
@@ -254,7 +255,7 @@ def styled(
|
||||
return '\033[{}m{}\033[{}m'.format(';'.join(start), text, ';'.join(end))
|
||||
|
||||
|
||||
def serialize_gr_command(cmd: Dict[str, Union[int, str]], payload: Optional[bytes] = None) -> bytes:
|
||||
def serialize_gr_command(cmd: dict[str, int | str], payload: bytes | None = None) -> bytes:
|
||||
from .images import GraphicsCommand
|
||||
gc = GraphicsCommand()
|
||||
for k, v in cmd.items():
|
||||
@@ -263,7 +264,7 @@ def serialize_gr_command(cmd: Dict[str, Union[int, str]], payload: Optional[byte
|
||||
|
||||
|
||||
@cmd
|
||||
def gr_command(cmd: Union[Dict[str, Union[int, str]], 'GraphicsCommandType'], payload: Optional[bytes] = None) -> str:
|
||||
def gr_command(cmd: Union[dict[str, int | str], 'GraphicsCommandType'], payload: bytes | None = None) -> str:
|
||||
if isinstance(cmd, dict):
|
||||
raw = serialize_gr_command(cmd, payload)
|
||||
else:
|
||||
@@ -358,7 +359,7 @@ def alternate_screen() -> Generator[None, None, None]:
|
||||
|
||||
|
||||
@contextmanager
|
||||
def raw_mode(fd: Optional[int] = None) -> Generator[None, None, None]:
|
||||
def raw_mode(fd: int | None = None) -> Generator[None, None, None]:
|
||||
import termios
|
||||
import tty
|
||||
if fd is None:
|
||||
@@ -373,15 +374,15 @@ def raw_mode(fd: Optional[int] = None) -> Generator[None, None, None]:
|
||||
|
||||
@cmd
|
||||
def set_default_colors(
|
||||
fg: Optional[Union[Color, str]] = None,
|
||||
bg: Optional[Union[Color, str]] = None,
|
||||
cursor: Optional[Union[Color, str]] = None,
|
||||
select_bg: Optional[Union[Color, str]] = None,
|
||||
select_fg: Optional[Union[Color, str]] = None
|
||||
fg: Color | str | None = None,
|
||||
bg: Color | str | None = None,
|
||||
cursor: Color | str | None = None,
|
||||
select_bg: Color | str | None = None,
|
||||
select_fg: Color | str | None = None
|
||||
) -> str:
|
||||
ans = ''
|
||||
|
||||
def item(which: Optional[Union[Color, str]], num: int) -> None:
|
||||
def item(which: Color | str | None, num: int) -> None:
|
||||
nonlocal ans
|
||||
if which is None:
|
||||
ans += f'\x1b]1{num}\x1b\\'
|
||||
@@ -418,7 +419,7 @@ def overlay_ready() -> str:
|
||||
|
||||
|
||||
@cmd
|
||||
def write_to_clipboard(data: Union[str, bytes], use_primary: bool = False) -> str:
|
||||
def write_to_clipboard(data: str | bytes, use_primary: bool = False) -> str:
|
||||
from base64 import standard_b64encode
|
||||
fmt = 'p' if use_primary else 'c'
|
||||
if isinstance(data, str):
|
||||
@@ -435,7 +436,7 @@ def request_from_clipboard(use_primary: bool = False) -> str:
|
||||
# Boilerplate to make operations available via Handler.cmd {{{
|
||||
|
||||
|
||||
def writer(handler: HandlerType, func: Callable[..., Union[bytes, str]]) -> Callable[..., None]:
|
||||
def writer(handler: HandlerType, func: Callable[..., bytes | str]) -> Callable[..., None]:
|
||||
@wraps(func)
|
||||
def f(*a: Any, **kw: Any) -> None:
|
||||
handler.write(func(*a, **kw))
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
|
||||
|
||||
import os
|
||||
from typing import Any, Callable, Dict, Generator, Optional, Sequence, Tuple
|
||||
from collections.abc import Callable, Generator, Sequence
|
||||
from typing import Any
|
||||
|
||||
from kitty.fast_data_types import wcswidth
|
||||
from kitty.utils import ScreenSize, screen_size_function
|
||||
@@ -93,7 +94,7 @@ class PathCompleter:
|
||||
readline.set_completion_display_matches_hook(self.format_completions)
|
||||
self.original_completer = readline.get_completer()
|
||||
readline.set_completer(self)
|
||||
self.cache: Dict[str, Tuple[str, ...]] = {}
|
||||
self.cache: dict[str, tuple[str, ...]] = {}
|
||||
self.dircolors = Dircolors()
|
||||
return self
|
||||
|
||||
@@ -126,7 +127,7 @@ class PathCompleter:
|
||||
print(f"\r\033[{pos}C", end='')
|
||||
print(sep='', end='', flush=True)
|
||||
|
||||
def __call__(self, text: str, state: int) -> Optional[str]:
|
||||
def __call__(self, text: str, state: int) -> str | None:
|
||||
options = self.cache.get(text)
|
||||
if options is None:
|
||||
options = self.cache[text] = tuple(find_completions(text))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
from typing import Dict, Sequence
|
||||
from collections.abc import Sequence
|
||||
|
||||
from kitty.fast_data_types import monotonic
|
||||
from kitty.typing import TypedDict
|
||||
@@ -14,7 +14,7 @@ class SpinnerDef(TypedDict):
|
||||
|
||||
# Spinner definitions are from
|
||||
# https://raw.githubusercontent.com/sindresorhus/cli-spinners/main/spinners.json
|
||||
spinners: Dict[str, SpinnerDef] = { # {{{
|
||||
spinners: dict[str, SpinnerDef] = { # {{{
|
||||
"dots": {
|
||||
"interval": 80,
|
||||
"frames": ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
|
||||
import os
|
||||
import sys
|
||||
from collections.abc import Sequence
|
||||
from contextlib import suppress
|
||||
from typing import TYPE_CHECKING, Optional, Sequence, Tuple, cast
|
||||
from typing import TYPE_CHECKING, Optional, cast
|
||||
|
||||
from kitty.types import run_once
|
||||
|
||||
@@ -46,7 +47,7 @@ def format_number(val: float, max_num_of_decimals: int = 2) -> str:
|
||||
def human_size(
|
||||
size: int, sep: str = ' ',
|
||||
max_num_of_decimals: int = 2,
|
||||
unit_list: Tuple[str, ...] = ('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB')
|
||||
unit_list: tuple[str, ...] = ('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB')
|
||||
) -> str:
|
||||
""" Convert a size in bytes into a human readable form """
|
||||
if size < 2:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
from kitty.typing import BossType
|
||||
|
||||
@@ -29,12 +28,12 @@ The initial tab to display. Defaults to using the tab from the previous kitten i
|
||||
|
||||
|
||||
@result_handler(has_ready_notification=True)
|
||||
def handle_result(args: List[str], current_char: str, target_window_id: int, boss: BossType) -> None:
|
||||
def handle_result(args: list[str], current_char: str, target_window_id: int, boss: BossType) -> None:
|
||||
w = boss.window_id_map.get(target_window_id)
|
||||
if w is not None:
|
||||
w.paste_text(current_char)
|
||||
|
||||
def main(args: List[str]) -> Optional[str]:
|
||||
def main(args: list[str]) -> str | None:
|
||||
raise SystemExit('This should be run as kitten unicode_input')
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
Reference in New Issue
Block a user