diff --git a/CHANGELOG.md b/CHANGELOG.md index f496942..e47a14f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,11 @@ CHANGELOG # Right-aligned (negative integer) fzf --height=10 --border-label="╢ $label ╟" --border=bottom --border-label-pos=-3 --color=label:italic:black ``` +- Info panel (counter) will be followed by a horizontal separator by default + - The color of the separator can be customized via `--color=separator:...` + - Separator can be disabled by adding `:nosep` to `--info` + - `--info=nosep` + - `--info=inline:nosep` 0.34.0 ------ diff --git a/man/man1/fzf.1 b/man/man1/fzf.1 index c6a17c8..9d46d50 100644 --- a/man/man1/fzf.1 +++ b/man/man1/fzf.1 @@ -394,6 +394,7 @@ color mappings. \fBquery \fRQuery string \fBdisabled \fRQuery string when search is disabled \fBinfo \fRInfo line (match counters) + \fBseparator \fRHorizontal separator on info line (match counters) \fBborder \fRBorder around the window (\fB--border\fR and \fB--preview\fR) \fBlabel \fRBorder label (\fB--border-label\fR) \fBprompt \fRPrompt diff --git a/src/options.go b/src/options.go index 80ca3e1..36fd205 100644 --- a/src/options.go +++ b/src/options.go @@ -69,7 +69,7 @@ const usage = `usage: fzf [options] NEGATIVE_INTEGER: columns from right] (default: 0) --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|inline|hidden] + --info=STYLE Finder info style [default|inline|hidden[:nosep]] --prompt=STR Input prompt (default: '> ') --pointer=STR Pointer to the current line (default: '>') --marker=STR Multi-select marker (default: '>') @@ -169,10 +169,14 @@ const ( layoutReverseList ) -type infoStyle int +type infoLayout int +type infoStyle struct { + layout infoLayout + separator bool +} const ( - infoDefault infoStyle = iota + infoDefault infoLayout = iota infoInline infoHidden ) @@ -310,7 +314,7 @@ func defaultOptions() *Options { HscrollOff: 10, ScrollOff: 0, FileWord: false, - InfoStyle: infoDefault, + InfoStyle: infoStyle{layout: infoDefault, separator: true}, JumpLabels: defaultJumpLabels, Prompt: "> ", Pointer: ">", @@ -813,6 +817,8 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) *tui.ColorTheme { mergeAttr(&theme.CurrentMatch) case "border": mergeAttr(&theme.Border) + case "separator": + mergeAttr(&theme.Separator) case "label": mergeAttr(&theme.BorderLabel) case "prompt": @@ -1214,17 +1220,26 @@ func parseLayout(str string) layoutType { } 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)") + layout := infoDefault + separator := true + + for _, token := range regexp.MustCompile("[,:]").Split(strings.ToLower(str), -1) { + switch token { + case "default": + layout = infoDefault + case "inline": + layout = infoInline + case "hidden": + layout = infoHidden + case "nosep": + separator = false + case "sep": + separator = true + default: + errorExit("invalid info style (expected: default|inline|hidden[:nosep])") + } } - return infoDefault + return infoStyle{layout: layout, separator: separator} } func parsePreviewWindow(opts *previewOpts, input string) { @@ -1486,11 +1501,11 @@ func parseOptions(opts *Options, allArgs []string) { opts.InfoStyle = parseInfoStyle( nextString(allArgs, &i, "info style required")) case "--no-info": - opts.InfoStyle = infoHidden + opts.InfoStyle.layout = infoHidden case "--inline-info": - opts.InfoStyle = infoInline + opts.InfoStyle.layout = infoInline case "--no-inline-info": - opts.InfoStyle = infoDefault + opts.InfoStyle.layout = infoDefault case "--jump-labels": opts.JumpLabels = nextString(allArgs, &i, "label characters required") validateJumpLabels = true diff --git a/src/terminal.go b/src/terminal.go index c28b533..ca50de4 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -495,7 +495,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal { if previewBox != nil && opts.Preview.aboveOrBelow() { effectiveMinHeight += 1 + borderLines(opts.Preview.border) } - if opts.InfoStyle != infoDefault { + if opts.InfoStyle.layout != infoDefault { effectiveMinHeight-- } effectiveMinHeight += borderLines(opts.BorderShape) @@ -677,7 +677,7 @@ func (t *Terminal) parsePrompt(prompt string) (func(), int) { } func (t *Terminal) noInfoLine() bool { - return t.infoStyle != infoDefault + return t.infoStyle.layout != infoDefault } // Input returns current query string @@ -1153,7 +1153,7 @@ func (t *Terminal) trimMessage(message string, maxWidth int) string { func (t *Terminal) printInfo() { pos := 0 line := t.promptLine() - switch t.infoStyle { + switch t.infoStyle.layout { case infoDefault: t.move(line+1, 0, true) if t.reading { @@ -1202,8 +1202,17 @@ func (t *Terminal) printInfo() { if t.failed != nil && t.count == 0 { output = fmt.Sprintf("[Command failed: %s]", *t.failed) } - output = t.trimMessage(output, t.window.Width()-pos) + maxWidth := t.window.Width() - pos + output = t.trimMessage(output, maxWidth) t.window.CPrint(tui.ColInfo, output) + + if t.infoStyle.separator && len(output) < maxWidth-2 { + bar := "─" + if !t.unicode { + bar = "-" + } + t.window.CPrint(tui.ColSeparator, " "+strings.Repeat(bar, maxWidth-len(output)-2)) + } } func (t *Terminal) printHeader() { diff --git a/src/tui/tui.go b/src/tui/tui.go index 1a9c748..793d410 100644 --- a/src/tui/tui.go +++ b/src/tui/tui.go @@ -267,6 +267,7 @@ type ColorTheme struct { Cursor ColorAttr Selected ColorAttr Header ColorAttr + Separator ColorAttr Border ColorAttr BorderLabel ColorAttr } @@ -439,6 +440,7 @@ var ( ColSpinner ColorPair ColInfo ColorPair ColHeader ColorPair + ColSeparator ColorPair ColBorder ColorPair ColPreview ColorPair ColPreviewBorder ColorPair @@ -465,6 +467,7 @@ func EmptyTheme() *ColorTheme { Cursor: ColorAttr{colUndefined, AttrUndefined}, Selected: ColorAttr{colUndefined, AttrUndefined}, Header: ColorAttr{colUndefined, AttrUndefined}, + Separator: ColorAttr{colUndefined, AttrUndefined}, Border: ColorAttr{colUndefined, AttrUndefined}, BorderLabel: ColorAttr{colUndefined, AttrUndefined}, } @@ -490,6 +493,7 @@ func NoColorTheme() *ColorTheme { Cursor: ColorAttr{colDefault, AttrRegular}, Selected: ColorAttr{colDefault, AttrRegular}, Header: ColorAttr{colDefault, AttrRegular}, + Separator: ColorAttr{colDefault, AttrRegular}, Border: ColorAttr{colDefault, AttrRegular}, BorderLabel: ColorAttr{colDefault, AttrRegular}, } @@ -520,6 +524,7 @@ func init() { Cursor: ColorAttr{colRed, AttrUndefined}, Selected: ColorAttr{colMagenta, AttrUndefined}, Header: ColorAttr{colCyan, AttrUndefined}, + Separator: ColorAttr{colBlack, AttrUndefined}, Border: ColorAttr{colBlack, AttrUndefined}, BorderLabel: ColorAttr{colWhite, AttrUndefined}, } @@ -542,6 +547,7 @@ func init() { Cursor: ColorAttr{161, AttrUndefined}, Selected: ColorAttr{168, AttrUndefined}, Header: ColorAttr{109, AttrUndefined}, + Separator: ColorAttr{59, AttrUndefined}, Border: ColorAttr{59, AttrUndefined}, BorderLabel: ColorAttr{145, AttrUndefined}, } @@ -564,6 +570,7 @@ func init() { Cursor: ColorAttr{161, AttrUndefined}, Selected: ColorAttr{168, AttrUndefined}, Header: ColorAttr{31, AttrUndefined}, + Separator: ColorAttr{145, AttrUndefined}, Border: ColorAttr{145, AttrUndefined}, BorderLabel: ColorAttr{59, AttrUndefined}, } @@ -601,6 +608,7 @@ func initTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool) { theme.Cursor = o(baseTheme.Cursor, theme.Cursor) theme.Selected = o(baseTheme.Selected, theme.Selected) theme.Header = o(baseTheme.Header, theme.Header) + theme.Separator = o(baseTheme.Separator, theme.Separator) theme.Border = o(baseTheme.Border, theme.Border) theme.BorderLabel = o(baseTheme.BorderLabel, theme.BorderLabel) @@ -634,6 +642,7 @@ func initPalette(theme *ColorTheme) { ColSpinner = pair(theme.Spinner, theme.Bg) ColInfo = pair(theme.Info, theme.Bg) ColHeader = pair(theme.Header, theme.Bg) + ColSeparator = pair(theme.Separator, theme.Bg) ColBorder = pair(theme.Border, theme.Bg) ColBorderLabel = pair(theme.BorderLabel, theme.Bg) ColPreview = pair(theme.PreviewFg, theme.PreviewBg)