No top level typing issues found in kitty package

This commit is contained in:
Kovid Goyal 2020-03-04 07:31:22 +05:30
parent 5035ed61ee
commit c9ce2f47dc
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
9 changed files with 159 additions and 102 deletions

View File

@ -10,7 +10,7 @@ from .operations import commander
class Handler: class Handler:
image_manager_class = None # type: Type[ImageManagerBase] image_manager_class: Optional[Type['ImageManagerBase']] = None
def _initialize(self, screen_size, term_manager, schedule_write, tui_loop, debug, image_manager=None): def _initialize(self, screen_size, term_manager, schedule_write, tui_loop, debug, image_manager=None):
self.screen_size = screen_size self.screen_size = screen_size

View File

@ -36,12 +36,12 @@ MODES = dict(
) )
def set_mode(which, private=True) -> str: def set_mode(which: str, private=True) -> str:
num, private = MODES[which] num, private = MODES[which]
return '\033[{}{}h'.format(private, num) return '\033[{}{}h'.format(private, num)
def reset_mode(which) -> str: def reset_mode(which: str) -> str:
num, private = MODES[which] num, private = MODES[which]
return '\033[{}{}l'.format(private, num) return '\033[{}{}l'.format(private, num)
@ -66,12 +66,12 @@ def set_window_title(value) -> str:
return ('\033]2;' + value.replace('\033', '').replace('\x9c', '') + '\033\\') return ('\033]2;' + value.replace('\033', '').replace('\x9c', '') + '\033\\')
def set_line_wrapping(yes_or_no) -> str: def set_line_wrapping(yes_or_no: bool) -> str:
return (set_mode if yes_or_no else reset_mode)('DECAWM') return set_mode('DECAWM') if yes_or_no else reset_mode('DECAWM')
def set_cursor_visible(yes_or_no) -> str: def set_cursor_visible(yes_or_no: bool) -> str:
return (set_mode if yes_or_no else reset_mode)('DECTCEM') return set_mode('DECTEM') if yes_or_no else reset_mode('DECTCEM')
def set_cursor_position(x, y) -> str: # (0, 0) is top left def set_cursor_position(x, y) -> str: # (0, 0) is top left
@ -151,13 +151,16 @@ def styled(text, fg=None, bg=None, fg_intense=False, bg_intense=False, italic=No
end.append('4:0') end.append('4:0')
if italic is not None: if italic is not None:
s, e = (start, end) if italic else (end, start) s, e = (start, end) if italic else (end, start)
s.append('3'), e.append('23') s.append('3')
e.append('23')
if bold is not None: if bold is not None:
s, e = (start, end) if bold else (end, start) s, e = (start, end) if bold else (end, start)
s.append('1'), e.append('22') s.append('1')
e.append('22')
if reverse is not None: if reverse is not None:
s, e = (start, end) if reverse else (end, start) s, e = (start, end) if reverse else (end, start)
s.append('7'), e.append('27') s.append('7')
e.append('27')
if not start: if not start:
return text return text
return '\033[{}m{}\033[{}m'.format(';'.join(start), text, ';'.join(end)) return '\033[{}m{}\033[{}m'.format(';'.join(start), text, ';'.join(end))

View File

@ -7,6 +7,7 @@ import os
import sys import sys
from collections import defaultdict from collections import defaultdict
from contextlib import contextmanager, suppress from contextlib import contextmanager, suppress
from typing import DefaultDict, List
import kitty.fast_data_types as fast_data_types import kitty.fast_data_types as fast_data_types
@ -18,31 +19,31 @@ if is_macos:
process_group_map as _process_group_map process_group_map as _process_group_map
) )
def cwd_of_process(pid): def cwd_of_process(pid: int) -> str:
return os.path.realpath(_cwd(pid)) return os.path.realpath(_cwd(pid))
def process_group_map(): def process_group_map() -> DefaultDict[int, List[int]]:
ans = defaultdict(list) ans: DefaultDict[int, List] = defaultdict(list)
for pid, pgid in _process_group_map(): for pid, pgid in _process_group_map():
ans[pgid].append(pid) ans[pgid].append(pid)
return ans return ans
else: else:
def cmdline_of_process(pid): def cmdline_of_process(pid: int) -> List[str]:
with open('/proc/{}/cmdline'.format(pid), 'rb') as f: with open('/proc/{}/cmdline'.format(pid), 'rb') as f:
return list(filter(None, f.read().decode('utf-8').split('\0'))) return list(filter(None, f.read().decode('utf-8').split('\0')))
def cwd_of_process(pid): def cwd_of_process(pid: int) -> str:
ans = '/proc/{}/cwd'.format(pid) ans = '/proc/{}/cwd'.format(pid)
return os.path.realpath(ans) return os.path.realpath(ans)
def _environ_of_process(pid): def _environ_of_process(pid: int) -> str:
with open('/proc/{}/environ'.format(pid), 'rb') as f: with open('/proc/{}/environ'.format(pid), 'rb') as f:
return f.read().decode('utf-8') return f.read().decode('utf-8')
def process_group_map(): def process_group_map() -> DefaultDict[int, List[int]]:
ans = defaultdict(list) ans: DefaultDict[int, List[int]] = defaultdict(list)
for x in os.listdir('/proc'): for x in os.listdir('/proc'):
try: try:
pid = int(x) pid = int(x)

