m/fzf
1
0
mirror of https://github.com/junegunn/fzf.git synced 2025-11-12 13:23:48 -05:00

Compare commits

..

26 Commits

Author SHA1 Message Date
Junegunn Choi
d226d841a1 0.62.0 2025-05-04 18:31:18 +09:00
Junegunn Choi
c6d83047e5 Allow whitespace as separator in --color option 2025-05-04 15:08:23 +09:00
Junegunn Choi
46dabccdf1 [vim] Update g:fzf_colors example with 'query' 2025-05-04 14:52:22 +09:00
Junegunn Choi
cd9517b679 Add 'alt-bg' color for striped lines (#4370)
Test cases:

1. 'jump' should show alternating background colors even when 'alt-bg' is
not defined as before.

  go run main.go --bind load:jump

Two differences:
  * The alternating lines will not be in bold (was a bug)
  * The marker column will not be rendered with alternating background color

2. Use alternating background color when 'alt-bg' is set

  go run main.go --color bg:238,alt-bg:237
  go run main.go --color bg:238,alt-bg:237 --highlight-line

3. 'selected-bg' should take precedence

  go run main.go --color bg:238,alt-bg:237,selected-bg:232 \
                 --highlight-line --multi --bind 'load:select+up+select+up'

4. Should work with text with ANSI colors

  declare -f | perl -0777 -pe 's/^}\n/}\0/gm' |
    bat --plain --language bash --color always |
    go run main.go --read0 --ansi --reverse --multi \
                   --color bg:237,alt-bg:238,current-bg:236 --highlight-line

---

Close #4354
Fix #4372
2025-05-04 14:32:06 +09:00
junegunn
cd6677ba1d Deploying to master from @ junegunn/fzf@9c1a47acf7 🚀 2025-05-04 00:02:25 +00:00
bitraid
9c1a47acf7 [fish] Support deleting history items with SHIFT-DEL
Bind to SHIFT-DELETE a command that deletes the selected history items.
It can be overridden by $FZF_CTRL_R_OPTS.
2025-04-28 00:27:51 +09:00
bitraid
0c280a3ce1 [fish] Simplify commandline call in fzf-file-widget 2025-04-28 00:27:51 +09:00
bitraid
53e8b6e705 [fish] Add version check 2025-04-28 00:27:51 +09:00
bitraid
ad33165fa7 [fish] History: Operate only on line at cursor
This allows inserting history entries when constructing multiline
commands.
2025-04-28 00:27:51 +09:00
junegunn
2055db61c8 Deploying to master from @ junegunn/fzf@d2c662e54f 🚀 2025-04-27 00:02:22 +00:00
Junegunn Choi
d2c662e54f Reset coordinator delay on 'reload'
Fix #4364
2025-04-25 21:30:25 +09:00
Junegunn Choi
d24b58ef3f 0.61.3 2025-04-22 20:53:23 +09:00
RafaelDominiquini
06ae9b0f3b Add missing environment variables (#4356)
Co-authored-by: Rafael Baboni Dominiquini <rafaeldominiquini@gmail.com>
Co-authored-by: Junegunn Choi <junegunn.c@gmail.com>
2025-04-22 20:51:43 +09:00
Junegunn Choi
2a9c1c06a4 Revert "Disable tmux popup when already running inside one (#4351)"
This reverts commit af8fe918d8.

Fix #4360
Fix #4359
2025-04-22 20:20:21 +09:00
Junegunn Choi
90ad1b7f22 0.61.2 2025-04-20 11:37:15 +09:00
Junegunn Choi
f22fbcd1af Fix typo and update CHANGLOG 2025-04-20 11:31:15 +09:00
Junegunn Choi
1d761684c5 Add --tty-default=/dev/tty and --no-tty-default option (#4352)
Fix #4242.

Use --no-tty-default, if you want fzf to perform a TTY look-up instead of defaulting to /dev/tty.
2025-04-20 11:24:50 +09:00
bitraid
e491770f1c [fish] Improve option prefix processing
- Support single-letter options without = such as -fFILEPATH
- fish v3.3.0 and newer: Disable option prefix if -- is preceded
2025-04-18 21:06:25 +09:00
bitraid
a41be61506 [fish] Fix whitespace/regex characters in command line
This is a rewrite of __fzf_parse_commandline function, that fixes the
following issues, when CTRL-T/ALT-C is used and current command line
token contains:
- Escaped newlines (\n): This never worked correctly, but after 282884a,
  the string would split, and the script would enter an infinite loop
  while trying to set $dir.
- Escaped bell (\a, \cg), backspace (\b), form feed (\v, \cl), carriage
  return (\r), vertical tab (\v, \ck): walker-root would not set
  correctly for existing directories containing any of those characters.
- Regular expression special characters (^, +, ? etc): $dir would not be
  be stripped from $fzf_query if it contained any of those characters.

The lowest supported fish version is v3.1b. For optimal operation, the
function uses more recent commands when supported by the running
version. Specifically, for versions equal or newer than:
- v3.2.0: Sets variables using PCRE2 capture groups of `string match
  --regex` when needing to preserve any trailing newlines and
  simultaneously omit the extra newline that is appended by `string
  collect -N`.
- v3.5.0: Uses the builtin path command for path normalization, dirname
  extraction and existing directories check.
- v4.0.0: Uses the --tokens-expanded option of commandline, for
  expansion and dealing with unbalanced quotes and incomplete escape
  sequences. It also uses the regex style of string-escape, to prepare
  variable contents for regex operations. This is not used in older
  versions, because they don't escape newlines.
2025-04-18 21:06:25 +09:00
bitraid
1a8f633611 [fish] Fix for file/dir names containing newlines
CTRL-T/ALT-C now works correctly when selecting files or directories
that contain newlines in their names. When external commands defined by
$FZF_CTRL_T_COMMAND/$FZF_ALT_C_COMMAND are used (for example the fd
command with -0 switch), the --read0 option must also be set through
$FZF_CTRL_T_OPTS/$FZF_ALT_C_OPTS.
2025-04-18 21:06:25 +09:00
Pierre Guinoiseau
af8fe918d8 Disable tmux popup when already running inside one (#4351) 2025-04-18 17:35:48 +09:00
istepic
8ef9dfd9a2 Update reference to manpage in README.md (#4348) 2025-04-18 08:38:28 +09:00
phanium
66df24040f Fix panic when use header border without pointer/marker (#4345) 2025-04-13 20:24:29 +09:00
junegunn
ed4442d9ea Deploying to master from @ junegunn/fzf@0edb5d5ebb 🚀 2025-04-13 00:26:08 +00:00
Junegunn Choi
0edb5d5ebb Fix trailing ␊ not rendered with '--read0 --no-multi-line'
https://github.com/junegunn/fzf/pull/4334#issue-2966013714

    # Should display foo␊
    echo -en "foo\n" | fzf --read0  --no-multi-line
2025-04-11 20:46:49 +09:00
Junegunn Choi
9ffc2c7ca3 reader: Do not append '/' to '/'
https://github.com/junegunn/fzf/pull/4334#issue-2966013714
2025-04-11 20:38:16 +09:00
25 changed files with 326 additions and 127 deletions

View File

@@ -1,6 +1,50 @@
CHANGELOG
=========
0.62.0
------
- Relaxed the `--color` option syntax to allow whitespace-separated entries (in addition to commas), making multi-line definitions easier to write and read
```sh
# seoul256-light
fzf --style full --color='
fg:#616161 fg+:#616161
bg:#ffffff bg+:#e9e9e9 alt-bg:#f1f1f1
hl:#719872 hl+:#719899
pointer:#e12672 marker:#e17899
header:#719872
spinner:#719899 info:#727100
prompt:#0099bd query:#616161
border:#e1e1e1
'
```
- Added `alt-bg` color to create striped lines to visually separate rows
```sh
fzf --color bg:237,alt-bg:238,current-bg:236 --highlight-line
declare -f | perl -0777 -pe 's/^}\n/}\0/gm' |
bat --plain --language bash --color always |
fzf --read0 --ansi --reverse --multi \
--color bg:237,alt-bg:238,current-bg:236 --highlight-line
```
- [fish] Improvements in CTRL-R binding (@bitraid)
- You can trigger CTRL-R in the middle of a command to insert the selected item
- You can delete history items with SHIFT-DEL
- Bug fixes and improvements
- Fixed unnecessary 100ms delay after `reload` (#4364)
- Fixed `selected-bg` not applied to colored items (#4372)
0.61.3
------
- Reverted #4351 as it caused `tmux run-shell 'fzf --tmux'` to fail (#4559 #4560)
- More environment variables for child processes (#4356)
0.61.2
------
- Fixed panic when using header border without pointer/marker (@phanen)
- Fixed `--tmux` option when already inside a tmux popup (@peikk0)
- Bug fixes and improvements in CTRL-T binding of fish (#4334) (@bitraid)
- Added `--no-tty-default` option to make fzf search for the current TTY device instead of defaulting to `/dev/tty` (#4242)
0.61.1
------
- Disable bracketed-paste mode on exit. This fixes issue where pasting breaks after running fzf on old bash versions that don't support the mode.

View File

@@ -155,6 +155,7 @@ let g:fzf_layout = { 'window': '10new' }
let g:fzf_colors =
\ { 'fg': ['fg', 'Normal'],
\ 'bg': ['bg', 'Normal'],
\ 'query': ['fg', 'Normal'],
\ 'hl': ['fg', 'Comment'],
\ 'fg+': ['fg', 'CursorLine', 'CursorColumn', 'Normal'],
\ 'bg+': ['bg', 'CursorLine', 'CursorColumn'],

File diff suppressed because one or more lines are too long

View File

@@ -2,7 +2,7 @@
set -u
version=0.61.1
version=0.62.0
auto_completion=
key_bindings=
update_config=2

View File

@@ -1,4 +1,4 @@
$version="0.61.1"
$version="0.62.0"
$fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition

View File

@@ -11,7 +11,7 @@ import (
"github.com/junegunn/fzf/src/protector"
)
var version = "0.61"
var version = "0.62"
var revision = "devel"
//go:embed shell/key-bindings.bash

View File

@@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
..
.TH fzf\-tmux 1 "Apr 2025" "fzf 0.61.1" "fzf\-tmux - open fzf in tmux split pane"
.TH fzf\-tmux 1 "May 2025" "fzf 0.62.0" "fzf\-tmux - open fzf in tmux split pane"
.SH NAME
fzf\-tmux - open fzf in tmux split pane

View File

@@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
..
.TH fzf 1 "Apr 2025" "fzf 0.61.1" "fzf - a command-line fuzzy finder"
.TH fzf 1 "May 2025" "fzf 0.62.0" "fzf - a command-line fuzzy finder"
.SH NAME
fzf - a command-line fuzzy finder
@@ -228,6 +228,13 @@ e.g. \fB# Avoid rendering both fzf instances at the same time
(sleep 1; seq 1000000; sleep 1) |
fzf \-\-sync \-\-query 5 \-\-listen \-\-bind start:up,load:up,result:up,focus:change\-header:Ready\fR
.RE
.TP
.B "\-\-no\-tty\-default"
Make fzf search for the current TTY device via standard error instead of
defaulting to \fB/dev/tty\fR. This option avoids issues when launching
emacsclient from within fzf. Alternatively, you can change the default TTY
device by setting \fB--tty-default=DEVICE_NAME\fR.
.SS GLOBAL STYLE
.TP
.BI "\-\-style=" "PRESET"
@@ -235,7 +242,7 @@ Apply a style preset [default|minimal|full[:BORDER_STYLE]]
.TP
.BI "\-\-color=" "[BASE_SCHEME][,COLOR_NAME[:ANSI_COLOR][:ANSI_ATTRIBUTES]]..."
Color configuration. The name of the base color scheme is followed by custom
color mappings.
color mappings. Each entry is separated by a comma and/or whitespaces.
.RS
.B BASE SCHEME:
@@ -263,6 +270,7 @@ color mappings.
\fBcurrent\-bg (bg+) \fRBackground (current line)
\fBgutter \fRGutter on the left
\fBcurrent\-hl (hl+) \fRHighlighted substrings (current line)
\fBalt\-bg \fRAlternate background color to create striped lines
\fBquery (input\-fg) \fRQuery string
\fBdisabled \fRQuery string when search is disabled (\fB\-\-disabled\fR)
\fBinfo \fRInfo line (match counters)
@@ -330,7 +338,19 @@ color mappings.
# Seoul256 theme with 24-bit colors
fzf \-\-color='bg:#4B4B4B,bg+:#3F3F3F,info:#BDBB72,border:#6B6B6B,spinner:#98BC99' \\
\-\-color='hl:#719872,fg:#D9D9D9,header:#719872,fg+:#D9D9D9' \\
\-\-color='pointer:#E12672,marker:#E17899,prompt:#98BEDE,hl+:#98BC99'\fR
\-\-color='pointer:#E12672,marker:#E17899,prompt:#98BEDE,hl+:#98BC99'
# Seoul256 light theme with 24-bit colors, each entry separated by whitespaces
fzf \-\-style full \-\-color='
fg:#616161 fg+:#616161
bg:#ffffff bg+:#e9e9e9 alt-bg:#f1f1f1
hl:#719872 hl+:#719899
pointer:#e12672 marker:#e17899
header:#719872
spinner:#719899 info:#727100
prompt:#0099bd query:#616161
border:#e1e1e1
'\fR
.RE
.TP
.B "\-\-no\-color"
@@ -1272,10 +1292,20 @@ fzf exports the following environment variables to its child processes.
.br
.BR FZF_PROMPT " Prompt string"
.br
.BR FZF_GHOST " Ghost string"
.br
.BR FZF_POINTER " Pointer string"
.br
.BR FZF_PREVIEW_LABEL " Preview label string"
.br
.BR FZF_BORDER_LABEL " Border label string"
.br
.BR FZF_LIST_LABEL " List label string"
.br
.BR FZF_INPUT_LABEL " Input label string"
.br
.BR FZF_HEADER_LABEL " Header label string"
.br
.BR FZF_ACTION " The name of the last action performed"
.br
.BR FZF_KEY " The name of the last key pressed"

View File

@@ -14,12 +14,21 @@
# Key bindings
# ------------
# For compatibility with fish versions down to 3.1.2, the script does not use:
# - The -f/--function switch of command: set
# - The process substitution syntax: $(cmd)
# - Ranges that omit start/end indexes: $var[$start..] $var[..$end] $var[..]
# The oldest supported fish version is 3.1b1. To maintain compatibility, the
# command substitution syntax $(cmd) should never be used, even behind a version
# check, otherwise the source command will fail on fish versions older than 3.4.0.
function fzf_key_bindings
# Check fish version
set -l fish_ver (string match -r '^(\d+).(\d+)' $version 2> /dev/null; or echo 0\n0\n0)
if test \( "$fish_ver[2]" -lt 3 \) -o \( "$fish_ver[2]" -eq 3 -a "$fish_ver[3]" -lt 1 \)
echo "This script requires fish version 3.1b1 or newer." >&2
return 1
else if not type -q fzf
echo "fzf was not found in path." >&2
return 1
end
function __fzf_defaults
# $argv[1]: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
# $argv[2..]: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
@@ -42,45 +51,79 @@ function fzf_key_bindings
end
function __fzf_parse_commandline -d 'Parse the current command line token and return split of existing filepath, fzf query, and optional -option= prefix'
set -l fzf_query ''
set -l prefix ''
set -l dir '.'
set -l query
set -l commandline (commandline -t | string unescape -n)
# Strip -option= from token if present
set -l prefix (string match -r -- '^-[^\s=]+=' $commandline)
set commandline (string replace -- "$prefix" '' $commandline)
# Set variables containing the major and minor fish version numbers, using
# a method compatible with all supported fish versions.
set -l -- fish_major (string match -r -- '^\d+' $version)
set -l -- fish_minor (string match -r -- '^\d+\.(\d+)' $version)[2]
# Enable home directory expansion of leading ~/
set commandline (string replace -r -- '^~/' '\$HOME/' $commandline)
# Escape special characters, except for the $ sign of valid variable names,
# so that the original string with expanded variables is returned after eval.
set commandline (string escape -n -- $commandline)
set commandline (string replace -r -a -- '\\\\\$(?=[\w])' '\$' $commandline)
# eval is used to do shell expansion on paths
eval set commandline $commandline
# Combine multiple consecutive slashes into one.
set commandline (string replace -r -a -- '/+' '/' $commandline)
if test -n "$commandline"
# Strip trailing slash, unless $dir is root dir (/)
set dir (string replace -r -- '(?<!^)/$' '' $commandline)
# Set $dir to the longest existing filepath
while not test -d "$dir"
# If path is absolute, this can keep going until ends up at /
# If path is relative, this can keep going until entire input is consumed, dirname returns "."
set dir (dirname -- $dir)
# fish v3.3.0 and newer: Don't use option prefix if " -- " is preceded.
set -l -- match_regex '(?<fzf_query>[\s\S]*?(?=\n?$)$)'
set -l -- prefix_regex '^-[^\s=]+=|^-(?!-)\S'
if test "$fish_major" -eq 3 -a "$fish_minor" -lt 3
or string match -q -v -- '* -- *' (string sub -l (commandline -Cp) -- (commandline -p))
set -- match_regex "(?<prefix>$prefix_regex)?$match_regex"
end
if test "$dir" = '.'; and test (string sub -l 2 -- $commandline) != './'
# If $dir is "." but commandline is not a relative path, this means no file path found
set fzf_query $commandline
# Set $prefix and expanded $fzf_query with preserved trailing newlines.
if test "$fish_major" -ge 4
# fish v4.0.0 and newer
string match -q -r -- $match_regex (commandline --current-token --tokens-expanded | string collect -N)
else if test "$fish_major" -eq 3 -a "$fish_minor" -ge 2
# fish v3.2.0 - v3.7.1 (last v3)
string match -q -r -- $match_regex (commandline --current-token --tokenize | string collect -N)
eval set -- fzf_query (string escape -n -- $fzf_query | string replace -r -a '^\\\(?=~)|\\\(?=\$\w)' '')
else
# Also remove trailing slash after dir, to "split" input properly
set fzf_query (string replace -r -- "^$dir/?" '' $commandline)
# fish older than v3.2.0 (v3.1b1 - v3.1.2)
set -l -- cl_token (commandline --current-token --tokenize | string collect -N)
set -- prefix (string match -r -- $prefix_regex $cl_token)
set -- fzf_query (string replace -- "$prefix" '' $cl_token | string collect -N)
eval set -- fzf_query (string escape -n -- $fzf_query | string replace -r -a '^\\\(?=~)|\\\(?=\$\w)|\\\n\\\n$' '')
end
if test -n "$fzf_query"
# Normalize path in $fzf_query, set $dir to the longest existing directory.
if test \( "$fish_major" -ge 4 \) -o \( "$fish_major" -eq 3 -a "$fish_minor" -ge 5 \)
# fish v3.5.0 and newer
set -- fzf_query (path normalize -- $fzf_query)
set -- dir $fzf_query
while not path is -d $dir
set -- dir (path dirname $dir)
end
else
# fish older than v3.5.0 (v3.1b1 - v3.4.1)
if test "$fish_major" -eq 3 -a "$fish_minor" -ge 2
# fish v3.2.0 - v3.4.1
string match -q -r -- '(?<fzf_query>^[\s\S]*?(?=\n?$)$)' \
(string replace -r -a -- '(?<=/)/|(?<!^)/+(?!\n)$' '' $fzf_query | string collect -N)
else
# fish v3.1b1 - v3.1.2
set -- fzf_query (string replace -r -a -- '(?<=/)/|(?<!^)/+(?!\n)$' '' $fzf_query | string collect -N)
eval set -- fzf_query (string escape -n -- $fzf_query | string replace -r '\\\n$' '')
end
set -- dir $fzf_query
while not test -d "$dir"
set -- dir (dirname -z -- "$dir" | string split0)
end
end
if not string match -q -- '.' $dir; or string match -q -r -- '^\./|^\.$' $fzf_query
# Strip $dir from $fzf_query - preserve trailing newlines.
if test "$fish_major" -ge 4
# fish v4.0.0 and newer
string match -q -r -- '^'(string escape --style=regex -- $dir)'/?(?<fzf_query>[\s\S]*)' $fzf_query
else if test "$fish_major" -eq 3 -a "$fish_minor" -ge 2
# fish v3.2.0 - v3.7.1 (last v3)
string match -q -r -- '^/?(?<fzf_query>[\s\S]*?(?=\n?$)$)' \
(string replace -- "$dir" '' $fzf_query | string collect -N)
else
# fish older than v3.2.0 (v3.1b1 - v3.1.2)
set -- fzf_query (string replace -- "$dir" '' $fzf_query | string collect -N)
eval set -- fzf_query (string escape -n -- $fzf_query | string replace -r -a '^/?|\\\n$' '')
end
end
end
@@ -95,28 +138,27 @@ function fzf_key_bindings
set -l prefix $commandline[3]
set -lx FZF_DEFAULT_OPTS (__fzf_defaults \
"--reverse --walker=file,dir,follow,hidden --scheme=path --walker-root=$dir" \
"$FZF_CTRL_T_OPTS --multi")
"--reverse --walker=file,dir,follow,hidden --scheme=path" \
"$FZF_CTRL_T_OPTS --multi --print0")
set -lx FZF_DEFAULT_COMMAND "$FZF_CTRL_T_COMMAND"
set -lx FZF_DEFAULT_OPTS_FILE
if set -l result (eval (__fzfcmd) --query=$fzf_query)
# Remove last token from commandline.
commandline -t ''
for i in $result
commandline -it -- $prefix(string escape -- $i)' '
end
end
set -l result (eval (__fzfcmd) --walker-root=$dir --query=$fzf_query | string split0)
and commandline -rt -- (string join -- ' ' $prefix(string escape -- $result))' '
commandline -f repaint
end
function fzf-history-widget -d "Show command history"
set -l fzf_query (commandline | string escape)
set -l -- command_line (commandline)
set -l -- current_line (commandline -L)
set -l -- total_lines (count $command_line)
set -l -- fzf_query (string escape -- $command_line[$current_line])
set -lx FZF_DEFAULT_OPTS (__fzf_defaults '' \
'--nth=2..,.. --scheme=history --multi --wrap-sign="\t↳ "' \
'--bind=\'shift-delete:execute-silent(eval history delete --exact --case-sensitive -- (string escape -n -- {+} | string replace -r -a "^\d*\\\\\\t|(?<=\\\\\\n)\\\\\\t" ""))+reload(eval $FZF_DEFAULT_COMMAND)\'' \
"--bind=ctrl-r:toggle-sort --highlight-line $FZF_CTRL_R_OPTS" \
'--accept-nth=2.. --read0 --print0 --with-shell='(status fish-path)\\ -c)
@@ -138,9 +180,13 @@ function fzf_key_bindings
test -z "$fish_private_mode"; and builtin history merge
if set -l result (eval $FZF_DEFAULT_COMMAND \| (__fzfcmd) --query=$fzf_query | string split0)
commandline -- (string replace -a -- \n\t \n $result[1])
test (count $result) -gt 1; and for i in $result[2..-1]
commandline -i -- (string replace -a -- \n\t \n \n$i)
if test "$total_lines" -eq 1
commandline -- (string replace -a -- \n\t \n $result)
else
set -l a (math $current_line - 1)
set -l b (math $current_line + 1)
commandline -- $command_line[1..$a] (string replace -a -- \n\t \n $result)
commandline -a -- '' $command_line[$b..-1]
end
end
@@ -154,13 +200,13 @@ function fzf_key_bindings
set -l prefix $commandline[3]
set -lx FZF_DEFAULT_OPTS (__fzf_defaults \
"--reverse --walker=dir,follow,hidden --scheme=path --walker-root=$dir" \
"$FZF_ALT_C_OPTS --no-multi")
"--reverse --walker=dir,follow,hidden --scheme=path" \
"$FZF_ALT_C_OPTS --no-multi --print0")
set -lx FZF_DEFAULT_OPTS_FILE
set -lx FZF_DEFAULT_COMMAND "$FZF_ALT_C_COMMAND"
if set -l result (eval (__fzfcmd) --query=$fzf_query)
if set -l result (eval (__fzfcmd) --query=$fzf_query --walker-root=$dir | string split0)
cd -- $result
commandline -rt -- $prefix
end

View File

@@ -295,6 +295,7 @@ func Run(opts *Options) (int, error) {
// Event coordination
reading := true
ticks := 0
startTick := 0
var nextCommand *commandSpec
var nextEnviron []string
eventBox.Watch(EvtReadNew)
@@ -321,6 +322,7 @@ func Run(opts *Options) (int, error) {
clearDenylist()
}
reading = true
startTick = ticks
chunkList.Clear()
itemIndex = 0
inputRevision.bumpMajor()
@@ -509,7 +511,7 @@ func Run(opts *Options) (int, error) {
}
if delay && reading {
dur := util.DurWithin(
time.Duration(ticks)*coordinatorDelayStep,
time.Duration(ticks-startTick)*coordinatorDelayStep,
0, coordinatorDelayMax)
time.Sleep(dur)
}

View File

@@ -631,6 +631,7 @@ type Options struct {
MEMProfile string
BlockProfile string
MutexProfile string
TtyDefault string
}
func filterNonEmpty(input []string) []string {
@@ -730,6 +731,7 @@ func defaultOptions() *Options {
WalkerOpts: walkerOpts{file: true, hidden: true, follow: true},
WalkerRoot: []string{"."},
WalkerSkip: []string{".git", "node_modules"},
TtyDefault: tui.DefaultTtyDevice,
Help: false,
Version: false}
}
@@ -1182,7 +1184,12 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) (*tui.ColorTheme, erro
var err error
theme := dupeTheme(defaultTheme)
rrggbb := regexp.MustCompile("^#[0-9a-fA-F]{6}$")
for _, str := range strings.Split(strings.ToLower(str), ",") {
comma := regexp.MustCompile(`[\s,]+`)
for _, str := range comma.Split(strings.ToLower(str), -1) {
str = strings.TrimSpace(str)
if len(str) == 0 {
continue
}
switch str {
case "dark":
theme = dupeTheme(tui.Dark256)
@@ -1293,6 +1300,8 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) (*tui.ColorTheme, erro
mergeAttr(&theme.Current)
case "current-bg", "bg+":
mergeAttr(&theme.DarkBg)
case "alt-bg":
mergeAttr(&theme.AltBg)
case "selected-fg":
mergeAttr(&theme.SelectedFg)
case "selected-bg":
@@ -2336,6 +2345,12 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
}
case "--no-tmux":
opts.Tmux = nil
case "--tty-default":
if opts.TtyDefault, err = nextString("tty device name required"); err != nil {
return err
}
case "--no-tty-default":
opts.TtyDefault = ""
case "--force-tty-in":
// NOTE: We need this because `system('fzf --tmux < /dev/tty')` doesn't
// work on Neovim. Same as '-' option of fzf-tmux.

View File

@@ -333,7 +333,7 @@ func TestColorSpec(t *testing.T) {
t.Errorf("colors should now be equivalent: %v, %v", tui.Dark256, customized)
}
customized, _ = parseTheme(theme, "fg:231,dark,bg:232")
customized, _ = parseTheme(theme, "fg:231,dark bg:232")
if customized.Fg != tui.Dark256.Fg || customized.Bg == tui.Dark256.Bg {
t.Errorf("color not customized")
}

View File

@@ -144,7 +144,7 @@ func runProxy(commandPrefix string, cmdBuilder func(temp string, needBash bool)
env = elems[1:]
}
executor := util.NewExecutor(opts.WithShell)
ttyin, err := tui.TtyIn()
ttyin, err := tui.TtyIn(opts.TtyDefault)
if err != nil {
return ExitError, err
}

View File

@@ -323,8 +323,10 @@ func (r *Reader) readFiles(roots []string, opts walkerOpts, ignores []string) bo
return filepath.SkipDir
}
}
if path != sep {
path += sep
}
}
if ((opts.file && !isDir) || (opts.dir && isDir)) && r.pusher(stringBytes(path)) {
atomic.StoreInt32(&r.event, int32(EvtReadNew))
}

View File

@@ -119,7 +119,7 @@ func minRank() Result {
return Result{item: &minItem, points: [4]uint16{math.MaxUint16, 0, 0, 0}}
}
func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, theme *tui.ColorTheme, colBase tui.ColorPair, colMatch tui.ColorPair, attrNth tui.Attr, current bool) []colorOffset {
func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, theme *tui.ColorTheme, colBase tui.ColorPair, colMatch tui.ColorPair, attrNth tui.Attr) []colorOffset {
itemColors := result.item.Colors()
// No ANSI codes
@@ -182,18 +182,10 @@ func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, t
fg := ansi.color.fg
bg := ansi.color.bg
if fg == -1 {
if current {
fg = theme.Current.Color
} else {
fg = theme.Fg.Color
}
fg = colBase.Fg()
}
if bg == -1 {
if current {
bg = theme.DarkBg.Color
} else {
bg = theme.Bg.Color
}
bg = colBase.Bg()
}
return tui.NewColorPair(fg, bg, ansi.color.attr).MergeAttr(base)
}

View File

@@ -131,7 +131,7 @@ func TestColorOffset(t *testing.T) {
colBase := tui.NewColorPair(89, 189, tui.AttrUndefined)
colMatch := tui.NewColorPair(99, 199, tui.AttrUndefined)
colors := item.colorOffsets(offsets, nil, tui.Dark256, colBase, colMatch, tui.AttrUndefined, true)
colors := item.colorOffsets(offsets, nil, tui.Dark256, colBase, colMatch, tui.AttrUndefined)
assert := func(idx int, b int32, e int32, c tui.ColorPair) {
o := colors[idx]
if o.offset[0] != b || o.offset[1] != e || o.color != c {
@@ -158,7 +158,7 @@ func TestColorOffset(t *testing.T) {
nthOffsets := []Offset{{37, 39}, {42, 45}}
for _, attr := range []tui.Attr{tui.AttrRegular, tui.StrikeThrough} {
colors = item.colorOffsets(offsets, nthOffsets, tui.Dark256, colRegular, colUnderline, attr, true)
colors = item.colorOffsets(offsets, nthOffsets, tui.Dark256, colRegular, colUnderline, attr)
// [{[0 5] {1 5 0}} {[5 15] {1 5 8}} {[15 20] {1 5 0}}
// {[22 25] {2 6 1}} {[25 27] {2 6 9}} {[27 30] {-1 -1 8}}

View File

@@ -381,6 +381,7 @@ type Terminal struct {
slab *util.Slab
theme *tui.ColorTheme
tui tui.Renderer
ttyDefault string
ttyin *os.File
executing *util.AtomicBool
termSize tui.TermSize
@@ -809,7 +810,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
// when you run fzf multiple times in your Go program. Closing it is known to
// cause problems with 'become' action and invalid terminal state after exit.
if ttyin == nil {
if ttyin, err = tui.TtyIn(); err != nil {
if ttyin, err = tui.TtyIn(opts.TtyDefault); err != nil {
return nil, err
}
}
@@ -817,7 +818,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
if tui.HasFullscreenRenderer() {
renderer = tui.NewFullscreenRenderer(opts.Theme, opts.Black, opts.Mouse)
} else {
renderer, err = tui.NewLightRenderer(ttyin, opts.Theme, opts.Black, opts.Mouse, opts.Tabstop, opts.ClearOnExit,
renderer, err = tui.NewLightRenderer(opts.TtyDefault, ttyin, opts.Theme, opts.Black, opts.Mouse, opts.Tabstop, opts.ClearOnExit,
true, func(h int) int { return h })
}
} else {
@@ -833,7 +834,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
effectiveMinHeight += borderLines(opts.BorderShape)
return util.Min(termHeight, util.Max(evaluateHeight(opts, termHeight), effectiveMinHeight))
}
renderer, err = tui.NewLightRenderer(ttyin, opts.Theme, opts.Black, opts.Mouse, opts.Tabstop, opts.ClearOnExit, false, maxHeightFunc)
renderer, err = tui.NewLightRenderer(opts.TtyDefault, ttyin, opts.Theme, opts.Black, opts.Mouse, opts.Tabstop, opts.ClearOnExit, false, maxHeightFunc)
}
if err != nil {
return nil, err
@@ -967,6 +968,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
keyChan: make(chan tui.Event),
eventChan: make(chan tui.Event, 6), // start | (load + result + zero|one) | (focus) | (resize)
tui: renderer,
ttyDefault: opts.TtyDefault,
ttyin: ttyin,
initFunc: func() error { return renderer.Init() },
executing: util.NewAtomicBool(false),
@@ -1089,9 +1091,13 @@ func (t *Terminal) environImpl(forPreview bool) []string {
env = append(env, "FZF_ACTION="+t.lastAction.Name())
env = append(env, "FZF_KEY="+t.lastKey)
env = append(env, "FZF_PROMPT="+string(t.promptString))
env = append(env, "FZF_GHOST="+string(t.ghost))
env = append(env, "FZF_POINTER="+string(t.pointer))
env = append(env, "FZF_PREVIEW_LABEL="+t.previewLabelOpts.label)
env = append(env, "FZF_BORDER_LABEL="+t.borderLabelOpts.label)
env = append(env, "FZF_LIST_LABEL="+t.listLabelOpts.label)
env = append(env, "FZF_INPUT_LABEL="+t.inputLabelOpts.label)
env = append(env, "FZF_HEADER_LABEL="+t.headerLabelOpts.label)
if len(t.nthCurrent) > 0 {
env = append(env, "FZF_NTH="+RangesToString(t.nthCurrent))
}
@@ -1252,7 +1258,7 @@ func (t *Terminal) ansiLabelPrinter(str string, color *tui.ColorPair, fill bool)
printFn := func(window tui.Window, limit int) {
if offsets == nil {
// tui.Col* are not initialized until renderer.Init()
offsets = result.colorOffsets(nil, nil, t.theme, *color, *color, t.nthAttr, false)
offsets = result.colorOffsets(nil, nil, t.theme, *color, *color, t.nthAttr)
}
for limit > 0 {
if length > limit {
@@ -2647,6 +2653,9 @@ func (t *Terminal) headerIndent(borderShape tui.BorderShape) int {
}
if borderShape.HasLeft() {
indentSize -= 1 + t.borderWidth
if indentSize < 0 {
indentSize = 0
}
}
return indentSize
}
@@ -2782,18 +2791,29 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu
_, selected := t.selected[item.Index()]
label := ""
extraWidth := 0
alt := false
altBg := t.theme.AltBg
selectedBg := selected && t.theme.SelectedBg != t.theme.ListBg
if t.jumping != jumpDisabled {
if index < len(t.jumpLabels) {
// Striped
current = index%2 == 0
if !altBg.IsColorDefined() {
altBg = t.theme.DarkBg
alt = index%2 == 0
} else {
alt = index%2 == 1
}
label = t.jumpLabels[index:index+1] + strings.Repeat(" ", util.Max(0, t.pointerLen-1))
if t.pointerLen == 0 {
extraWidth = 1
}
}
} else if current {
} else {
if current {
label = t.pointer
}
alt = !selectedBg && altBg.IsColorDefined() && index%2 == 1
}
// Avoid unnecessary redraw
numLines, _ := t.numItemLines(item, maxLine-line+1)
@@ -2819,10 +2839,12 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu
maxWidth := t.window.Width() - (t.pointerLen + t.markerLen + 1)
postTask := func(lineNum int, width int, wrapped bool, forceRedraw bool) {
width += extraWidth
if (current || selected) && t.highlightLine {
if (current || selected || alt) && t.highlightLine {
color := tui.ColSelected
if current {
color = tui.ColCurrent
} else if alt {
color = color.WithBg(altBg)
}
fillSpaces := maxWidth - width
if wrapped {
@@ -2920,6 +2942,10 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu
base = tui.ColNormal
match = tui.ColMatch
}
if alt {
base = base.WithBg(altBg)
match = match.WithBg(altBg)
}
finalLineNum = t.printHighlighted(result, base, match, false, true, line, maxLine, forceRedraw, preTask, postTask)
}
for i := 0; i < t.gap && finalLineNum < maxLine; i++ {
@@ -3018,7 +3044,7 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
sort.Sort(ByOrder(nthOffsets))
}
}
allOffsets := result.colorOffsets(charOffsets, nthOffsets, t.theme, colBase, colMatch, t.nthAttr, current)
allOffsets := result.colorOffsets(charOffsets, nthOffsets, t.theme, colBase, colMatch, t.nthAttr)
maxLines := 1
if t.canSpanMultiLines() {
@@ -3144,7 +3170,7 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
wasWrapped = true
}
if len(line) > 0 && line[len(line)-1] == '\n' {
if len(line) > 0 && line[len(line)-1] == '\n' && lineOffset < len(lines)-1 {
line = line[:len(line)-1]
} else {
wrapped = true
@@ -4039,7 +4065,7 @@ func (t *Terminal) executeCommand(template string, forcePlus bool, background bo
t.executing.Set(true)
if !background {
// Open a separate handle for tty input
if in, _ := tui.TtyIn(); in != nil {
if in, _ := tui.TtyIn(t.ttyDefault); in != nil {
cmd.Stdin = in
if in != os.Stdin {
defer in.Close()
@@ -4048,7 +4074,7 @@ func (t *Terminal) executeCommand(template string, forcePlus bool, background bo
cmd.Stdout = os.Stdout
if !util.IsTty(os.Stdout) {
if out, _ := tui.TtyOut(); out != nil {
if out, _ := tui.TtyOut(t.ttyDefault); out != nil {
cmd.Stdout = out
defer out.Close()
}
@@ -4056,7 +4082,7 @@ func (t *Terminal) executeCommand(template string, forcePlus bool, background bo
cmd.Stderr = os.Stderr
if !util.IsTty(os.Stderr) {
if out, _ := tui.TtyOut(); out != nil {
if out, _ := tui.TtyOut(t.ttyDefault); out != nil {
cmd.Stderr = out
defer out.Close()
}

View File

@@ -28,7 +28,7 @@ const (
maxInputBuffer = 1024 * 1024
)
const consoleDevice string = "/dev/tty"
const DefaultTtyDevice string = "/dev/tty"
var offsetRegexp = regexp.MustCompile("(.*?)\x00?\x1b\\[([0-9]+);([0-9]+)R")
var offsetRegexpBegin = regexp.MustCompile("^\x1b\\[[0-9]+;[0-9]+R")
@@ -146,8 +146,8 @@ type LightWindow struct {
wrapSignWidth int
}
func NewLightRenderer(ttyin *os.File, theme *ColorTheme, forceBlack bool, mouse bool, tabstop int, clearOnExit bool, fullscreen bool, maxHeightFunc func(int) int) (Renderer, error) {
out, err := openTtyOut()
func NewLightRenderer(ttyDefault string, ttyin *os.File, theme *ColorTheme, forceBlack bool, mouse bool, tabstop int, clearOnExit bool, fullscreen bool, maxHeightFunc func(int) int) (Renderer, error) {
out, err := openTtyOut(ttyDefault)
if err != nil {
out = os.Stderr
}
@@ -271,7 +271,7 @@ func (r *LightRenderer) getBytesInternal(buffer []byte, nonblock bool) ([]byte,
c, ok := r.getch(nonblock)
if !nonblock && !ok {
r.Close()
return nil, errors.New("failed to read " + consoleDevice)
return nil, errors.New("failed to read " + DefaultTtyDevice)
}
retries := 0

View File

@@ -42,26 +42,35 @@ func (r *LightRenderer) closePlatform() {
r.ttyout.Close()
}
func openTty(mode int) (*os.File, error) {
in, err := os.OpenFile(consoleDevice, mode, 0)
if err != nil {
func openTty(ttyDefault string, mode int) (*os.File, error) {
var in *os.File
var err error
if len(ttyDefault) > 0 {
in, err = os.OpenFile(ttyDefault, mode, 0)
}
if in == nil || err != nil || ttyDefault != DefaultTtyDevice && !util.IsTty(in) {
tty := ttyname()
if len(tty) > 0 {
if in, err := os.OpenFile(tty, mode, 0); err == nil {
return in, nil
}
}
return nil, errors.New("failed to open " + consoleDevice)
if ttyDefault != DefaultTtyDevice {
if in, err = os.OpenFile(DefaultTtyDevice, mode, 0); err == nil {
return in, nil
}
}
return nil, errors.New("failed to open " + DefaultTtyDevice)
}
return in, nil
}
func openTtyIn() (*os.File, error) {
return openTty(syscall.O_RDONLY)
func openTtyIn(ttyDefault string) (*os.File, error) {
return openTty(ttyDefault, syscall.O_RDONLY)
}
func openTtyOut() (*os.File, error) {
return openTty(syscall.O_WRONLY)
func openTtyOut(ttyDefault string) (*os.File, error) {
return openTty(ttyDefault, syscall.O_WRONLY)
}
func (r *LightRenderer) setupTerminal() {

View File

@@ -76,12 +76,12 @@ func (r *LightRenderer) closePlatform() {
windows.SetConsoleMode(windows.Handle(r.inHandle), r.origStateInput)
}
func openTtyIn() (*os.File, error) {
func openTtyIn(ttyDefault string) (*os.File, error) {
// not used
return nil, nil
}
func openTtyOut() (*os.File, error) {
func openTtyOut(ttyDefault string) (*os.File, error) {
return os.Stderr, nil
}

View File

@@ -44,11 +44,11 @@ func ttyname() string {
}
// TtyIn returns terminal device to read user input
func TtyIn() (*os.File, error) {
return openTtyIn()
func TtyIn(ttyDefault string) (*os.File, error) {
return openTtyIn(ttyDefault)
}
// TtyIn returns terminal device to write to
func TtyOut() (*os.File, error) {
return openTtyOut()
func TtyOut(ttyDefault string) (*os.File, error) {
return openTtyOut(ttyDefault)
}

View File

@@ -11,11 +11,11 @@ func ttyname() string {
}
// TtyIn on Windows returns os.Stdin
func TtyIn() (*os.File, error) {
func TtyIn(ttyDefault string) (*os.File, error) {
return os.Stdin, nil
}
// TtyOut on Windows returns nil
func TtyOut() (*os.File, error) {
func TtyOut(ttyDefault string) (*os.File, error) {
return nil, nil
}

View File

@@ -308,6 +308,12 @@ func (p ColorPair) WithAttr(attr Attr) ColorPair {
return dup
}
func (p ColorPair) WithBg(bg ColorAttr) ColorPair {
dup := p
bgPair := ColorPair{colUndefined, bg.Color, bg.Attr}
return dup.Merge(bgPair)
}
func (p ColorPair) MergeAttr(other ColorPair) ColorPair {
return p.WithAttr(other.attr)
}
@@ -328,6 +334,7 @@ type ColorTheme struct {
Bg ColorAttr
ListFg ColorAttr
ListBg ColorAttr
AltBg ColorAttr
Nth ColorAttr
SelectedFg ColorAttr
SelectedBg ColorAttr
@@ -735,6 +742,7 @@ func EmptyTheme() *ColorTheme {
Bg: ColorAttr{colUndefined, AttrUndefined},
ListFg: ColorAttr{colUndefined, AttrUndefined},
ListBg: ColorAttr{colUndefined, AttrUndefined},
AltBg: ColorAttr{colUndefined, AttrUndefined},
SelectedFg: ColorAttr{colUndefined, AttrUndefined},
SelectedBg: ColorAttr{colUndefined, AttrUndefined},
SelectedMatch: ColorAttr{colUndefined, AttrUndefined},
@@ -780,6 +788,7 @@ func NoColorTheme() *ColorTheme {
Bg: ColorAttr{colDefault, AttrUndefined},
ListFg: ColorAttr{colDefault, AttrUndefined},
ListBg: ColorAttr{colDefault, AttrUndefined},
AltBg: ColorAttr{colUndefined, AttrUndefined},
SelectedFg: ColorAttr{colDefault, AttrUndefined},
SelectedBg: ColorAttr{colDefault, AttrUndefined},
SelectedMatch: ColorAttr{colDefault, AttrUndefined},
@@ -825,6 +834,7 @@ func init() {
Bg: ColorAttr{colDefault, AttrUndefined},
ListFg: ColorAttr{colUndefined, AttrUndefined},
ListBg: ColorAttr{colUndefined, AttrUndefined},
AltBg: ColorAttr{colUndefined, AttrUndefined},
SelectedFg: ColorAttr{colUndefined, AttrUndefined},
SelectedBg: ColorAttr{colUndefined, AttrUndefined},
SelectedMatch: ColorAttr{colUndefined, AttrUndefined},
@@ -864,6 +874,7 @@ func init() {
Bg: ColorAttr{colDefault, AttrUndefined},
ListFg: ColorAttr{colUndefined, AttrUndefined},
ListBg: ColorAttr{colUndefined, AttrUndefined},
AltBg: ColorAttr{colUndefined, AttrUndefined},
SelectedFg: ColorAttr{colUndefined, AttrUndefined},
SelectedBg: ColorAttr{colUndefined, AttrUndefined},
SelectedMatch: ColorAttr{colUndefined, AttrUndefined},
@@ -903,6 +914,7 @@ func init() {
Bg: ColorAttr{colDefault, AttrUndefined},
ListFg: ColorAttr{colUndefined, AttrUndefined},
ListBg: ColorAttr{colUndefined, AttrUndefined},
AltBg: ColorAttr{colUndefined, AttrUndefined},
SelectedFg: ColorAttr{colUndefined, AttrUndefined},
SelectedBg: ColorAttr{colUndefined, AttrUndefined},
SelectedMatch: ColorAttr{colUndefined, AttrUndefined},

View File

@@ -1632,14 +1632,16 @@ class TestCore < TestInteractive
end
def test_env_vars
def to_vars(lines)
lines.select { it.start_with?('FZF_') }.to_h do
key, val = it.split('=', 2)
def env_vars
return {} unless File.exist?(tempname)
File.readlines(tempname).select { it.start_with?('FZF_') }.to_h do
key, val = it.chomp.split('=', 2)
[key.to_sym, val]
end
end
tmux.send_keys %(seq 100 | #{FZF} --multi --reverse --preview-window up,99%,noborder --preview 'env | grep ^FZF_ | sort' --no-input --bind enter:show-input+refresh-preview,space:disable-search+refresh-preview), :Enter
tmux.send_keys %(seq 100 | #{FZF} --multi --reverse --preview-window 0 --preview 'env | grep ^FZF_ | sort > #{tempname}' --no-input --bind enter:show-input+refresh-preview,space:disable-search+refresh-preview), :Enter
expected = {
FZF_TOTAL_COUNT: '100',
FZF_MATCH_COUNT: '100',
@@ -1648,31 +1650,32 @@ class TestCore < TestInteractive
FZF_KEY: '',
FZF_POS: '1',
FZF_QUERY: '',
FZF_POINTER: '>',
FZF_PROMPT: '> ',
FZF_INPUT_STATE: 'hidden'
}
tmux.until do |lines|
assert_equal expected, to_vars(lines).slice(*expected.keys)
tmux.until do
assert_equal expected, env_vars.slice(*expected.keys)
end
tmux.send_keys :Enter
tmux.until do |lines|
tmux.until do
expected.merge!(FZF_INPUT_STATE: 'enabled', FZF_ACTION: 'show-input', FZF_KEY: 'enter')
assert_equal expected, to_vars(lines).slice(*expected.keys)
assert_equal expected, env_vars.slice(*expected.keys)
end
tmux.send_keys :Tab, :Tab
tmux.until do |lines|
tmux.until do
expected.merge!(FZF_ACTION: 'toggle-down', FZF_KEY: 'tab', FZF_POS: '3', FZF_SELECT_COUNT: '2')
assert_equal expected, to_vars(lines).slice(*expected.keys)
assert_equal expected, env_vars.slice(*expected.keys)
end
tmux.send_keys '99'
tmux.until do |lines|
tmux.until do
expected.merge!(FZF_ACTION: 'char', FZF_KEY: '9', FZF_QUERY: '99', FZF_MATCH_COUNT: '1', FZF_POS: '1')
assert_equal expected, to_vars(lines).slice(*expected.keys)
assert_equal expected, env_vars.slice(*expected.keys)
end
tmux.send_keys :Space
tmux.until do |lines|
tmux.until do
expected.merge!(FZF_INPUT_STATE: 'disabled', FZF_ACTION: 'disable-search', FZF_KEY: 'space')
assert_equal expected, to_vars(lines).slice(*expected.keys)
assert_equal expected, env_vars.slice(*expected.keys)
end
end
@@ -1931,4 +1934,9 @@ class TestCore < TestInteractive
tmux.send_keys :Space
tmux.until { |lines| assert lines.any_include?('bar') }
end
def test_trailing_new_line
tmux.send_keys %(echo -en "foo\n" | fzf --read0 --no-multi-line), :Enter
tmux.until { |lines| assert_includes lines, '> foo␊' }
end
end

View File

@@ -991,4 +991,16 @@ class TestLayout < TestInteractive
BLOCK
tmux.until { assert_block(block, it) }
end
def test_header_border_no_pointer_and_marker
tmux.send_keys %(seq 10 | #{FZF} --header-lines 1 --header-border sharp --no-list-border --pointer '' --marker ''), :Enter
block = <<~BLOCK
1
9/9
>
BLOCK
tmux.until { assert_block(block, it) }
end
end