Load font variable data on demand

This commit is contained in:
Kovid Goyal
2024-05-03 16:53:07 +05:30
parent 217ded7b3f
commit 198aec84c2
4 changed files with 125 additions and 21 deletions

View File

@@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"os"
"sync"
"kitty/tools/cli"
"kitty/tools/tty"
@@ -36,6 +37,20 @@ func to_kitty(v any) error {
return nil
}
var query_kitty_lock sync.Mutex
func query_kitty(action string, cmd map[string]any, result any) error {
query_kitty_lock.Lock()
defer query_kitty_lock.Unlock()
if action != "" {
cmd["action"] = action
if err := to_kitty(cmd); err != nil {
return err
}
}
return json_decode(result)
}
func main() (rc int, err error) {
json_decoder = json.NewDecoder(os.Stdin)
lp, err := loop.New()

View File

@@ -2,6 +2,7 @@ package list_fonts
import (
"fmt"
"sync"
)
var _ = fmt.Print
@@ -42,6 +43,15 @@ type MultiAxisStyle struct {
Values []AxisValue `json:"values"`
}
type ListedFont struct {
Family string `json:"family"`
Fullname string `json:"full_name"`
Postscript_name string `json:"postscript_name"`
Is_monospace bool `json:"is_monospace"`
Is_variable bool `json:"is_variable"`
Descriptor map[string]any `json:"descriptor"`
}
type VariableData struct {
Axes []VariableAxis `json:"axes"`
Named_styles []NamedStyle `json:"named_styles"`
@@ -51,12 +61,68 @@ type VariableData struct {
Multi_axis_styles []MultiAxisStyle `json:"multi_axis_styles"`
}
type ListedFont struct {
Family string `json:"family"`
Fullname string `json:"full_name"`
Postscript_name string `json:"postscript_name"`
Is_monospace bool `json:"is_monospace"`
Is_variable bool `json:"is_variable"`
Variable_data VariableData `json:"variable_data"`
Descriptor map[string]any `json:"descriptor"`
var variable_data_cache map[string]VariableData
var variable_data_cache_mutex sync.Mutex
func (f ListedFont) cache_key() string {
key := f.Postscript_name
if key == "" {
key = "path:" + f.Descriptor["path"].(string)
} else {
key = "psname:" + key
}
return key
}
func ensure_variable_data_for_fonts(fonts ...ListedFont) error {
descriptors := make([]map[string]any, 0, len(fonts))
keys := make([]string, 0, len(fonts))
variable_data_cache_mutex.Lock()
for _, f := range fonts {
key := f.cache_key()
if _, found := variable_data_cache[key]; !found {
descriptors = append(descriptors, f.Descriptor)
keys = append(keys, key)
}
}
variable_data_cache_mutex.Unlock()
var data []VariableData
if err := query_kitty("read_variable_data", map[string]any{"descriptors": descriptors}, &data); err != nil {
return err
}
variable_data_cache_mutex.Lock()
for i, key := range keys {
variable_data_cache[key] = data[i]
}
variable_data_cache_mutex.Unlock()
return nil
}
func initialize_variable_data_cache() {
variable_data_cache = make(map[string]VariableData)
}
func _cached_vd(key string) (ans VariableData, found bool) {
variable_data_cache_mutex.Lock()
defer variable_data_cache_mutex.Unlock()
ans, found = variable_data_cache[key]
return
}
func variable_data_for(f ListedFont) VariableData {
key := f.cache_key()
ans, found := _cached_vd(key)
if found {
return ans
}
if err := ensure_variable_data_for_fonts(f); err != nil {
panic(err)
}
ans, found = _cached_vd(key)
return ans
}
func has_variable_data_for_font(font ListedFont) bool {
_, found := _cached_vd(font.cache_key())
return found
}

View File

@@ -31,8 +31,9 @@ type handler struct {
err_in_worker_thread error
// Listing
rl *readline.Readline
family_list FamilyList
rl *readline.Readline
family_list FamilyList
variable_data_requested_for *utils.Set[string]
}
func (h *handler) set_worker_error(err error) {
@@ -77,6 +78,22 @@ func (h *handler) draw_family_summary(start_x int, sz loop.ScreenSize) (err erro
h.lp.SprintStyled("fg=green bold", center_string(family, int(sz.WidthCells)-start_x)),
"",
}
fonts := h.fonts[family]
if len(fonts) == 0 {
return fmt.Errorf("The family: %s has no fonts", family)
}
if has_variable_data_for_font(fonts[0]) {
} else {
lines = append(lines, "Reading font data, please wait…")
key := fonts[0].cache_key()
if !h.variable_data_requested_for.Has(key) {
h.variable_data_requested_for.Add(key)
go func() {
h.set_worker_error(ensure_variable_data_for_fonts(fonts...))
h.lp.WakeupMainThread()
}()
}
}
for i, line := range lines {
if i >= int(sz.HeightCells)-1 {
@@ -115,7 +132,7 @@ func (h *handler) draw_listing_screen() (err error) {
h.lp.Println(SEPARATOR)
}
if h.family_list.Len() > 0 {
if err = h.draw_family_summary(mw+2, sz); err != nil {
if err = h.draw_family_summary(mw+3, sz); err != nil {
return err
}
}
@@ -207,9 +224,11 @@ func (h *handler) handle_listing_text(text string, from_key_event bool, in_brack
func (h *handler) initialize() {
h.lp.SetCursorVisible(false)
h.rl = readline.New(h.lp, readline.RlInit{DontMarkPrompts: true, Prompt: "Family: "})
h.variable_data_requested_for = utils.NewSet[string](256)
h.draw_screen()
initialize_variable_data_cache()
go func() {
h.set_worker_error(json_decode(&h.fonts))
h.set_worker_error(query_kitty("", nil, &h.fonts))
h.lp.WakeupMainThread()
}()
}
@@ -243,6 +262,8 @@ func (h *handler) on_wakeup() (err error) {
h.state = LISTING_FAMILIES
h.family_list.UpdateFamilies(utils.StableSortWithKey(maps.Keys(h.fonts), strings.ToLower))
return h.draw_screen()
case LISTING_FAMILIES:
return h.draw_screen()
}
return
}