View File

@ -228,71 +228,75 @@ For example: {appname} sh -c "echo hello, world. Press ENTER to quit; read"
For comprehensive documentation for kitty, please see: https://sw.kovidgoyal.net/kitty/''').format(appname=appname) For comprehensive documentation for kitty, please see: https://sw.kovidgoyal.net/kitty/''').format(appname=appname)
def print_help_for_seq(seq, usage, message, appname): class PrintHelpForSeq:
from kitty.utils import screen_size_function
screen_size = screen_size_function()
try:
linesz = min(screen_size().cols, 76)
except OSError:
linesz = 76
blocks = []
a = blocks.append
def wa(text, indent=0, leading_indent=None): allow_pager = True
if leading_indent is None:
leading_indent = indent
j = '\n' + (' ' * indent)
lines = []
for l in text.splitlines():
if l:
lines.extend(wrap(l, limit=linesz - indent))
else:
lines.append('')
a((' ' * leading_indent) + j.join(lines))
usage = '[program-to-run ...]' if usage is None else usage def __call__(self, seq, usage, message, appname):
optstring = '[options] ' if seq else '' from kitty.utils import screen_size_function
a('{}: {} {}{}'.format(title('Usage'), bold(yellow(appname)), optstring, usage)) screen_size = screen_size_function()
a('')
message = message or default_msg
wa(prettify(message))
a('')
if seq:
a('{}:'.format(title('Options')))
for opt in seq:
if isinstance(opt, str):
a('{}:'.format(title(opt)))
continue
help_text = opt['help']
if help_text == '!':
continue # hidden option
a(' ' + ', '.join(map(green, sorted(opt['aliases']))))
if not opt.get('type', '').startswith('bool-'):
blocks[-1] += '={}'.format(italic(opt['dest'].upper()))
if opt.get('help'):
defval = opt.get('default')
t = help_text.replace('%default', str(defval))
wa(prettify(t.strip()), indent=4)
if defval is not None:
wa('Default: {}'.format(defval), indent=4)
if 'choices' in opt:
wa('Choices: {}'.format(', '.join(opt['choices'])), indent=4)
a('')
text = '\n'.join(blocks) + '\n\n' + version()
if print_help_for_seq.allow_pager and sys.stdout.isatty():
import subprocess
p = subprocess.Popen(['less', '-isRXF'], stdin=subprocess.PIPE)
try: try:
p.communicate(text.encode('utf-8')) linesz = min(screen_size().cols, 76)
except KeyboardInterrupt: except OSError:
raise SystemExit(1) linesz = 76
raise SystemExit(p.wait()) blocks = []
else: a = blocks.append
print(text)
def wa(text, indent=0, leading_indent=None):
if leading_indent is None:
leading_indent = indent
j = '\n' + (' ' * indent)
lines = []
for l in text.splitlines():
if l:
lines.extend(wrap(l, limit=linesz - indent))
else:
lines.append('')
a((' ' * leading_indent) + j.join(lines))
usage = '[program-to-run ...]' if usage is None else usage
optstring = '[options] ' if seq else ''
a('{}: {} {}{}'.format(title('Usage'), bold(yellow(appname)), optstring, usage))
a('')
message = message or default_msg
wa(prettify(message))
a('')
if seq:
a('{}:'.format(title('Options')))
for opt in seq:
if isinstance(opt, str):
a('{}:'.format(title(opt)))
continue
help_text = opt['help']
if help_text == '!':
continue # hidden option
a(' ' + ', '.join(map(green, sorted(opt['aliases']))))
if not opt.get('type', '').startswith('bool-'):
blocks[-1] += '={}'.format(italic(opt['dest'].upper()))
if opt.get('help'):
defval = opt.get('default')
t = help_text.replace('%default', str(defval))
wa(prettify(t.strip()), indent=4)
if defval is not None:
wa('Default: {}'.format(defval), indent=4)
if 'choices' in opt:
wa('Choices: {}'.format(', '.join(opt['choices'])), indent=4)
a('')
text = '\n'.join(blocks) + '\n\n' + version()
if print_help_for_seq.allow_pager and sys.stdout.isatty():
import subprocess
p = subprocess.Popen(['less', '-isRXF'], stdin=subprocess.PIPE)
try:
p.communicate(text.encode('utf-8'))
except KeyboardInterrupt:
raise SystemExit(1)
raise SystemExit(p.wait())
else:
print(text)
print_help_for_seq.allow_pager = True print_help_for_seq = PrintHelpForSeq()
def seq_as_rst(seq, usage, message, appname, heading_char='-'): def seq_as_rst(seq, usage, message, appname, heading_char='-'):

