m/fzf
1
0
mirror of https://github.com/junegunn/fzf.git synced 2025-11-16 23:33:39 -05:00

Compare commits

...

23 Commits

Author SHA1 Message Date
Junegunn Choi
a0ef8987fb 0.31.0 2022-07-21 22:46:34 +09:00
Junegunn Choi
3af5b7f2ac Do not validate other options when --version is present
Close #2690
2022-07-21 22:36:52 +09:00
Junegunn Choi
7a7cfcacbe Lift unicode.IsGraphic constraint for pointer, marker, and ellipsis
Use at your own risk.

Close #2709
Close #2055
2022-07-21 22:30:01 +09:00
Junegunn Choi
52594355bf [shell] 'kill' completion will now require trigger sequence (**)
'kill **<tab>' instead of 'kill <tab>' just like any other completions.

Close #2716
Close #385
2022-07-21 22:21:11 +09:00
Junegunn Choi
0d06c28b19 Fix delimiter regex to properly support caret (^)
Fix #2861
2022-07-21 21:21:06 +09:00
Junegunn Choi
ccc4677252 [vim] fzf#exec: Shell-escape fzf binary path
Fix #2877
2022-07-20 14:29:52 +09:00
Junegunn Choi
821fc9feed Fix failing test case 2022-07-20 12:29:45 +09:00
Junegunn Choi
82b46726fc Add support for an alternative preview window layout
Close #2804
Close #2844

