diff --git a/kitty/fonts/common.py b/kitty/fonts/common.py index a2a7a13e9..0af88524b 100644 --- a/kitty/fonts/common.py +++ b/kitty/fonts/common.py @@ -92,7 +92,7 @@ def pprint(*a: Any) -> None: pprint(*a) -def find_medium_variant(font: Descriptor) -> Descriptor: +def find_medium_variant(font: DescriptorVar) -> DescriptorVar: font = font.copy() vd = get_variable_data_for_descriptor(font) for i, ns in enumerate(vd['named_styles']): diff --git a/kitty/fonts/core_text.py b/kitty/fonts/core_text.py index 63613fe64..8cf20d7bf 100644 --- a/kitty/fonts/core_text.py +++ b/kitty/fonts/core_text.py @@ -183,6 +183,15 @@ def find_best_match( if possible != ignore_face: return possible + # See if we have a variable font + if not bold and not italic and font_map['variable_map'].get(q): + candidates = font_map['variable_map'][q] + candidates = scorer.sorted_candidates(candidates) + possible = candidates[0] + if possible != ignore_face: + from .common import find_medium_variant + return find_medium_variant(possible) + # Let CoreText choose the font if the family exists, otherwise # fallback to Menlo if q not in font_map['family_map']: diff --git a/kitty_tests/fonts.py b/kitty_tests/fonts.py index 0e7656e56..98195f7ad 100644 --- a/kitty_tests/fonts.py +++ b/kitty_tests/fonts.py @@ -27,7 +27,7 @@ class Selection(BaseTest): names = set(fonts_map['family_map']) | set(fonts_map['variable_map']) del fonts_map - def s(family: str, *expected: str) -> None: + def s(family: str, *expected: str, alternate=None) -> None: opts.font_family = parse_font_spec(family) ff = get_font_files(opts) actual = tuple(face_from_descriptor(ff[x]).postscript_name() for x in ('medium', 'bold', 'italic', 'bi')) # type: ignore @@ -36,11 +36,17 @@ class Selection(BaseTest): if '/' in x: # Old FreeType failed to generate postscript name for a variable font probably return with self.subTest(spec=family): - self.ae(expected, actual) + try: + self.ae(expected, actual) + except AssertionError: + if alternate: + self.ae(tuple(map(alternate, expected)), actual) + else: + raise - def both(family: str, *expected: str) -> None: + def both(family: str, *expected: str, alternate=None) -> None: for family in (family, f'family="{family}"'): - s(family, *expected) + s(family, *expected, alternate=alternate) def has(family, allow_missing_in_ci=False): ans = family_name_to_key(family) in names @@ -48,12 +54,12 @@ class Selection(BaseTest): raise AssertionError(f'The family: {family} is not available') return ans - def t(family, psprefix, bold='Bold', italic='Italic', bi='', reg='Regular', allow_missing_in_ci=False): + def t(family, psprefix, bold='Bold', italic='Italic', bi='', reg='Regular', allow_missing_in_ci=False, alternate=None): if has(family, allow_missing_in_ci=allow_missing_in_ci): bi = bi or bold + italic if reg: reg = '-' + reg - both(family, f'{psprefix}{reg}', f'{psprefix}-{bold}', f'{psprefix}-{italic}', f'{psprefix}-{bi}') + both(family, f'{psprefix}{reg}', f'{psprefix}-{bold}', f'{psprefix}-{italic}', f'{psprefix}-{bi}', alternate=alternate) t('Source Code Pro', 'SourceCodePro', 'Semibold', 'It') t('sourcecodeVf', 'SourceCodeVF', 'Semibold')