Fix issues in tcell renderer and Windows build
- Fix display of CJK wide characters - Fix horizontal offset of header lines - Add support for keys with ALT modifier, shift-tab, page-up and down - Fix util.ExecCommand to properly parse command-line arguments - Fix redraw on resize - Implement Pause/Resume for execute action - Remove runtime check of GOOS - Change exit status to 2 when tcell failed to start - TBD: Travis CI build for tcell renderer - Pending. tcell cannot reliably ingest keys from tmux send-keys
This commit is contained in:
parent
26895da969
commit
898d8d94c8
@ -1,6 +1,10 @@
|
||||
language: ruby
|
||||
rvm:
|
||||
- 2.2.0
|
||||
matrix:
|
||||
include:
|
||||
- env: TAGS=
|
||||
rvm: 2.2.0
|
||||
# - env: TAGS=tcell
|
||||
# rvm: 2.2.0
|
||||
|
||||
install:
|
||||
- sudo apt-get update
|
||||
|
@ -52,7 +52,7 @@ android-build: $(SRCDIR)
|
||||
rm -f $(RELEASEARM7)
|
||||
|
||||
test: deps
|
||||
SHELL=/bin/sh go test -v ./...
|
||||
SHELL=/bin/sh go test -v -tags "$(TAGS)" ./...
|
||||
|
||||
install: $(BINDIR)/fzf
|
||||
|
||||
|
@ -4,7 +4,6 @@ import (
|
||||
"bufio"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/junegunn/fzf/src/util"
|
||||
)
|
||||
@ -44,7 +43,7 @@ func (r *Reader) feed(src io.Reader) {
|
||||
if len(bytea) > 0 {
|
||||
if err == nil {
|
||||
// get rid of carriage return if under Windows:
|
||||
if runtime.GOOS == "windows" && byteaLen >= 2 && bytea[byteaLen-2] == byte('\r') {
|
||||
if util.IsWindows() && byteaLen >= 2 && bytea[byteaLen-2] == byte('\r') {
|
||||
bytea = bytea[:byteaLen-2]
|
||||
} else {
|
||||
bytea = bytea[:byteaLen-1]
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"os/signal"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
@ -919,6 +920,9 @@ func keyMatch(key int, event tui.Event) bool {
|
||||
}
|
||||
|
||||
func quoteEntry(entry string) string {
|
||||
if util.IsWindows() {
|
||||
return strconv.Quote(strings.Replace(entry, "\"", "\\\"", -1))
|
||||
}
|
||||
return "'" + strings.Replace(entry, "'", "'\\''", -1) + "'"
|
||||
}
|
||||
|
||||
@ -982,6 +986,9 @@ func (t *Terminal) executeCommand(template string, items []*Item) {
|
||||
cmd.Stderr = os.Stderr
|
||||
tui.Pause()
|
||||
cmd.Run()
|
||||
if tui.Resume() {
|
||||
t.printAll()
|
||||
}
|
||||
t.refresh()
|
||||
}
|
||||
|
||||
|
@ -138,6 +138,10 @@ func Pause() {
|
||||
C.endwin()
|
||||
}
|
||||
|
||||
func Resume() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func Close() {
|
||||
C.endwin()
|
||||
C.delscreen(_screen)
|
||||
|
@ -13,6 +13,8 @@ import (
|
||||
|
||||
"github.com/gdamore/tcell"
|
||||
"github.com/gdamore/tcell/encoding"
|
||||
|
||||
"github.com/junegunn/go-runewidth"
|
||||
)
|
||||
|
||||
type ColorPair [2]Color
|
||||
@ -108,21 +110,32 @@ func (a Attr) Merge(b Attr) Attr {
|
||||
|
||||
var (
|
||||
_screen tcell.Screen
|
||||
_mouse bool
|
||||
)
|
||||
|
||||
func initScreen() {
|
||||
s, e := tcell.NewScreen()
|
||||
if e != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", e)
|
||||
os.Exit(2)
|
||||
}
|
||||
if e = s.Init(); e != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", e)
|
||||
os.Exit(2)
|
||||
}
|
||||
if _mouse {
|
||||
s.EnableMouse()
|
||||
} else {
|
||||
s.DisableMouse()
|
||||
}
|
||||
_screen = s
|
||||
}
|
||||
|
||||
func Init(theme *ColorTheme, black bool, mouse bool) {
|
||||
encoding.Register()
|
||||
|
||||
s, e := tcell.NewScreen()
|
||||
if e != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", e)
|
||||
os.Exit(1)
|
||||
}
|
||||
if e = s.Init(); e != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", e)
|
||||
os.Exit(1)
|
||||
}
|
||||
_screen = s
|
||||
_mouse = mouse
|
||||
initScreen()
|
||||
|
||||
_color = theme != nil
|
||||
if _color {
|
||||
@ -139,12 +152,6 @@ func Init(theme *ColorTheme, black bool, mouse bool) {
|
||||
ColSelected = ColorPair{theme.Selected, theme.DarkBg}
|
||||
ColHeader = ColorPair{theme.Header, theme.Bg}
|
||||
ColBorder = ColorPair{theme.Border, theme.Bg}
|
||||
|
||||
if mouse {
|
||||
_screen.EnableMouse()
|
||||
} else {
|
||||
_screen.DisableMouse()
|
||||
}
|
||||
}
|
||||
|
||||
func MaxX() int {
|
||||
@ -162,6 +169,7 @@ func (w *Window) win() *WindowTcell {
|
||||
}
|
||||
|
||||
func Clear() {
|
||||
_screen.Sync()
|
||||
_screen.Clear()
|
||||
}
|
||||
|
||||
@ -211,6 +219,7 @@ func GetChar() Event {
|
||||
|
||||
// process keyboard:
|
||||
case *tcell.EventKey:
|
||||
alt := (ev.Modifiers() & tcell.ModAlt) > 0
|
||||
switch ev.Key() {
|
||||
case tcell.KeyCtrlA:
|
||||
return Event{CtrlA, 0, nil}
|
||||
@ -233,6 +242,9 @@ func GetChar() Event {
|
||||
case tcell.KeyCtrlL:
|
||||
return Event{CtrlL, 0, nil}
|
||||
case tcell.KeyCtrlM:
|
||||
if alt {
|
||||
return Event{AltEnter, 0, nil}
|
||||
}
|
||||
return Event{CtrlM, 0, nil}
|
||||
case tcell.KeyCtrlN:
|
||||
return Event{CtrlN, 0, nil}
|
||||
@ -261,6 +273,9 @@ func GetChar() Event {
|
||||
case tcell.KeyCtrlZ:
|
||||
return Event{CtrlZ, 0, nil}
|
||||
case tcell.KeyBackspace, tcell.KeyBackspace2:
|
||||
if alt {
|
||||
return Event{AltBS, 0, nil}
|
||||
}
|
||||
return Event{BSpace, 0, nil}
|
||||
|
||||
case tcell.KeyUp:
|
||||
@ -278,13 +293,15 @@ func GetChar() Event {
|
||||
return Event{Del, 0, nil}
|
||||
case tcell.KeyEnd:
|
||||
return Event{End, 0, nil}
|
||||
/*case tcell.KeyPgUp:
|
||||
case tcell.KeyPgUp:
|
||||
return Event{PgUp, 0, nil}
|
||||
case tcell.KeyPgdn:
|
||||
return Event{PgDn, 0, nil}*/
|
||||
case tcell.KeyPgDn:
|
||||
return Event{PgDn, 0, nil}
|
||||
|
||||
case tcell.KeyTab:
|
||||
return Event{Tab, 0, nil}
|
||||
case tcell.KeyBacktab:
|
||||
return Event{BTab, 0, nil}
|
||||
|
||||
case tcell.KeyF1:
|
||||
return Event{F1, 0, nil}
|
||||
@ -313,7 +330,19 @@ func GetChar() Event {
|
||||
|
||||
// ev.Ch doesn't work for some reason for space:
|
||||
case tcell.KeyRune:
|
||||
return Event{Rune, ev.Rune(), nil}
|
||||
r := ev.Rune()
|
||||
if alt {
|
||||
switch r {
|
||||
case ' ':
|
||||
return Event{AltSpace, 0, nil}
|
||||
case '/':
|
||||
return Event{AltSlash, 0, nil}
|
||||
}
|
||||
if r >= 'a' && r <= 'z' {
|
||||
return Event{AltA + int(r) - 'a', 0, nil}
|
||||
}
|
||||
}
|
||||
return Event{Rune, r, nil}
|
||||
|
||||
case tcell.KeyEsc:
|
||||
return Event{ESC, 0, nil}
|
||||
@ -325,7 +354,12 @@ func GetChar() Event {
|
||||
}
|
||||
|
||||
func Pause() {
|
||||
// TODO
|
||||
_screen.Fini()
|
||||
}
|
||||
|
||||
func Resume() bool {
|
||||
initScreen()
|
||||
return true
|
||||
}
|
||||
|
||||
func Close() {
|
||||
@ -391,11 +425,10 @@ func (w *Window) Move(y int, x int) {
|
||||
|
||||
func (w *Window) MoveAndClear(y int, x int) {
|
||||
w.Move(y, x)
|
||||
r, _ := utf8.DecodeRuneInString(" ")
|
||||
for i := w.win().LastX; i < w.Width; i++ {
|
||||
_screen.SetContent(i+w.Left, w.win().LastY+w.Top, r, nil, ColDefault.style())
|
||||
_screen.SetContent(i+w.Left, w.win().LastY+w.Top, rune(' '), nil, ColDefault.style())
|
||||
}
|
||||
w.win().LastX = 0
|
||||
w.win().LastX = x
|
||||
}
|
||||
|
||||
func (w *Window) Print(text string) {
|
||||
@ -439,7 +472,7 @@ func (w *Window) PrintString(text string, pair ColorPair, a Attr) {
|
||||
if xPos < (w.Left+w.Width) && yPos < (w.Top+w.Height) {
|
||||
_screen.SetContent(xPos, yPos, r, nil, style)
|
||||
}
|
||||
lx++
|
||||
lx += runewidth.RuneWidth(r)
|
||||
}
|
||||
}
|
||||
w.win().LastX += lx
|
||||
@ -482,7 +515,7 @@ func (w *Window) FillString(text string, pair ColorPair, a Attr) bool {
|
||||
}
|
||||
|
||||
_screen.SetContent(xPos, yPos, r, nil, style)
|
||||
lx++
|
||||
lx += runewidth.RuneWidth(r)
|
||||
}
|
||||
}
|
||||
w.win().LastX += lx
|
||||
|
@ -15,3 +15,8 @@ func ExecCommand(command string) *exec.Cmd {
|
||||
}
|
||||
return exec.Command(shell, "-c", command)
|
||||
}
|
||||
|
||||
// IsWindows returns true on Windows
|
||||
func IsWindows() bool {
|
||||
return false
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ package util
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/junegunn/go-shellwords"
|
||||
)
|
||||
|
||||
// ExecCommand executes the given command with $SHELL
|
||||
@ -13,5 +15,14 @@ func ExecCommand(command string) *exec.Cmd {
|
||||
if len(shell) == 0 {
|
||||
shell = "cmd"
|
||||
}
|
||||
return exec.Command(shell, "/c", command)
|
||||
args, _ := shellwords.Parse(command)
|
||||
allArgs := make([]string, len(args)+1)
|
||||
allArgs[0] = "/c"
|
||||
copy(allArgs[1:], args)
|
||||
return exec.Command(shell, allArgs...)
|
||||
}
|
||||
|
||||
// IsWindows returns true on Windows
|
||||
func IsWindows() bool {
|
||||
return true
|
||||
}
|
||||
|
@ -1058,7 +1058,7 @@ class TestGoFZF < TestBase
|
||||
def test_invalid_term
|
||||
lines = `TERM=xxx #{FZF}`
|
||||
assert_equal 2, $?.exitstatus
|
||||
assert lines.include?('Invalid $TERM: xxx')
|
||||
assert lines.include?('Invalid $TERM: xxx') || lines.include?('terminal entry not found')
|
||||
end
|
||||
|
||||
def test_invalid_option
|
||||
|
Loading…
x
Reference in New Issue
Block a user