diff --git a/CHANGELOG.md b/CHANGELOG.md index a91d7b04..70d89357 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,14 @@ CHANGELOG 0.49.0 ------ -- Performance improvements - - Ingestion performance improved by 40% - - `--ansi` performance improved by 50% - - `--with-nth` performance improved by 30% +- Ingestion performance improved by around 40% (more or less depending on options) +- `--info=hidden` and `--info=inline-right` will no longer hide the horizontal separator by default. This gives you more flexibility in customizing the layout. + ```sh + fzf --border --info=inline-right + fzf --border --info=inline-right --no-separator + fzf --border --info=hidden + fzf --border --info=hidden --no-separator + ``` - Added two environment variables exported to the child processes - `FZF_PREVIEW_LABEL` - `FZF_BORDER_LABEL` @@ -22,7 +26,7 @@ CHANGELOG - `track` is still available as an alias - Added `untrack-current` and `toggle-track-current` actions - `*-current` actions are no-op when the global tracking state is set -- Bug fixes +- Bug fixes and minor improvements 0.48.1 ------ diff --git a/man/man1/fzf.1 b/man/man1/fzf.1 index 3f8619ab..6d682ef4 100644 --- a/man/man1/fzf.1 +++ b/man/man1/fzf.1 @@ -372,20 +372,21 @@ e.g. .TP .BI "--info=" "STYLE" -Determines the display style of finder info (match counters). +Determines the display style of the finder info. (e.g. match counter, loading indicator, etc.) +.BR default " On the left end of the horizontal separator" .br -.BR default " Display on the next line to the prompt" +.BR right " On the right end of the horizontal separator" .br -.BR right " Display on the right end of the next line to the prompt" +.BR hidden " Do not display finder info" .br -.BR inline " Display on the same line with the default separator ' < '" +.BR inline " After the prompt with the default prefix ' < '" .br -.BR inline:SEPARATOR " Display on the same line with a non-default separator" +.BR inline:PREFIX " After the prompt with a non-default prefix" .br -.BR inline-right " Display on the right end of the same line +.BR inline-right " On the right end of the prompt line" .br -.BR hidden " Do not display finder info" +.BR inline-right:PREFIX " On the right end of the prompt line with a custom prefix" .br .TP diff --git a/src/options.go b/src/options.go index a28e9e6f..5c73aee7 100644 --- a/src/options.go +++ b/src/options.go @@ -75,7 +75,7 @@ const usage = `usage: fzf [options] --margin=MARGIN Screen margin (TRBL | TB,RL | T,RL,B | T,R,B,L) --padding=PADDING Padding inside border (TRBL | TB,RL | T,RL,B | T,R,B,L) --info=STYLE Finder info style - [default|right|hidden|inline[:SEPARATOR]|inline-right] + [default|right|hidden|inline[-right][:PREFIX]] --separator=STR String to form horizontal separator on info line --no-separator Hide info line separator --scrollbar[=C1[C2]] Scrollbar character(s) (each for main and preview window) @@ -143,7 +143,7 @@ const usage = `usage: fzf [options] ` -const defaultInfoSep = " < " +const defaultInfoPrefix = " < " // Case denotes case-sensitivity of search type Case int @@ -217,10 +217,6 @@ const ( infoHidden ) -func (s infoStyle) noExtraLine() bool { - return s == infoInline || s == infoInlineRight || s == infoHidden -} - type labelOpts struct { label string column int @@ -327,7 +323,7 @@ type Options struct { ScrollOff int FileWord bool InfoStyle infoStyle - InfoSep string + InfoPrefix string Separator *string JumpLabels string Prompt string @@ -1506,17 +1502,24 @@ func parseInfoStyle(str string) (infoStyle, string) { case "right": return infoRight, "" case "inline": - return infoInline, defaultInfoSep + return infoInline, defaultInfoPrefix case "inline-right": return infoInlineRight, "" case "hidden": return infoHidden, "" default: - prefix := "inline:" - if strings.HasPrefix(str, prefix) { - return infoInline, strings.ReplaceAll(str[len(prefix):], "\n", " ") + type infoSpec struct { + name string + style infoStyle + } + for _, spec := range []infoSpec{ + {"inline", infoInline}, + {"inline-right", infoInlineRight}} { + if strings.HasPrefix(str, spec.name+":") { + return spec.style, strings.ReplaceAll(str[len(spec.name)+1:], "\n", " ") + } } - errorExit("invalid info style (expected: default|right|hidden|inline[:SEPARATOR]|inline-right)") + errorExit("invalid info style (expected: default|right|hidden|inline[-right][:PREFIX])") } return infoDefault, "" } @@ -1807,13 +1810,13 @@ func parseOptions(opts *Options, allArgs []string) { case "--no-filepath-word": opts.FileWord = false case "--info": - opts.InfoStyle, opts.InfoSep = parseInfoStyle( + opts.InfoStyle, opts.InfoPrefix = parseInfoStyle( nextString(allArgs, &i, "info style required")) case "--no-info": opts.InfoStyle = infoHidden case "--inline-info": opts.InfoStyle = infoInline - opts.InfoSep = defaultInfoSep + opts.InfoPrefix = defaultInfoPrefix case "--no-inline-info": opts.InfoStyle = infoDefault case "--separator": @@ -2015,7 +2018,7 @@ func parseOptions(opts *Options, allArgs []string) { } else if match, value := optString(arg, "--layout="); match { opts.Layout = parseLayout(value) } else if match, value := optString(arg, "--info="); match { - opts.InfoStyle, opts.InfoSep = parseInfoStyle(value) + opts.InfoStyle, opts.InfoPrefix = parseInfoStyle(value) } else if match, value := optString(arg, "--separator="); match { opts.Separator = &value } else if match, value := optString(arg, "--scrollbar="); match { diff --git a/src/terminal.go b/src/terminal.go index ef7ba9dd..2289a7f9 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -181,7 +181,7 @@ type Status struct { type Terminal struct { initDelay time.Duration infoStyle infoStyle - infoSep string + infoPrefix string separator labelPrinter separatorLen int spinner []string @@ -677,7 +677,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal { if previewBox != nil && opts.Preview.aboveOrBelow() { effectiveMinHeight += 1 + borderLines(opts.Preview.border) } - if opts.InfoStyle.noExtraLine() { + if noSeparatorLine(opts.InfoStyle, opts.Separator == nil || uniseg.StringWidth(*opts.Separator) > 0) { effectiveMinHeight-- } effectiveMinHeight += borderLines(opts.BorderShape) @@ -699,7 +699,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal { t := Terminal{ initDelay: delay, infoStyle: opts.InfoStyle, - infoSep: opts.InfoSep, + infoPrefix: opts.InfoPrefix, separator: nil, spinner: makeSpinner(opts.Unicode), promptString: opts.Prompt, @@ -882,7 +882,7 @@ func (t *Terminal) visibleHeaderLines() int { // Extra number of lines needed to display fzf func (t *Terminal) extraLines() int { extra := t.visibleHeaderLines() + 1 - if !t.noInfoLine() { + if !t.noSeparatorLine() { extra++ } return extra @@ -988,8 +988,18 @@ func (t *Terminal) parsePrompt(prompt string) (func(), int) { return output, promptLen } -func (t *Terminal) noInfoLine() bool { - return t.infoStyle.noExtraLine() +func noSeparatorLine(style infoStyle, separator bool) bool { + switch style { + case infoInline: + return true + case infoHidden, infoInlineRight: + return !separator + } + return false +} + +func (t *Terminal) noSeparatorLine() bool { + return noSeparatorLine(t.infoStyle, t.separatorLen > 0) } func getScrollbar(total int, height int, offset int) (int, int) { @@ -1241,7 +1251,7 @@ func (t *Terminal) adjustMarginAndPadding() (int, int, [4]int, [4]int) { minAreaWidth := minWidth minAreaHeight := minHeight - if t.noInfoLine() { + if t.noSeparatorLine() { minAreaHeight -= 1 } if t.needPreviewWindow() { @@ -1522,7 +1532,7 @@ func (t *Terminal) move(y int, x int, clear bool) { y = h - y - 1 case layoutReverseList: n := 2 + t.visibleHeaderLines() - if t.noInfoLine() { + if t.noSeparatorLine() { n-- } if y < n { @@ -1562,7 +1572,7 @@ func (t *Terminal) updatePromptOffset() ([]rune, []rune) { func (t *Terminal) promptLine() int { if t.headerFirst { max := t.window.Height() - 1 - if !t.noInfoLine() { + if !t.noSeparatorLine() { max-- } return util.Min(t.visibleHeaderLines(), max) @@ -1607,20 +1617,8 @@ func (t *Terminal) printInfo() { t.window.Print(" ") // Clear spinner } } - switch t.infoStyle { - case infoDefault: - t.move(line+1, 0, t.separatorLen == 0) - printSpinner() - t.move(line+1, 2, false) - pos = 2 - case infoRight: - t.move(line+1, 0, false) - case infoInlineRight: - pos = t.promptLen + t.queryLen[0] + t.queryLen[1] + 1 - t.move(line, pos, true) - case infoInline: - pos = t.promptLen + t.queryLen[0] + t.queryLen[1] + 1 - str := t.infoSep + printInfoPrefix := func() { + str := t.infoPrefix maxWidth := t.window.Width() - pos width := util.StringWidth(str) if width > maxWidth { @@ -1635,7 +1633,34 @@ func (t *Terminal) printInfo() { t.window.CPrint(tui.ColPrompt, str) } pos += width + } + printSeparator := func(fillLength int, pad bool) { + // --------_ + if t.separatorLen > 0 { + t.separator(t.window, fillLength) + t.window.Print(" ") + } else if pad { + t.window.Print(strings.Repeat(" ", fillLength+1)) + } + } + switch t.infoStyle { + case infoDefault: + t.move(line+1, 0, t.separatorLen == 0) + printSpinner() + t.move(line+1, 2, false) + pos = 2 + case infoRight: + t.move(line+1, 0, false) + case infoInlineRight: + pos = t.promptLen + t.queryLen[0] + t.queryLen[1] + 1 + case infoInline: + pos = t.promptLen + t.queryLen[0] + t.queryLen[1] + 1 + printInfoPrefix() case infoHidden: + if t.separatorLen > 0 { + t.move(line+1, 0, false) + printSeparator(t.window.Width()-1, false) + } return } @@ -1669,15 +1694,6 @@ func (t *Terminal) printInfo() { output = fmt.Sprintf("[Command failed: %s]", *t.failed) } - printSeparator := func(fillLength int, pad bool) { - // --------_ - if t.separatorLen > 0 { - t.separator(t.window, fillLength) - t.window.Print(" ") - } else if pad { - t.window.Print(strings.Repeat(" ", fillLength+1)) - } - } if t.infoStyle == infoRight { maxWidth := t.window.Width() if t.reading { @@ -1700,19 +1716,35 @@ func (t *Terminal) printInfo() { } if t.infoStyle == infoInlineRight { - pos = util.Max(pos, t.window.Width()-util.StringWidth(output)-3) - if pos >= t.window.Width() { - return + if len(t.infoPrefix) == 0 { + pos = util.Max(pos, t.window.Width()-util.StringWidth(output)-3) + if pos < t.window.Width() { + t.move(line, pos, false) + printSpinner() + pos++ + } + if pos < t.window.Width()-1 { + t.window.Print(" ") + pos++ + } + } else { + pos = util.Max(pos, t.window.Width()-util.StringWidth(output)-util.StringWidth(t.infoPrefix)-1) + printInfoPrefix() } - t.move(line, pos, false) - printSpinner() - t.window.Print(" ") - pos += 2 } maxWidth := t.window.Width() - pos output = t.trimMessage(output, maxWidth) t.window.CPrint(tui.ColInfo, output) + + if t.infoStyle == infoInlineRight { + if t.separatorLen > 0 { + t.move(line+1, 0, false) + printSeparator(t.window.Width()-1, false) + } + return + } + fillLength := maxWidth - len(output) - 2 if fillLength > 0 { t.window.CPrint(tui.ColSeparator, " ") @@ -1727,7 +1759,7 @@ func (t *Terminal) printHeader() { max := t.window.Height() if t.headerFirst { max-- - if !t.noInfoLine() { + if !t.noSeparatorLine() { max-- } } @@ -1744,7 +1776,7 @@ func (t *Terminal) printHeader() { } if !t.headerFirst { line++ - if !t.noInfoLine() { + if !t.noSeparatorLine() { line++ } } @@ -1776,7 +1808,7 @@ func (t *Terminal) printList() { i = maxy - 1 - j } line := i + 2 + t.visibleHeaderLines() - if t.noInfoLine() { + if t.noSeparatorLine() { line-- } if i < count { @@ -3102,7 +3134,7 @@ func (t *Terminal) Loop() { switch req { case reqPrompt: t.printPrompt() - if t.noInfoLine() { + if t.infoStyle == infoInline || t.infoStyle == infoInlineRight { t.printInfo() } case reqInfo: @@ -3904,7 +3936,7 @@ func (t *Terminal) Loop() { mx -= t.window.Left() my -= t.window.Top() min := 2 + t.visibleHeaderLines() - if t.noInfoLine() { + if t.noSeparatorLine() { min-- } h := t.window.Height() @@ -4196,7 +4228,7 @@ func (t *Terminal) vset(o int) bool { func (t *Terminal) maxItems() int { max := t.window.Height() - 2 - t.visibleHeaderLines() - if t.noInfoLine() { + if t.noSeparatorLine() { max++ } return util.Max(max, 0) diff --git a/test/test_go.rb b/test/test_go.rb index 5c07dde2..dc4d646a 100755 --- a/test/test_go.rb +++ b/test/test_go.rb @@ -1719,7 +1719,7 @@ class TestGoFZF < TestBase end def test_info_hidden - tmux.send_keys 'seq 10 | fzf --info=hidden', :Enter + tmux.send_keys 'seq 10 | fzf --info=hidden --no-separator', :Enter tmux.until { |lines| assert_equal '> 1', lines[-2] } end