mirror of
https://github.com/junegunn/fzf.git
synced 2025-08-17 21:43:50 -07:00
Compare commits
72 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
65db7352b7 | ||
|
a4db8bd7b5 | ||
|
f1c1b02d77 | ||
|
6580f32b43 | ||
|
b028cbd8bd | ||
|
a1a5418318 | ||
|
5a32634b74 | ||
|
c1875af70b | ||
|
0a10d14e19 | ||
|
ed8ceec66f | ||
|
03760011d7 | ||
|
0d5aebb806 | ||
|
1313510890 | ||
|
b712f2bb6a | ||
|
938c15ec63 | ||
|
3e7f032ec2 | ||
|
b42f5bfb19 | ||
|
717562b264 | ||
|
9d6637c1b3 | ||
|
56fef7c8df | ||
|
ba0935c71f | ||
|
d83eb2800a | ||
|
6f943112a9 | ||
|
f422893b8e | ||
|
22b498489c | ||
|
5460517bd2 | ||
|
9a6e557e52 | ||
|
4fdc07927f | ||
|
9030b67e4f | ||
|
43eafdf4b7 | ||
|
dfb88edb5e | ||
|
bd3e65df4d | ||
|
d7b13f3408 | ||
|
14ef8e8051 | ||
|
cc1d9f124e | ||
|
93c0299606 | ||
|
55e3c73221 | ||
|
6783417504 | ||
|
fa3f706e71 | ||
|
9c2f6cae88 | ||
|
a30181e240 | ||
|
b4ccf64e62 | ||
|
88d768bf6b | ||
|
6444cc7905 | ||
|
328af1f397 | ||
|
5ae60e2e80 | ||
|
0e0b868342 | ||
|
a5beb08ed7 | ||
|
45fc7b903d | ||
|
4f2c274942 | ||
|
93415493b4 | ||
|
8e4d338de9 | ||
|
8a71e091a8 | ||
|
120cd7f25a | ||
|
fb3bf6c984 | ||
|
d57e1f8baa | ||
|
15ca9ad8eb | ||
|
c2e1861747 | ||
|
543d41f3dd | ||
|
e5cfc988ec | ||
|
ee3916be17 | ||
|
fd513f8af8 | ||
|
9a2b7f559c | ||
|
b8d2b0df7e | ||
|
fe3a9c603e | ||
|
97030d4cb1 | ||
|
b2c3e567da | ||
|
ca5e633399 | ||
|
e60a9a628b | ||
|
0167691941 | ||
|
3b0f976380 | ||
|
7bd298b536 |
2
.github/workflows/typos.yml
vendored
2
.github/workflows/typos.yml
vendored
@@ -7,4 +7,4 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: crate-ci/typos@v1.28.2
|
||||
- uses: crate-ci/typos@v1.28.4
|
||||
|
@@ -128,7 +128,7 @@ fzf --height 70% --tmux 70%
|
||||
You can also specify the position, width, and height of the popup window in
|
||||
the following format:
|
||||
|
||||
* `[center|top|bottom|left|right][,SIZE[%]][,SIZE[%]]`
|
||||
* `[center|top|bottom|left|right][,SIZE[%]][,SIZE[%][,border-native]]`
|
||||
|
||||
```sh
|
||||
# 100% width and 60% height
|
||||
|
102
CHANGELOG.md
102
CHANGELOG.md
@@ -1,6 +1,108 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
0.58.0
|
||||
------
|
||||
_Release highlights: https://junegunn.github.io/fzf/releases/0.58.0/_
|
||||
|
||||
This version introduces three new border types, `--list-border`, `--input-border`, and `--header-border`, offering much greater flexibility for customizing the user interface.
|
||||
|
||||
<img src="https://raw.githubusercontent.com/junegunn/i/master/fzf-4-borders.png" />
|
||||
|
||||
Also, fzf now offers "style presets" for quick customization, which can be activated using the `--style` option.
|
||||
|
||||
| Preset | Screenshot |
|
||||
| :--- | :--- |
|
||||
| `default` | <img src="https://raw.githubusercontent.com/junegunn/i/master/fzf-style-default.png"/> |
|
||||
| `full` | <img src="https://raw.githubusercontent.com/junegunn/i/master/fzf-style-full.png"/> |
|
||||
| `minimal` | <img src="https://raw.githubusercontent.com/junegunn/i/master/fzf-style-minimal.png"/> |
|
||||
|
||||
- Style presets (#4160)
|
||||
- `--style=full[:BORDER_STYLE]`
|
||||
- `--style=default`
|
||||
- `--style=minimal`
|
||||
- Border and label for the list section (#4148)
|
||||
- Options
|
||||
- `--list-border[=STYLE]`
|
||||
- `--list-label=LABEL`
|
||||
- `--list-label-pos=COL[:bottom]`
|
||||
- Colors
|
||||
- `list-fg`
|
||||
- `list-bg`
|
||||
- `list-border`
|
||||
- `list-label`
|
||||
- Actions
|
||||
- `change-list-label`
|
||||
- `transform-list-label`
|
||||
- Border and label for the input section (prompt line and info line) (#4154)
|
||||
- Options
|
||||
- `--input-border[=STYLE]`
|
||||
- `--input-label=LABEL`
|
||||
- `--input-label-pos=COL[:bottom]`
|
||||
- Colors
|
||||
- `input-fg` (`query`)
|
||||
- `input-bg`
|
||||
- `input-border`
|
||||
- `input-label`
|
||||
- Actions
|
||||
- `change-input-label`
|
||||
- `transform-input-label`
|
||||
- Border and label for the header section (#4159)
|
||||
- Options
|
||||
- `--header-border[=STYLE]`
|
||||
- `--header-label=LABEL`
|
||||
- `--header-label-pos=COL[:bottom]`
|
||||
- Colors
|
||||
- `header-fg` (`header`)
|
||||
- `header-bg`
|
||||
- `header-border`
|
||||
- `header-label`
|
||||
- Actions
|
||||
- `change-header-label`
|
||||
- `transform-header-label`
|
||||
- Added `--preview-border[=STYLE]` as short for `--preview-window=border[-STYLE]`
|
||||
- Added new preview border style `line` which draws a single separator line between the preview window and the rest of the interface
|
||||
- fzf will now render a dashed line (`┈┈`) in each `--gap` for better visual separation.
|
||||
```sh
|
||||
# All bash/zsh functions, highlighted
|
||||
declare -f |
|
||||
perl -0 -pe 's/^}\n/}\0/gm' |
|
||||
bat --plain --language bash --color always |
|
||||
fzf --read0 --ansi --layout reverse --multi --highlight-line --gap
|
||||
```
|
||||
* You can customize the line using `--gap-line[=STR]`.
|
||||
- You can specify `border-native` to `--tmux` so that native tmux border is used instead of `--border`. This can be useful if you start a different program from inside the popup.
|
||||
```sh
|
||||
fzf --tmux border-native --bind 'enter:execute:less {}'
|
||||
```
|
||||
- Added `toggle-multi-line` action
|
||||
- Added `toggle-hscroll` action
|
||||
- Added `change-nth` action for dynamically changing the value of the `--nth` option
|
||||
```sh
|
||||
# Start with --nth 1, then 2, then 3, then back to the default, 1
|
||||
echo 'foo foobar foobarbaz' | fzf --bind 'space:change-nth(2|3|)' --nth 1 -q foo
|
||||
```
|
||||
- `--nth` parts of each line can now be rendered in a different text style
|
||||
```sh
|
||||
# nth in a different style
|
||||
ls -al | fzf --nth -1 --color nth:italic
|
||||
ls -al | fzf --nth -1 --color nth:reverse
|
||||
ls -al | fzf --nth -1 --color nth:reverse:bold
|
||||
|
||||
# Dim the other parts
|
||||
ls -al | fzf --nth -1 --color nth:regular,fg:dim
|
||||
|
||||
# With 'change-nth'. The current nth option is exported as $FZF_NTH.
|
||||
ps -ef | fzf --reverse --header-lines 1 --header-border bottom --input-border \
|
||||
--color nth:regular,fg:dim \
|
||||
--bind 'ctrl-n:change-nth(8..|1|2|3|4|5|6|7|)' \
|
||||
--bind 'result:transform-prompt:echo "${FZF_NTH}> "'
|
||||
```
|
||||
- A single-character delimiter is now treated as a plain string delimiter rather than a regular expression delimiter, even if it's a regular expression meta-character.
|
||||
- This means you can just write `--delimiter '|'` instead of escaping it as `--delimiter '\|'`
|
||||
- Bug fixes
|
||||
- Bug fixes and improvements in fish scripts (thanks to @bitraid)
|
||||
|
||||
0.57.0
|
||||
------
|
||||
- You can now resize the preview window by dragging the border
|
||||
|
3
Makefile
3
Makefile
@@ -1,4 +1,3 @@
|
||||
SHELL := bash
|
||||
GO ?= go
|
||||
GOOS ?= $(shell $(GO) env GOOS)
|
||||
|
||||
@@ -14,7 +13,7 @@ endif
|
||||
ifeq ($(VERSION),)
|
||||
$(error Not on git repository; cannot determine $$FZF_VERSION)
|
||||
endif
|
||||
VERSION_TRIM := $(shell sed "s/^v//; s/-.*//" <<< $(VERSION))
|
||||
VERSION_TRIM := $(shell echo $(VERSION) | sed "s/^v//; s/-.*//")
|
||||
VERSION_REGEX := $(subst .,\.,$(VERSION_TRIM))
|
||||
|
||||
ifdef FZF_REVISION
|
||||
|
@@ -9,12 +9,24 @@
|
||||
# - https://iterm2.com/utilities/imgcat
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
>&2 echo "usage: $0 FILENAME"
|
||||
>&2 echo "usage: $0 FILENAME[:LINENO][:IGNORED]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
file=${1/#\~\//$HOME/}
|
||||
type=$(file --dereference --mime -- "$file")
|
||||
|
||||
center=0
|
||||
if [[ ! -r $file ]]; then
|
||||
if [[ $file =~ ^(.+):([0-9]+)\ *$ ]] && [[ -r ${BASH_REMATCH[1]} ]]; then
|
||||
file=${BASH_REMATCH[1]}
|
||||
center=${BASH_REMATCH[2]}
|
||||
elif [[ $file =~ ^(.+):([0-9]+):[0-9]+\ *$ ]] && [[ -r ${BASH_REMATCH[1]} ]]; then
|
||||
file=${BASH_REMATCH[1]}
|
||||
center=${BASH_REMATCH[2]}
|
||||
fi
|
||||
fi
|
||||
|
||||
type=$(file --brief --dereference --mime -- "$file")
|
||||
|
||||
if [[ ! $type =~ image/ ]]; then
|
||||
if [[ $type =~ =binary ]]; then
|
||||
@@ -32,7 +44,7 @@ if [[ ! $type =~ image/ ]]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
${batname} --style="${BAT_STYLE:-numbers}" --color=always --pager=never -- "$file"
|
||||
${batname} --style="${BAT_STYLE:-numbers}" --color=always --pager=never --highlight-line="${center:-0}" -- "$file"
|
||||
exit
|
||||
fi
|
||||
|
||||
|
12
go.mod
12
go.mod
@@ -2,19 +2,19 @@ module github.com/junegunn/fzf
|
||||
|
||||
require (
|
||||
github.com/charlievieth/fastwalk v1.0.9
|
||||
github.com/gdamore/tcell/v2 v2.7.4
|
||||
github.com/gdamore/tcell/v2 v2.8.1
|
||||
github.com/junegunn/go-shellwords v0.0.0-20240813092932-a62c48c52e97
|
||||
github.com/mattn/go-isatty v0.0.20
|
||||
github.com/rivo/uniseg v0.4.7
|
||||
golang.org/x/sys v0.28.0
|
||||
golang.org/x/term v0.27.0
|
||||
golang.org/x/sys v0.29.0
|
||||
golang.org/x/term v0.28.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/gdamore/encoding v1.0.0 // indirect
|
||||
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.15 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
)
|
||||
|
||||
go 1.20
|
||||
|
50
go.sum
50
go.sum
@@ -1,17 +1,18 @@
|
||||
github.com/charlievieth/fastwalk v1.0.9 h1:Odb92AfoReO3oFBfDGT5J+nwgzQPF/gWAw6E6/lkor0=
|
||||
github.com/charlievieth/fastwalk v1.0.9/go.mod h1:yGy1zbxog41ZVMcKA/i8ojXLFsuayX5VvwhQVoj9PBI=
|
||||
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
|
||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||
github.com/gdamore/tcell/v2 v2.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU=
|
||||
github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg=
|
||||
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/junegunn/go-shellwords v0.0.0-20240813092932-a62c48c52e97 h1:rqzLixVo1c/GQW6px9j1xQmlvQIn+lf/V6M1UQ7IFzw=
|
||||
github.com/junegunn/go-shellwords v0.0.0-20240813092932-a62c48c52e97/go.mod h1:6EILKtGpo5t+KLb85LNZLAF6P9LKp78hJI80PXMcn3c=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
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=
|
||||
@@ -19,15 +20,29 @@ github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc
|
||||
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=
|
||||
@@ -35,23 +50,36 @@ 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.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.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 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
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.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
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.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
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/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=
|
||||
|
4
install
4
install
@@ -2,7 +2,7 @@
|
||||
|
||||
set -u
|
||||
|
||||
version=0.57.0
|
||||
version=0.58.0
|
||||
auto_completion=
|
||||
key_bindings=
|
||||
update_config=2
|
||||
@@ -83,7 +83,7 @@ ask() {
|
||||
check_binary() {
|
||||
echo -n " - Checking fzf executable ... "
|
||||
local output
|
||||
output=$("$fzf_base"/bin/fzf --version 2>&1)
|
||||
output=$(FZF_DEFAULT_OPTS= "$fzf_base"/bin/fzf --version 2>&1)
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: $output"
|
||||
binary_error="Invalid binary"
|
||||
|
@@ -1,4 +1,4 @@
|
||||
$version="0.57.0"
|
||||
$version="0.58.0"
|
||||
|
||||
$fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition
|
||||
|
||||
|
2
main.go
2
main.go
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/junegunn/fzf/src/protector"
|
||||
)
|
||||
|
||||
var version = "0.57"
|
||||
var version = "0.58"
|
||||
var revision = "devel"
|
||||
|
||||
//go:embed shell/key-bindings.bash
|
||||
|
@@ -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 "Dec 2024" "fzf 0.57.0" "fzf\-tmux - open fzf in tmux split pane"
|
||||
.TH fzf\-tmux 1 "Jan 2025" "fzf 0.58.0" "fzf\-tmux - open fzf in tmux split pane"
|
||||
|
||||
.SH NAME
|
||||
fzf\-tmux - open fzf in tmux split pane
|
||||
|
765
man/man1/fzf.1
765
man/man1/fzf.1
@@ -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 "Dec 2024" "fzf 0.57.0" "fzf - a command-line fuzzy finder"
|
||||
.TH fzf 1 "Jan 2025" "fzf 0.58.0" "fzf - a command-line fuzzy finder"
|
||||
|
||||
.SH NAME
|
||||
fzf - a command-line fuzzy finder
|
||||
@@ -36,15 +36,15 @@ It implements a "fuzzy" matching algorithm, so you can quickly type in patterns
|
||||
with omitted characters and still get the results you want.
|
||||
|
||||
.SH OPTIONS
|
||||
.SS Note
|
||||
.SS NOTE
|
||||
.TP
|
||||
Most long options have the opposite version with \fB\-\-no\-\fR prefix.
|
||||
|
||||
.SS Search mode
|
||||
.SS SEARCH
|
||||
.TP
|
||||
.B "\-x, \-\-extended"
|
||||
Extended-search mode. Since 0.10.9, this is enabled by default. You can disable
|
||||
it with \fB+x\fR or \fB\-\-no\-extended\fR.
|
||||
Extended-search mode. Enabled by default. You can disable it with \fB+x\fR or
|
||||
\fB\-\-no\-extended\fR.
|
||||
.TP
|
||||
.B "\-e, \-\-exact"
|
||||
Enable exact-match
|
||||
@@ -55,6 +55,9 @@ Case-insensitive match (default: smart-case match)
|
||||
.B "+i, \-\-no\-ignore\-case"
|
||||
Case-sensitive match
|
||||
.TP
|
||||
.B "\-\-smart\-case"
|
||||
Smart-case match (default)
|
||||
.TP
|
||||
.B "\-\-literal"
|
||||
Do not normalize latin script letters for matching.
|
||||
.TP
|
||||
@@ -109,49 +112,28 @@ fields.
|
||||
.BI "\-\-with\-nth=" "N[,..]"
|
||||
Transform the presentation of each line using field index expressions
|
||||
.TP
|
||||
.B "+s, \-\-no\-sort"
|
||||
Do not sort the result
|
||||
.TP
|
||||
.BI "\-d, \-\-delimiter=" "STR"
|
||||
Field delimiter regex for \fB\-\-nth\fR, \fB\-\-with\-nth\fR, and field index
|
||||
expressions (default: AWK-style)
|
||||
.TP
|
||||
.BI "\-\-disabled"
|
||||
Do not perform search. With this option, fzf becomes a simple selector
|
||||
interface rather than a "fuzzy finder". You can later enable the search using
|
||||
\fBenable\-search\fR or \fBtoggle\-search\fR action.
|
||||
.SS Search result
|
||||
.TP
|
||||
.B "+s, \-\-no\-sort"
|
||||
Do not sort the result
|
||||
.TP
|
||||
.B "\-\-tail=NUM"
|
||||
Maximum number of items to keep in memory. This is useful when you want to
|
||||
browse an endless stream of data (e.g. log stream) with fzf while limiting
|
||||
memory usage.
|
||||
|
||||
.RS
|
||||
e.g.
|
||||
\fB# Interactive filtering of a log stream
|
||||
tail \-f *.log | fzf \-\-tail 100000 \-\-tac \-\-no\-sort \-\-exact\fR
|
||||
.RE
|
||||
.TP
|
||||
.B "\-\-track"
|
||||
Make fzf track the current selection when the result list is updated.
|
||||
This can be useful when browsing logs using fzf with sorting disabled. It is
|
||||
not recommended to use this option with \fB\-\-tac\fR as the resulting behavior
|
||||
can be confusing. Also, consider using \fBtrack\fR action instead of this
|
||||
option.
|
||||
|
||||
.RS
|
||||
e.g.
|
||||
\fBgit log \-\-oneline \-\-graph \-\-color=always | nl |
|
||||
fzf \-\-ansi \-\-track \-\-no\-sort \-\-layout=reverse\-list\fR
|
||||
.RE
|
||||
.TP
|
||||
.B "\-\-tac"
|
||||
Reverse the order of the input
|
||||
|
||||
.RS
|
||||
e.g.
|
||||
\fBhistory | fzf \-\-tac \-\-no\-sort\fR
|
||||
.RE
|
||||
.BI "\-\-disabled"
|
||||
Do not perform search. With this option, fzf becomes a simple selector
|
||||
interface rather than a "fuzzy finder". You can later enable the search using
|
||||
\fBenable\-search\fR or \fBtoggle\-search\fR action.
|
||||
.TP
|
||||
.BI "\-\-tiebreak=" "CRI[,..]"
|
||||
Comma-separated list of sort criteria to apply when the scores are tied.
|
||||
@@ -179,69 +161,146 @@ Comma-separated list of sort criteria to apply when the scores are tied.
|
||||
- Default is \fBlength\fR (or equivalently \fBlength\fR,index)
|
||||
.br
|
||||
- If \fBend\fR is found in the list, fzf will scan each line backwards
|
||||
.SS Interface
|
||||
.SS INPUT/OUTPUT
|
||||
.TP
|
||||
.B "\-m, \-\-multi"
|
||||
Enable multi-select with tab/shift\-tab. It optionally takes an integer argument
|
||||
which denotes the maximum number of items that can be selected.
|
||||
.B "\-\-read0"
|
||||
Read input delimited by ASCII NUL characters instead of newline characters
|
||||
.TP
|
||||
.B "+m, \-\-no\-multi"
|
||||
Disable multi-select
|
||||
.B "\-\-print0"
|
||||
Print output delimited by ASCII NUL characters instead of newline characters
|
||||
.TP
|
||||
.B "\-\-no\-mouse"
|
||||
Disable mouse
|
||||
.B "\-\-ansi"
|
||||
Enable processing of ANSI color codes
|
||||
.TP
|
||||
.BI "\-\-bind=" "KEYBINDS"
|
||||
Comma-separated list of custom key bindings. See \fBKEY/EVENT BINDINGS\fR for
|
||||
the details.
|
||||
.TP
|
||||
.B "\-\-cycle"
|
||||
Enable cyclic scroll
|
||||
.TP
|
||||
.B "\-\-wrap"
|
||||
Enable line wrap
|
||||
.TP
|
||||
.BI "\-\-wrap\-sign" "=INDICATOR"
|
||||
Indicator for wrapped lines. The default is '↳ ' or '> ' depending on
|
||||
\fB\-\-no\-unicode\fR.
|
||||
.TP
|
||||
.B "\-\-no\-multi\-line"
|
||||
Disable multi-line display of items when using \fB\-\-read0\fR
|
||||
.TP
|
||||
.BI "\-\-gap" "[=N]"
|
||||
Render empty lines between each item
|
||||
.TP
|
||||
.B "\-\-keep\-right"
|
||||
Keep the right end of the line visible when it's too long. Effective only when
|
||||
the query string is empty.
|
||||
.TP
|
||||
.BI "\-\-scroll\-off=" "LINES"
|
||||
Number of screen lines to keep above or below when scrolling to the top or to
|
||||
the bottom (default: 3).
|
||||
.TP
|
||||
.B "\-\-no\-hscroll"
|
||||
Disable horizontal scroll
|
||||
.TP
|
||||
.BI "\-\-hscroll\-off=" "COLS"
|
||||
Number of screen columns to keep to the right of the highlighted substring
|
||||
(default: 10). Setting it to a large value will cause the text to be positioned
|
||||
on the center of the screen.
|
||||
.TP
|
||||
.B "\-\-filepath\-word"
|
||||
Make word-wise movements and actions respect path separators. The following
|
||||
actions are affected:
|
||||
.B "\-\-sync"
|
||||
Synchronous search for multi-staged filtering. If specified, fzf will launch
|
||||
the finder only after the input stream is complete and the initial filtering
|
||||
and the associated actions (bound to any of \fBstart\fR, \fBload\fR,
|
||||
\fBresult\fR, or \fBfocus\fR) are complete.
|
||||
|
||||
\fBbackward\-kill\-word\fR
|
||||
.br
|
||||
\fBbackward\-word\fR
|
||||
.br
|
||||
\fBforward\-word\fR
|
||||
.br
|
||||
\fBkill\-word\fR
|
||||
.RS
|
||||
e.g. \fB# Avoid rendering both fzf instances at the same time
|
||||
fzf \-\-multi | fzf \-\-sync
|
||||
|
||||
# fzf will not render intermediate states
|
||||
(sleep 1; seq 1000000; sleep 1) |
|
||||
fzf \-\-sync \-\-query 5 \-\-listen \-\-bind start:up,load:up,result:up,focus:change\-header:Ready\fR
|
||||
.RE
|
||||
.SS GLOBAL STYLE
|
||||
.TP
|
||||
.BI "\-\-jump\-labels=" "CHARS"
|
||||
Label characters for \fBjump\fR mode.
|
||||
.SS Layout
|
||||
.BI "\-\-style=" "PRESET"
|
||||
Apply a style preset [default|minimal|full[:BORDER_STYLE]]
|
||||
.TP
|
||||
.BI "\-\-color=" "[BASE_SCHEME][,COLOR_NAME[:ANSI_COLOR][:ANSI_ATTRIBUTES]]..."
|
||||
Color configuration. The name of the base color scheme is followed by custom
|
||||
color mappings.
|
||||
|
||||
.RS
|
||||
.B BASE SCHEME:
|
||||
(default: \fBdark\fR on 256-color terminal, otherwise \fB16\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
|
||||
\fBbw \fRNo colors (equivalent to \fB\-\-no\-color\fR)
|
||||
|
||||
.B COLOR NAMES:
|
||||
\fBfg \fRText
|
||||
\fBlist\-fg \fRText in the list section
|
||||
\fBselected\-fg \fRSelected line text
|
||||
\fBpreview\-fg \fRPreview window text
|
||||
\fBbg \fRBackground
|
||||
\fBlist\-bg \fRList section background
|
||||
\fBselected\-bg \fRSelected line background
|
||||
\fBpreview\-bg \fRPreview window background
|
||||
\fBinput\-bg \fRInput window background (\fB\-\-input\-border\fR)
|
||||
\fBheader\-bg \fRHeader window background (\fB\-\-header\-border\fR)
|
||||
\fBhl \fRHighlighted substrings
|
||||
\fBselected\-hl \fRHighlighted substrings in the selected line
|
||||
\fBcurrent\-fg (fg+) \fRText (current line)
|
||||
\fBcurrent\-bg (bg+) \fRBackground (current line)
|
||||
\fBgutter \fRGutter on the left
|
||||
\fBcurrent\-hl (hl+) \fRHighlighted substrings (current line)
|
||||
\fBquery (input\-fg) \fRQuery string
|
||||
\fBdisabled \fRQuery string when search is disabled (\fB\-\-disabled\fR)
|
||||
\fBinfo \fRInfo line (match counters)
|
||||
\fBborder \fRBorder around the window (\fB\-\-border\fR and \fB\-\-preview\fR)
|
||||
\fBlist\-border \fRBorder around the list section (\fB\-\-list\-border\fR)
|
||||
\fBscrollbar \fRScrollbar
|
||||
\fBseparator \fRHorizontal separator on info line
|
||||
\fBgap\-line \fRHorizontal line on each gap
|
||||
\fBpreview\-border \fRBorder around the preview window (\fB\-\-preview\fR)
|
||||
\fBpreview\-scrollbar \fRScrollbar
|
||||
\fBinput\-border \fRBorder around the input window (\fB\-\-input\-border\fR)
|
||||
\fBheader\-border \fRBorder around the header window (\fB\-\-header\-border\fR)
|
||||
\fBlabel \fRBorder label (\fB\-\-border\-label\fR, \fB\-\-list\-label\fR, \fB\-\-input\-label\fR, and \fB\-\-preview\-label\fR)
|
||||
\fBlist\-label \fRBorder label of the list section (\fB\-\-list\-label\fR)
|
||||
\fBpreview\-label \fRBorder label of the preview window (\fB\-\-preview\-label\fR)
|
||||
\fBinput\-label \fRBorder label of the input window (\fB\-\-input\-label\fR)
|
||||
\fBheader\-label \fRBorder label of the header window (\fB\-\-header\-label\fR)
|
||||
\fBprompt \fRPrompt
|
||||
\fBpointer \fRPointer to the current line
|
||||
\fBmarker \fRMulti\-select marker
|
||||
\fBspinner \fRStreaming input indicator
|
||||
\fBheader (header\-fg) \fRHeader
|
||||
\fBnth \fRParts of the line specified by \fB\-\-nth\fR (only supports attributes)
|
||||
|
||||
.B ANSI COLORS:
|
||||
\fB\-1 \fRDefault terminal foreground/background color
|
||||
\fB \fR(or the original color of the text)
|
||||
\fB0 ~ 15 \fR16 base colors
|
||||
\fBblack\fR
|
||||
\fBred\fR
|
||||
\fBgreen\fR
|
||||
\fByellow\fR
|
||||
\fBblue\fR
|
||||
\fBmagenta\fR
|
||||
\fBcyan\fR
|
||||
\fBwhite\fR
|
||||
\fBbright\-black\fR (gray | grey)
|
||||
\fBbright\-red\fR
|
||||
\fBbright\-green\fR
|
||||
\fBbright\-yellow\fR
|
||||
\fBbright\-blue\fR
|
||||
\fBbright\-magenta\fR
|
||||
\fBbright\-cyan\fR
|
||||
\fBbright\-white\fR
|
||||
\fB16 ~ 255 \fRANSI 256 colors
|
||||
\fB#rrggbb \fR24-bit colors
|
||||
|
||||
.B ANSI ATTRIBUTES: (Only applies to foreground colors)
|
||||
\fBregular \fRClears previously set attributes; should precede the other ones
|
||||
\fBbold\fR
|
||||
\fBunderline\fR
|
||||
\fBreverse\fR
|
||||
\fBdim\fR
|
||||
\fBitalic\fR
|
||||
\fBstrikethrough\fR
|
||||
|
||||
.B EXAMPLES:
|
||||
|
||||
\fB# Seoul256 theme with 8-bit colors
|
||||
# (https://github.com/junegunn/seoul256.vim)
|
||||
fzf \-\-color='bg:237,bg+:236,info:143,border:240,spinner:108' \\
|
||||
\-\-color='hl:65,fg:252,header:65,fg+:252' \\
|
||||
\-\-color='pointer:161,marker:168,prompt:110,hl+:108'
|
||||
|
||||
# Seoul256 theme with 24-bit colors
|
||||
fzf \-\-color='bg:#4B4B4B,bg+:#3F3F3F,info:#BDBB72,border:#6B6B6B,spinner:#98BC99' \\
|
||||
\-\-color='hl:#719872,fg:#D9D9D9,header:#719872,fg+:#D9D9D9' \\
|
||||
\-\-color='pointer:#E12672,marker:#E17899,prompt:#98BEDE,hl+:#98BC99'\fR
|
||||
.RE
|
||||
.TP
|
||||
.B "\-\-no\-color"
|
||||
Disable colors
|
||||
.TP
|
||||
.B "\-\-no\-bold"
|
||||
Do not use bold text
|
||||
.TP
|
||||
.B "\-\-black"
|
||||
Use black background
|
||||
|
||||
.SS DISPLAY MODE
|
||||
.TP
|
||||
.BI "\-\-height=" "[~]HEIGHT[%]"
|
||||
Display fzf window below the cursor with the given height instead of using
|
||||
@@ -271,7 +330,7 @@ Adaptive height has the following limitations:
|
||||
Minimum height when \fB\-\-height\fR is given in percent (default: 10).
|
||||
Ignored when \fB\-\-height\fR is not specified.
|
||||
.TP
|
||||
.BI "\-\-tmux" "[=[center|top|bottom|left|right][,SIZE[%]][,SIZE[%]]]"
|
||||
.BI "\-\-tmux" "[=[center|top|bottom|left|right][,SIZE[%]][,SIZE[%]][,border-native]]"
|
||||
Start fzf in a tmux popup (default \fBcenter,50%\fR). Requires tmux 3.3 or
|
||||
later. This option is ignored if you are not running fzf inside tmux.
|
||||
|
||||
@@ -286,8 +345,12 @@ e.g.
|
||||
fzf \-\-tmux bottom,30%
|
||||
|
||||
# Popup on the top with 80% width and 40% height
|
||||
fzf \-\-tmux top,80%,40%\fR
|
||||
fzf \-\-tmux top,80%,40%
|
||||
|
||||
# Popup with a native tmux border in the center with 80% width and height
|
||||
fzf \-\-tmux center,80%,border\-native\fR
|
||||
|
||||
.SS LAYOUT
|
||||
.TP
|
||||
.BI "\-\-layout=" "LAYOUT"
|
||||
Choose the layout (default: default)
|
||||
@@ -305,7 +368,56 @@ Choose the layout (default: default)
|
||||
A synonym for \fB\-\-layout=reverse\fB
|
||||
|
||||
.TP
|
||||
.BI "\-\-border" [=BORDER_OPT]
|
||||
.BI "\-\-margin=" MARGIN
|
||||
Comma-separated expression for margins around the finder.
|
||||
.br
|
||||
|
||||
.br
|
||||
.RS
|
||||
.BR TRBL " Same margin for top, right, bottom, and left"
|
||||
.br
|
||||
.BR TB,RL " Vertical, horizontal margin"
|
||||
.br
|
||||
.BR T,RL,B " Top, horizontal, bottom margin"
|
||||
.br
|
||||
.BR T,R,B,L " Top, right, bottom, left margin"
|
||||
.br
|
||||
|
||||
.br
|
||||
Each part can be given in absolute number or in percentage relative to the
|
||||
terminal size with \fB%\fR suffix.
|
||||
.br
|
||||
|
||||
.br
|
||||
e.g.
|
||||
\fBfzf \-\-margin 10%
|
||||
fzf \-\-margin 1,5%\fR
|
||||
.RE
|
||||
.TP
|
||||
.BI "\-\-padding=" PADDING
|
||||
Comma-separated expression for padding inside the border. Padding is
|
||||
distinguishable from margin only when \fB\-\-border\fR option is used.
|
||||
.br
|
||||
|
||||
.br
|
||||
e.g.
|
||||
\fBfzf \-\-margin 5% \-\-padding 5% \-\-border \-\-preview 'cat {}' \\
|
||||
\-\-color bg:#222222,preview\-bg:#333333\fR
|
||||
|
||||
.br
|
||||
.RS
|
||||
.BR TRBL " Same padding for top, right, bottom, and left"
|
||||
.br
|
||||
.BR TB,RL " Vertical, horizontal padding"
|
||||
.br
|
||||
.BR T,RL,B " Top, horizontal, bottom padding"
|
||||
.br
|
||||
.BR T,R,B,L " Top, right, bottom, left padding"
|
||||
.br
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.BI "\-\-border" [=STYLE]
|
||||
Draw border around the finder
|
||||
|
||||
.br
|
||||
@@ -384,65 +496,120 @@ the label. Label is printed on the top border line by default, add
|
||||
\fB:bottom\fR to put it on the border line on the bottom. The default value
|
||||
\fB0 (or \fBcenter\fR) will put the label at the center of the border line.
|
||||
|
||||
.SS LIST SECTION
|
||||
.TP
|
||||
.B "\-\-no\-unicode"
|
||||
Use ASCII characters instead of Unicode drawing characters to draw borders,
|
||||
the spinner and the horizontal separator.
|
||||
|
||||
.BI "\-m, \-\-multi" "[=MAX]"
|
||||
Enable multi-select with tab/shift\-tab. It optionally takes an integer argument
|
||||
which denotes the maximum number of items that can be selected.
|
||||
.TP
|
||||
.B "\-\-ambidouble"
|
||||
Set this option if your terminal displays ambiguous width characters (e.g.
|
||||
box-drawing characters for borders) as 2 columns.
|
||||
|
||||
.B "+m, \-\-no\-multi"
|
||||
Disable multi-select
|
||||
.TP
|
||||
.BI "\-\-margin=" MARGIN
|
||||
Comma-separated expression for margins around the finder.
|
||||
.br
|
||||
.B "\-\-highlight\-line"
|
||||
Highlight the whole current line
|
||||
.TP
|
||||
.B "\-\-cycle"
|
||||
Enable cyclic scroll
|
||||
.TP
|
||||
.B "\-\-wrap"
|
||||
Enable line wrap
|
||||
.TP
|
||||
.BI "\-\-wrap\-sign" "=INDICATOR"
|
||||
Indicator for wrapped lines. The default is '↳ ' or '> ' depending on
|
||||
\fB\-\-no\-unicode\fR.
|
||||
.TP
|
||||
.B "\-\-no\-multi\-line"
|
||||
Disable multi-line display of items when using \fB\-\-read0\fR
|
||||
.TP
|
||||
.B "\-\-track"
|
||||
Make fzf track the current selection when the result list is updated.
|
||||
This can be useful when browsing logs using fzf with sorting disabled. It is
|
||||
not recommended to use this option with \fB\-\-tac\fR as the resulting behavior
|
||||
can be confusing. Also, consider using \fBtrack\fR action instead of this
|
||||
option.
|
||||
|
||||
.br
|
||||
.RS
|
||||
.BR TRBL " Same margin for top, right, bottom, and left"
|
||||
.br
|
||||
.BR TB,RL " Vertical, horizontal margin"
|
||||
.br
|
||||
.BR T,RL,B " Top, horizontal, bottom margin"
|
||||
.br
|
||||
.BR T,R,B,L " Top, right, bottom, left margin"
|
||||
.br
|
||||
|
||||
.br
|
||||
Each part can be given in absolute number or in percentage relative to the
|
||||
terminal size with \fB%\fR suffix.
|
||||
.br
|
||||
|
||||
.br
|
||||
e.g.
|
||||
\fBfzf \-\-margin 10%
|
||||
fzf \-\-margin 1,5%\fR
|
||||
\fBgit log \-\-oneline \-\-graph \-\-color=always | nl |
|
||||
fzf \-\-ansi \-\-track \-\-no\-sort \-\-layout=reverse\-list\fR
|
||||
.RE
|
||||
.TP
|
||||
.BI "\-\-padding=" PADDING
|
||||
Comma-separated expression for padding inside the border. Padding is
|
||||
distinguishable from margin only when \fB\-\-border\fR option is used.
|
||||
.br
|
||||
.B "\-\-tac"
|
||||
Reverse the order of the input
|
||||
|
||||
.br
|
||||
e.g.
|
||||
\fBfzf \-\-margin 5% \-\-padding 5% \-\-border \-\-preview 'cat {}' \\
|
||||
\-\-color bg:#222222,preview\-bg:#333333\fR
|
||||
|
||||
.br
|
||||
.RS
|
||||
.BR TRBL " Same padding for top, right, bottom, and left"
|
||||
.br
|
||||
.BR TB,RL " Vertical, horizontal padding"
|
||||
.br
|
||||
.BR T,RL,B " Top, horizontal, bottom padding"
|
||||
.br
|
||||
.BR T,R,B,L " Top, right, bottom, left padding"
|
||||
.br
|
||||
e.g.
|
||||
\fBhistory | fzf \-\-tac \-\-no\-sort\fR
|
||||
.RE
|
||||
.TP
|
||||
.BI "\-\-gap" "[=N]"
|
||||
Render empty lines between each item
|
||||
.TP
|
||||
.BI "\-\-gap\-line" "[=STR]"
|
||||
The given string will be repeated to draw a horizontal line on each gap
|
||||
(default: '┈' or '\-' depending on \fB\-\-no\-unicode\fR).
|
||||
.TP
|
||||
.B "\-\-keep\-right"
|
||||
Keep the right end of the line visible when it's too long. Effective only when
|
||||
the query string is empty.
|
||||
.TP
|
||||
.BI "\-\-scroll\-off=" "LINES"
|
||||
Number of screen lines to keep above or below when scrolling to the top or to
|
||||
the bottom (default: 3).
|
||||
.TP
|
||||
.B "\-\-no\-hscroll"
|
||||
Disable horizontal scroll
|
||||
.TP
|
||||
.BI "\-\-hscroll\-off=" "COLS"
|
||||
Number of screen columns to keep to the right of the highlighted substring
|
||||
(default: 10). Setting it to a large value will cause the text to be positioned
|
||||
on the center of the screen.
|
||||
.TP
|
||||
.BI "\-\-jump\-labels=" "CHARS"
|
||||
Label characters for \fBjump\fR mode.
|
||||
.TP
|
||||
.BI "\-\-pointer=" "STR"
|
||||
Pointer to the current line (default: '▌' or '>' depending on \fB\-\-no\-unicode\fR)
|
||||
.TP
|
||||
.BI "\-\-marker=" "STR"
|
||||
Multi-select marker (default: '┃' or '>' depending on \fB\-\-no\-unicode\fR)
|
||||
.TP
|
||||
.BI "\-\-marker\-multi\-line=" "STR"
|
||||
Multi-select marker for multi-line entries. 3 elements for top, middle, and bottom.
|
||||
(default: '╻┃╹' or '.|'' depending on \fB\-\-no\-unicode\fR)
|
||||
.TP
|
||||
.BI "\-\-ellipsis=" "STR"
|
||||
Ellipsis to show when line is truncated (default: '··')
|
||||
.TP
|
||||
.BI "\-\-tabstop=" SPACES
|
||||
Number of spaces for a tab character (default: 8)
|
||||
.TP
|
||||
.BI "\-\-scrollbar=" "CHAR1[CHAR2]"
|
||||
Use the given character to render scrollbar. (default: '│' or ':' depending on
|
||||
\fB\-\-no\-unicode\fR). The optional \fBCHAR2\fR is used to render scrollbar of
|
||||
the preview window.
|
||||
|
||||
.TP
|
||||
.B "\-\-no\-scrollbar"
|
||||
Do not display scrollbar. A synonym for \fB\-\-scrollbar=''\fB
|
||||
|
||||
.TP
|
||||
.BI "\-\-list\-border" [=STYLE]
|
||||
Draw border around the list section
|
||||
|
||||
.TP
|
||||
.BI "\-\-list\-label" [=LABEL]
|
||||
Label to print on the list border
|
||||
|
||||
.TP
|
||||
.BI "\-\-list\-label\-pos" [=N[:top|bottom]]
|
||||
Position of the list label
|
||||
|
||||
.SS INPUT SECTION
|
||||
|
||||
.TP
|
||||
.BI "\-\-prompt=" "STR"
|
||||
Input prompt (default: '> ')
|
||||
.TP
|
||||
.BI "\-\-info=" "STYLE"
|
||||
Determines the display style of the finder info. (e.g. match counter, loading indicator, etc.)
|
||||
@@ -491,160 +658,30 @@ Do not display horizontal separator on the info line. A synonym for
|
||||
\fB\-\-separator=''\fB
|
||||
|
||||
.TP
|
||||
.BI "\-\-scrollbar=" "CHAR1[CHAR2]"
|
||||
Use the given character to render scrollbar. (default: '│' or ':' depending on
|
||||
\fB\-\-no\-unicode\fR). The optional \fBCHAR2\fR is used to render scrollbar of
|
||||
the preview window.
|
||||
.B "\-\-filepath\-word"
|
||||
Make word-wise movements and actions respect path separators. The following
|
||||
actions are affected:
|
||||
|
||||
\fBbackward\-kill\-word\fR
|
||||
.br
|
||||
\fBbackward\-word\fR
|
||||
.br
|
||||
\fBforward\-word\fR
|
||||
.br
|
||||
\fBkill\-word\fR
|
||||
.TP
|
||||
.BI "\-\-input\-border" [=STYLE]
|
||||
Draw border around the input section
|
||||
|
||||
.TP
|
||||
.B "\-\-no\-scrollbar"
|
||||
Do not display scrollbar. A synonym for \fB\-\-scrollbar=''\fB
|
||||
.BI "\-\-input\-label" [=LABEL]
|
||||
Label to print on the input border
|
||||
|
||||
.TP
|
||||
.BI "\-\-prompt=" "STR"
|
||||
Input prompt (default: '> ')
|
||||
.TP
|
||||
.BI "\-\-pointer=" "STR"
|
||||
Pointer to the current line (default: '▌' or '>' depending on \fB\-\-no\-unicode\fR)
|
||||
.TP
|
||||
.BI "\-\-marker=" "STR"
|
||||
Multi-select marker (default: '┃' or '>' depending on \fB\-\-no\-unicode\fR)
|
||||
.TP
|
||||
.BI "\-\-marker\-multi\-line=" "STR"
|
||||
Multi-select marker for multi-line entries. 3 elements for top, middle, and bottom.
|
||||
(default: '╻┃╹' or '.|'' depending on \fB\-\-no\-unicode\fR)
|
||||
.TP
|
||||
.BI "\-\-header=" "STR"
|
||||
The given string will be printed as the sticky header. The lines are displayed
|
||||
in the given order from top to bottom regardless of \fB\-\-layout\fR option, and
|
||||
are not affected by \fB\-\-with\-nth\fR. ANSI color codes are processed even when
|
||||
\fB\-\-ansi\fR is not set.
|
||||
.TP
|
||||
.BI "\-\-header\-lines=" "N"
|
||||
The first N lines of the input are treated as the sticky header. When
|
||||
\fB\-\-with\-nth\fR is set, the lines are transformed just like the other
|
||||
lines that follow.
|
||||
.TP
|
||||
.B "\-\-header\-first"
|
||||
Print header before the prompt line
|
||||
.TP
|
||||
.BI "\-\-ellipsis=" "STR"
|
||||
Ellipsis to show when line is truncated (default: '··')
|
||||
.SS Display
|
||||
.TP
|
||||
.B "\-\-ansi"
|
||||
Enable processing of ANSI color codes
|
||||
.TP
|
||||
.BI "\-\-tabstop=" SPACES
|
||||
Number of spaces for a tab character (default: 8)
|
||||
.TP
|
||||
.BI "\-\-color=" "[BASE_SCHEME][,COLOR_NAME[:ANSI_COLOR][:ANSI_ATTRIBUTES]]..."
|
||||
Color configuration. The name of the base color scheme is followed by custom
|
||||
color mappings.
|
||||
.BI "\-\-input\-label\-pos" [=N[:top|bottom]]
|
||||
Position of the input label
|
||||
|
||||
.RS
|
||||
.B BASE SCHEME:
|
||||
(default: \fBdark\fR on 256-color terminal, otherwise \fB16\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
|
||||
\fBbw \fRNo colors (equivalent to \fB\-\-no\-color\fR)
|
||||
|
||||
.B COLOR NAMES:
|
||||
\fBfg \fRText
|
||||
\fBselected\-fg \fRSelected line text
|
||||
\fBpreview\-fg \fRPreview window text
|
||||
\fBbg \fRBackground
|
||||
\fBselected\-bg \fRSelected line background
|
||||
\fBpreview\-bg \fRPreview window background
|
||||
\fBhl \fRHighlighted substrings
|
||||
\fBselected\-hl \fRHighlighted substrings in the selected line
|
||||
\fBcurrent\-fg (fg+) \fRText (current line)
|
||||
\fBcurrent\-bg (bg+) \fRBackground (current line)
|
||||
\fBgutter \fRGutter on the left
|
||||
\fBcurrent\-hl (hl+) \fRHighlighted substrings (current line)
|
||||
\fBquery \fRQuery string
|
||||
\fBdisabled \fRQuery string when search is disabled (\fB\-\-disabled\fR)
|
||||
\fBinfo \fRInfo line (match counters)
|
||||
\fBborder \fRBorder around the window (\fB\-\-border\fR and \fB\-\-preview\fR)
|
||||
\fBscrollbar \fRScrollbar
|
||||
\fBpreview\-border \fRBorder around the preview window (\fB\-\-preview\fR)
|
||||
\fBpreview\-scrollbar \fRScrollbar
|
||||
\fBseparator \fRHorizontal separator on info line
|
||||
\fBlabel \fRBorder label (\fB\-\-border\-label\fR and \fB\-\-preview\-label\fR)
|
||||
\fBpreview\-label \fRBorder label of the preview window (\fB\-\-preview\-label\fR)
|
||||
\fBprompt \fRPrompt
|
||||
\fBpointer \fRPointer to the current line
|
||||
\fBmarker \fRMulti\-select marker
|
||||
\fBspinner \fRStreaming input indicator
|
||||
\fBheader \fRHeader
|
||||
|
||||
.B ANSI COLORS:
|
||||
\fB\-1 \fRDefault terminal foreground/background color
|
||||
\fB \fR(or the original color of the text)
|
||||
\fB0 ~ 15 \fR16 base colors
|
||||
\fBblack\fR
|
||||
\fBred\fR
|
||||
\fBgreen\fR
|
||||
\fByellow\fR
|
||||
\fBblue\fR
|
||||
\fBmagenta\fR
|
||||
\fBcyan\fR
|
||||
\fBwhite\fR
|
||||
\fBbright\-black\fR (gray | grey)
|
||||
\fBbright\-red\fR
|
||||
\fBbright\-green\fR
|
||||
\fBbright\-yellow\fR
|
||||
\fBbright\-blue\fR
|
||||
\fBbright\-magenta\fR
|
||||
\fBbright\-cyan\fR
|
||||
\fBbright\-white\fR
|
||||
\fB16 ~ 255 \fRANSI 256 colors
|
||||
\fB#rrggbb \fR24-bit colors
|
||||
|
||||
.B ANSI ATTRIBUTES: (Only applies to foreground colors)
|
||||
\fBregular \fRClears previously set attributes; should precede the other ones
|
||||
\fBbold\fR
|
||||
\fBunderline\fR
|
||||
\fBreverse\fR
|
||||
\fBdim\fR
|
||||
\fBitalic\fR
|
||||
\fBstrikethrough\fR
|
||||
|
||||
.B EXAMPLES:
|
||||
|
||||
\fB# Seoul256 theme with 8-bit colors
|
||||
# (https://github.com/junegunn/seoul256.vim)
|
||||
fzf \-\-color='bg:237,bg+:236,info:143,border:240,spinner:108' \\
|
||||
\-\-color='hl:65,fg:252,header:65,fg+:252' \\
|
||||
\-\-color='pointer:161,marker:168,prompt:110,hl+:108'
|
||||
|
||||
# Seoul256 theme with 24-bit colors
|
||||
fzf \-\-color='bg:#4B4B4B,bg+:#3F3F3F,info:#BDBB72,border:#6B6B6B,spinner:#98BC99' \\
|
||||
\-\-color='hl:#719872,fg:#D9D9D9,header:#719872,fg+:#D9D9D9' \\
|
||||
\-\-color='pointer:#E12672,marker:#E17899,prompt:#98BEDE,hl+:#98BC99'\fR
|
||||
.RE
|
||||
.TP
|
||||
.B "\-\-highlight\-line"
|
||||
Highlight the whole current line
|
||||
.TP
|
||||
.B "\-\-no\-bold"
|
||||
Do not use bold text
|
||||
.TP
|
||||
.B "\-\-black"
|
||||
Use black background
|
||||
.SS History
|
||||
.TP
|
||||
.BI "\-\-history=" "HISTORY_FILE"
|
||||
Load search history from the specified file and update the file on completion.
|
||||
When enabled, \fBCTRL\-N\fR and \fBCTRL\-P\fR are automatically remapped to
|
||||
\fBnext\-history\fR and \fBprev\-history\fR.
|
||||
.TP
|
||||
.BI "\-\-history\-size=" "N"
|
||||
Maximum number of entries in the history file (default: 1000). The file is
|
||||
automatically truncated when the number of the lines exceeds the value.
|
||||
.SS Preview
|
||||
.SS PREVIEW WINDOW
|
||||
.TP
|
||||
.BI "\-\-preview=" "COMMAND"
|
||||
Execute the given command for the current line and display the result on the
|
||||
@@ -724,6 +761,13 @@ e.g.
|
||||
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.BI "\-\-preview\-border" [=STYLE]
|
||||
Short for \fB\-\-preview\-window=border\-STYLE\fR. In addition to the other
|
||||
styles, \fBline\fR style is also supported for preview border, which draws
|
||||
a single separator line between the preview window and the rest of the
|
||||
interface.
|
||||
|
||||
.TP
|
||||
.BI "\-\-preview\-label" [=LABEL]
|
||||
Label to print on the horizontal border line of the preview window.
|
||||
@@ -759,7 +803,7 @@ default value 0 (or \fBcenter\fR) will put the label at the center of the
|
||||
border line.
|
||||
|
||||
.TP
|
||||
.BI "\-\-preview\-window=" "[POSITION][,SIZE[%]][,border\-BORDER_OPT][,[no]wrap][,[no]follow][,[no]cycle][,[no]info][,[no]hidden][,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES][,default][,<SIZE_THRESHOLD(ALTERNATIVE_LAYOUT)]"
|
||||
.BI "\-\-preview\-window=" "[POSITION][,SIZE[%]][,border\-STYLE][,[no]wrap][,[no]follow][,[no]cycle][,[no]info][,[no]hidden][,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES][,default][,<SIZE_THRESHOLD(ALTERNATIVE_LAYOUT)]"
|
||||
|
||||
.RS
|
||||
.B POSITION: (default: right)
|
||||
@@ -802,6 +846,10 @@ e.g. \fBborder\-rounded\fR (border with rounded edges, default),
|
||||
\fBborder\-sharp\fR (border with sharp edges), \fBborder\-left\fR,
|
||||
\fBborder\-none\fR, etc.
|
||||
|
||||
* In addition to the other border styles, \fBborder\-line\fR style is also
|
||||
supported, which draws a single separator line between the preview window and
|
||||
the rest of the interface.
|
||||
|
||||
* \fB[:+SCROLL[OFFSETS][/DENOM]]\fR determines the initial scroll offset of the
|
||||
preview window.
|
||||
|
||||
@@ -853,7 +901,35 @@ e.g.
|
||||
\fBfzf \-\-preview 'cat {}' \-\-preview\-window 'right,border\-left,<30(up,30%,border\-bottom)'\fR
|
||||
.RE
|
||||
|
||||
.SS Scripting
|
||||
.SS HEADER
|
||||
|
||||
.TP
|
||||
.BI "\-\-header=" "STR"
|
||||
The given string will be printed as the sticky header. The lines are displayed
|
||||
in the given order from top to bottom regardless of \fB\-\-layout\fR option, and
|
||||
are not affected by \fB\-\-with\-nth\fR. ANSI color codes are processed even when
|
||||
\fB\-\-ansi\fR is not set.
|
||||
.TP
|
||||
.BI "\-\-header\-lines=" "N"
|
||||
The first N lines of the input are treated as the sticky header. When
|
||||
\fB\-\-with\-nth\fR is set, the lines are transformed just like the other
|
||||
lines that follow.
|
||||
.TP
|
||||
.B "\-\-header\-first"
|
||||
Print header before the prompt line
|
||||
.TP
|
||||
.BI "\-\-header\-border" [=STYLE]
|
||||
Draw border around the header section
|
||||
|
||||
.TP
|
||||
.BI "\-\-header\-label" [=LABEL]
|
||||
Label to print on the header border
|
||||
|
||||
.TP
|
||||
.BI "\-\-header\-label\-pos" [=N[:top|bottom]]
|
||||
Position of the header label
|
||||
|
||||
.SS SCRIPTING
|
||||
.TP
|
||||
.BI "\-q, \-\-query=" "STR"
|
||||
Start the finder with the given query
|
||||
@@ -882,24 +958,15 @@ with the default enter key. If \fB\-\-expect\fR option is specified multiple
|
||||
times, fzf will expect the union of the keys. \fB\-\-no\-expect\fR will clear the
|
||||
list.
|
||||
|
||||
.RS
|
||||
e.g.
|
||||
\fBfzf \-\-expect=ctrl\-v,ctrl\-t,alt\-s \-\-expect=f1,f2,~,@\fR
|
||||
.RE
|
||||
|
||||
This option is not compatible with \fB\-\-bind\fR on the same key and will take
|
||||
precedence over it. To combine the two, use \fBprint\fR action.
|
||||
|
||||
.RS
|
||||
e.g.
|
||||
\fBfzf \-\-multi \-\-bind 'enter:print()+accept,ctrl\-y:select\-all+print(ctrl\-y)+accept'\fR
|
||||
.RE
|
||||
.TP
|
||||
.B "\-\-read0"
|
||||
Read input delimited by ASCII NUL characters instead of newline characters
|
||||
.TP
|
||||
.B "\-\-print0"
|
||||
Print output delimited by ASCII NUL characters instead of newline characters
|
||||
\fBfzf \-\-multi \\
|
||||
\-\-bind 'enter:print()+accept,ctrl\-y:select\-all+print(ctrl\-y)+accept'\fR
|
||||
.TP
|
||||
.B "\-\-no\-clear"
|
||||
Do not clear finder interface on exit. If fzf was started in full screen mode,
|
||||
@@ -915,21 +982,13 @@ e.g.
|
||||
exit 1
|
||||
) && seq "$foo" 100 | fzf
|
||||
|
||||
.SS KEY/EVENT BINDING
|
||||
.TP
|
||||
.B "\-\-sync"
|
||||
Synchronous search for multi-staged filtering. If specified, fzf will launch
|
||||
the finder only after the input stream is complete and the initial filtering
|
||||
and the associated actions (bound to any of \fBstart\fR, \fBload\fR,
|
||||
\fBresult\fR, or \fBfocus\fR) are complete.
|
||||
.BI "\-\-bind=" "BINDINGS"
|
||||
Comma-separated list of custom key/event bindings. See \fBKEY/EVENT BINDINGS\fR
|
||||
for the details.
|
||||
|
||||
.RS
|
||||
e.g. \fB# Avoid rendering both fzf instances at the same time
|
||||
fzf \-\-multi | fzf \-\-sync
|
||||
|
||||
# fzf will not render intermediate states
|
||||
(sleep 1; seq 1000000; sleep 1) |
|
||||
fzf \-\-sync \-\-query 5 \-\-listen \-\-bind start:up,load:up,result:up,focus:change\-header:Ready\fR
|
||||
.RE
|
||||
.SS ADVANCED
|
||||
.TP
|
||||
.B "\-\-with\-shell=STR"
|
||||
Shell command and flags to start child processes with. On *nix Systems, the
|
||||
@@ -937,9 +996,6 @@ default value is \fB$SHELL \-c\fR if \fB$SHELL\fR is set, otherwise \fBsh \-c\fR
|
||||
On Windows, the default value is \fBcmd /s/c\fR when \fB$SHELL\fR is not
|
||||
set.
|
||||
|
||||
.RS
|
||||
e.g. \fBgem list | fzf \-\-with\-shell 'ruby \-e' \-\-preview 'pp Gem::Specification.find_by_name({1})'\fR
|
||||
.RE
|
||||
.TP
|
||||
.B "\-\-listen[=[ADDR:]PORT]" "\-\-listen\-unsafe[=[ADDR:]PORT]"
|
||||
Start HTTP server and listen on the given address. It allows external processes
|
||||
@@ -978,18 +1034,8 @@ e.g.
|
||||
# Choose port automatically and export it as $FZF_PORT to the child process
|
||||
fzf \-\-listen \-\-bind 'start:execute\-silent:echo $FZF_PORT > /tmp/fzf\-port'
|
||||
\fR
|
||||
.SS Help
|
||||
.TP
|
||||
.B "\-\-version"
|
||||
Display version information and exit
|
||||
.TP
|
||||
.B "\-\-help"
|
||||
Show help message
|
||||
.TP
|
||||
.B "\-\-man"
|
||||
Show man page
|
||||
|
||||
.SS Directory traversal
|
||||
.SS DIRECTORY TRAVERSAL
|
||||
.TP
|
||||
.B "\-\-walker=[file][,dir][,follow][,hidden]"
|
||||
Determines the behavior of the built-in directory walker that is used when
|
||||
@@ -1014,7 +1060,22 @@ The default value is the current working directory.
|
||||
Comma-separated list of directory names to skip during the directory walk.
|
||||
The default value is \fB.git,node_modules\fR.
|
||||
|
||||
.SS Shell integration
|
||||
.SS HISTORY
|
||||
.TP
|
||||
.BI "\-\-history=" "HISTORY_FILE"
|
||||
Load search history from the specified file and update the file on completion.
|
||||
When enabled, \fBCTRL\-N\fR and \fBCTRL\-P\fR are automatically remapped to
|
||||
\fBnext\-history\fR and \fBprev\-history\fR.
|
||||
.TP
|
||||
.BI "\-\-history\-size=" "N"
|
||||
Maximum number of entries in the history file (default: 1000). The file is
|
||||
automatically truncated when the number of the lines exceeds the value.
|
||||
|
||||
.RS
|
||||
e.g. \fBgem list | fzf \-\-with\-shell 'ruby \-e' \-\-preview 'pp Gem::Specification.find_by_name({1})'\fR
|
||||
.RE
|
||||
|
||||
.SS SHELL INTEGRATION
|
||||
.TP
|
||||
.B "\-\-bash"
|
||||
Print script to set up Bash shell integration
|
||||
@@ -1033,6 +1094,31 @@ Print script to set up Fish shell integration
|
||||
|
||||
e.g. \fBfzf \-\-fish | source\fR
|
||||
|
||||
.SS OTHERS
|
||||
.TP
|
||||
.B "\-\-no\-mouse"
|
||||
Disable mouse
|
||||
.TP
|
||||
.B "\-\-no\-unicode"
|
||||
Use ASCII characters instead of Unicode drawing characters to draw borders,
|
||||
the spinner and the horizontal separator.
|
||||
|
||||
.TP
|
||||
.B "\-\-ambidouble"
|
||||
Set this option if your terminal displays ambiguous width characters (e.g.
|
||||
box-drawing characters for borders) as 2 columns.
|
||||
|
||||
.SS HELP
|
||||
.TP
|
||||
.B "\-\-version"
|
||||
Display version information and exit
|
||||
.TP
|
||||
.B "\-\-help"
|
||||
Show help message
|
||||
.TP
|
||||
.B "\-\-man"
|
||||
Show man page
|
||||
|
||||
.SH ENVIRONMENT VARIABLES
|
||||
.TP
|
||||
.B FZF_DEFAULT_COMMAND
|
||||
@@ -1110,6 +1196,8 @@ fzf exports the following environment variables to its child processes.
|
||||
.br
|
||||
.BR FZF_QUERY " Current query string"
|
||||
.br
|
||||
.BR FZF_NTH " Current \-\-nth option"
|
||||
.br
|
||||
.BR FZF_PROMPT " Prompt string"
|
||||
.br
|
||||
.BR FZF_PREVIEW_LABEL " Preview label string"
|
||||
@@ -1440,8 +1528,12 @@ A key or an event can be bound to one or more of the following actions.
|
||||
\fBcancel\fR (clear query string if not empty, abort fzf otherwise)
|
||||
\fBchange\-border\-label(...)\fR (change \fB\-\-border\-label\fR to the given string)
|
||||
\fBchange\-header(...)\fR (change header to the given string; doesn't affect \fB\-\-header\-lines\fR)
|
||||
\fBchange\-header\-label(...)\fR (change \fB\-\-header\-label\fR to the given string)
|
||||
\fBchange\-input\-label(...)\fR (change \fB\-\-input\-label\fR to the given string)
|
||||
\fBchange\-list\-label(...)\fR (change \fB\-\-list\-label\fR to the given string)
|
||||
\fBchange\-multi\fR (enable multi-select mode with no limit)
|
||||
\fBchange\-multi(...)\fR (enable multi-select mode with a limit or disable it with 0)
|
||||
\fBchange\-nth(...)\fR (change \fB\-\-nth\fR option; rotate through the multiple options separated by '|')
|
||||
\fBchange\-preview(...)\fR (change \fB\-\-preview\fR option)
|
||||
\fBchange\-preview\-label(...)\fR (change \fB\-\-preview\-label\fR to the given string)
|
||||
\fBchange\-preview\-window(...)\fR (change \fB\-\-preview\-window\fR option; rotate through the multiple option sets separated by '|')
|
||||
@@ -1492,7 +1584,7 @@ A key or an event can be bound to one or more of the following actions.
|
||||
\fBpreview\-half\-page\-up\fR
|
||||
\fBpreview\-bottom\fR
|
||||
\fBpreview\-top\fR
|
||||
\fBprint(...)\fR (add string to the output queue and print on exit)
|
||||
\fBprint(...)\fR (add string to the output queue and print on normal exit)
|
||||
\fBput\fR (put the character to the prompt)
|
||||
\fBput(...)\fR (put the given string to the prompt)
|
||||
\fBrefresh\-preview\fR
|
||||
@@ -1506,10 +1598,11 @@ A key or an event can be bound to one or more of the following actions.
|
||||
\fBshow\-preview\fR
|
||||
\fBtoggle\fR (\fIright\-click\fR)
|
||||
\fBtoggle\-all\fR (toggle all matches)
|
||||
\fBtoggle+down\fR \fIctrl\-i (tab)\fR
|
||||
\fBtoggle\-header\fR
|
||||
\fBtoggle\-in\fR (\fB\-\-layout=reverse*\fR ? \fBtoggle+up\fR : \fBtoggle+down\fR)
|
||||
\fBtoggle\-out\fR (\fB\-\-layout=reverse*\fR ? \fBtoggle+down\fR : \fBtoggle+up\fR)
|
||||
\fBtoggle\-header\fR
|
||||
\fBtoggle\-hscroll\fR
|
||||
\fBtoggle\-multi\-line\fR
|
||||
\fBtoggle\-preview\fR
|
||||
\fBtoggle\-preview\-wrap\fR
|
||||
\fBtoggle\-search\fR (toggle search functionality)
|
||||
@@ -1517,11 +1610,15 @@ A key or an event can be bound to one or more of the following actions.
|
||||
\fBtoggle\-track\fR (toggle global tracking option (\fB\-\-track\fR))
|
||||
\fBtoggle\-track\-current\fR (toggle tracking of the current item)
|
||||
\fBtoggle\-wrap\fR \fIctrl\-/\fR \fIalt\-/\fR
|
||||
\fBtoggle+down\fR \fIctrl\-i (tab)\fR
|
||||
\fBtoggle+up\fR \fIbtab (shift\-tab)\fR
|
||||
\fBtrack\-current\fR (track the current item; automatically disabled if focus changes)
|
||||
\fBtransform(...)\fR (transform states using the output of an external command)
|
||||
\fBtransform\-border\-label(...)\fR (transform border label using an external command)
|
||||
\fBtransform\-header(...)\fR (transform header using an external command)
|
||||
\fBtransform\-header\-label(...)\fR (transform header label using an external command)
|
||||
\fBtransform\-input\-label(...)\fR (transform input label using an external command)
|
||||
\fBtransform\-list\-label(...)\fR (transform list label using an external command)
|
||||
\fBtransform\-preview\-label(...)\fR (transform preview label using an external command)
|
||||
\fBtransform\-prompt(...)\fR (transform prompt string using an external command)
|
||||
\fBtransform\-query(...)\fR (transform query string using an external command)
|
||||
|
@@ -31,13 +31,14 @@ function fzf_key_bindings
|
||||
set -lx dir $commandline[1]
|
||||
set -l fzf_query $commandline[2]
|
||||
set -l prefix $commandline[3]
|
||||
set -l result
|
||||
|
||||
test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
|
||||
begin
|
||||
set -lx FZF_DEFAULT_OPTS (__fzf_defaults "--reverse --walker=file,dir,follow,hidden --scheme=path --walker-root=$dir" "$FZF_CTRL_T_OPTS")
|
||||
set -lx FZF_DEFAULT_COMMAND "$FZF_CTRL_T_COMMAND"
|
||||
set -lx FZF_DEFAULT_OPTS_FILE ''
|
||||
eval (__fzfcmd) -m --query=$fzf_query | while read -l r; set -a result $r; end
|
||||
set result (eval (__fzfcmd) -m --query=$fzf_query)
|
||||
end
|
||||
if test -z "$result"
|
||||
commandline -f repaint
|
||||
@@ -57,33 +58,25 @@ function fzf_key_bindings
|
||||
function fzf-history-widget -d "Show command history"
|
||||
test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
|
||||
begin
|
||||
set -l FISH_MAJOR (string split '.' -- $version)[1]
|
||||
set -l FISH_MINOR (string split '.' -- $version)[2]
|
||||
|
||||
# merge history from other sessions before searching
|
||||
test -z "$fish_private_mode"; and builtin history merge
|
||||
|
||||
# history's -z flag is needed for multi-line support.
|
||||
# history's -z flag was added in fish 2.4.0, so don't use it for versions
|
||||
# before 2.4.0.
|
||||
if test "$FISH_MAJOR" -gt 2 -o \( "$FISH_MAJOR" -eq 2 -a "$FISH_MINOR" -ge 4 \)
|
||||
set -lx FZF_DEFAULT_OPTS (__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort --wrap-sign '"\t"↳ ' --highlight-line $FZF_CTRL_R_OPTS +m")
|
||||
set -lx FZF_DEFAULT_OPTS_FILE ''
|
||||
if type -q perl
|
||||
builtin history -z --reverse | command perl -0 -pe 's/^/$.\t/g; s/\n/\n\t/gm' | eval (__fzfcmd) --tac --read0 --print0 -q '(commandline)' | string replace -r '^\d*\t' '' | read -lz result
|
||||
and commandline -- $result
|
||||
else
|
||||
set -l line 0
|
||||
for i in (builtin history -z --reverse | string split0)
|
||||
set line (math $line + 1)
|
||||
string escape -n -- $line\t$i
|
||||
end | string join0 | string replace -a '\n' '\n\t' | string unescape -n | eval (__fzfcmd) --tac --read0 --print0 -q '(commandline)' | string replace -r '^\d*\t' '' | read -lz result
|
||||
and commandline -- $result
|
||||
end
|
||||
set -lx FZF_DEFAULT_OPTS (__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort --wrap-sign '"\t"↳ ' --highlight-line +m $FZF_CTRL_R_OPTS")
|
||||
set -lx FZF_DEFAULT_OPTS_FILE ''
|
||||
set -lx FZF_DEFAULT_COMMAND
|
||||
string match -q -r -- '/fish$' $SHELL; or set -lx SHELL (type -p fish)
|
||||
if type -q perl
|
||||
set -a FZF_DEFAULT_OPTS '--tac'
|
||||
set FZF_DEFAULT_COMMAND 'builtin history -z --reverse | command perl -0 -pe \'s/^/$.\t/g; s/\n/\n\t/gm\''
|
||||
else
|
||||
builtin history | eval (__fzfcmd) -q '(commandline)' | read -l result
|
||||
and commandline -- $result
|
||||
set FZF_DEFAULT_COMMAND \
|
||||
'set -l h (builtin history -z --reverse | string split0);' \
|
||||
'for i in (seq (count $h) -1 1);' \
|
||||
'string join0 -- $i\t(string replace -a -- \n \n\t $h[$i] | string collect);' \
|
||||
'end'
|
||||
end
|
||||
set -l result (eval "$FZF_DEFAULT_COMMAND | $(__fzfcmd) --read0 --print0 -q (commandline) --bind='enter:become:string replace -a -- \n\t \n {2..} | string collect'")
|
||||
and commandline -- $result
|
||||
end
|
||||
commandline -f repaint
|
||||
end
|
||||
@@ -99,7 +92,7 @@ function fzf_key_bindings
|
||||
set -lx FZF_DEFAULT_OPTS (__fzf_defaults "--reverse --walker=dir,follow,hidden --scheme=path --walker-root=$dir" "$FZF_ALT_C_OPTS")
|
||||
set -lx FZF_DEFAULT_OPTS_FILE ''
|
||||
set -lx FZF_DEFAULT_COMMAND "$FZF_ALT_C_COMMAND"
|
||||
eval (__fzfcmd) +m --query=$fzf_query | read -l result
|
||||
set -l result (eval (__fzfcmd) +m --query=$fzf_query)
|
||||
|
||||
if test -n "$result"
|
||||
cd -- $result
|
||||
@@ -133,14 +126,12 @@ function fzf_key_bindings
|
||||
bind \ec fzf-cd-widget
|
||||
end
|
||||
|
||||
if bind -M insert &> /dev/null
|
||||
bind -M insert \cr fzf-history-widget
|
||||
if not set -q FZF_CTRL_T_COMMAND; or test -n "$FZF_CTRL_T_COMMAND"
|
||||
bind -M insert \ct fzf-file-widget
|
||||
end
|
||||
if not set -q FZF_ALT_C_COMMAND; or test -n "$FZF_ALT_C_COMMAND"
|
||||
bind -M insert \ec fzf-cd-widget
|
||||
end
|
||||
bind -M insert \cr fzf-history-widget
|
||||
if not set -q FZF_CTRL_T_COMMAND; or test -n "$FZF_CTRL_T_COMMAND"
|
||||
bind -M insert \ct fzf-file-widget
|
||||
end
|
||||
if not set -q FZF_ALT_C_COMMAND; or test -n "$FZF_ALT_C_COMMAND"
|
||||
bind -M insert \ec fzf-cd-widget
|
||||
end
|
||||
|
||||
function __fzf_parse_commandline -d 'Parse the current command line token and return split of existing filepath, fzf query, and optional -option= prefix'
|
||||
@@ -150,17 +141,20 @@ function fzf_key_bindings
|
||||
set -l prefix (string match -r -- '^-[^\s=]+=' $commandline)
|
||||
set commandline (string replace -- "$prefix" '' $commandline)
|
||||
|
||||
# Enable home directory expansion of leading ~/
|
||||
set commandline (string replace -r -- '^~/' '\$HOME/' $commandline)
|
||||
|
||||
# escape special characters, except for the $ sign of valid variable names,
|
||||
# so that after eval, the original string is returned, but with the
|
||||
# variable names replaced by their values.
|
||||
set commandline (string escape -n -- $commandline)
|
||||
set commandline (string replace -r -a '\x5c\$(?=[\w])' '\$' -- $commandline)
|
||||
set commandline (string replace -r -a -- '\x5c\$(?=[\w])' '\$' $commandline)
|
||||
|
||||
# eval is used to do shell expansion on paths
|
||||
eval set commandline $commandline
|
||||
|
||||
# Combine multiple consecutive slashes into one
|
||||
set commandline (string replace -r -a '/+' '/' -- $commandline)
|
||||
set commandline (string replace -r -a -- '/+' '/' $commandline)
|
||||
|
||||
if test -z "$commandline"
|
||||
# Default to current directory with no --query
|
||||
@@ -172,12 +166,12 @@ function fzf_key_bindings
|
||||
# BUG: on combined expressions, if a left argument is a single `!`, the
|
||||
# builtin test command of fish will treat it as the ! operator. To
|
||||
# overcome this, have the variable parts on the right.
|
||||
if test "." = "$dir" -a "." != (string sub -l 1 -- $commandline)
|
||||
if test "." = "$dir" -a "./" != (string sub -l 2 -- $commandline)
|
||||
# if $dir is "." but commandline is not a relative path, this means no file path found
|
||||
set fzf_query $commandline
|
||||
else
|
||||
# Also remove trailing slash after dir, to "split" input properly
|
||||
set fzf_query (string replace -r "^$dir/?" '' -- $commandline)
|
||||
set fzf_query (string replace -r -- "^$dir/?" '' $commandline)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -190,7 +184,7 @@ function fzf_key_bindings
|
||||
set dir $argv
|
||||
|
||||
# Strip trailing slash, unless $dir is root dir (/)
|
||||
set dir (string replace -r '(?<!^)/$' '' -- $dir)
|
||||
set dir (string replace -r -- '(?<!^)/$' '' $dir)
|
||||
|
||||
# Iteratively check if dir exists and strip tail end of path
|
||||
while test ! -d "$dir"
|
||||
|
@@ -25,107 +25,116 @@ func _() {
|
||||
_ = x[actBackwardWord-14]
|
||||
_ = x[actCancel-15]
|
||||
_ = x[actChangeBorderLabel-16]
|
||||
_ = x[actChangeHeader-17]
|
||||
_ = x[actChangeMulti-18]
|
||||
_ = x[actChangePreviewLabel-19]
|
||||
_ = x[actChangePrompt-20]
|
||||
_ = x[actChangeQuery-21]
|
||||
_ = x[actClearScreen-22]
|
||||
_ = x[actClearQuery-23]
|
||||
_ = x[actClearSelection-24]
|
||||
_ = x[actClose-25]
|
||||
_ = x[actDeleteChar-26]
|
||||
_ = x[actDeleteCharEof-27]
|
||||
_ = x[actEndOfLine-28]
|
||||
_ = x[actFatal-29]
|
||||
_ = x[actForwardChar-30]
|
||||
_ = x[actForwardWord-31]
|
||||
_ = x[actKillLine-32]
|
||||
_ = x[actKillWord-33]
|
||||
_ = x[actUnixLineDiscard-34]
|
||||
_ = x[actUnixWordRubout-35]
|
||||
_ = x[actYank-36]
|
||||
_ = x[actBackwardKillWord-37]
|
||||
_ = x[actSelectAll-38]
|
||||
_ = x[actDeselectAll-39]
|
||||
_ = x[actToggle-40]
|
||||
_ = x[actToggleSearch-41]
|
||||
_ = x[actToggleAll-42]
|
||||
_ = x[actToggleDown-43]
|
||||
_ = x[actToggleUp-44]
|
||||
_ = x[actToggleIn-45]
|
||||
_ = x[actToggleOut-46]
|
||||
_ = x[actToggleTrack-47]
|
||||
_ = x[actToggleTrackCurrent-48]
|
||||
_ = x[actToggleHeader-49]
|
||||
_ = x[actToggleWrap-50]
|
||||
_ = x[actTrackCurrent-51]
|
||||
_ = x[actUntrackCurrent-52]
|
||||
_ = x[actDown-53]
|
||||
_ = x[actUp-54]
|
||||
_ = x[actPageUp-55]
|
||||
_ = x[actPageDown-56]
|
||||
_ = x[actPosition-57]
|
||||
_ = x[actHalfPageUp-58]
|
||||
_ = x[actHalfPageDown-59]
|
||||
_ = x[actOffsetUp-60]
|
||||
_ = x[actOffsetDown-61]
|
||||
_ = x[actOffsetMiddle-62]
|
||||
_ = x[actJump-63]
|
||||
_ = x[actJumpAccept-64]
|
||||
_ = x[actPrintQuery-65]
|
||||
_ = x[actRefreshPreview-66]
|
||||
_ = x[actReplaceQuery-67]
|
||||
_ = x[actToggleSort-68]
|
||||
_ = x[actShowPreview-69]
|
||||
_ = x[actHidePreview-70]
|
||||
_ = x[actTogglePreview-71]
|
||||
_ = x[actTogglePreviewWrap-72]
|
||||
_ = x[actTransform-73]
|
||||
_ = x[actTransformBorderLabel-74]
|
||||
_ = x[actTransformHeader-75]
|
||||
_ = x[actTransformPreviewLabel-76]
|
||||
_ = x[actTransformPrompt-77]
|
||||
_ = x[actTransformQuery-78]
|
||||
_ = x[actPreview-79]
|
||||
_ = x[actChangePreview-80]
|
||||
_ = x[actChangePreviewWindow-81]
|
||||
_ = x[actPreviewTop-82]
|
||||
_ = x[actPreviewBottom-83]
|
||||
_ = x[actPreviewUp-84]
|
||||
_ = x[actPreviewDown-85]
|
||||
_ = x[actPreviewPageUp-86]
|
||||
_ = x[actPreviewPageDown-87]
|
||||
_ = x[actPreviewHalfPageUp-88]
|
||||
_ = x[actPreviewHalfPageDown-89]
|
||||
_ = x[actPrevHistory-90]
|
||||
_ = x[actPrevSelected-91]
|
||||
_ = x[actPrint-92]
|
||||
_ = x[actPut-93]
|
||||
_ = x[actNextHistory-94]
|
||||
_ = x[actNextSelected-95]
|
||||
_ = x[actExecute-96]
|
||||
_ = x[actExecuteSilent-97]
|
||||
_ = x[actExecuteMulti-98]
|
||||
_ = x[actSigStop-99]
|
||||
_ = x[actFirst-100]
|
||||
_ = x[actLast-101]
|
||||
_ = x[actReload-102]
|
||||
_ = x[actReloadSync-103]
|
||||
_ = x[actDisableSearch-104]
|
||||
_ = x[actEnableSearch-105]
|
||||
_ = x[actSelect-106]
|
||||
_ = x[actDeselect-107]
|
||||
_ = x[actUnbind-108]
|
||||
_ = x[actRebind-109]
|
||||
_ = x[actBecome-110]
|
||||
_ = x[actShowHeader-111]
|
||||
_ = x[actHideHeader-112]
|
||||
_ = x[actChangeListLabel-17]
|
||||
_ = x[actChangeInputLabel-18]
|
||||
_ = x[actChangeHeader-19]
|
||||
_ = x[actChangeHeaderLabel-20]
|
||||
_ = x[actChangeMulti-21]
|
||||
_ = x[actChangePreviewLabel-22]
|
||||
_ = x[actChangePrompt-23]
|
||||
_ = x[actChangeQuery-24]
|
||||
_ = x[actChangeNth-25]
|
||||
_ = x[actClearScreen-26]
|
||||
_ = x[actClearQuery-27]
|
||||
_ = x[actClearSelection-28]
|
||||
_ = x[actClose-29]
|
||||
_ = x[actDeleteChar-30]
|
||||
_ = x[actDeleteCharEof-31]
|
||||
_ = x[actEndOfLine-32]
|
||||
_ = x[actFatal-33]
|
||||
_ = x[actForwardChar-34]
|
||||
_ = x[actForwardWord-35]
|
||||
_ = x[actKillLine-36]
|
||||
_ = x[actKillWord-37]
|
||||
_ = x[actUnixLineDiscard-38]
|
||||
_ = x[actUnixWordRubout-39]
|
||||
_ = x[actYank-40]
|
||||
_ = x[actBackwardKillWord-41]
|
||||
_ = x[actSelectAll-42]
|
||||
_ = x[actDeselectAll-43]
|
||||
_ = x[actToggle-44]
|
||||
_ = x[actToggleSearch-45]
|
||||
_ = x[actToggleAll-46]
|
||||
_ = x[actToggleDown-47]
|
||||
_ = x[actToggleUp-48]
|
||||
_ = x[actToggleIn-49]
|
||||
_ = x[actToggleOut-50]
|
||||
_ = x[actToggleTrack-51]
|
||||
_ = x[actToggleTrackCurrent-52]
|
||||
_ = x[actToggleHeader-53]
|
||||
_ = x[actToggleWrap-54]
|
||||
_ = x[actToggleMultiLine-55]
|
||||
_ = x[actToggleHscroll-56]
|
||||
_ = x[actTrackCurrent-57]
|
||||
_ = x[actUntrackCurrent-58]
|
||||
_ = x[actDown-59]
|
||||
_ = x[actUp-60]
|
||||
_ = x[actPageUp-61]
|
||||
_ = x[actPageDown-62]
|
||||
_ = x[actPosition-63]
|
||||
_ = x[actHalfPageUp-64]
|
||||
_ = x[actHalfPageDown-65]
|
||||
_ = x[actOffsetUp-66]
|
||||
_ = x[actOffsetDown-67]
|
||||
_ = x[actOffsetMiddle-68]
|
||||
_ = x[actJump-69]
|
||||
_ = x[actJumpAccept-70]
|
||||
_ = x[actPrintQuery-71]
|
||||
_ = x[actRefreshPreview-72]
|
||||
_ = x[actReplaceQuery-73]
|
||||
_ = x[actToggleSort-74]
|
||||
_ = x[actShowPreview-75]
|
||||
_ = x[actHidePreview-76]
|
||||
_ = x[actTogglePreview-77]
|
||||
_ = x[actTogglePreviewWrap-78]
|
||||
_ = x[actTransform-79]
|
||||
_ = x[actTransformBorderLabel-80]
|
||||
_ = x[actTransformListLabel-81]
|
||||
_ = x[actTransformInputLabel-82]
|
||||
_ = x[actTransformHeader-83]
|
||||
_ = x[actTransformHeaderLabel-84]
|
||||
_ = x[actTransformPreviewLabel-85]
|
||||
_ = x[actTransformPrompt-86]
|
||||
_ = x[actTransformQuery-87]
|
||||
_ = x[actPreview-88]
|
||||
_ = x[actChangePreview-89]
|
||||
_ = x[actChangePreviewWindow-90]
|
||||
_ = x[actPreviewTop-91]
|
||||
_ = x[actPreviewBottom-92]
|
||||
_ = x[actPreviewUp-93]
|
||||
_ = x[actPreviewDown-94]
|
||||
_ = x[actPreviewPageUp-95]
|
||||
_ = x[actPreviewPageDown-96]
|
||||
_ = x[actPreviewHalfPageUp-97]
|
||||
_ = x[actPreviewHalfPageDown-98]
|
||||
_ = x[actPrevHistory-99]
|
||||
_ = x[actPrevSelected-100]
|
||||
_ = x[actPrint-101]
|
||||
_ = x[actPut-102]
|
||||
_ = x[actNextHistory-103]
|
||||
_ = x[actNextSelected-104]
|
||||
_ = x[actExecute-105]
|
||||
_ = x[actExecuteSilent-106]
|
||||
_ = x[actExecuteMulti-107]
|
||||
_ = x[actSigStop-108]
|
||||
_ = x[actFirst-109]
|
||||
_ = x[actLast-110]
|
||||
_ = x[actReload-111]
|
||||
_ = x[actReloadSync-112]
|
||||
_ = x[actDisableSearch-113]
|
||||
_ = x[actEnableSearch-114]
|
||||
_ = x[actSelect-115]
|
||||
_ = x[actDeselect-116]
|
||||
_ = x[actUnbind-117]
|
||||
_ = x[actRebind-118]
|
||||
_ = x[actBecome-119]
|
||||
_ = x[actShowHeader-120]
|
||||
_ = x[actHideHeader-121]
|
||||
}
|
||||
|
||||
const _actionType_name = "actIgnoreactStartactClickactInvalidactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeHeaderactChangeMultiactChangePreviewLabelactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactTrackCurrentactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformHeaderactTransformPreviewLabelactTransformPromptactTransformQueryactPreviewactChangePreviewactChangePreviewWindowactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactBecomeactShowHeaderactHideHeader"
|
||||
const _actionType_name = "actIgnoreactStartactClickactInvalidactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeListLabelactChangeInputLabelactChangeHeaderactChangeHeaderLabelactChangeMultiactChangePreviewLabelactChangePromptactChangeQueryactChangeNthactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformListLabelactTransformInputLabelactTransformHeaderactTransformHeaderLabelactTransformPreviewLabelactTransformPromptactTransformQueryactPreviewactChangePreviewactChangePreviewWindowactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactBecomeactShowHeaderactHideHeader"
|
||||
|
||||
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 42, 50, 68, 76, 85, 102, 123, 138, 159, 183, 198, 207, 227, 242, 256, 277, 292, 306, 320, 333, 350, 358, 371, 387, 399, 407, 421, 435, 446, 457, 475, 492, 499, 518, 530, 544, 553, 568, 580, 593, 604, 615, 627, 641, 662, 677, 690, 705, 722, 729, 734, 743, 754, 765, 778, 793, 804, 817, 832, 839, 852, 865, 882, 897, 910, 924, 938, 954, 974, 986, 1009, 1027, 1051, 1069, 1086, 1096, 1112, 1134, 1147, 1163, 1175, 1189, 1205, 1223, 1243, 1265, 1279, 1294, 1302, 1308, 1322, 1337, 1347, 1363, 1378, 1388, 1396, 1403, 1412, 1425, 1441, 1456, 1465, 1476, 1485, 1494, 1503, 1516, 1529}
|
||||
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 42, 50, 68, 76, 85, 102, 123, 138, 159, 183, 198, 207, 227, 245, 264, 279, 299, 313, 334, 349, 363, 375, 389, 402, 419, 427, 440, 456, 468, 476, 490, 504, 515, 526, 544, 561, 568, 587, 599, 613, 622, 637, 649, 662, 673, 684, 696, 710, 731, 746, 759, 777, 793, 808, 825, 832, 837, 846, 857, 868, 881, 896, 907, 920, 935, 942, 955, 968, 985, 1000, 1013, 1027, 1041, 1057, 1077, 1089, 1112, 1133, 1155, 1173, 1196, 1220, 1238, 1255, 1265, 1281, 1303, 1316, 1332, 1344, 1358, 1374, 1392, 1412, 1434, 1448, 1463, 1471, 1477, 1491, 1506, 1516, 1532, 1547, 1557, 1565, 1572, 1581, 1594, 1610, 1625, 1634, 1645, 1654, 1663, 1672, 1685, 1698}
|
||||
|
||||
func (i actionType) String() string {
|
||||
if i < 0 || i >= actionType(len(_actionType_index)-1) {
|
||||
|
@@ -401,7 +401,7 @@ func debugV2(T []rune, pattern []rune, F []int32, lastIdx int, H []int16, C []in
|
||||
if i == 0 {
|
||||
fmt.Print(" ")
|
||||
for j := int(f); j <= lastIdx; j++ {
|
||||
fmt.Printf(" " + string(T[j]) + " ")
|
||||
fmt.Print(" " + string(T[j]) + " ")
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
52
src/ansi.go
52
src/ansi.go
@@ -44,7 +44,7 @@ func (s *ansiState) ToString() string {
|
||||
}
|
||||
|
||||
ret := ""
|
||||
if s.attr&tui.Bold > 0 {
|
||||
if s.attr&tui.Bold > 0 || s.attr&tui.BoldForce > 0 {
|
||||
ret += "1;"
|
||||
}
|
||||
if s.attr&tui.Dim > 0 {
|
||||
@@ -98,11 +98,11 @@ func isPrint(c uint8) bool {
|
||||
return '\x20' <= c && c <= '\x7e'
|
||||
}
|
||||
|
||||
func matchOperatingSystemCommand(s string) int {
|
||||
func matchOperatingSystemCommand(s string, start int) int {
|
||||
// `\x1b][0-9][;:][[:print:]]+(?:\x1b\\\\|\x07)`
|
||||
// ^ match starting here
|
||||
// ^ match starting here after the first printable character
|
||||
//
|
||||
i := 5 // prefix matched in nextAnsiEscapeSequence()
|
||||
i := start // prefix matched in nextAnsiEscapeSequence()
|
||||
for ; i < len(s) && isPrint(s[i]); i++ {
|
||||
}
|
||||
if i < len(s) {
|
||||
@@ -156,7 +156,7 @@ func isCtrlSeqStart(c uint8) bool {
|
||||
// nextAnsiEscapeSequence returns the ANSI escape sequence and is equivalent to
|
||||
// calling FindStringIndex() on the below regex (which was originally used):
|
||||
//
|
||||
// "(?:\x1b[\\[()][0-9;:?]*[a-zA-Z@]|\x1b][0-9][;:][[:print:]]+(?:\x1b\\\\|\x07)|\x1b.|[\x0e\x0f]|.\x08)"
|
||||
// "(?:\x1b[\\[()][0-9;:?]*[a-zA-Z@]|\x1b][0-9]+[;:][[:print:]]+(?:\x1b\\\\|\x07)|\x1b.|[\x0e\x0f]|.\x08)"
|
||||
func nextAnsiEscapeSequence(s string) (int, int) {
|
||||
// fast check for ANSI escape sequences
|
||||
i := 0
|
||||
@@ -191,12 +191,20 @@ Loop:
|
||||
}
|
||||
}
|
||||
|
||||
// match: `\x1b][0-9][;:][[:print:]]+(?:\x1b\\\\|\x07)`
|
||||
if i+5 < len(s) && s[i+1] == ']' && isNumeric(s[i+2]) &&
|
||||
(s[i+3] == ';' || s[i+3] == ':') && isPrint(s[i+4]) {
|
||||
// match: `\x1b][0-9]+[;:][[:print:]]+(?:\x1b\\\\|\x07)`
|
||||
if i+5 < len(s) && s[i+1] == ']' {
|
||||
j := 2
|
||||
// \x1b][0-9]+[;:][[:print:]]+(?:\x1b\\\\|\x07)
|
||||
// ------
|
||||
for ; i+j < len(s) && isNumeric(s[i+j]); j++ {
|
||||
}
|
||||
|
||||
if j := matchOperatingSystemCommand(s[i:]); j != -1 {
|
||||
return i, i + j
|
||||
// \x1b][0-9]+[;:][[:print:]]+(?:\x1b\\\\|\x07)
|
||||
// ---------------
|
||||
if j > 2 && i+j+1 < len(s) && (s[i+j] == ';' || s[i+j] == ':') && isPrint(s[i+j+1]) {
|
||||
if k := matchOperatingSystemCommand(s[i:], j+2); k != -1 {
|
||||
return i, i + k
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,20 +318,15 @@ func extractColor(str string, state *ansiState, proc func(string, *ansiState) bo
|
||||
return trimmed, nil, state
|
||||
}
|
||||
|
||||
func parseAnsiCode(s string, delimiter byte) (int, byte, string) {
|
||||
func parseAnsiCode(s string) (int, string) {
|
||||
var remaining string
|
||||
var i int
|
||||
if delimiter == 0 {
|
||||
// Faster than strings.IndexAny(";:")
|
||||
i = strings.IndexByte(s, ';')
|
||||
if i < 0 {
|
||||
i = strings.IndexByte(s, ':')
|
||||
}
|
||||
} else {
|
||||
i = strings.IndexByte(s, delimiter)
|
||||
// Faster than strings.IndexAny(";:")
|
||||
i = strings.IndexByte(s, ';')
|
||||
if i < 0 {
|
||||
i = strings.IndexByte(s, ':')
|
||||
}
|
||||
if i >= 0 {
|
||||
delimiter = s[i]
|
||||
remaining = s[i+1:]
|
||||
s = s[:i]
|
||||
}
|
||||
@@ -335,14 +338,14 @@ func parseAnsiCode(s string, delimiter byte) (int, byte, string) {
|
||||
for _, ch := range stringBytes(s) {
|
||||
ch -= '0'
|
||||
if ch > 9 {
|
||||
return -1, delimiter, remaining
|
||||
return -1, remaining
|
||||
}
|
||||
code = code*10 + int(ch)
|
||||
}
|
||||
return code, delimiter, remaining
|
||||
return code, remaining
|
||||
}
|
||||
|
||||
return -1, delimiter, remaining
|
||||
return -1, remaining
|
||||
}
|
||||
|
||||
func interpretCode(ansiCode string, prevState *ansiState) ansiState {
|
||||
@@ -378,11 +381,10 @@ func interpretCode(ansiCode string, prevState *ansiState) ansiState {
|
||||
state256 := 0
|
||||
ptr := &state.fg
|
||||
|
||||
var delimiter byte
|
||||
count := 0
|
||||
for len(ansiCode) != 0 {
|
||||
var num int
|
||||
if num, delimiter, ansiCode = parseAnsiCode(ansiCode, delimiter); num != -1 {
|
||||
if num, ansiCode = parseAnsiCode(ansiCode); num != -1 {
|
||||
count++
|
||||
switch state256 {
|
||||
case 0:
|
||||
|
@@ -335,6 +335,28 @@ func TestExtractColor(t *testing.T) {
|
||||
assert((*offsets)[0], 0, 6, 2, -1, true)
|
||||
assert((*offsets)[1], 6, 11, 200, 100, false)
|
||||
})
|
||||
|
||||
state = nil
|
||||
var color24 tui.Color = (1 << 24) + (180 << 16) + (190 << 8) + 254
|
||||
src = "\x1b[1mhello \x1b[22;1;38:2:180:190:254mworld"
|
||||
check(func(offsets *[]ansiOffset, state *ansiState) {
|
||||
if len(*offsets) != 2 {
|
||||
t.Fail()
|
||||
}
|
||||
if state.fg != color24 || state.attr != 1 {
|
||||
t.Fail()
|
||||
}
|
||||
assert((*offsets)[0], 0, 6, -1, -1, true)
|
||||
assert((*offsets)[1], 6, 11, color24, -1, true)
|
||||
})
|
||||
|
||||
src = "\x1b]133;A\x1b\\hello \x1b]133;C\x1b\\world"
|
||||
check(func(offsets *[]ansiOffset, state *ansiState) {
|
||||
if len(*offsets) != 1 {
|
||||
t.Fail()
|
||||
}
|
||||
assert((*offsets)[0], 0, 11, color24, -1, true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAnsiCodeStringConversion(t *testing.T) {
|
||||
@@ -381,7 +403,7 @@ func TestParseAnsiCode(t *testing.T) {
|
||||
{"-2", "", -1},
|
||||
}
|
||||
for _, x := range tests {
|
||||
n, _, s := parseAnsiCode(x.In, 0)
|
||||
n, s := parseAnsiCode(x.In)
|
||||
if n != x.N || s != x.Exp {
|
||||
t.Fatalf("%q: got: (%d %q) want: (%d %q)", x.In, n, s, x.N, x.Exp)
|
||||
}
|
||||
|
13
src/core.go
13
src/core.go
@@ -190,11 +190,14 @@ func Run(opts *Options) (int, error) {
|
||||
forward = true
|
||||
}
|
||||
}
|
||||
|
||||
nth := opts.Nth
|
||||
nthRevision := 0
|
||||
patternCache := make(map[string]*Pattern)
|
||||
patternBuilder := func(runes []rune) *Pattern {
|
||||
return BuildPattern(cache, patternCache,
|
||||
opts.Fuzzy, opts.FuzzyAlgo, opts.Extended, opts.Case, opts.Normalize, forward, withPos,
|
||||
opts.Filter == nil, opts.Nth, opts.Delimiter, runes)
|
||||
opts.Filter == nil, nth, opts.Delimiter, nthRevision, runes)
|
||||
}
|
||||
inputRevision := revision{}
|
||||
snapshotRevision := revision{}
|
||||
@@ -373,6 +376,14 @@ func Run(opts *Options) (int, error) {
|
||||
command = val.command
|
||||
environ = val.environ
|
||||
changed = val.changed
|
||||
if val.nth != nil {
|
||||
// Change nth and clear caches
|
||||
nth = *val.nth
|
||||
nthRevision++
|
||||
patternCache = make(map[string]*Pattern)
|
||||
cache.Clear()
|
||||
inputRevision.bumpMinor()
|
||||
}
|
||||
if command != nil {
|
||||
useSnapshot = val.sync
|
||||
}
|
||||
|
@@ -6,10 +6,17 @@ import (
|
||||
"github.com/junegunn/fzf/src/util"
|
||||
)
|
||||
|
||||
type transformed struct {
|
||||
// Because nth can be changed dynamically by change-nth action, we need to
|
||||
// keep the revision number at the time of transformation.
|
||||
revision int
|
||||
tokens []Token
|
||||
}
|
||||
|
||||
// Item represents each input line. 56 bytes.
|
||||
type Item struct {
|
||||
text util.Chars // 32 = 24 + 1 + 1 + 2 + 4
|
||||
transformed *[]Token // 8
|
||||
transformed *transformed // 8
|
||||
origText *[]byte // 8
|
||||
colors *[]ansiOffset // 8
|
||||
}
|
||||
|
1266
src/options.go
1266
src/options.go
File diff suppressed because it is too large
Load Diff
@@ -9,9 +9,13 @@ import (
|
||||
)
|
||||
|
||||
func TestDelimiterRegex(t *testing.T) {
|
||||
// Valid regex
|
||||
// Valid regex, but a single character -> string
|
||||
delim := delimiterRegexp(".")
|
||||
if delim.regex == nil || delim.str != nil {
|
||||
if delim.regex != nil || *delim.str != "." {
|
||||
t.Error(delim)
|
||||
}
|
||||
delim = delimiterRegexp("|")
|
||||
if delim.regex != nil || *delim.str != "|" {
|
||||
t.Error(delim)
|
||||
}
|
||||
// Broken regex -> string
|
||||
|
@@ -60,6 +60,7 @@ type Pattern struct {
|
||||
cacheKey string
|
||||
delimiter Delimiter
|
||||
nth []Range
|
||||
revision int
|
||||
procFun map[termType]algo.Algo
|
||||
cache *ChunkCache
|
||||
}
|
||||
@@ -72,7 +73,7 @@ func init() {
|
||||
|
||||
// BuildPattern builds Pattern object from the given arguments
|
||||
func BuildPattern(cache *ChunkCache, patternCache map[string]*Pattern, fuzzy bool, fuzzyAlgo algo.Algo, extended bool, caseMode Case, normalize bool, forward bool,
|
||||
withPos bool, cacheable bool, nth []Range, delimiter Delimiter, runes []rune) *Pattern {
|
||||
withPos bool, cacheable bool, nth []Range, delimiter Delimiter, revision int, runes []rune) *Pattern {
|
||||
|
||||
var asString string
|
||||
if extended {
|
||||
@@ -140,6 +141,7 @@ func BuildPattern(cache *ChunkCache, patternCache map[string]*Pattern, fuzzy boo
|
||||
sortable: sortable,
|
||||
cacheable: cacheable,
|
||||
nth: nth,
|
||||
revision: revision,
|
||||
delimiter: delimiter,
|
||||
cache: cache,
|
||||
procFun: make(map[termType]algo.Algo)}
|
||||
@@ -393,12 +395,15 @@ func (p *Pattern) extendedMatch(item *Item, withPos bool, slab *util.Slab) ([]Of
|
||||
|
||||
func (p *Pattern) transformInput(item *Item) []Token {
|
||||
if item.transformed != nil {
|
||||
return *item.transformed
|
||||
transformed := *item.transformed
|
||||
if transformed.revision == p.revision {
|
||||
return transformed.tokens
|
||||
}
|
||||
}
|
||||
|
||||
tokens := Tokenize(item.text.ToString(), p.delimiter)
|
||||
ret := Transform(tokens, p.nth)
|
||||
item.transformed = &ret
|
||||
item.transformed = &transformed{p.revision, ret}
|
||||
return ret
|
||||
}
|
||||
|
||||
|
@@ -68,7 +68,7 @@ func buildPattern(fuzzy bool, fuzzyAlgo algo.Algo, extended bool, caseMode Case,
|
||||
withPos bool, cacheable bool, nth []Range, delimiter Delimiter, runes []rune) *Pattern {
|
||||
return BuildPattern(NewChunkCache(), make(map[string]*Pattern),
|
||||
fuzzy, fuzzyAlgo, extended, caseMode, normalize, forward,
|
||||
withPos, cacheable, nth, delimiter, runes)
|
||||
withPos, cacheable, nth, delimiter, 0, runes)
|
||||
}
|
||||
|
||||
func TestExact(t *testing.T) {
|
||||
@@ -135,12 +135,12 @@ func TestOrigTextAndTransformed(t *testing.T) {
|
||||
chunk.items[0] = Item{
|
||||
text: util.ToChars([]byte("junegunn")),
|
||||
origText: &origBytes,
|
||||
transformed: &trans}
|
||||
transformed: &transformed{pattern.revision, trans}}
|
||||
pattern.extended = extended
|
||||
matches := pattern.matchChunk(&chunk, nil, slab) // No cache
|
||||
if !(matches[0].item.text.ToString() == "junegunn" &&
|
||||
string(*matches[0].item.origText) == "junegunn.choi" &&
|
||||
reflect.DeepEqual(*matches[0].item.transformed, trans)) {
|
||||
reflect.DeepEqual((*matches[0].item.transformed).tokens, trans)) {
|
||||
t.Error("Invalid match result", matches)
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ func TestOrigTextAndTransformed(t *testing.T) {
|
||||
if !(match.item.text.ToString() == "junegunn" &&
|
||||
string(*match.item.origText) == "junegunn.choi" &&
|
||||
offsets[0][0] == 0 && offsets[0][1] == 5 &&
|
||||
reflect.DeepEqual(*match.item.transformed, trans)) {
|
||||
reflect.DeepEqual((*match.item.transformed).tokens, trans)) {
|
||||
t.Error("Invalid match result", match, offsets, extended)
|
||||
}
|
||||
if !((*pos)[0] == 4 && (*pos)[1] == 0) {
|
||||
|
@@ -104,11 +104,11 @@ func minRank() Result {
|
||||
return Result{item: &minItem, points: [4]uint16{math.MaxUint16, 0, 0, 0}}
|
||||
}
|
||||
|
||||
func (result *Result) colorOffsets(matchOffsets []Offset, theme *tui.ColorTheme, colBase tui.ColorPair, colMatch tui.ColorPair, current bool) []colorOffset {
|
||||
func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, theme *tui.ColorTheme, colBase tui.ColorPair, colMatch tui.ColorPair, attrNth tui.Attr, current bool) []colorOffset {
|
||||
itemColors := result.item.Colors()
|
||||
|
||||
// No ANSI codes
|
||||
if len(itemColors) == 0 {
|
||||
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})
|
||||
@@ -118,7 +118,7 @@ func (result *Result) colorOffsets(matchOffsets []Offset, theme *tui.ColorTheme,
|
||||
|
||||
// Find max column
|
||||
var maxCol int32
|
||||
for _, off := range matchOffsets {
|
||||
for _, off := range append(matchOffsets, nthOffsets...) {
|
||||
if off[1] > maxCol {
|
||||
maxCol = off[1]
|
||||
}
|
||||
@@ -129,20 +129,29 @@ func (result *Result) colorOffsets(matchOffsets []Offset, theme *tui.ColorTheme,
|
||||
}
|
||||
}
|
||||
|
||||
cols := make([]int, maxCol)
|
||||
type cellInfo struct {
|
||||
index int
|
||||
color bool
|
||||
match bool
|
||||
nth bool
|
||||
}
|
||||
|
||||
cols := make([]cellInfo, maxCol)
|
||||
for colorIndex, ansi := range itemColors {
|
||||
for i := ansi.offset[0]; i < ansi.offset[1]; i++ {
|
||||
cols[i] = colorIndex + 1 // 1-based index of itemColors
|
||||
cols[i] = cellInfo{colorIndex, true, false, false}
|
||||
}
|
||||
}
|
||||
|
||||
for _, off := range matchOffsets {
|
||||
for i := off[0]; i < off[1]; i++ {
|
||||
// Negative of 1-based index of itemColors
|
||||
// - The extra -1 means highlighted
|
||||
if cols[i] >= 0 {
|
||||
cols[i] = cols[i]*-1 - 1
|
||||
}
|
||||
cols[i].match = true
|
||||
}
|
||||
}
|
||||
|
||||
for _, off := range nthOffsets {
|
||||
for i := off[0]; i < off[1]; i++ {
|
||||
cols[i].nth = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +161,7 @@ func (result *Result) colorOffsets(matchOffsets []Offset, theme *tui.ColorTheme,
|
||||
// ------------ ---- -- ----
|
||||
// ++++++++ ++++++++++
|
||||
// --++++++++-- --++++++++++---
|
||||
curr := 0
|
||||
var curr cellInfo = cellInfo{0, false, false, false}
|
||||
start := 0
|
||||
ansiToColorPair := func(ansi ansiOffset, base tui.ColorPair) tui.ColorPair {
|
||||
fg := ansi.color.fg
|
||||
@@ -175,12 +184,17 @@ func (result *Result) colorOffsets(matchOffsets []Offset, theme *tui.ColorTheme,
|
||||
}
|
||||
var colors []colorOffset
|
||||
add := func(idx int) {
|
||||
if curr != 0 && idx > start {
|
||||
if curr < 0 {
|
||||
color := colMatch
|
||||
if (curr.color || curr.nth || curr.match) && idx > start {
|
||||
if curr.match {
|
||||
var color tui.ColorPair
|
||||
if curr.nth {
|
||||
color = colBase.WithAttr(attrNth).Merge(colMatch)
|
||||
} else {
|
||||
color = colBase.Merge(colMatch)
|
||||
}
|
||||
var url *url
|
||||
if curr < -1 && theme.Colored {
|
||||
ansi := itemColors[-curr-2]
|
||||
if curr.color && theme.Colored {
|
||||
ansi := itemColors[curr.index]
|
||||
url = ansi.color.url
|
||||
origColor := ansiToColorPair(ansi, colMatch)
|
||||
// hl or hl+ only sets the foreground color, so colMatch is the
|
||||
@@ -193,19 +207,32 @@ func (result *Result) colorOffsets(matchOffsets []Offset, theme *tui.ColorTheme,
|
||||
// echo -e "\x1b[42mfoo\x1b[mbar" | fzf --ansi --color bg+:1,hl+:-1:underline
|
||||
if color.Fg().IsDefault() && origColor.HasBg() {
|
||||
color = origColor
|
||||
if curr.nth {
|
||||
color = color.WithAttr(attrNth)
|
||||
}
|
||||
} else {
|
||||
color = origColor.MergeNonDefault(color)
|
||||
}
|
||||
}
|
||||
colors = append(colors, colorOffset{
|
||||
offset: [2]int32{int32(start), int32(idx)}, color: color, match: true, url: url})
|
||||
} else {
|
||||
ansi := itemColors[curr-1]
|
||||
} else if curr.color {
|
||||
ansi := itemColors[curr.index]
|
||||
color := ansiToColorPair(ansi, colBase)
|
||||
if curr.nth {
|
||||
color = color.WithAttr(attrNth)
|
||||
}
|
||||
colors = append(colors, colorOffset{
|
||||
offset: [2]int32{int32(start), int32(idx)},
|
||||
color: ansiToColorPair(ansi, colBase),
|
||||
color: color,
|
||||
match: false,
|
||||
url: ansi.color.url})
|
||||
} else {
|
||||
colors = append(colors, colorOffset{
|
||||
offset: [2]int32{int32(start), int32(idx)},
|
||||
color: colBase.WithAttr(attrNth),
|
||||
match: false,
|
||||
url: nil})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -131,7 +131,7 @@ func TestColorOffset(t *testing.T) {
|
||||
|
||||
colBase := tui.NewColorPair(89, 189, tui.AttrUndefined)
|
||||
colMatch := tui.NewColorPair(99, 199, tui.AttrUndefined)
|
||||
colors := item.colorOffsets(offsets, tui.Dark256, colBase, colMatch, true)
|
||||
colors := item.colorOffsets(offsets, nil, tui.Dark256, colBase, colMatch, tui.AttrUndefined, true)
|
||||
assert := func(idx int, b int32, e int32, c tui.ColorPair) {
|
||||
o := colors[idx]
|
||||
if o.offset[0] != b || o.offset[1] != e || o.color != c {
|
||||
@@ -155,20 +155,30 @@ func TestColorOffset(t *testing.T) {
|
||||
|
||||
colRegular := tui.NewColorPair(-1, -1, tui.AttrUndefined)
|
||||
colUnderline := tui.NewColorPair(-1, -1, tui.Underline)
|
||||
colors = item.colorOffsets(offsets, tui.Dark256, colRegular, colUnderline, true)
|
||||
|
||||
// [{[0 5] {1 5 0}} {[5 15] {1 5 8}} {[15 20] {1 5 0}}
|
||||
// {[22 25] {2 6 1}} {[25 27] {2 6 9}} {[27 30] {-1 -1 8}}
|
||||
// {[30 32] {3 7 8}} {[32 33] {-1 -1 8}} {[33 35] {4 8 9}}
|
||||
// {[35 40] {4 8 1}}]
|
||||
assert(0, 0, 5, tui.NewColorPair(1, 5, tui.AttrUndefined))
|
||||
assert(1, 5, 15, tui.NewColorPair(1, 5, tui.Underline))
|
||||
assert(2, 15, 20, tui.NewColorPair(1, 5, tui.AttrUndefined))
|
||||
assert(3, 22, 25, tui.NewColorPair(2, 6, tui.Bold))
|
||||
assert(4, 25, 27, tui.NewColorPair(2, 6, tui.Bold|tui.Underline))
|
||||
assert(5, 27, 30, colUnderline)
|
||||
assert(6, 30, 32, tui.NewColorPair(3, 7, tui.Underline))
|
||||
assert(7, 32, 33, colUnderline)
|
||||
assert(8, 33, 35, tui.NewColorPair(4, 8, tui.Bold|tui.Underline))
|
||||
assert(9, 35, 40, tui.NewColorPair(4, 8, tui.Bold))
|
||||
nthOffsets := []Offset{{37, 39}, {42, 45}}
|
||||
for _, attr := range []tui.Attr{tui.AttrRegular, tui.StrikeThrough} {
|
||||
colors = item.colorOffsets(offsets, nthOffsets, tui.Dark256, colRegular, colUnderline, attr, true)
|
||||
|
||||
// [{[0 5] {1 5 0}} {[5 15] {1 5 8}} {[15 20] {1 5 0}}
|
||||
// {[22 25] {2 6 1}} {[25 27] {2 6 9}} {[27 30] {-1 -1 8}}
|
||||
// {[30 32] {3 7 8}} {[32 33] {-1 -1 8}} {[33 35] {4 8 9}}
|
||||
// {[35 37] {4 8 1}} {[37 39] {4 8 x|1}} {[39 40] {4 8 x|1}}]
|
||||
assert(0, 0, 5, tui.NewColorPair(1, 5, tui.AttrUndefined))
|
||||
assert(1, 5, 15, tui.NewColorPair(1, 5, tui.Underline))
|
||||
assert(2, 15, 20, tui.NewColorPair(1, 5, tui.AttrUndefined))
|
||||
assert(3, 22, 25, tui.NewColorPair(2, 6, tui.Bold))
|
||||
assert(4, 25, 27, tui.NewColorPair(2, 6, tui.Bold|tui.Underline))
|
||||
assert(5, 27, 30, colUnderline)
|
||||
assert(6, 30, 32, tui.NewColorPair(3, 7, tui.Underline))
|
||||
assert(7, 32, 33, colUnderline)
|
||||
assert(8, 33, 35, tui.NewColorPair(4, 8, tui.Bold|tui.Underline))
|
||||
assert(9, 35, 37, tui.NewColorPair(4, 8, tui.Bold))
|
||||
expected := tui.Bold | attr
|
||||
if attr == tui.AttrRegular {
|
||||
expected = tui.AttrRegular
|
||||
}
|
||||
assert(10, 37, 39, tui.NewColorPair(4, 8, expected))
|
||||
assert(11, 39, 40, tui.NewColorPair(4, 8, tui.Bold))
|
||||
}
|
||||
}
|
||||
|
797
src/terminal.go
797
src/terminal.go
File diff suppressed because it is too large
Load Diff
20
src/tmux.go
20
src/tmux.go
@@ -9,13 +9,18 @@ import (
|
||||
|
||||
func runTmux(args []string, opts *Options) (int, error) {
|
||||
// Prepare arguments
|
||||
fzf := args[0]
|
||||
args = append([]string{"--bind=ctrl-z:ignore"}, args[1:]...)
|
||||
if opts.BorderShape == tui.BorderUndefined {
|
||||
args = append(args, "--border")
|
||||
fzf, rest := args[0], args[1:]
|
||||
args = []string{"--bind=ctrl-z:ignore"}
|
||||
if !opts.Tmux.border && opts.BorderShape == tui.BorderUndefined {
|
||||
// We append --border option at the end, because `--style=full:STYLE`
|
||||
// may have changed the default border style.
|
||||
rest = append(rest, "--border")
|
||||
}
|
||||
if opts.Tmux.border && opts.Margin == defaultMargin() {
|
||||
args = append(args, "--margin=0,1")
|
||||
}
|
||||
argStr := escapeSingleQuote(fzf)
|
||||
for _, arg := range args {
|
||||
for _, arg := range append(args, rest...) {
|
||||
argStr += " " + escapeSingleQuote(arg)
|
||||
}
|
||||
argStr += ` --no-tmux --no-height`
|
||||
@@ -33,7 +38,10 @@ func runTmux(args []string, opts *Options) (int, error) {
|
||||
// M Both The mouse position
|
||||
// W Both The window position on the status line
|
||||
// S -y The line above or below the status line
|
||||
tmuxArgs := []string{"display-popup", "-E", "-B", "-d", dir}
|
||||
tmuxArgs := []string{"display-popup", "-E", "-d", dir}
|
||||
if !opts.Tmux.border {
|
||||
tmuxArgs = append(tmuxArgs, "-B")
|
||||
}
|
||||
switch opts.Tmux.position {
|
||||
case posUp:
|
||||
tmuxArgs = append(tmuxArgs, "-xC", "-y0")
|
||||
|
@@ -18,6 +18,36 @@ type Range struct {
|
||||
end int
|
||||
}
|
||||
|
||||
func (r Range) IsFull() bool {
|
||||
return r.begin == rangeEllipsis && r.end == rangeEllipsis
|
||||
}
|
||||
|
||||
func RangesToString(ranges []Range) string {
|
||||
strs := []string{}
|
||||
for _, r := range ranges {
|
||||
s := ""
|
||||
if r.begin == rangeEllipsis && r.end == rangeEllipsis {
|
||||
s = ".."
|
||||
} else if r.begin == r.end {
|
||||
s = strconv.Itoa(r.begin)
|
||||
} else {
|
||||
if r.begin != rangeEllipsis {
|
||||
s += strconv.Itoa(r.begin)
|
||||
}
|
||||
|
||||
if r.begin != -1 {
|
||||
s += ".."
|
||||
if r.end != rangeEllipsis {
|
||||
s += strconv.Itoa(r.end)
|
||||
}
|
||||
}
|
||||
}
|
||||
strs = append(strs, s)
|
||||
}
|
||||
|
||||
return strings.Join(strs, ",")
|
||||
}
|
||||
|
||||
// Token contains the tokenized part of the strings and its prefix length
|
||||
type Token struct {
|
||||
text *util.Chars
|
||||
@@ -41,7 +71,7 @@ func (d Delimiter) String() string {
|
||||
}
|
||||
|
||||
func newRange(begin int, end int) Range {
|
||||
if begin == 1 {
|
||||
if begin == 1 && end != 1 {
|
||||
begin = rangeEllipsis
|
||||
}
|
||||
if end == -1 {
|
||||
@@ -73,7 +103,7 @@ func ParseRange(str *string) (Range, bool) {
|
||||
}
|
||||
begin, err1 := strconv.Atoi(ns[0])
|
||||
end, err2 := strconv.Atoi(ns[1])
|
||||
if err1 != nil || err2 != nil || begin == 0 || end == 0 {
|
||||
if err1 != nil || err2 != nil || begin == 0 || end == 0 || begin < 0 && end > 0 {
|
||||
return Range{}, false
|
||||
}
|
||||
return newRange(begin, end), true
|
||||
|
@@ -40,6 +40,18 @@ func TestParseRange(t *testing.T) {
|
||||
t.Errorf("%v", r)
|
||||
}
|
||||
}
|
||||
{
|
||||
i := "1..3..5"
|
||||
if r, ok := ParseRange(&i); ok {
|
||||
t.Errorf("%v", r)
|
||||
}
|
||||
}
|
||||
{
|
||||
i := "-3..3"
|
||||
if r, ok := ParseRange(&i); ok {
|
||||
t.Errorf("%v", r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTokenize(t *testing.T) {
|
||||
|
@@ -11,6 +11,11 @@ func HasFullscreenRenderer() bool {
|
||||
var DefaultBorderShape = BorderRounded
|
||||
|
||||
func (a Attr) Merge(b Attr) Attr {
|
||||
if b&AttrRegular > 0 {
|
||||
// Only keep bold attribute set by the system
|
||||
return b | (a & BoldForce)
|
||||
}
|
||||
|
||||
return a | b
|
||||
}
|
||||
|
||||
@@ -18,6 +23,7 @@ const (
|
||||
AttrUndefined = Attr(0)
|
||||
AttrRegular = Attr(1 << 8)
|
||||
AttrClear = Attr(1 << 9)
|
||||
BoldForce = Attr(1 << 10)
|
||||
|
||||
Bold = Attr(1)
|
||||
Dim = Attr(1 << 1)
|
||||
@@ -30,6 +36,7 @@ const (
|
||||
)
|
||||
|
||||
func (r *FullscreenRenderer) Init() error { return nil }
|
||||
func (r *FullscreenRenderer) DefaultTheme() *ColorTheme { return nil }
|
||||
func (r *FullscreenRenderer) Resize(maxHeightFunc func(int) int) {}
|
||||
func (r *FullscreenRenderer) Pause(bool) {}
|
||||
func (r *FullscreenRenderer) Resume(bool, bool) {}
|
||||
@@ -48,6 +55,6 @@ func (r *FullscreenRenderer) MaxY() int { return 0 }
|
||||
|
||||
func (r *FullscreenRenderer) RefreshWindows(windows []Window) {}
|
||||
|
||||
func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window {
|
||||
func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, windowType WindowType, borderStyle BorderStyle, erase bool) Window {
|
||||
return nil
|
||||
}
|
||||
|
117
src/tui/light.go
117
src/tui/light.go
@@ -116,19 +116,19 @@ type LightRenderer struct {
|
||||
}
|
||||
|
||||
type LightWindow struct {
|
||||
renderer *LightRenderer
|
||||
colored bool
|
||||
preview bool
|
||||
border BorderStyle
|
||||
top int
|
||||
left int
|
||||
width int
|
||||
height int
|
||||
posx int
|
||||
posy int
|
||||
tabstop int
|
||||
fg Color
|
||||
bg Color
|
||||
renderer *LightRenderer
|
||||
colored bool
|
||||
windowType WindowType
|
||||
border BorderStyle
|
||||
top int
|
||||
left int
|
||||
width int
|
||||
height int
|
||||
posx int
|
||||
posy int
|
||||
tabstop int
|
||||
fg Color
|
||||
bg Color
|
||||
}
|
||||
|
||||
func NewLightRenderer(ttyin *os.File, theme *ColorTheme, forceBlack bool, mouse bool, tabstop int, clearOnExit bool, fullscreen bool, maxHeightFunc func(int) int) (Renderer, error) {
|
||||
@@ -174,7 +174,6 @@ func (r *LightRenderer) Init() error {
|
||||
return err
|
||||
}
|
||||
r.updateTerminalSize()
|
||||
initTheme(r.theme, r.defaultTheme(), r.forceBlack)
|
||||
|
||||
if r.fullscreen {
|
||||
r.smcup()
|
||||
@@ -780,27 +779,40 @@ func (r *LightRenderer) MaxY() int {
|
||||
return r.height
|
||||
}
|
||||
|
||||
func (r *LightRenderer) NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window {
|
||||
func (r *LightRenderer) NewWindow(top int, left int, width int, height int, windowType WindowType, borderStyle BorderStyle, erase bool) Window {
|
||||
width = util.Max(0, width)
|
||||
height = util.Max(0, height)
|
||||
w := &LightWindow{
|
||||
renderer: r,
|
||||
colored: r.theme.Colored,
|
||||
preview: preview,
|
||||
border: borderStyle,
|
||||
top: top,
|
||||
left: left,
|
||||
width: width,
|
||||
height: height,
|
||||
tabstop: r.tabstop,
|
||||
fg: colDefault,
|
||||
bg: colDefault}
|
||||
if preview {
|
||||
w.fg = r.theme.PreviewFg.Color
|
||||
w.bg = r.theme.PreviewBg.Color
|
||||
} else {
|
||||
renderer: r,
|
||||
colored: r.theme.Colored,
|
||||
windowType: windowType,
|
||||
border: borderStyle,
|
||||
top: top,
|
||||
left: left,
|
||||
width: width,
|
||||
height: height,
|
||||
tabstop: r.tabstop,
|
||||
fg: colDefault,
|
||||
bg: colDefault}
|
||||
switch windowType {
|
||||
case WindowBase:
|
||||
w.fg = r.theme.Fg.Color
|
||||
w.bg = r.theme.Bg.Color
|
||||
case WindowList:
|
||||
w.fg = r.theme.ListFg.Color
|
||||
w.bg = r.theme.ListBg.Color
|
||||
case WindowInput:
|
||||
w.fg = r.theme.Input.Color
|
||||
w.bg = r.theme.InputBg.Color
|
||||
case WindowHeader:
|
||||
w.fg = r.theme.Header.Color
|
||||
w.bg = r.theme.HeaderBg.Color
|
||||
case WindowPreview:
|
||||
w.fg = r.theme.PreviewFg.Color
|
||||
w.bg = r.theme.PreviewBg.Color
|
||||
}
|
||||
if !w.bg.IsDefault() && w.border.shape != BorderNone {
|
||||
if erase && !w.bg.IsDefault() && w.border.shape != BorderNone {
|
||||
// fzf --color bg:blue --border --padding 1,2
|
||||
w.Erase()
|
||||
}
|
||||
w.drawBorder(false)
|
||||
@@ -816,6 +828,9 @@ func (w *LightWindow) DrawHBorder() {
|
||||
}
|
||||
|
||||
func (w *LightWindow) drawBorder(onlyHorizontal bool) {
|
||||
if w.height == 0 {
|
||||
return
|
||||
}
|
||||
switch w.border.shape {
|
||||
case BorderRounded, BorderSharp, BorderBold, BorderBlock, BorderThinBlock, BorderDouble:
|
||||
w.drawBorderAround(onlyHorizontal)
|
||||
@@ -845,7 +860,14 @@ func (w *LightWindow) drawBorder(onlyHorizontal bool) {
|
||||
|
||||
func (w *LightWindow) drawBorderHorizontal(top, bottom bool) {
|
||||
color := ColBorder
|
||||
if w.preview {
|
||||
switch w.windowType {
|
||||
case WindowList:
|
||||
color = ColListBorder
|
||||
case WindowInput:
|
||||
color = ColInputBorder
|
||||
case WindowHeader:
|
||||
color = ColHeaderBorder
|
||||
case WindowPreview:
|
||||
color = ColPreviewBorder
|
||||
}
|
||||
hw := runeWidth(w.border.top)
|
||||
@@ -863,7 +885,14 @@ func (w *LightWindow) drawBorderHorizontal(top, bottom bool) {
|
||||
func (w *LightWindow) drawBorderVertical(left, right bool) {
|
||||
vw := runeWidth(w.border.left)
|
||||
color := ColBorder
|
||||
if w.preview {
|
||||
switch w.windowType {
|
||||
case WindowList:
|
||||
color = ColListBorder
|
||||
case WindowInput:
|
||||
color = ColInputBorder
|
||||
case WindowHeader:
|
||||
color = ColHeaderBorder
|
||||
case WindowPreview:
|
||||
color = ColPreviewBorder
|
||||
}
|
||||
for y := 0; y < w.height; y++ {
|
||||
@@ -883,7 +912,14 @@ func (w *LightWindow) drawBorderVertical(left, right bool) {
|
||||
func (w *LightWindow) drawBorderAround(onlyHorizontal bool) {
|
||||
w.Move(0, 0)
|
||||
color := ColBorder
|
||||
if w.preview {
|
||||
switch w.windowType {
|
||||
case WindowList:
|
||||
color = ColListBorder
|
||||
case WindowInput:
|
||||
color = ColInputBorder
|
||||
case WindowHeader:
|
||||
color = ColHeaderBorder
|
||||
case WindowPreview:
|
||||
color = ColPreviewBorder
|
||||
}
|
||||
hw := runeWidth(w.border.top)
|
||||
@@ -943,9 +979,16 @@ func (w *LightWindow) Y() int {
|
||||
return w.posy
|
||||
}
|
||||
|
||||
func (w *LightWindow) EncloseX(x int) bool {
|
||||
return x >= w.left && x < (w.left+w.width)
|
||||
}
|
||||
|
||||
func (w *LightWindow) EncloseY(y int) bool {
|
||||
return y >= w.top && y < (w.top+w.height)
|
||||
}
|
||||
|
||||
func (w *LightWindow) Enclose(y int, x int) bool {
|
||||
return x >= w.left && x < (w.left+w.width) &&
|
||||
y >= w.top && y < (w.top+w.height)
|
||||
return w.EncloseX(x) && w.EncloseY(y)
|
||||
}
|
||||
|
||||
func (w *LightWindow) Move(y int, x int) {
|
||||
@@ -968,7 +1011,7 @@ func attrCodes(attr Attr) []string {
|
||||
if (attr & AttrClear) > 0 {
|
||||
return codes
|
||||
}
|
||||
if (attr & Bold) > 0 {
|
||||
if (attr&Bold) > 0 || (attr&BoldForce) > 0 {
|
||||
codes = append(codes, "1")
|
||||
}
|
||||
if (attr & Dim) > 0 {
|
||||
|
@@ -18,7 +18,7 @@ func IsLightRendererSupported() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *LightRenderer) defaultTheme() *ColorTheme {
|
||||
func (r *LightRenderer) DefaultTheme() *ColorTheme {
|
||||
if strings.Contains(os.Getenv("TERM"), "256") {
|
||||
return Dark256
|
||||
}
|
||||
|
@@ -39,7 +39,7 @@ func IsLightRendererSupported() bool {
|
||||
return canSetVt100
|
||||
}
|
||||
|
||||
func (r *LightRenderer) defaultTheme() *ColorTheme {
|
||||
func (r *LightRenderer) DefaultTheme() *ColorTheme {
|
||||
// the getenv check is borrowed from here: https://github.com/gdamore/tcell/commit/0c473b86d82f68226a142e96cc5a34c5a29b3690#diff-b008fcd5e6934bf31bc3d33bf49f47d8R178:
|
||||
if !IsLightRendererSupported() || os.Getenv("ConEmuPID") != "" || os.Getenv("TCELL_TRUECOLOR") == "disable" {
|
||||
return Default16
|
||||
|
@@ -40,7 +40,7 @@ type Attr int32
|
||||
|
||||
type TcellWindow struct {
|
||||
color bool
|
||||
preview bool
|
||||
windowType WindowType
|
||||
top int
|
||||
left int
|
||||
width int
|
||||
@@ -97,6 +97,7 @@ const (
|
||||
AttrUndefined = Attr(0)
|
||||
AttrRegular = Attr(1 << 7)
|
||||
AttrClear = Attr(1 << 8)
|
||||
BoldForce = Attr(1 << 10)
|
||||
)
|
||||
|
||||
func (r *FullscreenRenderer) PassThrough(str string) {
|
||||
@@ -106,8 +107,12 @@ func (r *FullscreenRenderer) PassThrough(str string) {
|
||||
|
||||
func (r *FullscreenRenderer) Resize(maxHeightFunc func(int) int) {}
|
||||
|
||||
func (r *FullscreenRenderer) defaultTheme() *ColorTheme {
|
||||
if _screen.Colors() >= 256 {
|
||||
func (r *FullscreenRenderer) DefaultTheme() *ColorTheme {
|
||||
s, e := r.getScreen()
|
||||
if e != nil {
|
||||
return Default16
|
||||
}
|
||||
if s.Colors() >= 256 {
|
||||
return Dark256
|
||||
}
|
||||
return Default16
|
||||
@@ -137,6 +142,11 @@ func (c Color) Style() tcell.Color {
|
||||
}
|
||||
|
||||
func (a Attr) Merge(b Attr) Attr {
|
||||
if b&AttrRegular > 0 {
|
||||
// Only keep bold attribute set by the system
|
||||
return b | (a & BoldForce)
|
||||
}
|
||||
|
||||
return a | b
|
||||
}
|
||||
|
||||
@@ -148,8 +158,19 @@ var (
|
||||
_initialResize bool = true
|
||||
)
|
||||
|
||||
func (r *FullscreenRenderer) getScreen() (tcell.Screen, error) {
|
||||
if _screen == nil {
|
||||
s, e := tcell.NewScreen()
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
_screen = s
|
||||
}
|
||||
return _screen, nil
|
||||
}
|
||||
|
||||
func (r *FullscreenRenderer) initScreen() error {
|
||||
s, e := tcell.NewScreen()
|
||||
s, e := r.getScreen()
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
@@ -161,7 +182,6 @@ func (r *FullscreenRenderer) initScreen() error {
|
||||
} else {
|
||||
s.DisableMouse()
|
||||
}
|
||||
_screen = s
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -174,7 +194,6 @@ func (r *FullscreenRenderer) Init() error {
|
||||
if err := r.initScreen(); err != nil {
|
||||
return err
|
||||
}
|
||||
initTheme(r.theme, r.defaultTheme(), r.forceBlack)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -537,14 +556,23 @@ func (r *FullscreenRenderer) RefreshWindows(windows []Window) {
|
||||
_screen.Show()
|
||||
}
|
||||
|
||||
func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window {
|
||||
normal := ColNormal
|
||||
if preview {
|
||||
func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, windowType WindowType, borderStyle BorderStyle, erase bool) Window {
|
||||
width = util.Max(0, width)
|
||||
height = util.Max(0, height)
|
||||
normal := ColBorder
|
||||
switch windowType {
|
||||
case WindowList:
|
||||
normal = ColNormal
|
||||
case WindowHeader:
|
||||
normal = ColHeader
|
||||
case WindowInput:
|
||||
normal = ColInput
|
||||
case WindowPreview:
|
||||
normal = ColPreview
|
||||
}
|
||||
w := &TcellWindow{
|
||||
color: r.theme.Colored,
|
||||
preview: preview,
|
||||
windowType: windowType,
|
||||
top: top,
|
||||
left: left,
|
||||
width: width,
|
||||
@@ -564,11 +592,7 @@ func fill(x, y, w, h int, n ColorPair, r rune) {
|
||||
}
|
||||
|
||||
func (w *TcellWindow) Erase() {
|
||||
if w.borderStyle.shape.HasLeft() {
|
||||
fill(w.left-1, w.top, w.width, w.height-1, w.normal, ' ')
|
||||
} else {
|
||||
fill(w.left, w.top, w.width-1, w.height-1, w.normal, ' ')
|
||||
}
|
||||
fill(w.left, w.top, w.width-1, w.height-1, w.normal, ' ')
|
||||
w.drawBorder(false)
|
||||
}
|
||||
|
||||
@@ -577,9 +601,16 @@ func (w *TcellWindow) EraseMaybe() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *TcellWindow) EncloseX(x int) bool {
|
||||
return x >= w.left && x < (w.left+w.width)
|
||||
}
|
||||
|
||||
func (w *TcellWindow) EncloseY(y int) bool {
|
||||
return y >= w.top && y < (w.top+w.height)
|
||||
}
|
||||
|
||||
func (w *TcellWindow) Enclose(y int, x int) bool {
|
||||
return x >= w.left && x < (w.left+w.width) &&
|
||||
y >= w.top && y < (w.top+w.height)
|
||||
return w.EncloseX(x) && w.EncloseY(y)
|
||||
}
|
||||
|
||||
func (w *TcellWindow) Move(y int, x int) {
|
||||
@@ -669,7 +700,7 @@ func (w *TcellWindow) fillString(text string, pair ColorPair) FillReturn {
|
||||
}
|
||||
style = style.
|
||||
Blink(a&Attr(tcell.AttrBlink) != 0).
|
||||
Bold(a&Attr(tcell.AttrBold) != 0).
|
||||
Bold(a&Attr(tcell.AttrBold) != 0 || a&BoldForce != 0).
|
||||
Dim(a&Attr(tcell.AttrDim) != 0).
|
||||
Reverse(a&Attr(tcell.AttrReverse) != 0).
|
||||
Underline(a&Attr(tcell.AttrUnderline) != 0).
|
||||
@@ -756,6 +787,9 @@ func (w *TcellWindow) DrawHBorder() {
|
||||
}
|
||||
|
||||
func (w *TcellWindow) drawBorder(onlyHorizontal bool) {
|
||||
if w.height == 0 {
|
||||
return
|
||||
}
|
||||
shape := w.borderStyle.shape
|
||||
if shape == BorderNone {
|
||||
return
|
||||
@@ -768,10 +802,17 @@ func (w *TcellWindow) drawBorder(onlyHorizontal bool) {
|
||||
|
||||
var style tcell.Style
|
||||
if w.color {
|
||||
if w.preview {
|
||||
style = ColPreviewBorder.style()
|
||||
} else {
|
||||
switch w.windowType {
|
||||
case WindowBase:
|
||||
style = ColBorder.style()
|
||||
case WindowList:
|
||||
style = ColListBorder.style()
|
||||
case WindowHeader:
|
||||
style = ColHeaderBorder.style()
|
||||
case WindowInput:
|
||||
style = ColInputBorder.style()
|
||||
case WindowPreview:
|
||||
style = ColPreviewBorder.style()
|
||||
}
|
||||
} else {
|
||||
style = w.normal.style()
|
||||
|
@@ -15,7 +15,7 @@ func TtyIn() (*os.File, error) {
|
||||
return os.Stdin, nil
|
||||
}
|
||||
|
||||
// TtyIn on Windows returns nil
|
||||
// TtyOut on Windows returns nil
|
||||
func TtyOut() (*os.File, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
199
src/tui/tui.go
199
src/tui/tui.go
@@ -205,10 +205,24 @@ type ColorAttr struct {
|
||||
Attr Attr
|
||||
}
|
||||
|
||||
func (a ColorAttr) IsColorDefined() bool {
|
||||
return a.Color != colUndefined
|
||||
}
|
||||
|
||||
func NewColorAttr() ColorAttr {
|
||||
return ColorAttr{Color: colUndefined, Attr: AttrUndefined}
|
||||
}
|
||||
|
||||
func (a ColorAttr) Merge(other ColorAttr) ColorAttr {
|
||||
if other.Color != colUndefined {
|
||||
a.Color = other.Color
|
||||
}
|
||||
if other.Attr != AttrUndefined {
|
||||
a.Attr = a.Attr.Merge(other.Attr)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
const (
|
||||
colUndefined Color = -2
|
||||
colDefault Color = -1
|
||||
@@ -303,6 +317,9 @@ type ColorTheme struct {
|
||||
Disabled ColorAttr
|
||||
Fg ColorAttr
|
||||
Bg ColorAttr
|
||||
ListFg ColorAttr
|
||||
ListBg ColorAttr
|
||||
Nth ColorAttr
|
||||
SelectedFg ColorAttr
|
||||
SelectedBg ColorAttr
|
||||
SelectedMatch ColorAttr
|
||||
@@ -311,6 +328,9 @@ type ColorTheme struct {
|
||||
DarkBg ColorAttr
|
||||
Gutter ColorAttr
|
||||
Prompt ColorAttr
|
||||
InputBg ColorAttr
|
||||
InputBorder ColorAttr
|
||||
InputLabel ColorAttr
|
||||
Match ColorAttr
|
||||
Current ColorAttr
|
||||
CurrentMatch ColorAttr
|
||||
@@ -319,13 +339,19 @@ type ColorTheme struct {
|
||||
Cursor ColorAttr
|
||||
Marker ColorAttr
|
||||
Header ColorAttr
|
||||
HeaderBg ColorAttr
|
||||
HeaderBorder ColorAttr
|
||||
HeaderLabel ColorAttr
|
||||
Separator ColorAttr
|
||||
Scrollbar ColorAttr
|
||||
Border ColorAttr
|
||||
PreviewBorder ColorAttr
|
||||
PreviewLabel ColorAttr
|
||||
PreviewScrollbar ColorAttr
|
||||
BorderLabel ColorAttr
|
||||
PreviewLabel ColorAttr
|
||||
ListLabel ColorAttr
|
||||
ListBorder ColorAttr
|
||||
GapLine ColorAttr
|
||||
}
|
||||
|
||||
type Event struct {
|
||||
@@ -348,6 +374,7 @@ type BorderShape int
|
||||
|
||||
const (
|
||||
BorderUndefined BorderShape = iota
|
||||
BorderLine
|
||||
BorderNone
|
||||
BorderRounded
|
||||
BorderSharp
|
||||
@@ -365,7 +392,7 @@ const (
|
||||
|
||||
func (s BorderShape) HasLeft() bool {
|
||||
switch s {
|
||||
case BorderNone, BorderRight, BorderTop, BorderBottom, BorderHorizontal: // No Left
|
||||
case BorderNone, BorderLine, BorderRight, BorderTop, BorderBottom, BorderHorizontal: // No Left
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -373,7 +400,7 @@ func (s BorderShape) HasLeft() bool {
|
||||
|
||||
func (s BorderShape) HasRight() bool {
|
||||
switch s {
|
||||
case BorderNone, BorderLeft, BorderTop, BorderBottom, BorderHorizontal: // No right
|
||||
case BorderNone, BorderLine, BorderLeft, BorderTop, BorderBottom, BorderHorizontal: // No right
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -381,7 +408,7 @@ func (s BorderShape) HasRight() bool {
|
||||
|
||||
func (s BorderShape) HasTop() bool {
|
||||
switch s {
|
||||
case BorderNone, BorderLeft, BorderRight, BorderBottom, BorderVertical: // No top
|
||||
case BorderNone, BorderLine, BorderLeft, BorderRight, BorderBottom, BorderVertical: // No top
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -389,12 +416,16 @@ func (s BorderShape) HasTop() bool {
|
||||
|
||||
func (s BorderShape) HasBottom() bool {
|
||||
switch s {
|
||||
case BorderNone, BorderLeft, BorderRight, BorderTop, BorderVertical: // No bottom
|
||||
case BorderNone, BorderLine, BorderLeft, BorderRight, BorderTop, BorderVertical: // No bottom
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s BorderShape) Visible() bool {
|
||||
return s != BorderNone
|
||||
}
|
||||
|
||||
type BorderStyle struct {
|
||||
shape BorderShape
|
||||
top rune
|
||||
@@ -525,7 +556,18 @@ type TermSize struct {
|
||||
PxHeight int
|
||||
}
|
||||
|
||||
type WindowType int
|
||||
|
||||
const (
|
||||
WindowBase WindowType = iota
|
||||
WindowList
|
||||
WindowPreview
|
||||
WindowInput
|
||||
WindowHeader
|
||||
)
|
||||
|
||||
type Renderer interface {
|
||||
DefaultTheme() *ColorTheme
|
||||
Init() error
|
||||
Resize(maxHeightFunc func(int) int)
|
||||
Pause(clear bool)
|
||||
@@ -546,7 +588,7 @@ type Renderer interface {
|
||||
|
||||
Size() TermSize
|
||||
|
||||
NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window
|
||||
NewWindow(top int, left int, width int, height int, windowType WindowType, borderStyle BorderStyle, erase bool) Window
|
||||
}
|
||||
|
||||
type Window interface {
|
||||
@@ -562,6 +604,8 @@ type Window interface {
|
||||
|
||||
X() int
|
||||
Y() int
|
||||
EncloseX(x int) bool
|
||||
EncloseY(y int) bool
|
||||
Enclose(y int, x int) bool
|
||||
|
||||
Move(y int, x int)
|
||||
@@ -618,8 +662,11 @@ var (
|
||||
ColSpinner ColorPair
|
||||
ColInfo ColorPair
|
||||
ColHeader ColorPair
|
||||
ColHeaderBorder ColorPair
|
||||
ColHeaderLabel ColorPair
|
||||
ColSeparator ColorPair
|
||||
ColScrollbar ColorPair
|
||||
ColGapLine ColorPair
|
||||
ColBorder ColorPair
|
||||
ColPreview ColorPair
|
||||
ColPreviewBorder ColorPair
|
||||
@@ -627,6 +674,10 @@ var (
|
||||
ColPreviewLabel ColorPair
|
||||
ColPreviewScrollbar ColorPair
|
||||
ColPreviewSpinner ColorPair
|
||||
ColListBorder ColorPair
|
||||
ColListLabel ColorPair
|
||||
ColInputBorder ColorPair
|
||||
ColInputLabel ColorPair
|
||||
)
|
||||
|
||||
func EmptyTheme() *ColorTheme {
|
||||
@@ -635,6 +686,8 @@ func EmptyTheme() *ColorTheme {
|
||||
Input: ColorAttr{colUndefined, AttrUndefined},
|
||||
Fg: ColorAttr{colUndefined, AttrUndefined},
|
||||
Bg: ColorAttr{colUndefined, AttrUndefined},
|
||||
ListFg: ColorAttr{colUndefined, AttrUndefined},
|
||||
ListBg: ColorAttr{colUndefined, AttrUndefined},
|
||||
SelectedFg: ColorAttr{colUndefined, AttrUndefined},
|
||||
SelectedBg: ColorAttr{colUndefined, AttrUndefined},
|
||||
SelectedMatch: ColorAttr{colUndefined, AttrUndefined},
|
||||
@@ -650,6 +703,8 @@ func EmptyTheme() *ColorTheme {
|
||||
Header: ColorAttr{colUndefined, AttrUndefined},
|
||||
Border: ColorAttr{colUndefined, AttrUndefined},
|
||||
BorderLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||
ListLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||
ListBorder: ColorAttr{colUndefined, AttrUndefined},
|
||||
Disabled: ColorAttr{colUndefined, AttrUndefined},
|
||||
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
|
||||
PreviewBg: ColorAttr{colUndefined, AttrUndefined},
|
||||
@@ -659,6 +714,14 @@ func EmptyTheme() *ColorTheme {
|
||||
PreviewLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||
Separator: ColorAttr{colUndefined, AttrUndefined},
|
||||
Scrollbar: ColorAttr{colUndefined, AttrUndefined},
|
||||
InputBg: ColorAttr{colUndefined, AttrUndefined},
|
||||
InputBorder: ColorAttr{colUndefined, AttrUndefined},
|
||||
InputLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||
HeaderBg: ColorAttr{colUndefined, AttrUndefined},
|
||||
HeaderBorder: ColorAttr{colUndefined, AttrUndefined},
|
||||
HeaderLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||
GapLine: ColorAttr{colUndefined, AttrUndefined},
|
||||
Nth: ColorAttr{colUndefined, AttrUndefined},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -668,6 +731,8 @@ func NoColorTheme() *ColorTheme {
|
||||
Input: ColorAttr{colDefault, AttrUndefined},
|
||||
Fg: ColorAttr{colDefault, AttrUndefined},
|
||||
Bg: ColorAttr{colDefault, AttrUndefined},
|
||||
ListFg: ColorAttr{colDefault, AttrUndefined},
|
||||
ListBg: ColorAttr{colDefault, AttrUndefined},
|
||||
SelectedFg: ColorAttr{colDefault, AttrUndefined},
|
||||
SelectedBg: ColorAttr{colDefault, AttrUndefined},
|
||||
SelectedMatch: ColorAttr{colDefault, AttrUndefined},
|
||||
@@ -690,8 +755,18 @@ func NoColorTheme() *ColorTheme {
|
||||
PreviewBorder: ColorAttr{colDefault, AttrUndefined},
|
||||
PreviewScrollbar: ColorAttr{colDefault, AttrUndefined},
|
||||
PreviewLabel: ColorAttr{colDefault, AttrUndefined},
|
||||
ListLabel: ColorAttr{colDefault, AttrUndefined},
|
||||
ListBorder: ColorAttr{colDefault, AttrUndefined},
|
||||
Separator: ColorAttr{colDefault, AttrUndefined},
|
||||
Scrollbar: ColorAttr{colDefault, AttrUndefined},
|
||||
InputBg: ColorAttr{colDefault, AttrUndefined},
|
||||
InputBorder: ColorAttr{colDefault, AttrUndefined},
|
||||
InputLabel: ColorAttr{colDefault, AttrUndefined},
|
||||
HeaderBg: ColorAttr{colDefault, AttrUndefined},
|
||||
HeaderBorder: ColorAttr{colDefault, AttrUndefined},
|
||||
HeaderLabel: ColorAttr{colDefault, AttrUndefined},
|
||||
GapLine: ColorAttr{colDefault, AttrUndefined},
|
||||
Nth: ColorAttr{colUndefined, AttrUndefined},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -701,6 +776,8 @@ func init() {
|
||||
Input: ColorAttr{colDefault, AttrUndefined},
|
||||
Fg: ColorAttr{colDefault, AttrUndefined},
|
||||
Bg: ColorAttr{colDefault, AttrUndefined},
|
||||
ListFg: ColorAttr{colUndefined, AttrUndefined},
|
||||
ListBg: ColorAttr{colUndefined, AttrUndefined},
|
||||
SelectedFg: ColorAttr{colUndefined, AttrUndefined},
|
||||
SelectedBg: ColorAttr{colUndefined, AttrUndefined},
|
||||
SelectedMatch: ColorAttr{colUndefined, AttrUndefined},
|
||||
@@ -723,14 +800,23 @@ func init() {
|
||||
PreviewBorder: ColorAttr{colUndefined, AttrUndefined},
|
||||
PreviewScrollbar: ColorAttr{colUndefined, AttrUndefined},
|
||||
PreviewLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||
ListLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||
ListBorder: ColorAttr{colUndefined, AttrUndefined},
|
||||
Separator: ColorAttr{colUndefined, AttrUndefined},
|
||||
Scrollbar: ColorAttr{colUndefined, AttrUndefined},
|
||||
InputBg: ColorAttr{colUndefined, AttrUndefined},
|
||||
InputBorder: ColorAttr{colUndefined, AttrUndefined},
|
||||
InputLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||
GapLine: ColorAttr{colUndefined, AttrUndefined},
|
||||
Nth: ColorAttr{colUndefined, AttrUndefined},
|
||||
}
|
||||
Dark256 = &ColorTheme{
|
||||
Colored: true,
|
||||
Input: ColorAttr{colDefault, AttrUndefined},
|
||||
Fg: ColorAttr{colDefault, AttrUndefined},
|
||||
Bg: ColorAttr{colDefault, AttrUndefined},
|
||||
ListFg: ColorAttr{colUndefined, AttrUndefined},
|
||||
ListBg: ColorAttr{colUndefined, AttrUndefined},
|
||||
SelectedFg: ColorAttr{colUndefined, AttrUndefined},
|
||||
SelectedBg: ColorAttr{colUndefined, AttrUndefined},
|
||||
SelectedMatch: ColorAttr{colUndefined, AttrUndefined},
|
||||
@@ -753,14 +839,23 @@ func init() {
|
||||
PreviewBorder: ColorAttr{colUndefined, AttrUndefined},
|
||||
PreviewScrollbar: ColorAttr{colUndefined, AttrUndefined},
|
||||
PreviewLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||
ListLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||
ListBorder: ColorAttr{colUndefined, AttrUndefined},
|
||||
Separator: ColorAttr{colUndefined, AttrUndefined},
|
||||
Scrollbar: ColorAttr{colUndefined, AttrUndefined},
|
||||
InputBg: ColorAttr{colUndefined, AttrUndefined},
|
||||
InputBorder: ColorAttr{colUndefined, AttrUndefined},
|
||||
InputLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||
GapLine: ColorAttr{colUndefined, AttrUndefined},
|
||||
Nth: ColorAttr{colUndefined, AttrUndefined},
|
||||
}
|
||||
Light256 = &ColorTheme{
|
||||
Colored: true,
|
||||
Input: ColorAttr{colDefault, AttrUndefined},
|
||||
Fg: ColorAttr{colDefault, AttrUndefined},
|
||||
Bg: ColorAttr{colDefault, AttrUndefined},
|
||||
ListFg: ColorAttr{colUndefined, AttrUndefined},
|
||||
ListBg: ColorAttr{colUndefined, AttrUndefined},
|
||||
SelectedFg: ColorAttr{colUndefined, AttrUndefined},
|
||||
SelectedBg: ColorAttr{colUndefined, AttrUndefined},
|
||||
SelectedMatch: ColorAttr{colUndefined, AttrUndefined},
|
||||
@@ -783,12 +878,22 @@ func init() {
|
||||
PreviewBorder: ColorAttr{colUndefined, AttrUndefined},
|
||||
PreviewScrollbar: ColorAttr{colUndefined, AttrUndefined},
|
||||
PreviewLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||
ListLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||
ListBorder: ColorAttr{colUndefined, AttrUndefined},
|
||||
Separator: ColorAttr{colUndefined, AttrUndefined},
|
||||
Scrollbar: ColorAttr{colUndefined, AttrUndefined},
|
||||
InputBg: ColorAttr{colUndefined, AttrUndefined},
|
||||
InputBorder: ColorAttr{colUndefined, AttrUndefined},
|
||||
InputLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||
HeaderBg: ColorAttr{colUndefined, AttrUndefined},
|
||||
HeaderBorder: ColorAttr{colUndefined, AttrUndefined},
|
||||
HeaderLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||
GapLine: ColorAttr{colUndefined, AttrUndefined},
|
||||
Nth: ColorAttr{colUndefined, AttrUndefined},
|
||||
}
|
||||
}
|
||||
|
||||
func initTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool) {
|
||||
func InitTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool, hasInputWindow bool, hasHeaderWindow bool) {
|
||||
if forceBlack {
|
||||
theme.Bg = ColorAttr{colBlack, AttrUndefined}
|
||||
}
|
||||
@@ -809,7 +914,9 @@ func initTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool) {
|
||||
theme.DarkBg = o(baseTheme.DarkBg, theme.DarkBg)
|
||||
theme.Prompt = o(baseTheme.Prompt, theme.Prompt)
|
||||
theme.Match = o(baseTheme.Match, theme.Match)
|
||||
theme.Current = o(baseTheme.Current, theme.Current)
|
||||
// Inherit from 'fg', so that we don't have to write 'current-fg:dim'
|
||||
// e.g. fzf --delimiter / --nth -1 --color fg:dim,nth:regular
|
||||
theme.Current = theme.Fg.Merge(o(baseTheme.Current, theme.Current))
|
||||
theme.CurrentMatch = o(baseTheme.CurrentMatch, theme.CurrentMatch)
|
||||
theme.Spinner = o(baseTheme.Spinner, theme.Spinner)
|
||||
theme.Info = o(baseTheme.Info, theme.Info)
|
||||
@@ -819,9 +926,15 @@ func initTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool) {
|
||||
theme.Border = o(baseTheme.Border, theme.Border)
|
||||
theme.BorderLabel = o(baseTheme.BorderLabel, theme.BorderLabel)
|
||||
|
||||
undefined := NewColorAttr()
|
||||
scrollbarDefined := theme.Scrollbar != undefined
|
||||
previewBorderDefined := theme.PreviewBorder != undefined
|
||||
|
||||
// These colors are not defined in the base themes
|
||||
theme.SelectedFg = o(theme.Fg, theme.SelectedFg)
|
||||
theme.SelectedBg = o(theme.Bg, theme.SelectedBg)
|
||||
theme.ListFg = o(theme.Fg, theme.ListFg)
|
||||
theme.ListBg = o(theme.Bg, theme.ListBg)
|
||||
theme.SelectedFg = o(theme.ListFg, theme.SelectedFg)
|
||||
theme.SelectedBg = o(theme.ListBg, theme.SelectedBg)
|
||||
theme.SelectedMatch = o(theme.Match, theme.SelectedMatch)
|
||||
theme.Disabled = o(theme.Input, theme.Disabled)
|
||||
theme.Gutter = o(theme.DarkBg, theme.Gutter)
|
||||
@@ -829,9 +942,38 @@ func initTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool) {
|
||||
theme.PreviewBg = o(theme.Bg, theme.PreviewBg)
|
||||
theme.PreviewLabel = o(theme.BorderLabel, theme.PreviewLabel)
|
||||
theme.PreviewBorder = o(theme.Border, theme.PreviewBorder)
|
||||
theme.Separator = o(theme.Border, theme.Separator)
|
||||
theme.Scrollbar = o(theme.Border, theme.Scrollbar)
|
||||
theme.PreviewScrollbar = o(theme.PreviewBorder, theme.PreviewScrollbar)
|
||||
theme.ListLabel = o(theme.BorderLabel, theme.ListLabel)
|
||||
theme.ListBorder = o(theme.Border, theme.ListBorder)
|
||||
theme.Separator = o(theme.ListBorder, theme.Separator)
|
||||
theme.Scrollbar = o(theme.ListBorder, theme.Scrollbar)
|
||||
theme.GapLine = o(theme.ListBorder, theme.GapLine)
|
||||
/*
|
||||
--color list-border:green
|
||||
--color scrollbar:red
|
||||
--color scrollbar:red,list-border:green
|
||||
--color scrollbar:red,preview-border:green
|
||||
*/
|
||||
if scrollbarDefined && !previewBorderDefined {
|
||||
theme.PreviewScrollbar = o(theme.Scrollbar, theme.PreviewScrollbar)
|
||||
} else {
|
||||
theme.PreviewScrollbar = o(theme.PreviewBorder, theme.PreviewScrollbar)
|
||||
}
|
||||
if hasInputWindow {
|
||||
theme.InputBg = o(theme.Bg, theme.InputBg)
|
||||
} else {
|
||||
// We shouldn't use input-bg if there's no separate input window
|
||||
// e.g. fzf --color 'list-bg:green,input-bg:red' --no-input-border
|
||||
theme.InputBg = o(theme.Bg, theme.ListBg)
|
||||
}
|
||||
theme.InputBorder = o(theme.Border, theme.InputBorder)
|
||||
theme.InputLabel = o(theme.BorderLabel, theme.InputLabel)
|
||||
if hasHeaderWindow {
|
||||
theme.HeaderBg = o(theme.Bg, theme.HeaderBg)
|
||||
} else {
|
||||
theme.HeaderBg = o(theme.Bg, theme.ListBg)
|
||||
}
|
||||
theme.HeaderBorder = o(theme.Border, theme.HeaderBorder)
|
||||
theme.HeaderLabel = o(theme.BorderLabel, theme.HeaderLabel)
|
||||
|
||||
initPalette(theme)
|
||||
}
|
||||
@@ -843,19 +985,19 @@ func initPalette(theme *ColorTheme) {
|
||||
}
|
||||
return ColorPair{fg.Color, bg.Color, fg.Attr}
|
||||
}
|
||||
blank := theme.Fg
|
||||
blank := theme.ListFg
|
||||
blank.Attr = AttrRegular
|
||||
|
||||
ColPrompt = pair(theme.Prompt, theme.Bg)
|
||||
ColNormal = pair(theme.Fg, theme.Bg)
|
||||
ColPrompt = pair(theme.Prompt, theme.InputBg)
|
||||
ColNormal = pair(theme.ListFg, theme.ListBg)
|
||||
ColSelected = pair(theme.SelectedFg, theme.SelectedBg)
|
||||
ColInput = pair(theme.Input, theme.Bg)
|
||||
ColDisabled = pair(theme.Disabled, theme.Bg)
|
||||
ColMatch = pair(theme.Match, theme.Bg)
|
||||
ColInput = pair(theme.Input, theme.InputBg)
|
||||
ColDisabled = pair(theme.Disabled, theme.ListBg)
|
||||
ColMatch = pair(theme.Match, theme.ListBg)
|
||||
ColSelectedMatch = pair(theme.SelectedMatch, theme.SelectedBg)
|
||||
ColCursor = pair(theme.Cursor, theme.Gutter)
|
||||
ColCursorEmpty = pair(blank, theme.Gutter)
|
||||
if theme.SelectedBg.Color != theme.Bg.Color {
|
||||
if theme.SelectedBg.Color != theme.ListBg.Color {
|
||||
ColMarker = pair(theme.Marker, theme.SelectedBg)
|
||||
} else {
|
||||
ColMarker = pair(theme.Marker, theme.Gutter)
|
||||
@@ -866,11 +1008,11 @@ func initPalette(theme *ColorTheme) {
|
||||
ColCurrentCursorEmpty = pair(blank, theme.DarkBg)
|
||||
ColCurrentMarker = pair(theme.Marker, theme.DarkBg)
|
||||
ColCurrentSelectedEmpty = pair(blank, theme.DarkBg)
|
||||
ColSpinner = pair(theme.Spinner, theme.Bg)
|
||||
ColInfo = pair(theme.Info, theme.Bg)
|
||||
ColHeader = pair(theme.Header, theme.Bg)
|
||||
ColSeparator = pair(theme.Separator, theme.Bg)
|
||||
ColScrollbar = pair(theme.Scrollbar, theme.Bg)
|
||||
ColSpinner = pair(theme.Spinner, theme.InputBg)
|
||||
ColInfo = pair(theme.Info, theme.InputBg)
|
||||
ColSeparator = pair(theme.Separator, theme.InputBg)
|
||||
ColScrollbar = pair(theme.Scrollbar, theme.ListBg)
|
||||
ColGapLine = pair(theme.GapLine, theme.ListBg)
|
||||
ColBorder = pair(theme.Border, theme.Bg)
|
||||
ColBorderLabel = pair(theme.BorderLabel, theme.Bg)
|
||||
ColPreviewLabel = pair(theme.PreviewLabel, theme.PreviewBg)
|
||||
@@ -878,6 +1020,13 @@ func initPalette(theme *ColorTheme) {
|
||||
ColPreviewBorder = pair(theme.PreviewBorder, theme.PreviewBg)
|
||||
ColPreviewScrollbar = pair(theme.PreviewScrollbar, theme.PreviewBg)
|
||||
ColPreviewSpinner = pair(theme.Spinner, theme.PreviewBg)
|
||||
ColListLabel = pair(theme.ListLabel, theme.ListBg)
|
||||
ColListBorder = pair(theme.ListBorder, theme.ListBg)
|
||||
ColInputBorder = pair(theme.InputBorder, theme.InputBg)
|
||||
ColInputLabel = pair(theme.InputLabel, theme.InputBg)
|
||||
ColHeader = pair(theme.Header, theme.HeaderBg)
|
||||
ColHeaderBorder = pair(theme.HeaderBorder, theme.HeaderBg)
|
||||
ColHeaderLabel = pair(theme.HeaderLabel, theme.HeaderBg)
|
||||
}
|
||||
|
||||
func runeWidth(r rune) int {
|
||||
|
357
test/test_go.rb
357
test/test_go.rb
@@ -1442,10 +1442,14 @@ class TestGoFZF < TestBase
|
||||
writelines(['=' * 10_000 + '0123456789'])
|
||||
[0, 3, 6].each do |off|
|
||||
tmux.prepare
|
||||
tmux.send_keys "#{FZF} --hscroll-off=#{off} -q 0 < #{tempname}", :Enter
|
||||
tmux.send_keys "#{FZF} --hscroll-off=#{off} -q 0 --bind space:toggle-hscroll < #{tempname}", :Enter
|
||||
tmux.until { |lines| assert lines[-3]&.end_with?((0..off).to_a.join + '··') }
|
||||
tmux.send_keys '9'
|
||||
tmux.until { |lines| assert lines[-3]&.end_with?('789') }
|
||||
tmux.send_keys :Space
|
||||
tmux.until { |lines| assert lines[-3]&.end_with?('=··') }
|
||||
tmux.send_keys :Space
|
||||
tmux.until { |lines| assert lines[-3]&.end_with?('789') }
|
||||
tmux.send_keys :Enter
|
||||
end
|
||||
end
|
||||
@@ -2133,7 +2137,11 @@ class TestGoFZF < TestBase
|
||||
end
|
||||
|
||||
def test_keep_right
|
||||
tmux.send_keys "seq 10000 | #{FZF} --read0 --keep-right --no-multi-line", :Enter
|
||||
tmux.send_keys "seq 10000 | #{FZF} --read0 --keep-right --no-multi-line --bind space:toggle-multi-line", :Enter
|
||||
tmux.until { |lines| assert lines.any_include?('9999␊10000') }
|
||||
tmux.send_keys :Space
|
||||
tmux.until { |lines| assert lines.any_include?('> 1') }
|
||||
tmux.send_keys :Space
|
||||
tmux.until { |lines| assert lines.any_include?('9999␊10000') }
|
||||
end
|
||||
|
||||
@@ -2638,7 +2646,7 @@ class TestGoFZF < TestBase
|
||||
end
|
||||
|
||||
def test_change_preview_window
|
||||
tmux.send_keys "seq 1000 | #{FZF} --preview 'echo [[{}]]' --preview-window border-none --bind '" \
|
||||
tmux.send_keys "seq 1000 | #{FZF} --preview 'echo [[{}]]' --no-preview-border --bind '" \
|
||||
'a:change-preview(echo __{}__),' \
|
||||
'b:change-preview-window(down)+change-preview(echo =={}==)+change-preview-window(up),' \
|
||||
'c:change-preview(),d:change-preview-window(hidden),' \
|
||||
@@ -3415,32 +3423,363 @@ class TestGoFZF < TestBase
|
||||
│ >
|
||||
│ 100/100 ──────
|
||||
│ > 1
|
||||
│
|
||||
│ ┈┈┈┈┈┈┈┈┈┈┈┈┈┈
|
||||
│ 2
|
||||
│
|
||||
│ ┈┈┈┈┈┈┈┈┈┈┈┈┈┈
|
||||
│ 3
|
||||
│
|
||||
│ ┈┈┈┈┈┈┈┈┈┈┈┈┈┈
|
||||
│ 4
|
||||
BLOCK
|
||||
tmux.until { assert_block(block, _1) }
|
||||
end
|
||||
|
||||
def test_gap_2
|
||||
tmux.send_keys %(seq 100 | #{FZF} --gap=2 --border --reverse), :Enter
|
||||
tmux.send_keys %(seq 100 | #{FZF} --gap=2 --gap-line xyz --border --reverse), :Enter
|
||||
block = <<~BLOCK
|
||||
╭─────────────────
|
||||
│ >
|
||||
│ 100/100 ──────
|
||||
│ > 1
|
||||
│
|
||||
│
|
||||
│ xyzxyzxyzxyzxy
|
||||
│ 2
|
||||
│
|
||||
│
|
||||
│ xyzxyzxyzxyzxy
|
||||
│ 3
|
||||
BLOCK
|
||||
tmux.until { assert_block(block, _1) }
|
||||
end
|
||||
|
||||
def test_list_border_and_label
|
||||
tmux.send_keys %(seq 100 | #{FZF} --border rounded --list-border double --list-label list --list-label-pos 2:bottom --header-lines 3 --query 1 --padding 1,2), :Enter
|
||||
block = <<~BLOCK
|
||||
│ ║ 11
|
||||
│ ║ > 10
|
||||
│ ║ 3
|
||||
│ ║ 2
|
||||
│ ║ 1
|
||||
│ ║ 19/97 ─
|
||||
│ ║ > 1
|
||||
│ ╚list══════
|
||||
│
|
||||
╰──────────────
|
||||
BLOCK
|
||||
tmux.until { assert_block(block, _1) }
|
||||
end
|
||||
|
||||
def test_input_border_and_label
|
||||
tmux.send_keys %(seq 100 | #{FZF} --border rounded --input-border bold --input-label input --input-label-pos 2 --header-lines 3 --query 1 --padding 1,2), :Enter
|
||||
block = <<~BLOCK
|
||||
│ 11
|
||||
│ > 10
|
||||
│ 3
|
||||
│ 2
|
||||
│ 1
|
||||
│ ┏input━━━━━
|
||||
│ ┃ 19/97
|
||||
│ ┃ > 1
|
||||
│ ┗━━━━━━━━━━
|
||||
│
|
||||
╰──────────────
|
||||
BLOCK
|
||||
tmux.until { assert_block(block, _1) }
|
||||
end
|
||||
|
||||
def test_input_border_and_label_header_first
|
||||
tmux.send_keys %(seq 100 | #{FZF} --border rounded --input-border bold --input-label input --input-label-pos 2 --header-lines 3 --query 1 --padding 1,2 --header-first), :Enter
|
||||
block = <<~BLOCK
|
||||
│ 11
|
||||
│ > 10
|
||||
│ ┏input━━━━━
|
||||
│ ┃ 19/97
|
||||
│ ┃ > 1
|
||||
│ ┗━━━━━━━━━━
|
||||
│ 3
|
||||
│ 2
|
||||
│ 1
|
||||
│
|
||||
╰──────────────
|
||||
BLOCK
|
||||
tmux.until { assert_block(block, _1) }
|
||||
end
|
||||
|
||||
def test_list_input_border_and_label
|
||||
tmux.send_keys %(
|
||||
seq 100 | #{FZF} --border rounded --list-border double --input-border bold --list-label-pos 2:bottom --input-label-pos 2 --header-lines 3 --query 1 --padding 1,2 \
|
||||
--bind 'start:transform-input-label(echo INPUT)+transform-list-label(echo LIST)' \
|
||||
--bind 'space:change-input-label( input )+change-list-label( list )'
|
||||
).strip, :Enter
|
||||
block = <<~BLOCK
|
||||
│ ║ 11
|
||||
│ ║ > 10
|
||||
│ ╚LIST══════
|
||||
│ 3
|
||||
│ 2
|
||||
│ 1
|
||||
│ ┏INPUT━━━━━
|
||||
│ ┃ 19/97
|
||||
│ ┃ > 1
|
||||
│ ┗━━━━━━━━━━
|
||||
│
|
||||
╰──────────────
|
||||
BLOCK
|
||||
tmux.until { assert_block(block, _1) }
|
||||
tmux.send_keys :Space
|
||||
block = <<~BLOCK
|
||||
│ ║ 11
|
||||
│ ║ > 10
|
||||
│ ╚ list ════
|
||||
│ 3
|
||||
│ 2
|
||||
│ 1
|
||||
│ ┏ input ━━━
|
||||
│ ┃ 19/97
|
||||
│ ┃ > 1
|
||||
│ ┗━━━━━━━━━━
|
||||
│
|
||||
╰──────────────
|
||||
BLOCK
|
||||
tmux.until { assert_block(block, _1) }
|
||||
end
|
||||
|
||||
def test_list_input_border_and_label_header_first
|
||||
tmux.send_keys %(
|
||||
seq 100 | #{FZF} --border rounded --list-border double --input-border bold --list-label-pos 2:bottom --input-label-pos 2 --header-lines 3 --query 1 --padding 1,2 \
|
||||
--bind 'start:transform-input-label(echo INPUT)+transform-list-label(echo LIST)' \
|
||||
--bind 'space:change-input-label( input )+change-list-label( list )' --header-first
|
||||
).strip, :Enter
|
||||
block = <<~BLOCK
|
||||
│ ║ 11
|
||||
│ ║ > 10
|
||||
│ ╚LIST══════
|
||||
│ ┏INPUT━━━━━
|
||||
│ ┃ 19/97
|
||||
│ ┃ > 1
|
||||
│ ┗━━━━━━━━━━
|
||||
│ 3
|
||||
│ 2
|
||||
│ 1
|
||||
│
|
||||
╰──────────────
|
||||
BLOCK
|
||||
tmux.until { assert_block(block, _1) }
|
||||
tmux.send_keys :Space
|
||||
block = <<~BLOCK
|
||||
│ ║ 11
|
||||
│ ║ > 10
|
||||
│ ╚ list ════
|
||||
│ ┏ input ━━━
|
||||
│ ┃ 19/97
|
||||
│ ┃ > 1
|
||||
│ ┗━━━━━━━━━━
|
||||
│ 3
|
||||
│ 2
|
||||
│ 1
|
||||
│
|
||||
╰──────────────
|
||||
BLOCK
|
||||
tmux.until { assert_block(block, _1) }
|
||||
end
|
||||
|
||||
def test_header_border_and_label
|
||||
tmux.send_keys %(seq 100 | #{FZF} --border rounded --header-lines 3 --header-border sharp --header-label header --header-label-pos 2:bottom --query 1 --padding 1,2), :Enter
|
||||
block = <<~BLOCK
|
||||
│ 12
|
||||
│ 11
|
||||
│ > 10
|
||||
│ ┌────────
|
||||
│ │ 3
|
||||
│ │ 2
|
||||
│ │ 1
|
||||
│ └header──
|
||||
│ 19/97 ─
|
||||
│ > 1
|
||||
│
|
||||
╰────────────
|
||||
BLOCK
|
||||
tmux.until { assert_block(block, _1) }
|
||||
end
|
||||
|
||||
def test_header_border_and_label_header_first
|
||||
tmux.send_keys %(seq 100 | #{FZF} --border rounded --header-lines 3 --header-border sharp --header-label header --header-label-pos 2:bottom --query 1 --padding 1,2 --header-first), :Enter
|
||||
block = <<~BLOCK
|
||||
│ 12
|
||||
│ 11
|
||||
│ > 10
|
||||
│ 19/97 ─
|
||||
│ > 1
|
||||
│ ┌────────
|
||||
│ │ 3
|
||||
│ │ 2
|
||||
│ │ 1
|
||||
│ └header──
|
||||
│
|
||||
╰────────────
|
||||
BLOCK
|
||||
tmux.until { assert_block(block, _1) }
|
||||
end
|
||||
|
||||
def test_header_border_and_label_with_list_border
|
||||
tmux.send_keys %(seq 100 | #{FZF} --border rounded --list-border double --list-label list --list-label-pos 2:bottom --header-lines 3 --header-border sharp --header-label header --header-label-pos 2:bottom --query 1 --padding 1,2), :Enter
|
||||
block = <<~BLOCK
|
||||
│ ║ 12
|
||||
│ ║ 11
|
||||
│ ║ > 10
|
||||
│ ╚list════
|
||||
│ ┌────────
|
||||
│ │ 3
|
||||
│ │ 2
|
||||
│ │ 1
|
||||
│ └header──
|
||||
│ 19/97 ─
|
||||
│ > 1
|
||||
│
|
||||
╰────────────
|
||||
BLOCK
|
||||
tmux.until { assert_block(block, _1) }
|
||||
end
|
||||
|
||||
def test_header_border_and_label_with_list_border_header_first
|
||||
tmux.send_keys %(seq 100 | #{FZF} --border rounded --list-border double --list-label list --list-label-pos 2:bottom --header-lines 3 --header-border sharp --header-label header --header-label-pos 2:bottom --query 1 --padding 1,2 --header-first), :Enter
|
||||
block = <<~BLOCK
|
||||
│ ║ 12
|
||||
│ ║ 11
|
||||
│ ║ > 10
|
||||
│ ╚list════
|
||||
│ 19/97 ─
|
||||
│ > 1
|
||||
│ ┌────────
|
||||
│ │ 3
|
||||
│ │ 2
|
||||
│ │ 1
|
||||
│ └header──
|
||||
│
|
||||
╰────────────
|
||||
BLOCK
|
||||
tmux.until { assert_block(block, _1) }
|
||||
end
|
||||
|
||||
def test_all_borders
|
||||
tmux.send_keys %(seq 100 | #{FZF} --border rounded --list-border double --list-label list --list-label-pos 2:bottom --header-lines 3 --header-border sharp --header-label header --header-label-pos 2:bottom --query 1 --padding 1,2 --input-border bold --input-label input --input-label-pos 2:bottom), :Enter
|
||||
block = <<~BLOCK
|
||||
│ ║ 12
|
||||
│ ║ 11
|
||||
│ ║ > 10
|
||||
│ ╚list══════
|
||||
│ ┌──────────
|
||||
│ │ 3
|
||||
│ │ 2
|
||||
│ │ 1
|
||||
│ └header────
|
||||
│ ┏━━━━━━━━━━
|
||||
│ ┃ 19/97
|
||||
│ ┃ > 1
|
||||
│ ┗input━━━━━
|
||||
│
|
||||
╰──────────────
|
||||
BLOCK
|
||||
tmux.until { assert_block(block, _1) }
|
||||
end
|
||||
|
||||
def test_all_borders_header_first
|
||||
tmux.send_keys %(seq 100 | #{FZF} --border rounded --list-border double --list-label list --list-label-pos 2:bottom --header-lines 3 --header-border sharp --header-label header --header-label-pos 2:bottom --query 1 --padding 1,2 --input-border bold --input-label input --input-label-pos 2:bottom --header-first), :Enter
|
||||
block = <<~BLOCK
|
||||
│ ║ 12
|
||||
│ ║ 11
|
||||
│ ║ > 10
|
||||
│ ╚list══════
|
||||
│ ┏━━━━━━━━━━
|
||||
│ ┃ 19/97
|
||||
│ ┃ > 1
|
||||
│ ┗input━━━━━
|
||||
│ ┌──────────
|
||||
│ │ 3
|
||||
│ │ 2
|
||||
│ │ 1
|
||||
│ └header────
|
||||
│
|
||||
╰──────────────
|
||||
BLOCK
|
||||
tmux.until { assert_block(block, _1) }
|
||||
end
|
||||
|
||||
def test_style_full_adaptive_height
|
||||
tmux.send_keys %(seq 1| #{FZF} --style=full --height=~100% --header-lines=1 --info=default), :Enter
|
||||
block = <<~BLOCK
|
||||
╭────────
|
||||
╰────────
|
||||
╭────────
|
||||
│ 1
|
||||
╰────────
|
||||
╭────────
|
||||
│ 0/0
|
||||
│ >
|
||||
╰────────
|
||||
BLOCK
|
||||
tmux.until { assert_block(block, _1) }
|
||||
end
|
||||
|
||||
def test_style_full_adaptive_height_double
|
||||
tmux.send_keys %(seq 1| #{FZF} --style=full:double --border --height=~100% --header-lines=1 --info=default), :Enter
|
||||
block = <<~BLOCK
|
||||
╔══════════
|
||||
║ ╔════════
|
||||
║ ╚════════
|
||||
║ ╔════════
|
||||
║ ║ 1
|
||||
║ ╚════════
|
||||
║ ╔════════
|
||||
║ ║ 0/0
|
||||
║ ║ >
|
||||
║ ╚════════
|
||||
╚══════════
|
||||
BLOCK
|
||||
tmux.until { assert_block(block, _1) }
|
||||
end
|
||||
|
||||
def test_change_nth
|
||||
input = [
|
||||
*[''] * 1000,
|
||||
'foo bar bar bar bar',
|
||||
'foo foo bar bar bar',
|
||||
'foo foo foo bar bar',
|
||||
'foo foo foo foo bar',
|
||||
*[''] * 1000
|
||||
]
|
||||
writelines(input)
|
||||
nths = '1,2..4,-1,-3..,..2'
|
||||
tmux.send_keys %(#{FZF} -qfoo -n#{nths} --bind 'space:change-nth(2|3|4|5|),result:transform-prompt:echo "[$FZF_NTH] "' < #{tempname}), :Enter
|
||||
|
||||
tmux.until do |lines|
|
||||
assert lines.any_include?("[#{nths}] foo")
|
||||
assert_equal 4, lines.match_count
|
||||
end
|
||||
tmux.send_keys :Space
|
||||
tmux.until do |lines|
|
||||
assert lines.any_include?('[2] foo')
|
||||
assert_equal 3, lines.match_count
|
||||
end
|
||||
tmux.send_keys :Space
|
||||
tmux.until do |lines|
|
||||
assert lines.any_include?('[3] foo')
|
||||
assert_equal 2, lines.match_count
|
||||
end
|
||||
tmux.send_keys :Space
|
||||
tmux.until do |lines|
|
||||
assert lines.any_include?('[4] foo')
|
||||
assert_equal 1, lines.match_count
|
||||
end
|
||||
tmux.send_keys :Space
|
||||
tmux.until do |lines|
|
||||
assert lines.any_include?('[5] foo')
|
||||
assert_equal 0, lines.match_count
|
||||
end
|
||||
tmux.send_keys :Space
|
||||
tmux.until do |lines|
|
||||
assert lines.any_include?("[#{nths}] foo")
|
||||
assert_equal 4, lines.match_count
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module TestShell
|
||||
|
Reference in New Issue
Block a user