Use a stub rather than TYPE_CHECKING
This commit is contained in:
parent
871ca4dda6
commit
382c31ddf2
@ -9,13 +9,13 @@ from typing import TYPE_CHECKING, List, Optional, Tuple
|
||||
from kitty.cli import parse_args
|
||||
from kitty.cli_stub import AskCLIOptions
|
||||
from kitty.constants import cache_dir
|
||||
from kitty.typing import BossType
|
||||
|
||||
from ..tui.handler import result_handler
|
||||
from ..tui.operations import alternate_screen, styled
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import readline
|
||||
import kitty
|
||||
else:
|
||||
readline = None
|
||||
|
||||
@ -127,7 +127,7 @@ def main(args: List[str]) -> Response:
|
||||
|
||||
|
||||
@result_handler()
|
||||
def handle_result(args: List[str], data: Response, target_window_id: int, boss: 'kitty.boss.Boss') -> 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)
|
||||
|
||||
@ -10,8 +10,8 @@ from functools import lru_cache
|
||||
from gettext import gettext as _
|
||||
from itertools import repeat
|
||||
from typing import (
|
||||
TYPE_CHECKING, Any, Callable, Dict, Generator, Iterable, List, Optional,
|
||||
Pattern, Sequence, Set, Tuple, Type, cast
|
||||
Any, Callable, Dict, Generator, Iterable, List, Optional, Pattern,
|
||||
Sequence, Set, Tuple, Type, cast
|
||||
)
|
||||
|
||||
from kitty.cli import parse_args
|
||||
@ -20,30 +20,26 @@ from kitty.fast_data_types import set_clipboard_string
|
||||
from kitty.key_encoding import (
|
||||
KeyEvent, backspace_key, enter_key, key_defs as K
|
||||
)
|
||||
from kitty.typing import BossType, KittyCommonOpts
|
||||
from kitty.utils import ScreenSize, screen_size_function
|
||||
|
||||
from ..tui.handler import Handler, result_handler
|
||||
from ..tui.loop import Loop
|
||||
from ..tui.operations import faint, styled
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from kitty.config import KittyCommonOpts
|
||||
from kitty.boss import Boss
|
||||
|
||||
|
||||
@lru_cache()
|
||||
def kitty_common_opts() -> 'KittyCommonOpts':
|
||||
def kitty_common_opts() -> KittyCommonOpts:
|
||||
import json
|
||||
v = os.environ.get('KITTY_COMMON_OPTS')
|
||||
if v:
|
||||
return cast('KittyCommonOpts', json.loads(v))
|
||||
return cast(KittyCommonOpts, json.loads(v))
|
||||
from kitty.config import common_opts_as_dict
|
||||
return common_opts_as_dict()
|
||||
|
||||
|
||||
DEFAULT_HINT_ALPHABET = string.digits + string.ascii_lowercase
|
||||
DEFAULT_REGEX = r'(?m)^\s*(.+)\s*$'
|
||||
screen_size = screen_size_function()
|
||||
ESCAPE = K['ESCAPE']
|
||||
|
||||
|
||||
@ -346,7 +342,7 @@ def parse_input(text: str) -> str:
|
||||
try:
|
||||
cols = int(os.environ['OVERLAID_WINDOW_COLS'])
|
||||
except KeyError:
|
||||
cols = screen_size().cols
|
||||
cols = screen_size_function()().cols
|
||||
return convert_text(text, cols)
|
||||
|
||||
|
||||
@ -560,7 +556,7 @@ def main(args: List[str]) -> Optional[Dict[str, Any]]:
|
||||
return run(opts, text, items)
|
||||
|
||||
|
||||
def linenum_handle_result(args: List[str], data: Dict[str, Any], target_window_id: int, boss: 'Boss', 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:
|
||||
for m, g in zip(data['match'], data['groupdicts']):
|
||||
if m:
|
||||
path, line = g['path'], g['line']
|
||||
@ -589,7 +585,7 @@ def linenum_handle_result(args: List[str], data: Dict[str, Any], target_window_i
|
||||
|
||||
|
||||
@result_handler(type_of_input='screen')
|
||||
def handle_result(args: List[str], data: Dict[str, Any], target_window_id: int, boss: 'Boss') -> None:
|
||||
def handle_result(args: List[str], data: Dict[str, Any], target_window_id: int, boss: BossType) -> None:
|
||||
if data['customize_processing']:
|
||||
m = load_custom_processor(data['customize_processing'])
|
||||
if 'handle_result' in m:
|
||||
|
||||
@ -13,13 +13,13 @@ from functools import lru_cache
|
||||
from math import ceil
|
||||
from tempfile import NamedTemporaryFile
|
||||
from typing import (
|
||||
TYPE_CHECKING, Dict, Generator, List, NamedTuple, Optional, Pattern, Tuple,
|
||||
Union
|
||||
Dict, Generator, List, NamedTuple, Optional, Pattern, Tuple, Union
|
||||
)
|
||||
|
||||
from kitty.cli import parse_args
|
||||
from kitty.cli_stub import IcatCLIOptions
|
||||
from kitty.constants import appname
|
||||
from kitty.typing import GRT_f, GRT_t
|
||||
from kitty.utils import (
|
||||
TTYIO, ScreenSize, ScreenSizeGetter, fit_image, screen_size_function
|
||||
)
|
||||
@ -30,9 +30,6 @@ from ..tui.images import (
|
||||
)
|
||||
from ..tui.operations import clear_images_on_screen
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..tui.images import GRT_f, GRT_t # noqa
|
||||
|
||||
OPTIONS = '''\
|
||||
--align
|
||||
type=choices
|
||||
|
||||
@ -3,35 +3,29 @@
|
||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
|
||||
from types import TracebackType
|
||||
from typing import (
|
||||
TYPE_CHECKING, Any, Callable, ContextManager, Dict, Optional, Sequence, Type,
|
||||
Union
|
||||
Any, Callable, ContextManager, Dict, Optional, Sequence, Type, Union
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from kitty.utils import ScreenSize
|
||||
from .loop import TermManager, Loop, Debug, MouseEvent
|
||||
from .images import ImageManager
|
||||
from kitty.conf.utils import KittensKeyAction
|
||||
from kitty.boss import Boss
|
||||
from kitty.key_encoding import KeyEvent
|
||||
from types import TracebackType
|
||||
ScreenSize, TermManager, Loop, Debug, KeyEvent, MouseEvent, TracebackType, Boss, ImageManager
|
||||
import asyncio
|
||||
from kitty.typing import (
|
||||
AbstractEventLoop, BossType, Debug, ImageManagerType, KeyEventType,
|
||||
KittensKeyActionType, LoopType, MouseEvent, ScreenSize, TermManagerType
|
||||
)
|
||||
|
||||
|
||||
class Handler:
|
||||
|
||||
image_manager_class: Optional[Type['ImageManager']] = None
|
||||
image_manager_class: Optional[Type[ImageManagerType]] = None
|
||||
|
||||
def _initialize(
|
||||
self,
|
||||
screen_size: 'ScreenSize',
|
||||
term_manager: 'TermManager',
|
||||
screen_size: ScreenSize,
|
||||
term_manager: TermManagerType,
|
||||
schedule_write: Callable[[bytes], None],
|
||||
tui_loop: 'Loop',
|
||||
debug: 'Debug',
|
||||
image_manager: Optional['ImageManager'] = None
|
||||
tui_loop: LoopType,
|
||||
debug: Debug,
|
||||
image_manager: Optional[ImageManagerType] = None
|
||||
) -> None:
|
||||
from .operations import commander
|
||||
self.screen_size = screen_size
|
||||
@ -43,15 +37,15 @@ class Handler:
|
||||
self._image_manager = image_manager
|
||||
|
||||
@property
|
||||
def image_manager(self) -> 'ImageManager':
|
||||
def image_manager(self) -> ImageManagerType:
|
||||
assert self._image_manager is not None
|
||||
return self._image_manager
|
||||
|
||||
@property
|
||||
def asyncio_loop(self) -> 'asyncio.AbstractEventLoop':
|
||||
def asyncio_loop(self) -> AbstractEventLoop:
|
||||
return self._tui_loop.asycio_loop
|
||||
|
||||
def add_shortcut(self, action: 'KittensKeyAction', key: str, mods: Optional[int] = None, is_text: Optional[bool] = False) -> None:
|
||||
def add_shortcut(self, action: KittensKeyActionType, key: str, mods: Optional[int] = None, is_text: Optional[bool] = False) -> None:
|
||||
if not hasattr(self, '_text_shortcuts'):
|
||||
self._text_shortcuts, self._key_shortcuts = {}, {}
|
||||
if is_text:
|
||||
@ -59,7 +53,7 @@ class Handler:
|
||||
else:
|
||||
self._key_shortcuts[(key, mods or 0)] = action
|
||||
|
||||
def shortcut_action(self, key_event_or_text: Union[str, 'KeyEvent']) -> Optional['KittensKeyAction']:
|
||||
def shortcut_action(self, key_event_or_text: Union[str, KeyEventType]) -> Optional[KittensKeyActionType]:
|
||||
if isinstance(key_event_or_text, str):
|
||||
return self._text_shortcuts.get(key_event_or_text)
|
||||
return self._key_shortcuts.get((key_event_or_text.key, key_event_or_text.mods))
|
||||
@ -70,7 +64,7 @@ class Handler:
|
||||
self.debug.fobj = self
|
||||
self.initialize()
|
||||
|
||||
def __exit__(self, etype: type, value: Exception, tb: 'TracebackType') -> None:
|
||||
def __exit__(self, etype: type, value: Exception, tb: TracebackType) -> None:
|
||||
del self.debug.fobj
|
||||
self.finalize()
|
||||
if self._image_manager is not None:
|
||||
@ -82,7 +76,7 @@ class Handler:
|
||||
def finalize(self) -> None:
|
||||
pass
|
||||
|
||||
def on_resize(self, screen_size: 'ScreenSize') -> None:
|
||||
def on_resize(self, screen_size: ScreenSize) -> None:
|
||||
self.screen_size = screen_size
|
||||
|
||||
def quit_loop(self, return_code: Optional[int] = None) -> None:
|
||||
@ -94,7 +88,7 @@ class Handler:
|
||||
def on_text(self, text: str, in_bracketed_paste: bool = False) -> None:
|
||||
pass
|
||||
|
||||
def on_key(self, key_event: 'KeyEvent') -> None:
|
||||
def on_key(self, key_event: KeyEventType) -> None:
|
||||
pass
|
||||
|
||||
def on_mouse(self, mouse_event: 'MouseEvent') -> None:
|
||||
@ -127,7 +121,7 @@ class Handler:
|
||||
data = sep.join(map(str, args)) + end
|
||||
self.write(data)
|
||||
|
||||
def suspend(self) -> ContextManager['TermManager']:
|
||||
def suspend(self) -> ContextManager[TermManagerType]:
|
||||
return self._term_manager.suspend()
|
||||
|
||||
|
||||
@ -141,7 +135,7 @@ class HandleResult:
|
||||
self.no_ui = no_ui
|
||||
self.type_of_input = type_of_input
|
||||
|
||||
def __call__(self, args: Sequence[str], data: Any, target_window_id: int, boss: 'Boss') -> Any:
|
||||
def __call__(self, args: Sequence[str], data: Any, target_window_id: int, boss: BossType) -> Any:
|
||||
return self.impl(args, data, target_window_id, boss)
|
||||
|
||||
|
||||
|
||||
@ -10,10 +10,13 @@ from collections import defaultdict, deque
|
||||
from contextlib import suppress
|
||||
from itertools import count
|
||||
from typing import (
|
||||
TYPE_CHECKING, Any, DefaultDict, Deque, Dict, List, Optional, Sequence,
|
||||
Tuple, Union
|
||||
Any, DefaultDict, Deque, Dict, List, Optional, Sequence, Tuple, Union
|
||||
)
|
||||
|
||||
from kitty.typing import (
|
||||
CompletedProcess, GRT_a, GRT_d, GRT_f, GRT_m, GRT_o, GRT_t, HandlerType,
|
||||
TypedDict
|
||||
)
|
||||
from kitty.utils import ScreenSize, fit_image
|
||||
|
||||
from .operations import cursor
|
||||
@ -25,28 +28,11 @@ except Exception:
|
||||
fsenc = 'utf-8'
|
||||
|
||||
|
||||
try:
|
||||
from typing import TypedDict, Literal
|
||||
GRT_a = Literal['t', 'T', 'q', 'p', 'd']
|
||||
GRT_f = Literal[24, 32, 100]
|
||||
GRT_t = Literal['d', 'f', 't', 's']
|
||||
GRT_o = Literal['z']
|
||||
GRT_m = Literal[0, 1]
|
||||
GRT_d = Literal['a', 'A', 'c', 'C', 'i', 'I', 'p', 'P', 'q', 'Q', 'x', 'X', 'y', 'Y', 'z', 'Z']
|
||||
except ImportError:
|
||||
TypedDict = dict
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import subprocess
|
||||
from .handler import Handler
|
||||
|
||||
|
||||
class ImageData:
|
||||
|
||||
def __init__(self, fmt: str, width: int, height: int, mode: str):
|
||||
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.transmit_fmt: GRT_f = (24 if self.mode == 'rgb' else 32)
|
||||
|
||||
|
||||
class OpenFailed(ValueError):
|
||||
@ -71,7 +57,7 @@ class NoImageMagick(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def run_imagemagick(path: str, cmd: Sequence[str], keep_stdout: bool = True) -> 'subprocess.CompletedProcess[bytes]':
|
||||
def run_imagemagick(path: str, cmd: Sequence[str], keep_stdout: bool = True) -> CompletedProcess:
|
||||
import subprocess
|
||||
try:
|
||||
p = subprocess.run(cmd, stdout=subprocess.PIPE if keep_stdout else subprocess.DEVNULL, stderr=subprocess.PIPE)
|
||||
@ -140,16 +126,16 @@ SentImageKey = Tuple[int, int, int]
|
||||
|
||||
|
||||
class GraphicsCommand:
|
||||
a: 'GRT_a' = 't' # action
|
||||
f: 'GRT_f' = 32 # image data format
|
||||
t: 'GRT_t' = 'd' # transmission medium
|
||||
a: GRT_a = 't' # action
|
||||
f: GRT_f = 32 # image data format
|
||||
t: GRT_t = 'd' # transmission medium
|
||||
s: int = 0 # sent image width
|
||||
v: int = 0 # sent image height
|
||||
S: int = 0 # size of data to read from file
|
||||
O: int = 0 # offset of data to read from file
|
||||
i: int = 0 # image id
|
||||
o: Optional['GRT_o'] = None # type of compression
|
||||
m: 'GRT_m' = 0 # 0 or 1 whether there is more chunked data
|
||||
o: Optional[GRT_o] = None # type of compression
|
||||
m: GRT_m = 0 # 0 or 1 whether there is more chunked data
|
||||
x: int = 0 # left edge of image area to display
|
||||
y: int = 0 # top edge of image area to display
|
||||
w: int = 0 # image width to display
|
||||
@ -159,7 +145,7 @@ class GraphicsCommand:
|
||||
c: int = 0 # number of cols to display image over
|
||||
r: int = 0 # number of rows to display image over
|
||||
z: int = 0 # z-index
|
||||
d: 'GRT_d' = 'a' # what to delete
|
||||
d: GRT_d = 'a' # what to delete
|
||||
|
||||
def serialize(self, payload: bytes = b'') -> bytes:
|
||||
items = []
|
||||
@ -193,7 +179,7 @@ class Placement(TypedDict):
|
||||
|
||||
class ImageManager:
|
||||
|
||||
def __init__(self, handler: 'Handler'):
|
||||
def __init__(self, handler: HandlerType):
|
||||
self.image_id_counter = count()
|
||||
self.handler = handler
|
||||
self.filesystem_ok: Optional[bool] = None
|
||||
|
||||
@ -12,9 +12,7 @@ import signal
|
||||
import sys
|
||||
from contextlib import contextmanager
|
||||
from functools import partial
|
||||
from typing import (
|
||||
TYPE_CHECKING, Any, Callable, Dict, Generator, List, NamedTuple, Optional
|
||||
)
|
||||
from typing import Any, Callable, Dict, Generator, List, NamedTuple, Optional
|
||||
|
||||
from kitty.constants import is_macos
|
||||
from kitty.fast_data_types import (
|
||||
@ -24,20 +22,12 @@ from kitty.key_encoding import (
|
||||
ALT, CTRL, PRESS, RELEASE, REPEAT, SHIFT, backspace_key, decode_key_event,
|
||||
enter_key, key_defs as K
|
||||
)
|
||||
from kitty.utils import screen_size_function, write_all
|
||||
from kitty.typing import ImageManagerType, KeyEventType, Protocol
|
||||
from kitty.utils import ScreenSizeGetter, screen_size_function, write_all
|
||||
|
||||
from .handler import Handler
|
||||
from .operations import init_state, reset_state
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from kitty.key_encoding import KeyEvent
|
||||
from .images import ImageManager
|
||||
KeyEvent, ImageManager
|
||||
from typing import Protocol
|
||||
else:
|
||||
Protocol = object
|
||||
|
||||
|
||||
C, D = K['C'], K['D']
|
||||
|
||||
|
||||
@ -156,7 +146,7 @@ class UnhandledException(Handler):
|
||||
self.write('\r\n')
|
||||
self.write('Press the Enter key to quit')
|
||||
|
||||
def on_key(self, key_event: 'KeyEvent') -> None:
|
||||
def on_key(self, key_event: KeyEventType) -> None:
|
||||
if key_event is enter_key:
|
||||
self.quit_loop(1)
|
||||
|
||||
@ -355,7 +345,7 @@ class Loop:
|
||||
self.return_code = return_code
|
||||
self.asycio_loop.stop()
|
||||
|
||||
def loop_impl(self, handler: Handler, term_manager: TermManager, image_manager: Optional['ImageManager'] = None) -> Optional[str]:
|
||||
def loop_impl(self, handler: Handler, term_manager: TermManager, image_manager: Optional[ImageManagerType] = None) -> Optional[str]:
|
||||
self.write_buf = []
|
||||
tty_fd = term_manager.tty_fd
|
||||
tb = None
|
||||
@ -399,7 +389,7 @@ class Loop:
|
||||
|
||||
signal_manager = SignalManager(self.asycio_loop, _on_sigwinch, handler.on_interrupt, handler.on_term)
|
||||
with TermManager() as term_manager, signal_manager:
|
||||
self._get_screen_size = screen_size_function(term_manager.tty_fd)
|
||||
self._get_screen_size: ScreenSizeGetter = screen_size_function(term_manager.tty_fd)
|
||||
image_manager = None
|
||||
if handler.image_manager_class is not None:
|
||||
image_manager = handler.image_manager_class(handler)
|
||||
|
||||
@ -6,20 +6,15 @@ import sys
|
||||
from contextlib import contextmanager
|
||||
from functools import wraps
|
||||
from typing import (
|
||||
IO, TYPE_CHECKING, Any, Callable, Dict, Generator, Optional, Tuple,
|
||||
TypeVar, Union
|
||||
IO, Any, Callable, Dict, Generator, Optional, Tuple, TypeVar, Union
|
||||
)
|
||||
|
||||
from kitty.rgb import Color, color_as_sharp, to_color
|
||||
from kitty.typing import GraphicsCommandType, HandlerType, ScreenSize
|
||||
|
||||
from .operations_stub import CMD
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from kitty.utils import ScreenSize
|
||||
from .images import GraphicsCommand
|
||||
from .handler import Handler
|
||||
ScreenSize, GraphicsCommand, Handler
|
||||
|
||||
GraphicsCommandType, ScreenSize # needed for stub generation
|
||||
S7C1T = '\033 F'
|
||||
SAVE_CURSOR = '\0337'
|
||||
RESTORE_CURSOR = '\0338'
|
||||
@ -232,7 +227,7 @@ def serialize_gr_command(cmd: Dict[str, Union[int, str]], payload: Optional[byte
|
||||
|
||||
|
||||
@cmd
|
||||
def gr_command(cmd: Union[Dict, 'GraphicsCommand'], payload: Optional[bytes] = None) -> str:
|
||||
def gr_command(cmd: Union[Dict, 'GraphicsCommandType'], payload: Optional[bytes] = None) -> str:
|
||||
if isinstance(cmd, dict):
|
||||
raw = serialize_gr_command(cmd, payload)
|
||||
else:
|
||||
@ -349,14 +344,14 @@ def request_from_clipboard(use_primary: bool = False) -> str:
|
||||
# Boilerplate to make operations availble via Handler.cmd {{{
|
||||
|
||||
|
||||
def writer(handler: 'Handler', func: Callable) -> Callable:
|
||||
def writer(handler: HandlerType, func: Callable) -> Callable:
|
||||
@wraps(func)
|
||||
def f(*a: Any, **kw: Any) -> None:
|
||||
handler.write(func(*a, **kw))
|
||||
return f
|
||||
|
||||
|
||||
def commander(handler: 'Handler') -> CMD:
|
||||
def commander(handler: HandlerType) -> CMD:
|
||||
ans = CMD()
|
||||
for name, func in all_cmds.items():
|
||||
setattr(ans, name, writer(handler, func))
|
||||
@ -374,8 +369,7 @@ def func_sig(func: Callable) -> Generator[str, None, None]:
|
||||
def as_type_stub() -> str:
|
||||
ans = [
|
||||
'from typing import * # noqa',
|
||||
'from kitty.utils import ScreenSize',
|
||||
'from kittens.tui.images import GraphicsCommand',
|
||||
'from kitty.typing import GraphicsCommandType, ScreenSize',
|
||||
'from kitty.rgb import Color',
|
||||
'import kitty.rgb',
|
||||
]
|
||||
|
||||
@ -10,7 +10,7 @@ from contextlib import suppress
|
||||
from functools import lru_cache
|
||||
from gettext import gettext as _
|
||||
from typing import (
|
||||
TYPE_CHECKING, Any, Dict, FrozenSet, Generator, Iterable, List, Optional, Sequence, Tuple,
|
||||
Any, Dict, FrozenSet, Generator, Iterable, List, Optional, Sequence, Tuple,
|
||||
Union
|
||||
)
|
||||
|
||||
@ -22,6 +22,7 @@ from kitty.fast_data_types import is_emoji_presentation_base, wcswidth
|
||||
from kitty.key_encoding import (
|
||||
CTRL, RELEASE, SHIFT, KeyEvent, enter_key, key_defs as K
|
||||
)
|
||||
from kitty.typing import BossType
|
||||
from kitty.utils import ScreenSize, get_editor
|
||||
|
||||
from ..tui.handler import Handler, result_handler
|
||||
@ -32,11 +33,6 @@ from ..tui.operations import (
|
||||
sgr, styled
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from kitty.boss import Boss
|
||||
Boss
|
||||
|
||||
|
||||
HEX, NAME, EMOTICONS, FAVORITES = 'HEX', 'NAME', 'EMOTICONS', 'FAVORITES'
|
||||
UP = K['UP']
|
||||
DOWN = K['DOWN']
|
||||
@ -579,7 +575,7 @@ def main(args: List[str]) -> Optional[str]:
|
||||
|
||||
|
||||
@result_handler()
|
||||
def handle_result(args: List[str], current_char: str, target_window_id: int, boss: 'Boss') -> 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(current_char)
|
||||
|
||||
@ -2,8 +2,9 @@
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
from enum import IntFlag
|
||||
from itertools import chain
|
||||
from typing import TYPE_CHECKING, List, Optional, Sequence, Tuple
|
||||
from typing import List, Optional, Sequence, Tuple
|
||||
|
||||
from .constants import WindowGeometry
|
||||
from .fast_data_types import (
|
||||
@ -12,17 +13,7 @@ from .fast_data_types import (
|
||||
)
|
||||
from .options_stub import Options
|
||||
from .utils import load_shaders
|
||||
|
||||
try:
|
||||
from enum import IntFlag
|
||||
except ImportError:
|
||||
from enum import IntEnum as IntFlag # type: ignore
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .window import Window
|
||||
from .layout import Layout
|
||||
Window, Layout
|
||||
from .typing import WindowType, LayoutType
|
||||
|
||||
|
||||
class BorderColor(IntFlag):
|
||||
@ -63,9 +54,9 @@ class Borders:
|
||||
|
||||
def __call__(
|
||||
self,
|
||||
windows: List['Window'],
|
||||
active_window: Optional['Window'],
|
||||
current_layout: 'Layout',
|
||||
windows: List[WindowType],
|
||||
active_window: Optional[WindowType],
|
||||
current_layout: LayoutType,
|
||||
extra_blank_rects: Sequence[Tuple[int, int, int, int]],
|
||||
padding_width: int,
|
||||
border_width: int,
|
||||
|
||||
@ -10,8 +10,7 @@ from contextlib import suppress
|
||||
from functools import partial
|
||||
from gettext import gettext as _
|
||||
from typing import (
|
||||
TYPE_CHECKING, Any, Callable, Dict, Generator, Iterable, List, Optional,
|
||||
Tuple, Union
|
||||
Any, Callable, Dict, Generator, Iterable, List, Optional, Tuple, Union
|
||||
)
|
||||
from weakref import WeakValueDictionary
|
||||
|
||||
@ -44,6 +43,7 @@ from .session import Session, create_sessions
|
||||
from .tabs import (
|
||||
SpecialWindow, SpecialWindowInstance, Tab, TabDict, TabManager
|
||||
)
|
||||
from .typing import PopenType, TypedDict
|
||||
from .utils import (
|
||||
func_name, get_editor, get_primary_selection, is_path_in_temp_dir,
|
||||
log_error, open_url, parse_address_spec, remove_socket_file, safe_print,
|
||||
@ -51,13 +51,6 @@ from .utils import (
|
||||
)
|
||||
from .window import MatchPatternType, Window
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import TypedDict
|
||||
from .rc.base import RemoteCommand # noqa
|
||||
from subprocess import Popen # noqa
|
||||
else:
|
||||
TypedDict = dict
|
||||
|
||||
|
||||
class OSWindowDict(TypedDict):
|
||||
id: int
|
||||
@ -149,7 +142,7 @@ class Boss:
|
||||
):
|
||||
set_layout_options(opts)
|
||||
self.clipboard_buffers: Dict[str, str] = {}
|
||||
self.update_check_process: Optional['Popen'] = None
|
||||
self.update_check_process: Optional[PopenType] = None
|
||||
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
|
||||
@ -1209,7 +1202,7 @@ class Boss:
|
||||
with suppress(FileNotFoundError):
|
||||
os.remove(path)
|
||||
|
||||
def set_update_check_process(self, process: Optional['Popen'] = None) -> None:
|
||||
def set_update_check_process(self, process: Optional[PopenType] = None) -> None:
|
||||
if self.update_check_process is not None:
|
||||
with suppress(Exception):
|
||||
if self.update_check_process.poll() is None:
|
||||
|
||||
@ -4,15 +4,13 @@
|
||||
|
||||
import re
|
||||
|
||||
from typing import TYPE_CHECKING, List, Generator, Any, Type
|
||||
from typing import List, Generator, Any, Type
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from kitty.cli_stub import HintsCLIOptions
|
||||
from kittens.hints.main import Mark as MarkClass
|
||||
HintsCLIOptions, MarkClass
|
||||
from .cli_stub import HintsCLIOptions
|
||||
from .typing import MarkType
|
||||
|
||||
|
||||
def mark(text: str, args: 'HintsCLIOptions', Mark: Type['MarkClass'], extra_cli_args: List[str], *a: Any) -> Generator['MarkClass', None, None]:
|
||||
def mark(text: str, args: HintsCLIOptions, Mark: Type[MarkType], extra_cli_args: List[str], *a: Any) -> Generator[MarkType, None, None]:
|
||||
for idx, m in enumerate(re.finditer(args.regex, text)):
|
||||
start, end = m.span()
|
||||
mark_text = text[start:end].replace('\n', '').replace('\0', '')
|
||||
|
||||
27
kitty/cli.py
27
kitty/cli.py
@ -7,19 +7,19 @@ import re
|
||||
import sys
|
||||
from collections import deque
|
||||
from typing import (
|
||||
TYPE_CHECKING, Any, Callable, Dict, FrozenSet, Iterable, Iterator, List,
|
||||
Match, Optional, Sequence, Set, Tuple, Type, TypeVar, Union, cast
|
||||
Any, Callable, Dict, FrozenSet, Iterable, Iterator, List, Match, Optional,
|
||||
Sequence, Set, Tuple, Type, TypeVar, Union, cast
|
||||
)
|
||||
|
||||
from .cli_stub import CLIOptions
|
||||
from .conf.utils import resolve_config
|
||||
from .config import KeyAction
|
||||
from .constants import appname, defconf, is_macos, is_wayland, str_version
|
||||
from .options_stub import Options as OptionsStub
|
||||
from .typing import BadLineType, KeySpec, SequenceMap, TypedDict
|
||||
|
||||
try:
|
||||
from typing import TypedDict
|
||||
|
||||
class OptionDict(TypedDict):
|
||||
class OptionDict(TypedDict):
|
||||
dest: str
|
||||
aliases: FrozenSet[str]
|
||||
help: str
|
||||
@ -27,12 +27,7 @@ try:
|
||||
type: str
|
||||
default: Optional[str]
|
||||
condition: bool
|
||||
except ImportError:
|
||||
OptionDict = Dict[str, Any] # type: ignore
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .config import KeyAction, KeySpec, SequenceMap # noqa
|
||||
from .conf.utils import BadLine # noqa
|
||||
|
||||
CONFIG_HELP = '''\
|
||||
Specify a path to the configuration file(s) to use. All configuration files are
|
||||
@ -733,10 +728,10 @@ def parse_args(
|
||||
|
||||
|
||||
SYSTEM_CONF = '/etc/xdg/kitty/kitty.conf'
|
||||
ShortcutMap = Dict[Tuple['KeySpec', ...], 'KeyAction']
|
||||
ShortcutMap = Dict[Tuple[KeySpec, ...], KeyAction]
|
||||
|
||||
|
||||
def print_shortcut(key_sequence: Iterable['KeySpec'], action: 'KeyAction') -> None:
|
||||
def print_shortcut(key_sequence: Iterable[KeySpec], action: KeyAction) -> None:
|
||||
if not getattr(print_shortcut, 'maps', None):
|
||||
from kitty.keys import defines
|
||||
v = vars(defines)
|
||||
@ -764,7 +759,7 @@ def print_shortcut(key_sequence: Iterable['KeySpec'], action: 'KeyAction') -> No
|
||||
print('\t', ' > '.join(keys), action)
|
||||
|
||||
|
||||
def print_shortcut_changes(defns: ShortcutMap, text: str, changes: Set[Tuple['KeySpec', ...]]) -> None:
|
||||
def print_shortcut_changes(defns: ShortcutMap, text: str, changes: Set[Tuple[KeySpec, ...]]) -> None:
|
||||
if changes:
|
||||
print(title(text))
|
||||
|
||||
@ -781,8 +776,8 @@ def compare_keymaps(final: ShortcutMap, initial: ShortcutMap) -> None:
|
||||
print_shortcut_changes(final, 'Changed shortcuts:', changed)
|
||||
|
||||
|
||||
def flatten_sequence_map(m: 'SequenceMap') -> ShortcutMap:
|
||||
ans: Dict[Tuple['KeySpec', ...], 'KeyAction'] = {}
|
||||
def flatten_sequence_map(m: SequenceMap) -> ShortcutMap:
|
||||
ans: Dict[Tuple[KeySpec, ...], KeyAction] = {}
|
||||
for key_spec, rest_map in m.items():
|
||||
for r, action in rest_map.items():
|
||||
ans[(key_spec,) + (r)] = action
|
||||
@ -811,7 +806,7 @@ def compare_opts(opts: OptionsStub) -> None:
|
||||
compare_keymaps(final, initial)
|
||||
|
||||
|
||||
def create_opts(args: CLIOptions, debug_config: bool = False, accumulate_bad_lines: Optional[List['BadLine']] = None) -> OptionsStub:
|
||||
def create_opts(args: CLIOptions, debug_config: bool = False, accumulate_bad_lines: Optional[List[BadLineType]] = None) -> OptionsStub:
|
||||
from .config import load_config
|
||||
config = tuple(resolve_config(SYSTEM_CONF, defconf, args.config))
|
||||
if debug_config:
|
||||
|
||||
@ -23,14 +23,9 @@ from .config_data import all_options, parse_mods, type_convert
|
||||
from .constants import cache_dir, defconf, is_macos
|
||||
from .key_names import get_key_name_lookup, key_name_aliases
|
||||
from .options_stub import Options as OptionsStub
|
||||
from .typing import TypedDict
|
||||
from .utils import log_error
|
||||
|
||||
try:
|
||||
from typing import TypedDict
|
||||
except ImportError:
|
||||
TypedDict = dict
|
||||
|
||||
|
||||
KeySpec = Tuple[int, bool, int]
|
||||
KeyMap = Dict[KeySpec, 'KeyAction']
|
||||
KeySequence = Tuple[KeySpec, ...]
|
||||
|
||||
@ -8,10 +8,9 @@ import pwd
|
||||
import sys
|
||||
from contextlib import suppress
|
||||
from functools import lru_cache
|
||||
from typing import TYPE_CHECKING, NamedTuple, Optional, Set
|
||||
from typing import NamedTuple, Optional, Set
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .options_stub import Options # noqa
|
||||
from .options_stub import Options
|
||||
|
||||
|
||||
class Version(NamedTuple):
|
||||
@ -20,11 +19,11 @@ class Version(NamedTuple):
|
||||
patch: int
|
||||
|
||||
|
||||
appname = 'kitty'
|
||||
version = Version(0, 16, 0)
|
||||
str_version = '.'.join(map(str, version))
|
||||
appname: str = 'kitty'
|
||||
version: Version = Version(0, 16, 0)
|
||||
str_version: str = '.'.join(map(str, version))
|
||||
_plat = sys.platform.lower()
|
||||
is_macos = 'darwin' in _plat
|
||||
is_macos: bool = 'darwin' in _plat
|
||||
base = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
@ -179,7 +178,7 @@ def detect_if_wayland_ok() -> bool:
|
||||
return ans == b'YES'
|
||||
|
||||
|
||||
def is_wayland(opts: Optional['Options'] = None) -> bool:
|
||||
def is_wayland(opts: Optional[Options] = None) -> bool:
|
||||
if is_macos:
|
||||
return False
|
||||
if opts is None:
|
||||
|
||||
@ -3,31 +3,25 @@
|
||||
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import re
|
||||
from typing import (
|
||||
TYPE_CHECKING, Dict, Generator, Iterable, List, Optional, Tuple
|
||||
)
|
||||
from typing import Dict, Generator, Iterable, List, Optional, Tuple
|
||||
|
||||
from kitty.fast_data_types import coretext_all_fonts
|
||||
from kitty.options_stub import Options
|
||||
from kitty.typing import CoreTextFont
|
||||
from kitty.utils import log_error
|
||||
|
||||
from . import ListedFont
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from kitty.fast_data_types import CoreTextFont as C
|
||||
CoreTextFont = C
|
||||
|
||||
|
||||
attr_map = {(False, False): 'font_family',
|
||||
(True, False): 'bold_font',
|
||||
(False, True): 'italic_font',
|
||||
(True, True): 'bold_italic_font'}
|
||||
|
||||
|
||||
FontMap = Dict[str, Dict[str, List['CoreTextFont']]]
|
||||
FontMap = Dict[str, Dict[str, List[CoreTextFont]]]
|
||||
|
||||
|
||||
def create_font_map(all_fonts: Iterable['CoreTextFont']) -> FontMap:
|
||||
def create_font_map(all_fonts: Iterable[CoreTextFont]) -> FontMap:
|
||||
ans: FontMap = {'family_map': {}, 'ps_map': {}, 'full_map': {}}
|
||||
for x in all_fonts:
|
||||
f = (x['family'] or '').lower()
|
||||
@ -56,11 +50,11 @@ def list_fonts() -> Generator[ListedFont, None, None]:
|
||||
yield {'family': f, 'full_name': fn, 'postscript_name': fd['postscript_name'] or '', 'is_monospace': is_mono}
|
||||
|
||||
|
||||
def find_best_match(family: str, bold: bool = False, italic: bool = False) -> 'CoreTextFont':
|
||||
def find_best_match(family: str, bold: bool = False, italic: bool = False) -> CoreTextFont:
|
||||
q = re.sub(r'\s+', ' ', family.lower())
|
||||
font_map = all_fonts_map()
|
||||
|
||||
def score(candidate: 'CoreTextFont') -> Tuple[int, int]:
|
||||
def score(candidate: CoreTextFont) -> Tuple[int, int]:
|
||||
style_match = 1 if candidate['bold'] == bold and candidate[
|
||||
'italic'
|
||||
] == italic else 0
|
||||
@ -90,8 +84,8 @@ def resolve_family(f: str, main_family: str, bold: bool = False, italic: bool =
|
||||
return f
|
||||
|
||||
|
||||
def get_font_files(opts: Options) -> Dict[str, 'CoreTextFont']:
|
||||
ans: Dict[str, 'CoreTextFont'] = {}
|
||||
def get_font_files(opts: Options) -> Dict[str, CoreTextFont]:
|
||||
ans: Dict[str, CoreTextFont] = {}
|
||||
for (bold, italic), attr in attr_map.items():
|
||||
face = find_best_match(resolve_family(getattr(opts, attr), opts.font_family, bold, italic), bold, italic)
|
||||
key = {(False, False): 'medium',
|
||||
@ -104,6 +98,6 @@ def get_font_files(opts: Options) -> Dict[str, 'CoreTextFont']:
|
||||
return ans
|
||||
|
||||
|
||||
def font_for_family(family: str) -> Tuple['CoreTextFont', bool, bool]:
|
||||
def font_for_family(family: str) -> Tuple[CoreTextFont, bool, bool]:
|
||||
ans = find_best_match(resolve_family(family, getattr(get_font_files, 'medium_family')))
|
||||
return ans, ans['bold'], ans['italic']
|
||||
|
||||
@ -4,31 +4,27 @@
|
||||
|
||||
import re
|
||||
from functools import lru_cache
|
||||
from typing import TYPE_CHECKING, Dict, Generator, List, Optional, Tuple, cast
|
||||
from typing import Dict, Generator, List, Optional, Tuple, cast
|
||||
|
||||
from kitty.fast_data_types import (
|
||||
FC_DUAL, FC_MONO, FC_SLANT_ITALIC, FC_SLANT_ROMAN, FC_WEIGHT_BOLD,
|
||||
FC_WEIGHT_REGULAR, fc_list, fc_match as fc_match_impl
|
||||
)
|
||||
from kitty.options_stub import Options
|
||||
from kitty.typing import FontConfigPattern
|
||||
|
||||
from . import ListedFont
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from kitty.fast_data_types import FontConfigPattern as F
|
||||
FontConfigPattern = F
|
||||
|
||||
|
||||
attr_map = {(False, False): 'font_family',
|
||||
(True, False): 'bold_font',
|
||||
(False, True): 'italic_font',
|
||||
(True, True): 'bold_italic_font'}
|
||||
|
||||
|
||||
FontMap = Dict[str, Dict[str, List['FontConfigPattern']]]
|
||||
FontMap = Dict[str, Dict[str, List[FontConfigPattern]]]
|
||||
|
||||
|
||||
def create_font_map(all_fonts: Tuple['FontConfigPattern', ...]) -> FontMap:
|
||||
def create_font_map(all_fonts: Tuple[FontConfigPattern, ...]) -> FontMap:
|
||||
ans: FontMap = {'family_map': {}, 'ps_map': {}, 'full_map': {}}
|
||||
for x in all_fonts:
|
||||
if 'path' not in x:
|
||||
@ -69,15 +65,15 @@ def family_name_to_key(family: str) -> str:
|
||||
|
||||
|
||||
@lru_cache()
|
||||
def fc_match(family: str, bold: bool, italic: bool, spacing: int = FC_MONO) -> 'FontConfigPattern':
|
||||
def fc_match(family: str, bold: bool, italic: bool, spacing: int = FC_MONO) -> FontConfigPattern:
|
||||
return fc_match_impl(family, bold, italic, spacing)
|
||||
|
||||
|
||||
def find_best_match(family: str, bold: bool = False, italic: bool = False, monospaced: bool = True) -> 'FontConfigPattern':
|
||||
def find_best_match(family: str, bold: bool = False, italic: bool = False, monospaced: bool = True) -> FontConfigPattern:
|
||||
q = family_name_to_key(family)
|
||||
font_map = all_fonts_map(monospaced)
|
||||
|
||||
def score(candidate: 'FontConfigPattern') -> Tuple[int, int]:
|
||||
def score(candidate: FontConfigPattern) -> Tuple[int, int]:
|
||||
bold_score = abs((FC_WEIGHT_BOLD if bold else FC_WEIGHT_REGULAR) - candidate.get('weight', 0))
|
||||
italic_score = abs((FC_SLANT_ITALIC if italic else FC_SLANT_ROMAN) - candidate.get('slant', 0))
|
||||
monospace_match = 0 if candidate.get('spacing') == 'MONO' else 1
|
||||
@ -118,8 +114,8 @@ def resolve_family(f: str, main_family: str, bold: bool, italic: bool) -> str:
|
||||
return f
|
||||
|
||||
|
||||
def get_font_files(opts: Options) -> Dict[str, 'FontConfigPattern']:
|
||||
ans: Dict[str, 'FontConfigPattern'] = {}
|
||||
def get_font_files(opts: Options) -> Dict[str, FontConfigPattern]:
|
||||
ans: Dict[str, FontConfigPattern] = {}
|
||||
for (bold, italic), attr in attr_map.items():
|
||||
rf = resolve_family(getattr(opts, attr), opts.font_family, bold, italic)
|
||||
font = find_best_match(rf, bold, italic)
|
||||
@ -131,6 +127,6 @@ def get_font_files(opts: Options) -> Dict[str, 'FontConfigPattern']:
|
||||
return ans
|
||||
|
||||
|
||||
def font_for_family(family: str) -> Tuple['FontConfigPattern', bool, bool]:
|
||||
def font_for_family(family: str) -> Tuple[FontConfigPattern, bool, bool]:
|
||||
ans = find_best_match(family, monospaced=False)
|
||||
return ans, ans.get('weight', 0) >= FC_WEIGHT_BOLD, ans.get('slant', FC_SLANT_ROMAN) != FC_SLANT_ROMAN
|
||||
|
||||
@ -6,9 +6,7 @@ import ctypes
|
||||
import sys
|
||||
from functools import partial
|
||||
from math import ceil, cos, floor, pi
|
||||
from typing import (
|
||||
TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, Union, cast
|
||||
)
|
||||
from typing import Any, Callable, Dict, List, Optional, Tuple, Union, cast
|
||||
|
||||
from kitty.config import defaults
|
||||
from kitty.constants import is_macos
|
||||
@ -21,18 +19,15 @@ from kitty.fonts.box_drawing import (
|
||||
BufType, render_box_char, render_missing_glyph
|
||||
)
|
||||
from kitty.options_stub import Options as OptionsStub
|
||||
from kitty.typing import CoreTextFont, FontConfigPattern
|
||||
from kitty.utils import log_error
|
||||
|
||||
if is_macos:
|
||||
from .core_text import get_font_files as get_font_files_coretext, font_for_family as font_for_family_macos
|
||||
if TYPE_CHECKING:
|
||||
from .core_text import CoreTextFont # noqa
|
||||
else:
|
||||
from .fontconfig import get_font_files as get_font_files_fontconfig, font_for_family as font_for_family_fontconfig
|
||||
if TYPE_CHECKING:
|
||||
from .fontconfig import FontConfigPattern # noqa
|
||||
|
||||
FontObject = Union['CoreTextFont', 'FontConfigPattern']
|
||||
FontObject = Union[CoreTextFont, FontConfigPattern]
|
||||
current_faces: List[Tuple[FontObject, bool, bool]] = []
|
||||
|
||||
|
||||
|
||||
8
kitty/key_encoding.py
generated
8
kitty/key_encoding.py
generated
@ -3,7 +3,7 @@
|
||||
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import string
|
||||
from typing import NamedTuple, Optional
|
||||
from typing import Dict, NamedTuple, Optional
|
||||
|
||||
from . import fast_data_types as defines
|
||||
from .key_names import key_name_aliases
|
||||
@ -457,14 +457,16 @@ class KeyEvent(NamedTuple):
|
||||
key: str
|
||||
|
||||
|
||||
PRESS, REPEAT, RELEASE = 1, 2, 4
|
||||
PRESS: int = 1
|
||||
REPEAT: int = 2
|
||||
RELEASE: int = 4
|
||||
SHIFT, ALT, CTRL, SUPER = 1, 2, 4, 8
|
||||
type_map = {'p': PRESS, 't': REPEAT, 'r': RELEASE}
|
||||
rtype_map = {v: k for k, v in type_map.items()}
|
||||
mod_map = {c: i for i, c in enumerate('ABCDEFGHIJKLMNOP')}
|
||||
rmod_map = {v: k for k, v in mod_map.items()}
|
||||
key_rmap = {}
|
||||
key_defs = {}
|
||||
key_defs: Dict[str, str] = {}
|
||||
config_key_map = {}
|
||||
config_mod_map = {
|
||||
'SHIFT': SHIFT,
|
||||
|
||||
@ -3,20 +3,15 @@
|
||||
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import string
|
||||
from typing import (
|
||||
TYPE_CHECKING, Any, Callable, Dict, Iterable, Optional, Tuple, Union
|
||||
)
|
||||
from typing import Any, Callable, Dict, Iterable, Optional, Tuple, Union
|
||||
|
||||
from . import fast_data_types as defines
|
||||
from .config import KeyAction, KeyMap, KeySpec, SequenceMap, SubSequenceMap
|
||||
from .key_encoding import KEY_MAP
|
||||
from .terminfo import key_as_bytes, modify_key_bytes
|
||||
from .typing import ScreenType, WindowType
|
||||
from .utils import base64_encode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .fast_data_types import Screen # noqa
|
||||
from .window import Window # noqa
|
||||
|
||||
|
||||
def modify_complex_key(name: Union[str, bytes], amt: int) -> bytes:
|
||||
q = name if isinstance(name, bytes) else key_as_bytes(name)
|
||||
@ -149,7 +144,7 @@ rmkx_key_map.update({
|
||||
cursor_key_mode_map = {True: smkx_key_map, False: rmkx_key_map}
|
||||
|
||||
|
||||
def keyboard_mode_name(screen: 'Screen') -> str:
|
||||
def keyboard_mode_name(screen: ScreenType) -> str:
|
||||
if screen.extended_keyboard:
|
||||
return 'kitty'
|
||||
return 'application' if screen.cursor_key_mode else 'normal'
|
||||
@ -270,7 +265,7 @@ def key_to_bytes(key: int, smkx: bool, extended: bool, mods: int, action: int) -
|
||||
return bytes(data)
|
||||
|
||||
|
||||
def interpret_key_event(key: int, native_key: int, mods: int, window: 'Window', action: int) -> bytes:
|
||||
def interpret_key_event(key: int, native_key: int, mods: int, window: WindowType, action: int) -> bytes:
|
||||
screen = window.screen
|
||||
if (
|
||||
action == defines.GLFW_PRESS or
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
from functools import lru_cache, partial
|
||||
from itertools import islice, repeat
|
||||
from typing import (
|
||||
TYPE_CHECKING, Callable, Collection, Deque, Dict, FrozenSet, Generator,
|
||||
Callable, Collection, Deque, Dict, FrozenSet, Generator,
|
||||
Iterable, List, NamedTuple, Optional, Sequence, Tuple, Union, cast
|
||||
)
|
||||
|
||||
@ -14,20 +14,7 @@ from .fast_data_types import (
|
||||
Region, set_active_window, swap_windows, viewport_for_window
|
||||
)
|
||||
from .options_stub import Options
|
||||
|
||||
try:
|
||||
from typing import TypedDict, Literal
|
||||
EdgeLiteral = Literal['left', 'top', 'right', 'bottom']
|
||||
except ImportError:
|
||||
TypedDict = dict
|
||||
EdgeLiteral = str # type: ignore
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .window import Window
|
||||
Window
|
||||
else:
|
||||
Window = object
|
||||
from .typing import WindowType, EdgeLiteral, TypedDict
|
||||
|
||||
|
||||
class Borders(NamedTuple):
|
||||
@ -53,7 +40,7 @@ draw_active_borders = True
|
||||
align_top_left = False
|
||||
LayoutDimension = Generator[Tuple[int, int], None, None]
|
||||
DecorationPairs = Sequence[Tuple[int, int]]
|
||||
WindowList = Union[List[Window], Deque[Window]]
|
||||
WindowList = Union[List[WindowType], Deque[WindowType]]
|
||||
|
||||
|
||||
class InternalNeighborsMap(TypedDict):
|
||||
@ -70,7 +57,7 @@ class NeighborsMap(TypedDict):
|
||||
bottom: Tuple[int, ...]
|
||||
|
||||
|
||||
def idx_for_id(win_id: int, windows: Iterable[Window]) -> Optional[int]:
|
||||
def idx_for_id(win_id: int, windows: Iterable[WindowType]) -> Optional[int]:
|
||||
for i, w in enumerate(windows):
|
||||
if w.id == win_id:
|
||||
return i
|
||||
@ -134,7 +121,7 @@ class Rect(NamedTuple):
|
||||
bottom: int
|
||||
|
||||
|
||||
def process_overlaid_windows(all_windows: WindowList) -> Tuple[FrozenSet[Window], WindowList]:
|
||||
def process_overlaid_windows(all_windows: WindowList) -> Tuple[FrozenSet[WindowType], WindowList]:
|
||||
id_map = {w.id: w for w in all_windows}
|
||||
overlaid_windows = frozenset(w for w in all_windows if w.overlay_window_id is not None and w.overlay_window_id in id_map)
|
||||
windows = [w for w in all_windows if w not in overlaid_windows]
|
||||
@ -151,25 +138,25 @@ def layout_single_window(xdecoration_pairs: DecorationPairs, ydecoration_pairs:
|
||||
return window_geometry(xstart, xnum, ystart, ynum)
|
||||
|
||||
|
||||
def left_blank_rect(w: Window, rects: List[Rect]) -> None:
|
||||
def left_blank_rect(w: WindowType, rects: List[Rect]) -> None:
|
||||
lt = w.geometry.left
|
||||
if lt > central.left:
|
||||
rects.append(Rect(central.left, central.top, lt, central.bottom + 1))
|
||||
|
||||
|
||||
def right_blank_rect(w: Window, rects: List[Rect]) -> None:
|
||||
def right_blank_rect(w: WindowType, rects: List[Rect]) -> None:
|
||||
r = w.geometry.right
|
||||
if r < central.right:
|
||||
rects.append(Rect(r, central.top, central.right + 1, central.bottom + 1))
|
||||
|
||||
|
||||
def top_blank_rect(w: Window, rects: List[Rect]) -> None:
|
||||
def top_blank_rect(w: WindowType, rects: List[Rect]) -> None:
|
||||
t = w.geometry.top
|
||||
if t > central.top:
|
||||
rects.append(Rect(central.left, central.top, central.right + 1, t))
|
||||
|
||||
|
||||
def bottom_blank_rect(w: Window, rects: List[Rect]) -> None:
|
||||
def bottom_blank_rect(w: WindowType, rects: List[Rect]) -> None:
|
||||
b = w.geometry.bottom
|
||||
# Need to use <= here as otherwise a single pixel row at the bottom of the
|
||||
# window is sometimes not covered. See https://github.com/kovidgoyal/kitty/issues/506
|
||||
@ -177,7 +164,7 @@ def bottom_blank_rect(w: Window, rects: List[Rect]) -> None:
|
||||
rects.append(Rect(central.left, b, central.right + 1, central.bottom + 1))
|
||||
|
||||
|
||||
def blank_rects_for_window(w: Window) -> List[Rect]:
|
||||
def blank_rects_for_window(w: WindowType) -> List[Rect]:
|
||||
ans: List[Rect] = []
|
||||
left_blank_rect(w, ans)
|
||||
top_blank_rect(w, ans)
|
||||
@ -288,7 +275,7 @@ class Layout: # {{{
|
||||
data[k] = v
|
||||
return type(self.layout_opts)(data)
|
||||
|
||||
def nth_window(self, all_windows: WindowList, num: int) -> Window:
|
||||
def nth_window(self, all_windows: WindowList, num: int) -> WindowType:
|
||||
windows = process_overlaid_windows(all_windows)[1]
|
||||
w = windows[min(num, len(windows) - 1)]
|
||||
return w
|
||||
@ -370,7 +357,7 @@ class Layout: # {{{
|
||||
def swap_windows_in_layout(self, all_windows: WindowList, a: int, b: int) -> None:
|
||||
all_windows[a], all_windows[b] = all_windows[b], all_windows[a]
|
||||
|
||||
def add_window(self, all_windows: WindowList, window: Window, current_active_window_idx: int, location: Optional[str] = None) -> int:
|
||||
def add_window(self, all_windows: WindowList, window: WindowType, current_active_window_idx: int, location: Optional[str] = None) -> int:
|
||||
active_window_idx = None
|
||||
if window.overlay_for is not None:
|
||||
i = idx_for_id(window.overlay_for, all_windows)
|
||||
@ -390,7 +377,7 @@ class Layout: # {{{
|
||||
self.set_active_window_in_os_window(active_window_idx)
|
||||
return active_window_idx
|
||||
|
||||
def do_add_window(self, all_windows: WindowList, window: Window, current_active_window_idx: Optional[int], location: Optional[str]) -> int:
|
||||
def do_add_window(self, all_windows: WindowList, window: WindowType, current_active_window_idx: Optional[int], location: Optional[str]) -> int:
|
||||
active_window_idx = None
|
||||
if location is not None:
|
||||
if location in ('after', 'vsplit', 'hsplit') and current_active_window_idx is not None and len(all_windows) > 1:
|
||||
@ -409,7 +396,7 @@ class Layout: # {{{
|
||||
all_windows.append(window)
|
||||
return active_window_idx
|
||||
|
||||
def remove_window(self, all_windows: WindowList, window: Window, current_active_window_idx: int, swapped: bool = False) -> int:
|
||||
def remove_window(self, all_windows: WindowList, window: WindowType, current_active_window_idx: int, swapped: bool = False) -> int:
|
||||
try:
|
||||
active_window = all_windows[current_active_window_idx]
|
||||
except Exception:
|
||||
@ -443,7 +430,7 @@ class Layout: # {{{
|
||||
self(all_windows, active_window_idx)
|
||||
return self.set_active_window(all_windows, active_window_idx)
|
||||
|
||||
def update_visibility(self, all_windows: WindowList, active_window: Window, overlaid_windows: Optional[FrozenSet[Window]] = None) -> None:
|
||||
def update_visibility(self, all_windows: WindowList, active_window: WindowType, overlaid_windows: Optional[FrozenSet[WindowType]] = None) -> None:
|
||||
if overlaid_windows is None:
|
||||
overlaid_windows = process_overlaid_windows(all_windows)[0]
|
||||
for i, w in enumerate(all_windows):
|
||||
@ -492,7 +479,7 @@ class Layout: # {{{
|
||||
return cast(int, idx_for_id(active_window.id, all_windows))
|
||||
|
||||
# Utils {{{
|
||||
def layout_single_window(self, w: Window) -> None:
|
||||
def layout_single_window(self, w: WindowType) -> None:
|
||||
mw = self.margin_width if self.single_window_margin_width < 0 else self.single_window_margin_width
|
||||
decoration_pairs = ((self.padding_width + mw, self.padding_width + mw),)
|
||||
wg = layout_single_window(decoration_pairs, decoration_pairs)
|
||||
@ -521,19 +508,19 @@ class Layout: # {{{
|
||||
height = central.height
|
||||
return layout_dimension(top, height, cell_height, decoration_pairs, bias=bias, left_align=align_top_left)
|
||||
|
||||
def simple_blank_rects(self, first_window: Window, last_window: Window) -> None:
|
||||
def simple_blank_rects(self, first_window: WindowType, last_window: WindowType) -> None:
|
||||
br = self.blank_rects
|
||||
left_blank_rect(first_window, br)
|
||||
top_blank_rect(first_window, br)
|
||||
right_blank_rect(last_window, br)
|
||||
|
||||
def between_blank_rect(self, left_window: Window, right_window: Window, vertical: bool = True) -> None:
|
||||
def between_blank_rect(self, left_window: WindowType, right_window: WindowType, vertical: bool = True) -> None:
|
||||
if vertical:
|
||||
self.blank_rects.append(Rect(left_window.geometry.right, central.top, right_window.geometry.left, central.bottom + 1))
|
||||
else:
|
||||
self.blank_rects.append(Rect(central.left, left_window.geometry.top, central.right + 1, right_window.geometry.bottom))
|
||||
|
||||
def bottom_blank_rect(self, window: Window) -> None:
|
||||
def bottom_blank_rect(self, window: WindowType) -> None:
|
||||
self.blank_rects.append(Rect(window.geometry.left, window.geometry.bottom, window.geometry.right, central.bottom + 1))
|
||||
# }}}
|
||||
|
||||
@ -543,24 +530,24 @@ class Layout: # {{{
|
||||
def do_layout_all_windows(self, windows: WindowList, active_window_idx: int, all_windows: WindowList) -> None:
|
||||
raise NotImplementedError()
|
||||
|
||||
def neighbors_for_window(self, window: Window, windows: WindowList) -> InternalNeighborsMap:
|
||||
def neighbors_for_window(self, window: WindowType, windows: WindowList) -> InternalNeighborsMap:
|
||||
return {'left': [], 'right': [], 'top': [], 'bottom': []}
|
||||
|
||||
def compute_needs_borders_map(self, windows: WindowList, active_window: Optional[Window]) -> Dict[int, bool]:
|
||||
def compute_needs_borders_map(self, windows: WindowList, active_window: Optional[WindowType]) -> Dict[int, bool]:
|
||||
return {w.id: ((w is active_window and draw_active_borders) or w.needs_attention) for w in windows}
|
||||
|
||||
def resolve_borders(self, windows: WindowList, active_window: Optional[Window]) -> Generator[Borders, None, None]:
|
||||
def resolve_borders(self, windows: WindowList, active_window: Optional[WindowType]) -> Generator[Borders, None, None]:
|
||||
if draw_minimal_borders:
|
||||
needs_borders_map = self.compute_needs_borders_map(windows, active_window)
|
||||
yield from self.minimal_borders(windows, active_window, needs_borders_map)
|
||||
else:
|
||||
yield from Layout.minimal_borders(self, windows, active_window, {})
|
||||
|
||||
def window_independent_borders(self, windows: WindowList, active_window: Optional[Window] = None) -> Generator[Tuple[int, int, int, int], None, None]:
|
||||
def window_independent_borders(self, windows: WindowList, active_window: Optional[WindowType] = None) -> Generator[Tuple[int, int, int, int], None, None]:
|
||||
return
|
||||
yield (0, 0, 0, 0) # type: ignore
|
||||
|
||||
def minimal_borders(self, windows: WindowList, active_window: Optional[Window], needs_borders_map: Dict[int, bool]) -> Generator[Borders, None, None]:
|
||||
def minimal_borders(self, windows: WindowList, active_window: Optional[WindowType], needs_borders_map: Dict[int, bool]) -> Generator[Borders, None, None]:
|
||||
for w in windows:
|
||||
if (w is active_window and draw_active_borders) or w.needs_attention:
|
||||
yield all_borders
|
||||
@ -592,7 +579,7 @@ class Stack(Layout): # {{{
|
||||
# Tall {{{
|
||||
|
||||
|
||||
def neighbors_for_tall_window(num_full_size_windows: int, window: Window, windows: WindowList) -> InternalNeighborsMap:
|
||||
def neighbors_for_tall_window(num_full_size_windows: int, window: WindowType, windows: WindowList) -> InternalNeighborsMap:
|
||||
idx = windows.index(window)
|
||||
prev = None if idx == 0 else windows[idx-1]
|
||||
nxt = None if idx == len(windows) - 1 else windows[idx+1]
|
||||
@ -713,10 +700,10 @@ class Tall(Layout):
|
||||
# left, top and right blank rects
|
||||
self.simple_blank_rects(windows[0], windows[-1])
|
||||
|
||||
def neighbors_for_window(self, window: Window, windows: WindowList) -> InternalNeighborsMap:
|
||||
def neighbors_for_window(self, window: WindowType, windows: WindowList) -> InternalNeighborsMap:
|
||||
return neighbors_for_tall_window(self.num_full_size_windows, window, windows)
|
||||
|
||||
def minimal_borders(self, windows: WindowList, active_window: Optional[Window], needs_borders_map: Dict[int, bool]) -> Generator[Borders, None, None]:
|
||||
def minimal_borders(self, windows: WindowList, active_window: Optional[WindowType], needs_borders_map: Dict[int, bool]) -> Generator[Borders, None, None]:
|
||||
last_i = len(windows) - 1
|
||||
for i, w in enumerate(windows):
|
||||
if needs_borders_map[w.id]:
|
||||
@ -778,7 +765,7 @@ class Fat(Tall): # {{{
|
||||
# left, top and right blank rects
|
||||
self.simple_blank_rects(windows[0], windows[-1])
|
||||
|
||||
def neighbors_for_window(self, window: Window, windows: WindowList) -> InternalNeighborsMap:
|
||||
def neighbors_for_window(self, window: WindowType, windows: WindowList) -> InternalNeighborsMap:
|
||||
idx = windows.index(window)
|
||||
prev = None if idx == 0 else windows[idx-1]
|
||||
nxt = None if idx == len(windows) - 1 else windows[idx+1]
|
||||
@ -925,7 +912,7 @@ class Grid(Layout):
|
||||
for i in range(ncols - 1):
|
||||
self.between_blank_rect(win_col_map[i][0], win_col_map[i + 1][0])
|
||||
|
||||
def minimal_borders(self, windows: WindowList, active_window: Optional[Window], needs_borders_map: Dict[int, bool]) -> Generator[Borders, None, None]:
|
||||
def minimal_borders(self, windows: WindowList, active_window: Optional[WindowType], needs_borders_map: Dict[int, bool]) -> Generator[Borders, None, None]:
|
||||
n = len(windows)
|
||||
ncols, nrows, special_rows, special_col = calc_grid_size(n)
|
||||
blank_row: List[Optional[int]] = [None for i in range(ncols)]
|
||||
@ -962,7 +949,7 @@ class Grid(Layout):
|
||||
bottom_neighbor_id is not None and not needs_borders_map[bottom_neighbor_id]
|
||||
)
|
||||
|
||||
def neighbors_for_window(self, window: Window, windows: WindowList) -> InternalNeighborsMap:
|
||||
def neighbors_for_window(self, window: WindowType, windows: WindowList) -> InternalNeighborsMap:
|
||||
n = len(windows)
|
||||
if n < 4:
|
||||
return neighbors_for_tall_window(1, window, windows)
|
||||
@ -1051,7 +1038,7 @@ class Vertical(Layout): # {{{
|
||||
# left, top and right blank rects
|
||||
self.simple_blank_rects(windows[0], windows[-1])
|
||||
|
||||
def minimal_borders(self, windows: WindowList, active_window: Optional[Window], needs_borders_map: Dict[int, bool]) -> Generator[Borders, None, None]:
|
||||
def minimal_borders(self, windows: WindowList, active_window: Optional[WindowType], needs_borders_map: Dict[int, bool]) -> Generator[Borders, None, None]:
|
||||
last_i = len(windows) - 1
|
||||
for i, w in enumerate(windows):
|
||||
if needs_borders_map[w.id]:
|
||||
@ -1065,7 +1052,7 @@ class Vertical(Layout): # {{{
|
||||
else:
|
||||
yield self.only_between_border
|
||||
|
||||
def neighbors_for_window(self, window: Window, windows: WindowList) -> InternalNeighborsMap:
|
||||
def neighbors_for_window(self, window: WindowType, windows: WindowList) -> InternalNeighborsMap:
|
||||
idx = windows.index(window)
|
||||
before = [] if window is windows[0] else [windows[idx-1].id]
|
||||
after = [] if window is windows[-1] else [windows[idx+1].id]
|
||||
@ -1220,7 +1207,7 @@ class Pair:
|
||||
tuple(map(pair.balanced_add, q))
|
||||
return pair
|
||||
|
||||
def apply_window_geometry(self, window_id: int, window_geometry: WindowGeometry, id_window_map: Dict[int, Window], id_idx_map: Dict[int, int]) -> None:
|
||||
def apply_window_geometry(self, window_id: int, window_geometry: WindowGeometry, id_window_map: Dict[int, WindowType], id_idx_map: Dict[int, int]) -> None:
|
||||
w = id_window_map[window_id]
|
||||
w.set_geometry(id_idx_map[window_id], window_geometry)
|
||||
if w.overlay_window_id is not None:
|
||||
@ -1228,7 +1215,7 @@ class Pair:
|
||||
if q is not None:
|
||||
q.set_geometry(id_idx_map[q.id], window_geometry)
|
||||
|
||||
def blank_rects_for_window(self, layout_object: Layout, window: Window, left: int, top: int, width: int, height: int) -> None:
|
||||
def blank_rects_for_window(self, layout_object: Layout, window: WindowType, left: int, top: int, width: int, height: int) -> None:
|
||||
right = left + width - 1
|
||||
bottom = top + height - 1
|
||||
g = window.geometry
|
||||
@ -1249,7 +1236,7 @@ class Pair:
|
||||
def layout_pair(
|
||||
self,
|
||||
left: int, top: int, width: int, height: int,
|
||||
id_window_map: Dict[int, Window],
|
||||
id_window_map: Dict[int, WindowType],
|
||||
id_idx_map: Dict[int, int],
|
||||
layout_object: Layout
|
||||
) -> None:
|
||||
@ -1436,7 +1423,7 @@ class Splits(Layout):
|
||||
def do_add_window(
|
||||
self,
|
||||
all_windows: WindowList,
|
||||
window: Window,
|
||||
window: WindowType,
|
||||
current_active_window_idx: Optional[int],
|
||||
location: Optional[str]
|
||||
) -> int:
|
||||
@ -1490,14 +1477,14 @@ class Splits(Layout):
|
||||
pair.bias = 0.5
|
||||
return True
|
||||
|
||||
def window_independent_borders(self, windows: WindowList, active_window: Optional[Window] = None) -> Generator[Tuple[int, int, int, int], None, None]:
|
||||
def window_independent_borders(self, windows: WindowList, active_window: Optional[WindowType] = None) -> Generator[Tuple[int, int, int, int], None, None]:
|
||||
if not draw_minimal_borders:
|
||||
return
|
||||
for pair in self.pairs_root.self_and_descendants():
|
||||
if pair.between_border is not None:
|
||||
yield pair.between_border
|
||||
|
||||
def neighbors_for_window(self, window: Window, windows: WindowList) -> InternalNeighborsMap:
|
||||
def neighbors_for_window(self, window: WindowType, windows: WindowList) -> InternalNeighborsMap:
|
||||
window_id = window.overlay_for or window.id
|
||||
pair = self.pairs_root.pair_for_window(window_id)
|
||||
ans: InternalNeighborsMap = {'left': [], 'right': [], 'top': [], 'bottom': []}
|
||||
|
||||
@ -10,7 +10,7 @@ import types
|
||||
from contextlib import suppress
|
||||
from functools import partial
|
||||
from typing import (
|
||||
TYPE_CHECKING, Any, Dict, Generator, Iterable, List, Optional, Tuple,
|
||||
Any, Dict, Generator, Iterable, List, Optional, Tuple,
|
||||
Union, cast
|
||||
)
|
||||
|
||||
@ -22,14 +22,11 @@ from .rc.base import (
|
||||
PayloadGetter, all_command_names, command_for_name,
|
||||
no_response as no_response_sentinel, parse_subcommand_cli
|
||||
)
|
||||
from .typing import BossType, WindowType
|
||||
from .utils import TTYIO, parse_address_spec
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .boss import Boss # noqa
|
||||
from .window import Window # noqa
|
||||
|
||||
|
||||
def handle_cmd(boss: 'Boss', window: Optional['Window'], serialized_cmd: str) -> Optional[Dict[str, Any]]:
|
||||
def handle_cmd(boss: BossType, window: Optional[WindowType], serialized_cmd: str) -> Optional[Dict[str, Any]]:
|
||||
cmd = json.loads(serialized_cmd)
|
||||
v = cmd['version']
|
||||
no_response = cmd.get('no_response', False)
|
||||
|
||||
@ -4,20 +4,16 @@
|
||||
|
||||
import shlex
|
||||
import sys
|
||||
from typing import (
|
||||
TYPE_CHECKING, Generator, List, NamedTuple, Optional, Tuple, Union
|
||||
)
|
||||
from typing import Generator, List, NamedTuple, Optional, Tuple, Union
|
||||
|
||||
from .cli_stub import CLIOptions
|
||||
from .config_data import to_layout_names
|
||||
from .constants import kitty_exe
|
||||
from .layout import all_layouts
|
||||
from .options_stub import Options
|
||||
from .typing import SpecialWindowInstance
|
||||
from .utils import log_error, resolved_shell
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .tabs import SpecialWindowInstance # noqa
|
||||
from .cli_stub import CLIOptions # noqa
|
||||
|
||||
|
||||
class WindowSizeOpts(NamedTuple):
|
||||
|
||||
@ -135,7 +131,7 @@ def parse_session(raw: str, opts: Options, default_title: Optional[str] = None)
|
||||
|
||||
def create_sessions(
|
||||
opts: Options,
|
||||
args: Optional['CLIOptions'] = None,
|
||||
args: Optional[CLIOptions] = None,
|
||||
special_window: Optional['SpecialWindowInstance'] = None,
|
||||
cwd_from: Optional[int] = None,
|
||||
respect_cwd: bool = False,
|
||||
|
||||
@ -7,7 +7,7 @@ from collections import deque
|
||||
from contextlib import suppress
|
||||
from functools import partial
|
||||
from typing import (
|
||||
TYPE_CHECKING, Deque, Dict, Generator, Iterator, List, NamedTuple,
|
||||
Deque, Dict, Generator, Iterator, List, NamedTuple,
|
||||
Optional, Pattern, Sequence, Tuple, cast
|
||||
)
|
||||
|
||||
@ -27,13 +27,7 @@ from .options_stub import Options
|
||||
from .tab_bar import TabBar, TabBarData
|
||||
from .utils import log_error, resolved_shell
|
||||
from .window import Window, WindowDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .session import Session, Tab as SessionTab
|
||||
SessionTab, Session
|
||||
from typing import TypedDict
|
||||
else:
|
||||
TypedDict = dict
|
||||
from .typing import TypedDict, SessionTab, SessionType
|
||||
|
||||
|
||||
class TabDict(TypedDict):
|
||||
@ -555,7 +549,7 @@ class Tab: # {{{
|
||||
|
||||
class TabManager: # {{{
|
||||
|
||||
def __init__(self, os_window_id: int, opts: Options, args: CLIOptions, startup_session: Optional['Session'] = None):
|
||||
def __init__(self, os_window_id: int, opts: Options, args: CLIOptions, startup_session: Optional[SessionType] = None):
|
||||
self.os_window_id = os_window_id
|
||||
self.last_active_tab_id = None
|
||||
self.opts, self.args = opts, args
|
||||
|
||||
21
kitty/typing.py
Normal file
21
kitty/typing.py
Normal file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
from typing import Tuple
|
||||
|
||||
|
||||
BossType = ChildType = TabType = WindowType = ScreenType = None
|
||||
BadLineType = KeySpec = SequenceMap = KeyActionType = None
|
||||
AddressFamily = PopenType = Socket = StartupCtx = None
|
||||
SessionTab = SessionType = LayoutType = SpecialWindowInstance = None
|
||||
MarkType = RemoteCommandType = CoreTextFont = FontConfigPattern = None
|
||||
KeyEventType = ImageManagerType = KittyCommonOpts = HandlerType = None
|
||||
GRT_t = GRT_a = GRT_d = GRT_f = GRT_m = GRT_o = None
|
||||
ScreenSize = KittensKeyActionType = MouseEvent = AbstractEventLoop = None
|
||||
TermManagerType = LoopType = Debug = GraphicsCommandType = None
|
||||
|
||||
CompletedProcess = Tuple
|
||||
TypedDict = dict
|
||||
EdgeLiteral = str
|
||||
Protocol = object
|
||||
51
kitty/typing.pyi
Normal file
51
kitty/typing.pyi
Normal file
@ -0,0 +1,51 @@
|
||||
from asyncio import AbstractEventLoop as AbstractEventLoop # noqa
|
||||
from socket import AddressFamily as AddressFamily, socket as Socket # noqa
|
||||
from typing import ( # noqa
|
||||
Literal, Protocol as Protocol, TypedDict as TypedDict
|
||||
)
|
||||
|
||||
from kittens.hints.main import Mark as MarkType # noqa
|
||||
from kittens.tui.handler import Handler as HandlerType # noqa
|
||||
from kittens.tui.images import ( # noqa
|
||||
GraphicsCommand as GraphicsCommandType, ImageManager as ImageManagerType
|
||||
)
|
||||
from kittens.tui.loop import ( # noqa
|
||||
Debug as Debug, Loop as LoopType, MouseEvent as MouseEvent,
|
||||
TermManager as TermManagerType
|
||||
)
|
||||
from kitty.conf.utils import KittensKeyAction as KittensKeyActionType # noqa
|
||||
|
||||
from .boss import Boss as BossType # noqa
|
||||
from .child import Child as ChildType # noqa
|
||||
from .conf.utils import BadLine as BadLineType # noqa
|
||||
from .fast_data_types import ( # noqa
|
||||
CoreTextFont as CoreTextFont, FontConfigPattern as FontConfigPattern,
|
||||
Screen as ScreenType, StartupCtx as StartupCtx
|
||||
)
|
||||
from .key_encoding import KeyEvent as KeyEventType # noqa
|
||||
from .layout import Layout as LayoutType # noqa
|
||||
from .rc.base import RemoteCommand as RemoteCommandType # noqa
|
||||
from .session import Session as SessionType, Tab as SessionTab # noqa
|
||||
from .tabs import ( # noqa
|
||||
SpecialWindowInstance as SpecialWindowInstance, Tab as TabType
|
||||
)
|
||||
from .utils import ScreenSize as ScreenSize # noqa
|
||||
from .window import Window as WindowType # noqa
|
||||
|
||||
from subprocess import ( # noqa; noqa
|
||||
CompletedProcess as CompletedProcess, Popen as PopenType
|
||||
)
|
||||
|
||||
|
||||
from .config import ( # noqa; noqa
|
||||
KeyAction as KeyActionType, KeyMap as KeyMap, KeySpec as KeySpec,
|
||||
KittyCommonOpts as KittyCommonOpts, SequenceMap as SequenceMap
|
||||
)
|
||||
|
||||
EdgeLiteral = Literal['left', 'top', 'right', 'bottom']
|
||||
GRT_a = Literal['t', 'T', 'q', 'p', 'd']
|
||||
GRT_f = Literal[24, 32, 100]
|
||||
GRT_t = Literal['d', 'f', 't', 's']
|
||||
GRT_o = Literal['z']
|
||||
GRT_m = Literal[0, 1]
|
||||
GRT_d = Literal['a', 'A', 'c', 'C', 'i', 'I', 'p', 'P', 'q', 'Q', 'x', 'X', 'y', 'Y', 'z', 'Z']
|
||||
@ -14,8 +14,8 @@ from contextlib import suppress
|
||||
from functools import lru_cache
|
||||
from time import monotonic
|
||||
from typing import (
|
||||
TYPE_CHECKING, Any, Callable, Dict, Generator, Iterable, List,
|
||||
NamedTuple, Optional, Tuple, Union, cast
|
||||
Any, Callable, Dict, Generator, Iterable, List, NamedTuple, Optional,
|
||||
Tuple, Union, cast
|
||||
)
|
||||
|
||||
from .constants import (
|
||||
@ -23,11 +23,7 @@ from .constants import (
|
||||
)
|
||||
from .options_stub import Options
|
||||
from .rgb import Color, to_color
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from subprocess import Popen # noqa
|
||||
from .fast_data_types import StartupCtx # noqa
|
||||
from socket import socket as Socket, AddressFamily # noqa
|
||||
from .typing import AddressFamily, PopenType, Socket, StartupCtx
|
||||
|
||||
BASE = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
@ -182,7 +178,7 @@ def command_for_open(program: Union[str, List[str]] = 'default') -> List[str]:
|
||||
return cmd
|
||||
|
||||
|
||||
def open_cmd(cmd: Union[Iterable[str], List[str]], arg: Union[None, Iterable[str], str] = None, cwd: Optional[str] = None) -> 'Popen':
|
||||
def open_cmd(cmd: Union[Iterable[str], List[str]], arg: Union[None, Iterable[str], str] = None, cwd: Optional[str] = None) -> PopenType:
|
||||
import subprocess
|
||||
if arg is not None:
|
||||
cmd = list(cmd)
|
||||
@ -193,7 +189,7 @@ def open_cmd(cmd: Union[Iterable[str], List[str]], arg: Union[None, Iterable[str
|
||||
return subprocess.Popen(tuple(cmd), stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, cwd=cwd or None)
|
||||
|
||||
|
||||
def open_url(url: str, program: Union[str, List[str]] = 'default', cwd: Optional[str] = None) -> 'Popen':
|
||||
def open_url(url: str, program: Union[str, List[str]] = 'default', cwd: Optional[str] = None) -> PopenType:
|
||||
return open_cmd(command_for_open(program), url, cwd=cwd)
|
||||
|
||||
|
||||
@ -367,7 +363,7 @@ class SingleInstance:
|
||||
single_instance = SingleInstance()
|
||||
|
||||
|
||||
def parse_address_spec(spec: str) -> Tuple['AddressFamily', Union[Tuple[str, int], str], Optional[str]]:
|
||||
def parse_address_spec(spec: str) -> Tuple[AddressFamily, Union[Tuple[str, int], str], Optional[str]]:
|
||||
import socket
|
||||
protocol, rest = spec.split(':', 1)
|
||||
socket_path = None
|
||||
|
||||
@ -10,8 +10,8 @@ from collections import deque
|
||||
from enum import IntEnum
|
||||
from itertools import chain
|
||||
from typing import (
|
||||
TYPE_CHECKING, Any, Callable, Deque, Dict, List, Optional, Pattern,
|
||||
Sequence, Tuple, Union
|
||||
Any, Callable, Deque, Dict, List, Optional, Pattern, Sequence, Tuple,
|
||||
Union
|
||||
)
|
||||
|
||||
from .child import ProcessDesc
|
||||
@ -32,20 +32,13 @@ from .keys import defines, extended_key_event, keyboard_mode_name
|
||||
from .options_stub import Options
|
||||
from .rgb import to_color
|
||||
from .terminfo import get_capabilities
|
||||
from .typing import ChildType, TabType, TypedDict
|
||||
from .utils import (
|
||||
color_as_int, get_primary_selection, load_shaders, open_cmd, open_url,
|
||||
parse_color_set, read_shell_environment, sanitize_title,
|
||||
set_primary_selection
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .tabs import Tab
|
||||
from .child import Child
|
||||
from typing import TypedDict
|
||||
Tab, Child
|
||||
else:
|
||||
TypedDict = dict
|
||||
|
||||
MatchPatternType = Union[Pattern[str], Tuple[Pattern[str], Optional[Pattern[str]]]]
|
||||
|
||||
|
||||
@ -183,8 +176,8 @@ class Window:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
tab: 'Tab',
|
||||
child: 'Child',
|
||||
tab: TabType,
|
||||
child: ChildType,
|
||||
opts: Options,
|
||||
args: CLIOptions,
|
||||
override_title: Optional[str] = None,
|
||||
@ -207,7 +200,7 @@ class Window:
|
||||
raise Exception('No tab with id: {} in OS Window: {} was found, or the window counter wrapped'.format(tab.id, tab.os_window_id))
|
||||
self.tab_id = tab.id
|
||||
self.os_window_id = tab.os_window_id
|
||||
self.tabref: Callable[[], Optional['Tab']] = weakref.ref(tab)
|
||||
self.tabref: Callable[[], Optional[TabType]] = weakref.ref(tab)
|
||||
self.clipboard_control_buffers = {'p': '', 'c': ''}
|
||||
self.destroyed = False
|
||||
self.geometry = WindowGeometry(0, 0, 0, 0, 0, 0)
|
||||
@ -221,7 +214,7 @@ class Window:
|
||||
else:
|
||||
setup_colors(self.screen, opts)
|
||||
|
||||
def change_tab(self, tab: 'Tab') -> None:
|
||||
def change_tab(self, tab: TabType) -> None:
|
||||
self.tab_id = tab.id
|
||||
self.os_window_id = tab.os_window_id
|
||||
self.tabref = weakref.ref(tab)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user