123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- package choose_fonts
- import (
- "encoding/json"
- "fmt"
- "io"
- "os"
- "os/exec"
- "strings"
- "sync"
- "time"
- "kitty/tools/utils"
- )
- var _ = fmt.Print
- type kitty_font_backend_type struct {
- from io.ReadCloser
- to io.WriteCloser
- json_decoder *json.Decoder
- cmd *exec.Cmd
- stderr strings.Builder
- lock sync.Mutex
- r io.ReadCloser
- w io.WriteCloser
- wait_for_exit chan error
- started, exited, failed bool
- timeout time.Duration
- }
- func (k *kitty_font_backend_type) start() (err error) {
- exe := utils.KittyExe()
- if exe == "" {
- exe = utils.Which("kitty")
- }
- if exe == "" {
- return fmt.Errorf("Failed to find the kitty executable, this kitten requires the kitty executable to be present. You can use the environment variable KITTY_PATH_TO_KITTY_EXE to specify the path to the kitty executable")
- }
- k.cmd = exec.Command(exe, "+runpy", "from kittens.choose_fonts.backend import main; main()")
- k.cmd.Stderr = &k.stderr
- if k.r, k.to, err = os.Pipe(); err != nil {
- return err
- }
- k.cmd.Stdin = k.r
- if k.from, k.w, err = os.Pipe(); err != nil {
- return err
- }
- k.cmd.Stdout = k.w
- k.json_decoder = json.NewDecoder(k.from)
- if err = k.cmd.Start(); err != nil {
- return err
- }
- k.started = true
- k.timeout = 60 * time.Second
- k.wait_for_exit = make(chan error)
- go func() {
- k.wait_for_exit <- k.cmd.Wait()
- }()
- return
- }
- var kitty_font_backend kitty_font_backend_type
- func (k *kitty_font_backend_type) send(v any) error {
- data, err := json.Marshal(v)
- if err != nil {
- return fmt.Errorf("Could not encode message to kitty with error: %w", err)
- }
- c := make(chan error)
- go func() {
- if _, err = k.to.Write(data); err != nil {
- c <- fmt.Errorf("Failed to send message to kitty with I/O error: %w", err)
- return
- }
- if _, err = k.to.Write([]byte{'\n'}); err != nil {
- c <- fmt.Errorf("Failed to send message to kitty with I/O error: %w", err)
- return
- }
- c <- nil
- }()
- select {
- case err := <-c:
- return err
- case <-time.After(k.timeout):
- return fmt.Errorf("Timed out waiting to write to kitty font backend after %v", k.timeout)
- case err := <-k.wait_for_exit:
- k.exited = true
- if err == nil {
- err = fmt.Errorf("kitty font backend exited with no error while waiting for a response from it")
- } else {
- k.failed = true
- }
- return err
- }
- }
- func (k *kitty_font_backend_type) query(action string, cmd map[string]any, result any) error {
- k.lock.Lock()
- defer k.lock.Unlock()
- if cmd == nil {
- cmd = make(map[string]any)
- }
- cmd["action"] = action
- if err := k.send(cmd); err != nil {
- return err
- }
- c := make(chan error)
- go func() {
- if err := k.json_decoder.Decode(result); err != nil {
- c <- fmt.Errorf("Failed to decode JSON from kitty with error: %w", err)
- }
- c <- nil
- }()
- select {
- case err := <-c:
- return err
- case <-time.After(k.timeout):
- return fmt.Errorf("Timed out waiting for response from kitty font backend after %v", k.timeout)
- case err := <-k.wait_for_exit:
- k.exited = true
- if err == nil {
- err = fmt.Errorf("kitty font backed exited with no error while waiting for a response from it")
- } else {
- k.failed = true
- }
- return err
- }
- }
- func (k *kitty_font_backend_type) release() (err error) {
- if k.r != nil {
- k.r.Close()
- k.r = nil
- }
- if k.to != nil {
- k.to.Close()
- k.to = nil
- }
- if k.w != nil {
- k.w.Close()
- k.w = nil
- }
- if k.from != nil {
- k.from.Close()
- k.from = nil
- }
- if k.started && !k.exited {
- timeout := 2 * time.Second
- select {
- case err = <-k.wait_for_exit:
- k.exited = true
- if err != nil {
- k.failed = true
- }
- case <-time.After(timeout):
- k.failed = true
- err = fmt.Errorf("Timed out waiting for kitty font backend to exit for %v", timeout)
- }
- }
- os.Stderr.WriteString(k.stderr.String())
- return
- }
|