More typing work
This commit is contained in:
parent
7057bc663e
commit
308d171dae
@ -9,8 +9,8 @@ import re
|
||||
from contextlib import suppress
|
||||
from functools import partial
|
||||
from gettext import gettext as _
|
||||
from typing import Dict, Optional
|
||||
from weakref import WeakValueDictionary
|
||||
from typing import Optional
|
||||
|
||||
from .child import cached_process_data, cwd_of_process
|
||||
from .cli import create_opts, parse_args
|
||||
@ -39,7 +39,7 @@ from .utils import (
|
||||
log_error, open_url, parse_address_spec, remove_socket_file, safe_print,
|
||||
set_primary_selection, single_instance, startup_notification_handler
|
||||
)
|
||||
from .window import Window
|
||||
from .window import MatchPatternType, Window
|
||||
|
||||
|
||||
def notification_activated(identifier: str) -> None:
|
||||
@ -117,7 +117,7 @@ class Boss:
|
||||
set_layout_options(opts)
|
||||
self.clipboard_buffers = {}
|
||||
self.update_check_process = None
|
||||
self.window_id_map = WeakValueDictionary()
|
||||
self.window_id_map: WeakValueDictionary[int, Window] = WeakValueDictionary()
|
||||
self.startup_colors = {k: opts[k] for k in opts if isinstance(opts[k], Color)}
|
||||
self.startup_cursor_text_color = opts.cursor_text_color
|
||||
self.pending_sequences = None
|
||||
@ -210,7 +210,7 @@ class Boss:
|
||||
if field == 'env':
|
||||
kp, vp = exp.partition('=')[::2]
|
||||
if vp:
|
||||
pat = tuple(map(re.compile, (kp, vp)))
|
||||
pat: MatchPatternType = re.compile(kp), re.compile(vp)
|
||||
else:
|
||||
pat = re.compile(kp), None
|
||||
else:
|
||||
|
||||
@ -805,7 +805,7 @@ def compare_opts(opts: OptionsStub) -> None:
|
||||
compare_keymaps(final, initial)
|
||||
|
||||
|
||||
def create_opts(args, debug_config=False, accumulate_bad_lines=None):
|
||||
def create_opts(args: CLIOptions, debug_config=False, accumulate_bad_lines=None) -> OptionsStub:
|
||||
from .config import load_config
|
||||
config = tuple(resolve_config(SYSTEM_CONF, defconf, args.config))
|
||||
if debug_config:
|
||||
|
||||
@ -24,7 +24,7 @@ def generate_stub() -> None:
|
||||
nonlocal text
|
||||
text += as_type_stub(*parse_option_spec(otext), class_name=cls, extra_fields=extra_fields)
|
||||
|
||||
do()
|
||||
do(extra_fields=('args: typing.Sequence[str]',))
|
||||
|
||||
from .launch import options_spec
|
||||
do(options_spec(), 'LaunchCLIOptions')
|
||||
|
||||
@ -5,17 +5,21 @@
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
from collections import namedtuple
|
||||
from typing import (
|
||||
Any, Callable, Dict, FrozenSet, Iterable, List, Optional, Sequence, Tuple,
|
||||
Type, Union
|
||||
Any, Callable, Dict, FrozenSet, Iterable, List, NamedTuple, Optional,
|
||||
Sequence, Tuple, Type, Union
|
||||
)
|
||||
|
||||
from ..rgb import Color, to_color as as_color
|
||||
from ..utils import log_error
|
||||
|
||||
key_pat = re.compile(r'([a-zA-Z][a-zA-Z0-9_-]*)\s+(.+)$')
|
||||
BadLine = namedtuple('BadLine', 'number line exception')
|
||||
|
||||
|
||||
class BadLine(NamedTuple):
|
||||
number: int
|
||||
line: str
|
||||
exception: Exception
|
||||
|
||||
|
||||
def to_color(x: str) -> Color:
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
from typing import Any, Callable, Dict, List, NewType, Optional, Tuple, Union
|
||||
from typing import (
|
||||
Any, AnyStr, Callable, Dict, List, NewType, Optional, Tuple, Union
|
||||
)
|
||||
|
||||
from kitty.boss import Boss
|
||||
from kitty.options_stub import Options
|
||||
@ -577,7 +579,7 @@ def set_in_sequence_mode(yes: bool) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def set_clipboard_string(data: bytes) -> None:
|
||||
def set_clipboard_string(data: AnyStr) -> None:
|
||||
pass
|
||||
|
||||
|
||||
@ -594,7 +596,7 @@ def set_boss(boss: Boss) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def get_boss() -> Optional[Boss]:
|
||||
def get_boss() -> Boss: # this can return None but we ignore that for convenience
|
||||
pass
|
||||
|
||||
|
||||
@ -607,7 +609,23 @@ def patch_global_colors(spec: Dict[str, int], configured: bool) -> None:
|
||||
|
||||
|
||||
class ColorProfile:
|
||||
pass
|
||||
|
||||
default_bg: int
|
||||
|
||||
def as_dict(self) -> Dict:
|
||||
pass
|
||||
|
||||
def as_color(self, val: int) -> Tuple[int, int, int]:
|
||||
pass
|
||||
|
||||
def set_color(self, num: int, val: int) -> None:
|
||||
pass
|
||||
|
||||
def reset_color_table(self) -> None:
|
||||
pass
|
||||
|
||||
def reset_color(self, num: int) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def patch_color_profiles(
|
||||
@ -623,6 +641,18 @@ def os_window_font_size(
|
||||
pass
|
||||
|
||||
|
||||
def cocoa_set_notification_activated_callback(identifier: Callable[[str], None]) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def cocoa_set_new_window_trigger(mods: int, key: int) -> bool:
|
||||
pass
|
||||
|
||||
|
||||
def cocoa_get_lang() -> Optional[str]:
|
||||
pass
|
||||
|
||||
|
||||
def mark_os_window_for_close(os_window_id: int, yes: bool = True) -> bool:
|
||||
pass
|
||||
|
||||
@ -639,6 +669,14 @@ def focus_os_window(os_window_id: int, also_raise: bool = True) -> bool:
|
||||
pass
|
||||
|
||||
|
||||
def start_profiler(path: str) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def stop_profiler() -> None:
|
||||
pass
|
||||
|
||||
|
||||
def destroy_global_data() -> None:
|
||||
pass
|
||||
|
||||
@ -828,8 +866,95 @@ def create_test_font_group(sz: float, dpix: float,
|
||||
pass
|
||||
|
||||
|
||||
class HistoryBuf:
|
||||
|
||||
def as_text(self, callback: Callable[[str], None], as_ansi: bool, insert_wrap_markers: bool) -> None:
|
||||
pass
|
||||
|
||||
def pagerhist_as_text(self, callback: Callable[[str], None]) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class LineBuf:
|
||||
|
||||
def is_continued(self, idx: int) -> bool:
|
||||
pass
|
||||
|
||||
|
||||
class Cursor:
|
||||
x: int
|
||||
y: int
|
||||
|
||||
|
||||
class Screen:
|
||||
pass
|
||||
|
||||
color_profile: ColorProfile
|
||||
columns: int
|
||||
lines: int
|
||||
focus_tracking_enabled: bool
|
||||
historybuf: HistoryBuf
|
||||
linebuf: LineBuf
|
||||
in_bracketed_paste_mode: bool
|
||||
scrolled_by: int
|
||||
cursor: Cursor
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
callbacks: Any = None,
|
||||
lines: int = 80, columns: int = 24, scrollback: int = 0,
|
||||
cell_width: int = 10, cell_height: int = 20,
|
||||
window_id: int = 0,
|
||||
test_child: Any = None
|
||||
):
|
||||
pass
|
||||
|
||||
def copy_colors_from(self, other: 'Screen') -> None:
|
||||
pass
|
||||
|
||||
def mark_as_dirty(self) -> None:
|
||||
pass
|
||||
|
||||
def resize(self, width: int, height: int) -> None:
|
||||
pass
|
||||
|
||||
def send_escape_code_to_child(self, code: int, text: str) -> None:
|
||||
pass
|
||||
|
||||
def reset_callbacks(self) -> None:
|
||||
pass
|
||||
|
||||
def text_for_selection(self) -> Tuple[str, ...]:
|
||||
pass
|
||||
|
||||
def is_rectangle_select(self) -> bool:
|
||||
pass
|
||||
|
||||
def is_using_alternate_linebuf(self) -> bool:
|
||||
pass
|
||||
|
||||
def is_main_linebuf(self) -> bool:
|
||||
pass
|
||||
|
||||
def scroll(self, amt: int, upwards: bool) -> bool:
|
||||
pass
|
||||
|
||||
def scroll_to_next_mark(self, mark: int = 0, backwards: bool = True) -> bool:
|
||||
pass
|
||||
|
||||
def clear_selection(self) -> None:
|
||||
pass
|
||||
|
||||
def set_marker(self, marker: Optional[Callable] = None) -> None:
|
||||
pass
|
||||
|
||||
def paste_bytes(self, data: bytes) -> None:
|
||||
pass
|
||||
paste = paste_bytes
|
||||
|
||||
def as_text(self, callback: Callable[[str], None], as_ansi: bool, insert_wrap_markers: bool) -> None:
|
||||
pass
|
||||
as_text_non_visual = as_text
|
||||
as_text_alternate = as_text
|
||||
|
||||
|
||||
def set_tab_bar_render_data(
|
||||
@ -866,3 +991,15 @@ class ChildMonitor:
|
||||
|
||||
def wakeup(self) -> None:
|
||||
pass
|
||||
|
||||
def main_loop(self) -> None:
|
||||
pass
|
||||
|
||||
def resize_pty(self, window_id: int, rows: int, cols: int, x_pixels: int, y_pixels: int) -> None:
|
||||
pass
|
||||
|
||||
def needs_write(self, child_id: int, data: bytes) -> bool:
|
||||
pass
|
||||
|
||||
def set_iutf8_winid(self, win_id: int, on: bool) -> bool:
|
||||
pass
|
||||
|
||||
@ -7,12 +7,14 @@ import os
|
||||
import shutil
|
||||
import sys
|
||||
from contextlib import contextmanager, suppress
|
||||
from typing import Generator, List, Mapping, Optional, Tuple
|
||||
|
||||
from .borders import load_borders_program
|
||||
from .boss import Boss
|
||||
from .child import set_default_env
|
||||
from .cli import create_opts, parse_args
|
||||
from .cli_stub import CLIOptions
|
||||
from .conf.utils import BadLine
|
||||
from .config import cached_values_for, initial_window_size_func
|
||||
from .constants import (
|
||||
appname, beam_cursor_data_file, config_dir, glfw_path, is_macos,
|
||||
@ -25,6 +27,7 @@ from .fast_data_types import (
|
||||
)
|
||||
from .fonts.box_drawing import set_scale
|
||||
from .fonts.render import set_font_family
|
||||
from .options_stub import Options as OptionsStub
|
||||
from .utils import (
|
||||
detach, log_error, read_shell_environment, single_instance,
|
||||
startup_notification_handler, unix_socket_paths
|
||||
@ -66,13 +69,15 @@ def talk_to_instance(args):
|
||||
data['notify_on_os_window_death'] = address
|
||||
notify_socket.listen()
|
||||
|
||||
data = json.dumps(data, ensure_ascii=False).encode('utf-8')
|
||||
single_instance.socket.sendall(data)
|
||||
sdata = json.dumps(data, ensure_ascii=False).encode('utf-8')
|
||||
assert single_instance.socket is not None
|
||||
single_instance.socket.sendall(sdata)
|
||||
with suppress(OSError):
|
||||
single_instance.socket.shutdown(socket.SHUT_RDWR)
|
||||
single_instance.socket.close()
|
||||
|
||||
if args.wait_for_single_instance_window_close:
|
||||
assert notify_socket is not None
|
||||
conn = notify_socket.accept()[0]
|
||||
conn.recv(1)
|
||||
with suppress(OSError):
|
||||
@ -96,7 +101,7 @@ def init_glfw(opts, debug_keyboard=False):
|
||||
return glfw_module
|
||||
|
||||
|
||||
def get_new_os_window_trigger(opts):
|
||||
def get_new_os_window_trigger(opts: OptionsStub) -> Optional[Tuple[int, bool, int]]:
|
||||
new_os_window_trigger = None
|
||||
if is_macos:
|
||||
new_os_window_shortcuts = []
|
||||
@ -113,7 +118,7 @@ def get_new_os_window_trigger(opts):
|
||||
return new_os_window_trigger
|
||||
|
||||
|
||||
def _run_app(opts, args, bad_lines=()):
|
||||
def _run_app(opts: OptionsStub, args, bad_lines=()):
|
||||
new_os_window_trigger = get_new_os_window_trigger(opts)
|
||||
if is_macos and opts.macos_custom_beam_cursor:
|
||||
set_custom_ibeam_cursor()
|
||||
@ -145,7 +150,7 @@ class AppRunner:
|
||||
self.first_window_callback = lambda window_handle: None
|
||||
self.initial_window_size_func = initial_window_size_func
|
||||
|
||||
def __call__(self, opts, args, bad_lines=()):
|
||||
def __call__(self, opts: OptionsStub, args: CLIOptions, bad_lines=()) -> None:
|
||||
set_scale(opts.box_drawing_scale)
|
||||
set_options(opts, is_wayland(), args.debug_gl, args.debug_font_fallback)
|
||||
set_font_family(opts, debug_font_matching=args.debug_font_fallback)
|
||||
@ -158,7 +163,7 @@ class AppRunner:
|
||||
run_app = AppRunner()
|
||||
|
||||
|
||||
def ensure_macos_locale():
|
||||
def ensure_macos_locale() -> None:
|
||||
# Ensure the LANG env var is set. See
|
||||
# https://github.com/kovidgoyal/kitty/issues/90
|
||||
from .fast_data_types import cocoa_get_lang
|
||||
@ -169,15 +174,16 @@ def ensure_macos_locale():
|
||||
|
||||
|
||||
@contextmanager
|
||||
def setup_profiling(args):
|
||||
def setup_profiling(args) -> Generator[None, None, None]:
|
||||
try:
|
||||
from .fast_data_types import start_profiler, stop_profiler
|
||||
do_profile = True
|
||||
except ImportError:
|
||||
start_profiler = stop_profiler = None
|
||||
if start_profiler is not None:
|
||||
do_profile = False
|
||||
if do_profile:
|
||||
start_profiler('/tmp/kitty-profile.log')
|
||||
yield
|
||||
if stop_profiler is not None:
|
||||
if do_profile:
|
||||
import subprocess
|
||||
stop_profiler()
|
||||
exe = kitty_exe()
|
||||
@ -206,7 +212,7 @@ def macos_cmdline(argv_args):
|
||||
return ans
|
||||
|
||||
|
||||
def get_editor_from_env(shell_env):
|
||||
def get_editor_from_env(shell_env: Mapping[str, str]) -> Optional[str]:
|
||||
for var in ('VISUAL', 'EDITOR'):
|
||||
editor = shell_env.get(var)
|
||||
if editor:
|
||||
@ -214,8 +220,9 @@ def get_editor_from_env(shell_env):
|
||||
import shlex
|
||||
editor_cmd = shlex.split(editor)
|
||||
if not os.path.isabs(editor_cmd[0]):
|
||||
editor_cmd[0] = shutil.which(editor_cmd[0], path=shell_env['PATH'])
|
||||
if editor_cmd[0]:
|
||||
q = shutil.which(editor_cmd[0], path=shell_env['PATH'])
|
||||
if q:
|
||||
editor_cmd[0] = q
|
||||
editor = ' '.join(map(shlex.quote, editor_cmd))
|
||||
else:
|
||||
editor = None
|
||||
@ -282,30 +289,30 @@ def _main():
|
||||
cwd_ok = False
|
||||
if not cwd_ok:
|
||||
os.chdir(os.path.expanduser('~'))
|
||||
args, rest = parse_args(result_class=CLIOptions, args=args)
|
||||
args.args = rest
|
||||
if args.debug_config:
|
||||
create_opts(args, debug_config=True)
|
||||
cli_opts, rest = parse_args(args=args, result_class=CLIOptions)
|
||||
cli_opts.args = rest
|
||||
if cli_opts.debug_config:
|
||||
create_opts(cli_opts, debug_config=True)
|
||||
return
|
||||
if getattr(args, 'detach', False):
|
||||
if cli_opts.detach:
|
||||
detach()
|
||||
if args.replay_commands:
|
||||
from kitty.client import main
|
||||
main(args.replay_commands)
|
||||
if cli_opts.replay_commands:
|
||||
from kitty.client import main as client_main
|
||||
client_main(cli_opts.replay_commands)
|
||||
return
|
||||
if args.single_instance:
|
||||
is_first = single_instance(args.instance_group)
|
||||
if cli_opts.single_instance:
|
||||
is_first = single_instance(cli_opts.instance_group)
|
||||
if not is_first:
|
||||
talk_to_instance(args)
|
||||
talk_to_instance(cli_opts)
|
||||
return
|
||||
bad_lines = []
|
||||
opts = create_opts(args, accumulate_bad_lines=bad_lines)
|
||||
init_glfw(opts, args.debug_keyboard)
|
||||
setup_environment(opts, args)
|
||||
bad_lines: List[BadLine] = []
|
||||
opts = create_opts(cli_opts, accumulate_bad_lines=bad_lines)
|
||||
init_glfw(opts, cli_opts.debug_keyboard)
|
||||
setup_environment(opts, cli_opts)
|
||||
try:
|
||||
with setup_profiling(args):
|
||||
with setup_profiling(cli_opts):
|
||||
# Avoid needing to launch threads to reap zombies
|
||||
run_app(opts, args, bad_lines)
|
||||
run_app(opts, cli_opts, bad_lines)
|
||||
finally:
|
||||
glfw_terminate()
|
||||
|
||||
|
||||
@ -9,7 +9,8 @@ import weakref
|
||||
from collections import deque
|
||||
from enum import IntEnum
|
||||
from itertools import chain
|
||||
from typing import List
|
||||
from re import Pattern
|
||||
from typing import Deque, Dict, List, Optional, Tuple, Union
|
||||
|
||||
from .config import build_ansi_color_table
|
||||
from .constants import ScreenGeometry, WindowGeometry, appname, wakeup
|
||||
@ -32,6 +33,8 @@ from .utils import (
|
||||
set_primary_selection
|
||||
)
|
||||
|
||||
MatchPatternType = Union[Pattern, Tuple[Pattern, Optional[Pattern]]]
|
||||
|
||||
|
||||
class DynamicColor(IntEnum):
|
||||
default_fg, default_bg, cursor_color, highlight_fg, highlight_bg = range(1, 6)
|
||||
@ -123,7 +126,8 @@ def text_sanitizer(as_ansi, add_wrap_markers):
|
||||
pat = getattr(text_sanitizer, 'pat', None)
|
||||
if pat is None:
|
||||
import re
|
||||
pat = text_sanitizer.pat = re.compile(r'\033\[.+?m')
|
||||
pat = re.compile(r'\033\[.+?m')
|
||||
setattr(text_sanitizer, 'pat', pat)
|
||||
|
||||
ansi, wrap_markers = not as_ansi, not add_wrap_markers
|
||||
|
||||
@ -153,7 +157,7 @@ class Window:
|
||||
self.overlay_for = None
|
||||
self.default_title = os.path.basename(child.argv[0] or appname)
|
||||
self.child_title = self.default_title
|
||||
self.title_stack = deque(maxlen=10)
|
||||
self.title_stack: Deque[str] = deque(maxlen=10)
|
||||
self.allow_remote_control = child.allow_remote_control
|
||||
self.id = add_window(tab.os_window_id, tab.id, self.title)
|
||||
if not self.id:
|
||||
@ -200,14 +204,23 @@ class Window:
|
||||
)
|
||||
|
||||
@property
|
||||
def current_colors(self):
|
||||
def current_colors(self) -> Dict:
|
||||
return self.screen.color_profile.as_dict()
|
||||
|
||||
def matches(self, field, pat):
|
||||
def matches(self, field: str, pat: MatchPatternType) -> bool:
|
||||
if field == 'env':
|
||||
assert isinstance(pat, tuple)
|
||||
key_pat, val_pat = pat
|
||||
for key, val in self.child.environ.items():
|
||||
if key_pat.search(key) is not None and (
|
||||
val_pat is None or val_pat.search(val) is not None):
|
||||
return True
|
||||
|
||||
assert isinstance(pat, Pattern)
|
||||
if field == 'id':
|
||||
return pat.pattern == str(self.id)
|
||||
return True if pat.pattern == str(self.id) else False
|
||||
if field == 'pid':
|
||||
return pat.pattern == str(self.child.pid)
|
||||
return True if pat.pattern == str(self.child.pid) else False
|
||||
if field == 'title':
|
||||
return pat.search(self.override_title or self.title) is not None
|
||||
if field in 'cwd':
|
||||
@ -217,12 +230,6 @@ class Window:
|
||||
if pat.search(x) is not None:
|
||||
return True
|
||||
return False
|
||||
if field == 'env':
|
||||
key_pat, val_pat = pat
|
||||
for key, val in self.child.environ.items():
|
||||
if key_pat.search(key) is not None and (
|
||||
val_pat is None or val_pat.search(val) is not None):
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_visible_in_layout(self, window_idx, val):
|
||||
@ -488,15 +495,15 @@ class Window:
|
||||
lines = self.screen.text_for_selection()
|
||||
if self.opts.strip_trailing_spaces == 'always' or (
|
||||
self.opts.strip_trailing_spaces == 'smart' and not self.screen.is_rectangle_select()):
|
||||
lines = ((l.rstrip() or '\n') for l in lines)
|
||||
return ''.join((l.rstrip() or '\n') for l in lines)
|
||||
return ''.join(lines)
|
||||
|
||||
def destroy(self):
|
||||
self.destroyed = True
|
||||
if self.screen is not None:
|
||||
if hasattr(self, 'screen'):
|
||||
# Remove cycles so that screen is de-allocated immediately
|
||||
self.screen.reset_callbacks()
|
||||
self.screen = None
|
||||
del self.screen
|
||||
|
||||
def as_text(self, as_ansi=False, add_history=False, add_wrap_markers=False, alternate_screen=False) -> str:
|
||||
lines: List[str] = []
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user