more typing work
This commit is contained in:
parent
25be705bcf
commit
8803eeb890
@ -7,13 +7,21 @@ 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, 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
|
import kitty.fast_data_types as fast_data_types
|
||||||
|
|
||||||
from .constants import is_macos, shell_path, terminfo_dir
|
from .constants import is_macos, shell_path, terminfo_dir
|
||||||
from .options_stub import Options
|
from .options_stub import Options
|
||||||
|
|
||||||
|
try:
|
||||||
|
from typing import TypedDict
|
||||||
|
except ImportError:
|
||||||
|
TypedDict = dict
|
||||||
|
|
||||||
|
|
||||||
if is_macos:
|
if is_macos:
|
||||||
from kitty.fast_data_types import (
|
from kitty.fast_data_types import (
|
||||||
cmdline_of_process, cwd_of_process as _cwd, environ_of_process as _environ_of_process,
|
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)
|
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
|
master, slave = os.openpty() # Note that master and slave are in blocking mode
|
||||||
remove_cloexec(slave)
|
remove_cloexec(slave)
|
||||||
fast_data_types.set_iutf8_fd(master, True)
|
fast_data_types.set_iutf8_fd(master, True)
|
||||||
return master, slave
|
return master, slave
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessDesc(TypedDict):
|
||||||
|
cwd: Optional[str]
|
||||||
|
pid: int
|
||||||
|
cmdline: Optional[Sequence[str]]
|
||||||
|
|
||||||
|
|
||||||
class Child:
|
class Child:
|
||||||
|
|
||||||
child_fd: Optional[int] = None
|
child_fd: Optional[int] = None
|
||||||
@ -174,7 +188,7 @@ class Child:
|
|||||||
stdin: Optional[bytes] = None,
|
stdin: Optional[bytes] = None,
|
||||||
env: Optional[Dict[str, str]] = None,
|
env: Optional[Dict[str, str]] = None,
|
||||||
cwd_from: Optional[int] = None,
|
cwd_from: Optional[int] = None,
|
||||||
allow_remote_control=False
|
allow_remote_control: bool = False
|
||||||
):
|
):
|
||||||
self.allow_remote_control = allow_remote_control
|
self.allow_remote_control = allow_remote_control
|
||||||
self.argv = argv
|
self.argv = argv
|
||||||
@ -254,27 +268,27 @@ class Child:
|
|||||||
remove_blocking(self.child_fd)
|
remove_blocking(self.child_fd)
|
||||||
return pid
|
return pid
|
||||||
|
|
||||||
def mark_terminal_ready(self):
|
def mark_terminal_ready(self) -> None:
|
||||||
os.close(self.terminal_ready_fd)
|
os.close(self.terminal_ready_fd)
|
||||||
self.terminal_ready_fd = -1
|
self.terminal_ready_fd = -1
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def foreground_processes(self) -> List[int]:
|
def foreground_processes(self) -> List[ProcessDesc]:
|
||||||
if self.child_fd is None:
|
if self.child_fd is None:
|
||||||
return []
|
return []
|
||||||
try:
|
try:
|
||||||
pgrp = os.tcgetpgrp(self.child_fd)
|
pgrp = os.tcgetpgrp(self.child_fd)
|
||||||
foreground_processes = processes_in_group(pgrp) if pgrp >= 0 else []
|
foreground_processes = processes_in_group(pgrp) if pgrp >= 0 else []
|
||||||
|
|
||||||
def process_desc(pid):
|
def process_desc(pid: int) -> ProcessDesc:
|
||||||
ans = {'pid': pid}
|
ans: ProcessDesc = {'pid': pid, 'cmdline': None, 'cwd': None}
|
||||||
with suppress(Exception):
|
with suppress(Exception):
|
||||||
ans['cmdline'] = cmdline_of_process(pid)
|
ans['cmdline'] = cmdline_of_process(pid)
|
||||||
with suppress(Exception):
|
with suppress(Exception):
|
||||||
ans['cwd'] = cwd_of_process(pid) or None
|
ans['cwd'] = cwd_of_process(pid) or None
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
return list(map(process_desc, foreground_processes))
|
return [process_desc(x) for x in foreground_processes]
|
||||||
except Exception:
|
except Exception:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
from ctypes import Array
|
||||||
from typing import (
|
from typing import (
|
||||||
Any, AnyStr, Callable, Dict, List, NewType, Optional, Tuple, TypedDict,
|
Any, AnyStr, Callable, Dict, List, NewType, Optional, Tuple, TypedDict,
|
||||||
Union
|
Union
|
||||||
@ -393,6 +394,8 @@ def default_color_table() -> Tuple[int, ...]:
|
|||||||
|
|
||||||
|
|
||||||
class FontConfigPattern(TypedDict):
|
class FontConfigPattern(TypedDict):
|
||||||
|
path: str
|
||||||
|
index: int
|
||||||
family: str
|
family: str
|
||||||
full_name: str
|
full_name: str
|
||||||
postscript_name: str
|
postscript_name: str
|
||||||
@ -400,6 +403,13 @@ class FontConfigPattern(TypedDict):
|
|||||||
spacing: str
|
spacing: str
|
||||||
weight: int
|
weight: int
|
||||||
slant: int
|
slant: int
|
||||||
|
hint_style: int
|
||||||
|
subpixel: int
|
||||||
|
lcdfilter: int
|
||||||
|
hinting: bool
|
||||||
|
scalable: bool
|
||||||
|
outline: bool
|
||||||
|
color: bool
|
||||||
|
|
||||||
|
|
||||||
def fc_list(
|
def fc_list(
|
||||||
@ -885,10 +895,10 @@ def set_send_sprite_to_gpu(
|
|||||||
|
|
||||||
def set_font_data(
|
def set_font_data(
|
||||||
box_drawing_func: Callable[[int, int, int, float],
|
box_drawing_func: Callable[[int, int, int, float],
|
||||||
Tuple[int, Union[bytearray, bytes]]],
|
Tuple[int, Union[bytearray, bytes, Array]]],
|
||||||
prerender_func: Callable[
|
prerender_func: Callable[
|
||||||
[int, int, int, int, int, float, float, float, float],
|
[int, int, int, int, int, float, float, float, float],
|
||||||
Tuple[int, ...]],
|
Tuple[Union[Array, int], ...]],
|
||||||
descriptor_for_idx: Callable[[int], Tuple[FontObject, bool, bool]],
|
descriptor_for_idx: Callable[[int], Tuple[FontObject, bool, bool]],
|
||||||
bold: int, italic: int, bold_italic: int, num_symbol_fonts: int,
|
bold: int, italic: int, bold_italic: int, num_symbol_fonts: int,
|
||||||
symbol_maps: Tuple[Tuple[int, int, int], ...], font_sz_in_pts: float,
|
symbol_maps: Tuple[Tuple[int, int, int], ...], font_sz_in_pts: float,
|
||||||
|
|||||||
@ -49,12 +49,12 @@ def draw_vline(buf: BufType, width: int, y1: int, y2: int, x: int, level: int) -
|
|||||||
buf[x + y * width] = 255
|
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)
|
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)
|
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)
|
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)
|
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')
|
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)
|
||||||
half_vline(buf, width, height, level=level, which='bottom')
|
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)
|
hline(buf, width, height, level=level)
|
||||||
add_hholes(buf, width, height, level=level, num=num)
|
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)
|
vline(buf, width, height, level=level)
|
||||||
add_vholes(buf, width, height, level=level, num=num)
|
add_vholes(buf, width, height, level=level, num=num)
|
||||||
|
|
||||||
|
|
||||||
def corner(buf: BufType, width: int, height: int, hlevel=1, vlevel=1, which=None) -> None:
|
def corner(buf: BufType, width: int, height: int, hlevel: int = 1, vlevel: int = 1, which: Optional[str] = None) -> None:
|
||||||
wh = 'right' if which in '┌└' else 'left'
|
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)
|
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)
|
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_vline(buf, width, height, level=a, which='top')
|
||||||
half_hline(buf, width, height, level=b, which='left' if which == '┤' else 'right')
|
half_hline(buf, width, height, level=b, which='left' if which == '┤' else 'right')
|
||||||
half_vline(buf, width, height, level=c, which='bottom')
|
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=a, which='left')
|
||||||
half_hline(buf, width, height, level=b, which='right')
|
half_hline(buf, width, height, level=b, which='right')
|
||||||
half_vline(buf, width, height, level=c, which='top' if which == '┴' else 'bottom')
|
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=a)
|
||||||
half_hline(buf, width, height, level=b, which='right')
|
half_hline(buf, width, height, level=b, which='right')
|
||||||
half_vline(buf, width, height, level=c)
|
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
|
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)
|
half_dvline(buf, width, height, only=only, level=level)
|
||||||
return half_dvline(buf, width, height, only=only, which='bottom', 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)
|
half_dhline(buf, width, height, only=only, level=level)
|
||||||
return half_dhline(buf, width, height, only=only, which='bottom', 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'
|
hw = 'right' if which in '╒╘' else 'left'
|
||||||
half_dhline(buf, width, height, which=hw)
|
half_dhline(buf, width, height, which=hw)
|
||||||
vw = 'top' if which in '╘╛' else 'bottom'
|
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))
|
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'
|
vw = 'top' if which in '╙╜' else 'bottom'
|
||||||
half_dvline(buf, width, height, which=vw)
|
half_dvline(buf, width, height, which=vw)
|
||||||
hw = 'right' if which in '╓╙' else 'left'
|
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]
|
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
|
num_cols = width // 2
|
||||||
left = x * num_cols
|
left = x * num_cols
|
||||||
right = width if x else num_cols
|
right = width if x else num_cols
|
||||||
@ -692,7 +692,7 @@ def test_char(ch: str, sz: int = 48) -> None:
|
|||||||
try:
|
try:
|
||||||
render_box_char(ch, buf, width, height)
|
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)
|
cells = tuple(bytes(x) for x in cells)
|
||||||
return concat_cells(width, height, False, 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):
|
with setup_for_testing(family, sz) as (_, width, height):
|
||||||
space = bytearray(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)
|
cells = tuple(bytes(x) for x in cells)
|
||||||
return concat_cells(width, height, False, cells)
|
return concat_cells(width, height, False, cells)
|
||||||
|
|
||||||
def render_chr(ch):
|
def render_chr(ch: str) -> bytearray:
|
||||||
if ch in box_chars:
|
if ch in box_chars:
|
||||||
cell = bytearray(len(space))
|
cell = bytearray(len(space))
|
||||||
render_box_char(ch, cell, width, height)
|
render_box_char(ch, cell, width, height)
|
||||||
|
|||||||
@ -60,7 +60,7 @@ def find_best_match(family: str, bold: bool = False, italic: bool = False) -> 'C
|
|||||||
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):
|
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
|
||||||
|
|||||||
@ -43,7 +43,7 @@ def create_font_map(all_fonts: Tuple['FontConfigPattern', ...]) -> FontMap:
|
|||||||
|
|
||||||
|
|
||||||
@lru_cache()
|
@lru_cache()
|
||||||
def all_fonts_map(monospaced=True) -> FontMap:
|
def all_fonts_map(monospaced: bool = True) -> FontMap:
|
||||||
if monospaced:
|
if monospaced:
|
||||||
ans = fc_list(FC_DUAL) + fc_list(FC_MONO)
|
ans = fc_list(FC_DUAL) + fc_list(FC_MONO)
|
||||||
else:
|
else:
|
||||||
@ -69,15 +69,15 @@ def family_name_to_key(family: str) -> str:
|
|||||||
|
|
||||||
|
|
||||||
@lru_cache()
|
@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)
|
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)
|
q = family_name_to_key(family)
|
||||||
font_map = all_fonts_map(monospaced)
|
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))
|
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
|
||||||
|
|||||||
@ -6,7 +6,9 @@ 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 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.config import defaults
|
||||||
from kitty.constants import is_macos
|
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))
|
items = tuple((k, maps[k]) for k in sorted(maps))
|
||||||
ans = [items[0]]
|
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]
|
s, e = item[0]
|
||||||
pe = prev_item[0][1]
|
pe = prev_item[0][1]
|
||||||
ans[-1] = ((prev_item[0][0], max(pe, e)), prev_item[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 dump_faces(ftypes: List[str], indices: Dict[str, int]) -> None:
|
||||||
def face_str(f):
|
def face_str(f: Tuple[FontObject, bool, bool]) -> str:
|
||||||
f = f[0]
|
fo = f[0]
|
||||||
if is_macos:
|
if 'index' in fo:
|
||||||
return f
|
return '{}:{}'.format(fo['path'], cast('FontConfigPattern', fo)['index'])
|
||||||
return '{}:{}'.format(f['path'], f['index'])
|
fo = cast('CoreTextFont', fo)
|
||||||
|
return fo['path']
|
||||||
|
|
||||||
log_error('Preloaded font faces:')
|
log_error('Preloaded font faces:')
|
||||||
log_error('normal face:', face_str(current_faces[0]))
|
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))
|
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
|
global current_faces
|
||||||
opts = opts or defaults
|
opts = opts or defaults
|
||||||
sz = override_font_size or opts.font_size
|
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
|
y = position - thickness // 2
|
||||||
while thickness > 0 and -1 < y < cell_height:
|
while thickness > 0 and -1 < y < cell_height:
|
||||||
thickness -= 1
|
thickness -= 1
|
||||||
@ -138,7 +144,7 @@ def add_line(buf, cell_width, position, thickness, cell_height):
|
|||||||
y += 1
|
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)
|
a = min(position - thickness, cell_height - 1)
|
||||||
b = min(position, cell_height - 1)
|
b = min(position, cell_height - 1)
|
||||||
top, bottom = min(a, b), max(a, b)
|
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)
|
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
|
max_x, max_y = cell_width - 1, cell_height - 1
|
||||||
xfactor = 2.0 * pi / max_x
|
xfactor = 2.0 * pi / max_x
|
||||||
half_height = max(thickness // 2, 1)
|
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 += position
|
||||||
y = min(y, max_y)
|
y = min(y, max_y)
|
||||||
idx = cell_width * y + x
|
idx = cell_width * y + x
|
||||||
@ -186,13 +192,25 @@ def add_curl(buf, cell_width, position, thickness, cell_height):
|
|||||||
|
|
||||||
|
|
||||||
def render_special(
|
def render_special(
|
||||||
underline=0, strikethrough=False, missing=False,
|
underline: int = 0,
|
||||||
cell_width=None, cell_height=None, baseline=None, underline_position=None, underline_thickness=None):
|
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)
|
underline_position = min(underline_position, cell_height - underline_thickness)
|
||||||
CharTexture = ctypes.c_ubyte * (cell_width * cell_height)
|
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:
|
try:
|
||||||
f(ans, cell_width, *a)
|
f(ans, cell_width, *a)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -203,23 +221,27 @@ def render_special(
|
|||||||
t = underline_thickness
|
t = underline_thickness
|
||||||
if underline > 1:
|
if underline > 1:
|
||||||
t = max(1, min(cell_height - underline_position - 1, t))
|
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:
|
if strikethrough:
|
||||||
pos = int(0.65 * baseline)
|
pos = int(0.65 * baseline)
|
||||||
dl(add_line, pos, underline_thickness, cell_height)
|
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
|
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)
|
CharTexture = ctypes.c_ubyte * (cell_width * cell_height)
|
||||||
ans = CharTexture()
|
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))
|
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)
|
left = 0 if edge == 'left' else max(0, cell_width - width)
|
||||||
for y in range(cell_height):
|
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):
|
for x in range(offset, offset + width):
|
||||||
ans[x] = 255
|
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))
|
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)
|
top = 0 if edge == 'top' else max(0, cell_height - height)
|
||||||
for y in range(top, top + 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
|
elif which == 2: # underline
|
||||||
horz('bottom', cursor_underline_thickness)
|
horz('bottom', cursor_underline_thickness)
|
||||||
elif which == 3: # hollow
|
elif which == 3: # hollow
|
||||||
vert('left'), vert('right'), horz('top'), horz('bottom')
|
vert('left')
|
||||||
|
vert('right')
|
||||||
|
horz('top')
|
||||||
|
horz('bottom')
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
def prerender_function(
|
def prerender_function(
|
||||||
cell_width, cell_height, baseline, underline_position, underline_thickness,
|
cell_width: int,
|
||||||
cursor_beam_thickness, cursor_underline_thickness, dpi_x, dpi_y):
|
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
|
# Pre-render the special underline, strikethrough and missing and cursor cells
|
||||||
f = partial(
|
f = partial(
|
||||||
render_special, cell_width=cell_width, cell_height=cell_height, baseline=baseline,
|
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,)
|
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)
|
CharTexture = ctypes.c_ubyte * (cell_width * cell_height)
|
||||||
buf = CharTexture()
|
buf = CharTexture()
|
||||||
render_box_char(
|
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:
|
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
|
self.family, self.size, self.dpi = family, size, dpi
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self) -> Tuple[Dict[Tuple[int, int, int], bytes], int, int]:
|
||||||
from collections import OrderedDict
|
|
||||||
opts = defaults._replace(font_family=self.family, font_size=self.size)
|
opts = defaults._replace(font_family=self.family, font_size=self.size)
|
||||||
set_options(opts)
|
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
|
sprites[(x, y, z)] = data
|
||||||
|
|
||||||
sprite_map_set_limits(100000, 100)
|
sprite_map_set_limits(100000, 100)
|
||||||
@ -292,11 +324,11 @@ class setup_for_testing:
|
|||||||
set_send_sprite_to_gpu(None)
|
set_send_sprite_to_gpu(None)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def __exit__(self, *args):
|
def __exit__(self, *args: Any) -> None:
|
||||||
set_send_sprite_to_gpu(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):
|
with setup_for_testing(family, size, dpi) as (sprites, cell_width, cell_height):
|
||||||
s = Screen(None, 1, len(text)*2)
|
s = Screen(None, 1, len(text)*2)
|
||||||
line = s.line(0)
|
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)):
|
for i in reversed(range(s.columns)):
|
||||||
sp = list(line.sprite_at(i))
|
sp = list(line.sprite_at(i))
|
||||||
sp[2] &= 0xfff
|
sp[2] &= 0xfff
|
||||||
tsp = tuple(sp)
|
tsp = sp[0], sp[1], sp[2]
|
||||||
if tsp == (0, 0, 0) and not found_content:
|
if tsp == (0, 0, 0) and not found_content:
|
||||||
continue
|
continue
|
||||||
found_content = True
|
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))
|
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):
|
with setup_for_testing(family, size, dpi) as (sprites, cell_width, cell_height):
|
||||||
s = Screen(None, 1, len(text)*2)
|
s = Screen(None, 1, len(text)*2)
|
||||||
line = s.line(0)
|
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)
|
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 tempfile import NamedTemporaryFile
|
||||||
from kittens.icat.main import detect_support, show
|
from kittens.icat.main import detect_support, show
|
||||||
if not hasattr(display_bitmap, 'detected') and not detect_support():
|
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')
|
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
|
from kitty.fast_data_types import concat_cells, current_fonts
|
||||||
|
|
||||||
cell_width, cell_height, cells = render_string(text, family, size, dpi)
|
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')
|
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():
|
with setup_for_testing():
|
||||||
if qtext:
|
if qtext:
|
||||||
trials = [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'))
|
sys.stdout.buffer.write((text + ' %s\n' % f).encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
def showcase():
|
def showcase() -> None:
|
||||||
f = 'monospace' if is_macos else 'Liberation Mono'
|
f = 'monospace' if is_macos else 'Liberation Mono'
|
||||||
test_render_string('He\u0347\u0305llo\u0337, w\u0302or\u0306l\u0354d!', family=f)
|
test_render_string('He\u0347\u0305llo\u0337, w\u0302or\u0306l\u0354d!', family=f)
|
||||||
test_render_string('你好,世界', family=f)
|
test_render_string('你好,世界', family=f)
|
||||||
|
|||||||
@ -22,7 +22,7 @@ except ImportError:
|
|||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=2)
|
@lru_cache(maxsize=2)
|
||||||
def options_spec():
|
def options_spec() -> str:
|
||||||
return '''
|
return '''
|
||||||
--window-title --title
|
--window-title --title
|
||||||
The title to set for the new window. By default, title is controlled by the
|
The title to set for the new window. By default, title is controlled by the
|
||||||
|
|||||||
@ -27,7 +27,7 @@ warn_unused_configs = True
|
|||||||
check_untyped_defs = True
|
check_untyped_defs = True
|
||||||
# disallow_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
|
disallow_untyped_defs = True
|
||||||
|
|
||||||
[mypy-conf]
|
[mypy-conf]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user