summaryrefslogtreecommitdiff
path: root/src/options.go
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2025-06-10 00:26:57 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2025-06-10 23:02:23 +0900
commit3b68dcdd81394f1ac9f743e1f74ff754f95eef9e (patch)
treee4856fba0fee27eb1ae98ca15844ec04bf60ff5a /src/options.go
parent39db02616158020b180a56dc8f1bdcf9f8365945 (diff)
downloadfzf-3b68dcdd81394f1ac9f743e1f74ff754f95eef9e.tar.gz
Add footer
Options: --footer=STR String to print as footer --footer-border[=STYLE] Draw border around the footer section [rounded|sharp|bold|block|thinblock|double|horizontal|vertical| top|bottom|left|right|line|none] (default: line) --footer-label=LABEL Label to print on the footer border --footer-label-pos=COL Position of the footer label [POSITIVE_INTEGER: columns from left| NEGATIVE_INTEGER: columns from right][:bottom] (default: 0 or center) The default border type for footer is 'line', which draws a single separator between the footer and the list. It changes its position depending on `--layout`, so you don't have to manually switch between 'top' and 'bottom' The 'line' style is now supported by other border types as well. `--list-border` is the only exception.
Diffstat (limited to 'src/options.go')
-rw-r--r--src/options.go108
1 files changed, 92 insertions, 16 deletions
diff --git a/src/options.go b/src/options.go
index 142179e5..2fd6f821 100644
--- a/src/options.go
+++ b/src/options.go
@@ -83,7 +83,7 @@ Usage: fzf [options]
--padding=PADDING Padding inside border (TRBL | TB,RL | T,RL,B | T,R,B,L)
--border[=STYLE] Draw border around the finder
[rounded|sharp|bold|block|thinblock|double|horizontal|vertical|
- top|bottom|left|right|none] (default: rounded)
+ top|bottom|left|right|line|none] (default: rounded)
--border-label=LABEL Label to print on the border
--border-label-pos=COL Position of the border label
[POSITIVE_INTEGER: columns from left|
@@ -140,7 +140,7 @@ Usage: fzf [options]
--filepath-word Make word-wise movements respect path separators
--input-border[=STYLE] Draw border around the input section
[rounded|sharp|bold|block|thinblock|double|horizontal|vertical|
- top|bottom|left|right|none] (default: rounded)
+ top|bottom|left|right|line|none] (default: rounded)
--input-label=LABEL Label to print on the input border
--input-label-pos=COL Position of the input label
[POSITIVE_INTEGER: columns from left|
@@ -168,7 +168,7 @@ Usage: fzf [options]
--header-first Print header before the prompt line
--header-border[=STYLE] Draw border around the header section
[rounded|sharp|bold|block|thinblock|double|horizontal|vertical|
- top|bottom|left|right|none] (default: rounded)
+ top|bottom|left|right|line|none] (default: rounded)
--header-lines-border[=STYLE]
Display header from --header-lines with a separate border.
Pass 'none' to still separate it but without a border.
@@ -178,6 +178,17 @@ Usage: fzf [options]
NEGATIVE_INTEGER: columns from right][:bottom]
(default: 0 or center)
+ FOOTER
+ --footer=STR String to print as footer
+ --footer-border[=STYLE] Draw border around the footer section
+ [rounded|sharp|bold|block|thinblock|double|horizontal|vertical|
+ top|bottom|left|right|line|none] (default: line)
+ --footer-label=LABEL Label to print on the footer border
+ --footer-label-pos=COL Position of the footer label
+ [POSITIVE_INTEGER: columns from left|
+ NEGATIVE_INTEGER: columns from right][:bottom]
+ (default: 0 or center)
+
SCRIPTING
-q, --query=STR Start the finder with the given query
-1, --select-1 Automatically select the only match
@@ -599,6 +610,7 @@ type Options struct {
Header []string
HeaderLines int
HeaderFirst bool
+ Footer []string
Gap int
GapLine *string
Ellipsis *string
@@ -610,8 +622,10 @@ type Options struct {
InputBorderShape tui.BorderShape
HeaderBorderShape tui.BorderShape
HeaderLinesShape tui.BorderShape
+ FooterBorderShape tui.BorderShape
InputLabel labelOpts
HeaderLabel labelOpts
+ FooterLabel labelOpts
BorderLabel labelOpts
ListLabel labelOpts
PreviewLabel labelOpts
@@ -716,6 +730,7 @@ func defaultOptions() *Options {
Header: make([]string, 0),
HeaderLines: 0,
HeaderFirst: false,
+ Footer: make([]string, 0),
Gap: 0,
Ellipsis: nil,
Scrollbar: nil,
@@ -880,12 +895,9 @@ func parseAlgo(str string) (algo.Algo, error) {
return nil, errors.New("invalid algorithm (expected: v1 or v2)")
}
-func parseBorder(str string, optional bool, allowLine bool) (tui.BorderShape, error) {
+func parseBorder(str string, optional bool) (tui.BorderShape, error) {
switch str {
case "line":
- if !allowLine {
- return tui.BorderNone, errors.New("'line' is only allowed for preview border")
- }
return tui.BorderLine, nil
case "rounded":
return tui.BorderRounded, nil
@@ -1348,6 +1360,10 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) (*tui.ColorTheme, erro
mergeAttr(&theme.HeaderBorder)
case "header-label":
mergeAttr(&theme.HeaderLabel)
+ case "footer-border":
+ mergeAttr(&theme.FooterBorder)
+ case "footer-label":
+ mergeAttr(&theme.FooterLabel)
case "spinner":
mergeAttr(&theme.Spinner)
case "info":
@@ -1360,6 +1376,10 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) (*tui.ColorTheme, erro
mergeAttr(&theme.Header)
case "header-bg":
mergeAttr(&theme.HeaderBg)
+ case "footer", "footer-fg":
+ mergeAttr(&theme.Footer)
+ case "footer-bg":
+ mergeAttr(&theme.FooterBg)
case "gap-line":
mergeAttr(&theme.GapLine)
default:
@@ -1415,7 +1435,7 @@ const (
func init() {
executeRegexp = regexp.MustCompile(
- `(?si)[:+](become|execute(?:-multi|-silent)?|reload(?:-sync)?|preview|(?:change|transform)-(?:query|prompt|(?:border|list|preview|input|header)-label|header|search|nth|pointer|ghost)|transform|change-(?:preview-window|preview|multi)|(?:re|un|toggle-)bind|pos|put|print|search)`)
+ `(?si)[:+](become|execute(?:-multi|-silent)?|reload(?:-sync)?|preview|(?:change|transform)-(?:query|prompt|(?:border|list|preview|input|header|footer)-label|header|footer|search|nth|pointer|ghost)|transform|change-(?:preview-window|preview|multi)|(?:re|un|toggle-)bind|pos|put|print|search)`)
splitRegexp = regexp.MustCompile("[,:]+")
actionNameRegexp = regexp.MustCompile("(?i)^[a-z-]+")
}
@@ -1800,6 +1820,8 @@ func isExecuteAction(str string) actionType {
return actPreview
case "change-header":
return actChangeHeader
+ case "change-footer":
+ return actChangeFooter
case "change-list-label":
return actChangeListLabel
case "change-border-label":
@@ -1810,6 +1832,8 @@ func isExecuteAction(str string) actionType {
return actChangeInputLabel
case "change-header-label":
return actChangeHeaderLabel
+ case "change-footer-label":
+ return actChangeFooterLabel
case "change-ghost":
return actChangeGhost
case "change-pointer":
@@ -1850,6 +1874,10 @@ func isExecuteAction(str string) actionType {
return actTransformInputLabel
case "transform-header-label":
return actTransformHeaderLabel
+ case "transform-footer-label":
+ return actTransformFooterLabel
+ case "transform-footer":
+ return actTransformFooter
case "transform-header":
return actTransformHeader
case "transform-ghost":
@@ -2729,6 +2757,14 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
if opts.HeaderLines, err = nextInt("number of header lines required"); err != nil {
return err
}
+ case "--no-footer":
+ opts.Footer = []string{}
+ case "--footer":
+ str, err := nextString("footer string required")
+ if err != nil {
+ return err
+ }
+ opts.Footer = strLines(str)
case "--header-first":
opts.HeaderFirst = true
case "--no-header-first":
@@ -2773,7 +2809,7 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
opts.Preview.border = tui.BorderNone
case "--preview-border":
hasArg, arg := optionalNextString()
- if opts.Preview.border, err = parseBorder(arg, !hasArg, true); err != nil {
+ if opts.Preview.border, err = parseBorder(arg, !hasArg); err != nil {
return err
}
case "--height":
@@ -2812,14 +2848,17 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
opts.BorderShape = tui.BorderNone
case "--border":
hasArg, arg := optionalNextString()
- if opts.BorderShape, err = parseBorder(arg, !hasArg, false); err != nil {
+ if opts.BorderShape, err = parseBorder(arg, !hasArg); err != nil {
return err
}
case "--list-border":
hasArg, arg := optionalNextString()
- if opts.ListBorderShape, err = parseBorder(arg, !hasArg, false); err != nil {
+ if opts.ListBorderShape, err = parseBorder(arg, !hasArg); err != nil {
return err
}
+ if opts.ListBorderShape == tui.BorderLine {
+ return errors.New("list border cannot be 'line'")
+ }
case "--no-list-border":
opts.ListBorderShape = tui.BorderNone
case "--no-list-label":
@@ -2841,14 +2880,14 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
opts.HeaderBorderShape = tui.BorderNone
case "--header-border":
hasArg, arg := optionalNextString()
- if opts.HeaderBorderShape, err = parseBorder(arg, !hasArg, false); err != nil {
+ if opts.HeaderBorderShape, err = parseBorder(arg, !hasArg); err != nil {
return err
}
case "--no-header-lines-border":
opts.HeaderLinesShape = tui.BorderNone
case "--header-lines-border":
hasArg, arg := optionalNextString()
- if opts.HeaderLinesShape, err = parseBorder(arg, !hasArg, false); err != nil {
+ if opts.HeaderLinesShape, err = parseBorder(arg, !hasArg); err != nil {
return err
}
case "--no-header-label":
@@ -2865,11 +2904,32 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
if err := parseLabelPosition(&opts.HeaderLabel, pos); err != nil {
return err
}
+ case "--no-footer-border":
+ opts.FooterBorderShape = tui.BorderNone
+ case "--footer-border":
+ hasArg, arg := optionalNextString()
+ if opts.FooterBorderShape, err = parseBorder(arg, !hasArg); err != nil {
+ return err
+ }
+ case "--no-footer-label":
+ opts.FooterLabel.label = ""
+ case "--footer-label":
+ if opts.FooterLabel.label, err = nextString("footer label required"); err != nil {
+ return err
+ }
+ case "--footer-label-pos":
+ pos, err := nextString("footer label position required (positive or negative integer or 'center')")
+ if err != nil {
+ return err
+ }
+ if err := parseLabelPosition(&opts.FooterLabel, pos); err != nil {
+ return err
+ }
case "--no-input-border":
opts.InputBorderShape = tui.BorderNone
case "--input-border":
hasArg, arg := optionalNextString()
- if opts.InputBorderShape, err = parseBorder(arg, !hasArg, false); err != nil {
+ if opts.InputBorderShape, err = parseBorder(arg, !hasArg); err != nil {
return err
}
case "--no-input-label":
@@ -3077,6 +3137,7 @@ func applyPreset(opts *Options, preset string) error {
opts.ListBorderShape = tui.BorderUndefined
opts.InputBorderShape = tui.BorderUndefined
opts.HeaderBorderShape = tui.BorderUndefined
+ opts.FooterBorderShape = tui.BorderUndefined
opts.Preview.border = defaultBorderShape
opts.Preview.info = true
opts.InfoStyle = infoDefault
@@ -3088,6 +3149,7 @@ func applyPreset(opts *Options, preset string) error {
opts.ListBorderShape = tui.BorderUndefined
opts.InputBorderShape = tui.BorderUndefined
opts.HeaderBorderShape = tui.BorderUndefined
+ opts.FooterBorderShape = tui.BorderLine
opts.Preview.border = tui.BorderLine
opts.Preview.info = false
opts.InfoStyle = infoDefault
@@ -3103,16 +3165,22 @@ func applyPreset(opts *Options, preset string) error {
}
if len(tokens) == 2 && len(tokens[1]) > 0 {
var err error
- defaultBorderShape, err = parseBorder(tokens[1], false, false)
+ defaultBorderShape, err = parseBorder(tokens[1], false)
if err != nil {
return err
}
}
- opts.ListBorderShape = defaultBorderShape
+ if defaultBorderShape != tui.BorderLine {
+ opts.ListBorderShape = defaultBorderShape
+ }
opts.InputBorderShape = defaultBorderShape
opts.HeaderBorderShape = defaultBorderShape
+ opts.FooterBorderShape = defaultBorderShape
opts.Preview.border = defaultBorderShape
+ if defaultBorderShape == tui.BorderLine {
+ opts.BorderShape = defaultBorderShape
+ }
opts.Preview.info = true
opts.InfoStyle = infoInlineRight
opts.Theme.Gutter = tui.NewColorAttr()
@@ -3185,6 +3253,10 @@ func noSeparatorLine(style infoStyle, separator bool) bool {
return false
}
+func (opts *Options) useTmux() bool {
+ return opts.Tmux != nil && len(os.Getenv("TMUX")) > 0 && opts.Tmux.index >= opts.Height.index
+}
+
func (opts *Options) noSeparatorLine() bool {
if opts.Inputless {
return true
@@ -3216,6 +3288,10 @@ func postProcessOptions(opts *Options) error {
opts.HeaderBorderShape = tui.BorderNone
}
+ if opts.FooterBorderShape == tui.BorderUndefined {
+ opts.FooterBorderShape = tui.BorderLine
+ }
+
if opts.HeaderLinesShape == tui.BorderNone {
opts.HeaderLinesShape = tui.BorderPhantom
}