Get preview to basically display

This commit is contained in:
Kovid Goyal 2024-05-12 12:59:44 +05:30
parent 6c11f0eeb5
commit a0840a7328
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
6 changed files with 128 additions and 28 deletions

View file

@ -160,8 +160,6 @@ func (k *kitty_font_backend_type) release() (err error) {
err = fmt.Errorf("Timed out waiting for kitty font backend to exit for %v", timeout)
}
}
if k.failed {
os.Stderr.WriteString(k.stderr.String())
}
os.Stderr.WriteString(k.stderr.String())
return
}

View file

@ -33,7 +33,13 @@ class TextStyle(TypedDict):
background: str
FamilyKey = Tuple[str, ...]
def print(*a: Any) -> None:
import builtins
builtins.print(*a, file=sys.stderr)
OptNames = Literal['font_family', 'bold_font', 'italic_font', 'bold_italic_font']
FamilyKey = Tuple[OptNames, ...]
def opts_from_cmd(cmd: Dict[str, Any]) -> Tuple[Options, FamilyKey, float, float]:
@ -43,18 +49,14 @@ def opts_from_cmd(cmd: Dict[str, Any]) -> Tuple[Options, FamilyKey, float, float
opts.foreground = to_color(ts['foreground'])
opts.background = to_color(ts['background'])
family_key = []
if 'font_family' in cmd:
opts.font_family = parse_font_spec(cmd['font_family'])
family_key.append(cmd['font_family'])
if 'bold_font' in cmd:
opts.bold_font = parse_font_spec(cmd['bold_font'])
family_key.append(cmd['bold_font'])
if 'italic_font' in cmd:
opts.italic_font = parse_font_spec(cmd['italic_font'])
family_key.append(cmd['italic_font'])
if 'bold_italic_font' in cmd:
opts.bold_italic_font = parse_font_spec(cmd['bold_italic_font'])
family_key.append(cmd['bold_italic_font'])
def d(k: OptNames) -> None:
if k in cmd:
opts.font_family = parse_font_spec(cmd[k])
family_key.append(k)
d('font_family')
d('bold_font')
d('italic_font')
d('bold_italic_font')
return opts, tuple(family_key), ts['dpi_x'], ts['dpi_y']
@ -91,12 +93,12 @@ def render_family_sample(
ans[x] = cached
else:
with tempfile.NamedTemporaryFile(delete=False, suffix='.rgba', dir=output_dir) as tf:
tf.write(render_face_sample(desc, opts, dpi_x, dpi_y, width, height))
bitmap = render_face_sample(desc, opts, dpi_x, dpi_y, width, height)
tf.write(bitmap)
cache[key] = ans[x] = tf.name
return ans
OptNames = Literal['font_family', 'bold_font', 'italic_font', 'bold_italic_font']
ResolvedFace = Dict[Literal['family', 'spec'], str]

View file

@ -12,16 +12,29 @@ var _ = fmt.Print
type image struct {
id, image_number uint32
placement_id uint32
current_file string
}
func (i image) graphics_command() *graphics.GraphicsCommand {
gc := &graphics.GraphicsCommand{}
if i.id > 0 {
gc.SetImageId(i.id)
} else {
gc.SetImageNumber(i.image_number)
}
return gc
}
type graphics_manager struct {
main, bold, italic, bi, extra image
lp *loop.Loop
images [5]*image
}
func (g *graphics_manager) initialize(lp *loop.Loop) {
g.images = [5]*image{&g.main, &g.bold, &g.italic, &g.bi, &g.extra}
g.lp = lp
payload := []byte("123")
buf := strings.Builder{}
gc := &graphics.GraphicsCommand{}
@ -41,6 +54,24 @@ func (g *graphics_manager) initialize(lp *loop.Loop) {
lp.QueueWriteString(buf.String())
}
func (g *graphics_manager) clear_placements() {
gc := graphics.GraphicsCommand{}
gc.SetAction(graphics.GRT_action_delete).SetDelete(graphics.GRT_delete_visible)
gc.WriteWithPayloadToLoop(g.lp, nil)
}
func (g *graphics_manager) display_image(slot int, path string, img_width, img_height int) {
img := g.images[slot]
if img.current_file != path {
gc := img.graphics_command()
gc.SetAction(graphics.GRT_action_transmit).SetFormat(graphics.GRT_format_rgba).SetDataWidth(uint64(img_width)).SetDataHeight(uint64(img_height)).SetTransmission(graphics.GRT_transmission_file)
gc.WriteWithPayloadToLoop(g.lp, []byte(path))
}
gc := img.graphics_command()
gc.SetAction(graphics.GRT_action_display).SetCursorMovement(graphics.GRT_cursor_static)
gc.WriteWithPayloadToLoop(g.lp, nil)
}
func (g *graphics_manager) on_response(gc *graphics.GraphicsCommand) (err error) {
if gc.ResponseMessage() != "OK" {
return fmt.Errorf("Failed to load image with error: %s", gc.ResponseMessage())
@ -54,7 +85,7 @@ func (g *graphics_manager) on_response(gc *graphics.GraphicsCommand) (err error)
return
}
func (g *graphics_manager) finalize(lp *loop.Loop) {
func (g *graphics_manager) finalize() {
buf := strings.Builder{}
gc := &graphics.GraphicsCommand{}
gc.SetAction(graphics.GRT_action_delete).SetDelete(graphics.GRT_free_by_number)
@ -67,5 +98,5 @@ func (g *graphics_manager) finalize(lp *loop.Loop) {
d(g.italic.image_number)
d(g.bi.image_number)
d(g.extra.image_number)
lp.QueueWriteString(buf.String())
g.lp.QueueWriteString(buf.String())
}

View file

@ -7,11 +7,18 @@ import (
"kitty/tools/utils"
"kitty/tools/utils/style"
"kitty/tools/wcswidth"
"math"
"strings"
"sync"
)
var _ = fmt.Print
type preview_cache_key struct {
family string
width, height int
}
type FontList struct {
rl *readline.Readline
family_list FamilyList
@ -19,10 +26,13 @@ type FontList struct {
resolved_faces_from_kitty_conf ResolvedFaces
handler *handler
variable_data_requested_for *utils.Set[string]
preview_cache map[preview_cache_key]string
preview_cache_mutex sync.Mutex
}
func (self *FontList) initialize(h *handler) {
self.handler = h
self.preview_cache = make(map[preview_cache_key]string)
self.rl = readline.New(h.lp, readline.RlInit{DontMarkPrompts: true, Prompt: "Family: "})
self.variable_data_requested_for = utils.NewSet[string](256)
}
@ -89,13 +99,61 @@ func (self *FontList) draw_family_summary(start_x int, sz loop.ScreenSize) (err
}
}
for i, line := range lines {
if i >= int(sz.HeightCells)-1 {
y := 0
for _, line := range lines {
if y >= int(sz.HeightCells)-1 {
break
}
lp.MoveCursorTo(start_x+1, i+1)
lp.MoveCursorTo(start_x+1, y+1)
lp.QueueWriteString(line)
y++
}
if self.handler.text_style.Background != "" {
return self.draw_preview(start_x, y, sz)
}
return
}
func (self *FontList) draw_preview(x, y int, sz loop.ScreenSize) (err error) {
width_cells, height_cells := int(sz.WidthCells)-x-1, int(sz.HeightCells)-y
if height_cells < 3 {
return
}
y++
self.handler.lp.MoveCursorTo(x+1, y+1)
self.handler.lp.QueueWriteString("Preview:")
y++
height_cells -= 2
height_cells = min(height_cells, int(math.Ceil(100./float64(width_cells))))
self.handler.lp.MoveCursorTo(x+1, y+1)
key := preview_cache_key{
family: self.family_list.CurrentFamily(), width: int(sz.CellWidth) * width_cells, height: int(sz.CellHeight) * height_cells,
}
if key.family == "" {
return
}
self.preview_cache_mutex.Lock()
defer self.preview_cache_mutex.Unlock()
img_path := self.preview_cache[key]
switch img_path {
case "":
self.preview_cache[key] = "requested"
go func() {
var r map[string]string
self.handler.set_worker_error(kitty_font_backend.query("render_family_samples", map[string]any{
"text_style": self.handler.text_style, "font_family": key.family, "width": key.width, "height": key.height,
"output_dir": self.handler.temp_dir,
}, &r))
self.preview_cache_mutex.Lock()
defer self.preview_cache_mutex.Unlock()
self.preview_cache[key] = r["font_family"]
self.handler.lp.WakeupMainThread()
}()
return
case "requested":
return
}
self.handler.graphics_manager.display_image(0, img_path, key.width, key.height)
return
}

View file

@ -34,8 +34,7 @@ func main() (rc int, err error) {
lp.OnInitialize = func() (string, error) {
lp.AllowLineWrapping(false)
lp.SetWindowTitle(`Choose a font for kitty`)
h.initialize()
return "", nil
return "", h.initialize()
}
lp.OnWakeup = h.on_wakeup
lp.OnEscapeCode = h.on_escape_code

View file

@ -2,6 +2,7 @@ package choose_fonts
import (
"fmt"
"os"
"strconv"
"sync"
@ -38,6 +39,7 @@ type handler struct {
render_lines tui.RenderLines
text_style TextStyle
graphics_manager graphics_manager
temp_dir string
listing FontList
}
@ -55,12 +57,14 @@ func (h *handler) get_worker_error() error {
}
// Events {{{
func (h *handler) initialize() {
func (h *handler) initialize() (err error) {
h.lp.SetCursorVisible(false)
h.lp.OnQueryResponse = h.on_query_response
h.lp.QueryTerminal("font_size", "dpi_x", "dpi_y", "foreground", "background")
h.listing.initialize(h)
h.draw_screen()
if h.temp_dir, err = os.MkdirTemp("", "kitten-choose-fonts-*"); err != nil {
return
}
initialize_variable_data_cache()
h.graphics_manager.initialize(h.lp)
go func() {
@ -70,12 +74,18 @@ func (h *handler) initialize() {
h.listing.resolved_faces_from_kitty_conf = r.Resolved_faces
h.lp.WakeupMainThread()
}()
h.draw_screen()
return
}
func (h *handler) finalize() {
if h.temp_dir != "" {
os.RemoveAll(h.temp_dir)
h.temp_dir = ""
}
h.lp.SetCursorVisible(true)
h.lp.SetCursorShape(loop.BLOCK_CURSOR, true)
h.graphics_manager.finalize(h.lp)
h.graphics_manager.finalize()
}
func (h *handler) on_query_response(key, val string, valid bool) error {
@ -107,6 +117,7 @@ func (h *handler) on_query_response(key, val string, valid bool) error {
h.text_style.Foreground = val
case "background":
h.text_style.Background = val
return h.draw_screen()
}
return nil
}
@ -119,6 +130,7 @@ func (h *handler) draw_screen() (err error) {
h.mouse_state.ApplyHoverStyles(h.lp)
h.lp.EndAtomicUpdate()
}()
h.graphics_manager.clear_placements()
h.lp.ClearScreen()
h.lp.AllowLineWrapping(false)
h.mouse_state.ClearCellRegions()