Do not hide separator by default on --info=inline-right|hidden

pull/3709/head
Junegunn Choi 2 months ago
parent c30e486b64
commit 8a2df79711
No known key found for this signature in database
GPG Key ID: 254BC280FEF9C627

@ -3,10 +3,14 @@ CHANGELOG
0.49.0 0.49.0
------ ------
- Performance improvements - Ingestion performance improved by around 40% (more or less depending on options)
- Ingestion performance improved by 40% - `--info=hidden` and `--info=inline-right` will no longer hide the horizontal separator by default. This gives you more flexibility in customizing the layout.
- `--ansi` performance improved by 50% ```sh
- `--with-nth` performance improved by 30% 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 - Added two environment variables exported to the child processes
- `FZF_PREVIEW_LABEL` - `FZF_PREVIEW_LABEL`
- `FZF_BORDER_LABEL` - `FZF_BORDER_LABEL`
@ -22,7 +26,7 @@ CHANGELOG
- `track` is still available as an alias - `track` is still available as an alias
- Added `untrack-current` and `toggle-track-current` actions - Added `untrack-current` and `toggle-track-current` actions
- `*-current` actions are no-op when the global tracking state is set - `*-current` actions are no-op when the global tracking state is set
- Bug fixes - Bug fixes and minor improvements
0.48.1 0.48.1
------ ------

@ -372,20 +372,21 @@ e.g.
.TP .TP
.BI "--info=" "STYLE" .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
.BR default " Display on the next line to the prompt" .BR right " On the right end of the horizontal separator"
.br .br
.BR right " Display on the right end of the next line to the prompt" .BR hidden " Do not display finder info"
.br .br
.BR inline " Display on the same line with the default separator ' < '" .BR inline " After the prompt with the default prefix ' < '"
.br .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
.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
.BR hidden " Do not display finder info" .BR inline-right:PREFIX " On the right end of the prompt line with a custom prefix"
.br .br
.TP .TP

@ -75,7 +75,7 @@ const usage = `usage: fzf [options]
--margin=MARGIN Screen margin (TRBL | TB,RL | T,RL,B | T,R,B,L) --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) --padding=PADDING Padding inside border (TRBL | TB,RL | T,RL,B | T,R,B,L)
--info=STYLE Finder info style --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 --separator=STR String to form horizontal separator on info line
--no-separator Hide info line separator --no-separator Hide info line separator
--scrollbar[=C1[C2]] Scrollbar character(s) (each for main and preview window) --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 // Case denotes case-sensitivity of search
type Case int type Case int
@ -217,10 +217,6 @@ const (
infoHidden infoHidden
) )
func (s infoStyle) noExtraLine() bool {
return s == infoInline || s == infoInlineRight || s == infoHidden
}
type labelOpts struct { type labelOpts struct {
label string label string
column int column int
@ -327,7 +323,7 @@ type Options struct {
ScrollOff int ScrollOff int
FileWord bool FileWord bool
InfoStyle infoStyle InfoStyle infoStyle
InfoSep string InfoPrefix string
Separator *string Separator *string
JumpLabels string JumpLabels string
Prompt string Prompt string
@ -1506,17 +1502,24 @@ func parseInfoStyle(str string) (infoStyle, string) {
case "right": case "right":
return infoRight, "" return infoRight, ""
case "inline": case "inline":
return infoInline, defaultInfoSep return infoInline, defaultInfoPrefix
case "inline-right": case "inline-right":
return infoInlineRight, "" return infoInlineRight, ""
case "hidden": case "hidden":
return infoHidden, "" return infoHidden, ""
default: default:
prefix := "inline:" type infoSpec struct {
if strings.HasPrefix(str, prefix) { name string
return infoInline, strings.ReplaceAll(str[len(prefix):], "\n", " ") 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, "" return infoDefault, ""
} }
@ -1807,13 +1810,13 @@ func parseOptions(opts *Options, allArgs []string) {
case "--no-filepath-word": case "--no-filepath-word":
opts.FileWord = false opts.FileWord = false
case "--info": case "--info":
opts.InfoStyle, opts.InfoSep = parseInfoStyle( opts.InfoStyle, opts.InfoPrefix = parseInfoStyle(
nextString(allArgs, &i, "info style required")) nextString(allArgs, &i, "info style required"))
case "--no-info": case "--no-info":
opts.InfoStyle = infoHidden opts.InfoStyle = infoHidden
case "--inline-info": case "--inline-info":
opts.InfoStyle = infoInline opts.InfoStyle = infoInline
opts.InfoSep = defaultInfoSep opts.InfoPrefix = defaultInfoPrefix
case "--no-inline-info": case "--no-inline-info":
opts.InfoStyle = infoDefault opts.InfoStyle = infoDefault
case "--separator": case "--separator":
@ -2015,7 +2018,7 @@ func parseOptions(opts *Options, allArgs []string) {
} else if match, value := optString(arg, "--layout="); match { } else if match, value := optString(arg, "--layout="); match {
opts.Layout = parseLayout(value) opts.Layout = parseLayout(value)
} else if match, value := optString(arg, "--info="); match { } 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 { } else if match, value := optString(arg, "--separator="); match {
opts.Separator = &value opts.Separator = &value
} else if match, value := optString(arg, "--scrollbar="); match { } else if match, value := optString(arg, "--scrollbar="); match {

@ -181,7 +181,7 @@ type Status struct {
type Terminal struct { type Terminal struct {
initDelay time.Duration initDelay time.Duration
infoStyle infoStyle infoStyle infoStyle
infoSep string infoPrefix string
separator labelPrinter separator labelPrinter
separatorLen int separatorLen int
spinner []string spinner []string
@ -677,7 +677,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
if previewBox != nil && opts.Preview.aboveOrBelow() { if previewBox != nil && opts.Preview.aboveOrBelow() {
effectiveMinHeight += 1 + borderLines(opts.Preview.border) effectiveMinHeight += 1 + borderLines(opts.Preview.border)
} }
if opts.InfoStyle.noExtraLine() { if noSeparatorLine(opts.InfoStyle, opts.Separator == nil || uniseg.StringWidth(*opts.Separator) > 0) {
effectiveMinHeight-- effectiveMinHeight--
} }
effectiveMinHeight += borderLines(opts.BorderShape) effectiveMinHeight += borderLines(opts.BorderShape)
@ -699,7 +699,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
t := Terminal{ t := Terminal{
initDelay: delay, initDelay: delay,
infoStyle: opts.InfoStyle, infoStyle: opts.InfoStyle,
infoSep: opts.InfoSep, infoPrefix: opts.InfoPrefix,
separator: nil, separator: nil,
spinner: makeSpinner(opts.Unicode), spinner: makeSpinner(opts.Unicode),
promptString: opts.Prompt, promptString: opts.Prompt,
@ -882,7 +882,7 @@ func (t *Terminal) visibleHeaderLines() int {
// Extra number of lines needed to display fzf // Extra number of lines needed to display fzf
func (t *Terminal) extraLines() int { func (t *Terminal) extraLines() int {
extra := t.visibleHeaderLines() + 1 extra := t.visibleHeaderLines() + 1
if !t.noInfoLine() { if !t.noSeparatorLine() {
extra++ extra++
} }
return extra return extra
@ -988,8 +988,18 @@ func (t *Terminal) parsePrompt(prompt string) (func(), int) {
return output, promptLen return output, promptLen
} }
func (t *Terminal) noInfoLine() bool { func noSeparatorLine(style infoStyle, separator bool) bool {
return t.infoStyle.noExtraLine() 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) { 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 minAreaWidth := minWidth
minAreaHeight := minHeight minAreaHeight := minHeight
if t.noInfoLine() { if t.noSeparatorLine() {
minAreaHeight -= 1 minAreaHeight -= 1
} }
if t.needPreviewWindow() { if t.needPreviewWindow() {
@ -1522,7 +1532,7 @@ func (t *Terminal) move(y int, x int, clear bool) {
y = h - y - 1 y = h - y - 1
case layoutReverseList: case layoutReverseList:
n := 2 + t.visibleHeaderLines() n := 2 + t.visibleHeaderLines()
if t.noInfoLine() { if t.noSeparatorLine() {
n-- n--
} }
if y < n { if y < n {
@ -1562,7 +1572,7 @@ func (t *Terminal) updatePromptOffset() ([]rune, []rune) {
func (t *Terminal) promptLine() int { func (t *Terminal) promptLine() int {
if t.headerFirst { if t.headerFirst {
max := t.window.Height() - 1 max := t.window.Height() - 1
if !t.noInfoLine() { if !t.noSeparatorLine() {
max-- max--
} }
return util.Min(t.visibleHeaderLines(), max) return util.Min(t.visibleHeaderLines(), max)
@ -1607,20 +1617,8 @@ func (t *Terminal) printInfo() {
t.window.Print(" ") // Clear spinner t.window.Print(" ") // Clear spinner
} }
} }
switch t.infoStyle { printInfoPrefix := func() {
case infoDefault: str := t.infoPrefix
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
maxWidth := t.window.Width() - pos maxWidth := t.window.Width() - pos
width := util.StringWidth(str) width := util.StringWidth(str)
if width > maxWidth { if width > maxWidth {
@ -1635,7 +1633,34 @@ func (t *Terminal) printInfo() {
t.window.CPrint(tui.ColPrompt, str) t.window.CPrint(tui.ColPrompt, str)
} }
pos += width 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: case infoHidden:
if t.separatorLen > 0 {
t.move(line+1, 0, false)
printSeparator(t.window.Width()-1, false)
}
return return
} }
@ -1669,15 +1694,6 @@ func (t *Terminal) printInfo() {
output = fmt.Sprintf("[Command failed: %s]", *t.failed) 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 { if t.infoStyle == infoRight {
maxWidth := t.window.Width() maxWidth := t.window.Width()
if t.reading { if t.reading {
@ -1700,19 +1716,35 @@ func (t *Terminal) printInfo() {
} }
if t.infoStyle == infoInlineRight { if t.infoStyle == infoInlineRight {
pos = util.Max(pos, t.window.Width()-util.StringWidth(output)-3) if len(t.infoPrefix) == 0 {
if pos >= t.window.Width() { pos = util.Max(pos, t.window.Width()-util.StringWidth(output)-3)
return 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 maxWidth := t.window.Width() - pos
output = t.trimMessage(output, maxWidth) output = t.trimMessage(output, maxWidth)
t.window.CPrint(tui.ColInfo, output) 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 fillLength := maxWidth - len(output) - 2
if fillLength > 0 { if fillLength > 0 {
t.window.CPrint(tui.ColSeparator, " ") t.window.CPrint(tui.ColSeparator, " ")
@ -1727,7 +1759,7 @@ func (t *Terminal) printHeader() {
max := t.window.Height() max := t.window.Height()
if t.headerFirst { if t.headerFirst {
max-- max--
if !t.noInfoLine() { if !t.noSeparatorLine() {
max-- max--
} }
} }
@ -1744,7 +1776,7 @@ func (t *Terminal) printHeader() {
} }
if !t.headerFirst { if !t.headerFirst {
line++ line++
if !t.noInfoLine() { if !t.noSeparatorLine() {
line++ line++
} }
} }
@ -1776,7 +1808,7 @@ func (t *Terminal) printList() {
i = maxy - 1 - j i = maxy - 1 - j
} }
line := i + 2 + t.visibleHeaderLines() line := i + 2 + t.visibleHeaderLines()
if t.noInfoLine() { if t.noSeparatorLine() {
line-- line--
} }
if i < count { if i < count {
@ -3102,7 +3134,7 @@ func (t *Terminal) Loop() {
switch req { switch req {
case reqPrompt: case reqPrompt:
t.printPrompt() t.printPrompt()
if t.noInfoLine() { if t.infoStyle == infoInline || t.infoStyle == infoInlineRight {
t.printInfo() t.printInfo()
} }
case reqInfo: case reqInfo:
@ -3904,7 +3936,7 @@ func (t *Terminal) Loop() {
mx -= t.window.Left() mx -= t.window.Left()
my -= t.window.Top() my -= t.window.Top()
min := 2 + t.visibleHeaderLines() min := 2 + t.visibleHeaderLines()
if t.noInfoLine() { if t.noSeparatorLine() {
min-- min--
} }
h := t.window.Height() h := t.window.Height()
@ -4196,7 +4228,7 @@ func (t *Terminal) vset(o int) bool {
func (t *Terminal) maxItems() int { func (t *Terminal) maxItems() int {
max := t.window.Height() - 2 - t.visibleHeaderLines() max := t.window.Height() - 2 - t.visibleHeaderLines()
if t.noInfoLine() { if t.noSeparatorLine() {
max++ max++
} }
return util.Max(max, 0) return util.Max(max, 0)

@ -1719,7 +1719,7 @@ class TestGoFZF < TestBase
end end
def test_info_hidden 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] } tmux.until { |lines| assert_equal '> 1', lines[-2] }
end end

Loading…
Cancel
Save