mirror of
https://github.com/junegunn/fzf.git
synced 2025-11-14 14:23:47 -05:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
098ef4d7cf | ||
|
|
e3f91bfe1b | ||
|
|
7374fe73a3 | ||
|
|
d2bde205f0 | ||
|
|
5620f70f9a | ||
|
|
37f258b1bf | ||
|
|
e2dd2a133e | ||
|
|
7514644e07 | ||
|
|
16b0aeda7d | ||
|
|
86e4f4a841 | ||
|
|
607eacf8c7 | ||
|
|
7a049644a8 | ||
|
|
17a13f00f8 | ||
|
|
43436e48e0 | ||
|
|
5a39102405 | ||
|
|
94999101e3 | ||
|
|
e619b7c4f4 | ||
|
|
b7c2e8cb67 |
2
.github/workflows/typos.yml
vendored
2
.github/workflows/typos.yml
vendored
@@ -7,4 +7,4 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: crate-ci/typos@v1.13.16
|
- uses: crate-ci/typos@v1.14.10
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
golang 1.20.2
|
golang 1.20.4
|
||||||
|
|||||||
55
ADVANCED.md
55
ADVANCED.md
@@ -1,8 +1,8 @@
|
|||||||
Advanced fzf examples
|
Advanced fzf examples
|
||||||
======================
|
======================
|
||||||
|
|
||||||
* *Last update: 2023/02/15*
|
* *Last update: 2023/05/26*
|
||||||
* *Requires fzf 0.38.0 or above*
|
* *Requires fzf 0.41.0 or above*
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -336,9 +336,8 @@ projects, and it will free up memory as you narrow down the results.
|
|||||||
# 3. Open the file in Vim
|
# 3. Open the file in Vim
|
||||||
RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case "
|
RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case "
|
||||||
INITIAL_QUERY="${*:-}"
|
INITIAL_QUERY="${*:-}"
|
||||||
FZF_DEFAULT_COMMAND="$RG_PREFIX $(printf %q "$INITIAL_QUERY")" \
|
: | fzf --ansi --disabled --query "$INITIAL_QUERY" \
|
||||||
fzf --ansi \
|
--bind "start:reload:$RG_PREFIX {q}" \
|
||||||
--disabled --query "$INITIAL_QUERY" \
|
|
||||||
--bind "change:reload:sleep 0.1; $RG_PREFIX {q} || true" \
|
--bind "change:reload:sleep 0.1; $RG_PREFIX {q} || true" \
|
||||||
--delimiter : \
|
--delimiter : \
|
||||||
--preview 'bat --color=always {1} --highlight-line {2}' \
|
--preview 'bat --color=always {1} --highlight-line {2}' \
|
||||||
@@ -348,11 +347,11 @@ fzf --ansi \
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
- Instead of starting fzf in `rg ... | fzf` form, we start fzf without an
|
- Instead of starting fzf in the usual `rg ... | fzf` form, we start fzf with
|
||||||
explicit input, but with a custom `FZF_DEFAULT_COMMAND` variable. This way
|
an empty input (`: | fzf`), then we make it start the initial Ripgrep
|
||||||
fzf can kill the initial Ripgrep process it starts with the initial query.
|
process immediately via `start:reload` binding. This way, fzf owns the
|
||||||
Otherwise, the initial Ripgrep process will keep consuming system resources
|
initial Ripgrep process so it can kill it on the next `reload`. Otherwise,
|
||||||
even after `reload` is triggered.
|
the process will keep running in the background.
|
||||||
- Filtering is no longer a responsibility of fzf; hence `--disabled`
|
- Filtering is no longer a responsibility of fzf; hence `--disabled`
|
||||||
- `{q}` in the reload command evaluates to the query string on fzf prompt.
|
- `{q}` in the reload command evaluates to the query string on fzf prompt.
|
||||||
- `sleep 0.1` in the reload command is for "debouncing". This small delay will
|
- `sleep 0.1` in the reload command is for "debouncing". This small delay will
|
||||||
@@ -376,12 +375,11 @@ fzf-only search mode by *"unbinding"* `reload` action from `change` event.
|
|||||||
# 3. Open the file in Vim
|
# 3. Open the file in Vim
|
||||||
RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case "
|
RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case "
|
||||||
INITIAL_QUERY="${*:-}"
|
INITIAL_QUERY="${*:-}"
|
||||||
FZF_DEFAULT_COMMAND="$RG_PREFIX $(printf %q "$INITIAL_QUERY")" \
|
: | fzf --ansi --disabled --query "$INITIAL_QUERY" \
|
||||||
fzf --ansi \
|
--bind "start:reload:$RG_PREFIX {q}" \
|
||||||
--color "hl:-1:underline,hl+:-1:underline:reverse" \
|
|
||||||
--disabled --query "$INITIAL_QUERY" \
|
|
||||||
--bind "change:reload:sleep 0.1; $RG_PREFIX {q} || true" \
|
--bind "change:reload:sleep 0.1; $RG_PREFIX {q} || true" \
|
||||||
--bind "alt-enter:unbind(change,alt-enter)+change-prompt(2. fzf> )+enable-search+clear-query" \
|
--bind "alt-enter:unbind(change,alt-enter)+change-prompt(2. fzf> )+enable-search+clear-query" \
|
||||||
|
--color "hl:-1:underline,hl+:-1:underline:reverse" \
|
||||||
--prompt '1. ripgrep> ' \
|
--prompt '1. ripgrep> ' \
|
||||||
--delimiter : \
|
--delimiter : \
|
||||||
--preview 'bat --color=always {1} --highlight-line {2}' \
|
--preview 'bat --color=always {1} --highlight-line {2}' \
|
||||||
@@ -421,14 +419,12 @@ CTRL-F.
|
|||||||
rm -f /tmp/rg-fzf-{r,f}
|
rm -f /tmp/rg-fzf-{r,f}
|
||||||
RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case "
|
RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case "
|
||||||
INITIAL_QUERY="${*:-}"
|
INITIAL_QUERY="${*:-}"
|
||||||
FZF_DEFAULT_COMMAND="$RG_PREFIX $(printf %q "$INITIAL_QUERY")" \
|
: | fzf --ansi --disabled --query "$INITIAL_QUERY" \
|
||||||
fzf --ansi \
|
--bind "start:reload($RG_PREFIX {q})+unbind(ctrl-r)" \
|
||||||
--color "hl:-1:underline,hl+:-1:underline:reverse" \
|
|
||||||
--disabled --query "$INITIAL_QUERY" \
|
|
||||||
--bind "change:reload:sleep 0.1; $RG_PREFIX {q} || true" \
|
--bind "change:reload:sleep 0.1; $RG_PREFIX {q} || true" \
|
||||||
--bind "ctrl-f:unbind(change,ctrl-f)+change-prompt(2. fzf> )+enable-search+rebind(ctrl-r)+transform-query(echo {q} > /tmp/rg-fzf-r; cat /tmp/rg-fzf-f)" \
|
--bind "ctrl-f:unbind(change,ctrl-f)+change-prompt(2. fzf> )+enable-search+rebind(ctrl-r)+transform-query(echo {q} > /tmp/rg-fzf-r; cat /tmp/rg-fzf-f)" \
|
||||||
--bind "ctrl-r:unbind(ctrl-r)+change-prompt(1. ripgrep> )+disable-search+reload($RG_PREFIX {q} || true)+rebind(change,ctrl-f)+transform-query(echo {q} > /tmp/rg-fzf-f; cat /tmp/rg-fzf-r)" \
|
--bind "ctrl-r:unbind(ctrl-r)+change-prompt(1. ripgrep> )+disable-search+reload($RG_PREFIX {q} || true)+rebind(change,ctrl-f)+transform-query(echo {q} > /tmp/rg-fzf-f; cat /tmp/rg-fzf-r)" \
|
||||||
--bind "start:unbind(ctrl-r)" \
|
--color "hl:-1:underline,hl+:-1:underline:reverse" \
|
||||||
--prompt '1. ripgrep> ' \
|
--prompt '1. ripgrep> ' \
|
||||||
--delimiter : \
|
--delimiter : \
|
||||||
--header '╱ CTRL-R (ripgrep mode) ╱ CTRL-F (fzf mode) ╱' \
|
--header '╱ CTRL-R (ripgrep mode) ╱ CTRL-F (fzf mode) ╱' \
|
||||||
@@ -471,16 +467,17 @@ Kubernetes pods.
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
pods() {
|
pods() {
|
||||||
FZF_DEFAULT_COMMAND="kubectl get pods --all-namespaces" \
|
: | command='kubectl get pods --all-namespaces' fzf \
|
||||||
fzf --info=inline --layout=reverse --header-lines=1 \
|
--info=inline --layout=reverse --header-lines=1 \
|
||||||
--prompt "$(kubectl config current-context | sed 's/-context$//')> " \
|
--prompt "$(kubectl config current-context | sed 's/-context$//')> " \
|
||||||
--header $'╱ Enter (kubectl exec) ╱ CTRL-O (open log in editor) ╱ CTRL-R (reload) ╱\n\n' \
|
--header $'╱ Enter (kubectl exec) ╱ CTRL-O (open log in editor) ╱ CTRL-R (reload) ╱\n\n' \
|
||||||
--bind 'ctrl-/:change-preview-window(80%,border-bottom|hidden|)' \
|
--bind 'start:reload:$command' \
|
||||||
--bind 'enter:execute:kubectl exec -it --namespace {1} {2} -- bash > /dev/tty' \
|
--bind 'ctrl-r:reload:$command' \
|
||||||
--bind 'ctrl-o:execute:${EDITOR:-vim} <(kubectl logs --all-containers --namespace {1} {2}) > /dev/tty' \
|
--bind 'ctrl-/:change-preview-window(80%,border-bottom|hidden|)' \
|
||||||
--bind 'ctrl-r:reload:$FZF_DEFAULT_COMMAND' \
|
--bind 'enter:execute:kubectl exec -it --namespace {1} {2} -- bash > /dev/tty' \
|
||||||
--preview-window up:follow \
|
--bind 'ctrl-o:execute:${EDITOR:-vim} <(kubectl logs --all-containers --namespace {1} {2}) > /dev/tty' \
|
||||||
--preview 'kubectl logs --follow --all-containers --tail=10000 --namespace {1} {2}' "$@"
|
--preview-window up:follow \
|
||||||
|
--preview 'kubectl logs --follow --all-containers --tail=10000 --namespace {1} {2}' "$@"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
15
CHANGELOG.md
15
CHANGELOG.md
@@ -1,6 +1,21 @@
|
|||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
0.41.0
|
||||||
|
------
|
||||||
|
- Added color name `preview-border` and `preview-scrollbar`
|
||||||
|
- Added new border style `block` which uses [block elements](https://en.wikipedia.org/wiki/Block_Elements)
|
||||||
|
- `--scrollbar` can take two characters, one for the main window, the other
|
||||||
|
for the preview window
|
||||||
|
- Putting it altogether:
|
||||||
|
```sh
|
||||||
|
fzf-tmux -p 80% --padding 1,2 --preview 'bat --style=plain --color=always {}' \
|
||||||
|
--color 'bg:237,bg+:235,gutter:237,border:238,scrollbar:236' \
|
||||||
|
--color 'preview-bg:235,preview-border:236,preview-scrollbar:234' \
|
||||||
|
--preview-window 'border-block' --border block --scrollbar '▌▐'
|
||||||
|
```
|
||||||
|
- Bug fixes and improvements
|
||||||
|
|
||||||
0.40.0
|
0.40.0
|
||||||
------
|
------
|
||||||
- Added `zero` event that is triggered when there's no match
|
- Added `zero` event that is triggered when there's no match
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM archlinux
|
FROM --platform=linux/amd64 archlinux
|
||||||
RUN pacman -Sy && pacman --noconfirm -S awk git tmux zsh fish ruby procps go make gcc
|
RUN pacman -Sy && pacman --noconfirm -S awk git tmux zsh fish ruby procps go make gcc
|
||||||
RUN gem install --no-document -v 5.14.2 minitest
|
RUN gem install --no-document -v 5.14.2 minitest
|
||||||
RUN echo '. /usr/share/bash-completion/completions/git' >> ~/.bashrc
|
RUN echo '. /usr/share/bash-completion/completions/git' >> ~/.bashrc
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -88,7 +88,7 @@ bench:
|
|||||||
install: bin/fzf
|
install: bin/fzf
|
||||||
|
|
||||||
build:
|
build:
|
||||||
goreleaser --rm-dist --snapshot
|
goreleaser build --rm-dist --snapshot --skip-post-hooks
|
||||||
|
|
||||||
release:
|
release:
|
||||||
ifndef GITHUB_TOKEN
|
ifndef GITHUB_TOKEN
|
||||||
|
|||||||
18
README.md
18
README.md
@@ -630,8 +630,8 @@ more details.
|
|||||||
#### 1. Update the list of processes by pressing CTRL-R
|
#### 1. Update the list of processes by pressing CTRL-R
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
FZF_DEFAULT_COMMAND='ps -ef' \
|
ps -ef |
|
||||||
fzf --bind 'ctrl-r:reload(eval "$FZF_DEFAULT_COMMAND")' \
|
fzf --bind 'ctrl-r:reload(ps -ef)' \
|
||||||
--header 'Press CTRL-R to reload' --header-lines=1 \
|
--header 'Press CTRL-R to reload' --header-lines=1 \
|
||||||
--height=50% --layout=reverse
|
--height=50% --layout=reverse
|
||||||
```
|
```
|
||||||
@@ -653,12 +653,12 @@ expression `{q}`. Also, note that we used `--disabled` option so that fzf
|
|||||||
doesn't perform any secondary filtering.
|
doesn't perform any secondary filtering.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
INITIAL_QUERY=""
|
: | rg_prefix='rg --column --line-number --no-heading --color=always --smart-case' \
|
||||||
RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case "
|
fzf --bind 'start:reload:$rg_prefix ""' \
|
||||||
FZF_DEFAULT_COMMAND="$RG_PREFIX '$INITIAL_QUERY'" \
|
--bind 'change:reload:$rg_prefix {q} || true' \
|
||||||
fzf --bind "change:reload:$RG_PREFIX {q} || true" \
|
--bind 'enter:become(vim {1} +{2})' \
|
||||||
--ansi --disabled --query "$INITIAL_QUERY" \
|
--ansi --disabled \
|
||||||
--height=50% --layout=reverse
|
--height=50% --layout=reverse
|
||||||
```
|
```
|
||||||
|
|
||||||
If ripgrep doesn't find any matches, it will exit with a non-zero exit status,
|
If ripgrep doesn't find any matches, it will exit with a non-zero exit status,
|
||||||
@@ -666,7 +666,7 @@ and fzf will warn you about it. To suppress the warning message, we added
|
|||||||
`|| true` to the command, so that it always exits with 0.
|
`|| true` to the command, so that it always exits with 0.
|
||||||
|
|
||||||
See ["Using fzf as interactive Ripgrep launcher"](https://github.com/junegunn/fzf/blob/master/ADVANCED.md#using-fzf-as-interactive-ripgrep-launcher)
|
See ["Using fzf as interactive Ripgrep launcher"](https://github.com/junegunn/fzf/blob/master/ADVANCED.md#using-fzf-as-interactive-ripgrep-launcher)
|
||||||
for a fuller example with preview window options.
|
for more sophisticated examples.
|
||||||
|
|
||||||
### Preview window
|
### Preview window
|
||||||
|
|
||||||
|
|||||||
4
go.mod
4
go.mod
@@ -7,8 +7,8 @@ require (
|
|||||||
github.com/mattn/go-shellwords v1.0.12
|
github.com/mattn/go-shellwords v1.0.12
|
||||||
github.com/rivo/uniseg v0.4.4
|
github.com/rivo/uniseg v0.4.4
|
||||||
github.com/saracen/walker v0.1.3
|
github.com/saracen/walker v0.1.3
|
||||||
golang.org/x/sys v0.7.0
|
golang.org/x/sys v0.8.0
|
||||||
golang.org/x/term v0.7.0
|
golang.org/x/term v0.8.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|||||||
8
go.sum
8
go.sum
@@ -32,12 +32,12 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
|
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
|
||||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
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.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.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
|||||||
2
install
2
install
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
set -u
|
set -u
|
||||||
|
|
||||||
version=0.40.0
|
version=0.41.0
|
||||||
auto_completion=
|
auto_completion=
|
||||||
key_bindings=
|
key_bindings=
|
||||||
update_config=2
|
update_config=2
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
$version="0.40.0"
|
$version="0.41.0"
|
||||||
|
|
||||||
$fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition
|
$fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition
|
||||||
|
|
||||||
|
|||||||
2
main.go
2
main.go
@@ -5,7 +5,7 @@ import (
|
|||||||
"github.com/junegunn/fzf/src/protector"
|
"github.com/junegunn/fzf/src/protector"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version string = "0.40"
|
var version string = "0.41"
|
||||||
var revision string = "devel"
|
var revision string = "devel"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
..
|
..
|
||||||
.TH fzf-tmux 1 "May 2023" "fzf 0.40.0" "fzf-tmux - open fzf in tmux split pane"
|
.TH fzf-tmux 1 "May 2023" "fzf 0.41.0" "fzf-tmux - open fzf in tmux split pane"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fzf-tmux - open fzf in tmux split pane
|
fzf-tmux - open fzf in tmux split pane
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
..
|
..
|
||||||
.TH fzf 1 "May 2023" "fzf 0.40.0" "fzf - a command-line fuzzy finder"
|
.TH fzf 1 "May 2023" "fzf 0.41.0" "fzf - a command-line fuzzy finder"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fzf - a command-line fuzzy finder
|
fzf - a command-line fuzzy finder
|
||||||
@@ -377,9 +377,10 @@ Do not display horizontal separator on the info line. A synonym for
|
|||||||
\fB--separator=''\fB
|
\fB--separator=''\fB
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BI "--scrollbar=" "CHAR"
|
.BI "--scrollbar=" "CHAR1[CHAR2]"
|
||||||
Use the given character to render scrollbar. (default: '│' or ':' depending on
|
Use the given character to render scrollbar. (default: '│' or ':' depending on
|
||||||
\fB--no-unicode\fR).
|
\fB--no-unicode\fR). The optional \fBCHAR2\fR is used to render scrollbar of
|
||||||
|
the preview window.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B "--no-scrollbar"
|
.B "--no-scrollbar"
|
||||||
@@ -433,28 +434,30 @@ color mappings.
|
|||||||
\fBbw \fRNo colors (equivalent to \fB--no-color\fR)
|
\fBbw \fRNo colors (equivalent to \fB--no-color\fR)
|
||||||
|
|
||||||
.B COLOR NAMES:
|
.B COLOR NAMES:
|
||||||
\fBfg \fRText
|
\fBfg \fRText
|
||||||
\fBpreview-fg \fRPreview window text
|
\fBpreview-fg \fRPreview window text
|
||||||
\fBbg \fRBackground
|
\fBbg \fRBackground
|
||||||
\fBpreview-bg \fRPreview window background
|
\fBpreview-bg \fRPreview window background
|
||||||
\fBhl \fRHighlighted substrings
|
\fBhl \fRHighlighted substrings
|
||||||
\fBfg+ \fRText (current line)
|
\fBfg+ \fRText (current line)
|
||||||
\fBbg+ \fRBackground (current line)
|
\fBbg+ \fRBackground (current line)
|
||||||
\fBgutter \fRGutter on the left
|
\fBgutter \fRGutter on the left
|
||||||
\fBhl+ \fRHighlighted substrings (current line)
|
\fBhl+ \fRHighlighted substrings (current line)
|
||||||
\fBquery \fRQuery string
|
\fBquery \fRQuery string
|
||||||
\fBdisabled \fRQuery string when search is disabled (\fB--disabled\fR)
|
\fBdisabled \fRQuery string when search is disabled (\fB--disabled\fR)
|
||||||
\fBinfo \fRInfo line (match counters)
|
\fBinfo \fRInfo line (match counters)
|
||||||
\fBborder \fRBorder around the window (\fB--border\fR and \fB--preview\fR)
|
\fBborder \fRBorder around the window (\fB--border\fR and \fB--preview\fR)
|
||||||
\fBseparator \fRHorizontal separator on info line
|
\fBscrollbar \fRScrollbar
|
||||||
\fBscrollbar \fRScrollbar
|
\fBpreview-border \fRBorder around the preview window (\fB--preview\fR)
|
||||||
\fBlabel \fRBorder label (\fB--border-label\fR and \fB--preview-label\fR)
|
\fBpreview-scrollbar \fRScrollbar
|
||||||
\fBpreview-label \fRBorder label of the preview window (\fB--preview-label\fR)
|
\fBseparator \fRHorizontal separator on info line
|
||||||
\fBprompt \fRPrompt
|
\fBlabel \fRBorder label (\fB--border-label\fR and \fB--preview-label\fR)
|
||||||
\fBpointer \fRPointer to the current line
|
\fBpreview-label \fRBorder label of the preview window (\fB--preview-label\fR)
|
||||||
\fBmarker \fRMulti-select marker
|
\fBprompt \fRPrompt
|
||||||
\fBspinner \fRStreaming input indicator
|
\fBpointer \fRPointer to the current line
|
||||||
\fBheader \fRHeader
|
\fBmarker \fRMulti-select marker
|
||||||
|
\fBspinner \fRStreaming input indicator
|
||||||
|
\fBheader \fRHeader
|
||||||
|
|
||||||
.B ANSI COLORS:
|
.B ANSI COLORS:
|
||||||
\fB-1 \fRDefault terminal foreground/background color
|
\fB-1 \fRDefault terminal foreground/background color
|
||||||
@@ -870,6 +873,8 @@ e.g.
|
|||||||
.br
|
.br
|
||||||
\fIctrl-space\fR
|
\fIctrl-space\fR
|
||||||
.br
|
.br
|
||||||
|
\fIctrl-delete\fR
|
||||||
|
.br
|
||||||
\fIctrl-\\\fR
|
\fIctrl-\\\fR
|
||||||
.br
|
.br
|
||||||
\fIctrl-]\fR
|
\fIctrl-]\fR
|
||||||
@@ -938,6 +943,8 @@ e.g.
|
|||||||
.br
|
.br
|
||||||
\fIshift-right\fR
|
\fIshift-right\fR
|
||||||
.br
|
.br
|
||||||
|
\fIshift-delete\fR
|
||||||
|
.br
|
||||||
\fIalt-shift-up\fR
|
\fIalt-shift-up\fR
|
||||||
.br
|
.br
|
||||||
\fIalt-shift-down\fR
|
\fIalt-shift-down\fR
|
||||||
|
|||||||
@@ -320,15 +320,16 @@ func Run(opts *Options, version string, revision string) {
|
|||||||
if !changed {
|
if !changed {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
reset := false
|
||||||
if !useSnapshot {
|
if !useSnapshot {
|
||||||
newSnapshot, _ := chunkList.Snapshot()
|
newSnapshot, _ := chunkList.Snapshot()
|
||||||
// We want to avoid showing empty list when reload is triggered
|
// We want to avoid showing empty list when reload is triggered
|
||||||
// and the query string is changed at the same time i.e. command != nil && changed
|
// and the query string is changed at the same time i.e. command != nil && changed
|
||||||
if command == nil || len(newSnapshot) > 0 {
|
if command == nil || len(newSnapshot) > 0 {
|
||||||
snapshot = newSnapshot
|
snapshot = newSnapshot
|
||||||
|
reset = clearCache()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reset := !useSnapshot && clearCache()
|
|
||||||
matcher.Reset(snapshot, input(reset), true, !reading, sort, reset)
|
matcher.Reset(snapshot, input(reset), true, !reading, sort, reset)
|
||||||
delay = false
|
delay = false
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ const usage = `usage: fzf [options]
|
|||||||
(default: 10)
|
(default: 10)
|
||||||
--layout=LAYOUT Choose layout: [default|reverse|reverse-list]
|
--layout=LAYOUT Choose layout: [default|reverse|reverse-list]
|
||||||
--border[=STYLE] Draw border around the finder
|
--border[=STYLE] Draw border around the finder
|
||||||
[rounded|sharp|horizontal|vertical|
|
[rounded|sharp|bold|block|double|horizontal|vertical|
|
||||||
top|bottom|left|right|none] (default: rounded)
|
top|bottom|left|right|none] (default: rounded)
|
||||||
--border-label=LABEL Label to print on the border
|
--border-label=LABEL Label to print on the border
|
||||||
--border-label-pos=COL Position of the border label
|
--border-label-pos=COL Position of the border label
|
||||||
@@ -75,7 +75,7 @@ const usage = `usage: fzf [options]
|
|||||||
--info=STYLE Finder info style [default|hidden|inline|inline:SEPARATOR]
|
--info=STYLE Finder info style [default|hidden|inline|inline:SEPARATOR]
|
||||||
--separator=STR String to form horizontal separator on info line
|
--separator=STR String to form horizontal separator on info line
|
||||||
--no-separator Hide info line separator
|
--no-separator Hide info line separator
|
||||||
--scrollbar[=CHAR] Scrollbar character
|
--scrollbar[=C1[C2]] Scrollbar character(s) (each for main and preview window)
|
||||||
--no-scrollbar Hide scrollbar
|
--no-scrollbar Hide scrollbar
|
||||||
--prompt=STR Input prompt (default: '> ')
|
--prompt=STR Input prompt (default: '> ')
|
||||||
--pointer=STR Pointer to the current line (default: '>')
|
--pointer=STR Pointer to the current line (default: '>')
|
||||||
@@ -544,6 +544,8 @@ func parseBorder(str string, optional bool) tui.BorderShape {
|
|||||||
return tui.BorderSharp
|
return tui.BorderSharp
|
||||||
case "bold":
|
case "bold":
|
||||||
return tui.BorderBold
|
return tui.BorderBold
|
||||||
|
case "block":
|
||||||
|
return tui.BorderBlock
|
||||||
case "double":
|
case "double":
|
||||||
return tui.BorderDouble
|
return tui.BorderDouble
|
||||||
case "horizontal":
|
case "horizontal":
|
||||||
@@ -564,7 +566,7 @@ func parseBorder(str string, optional bool) tui.BorderShape {
|
|||||||
if optional && str == "" {
|
if optional && str == "" {
|
||||||
return tui.DefaultBorderShape
|
return tui.DefaultBorderShape
|
||||||
}
|
}
|
||||||
errorExit("invalid border style (expected: rounded|sharp|bold|double|horizontal|vertical|top|bottom|left|right|none)")
|
errorExit("invalid border style (expected: rounded|sharp|bold|block|double|horizontal|vertical|top|bottom|left|right|none)")
|
||||||
}
|
}
|
||||||
return tui.BorderNone
|
return tui.BorderNone
|
||||||
}
|
}
|
||||||
@@ -612,6 +614,8 @@ func parseKeyChordsImpl(str string, message string, exit func(string)) map[tui.E
|
|||||||
add(tui.BSpace)
|
add(tui.BSpace)
|
||||||
case "ctrl-space":
|
case "ctrl-space":
|
||||||
add(tui.CtrlSpace)
|
add(tui.CtrlSpace)
|
||||||
|
case "ctrl-delete":
|
||||||
|
add(tui.CtrlDelete)
|
||||||
case "ctrl-^", "ctrl-6":
|
case "ctrl-^", "ctrl-6":
|
||||||
add(tui.CtrlCaret)
|
add(tui.CtrlCaret)
|
||||||
case "ctrl-/", "ctrl-_":
|
case "ctrl-/", "ctrl-_":
|
||||||
@@ -682,6 +686,8 @@ func parseKeyChordsImpl(str string, message string, exit func(string)) map[tui.E
|
|||||||
add(tui.SLeft)
|
add(tui.SLeft)
|
||||||
case "shift-right":
|
case "shift-right":
|
||||||
add(tui.SRight)
|
add(tui.SRight)
|
||||||
|
case "shift-delete":
|
||||||
|
add(tui.SDelete)
|
||||||
case "left-click":
|
case "left-click":
|
||||||
add(tui.LeftClick)
|
add(tui.LeftClick)
|
||||||
case "right-click":
|
case "right-click":
|
||||||
@@ -888,10 +894,14 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) *tui.ColorTheme {
|
|||||||
mergeAttr(&theme.CurrentMatch)
|
mergeAttr(&theme.CurrentMatch)
|
||||||
case "border":
|
case "border":
|
||||||
mergeAttr(&theme.Border)
|
mergeAttr(&theme.Border)
|
||||||
|
case "preview-border":
|
||||||
|
mergeAttr(&theme.PreviewBorder)
|
||||||
case "separator":
|
case "separator":
|
||||||
mergeAttr(&theme.Separator)
|
mergeAttr(&theme.Separator)
|
||||||
case "scrollbar":
|
case "scrollbar":
|
||||||
mergeAttr(&theme.Scrollbar)
|
mergeAttr(&theme.Scrollbar)
|
||||||
|
case "preview-scrollbar":
|
||||||
|
mergeAttr(&theme.PreviewScrollbar)
|
||||||
case "label":
|
case "label":
|
||||||
mergeAttr(&theme.BorderLabel)
|
mergeAttr(&theme.BorderLabel)
|
||||||
case "preview-label":
|
case "preview-label":
|
||||||
@@ -1426,6 +1436,8 @@ func parsePreviewWindowImpl(opts *previewOpts, input string, exit func(string))
|
|||||||
opts.border = tui.BorderSharp
|
opts.border = tui.BorderSharp
|
||||||
case "border-bold":
|
case "border-bold":
|
||||||
opts.border = tui.BorderBold
|
opts.border = tui.BorderBold
|
||||||
|
case "border-block":
|
||||||
|
opts.border = tui.BorderBlock
|
||||||
case "border-double":
|
case "border-double":
|
||||||
opts.border = tui.BorderDouble
|
opts.border = tui.BorderDouble
|
||||||
case "noborder", "border-none":
|
case "noborder", "border-none":
|
||||||
@@ -1952,8 +1964,16 @@ func postProcessOptions(opts *Options) {
|
|||||||
errorExit("--height option is currently not supported on this platform")
|
errorExit("--height option is currently not supported on this platform")
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Scrollbar != nil && runewidth.StringWidth(*opts.Scrollbar) > 1 {
|
if opts.Scrollbar != nil {
|
||||||
errorExit("scrollbar display width should be 1")
|
runes := []rune(*opts.Scrollbar)
|
||||||
|
if len(runes) > 2 {
|
||||||
|
errorExit("--scrollbar should be given one or two characters")
|
||||||
|
}
|
||||||
|
for _, r := range runes {
|
||||||
|
if runewidth.RuneWidth(r) != 1 {
|
||||||
|
errorExit("scrollbar display width should be 1")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default actions for CTRL-N / CTRL-P when --history is set
|
// Default actions for CTRL-N / CTRL-P when --history is set
|
||||||
@@ -1969,25 +1989,25 @@ func postProcessOptions(opts *Options) {
|
|||||||
// Extend the default key map
|
// Extend the default key map
|
||||||
keymap := defaultKeymap()
|
keymap := defaultKeymap()
|
||||||
for key, actions := range opts.Keymap {
|
for key, actions := range opts.Keymap {
|
||||||
var lastChangePreviewWindow *action
|
reordered := []*action{}
|
||||||
for _, act := range actions {
|
for _, act := range actions {
|
||||||
switch act.t {
|
switch act.t {
|
||||||
case actToggleSort:
|
case actToggleSort:
|
||||||
// To display "+S"/"-S" on info line
|
// To display "+S"/"-S" on info line
|
||||||
opts.ToggleSort = true
|
opts.ToggleSort = true
|
||||||
case actChangePreviewWindow:
|
case actTogglePreview, actShowPreview, actHidePreview, actChangePreviewWindow:
|
||||||
lastChangePreviewWindow = act
|
reordered = append(reordered, act)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-organize actions so that we only keep the last change-preview-window
|
// Re-organize actions so that we put actions that change the preview window first in the list.
|
||||||
// and it comes first in the list.
|
|
||||||
// * change-preview-window(up,+10)+preview(sleep 3; cat {})+change-preview-window(up,+20)
|
// * change-preview-window(up,+10)+preview(sleep 3; cat {})+change-preview-window(up,+20)
|
||||||
// -> change-preview-window(up,+20)+preview(sleep 3; cat {})
|
// -> change-preview-window(up,+10)+change-preview-window(up,+20)+preview(sleep 3; cat {})
|
||||||
if lastChangePreviewWindow != nil {
|
if len(reordered) > 0 {
|
||||||
reordered := []*action{lastChangePreviewWindow}
|
|
||||||
for _, act := range actions {
|
for _, act := range actions {
|
||||||
if act.t != actChangePreviewWindow {
|
switch act.t {
|
||||||
|
case actTogglePreview, actShowPreview, actHidePreview, actChangePreviewWindow:
|
||||||
|
default:
|
||||||
reordered = append(reordered, act)
|
reordered = append(reordered, act)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -199,6 +199,7 @@ type Terminal struct {
|
|||||||
header0 []string
|
header0 []string
|
||||||
ellipsis string
|
ellipsis string
|
||||||
scrollbar string
|
scrollbar string
|
||||||
|
previewScrollbar string
|
||||||
ansi bool
|
ansi bool
|
||||||
tabstop int
|
tabstop int
|
||||||
margin [4]sizeSpec
|
margin [4]sizeSpec
|
||||||
@@ -690,8 +691,16 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
|||||||
} else {
|
} else {
|
||||||
t.scrollbar = "|"
|
t.scrollbar = "|"
|
||||||
}
|
}
|
||||||
|
t.previewScrollbar = t.scrollbar
|
||||||
} else {
|
} else {
|
||||||
t.scrollbar = *opts.Scrollbar
|
runes := []rune(*opts.Scrollbar)
|
||||||
|
if len(runes) > 0 {
|
||||||
|
t.scrollbar = string(runes[0])
|
||||||
|
t.previewScrollbar = t.scrollbar
|
||||||
|
if len(runes) > 1 {
|
||||||
|
t.previewScrollbar = string(runes[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, t.hasLoadActions = t.keymap[tui.Load.AsEvent()]
|
_, t.hasLoadActions = t.keymap[tui.Load.AsEvent()]
|
||||||
@@ -717,7 +726,7 @@ func (t *Terminal) environ() []string {
|
|||||||
|
|
||||||
func borderLines(shape tui.BorderShape) int {
|
func borderLines(shape tui.BorderShape) int {
|
||||||
switch shape {
|
switch shape {
|
||||||
case tui.BorderHorizontal, tui.BorderRounded, tui.BorderSharp, tui.BorderBold, tui.BorderDouble:
|
case tui.BorderHorizontal, tui.BorderRounded, tui.BorderSharp, tui.BorderBold, tui.BorderBlock, tui.BorderDouble:
|
||||||
return 2
|
return 2
|
||||||
case tui.BorderTop, tui.BorderBottom:
|
case tui.BorderTop, tui.BorderBottom:
|
||||||
return 1
|
return 1
|
||||||
@@ -1073,7 +1082,7 @@ func (t *Terminal) adjustMarginAndPadding() (int, int, [4]int, [4]int) {
|
|||||||
if idx == 3 {
|
if idx == 3 {
|
||||||
extraMargin[idx] += 1 + bw
|
extraMargin[idx] += 1 + bw
|
||||||
}
|
}
|
||||||
case tui.BorderRounded, tui.BorderSharp, tui.BorderBold, tui.BorderDouble:
|
case tui.BorderRounded, tui.BorderSharp, tui.BorderBold, tui.BorderBlock, tui.BorderDouble:
|
||||||
extraMargin[idx] += 1 + bw*(idx%2)
|
extraMargin[idx] += 1 + bw*(idx%2)
|
||||||
}
|
}
|
||||||
marginInt[idx] = sizeSpecToInt(idx, sizeSpec) + extraMargin[idx]
|
marginInt[idx] = sizeSpecToInt(idx, sizeSpec) + extraMargin[idx]
|
||||||
@@ -1166,7 +1175,7 @@ func (t *Terminal) resizeWindows(forcePreview bool) {
|
|||||||
t.border = t.tui.NewWindow(
|
t.border = t.tui.NewWindow(
|
||||||
marginInt[0], marginInt[3], width+(1+bw), height,
|
marginInt[0], marginInt[3], width+(1+bw), height,
|
||||||
false, tui.MakeBorderStyle(tui.BorderRight, t.unicode))
|
false, tui.MakeBorderStyle(tui.BorderRight, t.unicode))
|
||||||
case tui.BorderRounded, tui.BorderSharp, tui.BorderBold, tui.BorderDouble:
|
case tui.BorderRounded, tui.BorderSharp, tui.BorderBold, tui.BorderBlock, tui.BorderDouble:
|
||||||
t.border = t.tui.NewWindow(
|
t.border = t.tui.NewWindow(
|
||||||
marginInt[0]-1, marginInt[3]-(1+bw), width+(1+bw)*2, height+2,
|
marginInt[0]-1, marginInt[3]-(1+bw), width+(1+bw)*2, height+2,
|
||||||
false, tui.MakeBorderStyle(t.borderShape, t.unicode))
|
false, tui.MakeBorderStyle(t.borderShape, t.unicode))
|
||||||
@@ -1200,7 +1209,7 @@ func (t *Terminal) resizeWindows(forcePreview bool) {
|
|||||||
}
|
}
|
||||||
t.pborder = t.tui.NewWindow(y, x, w, h, true, previewBorder)
|
t.pborder = t.tui.NewWindow(y, x, w, h, true, previewBorder)
|
||||||
switch previewOpts.border {
|
switch previewOpts.border {
|
||||||
case tui.BorderSharp, tui.BorderRounded, tui.BorderBold, tui.BorderDouble:
|
case tui.BorderSharp, tui.BorderRounded, tui.BorderBold, tui.BorderBlock, tui.BorderDouble:
|
||||||
pwidth -= (1 + bw) * 2
|
pwidth -= (1 + bw) * 2
|
||||||
pheight -= 2
|
pheight -= 2
|
||||||
x += 1 + bw
|
x += 1 + bw
|
||||||
@@ -1226,6 +1235,8 @@ func (t *Terminal) resizeWindows(forcePreview bool) {
|
|||||||
// Need a column to show scrollbar
|
// Need a column to show scrollbar
|
||||||
pwidth -= 1
|
pwidth -= 1
|
||||||
}
|
}
|
||||||
|
pwidth = util.Max(0, pwidth)
|
||||||
|
pheight = util.Max(0, pheight)
|
||||||
t.pwindow = t.tui.NewWindow(y, x, pwidth, pheight, true, noBorder)
|
t.pwindow = t.tui.NewWindow(y, x, pwidth, pheight, true, noBorder)
|
||||||
}
|
}
|
||||||
verticalPad := 2
|
verticalPad := 2
|
||||||
@@ -1342,7 +1353,7 @@ func (t *Terminal) printLabel(window tui.Window, render labelPrinter, opts label
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch borderShape {
|
switch borderShape {
|
||||||
case tui.BorderHorizontal, tui.BorderTop, tui.BorderBottom, tui.BorderRounded, tui.BorderSharp, tui.BorderBold, tui.BorderDouble:
|
case tui.BorderHorizontal, tui.BorderTop, tui.BorderBottom, tui.BorderRounded, tui.BorderSharp, tui.BorderBold, tui.BorderBlock, tui.BorderDouble:
|
||||||
if redrawBorder {
|
if redrawBorder {
|
||||||
window.DrawHBorder()
|
window.DrawHBorder()
|
||||||
}
|
}
|
||||||
@@ -1930,7 +1941,9 @@ func (t *Terminal) renderPreviewText(height int, lines []string, lineNo int, unc
|
|||||||
func (t *Terminal) renderPreviewScrollbar(yoff int, barLength int, barStart int) {
|
func (t *Terminal) renderPreviewScrollbar(yoff int, barLength int, barStart int) {
|
||||||
height := t.pwindow.Height()
|
height := t.pwindow.Height()
|
||||||
w := t.pborder.Width()
|
w := t.pborder.Width()
|
||||||
|
redraw := false
|
||||||
if len(t.previewer.bar) != height {
|
if len(t.previewer.bar) != height {
|
||||||
|
redraw = true
|
||||||
t.previewer.bar = make([]bool, height)
|
t.previewer.bar = make([]bool, height)
|
||||||
}
|
}
|
||||||
xshift := -1 - t.borderWidth
|
xshift := -1 - t.borderWidth
|
||||||
@@ -1947,22 +1960,22 @@ func (t *Terminal) renderPreviewScrollbar(yoff int, barLength int, barStart int)
|
|||||||
|
|
||||||
// Avoid unnecessary redraws
|
// Avoid unnecessary redraws
|
||||||
bar := i >= yoff+barStart && i < yoff+barStart+barLength
|
bar := i >= yoff+barStart && i < yoff+barStart+barLength
|
||||||
if bar == t.previewer.bar[i] && !t.tui.NeedScrollbarRedraw() {
|
if !redraw && bar == t.previewer.bar[i] && !t.tui.NeedScrollbarRedraw() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
t.previewer.bar[i] = bar
|
t.previewer.bar[i] = bar
|
||||||
t.pborder.Move(y, x)
|
t.pborder.Move(y, x)
|
||||||
if i >= yoff+barStart && i < yoff+barStart+barLength {
|
if i >= yoff+barStart && i < yoff+barStart+barLength {
|
||||||
t.pborder.CPrint(tui.ColScrollbar, t.scrollbar)
|
t.pborder.CPrint(tui.ColPreviewScrollbar, t.previewScrollbar)
|
||||||
} else {
|
} else {
|
||||||
t.pborder.Print(" ")
|
t.pborder.CPrint(tui.ColPreviewScrollbar, " ")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) printPreview() {
|
func (t *Terminal) printPreview() {
|
||||||
if !t.hasPreviewWindow() {
|
if !t.hasPreviewWindow() || t.pwindow.Height() == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
numLines := len(t.previewer.lines)
|
numLines := len(t.previewer.lines)
|
||||||
@@ -2706,11 +2719,6 @@ func (t *Terminal) Loop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var onFocus []*action
|
|
||||||
if actions, prs := t.keymap[tui.Focus.AsEvent()]; prs {
|
|
||||||
onFocus = actions
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
var focusedIndex int32 = minItem.Index()
|
var focusedIndex int32 = minItem.Index()
|
||||||
var version int64 = -1
|
var version int64 = -1
|
||||||
@@ -2751,7 +2759,7 @@ func (t *Terminal) Loop() {
|
|||||||
t.track = trackDisabled
|
t.track = trackDisabled
|
||||||
t.printInfo()
|
t.printInfo()
|
||||||
}
|
}
|
||||||
if onFocus != nil && focusChanged {
|
if onFocus, prs := t.keymap[tui.Focus.AsEvent()]; prs && focusChanged {
|
||||||
t.serverChan <- onFocus
|
t.serverChan <- onFocus
|
||||||
}
|
}
|
||||||
if focusChanged || version != t.version {
|
if focusChanged || version != t.version {
|
||||||
@@ -2953,6 +2961,14 @@ func (t *Terminal) Loop() {
|
|||||||
if t.history != nil {
|
if t.history != nil {
|
||||||
t.history.append(string(t.input))
|
t.history.append(string(t.input))
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
FIXME: It is not at all clear why this is required.
|
||||||
|
The following command will report 'not a tty', unless we open
|
||||||
|
/dev/tty *twice* after closing the standard input for 'reload'
|
||||||
|
in Reader.terminate().
|
||||||
|
: | fzf --bind 'start:reload:ls' --bind 'enter:become:tty'
|
||||||
|
*/
|
||||||
|
tui.TtyIn()
|
||||||
util.SetStdin(tui.TtyIn())
|
util.SetStdin(tui.TtyIn())
|
||||||
syscall.Exec(shellPath, []string{shell, "-c", command}, os.Environ())
|
syscall.Exec(shellPath, []string{shell, "-c", command}, os.Environ())
|
||||||
}
|
}
|
||||||
@@ -3523,6 +3539,9 @@ func (t *Terminal) Loop() {
|
|||||||
|
|
||||||
// Split window options
|
// Split window options
|
||||||
tokens := strings.Split(a.a, "|")
|
tokens := strings.Split(a.a, "|")
|
||||||
|
if len(tokens[0]) > 0 && t.initialPreviewOpts.hidden {
|
||||||
|
t.previewOpts.hidden = false
|
||||||
|
}
|
||||||
parsePreviewWindow(&t.previewOpts, tokens[0])
|
parsePreviewWindow(&t.previewOpts, tokens[0])
|
||||||
if len(tokens) > 1 {
|
if len(tokens) > 1 {
|
||||||
a.a = strings.Join(append(tokens[1:], tokens[0]), "|")
|
a.a = strings.Join(append(tokens[1:], tokens[0]), "|")
|
||||||
|
|||||||
@@ -430,7 +430,19 @@ func (r *LightRenderer) escSequence(sz *int) Event {
|
|||||||
}
|
}
|
||||||
return Event{Invalid, 0, nil} // INS
|
return Event{Invalid, 0, nil} // INS
|
||||||
case '3':
|
case '3':
|
||||||
return Event{Del, 0, nil}
|
if r.buffer[3] == '~' {
|
||||||
|
return Event{Del, 0, nil}
|
||||||
|
}
|
||||||
|
if len(r.buffer) == 6 && r.buffer[5] == '~' {
|
||||||
|
*sz = 6
|
||||||
|
switch r.buffer[4] {
|
||||||
|
case '5':
|
||||||
|
return Event{CtrlDelete, 0, nil}
|
||||||
|
case '2':
|
||||||
|
return Event{SDelete, 0, nil}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Event{Invalid, 0, nil}
|
||||||
case '4':
|
case '4':
|
||||||
return Event{End, 0, nil}
|
return Event{End, 0, nil}
|
||||||
case '5':
|
case '5':
|
||||||
@@ -745,7 +757,7 @@ func (w *LightWindow) DrawHBorder() {
|
|||||||
|
|
||||||
func (w *LightWindow) drawBorder(onlyHorizontal bool) {
|
func (w *LightWindow) drawBorder(onlyHorizontal bool) {
|
||||||
switch w.border.shape {
|
switch w.border.shape {
|
||||||
case BorderRounded, BorderSharp, BorderBold, BorderDouble:
|
case BorderRounded, BorderSharp, BorderBold, BorderBlock, BorderDouble:
|
||||||
w.drawBorderAround(onlyHorizontal)
|
w.drawBorderAround(onlyHorizontal)
|
||||||
case BorderHorizontal:
|
case BorderHorizontal:
|
||||||
w.drawBorderHorizontal(true, true)
|
w.drawBorderHorizontal(true, true)
|
||||||
@@ -776,14 +788,14 @@ func (w *LightWindow) drawBorderHorizontal(top, bottom bool) {
|
|||||||
if w.preview {
|
if w.preview {
|
||||||
color = ColPreviewBorder
|
color = ColPreviewBorder
|
||||||
}
|
}
|
||||||
hw := runewidth.RuneWidth(w.border.horizontal)
|
hw := runewidth.RuneWidth(w.border.top)
|
||||||
if top {
|
if top {
|
||||||
w.Move(0, 0)
|
w.Move(0, 0)
|
||||||
w.CPrint(color, repeat(w.border.horizontal, w.width/hw))
|
w.CPrint(color, repeat(w.border.top, w.width/hw))
|
||||||
}
|
}
|
||||||
if bottom {
|
if bottom {
|
||||||
w.Move(w.height-1, 0)
|
w.Move(w.height-1, 0)
|
||||||
w.CPrint(color, repeat(w.border.horizontal, w.width/hw))
|
w.CPrint(color, repeat(w.border.bottom, w.width/hw))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -799,11 +811,11 @@ func (w *LightWindow) drawBorderVertical(left, right bool) {
|
|||||||
for y := 0; y < w.height; y++ {
|
for y := 0; y < w.height; y++ {
|
||||||
w.Move(y, 0)
|
w.Move(y, 0)
|
||||||
if left {
|
if left {
|
||||||
w.CPrint(color, string(w.border.vertical))
|
w.CPrint(color, string(w.border.left))
|
||||||
}
|
}
|
||||||
w.CPrint(color, repeat(' ', width))
|
w.CPrint(color, repeat(' ', width))
|
||||||
if right {
|
if right {
|
||||||
w.CPrint(color, string(w.border.vertical))
|
w.CPrint(color, string(w.border.right))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -814,23 +826,23 @@ func (w *LightWindow) drawBorderAround(onlyHorizontal bool) {
|
|||||||
if w.preview {
|
if w.preview {
|
||||||
color = ColPreviewBorder
|
color = ColPreviewBorder
|
||||||
}
|
}
|
||||||
hw := runewidth.RuneWidth(w.border.horizontal)
|
hw := runewidth.RuneWidth(w.border.top)
|
||||||
tcw := runewidth.RuneWidth(w.border.topLeft) + runewidth.RuneWidth(w.border.topRight)
|
tcw := runewidth.RuneWidth(w.border.topLeft) + runewidth.RuneWidth(w.border.topRight)
|
||||||
bcw := runewidth.RuneWidth(w.border.bottomLeft) + runewidth.RuneWidth(w.border.bottomRight)
|
bcw := runewidth.RuneWidth(w.border.bottomLeft) + runewidth.RuneWidth(w.border.bottomRight)
|
||||||
rem := (w.width - tcw) % hw
|
rem := (w.width - tcw) % hw
|
||||||
w.CPrint(color, string(w.border.topLeft)+repeat(w.border.horizontal, (w.width-tcw)/hw)+repeat(' ', rem)+string(w.border.topRight))
|
w.CPrint(color, string(w.border.topLeft)+repeat(w.border.top, (w.width-tcw)/hw)+repeat(' ', rem)+string(w.border.topRight))
|
||||||
if !onlyHorizontal {
|
if !onlyHorizontal {
|
||||||
vw := runewidth.RuneWidth(w.border.vertical)
|
vw := runewidth.RuneWidth(w.border.left)
|
||||||
for y := 1; y < w.height-1; y++ {
|
for y := 1; y < w.height-1; y++ {
|
||||||
w.Move(y, 0)
|
w.Move(y, 0)
|
||||||
w.CPrint(color, string(w.border.vertical))
|
w.CPrint(color, string(w.border.left))
|
||||||
w.CPrint(color, repeat(' ', w.width-vw*2))
|
w.CPrint(color, repeat(' ', w.width-vw*2))
|
||||||
w.CPrint(color, string(w.border.vertical))
|
w.CPrint(color, string(w.border.right))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.Move(w.height-1, 0)
|
w.Move(w.height-1, 0)
|
||||||
rem = (w.width - bcw) % hw
|
rem = (w.width - bcw) % hw
|
||||||
w.CPrint(color, string(w.border.bottomLeft)+repeat(w.border.horizontal, (w.width-bcw)/hw)+repeat(' ', rem)+string(w.border.bottomRight))
|
w.CPrint(color, string(w.border.bottomLeft)+repeat(w.border.bottom, (w.width-bcw)/hw)+repeat(' ', rem)+string(w.border.bottomRight))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *LightWindow) csi(code string) string {
|
func (w *LightWindow) csi(code string) string {
|
||||||
|
|||||||
@@ -413,6 +413,12 @@ func (r *FullscreenRenderer) GetChar() Event {
|
|||||||
case tcell.KeyHome:
|
case tcell.KeyHome:
|
||||||
return Event{Home, 0, nil}
|
return Event{Home, 0, nil}
|
||||||
case tcell.KeyDelete:
|
case tcell.KeyDelete:
|
||||||
|
if ctrl {
|
||||||
|
return Event{CtrlDelete, 0, nil}
|
||||||
|
}
|
||||||
|
if shift {
|
||||||
|
return Event{SDelete, 0, nil}
|
||||||
|
}
|
||||||
return Event{Del, 0, nil}
|
return Event{Del, 0, nil}
|
||||||
case tcell.KeyEnd:
|
case tcell.KeyEnd:
|
||||||
return Event{End, 0, nil}
|
return Event{End, 0, nil}
|
||||||
@@ -707,9 +713,9 @@ func (w *TcellWindow) drawBorder(onlyHorizontal bool) {
|
|||||||
style = w.normal.style()
|
style = w.normal.style()
|
||||||
}
|
}
|
||||||
|
|
||||||
hw := runewidth.RuneWidth(w.borderStyle.horizontal)
|
hw := runewidth.RuneWidth(w.borderStyle.top)
|
||||||
switch shape {
|
switch shape {
|
||||||
case BorderRounded, BorderSharp, BorderBold, BorderDouble, BorderHorizontal, BorderTop:
|
case BorderRounded, BorderSharp, BorderBold, BorderBlock, BorderDouble, BorderHorizontal, BorderTop:
|
||||||
max := right - 2*hw
|
max := right - 2*hw
|
||||||
if shape == BorderHorizontal || shape == BorderTop {
|
if shape == BorderHorizontal || shape == BorderTop {
|
||||||
max = right - hw
|
max = right - hw
|
||||||
@@ -720,36 +726,36 @@ func (w *TcellWindow) drawBorder(onlyHorizontal bool) {
|
|||||||
// ==================
|
// ==================
|
||||||
// ( HH ) => TR is ignored
|
// ( HH ) => TR is ignored
|
||||||
for x := left; x <= max; x += hw {
|
for x := left; x <= max; x += hw {
|
||||||
_screen.SetContent(x, top, w.borderStyle.horizontal, nil, style)
|
_screen.SetContent(x, top, w.borderStyle.top, nil, style)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch shape {
|
switch shape {
|
||||||
case BorderRounded, BorderSharp, BorderBold, BorderDouble, BorderHorizontal, BorderBottom:
|
case BorderRounded, BorderSharp, BorderBold, BorderBlock, BorderDouble, BorderHorizontal, BorderBottom:
|
||||||
max := right - 2*hw
|
max := right - 2*hw
|
||||||
if shape == BorderHorizontal || shape == BorderBottom {
|
if shape == BorderHorizontal || shape == BorderBottom {
|
||||||
max = right - hw
|
max = right - hw
|
||||||
}
|
}
|
||||||
for x := left; x <= max; x += hw {
|
for x := left; x <= max; x += hw {
|
||||||
_screen.SetContent(x, bot-1, w.borderStyle.horizontal, nil, style)
|
_screen.SetContent(x, bot-1, w.borderStyle.bottom, nil, style)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !onlyHorizontal {
|
if !onlyHorizontal {
|
||||||
switch shape {
|
switch shape {
|
||||||
case BorderRounded, BorderSharp, BorderBold, BorderDouble, BorderVertical, BorderLeft:
|
case BorderRounded, BorderSharp, BorderBold, BorderBlock, BorderDouble, BorderVertical, BorderLeft:
|
||||||
for y := top; y < bot; y++ {
|
for y := top; y < bot; y++ {
|
||||||
_screen.SetContent(left, y, w.borderStyle.vertical, nil, style)
|
_screen.SetContent(left, y, w.borderStyle.left, nil, style)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch shape {
|
switch shape {
|
||||||
case BorderRounded, BorderSharp, BorderBold, BorderDouble, BorderVertical, BorderRight:
|
case BorderRounded, BorderSharp, BorderBold, BorderBlock, BorderDouble, BorderVertical, BorderRight:
|
||||||
vw := runewidth.RuneWidth(w.borderStyle.vertical)
|
vw := runewidth.RuneWidth(w.borderStyle.right)
|
||||||
for y := top; y < bot; y++ {
|
for y := top; y < bot; y++ {
|
||||||
_screen.SetContent(right-vw, y, w.borderStyle.vertical, nil, style)
|
_screen.SetContent(right-vw, y, w.borderStyle.right, nil, style)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch shape {
|
switch shape {
|
||||||
case BorderRounded, BorderSharp, BorderBold, BorderDouble:
|
case BorderRounded, BorderSharp, BorderBold, BorderBlock, BorderDouble:
|
||||||
_screen.SetContent(left, top, w.borderStyle.topLeft, nil, style)
|
_screen.SetContent(left, top, w.borderStyle.topLeft, nil, style)
|
||||||
_screen.SetContent(right-runewidth.RuneWidth(w.borderStyle.topRight), top, w.borderStyle.topRight, nil, style)
|
_screen.SetContent(right-runewidth.RuneWidth(w.borderStyle.topRight), top, w.borderStyle.topRight, nil, style)
|
||||||
_screen.SetContent(left, bot-1, w.borderStyle.bottomLeft, nil, style)
|
_screen.SetContent(left, bot-1, w.borderStyle.bottomLeft, nil, style)
|
||||||
|
|||||||
354
src/tui/tui.go
354
src/tui/tui.go
@@ -41,6 +41,7 @@ const (
|
|||||||
CtrlZ
|
CtrlZ
|
||||||
ESC
|
ESC
|
||||||
CtrlSpace
|
CtrlSpace
|
||||||
|
CtrlDelete
|
||||||
|
|
||||||
// https://apple.stackexchange.com/questions/24261/how-do-i-send-c-that-is-control-slash-to-the-terminal
|
// https://apple.stackexchange.com/questions/24261/how-do-i-send-c-that-is-control-slash-to-the-terminal
|
||||||
CtrlBackSlash
|
CtrlBackSlash
|
||||||
@@ -74,6 +75,7 @@ const (
|
|||||||
SDown
|
SDown
|
||||||
SLeft
|
SLeft
|
||||||
SRight
|
SRight
|
||||||
|
SDelete
|
||||||
|
|
||||||
F1
|
F1
|
||||||
F2
|
F2
|
||||||
@@ -253,29 +255,31 @@ func (p ColorPair) MergeNonDefault(other ColorPair) ColorPair {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ColorTheme struct {
|
type ColorTheme struct {
|
||||||
Colored bool
|
Colored bool
|
||||||
Input ColorAttr
|
Input ColorAttr
|
||||||
Disabled ColorAttr
|
Disabled ColorAttr
|
||||||
Fg ColorAttr
|
Fg ColorAttr
|
||||||
Bg ColorAttr
|
Bg ColorAttr
|
||||||
PreviewFg ColorAttr
|
PreviewFg ColorAttr
|
||||||
PreviewBg ColorAttr
|
PreviewBg ColorAttr
|
||||||
DarkBg ColorAttr
|
DarkBg ColorAttr
|
||||||
Gutter ColorAttr
|
Gutter ColorAttr
|
||||||
Prompt ColorAttr
|
Prompt ColorAttr
|
||||||
Match ColorAttr
|
Match ColorAttr
|
||||||
Current ColorAttr
|
Current ColorAttr
|
||||||
CurrentMatch ColorAttr
|
CurrentMatch ColorAttr
|
||||||
Spinner ColorAttr
|
Spinner ColorAttr
|
||||||
Info ColorAttr
|
Info ColorAttr
|
||||||
Cursor ColorAttr
|
Cursor ColorAttr
|
||||||
Selected ColorAttr
|
Selected ColorAttr
|
||||||
Header ColorAttr
|
Header ColorAttr
|
||||||
Separator ColorAttr
|
Separator ColorAttr
|
||||||
Scrollbar ColorAttr
|
Scrollbar ColorAttr
|
||||||
Border ColorAttr
|
Border ColorAttr
|
||||||
BorderLabel ColorAttr
|
PreviewBorder ColorAttr
|
||||||
PreviewLabel ColorAttr
|
PreviewScrollbar ColorAttr
|
||||||
|
BorderLabel ColorAttr
|
||||||
|
PreviewLabel ColorAttr
|
||||||
}
|
}
|
||||||
|
|
||||||
type Event struct {
|
type Event struct {
|
||||||
@@ -310,6 +314,7 @@ const (
|
|||||||
BorderRounded
|
BorderRounded
|
||||||
BorderSharp
|
BorderSharp
|
||||||
BorderBold
|
BorderBold
|
||||||
|
BorderBlock
|
||||||
BorderDouble
|
BorderDouble
|
||||||
BorderHorizontal
|
BorderHorizontal
|
||||||
BorderVertical
|
BorderVertical
|
||||||
@@ -337,8 +342,10 @@ func (s BorderShape) HasTop() bool {
|
|||||||
|
|
||||||
type BorderStyle struct {
|
type BorderStyle struct {
|
||||||
shape BorderShape
|
shape BorderShape
|
||||||
horizontal rune
|
top rune
|
||||||
vertical rune
|
bottom rune
|
||||||
|
left rune
|
||||||
|
right rune
|
||||||
topLeft rune
|
topLeft rune
|
||||||
topRight rune
|
topRight rune
|
||||||
bottomLeft rune
|
bottomLeft rune
|
||||||
@@ -351,8 +358,10 @@ func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
|
|||||||
if !unicode {
|
if !unicode {
|
||||||
return BorderStyle{
|
return BorderStyle{
|
||||||
shape: shape,
|
shape: shape,
|
||||||
horizontal: '-',
|
top: '-',
|
||||||
vertical: '|',
|
bottom: '-',
|
||||||
|
left: '|',
|
||||||
|
right: '|',
|
||||||
topLeft: '+',
|
topLeft: '+',
|
||||||
topRight: '+',
|
topRight: '+',
|
||||||
bottomLeft: '+',
|
bottomLeft: '+',
|
||||||
@@ -363,8 +372,10 @@ func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
|
|||||||
case BorderSharp:
|
case BorderSharp:
|
||||||
return BorderStyle{
|
return BorderStyle{
|
||||||
shape: shape,
|
shape: shape,
|
||||||
horizontal: '─',
|
top: '─',
|
||||||
vertical: '│',
|
bottom: '─',
|
||||||
|
left: '│',
|
||||||
|
right: '│',
|
||||||
topLeft: '┌',
|
topLeft: '┌',
|
||||||
topRight: '┐',
|
topRight: '┐',
|
||||||
bottomLeft: '└',
|
bottomLeft: '└',
|
||||||
@@ -373,18 +384,37 @@ func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
|
|||||||
case BorderBold:
|
case BorderBold:
|
||||||
return BorderStyle{
|
return BorderStyle{
|
||||||
shape: shape,
|
shape: shape,
|
||||||
horizontal: '━',
|
top: '━',
|
||||||
vertical: '┃',
|
bottom: '━',
|
||||||
|
left: '┃',
|
||||||
|
right: '┃',
|
||||||
topLeft: '┏',
|
topLeft: '┏',
|
||||||
topRight: '┓',
|
topRight: '┓',
|
||||||
bottomLeft: '┗',
|
bottomLeft: '┗',
|
||||||
bottomRight: '┛',
|
bottomRight: '┛',
|
||||||
}
|
}
|
||||||
|
case BorderBlock:
|
||||||
|
// ▛▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▜
|
||||||
|
// ▌ ▐
|
||||||
|
// ▙▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▟
|
||||||
|
return BorderStyle{
|
||||||
|
shape: shape,
|
||||||
|
top: '▀',
|
||||||
|
bottom: '▄',
|
||||||
|
left: '▌',
|
||||||
|
right: '▐',
|
||||||
|
topLeft: '▛',
|
||||||
|
topRight: '▜',
|
||||||
|
bottomLeft: '▙',
|
||||||
|
bottomRight: '▟',
|
||||||
|
}
|
||||||
case BorderDouble:
|
case BorderDouble:
|
||||||
return BorderStyle{
|
return BorderStyle{
|
||||||
shape: shape,
|
shape: shape,
|
||||||
horizontal: '═',
|
top: '═',
|
||||||
vertical: '║',
|
bottom: '═',
|
||||||
|
left: '║',
|
||||||
|
right: '║',
|
||||||
topLeft: '╔',
|
topLeft: '╔',
|
||||||
topRight: '╗',
|
topRight: '╗',
|
||||||
bottomLeft: '╚',
|
bottomLeft: '╚',
|
||||||
@@ -393,8 +423,10 @@ func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
|
|||||||
}
|
}
|
||||||
return BorderStyle{
|
return BorderStyle{
|
||||||
shape: shape,
|
shape: shape,
|
||||||
horizontal: '─',
|
top: '─',
|
||||||
vertical: '│',
|
bottom: '─',
|
||||||
|
left: '│',
|
||||||
|
right: '│',
|
||||||
topLeft: '╭',
|
topLeft: '╭',
|
||||||
topRight: '╮',
|
topRight: '╮',
|
||||||
bottomLeft: '╰',
|
bottomLeft: '╰',
|
||||||
@@ -405,8 +437,10 @@ func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
|
|||||||
func MakeTransparentBorder() BorderStyle {
|
func MakeTransparentBorder() BorderStyle {
|
||||||
return BorderStyle{
|
return BorderStyle{
|
||||||
shape: BorderRounded,
|
shape: BorderRounded,
|
||||||
horizontal: ' ',
|
top: ' ',
|
||||||
vertical: ' ',
|
bottom: ' ',
|
||||||
|
left: ' ',
|
||||||
|
right: ' ',
|
||||||
topLeft: ' ',
|
topLeft: ' ',
|
||||||
topRight: ' ',
|
topRight: ' ',
|
||||||
bottomLeft: ' ',
|
bottomLeft: ' ',
|
||||||
@@ -503,61 +537,66 @@ var (
|
|||||||
ColPreviewBorder ColorPair
|
ColPreviewBorder ColorPair
|
||||||
ColBorderLabel ColorPair
|
ColBorderLabel ColorPair
|
||||||
ColPreviewLabel ColorPair
|
ColPreviewLabel ColorPair
|
||||||
|
ColPreviewScrollbar ColorPair
|
||||||
)
|
)
|
||||||
|
|
||||||
func EmptyTheme() *ColorTheme {
|
func EmptyTheme() *ColorTheme {
|
||||||
return &ColorTheme{
|
return &ColorTheme{
|
||||||
Colored: true,
|
Colored: true,
|
||||||
Input: ColorAttr{colUndefined, AttrUndefined},
|
Input: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Fg: ColorAttr{colUndefined, AttrUndefined},
|
Fg: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Bg: ColorAttr{colUndefined, AttrUndefined},
|
Bg: ColorAttr{colUndefined, AttrUndefined},
|
||||||
DarkBg: ColorAttr{colUndefined, AttrUndefined},
|
DarkBg: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Prompt: ColorAttr{colUndefined, AttrUndefined},
|
Prompt: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Match: ColorAttr{colUndefined, AttrUndefined},
|
Match: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Current: ColorAttr{colUndefined, AttrUndefined},
|
Current: ColorAttr{colUndefined, AttrUndefined},
|
||||||
CurrentMatch: ColorAttr{colUndefined, AttrUndefined},
|
CurrentMatch: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Spinner: ColorAttr{colUndefined, AttrUndefined},
|
Spinner: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Info: ColorAttr{colUndefined, AttrUndefined},
|
Info: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Cursor: ColorAttr{colUndefined, AttrUndefined},
|
Cursor: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Selected: ColorAttr{colUndefined, AttrUndefined},
|
Selected: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Header: ColorAttr{colUndefined, AttrUndefined},
|
Header: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Border: ColorAttr{colUndefined, AttrUndefined},
|
Border: ColorAttr{colUndefined, AttrUndefined},
|
||||||
BorderLabel: ColorAttr{colUndefined, AttrUndefined},
|
BorderLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Disabled: ColorAttr{colUndefined, AttrUndefined},
|
Disabled: ColorAttr{colUndefined, AttrUndefined},
|
||||||
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
|
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
|
||||||
PreviewBg: ColorAttr{colUndefined, AttrUndefined},
|
PreviewBg: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Gutter: ColorAttr{colUndefined, AttrUndefined},
|
Gutter: ColorAttr{colUndefined, AttrUndefined},
|
||||||
PreviewLabel: ColorAttr{colUndefined, AttrUndefined},
|
PreviewBorder: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Separator: ColorAttr{colUndefined, AttrUndefined},
|
PreviewScrollbar: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Scrollbar: ColorAttr{colUndefined, AttrUndefined},
|
PreviewLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||||
|
Separator: ColorAttr{colUndefined, AttrUndefined},
|
||||||
|
Scrollbar: ColorAttr{colUndefined, AttrUndefined},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NoColorTheme() *ColorTheme {
|
func NoColorTheme() *ColorTheme {
|
||||||
return &ColorTheme{
|
return &ColorTheme{
|
||||||
Colored: false,
|
Colored: false,
|
||||||
Input: ColorAttr{colDefault, AttrUndefined},
|
Input: ColorAttr{colDefault, AttrUndefined},
|
||||||
Fg: ColorAttr{colDefault, AttrUndefined},
|
Fg: ColorAttr{colDefault, AttrUndefined},
|
||||||
Bg: ColorAttr{colDefault, AttrUndefined},
|
Bg: ColorAttr{colDefault, AttrUndefined},
|
||||||
DarkBg: ColorAttr{colDefault, AttrUndefined},
|
DarkBg: ColorAttr{colDefault, AttrUndefined},
|
||||||
Prompt: ColorAttr{colDefault, AttrUndefined},
|
Prompt: ColorAttr{colDefault, AttrUndefined},
|
||||||
Match: ColorAttr{colDefault, Underline},
|
Match: ColorAttr{colDefault, Underline},
|
||||||
Current: ColorAttr{colDefault, Reverse},
|
Current: ColorAttr{colDefault, Reverse},
|
||||||
CurrentMatch: ColorAttr{colDefault, Reverse | Underline},
|
CurrentMatch: ColorAttr{colDefault, Reverse | Underline},
|
||||||
Spinner: ColorAttr{colDefault, AttrUndefined},
|
Spinner: ColorAttr{colDefault, AttrUndefined},
|
||||||
Info: ColorAttr{colDefault, AttrUndefined},
|
Info: ColorAttr{colDefault, AttrUndefined},
|
||||||
Cursor: ColorAttr{colDefault, AttrUndefined},
|
Cursor: ColorAttr{colDefault, AttrUndefined},
|
||||||
Selected: ColorAttr{colDefault, AttrUndefined},
|
Selected: ColorAttr{colDefault, AttrUndefined},
|
||||||
Header: ColorAttr{colDefault, AttrUndefined},
|
Header: ColorAttr{colDefault, AttrUndefined},
|
||||||
Border: ColorAttr{colDefault, AttrUndefined},
|
Border: ColorAttr{colDefault, AttrUndefined},
|
||||||
BorderLabel: ColorAttr{colDefault, AttrUndefined},
|
BorderLabel: ColorAttr{colDefault, AttrUndefined},
|
||||||
Disabled: ColorAttr{colDefault, AttrUndefined},
|
Disabled: ColorAttr{colDefault, AttrUndefined},
|
||||||
PreviewFg: ColorAttr{colDefault, AttrUndefined},
|
PreviewFg: ColorAttr{colDefault, AttrUndefined},
|
||||||
PreviewBg: ColorAttr{colDefault, AttrUndefined},
|
PreviewBg: ColorAttr{colDefault, AttrUndefined},
|
||||||
Gutter: ColorAttr{colDefault, AttrUndefined},
|
Gutter: ColorAttr{colDefault, AttrUndefined},
|
||||||
PreviewLabel: ColorAttr{colDefault, AttrUndefined},
|
PreviewBorder: ColorAttr{colDefault, AttrUndefined},
|
||||||
Separator: ColorAttr{colDefault, AttrUndefined},
|
PreviewScrollbar: ColorAttr{colDefault, AttrUndefined},
|
||||||
Scrollbar: ColorAttr{colDefault, AttrUndefined},
|
PreviewLabel: ColorAttr{colDefault, AttrUndefined},
|
||||||
|
Separator: ColorAttr{colDefault, AttrUndefined},
|
||||||
|
Scrollbar: ColorAttr{colDefault, AttrUndefined},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -568,79 +607,85 @@ func errorExit(message string) {
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Default16 = &ColorTheme{
|
Default16 = &ColorTheme{
|
||||||
Colored: true,
|
Colored: true,
|
||||||
Input: ColorAttr{colDefault, AttrUndefined},
|
Input: ColorAttr{colDefault, AttrUndefined},
|
||||||
Fg: ColorAttr{colDefault, AttrUndefined},
|
Fg: ColorAttr{colDefault, AttrUndefined},
|
||||||
Bg: ColorAttr{colDefault, AttrUndefined},
|
Bg: ColorAttr{colDefault, AttrUndefined},
|
||||||
DarkBg: ColorAttr{colBlack, AttrUndefined},
|
DarkBg: ColorAttr{colBlack, AttrUndefined},
|
||||||
Prompt: ColorAttr{colBlue, AttrUndefined},
|
Prompt: ColorAttr{colBlue, AttrUndefined},
|
||||||
Match: ColorAttr{colGreen, AttrUndefined},
|
Match: ColorAttr{colGreen, AttrUndefined},
|
||||||
Current: ColorAttr{colYellow, AttrUndefined},
|
Current: ColorAttr{colYellow, AttrUndefined},
|
||||||
CurrentMatch: ColorAttr{colGreen, AttrUndefined},
|
CurrentMatch: ColorAttr{colGreen, AttrUndefined},
|
||||||
Spinner: ColorAttr{colGreen, AttrUndefined},
|
Spinner: ColorAttr{colGreen, AttrUndefined},
|
||||||
Info: ColorAttr{colWhite, AttrUndefined},
|
Info: ColorAttr{colWhite, AttrUndefined},
|
||||||
Cursor: ColorAttr{colRed, AttrUndefined},
|
Cursor: ColorAttr{colRed, AttrUndefined},
|
||||||
Selected: ColorAttr{colMagenta, AttrUndefined},
|
Selected: ColorAttr{colMagenta, AttrUndefined},
|
||||||
Header: ColorAttr{colCyan, AttrUndefined},
|
Header: ColorAttr{colCyan, AttrUndefined},
|
||||||
Border: ColorAttr{colBlack, AttrUndefined},
|
Border: ColorAttr{colBlack, AttrUndefined},
|
||||||
BorderLabel: ColorAttr{colWhite, AttrUndefined},
|
BorderLabel: ColorAttr{colWhite, AttrUndefined},
|
||||||
Disabled: ColorAttr{colUndefined, AttrUndefined},
|
Disabled: ColorAttr{colUndefined, AttrUndefined},
|
||||||
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
|
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
|
||||||
PreviewBg: ColorAttr{colUndefined, AttrUndefined},
|
PreviewBg: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Gutter: ColorAttr{colUndefined, AttrUndefined},
|
Gutter: ColorAttr{colUndefined, AttrUndefined},
|
||||||
PreviewLabel: ColorAttr{colUndefined, AttrUndefined},
|
PreviewBorder: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Separator: ColorAttr{colUndefined, AttrUndefined},
|
PreviewScrollbar: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Scrollbar: ColorAttr{colUndefined, AttrUndefined},
|
PreviewLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||||
|
Separator: ColorAttr{colUndefined, AttrUndefined},
|
||||||
|
Scrollbar: ColorAttr{colUndefined, AttrUndefined},
|
||||||
}
|
}
|
||||||
Dark256 = &ColorTheme{
|
Dark256 = &ColorTheme{
|
||||||
Colored: true,
|
Colored: true,
|
||||||
Input: ColorAttr{colDefault, AttrUndefined},
|
Input: ColorAttr{colDefault, AttrUndefined},
|
||||||
Fg: ColorAttr{colDefault, AttrUndefined},
|
Fg: ColorAttr{colDefault, AttrUndefined},
|
||||||
Bg: ColorAttr{colDefault, AttrUndefined},
|
Bg: ColorAttr{colDefault, AttrUndefined},
|
||||||
DarkBg: ColorAttr{236, AttrUndefined},
|
DarkBg: ColorAttr{236, AttrUndefined},
|
||||||
Prompt: ColorAttr{110, AttrUndefined},
|
Prompt: ColorAttr{110, AttrUndefined},
|
||||||
Match: ColorAttr{108, AttrUndefined},
|
Match: ColorAttr{108, AttrUndefined},
|
||||||
Current: ColorAttr{254, AttrUndefined},
|
Current: ColorAttr{254, AttrUndefined},
|
||||||
CurrentMatch: ColorAttr{151, AttrUndefined},
|
CurrentMatch: ColorAttr{151, AttrUndefined},
|
||||||
Spinner: ColorAttr{148, AttrUndefined},
|
Spinner: ColorAttr{148, AttrUndefined},
|
||||||
Info: ColorAttr{144, AttrUndefined},
|
Info: ColorAttr{144, AttrUndefined},
|
||||||
Cursor: ColorAttr{161, AttrUndefined},
|
Cursor: ColorAttr{161, AttrUndefined},
|
||||||
Selected: ColorAttr{168, AttrUndefined},
|
Selected: ColorAttr{168, AttrUndefined},
|
||||||
Header: ColorAttr{109, AttrUndefined},
|
Header: ColorAttr{109, AttrUndefined},
|
||||||
Border: ColorAttr{59, AttrUndefined},
|
Border: ColorAttr{59, AttrUndefined},
|
||||||
BorderLabel: ColorAttr{145, AttrUndefined},
|
BorderLabel: ColorAttr{145, AttrUndefined},
|
||||||
Disabled: ColorAttr{colUndefined, AttrUndefined},
|
Disabled: ColorAttr{colUndefined, AttrUndefined},
|
||||||
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
|
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
|
||||||
PreviewBg: ColorAttr{colUndefined, AttrUndefined},
|
PreviewBg: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Gutter: ColorAttr{colUndefined, AttrUndefined},
|
Gutter: ColorAttr{colUndefined, AttrUndefined},
|
||||||
PreviewLabel: ColorAttr{colUndefined, AttrUndefined},
|
PreviewBorder: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Separator: ColorAttr{colUndefined, AttrUndefined},
|
PreviewScrollbar: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Scrollbar: ColorAttr{colUndefined, AttrUndefined},
|
PreviewLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||||
|
Separator: ColorAttr{colUndefined, AttrUndefined},
|
||||||
|
Scrollbar: ColorAttr{colUndefined, AttrUndefined},
|
||||||
}
|
}
|
||||||
Light256 = &ColorTheme{
|
Light256 = &ColorTheme{
|
||||||
Colored: true,
|
Colored: true,
|
||||||
Input: ColorAttr{colDefault, AttrUndefined},
|
Input: ColorAttr{colDefault, AttrUndefined},
|
||||||
Fg: ColorAttr{colDefault, AttrUndefined},
|
Fg: ColorAttr{colDefault, AttrUndefined},
|
||||||
Bg: ColorAttr{colDefault, AttrUndefined},
|
Bg: ColorAttr{colDefault, AttrUndefined},
|
||||||
DarkBg: ColorAttr{251, AttrUndefined},
|
DarkBg: ColorAttr{251, AttrUndefined},
|
||||||
Prompt: ColorAttr{25, AttrUndefined},
|
Prompt: ColorAttr{25, AttrUndefined},
|
||||||
Match: ColorAttr{66, AttrUndefined},
|
Match: ColorAttr{66, AttrUndefined},
|
||||||
Current: ColorAttr{237, AttrUndefined},
|
Current: ColorAttr{237, AttrUndefined},
|
||||||
CurrentMatch: ColorAttr{23, AttrUndefined},
|
CurrentMatch: ColorAttr{23, AttrUndefined},
|
||||||
Spinner: ColorAttr{65, AttrUndefined},
|
Spinner: ColorAttr{65, AttrUndefined},
|
||||||
Info: ColorAttr{101, AttrUndefined},
|
Info: ColorAttr{101, AttrUndefined},
|
||||||
Cursor: ColorAttr{161, AttrUndefined},
|
Cursor: ColorAttr{161, AttrUndefined},
|
||||||
Selected: ColorAttr{168, AttrUndefined},
|
Selected: ColorAttr{168, AttrUndefined},
|
||||||
Header: ColorAttr{31, AttrUndefined},
|
Header: ColorAttr{31, AttrUndefined},
|
||||||
Border: ColorAttr{145, AttrUndefined},
|
Border: ColorAttr{145, AttrUndefined},
|
||||||
BorderLabel: ColorAttr{59, AttrUndefined},
|
BorderLabel: ColorAttr{59, AttrUndefined},
|
||||||
Disabled: ColorAttr{colUndefined, AttrUndefined},
|
Disabled: ColorAttr{colUndefined, AttrUndefined},
|
||||||
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
|
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
|
||||||
PreviewBg: ColorAttr{colUndefined, AttrUndefined},
|
PreviewBg: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Gutter: ColorAttr{colUndefined, AttrUndefined},
|
Gutter: ColorAttr{colUndefined, AttrUndefined},
|
||||||
PreviewLabel: ColorAttr{colUndefined, AttrUndefined},
|
PreviewBorder: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Separator: ColorAttr{colUndefined, AttrUndefined},
|
PreviewScrollbar: ColorAttr{colUndefined, AttrUndefined},
|
||||||
Scrollbar: ColorAttr{colUndefined, AttrUndefined},
|
PreviewLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||||
|
Separator: ColorAttr{colUndefined, AttrUndefined},
|
||||||
|
Scrollbar: ColorAttr{colUndefined, AttrUndefined},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -681,8 +726,10 @@ func initTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool) {
|
|||||||
theme.PreviewFg = o(theme.Fg, theme.PreviewFg)
|
theme.PreviewFg = o(theme.Fg, theme.PreviewFg)
|
||||||
theme.PreviewBg = o(theme.Bg, theme.PreviewBg)
|
theme.PreviewBg = o(theme.Bg, theme.PreviewBg)
|
||||||
theme.PreviewLabel = o(theme.BorderLabel, theme.PreviewLabel)
|
theme.PreviewLabel = o(theme.BorderLabel, theme.PreviewLabel)
|
||||||
|
theme.PreviewBorder = o(theme.Border, theme.PreviewBorder)
|
||||||
theme.Separator = o(theme.Border, theme.Separator)
|
theme.Separator = o(theme.Border, theme.Separator)
|
||||||
theme.Scrollbar = o(theme.Border, theme.Scrollbar)
|
theme.Scrollbar = o(theme.Border, theme.Scrollbar)
|
||||||
|
theme.PreviewScrollbar = o(theme.PreviewBorder, theme.PreviewScrollbar)
|
||||||
|
|
||||||
initPalette(theme)
|
initPalette(theme)
|
||||||
}
|
}
|
||||||
@@ -720,5 +767,6 @@ func initPalette(theme *ColorTheme) {
|
|||||||
ColBorderLabel = pair(theme.BorderLabel, theme.Bg)
|
ColBorderLabel = pair(theme.BorderLabel, theme.Bg)
|
||||||
ColPreviewLabel = pair(theme.PreviewLabel, theme.PreviewBg)
|
ColPreviewLabel = pair(theme.PreviewLabel, theme.PreviewBg)
|
||||||
ColPreview = pair(theme.PreviewFg, theme.PreviewBg)
|
ColPreview = pair(theme.PreviewFg, theme.PreviewBg)
|
||||||
ColPreviewBorder = pair(theme.Border, theme.PreviewBg)
|
ColPreviewBorder = pair(theme.PreviewBorder, theme.PreviewBg)
|
||||||
|
ColPreviewScrollbar = pair(theme.PreviewScrollbar, theme.PreviewBg)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2493,6 +2493,39 @@ class TestGoFZF < TestBase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_change_preview_window_rotate_hidden
|
||||||
|
tmux.send_keys "seq 100 | #{FZF} --preview-window hidden --preview 'echo =={}==' --bind '" \
|
||||||
|
"a:change-preview-window(nohidden||down,1|)'", :Enter
|
||||||
|
tmux.until { |lines| assert_equal 100, lines.match_count }
|
||||||
|
tmux.until { |lines| refute_includes lines[1], '==1==' }
|
||||||
|
tmux.send_keys 'a'
|
||||||
|
tmux.until { |lines| assert_includes lines[1], '==1==' }
|
||||||
|
tmux.send_keys 'a'
|
||||||
|
tmux.until { |lines| refute_includes lines[1], '==1==' }
|
||||||
|
tmux.send_keys 'a'
|
||||||
|
tmux.until { |lines| assert_includes lines[-2], '==1==' }
|
||||||
|
tmux.send_keys 'a'
|
||||||
|
tmux.until { |lines| refute_includes lines[-2], '==1==' }
|
||||||
|
tmux.send_keys 'a'
|
||||||
|
tmux.until { |lines| assert_includes lines[1], '==1==' }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_change_preview_window_rotate_hidden_down
|
||||||
|
tmux.send_keys "seq 100 | #{FZF} --bind '?:change-preview-window:up||down|' --preview 'echo =={}==' --preview-window hidden,down,1", :Enter
|
||||||
|
tmux.until { |lines| assert_equal 100, lines.match_count }
|
||||||
|
tmux.until { |lines| refute_includes lines[1], '==1==' }
|
||||||
|
tmux.send_keys '?'
|
||||||
|
tmux.until { |lines| assert_includes lines[1], '==1==' }
|
||||||
|
tmux.send_keys '?'
|
||||||
|
tmux.until { |lines| refute_includes lines[1], '==1==' }
|
||||||
|
tmux.send_keys '?'
|
||||||
|
tmux.until { |lines| assert_includes lines[-2], '==1==' }
|
||||||
|
tmux.send_keys '?'
|
||||||
|
tmux.until { |lines| refute_includes lines[-2], '==1==' }
|
||||||
|
tmux.send_keys '?'
|
||||||
|
tmux.until { |lines| assert_includes lines[1], '==1==' }
|
||||||
|
end
|
||||||
|
|
||||||
def test_ellipsis
|
def test_ellipsis
|
||||||
tmux.send_keys 'seq 1000 | tr "\n" , | fzf --ellipsis=SNIPSNIP -e -q500', :Enter
|
tmux.send_keys 'seq 1000 | tr "\n" , | fzf --ellipsis=SNIPSNIP -e -q500', :Enter
|
||||||
tmux.until { |lines| assert_equal 1, lines.match_count }
|
tmux.until { |lines| assert_equal 1, lines.match_count }
|
||||||
@@ -2595,12 +2628,16 @@ class TestGoFZF < TestBase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_focus_event
|
def test_focus_event
|
||||||
tmux.send_keys 'seq 100 | fzf --bind "focus:transform-prompt(echo [[{}]])"', :Enter
|
tmux.send_keys 'seq 100 | fzf --bind "focus:transform-prompt(echo [[{}]]),?:unbind(focus)"', :Enter
|
||||||
tmux.until { |lines| assert_includes(lines[-1], '[[1]]') }
|
tmux.until { |lines| assert_includes(lines[-1], '[[1]]') }
|
||||||
tmux.send_keys :Up
|
tmux.send_keys :Up
|
||||||
tmux.until { |lines| assert_includes(lines[-1], '[[2]]') }
|
tmux.until { |lines| assert_includes(lines[-1], '[[2]]') }
|
||||||
tmux.send_keys :X
|
tmux.send_keys :X
|
||||||
tmux.until { |lines| assert_includes(lines[-1], '[[]]') }
|
tmux.until { |lines| assert_includes(lines[-1], '[[]]') }
|
||||||
|
tmux.send_keys '?'
|
||||||
|
tmux.send_keys :BSpace
|
||||||
|
tmux.until { |lines| assert_equal 100, lines.match_count }
|
||||||
|
tmux.until { |lines| refute_includes(lines[-1], '[[1]]') }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_labels_center
|
def test_labels_center
|
||||||
@@ -2866,6 +2903,38 @@ class TestGoFZF < TestBase
|
|||||||
tmux.send_keys "(echo foo; echo bar) | #{FZF} --bind 'load:reload-sync(sleep 60)+change-query(bar)'", :Enter
|
tmux.send_keys "(echo foo; echo bar) | #{FZF} --bind 'load:reload-sync(sleep 60)+change-query(bar)'", :Enter
|
||||||
tmux.until { |lines| assert_equal 1, lines.match_count }
|
tmux.until { |lines| assert_equal 1, lines.match_count }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_reload_and_change_cache
|
||||||
|
tmux.send_keys "echo bar | #{FZF} --bind 'zero:change-header(foo)+reload(echo foo)+clear-query'", :Enter
|
||||||
|
expected = <<~OUTPUT
|
||||||
|
> bar
|
||||||
|
1/1
|
||||||
|
>
|
||||||
|
OUTPUT
|
||||||
|
tmux.until { assert_block(expected, _1) }
|
||||||
|
tmux.send_keys :z
|
||||||
|
expected = <<~OUTPUT
|
||||||
|
> foo
|
||||||
|
foo
|
||||||
|
1/1
|
||||||
|
>
|
||||||
|
OUTPUT
|
||||||
|
tmux.until { assert_block(expected, _1) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_delete_with_modifiers
|
||||||
|
tmux.send_keys "seq 100 | #{FZF} --bind 'ctrl-delete:up+up,shift-delete:down,focus:transform-prompt:echo [{}]'", :Enter
|
||||||
|
tmux.until { |lines| assert_equal 100, lines.item_count }
|
||||||
|
tmux.send_keys 'C-Delete'
|
||||||
|
tmux.until { |lines| assert_equal '[3]', lines[-1] }
|
||||||
|
tmux.send_keys 'S-Delete'
|
||||||
|
tmux.until { |lines| assert_equal '[2]', lines[-1] }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_become_tty
|
||||||
|
tmux.send_keys "sleep 0.5 | #{FZF} --bind 'start:reload:ls' --bind 'load:become:tty'", :Enter
|
||||||
|
tmux.until { |lines| assert_includes lines, '/dev/tty' }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
module TestShell
|
module TestShell
|
||||||
|
|||||||
Reference in New Issue
Block a user