mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-08 14:18:26 +02:00
Get font selection for the cascadia code variable fonts working
This commit is contained in:
@@ -102,7 +102,7 @@ def find_medium_variant(font: Descriptor) -> Descriptor:
|
|||||||
vd = get_variable_data_for_descriptor(font)
|
vd = get_variable_data_for_descriptor(font)
|
||||||
for i, ns in enumerate(vd['named_styles']):
|
for i, ns in enumerate(vd['named_styles']):
|
||||||
if ns['name'] == 'Regular':
|
if ns['name'] == 'Regular':
|
||||||
set_named_style(ns['psname'], font, vd)
|
set_named_style(ns['psname'] or ns['name'], font, vd)
|
||||||
return font
|
return font
|
||||||
axis_values = {}
|
axis_values = {}
|
||||||
for i, ax in enumerate(vd['axes']):
|
for i, ax in enumerate(vd['axes']):
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from collections import defaultdict
|
|||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from typing import Dict, Generator, Iterable, List, NamedTuple, Optional, Sequence, Tuple
|
from typing import Dict, Generator, Iterable, List, NamedTuple, Optional, Sequence, Tuple
|
||||||
|
|
||||||
from kitty.fast_data_types import coretext_all_fonts
|
from kitty.fast_data_types import CTFace, coretext_all_fonts
|
||||||
from kitty.fonts import FontSpec, family_name_to_key
|
from kitty.fonts import FontSpec, family_name_to_key
|
||||||
from kitty.options.types import Options
|
from kitty.options.types import Options
|
||||||
from kitty.typing import CoreTextFont
|
from kitty.typing import CoreTextFont
|
||||||
@@ -109,9 +109,9 @@ def weight_range_for_family(family: str) -> WeightRange:
|
|||||||
bold = w
|
bold = w
|
||||||
elif s == 'bold' and bold == wr.bold:
|
elif s == 'bold' and bold == wr.bold:
|
||||||
bold = w
|
bold = w
|
||||||
elif s == 'medium':
|
elif s == 'regular':
|
||||||
medium = w
|
medium = w
|
||||||
elif s == 'regular' and medium == wr.medium:
|
elif s == 'medium' and medium == wr.medium:
|
||||||
medium = w
|
medium = w
|
||||||
return WeightRange(mini, maxi, medium, bold)
|
return WeightRange(mini, maxi, medium, bold)
|
||||||
|
|
||||||
@@ -148,15 +148,18 @@ class CTScorer(Scorer):
|
|||||||
families = {x['family'] for x in candidates}
|
families = {x['family'] for x in candidates}
|
||||||
if len(families) == 1:
|
if len(families) == 1:
|
||||||
wr = weight_range_for_family(next(iter(families)))
|
wr = weight_range_for_family(next(iter(families)))
|
||||||
if wr.is_valid and wr.minimum < 0 and wr.maximum <= 0: # Operator Mono is an example of this craziness
|
if wr.is_valid and wr.medium < 0: # Operator Mono is an example of this craziness
|
||||||
self.weight_range = wr
|
self.weight_range = wr
|
||||||
candidates = sorted(candidates, key=self.score)
|
candidates = sorted(candidates, key=self.score)
|
||||||
if dump:
|
if dump:
|
||||||
print(self)
|
print(self)
|
||||||
|
if self.weight_range:
|
||||||
|
print(self.weight_range)
|
||||||
for x in candidates:
|
for x in candidates:
|
||||||
assert x['descriptor_type'] == 'core_text'
|
assert x['descriptor_type'] == 'core_text'
|
||||||
print(x['postscript_name'], f'bold={x["bold"]}', f'italic={x["italic"]}', f'weight={x["weight"]:.2f}', f'slant={x["slant"]:.2f}')
|
print(CTFace(descriptor=x).postscript_name(),
|
||||||
print(self.score(x))
|
f'bold={x["bold"]}', f'italic={x["italic"]}', f'weight={x["weight"]:.2f}', f'slant={x["slant"]:.2f}')
|
||||||
|
print(' ', self.score(x))
|
||||||
print()
|
print()
|
||||||
return candidates
|
return candidates
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ from kitty.fast_data_types import (
|
|||||||
FC_SLANT_ROMAN,
|
FC_SLANT_ROMAN,
|
||||||
FC_WEIGHT_REGULAR,
|
FC_WEIGHT_REGULAR,
|
||||||
FC_WIDTH_NORMAL,
|
FC_WIDTH_NORMAL,
|
||||||
|
Face,
|
||||||
fc_list,
|
fc_list,
|
||||||
)
|
)
|
||||||
from kitty.fast_data_types import (
|
from kitty.fast_data_types import (
|
||||||
@@ -117,9 +118,9 @@ def weight_range_for_family(family: str) -> WeightRange:
|
|||||||
bold = w
|
bold = w
|
||||||
elif s == 'bold' and bold == wr.bold:
|
elif s == 'bold' and bold == wr.bold:
|
||||||
bold = w
|
bold = w
|
||||||
elif s == 'medium':
|
elif s == 'regular':
|
||||||
medium = w
|
medium = w
|
||||||
elif s == 'regular' and medium == wr.medium:
|
elif s == 'medium' and medium == wr.medium:
|
||||||
medium = w
|
medium = w
|
||||||
return WeightRange(mini, maxi, medium, bold)
|
return WeightRange(mini, maxi, medium, bold)
|
||||||
|
|
||||||
@@ -148,15 +149,17 @@ class FCScorer(Scorer):
|
|||||||
families = {x['family'] for x in candidates}
|
families = {x['family'] for x in candidates}
|
||||||
if len(families) == 1:
|
if len(families) == 1:
|
||||||
wr = weight_range_for_family(next(iter(families)))
|
wr = weight_range_for_family(next(iter(families)))
|
||||||
if wr.is_valid and wr.maximum < 100: # Operator Mono is an example of this craziness
|
if wr.is_valid and wr.medium < 100: # Operator Mono and Cascadia Code are examples
|
||||||
self.weight_range = wr
|
self.weight_range = wr
|
||||||
candidates = sorted(candidates, key=self.score)
|
candidates = sorted(candidates, key=self.score)
|
||||||
if dump:
|
if dump:
|
||||||
print(self)
|
print(self)
|
||||||
|
if self.weight_range:
|
||||||
|
print(self.weight_range)
|
||||||
for x in candidates:
|
for x in candidates:
|
||||||
assert x['descriptor_type'] == 'fontconfig'
|
assert x['descriptor_type'] == 'fontconfig'
|
||||||
print(x['postscript_name'], f'weight={x["weight"]}', f'slant={x["slant"]}')
|
print(Face(descriptor=x).postscript_name(), f'weight={x["weight"]}', f'slant={x["slant"]}')
|
||||||
print(self.score(x))
|
print(' ', self.score(x))
|
||||||
print()
|
print()
|
||||||
return candidates
|
return candidates
|
||||||
|
|
||||||
|
|||||||
@@ -25,19 +25,13 @@ class Selection(BaseTest):
|
|||||||
opts = Options()
|
opts = Options()
|
||||||
fonts_map = all_fonts_map(True)
|
fonts_map = all_fonts_map(True)
|
||||||
names = set(fonts_map['family_map']) | set(fonts_map['variable_map'])
|
names = set(fonts_map['family_map']) | set(fonts_map['variable_map'])
|
||||||
def has(x: str) -> bool:
|
del fonts_map
|
||||||
return family_name_to_key(x) in names
|
|
||||||
has_source_code_pro = has('Source Code Pro')
|
|
||||||
has_source_code_vf = has('sourcecodeVf')
|
|
||||||
has_fira_code = has('Fira Code')
|
|
||||||
has_hack = has('Hack')
|
|
||||||
has_operator_mono = has('Operator Mono')
|
|
||||||
del fonts_map, has
|
|
||||||
|
|
||||||
def s(family: str, *expected: str) -> None:
|
def s(family: str, *expected: str) -> None:
|
||||||
opts.font_family = parse_font_spec(family)
|
opts.font_family = parse_font_spec(family)
|
||||||
ff = get_font_files(opts)
|
ff = get_font_files(opts)
|
||||||
actual = tuple(face_from_descriptor(ff[x]).postscript_name() for x in ('medium', 'bold', 'italic', 'bi')) # type: ignore
|
actual = tuple(face_from_descriptor(ff[x]).postscript_name() for x in ('medium', 'bold', 'italic', 'bi')) # type: ignore
|
||||||
|
del ff
|
||||||
with self.subTest(spec=family):
|
with self.subTest(spec=family):
|
||||||
self.ae(expected, actual)
|
self.ae(expected, actual)
|
||||||
|
|
||||||
@@ -45,15 +39,34 @@ class Selection(BaseTest):
|
|||||||
for family in (family, f'family="{family}"'):
|
for family in (family, f'family="{family}"'):
|
||||||
s(family, *expected)
|
s(family, *expected)
|
||||||
|
|
||||||
if has_source_code_pro:
|
def has(family):
|
||||||
both('Source Code Pro', 'SourceCodePro-Regular', 'SourceCodePro-Semibold', 'SourceCodePro-It', 'SourceCodePro-SemiboldIt')
|
return family_name_to_key(family) in names
|
||||||
if has_source_code_vf:
|
|
||||||
both('sourcecodeVf', 'SourceCodeVF-Regular', 'SourceCodeVF-Semibold', 'SourceCodeVF-Italic', 'SourceCodeVF-SemiboldItalic')
|
def t(family, psprefix, bold='Bold', italic='Italic', bi='', reg='Regular'):
|
||||||
if has_fira_code:
|
if has(family):
|
||||||
both('fira code', 'FiraCodeRoman-Regular', 'FiraCodeRoman-SemiBold', 'FiraCodeRoman-Regular', 'FiraCodeRoman-SemiBold')
|
bi = bi or bold + italic
|
||||||
if has_hack:
|
if reg:
|
||||||
both('hack', 'Hack-Regular', 'Hack-Bold', 'Hack-Italic', 'Hack-BoldItalic')
|
reg = '-' + reg
|
||||||
if has_operator_mono:
|
both(family, f'{psprefix}{reg}', f'{psprefix}-{bold}', f'{psprefix}-{italic}', f'{psprefix}-{bi}')
|
||||||
|
|
||||||
|
t('Source Code Pro', 'SourceCodePro', 'Semibold', 'It')
|
||||||
|
t('sourcecodeVf', 'SourceCodeVF', 'Semibold')
|
||||||
|
t('fira code', 'FiraCodeRoman', 'SemiBold', 'Regular', 'SemiBold')
|
||||||
|
t('hack', 'Hack')
|
||||||
|
t('fantasque sans mono', 'FantasqueSansMono')
|
||||||
|
t('jetbrains mono', 'JetBrainsMono', 'SemiBold')
|
||||||
|
t('consolas', 'Consolas', reg='')
|
||||||
|
if has('cascadia code'):
|
||||||
|
if is_macos:
|
||||||
|
both('cascadia code', 'CascadiaCode-Regular', 'CascadiaCode-Regular_SemiBold', 'CascadiaCode-Italic', 'CascadiaCode-Italic_SemiBold-Italic')
|
||||||
|
else:
|
||||||
|
both('cascadia code', 'CascadiaCodeRoman-Regular', 'CascadiaCodeRoman-SemiBold', 'CascadiaCode-Italic', 'CascadiaCode-SemiBoldItalic')
|
||||||
|
if has('cascadia mono'):
|
||||||
|
if is_macos:
|
||||||
|
both('cascadia mono', 'CascadiaMono-Regular', 'CascadiaMono-Regular_SemiBold', 'CascadiaMono-Italic', 'CascadiaMono-Italic_SemiBold-Italic')
|
||||||
|
else:
|
||||||
|
both('cascadia mono', 'CascadiaMonoRoman-Regular', 'CascadiaMonoRoman-SemiBold', 'CascadiaMono-Italic', 'CascadiaMono-SemiBoldItalic')
|
||||||
|
if has('operator mono'):
|
||||||
both('operator mono', 'OperatorMono-Medium', 'OperatorMono-Bold', 'OperatorMono-MediumItalic', 'OperatorMono-BoldItalic')
|
both('operator mono', 'OperatorMono-Medium', 'OperatorMono-Bold', 'OperatorMono-MediumItalic', 'OperatorMono-BoldItalic')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user