View File

@ -5,7 +5,7 @@
# Utils {{{ # Utils {{{
import os import os
from gettext import gettext as _ from gettext import gettext as _
from typing import Mapping, Union from typing import Dict, Union
from . import fast_data_types as defines from . import fast_data_types as defines
from .conf.definition import Option, Shortcut, option_func from .conf.definition import Option, Shortcut, option_func
@ -55,7 +55,7 @@ def uniq(vals, result_type=list):
# Groups {{{ # Groups {{{
all_options: Mapping[str, Union[Option, Shortcut]] = {} all_options: Dict[str, Union[Option, Shortcut]] = {}
o, k, g, all_groups = option_func(all_options, { o, k, g, all_groups = option_func(all_options, {

View File

@ -1,10 +1,10 @@
from collections import namedtuple
from typing import ( from typing import (
Any, Callable, List, Dict, NewType, Optional, Tuple, Union Any, Callable, List, Dict, NewType, Optional, Tuple, Union
) )
from kitty.cli import Namespace from kitty.cli import Namespace
# Constants {{{
GLFW_IBEAM_CURSOR: int GLFW_IBEAM_CURSOR: int
GLFW_KEY_UNKNOWN: int GLFW_KEY_UNKNOWN: int
GLFW_KEY_SPACE: int GLFW_KEY_SPACE: int
@ -319,6 +319,23 @@ FC_WEIGHT_BOLD: int
FC_SLANT_ROMAN: int FC_SLANT_ROMAN: int
FC_SLANT_ITALIC: int FC_SLANT_ITALIC: int
BORDERS_PROGRAM: int BORDERS_PROGRAM: int
# }}}
def process_group_map() -> Tuple[Tuple[int, int], ...]:
pass
def environ_of_process(pid: int) -> str:
pass
def cmdline_of_process(pid: int) -> List[str]:
pass
def cwd_of_process(pid: int) -> str:
pass
def default_color_table() -> Tuple[int, ...]: def default_color_table() -> Tuple[int, ...]:
@ -545,10 +562,18 @@ def swap_tabs(os_window_id: int, a: int, b: int) -> None:
pass pass
def swap_windows(os_window_id: int, tab_id: int, a: int, b: int) -> None:
pass
def set_active_tab(os_window_id: int, a: int) -> None: def set_active_tab(os_window_id: int, a: int) -> None:
pass pass
def set_active_window(os_window_id: int, tab_id: int, window_idx: int) -> None:
pass
def ring_bell() -> None: def ring_bell() -> None:
pass pass
@ -589,7 +614,16 @@ def cell_size_for_window(os_window_id: int) -> Tuple[int, int]:
pass pass
Region = namedtuple('Region', 'left top right bottom width height') class Region:
left: int
top: int
right: int
bottom: int
width: int
height: int
def __init__(self, x: Tuple[int, int, int, int, int, int]):
pass
def viewport_for_window(os_window_id: int) -> Tuple[Region, Region, int, int, int, int]: def viewport_for_window(os_window_id: int) -> Tuple[Region, Region, int, int, int, int]:
@ -690,7 +724,7 @@ class ChildMonitor:
def __init__( def __init__(
self, self,
death_notify: Callable[[int], None], death_notify: Callable[[int], None],
dump_callback: Optional[callable], dump_callback: Optional[Callable],
talk_fd: int = -1, listen_fd: int = -1 talk_fd: int = -1, listen_fd: int = -1
): ):
pass pass

View File

@ -5,6 +5,7 @@
from collections import namedtuple from collections import namedtuple
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 Callable, Dict, Generator, List, Optional, Tuple, Union
from .constants import WindowGeometry from .constants import WindowGeometry
from .fast_data_types import ( from .fast_data_types import (
@ -19,6 +20,11 @@ no_borders = False, False, False, False
draw_minimal_borders = False draw_minimal_borders = False
draw_active_borders = True draw_active_borders = True
align_top_left = False align_top_left = False
LayoutDimension = Generator[Tuple[int, int], None, None]
XOrYLayout = Union[
Callable[['Layout', int, Optional[List[float]], Optional[int], Optional[int]], LayoutDimension],
Callable[['Layout', int, bool, Optional[List[float]], Optional[int], Optional[int]], LayoutDimension]
]
def idx_for_id(win_id, windows): def idx_for_id(win_id, windows):
@ -34,7 +40,10 @@ def set_layout_options(opts):
align_top_left = opts.placement_strategy == 'top-left' align_top_left = opts.placement_strategy == 'top-left'
def layout_dimension(start_at, length, cell_length, decoration_pairs, left_align=False, bias=None): def layout_dimension(
start_at, length, cell_length, decoration_pairs,
left_align=False, bias: Optional[List[float]] = None
) -> LayoutDimension:
number_of_windows = len(decoration_pairs) number_of_windows = len(decoration_pairs)
number_of_cells = length // cell_length number_of_cells = length // cell_length
space_needed_for_decorations = sum(map(sum, decoration_pairs)) space_needed_for_decorations = sum(map(sum, decoration_pairs))
@ -159,7 +168,7 @@ def variable_bias(num_windows, candidate):
class Layout: # {{{ class Layout: # {{{
name = None name: Optional[str] = None
needs_window_borders = True needs_window_borders = True
needs_all_windows = False needs_all_windows = False
only_active_window_visible = False only_active_window_visible = False
@ -405,7 +414,7 @@ class Layout: # {{{
w.set_geometry(0, wg) w.set_geometry(0, wg)
self.blank_rects = blank_rects_for_window(w) self.blank_rects = blank_rects_for_window(w)
def xlayout(self, num, bias=None, left=None, width=None): def xlayout(self, num: int, bias: Optional[List[float]] = None, left: Optional[int] = None, width: Optional[int] = None) -> LayoutDimension:
decoration = self.margin_width + self.border_width + self.padding_width decoration = self.margin_width + self.border_width + self.padding_width
decoration_pairs = tuple(repeat((decoration, decoration), num)) decoration_pairs = tuple(repeat((decoration, decoration), num))
if left is None: if left is None:
@ -414,7 +423,9 @@ class Layout: # {{{
width = central.width width = central.width
return layout_dimension(left, width, cell_width, decoration_pairs, bias=bias, left_align=align_top_left) return layout_dimension(left, width, cell_width, decoration_pairs, bias=bias, left_align=align_top_left)
def ylayout(self, num, left_align=True, bias=None, top=None, height=None): def ylayout(
self, num: int, left_align: bool = True, bias: Optional[List[float]] = None, top: Optional[int] = None, height: Optional[int] = None
) -> LayoutDimension:
decoration = self.margin_width + self.border_width + self.padding_width decoration = self.margin_width + self.border_width + self.padding_width
decoration_pairs = tuple(repeat((decoration, decoration), num)) decoration_pairs = tuple(repeat((decoration, decoration), num))
if top is None: if top is None:
@ -511,7 +522,7 @@ def neighbors_for_tall_window(num_full_size_windows, window, windows):
class Tall(Layout): class Tall(Layout):
name = 'tall' name = 'tall'
vlayout = Layout.ylayout vlayout: XOrYLayout = Layout.ylayout
main_is_horizontal = True main_is_horizontal = True
only_between_border = False, False, False, True only_between_border = False, False, False, True
only_main_border = False, False, True, False only_main_border = False, False, True, False
@ -892,7 +903,7 @@ class Vertical(Layout): # {{{
name = 'vertical' name = 'vertical'
main_is_horizontal = False main_is_horizontal = False
vlayout = Layout.ylayout vlayout: XOrYLayout = Layout.ylayout
only_between_border = False, False, False, True only_between_border = False, False, False, True
def variable_layout(self, num_windows, biased_map): def variable_layout(self, num_windows, biased_map):
@ -1408,17 +1419,20 @@ class Splits(Layout):
all_layouts = {o.name: o for o in globals().values() if isinstance(o, type) and issubclass(o, Layout) and o is not Layout} all_layouts = {o.name: o for o in globals().values() if isinstance(o, type) and issubclass(o, Layout) and o is not Layout}
def create_layout_object_for(name, os_window_id, tab_id, margin_width, single_window_margin_width, padding_width, border_width, layout_opts=''): class CreateLayoutObjectFor:
key = name, os_window_id, tab_id, margin_width, single_window_margin_width, padding_width, border_width, layout_opts cache: Dict[Tuple, Layout] = {}
ans = create_layout_object_for.cache.get(key)
if ans is None: def __call__(self, name, os_window_id, tab_id, margin_width, single_window_margin_width, padding_width, border_width, layout_opts=''):
name, layout_opts = name.partition(':')[::2] key = name, os_window_id, tab_id, margin_width, single_window_margin_width, padding_width, border_width, layout_opts
ans = create_layout_object_for.cache[key] = all_layouts[name]( ans = create_layout_object_for.cache.get(key)
os_window_id, tab_id, margin_width, single_window_margin_width, padding_width, border_width, layout_opts) if ans is None:
return ans name, layout_opts = name.partition(':')[::2]
ans = create_layout_object_for.cache[key] = all_layouts[name](
os_window_id, tab_id, margin_width, single_window_margin_width, padding_width, border_width, layout_opts)
return ans
create_layout_object_for.cache = {} create_layout_object_for = CreateLayoutObjectFor()
def evict_cached_layouts(tab_id): def evict_cached_layouts(tab_id):

View File

@ -2,7 +2,7 @@
# vim:fileencoding=utf-8 # vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net>
from typing import Mapping from typing import Dict
from .constants import is_macos, logo_png_file from .constants import is_macos, logo_png_file
@ -26,8 +26,8 @@ else:
from .fast_data_types import dbus_send_notification from .fast_data_types import dbus_send_notification
from .constants import get_boss from .constants import get_boss
alloc_map: Mapping[int, str] = {} alloc_map: Dict[int, str] = {}
identifier_map: Mapping[str, int] = {} identifier_map: Dict[str, int] = {}
def dbus_notification_created(alloc_id, notification_id): def dbus_notification_created(alloc_id, notification_id):
identifier = alloc_map.pop(alloc_id, None) identifier = alloc_map.pop(alloc_id, None)

View File

@ -4,6 +4,7 @@
import re import re
from binascii import hexlify, unhexlify from binascii import hexlify, unhexlify
from typing import cast, Dict
def modify_key_bytes(keybytes, amt): def modify_key_bytes(keybytes, amt):
@ -406,7 +407,7 @@ termcap_aliases.update({
'FV FW FX FY FZ Fa Fb Fc Fd Fe Ff Fg Fh Fi Fj Fk Fl Fm Fn Fo ' 'FV FW FX FY FZ Fa Fb Fc Fd Fe Ff Fg Fh Fi Fj Fk Fl Fm Fn Fo '
'Fp Fq Fr'.split(), 1)}) 'Fp Fq Fr'.split(), 1)})
queryable_capabilities = numeric_capabilities.copy() queryable_capabilities = cast(Dict[str, str], numeric_capabilities.copy())
queryable_capabilities.update(string_capabilities) queryable_capabilities.update(string_capabilities)
extra = (bool_capabilities | numeric_capabilities.keys() | string_capabilities.keys()) - set(termcap_aliases.values()) extra = (bool_capabilities | numeric_capabilities.keys() | string_capabilities.keys()) - set(termcap_aliases.values())
no_termcap_for = frozenset( no_termcap_for = frozenset(