2019-02-05 06:51:39 +00:00
|
|
|
// +build !windows
|
|
|
|
|
|
|
|
package tui
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
2020-09-02 04:47:13 +00:00
|
|
|
"os/exec"
|
|
|
|
"strings"
|
2019-02-05 06:51:39 +00:00
|
|
|
"syscall"
|
|
|
|
|
|
|
|
"github.com/junegunn/fzf/src/util"
|
2021-03-20 05:38:34 +00:00
|
|
|
"golang.org/x/term"
|
2019-02-05 06:51:39 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func IsLightRendererSupported() bool {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-09-02 04:47:13 +00:00
|
|
|
func (r *LightRenderer) defaultTheme() *ColorTheme {
|
|
|
|
if strings.Contains(os.Getenv("TERM"), "256") {
|
|
|
|
return Dark256
|
|
|
|
}
|
|
|
|
colors, err := exec.Command("tput", "colors").Output()
|
|
|
|
if err == nil && atoi(strings.TrimSpace(string(colors)), 16) > 16 {
|
|
|
|
return Dark256
|
|
|
|
}
|
|
|
|
return Default16
|
|
|
|
}
|
|
|
|
|
2019-02-05 06:51:39 +00:00
|
|
|
func (r *LightRenderer) fd() int {
|
|
|
|
return int(r.ttyin.Fd())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *LightRenderer) initPlatform() error {
|
|
|
|
fd := r.fd()
|
2021-03-20 05:38:34 +00:00
|
|
|
origState, err := term.GetState(fd)
|
2019-02-05 06:51:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
r.origState = origState
|
2021-03-20 05:38:34 +00:00
|
|
|
term.MakeRaw(fd)
|
2019-02-05 06:51:39 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *LightRenderer) closePlatform() {
|
|
|
|
// NOOP
|
|
|
|
}
|
|
|
|
|
|
|
|
func openTtyIn() *os.File {
|
|
|
|
in, err := os.OpenFile(consoleDevice, syscall.O_RDONLY, 0)
|
|
|
|
if err != nil {
|
|
|
|
tty := ttyname()
|
|
|
|
if len(tty) > 0 {
|
|
|
|
if in, err := os.OpenFile(tty, syscall.O_RDONLY, 0); err == nil {
|
|
|
|
return in
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fmt.Fprintln(os.Stderr, "Failed to open "+consoleDevice)
|
|
|
|
os.Exit(2)
|
|
|
|
}
|
|
|
|
return in
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *LightRenderer) setupTerminal() {
|
2021-03-20 05:38:34 +00:00
|
|
|
term.MakeRaw(r.fd())
|
2019-02-05 06:51:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *LightRenderer) restoreTerminal() {
|
2021-03-20 05:38:34 +00:00
|
|
|
term.Restore(r.fd(), r.origState)
|
2019-02-05 06:51:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *LightRenderer) updateTerminalSize() {
|
2021-03-20 05:38:34 +00:00
|
|
|
width, height, err := term.GetSize(r.fd())
|
2019-02-05 06:51:39 +00:00
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
r.width = width
|
|
|
|
r.height = r.maxHeightFunc(height)
|
|
|
|
} else {
|
|
|
|
r.width = getEnv("COLUMNS", defaultWidth)
|
|
|
|
r.height = r.maxHeightFunc(getEnv("LINES", defaultHeight))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *LightRenderer) findOffset() (row int, col int) {
|
|
|
|
r.csi("6n")
|
|
|
|
r.flush()
|
|
|
|
bytes := []byte{}
|
|
|
|
for tries := 0; tries < offsetPollTries; tries++ {
|
|
|
|
bytes = r.getBytesInternal(bytes, tries > 0)
|
|
|
|
offsets := offsetRegexp.FindSubmatch(bytes)
|
|
|
|
if len(offsets) > 3 {
|
|
|
|
// Add anything we skipped over to the input buffer
|
|
|
|
r.buffer = append(r.buffer, offsets[1]...)
|
|
|
|
return atoi(string(offsets[2]), 0) - 1, atoi(string(offsets[3]), 0) - 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1, -1
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *LightRenderer) getch(nonblock bool) (int, bool) {
|
|
|
|
b := make([]byte, 1)
|
|
|
|
fd := r.fd()
|
|
|
|
util.SetNonblock(r.ttyin, nonblock)
|
|
|
|
_, err := util.Read(fd, b)
|
|
|
|
if err != nil {
|
|
|
|
return 0, false
|
|
|
|
}
|
|
|
|
return int(b[0]), true
|
|
|
|
}
|