diff --git a/kitty/child.py b/kitty/child.py index 87ac8ad5a..a0188590b 100644 --- a/kitty/child.py +++ b/kitty/child.py @@ -7,13 +7,21 @@ import os import sys from collections import defaultdict from contextlib import contextmanager, suppress -from typing import DefaultDict, Dict, Generator, Iterable, List, Optional +from typing import ( + DefaultDict, Dict, Generator, Iterable, List, Optional, Sequence, Tuple +) import kitty.fast_data_types as fast_data_types from .constants import is_macos, shell_path, terminfo_dir from .options_stub import Options +try: + from typing import TypedDict +except ImportError: + TypedDict = dict + + if is_macos: from kitty.fast_data_types import ( cmdline_of_process, cwd_of_process as _cwd, environ_of_process as _environ_of_process, @@ -153,13 +161,19 @@ def set_default_env(val: Optional[Dict[str, str]] = None) -> None: setattr(default_env, 'env', env) -def openpty(): +def openpty() -> Tuple[int, int]: master, slave = os.openpty() # Note that master and slave are in blocking mode remove_cloexec(slave) fast_data_types.set_iutf8_fd(master, True) return master, slave +class ProcessDesc(TypedDict): + cwd: Optional[str] + pid: int + cmdline: Optional[Sequence[str]] + + class Child: child_fd: Optional[int] = None @@ -174,7 +188,7 @@ class Child: stdin: Optional[bytes] = None, env: Optional[Dict[str, str]] = None, cwd_from: Optional[int] = None, - allow_remote_control=False + allow_remote_control: bool = False ): self.allow_remote_control = allow_remote_control self.argv = argv @@ -254,27 +268,27 @@ class Child: remove_blocking(self.child_fd) return pid - def mark_terminal_ready(self): + def mark_terminal_ready(self) -> None: os.close(self.terminal_ready_fd) self.terminal_ready_fd = -1 @property - def foreground_processes(self) -> List[int]: + def foreground_processes(self) -> List[ProcessDesc]: if self.child_fd is None: return [] try: pgrp = os.tcgetpgrp(self.child_fd) foreground_processes = processes_in_group(pgrp) if pgrp >= 0 else [] - def process_desc(pid): - ans = {'pid': pid} + def process_desc(pid: int) -> ProcessDesc: + ans: ProcessDesc = {'pid': pid, 'cmdline': None, 'cwd': None} with suppress(Exception): ans['cmdline'] = cmdline_of_process(pid) with suppress(Exception): ans['cwd'] = cwd_of_process(pid) or None return ans - return list(map(process_desc, foreground_processes)) + return [process_desc(x) for x in foreground_processes] except Exception: return [] diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index 594739c55..c65e59cb9 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -1,3 +1,4 @@ +from ctypes import Array from typing import ( Any, AnyStr, Callable, Dict, List, NewType, Optional, Tuple, TypedDict, Union @@ -393,6 +394,8 @@ def default_color_table() -> Tuple[int, ...]: class FontConfigPattern(TypedDict): + path: str + index: int family: str full_name: str postscript_name: str @@ -400,6 +403,13 @@ class FontConfigPattern(TypedDict): spacing: str weight: int slant: int + hint_style: int + subpixel: int + lcdfilter: int + hinting: bool + scalable: bool + outline: bool + color: bool def fc_list( @@ -885,10 +895,10 @@ def set_send_sprite_to_gpu( def set_font_data( box_drawing_func: Callable[[int, int, int, float], - Tuple[int, Union[bytearray, bytes]]], + Tuple[int, Union[bytearray, bytes, Array]]], prerender_func: Callable[ [int, int, int, int, int, float, float, float, float], - Tuple[int, ...]], + Tuple[Union[Array, int], ...]], descriptor_for_idx: Callable[[int], Tuple[FontObject, bool, bool]], bold: int, italic: int, bold_italic: int, num_symbol_fonts: int, symbol_maps: Tuple[Tuple[int, int, int], ...], font_sz_in_pts: float, diff --git a/kitty/fonts/box_drawing.py b/kitty/fonts/box_drawing.py index f287c7bf3..c0832ea4a 100644 --- a/kitty/fonts/box_drawing.py +++ b/kitty/fonts/box_drawing.py @@ -49,12 +49,12 @@ def draw_vline(buf: BufType, width: int, y1: int, y2: int, x: int, level: int) - buf[x + y * width] = 255 -def half_hline(buf: BufType, width: int, height: int, level: int = 1, which: str = 'left', extend_by: int = 0): +def half_hline(buf: BufType, width: int, height: int, level: int = 1, which: str = 'left', extend_by: int = 0) -> None: x1, x2 = (0, extend_by + width // 2) if which == 'left' else (width // 2 - extend_by, width) draw_hline(buf, width, x1, x2, height // 2, level) -def half_vline(buf: BufType, width: int, height: int, level: int = 1, which: str = 'top', extend_by: int = 0): +def half_vline(buf: BufType, width: int, height: int, level: int = 1, which: str = 'top', extend_by: int = 0) -> None: y1, y2 = (0, height // 2 + extend_by) if which == 'top' else (height // 2 - extend_by, height) draw_vline(buf, width, y1, y2, width // 2, level) @@ -105,41 +105,41 @@ def hline(buf: BufType, width: int, height: int, level: int = 1) -> None: half_hline(buf, width, height, level=level, which='right') -def vline(buf: BufType, width: int, height: int, level=1) -> None: +def vline(buf: BufType, width: int, height: int, level: int = 1) -> None: half_vline(buf, width, height, level=level) half_vline(buf, width, height, level=level, which='bottom') -def hholes(buf: BufType, width: int, height: int, level=1, num=1) -> None: +def hholes(buf: BufType, width: int, height: int, level: int = 1, num: int = 1) -> None: hline(buf, width, height, level=level) add_hholes(buf, width, height, level=level, num=num) -def vholes(buf: BufType, width: int, height: int, level=1, num=1) -> None: +def vholes(buf: BufType, width: int, height: int, level: int = 1, num: int = 1) -> None: vline(buf, width, height, level=level) add_vholes(buf, width, height, level=level, num=num) -def corner(buf: BufType, width: int, height: int, hlevel=1, vlevel=1, which=None) -> None: - wh = 'right' if which in '┌└' else 'left' +def corner(buf: BufType, width: int, height: int, hlevel: int = 1, vlevel: int = 1, which: Optional[str] = None) -> None: + wh = 'right' if which is not None and which in '┌└' else 'left' half_hline(buf, width, height, level=hlevel, which=wh, extend_by=thickness(vlevel, horizontal=True) // 2) - wv = 'top' if which in '└┘' else 'bottom' + wv = 'top' if which is not None and which in '└┘' else 'bottom' half_vline(buf, width, height, level=vlevel, which=wv) -def vert_t(buf: BufType, width: int, height: int, a=1, b=1, c=1, which=None) -> None: +def vert_t(buf: BufType, width: int, height: int, a: int = 1, b: int = 1, c: int = 1, which: Optional[str] = None) -> None: half_vline(buf, width, height, level=a, which='top') half_hline(buf, width, height, level=b, which='left' if which == '┤' else 'right') half_vline(buf, width, height, level=c, which='bottom') -def horz_t(buf: BufType, width: int, height: int, a=1, b=1, c=1, which=None) -> None: +def horz_t(buf: BufType, width: int, height: int, a: int = 1, b: int = 1, c: int = 1, which: Optional[str] = None) -> None: half_hline(buf, width, height, level=a, which='left') half_hline(buf, width, height, level=b, which='right') half_vline(buf, width, height, level=c, which='top' if which == '┴' else 'bottom') -def cross(buf: BufType, width: int, height: int, a=1, b=1, c=1, d=1) -> None: +def cross(buf: BufType, width: int, height: int, a: int = 1, b: int = 1, c: int = 1, d: int = 1) -> None: half_hline(buf, width, height, level=a) half_hline(buf, width, height, level=b, which='right') half_vline(buf, width, height, level=c) @@ -400,17 +400,17 @@ def half_dvline(buf: BufType, width: int, height: int, level: int = 1, which: st return width // 2 - gap, width // 2 + gap -def dvline(buf: BufType, width: int, height: int, only=None, level=1): +def dvline(buf: BufType, width: int, height: int, only: Optional[str] = None, level: int = 1) -> Tuple[int, int]: half_dvline(buf, width, height, only=only, level=level) return half_dvline(buf, width, height, only=only, which='bottom', level=level) -def dhline(buf: BufType, width: int, height: int, only=None, level=1): +def dhline(buf: BufType, width: int, height: int, only: Optional[str] = None, level: int = 1) -> Tuple[int, int]: half_dhline(buf, width, height, only=only, level=level) return half_dhline(buf, width, height, only=only, which='bottom', level=level) -def dvcorner(buf: BufType, width: int, height: int, level=1, which='╒'): +def dvcorner(buf: BufType, width: int, height: int, level: int = 1, which: str = '╒') -> None: hw = 'right' if which in '╒╘' else 'left' half_dhline(buf, width, height, which=hw) vw = 'top' if which in '╘╛' else 'bottom' @@ -418,7 +418,7 @@ def dvcorner(buf: BufType, width: int, height: int, level=1, which='╒'): half_vline(buf, width, height, which=vw, extend_by=gap // 2 + thickness(level, horizontal=False)) -def dhcorner(buf: BufType, width: int, height: int, level=1, which='╓'): +def dhcorner(buf: BufType, width: int, height: int, level: int = 1, which: str = '╓') -> None: vw = 'top' if which in '╙╜' else 'bottom' half_dvline(buf, width, height, which=vw) hw = 'right' if which in '╓╙' else 'left' @@ -537,7 +537,7 @@ def shade(buf: BufType, width: int, height: int, light: bool = False, invert: bo buf[q] = 255 - dest[q] -def quad(buf, width, height, x=0, y=0): +def quad(buf: BufType, width: int, height: int, x: int = 0, y: int = 0) -> None: num_cols = width // 2 left = x * num_cols right = width if x else num_cols @@ -692,7 +692,7 @@ def test_char(ch: str, sz: int = 48) -> None: try: render_box_char(ch, buf, width, height) - def join_cells(*cells): + def join_cells(*cells: bytes) -> bytes: cells = tuple(bytes(x) for x in cells) return concat_cells(width, height, False, cells) @@ -710,11 +710,11 @@ def test_drawing(sz: int = 48, family: str = 'monospace') -> None: with setup_for_testing(family, sz) as (_, width, height): space = bytearray(width * height) - def join_cells(cells): + def join_cells(cells: Iterable[bytes]) -> bytes: cells = tuple(bytes(x) for x in cells) return concat_cells(width, height, False, cells) - def render_chr(ch): + def render_chr(ch: str) -> bytearray: if ch in box_chars: cell = bytearray(len(space)) render_box_char(ch, cell, width, height) diff --git a/kitty/fonts/core_text.py b/kitty/fonts/core_text.py index 7f2847576..b19e47e30 100644 --- a/kitty/fonts/core_text.py +++ b/kitty/fonts/core_text.py @@ -60,7 +60,7 @@ def find_best_match(family: str, bold: bool = False, italic: bool = False) -> 'C q = re.sub(r'\s+', ' ', family.lower()) font_map = all_fonts_map() - def score(candidate): + def score(candidate: 'CoreTextFont') -> Tuple[int, int]: style_match = 1 if candidate['bold'] == bold and candidate[ 'italic' ] == italic else 0 diff --git a/kitty/fonts/fontconfig.py b/kitty/fonts/fontconfig.py index afc452407..24450c851 100644 --- a/kitty/fonts/fontconfig.py +++ b/kitty/fonts/fontconfig.py @@ -43,7 +43,7 @@ def create_font_map(all_fonts: Tuple['FontConfigPattern', ...]) -> FontMap: @lru_cache() -def all_fonts_map(monospaced=True) -> FontMap: +def all_fonts_map(monospaced: bool = True) -> FontMap: if monospaced: ans = fc_list(FC_DUAL) + fc_list(FC_MONO) else: @@ -69,15 +69,15 @@ def family_name_to_key(family: str) -> str: @lru_cache() -def fc_match(family, bold, italic, spacing=FC_MONO) -> 'FontConfigPattern': +def fc_match(family: str, bold: bool, italic: bool, spacing: int = FC_MONO) -> 'FontConfigPattern': return fc_match_impl(family, bold, italic, spacing) -def find_best_match(family: str, bold=False, italic=False, monospaced=True) -> 'FontConfigPattern': +def find_best_match(family: str, bold: bool = False, italic: bool = False, monospaced: bool = True) -> 'FontConfigPattern': q = family_name_to_key(family) font_map = all_fonts_map(monospaced) - def score(candidate): + def score(candidate: 'FontConfigPattern') -> Tuple[int, int]: bold_score = abs((FC_WEIGHT_BOLD if bold else FC_WEIGHT_REGULAR) - candidate.get('weight', 0)) italic_score = abs((FC_SLANT_ITALIC if italic else FC_SLANT_ROMAN) - candidate.get('slant', 0)) monospace_match = 0 if candidate.get('spacing') == 'MONO' else 1 diff --git a/kitty/fonts/render.py b/kitty/fonts/render.py index 3ba72979b..80e32d59f 100644 --- a/kitty/fonts/render.py +++ b/kitty/fonts/render.py @@ -6,7 +6,9 @@ import ctypes import sys from functools import partial from math import ceil, cos, floor, pi -from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union, cast +from typing import ( + TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, Union, cast +) from kitty.config import defaults from kitty.constants import is_macos @@ -54,7 +56,7 @@ def coalesce_symbol_maps(maps: Dict[Tuple[int, int], str]) -> Dict[Tuple[int, in items = tuple((k, maps[k]) for k in sorted(maps)) ans = [items[0]] - def merge(prev_item, item): + def merge(prev_item: Tuple[Tuple[int, int], str], item: Tuple[Tuple[int, int], str]) -> None: s, e = item[0] pe = prev_item[0][1] ans[-1] = ((prev_item[0][0], max(pe, e)), prev_item[1]) @@ -88,11 +90,12 @@ def descriptor_for_idx(idx: int) -> Tuple[FontObject, bool, bool]: def dump_faces(ftypes: List[str], indices: Dict[str, int]) -> None: - def face_str(f): - f = f[0] - if is_macos: - return f - return '{}:{}'.format(f['path'], f['index']) + def face_str(f: Tuple[FontObject, bool, bool]) -> str: + fo = f[0] + if 'index' in fo: + return '{}:{}'.format(fo['path'], cast('FontConfigPattern', fo)['index']) + fo = cast('CoreTextFont', fo) + return fo['path'] log_error('Preloaded font faces:') log_error('normal face:', face_str(current_faces[0])) @@ -106,7 +109,7 @@ def dump_faces(ftypes: List[str], indices: Dict[str, int]) -> None: log_error(face_str(face)) -def set_font_family(opts: Optional[OptionsStub] = None, override_font_size=None, debug_font_matching=False): +def set_font_family(opts: Optional[OptionsStub] = None, override_font_size: Optional[float] = None, debug_font_matching: bool = False) -> None: global current_faces opts = opts or defaults sz = override_font_size or opts.font_size @@ -130,7 +133,10 @@ def set_font_family(opts: Optional[OptionsStub] = None, override_font_size=None, ) -def add_line(buf, cell_width, position, thickness, cell_height): +UnderlineCallback = Callable[[ctypes.Array, int, int, int, int], None] + + +def add_line(buf: ctypes.Array, cell_width: int, position: int, thickness: int, cell_height: int) -> None: y = position - thickness // 2 while thickness > 0 and -1 < y < cell_height: thickness -= 1 @@ -138,7 +144,7 @@ def add_line(buf, cell_width, position, thickness, cell_height): y += 1 -def add_dline(buf, cell_width, position, thickness, cell_height): +def add_dline(buf: ctypes.Array, cell_width: int, position: int, thickness: int, cell_height: int) -> None: a = min(position - thickness, cell_height - 1) b = min(position, cell_height - 1) top, bottom = min(a, b), max(a, b) @@ -158,12 +164,12 @@ def add_dline(buf, cell_width, position, thickness, cell_height): ctypes.memset(ctypes.addressof(buf) + (cell_width * y), 255, cell_width) -def add_curl(buf, cell_width, position, thickness, cell_height): +def add_curl(buf: ctypes.Array, cell_width: int, position: int, thickness: int, cell_height: int) -> None: max_x, max_y = cell_width - 1, cell_height - 1 xfactor = 2.0 * pi / max_x half_height = max(thickness // 2, 1) - def add_intensity(x, y, val): + def add_intensity(x: int, y: int, val: int) -> None: y += position y = min(y, max_y) idx = cell_width * y + x @@ -186,13 +192,25 @@ def add_curl(buf, cell_width, position, thickness, cell_height): def render_special( - underline=0, strikethrough=False, missing=False, - cell_width=None, cell_height=None, baseline=None, underline_position=None, underline_thickness=None): + underline: int = 0, + strikethrough: bool = False, + missing: bool = False, + cell_width: int = 0, cell_height: int = 0, + baseline: int = 0, + underline_position: int = 0, + underline_thickness: int = 0 +) -> ctypes.Array: underline_position = min(underline_position, cell_height - underline_thickness) CharTexture = ctypes.c_ubyte * (cell_width * cell_height) - ans = CharTexture if missing else CharTexture() - def dl(f, *a): + if missing: + buf = bytearray(cell_width * cell_height) + render_missing_glyph(buf, cell_width, cell_height) + return CharTexture.from_buffer(buf) + + ans = CharTexture() + + def dl(f: UnderlineCallback, *a: Any) -> None: try: f(ans, cell_width, *a) except Exception as e: @@ -203,23 +221,27 @@ def render_special( t = underline_thickness if underline > 1: t = max(1, min(cell_height - underline_position - 1, t)) - dl([None, add_line, add_dline, add_curl][underline], underline_position, t, cell_height) + dl([add_line, add_line, add_dline, add_curl][underline], underline_position, t, cell_height) if strikethrough: pos = int(0.65 * baseline) dl(add_line, pos, underline_thickness, cell_height) - if missing: - buf = bytearray(cell_width * cell_height) - render_missing_glyph(buf, cell_width, cell_height) - ans = CharTexture.from_buffer(buf) return ans -def render_cursor(which, cursor_beam_thickness, cursor_underline_thickness, cell_width=0, cell_height=0, dpi_x=0, dpi_y=0): +def render_cursor( + which: int, + cursor_beam_thickness: float, + cursor_underline_thickness: float, + cell_width: int = 0, + cell_height: int = 0, + dpi_x: float = 0, + dpi_y: float = 0 +) -> ctypes.Array: CharTexture = ctypes.c_ubyte * (cell_width * cell_height) ans = CharTexture() - def vert(edge, width_pt=1): + def vert(edge: str, width_pt: float = 1) -> None: width = max(1, min(int(round(width_pt * dpi_x / 72.0)), cell_width)) left = 0 if edge == 'left' else max(0, cell_width - width) for y in range(cell_height): @@ -227,7 +249,7 @@ def render_cursor(which, cursor_beam_thickness, cursor_underline_thickness, cell for x in range(offset, offset + width): ans[x] = 255 - def horz(edge, height_pt=1): + def horz(edge: str, height_pt: float = 1) -> None: height = max(1, min(int(round(height_pt * dpi_y / 72.0)), cell_height)) top = 0 if edge == 'top' else max(0, cell_height - height) for y in range(top, top + height): @@ -240,13 +262,24 @@ def render_cursor(which, cursor_beam_thickness, cursor_underline_thickness, cell elif which == 2: # underline horz('bottom', cursor_underline_thickness) elif which == 3: # hollow - vert('left'), vert('right'), horz('top'), horz('bottom') + vert('left') + vert('right') + horz('top') + horz('bottom') return ans def prerender_function( - cell_width, cell_height, baseline, underline_position, underline_thickness, - cursor_beam_thickness, cursor_underline_thickness, dpi_x, dpi_y): + cell_width: int, + cell_height: int, + baseline: int, + underline_position: int, + underline_thickness: int, + cursor_beam_thickness: float, + cursor_underline_thickness: float, + dpi_x: float, + dpi_y: float +) -> Tuple[Union[int, ctypes.Array], ...]: # Pre-render the special underline, strikethrough and missing and cursor cells f = partial( render_special, cell_width=cell_width, cell_height=cell_height, baseline=baseline, @@ -259,7 +292,7 @@ def prerender_function( return tuple(map(ctypes.addressof, cells)) + (cells,) -def render_box_drawing(codepoint: int, cell_width: int, cell_height: int, dpi: float): +def render_box_drawing(codepoint: int, cell_width: int, cell_height: int, dpi: float) -> Tuple[int, ctypes.Array]: CharTexture = ctypes.c_ubyte * (cell_width * cell_height) buf = CharTexture() render_box_char( @@ -270,16 +303,15 @@ def render_box_drawing(codepoint: int, cell_width: int, cell_height: int, dpi: f class setup_for_testing: - def __init__(self, family='monospace', size=11.0, dpi=96.0): + def __init__(self, family: str = 'monospace', size: float = 11.0, dpi: float = 96.0): self.family, self.size, self.dpi = family, size, dpi - def __enter__(self): - from collections import OrderedDict + def __enter__(self) -> Tuple[Dict[Tuple[int, int, int], bytes], int, int]: opts = defaults._replace(font_family=self.family, font_size=self.size) set_options(opts) - sprites = OrderedDict() + sprites = {} - def send_to_gpu(x, y, z, data): + def send_to_gpu(x: int, y: int, z: int, data: bytes) -> None: sprites[(x, y, z)] = data sprite_map_set_limits(100000, 100) @@ -292,11 +324,11 @@ class setup_for_testing: set_send_sprite_to_gpu(None) raise - def __exit__(self, *args): + def __exit__(self, *args: Any) -> None: set_send_sprite_to_gpu(None) -def render_string(text, family='monospace', size=11.0, dpi=96.0): +def render_string(text: str, family: str = 'monospace', size: float = 11.0, dpi: float = 96.0) -> Tuple[int, int, List[bytes]]: with setup_for_testing(family, size, dpi) as (sprites, cell_width, cell_height): s = Screen(None, 1, len(text)*2) line = s.line(0) @@ -307,7 +339,7 @@ def render_string(text, family='monospace', size=11.0, dpi=96.0): for i in reversed(range(s.columns)): sp = list(line.sprite_at(i)) sp[2] &= 0xfff - tsp = tuple(sp) + tsp = sp[0], sp[1], sp[2] if tsp == (0, 0, 0) and not found_content: continue found_content = True @@ -315,7 +347,9 @@ def render_string(text, family='monospace', size=11.0, dpi=96.0): return cell_width, cell_height, list(reversed(cells)) -def shape_string(text="abcd", family='monospace', size=11.0, dpi=96.0, path=None): +def shape_string( + text: str = "abcd", family: str = 'monospace', size: float = 11.0, dpi: float = 96.0, path: Optional[str] = None +) -> List[Tuple[int, int, int, Tuple[int, ...]]]: with setup_for_testing(family, size, dpi) as (sprites, cell_width, cell_height): s = Screen(None, 1, len(text)*2) line = s.line(0) @@ -323,7 +357,7 @@ def shape_string(text="abcd", family='monospace', size=11.0, dpi=96.0, path=None return test_shape(line, path) -def display_bitmap(rgb_data, width, height): +def display_bitmap(rgb_data: bytes, width: int, height: int) -> None: from tempfile import NamedTemporaryFile from kittens.icat.main import detect_support, show if not hasattr(display_bitmap, 'detected') and not detect_support(): @@ -335,7 +369,12 @@ def display_bitmap(rgb_data, width, height): show(f.name, width, height, 0, 32, align='left') -def test_render_string(text='Hello, world!', family='monospace', size=64.0, dpi=96.0): +def test_render_string( + text: str = 'Hello, world!', + family: str = 'monospace', + size: float = 64.0, + dpi: float = 96.0 +) -> None: from kitty.fast_data_types import concat_cells, current_fonts cell_width, cell_height, cells = render_string(text, family, size, dpi) @@ -352,7 +391,7 @@ def test_render_string(text='Hello, world!', family='monospace', size=64.0, dpi= print('\n') -def test_fallback_font(qtext: Optional[str] = None, bold=False, italic=False): +def test_fallback_font(qtext: Optional[str] = None, bold: bool = False, italic: bool = False) -> None: with setup_for_testing(): if qtext: trials = [qtext] @@ -366,7 +405,7 @@ def test_fallback_font(qtext: Optional[str] = None, bold=False, italic=False): sys.stdout.buffer.write((text + ' %s\n' % f).encode('utf-8')) -def showcase(): +def showcase() -> None: f = 'monospace' if is_macos else 'Liberation Mono' test_render_string('He\u0347\u0305llo\u0337, w\u0302or\u0306l\u0354d!', family=f) test_render_string('你好,世界', family=f) diff --git a/kitty/launch.py b/kitty/launch.py index ab06d8c35..6491d32f6 100644 --- a/kitty/launch.py +++ b/kitty/launch.py @@ -22,7 +22,7 @@ except ImportError: @lru_cache(maxsize=2) -def options_spec(): +def options_spec() -> str: return ''' --window-title --title The title to set for the new window. By default, title is controlled by the diff --git a/setup.cfg b/setup.cfg index 1f376e6a0..dadb82c7f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -27,7 +27,7 @@ warn_unused_configs = True check_untyped_defs = True # disallow_untyped_defs = True -[mypy-kitty.rc.*,kitty.conf.*] +[mypy-kitty.rc.*,kitty.conf.*,kitty.fonts.*,kitty.launch,kitty.child] disallow_untyped_defs = True [mypy-conf]