diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index 74dcaf084..0d9836cb9 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -3,7 +3,7 @@ from ctypes import Array, c_ubyte from typing import Any, Callable, Dict, Iterator, List, NewType, Optional, Tuple, TypedDict, Union, overload from kitty.boss import Boss -from kitty.fonts import FontFeature +from kitty.fonts import FontFeature, VariableData from kitty.fonts.render import FontObject from kitty.marks import MarkerFunc from kitty.options.types import Options @@ -416,26 +416,6 @@ def fc_match_postscript_name( pass -class VariableAxis(TypedDict): - minimum: float - maximum: float - default: float - hidden: bool - tag: str - strid: Optional[str] - - -class NamedStyle(TypedDict): - axis_values: Tuple[float, ...] - name: Optional[str] - psname: Optional[str] - - -class VariableData(TypedDict): - axes: Tuple[VariableAxis, ...] - named_styles: Tuple[NamedStyle, ...] - - class Face: def __init__(self, descriptor: Optional[FontConfigPattern] = None, path: str = '', index: int = 0): ... def get_variable_data(self) -> VariableData: ... diff --git a/kitty/fonts/__init__.py b/kitty/fonts/__init__.py index 1767efcd9..3fcfb319c 100644 --- a/kitty/fonts/__init__.py +++ b/kitty/fonts/__init__.py @@ -1,5 +1,5 @@ from enum import Enum, IntEnum, auto -from typing import Any, NamedTuple, TypedDict +from typing import Any, NamedTuple, Optional, Tuple, TypedDict class ListedFont(TypedDict): @@ -11,6 +11,27 @@ class ListedFont(TypedDict): descriptor: Any +class VariableAxis(TypedDict): + minimum: float + maximum: float + default: float + hidden: bool + tag: str + strid: Optional[str] + + +class NamedStyle(TypedDict): + axis_values: Tuple[float, ...] + name: Optional[str] + psname: Optional[str] + + +class VariableData(TypedDict): + axes: Tuple[VariableAxis, ...] + named_styles: Tuple[NamedStyle, ...] + + + class FontFeature: __slots__ = 'name', 'parsed' diff --git a/kitty/fonts/fontconfig.py b/kitty/fonts/fontconfig.py index 1bbb938ac..8ff38175d 100644 --- a/kitty/fonts/fontconfig.py +++ b/kitty/fonts/fontconfig.py @@ -13,16 +13,17 @@ from kitty.fast_data_types import ( FC_WEIGHT_BOLD, FC_WEIGHT_REGULAR, FC_WIDTH_NORMAL, + Face, fc_list, fc_match_postscript_name, parse_font_feature, ) -from kitty.fast_data_types import fc_match as fc_match_impl, Face +from kitty.fast_data_types import fc_match as fc_match_impl from kitty.options.types import Options from kitty.typing import FontConfigPattern from kitty.utils import log_error -from . import FontFeature, ListedFont +from . import FontFeature, ListedFont, VariableData attr_map = {(False, False): 'font_family', (True, False): 'bold_font', @@ -176,6 +177,5 @@ def font_for_family(family: str) -> Tuple[FontConfigPattern, bool, bool]: return ans, ans.get('weight', 0) >= FC_WEIGHT_BOLD, ans.get('slant', FC_SLANT_ROMAN) != FC_SLANT_ROMAN -def get_variable_data_for_descriptor(fd: FontConfigPattern) -> None: - f = Face(descriptor=fd) - print(f.get_variable_axes()) +def get_variable_data_for_descriptor(fd: FontConfigPattern) -> VariableData: + return Face(descriptor=fd).get_variable_data() diff --git a/kitty/fonts/list.py b/kitty/fonts/list.py index fefccbd03..b3d552026 100644 --- a/kitty/fonts/list.py +++ b/kitty/fonts/list.py @@ -6,6 +6,7 @@ from typing import Dict, List, Sequence from kittens.tui.operations import styled from kitty.constants import is_macos +from kitty.types import run_once from . import ListedFont @@ -15,18 +16,39 @@ else: from .fontconfig import get_variable_data_for_descriptor, list_fonts +@run_once +def isatty() -> bool: + return sys.stdout.isatty() + + def title(x: str) -> str: - if sys.stdout.isatty(): + if isatty(): return styled(x, fg='green', bold=True) return x def italic(x: str) -> str: - if sys.stdout.isatty(): + if isatty(): return styled(x, italic=True) return x +def variable_font_label(x: str) -> str: + if isatty(): + return styled(x, fg='yellow') + return x + + +def variable_font_tag(x: str) -> str: + if isatty(): + return styled(x, fg='cyan') + return x + + +def indented(x: str, level: int = 1) -> str: + return ' ' * level + x + + def create_family_groups(monospaced: bool = True) -> Dict[str, List[ListedFont]]: g: Dict[str, List[ListedFont]] = {} for f in list_fonts(): @@ -36,7 +58,28 @@ def create_family_groups(monospaced: bool = True) -> Dict[str, List[ListedFont]] def show_variable(f: ListedFont, psnames: bool) -> None: - get_variable_data_for_descriptor(f['descriptor']) + vd = get_variable_data_for_descriptor(f['descriptor']) + p = f"{italic(f['full_name'])} {variable_font_label('Variable font')}" + print(indented(p)) + print(indented(variable_font_label('Axes of variation'), level=2)) + for a in vd['axes']: + t = variable_font_tag(a['tag']) + n = a['strid'] or '' + if n: + t += f' ({n})' + print(indented(t, level=3) + ':', f'minimum={a["minimum"]:g}', f'maximum={a["maximum"]:g}', f'default={a["default"]:g}') + + if vd['named_styles']: + print(indented(variable_font_label('Named styles'), level=2)) + for ns in vd['named_styles']: + name = ns['name'] or '' + if psnames: + name += f' ({ns["psname"] or ""})' + axes = [] + for axis, val in zip(vd['axes'], ns['axis_values']): + axes.append(f'{axis["tag"]}={val:g}') + p = name + ': ' + ' '.join(axes) + print(indented(p, level=3)) def main(argv: Sequence[str]) -> None: @@ -51,5 +94,5 @@ def main(argv: Sequence[str]) -> None: p = italic(f['full_name']) if psnames: p += ' ({})'.format(f['postscript_name']) - print(' ', p) + print(indented(p)) print() diff --git a/kitty/freetype.c b/kitty/freetype.c index 1947937df..7de6d81bd 100644 --- a/kitty/freetype.c +++ b/kitty/freetype.c @@ -802,6 +802,7 @@ convert_named_style_to_python(Face *face, const FT_Var_Named_Style *src, unsigne static PyObject* tag_to_string(uint32_t tag) { + if (!tag) return PyUnicode_FromString(""); unsigned char bytes[5] = {0}; bytes[0] = (tag >> 24) & 0xff; bytes[1] = (tag >> 16) & 0xff;