mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-05-13 08:26:56 +00:00
168 lines
3.9 KiB
Go
168 lines
3.9 KiB
Go
package choose_fonts
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/kovidgoyal/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 {
|
|
if k.to == nil {
|
|
return fmt.Errorf("Trying to send data when to pipe is nil")
|
|
}
|
|
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
|
|
}
|