m/fzf
1
0
mirror of https://github.com/junegunn/fzf.git synced 2025-11-18 08:13:40 -05:00

Compare commits

...

44 Commits

Author SHA1 Message Date
junegunn
b51bc6b50e Deploying to master from @ junegunn/fzf@febaadbee5 🚀 2025-10-05 00:02:16 +00:00
Junegunn Choi
febaadbee5 Fix stray character artifacts when scrollbar is hidden
Fix #4537
2025-10-04 21:56:56 +09:00
dependabot[bot]
0e67c5aa7a Bump actions/setup-go from 5 to 6 (#4513)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5 to 6.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-29 21:20:26 +09:00
mickychang9
760d1b7c58 refactor: use maps.Copy and maps.Clone (#4518)
Signed-off-by: mickychang9 <mickychang9@outlook.com>
2025-09-29 18:11:19 +09:00
Junegunn Choi
9bdacc8df2 Update --help output to avoid confusion 2025-09-28 23:56:51 +09:00
junegunn
8e936ecfa7 Deploying to master from @ junegunn/fzf@db2e95b1f2 🚀 2025-09-28 00:02:15 +00:00
Junegunn Choi
db2e95b1f2 Remove unused field 2025-09-27 22:34:12 +09:00
alex-huff
687074e772 merger: fix chunk cache never getting cleared (#4531)
Commit 7fc13c5 indroduced less aggressive cache invalidation for the
chunk cache but saved the new revision before comparing it with the old
one, and so the cache was never considered invalid.

Fixes #4529
2025-09-27 09:01:13 +09:00
Junegunn Choi
3401c2e0c7 Remove alignment in .tool-versions for RuboCop 2025-09-24 22:41:54 +09:00
Junegunn Choi
e8cb315419 Apply shfmt to bash script files (make fmt) 2025-09-24 22:41:54 +09:00
Junegunn Choi
f0c4ee4047 make lint: Perform bash script linting 2025-09-24 22:41:54 +09:00
xieyonn
de0df2422a feat: add make fmt for *.sh *.bash
1. add .editorconfig file, add rules for .sh .bash files.
2. add make fmt target, use:
    - gofmt *.go.
    - shfmt *.sh *.bash, shell/completion.bash, shell/key-bindings.bash
        need a left indent due to an outermost if block.
3. add shfmt check for bash scripts in make lint target.
4. install shfmt in actions.
2025-09-24 22:41:54 +09:00
Massimo Mund
148b0a94cd tui/light: consume full 7-byte CSI sequences to prevent leftover printing (#4528)
- Fix parsing in escSequence so 7-byte CSI forms (e.g. ESC [ 5 ; 10 ~) set *sz = 7 and the entire sequence is consumed.
- Prevents trailing bytes (like 10~) from remaining in the input buffer and being printed as stray characters.
2025-09-23 23:33:41 +09:00
Junegunn Choi
ca294109c3 Apply RuboCop suggestions 2025-09-22 21:23:54 +09:00
Junegunn Choi
9cad2686e9 Update .tool-versions 2025-09-21 21:19:49 +09:00
junegunn
9a45172232 Deploying to master from @ junegunn/fzf@2a92c7d792 🚀 2025-09-21 00:02:16 +00:00
Junegunn Choi
2a92c7d792 Adjust base16 (16) theme (#4501)
Motivation:

`--color base16` can be a better default than `dark` or `light`, since it uses
the colors defined by the current theme. This usually blends in more
naturally and works well in both light and dark modes.

However, some elements were previously hard-coded with white or black
foreground colors, which can cause rendering issues in certain terminal
themes.
2025-09-17 19:38:49 +09:00
Junegunn Choi
f5975cf870 Add --gutter to --help and man page 2025-09-16 21:30:01 +09:00
Junegunn Choi
a67aa85820 Style change: thinner gutter column (#4521) 2025-09-16 21:22:56 +09:00
dependabot[bot]
c5cabe1691 Bump github.com/charlievieth/fastwalk from 1.0.13 to 1.0.14 (#4522)
Bumps [github.com/charlievieth/fastwalk](https://github.com/charlievieth/fastwalk) from 1.0.13 to 1.0.14.
- [Release notes](https://github.com/charlievieth/fastwalk/releases)
- [Commits](https://github.com/charlievieth/fastwalk/compare/v1.0.13...v1.0.14)

---
updated-dependencies:
- dependency-name: github.com/charlievieth/fastwalk
  dependency-version: 1.0.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-16 01:19:14 +09:00
Junegunn Choi
cbed41cd82 No emoji 2025-09-14 21:08:48 +09:00
Junegunn Choi
6684771cbf Fix CTRL-Z for tcell renderer by using the official API
See https://github.com/gdamore/tcell/pull/431
2025-09-14 11:41:12 +09:00
Junegunn Choi
f5f894ea47 Fix rendering of multiple OSC 8 links in a single line
Fix #4517
2025-09-14 11:26:47 +09:00
junegunn
a0a334fc8d Deploying to master from @ junegunn/fzf@ae12e94b1f 🚀 2025-09-07 00:02:03 +00:00
Massimo Mund
ae12e94b1f Add sub-word actions (#3997)
Add `backward-subword`, `forward-subword`, `kill-subword`, `backward-kill-subword` actions.
2025-09-05 19:38:22 +09:00
Massimo Mund
9ed971cc90 Add keybindings for CTRL, ALT, SHIFT + UP, DOWN, RIGHT, LEFT, HOME, END, BACKSPACE, DELETE & more (#3996)
* Added tests for `LightRenderer`

* Added common SHIFT, ALT and ALT+SHIFT key sequences

* Added common CTRL key sequences

* Added common CTRL+ALT, CTRL+SHIFT, CTRL+ALT+SHIFT key sequences

* Added proper xterm META modifier handling

according to defc6dd568/input.c (L357-L375)

* Fix `ctrl-backspace` and `ctrl-alt-backspace`

* Fix broken tcell tests on windows by swallowing Resize events

* Added tests for  FullscreenRenderer

* Removed own fork of tcell and updated tcell to 2.9.0

tcell 2.9.0 is needed for `Ctrl-Alt-*` and `Ctrl-Alt-Shift-*` shortcuts in Windows

* Replace conditional checks with switch statements to improve readability

* Replace long conditionals with constant slices to improve readability

* Bind `ctrl-bspace` (`ctrl-h`) to `backward-delete-char` by default

Since we now distinguish between Backspace and Ctrl-Backspace, Ctrl-Backspace should trigger the same action as Backspace by default. In that way nothing changes for the user but you can bind other actions to Ctrl-Backspace when desired.
2025-09-05 14:56:51 +09:00
Junegunn Choi
129cb23078 Require Go 1.23 2025-09-05 14:45:17 +09:00
dependabot[bot]
d22812e917 Bump github.com/gdamore/tcell/v2 from 2.8.1 to 2.9.0 (#4503)
Bumps [github.com/gdamore/tcell/v2](https://github.com/gdamore/tcell) from 2.8.1 to 2.9.0.
- [Release notes](https://github.com/gdamore/tcell/releases)
- [Changelog](https://github.com/gdamore/tcell/blob/main/CHANGESv2.md)
- [Commits](https://github.com/gdamore/tcell/compare/v2.8.1...v2.9.0)

---
updated-dependencies:
- dependency-name: github.com/gdamore/tcell/v2
  dependency-version: 2.9.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-05 14:39:37 +09:00
Charlie Vieth
10d712824a mod: update charlievieth/fastwalk to v1.0.13 and min Go version to 1.21 (#4508)
This commit updates github.com/charlievieth/fastwalk to v1.0.13 which
addresses fastwalk issue #61. It also updates the minimum supported Go
version to 1.21 (up from 1.20) since that is now the minimum version
supported by fastwalk.
2025-09-04 22:04:52 +09:00
Junegunn Choi
de4059c8fa Update README 2025-09-03 08:18:57 +09:00
Junegunn Choi
416aff86e9 0.65.2 2025-08-31 22:18:44 +09:00
zhedazijingang
59dc7f178f refactor: replace []byte(fmt.Sprintf) with fmt.Appendf (#4507)
Signed-off-by: zhedazijingang <unwrap_or_else@outlook.com>
2025-08-31 22:01:35 +09:00
junegunn
a3c9f8bfee Deploying to master from @ junegunn/fzf@5546c65491 🚀 2025-08-31 00:02:03 +00:00
Junegunn Choi
5546c65491 Fix rendering of items with tabs when using a non-default ellipsis
Fix #4505
2025-08-27 23:31:31 +09:00
junegunn
f2179f015c Deploying to master from @ junegunn/fzf@9a53d84b9c 🚀 2025-08-24 00:02:30 +00:00
Junegunn Choi
9a53d84b9c Update README.md 2025-08-22 22:51:04 +09:00
Junegunn Choi
0a8ff7899c Do not unset FZF_DEFAULT_* variables when using winpty
Fix #4497
Fix #4400
2025-08-22 19:24:01 +09:00
xty
f9d7877d8b [bash 3] Fix CTRL-T and ALT-C to preserve the last yank (#4496) 2025-08-19 23:31:02 +09:00
Peter Sideris
9fe9976591 Fix a typo in man page (#4495) 2025-08-19 23:25:57 +09:00
Chayoung You
de1824f71d [install] Support old uname in macOS (#4492) 2025-08-17 11:54:32 +09:00
dependabot[bot]
19a9296c47 Bump actions/checkout from 4 to 5 (#4485)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-15 21:17:29 +09:00
Ioannis Pinakoulakis
49967f3d45 Use fixed-length array when possible (#4488) 2025-08-15 21:16:41 +09:00
longhutianjie
978b6254c7 chore: remove redundant word in comment (#4490)
Signed-off-by: longhutianjie <keplrnewton@icloud.com>
2025-08-14 13:26:29 +09:00
Junegunn Choi
1afd143810 Fix incorrect truncation of --info-command with --info=inline-right
Fix #4479
2025-08-08 18:51:24 +09:00
48 changed files with 2081 additions and 663 deletions

20
.editorconfig Normal file
View File

@@ -0,0 +1,20 @@
root = true
[*.{sh,bash}]
indent_style = space
indent_size = 2
simplify = true
binary_next_line = false
switch_case_indent = true
space_redirects = true
function_next_line = false
# also bash scripts.
[{install,uninstall,bin/fzf-preview.sh,bin/fzf-tmux}]
indent_style = space
indent_size = 2
simplify = true
binary_next_line = false
switch_case_indent = true
space_redirects = true
function_next_line = false

View File

@@ -27,7 +27,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0

View File

@@ -9,6 +9,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: 'Dependency Review'
uses: actions/dependency-review-action@v4

View File

@@ -18,22 +18,22 @@ jobs:
build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: "1.20"
go-version: "1.23"
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.4.1
ruby-version: 3.4.6
- name: Install packages
run: sudo apt-get install --yes zsh fish tmux
run: sudo apt-get install --yes zsh fish tmux shfmt
- name: Install Ruby gems
run: bundle install

View File

@@ -15,14 +15,14 @@ jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: "1.20"
go-version: "1.23"
- name: Setup Ruby
uses: ruby/setup-ruby@v1
@@ -30,7 +30,7 @@ jobs:
ruby-version: 3.0.0
- name: Install packages
run: HOMEBREW_NO_INSTALL_CLEANUP=1 brew install fish zsh tmux
run: HOMEBREW_NO_INSTALL_CLEANUP=1 brew install fish zsh tmux shfmt
- name: Install Ruby gems
run: gem install --no-document minitest:5.14.2 rubocop:1.0.0 rubocop-minitest:0.10.1 rubocop-performance:1.8.1

View File

@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout 🛎️
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Generate Sponsors 💖
uses: JamesIves/github-sponsors-readme-action@v1

View File

@@ -6,5 +6,5 @@ jobs:
name: Spell Check with Typos
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: crate-ci/typos@v1.29.4

View File

@@ -1,2 +1,3 @@
golang 1.20.14
ruby 3.4.1
golang 1.23
ruby 3.4
shfmt 3.12

View File

@@ -6,7 +6,7 @@ Build instructions
### Prerequisites
- Go 1.20 or above
- Go 1.23 or above
### Using Makefile
@@ -41,6 +41,20 @@ make release
> --profile-block /tmp/block.pprof --profile-mutex /tmp/mutex.pprof
> ```
Running tests
-------------
```sh
# Run go unit tests
make test
# Run integration tests (requires to be on tmux)
make itest
# Run a single test case
ruby test/runner.rb --name test_something
```
Third-party libraries used
--------------------------

View File

@@ -1,6 +1,44 @@
CHANGELOG
=========
0.66.0
------
- Style changes
- Updated `--color base16` (alias: `16`) theme so that it works better with both dark and light themes.
- Narrowed the gutter column by using the left-half block character (`▌`).
- Removed background colors from markers.
- Added `--gutter CHAR` option for customizing the gutter column. Some examples using [box-drawing characters](https://en.wikipedia.org/wiki/Box-drawing_characters):
```sh
# Right-aligned gutter
fzf --gutter '▐'
# Even thinner gutter
fzf --gutter '▎'
# Checker
fzf --gutter '▚'
# Dotted
fzf --gutter '▖'
# Full-width
fzf --gutter '█'
# No gutter
fzf --gutter ' '
```
0.65.2
------
- Bug fixes and improvements
- Fix incorrect truncation of `--info-command` with `--info=inline-right` (#4479)
- [install] Support old uname in macOS (#4492)
- [bash 3] Fix `CTRL-T` and `ALT-C` to preserve the last yank (#4496)
- Do not unset `FZF_DEFAULT_*` variables when using winpty (#4497) (#4400)
- Fix rendering of items with tabs when using a non-default ellipsis (#4505)
- **This is the final release to support Windows 7.**
- Future versions will be built with the latest Go toolchain, which has dropped support for Windows 7.
0.65.1
------
- Fixed incorrect `$FZF_CLICK_HEADER_WORD` and `$FZF_CLICK_FOOTER_WORD` when the header or footer contains ANSI escape sequences and tab characters.

View File

@@ -5,6 +5,15 @@ MAKEFILE := $(realpath $(lastword $(MAKEFILE_LIST)))
ROOT_DIR := $(shell dirname $(MAKEFILE))
SOURCES := $(wildcard *.go src/*.go src/*/*.go shell/*sh man/man1/*.1) $(MAKEFILE)
BASH_SCRIPTS := $(ROOT_DIR)/bin/fzf-preview.sh \
$(ROOT_DIR)/bin/fzf-tmux \
$(ROOT_DIR)/install \
$(ROOT_DIR)/uninstall \
$(ROOT_DIR)/shell/common.sh \
$(ROOT_DIR)/shell/update.sh \
$(ROOT_DIR)/shell/completion.bash \
$(ROOT_DIR)/shell/key-bindings.bash
ifdef FZF_VERSION
VERSION := $(FZF_VERSION)
else
@@ -88,9 +97,14 @@ itest:
bench:
cd src && SHELL=/bin/sh GOOS= $(GO) test -v -tags "$(TAGS)" -run=Bench -bench=. -benchmem
lint: $(SOURCES) test/*.rb test/lib/*.rb
lint: $(SOURCES) test/*.rb test/lib/*.rb ${BASH_SCRIPTS}
[ -z "$$(gofmt -s -d src)" ] || (gofmt -s -d src; exit 1)
bundle exec rubocop -a --require rubocop-minitest --require rubocop-performance
shell/update.sh --check ${BASH_SCRIPTS}
fmt: $(SOURCES) $(BASH_SCRIPTS)
gofmt -s -w src
shell/update.sh ${BASH_SCRIPTS}
install: bin/fzf
@@ -189,4 +203,4 @@ update:
$(GO) get -u
$(GO) mod tidy
.PHONY: all generate build release test itest bench lint install clean docker docker-test update
.PHONY: all generate build release test itest bench lint install clean docker docker-test update fmt

File diff suppressed because one or more lines are too long

View File

@@ -49,9 +49,9 @@ if [[ ! $type =~ image/ ]]; then
fi
dim=${FZF_PREVIEW_COLUMNS}x${FZF_PREVIEW_LINES}
if [[ $dim = x ]]; then
if [[ $dim == x ]]; then
dim=$(stty size < /dev/tty | awk '{print $2 "x" $1}')
elif ! [[ $KITTY_WINDOW_ID ]] && (( FZF_PREVIEW_TOP + FZF_PREVIEW_LINES == $(stty size < /dev/tty | awk '{print $1}') )); then
elif ! [[ $KITTY_WINDOW_ID ]] && ((FZF_PREVIEW_TOP + FZF_PREVIEW_LINES == $(stty size < /dev/tty | awk '{print $1}'))); then
# Avoid scrolling issue when the Sixel image touches the bottom of the screen
# * https://github.com/junegunn/fzf/issues/2544
dim=${FZF_PREVIEW_COLUMNS}x$((FZF_PREVIEW_LINES - 1))

View File

@@ -8,7 +8,7 @@ fail() {
}
fzf="$(command which fzf)" || fzf="$(dirname "$0")/fzf"
[[ -x "$fzf" ]] || fail 'fzf executable not found'
[[ -x $fzf ]] || fail 'fzf executable not found'
args=()
opt=""
@@ -16,8 +16,8 @@ skip=""
swap=""
close=""
term=""
[[ -n "$LINES" ]] && lines=$LINES || lines=$(tput lines) || lines=$(tmux display-message -p "#{pane_height}")
[[ -n "$COLUMNS" ]] && columns=$COLUMNS || columns=$(tput cols) || columns=$(tmux display-message -p "#{pane_width}")
[[ -n $LINES ]] && lines=$LINES || lines=$(tput lines) || lines=$(tmux display-message -p "#{pane_height}")
[[ -n $COLUMNS ]] && columns=$COLUMNS || columns=$(tput cols) || columns=$(tmux display-message -p "#{pane_width}")
tmux_version=$(tmux -V | sed 's/[^0-9.]//g')
tmux_32=$(awk '{print ($1 >= 3.2)}' <<< "$tmux_version" 2> /dev/null || bc -l <<< "$tmux_version >= 3.2")
@@ -47,7 +47,7 @@ help() {
while [[ $# -gt 0 ]]; do
arg="$1"
shift
[[ -z "$skip" ]] && case "$arg" in
[[ -z $skip ]] && case "$arg" in
-)
term=1
;;
@@ -58,19 +58,19 @@ while [[ $# -gt 0 ]]; do
echo "fzf-tmux (with fzf $("$fzf" --version))"
exit
;;
-p*|-w*|-h*|-x*|-y*|-d*|-u*|-r*|-l*)
if [[ "$arg" =~ ^-[pwhxy] ]]; then
[[ "$opt" =~ "-E" ]] || opt="-E"
elif [[ "$arg" =~ ^.[lr] ]]; then
-p* | -w* | -h* | -x* | -y* | -d* | -u* | -r* | -l*)
if [[ $arg =~ ^-[pwhxy] ]]; then
[[ $opt =~ "-E" ]] || opt="-E"
elif [[ $arg =~ ^.[lr] ]]; then
opt="-h"
if [[ "$arg" =~ ^.l ]]; then
if [[ $arg =~ ^.l ]]; then
opt="$opt -d"
swap="; swap-pane -D ; select-pane -L"
close="; tmux swap-pane -D"
fi
else
opt=""
if [[ "$arg" =~ ^.u ]]; then
if [[ $arg =~ ^.u ]]; then
opt="$opt -d"
swap="; swap-pane -D ; select-pane -U"
close="; tmux swap-pane -D"
@@ -79,7 +79,7 @@ while [[ $# -gt 0 ]]; do
if [[ ${#arg} -gt 2 ]]; then
size="${arg:2}"
else
if [[ "$1" =~ ^[0-9%,]+$ ]] || [[ "$1" =~ ^[A-Z]$ ]]; then
if [[ $1 =~ ^[0-9%,]+$ ]] || [[ $1 =~ ^[A-Z]$ ]]; then
size="$1"
shift
else
@@ -87,37 +87,37 @@ while [[ $# -gt 0 ]]; do
fi
fi
if [[ "$arg" =~ ^-p ]]; then
if [[ -n "$size" ]]; then
if [[ $arg =~ ^-p ]]; then
if [[ -n $size ]]; then
w=${size%%,*}
h=${size##*,}
opt="$opt -w$w -h$h"
fi
elif [[ "$arg" =~ ^-[whxy] ]]; then
elif [[ $arg =~ ^-[whxy] ]]; then
opt="$opt ${arg:0:2}$size"
elif [[ "$size" =~ %$ ]]; then
size=${size:0:((${#size}-1))}
if [[ $tmux_32 = 1 ]]; then
if [[ -n "$swap" ]]; then
opt="$opt -l $(( 100 - size ))%"
elif [[ $size =~ %$ ]]; then
size=${size:0:${#size}-1}
if [[ $tmux_32 == 1 ]]; then
if [[ -n $swap ]]; then
opt="$opt -l $((100 - size))%"
else
opt="$opt -l $size%"
fi
else
if [[ -n "$swap" ]]; then
opt="$opt -p $(( 100 - size ))"
if [[ -n $swap ]]; then
opt="$opt -p $((100 - size))"
else
opt="$opt -p $size"
fi
fi
else
if [[ -n "$swap" ]]; then
if [[ "$arg" =~ ^.l ]]; then
if [[ -n $swap ]]; then
if [[ $arg =~ ^.l ]]; then
max=$columns
else
max=$lines
fi
size=$(( max - size ))
size=$((max - size))
[[ $size -lt 0 ]] && size=0
opt="$opt -l $size"
else
@@ -135,10 +135,10 @@ while [[ $# -gt 0 ]]; do
args+=("$arg")
;;
esac
[[ -n "$skip" ]] && args+=("$arg")
[[ -n $skip ]] && args+=("$arg")
done
if [[ -z "$TMUX" ]]; then
if [[ -z $TMUX ]]; then
"$fzf" "${args[@]}"
exit $?
fi
@@ -149,7 +149,7 @@ fi
args=("${args[@]}" "--no-height" "--bind=ctrl-z:ignore" "--no-tmux")
# Handle zoomed tmux pane without popup options by moving it to a temp window
if [[ ! "$opt" =~ "-E" ]] && tmux list-panes -F '#F' | grep -q Z; then
if [[ ! $opt =~ "-E" ]] && tmux list-panes -F '#F' | grep -q Z; then
zoomed_without_popup=1
original_window=$(tmux display-message -p "#{window_id}")
tmp_window=$(tmux new-window -d -P -F "#{window_id}" "bash -c 'while :; do for c in \\| / - '\\;' do sleep 0.2; printf \"\\r\$c fzf-tmux is running\\r\"; done; done'")
@@ -165,22 +165,22 @@ fifo1="${TMPDIR:-/tmp}/fzf-fifo1-$id"
fifo2="${TMPDIR:-/tmp}/fzf-fifo2-$id"
fifo3="${TMPDIR:-/tmp}/fzf-fifo3-$id"
if tmux_win_opts=$(tmux show-options -p remain-on-exit \; show-options -p synchronize-panes 2> /dev/null); then
tmux_win_opts=( $(sed '/ off/d; s/synchronize-panes/set-option -p synchronize-panes/; s/remain-on-exit/set-option -p remain-on-exit/; s/$/ \\;/' <<< "$tmux_win_opts") )
tmux_win_opts=($(sed '/ off/d; s/synchronize-panes/set-option -p synchronize-panes/; s/remain-on-exit/set-option -p remain-on-exit/; s/$/ \\;/' <<< "$tmux_win_opts"))
tmux_off_opts='; set-option -p synchronize-panes off ; set-option -p remain-on-exit off'
else
tmux_win_opts=( $(tmux show-window-options remain-on-exit \; show-window-options synchronize-panes | sed '/ off/d; s/^/set-window-option /; s/$/ \\;/') )
tmux_win_opts=($(tmux show-window-options remain-on-exit \; show-window-options synchronize-panes | sed '/ off/d; s/^/set-window-option /; s/$/ \\;/'))
tmux_off_opts='; set-window-option synchronize-panes off ; set-window-option remain-on-exit off'
fi
cleanup() {
\rm -f $argsf $fifo1 $fifo2 $fifo3
# Restore tmux window options
if [[ "${#tmux_win_opts[@]}" -gt 1 ]]; then
if [[ ${#tmux_win_opts[@]} -gt 1 ]]; then
eval "tmux ${tmux_win_opts[*]}"
fi
# Remove temp window if we were zoomed without popup options
if [[ -n "$zoomed_without_popup" ]]; then
if [[ -n $zoomed_without_popup ]]; then
tmux display-message -p "#{window_id}" > /dev/null
tmux swap-pane -t $original_window \; \
select-window -t $original_window \; \
@@ -197,10 +197,10 @@ trap 'cleanup 1' SIGUSR1
trap 'cleanup' EXIT
envs="export TERM=$TERM "
if [[ "$opt" =~ "-E" ]]; then
if [[ $tmux_version = 3.2 ]]; then
if [[ $opt =~ "-E" ]]; then
if [[ $tmux_version == 3.2 ]]; then
FZF_DEFAULT_OPTS="--margin 0,1 $FZF_DEFAULT_OPTS"
elif [[ $tmux_32 = 1 ]]; then
elif [[ $tmux_32 == 1 ]]; then
FZF_DEFAULT_OPTS="--border $FZF_DEFAULT_OPTS"
opt="-B $opt"
else
@@ -211,8 +211,8 @@ fi
envs="$envs FZF_DEFAULT_COMMAND=$(printf %q "$FZF_DEFAULT_COMMAND")"
envs="$envs FZF_DEFAULT_OPTS=$(printf %q "$FZF_DEFAULT_OPTS")"
envs="$envs FZF_DEFAULT_OPTS_FILE=$(printf %q "$FZF_DEFAULT_OPTS_FILE")"
[[ -n "$RUNEWIDTH_EASTASIAN" ]] && envs="$envs RUNEWIDTH_EASTASIAN=$(printf %q "$RUNEWIDTH_EASTASIAN")"
[[ -n "$BAT_THEME" ]] && envs="$envs BAT_THEME=$(printf %q "$BAT_THEME")"
[[ -n $RUNEWIDTH_EASTASIAN ]] && envs="$envs RUNEWIDTH_EASTASIAN=$(printf %q "$RUNEWIDTH_EASTASIAN")"
[[ -n $BAT_THEME ]] && envs="$envs BAT_THEME=$(printf %q "$BAT_THEME")"
echo "$envs;" > "$argsf"
# Build arguments to fzf
@@ -224,9 +224,9 @@ close="; trap - EXIT SIGINT SIGTERM $close"
export TMUX=$(cut -d , -f 1,2 <<< "$TMUX")
mkfifo -m o+w $fifo2
if [[ "$opt" =~ "-E" ]]; then
if [[ $opt =~ "-E" ]]; then
cat $fifo2 &
if [[ -n "$term" ]] || [[ -t 0 ]]; then
if [[ -n $term ]] || [[ -t 0 ]]; then
cat <<< "\"$fzf\" $opts > $fifo2; out=\$? $close; exit \$out" >> $argsf
else
mkfifo $fifo1
@@ -239,7 +239,7 @@ if [[ "$opt" =~ "-E" ]]; then
fi
mkfifo -m o+w $fifo3
if [[ -n "$term" ]] || [[ -t 0 ]]; then
if [[ -n $term ]] || [[ -t 0 ]]; then
cat <<< "\"$fzf\" $opts > $fifo2; echo \$? > $fifo3 $close" >> $argsf
else
mkfifo $fifo1
@@ -249,6 +249,9 @@ fi
tmux \
split-window -c "$PWD" $opt "bash -c 'exec -a fzf bash $argsf'" $swap \
$tmux_off_opts \
> /dev/null 2>&1 || { "$fzf" "${args[@]}"; exit $?; }
> /dev/null 2>&1 || {
"$fzf" "${args[@]}"
exit $?
}
cat $fifo2
exit "$(cat $fifo3)"

12
go.mod
View File

@@ -1,20 +1,20 @@
module github.com/junegunn/fzf
require (
github.com/charlievieth/fastwalk v1.0.12
github.com/gdamore/tcell/v2 v2.8.1
github.com/charlievieth/fastwalk v1.0.14
github.com/gdamore/tcell/v2 v2.9.0
github.com/junegunn/go-shellwords v0.0.0-20250127100254-2aa3b3277741
github.com/mattn/go-isatty v0.0.20
github.com/rivo/uniseg v0.4.7
golang.org/x/sys v0.30.0
golang.org/x/term v0.29.0
golang.org/x/sys v0.35.0
golang.org/x/term v0.34.0
)
require (
github.com/gdamore/encoding v1.0.1 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/text v0.28.0 // indirect
)
go 1.20
go 1.23.0

52
go.sum
View File

@@ -1,10 +1,9 @@
github.com/charlievieth/fastwalk v1.0.12 h1:pwfxe1LajixViQqo7EFLXU2+mQxb6OaO0CeNdVwRKTg=
github.com/charlievieth/fastwalk v1.0.12/go.mod h1:yGy1zbxog41ZVMcKA/i8ojXLFsuayX5VvwhQVoj9PBI=
github.com/charlievieth/fastwalk v1.0.14 h1:3Eh5uaFGwHZd8EGwTjJnSpBkfwfsak9h6ICgnWlhAyg=
github.com/charlievieth/fastwalk v1.0.14/go.mod h1:diVcUreiU1aQ4/Wu3NbxxH4/KYdKpLDojrQ1Bb2KgNY=
github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw=
github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo=
github.com/gdamore/tcell/v2 v2.8.1 h1:KPNxyqclpWpWQlPLx6Xui1pMk8S+7+R37h3g07997NU=
github.com/gdamore/tcell/v2 v2.8.1/go.mod h1:bj8ori1BG3OYMjmb3IklZVWfZUJ1UBQt9JXrOCOhGWw=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/gdamore/tcell/v2 v2.9.0 h1:N6t+eqK7/xwtRPwxzs1PXeRWnm0H9l02CrgJ7DLn1ys=
github.com/gdamore/tcell/v2 v2.9.0/go.mod h1:8/ZoqM9rxzYphT9tH/9LnunhV9oPBqwS8WHGYm5nrmo=
github.com/junegunn/go-shellwords v0.0.0-20250127100254-2aa3b3277741 h1:7dYDtfMDfKzjT+DVfIS4iqknSEKtZpEcXtu6vuaasHs=
github.com/junegunn/go-shellwords v0.0.0-20250127100254-2aa3b3277741/go.mod h1:6EILKtGpo5t+KLb85LNZLAF6P9LKp78hJI80PXMcn3c=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
@@ -14,35 +13,20 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -50,38 +34,22 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

110
install
View File

@@ -2,7 +2,7 @@
set -u
version=0.65.1
version=0.65.2
auto_completion=
key_bindings=
update_config=2
@@ -46,16 +46,16 @@ for opt in "$@"; do
prefix_expand=${XDG_CONFIG_HOME:-$HOME/.config}/fzf/fzf
mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}/fzf"
;;
--key-bindings) key_bindings=1 ;;
--no-key-bindings) key_bindings=0 ;;
--completion) auto_completion=1 ;;
--no-completion) auto_completion=0 ;;
--update-rc) update_config=1 ;;
--no-update-rc) update_config=0 ;;
--bin) ;;
--no-bash) shells=${shells/bash/} ;;
--no-zsh) shells=${shells/zsh/} ;;
--no-fish) shells=${shells/fish/} ;;
--key-bindings) key_bindings=1 ;;
--no-key-bindings) key_bindings=0 ;;
--completion) auto_completion=1 ;;
--no-completion) auto_completion=0 ;;
--update-rc) update_config=1 ;;
--no-update-rc) update_config=0 ;;
--bin) ;;
--no-bash) shells=${shells/bash/} ;;
--no-zsh) shells=${shells/zsh/} ;;
--no-fish) shells=${shells/fish/} ;;
*)
echo "unknown option: $opt"
help
@@ -104,7 +104,7 @@ check_binary() {
link_fzf_in_path() {
if which_fzf="$(command -v fzf)"; then
echo " - Found in \$PATH"
echo ' - Found in $PATH'
echo " - Creating symlink: bin/fzf -> $which_fzf"
(cd "$fzf_base"/bin && rm -f fzf && ln -sf "$which_fzf" fzf)
check_binary && return
@@ -114,22 +114,22 @@ link_fzf_in_path() {
try_curl() {
command -v curl > /dev/null &&
if [[ $1 =~ tar.gz$ ]]; then
curl -fL $1 | tar --no-same-owner -xzf -
else
local temp=${TMPDIR:-/tmp}/fzf.zip
curl -fLo "$temp" $1 && unzip -o "$temp" && rm -f "$temp"
fi
if [[ $1 =~ tar.gz$ ]]; then
curl -fL $1 | tar --no-same-owner -xzf -
else
local temp=${TMPDIR:-/tmp}/fzf.zip
curl -fLo "$temp" $1 && unzip -o "$temp" && rm -f "$temp"
fi
}
try_wget() {
command -v wget > /dev/null &&
if [[ $1 =~ tar.gz$ ]]; then
wget -O - $1 | tar --no-same-owner -xzf -
else
local temp=${TMPDIR:-/tmp}/fzf.zip
wget -O "$temp" $1 && unzip -o "$temp" && rm -f "$temp"
fi
if [[ $1 =~ tar.gz$ ]]; then
wget -O - $1 | tar --no-same-owner -xzf -
else
local temp=${TMPDIR:-/tmp}/fzf.zip
wget -O "$temp" $1 && unzip -o "$temp" && rm -f "$temp"
fi
}
download() {
@@ -164,29 +164,29 @@ download() {
}
# Try to download binary executable
archi=$(uname -smo)
archi=$(uname -smo 2> /dev/null || uname -sm)
binary_available=1
binary_error=""
case "$archi" in
Darwin\ arm64*) download fzf-$version-darwin_arm64.tar.gz ;;
Darwin\ x86_64*) download fzf-$version-darwin_amd64.tar.gz ;;
Linux\ armv5*) download fzf-$version-linux_armv5.tar.gz ;;
Linux\ armv6*) download fzf-$version-linux_armv6.tar.gz ;;
Linux\ armv7*) download fzf-$version-linux_armv7.tar.gz ;;
Linux\ armv8*) download fzf-$version-linux_arm64.tar.gz ;;
Darwin\ arm64*) download fzf-$version-darwin_arm64.tar.gz ;;
Darwin\ x86_64*) download fzf-$version-darwin_amd64.tar.gz ;;
Linux\ armv5*) download fzf-$version-linux_armv5.tar.gz ;;
Linux\ armv6*) download fzf-$version-linux_armv6.tar.gz ;;
Linux\ armv7*) download fzf-$version-linux_armv7.tar.gz ;;
Linux\ armv8*) download fzf-$version-linux_arm64.tar.gz ;;
Linux\ aarch64\ Android) download fzf-$version-android_arm64.tar.gz ;;
Linux\ aarch64*) download fzf-$version-linux_arm64.tar.gz ;;
Linux\ loongarch64*) download fzf-$version-linux_loong64.tar.gz ;;
Linux\ ppc64le*) download fzf-$version-linux_ppc64le.tar.gz ;;
Linux\ *64*) download fzf-$version-linux_amd64.tar.gz ;;
Linux\ s390x*) download fzf-$version-linux_s390x.tar.gz ;;
FreeBSD\ *64*) download fzf-$version-freebsd_amd64.tar.gz ;;
OpenBSD\ *64*) download fzf-$version-openbsd_amd64.tar.gz ;;
CYGWIN*\ *64*) download fzf-$version-windows_amd64.zip ;;
MINGW*\ *64*) download fzf-$version-windows_amd64.zip ;;
MSYS*\ *64*) download fzf-$version-windows_amd64.zip ;;
Windows*\ *64*) download fzf-$version-windows_amd64.zip ;;
*) binary_available=0 binary_error=1 ;;
Linux\ aarch64*) download fzf-$version-linux_arm64.tar.gz ;;
Linux\ loongarch64*) download fzf-$version-linux_loong64.tar.gz ;;
Linux\ ppc64le*) download fzf-$version-linux_ppc64le.tar.gz ;;
Linux\ *64*) download fzf-$version-linux_amd64.tar.gz ;;
Linux\ s390x*) download fzf-$version-linux_s390x.tar.gz ;;
FreeBSD\ *64*) download fzf-$version-freebsd_amd64.tar.gz ;;
OpenBSD\ *64*) download fzf-$version-openbsd_amd64.tar.gz ;;
CYGWIN*\ *64*) download fzf-$version-windows_amd64.zip ;;
MINGW*\ *64*) download fzf-$version-windows_amd64.zip ;;
MSYS*\ *64*) download fzf-$version-windows_amd64.zip ;;
Windows*\ *64*) download fzf-$version-windows_amd64.zip ;;
*) binary_available=0 binary_error=1 ;;
esac
cd "$fzf_base"
@@ -215,7 +215,7 @@ if [ -n "$binary_error" ]; then
fi
fi
[[ "$*" =~ "--bin" ]] && exit 0
[[ $* =~ "--bin" ]] && exit 0
for s in $shells; do
if ! command -v "$s" > /dev/null; then
@@ -242,7 +242,7 @@ fi
echo
for shell in $shells; do
[[ "$shell" = fish ]] && continue
[[ $shell == fish ]] && continue
src=${prefix_expand}.${shell}
echo -n "Generate $src ... "
@@ -266,7 +266,7 @@ fi
EOF
if [[ $auto_completion -eq 1 ]] && [[ $key_bindings -eq 1 ]]; then
if [[ "$shell" = zsh ]]; then
if [[ $shell == zsh ]]; then
echo "source <(fzf --$shell)" >> "$src"
else
echo "eval \"\$(fzf --$shell)\"" >> "$src"
@@ -286,7 +286,7 @@ EOF
done
# fish
if [[ "$shells" =~ fish ]]; then
if [[ $shells =~ fish ]]; then
echo -n "Update fish_user_paths ... "
fish << EOF
echo \$fish_user_paths | \grep "$fzf_base"/bin > /dev/null
@@ -318,9 +318,9 @@ append_line() {
sed 's/^/ Line /' <<< "$lines"
update=0
if ! \grep -qv "^[0-9]*:[[:space:]]*#" <<< "$lines" ; then
if ! \grep -qv "^[0-9]*:[[:space:]]*#" <<< "$lines"; then
echo " - But they all seem to be commented"
ask " - Continue modifying $file?"
ask " - Continue modifying $file?"
update=$?
fi
fi
@@ -356,12 +356,12 @@ if [ $update_config -eq 2 ]; then
fi
echo
for shell in $shells; do
[[ "$shell" = fish ]] && continue
[[ $shell == fish ]] && continue
[ $shell = zsh ] && dest=${ZDOTDIR:-~}/.zshrc || dest=~/.bashrc
append_line $update_config "[ -f ${prefix}.${shell} ] && source ${prefix}.${shell}" "$dest" "${prefix}.${shell}"
done
if [ $key_bindings -eq 1 ] && [[ "$shells" =~ fish ]]; then
if [ $key_bindings -eq 1 ] && [[ $shells =~ fish ]]; then
bind_file="${fish_dir}/functions/fish_user_key_bindings.fish"
if [ ! -e "$bind_file" ]; then
mkdir -p "${fish_dir}/functions"
@@ -386,13 +386,13 @@ fi
if [ $update_config -eq 1 ]; then
echo 'Finished. Restart your shell or reload config file.'
if [[ "$shells" =~ bash ]]; then
if [[ $shells =~ bash ]]; then
echo -n ' source ~/.bashrc # bash'
[[ "$archi" =~ Darwin ]] && echo -n ' (.bashrc should be loaded from .bash_profile)'
[[ $archi =~ Darwin ]] && echo -n ' (.bashrc should be loaded from .bash_profile)'
echo
fi
[[ "$shells" =~ zsh ]] && echo " source ${ZDOTDIR:-~}/.zshrc # zsh"
[[ "$shells" =~ fish ]] && [ $key_bindings -eq 1 ] && echo ' fzf_key_bindings # fish'
[[ $shells =~ zsh ]] && echo " source ${ZDOTDIR:-~}/.zshrc # zsh"
[[ $shells =~ fish ]] && [ $key_bindings -eq 1 ] && echo ' fzf_key_bindings # fish'
echo
echo 'Use uninstall script to remove fzf.'
echo

View File

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

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 "Aug 2025" "fzf 0.65.1" "fzf\-tmux - open fzf in tmux split pane"
.TH fzf\-tmux 1 "Aug 2025" "fzf 0.65.2" "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 "Aug 2025" "fzf 0.65.1" "fzf - a command-line fuzzy finder"
.TH fzf 1 "Sep 2025" "fzf 0.66.0" "fzf - a command-line fuzzy finder"
.SH NAME
fzf - a command-line fuzzy finder
@@ -246,11 +246,11 @@ color mappings. Each entry is separated by a comma and/or whitespaces.
.RS
.B BASE SCHEME:
(default: \fBdark\fR on 256-color terminal, otherwise \fB16\fR; If \fBNO_COLOR\fR is set, \fBbw\fR)
(default: \fBdark\fR on 256-color terminal, otherwise \fBbase16\fR; If \fBNO_COLOR\fR is set, \fBbw\fR)
\fBdark \fRColor scheme for dark 256-color terminal
\fBlight \fRColor scheme for light 256-color terminal
\fB16 \fRColor scheme for 16-color terminal
\fBdark \fRColor scheme for dark terminal
\fBlight \fRColor scheme for light terminal
\fBbase16 \fRColor scheme using base 16 colors (alias: \fB16\fR)
\fBbw \fRNo colors (equivalent to \fB\-\-no\-color\fR)
.B COLOR NAMES:
@@ -643,6 +643,9 @@ on the center of the screen.
.BI "\-\-jump\-labels=" "CHARS"
Label characters for \fBjump\fR mode.
.TP
.BI "\-\-gutter=" "CHAR"
Character used for the gutter column (default: '▌' unless \fB\-\-no\-unicode\fR is given)
.TP
.BI "\-\-pointer=" "STR"
Pointer to the current line (default: '▌' or '>' depending on \fB\-\-no\-unicode\fR)
.TP
@@ -1046,7 +1049,7 @@ are not affected by \fB\-\-with\-nth\fR. ANSI color codes are processed even whe
.TP
.BI "\-\-footer\-border" [=STYLE]
Draw border around the header section. \fBline\fR style draws a single
Draw border around the footer section. \fBline\fR style draws a single
separator line between the footer and the list section.
.TP
@@ -1473,12 +1476,22 @@ e.g.
.br
\fIalt\-right\fR
.br
\fIalt\-home\fR
.br
\fIalt\-end\fR
.br
\fIalt\-backspace\fR (\fIalt\-bspace\fR \fIalt\-bs\fR)
.br
\fIalt\-delete\fR
.br
\fIalt\-page\-up\fR
.br
\fIalt\-page\-down\fR
.br
\fIalt\-enter\fR
.br
\fIalt\-space\fR
.br
\fIalt\-backspace\fR (\fIalt\-bspace\fR \fIalt\-bs\fR)
.br
\fItab\fR
.br
\fIshift\-tab\fR (\fIbtab\fR)
@@ -1505,6 +1518,26 @@ e.g.
.br
\fIpage\-down\fR (\fIpgdn\fR)
.br
\fIctrl\-up\fR
.br
\fIctrl\-down\fR
.br
\fIctrl\-left\fR
.br
\fIctrl\-right\fR
.br
\fIctrl\-home\fR
.br
\fIctrl\-end\fR
.br
\fIctrl\-backspace\fR (\fIctrl\-bspace\fR \fIctrl\-bs\fR)
.br
\fIctrl\-delete\fR
.br
\fIctrl\-page\-up\fR
.br
\fIctrl\-page\-down\fR
.br
\fIshift\-up\fR
.br
\fIshift\-down\fR
@@ -1513,8 +1546,16 @@ e.g.
.br
\fIshift\-right\fR
.br
\fIshift\-home\fR
.br
\fIshift\-end\fR
.br
\fIshift\-delete\fR
.br
\fIshift\-page\-up\fR
.br
\fIshift\-page\-down\fR
.br
\fIalt\-shift\-up\fR
.br
\fIalt\-shift\-down\fR
@@ -1523,6 +1564,72 @@ e.g.
.br
\fIalt\-shift\-right\fR
.br
\fIalt\-shift\-home\fR
.br
\fIalt\-shift\-end\fR
.br
\fIalt\-shift\-delete\fR
.br
\fIalt\-shift\-page\-up\fR
.br
\fIalt\-shift\-page\-down\fR
.br
\fIctrl\-alt\-up\fR
.br
\fIctrl\-alt\-down\fR
.br
\fIctrl\-alt\-left\fR
.br
\fIctrl\-alt\-right\fR
.br
\fIctrl\-alt\-home\fR
.br
\fIctrl\-alt\-end\fR
.br
\fIctrl\-alt\-backspace\fR (\fIctrl\-alt\-bspace\fR \fIctrl\-alt\-bs\fR)
.br
\fIctrl\-alt\-delete\fR
.br
\fIctrl\-alt\-page\-up\fR
.br
\fIctrl\-alt\-page\-down\fR
.br
\fIctrl\-shift\-up\fR
.br
\fIctrl\-shift\-down\fR
.br
\fIctrl\-shift\-left\fR
.br
\fIctrl\-shift\-right\fR
.br
\fIctrl\-shift\-home\fR
.br
\fIctrl\-shift\-end\fR
.br
\fIctrl\-shift\-delete\fR
.br
\fIctrl\-shift\-page\-up\fR
.br
\fIctrl\-shift\-page\-down\fR
.br
\fIctrl\-alt\-shift\-up\fR
.br
\fIctrl\-alt\-shift\-down\fR
.br
\fIctrl\-alt\-shift\-left\fR
.br
\fIctrl\-alt\-shift\-right\fR
.br
\fIctrl\-alt\-shift\-home\fR
.br
\fIctrl\-alt\-shift\-end\fR
.br
\fIctrl\-alt\-shift\-delete\fR
.br
\fIctrl\-alt\-shift\-page\-up\fR
.br
\fIctrl\-alt\-shift\-page\-down\fR
.br
\fIleft\-click\fR
.br
\fIright\-click\fR
@@ -1547,6 +1654,8 @@ e.g.
.br
or any single character
Note that some terminal emulators may not support \fIctrl-*\fR bindings.
.SS AVAILABLE EVENTS:
\fIstart\fR
.RS
@@ -1699,9 +1808,11 @@ A key or an event can be bound to one or more of the following actions.
\fBaccept\-non\-empty\fR (same as \fBaccept\fR except that it prevents fzf from exiting without selection)
\fBaccept\-or\-print\-query\fR (same as \fBaccept\fR except that it prints the query when there's no match)
\fBbackward\-char\fR \fIctrl\-b left\fR
\fBbackward\-delete\-char\fR \fIctrl\-h bspace\fR
\fBbackward\-delete\-char\fR \fIctrl\-h ctrl\-bspace bspace\fR
\fBbackward\-delete\-char/eof\fR (same as \fBbackward\-delete\-char\fR except aborts fzf if query is empty)
\fBbackward\-kill\-subword\fR
\fBbackward\-kill\-word\fR \fIalt\-bs\fR
\fBbackward\-subword\fR
\fBbackward\-word\fR \fIalt\-b shift\-left\fR
\fBbecome(...)\fR (replace fzf process with the specified command; see below for the details)
\fBbeginning\-of\-line\fR \fIctrl\-a home\fR
@@ -1741,10 +1852,12 @@ A key or an event can be bound to one or more of the following actions.
\fBexecute\-silent(...)\fR (see below for the details)
\fBfirst\fR (move to the first match; same as \fBpos(1)\fR)
\fBforward\-char\fR \fIctrl\-f right\fR
\fBforward\-subword\fR
\fBforward\-word\fR \fIalt\-f shift\-right\fR
\fBignore\fR
\fBjump\fR (EasyMotion-like 2-keystroke movement)
\fBkill\-line\fR
\fBkill\-subword\fR
\fBkill\-word\fR \fIalt\-d\fR
\fBlast\fR (move to the last match; same as \fBpos(\-1)\fR)
\fBnext\-history\fR (\fIctrl\-n\fR on \fB\-\-history\fR)

View File

@@ -1,4 +1,3 @@
__fzf_defaults() {
# $1: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
# $2: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
@@ -22,12 +21,12 @@ __fzf_exec_awk() {
# modern point of view. To use a standard-conforming version in Solaris,
# one needs to explicitly use /usr/xpg4/bin/awk.
__fzf_awk=/usr/xpg4/bin/awk
elif command -v mawk >/dev/null 2>&1; then
elif command -v mawk > /dev/null 2>&1; then
# choose the faster mawk if: it's installed && build date >= 20230322 &&
# version >= 1.3.4
local n x y z d
IFS=' .' read -r n x y z d <<< $(command mawk -W version 2> /dev/null)
[[ $n == mawk ]] && (( d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004 )) && __fzf_awk=mawk
[[ $n == mawk ]] && ((d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004)) && __fzf_awk=mawk
fi
fi
# Note: macOS awk has a quirk that it stops processing at all when it sees

View File

@@ -31,9 +31,10 @@ if [[ $- =~ i ]]; then
###########################################################
#----BEGIN shfmt
#----BEGIN INCLUDE common.sh
# NOTE: Do not directly edit this section, which is copied from "common.sh".
# To modify it, one can edit "common.sh" and run "./update-common.sh" to apply
# To modify it, one can edit "common.sh" and run "./update.sh" to apply
# the changes. See code comments in "common.sh" for the implementation details.
__fzf_defaults() {
@@ -47,10 +48,10 @@ __fzf_exec_awk() {
__fzf_awk=awk
if [[ $OSTYPE == solaris* && -x /usr/xpg4/bin/awk ]]; then
__fzf_awk=/usr/xpg4/bin/awk
elif command -v mawk >/dev/null 2>&1; then
elif command -v mawk > /dev/null 2>&1; then
local n x y z d
IFS=' .' read -r n x y z d <<< $(command mawk -W version 2> /dev/null)
[[ $n == mawk ]] && (( d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004 )) && __fzf_awk=mawk
[[ $n == mawk ]] && ((d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004)) && __fzf_awk=mawk
fi
fi
LC_ALL=C exec "$__fzf_awk" "$@"
@@ -58,9 +59,9 @@ __fzf_exec_awk() {
#----END INCLUDE
__fzf_comprun() {
if [[ "$(type -t _fzf_comprun 2>&1)" = function ]]; then
if [[ "$(type -t _fzf_comprun 2>&1)" == function ]]; then
_fzf_comprun "$@"
elif [[ -n "${TMUX_PANE-}" ]] && { [[ "${FZF_TMUX:-0}" != 0 ]] || [[ -n "${FZF_TMUX_OPTS-}" ]]; }; then
elif [[ -n ${TMUX_PANE-} ]] && { [[ ${FZF_TMUX:-0} != 0 ]] || [[ -n ${FZF_TMUX_OPTS-} ]]; }; then
shift
fzf-tmux ${FZF_TMUX_OPTS:--d${FZF_TMUX_HEIGHT:-40%}} -- "$@"
else
@@ -72,13 +73,13 @@ __fzf_comprun() {
__fzf_orig_completion() {
local l comp f cmd
while read -r l; do
if [[ "$l" =~ ^(.*\ -F)\ *([^ ]*).*\ ([^ ]*)$ ]]; then
if [[ $l =~ ^(.*\ -F)\ *([^ ]*).*\ ([^ ]*)$ ]]; then
comp="${BASH_REMATCH[1]}"
f="${BASH_REMATCH[2]}"
cmd="${BASH_REMATCH[3]}"
[[ "$f" = _fzf_* ]] && continue
[[ $f == _fzf_* ]] && continue
printf -v "_fzf_orig_completion_${cmd//[^A-Za-z0-9_]/_}" "%s" "${comp} %s ${cmd} #${f}"
if [[ "$l" = *" -o nospace "* ]] && [[ ! "${__fzf_nospace_commands-}" = *" $cmd "* ]]; then
if [[ $l == *" -o nospace "* ]] && [[ ${__fzf_nospace_commands-} != *" $cmd "* ]]; then
__fzf_nospace_commands="${__fzf_nospace_commands-} $cmd "
fi
fi
@@ -114,7 +115,7 @@ _fzf_opts_completion() {
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
prev="${COMP_WORDS[COMP_CWORD - 1]}"
opts="
+c --no-color
+i --no-ignore-case
@@ -197,28 +198,28 @@ _fzf_opts_completion() {
--"
case "${prev}" in
--scheme)
COMPREPLY=( $(compgen -W "default path history" -- "$cur") )
return 0
;;
--tiebreak)
COMPREPLY=( $(compgen -W "length chunk begin end index" -- "$cur") )
return 0
;;
--color)
COMPREPLY=( $(compgen -W "dark light 16 bw no" -- "$cur") )
return 0
;;
--layout)
COMPREPLY=( $(compgen -W "default reverse reverse-list" -- "$cur") )
return 0
;;
--info)
COMPREPLY=( $(compgen -W "default right hidden inline inline-right" -- "$cur") )
return 0
;;
--preview-window)
COMPREPLY=( $(compgen -W "
--scheme)
COMPREPLY=($(compgen -W "default path history" -- "$cur"))
return 0
;;
--tiebreak)
COMPREPLY=($(compgen -W "length chunk begin end index" -- "$cur"))
return 0
;;
--color)
COMPREPLY=($(compgen -W "dark light 16 bw no" -- "$cur"))
return 0
;;
--layout)
COMPREPLY=($(compgen -W "default reverse reverse-list" -- "$cur"))
return 0
;;
--info)
COMPREPLY=($(compgen -W "default right hidden inline inline-right" -- "$cur"))
return 0
;;
--preview-window)
COMPREPLY=($(compgen -W "
default
hidden
nohidden
@@ -244,21 +245,21 @@ _fzf_opts_completion() {
border-left
border-right
follow
nofollow" -- "$cur") )
return 0
;;
--border)
COMPREPLY=( $(compgen -W "rounded sharp bold block thinblock double horizontal vertical top bottom left right none" -- "$cur") )
return 0
;;
--border-label-pos|--preview-label-pos)
COMPREPLY=( $(compgen -W "center bottom top" -- "$cur") )
return 0
;;
nofollow" -- "$cur"))
return 0
;;
--border)
COMPREPLY=($(compgen -W "rounded sharp bold block thinblock double horizontal vertical top bottom left right none" -- "$cur"))
return 0
;;
--border-label-pos | --preview-label-pos)
COMPREPLY=($(compgen -W "center bottom top" -- "$cur"))
return 0
;;
esac
if [[ "$cur" =~ ^-|\+ ]]; then
COMPREPLY=( $(compgen -W "${opts}" -- "$cur") )
if [[ $cur =~ ^-|\+ ]]; then
COMPREPLY=($(compgen -W "${opts}" -- "$cur"))
return 0
fi
@@ -272,7 +273,7 @@ _fzf_handle_dynamic_completion() {
orig_cmd="$1"
if __fzf_orig_completion_get_orig_func "$cmd"; then
"$REPLY" "$@"
elif [[ -n "${_fzf_completion_loader-}" ]]; then
elif [[ -n ${_fzf_completion_loader-} ]]; then
orig_complete=$(complete -p "$orig_cmd" 2> /dev/null)
$_fzf_completion_loader "$@"
ret=$?
@@ -286,7 +287,7 @@ _fzf_handle_dynamic_completion() {
__fzf_orig_completion_instantiate "$cmd" "${BASH_REMATCH[1]}" &&
orig_complete=$REPLY
if [[ "${__fzf_nospace_commands-}" = *" $orig_cmd "* ]]; then
if [[ ${__fzf_nospace_commands-} == *" $orig_cmd "* ]]; then
eval "${orig_complete/ -F / -o nospace -F }"
else
eval "$orig_complete"
@@ -306,18 +307,18 @@ __fzf_generic_path_completion() {
COMPREPLY=()
trigger=${FZF_COMPLETION_TRIGGER-'**'}
[[ $COMP_CWORD -ge 0 ]] && cur="${COMP_WORDS[COMP_CWORD]}"
if [[ "$cur" == *"$trigger" ]] && [[ $cur != *'$('* ]] && [[ $cur != *':='* ]] && [[ $cur != *'`'* ]]; then
if [[ $cur == *"$trigger" ]] && [[ $cur != *'$('* ]] && [[ $cur != *':='* ]] && [[ $cur != *'`'* ]]; then
base=${cur:0:${#cur}-${#trigger}}
eval "base=$base" 2> /dev/null || return
dir=
[[ $base = *"/"* ]] && dir="$base"
[[ $base == *"/"* ]] && dir="$base"
while true; do
if [[ -z "$dir" ]] || [[ -d "$dir" ]]; then
leftover=${base/#"$dir"}
leftover=${leftover/#\/}
[[ -z "$dir" ]] && dir='.'
[[ "$dir" != "/" ]] && dir="${dir/%\//}"
if [[ -z $dir ]] || [[ -d $dir ]]; then
leftover=${base/#"$dir"/}
leftover=${leftover/#\//}
[[ -z $dir ]] && dir='.'
[[ $dir != "/" ]] && dir="${dir/%\//}"
matches=$(
export FZF_DEFAULT_OPTS=$(__fzf_defaults "--reverse --scheme=path" "${FZF_COMPLETION_OPTS-} $2")
unset FZF_DEFAULT_COMMAND FZF_DEFAULT_OPTS_FILE
@@ -337,11 +338,11 @@ __fzf_generic_path_completion() {
done
)
matches=${matches% }
[[ -z "$3" ]] && [[ "${__fzf_nospace_commands-}" = *" ${COMP_WORDS[0]} "* ]] && matches="$matches "
if [[ -n "$matches" ]]; then
COMPREPLY=( "$matches" )
[[ -z $3 ]] && [[ ${__fzf_nospace_commands-} == *" ${COMP_WORDS[0]} "* ]] && matches="$matches "
if [[ -n $matches ]]; then
COMPREPLY=("$matches")
else
COMPREPLY=( "$cur" )
COMPREPLY=("$cur")
fi
# To redraw line after fzf closes (printf '\e[5n')
bind '"\e[0n": redraw-current-line' 2> /dev/null
@@ -349,7 +350,7 @@ __fzf_generic_path_completion() {
return 0
fi
dir=$(command dirname "$dir")
[[ "$dir" =~ /$ ]] || dir="$dir"/
[[ $dir =~ /$ ]] || dir="$dir"/
done
else
shift
@@ -365,15 +366,15 @@ _fzf_complete() {
args=("$@")
sep=
for i in "${!args[@]}"; do
if [[ "${args[$i]}" = -- ]]; then
if [[ ${args[$i]} == -- ]]; then
sep=$i
break
fi
done
if [[ -n "$sep" ]]; then
if [[ -n $sep ]]; then
str_arg=
rest=("${args[@]:$((sep + 1)):${#args[@]}}")
args=("${args[@]:0:$sep}")
args=("${args[@]:0:sep}")
else
str_arg=$1
args=()
@@ -388,15 +389,16 @@ _fzf_complete() {
trigger=${FZF_COMPLETION_TRIGGER-'**'}
cmd="${COMP_WORDS[0]}"
cur="${COMP_WORDS[COMP_CWORD]}"
if [[ "$cur" == *"$trigger" ]] && [[ $cur != *'$('* ]] && [[ $cur != *':='* ]] && [[ $cur != *'`'* ]]; then
if [[ $cur == *"$trigger" ]] && [[ $cur != *'$('* ]] && [[ $cur != *':='* ]] && [[ $cur != *'`'* ]]; then
cur=${cur:0:${#cur}-${#trigger}}
selected=$(
FZF_DEFAULT_OPTS=$(__fzf_defaults "--reverse" "${FZF_COMPLETION_OPTS-} $str_arg") \
FZF_DEFAULT_OPTS_FILE='' \
__fzf_comprun "${rest[0]}" "${args[@]}" -q "$cur" | eval "$post" | command tr '\n' ' ')
__fzf_comprun "${rest[0]}" "${args[@]}" -q "$cur" | eval "$post" | command tr '\n' ' '
)
selected=${selected% } # Strip trailing space not to repeat "-o nospace"
if [[ -n "$selected" ]]; then
if [[ -n $selected ]]; then
COMPREPLY=("$selected")
else
COMPREPLY=("$cur")
@@ -454,10 +456,10 @@ _fzf_proc_completion() {
'
_fzf_complete -m --header-lines=1 --no-preview --wrap --color fg:dim,nth:regular \
--bind "click-header:transform:$transformer" -- "$@" < <(
command ps -eo user,pid,ppid,start,time,command 2> /dev/null ||
command ps -eo user,pid,ppid,time,args 2> /dev/null || # For BusyBox
command ps --everyone --full --windows # For cygwin
)
command ps -eo user,pid,ppid,start,time,command 2> /dev/null ||
command ps -eo user,pid,ppid,time,args 2> /dev/null || # For BusyBox
command ps --everyone --full --windows # For cygwin
)
}
_fzf_proc_completion_post() {
@@ -540,12 +542,12 @@ _fzf_host_completion() {
# > and the third argument ($3) is the word preceding the word being completed on the current command line.
_fzf_complete_ssh() {
case $3 in
-i|-F|-E)
-i | -F | -E)
_fzf_path_completion "$@"
;;
*)
local user=
[[ "$2" =~ '@' ]] && user="${2%%@*}@"
[[ $2 =~ '@' ]] && user="${2%%@*}@"
_fzf_complete +m -- "$@" < <(__fzf_list_hosts | __fzf_exec_awk -v user="$user" '{print user $0}')
;;
esac
@@ -676,12 +678,13 @@ _fzf_setup_completion() {
__fzf_orig_completion < <(complete -p "$@" 2> /dev/null)
for cmd in "$@"; do
case "$kind" in
dir) __fzf_defc "$cmd" "$fn" "-o nospace -o dirnames" ;;
var) __fzf_defc "$cmd" "$fn" "-o default -o nospace -v" ;;
dir) __fzf_defc "$cmd" "$fn" "-o nospace -o dirnames" ;;
var) __fzf_defc "$cmd" "$fn" "-o default -o nospace -v" ;;
alias) __fzf_defc "$cmd" "$fn" "-a" ;;
*) __fzf_defc "$cmd" "$fn" "-o default -o bashdefault" ;;
*) __fzf_defc "$cmd" "$fn" "-o default -o bashdefault" ;;
esac
done
}
#----END shfmt
fi

View File

@@ -98,7 +98,7 @@ if [[ -o interactive ]]; then
#----BEGIN INCLUDE common.sh
# NOTE: Do not directly edit this section, which is copied from "common.sh".
# To modify it, one can edit "common.sh" and run "./update-common.sh" to apply
# To modify it, one can edit "common.sh" and run "./update.sh" to apply
# the changes. See code comments in "common.sh" for the implementation details.
__fzf_defaults() {
@@ -112,10 +112,10 @@ __fzf_exec_awk() {
__fzf_awk=awk
if [[ $OSTYPE == solaris* && -x /usr/xpg4/bin/awk ]]; then
__fzf_awk=/usr/xpg4/bin/awk
elif command -v mawk >/dev/null 2>&1; then
elif command -v mawk > /dev/null 2>&1; then
local n x y z d
IFS=' .' read -r n x y z d <<< $(command mawk -W version 2> /dev/null)
[[ $n == mawk ]] && (( d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004 )) && __fzf_awk=mawk
[[ $n == mawk ]] && ((d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004)) && __fzf_awk=mawk
fi
fi
LC_ALL=C exec "$__fzf_awk" "$@"

View File

@@ -17,9 +17,10 @@ if [[ $- =~ i ]]; then
# Key bindings
# ------------
#----BEGIN shfmt
#----BEGIN INCLUDE common.sh
# NOTE: Do not directly edit this section, which is copied from "common.sh".
# To modify it, one can edit "common.sh" and run "./update-common.sh" to apply
# To modify it, one can edit "common.sh" and run "./update.sh" to apply
# the changes. See code comments in "common.sh" for the implementation details.
__fzf_defaults() {
@@ -33,10 +34,10 @@ __fzf_exec_awk() {
__fzf_awk=awk
if [[ $OSTYPE == solaris* && -x /usr/xpg4/bin/awk ]]; then
__fzf_awk=/usr/xpg4/bin/awk
elif command -v mawk >/dev/null 2>&1; then
elif command -v mawk > /dev/null 2>&1; then
local n x y z d
IFS=' .' read -r n x y z d <<< $(command mawk -W version 2> /dev/null)
[[ $n == mawk ]] && (( d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004 )) && __fzf_awk=mawk
[[ $n == mawk ]] && ((d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004)) && __fzf_awk=mawk
fi
fi
LC_ALL=C exec "$__fzf_awk" "$@"
@@ -45,30 +46,30 @@ __fzf_exec_awk() {
__fzf_select__() {
FZF_DEFAULT_COMMAND=${FZF_CTRL_T_COMMAND:-} \
FZF_DEFAULT_OPTS=$(__fzf_defaults "--reverse --walker=file,dir,follow,hidden --scheme=path" "${FZF_CTRL_T_OPTS-} -m") \
FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd) "$@" |
FZF_DEFAULT_OPTS=$(__fzf_defaults "--reverse --walker=file,dir,follow,hidden --scheme=path" "${FZF_CTRL_T_OPTS-} -m") \
FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd) "$@" |
while read -r item; do
printf '%q ' "$item" # escape special chars
printf '%q ' "$item" # escape special chars
done
}
__fzfcmd() {
[[ -n "${TMUX_PANE-}" ]] && { [[ "${FZF_TMUX:-0}" != 0 ]] || [[ -n "${FZF_TMUX_OPTS-}" ]]; } &&
[[ -n ${TMUX_PANE-} ]] && { [[ ${FZF_TMUX:-0} != 0 ]] || [[ -n ${FZF_TMUX_OPTS-} ]]; } &&
echo "fzf-tmux ${FZF_TMUX_OPTS:--d${FZF_TMUX_HEIGHT:-40%}} -- " || echo "fzf"
}
fzf-file-widget() {
local selected="$(__fzf_select__ "$@")"
READLINE_LINE="${READLINE_LINE:0:$READLINE_POINT}$selected${READLINE_LINE:$READLINE_POINT}"
READLINE_POINT=$(( READLINE_POINT + ${#selected} ))
READLINE_LINE="${READLINE_LINE:0:READLINE_POINT}$selected${READLINE_LINE:READLINE_POINT}"
READLINE_POINT=$((READLINE_POINT + ${#selected}))
}
__fzf_cd__() {
local dir
dir=$(
FZF_DEFAULT_COMMAND=${FZF_ALT_C_COMMAND:-} \
FZF_DEFAULT_OPTS=$(__fzf_defaults "--reverse --walker=dir,follow,hidden --scheme=path" "${FZF_ALT_C_OPTS-} +m") \
FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd)
FZF_DEFAULT_OPTS=$(__fzf_defaults "--reverse --walker=dir,follow,hidden --scheme=path" "${FZF_ALT_C_OPTS-} +m") \
FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd)
) && printf 'builtin cd -- %q' "$(builtin unset CDPATH && builtin cd -- "$dir" && builtin pwd)"
}
@@ -84,7 +85,7 @@ if command -v perl > /dev/null; then
FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd) --query "$READLINE_LINE"
) || return
READLINE_LINE=$(command perl -pe 's/^\d*\t//' <<< "$output")
if [[ -z "$READLINE_POINT" ]]; then
if [[ -z $READLINE_POINT ]]; then
echo "$READLINE_LINE"
else
READLINE_POINT=0x7fffffff
@@ -93,7 +94,7 @@ if command -v perl > /dev/null; then
else # awk - fallback for POSIX systems
__fzf_history__() {
local output script
[[ $(HISTTIMEFORMAT='' builtin history 1) =~ [[:digit:]]+ ]] # how many history entries
[[ $(HISTTIMEFORMAT='' builtin history 1) =~ [[:digit:]]+ ]] # how many history entries
script='function P(b) { ++n; sub(/^[ *]/, "", b); if (!seen[b]++) { printf "%d\t%s%c", '$((BASH_REMATCH + 1))' - n, b, 0 } }
NR==1 { b = substr($0, 2); next }
/^\t/ { P(b); b = substr($0, 2); next }
@@ -101,13 +102,13 @@ else # awk - fallback for POSIX systems
END { if (NR) P(b) }'
output=$(
set +o pipefail
builtin fc -lnr -2147483648 2> /dev/null | # ( $'\t '<lines>$'\n' )* ; <lines> ::= [^\n]* ( $'\n'<lines> )*
__fzf_exec_awk "$script" | # ( <counter>$'\t'<lines>$'\000' )*
builtin fc -lnr -2147483648 2> /dev/null | # ( $'\t '<lines>$'\n' )* ; <lines> ::= [^\n]* ( $'\n'<lines> )*
__fzf_exec_awk "$script" | # ( <counter>$'\t'<lines>$'\000' )*
FZF_DEFAULT_OPTS=$(__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort --wrap-sign '"$'\t'"↳ ' --highlight-line ${FZF_CTRL_R_OPTS-} +m --read0") \
FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd) --query "$READLINE_LINE"
) || return
READLINE_LINE=${output#*$'\t'}
if [[ -z "$READLINE_POINT" ]]; then
if [[ -z $READLINE_POINT ]]; then
echo "$READLINE_LINE"
else
READLINE_POINT=0x7fffffff
@@ -122,10 +123,10 @@ bind -m vi-command '"\C-z": emacs-editing-mode'
bind -m vi-insert '"\C-z": emacs-editing-mode'
bind -m emacs-standard '"\C-z": vi-editing-mode'
if (( BASH_VERSINFO[0] < 4 )); then
if ((BASH_VERSINFO[0] < 4)); then
# CTRL-T - Paste the selected file path into the command line
if [[ "${FZF_CTRL_T_COMMAND-x}" != "" ]]; then
bind -m emacs-standard '"\C-t": " \C-b\C-k \C-u`__fzf_select__`\e\C-e\er\C-a\C-y\C-h\C-e\e \C-y\ey\C-x\C-x\C-f"'
if [[ ${FZF_CTRL_T_COMMAND-x} != "" ]]; then
bind -m emacs-standard '"\C-t": " \C-b\C-k \C-u`__fzf_select__`\e\C-e\er\C-a\C-y\C-h\C-e\e \C-y\ey\C-x\C-x\C-f\C-y\ey\C-_"'
bind -m vi-command '"\C-t": "\C-z\C-t\C-z"'
bind -m vi-insert '"\C-t": "\C-z\C-t\C-z"'
fi
@@ -136,7 +137,7 @@ if (( BASH_VERSINFO[0] < 4 )); then
bind -m vi-insert '"\C-r": "\C-z\C-r\C-z"'
else
# CTRL-T - Paste the selected file path into the command line
if [[ "${FZF_CTRL_T_COMMAND-x}" != "" ]]; then
if [[ ${FZF_CTRL_T_COMMAND-x} != "" ]]; then
bind -m emacs-standard -x '"\C-t": fzf-file-widget'
bind -m vi-command -x '"\C-t": fzf-file-widget'
bind -m vi-insert -x '"\C-t": fzf-file-widget'
@@ -149,10 +150,11 @@ else
fi
# ALT-C - cd into the selected directory
if [[ "${FZF_ALT_C_COMMAND-x}" != "" ]]; then
bind -m emacs-standard '"\ec": " \C-b\C-k \C-u`__fzf_cd__`\e\C-e\er\C-m\C-y\C-h\e \C-y\ey\C-x\C-x\C-d"'
if [[ ${FZF_ALT_C_COMMAND-x} != "" ]]; then
bind -m emacs-standard '"\ec": " \C-b\C-k \C-u`__fzf_cd__`\e\C-e\er\C-m\C-y\C-h\e \C-y\ey\C-x\C-x\C-d\C-y\ey\C-_"'
bind -m vi-command '"\ec": "\C-z\ec\C-z"'
bind -m vi-insert '"\ec": "\C-z\ec\C-z"'
fi
#----END shfmt
fi

View File

@@ -40,7 +40,7 @@ if [[ -o interactive ]]; then
#----BEGIN INCLUDE common.sh
# NOTE: Do not directly edit this section, which is copied from "common.sh".
# To modify it, one can edit "common.sh" and run "./update-common.sh" to apply
# To modify it, one can edit "common.sh" and run "./update.sh" to apply
# the changes. See code comments in "common.sh" for the implementation details.
__fzf_defaults() {
@@ -54,10 +54,10 @@ __fzf_exec_awk() {
__fzf_awk=awk
if [[ $OSTYPE == solaris* && -x /usr/xpg4/bin/awk ]]; then
__fzf_awk=/usr/xpg4/bin/awk
elif command -v mawk >/dev/null 2>&1; then
elif command -v mawk > /dev/null 2>&1; then
local n x y z d
IFS=' .' read -r n x y z d <<< $(command mawk -W version 2> /dev/null)
[[ $n == mawk ]] && (( d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004 )) && __fzf_awk=mawk
[[ $n == mawk ]] && ((d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004)) && __fzf_awk=mawk
fi
fi
LC_ALL=C exec "$__fzf_awk" "$@"

View File

@@ -1,31 +0,0 @@
#!/bin/sh
# This script applies the contents of "common.sh" to the other files.
set -e
# Go to the directory that contains this script
dir=${0%"${0##*/}"}
if [ -n "$dir" ]; then
cd "$dir"
fi
update() {
{
sed -n '1,/^#----BEGIN INCLUDE common\.sh/p' "$1"
cat <<EOF
# NOTE: Do not directly edit this section, which is copied from "common.sh".
# To modify it, one can edit "common.sh" and run "./update-common.sh" to apply
# the changes. See code comments in "common.sh" for the implementation details.
EOF
grep -v '^[[:blank:]]*#' common.sh # remove code comments in common.sh
sed -n '/^#----END INCLUDE/,$p' "$1"
} > "$1.part"
mv -f "$1.part" "$1"
}
update completion.bash
update completion.zsh
update key-bindings.bash
update key-bindings.zsh

68
shell/update.sh Executable file
View File

@@ -0,0 +1,68 @@
#!/usr/bin/env bash
# This script applies the contents of "common.sh" to the other files.
set -e
dir=${0%"${0##*/}"}
update() {
{
sed -n '1,/^#----BEGIN INCLUDE common\.sh/p' "$1"
cat << EOF
# NOTE: Do not directly edit this section, which is copied from "common.sh".
# To modify it, one can edit "common.sh" and run "./update.sh" to apply
# the changes. See code comments in "common.sh" for the implementation details.
EOF
echo
grep -v '^[[:blank:]]*#' "$dir/common.sh" # remove code comments in common.sh
sed -n '/^#----END INCLUDE/,$p' "$1"
} > "$1.part"
mv -f "$1.part" "$1"
}
update "$dir/completion.bash"
update "$dir/completion.zsh"
update "$dir/key-bindings.bash"
update "$dir/key-bindings.zsh"
# Check if --check is in ARGV
check=0
rest=()
for arg in "$@"; do
case $arg in
--check) check=1 ;;
*) rest+=("$arg") ;;
esac
done
fmt() {
if ! grep -q "^#----BEGIN shfmt" "$1"; then
if [[ $check == 1 ]]; then
shfmt -d "$1"
return $?
else
shfmt -w "$1"
fi
else
{
sed -n '1,/^#----BEGIN shfmt/p' "$1" | sed '$d'
sed -n '/^#----BEGIN shfmt/,/^#----END shfmt/p' "$1" | shfmt --filename "$1"
sed -n '/^#----END shfmt/,$p' "$1" | sed '1d'
} > "$1.part"
if [[ $check == 1 ]]; then
diff -q "$1" "$1.part"
ret=$?
rm -f "$1.part"
return $ret
fi
mv -f "$1.part" "$1"
fi
}
for file in "${rest[@]}"; do
fmt "$file" || exit $?
done

View File

@@ -25,154 +25,158 @@ func _() {
_ = x[actBackwardDeleteChar-14]
_ = x[actBackwardDeleteCharEof-15]
_ = x[actBackwardWord-16]
_ = x[actCancel-17]
_ = x[actChangeBorderLabel-18]
_ = x[actChangeGhost-19]
_ = x[actChangeHeader-20]
_ = x[actChangeFooter-21]
_ = x[actChangeHeaderLabel-22]
_ = x[actChangeFooterLabel-23]
_ = x[actChangeInputLabel-24]
_ = x[actChangeListLabel-25]
_ = x[actChangeMulti-26]
_ = x[actChangeNth-27]
_ = x[actChangePointer-28]
_ = x[actChangePreview-29]
_ = x[actChangePreviewLabel-30]
_ = x[actChangePreviewWindow-31]
_ = x[actChangePrompt-32]
_ = x[actChangeQuery-33]
_ = x[actClearScreen-34]
_ = x[actClearQuery-35]
_ = x[actClearSelection-36]
_ = x[actClose-37]
_ = x[actDeleteChar-38]
_ = x[actDeleteCharEof-39]
_ = x[actEndOfLine-40]
_ = x[actFatal-41]
_ = x[actForwardChar-42]
_ = x[actForwardWord-43]
_ = x[actKillLine-44]
_ = x[actKillWord-45]
_ = x[actUnixLineDiscard-46]
_ = x[actUnixWordRubout-47]
_ = x[actYank-48]
_ = x[actBackwardKillWord-49]
_ = x[actSelectAll-50]
_ = x[actDeselectAll-51]
_ = x[actToggle-52]
_ = x[actToggleSearch-53]
_ = x[actToggleAll-54]
_ = x[actToggleDown-55]
_ = x[actToggleUp-56]
_ = x[actToggleIn-57]
_ = x[actToggleOut-58]
_ = x[actToggleTrack-59]
_ = x[actToggleTrackCurrent-60]
_ = x[actToggleHeader-61]
_ = x[actToggleWrap-62]
_ = x[actToggleMultiLine-63]
_ = x[actToggleHscroll-64]
_ = x[actTrackCurrent-65]
_ = x[actToggleInput-66]
_ = x[actHideInput-67]
_ = x[actShowInput-68]
_ = x[actUntrackCurrent-69]
_ = x[actDown-70]
_ = x[actUp-71]
_ = x[actPageUp-72]
_ = x[actPageDown-73]
_ = x[actPosition-74]
_ = x[actHalfPageUp-75]
_ = x[actHalfPageDown-76]
_ = x[actOffsetUp-77]
_ = x[actOffsetDown-78]
_ = x[actOffsetMiddle-79]
_ = x[actJump-80]
_ = x[actJumpAccept-81]
_ = x[actPrintQuery-82]
_ = x[actRefreshPreview-83]
_ = x[actReplaceQuery-84]
_ = x[actToggleSort-85]
_ = x[actShowPreview-86]
_ = x[actHidePreview-87]
_ = x[actTogglePreview-88]
_ = x[actTogglePreviewWrap-89]
_ = x[actTransform-90]
_ = x[actTransformBorderLabel-91]
_ = x[actTransformGhost-92]
_ = x[actTransformHeader-93]
_ = x[actTransformFooter-94]
_ = x[actTransformHeaderLabel-95]
_ = x[actTransformFooterLabel-96]
_ = x[actTransformInputLabel-97]
_ = x[actTransformListLabel-98]
_ = x[actTransformNth-99]
_ = x[actTransformPointer-100]
_ = x[actTransformPreviewLabel-101]
_ = x[actTransformPrompt-102]
_ = x[actTransformQuery-103]
_ = x[actTransformSearch-104]
_ = x[actTrigger-105]
_ = x[actBgTransform-106]
_ = x[actBgTransformBorderLabel-107]
_ = x[actBgTransformGhost-108]
_ = x[actBgTransformHeader-109]
_ = x[actBgTransformFooter-110]
_ = x[actBgTransformHeaderLabel-111]
_ = x[actBgTransformFooterLabel-112]
_ = x[actBgTransformInputLabel-113]
_ = x[actBgTransformListLabel-114]
_ = x[actBgTransformNth-115]
_ = x[actBgTransformPointer-116]
_ = x[actBgTransformPreviewLabel-117]
_ = x[actBgTransformPrompt-118]
_ = x[actBgTransformQuery-119]
_ = x[actBgTransformSearch-120]
_ = x[actBgCancel-121]
_ = x[actSearch-122]
_ = x[actPreview-123]
_ = x[actPreviewTop-124]
_ = x[actPreviewBottom-125]
_ = x[actPreviewUp-126]
_ = x[actPreviewDown-127]
_ = x[actPreviewPageUp-128]
_ = x[actPreviewPageDown-129]
_ = x[actPreviewHalfPageUp-130]
_ = x[actPreviewHalfPageDown-131]
_ = x[actPrevHistory-132]
_ = x[actPrevSelected-133]
_ = x[actPrint-134]
_ = x[actPut-135]
_ = x[actNextHistory-136]
_ = x[actNextSelected-137]
_ = x[actExecute-138]
_ = x[actExecuteSilent-139]
_ = x[actExecuteMulti-140]
_ = x[actSigStop-141]
_ = x[actFirst-142]
_ = x[actLast-143]
_ = x[actReload-144]
_ = x[actReloadSync-145]
_ = x[actDisableSearch-146]
_ = x[actEnableSearch-147]
_ = x[actSelect-148]
_ = x[actDeselect-149]
_ = x[actUnbind-150]
_ = x[actRebind-151]
_ = x[actToggleBind-152]
_ = x[actBecome-153]
_ = x[actShowHeader-154]
_ = x[actHideHeader-155]
_ = x[actBell-156]
_ = x[actExclude-157]
_ = x[actExcludeMulti-158]
_ = x[actAsync-159]
_ = x[actBackwardSubWord-17]
_ = x[actCancel-18]
_ = x[actChangeBorderLabel-19]
_ = x[actChangeGhost-20]
_ = x[actChangeHeader-21]
_ = x[actChangeFooter-22]
_ = x[actChangeHeaderLabel-23]
_ = x[actChangeFooterLabel-24]
_ = x[actChangeInputLabel-25]
_ = x[actChangeListLabel-26]
_ = x[actChangeMulti-27]
_ = x[actChangeNth-28]
_ = x[actChangePointer-29]
_ = x[actChangePreview-30]
_ = x[actChangePreviewLabel-31]
_ = x[actChangePreviewWindow-32]
_ = x[actChangePrompt-33]
_ = x[actChangeQuery-34]
_ = x[actClearScreen-35]
_ = x[actClearQuery-36]
_ = x[actClearSelection-37]
_ = x[actClose-38]
_ = x[actDeleteChar-39]
_ = x[actDeleteCharEof-40]
_ = x[actEndOfLine-41]
_ = x[actFatal-42]
_ = x[actForwardChar-43]
_ = x[actForwardWord-44]
_ = x[actForwardSubWord-45]
_ = x[actKillLine-46]
_ = x[actKillWord-47]
_ = x[actKillSubWord-48]
_ = x[actUnixLineDiscard-49]
_ = x[actUnixWordRubout-50]
_ = x[actYank-51]
_ = x[actBackwardKillWord-52]
_ = x[actBackwardKillSubWord-53]
_ = x[actSelectAll-54]
_ = x[actDeselectAll-55]
_ = x[actToggle-56]
_ = x[actToggleSearch-57]
_ = x[actToggleAll-58]
_ = x[actToggleDown-59]
_ = x[actToggleUp-60]
_ = x[actToggleIn-61]
_ = x[actToggleOut-62]
_ = x[actToggleTrack-63]
_ = x[actToggleTrackCurrent-64]
_ = x[actToggleHeader-65]
_ = x[actToggleWrap-66]
_ = x[actToggleMultiLine-67]
_ = x[actToggleHscroll-68]
_ = x[actTrackCurrent-69]
_ = x[actToggleInput-70]
_ = x[actHideInput-71]
_ = x[actShowInput-72]
_ = x[actUntrackCurrent-73]
_ = x[actDown-74]
_ = x[actUp-75]
_ = x[actPageUp-76]
_ = x[actPageDown-77]
_ = x[actPosition-78]
_ = x[actHalfPageUp-79]
_ = x[actHalfPageDown-80]
_ = x[actOffsetUp-81]
_ = x[actOffsetDown-82]
_ = x[actOffsetMiddle-83]
_ = x[actJump-84]
_ = x[actJumpAccept-85]
_ = x[actPrintQuery-86]
_ = x[actRefreshPreview-87]
_ = x[actReplaceQuery-88]
_ = x[actToggleSort-89]
_ = x[actShowPreview-90]
_ = x[actHidePreview-91]
_ = x[actTogglePreview-92]
_ = x[actTogglePreviewWrap-93]
_ = x[actTransform-94]
_ = x[actTransformBorderLabel-95]
_ = x[actTransformGhost-96]
_ = x[actTransformHeader-97]
_ = x[actTransformFooter-98]
_ = x[actTransformHeaderLabel-99]
_ = x[actTransformFooterLabel-100]
_ = x[actTransformInputLabel-101]
_ = x[actTransformListLabel-102]
_ = x[actTransformNth-103]
_ = x[actTransformPointer-104]
_ = x[actTransformPreviewLabel-105]
_ = x[actTransformPrompt-106]
_ = x[actTransformQuery-107]
_ = x[actTransformSearch-108]
_ = x[actTrigger-109]
_ = x[actBgTransform-110]
_ = x[actBgTransformBorderLabel-111]
_ = x[actBgTransformGhost-112]
_ = x[actBgTransformHeader-113]
_ = x[actBgTransformFooter-114]
_ = x[actBgTransformHeaderLabel-115]
_ = x[actBgTransformFooterLabel-116]
_ = x[actBgTransformInputLabel-117]
_ = x[actBgTransformListLabel-118]
_ = x[actBgTransformNth-119]
_ = x[actBgTransformPointer-120]
_ = x[actBgTransformPreviewLabel-121]
_ = x[actBgTransformPrompt-122]
_ = x[actBgTransformQuery-123]
_ = x[actBgTransformSearch-124]
_ = x[actBgCancel-125]
_ = x[actSearch-126]
_ = x[actPreview-127]
_ = x[actPreviewTop-128]
_ = x[actPreviewBottom-129]
_ = x[actPreviewUp-130]
_ = x[actPreviewDown-131]
_ = x[actPreviewPageUp-132]
_ = x[actPreviewPageDown-133]
_ = x[actPreviewHalfPageUp-134]
_ = x[actPreviewHalfPageDown-135]
_ = x[actPrevHistory-136]
_ = x[actPrevSelected-137]
_ = x[actPrint-138]
_ = x[actPut-139]
_ = x[actNextHistory-140]
_ = x[actNextSelected-141]
_ = x[actExecute-142]
_ = x[actExecuteSilent-143]
_ = x[actExecuteMulti-144]
_ = x[actSigStop-145]
_ = x[actFirst-146]
_ = x[actLast-147]
_ = x[actReload-148]
_ = x[actReloadSync-149]
_ = x[actDisableSearch-150]
_ = x[actEnableSearch-151]
_ = x[actSelect-152]
_ = x[actDeselect-153]
_ = x[actUnbind-154]
_ = x[actRebind-155]
_ = x[actToggleBind-156]
_ = x[actBecome-157]
_ = x[actShowHeader-158]
_ = x[actHideHeader-159]
_ = x[actBell-160]
_ = x[actExclude-161]
_ = x[actExcludeMulti-162]
_ = x[actAsync-163]
}
const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactTriggeractBgTransformactBgTransformBorderLabelactBgTransformGhostactBgTransformHeaderactBgTransformFooteractBgTransformHeaderLabelactBgTransformFooterLabelactBgTransformInputLabelactBgTransformListLabelactBgTransformNthactBgTransformPointeractBgTransformPreviewLabelactBgTransformPromptactBgTransformQueryactBgTransformSearchactBgCancelactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMultiactAsync"
const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactBackwardSubWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactForwardSubWordactKillLineactKillWordactKillSubWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactBackwardKillSubWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactTriggeractBgTransformactBgTransformBorderLabelactBgTransformGhostactBgTransformHeaderactBgTransformFooteractBgTransformHeaderLabelactBgTransformFooterLabelactBgTransformInputLabelactBgTransformListLabelactBgTransformNthactBgTransformPointeractBgTransformPreviewLabelactBgTransformPromptactBgTransformQueryactBgTransformSearchactBgCancelactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMultiactAsync"
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 57, 77, 84, 92, 110, 118, 127, 144, 165, 180, 201, 225, 240, 249, 269, 283, 298, 313, 333, 353, 372, 390, 404, 416, 432, 448, 469, 491, 506, 520, 534, 547, 564, 572, 585, 601, 613, 621, 635, 649, 660, 671, 689, 706, 713, 732, 744, 758, 767, 782, 794, 807, 818, 829, 841, 855, 876, 891, 904, 922, 938, 953, 967, 979, 991, 1008, 1015, 1020, 1029, 1040, 1051, 1064, 1079, 1090, 1103, 1118, 1125, 1138, 1151, 1168, 1183, 1196, 1210, 1224, 1240, 1260, 1272, 1295, 1312, 1330, 1348, 1371, 1394, 1416, 1437, 1452, 1471, 1495, 1513, 1530, 1548, 1558, 1572, 1597, 1616, 1636, 1656, 1681, 1706, 1730, 1753, 1770, 1791, 1817, 1837, 1856, 1876, 1887, 1896, 1906, 1919, 1935, 1947, 1961, 1977, 1995, 2015, 2037, 2051, 2066, 2074, 2080, 2094, 2109, 2119, 2135, 2150, 2160, 2168, 2175, 2184, 2197, 2213, 2228, 2237, 2248, 2257, 2266, 2279, 2288, 2301, 2314, 2321, 2331, 2346, 2354}
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 57, 77, 84, 92, 110, 118, 127, 144, 165, 180, 201, 225, 240, 258, 267, 287, 301, 316, 331, 351, 371, 390, 408, 422, 434, 450, 466, 487, 509, 524, 538, 552, 565, 582, 590, 603, 619, 631, 639, 653, 667, 684, 695, 706, 720, 738, 755, 762, 781, 803, 815, 829, 838, 853, 865, 878, 889, 900, 912, 926, 947, 962, 975, 993, 1009, 1024, 1038, 1050, 1062, 1079, 1086, 1091, 1100, 1111, 1122, 1135, 1150, 1161, 1174, 1189, 1196, 1209, 1222, 1239, 1254, 1267, 1281, 1295, 1311, 1331, 1343, 1366, 1383, 1401, 1419, 1442, 1465, 1487, 1508, 1523, 1542, 1566, 1584, 1601, 1619, 1629, 1643, 1668, 1687, 1707, 1727, 1752, 1777, 1801, 1824, 1841, 1862, 1888, 1908, 1927, 1947, 1958, 1967, 1977, 1990, 2006, 2018, 2032, 2048, 2066, 2086, 2108, 2122, 2137, 2145, 2151, 2165, 2180, 2190, 2206, 2221, 2231, 2239, 2246, 2255, 2268, 2284, 2299, 2308, 2319, 2328, 2337, 2350, 2359, 2372, 2385, 2392, 2402, 2417, 2425}
func (i actionType) String() string {
if i < 0 || i >= actionType(len(_actionType_index)-1) {

View File

@@ -52,7 +52,7 @@ func TestChunkList(t *testing.T) {
// Add more data
for i := 0; i < chunkSize*2; i++ {
cl.Push([]byte(fmt.Sprintf("item %d", i)))
cl.Push(fmt.Appendf(nil, "item %d", i))
}
// Previous snapshot should remain the same
@@ -86,7 +86,7 @@ func TestChunkListTail(t *testing.T) {
})
total := chunkSize*2 + chunkSize/2
for i := 0; i < total; i++ {
cl.Push([]byte(fmt.Sprintf("item %d", i)))
cl.Push(fmt.Appendf(nil, "item %d", i))
}
snapshot, count, changed := cl.Snapshot(0)

View File

@@ -2,6 +2,7 @@
package fzf
import (
"maps"
"os"
"sync"
"time"
@@ -225,10 +226,7 @@ func Run(opts *Options) (int, error) {
}
patternBuilder := func(runes []rune) *Pattern {
denyMutex.Lock()
denylistCopy := make(map[int32]struct{})
for k, v := range denylist {
denylistCopy[k] = v
}
denylistCopy := maps.Clone(denylist)
denyMutex.Unlock()
return BuildPattern(cache, patternCache,
opts.Fuzzy, opts.FuzzyAlgo, opts.Extended, opts.Case, opts.Normalize, forward, withPos,

View File

@@ -85,11 +85,11 @@ func (m *Matcher) Loop() {
cacheCleared := false
if request.sort != m.sort || request.revision != m.revision {
m.sort = request.sort
m.revision = request.revision
m.mergerCache = make(map[string]*Merger)
if !request.revision.compatible(m.revision) {
m.cache.Clear()
}
m.revision = request.revision
cacheCleared = true
}

View File

@@ -3,6 +3,7 @@ package fzf
import (
"errors"
"fmt"
"maps"
"os"
"regexp"
"strconv"
@@ -59,7 +60,7 @@ Usage: fzf [options]
GLOBAL STYLE
--style=PRESET Apply a style preset [default|minimal|full[:BORDER_STYLE]
--color=COLSPEC Base scheme (dark|light|16|bw) and/or custom colors
--color=COLSPEC Base scheme (dark|light|base16|bw) and/or custom colors
--no-color Disable colors
--no-bold Do not use bold text
@@ -109,6 +110,7 @@ Usage: fzf [options]
--hscroll-off=COLS Number of screen columns to keep to the right of the
highlighted substring (default: 10)
--jump-labels=CHARS Label characters for jump mode
--gutter=CHAR Character used for the gutter column (default: '▌')
--pointer=STR Pointer to the current line (default: '▌' or '>')
--marker=STR Multi-select marker (default: '┃' or '>')
--marker-multi-line=STR Multi-select marker for multi-line entries;
@@ -212,8 +214,8 @@ Usage: fzf [options]
(default: .git,node_modules)
HISTORY
--history=FILE History file
--history-size=N Maximum number of history entries (default: 1000)
--history=FILE File to store fzf search history (*not* shell command history)
--history-size=N Maximum number of entries to keep in the file (default: 1000)
SHELL INTEGRATION
--bash Print script to set up Bash shell integration
@@ -590,6 +592,7 @@ type Options struct {
Separator *string
JumpLabels string
Prompt string
Gutter *string
Pointer *string
Marker *string
MarkerMulti *[3]string
@@ -710,6 +713,7 @@ func defaultOptions() *Options {
Separator: nil,
JumpLabels: defaultJumpLabels,
Prompt: "> ",
Gutter: nil,
Pointer: nil,
Marker: nil,
MarkerMulti: nil,
@@ -974,8 +978,6 @@ func parseKeyChords(str string, message string) (map[tui.Event]string, []tui.Eve
add(tui.Backspace)
case "ctrl-space":
add(tui.CtrlSpace)
case "ctrl-delete":
add(tui.CtrlDelete)
case "ctrl-^", "ctrl-6":
add(tui.CtrlCaret)
case "ctrl-/", "ctrl-_":
@@ -1022,6 +1024,10 @@ func parseKeyChords(str string, message string) (map[tui.Event]string, []tui.Eve
list = append(list, evt)
case "alt-bs", "alt-bspace", "alt-backspace":
add(tui.AltBackspace)
case "ctrl-bs", "ctrl-bspace", "ctrl-backspace":
add(tui.CtrlBackspace)
case "ctrl-alt-bs", "ctrl-alt-bspace", "ctrl-alt-backspace":
add(tui.CtrlAltBackspace)
case "alt-up":
add(tui.AltUp)
case "alt-down":
@@ -1030,6 +1036,16 @@ func parseKeyChords(str string, message string) (map[tui.Event]string, []tui.Eve
add(tui.AltLeft)
case "alt-right":
add(tui.AltRight)
case "alt-home":
add(tui.AltHome)
case "alt-end":
add(tui.AltEnd)
case "alt-delete":
add(tui.AltDelete)
case "alt-page-up":
add(tui.AltPageUp)
case "alt-page-down":
add(tui.AltPageDown)
case "tab":
add(tui.Tab)
case "btab", "shift-tab":
@@ -1056,6 +1072,88 @@ func parseKeyChords(str string, message string) (map[tui.Event]string, []tui.Eve
add(tui.AltShiftLeft)
case "alt-shift-right", "shift-alt-right":
add(tui.AltShiftRight)
case "alt-shift-home", "shift-alt-home":
add(tui.AltShiftHome)
case "alt-shift-end", "shift-alt-end":
add(tui.AltShiftEnd)
case "alt-shift-delete", "shift-alt-delete":
add(tui.AltShiftDelete)
case "alt-shift-page-up", "shift-alt-page-up":
add(tui.AltShiftPageUp)
case "alt-shift-page-down", "shift-alt-page-down":
add(tui.AltShiftPageDown)
case "ctrl-up":
add(tui.CtrlUp)
case "ctrl-down":
add(tui.CtrlDown)
case "ctrl-right":
add(tui.CtrlRight)
case "ctrl-left":
add(tui.CtrlLeft)
case "ctrl-home":
add(tui.CtrlHome)
case "ctrl-end":
add(tui.CtrlEnd)
case "ctrl-delete":
add(tui.CtrlDelete)
case "ctrl-page-up":
add(tui.CtrlPageUp)
case "ctrl-page-down":
add(tui.CtrlPageDown)
case "ctrl-alt-up", "alt-ctrl-up":
add(tui.CtrlAltUp)
case "ctrl-alt-down", "alt-ctrl-down":
add(tui.CtrlAltDown)
case "ctrl-alt-right", "alt-ctrl-right":
add(tui.CtrlAltRight)
case "ctrl-alt-left", "alt-ctrl-left":
add(tui.CtrlAltLeft)
case "ctrl-alt-home", "alt-ctrl-home":
add(tui.CtrlAltHome)
case "ctrl-alt-end", "alt-ctrl-end":
add(tui.CtrlAltEnd)
case "ctrl-alt-delete", "alt-ctrl-delete":
add(tui.CtrlAltDelete)
case "ctrl-alt-page-up", "alt-ctrl-page-up":
add(tui.CtrlAltPageUp)
case "ctrl-alt-page-down", "alt-ctrl-page-down":
add(tui.CtrlAltPageDown)
case "ctrl-shift-up", "shift-ctrl-up":
add(tui.CtrlShiftUp)
case "ctrl-shift-down", "shift-ctrl-down":
add(tui.CtrlShiftDown)
case "ctrl-shift-right", "shift-ctrl-right":
add(tui.CtrlShiftRight)
case "ctrl-shift-left", "shift-ctrl-left":
add(tui.CtrlShiftLeft)
case "ctrl-shift-home", "shift-ctrl-home":
add(tui.CtrlShiftHome)
case "ctrl-shift-end", "shift-ctrl-end":
add(tui.CtrlShiftEnd)
case "ctrl-shift-delete", "shift-ctrl-delete":
add(tui.CtrlShiftDelete)
case "ctrl-shift-page-up", "shift-ctrl-page-up":
add(tui.CtrlShiftPageUp)
case "ctrl-shift-page-down", "shift-ctrl-page-down":
add(tui.CtrlShiftPageDown)
case "ctrl-alt-shift-up":
add(tui.CtrlAltShiftUp)
case "ctrl-alt-shift-down":
add(tui.CtrlAltShiftDown)
case "ctrl-alt-shift-right":
add(tui.CtrlAltShiftRight)
case "ctrl-alt-shift-left":
add(tui.CtrlAltShiftLeft)
case "ctrl-alt-shift-home":
add(tui.CtrlAltShiftHome)
case "ctrl-alt-shift-end":
add(tui.CtrlAltShiftEnd)
case "ctrl-alt-shift-delete":
add(tui.CtrlAltShiftDelete)
case "ctrl-alt-shift-page-up":
add(tui.CtrlAltShiftPageUp)
case "ctrl-alt-shift-page-down":
add(tui.CtrlAltShiftPageDown)
case "shift-up":
add(tui.ShiftUp)
case "shift-down":
@@ -1064,8 +1162,16 @@ func parseKeyChords(str string, message string) (map[tui.Event]string, []tui.Eve
add(tui.ShiftLeft)
case "shift-right":
add(tui.ShiftRight)
case "shift-home":
add(tui.ShiftHome)
case "shift-end":
add(tui.ShiftEnd)
case "shift-delete":
add(tui.ShiftDelete)
case "shift-page-up":
add(tui.ShiftPageUp)
case "shift-page-down":
add(tui.ShiftPageDown)
case "left-click":
add(tui.LeftClick)
case "right-click":
@@ -1221,7 +1327,7 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) (*tui.ColorTheme, erro
theme = dupeTheme(tui.Dark256)
case "light":
theme = dupeTheme(tui.Light256)
case "16":
case "base16", "16":
theme = dupeTheme(tui.Default16)
case "bw", "no":
theme = tui.NoColorTheme()
@@ -1561,6 +1667,8 @@ func parseActionList(masked string, original string, prevActions []*action, putA
appendAction(actBackwardDeleteCharEof)
case "backward-word":
appendAction(actBackwardWord)
case "backward-subword":
appendAction(actBackwardSubWord)
case "clear-screen":
appendAction(actClearScreen)
case "delete-char":
@@ -1581,6 +1689,8 @@ func parseActionList(masked string, original string, prevActions []*action, putA
appendAction(actForwardChar)
case "forward-word":
appendAction(actForwardWord)
case "forward-subword":
appendAction(actForwardSubWord)
case "jump":
appendAction(actJump)
case "jump-accept":
@@ -1589,6 +1699,8 @@ func parseActionList(masked string, original string, prevActions []*action, putA
appendAction(actKillLine)
case "kill-word":
appendAction(actKillWord)
case "kill-subword":
appendAction(actKillSubWord)
case "unix-line-discard", "line-discard":
appendAction(actUnixLineDiscard)
case "unix-word-rubout", "word-rubout":
@@ -1597,6 +1709,8 @@ func parseActionList(masked string, original string, prevActions []*action, putA
appendAction(actYank)
case "backward-kill-word":
appendAction(actBackwardKillWord)
case "backward-kill-subword":
appendAction(actBackwardKillSubWord)
case "toggle-down":
appendAction(actToggle, actDown)
case "toggle-up":
@@ -2490,9 +2604,7 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
if err != nil {
return err
}
for k, v := range chords {
opts.Expect[k] = v
}
maps.Copy(opts.Expect, chords)
case "--no-expect":
opts.Expect = make(map[tui.Event]string)
case "--enabled", "--no-phony":
@@ -2747,6 +2859,13 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
if err != nil {
return err
}
case "--gutter":
str, err := nextString("gutter character required")
if err != nil {
return err
}
str = firstLine(str)
opts.Gutter = &str
case "--pointer":
str, err := nextString("pointer sign required")
if err != nil {
@@ -3245,22 +3364,28 @@ func applyPreset(opts *Options, preset string) error {
return nil
}
func validateSign(sign string, signOptName string) error {
if uniseg.StringWidth(sign) > 2 {
return fmt.Errorf("%v display width should be up to 2", signOptName)
func validateSign(sign string, signOptName string, maxWidth int) error {
if uniseg.StringWidth(sign) > maxWidth {
return fmt.Errorf("%v display width should be up to %d", signOptName, maxWidth)
}
return nil
}
func validateOptions(opts *Options) error {
if opts.Pointer != nil {
if err := validateSign(*opts.Pointer, "pointer"); err != nil {
if err := validateSign(*opts.Pointer, "pointer", 2); err != nil {
return err
}
}
if opts.Marker != nil {
if err := validateSign(*opts.Marker, "marker"); err != nil {
if err := validateSign(*opts.Marker, "marker", 2); err != nil {
return err
}
}
if opts.Gutter != nil {
if err := validateSign(*opts.Gutter, "gutter", 1); err != nil {
return err
}
}

View File

@@ -462,7 +462,7 @@ func TestValidateSign(t *testing.T) {
}
for _, testCase := range testCases {
err := validateSign(testCase.inputSign, "")
err := validateSign(testCase.inputSign, "", 2)
if testCase.isValid && err != nil {
t.Errorf("Input sign `%s` caused error", testCase.inputSign)
}

View File

@@ -90,11 +90,12 @@ func runProxy(commandPrefix string, cmdBuilder func(temp string, needBash bool)
}
}
// * Write the command to a temporary file and run it with sh to ensure POSIX compliance.
// * Nullify FZF_DEFAULT_* variables as tmux popup may inject them even when undefined.
exports := []string{"FZF_DEFAULT_COMMAND=", "FZF_DEFAULT_OPTS=", "FZF_DEFAULT_OPTS_FILE="}
// Write the command to a temporary file and run it with sh to ensure POSIX compliance.
var exports []string
needBash := false
if withExports {
// Nullify FZF_DEFAULT_* variables as tmux popup may inject them even when undefined.
exports = []string{"FZF_DEFAULT_COMMAND=", "FZF_DEFAULT_OPTS=", "FZF_DEFAULT_OPTS_FILE="}
validIdentifier := regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)
for _, pairStr := range os.Environ() {
pair := strings.SplitN(pairStr, "=", 2)

View File

@@ -285,7 +285,7 @@ func (r *Reader) readFiles(roots []string, opts walkerOpts, ignores []string) bo
if strings.HasPrefix(ignore, sep) {
ignoresSuffix = append(ignoresSuffix, ignore)
} else {
// 'foo/bar' should match match
// 'foo/bar' should match
// * 'foo/bar'
// * 'baz/foo/bar'
// * but NOT 'bazfoo/bar'

View File

@@ -128,9 +128,9 @@ func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, t
// No ANSI codes
if len(itemColors) == 0 && len(nthOffsets) == 0 {
var offsets []colorOffset
for _, off := range matchOffsets {
offsets = append(offsets, colorOffset{offset: [2]int32{off[0], off[1]}, color: colMatch, match: true})
offsets := make([]colorOffset, len(matchOffsets))
for i, off := range matchOffsets {
offsets[i] = colorOffset{offset: [2]int32{off[0], off[1]}, color: colMatch, match: true}
}
return offsets
}

View File

@@ -6,6 +6,7 @@ import (
"encoding/json"
"fmt"
"io"
"maps"
"math"
"net"
"os"
@@ -272,6 +273,7 @@ type Terminal struct {
footerLabel labelPrinter
footerLabelLen int
footerLabelOpts labelOpts
gutterReverse bool
pointer string
pointerLen int
pointerEmpty string
@@ -291,6 +293,8 @@ type Terminal struct {
gapLineLen int
wordRubout string
wordNext string
subWordRubout string
subWordNext string
cx int
cy int
offset int
@@ -397,7 +401,6 @@ type Terminal struct {
initFunc func() error
prevLines []itemLine
suppress bool
sigstop bool
startChan chan fitpad
killChan chan bool
serverInputChan chan []*action
@@ -512,6 +515,7 @@ const (
actBackwardDeleteChar
actBackwardDeleteCharEof
actBackwardWord
actBackwardSubWord
actCancel
actChangeBorderLabel
@@ -541,12 +545,15 @@ const (
actFatal
actForwardChar
actForwardWord
actForwardSubWord
actKillLine
actKillWord
actKillSubWord
actUnixLineDiscard
actUnixWordRubout
actYank
actBackwardKillWord
actBackwardKillSubWord
actSelectAll
actDeselectAll
actToggle
@@ -782,6 +789,7 @@ func defaultKeymap() map[tui.Event][]*action {
add(tui.CtrlF, actForwardChar)
add(tui.CtrlH, actBackwardDeleteChar)
add(tui.Backspace, actBackwardDeleteChar)
add(tui.CtrlBackspace, actBackwardDeleteChar)
add(tui.Tab, actToggleDown)
add(tui.ShiftTab, actToggleUp)
add(tui.CtrlJ, actDown)
@@ -936,15 +944,14 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
}
wordRubout := "[^\\pL\\pN][\\pL\\pN]"
wordNext := "[\\pL\\pN][^\\pL\\pN]|(.$)"
subWordRubout := "[a-z][A-Z]|[^\\pL\\pN][\\pL\\pN]"
subWordNext := "[a-z][A-Z]|[\\pL\\pN][^\\pL\\pN]|(.$)"
if opts.FileWord {
sep := regexp.QuoteMeta(string(os.PathSeparator))
wordRubout = fmt.Sprintf("%s[^%s]", sep, sep)
wordNext = fmt.Sprintf("[^%s]%s|(.$)", sep, sep)
}
keymapCopy := make(map[tui.Event][]*action)
for key, action := range opts.Keymap {
keymapCopy[key] = action
}
keymapCopy := maps.Clone(opts.Keymap)
t := Terminal{
initDelay: delay,
@@ -969,6 +976,8 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
markerMultiLine: *opts.MarkerMulti,
wordRubout: wordRubout,
wordNext: wordNext,
subWordRubout: subWordRubout,
subWordNext: subWordNext,
cx: len(input),
cy: 0,
offset: 0,
@@ -1083,10 +1092,27 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
// This should be called before accessing tui.Color*
tui.InitTheme(opts.Theme, renderer.DefaultTheme(), opts.Black, opts.InputBorderShape.Visible(), opts.HeaderBorderShape.Visible())
// Gutter character
var gutterChar string
if opts.Gutter != nil {
gutterChar = *opts.Gutter
} else if t.unicode && !t.theme.Gutter.Color.IsDefault() {
gutterChar = "▌"
} else {
gutterChar = " "
t.gutterReverse = true
}
t.prompt, t.promptLen = t.parsePrompt(opts.Prompt)
// Pre-calculated empty pointer and marker signs
t.pointerEmpty = strings.Repeat(" ", t.pointerLen)
if t.pointerLen == 0 {
t.pointerEmpty = ""
} else {
t.pointerEmpty = gutterChar + strings.Repeat(" ", util.Max(0, t.pointerLen-1))
}
t.markerEmpty = strings.Repeat(" ", t.markerLen)
// Labels
t.listLabel, t.listLabelLen = t.ansiLabelPrinter(opts.ListLabel.label, &tui.ColListLabel, false)
t.borderLabel, t.borderLabelLen = t.ansiLabelPrinter(opts.BorderLabel.label, &tui.ColBorderLabel, false)
t.previewLabel, t.previewLabelLen = t.ansiLabelPrinter(opts.PreviewLabel.label, &tui.ColPreviewLabel, false)
@@ -1394,7 +1420,7 @@ func (t *Terminal) ansiLabelPrinter(str string, color *tui.ColorPair, fill bool)
if !fill {
ellipsis, ellipsisWidth = util.Truncate(t.ellipsis, limit)
}
if length > limit-ellipsisWidth {
if length > limit {
trimmedRunes, _ := t.trimRight(runes, limit-ellipsisWidth)
window.CPrint(*color, string(trimmedRunes)+string(ellipsis))
} else if fill {
@@ -2371,6 +2397,13 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
innerHeight-shrink, tui.WindowList, noBorder, true)
}
if len(t.scrollbar) == 0 {
for y := 0; y < t.window.Height(); y++ {
t.window.Move(y, t.window.Width()-1)
t.window.Print(" ")
}
}
createInnerWindow := func(b tui.Window, shape tui.BorderShape, windowType tui.WindowType, shift int) tui.Window {
top := b.Top()
left := b.Left() + shift
@@ -2617,11 +2650,11 @@ func (t *Terminal) updatePromptOffset() ([]rune, []rune) {
}
maxWidth := util.Max(1, w.Width()-t.promptLen-1)
_, overflow := t.trimLeft(t.input[:t.cx], maxWidth)
_, overflow := t.trimLeft(t.input[:t.cx], maxWidth, 0)
minOffset := int(overflow)
maxOffset := minOffset + (maxWidth-util.Max(0, maxWidth-t.cx))/2
t.xoffset = util.Constrain(t.xoffset, minOffset, maxOffset)
before, _ := t.trimLeft(t.input[t.xoffset:t.cx], maxWidth)
before, _ := t.trimLeft(t.input[t.xoffset:t.cx], maxWidth, 0)
beforeLen := t.displayWidth(before)
after, _ := t.trimRight(t.input[t.cx:], maxWidth-beforeLen)
afterLen := t.displayWidth(after)
@@ -3085,9 +3118,21 @@ func (t *Terminal) renderEmptyLine(line int, barRange [2]int) {
t.renderBar(line, barRange)
}
func (t *Terminal) gutter(current bool) {
var color tui.ColorPair
if current {
color = tui.ColCurrentCursorEmpty
} else if t.gutterReverse {
color = tui.ColCursorEmpty
} else {
color = tui.ColCursorEmptyChar
}
t.window.CPrint(color, t.pointerEmpty)
}
func (t *Terminal) renderGapLine(line int, barRange [2]int, drawLine bool) {
t.move(line, 0, false)
t.window.CPrint(tui.ColCursorEmpty, t.pointerEmpty)
t.gutter(false)
t.window.Print(t.markerEmpty)
x := t.pointerLen + t.markerLen
@@ -3251,7 +3296,7 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu
return indentSize
}
if len(label) == 0 {
t.window.CPrint(tui.ColCurrentCursorEmpty, t.pointerEmpty)
t.gutter(true)
} else {
t.window.CPrint(tui.ColCurrentCursor, label)
}
@@ -3273,7 +3318,7 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu
return indentSize
}
if len(label) == 0 {
t.window.CPrint(tui.ColCursorEmpty, t.pointerEmpty)
t.gutter(false)
} else {
t.window.CPrint(tui.ColCursor, label)
}
@@ -3322,22 +3367,22 @@ func (t *Terminal) displayWidthWithLimit(runes []rune, prefixWidth int, limit in
return width
}
func (t *Terminal) trimLeft(runes []rune, width int) ([]rune, int32) {
func (t *Terminal) trimLeft(runes []rune, width int, ellipsisWidth int) ([]rune, int32) {
width = util.Max(0, width)
var trimmed int32
// Assume that each rune takes at least one column on screen
if len(runes) > width+2 {
diff := len(runes) - width - 2
if len(runes) > width {
diff := len(runes) - width
trimmed = int32(diff)
runes = runes[diff:]
}
currentWidth := t.displayWidth(runes)
for currentWidth > width && len(runes) > 0 {
for currentWidth > width-ellipsisWidth && len(runes) > 0 {
runes = runes[1:]
trimmed++
currentWidth = t.displayWidthWithLimit(runes, 2, width)
currentWidth = t.displayWidthWithLimit(runes, ellipsisWidth, width)
}
return runes, trimmed
}
@@ -3562,7 +3607,7 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
}
if t.hscroll {
if t.keepRight && pos == nil {
trimmed, diff := t.trimLeft(line, maxWidth-ellipsisWidth)
trimmed, diff := t.trimLeft(line, maxWidth, ellipsisWidth)
transformOffsets(diff, false)
line = append(ellipsis, trimmed...)
} else if !t.overflow(line[:maxe], maxWidth-ellipsisWidth) {
@@ -3578,7 +3623,7 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
}
// ..ri..
var diff int32
line, diff = t.trimLeft(line, maxWidth-ellipsisWidth)
line, diff = t.trimLeft(line, maxWidth, ellipsisWidth)
// Transform offsets
transformOffsets(diff, rightTrim)
@@ -3619,7 +3664,7 @@ func (t *Terminal) printColoredString(window tui.Window, text []rune, offsets []
for _, offset := range offsets {
b := util.Constrain32(offset.offset[0], index, maxOffset)
e := util.Constrain32(offset.offset[1], index, maxOffset)
if url != nil && offset.url == nil {
if url != nil && offset.url != url {
url = nil
window.LinkEnd()
}
@@ -6020,6 +6065,11 @@ func (t *Terminal) Loop() error {
if t.cx > 0 {
t.rubout(t.wordRubout)
}
case actBackwardKillSubWord:
beof = len(t.input) == 0
if t.cx > 0 {
t.rubout(t.subWordRubout)
}
case actYank:
suffix := copySlice(t.input[t.cx:])
t.input = append(append(t.input[:t.cx], t.yanked...), suffix...)
@@ -6131,6 +6181,10 @@ func (t *Terminal) Loop() error {
t.cx = findLastMatch(t.wordRubout, string(t.input[:t.cx])) + 1
case actForwardWord:
t.cx += findFirstMatch(t.wordNext, string(t.input[t.cx:])) + 1
case actBackwardSubWord:
t.cx = findLastMatch(t.subWordRubout, string(t.input[:t.cx])) + 1
case actForwardSubWord:
t.cx += findFirstMatch(t.subWordNext, string(t.input[t.cx:])) + 1
case actKillWord:
ncx := t.cx +
findFirstMatch(t.wordNext, string(t.input[t.cx:])) + 1
@@ -6138,6 +6192,13 @@ func (t *Terminal) Loop() error {
t.yanked = copySlice(t.input[t.cx:ncx])
t.input = append(t.input[:t.cx], t.input[ncx:]...)
}
case actKillSubWord:
ncx := t.cx +
findFirstMatch(t.subWordNext, string(t.input[t.cx:])) + 1
if ncx > t.cx {
t.yanked = copySlice(t.input[t.cx:ncx])
t.input = append(t.input[:t.cx], t.input[ncx:]...)
}
case actKillLine:
if t.cx < len(t.input) {
t.yanked = copySlice(t.input[t.cx:])

View File

@@ -37,86 +37,137 @@ func _() {
_ = x[CtrlZ-26]
_ = x[Esc-27]
_ = x[CtrlSpace-28]
_ = x[CtrlDelete-29]
_ = x[CtrlBackSlash-30]
_ = x[CtrlRightBracket-31]
_ = x[CtrlCaret-32]
_ = x[CtrlSlash-33]
_ = x[ShiftTab-34]
_ = x[Backspace-35]
_ = x[Delete-36]
_ = x[PageUp-37]
_ = x[PageDown-38]
_ = x[Up-39]
_ = x[Down-40]
_ = x[Left-41]
_ = x[Right-42]
_ = x[Home-43]
_ = x[End-44]
_ = x[Insert-45]
_ = x[ShiftUp-46]
_ = x[ShiftDown-47]
_ = x[ShiftLeft-48]
_ = x[ShiftRight-49]
_ = x[ShiftDelete-50]
_ = x[F1-51]
_ = x[F2-52]
_ = x[F3-53]
_ = x[F4-54]
_ = x[F5-55]
_ = x[F6-56]
_ = x[F7-57]
_ = x[F8-58]
_ = x[F9-59]
_ = x[F10-60]
_ = x[F11-61]
_ = x[F12-62]
_ = x[AltBackspace-63]
_ = x[AltUp-64]
_ = x[AltDown-65]
_ = x[AltLeft-66]
_ = x[AltRight-67]
_ = x[AltShiftUp-68]
_ = x[AltShiftDown-69]
_ = x[AltShiftLeft-70]
_ = x[AltShiftRight-71]
_ = x[Alt-72]
_ = x[CtrlAlt-73]
_ = x[Invalid-74]
_ = x[Fatal-75]
_ = x[BracketedPasteBegin-76]
_ = x[BracketedPasteEnd-77]
_ = x[Mouse-78]
_ = x[DoubleClick-79]
_ = x[LeftClick-80]
_ = x[RightClick-81]
_ = x[SLeftClick-82]
_ = x[SRightClick-83]
_ = x[ScrollUp-84]
_ = x[ScrollDown-85]
_ = x[SScrollUp-86]
_ = x[SScrollDown-87]
_ = x[PreviewScrollUp-88]
_ = x[PreviewScrollDown-89]
_ = x[Resize-90]
_ = x[Change-91]
_ = x[BackwardEOF-92]
_ = x[Start-93]
_ = x[Load-94]
_ = x[Focus-95]
_ = x[One-96]
_ = x[Zero-97]
_ = x[Result-98]
_ = x[Jump-99]
_ = x[JumpCancel-100]
_ = x[ClickHeader-101]
_ = x[ClickFooter-102]
_ = x[Multi-103]
_ = x[CtrlBackSlash-29]
_ = x[CtrlRightBracket-30]
_ = x[CtrlCaret-31]
_ = x[CtrlSlash-32]
_ = x[ShiftTab-33]
_ = x[Backspace-34]
_ = x[Delete-35]
_ = x[PageUp-36]
_ = x[PageDown-37]
_ = x[Up-38]
_ = x[Down-39]
_ = x[Left-40]
_ = x[Right-41]
_ = x[Home-42]
_ = x[End-43]
_ = x[Insert-44]
_ = x[ShiftUp-45]
_ = x[ShiftDown-46]
_ = x[ShiftLeft-47]
_ = x[ShiftRight-48]
_ = x[ShiftDelete-49]
_ = x[ShiftHome-50]
_ = x[ShiftEnd-51]
_ = x[ShiftPageUp-52]
_ = x[ShiftPageDown-53]
_ = x[F1-54]
_ = x[F2-55]
_ = x[F3-56]
_ = x[F4-57]
_ = x[F5-58]
_ = x[F6-59]
_ = x[F7-60]
_ = x[F8-61]
_ = x[F9-62]
_ = x[F10-63]
_ = x[F11-64]
_ = x[F12-65]
_ = x[AltBackspace-66]
_ = x[AltUp-67]
_ = x[AltDown-68]
_ = x[AltLeft-69]
_ = x[AltRight-70]
_ = x[AltDelete-71]
_ = x[AltHome-72]
_ = x[AltEnd-73]
_ = x[AltPageUp-74]
_ = x[AltPageDown-75]
_ = x[AltShiftUp-76]
_ = x[AltShiftDown-77]
_ = x[AltShiftLeft-78]
_ = x[AltShiftRight-79]
_ = x[AltShiftDelete-80]
_ = x[AltShiftHome-81]
_ = x[AltShiftEnd-82]
_ = x[AltShiftPageUp-83]
_ = x[AltShiftPageDown-84]
_ = x[CtrlUp-85]
_ = x[CtrlDown-86]
_ = x[CtrlLeft-87]
_ = x[CtrlRight-88]
_ = x[CtrlHome-89]
_ = x[CtrlEnd-90]
_ = x[CtrlBackspace-91]
_ = x[CtrlDelete-92]
_ = x[CtrlPageUp-93]
_ = x[CtrlPageDown-94]
_ = x[Alt-95]
_ = x[CtrlAlt-96]
_ = x[CtrlAltUp-97]
_ = x[CtrlAltDown-98]
_ = x[CtrlAltLeft-99]
_ = x[CtrlAltRight-100]
_ = x[CtrlAltHome-101]
_ = x[CtrlAltEnd-102]
_ = x[CtrlAltBackspace-103]
_ = x[CtrlAltDelete-104]
_ = x[CtrlAltPageUp-105]
_ = x[CtrlAltPageDown-106]
_ = x[CtrlShiftUp-107]
_ = x[CtrlShiftDown-108]
_ = x[CtrlShiftLeft-109]
_ = x[CtrlShiftRight-110]
_ = x[CtrlShiftHome-111]
_ = x[CtrlShiftEnd-112]
_ = x[CtrlShiftDelete-113]
_ = x[CtrlShiftPageUp-114]
_ = x[CtrlShiftPageDown-115]
_ = x[CtrlAltShiftUp-116]
_ = x[CtrlAltShiftDown-117]
_ = x[CtrlAltShiftLeft-118]
_ = x[CtrlAltShiftRight-119]
_ = x[CtrlAltShiftHome-120]
_ = x[CtrlAltShiftEnd-121]
_ = x[CtrlAltShiftDelete-122]
_ = x[CtrlAltShiftPageUp-123]
_ = x[CtrlAltShiftPageDown-124]
_ = x[Invalid-125]
_ = x[Fatal-126]
_ = x[BracketedPasteBegin-127]
_ = x[BracketedPasteEnd-128]
_ = x[Mouse-129]
_ = x[DoubleClick-130]
_ = x[LeftClick-131]
_ = x[RightClick-132]
_ = x[SLeftClick-133]
_ = x[SRightClick-134]
_ = x[ScrollUp-135]
_ = x[ScrollDown-136]
_ = x[SScrollUp-137]
_ = x[SScrollDown-138]
_ = x[PreviewScrollUp-139]
_ = x[PreviewScrollDown-140]
_ = x[Resize-141]
_ = x[Change-142]
_ = x[BackwardEOF-143]
_ = x[Start-144]
_ = x[Load-145]
_ = x[Focus-146]
_ = x[One-147]
_ = x[Zero-148]
_ = x[Result-149]
_ = x[Jump-150]
_ = x[JumpCancel-151]
_ = x[ClickHeader-152]
_ = x[ClickFooter-153]
_ = x[Multi-154]
}
const _EventType_name = "RuneCtrlACtrlBCtrlCCtrlDCtrlECtrlFCtrlGCtrlHTabCtrlJCtrlKCtrlLEnterCtrlNCtrlOCtrlPCtrlQCtrlRCtrlSCtrlTCtrlUCtrlVCtrlWCtrlXCtrlYCtrlZEscCtrlSpaceCtrlDeleteCtrlBackSlashCtrlRightBracketCtrlCaretCtrlSlashShiftTabBackspaceDeletePageUpPageDownUpDownLeftRightHomeEndInsertShiftUpShiftDownShiftLeftShiftRightShiftDeleteF1F2F3F4F5F6F7F8F9F10F11F12AltBackspaceAltUpAltDownAltLeftAltRightAltShiftUpAltShiftDownAltShiftLeftAltShiftRightAltCtrlAltInvalidFatalBracketedPasteBeginBracketedPasteEndMouseDoubleClickLeftClickRightClickSLeftClickSRightClickScrollUpScrollDownSScrollUpSScrollDownPreviewScrollUpPreviewScrollDownResizeChangeBackwardEOFStartLoadFocusOneZeroResultJumpJumpCancelClickHeaderClickFooterMulti"
const _EventType_name = "RuneCtrlACtrlBCtrlCCtrlDCtrlECtrlFCtrlGCtrlHTabCtrlJCtrlKCtrlLEnterCtrlNCtrlOCtrlPCtrlQCtrlRCtrlSCtrlTCtrlUCtrlVCtrlWCtrlXCtrlYCtrlZEscCtrlSpaceCtrlBackSlashCtrlRightBracketCtrlCaretCtrlSlashShiftTabBackspaceDeletePageUpPageDownUpDownLeftRightHomeEndInsertShiftUpShiftDownShiftLeftShiftRightShiftDeleteShiftHomeShiftEndShiftPageUpShiftPageDownF1F2F3F4F5F6F7F8F9F10F11F12AltBackspaceAltUpAltDownAltLeftAltRightAltDeleteAltHomeAltEndAltPageUpAltPageDownAltShiftUpAltShiftDownAltShiftLeftAltShiftRightAltShiftDeleteAltShiftHomeAltShiftEndAltShiftPageUpAltShiftPageDownCtrlUpCtrlDownCtrlLeftCtrlRightCtrlHomeCtrlEndCtrlBackspaceCtrlDeleteCtrlPageUpCtrlPageDownAltCtrlAltCtrlAltUpCtrlAltDownCtrlAltLeftCtrlAltRightCtrlAltHomeCtrlAltEndCtrlAltBackspaceCtrlAltDeleteCtrlAltPageUpCtrlAltPageDownCtrlShiftUpCtrlShiftDownCtrlShiftLeftCtrlShiftRightCtrlShiftHomeCtrlShiftEndCtrlShiftDeleteCtrlShiftPageUpCtrlShiftPageDownCtrlAltShiftUpCtrlAltShiftDownCtrlAltShiftLeftCtrlAltShiftRightCtrlAltShiftHomeCtrlAltShiftEndCtrlAltShiftDeleteCtrlAltShiftPageUpCtrlAltShiftPageDownInvalidFatalBracketedPasteBeginBracketedPasteEndMouseDoubleClickLeftClickRightClickSLeftClickSRightClickScrollUpScrollDownSScrollUpSScrollDownPreviewScrollUpPreviewScrollDownResizeChangeBackwardEOFStartLoadFocusOneZeroResultJumpJumpCancelClickHeaderClickFooterMulti"
var _EventType_index = [...]uint16{0, 4, 9, 14, 19, 24, 29, 34, 39, 44, 47, 52, 57, 62, 67, 72, 77, 82, 87, 92, 97, 102, 107, 112, 117, 122, 127, 132, 135, 144, 154, 167, 183, 192, 201, 209, 218, 224, 230, 238, 240, 244, 248, 253, 257, 260, 266, 273, 282, 291, 301, 312, 314, 316, 318, 320, 322, 324, 326, 328, 330, 333, 336, 339, 351, 356, 363, 370, 378, 388, 400, 412, 425, 428, 435, 442, 447, 466, 483, 488, 499, 508, 518, 528, 539, 547, 557, 566, 577, 592, 609, 615, 621, 632, 637, 641, 646, 649, 653, 659, 663, 673, 684, 695, 700}
var _EventType_index = [...]uint16{0, 4, 9, 14, 19, 24, 29, 34, 39, 44, 47, 52, 57, 62, 67, 72, 77, 82, 87, 92, 97, 102, 107, 112, 117, 122, 127, 132, 135, 144, 157, 173, 182, 191, 199, 208, 214, 220, 228, 230, 234, 238, 243, 247, 250, 256, 263, 272, 281, 291, 302, 311, 319, 330, 343, 345, 347, 349, 351, 353, 355, 357, 359, 361, 364, 367, 370, 382, 387, 394, 401, 409, 418, 425, 431, 440, 451, 461, 473, 485, 498, 512, 524, 535, 549, 565, 571, 579, 587, 596, 604, 611, 624, 634, 644, 656, 659, 666, 675, 686, 697, 709, 720, 730, 746, 759, 772, 787, 798, 811, 824, 838, 851, 863, 878, 893, 910, 924, 940, 956, 973, 989, 1004, 1022, 1040, 1060, 1067, 1072, 1091, 1108, 1113, 1124, 1133, 1143, 1153, 1164, 1172, 1182, 1191, 1202, 1217, 1234, 1240, 1246, 1257, 1262, 1266, 1271, 1274, 1278, 1284, 1288, 1298, 1309, 1320, 1325}
func (i EventType) String() string {
if i < 0 || i >= EventType(len(_EventType_index)-1) {

View File

@@ -335,6 +335,8 @@ func (r *LightRenderer) GetChar() Event {
return Event{CtrlQ, 0, nil}
case 127:
return Event{Backspace, 0, nil}
case 8:
return Event{CtrlBackspace, 0, nil}
case 0:
return Event{CtrlSpace, 0, nil}
case 28:
@@ -381,6 +383,9 @@ func (r *LightRenderer) escSequence(sz *int) Event {
}
*sz = 2
if r.buffer[1] == 8 {
return Event{CtrlAltBackspace, 0, nil}
}
if r.buffer[1] >= 1 && r.buffer[1] <= 'z'-'a'+1 {
return CtrlAltKey(rune(r.buffer[1] + 'a' - 1))
}
@@ -473,22 +478,139 @@ func (r *LightRenderer) escSequence(sz *int) Event {
if r.buffer[3] == '~' {
return Event{Delete, 0, nil}
}
if len(r.buffer) == 7 && r.buffer[6] == '~' && r.buffer[4] == '1' {
*sz = 7
switch r.buffer[5] {
case '0':
return Event{AltShiftDelete, 0, nil}
case '1':
return Event{AltDelete, 0, nil}
case '2':
return Event{AltShiftDelete, 0, nil}
case '3':
return Event{CtrlAltDelete, 0, nil}
case '4':
return Event{CtrlAltShiftDelete, 0, nil}
case '5':
return Event{CtrlAltDelete, 0, nil}
case '6':
return Event{CtrlAltShiftDelete, 0, nil}
}
}
if len(r.buffer) == 6 && r.buffer[5] == '~' {
*sz = 6
switch r.buffer[4] {
case '5':
return Event{CtrlDelete, 0, nil}
case '2':
return Event{ShiftDelete, 0, nil}
case '3':
return Event{AltDelete, 0, nil}
case '4':
return Event{AltShiftDelete, 0, nil}
case '5':
return Event{CtrlDelete, 0, nil}
case '6':
return Event{CtrlShiftDelete, 0, nil}
case '7':
return Event{CtrlAltDelete, 0, nil}
case '8':
return Event{CtrlAltShiftDelete, 0, nil}
case '9':
return Event{AltDelete, 0, nil}
}
}
return Event{Invalid, 0, nil}
case '4':
return Event{End, 0, nil}
case '5':
return Event{PageUp, 0, nil}
if r.buffer[3] == '~' {
return Event{PageUp, 0, nil}
}
if len(r.buffer) == 7 && r.buffer[6] == '~' && r.buffer[4] == '1' {
*sz = 7
switch r.buffer[5] {
case '0':
return Event{AltShiftPageUp, 0, nil}
case '1':
return Event{AltPageUp, 0, nil}
case '2':
return Event{AltShiftPageUp, 0, nil}
case '3':
return Event{CtrlAltPageUp, 0, nil}
case '4':
return Event{CtrlAltShiftPageUp, 0, nil}
case '5':
return Event{CtrlAltPageUp, 0, nil}
case '6':
return Event{CtrlAltShiftPageUp, 0, nil}
}
}
if len(r.buffer) == 6 && r.buffer[5] == '~' {
*sz = 6
switch r.buffer[4] {
case '2':
return Event{ShiftPageUp, 0, nil}
case '3':
return Event{AltPageUp, 0, nil}
case '4':
return Event{AltShiftPageUp, 0, nil}
case '5':
return Event{CtrlPageUp, 0, nil}
case '6':
return Event{CtrlShiftPageUp, 0, nil}
case '7':
return Event{CtrlAltPageUp, 0, nil}
case '8':
return Event{CtrlAltShiftPageUp, 0, nil}
case '9':
return Event{AltPageUp, 0, nil}
}
}
return Event{Invalid, 0, nil}
case '6':
return Event{PageDown, 0, nil}
if r.buffer[3] == '~' {
return Event{PageDown, 0, nil}
}
if len(r.buffer) == 7 && r.buffer[6] == '~' && r.buffer[4] == '1' {
*sz = 7
switch r.buffer[5] {
case '0':
return Event{AltShiftPageDown, 0, nil}
case '1':
return Event{AltPageDown, 0, nil}
case '2':
return Event{AltShiftPageDown, 0, nil}
case '3':
return Event{CtrlAltPageDown, 0, nil}
case '4':
return Event{CtrlAltShiftPageDown, 0, nil}
case '5':
return Event{CtrlAltPageDown, 0, nil}
case '6':
return Event{CtrlAltShiftPageDown, 0, nil}
}
}
if len(r.buffer) == 6 && r.buffer[5] == '~' {
*sz = 6
switch r.buffer[4] {
case '2':
return Event{ShiftPageDown, 0, nil}
case '3':
return Event{AltPageDown, 0, nil}
case '4':
return Event{AltShiftPageDown, 0, nil}
case '5':
return Event{CtrlPageDown, 0, nil}
case '6':
return Event{CtrlShiftPageDown, 0, nil}
case '7':
return Event{CtrlAltPageDown, 0, nil}
case '8':
return Event{CtrlAltShiftPageDown, 0, nil}
case '9':
return Event{AltPageDown, 0, nil}
}
}
return Event{Invalid, 0, nil}
case '7':
return Event{Home, 0, nil}
case '8':
@@ -526,63 +648,172 @@ func (r *LightRenderer) escSequence(sz *int) Event {
}
*sz = 6
switch r.buffer[4] {
case '1', '2', '3', '4', '5':
case '1', '2', '3', '4', '5', '6', '7', '8', '9':
// Kitty iTerm2 WezTerm
// SHIFT-ARROW "\e[1;2D"
// ALT-SHIFT-ARROW "\e[1;4D" "\e[1;10D" "\e[1;4D"
// CTRL-SHIFT-ARROW "\e[1;6D" N/A
// CMD-SHIFT-ARROW "\e[1;10D" N/A N/A ("\e[1;2D")
alt := r.buffer[4] == '3'
ctrl := bytes.IndexByte([]byte{'5', '6', '7', '8'}, r.buffer[4]) >= 0
alt := bytes.IndexByte([]byte{'3', '4', '7', '8'}, r.buffer[4]) >= 0
shift := bytes.IndexByte([]byte{'2', '4', '6', '8'}, r.buffer[4]) >= 0
char := r.buffer[5]
altShift := false
if r.buffer[4] == '1' && r.buffer[5] == '0' {
altShift = true
if len(r.buffer) < 7 {
return Event{Invalid, 0, nil}
}
*sz = 7
char = r.buffer[6]
} else if r.buffer[4] == '4' {
altShift = true
if r.buffer[4] == '9' {
ctrl = false
alt = true
shift = false
if len(r.buffer) < 6 {
return Event{Invalid, 0, nil}
}
*sz = 6
char = r.buffer[5]
} else if r.buffer[4] == '1' && bytes.IndexByte([]byte{'0', '1', '2', '3', '4', '5', '6'}, r.buffer[5]) >= 0 {
ctrl = bytes.IndexByte([]byte{'3', '4', '5', '6'}, r.buffer[5]) >= 0
alt = true
shift = bytes.IndexByte([]byte{'0', '2', '4', '6'}, r.buffer[5]) >= 0
if len(r.buffer) < 7 {
return Event{Invalid, 0, nil}
}
*sz = 7
char = r.buffer[6]
}
ctrlShift := ctrl && shift
ctrlAlt := ctrl && alt
altShift := alt && shift
ctrlAltShift := ctrl && alt && shift
switch char {
case 'A':
if alt {
return Event{AltUp, 0, nil}
if ctrlAltShift {
return Event{CtrlAltShiftUp, 0, nil}
}
if ctrlAlt {
return Event{CtrlAltUp, 0, nil}
}
if ctrlShift {
return Event{CtrlShiftUp, 0, nil}
}
if altShift {
return Event{AltShiftUp, 0, nil}
}
return Event{ShiftUp, 0, nil}
case 'B':
if ctrl {
return Event{CtrlUp, 0, nil}
}
if alt {
return Event{AltDown, 0, nil}
return Event{AltUp, 0, nil}
}
if shift {
return Event{ShiftUp, 0, nil}
}
case 'B':
if ctrlAltShift {
return Event{CtrlAltShiftDown, 0, nil}
}
if ctrlAlt {
return Event{CtrlAltDown, 0, nil}
}
if ctrlShift {
return Event{CtrlShiftDown, 0, nil}
}
if altShift {
return Event{AltShiftDown, 0, nil}
}
return Event{ShiftDown, 0, nil}
case 'C':
if ctrl {
return Event{CtrlDown, 0, nil}
}
if alt {
return Event{AltRight, 0, nil}
return Event{AltDown, 0, nil}
}
if shift {
return Event{ShiftDown, 0, nil}
}
case 'C':
if ctrlAltShift {
return Event{CtrlAltShiftRight, 0, nil}
}
if ctrlAlt {
return Event{CtrlAltRight, 0, nil}
}
if ctrlShift {
return Event{CtrlShiftRight, 0, nil}
}
if altShift {
return Event{AltShiftRight, 0, nil}
}
return Event{ShiftRight, 0, nil}
case 'D':
if ctrl {
return Event{CtrlRight, 0, nil}
}
if shift {
return Event{ShiftRight, 0, nil}
}
if alt {
return Event{AltLeft, 0, nil}
return Event{AltRight, 0, nil}
}
case 'D':
if ctrlAltShift {
return Event{CtrlAltShiftLeft, 0, nil}
}
if ctrlAlt {
return Event{CtrlAltLeft, 0, nil}
}
if ctrlShift {
return Event{CtrlShiftLeft, 0, nil}
}
if altShift {
return Event{AltShiftLeft, 0, nil}
}
return Event{ShiftLeft, 0, nil}
if ctrl {
return Event{CtrlLeft, 0, nil}
}
if alt {
return Event{AltLeft, 0, nil}
}
if shift {
return Event{ShiftLeft, 0, nil}
}
case 'H':
if ctrlAltShift {
return Event{CtrlAltShiftHome, 0, nil}
}
if ctrlAlt {
return Event{CtrlAltHome, 0, nil}
}
if ctrlShift {
return Event{CtrlShiftHome, 0, nil}
}
if altShift {
return Event{AltShiftHome, 0, nil}
}
if ctrl {
return Event{CtrlHome, 0, nil}
}
if alt {
return Event{AltHome, 0, nil}
}
if shift {
return Event{ShiftHome, 0, nil}
}
case 'F':
if ctrlAltShift {
return Event{CtrlAltShiftEnd, 0, nil}
}
if ctrlAlt {
return Event{CtrlAltEnd, 0, nil}
}
if ctrlShift {
return Event{CtrlShiftEnd, 0, nil}
}
if altShift {
return Event{AltShiftEnd, 0, nil}
}
if ctrl {
return Event{CtrlEnd, 0, nil}
}
if alt {
return Event{AltEnd, 0, nil}
}
if shift {
return Event{ShiftEnd, 0, nil}
}
}
} // r.buffer[4]
} // r.buffer[3]

335
src/tui/light_test.go Normal file
View File

@@ -0,0 +1,335 @@
package tui
import (
"fmt"
"os"
"testing"
"unicode"
)
func TestLightRenderer(t *testing.T) {
tty_file, _ := os.Open("")
renderer, _ := NewLightRenderer(
"", tty_file, &ColorTheme{}, true, false, 0, false, true,
func(h int) int { return h })
light_renderer := renderer.(*LightRenderer)
assertCharSequence := func(sequence string, name string) {
bytes := []byte(sequence)
light_renderer.buffer = bytes
event := light_renderer.GetChar()
if event.KeyName() != name {
t.Errorf(
"sequence: %q | %v | '%s' (%s) != %s",
string(bytes), bytes,
event.KeyName(), event.Type.String(), name)
}
}
assertEscSequence := func(sequence string, name string) {
bytes := []byte(sequence)
light_renderer.buffer = bytes
sz := 1
event := light_renderer.escSequence(&sz)
if fmt.Sprintf("!%s", event.Type.String()) == name {
// this is fine
} else if event.KeyName() != name {
t.Errorf(
"sequence: %q | %v | '%s' (%s) != %s",
string(bytes), bytes,
event.KeyName(), event.Type.String(), name)
}
}
// invalid
assertEscSequence("\x1b[<", "!Invalid")
assertEscSequence("\x1b[1;1R", "!Invalid")
assertEscSequence("\x1b[", "!Invalid")
assertEscSequence("\x1b[1", "!Invalid")
assertEscSequence("\x1b[3;3~1", "!Invalid")
assertEscSequence("\x1b[13", "!Invalid")
assertEscSequence("\x1b[1;3", "!Invalid")
assertEscSequence("\x1b[1;10", "!Invalid")
assertEscSequence("\x1b[220~", "!Invalid")
assertEscSequence("\x1b[5;30~", "!Invalid")
assertEscSequence("\x1b[6;30~", "!Invalid")
// general
for r := 'a'; r < 'z'; r++ {
lower_r := fmt.Sprintf("%c", r)
upper_r := fmt.Sprintf("%c", unicode.ToUpper(r))
assertCharSequence(lower_r, lower_r)
assertCharSequence(upper_r, upper_r)
}
assertCharSequence("\x01", "ctrl-a")
assertCharSequence("\x02", "ctrl-b")
assertCharSequence("\x03", "ctrl-c")
assertCharSequence("\x04", "ctrl-d")
assertCharSequence("\x05", "ctrl-e")
assertCharSequence("\x06", "ctrl-f")
assertCharSequence("\x07", "ctrl-g")
// ctrl-h is the same as ctrl-backspace
// ctrl-i is the same as tab
assertCharSequence("\n", "ctrl-j")
assertCharSequence("\x0b", "ctrl-k")
assertCharSequence("\x0c", "ctrl-l")
assertCharSequence("\r", "enter") // enter
assertCharSequence("\x0e", "ctrl-n")
assertCharSequence("\x0f", "ctrl-o")
assertCharSequence("\x10", "ctrl-p")
assertCharSequence("\x11", "ctrl-q")
assertCharSequence("\x12", "ctrl-r")
assertCharSequence("\x13", "ctrl-s")
assertCharSequence("\x14", "ctrl-t")
assertCharSequence("\x15", "ctrl-u")
assertCharSequence("\x16", "ctrl-v")
assertCharSequence("\x17", "ctrl-w")
assertCharSequence("\x18", "ctrl-x")
assertCharSequence("\x19", "ctrl-y")
assertCharSequence("\x1a", "ctrl-z")
assertCharSequence("\x00", "ctrl-space")
assertCharSequence("\x1c", "ctrl-\\")
assertCharSequence("\x1d", "ctrl-]")
assertCharSequence("\x1e", "ctrl-^")
assertCharSequence("\x1f", "ctrl-/")
assertEscSequence("\x1ba", "alt-a")
assertEscSequence("\x1bb", "alt-b")
assertEscSequence("\x1bc", "alt-c")
assertEscSequence("\x1bd", "alt-d")
assertEscSequence("\x1be", "alt-e")
assertEscSequence("\x1bf", "alt-f")
assertEscSequence("\x1bg", "alt-g")
assertEscSequence("\x1bh", "alt-h")
assertEscSequence("\x1bi", "alt-i")
assertEscSequence("\x1bj", "alt-j")
assertEscSequence("\x1bk", "alt-k")
assertEscSequence("\x1bl", "alt-l")
assertEscSequence("\x1bm", "alt-m")
assertEscSequence("\x1bn", "alt-n")
assertEscSequence("\x1bo", "alt-o")
assertEscSequence("\x1bp", "alt-p")
assertEscSequence("\x1bq", "alt-q")
assertEscSequence("\x1br", "alt-r")
assertEscSequence("\x1bs", "alt-s")
assertEscSequence("\x1bt", "alt-t")
assertEscSequence("\x1bu", "alt-u")
assertEscSequence("\x1bv", "alt-v")
assertEscSequence("\x1bw", "alt-w")
assertEscSequence("\x1bx", "alt-x")
assertEscSequence("\x1by", "alt-y")
assertEscSequence("\x1bz", "alt-z")
assertEscSequence("\x1bOP", "f1")
assertEscSequence("\x1bOQ", "f2")
assertEscSequence("\x1bOR", "f3")
assertEscSequence("\x1bOS", "f4")
assertEscSequence("\x1b[15~", "f5")
assertEscSequence("\x1b[17~", "f6")
assertEscSequence("\x1b[18~", "f7")
assertEscSequence("\x1b[19~", "f8")
assertEscSequence("\x1b[20~", "f9")
assertEscSequence("\x1b[21~", "f10")
assertEscSequence("\x1b[23~", "f11")
assertEscSequence("\x1b[24~", "f12")
assertEscSequence("\x1b", "esc")
assertCharSequence("\t", "tab")
assertEscSequence("\x1b[Z", "shift-tab")
assertCharSequence("\x7f", "backspace")
assertEscSequence("\x1b\x7f", "alt-backspace")
assertCharSequence("\b", "ctrl-backspace")
assertEscSequence("\x1b\b", "ctrl-alt-backspace")
assertEscSequence("\x1b[A", "up")
assertEscSequence("\x1b[B", "down")
assertEscSequence("\x1b[C", "right")
assertEscSequence("\x1b[D", "left")
assertEscSequence("\x1b[H", "home")
assertEscSequence("\x1b[F", "end")
assertEscSequence("\x1b[2~", "insert")
assertEscSequence("\x1b[3~", "delete")
assertEscSequence("\x1b[5~", "page-up")
assertEscSequence("\x1b[6~", "page-down")
assertEscSequence("\x1b[7~", "home")
assertEscSequence("\x1b[8~", "end")
assertEscSequence("\x1b[1;2A", "shift-up")
assertEscSequence("\x1b[1;2B", "shift-down")
assertEscSequence("\x1b[1;2C", "shift-right")
assertEscSequence("\x1b[1;2D", "shift-left")
assertEscSequence("\x1b[1;2H", "shift-home")
assertEscSequence("\x1b[1;2F", "shift-end")
assertEscSequence("\x1b[3;2~", "shift-delete")
assertEscSequence("\x1b[5;2~", "shift-page-up")
assertEscSequence("\x1b[6;2~", "shift-page-down")
assertEscSequence("\x1b\x1b", "esc")
assertEscSequence("\x1b\x1b[A", "alt-up")
assertEscSequence("\x1b\x1b[B", "alt-down")
assertEscSequence("\x1b\x1b[C", "alt-right")
assertEscSequence("\x1b\x1b[D", "alt-left")
assertEscSequence("\x1b[1;3A", "alt-up")
assertEscSequence("\x1b[1;3B", "alt-down")
assertEscSequence("\x1b[1;3C", "alt-right")
assertEscSequence("\x1b[1;3D", "alt-left")
assertEscSequence("\x1b[1;3H", "alt-home")
assertEscSequence("\x1b[1;3F", "alt-end")
assertEscSequence("\x1b[3;3~", "alt-delete")
assertEscSequence("\x1b[5;3~", "alt-page-up")
assertEscSequence("\x1b[6;3~", "alt-page-down")
assertEscSequence("\x1b[1;4A", "alt-shift-up")
assertEscSequence("\x1b[1;4B", "alt-shift-down")
assertEscSequence("\x1b[1;4C", "alt-shift-right")
assertEscSequence("\x1b[1;4D", "alt-shift-left")
assertEscSequence("\x1b[1;4H", "alt-shift-home")
assertEscSequence("\x1b[1;4F", "alt-shift-end")
assertEscSequence("\x1b[3;4~", "alt-shift-delete")
assertEscSequence("\x1b[5;4~", "alt-shift-page-up")
assertEscSequence("\x1b[6;4~", "alt-shift-page-down")
assertEscSequence("\x1b[1;5A", "ctrl-up")
assertEscSequence("\x1b[1;5B", "ctrl-down")
assertEscSequence("\x1b[1;5C", "ctrl-right")
assertEscSequence("\x1b[1;5D", "ctrl-left")
assertEscSequence("\x1b[1;5H", "ctrl-home")
assertEscSequence("\x1b[1;5F", "ctrl-end")
assertEscSequence("\x1b[3;5~", "ctrl-delete")
assertEscSequence("\x1b[5;5~", "ctrl-page-up")
assertEscSequence("\x1b[6;5~", "ctrl-page-down")
assertEscSequence("\x1b[1;7A", "ctrl-alt-up")
assertEscSequence("\x1b[1;7B", "ctrl-alt-down")
assertEscSequence("\x1b[1;7C", "ctrl-alt-right")
assertEscSequence("\x1b[1;7D", "ctrl-alt-left")
assertEscSequence("\x1b[1;7H", "ctrl-alt-home")
assertEscSequence("\x1b[1;7F", "ctrl-alt-end")
assertEscSequence("\x1b[3;7~", "ctrl-alt-delete")
assertEscSequence("\x1b[5;7~", "ctrl-alt-page-up")
assertEscSequence("\x1b[6;7~", "ctrl-alt-page-down")
assertEscSequence("\x1b[1;6A", "ctrl-shift-up")
assertEscSequence("\x1b[1;6B", "ctrl-shift-down")
assertEscSequence("\x1b[1;6C", "ctrl-shift-right")
assertEscSequence("\x1b[1;6D", "ctrl-shift-left")
assertEscSequence("\x1b[1;6H", "ctrl-shift-home")
assertEscSequence("\x1b[1;6F", "ctrl-shift-end")
assertEscSequence("\x1b[3;6~", "ctrl-shift-delete")
assertEscSequence("\x1b[5;6~", "ctrl-shift-page-up")
assertEscSequence("\x1b[6;6~", "ctrl-shift-page-down")
assertEscSequence("\x1b[1;8A", "ctrl-alt-shift-up")
assertEscSequence("\x1b[1;8B", "ctrl-alt-shift-down")
assertEscSequence("\x1b[1;8C", "ctrl-alt-shift-right")
assertEscSequence("\x1b[1;8D", "ctrl-alt-shift-left")
assertEscSequence("\x1b[1;8H", "ctrl-alt-shift-home")
assertEscSequence("\x1b[1;8F", "ctrl-alt-shift-end")
assertEscSequence("\x1b[3;8~", "ctrl-alt-shift-delete")
assertEscSequence("\x1b[5;8~", "ctrl-alt-shift-page-up")
assertEscSequence("\x1b[6;8~", "ctrl-alt-shift-page-down")
// xterm meta & mac
assertEscSequence("\x1b[1;9A", "alt-up")
assertEscSequence("\x1b[1;9B", "alt-down")
assertEscSequence("\x1b[1;9C", "alt-right")
assertEscSequence("\x1b[1;9D", "alt-left")
assertEscSequence("\x1b[1;9H", "alt-home")
assertEscSequence("\x1b[1;9F", "alt-end")
assertEscSequence("\x1b[3;9~", "alt-delete")
assertEscSequence("\x1b[5;9~", "alt-page-up")
assertEscSequence("\x1b[6;9~", "alt-page-down")
assertEscSequence("\x1b[1;10A", "alt-shift-up")
assertEscSequence("\x1b[1;10B", "alt-shift-down")
assertEscSequence("\x1b[1;10C", "alt-shift-right")
assertEscSequence("\x1b[1;10D", "alt-shift-left")
assertEscSequence("\x1b[1;10H", "alt-shift-home")
assertEscSequence("\x1b[1;10F", "alt-shift-end")
assertEscSequence("\x1b[3;10~", "alt-shift-delete")
assertEscSequence("\x1b[5;10~", "alt-shift-page-up")
assertEscSequence("\x1b[6;10~", "alt-shift-page-down")
assertEscSequence("\x1b[1;11A", "alt-up")
assertEscSequence("\x1b[1;11B", "alt-down")
assertEscSequence("\x1b[1;11C", "alt-right")
assertEscSequence("\x1b[1;11D", "alt-left")
assertEscSequence("\x1b[1;11H", "alt-home")
assertEscSequence("\x1b[1;11F", "alt-end")
assertEscSequence("\x1b[3;11~", "alt-delete")
assertEscSequence("\x1b[5;11~", "alt-page-up")
assertEscSequence("\x1b[6;11~", "alt-page-down")
assertEscSequence("\x1b[1;12A", "alt-shift-up")
assertEscSequence("\x1b[1;12B", "alt-shift-down")
assertEscSequence("\x1b[1;12C", "alt-shift-right")
assertEscSequence("\x1b[1;12D", "alt-shift-left")
assertEscSequence("\x1b[1;12H", "alt-shift-home")
assertEscSequence("\x1b[1;12F", "alt-shift-end")
assertEscSequence("\x1b[3;12~", "alt-shift-delete")
assertEscSequence("\x1b[5;12~", "alt-shift-page-up")
assertEscSequence("\x1b[6;12~", "alt-shift-page-down")
assertEscSequence("\x1b[1;13A", "ctrl-alt-up")
assertEscSequence("\x1b[1;13B", "ctrl-alt-down")
assertEscSequence("\x1b[1;13C", "ctrl-alt-right")
assertEscSequence("\x1b[1;13D", "ctrl-alt-left")
assertEscSequence("\x1b[1;13H", "ctrl-alt-home")
assertEscSequence("\x1b[1;13F", "ctrl-alt-end")
assertEscSequence("\x1b[3;13~", "ctrl-alt-delete")
assertEscSequence("\x1b[5;13~", "ctrl-alt-page-up")
assertEscSequence("\x1b[6;13~", "ctrl-alt-page-down")
assertEscSequence("\x1b[1;14A", "ctrl-alt-shift-up")
assertEscSequence("\x1b[1;14B", "ctrl-alt-shift-down")
assertEscSequence("\x1b[1;14C", "ctrl-alt-shift-right")
assertEscSequence("\x1b[1;14D", "ctrl-alt-shift-left")
assertEscSequence("\x1b[1;14H", "ctrl-alt-shift-home")
assertEscSequence("\x1b[1;14F", "ctrl-alt-shift-end")
assertEscSequence("\x1b[3;14~", "ctrl-alt-shift-delete")
assertEscSequence("\x1b[5;14~", "ctrl-alt-shift-page-up")
assertEscSequence("\x1b[6;14~", "ctrl-alt-shift-page-down")
assertEscSequence("\x1b[1;15A", "ctrl-alt-up")
assertEscSequence("\x1b[1;15B", "ctrl-alt-down")
assertEscSequence("\x1b[1;15C", "ctrl-alt-right")
assertEscSequence("\x1b[1;15D", "ctrl-alt-left")
assertEscSequence("\x1b[1;15H", "ctrl-alt-home")
assertEscSequence("\x1b[1;15F", "ctrl-alt-end")
assertEscSequence("\x1b[3;15~", "ctrl-alt-delete")
assertEscSequence("\x1b[5;15~", "ctrl-alt-page-up")
assertEscSequence("\x1b[6;15~", "ctrl-alt-page-down")
assertEscSequence("\x1b[1;16A", "ctrl-alt-shift-up")
assertEscSequence("\x1b[1;16B", "ctrl-alt-shift-down")
assertEscSequence("\x1b[1;16C", "ctrl-alt-shift-right")
assertEscSequence("\x1b[1;16D", "ctrl-alt-shift-left")
assertEscSequence("\x1b[1;16H", "ctrl-alt-shift-home")
assertEscSequence("\x1b[1;16F", "ctrl-alt-shift-end")
assertEscSequence("\x1b[3;16~", "ctrl-alt-shift-delete")
assertEscSequence("\x1b[5;16~", "ctrl-alt-shift-page-up")
assertEscSequence("\x1b[6;16~", "ctrl-alt-shift-page-down")
// tmux & emacs
assertEscSequence("\x1bOA", "up")
assertEscSequence("\x1bOB", "down")
assertEscSequence("\x1bOC", "right")
assertEscSequence("\x1bOD", "left")
assertEscSequence("\x1bOH", "home")
assertEscSequence("\x1bOF", "end")
// rrvt
assertEscSequence("\x1b[1~", "home")
assertEscSequence("\x1b[4~", "end")
assertEscSequence("\x1b[11~", "f1")
assertEscSequence("\x1b[12~", "f2")
assertEscSequence("\x1b[13~", "f3")
assertEscSequence("\x1b[14~", "f4")
}

View File

@@ -354,6 +354,8 @@ func (r *FullscreenRenderer) GetChar() Event {
shift := (mods & tcell.ModShift) > 0
ctrlAlt := ctrl && alt
altShift := alt && shift
ctrlShift := ctrl && shift
ctrlAltShift := ctrl && alt && shift
keyfn := func(r rune) Event {
if alt {
@@ -380,8 +382,11 @@ func (r *FullscreenRenderer) GetChar() Event {
case tcell.KeyCtrlH:
switch ev.Rune() {
case 0:
if ctrlAlt {
return Event{CtrlAltBackspace, 0, nil}
}
if ctrl {
return Event{Backspace, 0, nil}
return Event{CtrlBackspace, 0, nil}
}
case rune(tcell.KeyCtrlH):
switch {
@@ -442,6 +447,9 @@ func (r *FullscreenRenderer) GetChar() Event {
return Event{CtrlSlash, 0, nil}
// section 3: (Alt)+Backspace2
case tcell.KeyBackspace2:
if ctrl {
return Event{CtrlBackspace, 0, nil}
}
if alt {
return Event{AltBackspace, 0, nil}
}
@@ -449,9 +457,21 @@ func (r *FullscreenRenderer) GetChar() Event {
// section 4: (Alt+Shift)+Key(Up|Down|Left|Right)
case tcell.KeyUp:
if ctrlAltShift {
return Event{CtrlAltShiftUp, 0, nil}
}
if ctrlAlt {
return Event{CtrlAltUp, 0, nil}
}
if ctrlShift {
return Event{CtrlShiftUp, 0, nil}
}
if altShift {
return Event{AltShiftUp, 0, nil}
}
if ctrl {
return Event{CtrlUp, 0, nil}
}
if shift {
return Event{ShiftUp, 0, nil}
}
@@ -460,9 +480,21 @@ func (r *FullscreenRenderer) GetChar() Event {
}
return Event{Up, 0, nil}
case tcell.KeyDown:
if ctrlAltShift {
return Event{CtrlAltShiftDown, 0, nil}
}
if ctrlAlt {
return Event{CtrlAltDown, 0, nil}
}
if ctrlShift {
return Event{CtrlShiftDown, 0, nil}
}
if altShift {
return Event{AltShiftDown, 0, nil}
}
if ctrl {
return Event{CtrlDown, 0, nil}
}
if shift {
return Event{ShiftDown, 0, nil}
}
@@ -471,9 +503,21 @@ func (r *FullscreenRenderer) GetChar() Event {
}
return Event{Down, 0, nil}
case tcell.KeyLeft:
if ctrlAltShift {
return Event{CtrlAltShiftLeft, 0, nil}
}
if ctrlAlt {
return Event{CtrlAltLeft, 0, nil}
}
if ctrlShift {
return Event{CtrlShiftLeft, 0, nil}
}
if altShift {
return Event{AltShiftLeft, 0, nil}
}
if ctrl {
return Event{CtrlLeft, 0, nil}
}
if shift {
return Event{ShiftLeft, 0, nil}
}
@@ -482,9 +526,21 @@ func (r *FullscreenRenderer) GetChar() Event {
}
return Event{Left, 0, nil}
case tcell.KeyRight:
if ctrlAltShift {
return Event{CtrlAltShiftRight, 0, nil}
}
if ctrlAlt {
return Event{CtrlAltRight, 0, nil}
}
if ctrlShift {
return Event{CtrlShiftRight, 0, nil}
}
if altShift {
return Event{AltShiftRight, 0, nil}
}
if ctrl {
return Event{CtrlRight, 0, nil}
}
if shift {
return Event{ShiftRight, 0, nil}
}
@@ -497,20 +553,119 @@ func (r *FullscreenRenderer) GetChar() Event {
case tcell.KeyInsert:
return Event{Insert, 0, nil}
case tcell.KeyHome:
if ctrlAltShift {
return Event{CtrlAltShiftHome, 0, nil}
}
if ctrlAlt {
return Event{CtrlAltHome, 0, nil}
}
if ctrlShift {
return Event{CtrlShiftHome, 0, nil}
}
if altShift {
return Event{AltShiftHome, 0, nil}
}
if ctrl {
return Event{CtrlHome, 0, nil}
}
if shift {
return Event{ShiftHome, 0, nil}
}
if alt {
return Event{AltHome, 0, nil}
}
return Event{Home, 0, nil}
case tcell.KeyDelete:
if ctrlAltShift {
return Event{CtrlAltShiftDelete, 0, nil}
}
if ctrlAlt {
return Event{CtrlAltDelete, 0, nil}
}
if ctrlShift {
return Event{CtrlShiftDelete, 0, nil}
}
if altShift {
return Event{AltShiftDelete, 0, nil}
}
if ctrl {
return Event{CtrlDelete, 0, nil}
}
if alt {
return Event{AltDelete, 0, nil}
}
if shift {
return Event{ShiftDelete, 0, nil}
}
return Event{Delete, 0, nil}
case tcell.KeyEnd:
if ctrlAltShift {
return Event{CtrlAltShiftEnd, 0, nil}
}
if ctrlAlt {
return Event{CtrlAltEnd, 0, nil}
}
if ctrlShift {
return Event{CtrlShiftEnd, 0, nil}
}
if altShift {
return Event{AltShiftEnd, 0, nil}
}
if ctrl {
return Event{CtrlEnd, 0, nil}
}
if shift {
return Event{ShiftEnd, 0, nil}
}
if alt {
return Event{AltEnd, 0, nil}
}
return Event{End, 0, nil}
case tcell.KeyPgUp:
if ctrlAltShift {
return Event{CtrlAltShiftPageUp, 0, nil}
}
if ctrlAlt {
return Event{CtrlAltPageUp, 0, nil}
}
if ctrlShift {
return Event{CtrlShiftPageUp, 0, nil}
}
if altShift {
return Event{AltShiftPageUp, 0, nil}
}
if ctrl {
return Event{CtrlPageUp, 0, nil}
}
if shift {
return Event{ShiftPageUp, 0, nil}
}
if alt {
return Event{AltPageUp, 0, nil}
}
return Event{PageUp, 0, nil}
case tcell.KeyPgDn:
if ctrlAltShift {
return Event{CtrlAltShiftPageDown, 0, nil}
}
if ctrlAlt {
return Event{CtrlAltPageDown, 0, nil}
}
if ctrlShift {
return Event{CtrlShiftPageDown, 0, nil}
}
if altShift {
return Event{AltShiftPageDown, 0, nil}
}
if ctrl {
return Event{CtrlPageDown, 0, nil}
}
if shift {
return Event{ShiftPageDown, 0, nil}
}
if alt {
return Event{AltPageDown, 0, nil}
}
return Event{PageDown, 0, nil}
case tcell.KeyBacktab:
return Event{ShiftTab, 0, nil}
@@ -569,13 +724,13 @@ func (r *FullscreenRenderer) GetChar() Event {
func (r *FullscreenRenderer) Pause(clear bool) {
if clear {
r.Close()
_screen.Suspend()
}
}
func (r *FullscreenRenderer) Resume(clear bool, sigcont bool) {
if clear {
r.initScreen()
_screen.Resume()
}
}

View File

@@ -107,18 +107,20 @@ func TestGetCharEventKey(t *testing.T) {
{giveKey{tcell.KeyBackspace2, 0, tcell.ModAlt}, wantKey{AltBackspace, 0, nil}}, // fabricated
{giveKey{tcell.KeyDEL, 0, tcell.ModNone}, wantKey{Backspace, 0, nil}}, // fabricated, unhandled
{giveKey{tcell.KeyDelete, 0, tcell.ModNone}, wantKey{Delete, 0, nil}},
{giveKey{tcell.KeyDelete, 0, tcell.ModAlt}, wantKey{Delete, 0, nil}},
{giveKey{tcell.KeyDelete, 0, tcell.ModAlt}, wantKey{AltDelete, 0, nil}},
{giveKey{tcell.KeyBackspace, 0, tcell.ModCtrl}, wantKey{CtrlBackspace, 0, nil}},
{giveKey{tcell.KeyBackspace, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltBackspace, 0, nil}},
{giveKey{tcell.KeyBackspace, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
{giveKey{tcell.KeyBS, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
{giveKey{tcell.KeyCtrlH, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModNone}, wantKey{Backspace, 0, nil}}, // actual "Backspace" keystroke
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModAlt}, wantKey{AltBackspace, 0, nil}}, // actual "Alt+Backspace" keystroke
{giveKey{tcell.KeyDEL, rune(tcell.KeyDEL), tcell.ModCtrl}, wantKey{Backspace, 0, nil}}, // actual "Ctrl+Backspace" keystroke
{giveKey{tcell.KeyDEL, rune(tcell.KeyDEL), tcell.ModCtrl}, wantKey{CtrlBackspace, 0, nil}}, // actual "Ctrl+Backspace" keystroke
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModShift}, wantKey{Backspace, 0, nil}}, // actual "Shift+Backspace" keystroke
{giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{Backspace, 0, nil}}, // actual "Ctrl+Alt+Backspace" keystroke
{giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{Backspace, 0, nil}}, // actual "Ctrl+Shift+Backspace" keystroke
{giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltBackspace, 0, nil}}, // actual "Ctrl+Alt+Backspace" keystroke
{giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlBackspace, 0, nil}}, // actual "Ctrl+Shift+Backspace" keystroke
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModShift | tcell.ModAlt}, wantKey{AltBackspace, 0, nil}}, // actual "Shift+Alt+Backspace" keystroke
{giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModAlt | tcell.ModShift}, wantKey{Backspace, 0, nil}}, // actual "Ctrl+Shift+Alt+Backspace" keystroke
{giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModAlt | tcell.ModShift}, wantKey{CtrlAltBackspace, 0, nil}}, // actual "Ctrl+Shift+Alt+Backspace" keystroke
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl}, wantKey{CtrlH, 0, nil}}, // actual "Ctrl+H" keystroke
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAlt, 'h', nil}}, // fabricated "Ctrl+Alt+H" keystroke
{giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlH, 0, nil}}, // actual "Ctrl+Shift+H" keystroke
@@ -126,9 +128,41 @@ func TestGetCharEventKey(t *testing.T) {
// section 4: (Alt+Shift)+Key(Up|Down|Left|Right)
{giveKey{tcell.KeyUp, 0, tcell.ModNone}, wantKey{Up, 0, nil}},
{giveKey{tcell.KeyDown, 0, tcell.ModAlt}, wantKey{AltDown, 0, nil}},
{giveKey{tcell.KeyDown, 0, tcell.ModNone}, wantKey{Down, 0, nil}},
{giveKey{tcell.KeyLeft, 0, tcell.ModNone}, wantKey{Left, 0, nil}},
{giveKey{tcell.KeyRight, 0, tcell.ModNone}, wantKey{Right, 0, nil}},
{giveKey{tcell.KeyUp, 0, tcell.ModNone}, wantKey{Up, 0, nil}},
{giveKey{tcell.KeyDown, 0, tcell.ModNone}, wantKey{Down, 0, nil}},
{giveKey{tcell.KeyRight, 0, tcell.ModNone}, wantKey{Right, 0, nil}},
{giveKey{tcell.KeyLeft, 0, tcell.ModNone}, wantKey{Left, 0, nil}},
{giveKey{tcell.KeyUp, 0, tcell.ModCtrl}, wantKey{CtrlUp, 0, nil}},
{giveKey{tcell.KeyDown, 0, tcell.ModCtrl}, wantKey{CtrlDown, 0, nil}},
{giveKey{tcell.KeyRight, 0, tcell.ModCtrl}, wantKey{CtrlRight, 0, nil}},
{giveKey{tcell.KeyLeft, 0, tcell.ModCtrl}, wantKey{CtrlLeft, 0, nil}},
{giveKey{tcell.KeyUp, 0, tcell.ModShift}, wantKey{ShiftUp, 0, nil}},
{giveKey{tcell.KeyDown, 0, tcell.ModShift}, wantKey{ShiftDown, 0, nil}},
{giveKey{tcell.KeyRight, 0, tcell.ModShift}, wantKey{ShiftRight, 0, nil}},
{giveKey{tcell.KeyLeft, 0, tcell.ModShift}, wantKey{ShiftLeft, 0, nil}},
{giveKey{tcell.KeyUp, 0, tcell.ModAlt}, wantKey{AltUp, 0, nil}},
{giveKey{tcell.KeyDown, 0, tcell.ModAlt}, wantKey{AltDown, 0, nil}},
{giveKey{tcell.KeyRight, 0, tcell.ModAlt}, wantKey{AltRight, 0, nil}},
{giveKey{tcell.KeyLeft, 0, tcell.ModAlt}, wantKey{AltLeft, 0, nil}},
{giveKey{tcell.KeyUp, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlShiftUp, 0, nil}},
{giveKey{tcell.KeyDown, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlShiftDown, 0, nil}},
{giveKey{tcell.KeyRight, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlShiftRight, 0, nil}},
{giveKey{tcell.KeyLeft, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlShiftLeft, 0, nil}},
{giveKey{tcell.KeyUp, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltUp, 0, nil}},
{giveKey{tcell.KeyDown, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltDown, 0, nil}},
{giveKey{tcell.KeyRight, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltRight, 0, nil}},
{giveKey{tcell.KeyLeft, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltLeft, 0, nil}},
{giveKey{tcell.KeyUp, 0, tcell.ModShift | tcell.ModAlt}, wantKey{AltShiftUp, 0, nil}},
{giveKey{tcell.KeyDown, 0, tcell.ModShift | tcell.ModAlt}, wantKey{AltShiftDown, 0, nil}},
{giveKey{tcell.KeyRight, 0, tcell.ModShift | tcell.ModAlt}, wantKey{AltShiftRight, 0, nil}},
{giveKey{tcell.KeyLeft, 0, tcell.ModShift | tcell.ModAlt}, wantKey{AltShiftLeft, 0, nil}},
{giveKey{tcell.KeyUp, 0, tcell.ModCtrl | tcell.ModShift | tcell.ModAlt}, wantKey{CtrlAltShiftUp, 0, nil}},
{giveKey{tcell.KeyDown, 0, tcell.ModCtrl | tcell.ModShift | tcell.ModAlt}, wantKey{CtrlAltShiftDown, 0, nil}},
{giveKey{tcell.KeyRight, 0, tcell.ModCtrl | tcell.ModShift | tcell.ModAlt}, wantKey{CtrlAltShiftRight, 0, nil}},
{giveKey{tcell.KeyLeft, 0, tcell.ModCtrl | tcell.ModShift | tcell.ModAlt}, wantKey{CtrlAltShiftLeft, 0, nil}},
{giveKey{tcell.KeyUpLeft, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
{giveKey{tcell.KeyUpRight, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
{giveKey{tcell.KeyDownLeft, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
@@ -137,6 +171,46 @@ func TestGetCharEventKey(t *testing.T) {
// section 5: (Insert|Home|Delete|End|PgUp|PgDn|BackTab|F1-F12)
{giveKey{tcell.KeyInsert, 0, tcell.ModNone}, wantKey{Insert, 0, nil}},
{giveKey{tcell.KeyF1, 0, tcell.ModNone}, wantKey{F1, 0, nil}},
{giveKey{tcell.KeyHome, 0, tcell.ModNone}, wantKey{Home, 0, nil}},
{giveKey{tcell.KeyEnd, 0, tcell.ModNone}, wantKey{End, 0, nil}},
{giveKey{tcell.KeyDelete, 0, tcell.ModNone}, wantKey{Delete, 0, nil}},
{giveKey{tcell.KeyPgUp, 0, tcell.ModNone}, wantKey{PageUp, 0, nil}},
{giveKey{tcell.KeyPgDn, 0, tcell.ModNone}, wantKey{PageDown, 0, nil}},
{giveKey{tcell.KeyHome, 0, tcell.ModCtrl}, wantKey{CtrlHome, 0, nil}},
{giveKey{tcell.KeyEnd, 0, tcell.ModCtrl}, wantKey{CtrlEnd, 0, nil}},
{giveKey{tcell.KeyDelete, 0, tcell.ModCtrl}, wantKey{CtrlDelete, 0, nil}},
{giveKey{tcell.KeyPgUp, 0, tcell.ModCtrl}, wantKey{CtrlPageUp, 0, nil}},
{giveKey{tcell.KeyPgDn, 0, tcell.ModCtrl}, wantKey{CtrlPageDown, 0, nil}},
{giveKey{tcell.KeyHome, 0, tcell.ModShift}, wantKey{ShiftHome, 0, nil}},
{giveKey{tcell.KeyEnd, 0, tcell.ModShift}, wantKey{ShiftEnd, 0, nil}},
{giveKey{tcell.KeyDelete, 0, tcell.ModShift}, wantKey{ShiftDelete, 0, nil}},
{giveKey{tcell.KeyPgUp, 0, tcell.ModShift}, wantKey{ShiftPageUp, 0, nil}},
{giveKey{tcell.KeyPgDn, 0, tcell.ModShift}, wantKey{ShiftPageDown, 0, nil}},
{giveKey{tcell.KeyHome, 0, tcell.ModAlt}, wantKey{AltHome, 0, nil}},
{giveKey{tcell.KeyEnd, 0, tcell.ModAlt}, wantKey{AltEnd, 0, nil}},
{giveKey{tcell.KeyDelete, 0, tcell.ModAlt}, wantKey{AltDelete, 0, nil}},
{giveKey{tcell.KeyPgUp, 0, tcell.ModAlt}, wantKey{AltPageUp, 0, nil}},
{giveKey{tcell.KeyPgDn, 0, tcell.ModAlt}, wantKey{AltPageDown, 0, nil}},
{giveKey{tcell.KeyHome, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlShiftHome, 0, nil}},
{giveKey{tcell.KeyEnd, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlShiftEnd, 0, nil}},
{giveKey{tcell.KeyDelete, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlShiftDelete, 0, nil}},
{giveKey{tcell.KeyPgUp, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlShiftPageUp, 0, nil}},
{giveKey{tcell.KeyPgDn, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlShiftPageDown, 0, nil}},
{giveKey{tcell.KeyHome, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltHome, 0, nil}},
{giveKey{tcell.KeyEnd, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltEnd, 0, nil}},
{giveKey{tcell.KeyDelete, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltDelete, 0, nil}},
{giveKey{tcell.KeyPgUp, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltPageUp, 0, nil}},
{giveKey{tcell.KeyPgDn, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltPageDown, 0, nil}},
{giveKey{tcell.KeyHome, 0, tcell.ModShift | tcell.ModAlt}, wantKey{AltShiftHome, 0, nil}},
{giveKey{tcell.KeyEnd, 0, tcell.ModShift | tcell.ModAlt}, wantKey{AltShiftEnd, 0, nil}},
{giveKey{tcell.KeyDelete, 0, tcell.ModShift | tcell.ModAlt}, wantKey{AltShiftDelete, 0, nil}},
{giveKey{tcell.KeyPgUp, 0, tcell.ModShift | tcell.ModAlt}, wantKey{AltShiftPageUp, 0, nil}},
{giveKey{tcell.KeyPgDn, 0, tcell.ModShift | tcell.ModAlt}, wantKey{AltShiftPageDown, 0, nil}},
{giveKey{tcell.KeyHome, 0, tcell.ModCtrl | tcell.ModShift | tcell.ModAlt}, wantKey{CtrlAltShiftHome, 0, nil}},
{giveKey{tcell.KeyEnd, 0, tcell.ModCtrl | tcell.ModShift | tcell.ModAlt}, wantKey{CtrlAltShiftEnd, 0, nil}},
{giveKey{tcell.KeyDelete, 0, tcell.ModCtrl | tcell.ModShift | tcell.ModAlt}, wantKey{CtrlAltShiftDelete, 0, nil}},
{giveKey{tcell.KeyPgUp, 0, tcell.ModCtrl | tcell.ModShift | tcell.ModAlt}, wantKey{CtrlAltShiftPageUp, 0, nil}},
{giveKey{tcell.KeyPgDn, 0, tcell.ModCtrl | tcell.ModShift | tcell.ModAlt}, wantKey{CtrlAltShiftPageDown, 0, nil}},
// section 6: (Ctrl+Alt)+'rune'
{giveKey{tcell.KeyRune, 'a', tcell.ModNone}, wantKey{Rune, 'a', nil}},
{giveKey{tcell.KeyRune, 'a', tcell.ModCtrl}, wantKey{Rune, 'a', nil}}, // fabricated
@@ -198,6 +272,10 @@ func TestGetCharEventKey(t *testing.T) {
initialResizeAsInvalid = false
gotEvent = r.GetChar()
}
if gotEvent.Type == Resize {
t.Logf("Resize swallowed")
gotEvent = r.GetChar()
}
t.Logf("wantEvent = %T{Type: %v, Char: %q (%[3]v)}\n", test.wantKey, test.wantKey.Type, test.wantKey.Char)
t.Logf("gotEvent = %T{Type: %v, Char: %q (%[3]v)}\n", gotEvent, gotEvent.Type, gotEvent.Char)

View File

@@ -44,7 +44,6 @@ const (
CtrlZ
Esc
CtrlSpace
CtrlDelete
// https://apple.stackexchange.com/questions/24261/how-do-i-send-c-that-is-control-slash-to-the-terminal
CtrlBackSlash
@@ -72,6 +71,10 @@ const (
ShiftLeft
ShiftRight
ShiftDelete
ShiftHome
ShiftEnd
ShiftPageUp
ShiftPageDown
F1
F2
@@ -92,15 +95,67 @@ const (
AltDown
AltLeft
AltRight
AltDelete
AltHome
AltEnd
AltPageUp
AltPageDown
AltShiftUp
AltShiftDown
AltShiftLeft
AltShiftRight
AltShiftDelete
AltShiftHome
AltShiftEnd
AltShiftPageUp
AltShiftPageDown
CtrlUp
CtrlDown
CtrlLeft
CtrlRight
CtrlHome
CtrlEnd
CtrlBackspace
CtrlDelete
CtrlPageUp
CtrlPageDown
Alt
CtrlAlt
CtrlAltUp
CtrlAltDown
CtrlAltLeft
CtrlAltRight
CtrlAltHome
CtrlAltEnd
CtrlAltBackspace
CtrlAltDelete
CtrlAltPageUp
CtrlAltPageDown
CtrlShiftUp
CtrlShiftDown
CtrlShiftLeft
CtrlShiftRight
CtrlShiftHome
CtrlShiftEnd
CtrlShiftDelete
CtrlShiftPageUp
CtrlShiftPageDown
CtrlAltShiftUp
CtrlAltShiftDown
CtrlAltShiftLeft
CtrlAltShiftRight
CtrlAltShiftHome
CtrlAltShiftEnd
CtrlAltShiftDelete
CtrlAltShiftPageUp
CtrlAltShiftPageDown
Invalid
Fatal
BracketedPasteBegin
@@ -248,6 +303,14 @@ const (
colMagenta
colCyan
colWhite
colGrey
colBrightRed
colBrightGreen
colBrightYellow
colBrightBlue
colBrightMagenta
colBrightCyan
colBrightWhite
)
type FillReturn int
@@ -721,6 +784,7 @@ var (
ColMatch ColorPair
ColCursor ColorPair
ColCursorEmpty ColorPair
ColCursorEmptyChar ColorPair
ColMarker ColorPair
ColSelected ColorPair
ColSelectedMatch ColorPair
@@ -867,19 +931,19 @@ func init() {
SelectedFg: ColorAttr{colUndefined, AttrUndefined},
SelectedBg: ColorAttr{colUndefined, AttrUndefined},
SelectedMatch: ColorAttr{colUndefined, AttrUndefined},
DarkBg: ColorAttr{colBlack, AttrUndefined},
DarkBg: ColorAttr{colGrey, AttrUndefined},
Prompt: ColorAttr{colBlue, AttrUndefined},
Match: ColorAttr{colGreen, AttrUndefined},
Current: ColorAttr{colYellow, AttrUndefined},
CurrentMatch: ColorAttr{colGreen, AttrUndefined},
Current: ColorAttr{colBrightWhite, AttrUndefined},
CurrentMatch: ColorAttr{colBrightGreen, AttrUndefined},
Spinner: ColorAttr{colGreen, AttrUndefined},
Info: ColorAttr{colWhite, AttrUndefined},
Info: ColorAttr{colYellow, AttrUndefined},
Cursor: ColorAttr{colRed, AttrUndefined},
Marker: ColorAttr{colMagenta, AttrUndefined},
Header: ColorAttr{colCyan, AttrUndefined},
Footer: ColorAttr{colCyan, AttrUndefined},
Border: ColorAttr{colBlack, AttrUndefined},
BorderLabel: ColorAttr{colWhite, AttrUndefined},
Border: ColorAttr{colDefault, Dim},
BorderLabel: ColorAttr{colDefault, AttrUndefined},
Ghost: ColorAttr{colUndefined, Dim},
Disabled: ColorAttr{colUndefined, AttrUndefined},
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
@@ -1113,10 +1177,11 @@ func initPalette(theme *ColorTheme) {
ColSelectedMatch = pair(theme.SelectedMatch, theme.SelectedBg)
ColCursor = pair(theme.Cursor, theme.Gutter)
ColCursorEmpty = pair(blank, theme.Gutter)
ColCursorEmptyChar = pair(theme.Gutter, theme.ListBg)
if theme.SelectedBg.Color != theme.ListBg.Color {
ColMarker = pair(theme.Marker, theme.SelectedBg)
} else {
ColMarker = pair(theme.Marker, theme.Gutter)
ColMarker = pair(theme.Marker, theme.ListBg)
}
ColCurrent = pair(theme.Current, theme.DarkBg)
ColCurrentMatch = pair(theme.CurrentMatch, theme.DarkBg)

View File

@@ -24,7 +24,7 @@ DEFAULT_TIMEOUT = 10
FILE = File.expand_path(__FILE__)
BASE = File.expand_path('../..', __dir__)
Dir.chdir(BASE)
FZF = "FZF_DEFAULT_OPTS=\"--no-scrollbar --pointer \\> --marker \\>\" FZF_DEFAULT_COMMAND= #{BASE}/bin/fzf".freeze
FZF = %(FZF_DEFAULT_OPTS="--no-scrollbar --gutter ' ' --pointer '>' --marker '>'" FZF_DEFAULT_COMMAND= #{BASE}/bin/fzf).freeze
def wait(timeout = DEFAULT_TIMEOUT)
since = Time.now

View File

@@ -108,6 +108,40 @@ class TestCore < TestInteractive
assert_equal %w[3 2 5 6 8 7], fzf_output_lines
end
def test_subword_forward
tmux.send_keys "#{FZF} --bind K:kill-subword,F:forward-subword -q 'foo bar foo-bar fooFooBar'", :Enter, :Home
tmux.until { |lines| assert_equal '> foo bar foo-bar fooFooBar', lines.last }
tmux.send_keys 'F', :Delete
tmux.until { |lines| assert_equal '> foobar foo-bar fooFooBar', lines.last }
tmux.send_keys 'K'
tmux.until { |lines| assert_equal '> foo foo-bar fooFooBar', lines.last }
tmux.send_keys 'F', 'K'
tmux.until { |lines| assert_equal '> foo foo fooFooBar', lines.last }
tmux.send_keys 'F', 'F', 'K'
tmux.until { |lines| assert_equal '> foo foo fooFoo', lines.last }
end
def test_subword_backward
tmux.send_keys "#{FZF} --bind K:backward-kill-subword,B:backward-subword -q 'foo bar foo-bar fooBar'", :Enter
tmux.until { |lines| assert_equal '> foo bar foo-bar fooBar', lines.last }
tmux.send_keys 'B', :BSpace
tmux.until { |lines| assert_equal '> foo bar foo-bar foBar', lines.last }
tmux.send_keys 'K'
tmux.until { |lines| assert_equal '> foo bar foo-bar Bar', lines.last }
tmux.send_keys 'B', :BSpace
tmux.until { |lines| assert_equal '> foo bar foobar Bar', lines.last }
tmux.send_keys 'B', 'B', :BSpace
tmux.until { |lines| assert_equal '> foobar foobar Bar', lines.last }
end
def test_multi_max
tmux.send_keys "seq 1 10 | #{FZF} -m 3 --bind A:select-all,T:toggle-all --preview 'echo [{+}]/{}'", :Enter
@@ -1415,6 +1449,11 @@ class TestCore < TestInteractive
tmux.until { assert_match(%r{ --1/10000/10000-- *$}, it[-1]) }
end
def test_info_command_inline_right_no_ansi
tmux.send_keys(%(seq 10000 | #{FZF} --info-command 'echo -e "--$FZF_POS/$FZF_INFO--"' --info inline-right), :Enter)
tmux.until { assert_match(%r{ --1/10000/10000-- *$}, it[-1]) }
end
def test_info_command_and_focus
tmux.send_keys(%(seq 100 | #{FZF} --separator x --info-command 'echo $FZF_POS' --bind focus:clear-query), :Enter)
tmux.until { assert_match(/^ 1 xx/, it[-2]) }
@@ -1965,7 +2004,7 @@ class TestCore < TestInteractive
end
end
elapsed = Time.now - time
assert elapsed < 2
assert_operator elapsed, :<, 2
end
def test_bg_cancel
@@ -1978,7 +2017,7 @@ class TestCore < TestInteractive
tmux.until { assert_equal 2, it.match_count }
tmux.send_keys :Space
tmux.until { |lines| assert lines.any_include?('[0]') }
sleep 2
sleep(2)
tmux.until do |lines|
assert lines.any_include?('[0]')
refute lines.any_include?('[1]')

View File

@@ -403,7 +403,7 @@ class TestExec < TestInteractive
end
def test_become
tmux.send_keys "seq 100 | #{FZF} --bind 'enter:become:seq {} | #{FZF}'", :Enter
tmux.send_keys "seq 100 | fzf --bind 'enter:become:seq {} | fzf'", :Enter
tmux.until { |lines| assert_equal 100, lines.match_count }
tmux.send_keys 999
tmux.until { |lines| assert_equal 0, lines.match_count }

View File

@@ -178,8 +178,8 @@ class TestLayout < TestInteractive
tmux.send_keys 'seq 3 | fzf --height ~100% --info=inline --border rounded', :Enter
expected = <<~OUTPUT
3
2
3
2
> 1
> < 3/3
@@ -197,8 +197,8 @@ class TestLayout < TestInteractive
3
2
3
2
> 1
> < 3/3
@@ -247,7 +247,7 @@ class TestLayout < TestInteractive
tmux.send_keys 'seq 100 | fzf --height ~5 --info=inline --border rounded', :Enter
expected = <<~OUTPUT
2
2
> 1
> < 100/100
@@ -275,12 +275,12 @@ class TestLayout < TestInteractive
def test_fzf_multi_line
tmux.send_keys %[(echo -en '0\\0'; echo -en '1\\n2\\0'; seq 1000) | fzf --read0 --multi --bind load:select-all --border rounded], :Enter
block = <<~BLOCK
998
999
1000
1
2
998
999
1000
1
2
>>0
3/3 (3)
>
@@ -312,11 +312,11 @@ class TestLayout < TestInteractive
>
3/3 (3)
>>0
1
2
1
2
3
1
2
1
2
3
BLOCK
tmux.until { assert_block(block, it) }
end
@@ -1156,6 +1156,65 @@ class TestLayout < TestInteractive
tmux.until { assert_block(block, it) }
end
def test_gutter_default
tmux.send_keys %(seq 10 | fzf), :Enter
block = <<~BLOCK
3
2
> 1
10/10
>
BLOCK
tmux.until { assert_block(block, it) }
end
def test_gutter_default_no_unicode
tmux.send_keys %(seq 10 | fzf --no-unicode), :Enter
block = <<~BLOCK
3
2
> 1
10/10
>
BLOCK
tmux.until { assert_block(block, it) }
end
def test_gutter_custom
tmux.send_keys %(seq 10 | fzf --gutter x), :Enter
block = <<~BLOCK
x 3
x 2
> 1
10/10
>
BLOCK
tmux.until { assert_block(block, it) }
end
# https://github.com/junegunn/fzf/issues/4537
def test_no_scrollbar_preview_toggle
x = 'x' * 300
y = 'y' * 300
tmux.send_keys %(yes #{x} | head -1000 | fzf --bind 'tab:toggle-preview' --border --no-scrollbar --preview 'echo #{y}' --preview-window 'border-left'), :Enter
# │ ▌ xxxxxxxx·· │ yyyyyyyy│
tmux.until do |lines|
lines.any? { it.match?(/x·· │ y+│$/) }
end
tmux.send_keys :Tab
# │ ▌ xxxxxxxx·· │
tmux.until do |lines|
lines.none? { it.match?(/x··y│$/) }
end
tmux.send_keys :Tab
tmux.until do |lines|
lines.any? { it.match?(/x·· │ y+│$/) }
end
end
def test_combinations
skip unless ENV['LONGTEST']

View File

@@ -64,19 +64,19 @@ remove_line() {
line_no=1
continue
fi
line_no=$(( $(sed 's/:.*//' <<< "$line") + line_no - 1 ))
line_no=$(($(sed 's/:.*//' <<< "$line") + line_no - 1))
content=$(sed 's/^[0-9]*://' <<< "$line")
match=1
echo " - Line #$line_no: $content"
echo " - Line #$line_no: $content"
[ "$content" = "$1" ] || ask " - Remove?"
if [ $? -eq 0 ]; then
temp=$(mktemp)
awk -v n=$line_no 'NR == n {next} {print}' "$src" > "$temp" &&
cat "$temp" > "$src" && rm -f "$temp" || break
echo " - Removed"
echo " - Removed"
else
echo " - Skipped"
line_no=$(( line_no + 1 ))
echo " - Skipped"
line_no=$((line_no + 1))
fi
done
[ $match -eq 0 ] && echo " - Nothing found"
@@ -109,6 +109,6 @@ if [ -d "${fish_dir}/functions" ]; then
fi
config_dir=$(dirname "$prefix_expand")
if [[ "$xdg" = 1 ]] && [[ "$config_dir" = */fzf ]] && [[ -d "$config_dir" ]]; then
if [[ $xdg == 1 ]] && [[ $config_dir == */fzf ]] && [[ -d $config_dir ]]; then
rmdir "$config_dir"
fi