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
|
language: ruby
|
||||||
rvm:
|
matrix:
|
||||||
- 2.2.0
|
include:
|
||||||
|
- env: TAGS=
|
||||||
|
rvm: 2.2.0
|
||||||
|
# - env: TAGS=tcell
|
||||||
|
# rvm: 2.2.0
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- sudo apt-get update
|
- sudo apt-get update
|
||||||
|
@ -52,7 +52,7 @@ android-build: $(SRCDIR)
|
|||||||
rm -f $(RELEASEARM7)
|
rm -f $(RELEASEARM7)
|
||||||
|
|
||||||
test: deps
|
test: deps
|
||||||
SHELL=/bin/sh go test -v ./...
|
SHELL=/bin/sh go test -v -tags "$(TAGS)" ./...
|
||||||
|
|
||||||
install: $(BINDIR)/fzf
|
install: $(BINDIR)/fzf
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/junegunn/fzf/src/util"
|
"github.com/junegunn/fzf/src/util"
|
||||||
)
|
)
|
||||||
@ -44,7 +43,7 @@ func (r *Reader) feed(src io.Reader) {
|
|||||||
if len(bytea) > 0 {
|
if len(bytea) > 0 {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// get rid of carriage return if under Windows:
|
// 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]
|
bytea = bytea[:byteaLen-2]
|
||||||
} else {
|
} else {
|
||||||
bytea = bytea[:byteaLen-1]
|
bytea = bytea[:byteaLen-1]
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"os/signal"
|
"os/signal"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
@ -919,6 +920,9 @@ func keyMatch(key int, event tui.Event) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func quoteEntry(entry string) string {
|
func quoteEntry(entry string) string {
|
||||||
|
if util.IsWindows() {
|
||||||
|
return strconv.Quote(strings.Replace(entry, "\"", "\\\"", -1))
|
||||||
|
}
|
||||||
return "'" + 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
|
cmd.Stderr = os.Stderr
|
||||||
tui.Pause()
|
tui.Pause()
|
||||||
cmd.Run()
|
cmd.Run()
|
||||||
|
if tui.Resume() {
|
||||||
|
t.printAll()
|
||||||
|
}
|
||||||
t.refresh()
|
t.refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,6 +138,10 @@ func Pause() {
|
|||||||
C.endwin()
|
C.endwin()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Resume() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func Close() {
|
func Close() {
|
||||||
C.endwin()
|
C.endwin()
|
||||||
C.delscreen(_screen)
|
C.delscreen(_screen)
|
||||||
|
@ -13,6 +13,8 @@ import (
|
|||||||
|
|
||||||
"github.com/gdamore/tcell"
|
"github.com/gdamore/tcell"
|
||||||
"github.com/gdamore/tcell/encoding"
|
"github.com/gdamore/tcell/encoding"
|
||||||
|
|
||||||
|
"github.com/junegunn/go-runewidth"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ColorPair [2]Color
|
type ColorPair [2]Color
|
||||||
@ -108,21 +110,32 @@ func (a Attr) Merge(b Attr) Attr {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
_screen tcell.Screen
|
_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) {
|
func Init(theme *ColorTheme, black bool, mouse bool) {
|
||||||
encoding.Register()
|
encoding.Register()
|
||||||
|
|
||||||
s, e := tcell.NewScreen()
|
_mouse = mouse
|
||||||
if e != nil {
|
initScreen()
|
||||||
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
|
|
||||||
|
|
||||||
_color = theme != nil
|
_color = theme != nil
|
||||||
if _color {
|
if _color {
|
||||||
@ -139,12 +152,6 @@ func Init(theme *ColorTheme, black bool, mouse bool) {
|
|||||||
ColSelected = ColorPair{theme.Selected, theme.DarkBg}
|
ColSelected = ColorPair{theme.Selected, theme.DarkBg}
|
||||||
ColHeader = ColorPair{theme.Header, theme.Bg}
|
ColHeader = ColorPair{theme.Header, theme.Bg}
|
||||||
ColBorder = ColorPair{theme.Border, theme.Bg}
|
ColBorder = ColorPair{theme.Border, theme.Bg}
|
||||||
|
|
||||||
if mouse {
|
|
||||||
_screen.EnableMouse()
|
|
||||||
} else {
|
|
||||||
_screen.DisableMouse()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func MaxX() int {
|
func MaxX() int {
|
||||||
@ -162,6 +169,7 @@ func (w *Window) win() *WindowTcell {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Clear() {
|
func Clear() {
|
||||||
|
_screen.Sync()
|
||||||
_screen.Clear()
|
_screen.Clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,6 +219,7 @@ func GetChar() Event {
|
|||||||
|
|
||||||
// process keyboard:
|
// process keyboard:
|
||||||
case *tcell.EventKey:
|
case *tcell.EventKey:
|
||||||
|
alt := (ev.Modifiers() & tcell.ModAlt) > 0
|
||||||
switch ev.Key() {
|
switch ev.Key() {
|
||||||
case tcell.KeyCtrlA:
|
case tcell.KeyCtrlA:
|
||||||
return Event{CtrlA, 0, nil}
|
return Event{CtrlA, 0, nil}
|
||||||
@ -233,6 +242,9 @@ func GetChar() Event {
|
|||||||
case tcell.KeyCtrlL:
|
case tcell.KeyCtrlL:
|
||||||
return Event{CtrlL, 0, nil}
|
return Event{CtrlL, 0, nil}
|
||||||
case tcell.KeyCtrlM:
|
case tcell.KeyCtrlM:
|
||||||
|
if alt {
|
||||||
|
return Event{AltEnter, 0, nil}
|
||||||
|
}
|
||||||
return Event{CtrlM, 0, nil}
|
return Event{CtrlM, 0, nil}
|
||||||
case tcell.KeyCtrlN:
|
case tcell.KeyCtrlN:
|
||||||
return Event{CtrlN, 0, nil}
|
return Event{CtrlN, 0, nil}
|
||||||
@ -261,6 +273,9 @@ func GetChar() Event {
|
|||||||
case tcell.KeyCtrlZ:
|
case tcell.KeyCtrlZ:
|
||||||
return Event{CtrlZ, 0, nil}
|
return Event{CtrlZ, 0, nil}
|
||||||
case tcell.KeyBackspace, tcell.KeyBackspace2:
|
case tcell.KeyBackspace, tcell.KeyBackspace2:
|
||||||
|
if alt {
|
||||||
|
return Event{AltBS, 0, nil}
|
||||||
|
}
|
||||||
return Event{BSpace, 0, nil}
|
return Event{BSpace, 0, nil}
|
||||||
|
|
||||||
case tcell.KeyUp:
|
case tcell.KeyUp:
|
||||||
@ -278,13 +293,15 @@ func GetChar() Event {
|
|||||||
return Event{Del, 0, nil}
|
return Event{Del, 0, nil}
|
||||||
case tcell.KeyEnd:
|
case tcell.KeyEnd:
|
||||||
return Event{End, 0, nil}
|
return Event{End, 0, nil}
|
||||||
/*case tcell.KeyPgUp:
|
case tcell.KeyPgUp:
|
||||||
return Event{PgUp, 0, nil}
|
return Event{PgUp, 0, nil}
|
||||||
case tcell.KeyPgdn:
|
case tcell.KeyPgDn:
|
||||||
return Event{PgDn, 0, nil}*/
|
return Event{PgDn, 0, nil}
|
||||||
|
|
||||||
case tcell.KeyTab:
|
case tcell.KeyTab:
|
||||||
return Event{Tab, 0, nil}
|
return Event{Tab, 0, nil}
|
||||||
|
case tcell.KeyBacktab:
|
||||||
|
return Event{BTab, 0, nil}
|
||||||
|
|
||||||
case tcell.KeyF1:
|
case tcell.KeyF1:
|
||||||
return Event{F1, 0, nil}
|
return Event{F1, 0, nil}
|
||||||
@ -313,7 +330,19 @@ func GetChar() Event {
|
|||||||
|
|
||||||
// ev.Ch doesn't work for some reason for space:
|
// ev.Ch doesn't work for some reason for space:
|
||||||
case tcell.KeyRune:
|
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:
|
case tcell.KeyEsc:
|
||||||
return Event{ESC, 0, nil}
|
return Event{ESC, 0, nil}
|
||||||
@ -325,7 +354,12 @@ func GetChar() Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Pause() {
|
func Pause() {
|
||||||
// TODO
|
_screen.Fini()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Resume() bool {
|
||||||
|
initScreen()
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func Close() {
|
func Close() {
|
||||||
@ -391,11 +425,10 @@ func (w *Window) Move(y int, x int) {
|
|||||||
|
|
||||||
func (w *Window) MoveAndClear(y int, x int) {
|
func (w *Window) MoveAndClear(y int, x int) {
|
||||||
w.Move(y, x)
|
w.Move(y, x)
|
||||||
r, _ := utf8.DecodeRuneInString(" ")
|
|
||||||
for i := w.win().LastX; i < w.Width; i++ {
|
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) {
|
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) {
|
if xPos < (w.Left+w.Width) && yPos < (w.Top+w.Height) {
|
||||||
_screen.SetContent(xPos, yPos, r, nil, style)
|
_screen.SetContent(xPos, yPos, r, nil, style)
|
||||||
}
|
}
|
||||||
lx++
|
lx += runewidth.RuneWidth(r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.win().LastX += lx
|
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)
|
_screen.SetContent(xPos, yPos, r, nil, style)
|
||||||
lx++
|
lx += runewidth.RuneWidth(r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.win().LastX += lx
|
w.win().LastX += lx
|
||||||
|
@ -15,3 +15,8 @@ func ExecCommand(command string) *exec.Cmd {
|
|||||||
}
|
}
|
||||||
return exec.Command(shell, "-c", command)
|
return exec.Command(shell, "-c", command)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsWindows returns true on Windows
|
||||||
|
func IsWindows() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@ -5,6 +5,8 @@ package util
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/junegunn/go-shellwords"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExecCommand executes the given command with $SHELL
|
// ExecCommand executes the given command with $SHELL
|
||||||
@ -13,5 +15,14 @@ func ExecCommand(command string) *exec.Cmd {
|
|||||||
if len(shell) == 0 {
|
if len(shell) == 0 {
|
||||||
shell = "cmd"
|
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
|
def test_invalid_term
|
||||||
lines = `TERM=xxx #{FZF}`
|
lines = `TERM=xxx #{FZF}`
|
||||||
assert_equal 2, $?.exitstatus
|
assert_equal 2, $?.exitstatus
|
||||||
assert lines.include?('Invalid $TERM: xxx')
|
assert lines.include?('Invalid $TERM: xxx') || lines.include?('terminal entry not found')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_invalid_option
|
def test_invalid_option
|
||||||
|
Loading…
x
Reference in New Issue
Block a user