mirror of
https://github.com/Llewellynvdm/fzf.git
synced 2024-06-05 00:40:50 +00:00
Describe become(...) action and use it to simplify examples
This commit is contained in:
parent
4e305eca26
commit
27018787af
131
ADVANCED.md
131
ADVANCED.md
|
@ -1,30 +1,33 @@
|
||||||
Advanced fzf examples
|
Advanced fzf examples
|
||||||
======================
|
======================
|
||||||
|
|
||||||
*(Last update: 2023/02/12)*
|
* *Last update: 2023/02/15*
|
||||||
|
* *Requires fzf 0.38.0 or above*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
<!-- vim-markdown-toc GFM -->
|
<!-- vim-markdown-toc GFM -->
|
||||||
|
|
||||||
* [Introduction](#introduction)
|
* [Introduction](#introduction)
|
||||||
* [Screen Layout](#screen-layout)
|
* [Screen Layout](#screen-layout)
|
||||||
* [`--height`](#--height)
|
* [`--height`](#--height)
|
||||||
* [`fzf-tmux`](#fzf-tmux)
|
* [`fzf-tmux`](#fzf-tmux)
|
||||||
* [Popup window support](#popup-window-support)
|
* [Popup window support](#popup-window-support)
|
||||||
* [Dynamic reloading of the list](#dynamic-reloading-of-the-list)
|
* [Dynamic reloading of the list](#dynamic-reloading-of-the-list)
|
||||||
* [Updating the list of processes by pressing CTRL-R](#updating-the-list-of-processes-by-pressing-ctrl-r)
|
* [Updating the list of processes by pressing CTRL-R](#updating-the-list-of-processes-by-pressing-ctrl-r)
|
||||||
* [Toggling between data sources](#toggling-between-data-sources)
|
* [Toggling between data sources](#toggling-between-data-sources)
|
||||||
* [Ripgrep integration](#ripgrep-integration)
|
* [Ripgrep integration](#ripgrep-integration)
|
||||||
* [Using fzf as the secondary filter](#using-fzf-as-the-secondary-filter)
|
* [Using fzf as the secondary filter](#using-fzf-as-the-secondary-filter)
|
||||||
* [Using fzf as interactive Ripgrep launcher](#using-fzf-as-interactive-ripgrep-launcher)
|
* [Using fzf as interactive Ripgrep launcher](#using-fzf-as-interactive-ripgrep-launcher)
|
||||||
* [Switching to fzf-only search mode](#switching-to-fzf-only-search-mode)
|
* [Switching to fzf-only search mode](#switching-to-fzf-only-search-mode)
|
||||||
* [Switching between Ripgrep mode and fzf mode](#switching-between-ripgrep-mode-and-fzf-mode)
|
* [Switching between Ripgrep mode and fzf mode](#switching-between-ripgrep-mode-and-fzf-mode)
|
||||||
* [Log tailing](#log-tailing)
|
* [Log tailing](#log-tailing)
|
||||||
* [Key bindings for git objects](#key-bindings-for-git-objects)
|
* [Key bindings for git objects](#key-bindings-for-git-objects)
|
||||||
* [Files listed in `git status`](#files-listed-in-git-status)
|
* [Files listed in `git status`](#files-listed-in-git-status)
|
||||||
* [Branches](#branches)
|
* [Branches](#branches)
|
||||||
* [Commit hashes](#commit-hashes)
|
* [Commit hashes](#commit-hashes)
|
||||||
* [Color themes](#color-themes)
|
* [Color themes](#color-themes)
|
||||||
* [Generating fzf color theme from Vim color schemes](#generating-fzf-color-theme-from-vim-color-schemes)
|
* [Generating fzf color theme from Vim color schemes](#generating-fzf-color-theme-from-vim-color-schemes)
|
||||||
|
|
||||||
<!-- vim-markdown-toc -->
|
<!-- vim-markdown-toc -->
|
||||||
|
|
||||||
|
@ -236,15 +239,13 @@ file called `rfv`.
|
||||||
# 1. Search for text in files using Ripgrep
|
# 1. Search for text in files using Ripgrep
|
||||||
# 2. Interactively narrow down the list using fzf
|
# 2. Interactively narrow down the list using fzf
|
||||||
# 3. Open the file in Vim
|
# 3. Open the file in Vim
|
||||||
IFS=: read -ra selected < <(
|
rg --color=always --line-number --no-heading --smart-case "${*:-}" |
|
||||||
rg --color=always --line-number --no-heading --smart-case "${*:-}" |
|
fzf --ansi \
|
||||||
fzf --ansi \
|
--color "hl:-1:underline,hl+:-1:underline:reverse" \
|
||||||
--color "hl:-1:underline,hl+:-1:underline:reverse" \
|
--delimiter : \
|
||||||
--delimiter : \
|
--preview 'bat --color=always {1} --highlight-line {2}' \
|
||||||
--preview 'bat --color=always {1} --highlight-line {2}' \
|
--preview-window 'up,60%,border-bottom,+{2}+3/3,~3' \
|
||||||
--preview-window 'up,60%,border-bottom,+{2}+3/3,~3'
|
--bind 'enter:become(vim {1} +{2})'
|
||||||
)
|
|
||||||
[ -n "${selected[0]}" ] && vim "${selected[0]}" "+${selected[1]}"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
And run it with an initial query string.
|
And run it with an initial query string.
|
||||||
|
@ -307,8 +308,12 @@ I know it's a lot to digest, let's try to break down the code.
|
||||||
position in the window
|
position in the window
|
||||||
- `~3` makes the top three lines fixed header so that they are always
|
- `~3` makes the top three lines fixed header so that they are always
|
||||||
visible regardless of the scroll offset
|
visible regardless of the scroll offset
|
||||||
- Once we selected a line, we open the file with `vim` (`vim
|
- Instead of using shell script to process the final output of fzf, we use
|
||||||
"${selected[0]}"`) and move the cursor to the line (`+${selected[1]}`).
|
`become(...)` action which was added in [fzf 0.38.0][0.38.0] to turn fzf
|
||||||
|
into a new process that opens the file with `vim` (`vim {1}`) and move the
|
||||||
|
cursor to the line (`+{2}`).
|
||||||
|
|
||||||
|
[0.38.0]: https://github.com/junegunn/fzf/blob/master/CHANGELOG.md#0380
|
||||||
|
|
||||||
### Using fzf as interactive Ripgrep launcher
|
### Using fzf as interactive Ripgrep launcher
|
||||||
|
|
||||||
|
@ -331,16 +336,14 @@ 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="${*:-}"
|
||||||
IFS=: read -ra selected < <(
|
FZF_DEFAULT_COMMAND="$RG_PREFIX $(printf %q "$INITIAL_QUERY")" \
|
||||||
FZF_DEFAULT_COMMAND="$RG_PREFIX $(printf %q "$INITIAL_QUERY")" \
|
fzf --ansi \
|
||||||
fzf --ansi \
|
--disabled --query "$INITIAL_QUERY" \
|
||||||
--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}' \
|
--preview-window 'up,60%,border-bottom,+{2}+3/3,~3' \
|
||||||
--preview-window 'up,60%,border-bottom,+{2}+3/3,~3'
|
--bind 'enter:become(vim {1} +{2})'
|
||||||
)
|
|
||||||
[ -n "${selected[0]}" ] && vim "${selected[0]}" "+${selected[1]}"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
![image](https://user-images.githubusercontent.com/700826/113684212-f9ff0a00-96ff-11eb-8737-7bb571d320cc.png)
|
![image](https://user-images.githubusercontent.com/700826/113684212-f9ff0a00-96ff-11eb-8737-7bb571d320cc.png)
|
||||||
|
@ -358,8 +361,6 @@ IFS=: read -ra selected < <(
|
||||||
|
|
||||||
### Switching to fzf-only search mode
|
### Switching to fzf-only search mode
|
||||||
|
|
||||||
*(Requires fzf 0.27.1 or above)*
|
|
||||||
|
|
||||||
In the previous example, we lost fuzzy matching capability as we completely
|
In the previous example, we lost fuzzy matching capability as we completely
|
||||||
delegated search functionality to Ripgrep. But we can dynamically switch to
|
delegated search functionality to Ripgrep. But we can dynamically switch to
|
||||||
fzf-only search mode by *"unbinding"* `reload` action from `change` event.
|
fzf-only search mode by *"unbinding"* `reload` action from `change` event.
|
||||||
|
@ -375,19 +376,17 @@ 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="${*:-}"
|
||||||
IFS=: read -ra selected < <(
|
FZF_DEFAULT_COMMAND="$RG_PREFIX $(printf %q "$INITIAL_QUERY")" \
|
||||||
FZF_DEFAULT_COMMAND="$RG_PREFIX $(printf %q "$INITIAL_QUERY")" \
|
fzf --ansi \
|
||||||
fzf --ansi \
|
--color "hl:-1:underline,hl+:-1:underline:reverse" \
|
||||||
--color "hl:-1:underline,hl+:-1:underline:reverse" \
|
--disabled --query "$INITIAL_QUERY" \
|
||||||
--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" \
|
--prompt '1. ripgrep> ' \
|
||||||
--prompt '1. ripgrep> ' \
|
--delimiter : \
|
||||||
--delimiter : \
|
--preview 'bat --color=always {1} --highlight-line {2}' \
|
||||||
--preview 'bat --color=always {1} --highlight-line {2}' \
|
--preview-window 'up,60%,border-bottom,+{2}+3/3,~3' \
|
||||||
--preview-window 'up,60%,border-bottom,+{2}+3/3,~3'
|
--bind 'enter:become(vim {1} +{2})'
|
||||||
)
|
|
||||||
[ -n "${selected[0]}" ] && vim "${selected[0]}" "+${selected[1]}"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
* Phase 1. Filtering with Ripgrep
|
* Phase 1. Filtering with Ripgrep
|
||||||
|
@ -408,8 +407,6 @@ IFS=: read -ra selected < <(
|
||||||
|
|
||||||
### Switching between Ripgrep mode and fzf mode
|
### Switching between Ripgrep mode and fzf mode
|
||||||
|
|
||||||
*(Requires fzf 0.36.0 or above)*
|
|
||||||
|
|
||||||
[fzf 0.30.0][0.30.0] added `rebind` action so we can "rebind" the bindings
|
[fzf 0.30.0][0.30.0] added `rebind` action so we can "rebind" the bindings
|
||||||
that were previously "unbound" via `unbind`.
|
that were previously "unbound" via `unbind`.
|
||||||
|
|
||||||
|
@ -424,22 +421,20 @@ 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="${*:-}"
|
||||||
IFS=: read -ra selected < <(
|
FZF_DEFAULT_COMMAND="$RG_PREFIX $(printf %q "$INITIAL_QUERY")" \
|
||||||
FZF_DEFAULT_COMMAND="$RG_PREFIX $(printf %q "$INITIAL_QUERY")" \
|
fzf --ansi \
|
||||||
fzf --ansi \
|
--color "hl:-1:underline,hl+:-1:underline:reverse" \
|
||||||
--color "hl:-1:underline,hl+:-1:underline:reverse" \
|
--disabled --query "$INITIAL_QUERY" \
|
||||||
--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)" \
|
||||||
--bind "start:unbind(ctrl-r)" \
|
--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) ╱' \
|
--preview 'bat --color=always {1} --highlight-line {2}' \
|
||||||
--preview 'bat --color=always {1} --highlight-line {2}' \
|
--preview-window 'up,60%,border-bottom,+{2}+3/3,~3' \
|
||||||
--preview-window 'up,60%,border-bottom,+{2}+3/3,~3'
|
--bind 'enter:become(vim {1} +{2})'
|
||||||
)
|
|
||||||
[ -n "${selected[0]}" ] && vim "${selected[0]}" "+${selected[1]}"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
- To restore the query string when switching between modes, we store the
|
- To restore the query string when switching between modes, we store the
|
||||||
|
|
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -5,12 +5,12 @@ CHANGELOG
|
||||||
------
|
------
|
||||||
- New actions
|
- New actions
|
||||||
- `become(...)` - Replace the current fzf process with the specified
|
- `become(...)` - Replace the current fzf process with the specified
|
||||||
command using `execve(2)` system call. This action enables a simpler
|
command using `execve(2)` system call.
|
||||||
alternative to using `--expect` and checking the output in the wrapping
|
See https://github.com/junegunn/fzf#turning-into-a-different-process.
|
||||||
script.
|
|
||||||
```sh
|
```sh
|
||||||
# Open selected files in different editors
|
# Open the file in Vim and go to the line
|
||||||
fzf --multi --bind 'enter:become($EDITOR {+}),ctrl-n:become(nano {+})'
|
git grep --line-number . |
|
||||||
|
fzf --delimiter : --nth 3.. --bind 'enter:become(vim {1} +{2})'
|
||||||
```
|
```
|
||||||
- This action is not supported on Windows
|
- This action is not supported on Windows
|
||||||
- `show-preview`
|
- `show-preview`
|
||||||
|
|
58
README.md
58
README.md
|
@ -54,6 +54,7 @@ Table of Contents
|
||||||
* [Advanced topics](#advanced-topics)
|
* [Advanced topics](#advanced-topics)
|
||||||
* [Performance](#performance)
|
* [Performance](#performance)
|
||||||
* [Executing external programs](#executing-external-programs)
|
* [Executing external programs](#executing-external-programs)
|
||||||
|
* [Turning into a different process](#turning-into-a-different-process)
|
||||||
* [Reloading the candidate list](#reloading-the-candidate-list)
|
* [Reloading the candidate list](#reloading-the-candidate-list)
|
||||||
* [1. Update the list of processes by pressing CTRL-R](#1-update-the-list-of-processes-by-pressing-ctrl-r)
|
* [1. Update the list of processes by pressing CTRL-R](#1-update-the-list-of-processes-by-pressing-ctrl-r)
|
||||||
* [2. Switch between sources by pressing CTRL-D or CTRL-F](#2-switch-between-sources-by-pressing-ctrl-d-or-ctrl-f)
|
* [2. Switch between sources by pressing CTRL-D or CTRL-F](#2-switch-between-sources-by-pressing-ctrl-d-or-ctrl-f)
|
||||||
|
@ -204,6 +205,22 @@ files excluding hidden ones. (You can override the default command with
|
||||||
vim $(fzf)
|
vim $(fzf)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> *:bulb: A more robust solution would be to use `xargs` but we've presented
|
||||||
|
> the above as it's easier to grasp*
|
||||||
|
> ```sh
|
||||||
|
> fzf --print0 | xargs -0 -o vim
|
||||||
|
> ```
|
||||||
|
|
||||||
|
>
|
||||||
|
> *:bulb: fzf also has the ability to turn itself into a different process.*
|
||||||
|
>
|
||||||
|
> ```sh
|
||||||
|
> fzf --bind 'enter:become(vim {})'
|
||||||
|
> ```
|
||||||
|
>
|
||||||
|
> *See [Turning into a different process](#turning-into-a-different-process)
|
||||||
|
> for more information.*
|
||||||
|
|
||||||
### Using the finder
|
### Using the finder
|
||||||
|
|
||||||
- `CTRL-K` / `CTRL-J` (or `CTRL-P` / `CTRL-N`) to move cursor up and down
|
- `CTRL-K` / `CTRL-J` (or `CTRL-P` / `CTRL-N`) to move cursor up and down
|
||||||
|
@ -562,6 +579,47 @@ fzf --bind 'f1:execute(less -f {}),ctrl-y:execute-silent(echo {} | pbcopy)+abort
|
||||||
|
|
||||||
See *KEY BINDINGS* section of the man page for details.
|
See *KEY BINDINGS* section of the man page for details.
|
||||||
|
|
||||||
|
### Turning into a different process
|
||||||
|
|
||||||
|
`become(...)` is similar to `execute(...)`/`execute-silent(...)` described
|
||||||
|
above, but instead of executing the command and coming back to fzf on
|
||||||
|
complete, it turns fzf into a new process for the command.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
fzf --bind 'enter:become(vim {})'
|
||||||
|
```
|
||||||
|
|
||||||
|
Compared to the seemingly equivalent command substitution `vim "$(fzf)"`, this
|
||||||
|
approach has several advantages:
|
||||||
|
|
||||||
|
* Vim will not open an empty file when you terminate fzf with
|
||||||
|
<kbd>CTRL-C</kbd>
|
||||||
|
* Vim will not open an empty file when you press <kbd>ENTER</kbd> on an empty
|
||||||
|
result
|
||||||
|
* Can handle multiple selections even when they have whitespaces
|
||||||
|
```sh
|
||||||
|
fzf --multi --bind 'enter:become(vim {+})'
|
||||||
|
```
|
||||||
|
|
||||||
|
To be fair, running `fzf --print0 | xargs -0 -o vim` instead of `vim "$(fzf)"`
|
||||||
|
resolves all of the issues mentioned. Nonetheless, `become(...)` still offers
|
||||||
|
additional benefits in different scenarios.
|
||||||
|
|
||||||
|
* You can set up multiple bindings to handle the result in different ways
|
||||||
|
without any wrapping script
|
||||||
|
```sh
|
||||||
|
fzf --bind 'enter:become(vim {}),ctrl-e:become(emacs {})'
|
||||||
|
```
|
||||||
|
* Previously, you would have to use `--expect=ctrl-e` and check the first
|
||||||
|
line of the output of fzf
|
||||||
|
* You can easily build the subsequent command using the field index
|
||||||
|
expressions of fzf
|
||||||
|
```sh
|
||||||
|
# Open the file in Vim and go to the line
|
||||||
|
git grep --line-number . |
|
||||||
|
fzf --delimiter : --nth 3.. --bind 'enter:become(vim {1} +{2})'
|
||||||
|
```
|
||||||
|
|
||||||
### Reloading the candidate list
|
### Reloading the candidate list
|
||||||
|
|
||||||
By binding `reload` action to a key or an event, you can make fzf dynamically
|
By binding `reload` action to a key or an event, you can make fzf dynamically
|
||||||
|
|
Loading…
Reference in New Issue
Block a user