diff --git a/CHANGELOG.md b/CHANGELOG.md index d33a181b..0a1a8a6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,10 @@ CHANGELOG # usage: _fzf_setup_completion path|dir COMMANDS... _fzf_setup_completion path git kubectl ``` +- Info line style can be changed by `--info=STYLE` + - `--info=default` + - `--info=inline` (same as old `--inline-info`) + - `--info=hidden` - When you transform the input with `--with-nth`, the trailing white spaces are removed. - `ctrl-\`, `ctrl-]`, `ctrl-^`, and `ctrl-/` can now be used with `--bind` diff --git a/man/man1/fzf.1 b/man/man1/fzf.1 index bd18fb81..f90a0571 100644 --- a/man/man1/fzf.1 +++ b/man/man1/fzf.1 @@ -212,8 +212,21 @@ e.g. fzf --margin 1,5%\fR .RE .TP -.B "--inline-info" -Display finder info inline with the query +.BI "--info=" "STYLE" +Determines the display style of finder info. + +.br +.BR default " Display on the next line to the prompt" +.br +.BR inline " Display on the same line" +.br +.BR hidden " Do not display finder info" +.br + +.TP +.B "--no-info" +A synonym for \fB--info=hidden\fB + .TP .BI "--prompt=" "STR" Input prompt (default: '> ') diff --git a/src/options.go b/src/options.go index fb432a6f..fe0d06d3 100644 --- a/src/options.go +++ b/src/options.go @@ -57,7 +57,7 @@ const usage = `usage: fzf [options] --layout=LAYOUT Choose layout: [default|reverse|reverse-list] --border Draw border above and below the finder --margin=MARGIN Screen margin (TRBL / TB,RL / T,RL,B / T,R,B,L) - --inline-info Display finder info inline with the query + --info=STYLE Finder info style [default|inline|hidden] --prompt=STR Input prompt (default: '> ') --header=STR String to print as header --header-lines=N The first N lines of the input are treated as header @@ -142,6 +142,14 @@ const ( layoutReverseList ) +type infoStyle int + +const ( + infoDefault infoStyle = iota + infoInline + infoHidden +) + type previewOpts struct { command string position windowPosition @@ -177,7 +185,7 @@ type Options struct { Hscroll bool HscrollOff int FileWord bool - InlineInfo bool + InfoStyle infoStyle JumpLabels string Prompt string Query string @@ -230,7 +238,7 @@ func defaultOptions() *Options { Hscroll: true, HscrollOff: 10, FileWord: false, - InlineInfo: false, + InfoStyle: infoDefault, JumpLabels: defaultJumpLabels, Prompt: "> ", Query: "", @@ -904,6 +912,20 @@ func parseLayout(str string) layoutType { return layoutDefault } +func parseInfoStyle(str string) infoStyle { + switch str { + case "default": + return infoDefault + case "inline": + return infoInline + case "hidden": + return infoHidden + default: + errorExit("invalid info style (expected: default / inline / hidden)") + } + return infoDefault +} + func parsePreviewWindow(opts *previewOpts, input string) { // Default opts.position = posRight @@ -1109,10 +1131,15 @@ func parseOptions(opts *Options, allArgs []string) { opts.FileWord = true case "--no-filepath-word": opts.FileWord = false + case "--info": + opts.InfoStyle = parseInfoStyle( + nextString(allArgs, &i, "info style required")) + case "--no-info": + opts.InfoStyle = infoHidden case "--inline-info": - opts.InlineInfo = true + opts.InfoStyle = infoInline case "--no-inline-info": - opts.InlineInfo = false + opts.InfoStyle = infoDefault case "--jump-labels": opts.JumpLabels = nextString(allArgs, &i, "label characters required") validateJumpLabels = true @@ -1220,6 +1247,8 @@ func parseOptions(opts *Options, allArgs []string) { opts.MinHeight = atoi(value) } else if match, value := optString(arg, "--layout="); match { opts.Layout = parseLayout(value) + } else if match, value := optString(arg, "--info="); match { + opts.InfoStyle = parseInfoStyle(value) } else if match, value := optString(arg, "--toggle-sort="); match { parseToggleSort(opts.Keymap, value) } else if match, value := optString(arg, "--expect="); match { diff --git a/src/terminal.go b/src/terminal.go index c5ff3025..0b812ccc 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -60,7 +60,7 @@ var emptyLine = itemLine{} // Terminal represents terminal input/output type Terminal struct { initDelay time.Duration - inlineInfo bool + infoStyle infoStyle prompt string promptLen int queryLen [2]int @@ -361,7 +361,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal { if previewBox != nil && (opts.Preview.position == posUp || opts.Preview.position == posDown) { effectiveMinHeight *= 2 } - if opts.InlineInfo { + if opts.InfoStyle != infoDefault { effectiveMinHeight -= 1 } if opts.Bordered { @@ -380,7 +380,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal { } t := Terminal{ initDelay: delay, - inlineInfo: opts.InlineInfo, + infoStyle: opts.InfoStyle, queryLen: [2]int{0, 0}, layout: opts.Layout, fullscreen: fullscreen, @@ -438,6 +438,10 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal { return &t } +func (t *Terminal) noInfoLine() bool { + return t.infoStyle != infoDefault +} + // Input returns current query string func (t *Terminal) Input() []rune { t.mutex.Lock() @@ -672,7 +676,7 @@ func (t *Terminal) move(y int, x int, clear bool) { y = h - y - 1 case layoutReverseList: n := 2 + len(t.header) - if t.inlineInfo { + if t.noInfoLine() { n-- } if y < n { @@ -725,7 +729,17 @@ func (t *Terminal) printPrompt() { func (t *Terminal) printInfo() { pos := 0 - if t.inlineInfo { + switch t.infoStyle { + case infoDefault: + t.move(1, 0, true) + if t.reading { + duration := int64(spinnerDuration) + idx := (time.Now().UnixNano() % (duration * int64(len(_spinner)))) / duration + t.window.CPrint(tui.ColSpinner, t.strong, _spinner[idx]) + } + t.move(1, 2, false) + pos = 2 + case infoInline: pos = t.promptLen + t.queryLen[0] + t.queryLen[1] + 1 if pos+len(" < ") > t.window.Width() { return @@ -737,15 +751,8 @@ func (t *Terminal) printInfo() { t.window.CPrint(tui.ColPrompt, t.strong, " < ") } pos += len(" < ") - } else { - t.move(1, 0, true) - if t.reading { - duration := int64(spinnerDuration) - idx := (time.Now().UnixNano() % (duration * int64(len(_spinner)))) / duration - t.window.CPrint(tui.ColSpinner, t.strong, _spinner[idx]) - } - t.move(1, 2, false) - pos = 2 + case infoHidden: + return } found := t.merger.Length() @@ -787,7 +794,7 @@ func (t *Terminal) printHeader() { var state *ansiState for idx, lineStr := range t.header { line := idx + 2 - if t.inlineInfo { + if t.noInfoLine() { line-- } if line >= max { @@ -816,7 +823,7 @@ func (t *Terminal) printList() { i = maxy - 1 - j } line := i + 2 + len(t.header) - if t.inlineInfo { + if t.noInfoLine() { line-- } if i < count { @@ -1590,9 +1597,6 @@ func (t *Terminal) Loop() { } exit := func(getCode func() int) { - if !t.cleanExit && t.fullscreen && t.inlineInfo { - t.placeCursor() - } t.tui.Close() code := getCode() if code <= exitNoMatch && t.history != nil { @@ -1613,7 +1617,7 @@ func (t *Terminal) Loop() { switch req { case reqPrompt: t.printPrompt() - if t.inlineInfo { + if t.noInfoLine() { t.printInfo() } case reqInfo: @@ -1995,7 +1999,7 @@ func (t *Terminal) Loop() { my -= t.window.Top() mx = util.Constrain(mx-t.promptLen, 0, len(t.input)) min := 2 + len(t.header) - if t.inlineInfo { + if t.noInfoLine() { min-- } h := t.window.Height() @@ -2151,7 +2155,7 @@ func (t *Terminal) vset(o int) bool { func (t *Terminal) maxItems() int { max := t.window.Height() - 2 - len(t.header) - if t.inlineInfo { + if t.noInfoLine() { max++ } return util.Max(max, 0) diff --git a/test/test_go.rb b/test/test_go.rb index 210f8fec..501641e2 100755 --- a/test/test_go.rb +++ b/test/test_go.rb @@ -1516,6 +1516,11 @@ class TestGoFZF < TestBase tmux.until { |lines| lines[-1] == prompt } end + def test_info_hidden + tmux.send_keys 'seq 10 | fzf --info=hidden', :Enter + tmux.until { |lines| lines[-2] == '> 1' } + end + def test_change_top tmux.send_keys %(seq 1000 | #{FZF} --bind change:top), :Enter tmux.until { |lines| lines.match_count == 1000 }