Get preview to basically display
This commit is contained in:
parent
6c11f0eeb5
commit
a0840a7328
6 changed files with 128 additions and 28 deletions
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Reference in a new issue