Code to get specs from options

This commit is contained in:
Kovid Goyal
2024-05-11 15:38:44 +05:30
parent 0706c8cf7c
commit 1d6cd27c6f
5 changed files with 128 additions and 14 deletions

View File

@@ -5,12 +5,13 @@ import json
import string import string
import sys import sys
import tempfile import tempfile
from typing import Any, Dict, Tuple, TypedDict from typing import Any, Dict, Literal, Tuple, TypedDict
from kitty.cli import create_default_opts
from kitty.conf.utils import to_color from kitty.conf.utils import to_color
from kitty.constants import kitten_exe from kitty.constants import kitten_exe
from kitty.fonts import Descriptor from kitty.fonts import Descriptor
from kitty.fonts.common import face_from_descriptor, get_font_files, get_variable_data_for_descriptor from kitty.fonts.common import face_from_descriptor, get_font_files, get_variable_data_for_descriptor, spec_for_descriptor
from kitty.fonts.list import create_family_groups from kitty.fonts.list import create_family_groups
from kitty.fonts.render import display_bitmap from kitty.fonts.render import display_bitmap
from kitty.options.types import Options from kitty.options.types import Options
@@ -95,13 +96,31 @@ def render_family_sample(
return ans return ans
OptNames = Literal['font_family', 'bold_font', 'italic_font', 'bold_italic_font']
ResolvedFace = Dict[Literal['family', 'spec'], str]
def resolved_faces(opts: Options) -> Dict[OptNames, ResolvedFace]:
font_files = get_font_files(opts)
ans: Dict[OptNames, ResolvedFace] = {}
def d(key: Literal['medium', 'bold', 'italic', 'bi'], opt_name: OptNames) -> None:
descriptor = font_files[key]
ans[opt_name] = {'family': descriptor['family'], 'spec': spec_for_descriptor(descriptor)}
d('medium', 'font_family')
d('bold', 'bold_font')
d('italic', 'italic_font')
d('bi', 'bold_italic_font')
return ans
def main() -> None: def main() -> None:
cache: Dict[FaceKey, str] = {} cache: Dict[FaceKey, str] = {}
for line in sys.stdin.buffer: for line in sys.stdin.buffer:
cmd = json.loads(line) cmd = json.loads(line)
action = cmd.get('action', '') action = cmd.get('action', '')
if action == 'list_monospaced_fonts': if action == 'list_monospaced_fonts':
send_to_kitten(create_family_groups()) opts = create_default_opts()
send_to_kitten({'fonts': create_family_groups(), 'resolved_faces': resolved_faces(opts)})
elif action == 'read_variable_data': elif action == 'read_variable_data':
ans = [] ans = []
for descriptor in cmd['descriptors']: for descriptor in cmd['descriptors']:

View File

@@ -142,6 +142,16 @@ func (self *FamilyList) Lines(num_rows int) []Line {
return ans return ans
} }
func (self *FamilyList) SelectFamily(family string) bool {
for i, f := range self.families {
if f == family {
self.current_idx = i
return true
}
}
return false
}
func (self *FamilyList) CurrentFamily() string { func (self *FamilyList) CurrentFamily() string {
if self.current_idx >= 0 && self.current_idx < len(self.families) { if self.current_idx >= 0 && self.current_idx < len(self.families) {
return self.families[self.current_idx] return self.families[self.current_idx]

View File

@@ -69,6 +69,23 @@ type VariableData struct {
Multi_axis_styles []MultiAxisStyle `json:"multi_axis_styles"` Multi_axis_styles []MultiAxisStyle `json:"multi_axis_styles"`
} }
type ResolvedFace struct {
Family string `json:"family"`
Spec string `json:"spec"`
}
type ResolvedFaces struct {
Font_family ResolvedFace `json:"font_family"`
Bold_font ResolvedFace `json:"bold_font"`
Italic_font ResolvedFace `json:"italic_font"`
Bold_italic_font ResolvedFace `json:"bold_italic_font"`
}
type ListResult struct {
Fonts map[string][]ListedFont `json:"fonts"`
Resolved_faces ResolvedFaces `json:"resolved_faces"`
}
var variable_data_cache map[string]VariableData var variable_data_cache map[string]VariableData
var variable_data_cache_mutex sync.Mutex var variable_data_cache_mutex sync.Mutex

View File

@@ -35,7 +35,6 @@ type TextStyle struct {
type handler struct { type handler struct {
lp *loop.Loop lp *loop.Loop
fonts map[string][]ListedFont
state State state State
err_mutex sync.Mutex err_mutex sync.Mutex
err_in_worker_thread error err_in_worker_thread error
@@ -46,9 +45,11 @@ type handler struct {
graphics_manager graphics_manager graphics_manager graphics_manager
// Listing // Listing
rl *readline.Readline rl *readline.Readline
family_list FamilyList family_list FamilyList
variable_data_requested_for *utils.Set[string] variable_data_requested_for *utils.Set[string]
fonts map[string][]ListedFont
resolved_faces_from_kitty_conf ResolvedFaces
} }
func (h *handler) set_worker_error(err error) { func (h *handler) set_worker_error(err error) {
@@ -279,7 +280,10 @@ func (h *handler) initialize() {
initialize_variable_data_cache() initialize_variable_data_cache()
h.graphics_manager.initialize(h.lp) h.graphics_manager.initialize(h.lp)
go func() { go func() {
h.set_worker_error(kitty_font_backend.query("list_monospaced_fonts", nil, &h.fonts)) var r ListResult
h.set_worker_error(kitty_font_backend.query("list_monospaced_fonts", nil, &r))
h.fonts = r.Fonts
h.resolved_faces_from_kitty_conf = r.Resolved_faces
h.lp.WakeupMainThread() h.lp.WakeupMainThread()
}() }()
} }
@@ -351,7 +355,7 @@ func (h *handler) on_wakeup() (err error) {
case SCANNING_FAMILIES: case SCANNING_FAMILIES:
h.state = LISTING_FAMILIES h.state = LISTING_FAMILIES
h.family_list.UpdateFamilies(utils.StableSortWithKey(utils.Keys(h.fonts), strings.ToLower)) h.family_list.UpdateFamilies(utils.StableSortWithKey(utils.Keys(h.fonts), strings.ToLower))
case LISTING_FAMILIES: h.family_list.SelectFamily(h.resolved_faces_from_kitty_conf.Font_family.Family)
} }
return h.draw_screen() return h.draw_screen()
} }

View File

@@ -306,11 +306,7 @@ def axis_values_are_equal(defaults: Dict[str, float], a: Dict[str, float], b: Di
return ad == bd return ad == bd
def get_named_style(face: Face) -> Optional[NamedStyle]: def _get_named_style(axis_map: Dict[str, float], vd: VariableData) -> Optional[NamedStyle]:
axis_map = face.get_variation()
if axis_map is None:
return None
vd = get_variable_data_for_face(face)
defaults = {ax['tag']: ax['default'] for ax in vd['axes']} defaults = {ax['tag']: ax['default'] for ax in vd['axes']}
for ns in vd['named_styles']: for ns in vd['named_styles']:
if axis_values_are_equal(defaults, ns['axis_values'], axis_map): if axis_values_are_equal(defaults, ns['axis_values'], axis_map):
@@ -318,5 +314,73 @@ def get_named_style(face: Face) -> Optional[NamedStyle]:
return None return None
def get_named_style(face_or_descriptor: Union[Face, Descriptor]) -> Optional[NamedStyle]:
if isinstance(face_or_descriptor, dict):
d: Descriptor = face_or_descriptor
vd = get_variable_data_for_descriptor(d)
if d['descriptor_type'] == 'fontconfig':
ns = d.get('named_instance', -1)
if ns > -1 and ns < len(vd['named_styles']):
return vd['named_styles'][ns]
axis_map = {}
axes = vd['axes']
for i, val in enumerate(d.get('axes', ())):
if i < len(axes):
axis_map[axes[i]['tag']] = val
else:
axis_map = d.get('axis_map', {}).copy()
else:
face: Face = face_or_descriptor
q = face.get_variation()
if q is None:
return None
axis_map = q
return _get_named_style(axis_map, vd)
def get_axis_map(face_or_descriptor: Union[Face, Descriptor]) -> Dict[str, float]:
base_axis_map = {}
axis_map: Dict[str, float] = {}
if isinstance(face_or_descriptor, dict):
d: Descriptor = face_or_descriptor
vd = get_variable_data_for_descriptor(d)
if d['descriptor_type'] == 'fontconfig':
ns = d.get('named_instance', -1)
if ns > -1 and ns < len(vd['named_styles']):
base_axis_map = vd['named_styles'][ns]['axis_values'].copy()
axis_map = {}
axes = vd['axes']
for i, val in enumerate(d.get('axes', ())):
if i < len(axes):
axis_map[axes[i]['tag']] = val
else:
axis_map = d.get('axis_map', {}).copy()
else:
face: Face = face_or_descriptor
q = face.get_variation()
if q is not None:
axis_map = q
base_axis_map.update(axis_map)
return base_axis_map
def spec_for_descriptor(descriptor: Descriptor) -> str:
from shlex import quote as q
if is_variable(descriptor):
vd = get_variable_data_for_descriptor(descriptor)
spec = f'family={q(descriptor["family"])}'
if vd['variations_postscript_name_prefix']:
spec += f' variable_name={q(vd["variations_postscript_name_prefix"])}'
ns = get_named_style(descriptor)
if ns is None:
for key, val in get_axis_map(descriptor).items():
spec += f' {key}={val:g}'
else:
spec = f'{spec} style={q(ns["psname"])}'
return spec
return descriptor['postscript_name']
if __name__ == '__main__': if __name__ == '__main__':
develop() develop()