Add $FZF_DEFAULT_OPTS_FILE (#3618)

For those who prefer to manage default options in a file.
If the file is not found, fzf will exit with an error.

We're not setting a default value for it because:

1. it's hard to find a default value that can be universally agreed upon
2. to avoid fzf having to check for the existence of the file even when it's not used
This commit is contained in:
Junegunn Choi 2024-02-29 09:49:33 +09:00 committed by GitHub
parent 3dd42f5aa2
commit 1833670fb9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 50 additions and 7 deletions

View File

@ -12,6 +12,12 @@ CHANGELOG
- You would wonder why fzf implements directory traversal anyway when it's a filter program following the Unix philosophy. - You would wonder why fzf implements directory traversal anyway when it's a filter program following the Unix philosophy.
But fzf has had [the traversal code for years][walker] to tackle the performance problem on Windows. And I decided to use the same approach on different platforms as well for the benefits listed above. But fzf has had [the traversal code for years][walker] to tackle the performance problem on Windows. And I decided to use the same approach on different platforms as well for the benefits listed above.
- Built-in traversal is now done using the excellent [charlievieth/fastwalk][fastwalk] library, which easily outperforms its competitors and supports safely following symlinks. - Built-in traversal is now done using the excellent [charlievieth/fastwalk][fastwalk] library, which easily outperforms its competitors and supports safely following symlinks.
- Added `$FZF_DEFAULT_OPTS_FILE` to allow managing default options in a file
- See [#3618](https://github.com/junegunn/fzf/pull/3618)
- Option precedence from lower to higher
1. Options read from `$FZF_DEFAULT_OPTS_FILE`
1. Options from `$FZF_DEFAULT_OPTS`
1. Options from command-line arguments
[find]: https://github.com/junegunn/fzf/blob/0.46.1/src/constants.go#L60-L64 [find]: https://github.com/junegunn/fzf/blob/0.46.1/src/constants.go#L60-L64
[walker]: https://github.com/junegunn/fzf/pull/1847 [walker]: https://github.com/junegunn/fzf/pull/1847

View File

@ -329,6 +329,10 @@ or `py`.
- `FZF_DEFAULT_OPTS` - `FZF_DEFAULT_OPTS`
- Default options - Default options
- e.g. `export FZF_DEFAULT_OPTS="--layout=reverse --inline-info"` - e.g. `export FZF_DEFAULT_OPTS="--layout=reverse --inline-info"`
- `FZF_DEFAULT_OPTS_FILE`
- If you prefer to manage default options in a file, set this variable to
point to the location of the file
- e.g. `export FZF_DEFAULT_OPTS_FILE=~/.fzfrc`
### Options ### Options

View File

@ -865,7 +865,14 @@ with \fB$SHELL -c\fR if \fBSHELL\fR is set, otherwise with \fBsh -c\fR, so in
this case make sure that the command is POSIX-compliant. this case make sure that the command is POSIX-compliant.
.TP .TP
.B FZF_DEFAULT_OPTS .B FZF_DEFAULT_OPTS
Default options. e.g. \fBexport FZF_DEFAULT_OPTS="--extended --cycle"\fR Default options.
.br
e.g. \fBexport FZF_DEFAULT_OPTS="--layout=reverse --border --cycle"\fR
.TP
.B FZF_DEFAULT_OPTS_FILE
The location of the file that contains the default options.
.br
e.g. \fBexport FZF_DEFAULT_OPTS_FILE=~/.fzfrc\fR
.TP .TP
.B FZF_API_KEY .B FZF_API_KEY
Can be used to require an API key when using \fB--listen\fR option. If not set, Can be used to require an API key when using \fB--listen\fR option. If not set,

View File

@ -126,8 +126,8 @@ const usage = `usage: fzf [options]
Environment variables Environment variables
FZF_DEFAULT_COMMAND Default command to use when input is tty FZF_DEFAULT_COMMAND Default command to use when input is tty
FZF_DEFAULT_OPTS Default options FZF_DEFAULT_OPTS Default options (e.g. '--layout=reverse --info=inline')
(e.g. '--layout=reverse --inline-info') FZF_DEFAULT_OPTS_FILE Location of the file to read default options from
FZF_API_KEY X-API-Key header for HTTP server (--listen) FZF_API_KEY X-API-Key header for HTTP server (--listen)
` `
@ -421,8 +421,10 @@ func help(code int) {
os.Exit(code) os.Exit(code)
} }
var errorContext = ""
func errorExit(msg string) { func errorExit(msg string) {
os.Stderr.WriteString(msg + "\n") os.Stderr.WriteString(errorContext + msg + "\n")
os.Exit(exitError) os.Exit(exitError)
} }
@ -2167,13 +2169,36 @@ func ParseOptions() *Options {
} }
} }
// Options from Env var // 1. Options from $FZF_DEFAULT_OPTS_FILE
words, _ := shellwords.Parse(os.Getenv("FZF_DEFAULT_OPTS")) if path := os.Getenv("FZF_DEFAULT_OPTS_FILE"); path != "" {
bytes, err := os.ReadFile(path)
if err != nil {
errorContext = "$FZF_DEFAULT_OPTS_FILE: "
errorExit(err.Error())
}
words, parseErr := shellwords.Parse(string(bytes))
if parseErr != nil {
errorContext = path + ": "
errorExit(parseErr.Error())
}
if len(words) > 0 {
parseOptions(opts, words)
}
}
// 2. Options from $FZF_DEFAULT_OPTS string
words, parseErr := shellwords.Parse(os.Getenv("FZF_DEFAULT_OPTS"))
errorContext = "$FZF_DEFAULT_OPTS: "
if parseErr != nil {
errorExit(parseErr.Error())
}
if len(words) > 0 { if len(words) > 0 {
parseOptions(opts, words) parseOptions(opts, words)
} }
// Options from command-line arguments // 3. Options from command-line arguments
errorContext = ""
parseOptions(opts, os.Args[1:]) parseOptions(opts, os.Args[1:])
postProcessOptions(opts) postProcessOptions(opts)

View File

@ -2582,6 +2582,7 @@ class TestGoFZF < TestBase
def test_change_preview_window_rotate def test_change_preview_window_rotate
tmux.send_keys "seq 100 | #{FZF} --preview-window left,border-none --preview 'echo hello' --bind '" \ tmux.send_keys "seq 100 | #{FZF} --preview-window left,border-none --preview 'echo hello' --bind '" \
"a:change-preview-window(right|down|up|hidden|)'", :Enter "a:change-preview-window(right|down|up|hidden|)'", :Enter
tmux.until { |lines| assert(lines.any? { _1.include?('100/100') }) }
3.times do 3.times do
tmux.until { |lines| lines[0].start_with?('hello') } tmux.until { |lines| lines[0].start_with?('hello') }
tmux.send_keys 'a' tmux.send_keys 'a'