Skip to content

Commit

Permalink
Make height option work under Windows (#1341)
Browse files Browse the repository at this point in the history
Separate Unix & Windows code into platform specific files for light renderer
  • Loading branch information
kelleyma49 authored and junegunn committed Mar 9, 2020
1 parent 7c40a42 commit 7d5985b
Show file tree
Hide file tree
Showing 5 changed files with 244 additions and 69 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ CHANGELOG
finder instead of printing horizontal lines above and below it.
The previous style is available via `--border=horizontal`
- Added `--pointer` and `--marker` options
- `--height` option is now available on Windows binary (@kelleyma49)
- More keys and actions for `--bind`
- Bug fixes and improvements
- Vim plugin: Floating windows support
Expand Down
5 changes: 2 additions & 3 deletions src/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

"github.com/junegunn/fzf/src/algo"
"github.com/junegunn/fzf/src/tui"
"github.com/junegunn/fzf/src/util"

"github.com/mattn/go-runewidth"
"github.com/mattn/go-shellwords"
Expand Down Expand Up @@ -1412,8 +1411,8 @@ func validateSign(sign string, signOptName string) error {
}

func postProcessOptions(opts *Options) {
if util.IsWindows() && opts.Height.size > 0 {
errorExit("--height option is currently not supported on Windows")
if !tui.IsLightRendererSupported() && opts.Height.size > 0 {
errorExit("--height option is currently not supported on this platform")
}
// Default actions for CTRL-N / CTRL-P when --history is set
if opts.History != nil {
Expand Down
78 changes: 12 additions & 66 deletions src/tui/light.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"regexp"
"strconv"
"strings"
"syscall"
"time"
"unicode/utf8"

Expand All @@ -30,21 +29,6 @@ const consoleDevice string = "/dev/tty"

var offsetRegexp *regexp.Regexp = regexp.MustCompile("(.*)\x1b\\[([0-9]+);([0-9]+)R")

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) stderr(str string) {
r.stderrInternal(str, true)
}
Expand Down Expand Up @@ -101,6 +85,13 @@ type LightRenderer struct {
y int
x int
maxHeightFunc func(int) int

// Windows only
ttyinChannel chan byte
inHandle uintptr
outHandle uintptr
origStateInput uint32
origStateOutput uint32
}

type LightWindow struct {
Expand Down Expand Up @@ -134,10 +125,6 @@ func NewLightRenderer(theme *ColorTheme, forceBlack bool, mouse bool, tabstop in
return &r
}

func (r *LightRenderer) fd() int {
return int(r.ttyin.Fd())
}

func (r *LightRenderer) defaultTheme() *ColorTheme {
if strings.Contains(os.Getenv("TERM"), "256") {
return Dark256
Expand All @@ -149,22 +136,6 @@ func (r *LightRenderer) defaultTheme() *ColorTheme {
return Default16
}

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 repeat(r rune, times int) string {
if times > 0 {
return strings.Repeat(string(r), times)
Expand All @@ -183,13 +154,9 @@ func atoi(s string, defaultValue int) int {
func (r *LightRenderer) Init() {
r.escDelay = atoi(os.Getenv("ESCDELAY"), defaultEscDelay)

fd := r.fd()
origState, err := terminal.GetState(fd)
if err != nil {
if err := r.initPlatform(); err != nil {
errorExit(err.Error())
}
r.origState = origState
terminal.MakeRaw(fd)
r.updateTerminalSize()
initTheme(r.theme, r.defaultTheme(), r.forceBlack)

Expand Down Expand Up @@ -262,28 +229,6 @@ func getEnv(name string, defaultValue int) int {
return atoi(env, defaultValue)
}

func (r *LightRenderer) updateTerminalSize() {
width, height, err := terminal.GetSize(r.fd())
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) 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
}

func (r *LightRenderer) getBytes() []byte {
return r.getBytesInternal(r.buffer, false)
}
Expand Down Expand Up @@ -604,7 +549,7 @@ func (r *LightRenderer) rmcup() {
}

func (r *LightRenderer) Pause(clear bool) {
terminal.Restore(r.fd(), r.origState)
r.restoreTerminal()
if clear {
if r.fullscreen {
r.rmcup()
Expand All @@ -617,7 +562,7 @@ func (r *LightRenderer) Pause(clear bool) {
}

func (r *LightRenderer) Resume(clear bool) {
terminal.MakeRaw(r.fd())
r.setupTerminal()
if clear {
if r.fullscreen {
r.smcup()
Expand Down Expand Up @@ -671,7 +616,8 @@ func (r *LightRenderer) Close() {
r.csi("?1000l")
}
r.flush()
terminal.Restore(r.fd(), r.origState)
r.closePlatform()
r.restoreTerminal()
}

func (r *LightRenderer) MaxX() int {
Expand Down
97 changes: 97 additions & 0 deletions src/tui/light_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// +build !windows

package tui

import (
"fmt"
"os"
"syscall"

"github.com/junegunn/fzf/src/util"
"golang.org/x/crypto/ssh/terminal"
)

func IsLightRendererSupported() bool {
return true
}

func (r *LightRenderer) fd() int {
return int(r.ttyin.Fd())
}

func (r *LightRenderer) initPlatform() error {
fd := r.fd()
origState, err := terminal.GetState(fd)
if err != nil {
return err
}
r.origState = origState
terminal.MakeRaw(fd)
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() {
terminal.MakeRaw(r.fd())
}

func (r *LightRenderer) restoreTerminal() {
terminal.Restore(r.fd(), r.origState)
}

func (r *LightRenderer) updateTerminalSize() {
width, height, err := terminal.GetSize(r.fd())

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
}
Loading

0 comments on commit 7d5985b

Please sign in to comment.