mirror of
https://github.com/junegunn/fzf.git
synced 2025-11-15 06:43:47 -05:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c0d407f7ce | ||
|
|
461115afde | ||
|
|
bae1965231 | ||
|
|
b89c77ec9a | ||
|
|
1ca5f09d7b | ||
|
|
d79902ae59 | ||
|
|
77568e114f | ||
|
|
a24d274a3c | ||
|
|
dac81432d6 | ||
|
|
309b5081ef | ||
|
|
91bc4f2671 | ||
|
|
4c9d37d919 | ||
|
|
7e9566f66a | ||
|
|
3f7e8a475d | ||
|
|
1cf7c0f334 | ||
|
|
ff8ee9ee4e | ||
|
|
cbbd939a94 | ||
|
|
f232df2887 | ||
|
|
16bfb2c80c | ||
|
|
0ba066123e | ||
|
|
81c51c26cc | ||
|
|
6fa8295ac5 | ||
|
|
f975b40236 | ||
|
|
01d9d9c8c8 | ||
|
|
1eafc4e5d9 | ||
|
|
38e4020aa8 | ||
|
|
ac32fbb3b2 | ||
|
|
7d26eca5cc |
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,6 +1,20 @@
|
|||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
0.60.2
|
||||||
|
------
|
||||||
|
- Template for `--with-nth` and `--accept-nth` now supports `{n}` which evaluates to the zero-based ordinal index of the item
|
||||||
|
- Fixed a regression that caused the last field in the "nth" expression to be trimmed when a regular expression delimiter is used
|
||||||
|
- Thanks to @phanen for the fix
|
||||||
|
- Fixed 'jump' action when the pointer is an empty string
|
||||||
|
|
||||||
|
0.60.1
|
||||||
|
------
|
||||||
|
- Bug fixes and minor improvements
|
||||||
|
- Built-in walker now prints directory entries with a trailing slash
|
||||||
|
- Fixed a bug causing unexpected behavior with [fzf-tab](https://github.com/Aloxaf/fzf-tab). Please upgrade if you use it.
|
||||||
|
- Thanks to @alexeisersun, @bitraid, @Lompik, and @fsc0 for the contributions
|
||||||
|
|
||||||
0.60.0
|
0.60.0
|
||||||
------
|
------
|
||||||
_Release highlights: https://junegunn.github.io/fzf/releases/0.60.0/_
|
_Release highlights: https://junegunn.github.io/fzf/releases/0.60.0/_
|
||||||
|
|||||||
2
install
2
install
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
set -u
|
set -u
|
||||||
|
|
||||||
version=0.60.0
|
version=0.60.2
|
||||||
auto_completion=
|
auto_completion=
|
||||||
key_bindings=
|
key_bindings=
|
||||||
update_config=2
|
update_config=2
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
$version="0.60.0"
|
$version="0.60.2"
|
||||||
|
|
||||||
$fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition
|
$fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
..
|
..
|
||||||
.TH fzf\-tmux 1 "Feb 2025" "fzf 0.60.0" "fzf\-tmux - open fzf in tmux split pane"
|
.TH fzf\-tmux 1 "Feb 2025" "fzf 0.60.2" "fzf\-tmux - open fzf in tmux split pane"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fzf\-tmux - open fzf in tmux split pane
|
fzf\-tmux - open fzf in tmux split pane
|
||||||
|
|||||||
@@ -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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
..
|
..
|
||||||
.TH fzf 1 "Feb 2025" "fzf 0.60.0" "fzf - a command-line fuzzy finder"
|
.TH fzf 1 "Feb 2025" "fzf 0.60.2" "fzf - a command-line fuzzy finder"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fzf - a command-line fuzzy finder
|
fzf - a command-line fuzzy finder
|
||||||
@@ -56,7 +56,9 @@ Case-insensitive match (default: smart-case match)
|
|||||||
Case-sensitive match
|
Case-sensitive match
|
||||||
.TP
|
.TP
|
||||||
.B "\-\-smart\-case"
|
.B "\-\-smart\-case"
|
||||||
Smart-case match (default)
|
Smart-case match (default). In this mode, the search is case-insensitive by
|
||||||
|
default, but it becomes case-sensitive if the query contains any uppercase
|
||||||
|
letters.
|
||||||
.TP
|
.TP
|
||||||
.B "\-\-literal"
|
.B "\-\-literal"
|
||||||
Do not normalize latin script letters for matching.
|
Do not normalize latin script letters for matching.
|
||||||
@@ -120,7 +122,9 @@ fields.
|
|||||||
.BI "\-\-with\-nth=" "N[,..] or TEMPLATE"
|
.BI "\-\-with\-nth=" "N[,..] or TEMPLATE"
|
||||||
Transform the presentation of each line using the field index expressions.
|
Transform the presentation of each line using the field index expressions.
|
||||||
For advanced transformation, you can provide a template containing field index
|
For advanced transformation, you can provide a template containing field index
|
||||||
expressions in curly braces.
|
expressions in curly braces. When you use a template, the trailing delimiter is
|
||||||
|
stripped from each expression, giving you more control over the output.
|
||||||
|
\fB{n}\fR in template evaluates to the zero-based ordinal index of the line.
|
||||||
|
|
||||||
.RS
|
.RS
|
||||||
e.g.
|
e.g.
|
||||||
@@ -128,13 +132,16 @@ e.g.
|
|||||||
echo foo bar baz | fzf --with-nth 2..
|
echo foo bar baz | fzf --with-nth 2..
|
||||||
|
|
||||||
# Use template to rearrange fields
|
# Use template to rearrange fields
|
||||||
echo foo,bar,baz | fzf --delimiter , --with-nth '{1},{3},{2},{1..2}'
|
echo foo,bar,baz | fzf --delimiter , --with-nth '{n},{1},{3},{2},{1..2}'
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
.BI "\-\-accept\-nth=" "N[,..] or TEMPLATE"
|
.BI "\-\-accept\-nth=" "N[,..] or TEMPLATE"
|
||||||
Define which fields to print on accept. The last delimiter is stripped from the
|
Define which fields to print on accept. The last delimiter is stripped from the
|
||||||
output. For advanced transformation, you can provide a template containing
|
output. For advanced transformation, you can provide a template containing
|
||||||
field index expressions in curly braces.
|
field index expressions in curly braces. When you use a template, the trailing
|
||||||
|
delimiter is stripped from each expression, giving you more control over the
|
||||||
|
output. \fB{n}\fR in template evaluates to the zero-based ordinal index of the
|
||||||
|
line.
|
||||||
|
|
||||||
.RS
|
.RS
|
||||||
e.g.
|
e.g.
|
||||||
@@ -142,7 +149,7 @@ e.g.
|
|||||||
echo foo bar baz | fzf --accept-nth 2
|
echo foo bar baz | fzf --accept-nth 2
|
||||||
|
|
||||||
# Template
|
# Template
|
||||||
echo foo bar baz | fzf --accept-nth '1st: {1}, 2nd: {2}, 3rd: {3}'
|
echo foo bar baz | fzf --accept-nth 'Index: {n}, 1st: {1}, 2nd: {2}, 3rd: {3}'
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
.B "+s, \-\-no\-sort"
|
.B "+s, \-\-no\-sort"
|
||||||
@@ -1717,6 +1724,9 @@ e.g.
|
|||||||
\fBfzf \-\-multi \-\-bind 'ctrl\-a:select\-all+accept'\fR
|
\fBfzf \-\-multi \-\-bind 'ctrl\-a:select\-all+accept'\fR
|
||||||
\fBfzf \-\-multi \-\-bind 'ctrl\-a:select\-all' \-\-bind 'ctrl\-a:+accept'\fR
|
\fBfzf \-\-multi \-\-bind 'ctrl\-a:select\-all' \-\-bind 'ctrl\-a:+accept'\fR
|
||||||
|
|
||||||
|
Any action after a terminal action that exits fzf, such as \fBaccept\fR or
|
||||||
|
\fBabort\fR, is ignored.
|
||||||
|
|
||||||
.SS ACTION ARGUMENT
|
.SS ACTION ARGUMENT
|
||||||
|
|
||||||
An action denoted with \fB(...)\fR suffix takes an argument.
|
An action denoted with \fB(...)\fR suffix takes an argument.
|
||||||
|
|||||||
@@ -99,9 +99,9 @@ if [[ -o interactive ]]; then
|
|||||||
__fzf_defaults() {
|
__fzf_defaults() {
|
||||||
# $1: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
# $1: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
||||||
# $2: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
# $2: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
||||||
echo "--height ${FZF_TMUX_HEIGHT:-40%} --min-height 20+ --bind=ctrl-z:ignore $1"
|
echo -E "--height ${FZF_TMUX_HEIGHT:-40%} --min-height 20+ --bind=ctrl-z:ignore $1"
|
||||||
command cat "${FZF_DEFAULT_OPTS_FILE-}" 2> /dev/null
|
command cat "${FZF_DEFAULT_OPTS_FILE-}" 2> /dev/null
|
||||||
echo "${FZF_DEFAULT_OPTS-} $2"
|
echo -E "${FZF_DEFAULT_OPTS-} $2"
|
||||||
}
|
}
|
||||||
|
|
||||||
__fzf_comprun() {
|
__fzf_comprun() {
|
||||||
|
|||||||
@@ -14,102 +14,24 @@
|
|||||||
|
|
||||||
# Key bindings
|
# 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[..]
|
||||||
function fzf_key_bindings
|
function fzf_key_bindings
|
||||||
|
|
||||||
function __fzf_defaults
|
function __fzf_defaults
|
||||||
# $1: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
# $argv[1]: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
||||||
# $2: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
# $argv[2..]: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
||||||
test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
|
test -n "$FZF_TMUX_HEIGHT"; or set -l FZF_TMUX_HEIGHT 40%
|
||||||
echo "--height $FZF_TMUX_HEIGHT --min-height 20+ --bind=ctrl-z:ignore" $argv[1]
|
string join ' ' -- \
|
||||||
test -r "$FZF_DEFAULT_OPTS_FILE"; and string collect -N -- <$FZF_DEFAULT_OPTS_FILE
|
"--height $FZF_TMUX_HEIGHT --min-height=20+ --bind=ctrl-z:ignore" $argv[1] \
|
||||||
echo $FZF_DEFAULT_OPTS $argv[2]
|
(test -r "$FZF_DEFAULT_OPTS_FILE"; and string join -- ' ' <$FZF_DEFAULT_OPTS_FILE) \
|
||||||
end
|
$FZF_DEFAULT_OPTS $argv[2..-1]
|
||||||
|
|
||||||
# Store current token in $dir as root for the 'find' command
|
|
||||||
function fzf-file-widget -d "List files and folders"
|
|
||||||
set -l commandline (__fzf_parse_commandline)
|
|
||||||
set -lx dir $commandline[1]
|
|
||||||
set -l fzf_query $commandline[2]
|
|
||||||
set -l prefix $commandline[3]
|
|
||||||
set -l result
|
|
||||||
|
|
||||||
test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
|
|
||||||
begin
|
|
||||||
set -lx FZF_DEFAULT_OPTS (__fzf_defaults "--reverse --walker=file,dir,follow,hidden --scheme=path --walker-root=$dir" "$FZF_CTRL_T_OPTS")
|
|
||||||
set -lx FZF_DEFAULT_COMMAND "$FZF_CTRL_T_COMMAND"
|
|
||||||
set -lx FZF_DEFAULT_OPTS_FILE ''
|
|
||||||
set result (eval (__fzfcmd) -m --query=$fzf_query)
|
|
||||||
end
|
|
||||||
if test -z "$result"
|
|
||||||
commandline -f repaint
|
|
||||||
return
|
|
||||||
else
|
|
||||||
# Remove last token from commandline.
|
|
||||||
commandline -t ""
|
|
||||||
end
|
|
||||||
for i in $result
|
|
||||||
commandline -it -- $prefix
|
|
||||||
commandline -it -- (string escape -- $i)
|
|
||||||
commandline -it -- ' '
|
|
||||||
end
|
|
||||||
commandline -f repaint
|
|
||||||
end
|
|
||||||
|
|
||||||
function fzf-history-widget -d "Show command history"
|
|
||||||
test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
|
|
||||||
begin
|
|
||||||
# merge history from other sessions before searching
|
|
||||||
test -z "$fish_private_mode"; and builtin history merge
|
|
||||||
|
|
||||||
set -lx FZF_DEFAULT_OPTS (__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort --wrap-sign '"\t"↳ ' --highlight-line +m $FZF_CTRL_R_OPTS")
|
|
||||||
set -lx FZF_DEFAULT_OPTS_FILE ''
|
|
||||||
set -lx FZF_DEFAULT_COMMAND
|
|
||||||
set -a -- FZF_DEFAULT_OPTS --with-shell=(status fish-path)\\ -c
|
|
||||||
|
|
||||||
if type -q perl
|
|
||||||
set -a FZF_DEFAULT_OPTS '--tac'
|
|
||||||
set FZF_DEFAULT_COMMAND 'builtin history -z --reverse | command perl -0 -pe \'s/^/$.\t/g; s/\n/\n\t/gm\''
|
|
||||||
else
|
|
||||||
set FZF_DEFAULT_COMMAND \
|
|
||||||
'set -l h (builtin history -z --reverse | string split0);' \
|
|
||||||
'for i in (seq (count $h) -1 1);' \
|
|
||||||
'string join0 -- $i\t(string replace -a -- \n \n\t $h[$i] | string collect);' \
|
|
||||||
'end'
|
|
||||||
end
|
|
||||||
set -l result (eval $FZF_DEFAULT_COMMAND \| (__fzfcmd) --read0 --print0 -q (commandline | string escape) "--bind=enter:become:'string replace -a -- \n\t \n {2..} | string collect'")
|
|
||||||
and commandline -- $result
|
|
||||||
end
|
|
||||||
commandline -f repaint
|
|
||||||
end
|
|
||||||
|
|
||||||
function fzf-cd-widget -d "Change directory"
|
|
||||||
set -l commandline (__fzf_parse_commandline)
|
|
||||||
set -lx dir $commandline[1]
|
|
||||||
set -l fzf_query $commandline[2]
|
|
||||||
set -l prefix $commandline[3]
|
|
||||||
|
|
||||||
test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
|
|
||||||
begin
|
|
||||||
set -lx FZF_DEFAULT_OPTS (__fzf_defaults "--reverse --walker=dir,follow,hidden --scheme=path --walker-root=$dir" "$FZF_ALT_C_OPTS")
|
|
||||||
set -lx FZF_DEFAULT_OPTS_FILE ''
|
|
||||||
set -lx FZF_DEFAULT_COMMAND "$FZF_ALT_C_COMMAND"
|
|
||||||
set -l result (eval (__fzfcmd) +m --query=$fzf_query)
|
|
||||||
|
|
||||||
if test -n "$result"
|
|
||||||
cd -- $result
|
|
||||||
|
|
||||||
# Remove last token from commandline.
|
|
||||||
commandline -t ""
|
|
||||||
commandline -it -- $prefix
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
commandline -f repaint
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function __fzfcmd
|
function __fzfcmd
|
||||||
test -n "$FZF_TMUX"; or set FZF_TMUX 0
|
test -n "$FZF_TMUX_HEIGHT"; or set -l FZF_TMUX_HEIGHT 40%
|
||||||
test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
|
|
||||||
if test -n "$FZF_TMUX_OPTS"
|
if test -n "$FZF_TMUX_OPTS"
|
||||||
echo "fzf-tmux $FZF_TMUX_OPTS -- "
|
echo "fzf-tmux $FZF_TMUX_OPTS -- "
|
||||||
else if test "$FZF_TMUX" = "1"
|
else if test "$FZF_TMUX" = "1"
|
||||||
@@ -119,56 +41,42 @@ function fzf_key_bindings
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
bind \cr fzf-history-widget
|
|
||||||
if not set -q FZF_CTRL_T_COMMAND; or test -n "$FZF_CTRL_T_COMMAND"
|
|
||||||
bind \ct fzf-file-widget
|
|
||||||
end
|
|
||||||
if not set -q FZF_ALT_C_COMMAND; or test -n "$FZF_ALT_C_COMMAND"
|
|
||||||
bind \ec fzf-cd-widget
|
|
||||||
end
|
|
||||||
|
|
||||||
bind -M insert \cr fzf-history-widget
|
|
||||||
if not set -q FZF_CTRL_T_COMMAND; or test -n "$FZF_CTRL_T_COMMAND"
|
|
||||||
bind -M insert \ct fzf-file-widget
|
|
||||||
end
|
|
||||||
if not set -q FZF_ALT_C_COMMAND; or test -n "$FZF_ALT_C_COMMAND"
|
|
||||||
bind -M insert \ec fzf-cd-widget
|
|
||||||
end
|
|
||||||
|
|
||||||
function __fzf_parse_commandline -d 'Parse the current command line token and return split of existing filepath, fzf query, and optional -option= prefix'
|
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 commandline (commandline -t)
|
set -l dir '.'
|
||||||
|
set -l query
|
||||||
|
set -l commandline (commandline -t | string unescape -n)
|
||||||
|
|
||||||
# strip -option= from token if present
|
# Strip -option= from token if present
|
||||||
set -l prefix (string match -r -- '^-[^\s=]+=' $commandline)
|
set -l prefix (string match -r -- '^-[^\s=]+=' $commandline)
|
||||||
set commandline (string replace -- "$prefix" '' $commandline)
|
set commandline (string replace -- "$prefix" '' $commandline)
|
||||||
|
|
||||||
# Enable home directory expansion of leading ~/
|
# Enable home directory expansion of leading ~/
|
||||||
set commandline (string replace -r -- '^~/' '\$HOME/' $commandline)
|
set commandline (string replace -r -- '^~/' '\$HOME/' $commandline)
|
||||||
|
|
||||||
# escape special characters, except for the $ sign of valid variable names,
|
# Escape special characters, except for the $ sign of valid variable names,
|
||||||
# so that after eval, the original string is returned, but with the
|
# so that the original string with expanded variables is returned after eval.
|
||||||
# variable names replaced by their values.
|
|
||||||
set commandline (string escape -n -- $commandline)
|
set commandline (string escape -n -- $commandline)
|
||||||
set commandline (string replace -r -a -- '\x5c\$(?=[\w])' '\$' $commandline)
|
set commandline (string replace -r -a -- '\\\\\$(?=[\w])' '\$' $commandline)
|
||||||
|
|
||||||
# eval is used to do shell expansion on paths
|
# eval is used to do shell expansion on paths
|
||||||
eval set commandline $commandline
|
eval set commandline $commandline
|
||||||
|
|
||||||
# Combine multiple consecutive slashes into one, and unescape.
|
# Combine multiple consecutive slashes into one.
|
||||||
set commandline (string replace -r -a -- '/+' '/' $commandline | string unescape -n)
|
set commandline (string replace -r -a -- '/+' '/' $commandline)
|
||||||
|
|
||||||
if test -z "$commandline"
|
if test -n "$commandline"
|
||||||
# Default to current directory with no --query
|
# Strip trailing slash, unless $dir is root dir (/)
|
||||||
set dir '.'
|
set dir (string replace -r -- '(?<!^)/$' '' $commandline)
|
||||||
set fzf_query ''
|
|
||||||
else
|
|
||||||
set dir (__fzf_get_dir $commandline)
|
|
||||||
|
|
||||||
# BUG: on combined expressions, if a left argument is a single `!`, the
|
# Set $dir to the longest existing filepath
|
||||||
# builtin test command of fish will treat it as the ! operator. To
|
while not test -d "$dir"
|
||||||
# overcome this, have the variable parts on the right.
|
# If path is absolute, this can keep going until ends up at /
|
||||||
if test "." = "$dir" -a "./" != (string sub -l 2 -- $commandline)
|
# If path is relative, this can keep going until entire input is consumed, dirname returns "."
|
||||||
# if $dir is "." but commandline is not a relative path, this means no file path found
|
set dir (dirname -- $dir)
|
||||||
|
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 fzf_query $commandline
|
||||||
else
|
else
|
||||||
# Also remove trailing slash after dir, to "split" input properly
|
# Also remove trailing slash after dir, to "split" input properly
|
||||||
@@ -176,25 +84,98 @@ function fzf_key_bindings
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
echo -- $dir
|
string escape -n -- "$dir" "$fzf_query" "$prefix"
|
||||||
string escape -- $fzf_query
|
|
||||||
echo -- $prefix
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function __fzf_get_dir -d 'Find the longest existing filepath from input string'
|
# Store current token in $dir as root for the 'find' command
|
||||||
set dir $argv
|
function fzf-file-widget -d "List files and folders"
|
||||||
|
set -l commandline (__fzf_parse_commandline)
|
||||||
|
set -lx dir $commandline[1]
|
||||||
|
set -l fzf_query $commandline[2]
|
||||||
|
set -l prefix $commandline[3]
|
||||||
|
|
||||||
# Strip trailing slash, unless $dir is root dir (/)
|
set -lx FZF_DEFAULT_OPTS (__fzf_defaults \
|
||||||
set dir (string replace -r -- '(?<!^)/$' '' $dir)
|
"--reverse --walker=file,dir,follow,hidden --scheme=path --walker-root=$dir" \
|
||||||
|
"$FZF_CTRL_T_OPTS --multi")
|
||||||
|
|
||||||
# Iteratively check if dir exists and strip tail end of path
|
set -lx FZF_DEFAULT_COMMAND "$FZF_CTRL_T_COMMAND"
|
||||||
while test ! -d "$dir"
|
set -lx FZF_DEFAULT_OPTS_FILE
|
||||||
# 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 "."
|
if set -l result (eval (__fzfcmd) --query=$fzf_query)
|
||||||
set dir (dirname -- "$dir")
|
# Remove last token from commandline.
|
||||||
|
commandline -t ''
|
||||||
|
for i in $result
|
||||||
|
commandline -it -- $prefix(string escape -- $i)' '
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
string escape -n -- $dir
|
commandline -f repaint
|
||||||
|
end
|
||||||
|
|
||||||
|
function fzf-history-widget -d "Show command history"
|
||||||
|
set -l fzf_query (commandline | string escape)
|
||||||
|
|
||||||
|
set -lx FZF_DEFAULT_OPTS (__fzf_defaults '' \
|
||||||
|
'--nth=2..,.. --scheme=history --bind=ctrl-r:toggle-sort --wrap-sign="\t↳ "' \
|
||||||
|
"--highlight-line --no-multi $FZF_CTRL_R_OPTS --read0 --print0" \
|
||||||
|
"--bind='enter:become:string replace -a -- \n\t \n {2..} | string collect'" \
|
||||||
|
'--with-shell='(status fish-path)\\ -c)
|
||||||
|
|
||||||
|
set -lx FZF_DEFAULT_OPTS_FILE
|
||||||
|
set -lx FZF_DEFAULT_COMMAND
|
||||||
|
|
||||||
|
if type -q perl
|
||||||
|
set -a FZF_DEFAULT_OPTS '--tac'
|
||||||
|
set FZF_DEFAULT_COMMAND 'builtin history -z --reverse | command perl -0 -pe \'s/^/$.\t/g; s/\n/\n\t/gm\''
|
||||||
|
else
|
||||||
|
set FZF_DEFAULT_COMMAND \
|
||||||
|
'set -l h (builtin history -z --reverse | string split0);' \
|
||||||
|
'for i in (seq (count $h) -1 1);' \
|
||||||
|
'string join0 -- $i\t(string replace -a -- \n \n\t $h[$i] | string collect);' \
|
||||||
|
'end'
|
||||||
|
end
|
||||||
|
|
||||||
|
# Merge history from other sessions before searching
|
||||||
|
test -z "$fish_private_mode"; and builtin history merge
|
||||||
|
|
||||||
|
set -l result (eval $FZF_DEFAULT_COMMAND \| (__fzfcmd) --query=$fzf_query)
|
||||||
|
and commandline -- $result
|
||||||
|
|
||||||
|
commandline -f repaint
|
||||||
|
end
|
||||||
|
|
||||||
|
function fzf-cd-widget -d "Change directory"
|
||||||
|
set -l commandline (__fzf_parse_commandline)
|
||||||
|
set -lx dir $commandline[1]
|
||||||
|
set -l fzf_query $commandline[2]
|
||||||
|
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")
|
||||||
|
|
||||||
|
set -lx FZF_DEFAULT_OPTS_FILE
|
||||||
|
set -lx FZF_DEFAULT_COMMAND "$FZF_ALT_C_COMMAND"
|
||||||
|
|
||||||
|
if set -l result (eval (__fzfcmd) --query=$fzf_query)
|
||||||
|
cd -- $result
|
||||||
|
commandline -rt -- $prefix
|
||||||
|
end
|
||||||
|
|
||||||
|
commandline -f repaint
|
||||||
|
end
|
||||||
|
|
||||||
|
bind \cr fzf-history-widget
|
||||||
|
bind -M insert \cr fzf-history-widget
|
||||||
|
|
||||||
|
if not set -q FZF_CTRL_T_COMMAND; or test -n "$FZF_CTRL_T_COMMAND"
|
||||||
|
bind \ct fzf-file-widget
|
||||||
|
bind -M insert \ct fzf-file-widget
|
||||||
|
end
|
||||||
|
|
||||||
|
if not set -q FZF_ALT_C_COMMAND; or test -n "$FZF_ALT_C_COMMAND"
|
||||||
|
bind \ec fzf-cd-widget
|
||||||
|
bind -M insert \ec fzf-cd-widget
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ if [[ -o interactive ]]; then
|
|||||||
__fzf_defaults() {
|
__fzf_defaults() {
|
||||||
# $1: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
# $1: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
||||||
# $2: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
# $2: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
||||||
echo "--height ${FZF_TMUX_HEIGHT:-40%} --min-height 20+ --bind=ctrl-z:ignore $1"
|
echo -E "--height ${FZF_TMUX_HEIGHT:-40%} --min-height 20+ --bind=ctrl-z:ignore $1"
|
||||||
command cat "${FZF_DEFAULT_OPTS_FILE-}" 2> /dev/null
|
command cat "${FZF_DEFAULT_OPTS_FILE-}" 2> /dev/null
|
||||||
echo "${FZF_DEFAULT_OPTS-} $2"
|
echo -E "${FZF_DEFAULT_OPTS-} $2"
|
||||||
}
|
}
|
||||||
|
|
||||||
# CTRL-T - Paste the selected file path(s) into the command line
|
# CTRL-T - Paste the selected file path(s) into the command line
|
||||||
|
|||||||
@@ -767,6 +767,9 @@ func FuzzyMatchV1(caseSensitive bool, normalize bool, forward bool, text *util.C
|
|||||||
char = unicode.To(unicode.LowerCase, char)
|
char = unicode.To(unicode.LowerCase, char)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if normalize {
|
||||||
|
char = normalizeRune(char)
|
||||||
|
}
|
||||||
|
|
||||||
pidx_ := indexAt(pidx, lenPattern, forward)
|
pidx_ := indexAt(pidx, lenPattern, forward)
|
||||||
pchar := pattern[pidx_]
|
pchar := pattern[pidx_]
|
||||||
|
|||||||
@@ -200,3 +200,12 @@ func TestLongString(t *testing.T) {
|
|||||||
bytes[math.MaxUint16] = 'z'
|
bytes[math.MaxUint16] = 'z'
|
||||||
assertMatch(t, FuzzyMatchV2, true, true, string(bytes), "zx", math.MaxUint16, math.MaxUint16+2, scoreMatch*2+bonusConsecutive)
|
assertMatch(t, FuzzyMatchV2, true, true, string(bytes), "zx", math.MaxUint16, math.MaxUint16+2, scoreMatch*2+bonusConsecutive)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLongStringWithNormalize(t *testing.T) {
|
||||||
|
bytes := make([]byte, 30000)
|
||||||
|
for i := range bytes {
|
||||||
|
bytes[i] = 'x'
|
||||||
|
}
|
||||||
|
unicodeString := string(bytes) + " Minímal example"
|
||||||
|
assertMatch2(t, FuzzyMatchV1, false, true, false, unicodeString, "minim", 30001, 30006, 140)
|
||||||
|
}
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ func Run(opts *Options) (int, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
transformed := nthTransformer(tokens)
|
transformed := nthTransformer(tokens, itemIndex)
|
||||||
if len(header) < opts.HeaderLines {
|
if len(header) < opts.HeaderLines {
|
||||||
header = append(header, transformed)
|
header = append(header, transformed)
|
||||||
eventBox.Set(EvtHeader, header)
|
eventBox.Set(EvtHeader, header)
|
||||||
|
|||||||
@@ -544,8 +544,8 @@ type Options struct {
|
|||||||
Case Case
|
Case Case
|
||||||
Normalize bool
|
Normalize bool
|
||||||
Nth []Range
|
Nth []Range
|
||||||
WithNth func(Delimiter) func([]Token) string
|
WithNth func(Delimiter) func([]Token, int32) string
|
||||||
AcceptNth func(Delimiter) func([]Token) string
|
AcceptNth func(Delimiter) func([]Token, int32) string
|
||||||
Delimiter Delimiter
|
Delimiter Delimiter
|
||||||
Sort int
|
Sort int
|
||||||
Track trackOption
|
Track trackOption
|
||||||
@@ -769,30 +769,31 @@ func splitNth(str string) ([]Range, error) {
|
|||||||
return ranges, nil
|
return ranges, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func nthTransformer(str string) (func(Delimiter) func([]Token) string, error) {
|
func nthTransformer(str string) (func(Delimiter) func([]Token, int32) string, error) {
|
||||||
// ^[0-9,-.]+$"
|
// ^[0-9,-.]+$"
|
||||||
if match, _ := regexp.MatchString("^[0-9,-.]+$", str); match {
|
if match, _ := regexp.MatchString("^[0-9,-.]+$", str); match {
|
||||||
nth, err := splitNth(str)
|
nth, err := splitNth(str)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return func(Delimiter) func([]Token) string {
|
return func(Delimiter) func([]Token, int32) string {
|
||||||
return func(tokens []Token) string {
|
return func(tokens []Token, index int32) string {
|
||||||
return JoinTokens(Transform(tokens, nth))
|
return JoinTokens(Transform(tokens, nth))
|
||||||
}
|
}
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// {...} {...} ...
|
// {...} {...} ...
|
||||||
placeholder := regexp.MustCompile("{[0-9,-.]+}")
|
placeholder := regexp.MustCompile("{[0-9,-.]+}|{n}")
|
||||||
indexes := placeholder.FindAllStringIndex(str, -1)
|
indexes := placeholder.FindAllStringIndex(str, -1)
|
||||||
if indexes == nil {
|
if indexes == nil {
|
||||||
return nil, errors.New("template should include at least 1 placeholder: " + str)
|
return nil, errors.New("template should include at least 1 placeholder: " + str)
|
||||||
}
|
}
|
||||||
|
|
||||||
type NthParts struct {
|
type NthParts struct {
|
||||||
str string
|
str string
|
||||||
nth []Range
|
index bool
|
||||||
|
nth []Range
|
||||||
}
|
}
|
||||||
|
|
||||||
parts := make([]NthParts, len(indexes))
|
parts := make([]NthParts, len(indexes))
|
||||||
@@ -801,7 +802,10 @@ func nthTransformer(str string) (func(Delimiter) func([]Token) string, error) {
|
|||||||
if idx < index[0] {
|
if idx < index[0] {
|
||||||
parts = append(parts, NthParts{str: str[idx:index[0]]})
|
parts = append(parts, NthParts{str: str[idx:index[0]]})
|
||||||
}
|
}
|
||||||
if nth, err := splitNth(str[index[0]+1 : index[1]-1]); err == nil {
|
expr := str[index[0]+1 : index[1]-1]
|
||||||
|
if expr == "n" {
|
||||||
|
parts = append(parts, NthParts{index: true})
|
||||||
|
} else if nth, err := splitNth(expr); err == nil {
|
||||||
parts = append(parts, NthParts{nth: nth})
|
parts = append(parts, NthParts{nth: nth})
|
||||||
}
|
}
|
||||||
idx = index[1]
|
idx = index[1]
|
||||||
@@ -810,12 +814,16 @@ func nthTransformer(str string) (func(Delimiter) func([]Token) string, error) {
|
|||||||
parts = append(parts, NthParts{str: str[idx:]})
|
parts = append(parts, NthParts{str: str[idx:]})
|
||||||
}
|
}
|
||||||
|
|
||||||
return func(delimiter Delimiter) func([]Token) string {
|
return func(delimiter Delimiter) func([]Token, int32) string {
|
||||||
return func(tokens []Token) string {
|
return func(tokens []Token, index int32) string {
|
||||||
str := ""
|
str := ""
|
||||||
for _, holder := range parts {
|
for _, holder := range parts {
|
||||||
if holder.nth != nil {
|
if holder.nth != nil {
|
||||||
str += StripLastDelimiter(JoinTokens(Transform(tokens, holder.nth)), delimiter)
|
str += StripLastDelimiter(JoinTokens(Transform(tokens, holder.nth)), delimiter)
|
||||||
|
} else if holder.index {
|
||||||
|
if index >= 0 {
|
||||||
|
str += strconv.Itoa(int(index))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
str += holder.str
|
str += holder.str
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -320,6 +320,7 @@ func (r *Reader) readFiles(roots []string, opts walkerOpts, ignores []string) bo
|
|||||||
return filepath.SkipDir
|
return filepath.SkipDir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
path += sep
|
||||||
}
|
}
|
||||||
if ((opts.file && !isDir) || (opts.dir && isDir)) && r.pusher(stringBytes(path)) {
|
if ((opts.file && !isDir) || (opts.dir && isDir)) && r.pusher(stringBytes(path)) {
|
||||||
atomic.StoreInt32(&r.event, int32(EvtReadNew))
|
atomic.StoreInt32(&r.event, int32(EvtReadNew))
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ type Terminal struct {
|
|||||||
nthAttr tui.Attr
|
nthAttr tui.Attr
|
||||||
nth []Range
|
nth []Range
|
||||||
nthCurrent []Range
|
nthCurrent []Range
|
||||||
acceptNth func([]Token) string
|
acceptNth func([]Token, int32) string
|
||||||
tabstop int
|
tabstop int
|
||||||
margin [4]sizeSpec
|
margin [4]sizeSpec
|
||||||
padding [4]sizeSpec
|
padding [4]sizeSpec
|
||||||
@@ -638,6 +638,7 @@ type previewRequest struct {
|
|||||||
scrollOffset int
|
scrollOffset int
|
||||||
list []*Item
|
list []*Item
|
||||||
env []string
|
env []string
|
||||||
|
query string
|
||||||
}
|
}
|
||||||
|
|
||||||
type previewResult struct {
|
type previewResult struct {
|
||||||
@@ -1575,7 +1576,7 @@ func (t *Terminal) output() bool {
|
|||||||
if t.acceptNth != nil {
|
if t.acceptNth != nil {
|
||||||
transform = func(item *Item) string {
|
transform = func(item *Item) string {
|
||||||
tokens := Tokenize(item.AsString(t.ansi), t.delimiter)
|
tokens := Tokenize(item.AsString(t.ansi), t.delimiter)
|
||||||
transformed := t.acceptNth(tokens)
|
transformed := t.acceptNth(tokens, item.Index())
|
||||||
return StripLastDelimiter(transformed, t.delimiter)
|
return StripLastDelimiter(transformed, t.delimiter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2754,11 +2755,15 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu
|
|||||||
item := result.item
|
item := result.item
|
||||||
_, selected := t.selected[item.Index()]
|
_, selected := t.selected[item.Index()]
|
||||||
label := ""
|
label := ""
|
||||||
|
extraWidth := 0
|
||||||
if t.jumping != jumpDisabled {
|
if t.jumping != jumpDisabled {
|
||||||
if index < len(t.jumpLabels) {
|
if index < len(t.jumpLabels) {
|
||||||
// Striped
|
// Striped
|
||||||
current = index%2 == 0
|
current = index%2 == 0
|
||||||
label = t.jumpLabels[index:index+1] + strings.Repeat(" ", t.pointerLen-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
|
label = t.pointer
|
||||||
@@ -2787,6 +2792,7 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu
|
|||||||
|
|
||||||
maxWidth := t.window.Width() - (t.pointerLen + t.markerLen + 1)
|
maxWidth := t.window.Width() - (t.pointerLen + t.markerLen + 1)
|
||||||
postTask := func(lineNum int, width int, wrapped bool, forceRedraw bool) {
|
postTask := func(lineNum int, width int, wrapped bool, forceRedraw bool) {
|
||||||
|
width += extraWidth
|
||||||
if (current || selected) && t.highlightLine {
|
if (current || selected) && t.highlightLine {
|
||||||
color := tui.ColSelected
|
color := tui.ColSelected
|
||||||
if current {
|
if current {
|
||||||
@@ -3099,8 +3105,15 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
|
|||||||
maxWidth := t.window.Width() - (indentSize + 1)
|
maxWidth := t.window.Width() - (indentSize + 1)
|
||||||
wasWrapped := false
|
wasWrapped := false
|
||||||
if wrapped {
|
if wrapped {
|
||||||
maxWidth -= t.wrapSignWidth
|
wrapSign := t.wrapSign
|
||||||
t.window.CPrint(colBase.WithAttr(tui.Dim), t.wrapSign)
|
if maxWidth < t.wrapSignWidth {
|
||||||
|
runes, _ := util.Truncate(wrapSign, maxWidth)
|
||||||
|
wrapSign = string(runes)
|
||||||
|
maxWidth = 0
|
||||||
|
} else {
|
||||||
|
maxWidth -= t.wrapSignWidth
|
||||||
|
}
|
||||||
|
t.window.CPrint(colBase.WithAttr(tui.Dim), wrapSign)
|
||||||
wrapped = false
|
wrapped = false
|
||||||
wasWrapped = true
|
wasWrapped = true
|
||||||
}
|
}
|
||||||
@@ -3165,7 +3178,9 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
|
|||||||
displayWidth = t.displayWidthWithLimit(line, 0, displayWidth)
|
displayWidth = t.displayWidthWithLimit(line, 0, displayWidth)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.printColoredString(t.window, line, offsets, colBase)
|
if maxWidth > 0 {
|
||||||
|
t.printColoredString(t.window, line, offsets, colBase)
|
||||||
|
}
|
||||||
if postTask != nil {
|
if postTask != nil {
|
||||||
postTask(actualLineNum, displayWidth, wasWrapped, forceRedraw)
|
postTask(actualLineNum, displayWidth, wasWrapped, forceRedraw)
|
||||||
} else {
|
} else {
|
||||||
@@ -3374,8 +3389,10 @@ func (t *Terminal) renderPreviewText(height int, lines []string, lineNo int, unc
|
|||||||
wiped := false
|
wiped := false
|
||||||
image := false
|
image := false
|
||||||
wireframe := false
|
wireframe := false
|
||||||
|
var index int
|
||||||
|
var line string
|
||||||
Loop:
|
Loop:
|
||||||
for _, line := range lines {
|
for index, line = range lines {
|
||||||
var lbg tui.Color = -1
|
var lbg tui.Color = -1
|
||||||
if ansi != nil {
|
if ansi != nil {
|
||||||
ansi.lbg = -1
|
ansi.lbg = -1
|
||||||
@@ -3518,6 +3535,7 @@ Loop:
|
|||||||
}
|
}
|
||||||
lineNo++
|
lineNo++
|
||||||
}
|
}
|
||||||
|
t.previewer.scrollable = t.previewer.scrollable || index < len(lines)-1
|
||||||
t.previewed.image = image
|
t.previewed.image = image
|
||||||
t.previewed.wireframe = wireframe
|
t.previewed.wireframe = wireframe
|
||||||
}
|
}
|
||||||
@@ -4376,6 +4394,7 @@ func (t *Terminal) Loop() error {
|
|||||||
var items []*Item
|
var items []*Item
|
||||||
var commandTemplate string
|
var commandTemplate string
|
||||||
var env []string
|
var env []string
|
||||||
|
var query string
|
||||||
initialOffset := 0
|
initialOffset := 0
|
||||||
t.previewBox.Wait(func(events *util.Events) {
|
t.previewBox.Wait(func(events *util.Events) {
|
||||||
for req, value := range *events {
|
for req, value := range *events {
|
||||||
@@ -4389,6 +4408,7 @@ func (t *Terminal) Loop() error {
|
|||||||
initialOffset = request.scrollOffset
|
initialOffset = request.scrollOffset
|
||||||
items = request.list
|
items = request.list
|
||||||
env = request.env
|
env = request.env
|
||||||
|
query = request.query
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
events.Clear()
|
events.Clear()
|
||||||
@@ -4402,8 +4422,7 @@ func (t *Terminal) Loop() error {
|
|||||||
version++
|
version++
|
||||||
// We don't display preview window if no match
|
// We don't display preview window if no match
|
||||||
if items[0] != nil {
|
if items[0] != nil {
|
||||||
_, query := t.Input()
|
command, tempFiles := t.replacePlaceholder(commandTemplate, false, query, items)
|
||||||
command, tempFiles := t.replacePlaceholder(commandTemplate, false, string(query), items)
|
|
||||||
cmd := t.executor.ExecCommand(command, true)
|
cmd := t.executor.ExecCommand(command, true)
|
||||||
cmd.Env = env
|
cmd.Env = env
|
||||||
|
|
||||||
@@ -4531,7 +4550,7 @@ func (t *Terminal) Loop() error {
|
|||||||
if len(command) > 0 && t.canPreview() {
|
if len(command) > 0 && t.canPreview() {
|
||||||
_, list := t.buildPlusList(command, false)
|
_, list := t.buildPlusList(command, false)
|
||||||
t.cancelPreview()
|
t.cancelPreview()
|
||||||
t.previewBox.Set(reqPreviewEnqueue, previewRequest{command, t.evaluateScrollOffset(), list, t.environForPreview()})
|
t.previewBox.Set(reqPreviewEnqueue, previewRequest{command, t.evaluateScrollOffset(), list, t.environForPreview(), string(t.input)})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4963,7 +4982,7 @@ func (t *Terminal) Loop() error {
|
|||||||
if valid {
|
if valid {
|
||||||
t.cancelPreview()
|
t.cancelPreview()
|
||||||
t.previewBox.Set(reqPreviewEnqueue,
|
t.previewBox.Set(reqPreviewEnqueue,
|
||||||
previewRequest{t.previewOpts.command, t.evaluateScrollOffset(), list, t.environForPreview()})
|
previewRequest{t.previewOpts.command, t.evaluateScrollOffset(), list, t.environForPreview(), string(t.input)})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Discard the preview content so that it won't accidentally appear
|
// Discard the preview content so that it won't accidentally appear
|
||||||
|
|||||||
@@ -225,7 +225,9 @@ func StripLastDelimiter(str string, delimiter Delimiter) string {
|
|||||||
locs := delimiter.regex.FindAllStringIndex(str, -1)
|
locs := delimiter.regex.FindAllStringIndex(str, -1)
|
||||||
if len(locs) > 0 {
|
if len(locs) > 0 {
|
||||||
lastLoc := locs[len(locs)-1]
|
lastLoc := locs[len(locs)-1]
|
||||||
str = str[:lastLoc[0]]
|
if lastLoc[1] == len(str) {
|
||||||
|
str = str[:lastLoc[0]]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return strings.TrimRightFunc(str, unicode.IsSpace)
|
return strings.TrimRightFunc(str, unicode.IsSpace)
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ const (
|
|||||||
|
|
||||||
const consoleDevice string = "/dev/tty"
|
const consoleDevice string = "/dev/tty"
|
||||||
|
|
||||||
var offsetRegexp = regexp.MustCompile("(.*)\x1b\\[([0-9]+);([0-9]+)R")
|
var offsetRegexp = regexp.MustCompile("(.*?)\x00?\x1b\\[([0-9]+);([0-9]+)R")
|
||||||
var offsetRegexpBegin = regexp.MustCompile("^\x1b\\[[0-9]+;[0-9]+R")
|
var offsetRegexpBegin = regexp.MustCompile("^\x1b\\[[0-9]+;[0-9]+R")
|
||||||
|
|
||||||
func (r *LightRenderer) Bell() {
|
func (r *LightRenderer) Bell() {
|
||||||
|
|||||||
@@ -827,6 +827,24 @@ class TestCore < TestInteractive
|
|||||||
tmux.until { |lines| assert(lines.any? { it.include?('jump cancelled at 3') }) }
|
tmux.until { |lines| assert(lines.any? { it.include?('jump cancelled at 3') }) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_jump_no_pointer
|
||||||
|
tmux.send_keys "seq 100 | #{FZF} --pointer= --jump-labels 12345 --bind ctrl-j:jump", :Enter
|
||||||
|
tmux.until { |lines| assert_equal 100, lines.match_count }
|
||||||
|
tmux.send_keys 'C-j'
|
||||||
|
tmux.until { |lines| assert_equal '5 5', lines[-7] }
|
||||||
|
tmux.send_keys 'C-c'
|
||||||
|
tmux.until { |lines| assert_equal ' 5', lines[-7] }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_jump_no_pointer_no_marker
|
||||||
|
tmux.send_keys "seq 100 | #{FZF} --pointer= --marker= --jump-labels 12345 --bind ctrl-j:jump", :Enter
|
||||||
|
tmux.until { |lines| assert_equal 100, lines.match_count }
|
||||||
|
tmux.send_keys 'C-j'
|
||||||
|
tmux.until { |lines| assert_equal '55', lines[-7] }
|
||||||
|
tmux.send_keys 'C-c'
|
||||||
|
tmux.until { |lines| assert_equal '5', lines[-7] }
|
||||||
|
end
|
||||||
|
|
||||||
def test_pointer
|
def test_pointer
|
||||||
tmux.send_keys "seq 10 | #{fzf("--pointer '>>'")}", :Enter
|
tmux.send_keys "seq 10 | #{fzf("--pointer '>>'")}", :Enter
|
||||||
# Assert that specified pointer is displayed
|
# Assert that specified pointer is displayed
|
||||||
@@ -1773,12 +1791,21 @@ class TestCore < TestInteractive
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_accept_nth_template
|
def test_accept_nth_regex_delimiter_strip_last
|
||||||
tmux.send_keys %(echo "foo ,bar,baz" | #{FZF} -d, --accept-nth '1st: {1}, 3rd: {3}, 2nd: {2}' --sync --bind start:accept > #{tempname}), :Enter
|
tmux.send_keys %((echo "foo:,bar:,baz"; echo "foo:,bar:,baz:,qux:,") | #{FZF} --multi --delimiter='[:,]+' --accept-nth 2.. --sync --bind 'load:select-all+accept' > #{tempname}), :Enter
|
||||||
wait do
|
wait do
|
||||||
assert_path_exists tempname
|
assert_path_exists tempname
|
||||||
# Last delimiter and the whitespaces are removed
|
# Last delimiter and the whitespaces are removed
|
||||||
assert_equal ['1st: foo, 3rd: baz, 2nd: bar'], File.readlines(tempname, chomp: true)
|
assert_equal ['bar:,baz', 'bar:,baz:,qux'], File.readlines(tempname, chomp: true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_accept_nth_template
|
||||||
|
tmux.send_keys %(echo "foo ,bar,baz" | #{FZF} -d, --accept-nth '[{n}] 1st: {1}, 3rd: {3}, 2nd: {2}' --sync --bind start:accept > #{tempname}), :Enter
|
||||||
|
wait do
|
||||||
|
assert_path_exists tempname
|
||||||
|
# Last delimiter and the whitespaces are removed
|
||||||
|
assert_equal ['[0] 1st: foo, 3rd: baz, 2nd: bar'], File.readlines(tempname, chomp: true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -544,4 +544,18 @@ class TestPreview < TestInteractive
|
|||||||
tmux.send_keys :Up
|
tmux.send_keys :Up
|
||||||
tmux.until { |lines| assert_includes lines, '> 2' }
|
tmux.until { |lines| assert_includes lines, '> 2' }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_preview_query_should_not_be_affected_by_search
|
||||||
|
tmux.send_keys "seq 1 | #{FZF} --bind 'change:transform-search(echo {q:1})' --preview 'echo [{q}/{}]'", :Enter
|
||||||
|
tmux.until { |lines| assert_equal 1, lines.match_count }
|
||||||
|
tmux.send_keys '1'
|
||||||
|
tmux.until { |lines| assert lines.any_include?('[1/1]') }
|
||||||
|
tmux.send_keys :Space
|
||||||
|
tmux.until { |lines| assert lines.any_include?('[1 /1]') }
|
||||||
|
tmux.send_keys '2'
|
||||||
|
tmux.until do |lines|
|
||||||
|
assert lines.any_include?('[1 2/1]')
|
||||||
|
assert_equal 1, lines.match_count
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ module TestShell
|
|||||||
tmux.prepare
|
tmux.prepare
|
||||||
tmux.send_keys :Escape, :c
|
tmux.send_keys :Escape, :c
|
||||||
lines = tmux.until { |lines| assert_operator lines.match_count, :>, 0 }
|
lines = tmux.until { |lines| assert_operator lines.match_count, :>, 0 }
|
||||||
expected = lines.reverse.find { |l| l.start_with?('> ') }[2..]
|
expected = lines.reverse.find { |l| l.start_with?('> ') }[2..].chomp('/')
|
||||||
tmux.send_keys :Enter
|
tmux.send_keys :Enter
|
||||||
tmux.prepare
|
tmux.prepare
|
||||||
tmux.send_keys :pwd, :Enter
|
tmux.send_keys :pwd, :Enter
|
||||||
@@ -241,7 +241,7 @@ module CompletionTest
|
|||||||
tmux.until do |lines|
|
tmux.until do |lines|
|
||||||
assert_equal 1, lines.match_count
|
assert_equal 1, lines.match_count
|
||||||
assert_includes lines, '> 55'
|
assert_includes lines, '> 55'
|
||||||
assert_includes lines, '> /tmp/fzf-test/d55'
|
assert_includes lines, '> /tmp/fzf-test/d55/'
|
||||||
end
|
end
|
||||||
tmux.send_keys :Enter
|
tmux.send_keys :Enter
|
||||||
tmux.until(true) { |lines| assert_equal 'cd /tmp/fzf-test/d55/', lines[-1] }
|
tmux.until(true) { |lines| assert_equal 'cd /tmp/fzf-test/d55/', lines[-1] }
|
||||||
|
|||||||
Reference in New Issue
Block a user