File: sixel.go

package info (click to toggle)
lf 34%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 1,296 kB
  • sloc: sh: 126; makefile: 23; csh: 4
file content (69 lines) | stat: -rw-r--r-- 1,915 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/gdamore/tcell/v2"
)

const (
	gSixelBegin = "\033P"

	// The filler character should be:
	// - rarely used: the filler is used to trick tcell into redrawing, if the
	//   filler character appears in the user's preview, that cell might not
	//   be cleaned up properly
	// - ideally renders as empty space: the filler alternates between bold
	//   and regular, using a non-space would look weird to the user.
	gSixelFiller = '\u2000'
)

type sixelScreen struct {
	xprev, yprev int
	sixel        *string
	altFill      bool
	lastFile     string // TODO maybe use hash of sixels instead to flip altFill
}

func (sxs *sixelScreen) fillerStyle(filePath string) tcell.Style {
	if sxs.lastFile != filePath {
		sxs.altFill = !sxs.altFill
	}

	if sxs.altFill {
		return tcell.StyleDefault.Bold(true)
	}
	return tcell.StyleDefault
}

func (sxs *sixelScreen) showSixels() {
	if sxs.sixel == nil {
		return
	}

	// XXX: workaround for bug where quitting lf might leave the terminal in bold
	fmt.Fprint(os.Stderr, "\033[0m")

	fmt.Fprint(os.Stderr, "\0337")                              // Save cursor position
	fmt.Fprintf(os.Stderr, "\033[%d;%dH", sxs.yprev, sxs.xprev) // Move cursor to position
	fmt.Fprint(os.Stderr, *sxs.sixel)                           //
	fmt.Fprint(os.Stderr, "\0338")                              // Restore cursor position
}

func (sxs *sixelScreen) printSixel(win *win, screen tcell.Screen, reg *reg) {
	if reg.sixel == nil {
		return
	}

	// HACK: fillers are used to control when tcell redraws the region where a sixel image is drawn.
	// alternating between bold and regular is to clear the image before drawing a new one.
	st := sxs.fillerStyle(reg.path)
	for y := 0; y < win.h; y++ {
		st = win.print(screen, 0, y, st, strings.Repeat(string(gSixelFiller), win.w))
	}

	sxs.xprev, sxs.yprev = win.x+1, win.y+1
	sxs.sixel = reg.sixel
}