mirror of
https://github.com/junegunn/fzf.git
synced 2025-11-12 21:33:49 -05:00
Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2ae1b249c | ||
|
|
92b7efafca | ||
|
|
f092e4038f | ||
|
|
aa5dae391b | ||
|
|
08a6fd4ad4 | ||
|
|
a61150a96c | ||
|
|
0f9cb5590e | ||
|
|
c0a83b27eb | ||
|
|
f79b1f71b8 | ||
|
|
8e027c445f | ||
|
|
dda3e3c39a | ||
|
|
fd5157998c | ||
|
|
e0217e8c79 | ||
|
|
3ab1c42266 | ||
|
|
d1676776aa | ||
|
|
bdde69d011 | ||
|
|
6dec42a33a | ||
|
|
199bc3f0ad | ||
|
|
17dd833925 | ||
|
|
4ec144c969 | ||
|
|
3e36f2b0ac | ||
|
|
07a03b3e73 | ||
|
|
c33258832e | ||
|
|
a7aa08ce07 | ||
|
|
06d63a862e | ||
|
|
43d1c4c4b5 | ||
|
|
f81feb1e69 | ||
|
|
01cf01e084 | ||
|
|
97a725fbd0 | ||
|
|
ace92ba281 | ||
|
|
d631c76e8d | ||
|
|
e6d33f77da | ||
|
|
a6d3e3687b | ||
|
|
08c2bcb952 | ||
|
|
98ca4bdede | ||
|
|
3f8e741562 | ||
|
|
6e464ebd9b | ||
|
|
c329279339 | ||
|
|
cf04753ad7 | ||
|
|
69e7eab11f | ||
|
|
dea206b023 | ||
|
|
5deaf58928 | ||
|
|
15e2952a2b | ||
|
|
a9fba1c849 | ||
|
|
71e573d082 |
24
.rubocop.yml
Normal file
24
.rubocop.yml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
Layout/LineLength:
|
||||||
|
Enabled: false
|
||||||
|
Metrics:
|
||||||
|
Enabled: false
|
||||||
|
Lint/ShadowingOuterLocalVariable:
|
||||||
|
Enabled: false
|
||||||
|
Style/MethodCallWithArgsParentheses:
|
||||||
|
Enabled: true
|
||||||
|
IgnoredMethods:
|
||||||
|
- assert
|
||||||
|
- exit
|
||||||
|
- paste
|
||||||
|
- puts
|
||||||
|
- raise
|
||||||
|
- refute
|
||||||
|
- require
|
||||||
|
- send_keys
|
||||||
|
IgnoredPatterns:
|
||||||
|
- ^assert_
|
||||||
|
- ^refute_
|
||||||
|
Style/NumericPredicate:
|
||||||
|
Enabled: false
|
||||||
|
Style/WordArray:
|
||||||
|
MinSize: 1
|
||||||
@@ -1,22 +1,28 @@
|
|||||||
language: go
|
language: go
|
||||||
|
go:
|
||||||
|
- "1.14"
|
||||||
env: GO111MODULE=on
|
env: GO111MODULE=on
|
||||||
os:
|
os:
|
||||||
- linux
|
- linux
|
||||||
- osx
|
- osx
|
||||||
dist: bionic # For fish >= 2.3.0 string builtin
|
dist: bionic
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
- fish
|
- fish
|
||||||
- zsh
|
- zsh
|
||||||
|
sources:
|
||||||
|
sourceline: ppa:fish-shell/release-3
|
||||||
homebrew:
|
homebrew:
|
||||||
packages:
|
packages:
|
||||||
- fish
|
- fish
|
||||||
- tmux
|
- tmux
|
||||||
update: true
|
update: true
|
||||||
|
install: gem install minitest rubocop rubocop-minitest rubocop-performance
|
||||||
script:
|
script:
|
||||||
- make test
|
- make test
|
||||||
# LC_ALL=C to avoid escape codes in
|
# LC_ALL=C to avoid escape codes in
|
||||||
# printf %q $'\355\205\214\354\212\244\355\212\270' on macOS. Bash on
|
# printf %q $'\355\205\214\354\212\244\355\212\270' on macOS. Bash on
|
||||||
# macOS is built without HANDLE_MULTIBYTE?
|
# macOS is built without HANDLE_MULTIBYTE?
|
||||||
- make install && ./install --all && LC_ALL=C tmux new-session -d && ruby test/test_go.rb --verbose
|
- make install && ./install --all && LC_ALL=C tmux new-session -d && ruby test/test_go.rb --verbose
|
||||||
|
- rubocop --require rubocop-minitest --require rubocop-performance
|
||||||
|
|||||||
43
CHANGELOG.md
43
CHANGELOG.md
@@ -1,6 +1,49 @@
|
|||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
0.22.0
|
||||||
|
------
|
||||||
|
- Added more options for `--bind`
|
||||||
|
- `backward-eof` event
|
||||||
|
```sh
|
||||||
|
# Aborts when you delete backward when the query prompt is already empty
|
||||||
|
fzf --bind backward-eof:abort
|
||||||
|
```
|
||||||
|
- `refresh-preview` action
|
||||||
|
```sh
|
||||||
|
# Rerun preview command when you hit '?'
|
||||||
|
fzf --preview 'echo $RANDOM' --bind '?:refresh-preview'
|
||||||
|
```
|
||||||
|
- `preview` action
|
||||||
|
```sh
|
||||||
|
# Default preview command with an extra preview binding
|
||||||
|
fzf --preview 'file {}' --bind '?:preview:cat {}'
|
||||||
|
|
||||||
|
# A preview binding with no default preview command
|
||||||
|
# (Preview window is initially empty)
|
||||||
|
fzf --bind '?:preview:cat {}'
|
||||||
|
|
||||||
|
# Preview window hidden by default, it appears when you first hit '?'
|
||||||
|
fzf --bind '?:preview:cat {}' --preview-window hidden
|
||||||
|
```
|
||||||
|
- Added preview window option for setting the initial scroll offset
|
||||||
|
```sh
|
||||||
|
# Initial scroll offset is set to the line number of each line of
|
||||||
|
# git grep output *minus* 5 lines
|
||||||
|
git grep --line-number '' |
|
||||||
|
fzf --delimiter : --preview 'nl {1}' --preview-window +{2}-5
|
||||||
|
```
|
||||||
|
- Added support for ANSI colors in `--prompt` string
|
||||||
|
- Smart match of accented characters
|
||||||
|
- An unaccented character in the query string will match both accented and
|
||||||
|
unaccented characters, while an accented character will only match
|
||||||
|
accented characters. This is similar to how "smart-case" match works.
|
||||||
|
- Vim plugin
|
||||||
|
- `tmux` layout option for using fzf-tmux
|
||||||
|
```vim
|
||||||
|
let g:fzf_layout = { 'tmux': '-p90%,60%' }
|
||||||
|
```
|
||||||
|
|
||||||
0.21.1
|
0.21.1
|
||||||
------
|
------
|
||||||
- Shell extension
|
- Shell extension
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -6,7 +6,7 @@ ROOT_DIR := $(shell dirname $(MAKEFILE))
|
|||||||
SOURCES := $(wildcard *.go src/*.go src/*/*.go) $(MAKEFILE)
|
SOURCES := $(wildcard *.go src/*.go src/*/*.go) $(MAKEFILE)
|
||||||
|
|
||||||
REVISION := $(shell git log -n 1 --pretty=format:%h -- $(SOURCES))
|
REVISION := $(shell git log -n 1 --pretty=format:%h -- $(SOURCES))
|
||||||
BUILD_FLAGS := -a -ldflags "-X main.revision=$(REVISION) -w -extldflags=$(LDFLAGS)" -tags "$(TAGS)"
|
BUILD_FLAGS := -a -ldflags "-X main.revision=$(REVISION) -w '-extldflags=$(LDFLAGS)'" -tags "$(TAGS)"
|
||||||
|
|
||||||
BINARY32 := fzf-$(GOOS)_386
|
BINARY32 := fzf-$(GOOS)_386
|
||||||
BINARY64 := fzf-$(GOOS)_amd64
|
BINARY64 := fzf-$(GOOS)_amd64
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ let g:fzf_action = {
|
|||||||
|
|
||||||
" Default fzf layout
|
" Default fzf layout
|
||||||
" - down / up / left / right
|
" - down / up / left / right
|
||||||
let g:fzf_layout = { 'down': '~40%' }
|
let g:fzf_layout = { 'down': '40%' }
|
||||||
|
|
||||||
" You can set up fzf window using a Vim command (Neovim or latest Vim 8 required)
|
" You can set up fzf window using a Vim command (Neovim or latest Vim 8 required)
|
||||||
let g:fzf_layout = { 'window': 'enew' }
|
let g:fzf_layout = { 'window': 'enew' }
|
||||||
@@ -274,6 +274,7 @@ The following table summarizes the available options.
|
|||||||
| `options` | string/list | Options to fzf |
|
| `options` | string/list | Options to fzf |
|
||||||
| `dir` | string | Working directory |
|
| `dir` | string | Working directory |
|
||||||
| `up`/`down`/`left`/`right` | number/string | (Layout) Window position and size (e.g. `20`, `50%`) |
|
| `up`/`down`/`left`/`right` | number/string | (Layout) Window position and size (e.g. `20`, `50%`) |
|
||||||
|
| `tmux` | string | (Layout) fzf-tmux options (e.g. `-p90%,60%`) |
|
||||||
| `window` (Vim 8 / Neovim) | string | (Layout) Command to open fzf window (e.g. `vertical aboveleft 30new`) |
|
| `window` (Vim 8 / Neovim) | string | (Layout) Command to open fzf window (e.g. `vertical aboveleft 30new`) |
|
||||||
| `window` (Vim 8 / Neovim) | dict | (Layout) Popup window settings (e.g. `{'width': 0.9, 'height': 0.6}`) |
|
| `window` (Vim 8 / Neovim) | dict | (Layout) Popup window settings (e.g. `{'width': 0.9, 'height': 0.6}`) |
|
||||||
|
|
||||||
@@ -397,13 +398,25 @@ The latest versions of Vim and Neovim include builtin terminal emulator
|
|||||||
let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
|
let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Alternatively, you can make fzf open in a tmux popup window (requires tmux 3.2
|
||||||
|
or above) by putting fzf-tmux options in `tmux` key.
|
||||||
|
|
||||||
|
```vim
|
||||||
|
" See `man fzf-tmux` for available options
|
||||||
|
if exists('$TMUX')
|
||||||
|
let g:fzf_layout = { 'tmux': '-p90%,60%' }
|
||||||
|
else
|
||||||
|
let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
|
||||||
|
endif
|
||||||
|
```
|
||||||
|
|
||||||
#### Hide statusline
|
#### Hide statusline
|
||||||
|
|
||||||
When fzf starts in a terminal buffer, the file type of the buffer is set to
|
When fzf starts in a terminal buffer, the file type of the buffer is set to
|
||||||
`fzf`. So you can set up `FileType fzf` autocmd to customize the settings of
|
`fzf`. So you can set up `FileType fzf` autocmd to customize the settings of
|
||||||
the window.
|
the window.
|
||||||
|
|
||||||
For example, if you use the default layout (`{'down': '~40%'}`) on Neovim, you
|
For example, if you use the default layout (`{'down': '40%'}`) on Neovim, you
|
||||||
might want to temporarily disable the statusline for a cleaner look.
|
might want to temporarily disable the statusline for a cleaner look.
|
||||||
|
|
||||||
```vim
|
```vim
|
||||||
|
|||||||
40
README.md
40
README.md
@@ -104,16 +104,18 @@ git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
|
|||||||
|
|
||||||
### Using Linux package managers
|
### Using Linux package managers
|
||||||
|
|
||||||
| Distro | Command |
|
| Package Manager | Linux Distribution | Command |
|
||||||
| --- | --- |
|
| --- | --- | --- |
|
||||||
| Alpine Linux | `sudo apk add fzf` |
|
| APK | Alpine Linux | `sudo apk add fzf` |
|
||||||
| Arch Linux | `sudo pacman -S fzf` |
|
| APT | Debian 9+/Ubuntu 19.10+ | `sudo apt-get install fzf` |
|
||||||
| Debian | `sudo apt-get install fzf` |
|
| Conda | | `conda install -c conda-forge fzf` |
|
||||||
| Fedora | `sudo dnf install fzf` |
|
| DNF | Fedora | `sudo dnf install fzf` |
|
||||||
| FreeBSD | `pkg install fzf` |
|
| Nix | NixOS, etc. | `nix-env -iA nixpkgs.fzf` |
|
||||||
| NixOS | `nix-env -iA nixpkgs.fzf` |
|
| Pacman | Arch Linux | `sudo pacman -S fzf` |
|
||||||
| openSUSE | `sudo zypper install fzf` |
|
| pkg | FreeBSD | `pkg install fzf` |
|
||||||
| OpenBSD | `pkg_add fzf` |
|
| pkg_add | OpenBSD | `pkg_add fzf` |
|
||||||
|
| XBPS | Void Linux | `sudo xbps-install -S fzf` |
|
||||||
|
| Zypper | openSUSE | `sudo zypper install fzf` |
|
||||||
|
|
||||||
Shell extensions (key bindings and fuzzy auto-completion) and Vim/Neovim
|
Shell extensions (key bindings and fuzzy auto-completion) and Vim/Neovim
|
||||||
plugin may or may not be enabled by default depending on the package manager.
|
plugin may or may not be enabled by default depending on the package manager.
|
||||||
@@ -528,9 +530,10 @@ See *KEY BINDINGS* section of the man page for details.
|
|||||||
|
|
||||||
### Preview window
|
### Preview window
|
||||||
|
|
||||||
When `--preview` option is set, fzf automatically starts an external process with
|
When the `--preview` option is set, fzf automatically starts an external process
|
||||||
the current line as the argument and shows the result in the split window. Your
|
with the current line as the argument and shows the result in the split window.
|
||||||
`$SHELL` is used to execute the command with `$SHELL -c COMMAND`.
|
Your `$SHELL` is used to execute the command with `$SHELL -c COMMAND`.
|
||||||
|
The window can be scrolled using the mouse or custom key bindings.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# {} is replaced to the single-quoted string of the focused line
|
# {} is replaced to the single-quoted string of the focused line
|
||||||
@@ -546,13 +549,12 @@ fzf --preview 'head -100 {}'
|
|||||||
```
|
```
|
||||||
|
|
||||||
Preview window supports ANSI colors, so you can use any program that
|
Preview window supports ANSI colors, so you can use any program that
|
||||||
syntax-highlights the content of a file.
|
syntax-highlights the content of a file, such as
|
||||||
|
[Bat](https://github.com/sharkdp/bat) or
|
||||||
- Bat: https://github.com/sharkdp/bat
|
[Highlight](http://www.andre-simon.de/doku/highlight/en/highlight.php):
|
||||||
- Highlight: http://www.andre-simon.de/doku/highlight/en/highlight.php
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
fzf --preview 'bat --style=numbers --color=always {} | head -500'
|
fzf --preview 'bat --style=numbers --color=always --line-range :500 {}'
|
||||||
```
|
```
|
||||||
|
|
||||||
You can customize the size, position, and border of the preview window using
|
You can customize the size, position, and border of the preview window using
|
||||||
@@ -581,7 +583,7 @@ not a good idea to add `--preview` option to your `$FZF_DEFAULT_OPTS`**.
|
|||||||
# *********************
|
# *********************
|
||||||
# ** DO NOT DO THIS! **
|
# ** DO NOT DO THIS! **
|
||||||
# *********************
|
# *********************
|
||||||
export FZF_DEFAULT_OPTS='--preview "bat --style=numbers --color=always {} | head -500"'
|
export FZF_DEFAULT_OPTS='--preview "bat --style=numbers --color=always --line-range :500 {}"'
|
||||||
|
|
||||||
# bat doesn't work with any input other than the list of files
|
# bat doesn't work with any input other than the list of files
|
||||||
ps -ef | fzf
|
ps -ef | fzf
|
||||||
|
|||||||
12
bin/fzf-tmux
12
bin/fzf-tmux
@@ -77,7 +77,7 @@ while [[ $# -gt 0 ]]; do
|
|||||||
if [[ ${#arg} -gt 2 ]]; then
|
if [[ ${#arg} -gt 2 ]]; then
|
||||||
size="${arg:2}"
|
size="${arg:2}"
|
||||||
else
|
else
|
||||||
if [[ "$1" =~ ^[0-9%,C]+$ ]]; then
|
if [[ "$1" =~ ^[0-9%,]+$ ]] || [[ "$1" =~ ^[A-Z]$ ]]; then
|
||||||
size="$1"
|
size="$1"
|
||||||
shift
|
shift
|
||||||
else
|
else
|
||||||
@@ -138,9 +138,9 @@ fi
|
|||||||
# --height option is not allowed
|
# --height option is not allowed
|
||||||
args=("--no-height" "${args[@]}")
|
args=("--no-height" "${args[@]}")
|
||||||
|
|
||||||
# Handle zoomed tmux pane by moving it to a temp window
|
# Handle zoomed tmux pane without popup options by moving it to a temp window
|
||||||
if tmux list-panes -F '#F' | grep -q Z; then
|
if [[ ! "$opt" =~ "-K -E" ]] && tmux list-panes -F '#F' | grep -q Z; then
|
||||||
zoomed=1
|
zoomed_without_popup=1
|
||||||
original_window=$(tmux display-message -p "#{window_id}")
|
original_window=$(tmux display-message -p "#{window_id}")
|
||||||
tmp_window=$(tmux new-window -d -P -F "#{window_id}" "bash -c 'while :; do for c in \\| / - '\\;' do sleep 0.2; printf \"\\r\$c fzf-tmux is running\\r\"; done; done'")
|
tmp_window=$(tmux new-window -d -P -F "#{window_id}" "bash -c 'while :; do for c in \\| / - '\\;' do sleep 0.2; printf \"\\r\$c fzf-tmux is running\\r\"; done; done'")
|
||||||
tmux swap-pane -t $tmp_window \; select-window -t $tmp_window
|
tmux swap-pane -t $tmp_window \; select-window -t $tmp_window
|
||||||
@@ -162,8 +162,8 @@ cleanup() {
|
|||||||
eval "tmux ${tmux_win_opts[@]}"
|
eval "tmux ${tmux_win_opts[@]}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Remove temp window if we were zoomed
|
# Remove temp window if we were zoomed without popup options
|
||||||
if [[ -n "$zoomed" ]]; then
|
if [[ -n "$zoomed_without_popup" ]]; then
|
||||||
tmux display-message -p "#{window_id}" > /dev/null
|
tmux display-message -p "#{window_id}" > /dev/null
|
||||||
tmux swap-pane -t $original_window \; \
|
tmux swap-pane -t $original_window \; \
|
||||||
select-window -t $original_window \; \
|
select-window -t $original_window \; \
|
||||||
|
|||||||
104
doc/fzf.txt
104
doc/fzf.txt
@@ -1,12 +1,14 @@
|
|||||||
fzf.txt fzf Last change: February 14 2020
|
fzf.txt fzf Last change: April 4 2020
|
||||||
FZF - TABLE OF CONTENTS *fzf* *fzf-toc*
|
FZF - TABLE OF CONTENTS *fzf* *fzf-toc*
|
||||||
==============================================================================
|
==============================================================================
|
||||||
|
|
||||||
FZF Vim integration
|
FZF Vim integration
|
||||||
|
Installation
|
||||||
Summary
|
Summary
|
||||||
:FZF[!]
|
:FZF[!]
|
||||||
Configuration
|
Configuration
|
||||||
Examples
|
Examples
|
||||||
|
Explanation of g:fzf_colors
|
||||||
fzf#run
|
fzf#run
|
||||||
fzf#wrap
|
fzf#wrap
|
||||||
Tips
|
Tips
|
||||||
@@ -19,6 +21,46 @@ FZF VIM INTEGRATION *fzf-vim-integration*
|
|||||||
==============================================================================
|
==============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
INSTALLATION *fzf-installation*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
Once you have fzf installed, you can enable it inside Vim simply by adding the
|
||||||
|
directory to 'runtimepath' in your Vim configuration file. The path may differ
|
||||||
|
depending on the package manager.
|
||||||
|
>
|
||||||
|
" If installed using Homebrew
|
||||||
|
set rtp+=/usr/local/opt/fzf
|
||||||
|
|
||||||
|
" If installed using git
|
||||||
|
set rtp+=~/.fzf
|
||||||
|
<
|
||||||
|
If you use {vim-plug}{1}, the same can be written as:
|
||||||
|
>
|
||||||
|
" If installed using Homebrew
|
||||||
|
Plug '/usr/local/opt/fzf'
|
||||||
|
|
||||||
|
" If installed using git
|
||||||
|
Plug '~/.fzf'
|
||||||
|
<
|
||||||
|
But if you want the latest Vim plugin file from GitHub rather than the one
|
||||||
|
included in the package, write:
|
||||||
|
>
|
||||||
|
Plug 'junegunn/fzf'
|
||||||
|
<
|
||||||
|
The Vim plugin will pick up fzf binary available on the system. If fzf is not
|
||||||
|
found on `$PATH`, it will ask you if it should download the latest binary for
|
||||||
|
you.
|
||||||
|
|
||||||
|
To make sure that you have the latest version of the binary, set up
|
||||||
|
post-update hook like so:
|
||||||
|
|
||||||
|
*fzf#install*
|
||||||
|
>
|
||||||
|
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
|
||||||
|
<
|
||||||
|
{1} https://github.com/junegunn/vim-plug
|
||||||
|
|
||||||
|
|
||||||
SUMMARY *fzf-summary*
|
SUMMARY *fzf-summary*
|
||||||
==============================================================================
|
==============================================================================
|
||||||
|
|
||||||
@@ -38,12 +80,12 @@ the basic file selector command built on top of them.
|
|||||||
- Basic fuzzy file selector
|
- Basic fuzzy file selector
|
||||||
- A reference implementation for those who don't want to write VimScript to
|
- A reference implementation for those who don't want to write VimScript to
|
||||||
implement custom commands
|
implement custom commands
|
||||||
- If you're looking for more such commands, check out {fzf.vim}{1} project.
|
- If you're looking for more such commands, check out {fzf.vim}{2} project.
|
||||||
|
|
||||||
The most important of all is `fzf#run`, but it would be easier to understand
|
The most important of all is `fzf#run`, but it would be easier to understand
|
||||||
the whole if we start off with `:FZF` command.
|
the whole if we start off with `:FZF` command.
|
||||||
|
|
||||||
{1} https://github.com/junegunn/fzf.vim
|
{2} https://github.com/junegunn/fzf.vim
|
||||||
|
|
||||||
|
|
||||||
:FZF[!]
|
:FZF[!]
|
||||||
@@ -144,6 +186,51 @@ Examples~
|
|||||||
let g:fzf_history_dir = '~/.local/share/fzf-history'
|
let g:fzf_history_dir = '~/.local/share/fzf-history'
|
||||||
<
|
<
|
||||||
|
|
||||||
|
Explanation of g:fzf_colors~
|
||||||
|
*fzf-explanation-of-gfzfcolors*
|
||||||
|
|
||||||
|
`g:fzf_colors` is a dictionary mapping fzf elements to a color specification
|
||||||
|
list:
|
||||||
|
>
|
||||||
|
element: [ component, group1 [, group2, ...] ]
|
||||||
|
<
|
||||||
|
- `element` is an fzf element to apply a color to:
|
||||||
|
|
||||||
|
----------------------+------------------------------------------------------
|
||||||
|
Element | Description ~
|
||||||
|
----------------------+------------------------------------------------------
|
||||||
|
`fg` / `bg` / `hl` | Item (foreground / background / highlight)
|
||||||
|
`fg+` / `bg+` / `hl+` | Current item (foreground / background / highlight)
|
||||||
|
`hl` / `hl+` | Highlighted substrings (normal / current)
|
||||||
|
`gutter` | Background of the gutter on the left
|
||||||
|
`pointer` | Pointer to the current line ( `>` )
|
||||||
|
`marker` | Multi-select marker ( `>` )
|
||||||
|
`border` | Border around the window ( `--border` and `--preview` )
|
||||||
|
`header` | Header ( `--header` or `--header-lines` )
|
||||||
|
`info` | Info line (match counters)
|
||||||
|
`spinner` | Streaming input indicator
|
||||||
|
`prompt` | Prompt before query ( `> ` )
|
||||||
|
----------------------+------------------------------------------------------
|
||||||
|
- `component` specifies the component (`fg` / `bg`) from which to extract the
|
||||||
|
color when considering each of the following highlight groups
|
||||||
|
- `group1 [, group2, ...]` is a list of highlight groups that are searched (in
|
||||||
|
order) for a matching color definition
|
||||||
|
|
||||||
|
For example, consider the following specification:
|
||||||
|
>
|
||||||
|
'prompt': ['fg', 'Conditional', 'Comment'],
|
||||||
|
<
|
||||||
|
This means we color the prompt - using the `fg` attribute of the `Conditional`
|
||||||
|
if it exists, - otherwise use the `fg` attribute of the `Comment` highlight
|
||||||
|
group if it exists, - otherwise fall back to the default color settings for
|
||||||
|
the prompt.
|
||||||
|
|
||||||
|
You can examine the color option generated according the setting by printing
|
||||||
|
the result of `fzf#wrap()` function like so:
|
||||||
|
>
|
||||||
|
:echo fzf#wrap()
|
||||||
|
<
|
||||||
|
|
||||||
FZF#RUN
|
FZF#RUN
|
||||||
==============================================================================
|
==============================================================================
|
||||||
|
|
||||||
@@ -203,6 +290,7 @@ The following table summarizes the available options.
|
|||||||
`options` | string/list | Options to fzf
|
`options` | string/list | Options to fzf
|
||||||
`dir` | string | Working directory
|
`dir` | string | Working directory
|
||||||
`up` / `down` / `left` / `right` | number/string | (Layout) Window position and size (e.g. `20` , `50%` )
|
`up` / `down` / `left` / `right` | number/string | (Layout) Window position and size (e.g. `20` , `50%` )
|
||||||
|
`tmux` | string | (Layout) fzf-tmux options (e.g. `-p90%,60%` )
|
||||||
`window` (Vim 8 / Neovim) | string | (Layout) Command to open fzf window (e.g. `vertical aboveleft 30new` )
|
`window` (Vim 8 / Neovim) | string | (Layout) Command to open fzf window (e.g. `vertical aboveleft 30new` )
|
||||||
`window` (Vim 8 / Neovim) | dict | (Layout) Popup window settings (e.g. `{'width': 0.9, 'height': 0.6}` )
|
`window` (Vim 8 / Neovim) | dict | (Layout) Popup window settings (e.g. `{'width': 0.9, 'height': 0.6}` )
|
||||||
---------------------------+---------------+----------------------------------------------------------------------
|
---------------------------+---------------+----------------------------------------------------------------------
|
||||||
@@ -320,6 +408,16 @@ Starting fzf in a popup window~
|
|||||||
" - 'rounded' / 'sharp' / 'horizontal' / 'vertical' / 'top' / 'bottom' / 'left' / 'right'
|
" - 'rounded' / 'sharp' / 'horizontal' / 'vertical' / 'top' / 'bottom' / 'left' / 'right'
|
||||||
let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
|
let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
|
||||||
<
|
<
|
||||||
|
Alternatively, you can make fzf open in a tmux popup window (requires tmux 3.2
|
||||||
|
or above) by putting fzf-tmux options in `tmux` key.
|
||||||
|
>
|
||||||
|
" See `man fzf-tmux` for available options
|
||||||
|
if exists('$TMUX')
|
||||||
|
let g:fzf_layout = { 'tmux': '-p90%,60%' }
|
||||||
|
else
|
||||||
|
let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
|
||||||
|
endif
|
||||||
|
<
|
||||||
|
|
||||||
Hide statusline~
|
Hide statusline~
|
||||||
*fzf-hide-statusline*
|
*fzf-hide-statusline*
|
||||||
|
|||||||
8
install
8
install
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
set -u
|
set -u
|
||||||
|
|
||||||
version=0.21.1
|
version=0.22.0
|
||||||
auto_completion=
|
auto_completion=
|
||||||
key_bindings=
|
key_bindings=
|
||||||
update_config=2
|
update_config=2
|
||||||
@@ -384,7 +384,11 @@ fi
|
|||||||
|
|
||||||
if [ $update_config -eq 1 ]; then
|
if [ $update_config -eq 1 ]; then
|
||||||
echo 'Finished. Restart your shell or reload config file.'
|
echo 'Finished. Restart your shell or reload config file.'
|
||||||
[[ "$shells" =~ bash ]] && echo ' source ~/.bashrc # bash'
|
if [[ "$shells" =~ bash ]]; then
|
||||||
|
echo -n ' source ~/.bashrc # bash'
|
||||||
|
[[ "$archi" =~ Darwin ]] && echo -n ' (.bashrc should be loaded from .bash_profile)'
|
||||||
|
echo
|
||||||
|
fi
|
||||||
[[ "$shells" =~ zsh ]] && echo " source ${ZDOTDIR:-~}/.zshrc # zsh"
|
[[ "$shells" =~ zsh ]] && echo " source ${ZDOTDIR:-~}/.zshrc # zsh"
|
||||||
[[ "$shells" =~ fish ]] && [ $key_bindings -eq 1 ] && echo ' fzf_key_bindings # fish'
|
[[ "$shells" =~ fish ]] && [ $key_bindings -eq 1 ] && echo ' fzf_key_bindings # fish'
|
||||||
echo
|
echo
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
$version="0.21.1"
|
$version="0.22.0"
|
||||||
|
|
||||||
if ([Environment]::Is64BitProcess) {
|
if ([Environment]::Is64BitProcess) {
|
||||||
$binary_arch="amd64"
|
$binary_arch="amd64"
|
||||||
@@ -57,7 +57,7 @@ function download {
|
|||||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||||
(New-Object Net.WebClient).DownloadFile($url, $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("$temp"))
|
(New-Object Net.WebClient).DownloadFile($url, $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("$temp"))
|
||||||
if ($?) {
|
if ($?) {
|
||||||
(Expand-Archive -Path $temp -DestinationPath .); (Remove-Item $temp)
|
(Microsoft.PowerShell.Archive\Expand-Archive -Path $temp -DestinationPath .); (Remove-Item $temp)
|
||||||
} else {
|
} else {
|
||||||
$binary_error="Failed to download with powershell"
|
$binary_error="Failed to download with powershell"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 "Apr 2020" "fzf 0.21.1" "fzf-tmux - open fzf in tmux split pane"
|
.TH fzf-tmux 1 "Aug 2020" "fzf 0.22.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 "Apr 2020" "fzf 0.21.1" "fzf - a command-line fuzzy finder"
|
.TH fzf 1 "Aug 2020" "fzf 0.22.0" "fzf - a command-line fuzzy finder"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fzf - a command-line fuzzy finder
|
fzf - a command-line fuzzy finder
|
||||||
@@ -381,7 +381,7 @@ Preview window will be updated even when there is no match for the current
|
|||||||
query if any of the placeholder expressions evaluates to a non-empty string.
|
query if any of the placeholder expressions evaluates to a non-empty string.
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
.BI "--preview-window=" "[POSITION][:SIZE[%]][:noborder][:wrap][:hidden]"
|
.BI "--preview-window=" "[POSITION][:SIZE[%]][:noborder][:wrap][:hidden][:+SCROLL[-OFFSET]]"
|
||||||
Determines the layout of the preview window. If the argument contains
|
Determines the layout of the preview window. If the argument contains
|
||||||
\fB:hidden\fR, the preview window will be hidden by default until
|
\fB:hidden\fR, the preview window will be hidden by default until
|
||||||
\fBtoggle-preview\fR action is triggered. Long lines are truncated by default.
|
\fBtoggle-preview\fR action is triggered. Long lines are truncated by default.
|
||||||
@@ -390,6 +390,12 @@ Line wrap can be enabled with \fB:wrap\fR flag.
|
|||||||
If size is given as 0, preview window will not be visible, but fzf will still
|
If size is given as 0, preview window will not be visible, but fzf will still
|
||||||
execute the command in the background.
|
execute the command in the background.
|
||||||
|
|
||||||
|
\fB+SCROLL[-OFFSET]\fR determines the initial scroll offset of the preview
|
||||||
|
window. \fBSCROLL\fR can be either a numeric integer or a single-field index
|
||||||
|
expression that refers to a numeric integer. The optional \fB-OFFSET\fR part is
|
||||||
|
for adjusting the base offset so that you can see the text above it. It should
|
||||||
|
be given as a numeric integer.
|
||||||
|
|
||||||
.RS
|
.RS
|
||||||
.B POSITION: (default: right)
|
.B POSITION: (default: right)
|
||||||
\fBup
|
\fBup
|
||||||
@@ -400,8 +406,15 @@ execute the command in the background.
|
|||||||
|
|
||||||
.RS
|
.RS
|
||||||
e.g.
|
e.g.
|
||||||
\fBfzf --preview="head {}" --preview-window=up:30%
|
\fB# Non-default scroll window positions and sizes
|
||||||
fzf --preview="file {}" --preview-window=down:1\fR
|
fzf --preview="head {}" --preview-window=up:30%
|
||||||
|
fzf --preview="file {}" --preview-window=down:1
|
||||||
|
|
||||||
|
# Initial scroll offset is set to the line number of each line of
|
||||||
|
# git grep output *minus* 5 lines
|
||||||
|
git grep --line-number '' |
|
||||||
|
fzf --delimiter : --preview 'nl {1}' --preview-window +{2}-5\fR
|
||||||
|
|
||||||
.RE
|
.RE
|
||||||
.SS Scripting
|
.SS Scripting
|
||||||
.TP
|
.TP
|
||||||
@@ -635,12 +648,23 @@ e.g.
|
|||||||
or any single character
|
or any single character
|
||||||
|
|
||||||
.SS AVAILABLE EVENTS:
|
.SS AVAILABLE EVENTS:
|
||||||
\fIchange\fR (triggered whenever the query string is changed)
|
\fIchange\fR
|
||||||
.br
|
.RS
|
||||||
|
Triggered whenever the query string is changed
|
||||||
|
|
||||||
e.g.
|
e.g.
|
||||||
\fB# Moves cursor to the top (or bottom depending on --layout) whenever the query is changed
|
\fB# Moves cursor to the top (or bottom depending on --layout) whenever the query is changed
|
||||||
fzf --bind change:top\fR
|
fzf --bind change:top\fR
|
||||||
|
.RE
|
||||||
|
|
||||||
|
\fIbackward-eof\fR
|
||||||
|
.RS
|
||||||
|
Triggered when the query string is already empty and you try to delete it
|
||||||
|
backward.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
\fBfzf --bind backward-eof:abort\fR
|
||||||
|
.RE
|
||||||
|
|
||||||
.SS AVAILABLE ACTIONS:
|
.SS AVAILABLE ACTIONS:
|
||||||
A key or an event can be bound to one or more of the following actions.
|
A key or an event can be bound to one or more of the following actions.
|
||||||
@@ -679,12 +703,14 @@ A key or an event can be bound to one or more of the following actions.
|
|||||||
\fBpage-up\fR \fIpgup\fR
|
\fBpage-up\fR \fIpgup\fR
|
||||||
\fBhalf-page-down\fR
|
\fBhalf-page-down\fR
|
||||||
\fBhalf-page-up\fR
|
\fBhalf-page-up\fR
|
||||||
|
\fBpreview(...)\fR (see below for the details)
|
||||||
\fBpreview-down\fR \fIshift-down\fR
|
\fBpreview-down\fR \fIshift-down\fR
|
||||||
\fBpreview-up\fR \fIshift-up\fR
|
\fBpreview-up\fR \fIshift-up\fR
|
||||||
\fBpreview-page-down\fR
|
\fBpreview-page-down\fR
|
||||||
\fBpreview-page-up\fR
|
\fBpreview-page-up\fR
|
||||||
\fBprevious-history\fR (\fIctrl-p\fR on \fB--history\fR)
|
\fBprevious-history\fR (\fIctrl-p\fR on \fB--history\fR)
|
||||||
\fBprint-query\fR (print query and exit)
|
\fBprint-query\fR (print query and exit)
|
||||||
|
\fBrefresh-preview\fR
|
||||||
\fBreload(...)\fR (see below for the details)
|
\fBreload(...)\fR (see below for the details)
|
||||||
\fBreplace-query\fR (replace query string with the current selection)
|
\fBreplace-query\fR (replace query string with the current selection)
|
||||||
\fBselect-all\fR (select all matches)
|
\fBselect-all\fR (select all matches)
|
||||||
@@ -771,6 +797,24 @@ e.g.
|
|||||||
fzf --bind "change:reload:$RG_PREFIX {q} || true" \\
|
fzf --bind "change:reload:$RG_PREFIX {q} || true" \\
|
||||||
--ansi --phony --query "$INITIAL_QUERY"\fR
|
--ansi --phony --query "$INITIAL_QUERY"\fR
|
||||||
|
|
||||||
|
.SS PREVIEW BINDING
|
||||||
|
|
||||||
|
With \fBpreview(...)\fR action, you can specify multiple different preview
|
||||||
|
commands in addition to the default preview command given by \fB--preview\fR
|
||||||
|
option.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
|
||||||
|
# Default preview command with an extra preview binding
|
||||||
|
fzf --preview 'file {}' --bind '?:preview:cat {}'
|
||||||
|
|
||||||
|
# A preview binding with no default preview command
|
||||||
|
# (Preview window is initially empty)
|
||||||
|
fzf --bind '?:preview:cat {}'
|
||||||
|
|
||||||
|
# Preview window hidden by default, it appears when you first hit '?'
|
||||||
|
fzf --bind '?:preview:cat {}' --preview-window hidden
|
||||||
|
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
Junegunn Choi (\fIjunegunn.c@gmail.com\fR)
|
Junegunn Choi (\fIjunegunn.c@gmail.com\fR)
|
||||||
|
|
||||||
|
|||||||
106
plugin/fzf.vim
106
plugin/fzf.vim
@@ -116,7 +116,7 @@ function! s:fzf_tempname()
|
|||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
let s:default_layout = { 'down': '~40%' }
|
let s:default_layout = { 'down': '~40%' }
|
||||||
let s:layout_keys = ['window', 'up', 'down', 'left', 'right']
|
let s:layout_keys = ['window', 'tmux', 'up', 'down', 'left', 'right']
|
||||||
let s:fzf_go = s:base_dir.'/bin/fzf'
|
let s:fzf_go = s:base_dir.'/bin/fzf'
|
||||||
let s:fzf_tmux = s:base_dir.'/bin/fzf-tmux'
|
let s:fzf_tmux = s:base_dir.'/bin/fzf-tmux'
|
||||||
|
|
||||||
@@ -191,21 +191,6 @@ function! s:escape(path)
|
|||||||
return s:is_win ? escape(path, '$') : path
|
return s:is_win ? escape(path, '$') : path
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Upgrade legacy options
|
|
||||||
function! s:upgrade(dict)
|
|
||||||
let copy = copy(a:dict)
|
|
||||||
if has_key(copy, 'tmux')
|
|
||||||
let copy.down = remove(copy, 'tmux')
|
|
||||||
endif
|
|
||||||
if has_key(copy, 'tmux_height')
|
|
||||||
let copy.down = remove(copy, 'tmux_height')
|
|
||||||
endif
|
|
||||||
if has_key(copy, 'tmux_width')
|
|
||||||
let copy.right = remove(copy, 'tmux_width')
|
|
||||||
endif
|
|
||||||
return copy
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:error(msg)
|
function! s:error(msg)
|
||||||
echohl ErrorMsg
|
echohl ErrorMsg
|
||||||
echom a:msg
|
echom a:msg
|
||||||
@@ -251,9 +236,13 @@ function! s:common_sink(action, lines) abort
|
|||||||
endif
|
endif
|
||||||
try
|
try
|
||||||
let empty = empty(s:fzf_expand('%')) && line('$') == 1 && empty(getline(1)) && !&modified
|
let empty = empty(s:fzf_expand('%')) && line('$') == 1 && empty(getline(1)) && !&modified
|
||||||
let autochdir = &autochdir
|
" Preserve the current working directory in case it's changed during
|
||||||
set noautochdir
|
" the execution (e.g. `set autochdir` or `autocmd BufEnter * lcd ...`)
|
||||||
|
let cwd = exists('w:fzf_pushd') ? w:fzf_pushd.dir : expand('%:p:h')
|
||||||
for item in a:lines
|
for item in a:lines
|
||||||
|
if item[0] != '~' && item !~ (s:is_win ? '^[A-Z]:\' : '^/')
|
||||||
|
let item = join([cwd, item], (s:is_win ? '\' : '/'))
|
||||||
|
endif
|
||||||
if empty
|
if empty
|
||||||
execute 'e' s:escape(item)
|
execute 'e' s:escape(item)
|
||||||
let empty = 0
|
let empty = 0
|
||||||
@@ -267,7 +256,6 @@ function! s:common_sink(action, lines) abort
|
|||||||
endfor
|
endfor
|
||||||
catch /^Vim:Interrupt$/
|
catch /^Vim:Interrupt$/
|
||||||
finally
|
finally
|
||||||
let &autochdir = autochdir
|
|
||||||
silent! autocmd! fzf_swap
|
silent! autocmd! fzf_swap
|
||||||
endtry
|
endtry
|
||||||
endfunction
|
endfunction
|
||||||
@@ -312,7 +300,7 @@ function! fzf#wrap(...)
|
|||||||
let expects = map(copy(args), 'type(v:val)')
|
let expects = map(copy(args), 'type(v:val)')
|
||||||
let tidx = 0
|
let tidx = 0
|
||||||
for arg in copy(a:000)
|
for arg in copy(a:000)
|
||||||
let tidx = index(expects, type(arg), tidx)
|
let tidx = index(expects, type(arg) == 6 ? type(0) : type(arg), tidx)
|
||||||
if tidx < 0
|
if tidx < 0
|
||||||
throw 'Invalid arguments (expected: [name string] [opts dict] [fullscreen boolean])'
|
throw 'Invalid arguments (expected: [name string] [opts dict] [fullscreen boolean])'
|
||||||
endif
|
endif
|
||||||
@@ -384,7 +372,7 @@ function! fzf#run(...) abort
|
|||||||
try
|
try
|
||||||
let [shell, shellslash, shellcmdflag, shellxquote] = s:use_sh()
|
let [shell, shellslash, shellcmdflag, shellxquote] = s:use_sh()
|
||||||
|
|
||||||
let dict = exists('a:1') ? s:upgrade(a:1) : {}
|
let dict = exists('a:1') ? copy(a:1) : {}
|
||||||
let temps = { 'result': s:fzf_tempname() }
|
let temps = { 'result': s:fzf_tempname() }
|
||||||
let optstr = s:evaluate_opts(get(dict, 'options', ''))
|
let optstr = s:evaluate_opts(get(dict, 'options', ''))
|
||||||
try
|
try
|
||||||
@@ -416,7 +404,7 @@ try
|
|||||||
let prefix = ''
|
let prefix = ''
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let prefer_tmux = get(g:, 'fzf_prefer_tmux', 0)
|
let prefer_tmux = get(g:, 'fzf_prefer_tmux', 0) || has_key(dict, 'tmux')
|
||||||
let use_height = has_key(dict, 'down') && !has('gui_running') &&
|
let use_height = has_key(dict, 'down') && !has('gui_running') &&
|
||||||
\ !(has('nvim') || s:is_win || has('win32unix') || s:present(dict, 'up', 'left', 'right', 'window')) &&
|
\ !(has('nvim') || s:is_win || has('win32unix') || s:present(dict, 'up', 'left', 'right', 'window')) &&
|
||||||
\ executable('tput') && filereadable('/dev/tty')
|
\ executable('tput') && filereadable('/dev/tty')
|
||||||
@@ -424,7 +412,7 @@ try
|
|||||||
let has_nvim_term = has('nvim-0.2.1') || has('nvim') && !s:is_win
|
let has_nvim_term = has('nvim-0.2.1') || has('nvim') && !s:is_win
|
||||||
let use_term = has_nvim_term ||
|
let use_term = has_nvim_term ||
|
||||||
\ has_vim8_term && !has('win32unix') && (has('gui_running') || s:is_win || !use_height && s:present(dict, 'down', 'up', 'left', 'right', 'window'))
|
\ has_vim8_term && !has('win32unix') && (has('gui_running') || s:is_win || !use_height && s:present(dict, 'down', 'up', 'left', 'right', 'window'))
|
||||||
let use_tmux = (!use_height && !use_term || prefer_tmux) && !has('win32unix') && s:tmux_enabled() && s:splittable(dict)
|
let use_tmux = (has_key(dict, 'tmux') || (!use_height && !use_term || prefer_tmux) && !has('win32unix') && s:splittable(dict)) && s:tmux_enabled()
|
||||||
if prefer_tmux && use_tmux
|
if prefer_tmux && use_tmux
|
||||||
let use_height = 0
|
let use_height = 0
|
||||||
let use_term = 0
|
let use_term = 0
|
||||||
@@ -460,19 +448,21 @@ function! s:present(dict, ...)
|
|||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:fzf_tmux(dict)
|
function! s:fzf_tmux(dict)
|
||||||
let size = ''
|
let size = get(a:dict, 'tmux', '')
|
||||||
for o in ['up', 'down', 'left', 'right']
|
if empty(size)
|
||||||
if s:present(a:dict, o)
|
for o in ['up', 'down', 'left', 'right']
|
||||||
let spec = a:dict[o]
|
if s:present(a:dict, o)
|
||||||
if (o == 'up' || o == 'down') && spec[0] == '~'
|
let spec = a:dict[o]
|
||||||
let size = '-'.o[0].s:calc_size(&lines, spec, a:dict)
|
if (o == 'up' || o == 'down') && spec[0] == '~'
|
||||||
else
|
let size = '-'.o[0].s:calc_size(&lines, spec, a:dict)
|
||||||
" Legacy boolean option
|
else
|
||||||
let size = '-'.o[0].(spec == 1 ? '' : substitute(spec, '^\~', '', ''))
|
" Legacy boolean option
|
||||||
|
let size = '-'.o[0].(spec == 1 ? '' : substitute(spec, '^\~', '', ''))
|
||||||
|
endif
|
||||||
|
break
|
||||||
endif
|
endif
|
||||||
break
|
endfor
|
||||||
endif
|
endif
|
||||||
endfor
|
|
||||||
return printf('LINES=%d COLUMNS=%d %s %s %s --',
|
return printf('LINES=%d COLUMNS=%d %s %s %s --',
|
||||||
\ &lines, &columns, fzf#shellescape(s:fzf_tmux), size, (has_key(a:dict, 'source') ? '' : '-'))
|
\ &lines, &columns, fzf#shellescape(s:fzf_tmux), size, (has_key(a:dict, 'source') ? '' : '-'))
|
||||||
endfunction
|
endfunction
|
||||||
@@ -527,7 +517,7 @@ function! s:dopopd()
|
|||||||
if s:fzf_getcwd() ==# w:fzf_pushd.dir && (!&autochdir || w:fzf_pushd.bufname ==# bufname(''))
|
if s:fzf_getcwd() ==# w:fzf_pushd.dir && (!&autochdir || w:fzf_pushd.bufname ==# bufname(''))
|
||||||
execute w:fzf_pushd.command s:escape(w:fzf_pushd.origin)
|
execute w:fzf_pushd.command s:escape(w:fzf_pushd.origin)
|
||||||
endif
|
endif
|
||||||
unlet w:fzf_pushd
|
unlet! w:fzf_pushd
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:xterm_launcher()
|
function! s:xterm_launcher()
|
||||||
@@ -642,6 +632,9 @@ function! s:calc_size(max, val, dict)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
let opts = $FZF_DEFAULT_OPTS.' '.s:evaluate_opts(get(a:dict, 'options', ''))
|
let opts = $FZF_DEFAULT_OPTS.' '.s:evaluate_opts(get(a:dict, 'options', ''))
|
||||||
|
if opts =~ 'preview'
|
||||||
|
return size
|
||||||
|
endif
|
||||||
let margin = match(opts, '--inline-info\|--info[^-]\{-}inline') > match(opts, '--no-inline-info\|--info[^-]\{-}\(default\|hidden\)') ? 1 : 2
|
let margin = match(opts, '--inline-info\|--info[^-]\{-}inline') > match(opts, '--no-inline-info\|--info[^-]\{-}\(default\|hidden\)') ? 1 : 2
|
||||||
let margin += stridx(opts, '--border') > stridx(opts, '--no-border') ? 2 : 0
|
let margin += stridx(opts, '--border') > stridx(opts, '--no-border') ? 2 : 0
|
||||||
if stridx(opts, '--header') > stridx(opts, '--no-header')
|
if stridx(opts, '--header') > stridx(opts, '--no-header')
|
||||||
@@ -661,13 +654,15 @@ function! s:split(dict)
|
|||||||
\ 'left': ['vertical topleft', 'vertical resize', &columns],
|
\ 'left': ['vertical topleft', 'vertical resize', &columns],
|
||||||
\ 'right': ['vertical botright', 'vertical resize', &columns] }
|
\ 'right': ['vertical botright', 'vertical resize', &columns] }
|
||||||
let ppos = s:getpos()
|
let ppos = s:getpos()
|
||||||
|
let is_popup = 0
|
||||||
try
|
try
|
||||||
if s:present(a:dict, 'window')
|
if s:present(a:dict, 'window')
|
||||||
if type(a:dict.window) == type({})
|
if type(a:dict.window) == type({})
|
||||||
if !has('nvim') && !has('patch-8.2.191')
|
if !(has('nvim') ? has('nvim-0.4') : has('popupwin') && has('patch-8.2.191'))
|
||||||
throw 'Vim 8.2.191 or later is required for pop-up window'
|
throw 'Nvim 0.4+ or Vim 8.2.191+ with popupwin feature is required for pop-up window'
|
||||||
end
|
end
|
||||||
call s:popup(a:dict.window)
|
call s:popup(a:dict.window)
|
||||||
|
let is_popup = 1
|
||||||
else
|
else
|
||||||
execute 'keepalt' a:dict.window
|
execute 'keepalt' a:dict.window
|
||||||
endif
|
endif
|
||||||
@@ -685,20 +680,22 @@ function! s:split(dict)
|
|||||||
endif
|
endif
|
||||||
execute cmd sz.'new'
|
execute cmd sz.'new'
|
||||||
execute resz sz
|
execute resz sz
|
||||||
return [ppos, {}]
|
return [ppos, {}, is_popup]
|
||||||
endif
|
endif
|
||||||
endfor
|
endfor
|
||||||
endif
|
endif
|
||||||
return [ppos, { '&l:wfw': &l:wfw, '&l:wfh': &l:wfh }]
|
return [ppos, is_popup ? {} : { '&l:wfw': &l:wfw, '&l:wfh': &l:wfh }, is_popup]
|
||||||
finally
|
finally
|
||||||
setlocal winfixwidth winfixheight
|
if !is_popup
|
||||||
|
setlocal winfixwidth winfixheight
|
||||||
|
endif
|
||||||
endtry
|
endtry
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:execute_term(dict, command, temps) abort
|
function! s:execute_term(dict, command, temps) abort
|
||||||
let winrest = winrestcmd()
|
let winrest = winrestcmd()
|
||||||
let pbuf = bufnr('')
|
let pbuf = bufnr('')
|
||||||
let [ppos, winopts] = s:split(a:dict)
|
let [ppos, winopts, is_popup] = s:split(a:dict)
|
||||||
call s:use_sh()
|
call s:use_sh()
|
||||||
let b:fzf = a:dict
|
let b:fzf = a:dict
|
||||||
let fzf = { 'buf': bufnr(''), 'pbuf': pbuf, 'ppos': ppos, 'dict': a:dict, 'temps': a:temps,
|
let fzf = { 'buf': bufnr(''), 'pbuf': pbuf, 'ppos': ppos, 'dict': a:dict, 'temps': a:temps,
|
||||||
@@ -762,11 +759,17 @@ function! s:execute_term(dict, command, temps) abort
|
|||||||
if has('nvim')
|
if has('nvim')
|
||||||
call termopen(command, fzf)
|
call termopen(command, fzf)
|
||||||
else
|
else
|
||||||
if !len(&bufhidden)
|
let term_opts = {'exit_cb': function(fzf.on_exit)}
|
||||||
setlocal bufhidden=hide
|
if is_popup
|
||||||
|
let term_opts.hidden = 1
|
||||||
|
else
|
||||||
|
let term_opts.curwin = 1
|
||||||
endif
|
endif
|
||||||
let fzf.buf = term_start([&shell, &shellcmdflag, command], {'curwin': 1, 'exit_cb': function(fzf.on_exit)})
|
let fzf.buf = term_start([&shell, &shellcmdflag, command], term_opts)
|
||||||
if !has('patch-8.0.1261') && !has('nvim') && !s:is_win
|
if is_popup && exists('#TerminalWinOpen')
|
||||||
|
doautocmd <nomodeline> TerminalWinOpen
|
||||||
|
endif
|
||||||
|
if !has('patch-8.0.1261') && !s:is_win
|
||||||
call term_wait(fzf.buf, 20)
|
call term_wait(fzf.buf, 20)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
@@ -837,23 +840,22 @@ if has('nvim')
|
|||||||
else
|
else
|
||||||
function! s:create_popup(hl, opts) abort
|
function! s:create_popup(hl, opts) abort
|
||||||
let is_frame = has_key(a:opts, 'border')
|
let is_frame = has_key(a:opts, 'border')
|
||||||
let buf = is_frame ? '' : term_start(&shell, #{hidden: 1, term_finish: 'close'})
|
let s:popup_create = {buf -> popup_create(buf, #{
|
||||||
let id = popup_create(buf, #{
|
|
||||||
\ line: a:opts.row,
|
\ line: a:opts.row,
|
||||||
\ col: a:opts.col,
|
\ col: a:opts.col,
|
||||||
\ minwidth: a:opts.width,
|
\ minwidth: a:opts.width,
|
||||||
\ minheight: a:opts.height,
|
\ minheight: a:opts.height,
|
||||||
\ zindex: 50 - is_frame,
|
\ zindex: 50 - is_frame,
|
||||||
\ })
|
\ })}
|
||||||
|
|
||||||
if is_frame
|
if is_frame
|
||||||
|
let id = s:popup_create('')
|
||||||
call setwinvar(id, '&wincolor', a:hl)
|
call setwinvar(id, '&wincolor', a:hl)
|
||||||
call setbufline(winbufnr(id), 1, a:opts.border)
|
call setbufline(winbufnr(id), 1, a:opts.border)
|
||||||
execute 'autocmd BufWipeout * ++once call popup_close('..id..')'
|
execute 'autocmd BufWipeout * ++once call popup_close('..id..')'
|
||||||
|
return winbufnr(id)
|
||||||
else
|
else
|
||||||
execute 'autocmd BufWipeout * ++once call term_sendkeys('..buf..', "exit\<CR>")'
|
autocmd TerminalOpen * ++once call s:popup_create(str2nr(expand('<abuf>')))
|
||||||
endif
|
endif
|
||||||
return winbufnr(id)
|
|
||||||
endfunction
|
endfunction
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|||||||
@@ -249,17 +249,25 @@ _fzf_dir_completion() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_fzf_complete_kill() {
|
_fzf_complete_kill() {
|
||||||
[ -n "${COMP_WORDS[COMP_CWORD]}" ] && return 1
|
local trigger=${FZF_COMPLETION_TRIGGER-'**'}
|
||||||
|
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
local selected
|
if [[ -z "$cur" ]]; then
|
||||||
selected=$(command ps -ef | sed 1d | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-50%} --min-height 15 --reverse $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS --preview 'echo {}' --preview-window down:3:wrap" __fzf_comprun "kill" -m | awk '{print $2}' | tr '\n' ' ')
|
COMP_WORDS[$COMP_CWORD]=$trigger
|
||||||
selected=${selected% }
|
elif [[ "$cur" != *"$trigger" ]]; then
|
||||||
printf '\e[5n'
|
return 1
|
||||||
|
|
||||||
if [ -n "$selected" ]; then
|
|
||||||
COMPREPLY=( "$selected" )
|
|
||||||
return 0
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
_fzf_proc_completion "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
_fzf_proc_completion() {
|
||||||
|
_fzf_complete -m --preview 'echo {}' --preview-window down:3:wrap --min-height 15 -- "$@" < <(
|
||||||
|
command ps -ef | sed 1d
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
_fzf_proc_completion_post() {
|
||||||
|
awk '{print $2}'
|
||||||
}
|
}
|
||||||
|
|
||||||
_fzf_host_completion() {
|
_fzf_host_completion() {
|
||||||
@@ -296,11 +304,10 @@ a_cmds="
|
|||||||
find git grep gunzip gzip hg jar
|
find git grep gunzip gzip hg jar
|
||||||
ln ls mv open rm rsync scp
|
ln ls mv open rm rsync scp
|
||||||
svn tar unzip zip"
|
svn tar unzip zip"
|
||||||
x_cmds="kill"
|
|
||||||
|
|
||||||
# Preserve existing completion
|
# Preserve existing completion
|
||||||
eval "$(complete |
|
eval "$(complete |
|
||||||
sed -E '/-F/!d; / _fzf/d; '"/ ($(echo $d_cmds $a_cmds $x_cmds | sed 's/ /|/g; s/+/\\+/g'))$/"'!d' |
|
sed -E '/-F/!d; / _fzf/d; '"/ ($(echo $d_cmds $a_cmds | sed 's/ /|/g; s/+/\\+/g'))$/"'!d' |
|
||||||
__fzf_orig_completion_filter)"
|
__fzf_orig_completion_filter)"
|
||||||
|
|
||||||
if type _completion_loader > /dev/null 2>&1; then
|
if type _completion_loader > /dev/null 2>&1; then
|
||||||
@@ -332,17 +339,17 @@ for cmd in $d_cmds; do
|
|||||||
__fzf_defc "$cmd" _fzf_dir_completion "-o nospace -o dirnames"
|
__fzf_defc "$cmd" _fzf_dir_completion "-o nospace -o dirnames"
|
||||||
done
|
done
|
||||||
|
|
||||||
# Kill completion
|
# Kill completion (supports empty completion trigger)
|
||||||
complete -F _fzf_complete_kill -o default -o bashdefault kill
|
complete -F _fzf_complete_kill -o default -o bashdefault kill
|
||||||
|
|
||||||
unset cmd d_cmds a_cmds x_cmds
|
unset cmd d_cmds a_cmds
|
||||||
|
|
||||||
_fzf_setup_completion() {
|
_fzf_setup_completion() {
|
||||||
local kind fn cmd
|
local kind fn cmd
|
||||||
kind=$1
|
kind=$1
|
||||||
fn=_fzf_${1}_completion
|
fn=_fzf_${1}_completion
|
||||||
if [[ $# -lt 2 ]] || ! type -t "$fn" > /dev/null; then
|
if [[ $# -lt 2 ]] || ! type -t "$fn" > /dev/null; then
|
||||||
echo "usage: ${FUNCNAME[0]} path|dir|var|alias|host COMMANDS..."
|
echo "usage: ${FUNCNAME[0]} path|dir|var|alias|host|proc COMMANDS..."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
shift
|
shift
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ __fzf_extract_command() {
|
|||||||
local token tokens
|
local token tokens
|
||||||
tokens=(${(z)1})
|
tokens=(${(z)1})
|
||||||
for token in $tokens; do
|
for token in $tokens; do
|
||||||
|
token=${(Q)token}
|
||||||
if [[ "$token" =~ [[:alnum:]] && ! "$token" =~ "=" ]]; then
|
if [[ "$token" =~ [[:alnum:]] && ! "$token" =~ "=" ]]; then
|
||||||
echo "$token"
|
echo "$token"
|
||||||
return
|
return
|
||||||
@@ -249,6 +250,16 @@ _fzf_complete_unalias() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_fzf_complete_kill() {
|
||||||
|
_fzf_complete -m --preview 'echo {}' --preview-window down:3:wrap --min-height 15 -- "$@" < <(
|
||||||
|
command ps -ef | sed 1d
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
_fzf_complete_kill_post() {
|
||||||
|
awk '{print $2}'
|
||||||
|
}
|
||||||
|
|
||||||
fzf-completion() {
|
fzf-completion() {
|
||||||
local tokens cmd prefix trigger tail matches lbuf d_cmds
|
local tokens cmd prefix trigger tail matches lbuf d_cmds
|
||||||
setopt localoptions noshwordsplit noksh_arrays noposixbuiltins
|
setopt localoptions noshwordsplit noksh_arrays noposixbuiltins
|
||||||
@@ -273,20 +284,21 @@ fzf-completion() {
|
|||||||
tokens=(${tokens[0,-2]})
|
tokens=(${tokens[0,-2]})
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
lbuf=$LBUFFER
|
||||||
tail=${LBUFFER:$(( ${#LBUFFER} - ${#trigger} ))}
|
tail=${LBUFFER:$(( ${#LBUFFER} - ${#trigger} ))}
|
||||||
# Kill completion (do not require trigger sequence)
|
# Kill completion (do not require trigger sequence)
|
||||||
if [ $cmd = kill -a ${LBUFFER[-1]} = ' ' ]; then
|
if [ "$cmd" = kill -a ${LBUFFER[-1]} = ' ' ]; then
|
||||||
matches=$(command ps -ef | sed 1d | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-50%} --min-height 15 --reverse $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS --preview 'echo {}' --preview-window down:3:wrap" __fzf_comprun "$cmd" -m | awk '{print $2}' | tr '\n' ' ')
|
tail=$trigger
|
||||||
if [ -n "$matches" ]; then
|
tokens+=$trigger
|
||||||
LBUFFER="$LBUFFER$matches"
|
lbuf="$lbuf$trigger"
|
||||||
fi
|
fi
|
||||||
zle reset-prompt
|
|
||||||
# Trigger sequence given
|
# Trigger sequence given
|
||||||
elif [ ${#tokens} -gt 1 -a "$tail" = "$trigger" ]; then
|
if [ ${#tokens} -gt 1 -a "$tail" = "$trigger" ]; then
|
||||||
d_cmds=(${=FZF_COMPLETION_DIR_COMMANDS:-cd pushd rmdir})
|
d_cmds=(${=FZF_COMPLETION_DIR_COMMANDS:-cd pushd rmdir})
|
||||||
|
|
||||||
[ -z "$trigger" ] && prefix=${tokens[-1]} || prefix=${tokens[-1]:0:-${#trigger}}
|
[ -z "$trigger" ] && prefix=${tokens[-1]} || prefix=${tokens[-1]:0:-${#trigger}}
|
||||||
[ -z "${tokens[-1]}" ] && lbuf=$LBUFFER || lbuf=${LBUFFER:0:-${#tokens[-1]}}
|
[ -n "${tokens[-1]}" ] && lbuf=${lbuf:0:-${#tokens[-1]}}
|
||||||
|
|
||||||
if eval "type _fzf_complete_${cmd} > /dev/null"; then
|
if eval "type _fzf_complete_${cmd} > /dev/null"; then
|
||||||
prefix="$prefix" eval _fzf_complete_${cmd} ${(q)lbuf}
|
prefix="$prefix" eval _fzf_complete_${cmd} ${(q)lbuf}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ bindkey '\ec' fzf-cd-widget
|
|||||||
fzf-history-widget() {
|
fzf-history-widget() {
|
||||||
local selected num
|
local selected num
|
||||||
setopt localoptions noglobsubst noposixbuiltins pipefail no_aliases 2> /dev/null
|
setopt localoptions noglobsubst noposixbuiltins pipefail no_aliases 2> /dev/null
|
||||||
selected=( $(fc -rl 1 | perl -ne 'print if !$seen{($_ =~ s/^\s*[0-9]+\s+//r)}++' |
|
selected=( $(fc -rl 1 | perl -ne 'print if !$seen{(/^\s*[0-9]+\s+(.*)/, $1)}++' |
|
||||||
FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} $FZF_DEFAULT_OPTS -n2..,.. --tiebreak=index --bind=ctrl-r:toggle-sort $FZF_CTRL_R_OPTS --query=${(qqq)LBUFFER} +m" $(__fzfcmd)) )
|
FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} $FZF_DEFAULT_OPTS -n2..,.. --tiebreak=index --bind=ctrl-r:toggle-sort $FZF_CTRL_R_OPTS --query=${(qqq)LBUFFER} +m" $(__fzfcmd)) )
|
||||||
local ret=$?
|
local ret=$?
|
||||||
if [ -n "$selected" ]; then
|
if [ -n "$selected" ]; then
|
||||||
|
|||||||
@@ -405,6 +405,74 @@ var normalized map[rune]rune = map[rune]rune{
|
|||||||
0x024E: 'Y', // WITH STROKE, LATIN CAPITAL LETTER
|
0x024E: 'Y', // WITH STROKE, LATIN CAPITAL LETTER
|
||||||
0x028F: 'Y', // , LATIN LETTER SMALL CAPITAL
|
0x028F: 'Y', // , LATIN LETTER SMALL CAPITAL
|
||||||
0x1D22: 'Z', // , LATIN LETTER SMALL CAPITAL
|
0x1D22: 'Z', // , LATIN LETTER SMALL CAPITAL
|
||||||
|
|
||||||
|
'Ắ': 'A',
|
||||||
|
'Ấ': 'A',
|
||||||
|
'Ằ': 'A',
|
||||||
|
'Ầ': 'A',
|
||||||
|
'Ẳ': 'A',
|
||||||
|
'Ẩ': 'A',
|
||||||
|
'Ẵ': 'A',
|
||||||
|
'Ẫ': 'A',
|
||||||
|
'Ặ': 'A',
|
||||||
|
'Ậ': 'A',
|
||||||
|
|
||||||
|
'ắ': 'a',
|
||||||
|
'ấ': 'a',
|
||||||
|
'ằ': 'a',
|
||||||
|
'ầ': 'a',
|
||||||
|
'ẳ': 'a',
|
||||||
|
'ẩ': 'a',
|
||||||
|
'ẵ': 'a',
|
||||||
|
'ẫ': 'a',
|
||||||
|
'ặ': 'a',
|
||||||
|
'ậ': 'a',
|
||||||
|
|
||||||
|
'Ế': 'E',
|
||||||
|
'Ề': 'E',
|
||||||
|
'Ể': 'E',
|
||||||
|
'Ễ': 'E',
|
||||||
|
'Ệ': 'E',
|
||||||
|
|
||||||
|
'ế': 'e',
|
||||||
|
'ề': 'e',
|
||||||
|
'ể': 'e',
|
||||||
|
'ễ': 'e',
|
||||||
|
'ệ': 'e',
|
||||||
|
|
||||||
|
'Ố': 'O',
|
||||||
|
'Ớ': 'O',
|
||||||
|
'Ồ': 'O',
|
||||||
|
'Ờ': 'O',
|
||||||
|
'Ổ': 'O',
|
||||||
|
'Ở': 'O',
|
||||||
|
'Ỗ': 'O',
|
||||||
|
'Ỡ': 'O',
|
||||||
|
'Ộ': 'O',
|
||||||
|
'Ợ': 'O',
|
||||||
|
|
||||||
|
'ố': 'o',
|
||||||
|
'ớ': 'o',
|
||||||
|
'ồ': 'o',
|
||||||
|
'ờ': 'o',
|
||||||
|
'ổ': 'o',
|
||||||
|
'ở': 'o',
|
||||||
|
'ỗ': 'o',
|
||||||
|
'ỡ': 'o',
|
||||||
|
'ộ': 'o',
|
||||||
|
'ợ': 'o',
|
||||||
|
|
||||||
|
'Ứ': 'U',
|
||||||
|
'Ừ': 'U',
|
||||||
|
'Ử': 'U',
|
||||||
|
'Ữ': 'U',
|
||||||
|
'Ự': 'U',
|
||||||
|
|
||||||
|
'ứ': 'u',
|
||||||
|
'ừ': 'u',
|
||||||
|
'ử': 'u',
|
||||||
|
'ữ': 'u',
|
||||||
|
'ự': 'u',
|
||||||
}
|
}
|
||||||
|
|
||||||
// NormalizeRunes normalizes latin script letters
|
// NormalizeRunes normalizes latin script letters
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// Current version
|
// Current version
|
||||||
version = "0.21.1"
|
version = "0.22.0"
|
||||||
|
|
||||||
// Core
|
// Core
|
||||||
coordinatorDelayMax time.Duration = 100 * time.Millisecond
|
coordinatorDelayMax time.Duration = 100 * time.Millisecond
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ const usage = `usage: fzf [options]
|
|||||||
Preview
|
Preview
|
||||||
--preview=COMMAND Command to preview highlighted line ({})
|
--preview=COMMAND Command to preview highlighted line ({})
|
||||||
--preview-window=OPT Preview window layout (default: right:50%)
|
--preview-window=OPT Preview window layout (default: right:50%)
|
||||||
[up|down|left|right][:SIZE[%]][:wrap][:hidden]
|
[up|down|left|right][:SIZE[%]][:wrap][:hidden][:+SCROLL[-OFFSET]]
|
||||||
|
|
||||||
Scripting
|
Scripting
|
||||||
-q, --query=STR Start the finder with the given query
|
-q, --query=STR Start the finder with the given query
|
||||||
@@ -159,6 +159,7 @@ type previewOpts struct {
|
|||||||
command string
|
command string
|
||||||
position windowPosition
|
position windowPosition
|
||||||
size sizeSpec
|
size sizeSpec
|
||||||
|
scroll string
|
||||||
hidden bool
|
hidden bool
|
||||||
wrap bool
|
wrap bool
|
||||||
border bool
|
border bool
|
||||||
@@ -260,7 +261,7 @@ func defaultOptions() *Options {
|
|||||||
ToggleSort: false,
|
ToggleSort: false,
|
||||||
Expect: make(map[int]string),
|
Expect: make(map[int]string),
|
||||||
Keymap: make(map[int][]action),
|
Keymap: make(map[int][]action),
|
||||||
Preview: previewOpts{"", posRight, sizeSpec{50, true}, false, false, true},
|
Preview: previewOpts{"", posRight, sizeSpec{50, true}, "", false, false, true},
|
||||||
PrintQuery: false,
|
PrintQuery: false,
|
||||||
ReadZero: false,
|
ReadZero: false,
|
||||||
Printer: func(str string) { fmt.Println(str) },
|
Printer: func(str string) { fmt.Println(str) },
|
||||||
@@ -464,6 +465,8 @@ func parseKeyChords(str string, message string) map[int]string {
|
|||||||
chord = tui.CtrlRightBracket
|
chord = tui.CtrlRightBracket
|
||||||
case "change":
|
case "change":
|
||||||
chord = tui.Change
|
chord = tui.Change
|
||||||
|
case "backward-eof":
|
||||||
|
chord = tui.BackwardEOF
|
||||||
case "alt-enter", "alt-return":
|
case "alt-enter", "alt-return":
|
||||||
chord = tui.CtrlAltM
|
chord = tui.CtrlAltM
|
||||||
case "alt-space":
|
case "alt-space":
|
||||||
@@ -682,7 +685,7 @@ func init() {
|
|||||||
// Backreferences are not supported.
|
// Backreferences are not supported.
|
||||||
// "~!@#$%^&*;/|".each_char.map { |c| Regexp.escape(c) }.map { |c| "#{c}[^#{c}]*#{c}" }.join('|')
|
// "~!@#$%^&*;/|".each_char.map { |c| Regexp.escape(c) }.map { |c| "#{c}[^#{c}]*#{c}" }.join('|')
|
||||||
executeRegexp = regexp.MustCompile(
|
executeRegexp = regexp.MustCompile(
|
||||||
`(?si)[:+](execute(?:-multi|-silent)?|reload):.+|[:+](execute(?:-multi|-silent)?|reload)(\([^)]*\)|\[[^\]]*\]|~[^~]*~|![^!]*!|@[^@]*@|\#[^\#]*\#|\$[^\$]*\$|%[^%]*%|\^[^\^]*\^|&[^&]*&|\*[^\*]*\*|;[^;]*;|/[^/]*/|\|[^\|]*\|)`)
|
`(?si)[:+](execute(?:-multi|-silent)?|reload|preview):.+|[:+](execute(?:-multi|-silent)?|reload|preview)(\([^)]*\)|\[[^\]]*\]|~[^~]*~|![^!]*!|@[^@]*@|\#[^\#]*\#|\$[^\$]*\$|%[^%]*%|\^[^\^]*\^|&[^&]*&|\*[^\*]*\*|;[^;]*;|/[^/]*/|\|[^\|]*\|)`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseKeymap(keymap map[int][]action, str string) {
|
func parseKeymap(keymap map[int][]action, str string) {
|
||||||
@@ -694,6 +697,8 @@ func parseKeymap(keymap map[int][]action, str string) {
|
|||||||
prefix := symbol + "execute"
|
prefix := symbol + "execute"
|
||||||
if strings.HasPrefix(src[1:], "reload") {
|
if strings.HasPrefix(src[1:], "reload") {
|
||||||
prefix = symbol + "reload"
|
prefix = symbol + "reload"
|
||||||
|
} else if strings.HasPrefix(src[1:], "preview") {
|
||||||
|
prefix = symbol + "preview"
|
||||||
} else if src[len(prefix)] == '-' {
|
} else if src[len(prefix)] == '-' {
|
||||||
c := src[len(prefix)+1]
|
c := src[len(prefix)+1]
|
||||||
if c == 's' || c == 'S' {
|
if c == 's' || c == 'S' {
|
||||||
@@ -754,6 +759,8 @@ func parseKeymap(keymap map[int][]action, str string) {
|
|||||||
appendAction(actAcceptNonEmpty)
|
appendAction(actAcceptNonEmpty)
|
||||||
case "print-query":
|
case "print-query":
|
||||||
appendAction(actPrintQuery)
|
appendAction(actPrintQuery)
|
||||||
|
case "refresh-preview":
|
||||||
|
appendAction(actRefreshPreview)
|
||||||
case "replace-query":
|
case "replace-query":
|
||||||
appendAction(actReplaceQuery)
|
appendAction(actReplaceQuery)
|
||||||
case "backward-char":
|
case "backward-char":
|
||||||
@@ -859,6 +866,8 @@ func parseKeymap(keymap map[int][]action, str string) {
|
|||||||
switch t {
|
switch t {
|
||||||
case actReload:
|
case actReload:
|
||||||
offset = len("reload")
|
offset = len("reload")
|
||||||
|
case actPreview:
|
||||||
|
offset = len("preview")
|
||||||
case actExecuteSilent:
|
case actExecuteSilent:
|
||||||
offset = len("execute-silent")
|
offset = len("execute-silent")
|
||||||
case actExecuteMulti:
|
case actExecuteMulti:
|
||||||
@@ -896,6 +905,8 @@ func isExecuteAction(str string) actionType {
|
|||||||
switch prefix {
|
switch prefix {
|
||||||
case "reload":
|
case "reload":
|
||||||
return actReload
|
return actReload
|
||||||
|
case "preview":
|
||||||
|
return actPreview
|
||||||
case "execute":
|
case "execute":
|
||||||
return actExecute
|
return actExecute
|
||||||
case "execute-silent":
|
case "execute-silent":
|
||||||
@@ -984,6 +995,7 @@ func parsePreviewWindow(opts *previewOpts, input string) {
|
|||||||
|
|
||||||
tokens := strings.Split(input, ":")
|
tokens := strings.Split(input, ":")
|
||||||
sizeRegex := regexp.MustCompile("^[0-9]+%?$")
|
sizeRegex := regexp.MustCompile("^[0-9]+%?$")
|
||||||
|
offsetRegex := regexp.MustCompile("^\\+([0-9]+|{-?[0-9]+})(-[0-9]+)?$")
|
||||||
for _, token := range tokens {
|
for _, token := range tokens {
|
||||||
switch token {
|
switch token {
|
||||||
case "":
|
case "":
|
||||||
@@ -1006,8 +1018,10 @@ func parsePreviewWindow(opts *previewOpts, input string) {
|
|||||||
default:
|
default:
|
||||||
if sizeRegex.MatchString(token) {
|
if sizeRegex.MatchString(token) {
|
||||||
opts.size = parseSize(token, 99, "window size")
|
opts.size = parseSize(token, 99, "window size")
|
||||||
|
} else if offsetRegex.MatchString(token) {
|
||||||
|
opts.scroll = token[1:]
|
||||||
} else {
|
} else {
|
||||||
errorExit("invalid preview window layout: " + input)
|
errorExit("invalid preview window option: " + token)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1260,7 +1274,7 @@ func parseOptions(opts *Options, allArgs []string) {
|
|||||||
opts.Preview.command = ""
|
opts.Preview.command = ""
|
||||||
case "--preview-window":
|
case "--preview-window":
|
||||||
parsePreviewWindow(&opts.Preview,
|
parsePreviewWindow(&opts.Preview,
|
||||||
nextString(allArgs, &i, "preview window layout required: [up|down|left|right][:SIZE[%]][:noborder][:wrap][:hidden]"))
|
nextString(allArgs, &i, "preview window layout required: [up|down|left|right][:SIZE[%]][:noborder][:wrap][:hidden][:+SCROLL[-OFFSET]]"))
|
||||||
case "--height":
|
case "--height":
|
||||||
opts.Height = parseHeight(nextString(allArgs, &i, "height required: HEIGHT[%]"))
|
opts.Height = parseHeight(nextString(allArgs, &i, "height required: HEIGHT[%]"))
|
||||||
case "--min-height":
|
case "--min-height":
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ type term struct {
|
|||||||
inv bool
|
inv bool
|
||||||
text []rune
|
text []rune
|
||||||
caseSensitive bool
|
caseSensitive bool
|
||||||
|
normalize bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the string representation of a term.
|
// String returns the string representation of a term.
|
||||||
@@ -128,6 +129,8 @@ func BuildPattern(fuzzy bool, fuzzyAlgo algo.Algo, extended bool, caseMode Case,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
lowerString := strings.ToLower(asString)
|
lowerString := strings.ToLower(asString)
|
||||||
|
normalize = normalize &&
|
||||||
|
lowerString == string(algo.NormalizeRunes([]rune(lowerString)))
|
||||||
caseSensitive = caseMode == CaseRespect ||
|
caseSensitive = caseMode == CaseRespect ||
|
||||||
caseMode == CaseSmart && lowerString != asString
|
caseMode == CaseSmart && lowerString != asString
|
||||||
if !caseSensitive {
|
if !caseSensitive {
|
||||||
@@ -173,6 +176,8 @@ func parseTerms(fuzzy bool, caseMode Case, normalize bool, str string) []termSet
|
|||||||
lowerText := strings.ToLower(text)
|
lowerText := strings.ToLower(text)
|
||||||
caseSensitive := caseMode == CaseRespect ||
|
caseSensitive := caseMode == CaseRespect ||
|
||||||
caseMode == CaseSmart && text != lowerText
|
caseMode == CaseSmart && text != lowerText
|
||||||
|
normalizeTerm := normalize &&
|
||||||
|
lowerText == string(algo.NormalizeRunes([]rune(lowerText)))
|
||||||
if !caseSensitive {
|
if !caseSensitive {
|
||||||
text = lowerText
|
text = lowerText
|
||||||
}
|
}
|
||||||
@@ -222,14 +227,15 @@ func parseTerms(fuzzy bool, caseMode Case, normalize bool, str string) []termSet
|
|||||||
set = termSet{}
|
set = termSet{}
|
||||||
}
|
}
|
||||||
textRunes := []rune(text)
|
textRunes := []rune(text)
|
||||||
if normalize {
|
if normalizeTerm {
|
||||||
textRunes = algo.NormalizeRunes(textRunes)
|
textRunes = algo.NormalizeRunes(textRunes)
|
||||||
}
|
}
|
||||||
set = append(set, term{
|
set = append(set, term{
|
||||||
typ: typ,
|
typ: typ,
|
||||||
inv: inv,
|
inv: inv,
|
||||||
text: textRunes,
|
text: textRunes,
|
||||||
caseSensitive: caseSensitive})
|
caseSensitive: caseSensitive,
|
||||||
|
normalize: normalizeTerm})
|
||||||
switchSet = true
|
switchSet = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -360,7 +366,7 @@ func (p *Pattern) extendedMatch(item *Item, withPos bool, slab *util.Slab) ([]Of
|
|||||||
matched := false
|
matched := false
|
||||||
for _, term := range termSet {
|
for _, term := range termSet {
|
||||||
pfun := p.procFun[term.typ]
|
pfun := p.procFun[term.typ]
|
||||||
off, score, pos := p.iter(pfun, input, term.caseSensitive, p.normalize, p.forward, term.text, withPos, slab)
|
off, score, pos := p.iter(pfun, input, term.caseSensitive, term.normalize, p.forward, term.text, withPos, slab)
|
||||||
if sidx := off[0]; sidx >= 0 {
|
if sidx := off[0]; sidx >= 0 {
|
||||||
if term.inv {
|
if term.inv {
|
||||||
continue
|
continue
|
||||||
|
|||||||
171
src/terminal.go
171
src/terminal.go
@@ -23,12 +23,14 @@ import (
|
|||||||
// import "github.com/pkg/profile"
|
// import "github.com/pkg/profile"
|
||||||
|
|
||||||
var placeholder *regexp.Regexp
|
var placeholder *regexp.Regexp
|
||||||
|
var numericPrefix *regexp.Regexp
|
||||||
var activeTempFiles []string
|
var activeTempFiles []string
|
||||||
|
|
||||||
const ellipsis string = ".."
|
const ellipsis string = ".."
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
placeholder = regexp.MustCompile(`\\?(?:{[+sf]*[0-9,-.]*}|{q}|{\+?f?nf?})`)
|
placeholder = regexp.MustCompile(`\\?(?:{[+sf]*[0-9,-.]*}|{q}|{\+?f?nf?})`)
|
||||||
|
numericPrefix = regexp.MustCompile(`^[[:punct:]]*([0-9]+)`)
|
||||||
activeTempFiles = []string{}
|
activeTempFiles = []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +66,7 @@ type Terminal struct {
|
|||||||
initDelay time.Duration
|
initDelay time.Duration
|
||||||
infoStyle infoStyle
|
infoStyle infoStyle
|
||||||
spinner []string
|
spinner []string
|
||||||
prompt string
|
prompt func()
|
||||||
promptLen int
|
promptLen int
|
||||||
pointer string
|
pointer string
|
||||||
pointerLen int
|
pointerLen int
|
||||||
@@ -224,10 +226,12 @@ const (
|
|||||||
actJump
|
actJump
|
||||||
actJumpAccept
|
actJumpAccept
|
||||||
actPrintQuery
|
actPrintQuery
|
||||||
|
actRefreshPreview
|
||||||
actReplaceQuery
|
actReplaceQuery
|
||||||
actToggleSort
|
actToggleSort
|
||||||
actTogglePreview
|
actTogglePreview
|
||||||
actTogglePreviewWrap
|
actTogglePreviewWrap
|
||||||
|
actPreview
|
||||||
actPreviewUp
|
actPreviewUp
|
||||||
actPreviewDown
|
actPreviewDown
|
||||||
actPreviewPageUp
|
actPreviewPageUp
|
||||||
@@ -255,6 +259,16 @@ type searchRequest struct {
|
|||||||
command *string
|
command *string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type previewRequest struct {
|
||||||
|
template string
|
||||||
|
list []*Item
|
||||||
|
}
|
||||||
|
|
||||||
|
type previewResult struct {
|
||||||
|
content string
|
||||||
|
offset int
|
||||||
|
}
|
||||||
|
|
||||||
func toActions(types ...actionType) []action {
|
func toActions(types ...actionType) []action {
|
||||||
actions := make([]action, len(types))
|
actions := make([]action, len(types))
|
||||||
for idx, t := range types {
|
for idx, t := range types {
|
||||||
@@ -326,6 +340,17 @@ func trimQuery(query string) []rune {
|
|||||||
return []rune(strings.Replace(query, "\t", " ", -1))
|
return []rune(strings.Replace(query, "\t", " ", -1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hasPreviewAction(opts *Options) bool {
|
||||||
|
for _, actions := range opts.Keymap {
|
||||||
|
for _, action := range actions {
|
||||||
|
if action.t == actPreview {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// NewTerminal returns new Terminal object
|
// NewTerminal returns new Terminal object
|
||||||
func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
||||||
input := trimQuery(opts.Query)
|
input := trimQuery(opts.Query)
|
||||||
@@ -343,7 +368,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
|||||||
delay = initialDelay
|
delay = initialDelay
|
||||||
}
|
}
|
||||||
var previewBox *util.EventBox
|
var previewBox *util.EventBox
|
||||||
if len(opts.Preview.command) > 0 {
|
if len(opts.Preview.command) > 0 || hasPreviewAction(opts) {
|
||||||
previewBox = util.NewEventBox()
|
previewBox = util.NewEventBox()
|
||||||
}
|
}
|
||||||
strongAttr := tui.Bold
|
strongAttr := tui.Bold
|
||||||
@@ -382,8 +407,8 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
|||||||
}
|
}
|
||||||
renderer = tui.NewLightRenderer(opts.Theme, opts.Black, opts.Mouse, opts.Tabstop, opts.ClearOnExit, false, maxHeightFunc)
|
renderer = tui.NewLightRenderer(opts.Theme, opts.Black, opts.Mouse, opts.Tabstop, opts.ClearOnExit, false, maxHeightFunc)
|
||||||
}
|
}
|
||||||
wordRubout := "[^[:alnum:]][[:alnum:]]"
|
wordRubout := "[^\\pL\\pN][\\pL\\pN]"
|
||||||
wordNext := "[[:alnum:]][^[:alnum:]]|(.$)"
|
wordNext := "[\\pL\\pN][^\\pL\\pN]|(.$)"
|
||||||
if opts.FileWord {
|
if opts.FileWord {
|
||||||
sep := regexp.QuoteMeta(string(os.PathSeparator))
|
sep := regexp.QuoteMeta(string(os.PathSeparator))
|
||||||
wordRubout = fmt.Sprintf("%s[^%s]", sep, sep)
|
wordRubout = fmt.Sprintf("%s[^%s]", sep, sep)
|
||||||
@@ -451,7 +476,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
|||||||
killChan: make(chan int),
|
killChan: make(chan int),
|
||||||
tui: renderer,
|
tui: renderer,
|
||||||
initFunc: func() { renderer.Init() }}
|
initFunc: func() { renderer.Init() }}
|
||||||
t.prompt, t.promptLen = t.processTabs([]rune(opts.Prompt), 0)
|
t.prompt, t.promptLen = t.parsePrompt(opts.Prompt)
|
||||||
t.pointer, t.pointerLen = t.processTabs([]rune(opts.Pointer), 0)
|
t.pointer, t.pointerLen = t.processTabs([]rune(opts.Pointer), 0)
|
||||||
t.marker, t.markerLen = t.processTabs([]rune(opts.Marker), 0)
|
t.marker, t.markerLen = t.processTabs([]rune(opts.Marker), 0)
|
||||||
// Pre-calculated empty pointer and marker signs
|
// Pre-calculated empty pointer and marker signs
|
||||||
@@ -461,6 +486,19 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
|||||||
return &t
|
return &t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) parsePrompt(prompt string) (func(), int) {
|
||||||
|
var state *ansiState
|
||||||
|
trimmed, colors, _ := extractColor(prompt, state, nil)
|
||||||
|
item := &Item{text: util.ToChars([]byte(trimmed)), colors: colors}
|
||||||
|
output := func() {
|
||||||
|
t.printHighlighted(
|
||||||
|
Result{item: item}, t.strong, tui.ColPrompt, tui.ColPrompt, false, false)
|
||||||
|
}
|
||||||
|
_, promptLen := t.processTabs([]rune(trimmed), 0)
|
||||||
|
|
||||||
|
return output, promptLen
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Terminal) noInfoLine() bool {
|
func (t *Terminal) noInfoLine() bool {
|
||||||
return t.infoStyle != infoDefault
|
return t.infoStyle != infoDefault
|
||||||
}
|
}
|
||||||
@@ -762,7 +800,7 @@ func (t *Terminal) placeCursor() {
|
|||||||
|
|
||||||
func (t *Terminal) printPrompt() {
|
func (t *Terminal) printPrompt() {
|
||||||
t.move(0, 0, true)
|
t.move(0, 0, true)
|
||||||
t.window.CPrint(tui.ColPrompt, t.strong, t.prompt)
|
t.prompt()
|
||||||
|
|
||||||
before, after := t.updatePromptOffset()
|
before, after := t.updatePromptOffset()
|
||||||
t.window.CPrint(tui.ColNormal, t.strong, string(before))
|
t.window.CPrint(tui.ColNormal, t.strong, string(before))
|
||||||
@@ -1196,7 +1234,8 @@ func findLastMatch(pattern string, str string) int {
|
|||||||
if locs == nil {
|
if locs == nil {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
return locs[len(locs)-1][0]
|
prefix := []rune(str[:locs[len(locs)-1][0]])
|
||||||
|
return len(prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
func findFirstMatch(pattern string, str string) int {
|
func findFirstMatch(pattern string, str string) int {
|
||||||
@@ -1208,7 +1247,8 @@ func findFirstMatch(pattern string, str string) int {
|
|||||||
if loc == nil {
|
if loc == nil {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
return loc[0]
|
prefix := []rune(str[:loc[0]])
|
||||||
|
return len(prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
func copySlice(slice []rune) []rune {
|
func copySlice(slice []rune) []rune {
|
||||||
@@ -1316,6 +1356,43 @@ func cleanTemporaryFiles() {
|
|||||||
activeTempFiles = []string{}
|
activeTempFiles = []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) replacePlaceholder(template string, forcePlus bool, input string, list []*Item) string {
|
||||||
|
return replacePlaceholder(
|
||||||
|
template, t.ansi, t.delimiter, t.printsep, forcePlus, input, list)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ascii to positive integer
|
||||||
|
func atopi(s string) int {
|
||||||
|
matches := numericPrefix.FindStringSubmatch(s)
|
||||||
|
if len(matches) < 2 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
n, e := strconv.Atoi(matches[1])
|
||||||
|
if e != nil || n < 1 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) evaluateScrollOffset(list []*Item) int {
|
||||||
|
offsetExpr := t.replacePlaceholder(t.preview.scroll, false, "", list)
|
||||||
|
nums := strings.Split(offsetExpr, "-")
|
||||||
|
switch len(nums) {
|
||||||
|
case 0:
|
||||||
|
return 0
|
||||||
|
case 1, 2:
|
||||||
|
base := atopi(nums[0])
|
||||||
|
if base == 0 {
|
||||||
|
return 0
|
||||||
|
} else if len(nums) == 1 {
|
||||||
|
return base - 1
|
||||||
|
}
|
||||||
|
return base - atopi(nums[1]) - 1
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func replacePlaceholder(template string, stripAnsi bool, delimiter Delimiter, printsep string, forcePlus bool, query string, allItems []*Item) string {
|
func replacePlaceholder(template string, stripAnsi bool, delimiter Delimiter, printsep string, forcePlus bool, query string, allItems []*Item) string {
|
||||||
current := allItems[:1]
|
current := allItems[:1]
|
||||||
selected := allItems[1:]
|
selected := allItems[1:]
|
||||||
@@ -1414,7 +1491,7 @@ func (t *Terminal) executeCommand(template string, forcePlus bool, background bo
|
|||||||
if !valid {
|
if !valid {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
command := replacePlaceholder(template, t.ansi, t.delimiter, t.printsep, forcePlus, string(t.input), list)
|
command := t.replacePlaceholder(template, forcePlus, string(t.input), list)
|
||||||
cmd := util.ExecCommand(command, false)
|
cmd := util.ExecCommand(command, false)
|
||||||
if !background {
|
if !background {
|
||||||
cmd.Stdin = os.Stdin
|
cmd.Stdin = os.Stdin
|
||||||
@@ -1422,13 +1499,13 @@ func (t *Terminal) executeCommand(template string, forcePlus bool, background bo
|
|||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
t.tui.Pause(true)
|
t.tui.Pause(true)
|
||||||
cmd.Run()
|
cmd.Run()
|
||||||
t.tui.Resume(true)
|
t.tui.Resume(true, false)
|
||||||
t.redraw()
|
t.redraw()
|
||||||
t.refresh()
|
t.refresh()
|
||||||
} else {
|
} else {
|
||||||
t.tui.Pause(false)
|
t.tui.Pause(false)
|
||||||
cmd.Run()
|
cmd.Run()
|
||||||
t.tui.Resume(false)
|
t.tui.Resume(false, false)
|
||||||
}
|
}
|
||||||
cleanTemporaryFiles()
|
cleanTemporaryFiles()
|
||||||
}
|
}
|
||||||
@@ -1583,20 +1660,23 @@ func (t *Terminal) Loop() {
|
|||||||
if t.hasPreviewer() {
|
if t.hasPreviewer() {
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
var request []*Item
|
var items []*Item
|
||||||
|
var commandTemplate string
|
||||||
t.previewBox.Wait(func(events *util.Events) {
|
t.previewBox.Wait(func(events *util.Events) {
|
||||||
for req, value := range *events {
|
for req, value := range *events {
|
||||||
switch req {
|
switch req {
|
||||||
case reqPreviewEnqueue:
|
case reqPreviewEnqueue:
|
||||||
request = value.([]*Item)
|
request := value.(previewRequest)
|
||||||
|
commandTemplate = request.template
|
||||||
|
items = request.list
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
events.Clear()
|
events.Clear()
|
||||||
})
|
})
|
||||||
// We don't display preview window if no match
|
// We don't display preview window if no match
|
||||||
if request[0] != nil {
|
if items[0] != nil {
|
||||||
command := replacePlaceholder(t.preview.command,
|
command := t.replacePlaceholder(commandTemplate, false, string(t.Input()), items)
|
||||||
t.ansi, t.delimiter, t.printsep, false, string(t.Input()), request)
|
offset := t.evaluateScrollOffset(items)
|
||||||
cmd := util.ExecCommand(command, true)
|
cmd := util.ExecCommand(command, true)
|
||||||
if t.pwindow != nil {
|
if t.pwindow != nil {
|
||||||
env := os.Environ()
|
env := os.Environ()
|
||||||
@@ -1639,11 +1719,11 @@ func (t *Terminal) Loop() {
|
|||||||
cmd.Wait()
|
cmd.Wait()
|
||||||
finishChan <- true
|
finishChan <- true
|
||||||
if out.Len() > 0 || !<-updateChan {
|
if out.Len() > 0 || !<-updateChan {
|
||||||
t.reqBox.Set(reqPreviewDisplay, out.String())
|
t.reqBox.Set(reqPreviewDisplay, previewResult{out.String(), offset})
|
||||||
}
|
}
|
||||||
cleanTemporaryFiles()
|
cleanTemporaryFiles()
|
||||||
} else {
|
} else {
|
||||||
t.reqBox.Set(reqPreviewDisplay, "")
|
t.reqBox.Set(reqPreviewDisplay, previewResult{"", 0})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -1659,6 +1739,14 @@ func (t *Terminal) Loop() {
|
|||||||
t.killPreview(code)
|
t.killPreview(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refreshPreview := func(command string) {
|
||||||
|
if len(command) > 0 && t.isPreviewEnabled() {
|
||||||
|
_, list := t.buildPlusList(command, false)
|
||||||
|
t.cancelPreview()
|
||||||
|
t.previewBox.Set(reqPreviewEnqueue, previewRequest{command, list})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
var focusedIndex int32 = minItem.Index()
|
var focusedIndex int32 = minItem.Index()
|
||||||
var version int64 = -1
|
var version int64 = -1
|
||||||
@@ -1685,11 +1773,7 @@ func (t *Terminal) Loop() {
|
|||||||
if focusedIndex != currentIndex || version != t.version {
|
if focusedIndex != currentIndex || version != t.version {
|
||||||
version = t.version
|
version = t.version
|
||||||
focusedIndex = currentIndex
|
focusedIndex = currentIndex
|
||||||
if t.isPreviewEnabled() {
|
refreshPreview(t.preview.command)
|
||||||
_, list := t.buildPlusList(t.preview.command, false)
|
|
||||||
t.cancelPreview()
|
|
||||||
t.previewBox.Set(reqPreviewEnqueue, list)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case reqJump:
|
case reqJump:
|
||||||
if t.merger.Length() == 0 {
|
if t.merger.Length() == 0 {
|
||||||
@@ -1701,7 +1785,7 @@ func (t *Terminal) Loop() {
|
|||||||
case reqRefresh:
|
case reqRefresh:
|
||||||
t.suppress = false
|
t.suppress = false
|
||||||
case reqReinit:
|
case reqReinit:
|
||||||
t.tui.Resume(t.fullscreen)
|
t.tui.Resume(t.fullscreen, true)
|
||||||
t.redraw()
|
t.redraw()
|
||||||
case reqRedraw:
|
case reqRedraw:
|
||||||
t.redraw()
|
t.redraw()
|
||||||
@@ -1713,9 +1797,10 @@ func (t *Terminal) Loop() {
|
|||||||
return exitNoMatch
|
return exitNoMatch
|
||||||
})
|
})
|
||||||
case reqPreviewDisplay:
|
case reqPreviewDisplay:
|
||||||
t.previewer.text = value.(string)
|
result := value.(previewResult)
|
||||||
|
t.previewer.text = result.content
|
||||||
t.previewer.lines = strings.Count(t.previewer.text, "\n")
|
t.previewer.lines = strings.Count(t.previewer.text, "\n")
|
||||||
t.previewer.offset = 0
|
t.previewer.offset = util.Constrain(result.offset, 0, t.previewer.lines-1)
|
||||||
t.printPreview()
|
t.printPreview()
|
||||||
case reqPreviewRefresh:
|
case reqPreviewRefresh:
|
||||||
t.printPreview()
|
t.printPreview()
|
||||||
@@ -1738,6 +1823,7 @@ func (t *Terminal) Loop() {
|
|||||||
for looping {
|
for looping {
|
||||||
var newCommand *string
|
var newCommand *string
|
||||||
changed := false
|
changed := false
|
||||||
|
beof := false
|
||||||
queryChanged := false
|
queryChanged := false
|
||||||
|
|
||||||
event := t.tui.GetChar()
|
event := t.tui.GetChar()
|
||||||
@@ -1754,6 +1840,14 @@ func (t *Terminal) Loop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
togglePreview := func(enabled bool) {
|
||||||
|
if t.previewer.enabled != enabled {
|
||||||
|
t.previewer.enabled = enabled
|
||||||
|
t.tui.Clear()
|
||||||
|
t.resizeWindows()
|
||||||
|
req(reqPrompt, reqList, reqInfo, reqHeader)
|
||||||
|
}
|
||||||
|
}
|
||||||
toggle := func() bool {
|
toggle := func() bool {
|
||||||
if t.cy < t.merger.Length() && t.toggleItem(t.merger.Get(t.cy).item) {
|
if t.cy < t.merger.Length() && t.toggleItem(t.merger.Get(t.cy).item) {
|
||||||
req(reqInfo)
|
req(reqInfo)
|
||||||
@@ -1802,17 +1896,15 @@ func (t *Terminal) Loop() {
|
|||||||
return false
|
return false
|
||||||
case actTogglePreview:
|
case actTogglePreview:
|
||||||
if t.hasPreviewer() {
|
if t.hasPreviewer() {
|
||||||
t.previewer.enabled = !t.previewer.enabled
|
togglePreview(!t.previewer.enabled)
|
||||||
t.tui.Clear()
|
|
||||||
t.resizeWindows()
|
|
||||||
if t.previewer.enabled {
|
if t.previewer.enabled {
|
||||||
valid, list := t.buildPlusList(t.preview.command, false)
|
valid, list := t.buildPlusList(t.preview.command, false)
|
||||||
if valid {
|
if valid {
|
||||||
t.cancelPreview()
|
t.cancelPreview()
|
||||||
t.previewBox.Set(reqPreviewEnqueue, list)
|
t.previewBox.Set(reqPreviewEnqueue,
|
||||||
|
previewRequest{t.preview.command, list})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
req(reqPrompt, reqList, reqInfo, reqHeader)
|
|
||||||
}
|
}
|
||||||
case actTogglePreviewWrap:
|
case actTogglePreviewWrap:
|
||||||
if t.hasPreviewWindow() {
|
if t.hasPreviewWindow() {
|
||||||
@@ -1846,6 +1938,11 @@ func (t *Terminal) Loop() {
|
|||||||
}
|
}
|
||||||
case actPrintQuery:
|
case actPrintQuery:
|
||||||
req(reqPrintQuery)
|
req(reqPrintQuery)
|
||||||
|
case actPreview:
|
||||||
|
togglePreview(true)
|
||||||
|
refreshPreview(a.a)
|
||||||
|
case actRefreshPreview:
|
||||||
|
refreshPreview(t.preview.command)
|
||||||
case actReplaceQuery:
|
case actReplaceQuery:
|
||||||
if t.cy >= 0 && t.cy < t.merger.Length() {
|
if t.cy >= 0 && t.cy < t.merger.Length() {
|
||||||
t.input = t.merger.Get(t.cy).item.text.ToRunes()
|
t.input = t.merger.Get(t.cy).item.text.ToRunes()
|
||||||
@@ -1881,6 +1978,7 @@ func (t *Terminal) Loop() {
|
|||||||
t.cx++
|
t.cx++
|
||||||
}
|
}
|
||||||
case actBackwardDeleteChar:
|
case actBackwardDeleteChar:
|
||||||
|
beof = len(t.input) == 0
|
||||||
if t.cx > 0 {
|
if t.cx > 0 {
|
||||||
t.input = append(t.input[:t.cx-1], t.input[t.cx:]...)
|
t.input = append(t.input[:t.cx-1], t.input[t.cx:]...)
|
||||||
t.cx--
|
t.cx--
|
||||||
@@ -1973,16 +2071,19 @@ func (t *Terminal) Loop() {
|
|||||||
t.vset(0)
|
t.vset(0)
|
||||||
req(reqList)
|
req(reqList)
|
||||||
case actUnixLineDiscard:
|
case actUnixLineDiscard:
|
||||||
|
beof = len(t.input) == 0
|
||||||
if t.cx > 0 {
|
if t.cx > 0 {
|
||||||
t.yanked = copySlice(t.input[:t.cx])
|
t.yanked = copySlice(t.input[:t.cx])
|
||||||
t.input = t.input[t.cx:]
|
t.input = t.input[t.cx:]
|
||||||
t.cx = 0
|
t.cx = 0
|
||||||
}
|
}
|
||||||
case actUnixWordRubout:
|
case actUnixWordRubout:
|
||||||
|
beof = len(t.input) == 0
|
||||||
if t.cx > 0 {
|
if t.cx > 0 {
|
||||||
t.rubout("\\s\\S")
|
t.rubout("\\s\\S")
|
||||||
}
|
}
|
||||||
case actBackwardKillWord:
|
case actBackwardKillWord:
|
||||||
|
beof = len(t.input) == 0
|
||||||
if t.cx > 0 {
|
if t.cx > 0 {
|
||||||
t.rubout(t.wordRubout)
|
t.rubout(t.wordRubout)
|
||||||
}
|
}
|
||||||
@@ -2118,8 +2219,7 @@ func (t *Terminal) Loop() {
|
|||||||
valid = !slot || query
|
valid = !slot || query
|
||||||
}
|
}
|
||||||
if valid {
|
if valid {
|
||||||
command := replacePlaceholder(a.a,
|
command := t.replacePlaceholder(a.a, false, string(t.input), list)
|
||||||
t.ansi, t.delimiter, t.printsep, false, string(t.input), list)
|
|
||||||
newCommand = &command
|
newCommand = &command
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2145,6 +2245,11 @@ func (t *Terminal) Loop() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if onEOFs, prs := t.keymap[tui.BackwardEOF]; beof && prs {
|
||||||
|
if !doActions(onEOFs, tui.BackwardEOF) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if mapkey == tui.Rune {
|
if mapkey == tui.Rune {
|
||||||
if idx := strings.IndexRune(t.jumpLabels, event.Char); idx >= 0 && idx < t.maxItems() && idx < t.merger.Length() {
|
if idx := strings.IndexRune(t.jumpLabels, event.Char); idx >= 0 && idx < t.maxItems() && idx < t.merger.Length() {
|
||||||
|
|||||||
@@ -25,12 +25,12 @@ const (
|
|||||||
Reverse = Attr(1 << 6)
|
Reverse = Attr(1 << 6)
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *FullscreenRenderer) Init() {}
|
func (r *FullscreenRenderer) Init() {}
|
||||||
func (r *FullscreenRenderer) Pause(bool) {}
|
func (r *FullscreenRenderer) Pause(bool) {}
|
||||||
func (r *FullscreenRenderer) Resume(bool) {}
|
func (r *FullscreenRenderer) Resume(bool, bool) {}
|
||||||
func (r *FullscreenRenderer) Clear() {}
|
func (r *FullscreenRenderer) Clear() {}
|
||||||
func (r *FullscreenRenderer) Refresh() {}
|
func (r *FullscreenRenderer) Refresh() {}
|
||||||
func (r *FullscreenRenderer) Close() {}
|
func (r *FullscreenRenderer) Close() {}
|
||||||
|
|
||||||
func (r *FullscreenRenderer) DoesAutoWrap() bool { return false }
|
func (r *FullscreenRenderer) DoesAutoWrap() bool { return false }
|
||||||
func (r *FullscreenRenderer) GetChar() Event { return Event{} }
|
func (r *FullscreenRenderer) GetChar() Event { return Event{} }
|
||||||
|
|||||||
102
src/tui/light.go
102
src/tui/light.go
@@ -28,6 +28,7 @@ const (
|
|||||||
const consoleDevice string = "/dev/tty"
|
const consoleDevice string = "/dev/tty"
|
||||||
|
|
||||||
var offsetRegexp *regexp.Regexp = regexp.MustCompile("(.*)\x1b\\[([0-9]+);([0-9]+)R")
|
var offsetRegexp *regexp.Regexp = regexp.MustCompile("(.*)\x1b\\[([0-9]+);([0-9]+)R")
|
||||||
|
var offsetRegexpBegin *regexp.Regexp = regexp.MustCompile("^\x1b\\[[0-9]+;[0-9]+R")
|
||||||
|
|
||||||
func (r *LightRenderer) stderr(str string) {
|
func (r *LightRenderer) stderr(str string) {
|
||||||
r.stderrInternal(str, true)
|
r.stderrInternal(str, true)
|
||||||
@@ -333,6 +334,13 @@ func (r *LightRenderer) escSequence(sz *int) Event {
|
|||||||
if len(r.buffer) < 2 {
|
if len(r.buffer) < 2 {
|
||||||
return Event{ESC, 0, nil}
|
return Event{ESC, 0, nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loc := offsetRegexpBegin.FindIndex(r.buffer)
|
||||||
|
if loc != nil && loc[0] == 0 {
|
||||||
|
*sz = loc[1]
|
||||||
|
return Event{Invalid, 0, nil}
|
||||||
|
}
|
||||||
|
|
||||||
*sz = 2
|
*sz = 2
|
||||||
if r.buffer[1] >= 1 && r.buffer[1] <= 'z'-'a'+1 {
|
if r.buffer[1] >= 1 && r.buffer[1] <= 'z'-'a'+1 {
|
||||||
return Event{int(CtrlAltA + r.buffer[1] - 1), 0, nil}
|
return Event{int(CtrlAltA + r.buffer[1] - 1), 0, nil}
|
||||||
@@ -345,81 +353,81 @@ func (r *LightRenderer) escSequence(sz *int) Event {
|
|||||||
switch r.buffer[1] {
|
switch r.buffer[1] {
|
||||||
case ESC:
|
case ESC:
|
||||||
return Event{ESC, 0, nil}
|
return Event{ESC, 0, nil}
|
||||||
case 32:
|
case ' ':
|
||||||
return Event{AltSpace, 0, nil}
|
return Event{AltSpace, 0, nil}
|
||||||
case 47:
|
case '/':
|
||||||
return Event{AltSlash, 0, nil}
|
return Event{AltSlash, 0, nil}
|
||||||
case 98:
|
case 'b':
|
||||||
return Event{AltB, 0, nil}
|
return Event{AltB, 0, nil}
|
||||||
case 100:
|
case 'd':
|
||||||
return Event{AltD, 0, nil}
|
return Event{AltD, 0, nil}
|
||||||
case 102:
|
case 'f':
|
||||||
return Event{AltF, 0, nil}
|
return Event{AltF, 0, nil}
|
||||||
case 127:
|
case 127:
|
||||||
return Event{AltBS, 0, nil}
|
return Event{AltBS, 0, nil}
|
||||||
case 91, 79:
|
case '[', 'O':
|
||||||
if len(r.buffer) < 3 {
|
if len(r.buffer) < 3 {
|
||||||
return Event{Invalid, 0, nil}
|
return Event{Invalid, 0, nil}
|
||||||
}
|
}
|
||||||
*sz = 3
|
*sz = 3
|
||||||
switch r.buffer[2] {
|
switch r.buffer[2] {
|
||||||
case 68:
|
case 'D':
|
||||||
if alt {
|
if alt {
|
||||||
return Event{AltLeft, 0, nil}
|
return Event{AltLeft, 0, nil}
|
||||||
}
|
}
|
||||||
return Event{Left, 0, nil}
|
return Event{Left, 0, nil}
|
||||||
case 67:
|
case 'C':
|
||||||
if alt {
|
if alt {
|
||||||
// Ugh..
|
// Ugh..
|
||||||
return Event{AltRight, 0, nil}
|
return Event{AltRight, 0, nil}
|
||||||
}
|
}
|
||||||
return Event{Right, 0, nil}
|
return Event{Right, 0, nil}
|
||||||
case 66:
|
case 'B':
|
||||||
if alt {
|
if alt {
|
||||||
return Event{AltDown, 0, nil}
|
return Event{AltDown, 0, nil}
|
||||||
}
|
}
|
||||||
return Event{Down, 0, nil}
|
return Event{Down, 0, nil}
|
||||||
case 65:
|
case 'A':
|
||||||
if alt {
|
if alt {
|
||||||
return Event{AltUp, 0, nil}
|
return Event{AltUp, 0, nil}
|
||||||
}
|
}
|
||||||
return Event{Up, 0, nil}
|
return Event{Up, 0, nil}
|
||||||
case 90:
|
case 'Z':
|
||||||
return Event{BTab, 0, nil}
|
return Event{BTab, 0, nil}
|
||||||
case 72:
|
case 'H':
|
||||||
return Event{Home, 0, nil}
|
return Event{Home, 0, nil}
|
||||||
case 70:
|
case 'F':
|
||||||
return Event{End, 0, nil}
|
return Event{End, 0, nil}
|
||||||
case 77:
|
case 'M':
|
||||||
return r.mouseSequence(sz)
|
return r.mouseSequence(sz)
|
||||||
case 80:
|
case 'P':
|
||||||
return Event{F1, 0, nil}
|
return Event{F1, 0, nil}
|
||||||
case 81:
|
case 'Q':
|
||||||
return Event{F2, 0, nil}
|
return Event{F2, 0, nil}
|
||||||
case 82:
|
case 'R':
|
||||||
return Event{F3, 0, nil}
|
return Event{F3, 0, nil}
|
||||||
case 83:
|
case 'S':
|
||||||
return Event{F4, 0, nil}
|
return Event{F4, 0, nil}
|
||||||
case 49, 50, 51, 52, 53, 54:
|
case '1', '2', '3', '4', '5', '6':
|
||||||
if len(r.buffer) < 4 {
|
if len(r.buffer) < 4 {
|
||||||
return Event{Invalid, 0, nil}
|
return Event{Invalid, 0, nil}
|
||||||
}
|
}
|
||||||
*sz = 4
|
*sz = 4
|
||||||
switch r.buffer[2] {
|
switch r.buffer[2] {
|
||||||
case 50:
|
case '2':
|
||||||
if r.buffer[3] == 126 {
|
if r.buffer[3] == '~' {
|
||||||
return Event{Insert, 0, nil}
|
return Event{Insert, 0, nil}
|
||||||
}
|
}
|
||||||
if len(r.buffer) > 4 && r.buffer[4] == 126 {
|
if len(r.buffer) > 4 && r.buffer[4] == '~' {
|
||||||
*sz = 5
|
*sz = 5
|
||||||
switch r.buffer[3] {
|
switch r.buffer[3] {
|
||||||
case 48:
|
case '0':
|
||||||
return Event{F9, 0, nil}
|
return Event{F9, 0, nil}
|
||||||
case 49:
|
case '1':
|
||||||
return Event{F10, 0, nil}
|
return Event{F10, 0, nil}
|
||||||
case 51:
|
case '3':
|
||||||
return Event{F11, 0, nil}
|
return Event{F11, 0, nil}
|
||||||
case 52:
|
case '4':
|
||||||
return Event{F12, 0, nil}
|
return Event{F12, 0, nil}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -431,37 +439,37 @@ func (r *LightRenderer) escSequence(sz *int) Event {
|
|||||||
return r.GetChar()
|
return r.GetChar()
|
||||||
}
|
}
|
||||||
return Event{Invalid, 0, nil} // INS
|
return Event{Invalid, 0, nil} // INS
|
||||||
case 51:
|
case '3':
|
||||||
return Event{Del, 0, nil}
|
return Event{Del, 0, nil}
|
||||||
case 52:
|
case '4':
|
||||||
return Event{End, 0, nil}
|
return Event{End, 0, nil}
|
||||||
case 53:
|
case '5':
|
||||||
return Event{PgUp, 0, nil}
|
return Event{PgUp, 0, nil}
|
||||||
case 54:
|
case '6':
|
||||||
return Event{PgDn, 0, nil}
|
return Event{PgDn, 0, nil}
|
||||||
case 49:
|
case '1':
|
||||||
switch r.buffer[3] {
|
switch r.buffer[3] {
|
||||||
case 126:
|
case '~':
|
||||||
return Event{Home, 0, nil}
|
return Event{Home, 0, nil}
|
||||||
case 49, 50, 51, 52, 53, 55, 56, 57:
|
case '1', '2', '3', '4', '5', '7', '8', '9':
|
||||||
if len(r.buffer) == 5 && r.buffer[4] == 126 {
|
if len(r.buffer) == 5 && r.buffer[4] == '~' {
|
||||||
*sz = 5
|
*sz = 5
|
||||||
switch r.buffer[3] {
|
switch r.buffer[3] {
|
||||||
case 49:
|
case '1':
|
||||||
return Event{F1, 0, nil}
|
return Event{F1, 0, nil}
|
||||||
case 50:
|
case '2':
|
||||||
return Event{F2, 0, nil}
|
return Event{F2, 0, nil}
|
||||||
case 51:
|
case '3':
|
||||||
return Event{F3, 0, nil}
|
return Event{F3, 0, nil}
|
||||||
case 52:
|
case '4':
|
||||||
return Event{F4, 0, nil}
|
return Event{F4, 0, nil}
|
||||||
case 53:
|
case '5':
|
||||||
return Event{F5, 0, nil}
|
return Event{F5, 0, nil}
|
||||||
case 55:
|
case '7':
|
||||||
return Event{F6, 0, nil}
|
return Event{F6, 0, nil}
|
||||||
case 56:
|
case '8':
|
||||||
return Event{F7, 0, nil}
|
return Event{F7, 0, nil}
|
||||||
case 57:
|
case '9':
|
||||||
return Event{F8, 0, nil}
|
return Event{F8, 0, nil}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -561,7 +569,7 @@ func (r *LightRenderer) Pause(clear bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LightRenderer) Resume(clear bool) {
|
func (r *LightRenderer) Resume(clear bool, sigcont bool) {
|
||||||
r.setupTerminal()
|
r.setupTerminal()
|
||||||
if clear {
|
if clear {
|
||||||
if r.fullscreen {
|
if r.fullscreen {
|
||||||
@@ -570,10 +578,10 @@ func (r *LightRenderer) Resume(clear bool) {
|
|||||||
r.rmcup()
|
r.rmcup()
|
||||||
}
|
}
|
||||||
r.flush()
|
r.flush()
|
||||||
} else if !r.fullscreen && r.mouse {
|
} else if sigcont && !r.fullscreen && r.mouse {
|
||||||
// NOTE: Resume(false) is only called on SIGCONT after SIGSTOP.
|
// NOTE: SIGCONT (Coming back from CTRL-Z):
|
||||||
// And It's highly likely that the offset we obtained at the beginning will
|
// It's highly likely that the offset we obtained at the beginning is
|
||||||
// no longer be correct, so we simply disable mouse input.
|
// no longer correct, so we simply disable mouse input.
|
||||||
r.csi("?1000l")
|
r.csi("?1000l")
|
||||||
r.mouse = false
|
r.mouse = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -394,7 +394,7 @@ func (r *FullscreenRenderer) Pause(clear bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *FullscreenRenderer) Resume(clear bool) {
|
func (r *FullscreenRenderer) Resume(clear bool, sigcont bool) {
|
||||||
if clear {
|
if clear {
|
||||||
r.initScreen()
|
r.initScreen()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ const (
|
|||||||
F12
|
F12
|
||||||
|
|
||||||
Change
|
Change
|
||||||
|
BackwardEOF
|
||||||
|
|
||||||
AltSpace
|
AltSpace
|
||||||
AltSlash
|
AltSlash
|
||||||
@@ -275,7 +276,7 @@ func MakeTransparentBorder() BorderStyle {
|
|||||||
type Renderer interface {
|
type Renderer interface {
|
||||||
Init()
|
Init()
|
||||||
Pause(clear bool)
|
Pause(clear bool)
|
||||||
Resume(clear bool)
|
Resume(clear bool, sigcont bool)
|
||||||
Clear()
|
Clear()
|
||||||
RefreshWindows(windows []Window)
|
RefreshWindows(windows []Window)
|
||||||
Refresh()
|
Refresh()
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# http://www.rubydoc.info/github/rest-client/rest-client/RestClient
|
# http://www.rubydoc.info/github/rest-client/rest-client/RestClient
|
||||||
require 'rest_client'
|
require 'rest_client'
|
||||||
require 'json'
|
require 'json'
|
||||||
|
|
||||||
if ARGV.length < 3
|
if ARGV.length < 3
|
||||||
puts "usage: #$0 <token> <version> <files...>"
|
puts "usage: #{$PROGRAM_NAME} <token> <version> <files...>"
|
||||||
exit 1
|
exit 1
|
||||||
end
|
end
|
||||||
|
|
||||||
token, version, *files = ARGV
|
token, version, *files = ARGV
|
||||||
base = "https://api.github.com/repos/junegunn/fzf-bin/releases"
|
base = 'https://api.github.com/repos/junegunn/fzf-bin/releases'
|
||||||
|
|
||||||
# List releases
|
# List releases
|
||||||
rels = JSON.parse(RestClient.get(base, :authorization => "token #{token}"))
|
rels = JSON.parse(RestClient.get(base, authorization: "token #{token}"))
|
||||||
rel = rels.find { |r| r['tag_name'] == version }
|
rel = rels.find { |r| r['tag_name'] == version }
|
||||||
unless rel
|
unless rel
|
||||||
puts "#{version} not found"
|
puts "#{version} not found"
|
||||||
@@ -21,25 +22,26 @@ unless rel
|
|||||||
end
|
end
|
||||||
|
|
||||||
# List assets
|
# List assets
|
||||||
assets = Hash[rel['assets'].map { |a| a.values_at *%w[name id] }]
|
assets = Hash[rel['assets'].map { |a| a.values_at('name', 'id') }]
|
||||||
|
|
||||||
files.select { |f| File.exists? f }.map do |file|
|
files.select { |f| File.exist?(f) }.map do |file|
|
||||||
Thread.new do
|
Thread.new do
|
||||||
name = File.basename file
|
name = File.basename(file)
|
||||||
|
|
||||||
if asset_id = assets[name]
|
if asset_id = assets[name] # rubocop:todo Lint/AssignmentInCondition
|
||||||
puts "#{name} found. Deleting asset id #{asset_id}."
|
puts "#{name} found. Deleting asset id #{asset_id}."
|
||||||
RestClient.delete "#{base}/assets/#{asset_id}",
|
RestClient.delete("#{base}/assets/#{asset_id}",
|
||||||
:authorization => "token #{token}"
|
authorization: "token #{token}")
|
||||||
else
|
else
|
||||||
puts "#{name} not found"
|
puts "#{name} not found"
|
||||||
end
|
end
|
||||||
|
|
||||||
puts "Uploading #{name}"
|
puts "Uploading #{name}"
|
||||||
RestClient.post(
|
RestClient.post(
|
||||||
"#{base.sub 'api', 'uploads'}/#{rel['id']}/assets?name=#{name}",
|
"#{base.sub('api', 'uploads')}/#{rel['id']}/assets?name=#{name}",
|
||||||
File.read(file),
|
File.read(file),
|
||||||
:authorization => "token #{token}",
|
authorization: "token #{token}",
|
||||||
:content_type => "application/octet-stream")
|
content_type: 'application/octet-stream'
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end.each(&:join)
|
end.each(&:join)
|
||||||
|
|||||||
1548
test/test_go.rb
1548
test/test_go.rb
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user