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