Related #2277
2022-07-20 12:08:54 +09:00
Jakub Jirutka
8df872a482 [zsh] Replace perl with awk (#2777)
Unlike awk, which is even defined in POSIX, perl is not pre-installed
on all *nix systems. This awk command is functionally equivalent to
the original perl command.
2022-07-20 11:53:34 +09:00
Jonathan Zacsh
c79c306adb [bash] Fix fzf-tmux to have fzf's completion (#2871) 2022-07-15 15:53:23 +09:00
Junegunn Choi
51fdaad002 [uninstall] Remove readlink to support relative symlinks of dotfiles
Close #2853
2022-07-01 16:32:32 +09:00
znley
885cd8ff04 [make] Add loongarch64 support (#2857) 2022-06-28 09:16:26 +09:00
Tanish Yadav
2707af403a [shell] Don't export PATH in ~/.fzf.{bash,zsh} (#2852)
There is no use exporting PATH when it is already exported. Moreover, it
causes things like `typeset -U path` in zsh to break if done before
sourcing "~/.fzf.zsh".
2022-06-24 16:53:51 +09:00
Junegunn Choi
2d227e5222 [man] Fix unescaped backslash in awk example
Close #2854
2022-06-23 15:45:36 +09:00
Junegunn Choi
70529878e2 Use SGR mouse mode for larger terminals
Fix #2840
2022-06-17 12:48:04 +09:00
Daniel Zhang
3b7a962dc6 [vim] Fix fzf#shellescape when shell=fish (#2828)
`shellescape()` behavior is different when `shell=fish`, so we should set `shell` before calling `shellescape()`, otherwise an unexpected result may occur (e.g. https://github.com/kevinhwang91/nvim-bqf/issues/56).

Co-authored-by: Junegunn Choi <junegunn.c@gmail.com>
2022-05-25 09:50:10 +09:00
Jan Warchoł
6dcf5c3d7d [bash] Make complex commands slightly more friendly to work with (#2784)
- extract logical parts to separate variables (e.g. $opts)
- put options in $opts in similar order
- move +/-m into $opts (at the end, so they won't be overridden)
- split pipelines into multiple lines
- remove "echo" that seems to be redundant

All this should help with readability and also result in cleaner diffs
when changes are made.
2022-04-29 19:04:16 +09:00
Junegunn Choi
b089bb5e7b Fix scrollability of the preview window in certain cases
Fix #2683

This commit fixes the cases where fzf incorrectly determines the
scrollability of the preview window when `--preview-window-wrap` is set.

Wrapping of the preview content happens during the rendering phase, so
it's currently not possible to know how many lines are actually needed
to display the content beforehand. So `preview-bottom` still may not
move to the very bottom with wrapping enabled.
2022-04-28 11:46:24 +09:00
dependabot[bot]
a91a67668e Bump github/codeql-action from 2.1.6 to 2.1.8 (#2787)
* Bump github/codeql-action from 2.1.6 to 2.1.8

Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.1.6 to 2.1.8.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](28eead2408...1ed1437484)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Delete incorrect comments

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Junegunn Choi <junegunn.c@gmail.com>
2022-04-22 22:36:56 +09:00
dependabot[bot]
220a908118 Bump ruby/setup-ruby from 1.100.0 to 1.101.0 (#2795)
* Bump ruby/setup-ruby from 1.100.0 to 1.101.0

Bumps [ruby/setup-ruby](https://github.com/ruby/setup-ruby) from 1.100.0 to 1.101.0.
- [Release notes](https://github.com/ruby/setup-ruby/releases)
- [Commits](bd94d6a504...ebaea52cb2)

---
updated-dependencies:
- dependency-name: ruby/setup-ruby
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Delete incorrect comments

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Junegunn Choi <junegunn.c@gmail.com>
2022-04-22 22:35:51 +09:00
Ajeet D'Souza
54841248e7 [shell] ALT-C: Use builtin cd to avoid conflicts (#2799) 2022-04-22 21:58:32 +09:00
Junegunn Choi
a0b42e6538 Require Go 1.17 or above 2022-04-07 20:31:19 +09:00
Jan Warchoł
3312cf525d [bash] Allow passing args to __fzf_select__ via fzf-file-widget (#2783)
This makes it easier to make customizations, for example instead of

    bind -x '"\C-o\C-i": FZF_CTRL_T_COMMAND="fasd -Rl" FZF_DEFAULT_OPTS="$FZF_DEFAULT_OPTS --tiebreak=index " fzf-file-widget'

it's enough to just

    bind -x '"\C-o\C-i": FZF_CTRL_T_COMMAND="fasd -Rl" fzf-file-widget --tiebreak=index'
2022-04-06 11:29:01 +09:00
27 changed files with 318 additions and 210 deletions

View File

@@ -33,12 +33,12 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@28eead240834b314f7def40f6fcba65d100d99b1 # v1
uses: github/codeql-action/init@1ed1437484560351c5be56cf73a48a279d116b78
with:
languages: ${{ matrix.language }}
- name: Autobuild
uses: github/codeql-action/autobuild@28eead240834b314f7def40f6fcba65d100d99b1 # v1
uses: github/codeql-action/autobuild@1ed1437484560351c5be56cf73a48a279d116b78
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@28eead240834b314f7def40f6fcba65d100d99b1 # v1
uses: github/codeql-action/analyze@1ed1437484560351c5be56cf73a48a279d116b78

View File

@@ -25,7 +25,7 @@ jobs:
go-version: 1.18
- name: Setup Ruby
uses: ruby/setup-ruby@bd94d6a504586da892a5753afdd1480096ed30df # v1.62.0
uses: ruby/setup-ruby@ebaea52cb20fea395b0904125276395e37183dac
with:
ruby-version: 3.0.0

View File

@@ -25,7 +25,7 @@ jobs:
go-version: 1.18
- name: Setup Ruby
uses: ruby/setup-ruby@bd94d6a504586da892a5753afdd1480096ed30df # v1.62.0
uses: ruby/setup-ruby@ebaea52cb20fea395b0904125276395e37183dac
with:
ruby-version: 3.0.0

View File

@@ -6,7 +6,7 @@ Build instructions
### Prerequisites
- Go 1.13 or above
- Go 1.17 or above
### Using Makefile

View File

@@ -1,6 +1,26 @@
CHANGELOG
=========
0.31.0
------
- Added support for an alternative preview window layout that is activated
when the size of the preview window is smaller than a certain threshold.
```sh
# If the width of the preview window is smaller than 50 columns,
# it will be displayed above the search window.
fzf --preview 'cat {}' --preview-window 'right,50%,border-left,<50(up,30%,border-bottom)'
# Or you can just hide it like so
fzf --preview 'cat {}' --preview-window '<50(hidden)'
```
- fzf now uses SGR mouse mode to properly support mouse on larger terminals
- You can now use characters that do not satisfy `unicode.IsGraphic` constraint
for `--marker`, `--pointer`, and `--ellipsis`. Allows Nerd Fonts and stuff.
Use at your own risk.
- Bug fixes and improvements
- Shell extension
- `kill` completion now requires trigger sequence (`**`) for consistency
0.30.0
------
- Fixed cursor flickering over the screen by hiding it during rendering

View File

@@ -35,6 +35,7 @@ BINARYARM7 := fzf-$(GOOS)_arm7
BINARYARM8 := fzf-$(GOOS)_arm8
BINARYPPC64LE := fzf-$(GOOS)_ppc64le
BINARYRISCV64 := fzf-$(GOOS)_riscv64
BINARYLOONG64 := fzf-$(GOOS)_loong64
# https://en.wikipedia.org/wiki/Uname
UNAME_M := $(shell uname -m)
@@ -62,6 +63,8 @@ else ifeq ($(UNAME_M),ppc64le)
BINARY := $(BINARYPPC64LE)
else ifeq ($(UNAME_M),riscv64)
BINARY := $(BINARYRISCV64)
else ifeq ($(UNAME_M),loongarch64)
BINARY := $(BINARYLOONG64)
else
$(error Build on $(UNAME_M) is not supported, yet.)
endif
@@ -148,6 +151,9 @@ target/$(BINARYPPC64LE): $(SOURCES)
target/$(BINARYRISCV64): $(SOURCES)
GOARCH=riscv64 $(GO) build $(BUILD_FLAGS) -o $@
target/$(BINARYLOONG64): $(SOURCES)
GOARCH=loong64 $(GO) build $(BUILD_FLAGS) -o $@
bin/fzf: target/$(BINARY) | bin
cp -f target/$(BINARY) bin/fzf

View File

@@ -382,12 +382,11 @@ cd ~/github/fzf**<TAB>
#### Process IDs
Fuzzy completion for PIDs is provided for kill command. In this case,
there is no trigger sequence; just press the tab key after the kill command.
Fuzzy completion for PIDs is provided for kill command.
```sh
# Can select multiple processes with <TAB> or <Shift-TAB> keys
kill -9 <TAB>
kill -9 **<TAB>
```
#### Host names

16
go.mod
View File

@@ -2,16 +2,20 @@ module github.com/junegunn/fzf
require (
github.com/gdamore/tcell v1.4.0
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.14
github.com/mattn/go-runewidth v0.0.13
github.com/mattn/go-shellwords v1.0.12
github.com/rivo/uniseg v0.2.0
github.com/saracen/walker v0.1.2
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c
golang.org/x/term v0.0.0-20210317153231-de623e64d2a6
golang.org/x/text v0.3.6 // indirect
golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
)
go 1.13
require (
github.com/gdamore/encoding v1.0.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/text v0.3.7 // indirect
)
go 1.17

13
go.sum
View File

@@ -20,12 +20,13 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20210317153231-de623e64d2a6 h1:EC6+IGYTjPpRfv9a2b/6Puw0W+hLtAhkV1tPsXhutqs=
golang.org/x/term v0.0.0-20210317153231-de623e64d2a6/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12 h1:QyVthZKMsyaQwBTJE04jdNN0Pp5Fn9Qga0mrgxyERQM=
golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@@ -2,7 +2,7 @@
set -u
version=0.30.0
version=0.31.0
auto_completion=
key_bindings=
update_config=2
@@ -256,7 +256,7 @@ for shell in $shells; do
# Setup fzf
# ---------
if [[ ! "\$PATH" == *$fzf_base_esc/bin* ]]; then
export PATH="\${PATH:+\${PATH}:}$fzf_base/bin"
PATH="\${PATH:+\${PATH}:}$fzf_base/bin"
fi
# Auto-completion

View File

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

View File

@@ -5,7 +5,7 @@ import (
"github.com/junegunn/fzf/src/protector"
)
var version string = "0.30"
var version string = "0.31"
var revision string = "devel"
func main() {

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 2022" "fzf 0.30.0" "fzf-tmux - open fzf in tmux split pane"
.TH fzf-tmux 1 "Jul 2022" "fzf 0.31.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 2022" "fzf 0.30.0" "fzf - a command-line fuzzy finder"
.TH fzf 1 "Jul 2022" "fzf 0.31.0" "fzf - a command-line fuzzy finder"
.SH NAME
fzf - a command-line fuzzy finder
@@ -450,7 +450,7 @@ e.g.
\fB# Press CTRL-A to select 100K items and see the sum of all the numbers.
# This won't work properly without 'f' flag due to ARG_MAX limit.
seq 100000 | fzf --multi --bind ctrl-a:select-all \\
--preview "awk '{sum+=\$1} END {print sum}' {+f}"\fR
--preview "awk '{sum+=\\$1} END {print sum}' {+f}"\fR
Note that you can escape a placeholder pattern by prepending a backslash.
@@ -470,7 +470,7 @@ e.g.
done'\fR
.RE
.TP
.BI "--preview-window=" "[POSITION][,SIZE[%]][,border-BORDER_OPT][,[no]wrap][,[no]follow][,[no]cycle][,[no]hidden][,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES][,default]"
.BI "--preview-window=" "[POSITION][,SIZE[%]][,border-BORDER_OPT][,[no]wrap][,[no]follow][,[no]cycle][,[no]hidden][,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES][,default][,<SIZE_THRESHOLD(ALTERNATIVE_LAYOUT)]"
.RS
.B POSITION: (default: right)
@@ -488,9 +488,9 @@ default until \fBtoggle-preview\fR action is triggered.
execute the command in the background.
* Long lines are truncated by default. Line wrap can be enabled with
\fB:wrap\fR flag.
\fBwrap\fR flag.
* Preview window will automatically scroll to the bottom when \fB:follow\fR
* Preview window will automatically scroll to the bottom when \fBfollow\fR
flag is set, similarly to how \fBtail -f\fR works.
.RS
@@ -502,7 +502,7 @@ e.g.
done'\fR
.RE
* Cyclic scrolling is enabled with \fB:cycle\fR flag.
* Cyclic scrolling is enabled with \fBcycle\fR flag.
* To change the style of the border of the preview window, specify one of
the options for \fB--border\fR with \fBborder-\fR prefix.
@@ -552,6 +552,15 @@ e.g.
fzf --preview 'bat --style=full --color=always {}' --preview-window '~3'\fR
.RE
* You can specify an alternative set of options that are used only when the size
of the preview window is below a certain threshold. Note that only one
alternative layout is allowed.
.RS
e.g.
\fBfzf --preview 'cat {}' --preview-window 'right,border-left,<30(up,30%,border-bottom)'\fR
.RE
.SS Scripting
.TP
.BI "-q, --query=" "STR"

View File

@@ -96,7 +96,12 @@ function! fzf#shellescape(arg, ...)
if shell =~# 'cmd.exe$'
return s:shellesc_cmd(a:arg)
endif
return s:fzf_call('shellescape', a:arg)
try
let [shell, &shell] = [&shell, shell]
return s:fzf_call('shellescape', a:arg)
finally
let [shell, &shell] = [&shell, shell]
endtry
endfunction
function! s:fzf_getcwd()
@@ -159,7 +164,7 @@ function s:get_version(bin)
if has_key(s:versions, a:bin)
return s:versions[a:bin]
end
let command = a:bin . ' --version --no-height'
let command = fzf#shellescape(a:bin) . ' --version --no-height'
let output = systemlist(command)
if v:shell_error || empty(output)
return ''

View File

@@ -260,14 +260,6 @@ _fzf_dir_completion() {
}
_fzf_complete_kill() {
local trigger=${FZF_COMPLETION_TRIGGER-'**'}
local cur="${COMP_WORDS[COMP_CWORD]}"
if [[ -z "$cur" ]]; then
COMP_WORDS[$COMP_CWORD]=$trigger
elif [[ "$cur" != *"$trigger" ]]; then
return 1
fi
_fzf_proc_completion "$@"
}
@@ -304,6 +296,10 @@ _fzf_alias_completion() {
# fzf options
complete -o default -F _fzf_opts_completion fzf
# fzf-tmux is a thin fzf wrapper that has only a few more options than fzf
# itself. As a quick improvement we take fzf's completion. Adding the few extra
# fzf-tmux specific options (like `-w WIDTH`) are left as a future patch.
complete -o default -F _fzf_opts_completion fzf-tmux
d_cmds="${FZF_COMPLETION_DIR_COMMANDS:-cd pushd rmdir}"
a_cmds="
@@ -348,9 +344,6 @@ for cmd in $d_cmds; do
__fzf_defc "$cmd" _fzf_dir_completion "-o nospace -o dirnames"
done
# Kill completion (supports empty completion trigger)
complete -F _fzf_complete_kill -o default -o bashdefault kill
unset cmd d_cmds a_cmds
_fzf_setup_completion() {
@@ -373,9 +366,10 @@ _fzf_setup_completion() {
done
}
# Environment variables / Aliases / Hosts
# Environment variables / Aliases / Hosts / Process
_fzf_setup_completion 'var' export unset
_fzf_setup_completion 'alias' unalias
_fzf_setup_completion 'host' ssh telnet
_fzf_setup_completion 'proc' kill
fi

View File

@@ -285,12 +285,6 @@ fzf-completion() {
lbuf=$LBUFFER
tail=${LBUFFER:$(( ${#LBUFFER} - ${#trigger} ))}
# Kill completion (do not require trigger sequence)
if [ "$cmd" = kill -a ${LBUFFER[-1]} = ' ' ]; then
tail=$trigger
tokens+=$trigger
lbuf="$lbuf$trigger"
fi
# Trigger sequence given
if [ ${#tokens} -gt 1 -a "$tail" = "$trigger" ]; then

View File

@@ -14,14 +14,17 @@
# Key bindings
# ------------
__fzf_select__() {
local cmd="${FZF_CTRL_T_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
local cmd opts
cmd="${FZF_CTRL_T_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
-o -type f -print \
-o -type d -print \
-o -type l -print 2> /dev/null | cut -b3-"}"
eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_CTRL_T_OPTS" $(__fzfcmd) -m "$@" | while read -r item; do
printf '%q ' "$item"
done
echo
opts="--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore --reverse $FZF_DEFAULT_OPTS $FZF_CTRL_T_OPTS -m"
eval "$cmd" |
FZF_DEFAULT_OPTS="$opts" $(__fzfcmd) "$@" |
while read -r item; do
printf '%q ' "$item" # escape special chars
done
}
if [[ $- =~ i ]]; then
@@ -32,24 +35,27 @@ __fzfcmd() {
}
fzf-file-widget() {
local selected="$(__fzf_select__)"
local selected="$(__fzf_select__ "$@")"
READLINE_LINE="${READLINE_LINE:0:$READLINE_POINT}$selected${READLINE_LINE:$READLINE_POINT}"
READLINE_POINT=$(( READLINE_POINT + ${#selected} ))
}
__fzf_cd__() {
local cmd dir
local cmd opts dir
cmd="${FZF_ALT_C_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
-o -type d -print 2> /dev/null | cut -b3-"}"
dir=$(eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_ALT_C_OPTS" $(__fzfcmd) +m) && printf 'cd -- %q' "$dir"
opts="--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore --reverse $FZF_DEFAULT_OPTS $FZF_ALT_C_OPTS +m"
dir=$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" $(__fzfcmd)) && printf 'builtin cd -- %q' "$dir"
}
__fzf_history__() {
local output
local output opts script
opts="--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS -n2..,.. --tiebreak=index --bind=ctrl-r:toggle-sort $FZF_CTRL_R_OPTS +m --read0"
script='BEGIN { getc; $/ = "\n\t"; $HISTCOUNT = $ENV{last_hist} + 1 } s/^[ *]//; print $HISTCOUNT - $. . "\t$_" if !$seen{$_}++'
output=$(
builtin fc -lnr -2147483648 |
last_hist=$(HISTTIMEFORMAT='' builtin history 1) perl -n -l0 -e 'BEGIN { getc; $/ = "\n\t"; $HISTCMD = $ENV{last_hist} + 1 } s/^[ *]//; print $HISTCMD - $. . "\t$_" if !$seen{$_}++' |
FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} $FZF_DEFAULT_OPTS -n2..,.. --tiebreak=index --bind=ctrl-r:toggle-sort,ctrl-z:ignore $FZF_CTRL_R_OPTS +m --read0" $(__fzfcmd) --query "$READLINE_LINE"
last_hist=$(HISTTIMEFORMAT='' builtin history 1) perl -n -l0 -e "$script" |
FZF_DEFAULT_OPTS="$opts" $(__fzfcmd) --query "$READLINE_LINE"
) || return
READLINE_LINE=${output#*$'\t'}
if [[ -z "$READLINE_POINT" ]]; then

View File

@@ -87,7 +87,7 @@ function fzf_key_bindings
eval "$FZF_ALT_C_COMMAND | "(__fzfcmd)' +m --query "'$fzf_query'"' | read -l result
if [ -n "$result" ]
cd -- $result
builtin cd -- $result
# Remove last token from commandline.
commandline -t ""

View File

@@ -81,7 +81,7 @@ fzf-cd-widget() {
return 0
fi
zle push-line # Clear buffer. Auto-restored on next prompt.
BUFFER="cd -- ${(q)dir}"
BUFFER="builtin cd -- ${(q)dir}"
zle accept-line
local ret=$?
unset dir # ensure this doesn't end up appearing in prompt expansion
@@ -97,7 +97,7 @@ bindkey -M viins '\ec' fzf-cd-widget
fzf-history-widget() {
local selected num
setopt localoptions noglobsubst noposixbuiltins pipefail no_aliases 2> /dev/null
selected=( $(fc -rl 1 | perl -ne 'print if !$seen{(/^\s*[0-9]+\**\s+(.*)/, $1)}++' |
selected=( $(fc -rl 1 | awk '{ cmd=$0; sub(/^\s*[0-9]+\**\s+/, "", cmd); if (!seen[cmd]++) print $0 }' |
FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} $FZF_DEFAULT_OPTS -n2..,.. --tiebreak=index --bind=ctrl-r:toggle-sort,ctrl-z:ignore $FZF_CTRL_R_OPTS --query=${(qqq)LBUFFER} +m" $(__fzfcmd)) )
local ret=$?
if [ -n "$selected" ]; then

View File

@@ -89,7 +89,7 @@ const usage = `usage: fzf [options]
[,[no]wrap][,[no]cycle][,[no]follow][,[no]hidden]
[,border-BORDER_OPT]
[,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES]
[,default]
[,default][,<SIZE_THRESHOLD(ALTERNATIVE_LAYOUT)]
Scripting
-q, --query=STR Start the finder with the given query
@@ -175,10 +175,14 @@ type previewOpts struct {
follow bool
border tui.BorderShape
headerLines int
threshold int
alternative *previewOpts
}
func (a previewOpts) sameLayout(b previewOpts) bool {
return a.size == b.size && a.position == b.position && a.border == b.border && a.hidden == b.hidden
return a.size == b.size && a.position == b.position && a.border == b.border && a.hidden == b.hidden && a.threshold == b.threshold &&
(a.alternative != nil && b.alternative != nil && a.alternative.sameLayout(*b.alternative) ||
a.alternative == nil && b.alternative == nil)
}
func (a previewOpts) sameContentLayout(b previewOpts) bool {
@@ -247,7 +251,7 @@ type Options struct {
}
func defaultPreviewOpts(command string) previewOpts {
return previewOpts{command, posRight, sizeSpec{50, true}, "", false, false, false, false, tui.BorderRounded, 0}
return previewOpts{command, posRight, sizeSpec{50, true}, "", false, false, false, false, tui.BorderRounded, 0, 0, nil}
}
func defaultOptions() *Options {
@@ -1169,12 +1173,19 @@ func parseInfoStyle(str string) infoStyle {
}
func parsePreviewWindow(opts *previewOpts, input string) {
delimRegex := regexp.MustCompile("[:,]") // : for backward compatibility
tokenRegex := regexp.MustCompile(`[:,]*(<([1-9][0-9]*)\(([^)<]+)\)|[^,:]+)`)
sizeRegex := regexp.MustCompile("^[0-9]+%?$")
offsetRegex := regexp.MustCompile(`^(\+{-?[0-9]+})?([+-][0-9]+)*(-?/[1-9][0-9]*)?$`)
headerRegex := regexp.MustCompile("^~(0|[1-9][0-9]*)$")
tokens := delimRegex.Split(input, -1)
for _, token := range tokens {
tokens := tokenRegex.FindAllStringSubmatch(input, -1)
var alternative string
for _, match := range tokens {
if len(match[2]) > 0 {
opts.threshold = atoi(match[2])
alternative = match[3]
continue
}
token := match[1]
switch token {
case "":
case "default":
@@ -1233,6 +1244,13 @@ func parsePreviewWindow(opts *previewOpts, input string) {
}
}
}
if len(alternative) > 0 {
alternativeOpts := *opts
opts.alternative = &alternativeOpts
opts.alternative.hidden = false
opts.alternative.alternative = nil
parsePreviewWindow(opts.alternative, alternative)
}
}
func parseMargin(opt string, margin string) [4]sizeSpec {
@@ -1289,7 +1307,6 @@ func parseOptions(opts *Options, allArgs []string) {
validateJumpLabels := false
validatePointer := false
validateMarker := false
validateEllipsis := false
for i := 0; i < len(allArgs); i++ {
arg := allArgs[i]
switch arg {
@@ -1477,7 +1494,6 @@ func parseOptions(opts *Options, allArgs []string) {
opts.HeaderFirst = false
case "--ellipsis":
opts.Ellipsis = nextString(allArgs, &i, "ellipsis string required")
validateEllipsis = true
case "--preview":
opts.Preview.command = nextString(allArgs, &i, "preview command required")
case "--no-preview":
@@ -1577,7 +1593,6 @@ func parseOptions(opts *Options, allArgs []string) {
opts.HeaderLines = atoi(value)
} else if match, value := optString(arg, "--ellipsis="); match {
opts.Ellipsis = value
validateEllipsis = true
} else if match, value := optString(arg, "--preview="); match {
opts.Preview.command = value
} else if match, value := optString(arg, "--preview-window="); match {
@@ -1640,25 +1655,12 @@ func parseOptions(opts *Options, allArgs []string) {
errorExit(err.Error())
}
}
if validateEllipsis {
for _, r := range opts.Ellipsis {
if !unicode.IsGraphic(r) {
errorExit("invalid character in ellipsis")
}
}
}
}
func validateSign(sign string, signOptName string) error {
if sign == "" {
return fmt.Errorf("%v cannot be empty", signOptName)
}
for _, r := range sign {
if !unicode.IsGraphic(r) {
return fmt.Errorf("invalid character in %v", signOptName)
}
}
if runewidth.StringWidth(sign) > 2 {
return fmt.Errorf("%v display width should be up to 2", signOptName)
}
@@ -1744,6 +1746,13 @@ func postProcessOptions(opts *Options) {
func ParseOptions() *Options {
opts := defaultOptions()
for _, arg := range os.Args[1:] {
if arg == "--version" {
opts.Version = true
return opts
}
}
// Options from Env var
words, _ := shellwords.Parse(os.Getenv("FZF_DEFAULT_OPTS"))
if len(words) > 0 {

View File

@@ -65,6 +65,19 @@ func TestDelimiterRegexRegex(t *testing.T) {
}
}
func TestDelimiterRegexRegexCaret(t *testing.T) {
delim := delimiterRegexp(`(^\s*|\s+)`)
tokens := Tokenize("foo bar baz", delim)
if delim.str != nil ||
len(tokens) != 4 ||
tokens[0].text.ToString() != "" ||
tokens[1].text.ToString() != "foo " ||
tokens[2].text.ToString() != "bar " ||
tokens[3].text.ToString() != "baz" {
t.Errorf("%s %d", tokens, len(tokens))
}
}
func TestSplitNth(t *testing.T) {
{
ranges := splitNth("..")
@@ -440,8 +453,6 @@ func TestValidateSign(t *testing.T) {
{"😀", true},
{"", false},
{">>>", false},
{"\n", false},
{"\t", false},
}
for _, testCase := range testCases {

View File

@@ -819,12 +819,15 @@ func (t *Terminal) resizeWindows() {
}
if t.window != nil {
t.window.Close()
t.window = nil
}
if t.pborder != nil {
t.pborder.Close()
t.pborder = nil
}
if t.pwindow != nil {
t.pwindow.Close()
t.pwindow = nil
}
// Reset preview version so that full redraw occurs
t.previewed.version = 0
@@ -869,76 +872,97 @@ func (t *Terminal) resizeWindows() {
width = screenWidth - marginInt[1] - marginInt[3]
height = screenHeight - marginInt[0] - marginInt[2]
// Set up preview window
noBorder := tui.MakeBorderStyle(tui.BorderNone, t.unicode)
if previewVisible {
createPreviewWindow := func(y int, x int, w int, h int) {
pwidth := w
pheight := h
var previewBorder tui.BorderStyle
if t.previewOpts.border == tui.BorderNone {
previewBorder = tui.MakeTransparentBorder()
} else {
previewBorder = tui.MakeBorderStyle(t.previewOpts.border, t.unicode)
var resizePreviewWindows func(previewOpts previewOpts)
resizePreviewWindows = func(previewOpts previewOpts) {
hasThreshold := previewOpts.threshold > 0 && previewOpts.alternative != nil
createPreviewWindow := func(y int, x int, w int, h int) {
pwidth := w
pheight := h
var previewBorder tui.BorderStyle
if previewOpts.border == tui.BorderNone {
previewBorder = tui.MakeTransparentBorder()
} else {
previewBorder = tui.MakeBorderStyle(previewOpts.border, t.unicode)
}
t.pborder = t.tui.NewWindow(y, x, w, h, true, previewBorder)
switch previewOpts.border {
case tui.BorderSharp, tui.BorderRounded:
pwidth -= 4
pheight -= 2
x += 2
y += 1
case tui.BorderLeft:
pwidth -= 2
x += 2
case tui.BorderRight:
pwidth -= 2
case tui.BorderTop:
pheight -= 1
y += 1
case tui.BorderBottom:
pheight -= 1
case tui.BorderHorizontal:
pheight -= 2
y += 1
case tui.BorderVertical:
pwidth -= 4
x += 2
}
t.pwindow = t.tui.NewWindow(y, x, pwidth, pheight, true, noBorder)
}
t.pborder = t.tui.NewWindow(y, x, w, h, true, previewBorder)
switch t.previewOpts.border {
case tui.BorderSharp, tui.BorderRounded:
pwidth -= 4
pheight -= 2
x += 2
y += 1
case tui.BorderLeft:
pwidth -= 2
x += 2
case tui.BorderRight:
pwidth -= 2
case tui.BorderTop:
pheight -= 1
y += 1
case tui.BorderBottom:
pheight -= 1
case tui.BorderHorizontal:
pheight -= 2
y += 1
case tui.BorderVertical:
pwidth -= 4
x += 2
verticalPad := 2
minPreviewHeight := 3
switch previewOpts.border {
case tui.BorderNone, tui.BorderVertical, tui.BorderLeft, tui.BorderRight:
verticalPad = 0
minPreviewHeight = 1
case tui.BorderTop, tui.BorderBottom:
verticalPad = 1
minPreviewHeight = 2
}
switch previewOpts.position {
case posUp, posDown:
pheight := calculateSize(height, previewOpts.size, minHeight, minPreviewHeight, verticalPad)
if hasThreshold && pheight < previewOpts.threshold {
if !previewOpts.alternative.hidden {
resizePreviewWindows(*previewOpts.alternative)
}
return
}
if previewOpts.position == posUp {
t.window = t.tui.NewWindow(
marginInt[0]+pheight, marginInt[3], width, height-pheight, false, noBorder)
createPreviewWindow(marginInt[0], marginInt[3], width, pheight)
} else {
t.window = t.tui.NewWindow(
marginInt[0], marginInt[3], width, height-pheight, false, noBorder)
createPreviewWindow(marginInt[0]+height-pheight, marginInt[3], width, pheight)
}
case posLeft, posRight:
pwidth := calculateSize(width, previewOpts.size, minWidth, 5, 4)
if hasThreshold && pwidth < previewOpts.threshold {
if !previewOpts.alternative.hidden {
resizePreviewWindows(*previewOpts.alternative)
}
return
}
if previewOpts.position == posLeft {
t.window = t.tui.NewWindow(
marginInt[0], marginInt[3]+pwidth, width-pwidth, height, false, noBorder)
createPreviewWindow(marginInt[0], marginInt[3], pwidth, height)
} else {
t.window = t.tui.NewWindow(
marginInt[0], marginInt[3], width-pwidth, height, false, noBorder)
createPreviewWindow(marginInt[0], marginInt[3]+width-pwidth, pwidth, height)
}
}
t.pwindow = t.tui.NewWindow(y, x, pwidth, pheight, true, noBorder)
}
verticalPad := 2
minPreviewHeight := 3
switch t.previewOpts.border {
case tui.BorderNone, tui.BorderVertical, tui.BorderLeft, tui.BorderRight:
verticalPad = 0
minPreviewHeight = 1
case tui.BorderTop, tui.BorderBottom:
verticalPad = 1
minPreviewHeight = 2
}
switch t.previewOpts.position {
case posUp:
pheight := calculateSize(height, t.previewOpts.size, minHeight, minPreviewHeight, verticalPad)
t.window = t.tui.NewWindow(
marginInt[0]+pheight, marginInt[3], width, height-pheight, false, noBorder)
createPreviewWindow(marginInt[0], marginInt[3], width, pheight)
case posDown:
pheight := calculateSize(height, t.previewOpts.size, minHeight, minPreviewHeight, verticalPad)
t.window = t.tui.NewWindow(
marginInt[0], marginInt[3], width, height-pheight, false, noBorder)
createPreviewWindow(marginInt[0]+height-pheight, marginInt[3], width, pheight)
case posLeft:
pwidth := calculateSize(width, t.previewOpts.size, minWidth, 5, 4)
t.window = t.tui.NewWindow(
marginInt[0], marginInt[3]+pwidth, width-pwidth, height, false, noBorder)
createPreviewWindow(marginInt[0], marginInt[3], pwidth, height)
case posRight:
pwidth := calculateSize(width, t.previewOpts.size, minWidth, 5, 4)
t.window = t.tui.NewWindow(
marginInt[0], marginInt[3], width-pwidth, height, false, noBorder)
createPreviewWindow(marginInt[0], marginInt[3]+width-pwidth, pwidth, height)
}
} else {
resizePreviewWindows(t.previewOpts)
}
if t.window == nil {
t.window = t.tui.NewWindow(
marginInt[0],
marginInt[3],
@@ -1417,6 +1441,7 @@ func (t *Terminal) renderPreviewText(height int, lines []string, lineNo int, unc
line = strings.TrimSuffix(line, "\n")
if lineNo >= height || t.pwindow.Y() == height-1 && t.pwindow.X() > 0 {
t.previewed.filled = true
t.previewer.scrollable = true
break
} else if lineNo >= 0 {
var fillRet tui.FillReturn

View File

@@ -156,14 +156,14 @@ func Tokenize(text string, delimiter Delimiter) []Token {
// FIXME performance
var tokens []string
if delimiter.regex != nil {
for len(text) > 0 {
loc := delimiter.regex.FindStringIndex(text)
if len(loc) < 2 {
loc = []int{0, len(text)}
}
last := util.Max(loc[1], 1)
tokens = append(tokens, text[:last])
text = text[last:]
locs := delimiter.regex.FindAllStringIndex(text, -1)
begin := 0
for _, loc := range locs {
tokens = append(tokens, text[begin:loc[1]])
begin = loc[1]
}
if begin < len(text) {
tokens = append(tokens, text[begin:])
}
}
return withPrefixLengths(tokens, 0)

View File

@@ -176,6 +176,7 @@ func (r *LightRenderer) Init() {
if r.mouse {
r.csi("?1000h")
r.csi("?1006h")
}
r.csi(fmt.Sprintf("%dA", r.MaxY()-1))
r.csi("G")
@@ -378,7 +379,7 @@ func (r *LightRenderer) escSequence(sz *int) Event {
return Event{Home, 0, nil}
case 'F':
return Event{End, 0, nil}
case 'M':
case '<':
return r.mouseSequence(sz)
case 'P':
return Event{F1, 0, nil}
@@ -519,47 +520,73 @@ func (r *LightRenderer) escSequence(sz *int) Event {
return Event{Invalid, 0, nil}
}
// https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
func (r *LightRenderer) mouseSequence(sz *int) Event {
if len(r.buffer) < 6 || !r.mouse {
// "\e[<0;0;0M"
if len(r.buffer) < 9 || !r.mouse {
return Event{Invalid, 0, nil}
}
*sz = 6
switch r.buffer[3] {
case 32, 34, 36, 40, 48, // mouse-down / shift / cmd / ctrl
35, 39, 43, 51: // mouse-up / shift / cmd / ctrl
mod := r.buffer[3] >= 36
left := r.buffer[3] == 32
down := r.buffer[3]%2 == 0
x := int(r.buffer[4] - 33)
y := int(r.buffer[5]-33) - r.yoffset
double := false
if down {
now := time.Now()
if !left { // Right double click is not allowed
r.clickY = []int{}
} else if now.Sub(r.prevDownTime) < doubleClickDuration {
r.clickY = append(r.clickY, y)
} else {
r.clickY = []int{y}
}
r.prevDownTime = now
} else {
if len(r.clickY) > 1 && r.clickY[0] == r.clickY[1] &&
time.Since(r.prevDownTime) < doubleClickDuration {
double = true
}
}
return Event{Mouse, 0, &MouseEvent{y, x, 0, left, down, double, mod}}
case 96, 100, 104, 112, // scroll-up / shift / cmd / ctrl
97, 101, 105, 113: // scroll-down / shift / cmd / ctrl
mod := r.buffer[3] >= 100
s := 1 - int(r.buffer[3]%2)*2
x := int(r.buffer[4] - 33)
y := int(r.buffer[5]-33) - r.yoffset
return Event{Mouse, 0, &MouseEvent{y, x, s, false, false, false, mod}}
rest := r.buffer[*sz:]
end := bytes.IndexAny(rest, "mM")
if end == -1 {
return Event{Invalid, 0, nil}
}
return Event{Invalid, 0, nil}
elems := strings.SplitN(string(rest[:end]), ";", 3)
if len(elems) != 3 {
return Event{Invalid, 0, nil}
}
t := atoi(elems[0], -1)
x := atoi(elems[1], -1) - 1
y := atoi(elems[2], -1) - 1
if t < 0 || x < 0 || y < 0 {
return Event{Invalid, 0, nil}
}
*sz += end + 1
down := rest[end] == 'M'
scroll := 0
if t >= 64 {
t -= 64
if t&0b1 == 1 {
scroll = -1
} else {
scroll = 1
}
}
// middle := t & 0b1
left := t&0b11 == 0
// shift := t & 0b100
// ctrl := t & 0b1000
mod := t&0b1100 > 0
if scroll != 0 {
return Event{Mouse, 0, &MouseEvent{y, x, scroll, false, false, false, mod}}
}
double := false
if down {
now := time.Now()
if !left { // Right double click is not allowed
r.clickY = []int{}
} else if now.Sub(r.prevDownTime) < doubleClickDuration {
r.clickY = append(r.clickY, y)
} else {
r.clickY = []int{y}
}
r.prevDownTime = now
} else {
if len(r.clickY) > 1 && r.clickY[0] == r.clickY[1] &&
time.Since(r.prevDownTime) < doubleClickDuration {
double = true
}
}
return Event{Mouse, 0, &MouseEvent{y, x, 0, left, down, double, mod}}
}
func (r *LightRenderer) smcup() {
@@ -597,6 +624,7 @@ func (r *LightRenderer) Resume(clear bool, sigcont bool) {
// It's highly likely that the offset we obtained at the beginning is
// no longer correct, so we simply disable mouse input.
r.csi("?1000l")
r.csi("?1006l")
r.mouse = false
}
}
@@ -636,6 +664,7 @@ func (r *LightRenderer) Close() {
}
if r.mouse {
r.csi("?1000l")
r.csi("?1006l")
}
r.flush()
r.closePlatform()

View File

@@ -2478,7 +2478,7 @@ module CompletionTest
pid = lines[-1]&.split&.last
tmux.prepare
tmux.send_keys 'C-L'
tmux.send_keys 'kill ', :Tab
tmux.send_keys 'kill **', :Tab
tmux.until { |lines| assert_operator lines.match_count, :>, 0 }
tmux.send_keys 'sleep12345'
tmux.until { |lines| assert lines.any_include?('sleep 12345') }

View File

@@ -51,13 +51,8 @@ remove() {
}
remove_line() {
src=$(readlink "$1")
if [ $? -eq 0 ]; then
echo "Remove from $1 ($src):"
else
src=$1
echo "Remove from $1:"
fi
src=$1
echo "Remove from $1:"
shift
line_no=1
@@ -75,8 +70,9 @@ remove_line() {
echo " - Line #$line_no: $content"
[ "$content" = "$1" ] || ask " - Remove?"
if [ $? -eq 0 ]; then
awk -v n=$line_no 'NR == n {next} {print}' "$src" > "$src.bak" &&
mv "$src.bak" "$src" || break
temp=$(mktemp)
awk -v n=$line_no 'NR == n {next} {print}' "$src" > "$temp" &&
cat "$temp" > "$src" && rm -f "$temp" || break
echo " - Removed"
else
echo " - Skipped"