Compare commits

...

73 Commits

Author SHA1 Message Date
Junegunn Choi
fc7630a66d 0.23.1 2020-10-11 02:04:07 +09:00
Junegunn Choi
3248153d9f Add --preview-window=default for resetting the options 2020-10-11 01:54:39 +09:00
Junegunn Choi
246b9f3130 Simplify fzf-tmux script
# Should properly escape arguments
    FZF_DEFAULT_OPTS='--prompt "\$a`b\"c"' fzf-tmux --header $'$a\nb"c`d'
2020-10-09 23:02:03 +09:00
Junegunn Choi
865144850d Add nowrap, nocycle, nohidden for --preview-window
Close #2203
2020-10-09 21:56:16 +09:00
Junegunn Choi
d9752a4c21 Reset preview window flags that are not style-related
Fix #2203
2020-10-09 19:53:51 +09:00
Junegunn Choi
dba14d2630 0.23.0 2020-10-07 19:18:50 +09:00
Elvan Owen
2986e64a49 [completion] Make host completion handle source files without EOL 2020-10-06 20:54:42 +09:00
Junegunn Choi
1d8bd11b67 Fix preview window size calculation 2020-10-06 19:37:33 +09:00
Junegunn Choi
bafb99d520 Allow splitting preview-window options
e.g. --preview-window sharp --preview-window cycle
2020-10-06 18:44:13 +09:00
Junegunn Choi
3cc8a74a91 Add --preview-window option for cyclic scrolling
Close #2182
2020-10-06 10:05:57 +09:00
Tinmarino
c0aa5a438f Add preview-half-page-down and preview-half-page-up (#2145) 2020-10-05 21:58:56 +09:00
Junegunn Choi
825d401403 Show how to use reload action 2020-10-05 19:17:31 +09:00
Junegunn Choi
9dfca77c36 [zsh] Keep current $BUFFER on ALT-C
Ideally, we could only use `print -sr` to update the command history.
However, the "cd" command by ALT-C is added to the history only after we
finalize the current command by pressing an additional enter key.

i.e. The cd command from ALT-C is not visible when you hit Up arrow. But
it appears once you hit enter key.

So when the current buffer is empty, we use `zle accept-line` so that
the command history is immediately updated.

Close #2200
2020-10-03 14:55:02 +09:00
octaltree
82c4af2902 [zsh] Record cd execution in history (#2193) 2020-10-02 22:14:09 +09:00
Junegunn Choi
736344e151 Remove deprecated item from man page 2020-09-29 11:34:57 +09:00
Junegunn Choi
6f9663da62 Always allow preview/execute commands with no placeholder expressions
Fix #2017
2020-09-29 11:32:56 +09:00
Wenxuan
f8ae1786dd Fix items width limit (#2190) 2020-09-24 11:06:20 +09:00
Junegunn Choi
c60ed17583 [vim] Change the default layout to use popup window
The new default is

  { 'window' : { 'width': 0.9, 'height': 0.6, 'highlight': 'Normal' } }

The default highlight group for the border of the popup window is
'Comment', but 'Normal' seems to be a safer choice.

If you prefer the previous default, add this to your Vim configuration file:

  let g:fzf_layout = { 'down': '40%' }

(fzf will fall back to this if popup window is not supported)
2020-09-12 21:14:32 +09:00
Junegunn Choi
e0f0b5bcf9 Update CHANGELOG 2020-09-09 00:06:53 +09:00
Junegunn Choi
9e96073128 [vim] Expose fzf#exec() function 2020-09-09 00:02:37 +09:00
Junegunn Choi
0db65c22d3 [vim] Allow specifying popup width and height in absolute integer value
Fix https://github.com/junegunn/fzf.vim/issues/1116
2020-09-06 22:15:44 +09:00
Yuji Nakao
d785135606 [zsh] Fix the regular expression (#2140)
Fix the regular expression to capture the command containing asterisk.
2020-09-02 17:27:56 +09:00
Michael Kelley
ae15eda546 Add truecolor support for Windows, if available (#2156)
- Update to latest tcell which has 24 bit Windows support
- light renderer under Windows defaults to Dark256, if possible
- Respect TCELL_TRUECOLOR
- Remove tcell 1.3 references
2020-09-02 13:47:13 +09:00
Junegunn Choi
f2d44ab5a7 Revert horizontal padding around preview window on "noborder"
Use 2-space horizontal padding so that the preview content is aligned
with the candidate list when the position of the preview window is `up`
or `down`.
2020-08-23 17:17:57 +09:00
Junegunn Choi
43798fc2e8 Revert 1ab4289: Preview window of size 0 is allowed 2020-08-23 17:12:37 +09:00
Junegunn Choi
9dc4b40d7a Add more preview window options and reduce vertical padding on noborder
Fix #2138
Fix #2029
2020-08-23 17:05:45 +09:00
Junegunn Choi
1cb19dbf65 Support preview scroll offset relative to window height
Related: https://github.com/junegunn/fzf.vim/issues/1092
2020-08-23 15:57:49 +09:00
Junegunn Choi
1ab4289ad6 Disallow preview-window size of zero 2020-08-21 11:49:01 +09:00
Junegunn Choi
e2ae1b249c 0.22.0 2020-08-02 15:56:02 +09:00
Junegunn Choi
92b7efafca Ignore punctuation characters before and after preview offset column
This is to allow line numbers in a ctags output (e.g. 123;")
2020-08-02 10:03:17 +09:00
Junegunn Choi
f092e4038f Smart match of accented characters
Fix #1618
2020-07-28 13:06:57 +09:00
Junegunn Choi
aa5dae391b Fix handling of unicode characters in query string 2020-07-28 12:58:37 +09:00
Junegunn Choi
08a6fd4ad4 Fix Travis CI build: Use Go 1.14 2020-07-27 09:01:28 +09:00
Junegunn Choi
a61150a96c Allow negative field index in preview-window scroll offset 2020-07-27 00:30:25 +09:00
Junegunn Choi
0f9cb5590e Add preview window option for setting the initial scroll offset
Close #1057
Close #2120

  # 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
2020-07-27 00:27:03 +09:00
yuki yano
c0a83b27eb Fix failure of w:fzf_pushd unlet depending on timing (#2119) 2020-07-26 13:52:50 +09:00
Yanlin Sun
f79b1f71b8 [vim] Preserve current directory in case someone changes it (#2096)
Preserve current directory in case current directory is changed by others
after the call of s:open

Co-authored-by: Junegunn Choi <junegunn.c@gmail.com>
2020-07-15 13:20:56 +09:00
Junegunn Choi
8e027c445f Support ANSI colors in --prompt string
Close #2086
2020-07-05 16:16:46 +09:00
Atemu
dda3e3c39a README: Correct Nix distro support (#2051)
Nix can be installed on (almost) any Linux distro and on macOS.

See https://nixos.org/nix/ for more information.
2020-07-05 15:29:43 +09:00
anntnzrb
fd5157998c Void Linux installation instructions (#2100) 2020-07-03 23:14:12 +09:00
Junegunn Choi
e0217e8c79 Ignore cursor position report
Close #2081
2020-07-03 19:45:58 +09:00
Junegunn Choi
3ab1c42266 Use rune characters instaed of numbers in code 2020-07-03 19:41:19 +09:00
Junegunn Choi
d1676776aa Update CHANGELOG 2020-06-30 21:17:19 +09:00
Junegunn Choi
bdde69d011 [vim] Disable height calculation when 'preview' is found in the option string
Fix #2093

And we'll phase out height specification with `~` prefix.
2020-06-29 22:27:36 +09:00
Junegunn Choi
6dec42a33a Update version numbers in man pages 2020-06-29 22:07:48 +09:00
Junegunn Choi
199bc3f0ad Merge branch 'master' into devel 2020-06-21 22:43:03 +09:00
Junegunn Choi
17dd833925 Add preview action for --bind
Fix #2010
Fix #1638
2020-06-21 22:41:33 +09:00
Khon Trieu
4ec144c969 Accented character normalization for Vietnamese characters (#2090)
Fix #2088
2020-06-21 17:19:38 +09:00
Jan Edmund Lazo
3e36f2b0ac [nvim] Fix floating window requirements (#2089)
Vim 8.1.2371
05ad5ff0ab

Nvim 0.4.0
9a1675b065
2020-06-21 10:34:43 +09:00
Junegunn Choi
07a03b3e73 [vim] Make fzf#wrap support v:true and v:false as well
Fix #2087
2020-06-20 22:15:12 +09:00
Junegunn Choi
c33258832e Add refresh-preview action 2020-06-20 22:04:09 +09:00
Junegunn Choi
a7aa08ce07 Add backward-eof event for --bind 2020-06-07 23:07:03 +09:00
Ben
06d63a862e Fully qualify Expand-Archive (#2066)
If a user has the Powershell Community Extensions installed, it comes
with another command Expand-Archive that doesn't have a DestinationPath
argument, causing an error.
2020-06-07 10:57:23 +09:00
Janek
43d1c4c4b5 README: Use --line-range instead of head in bat example (#2064)
* Use --line-range instead of head in bat example

* README: extend preview section
2020-06-04 11:57:01 +09:00
Junegunn Choi
f81feb1e69 Revert file mode of key-bindings.zsh 2020-05-23 20:51:41 +09:00
karasu
01cf01e084 [fzf-tmux] Fix zoomed pane handling in popup mode (#2054)
When called with popup options, do not move to temp window.
2020-05-23 20:47:43 +09:00
Junegunn Choi
97a725fbd0 Do not disable mouse after execute(-silent) when --height option is used
The action takes place in the alternate screen so the offsets should
still be correct.
2020-05-18 02:43:58 +09:00
lacygoill
ace92ba281 [vim] Don't set wfw, wfh, bh options when opening popup (#2042)
* No need to restore &wfw and &wfh when using popup window

Co-authored-by: lacygoill <lacygoill@lacygoill.me>
Co-authored-by: Junegunn Choi <junegunn.c@gmail.com>
2020-05-17 23:28:23 +09:00
ichizok
d631c76e8d [vim] Don't start extra process when opening popup (#2000)
Fix #2038
2020-05-15 15:25:33 +09:00
Slaven Rezić
e6d33f77da [zsh] Make CTRL-R work with older Perls (#2003)
s///r is only available since perl 5.14. The Perl oneliner
was changed to work with older Perls, possibly even with 5.000.

Fix #2001
2020-04-24 22:56:55 +09:00
Jack Bates
a6d3e3687b Improve error messages (#1962)
* Add RuboCop Minitest extension
* Improve error messages
* Use chomp option
2020-04-21 10:12:00 +09:00
Raffaele
08c2bcb952 Quote LDFLAGS (#1995)
Make sure that `extldflags` is quoted so that LDFLAGS containing spaces won't break the build command.

Close #1994
2020-04-21 10:07:39 +09:00
Junegunn Choi
98ca4bdede Add conda installation instruction
Close #1949
2020-04-18 13:00:38 +09:00
Janek
3f8e741562 Add more details on apt installation in README.md (#1977) 2020-04-18 12:59:32 +09:00
Junegunn Choi
6e464ebd9b Remove dead code 2020-04-18 02:51:02 +09:00
Junegunn Choi
c329279339 [completion] Make kill completion more consistent with the others
Support both ordinary completion trigger and empty trigger

    kill <tab>
    kill foo**<tab>

Close #1988
Close #385
2020-04-18 02:46:40 +09:00
Jack Bates
cf04753ad7 Make flaky tests reliable (#1978) 2020-04-18 02:34:38 +09:00
Junegunn Choi
69e7eab11f [install] Clarify that .bashrc should be loaded from .bash_profile on macOS
Close #1986
2020-04-17 21:51:16 +09:00
Junegunn Choi
dea206b023 [zsh-completion] Fix error with backslash-prefixed commands
Fix #1973
Fix #1974
Fix #1975
2020-04-13 00:30:43 +09:00
Jack Bates
5deaf58928 Run rubocop --auto-correct --disable-uncorrectable (#1967)
Co-authored-by: Junegunn Choi <junegunn.c@gmail.com>
2020-04-13 00:23:31 +09:00
Junegunn Choi
15e2952a2b [fzf-tmux] Allow positional flags
Since we don't know in advance which flags tmux will support, simply
allow a single uppercase character ([A-Z]) for now.

    fzf-tmux -xR -yS
    fzf-tmux -x R -y S

Fix #1956
2020-04-07 09:55:48 +09:00
Junegunn Choi
a9fba1c849 Fix typo 2020-04-05 18:36:31 +09:00
Junegunn Choi
71e573d082 [vim] Add 'tmux' layout option to use fzf-tmux
e.g.

  if exists('$TMUX')
    let g:fzf_layout = { 'tmux': '-p90%,60%' }
  else
    let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
  endif
2020-04-05 18:16:36 +09:00
32 changed files with 1845 additions and 1146 deletions

24
.rubocop.yml Normal file
View 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

View File

@@ -1,22 +1,28 @@
language: go
go:
- "1.14"
env: GO111MODULE=on
os:
- linux
- osx
dist: bionic # For fish >= 2.3.0 string builtin
dist: bionic
addons:
apt:
packages:
- fish
- zsh
sources:
sourceline: ppa:fish-shell/release-3
homebrew:
packages:
- fish
- tmux
update: true
install: gem install minitest rubocop rubocop-minitest rubocop-performance
script:
- make test
# LC_ALL=C to avoid escape codes in
# printf %q $'\355\205\214\354\212\244\355\212\270' on macOS. Bash on
# macOS is built without HANDLE_MULTIBYTE?
- make install && ./install --all && LC_ALL=C tmux new-session -d && ruby test/test_go.rb --verbose
- rubocop --require rubocop-minitest --require rubocop-performance

View File

@@ -1,6 +1,83 @@
CHANGELOG
=========
0.23.1
------
- Added `--preview-window` options for disabling flags
- `nocycle`
- `nohidden`
- `nowrap`
- `default`
- Built with Go 1.14.9 due to performance regression
- https://github.com/golang/go/issues/40727
0.23.0
------
- Support preview scroll offset relative to window height
```sh
git grep --line-number '' |
fzf --delimiter : \
--preview 'bat --style=numbers --color=always --highlight-line {2} {1}' \
--preview-window +{2}-/2
```
- Added `--preview-window` option for sharp edges (`--preview-window sharp`)
- Added `--preview-window` option for cyclic scrolling (`--preview-window cycle`)
- Reduced vertical padding around the preview window when `--preview-window
noborder` is used
- Added actions for preview window
- `preview-half-page-up`
- `preview-half-page-down`
- Vim
- Popup width and height can be given in absolute integer values
- Added `fzf#exec()` function for getting the path of fzf executable
- It also downloads the latest binary if it's not available by running
`./install --bin`
- Built with Go 1.15.2
- We no longer provide 32-bit binaries
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
------
- Shell extension

View File

@@ -6,9 +6,8 @@ ROOT_DIR := $(shell dirname $(MAKEFILE))
SOURCES := $(wildcard *.go src/*.go src/*/*.go) $(MAKEFILE)
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
BINARY64 := fzf-$(GOOS)_amd64
BINARYARM5 := fzf-$(GOOS)_arm5
BINARYARM6 := fzf-$(GOOS)_arm6
@@ -16,7 +15,6 @@ BINARYARM7 := fzf-$(GOOS)_arm7
BINARYARM8 := fzf-$(GOOS)_arm8
BINARYPPC64LE := fzf-$(GOOS)_ppc64le
VERSION := $(shell awk -F= '/version =/ {print $$2}' src/constants.go | tr -d "\" ")
RELEASE32 := fzf-$(VERSION)-$(GOOS)_386
RELEASE64 := fzf-$(VERSION)-$(GOOS)_amd64
RELEASEARM5 := fzf-$(VERSION)-$(GOOS)_arm5
RELEASEARM6 := fzf-$(VERSION)-$(GOOS)_arm6
@@ -30,10 +28,6 @@ ifeq ($(UNAME_M),x86_64)
BINARY := $(BINARY64)
else ifeq ($(UNAME_M),amd64)
BINARY := $(BINARY64)
else ifeq ($(UNAME_M),i686)
BINARY := $(BINARY32)
else ifeq ($(UNAME_M),i386)
BINARY := $(BINARY32)
else ifeq ($(UNAME_M),armv5l)
BINARY := $(BINARYARM5)
else ifeq ($(UNAME_M),armv6l)
@@ -56,13 +50,11 @@ target:
mkdir -p $@
ifeq ($(GOOS),windows)
release: target/$(BINARY32) target/$(BINARY64)
cd target && cp -f $(BINARY32) fzf.exe && zip $(RELEASE32).zip fzf.exe
release: target/$(BINARY64)
cd target && cp -f $(BINARY64) fzf.exe && zip $(RELEASE64).zip fzf.exe
cd target && rm -f fzf.exe
else ifeq ($(GOOS),linux)
release: target/$(BINARY32) target/$(BINARY64) target/$(BINARYARM5) target/$(BINARYARM6) target/$(BINARYARM7) target/$(BINARYARM8) target/$(BINARYPPC64LE)
cd target && cp -f $(BINARY32) fzf && tar -czf $(RELEASE32).tgz fzf
release: target/$(BINARY64) target/$(BINARYARM5) target/$(BINARYARM6) target/$(BINARYARM7) target/$(BINARYARM8) target/$(BINARYPPC64LE)
cd target && cp -f $(BINARY64) fzf && tar -czf $(RELEASE64).tgz fzf
cd target && cp -f $(BINARYARM5) fzf && tar -czf $(RELEASEARM5).tgz fzf
cd target && cp -f $(BINARYARM6) fzf && tar -czf $(RELEASEARM6).tgz fzf
@@ -71,8 +63,7 @@ release: target/$(BINARY32) target/$(BINARY64) target/$(BINARYARM5) target/$(BIN
cd target && cp -f $(BINARYPPC64LE) fzf && tar -czf $(RELEASEPPC64LE).tgz fzf
cd target && rm -f fzf
else
release: target/$(BINARY32) target/$(BINARY64)
cd target && cp -f $(BINARY32) fzf && tar -czf $(RELEASE32).tgz fzf
release: target/$(BINARY64)
cd target && cp -f $(BINARY64) fzf && tar -czf $(RELEASE64).tgz fzf
cd target && rm -f fzf
endif
@@ -96,9 +87,6 @@ install: bin/fzf
clean:
$(RM) -r target
target/$(BINARY32): $(SOURCES)
GOARCH=386 $(GO) build $(BUILD_FLAGS) -o $@
target/$(BINARY64): $(SOURCES)
GOARCH=amd64 $(GO) build $(BUILD_FLAGS) -o $@

View File

@@ -127,8 +127,9 @@ let g:fzf_action = {
\ 'ctrl-v': 'vsplit' }
" Default fzf layout
" - down / up / left / right
let g:fzf_layout = { 'down': '~40%' }
" - down / up / left / right / window
let g:fzf_layout = { 'down': '40%' }
let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
" You can set up fzf window using a Vim command (Neovim or latest Vim 8 required)
let g:fzf_layout = { 'window': 'enew' }
@@ -274,6 +275,7 @@ The following table summarizes the available options.
| `options` | string/list | Options to fzf |
| `dir` | string | Working directory |
| `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) | dict | (Layout) Popup window settings (e.g. `{'width': 0.9, 'height': 0.6}`) |
@@ -289,8 +291,8 @@ When `window` entry is a dictionary, fzf will start in a popup window. The
following options are allowed:
- Required:
- `width` [float range [0 ~ 1]]
- `height` [float range [0 ~ 1]]
- `width` [float range [0 ~ 1]] or [integer range [8 ~ ]]
- `height` [float range [0 ~ 1]] or [integer range [4 ~ ]]
- Optional:
- `yoffset` [float default 0.5 range [0 ~ 1]]
- `xoffset` [float default 0.5 range [0 ~ 1]]
@@ -385,8 +387,8 @@ The latest versions of Vim and Neovim include builtin terminal emulator
```vim
" Required:
" - width [float range [0 ~ 1]]
" - height [float range [0 ~ 1]]
" - width [float range [0 ~ 1]] or [integer range [8 ~ ]]
" - height [float range [0 ~ 1]] or [integer range [4 ~ ]]
"
" Optional:
" - xoffset [float default 0.5 range [0 ~ 1]]
@@ -397,14 +399,26 @@ The latest versions of Vim and Neovim include builtin terminal emulator
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
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
the window.
For example, if you use the default layout (`{'down': '~40%'}`) on Neovim, you
might want to temporarily disable the statusline for a cleaner look.
For example, if you use a non-popup layout (e.g. `{'down': '40%'}`) on Neovim,
you might want to temporarily disable the statusline for a cleaner look.
```vim
if has('nvim') && !exists('g:fzf_layout')

164
README.md
View File

@@ -22,42 +22,50 @@ Pros
Table of Contents
-----------------
* [Installation](#installation)
* [Using Homebrew or Linuxbrew](#using-homebrew-or-linuxbrew)
* [Using git](#using-git)
* [Using Linux package managers](#using-linux-package-managers)
* [Windows](#windows)
* [As Vim plugin](#as-vim-plugin)
* [Upgrading fzf](#upgrading-fzf)
* [Building fzf](#building-fzf)
* [Usage](#usage)
* [Using the finder](#using-the-finder)
* [Layout](#layout)
* [Search syntax](#search-syntax)
* [Environment variables](#environment-variables)
* [Options](#options)
* [Demo](#demo)
* [Examples](#examples)
* [fzf-tmux script](#fzf-tmux-script)
* [Key bindings for command line](#key-bindings-for-command-line)
* [Fuzzy completion for bash and zsh](#fuzzy-completion-for-bash-and-zsh)
* [Files and directories](#files-and-directories)
* [Process IDs](#process-ids)
* [Host names](#host-names)
* [Environment variables / Aliases](#environment-variables--aliases)
* [Settings](#settings)
* [Supported commands](#supported-commands)
* [Custom fuzzy completion](#custom-fuzzy-completion)
* [Vim plugin](#vim-plugin)
* [Advanced topics](#advanced-topics)
* [Performance](#performance)
* [Executing external programs](#executing-external-programs)
* [Preview window](#preview-window)
* [Tips](#tips)
* [Respecting .gitignore](#respecting-gitignore)
* [Fish shell](#fish-shell)
* [Related projects](#related-projects)
* [<a href="LICENSE">License</a>](#license)
<!-- vim-markdown-toc GFM -->
* [Installation](#installation)
* [Using Homebrew or Linuxbrew](#using-homebrew-or-linuxbrew)
* [Using git](#using-git)
* [Using Linux package managers](#using-linux-package-managers)
* [Windows](#windows)
* [As Vim plugin](#as-vim-plugin)
* [Upgrading fzf](#upgrading-fzf)
* [Building fzf](#building-fzf)
* [Usage](#usage)
* [Using the finder](#using-the-finder)
* [Layout](#layout)
* [Search syntax](#search-syntax)
* [Environment variables](#environment-variables)
* [Options](#options)
* [Demo](#demo)
* [Examples](#examples)
* [`fzf-tmux` script](#fzf-tmux-script)
* [Key bindings for command-line](#key-bindings-for-command-line)
* [Fuzzy completion for bash and zsh](#fuzzy-completion-for-bash-and-zsh)
* [Files and directories](#files-and-directories)
* [Process IDs](#process-ids)
* [Host names](#host-names)
* [Environment variables / Aliases](#environment-variables--aliases)
* [Settings](#settings)
* [Supported commands](#supported-commands)
* [Custom fuzzy completion](#custom-fuzzy-completion)
* [Vim plugin](#vim-plugin)
* [Advanced topics](#advanced-topics)
* [Performance](#performance)
* [Executing external programs](#executing-external-programs)
* [Reloading the candidate list](#reloading-the-candidate-list)
* [1. Update the list of processes by pressing CTRL-R](#1-update-the-list-of-processes-by-pressing-ctrl-r)
* [2. Switch between sources by pressing CTRL-D or CTRL-F](#2-switch-between-sources-by-pressing-ctrl-d-or-ctrl-f)
* [3. Interactive ripgrep integration](#3-interactive-ripgrep-integration)
* [Preview window](#preview-window)
* [Tips](#tips)
* [Respecting `.gitignore`](#respecting-gitignore)
* [Fish shell](#fish-shell)
* [Related projects](#related-projects)
* [License](#license)
<!-- vim-markdown-toc -->
Installation
------------
@@ -104,16 +112,18 @@ git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
### Using Linux package managers
| Distro | Command |
| --- | --- |
| Alpine Linux | `sudo apk add fzf` |
| Arch Linux | `sudo pacman -S fzf` |
| Debian | `sudo apt-get install fzf` |
| Fedora | `sudo dnf install fzf` |
| FreeBSD | `pkg install fzf` |
| NixOS | `nix-env -iA nixpkgs.fzf` |
| openSUSE | `sudo zypper install fzf` |
| OpenBSD | `pkg_add fzf` |
| Package Manager | Linux Distribution | Command |
| --- | --- | --- |
| APK | Alpine Linux | `sudo apk add fzf` |
| APT | Debian 9+/Ubuntu 19.10+ | `sudo apt-get install fzf` |
| Conda | | `conda install -c conda-forge fzf` |
| DNF | Fedora | `sudo dnf install fzf` |
| Nix | NixOS, etc. | `nix-env -iA nixpkgs.fzf` |
| Pacman | Arch Linux | `sudo pacman -S fzf` |
| pkg | FreeBSD | `pkg install 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
plugin may or may not be enabled by default depending on the package manager.
@@ -526,11 +536,56 @@ fzf --bind 'f1:execute(less -f {}),ctrl-y:execute-silent(echo {} | pbcopy)+abort
See *KEY BINDINGS* section of the man page for details.
### Reloading the candidate list
By binding `reload` action to a key or an event, you can make fzf dynamically
reload the candidate list. See https://github.com/junegunn/fzf/issues/1750 for
more details.
#### 1. Update the list of processes by pressing CTRL-R
```sh
FZF_DEFAULT_COMMAND='ps -ef' \
fzf --bind 'ctrl-r:reload($FZF_DEFAULT_COMMAND)' \
--header 'Press CTRL-R to reload' --header-lines=1 \
--height=50% --layout=reverse
```
#### 2. Switch between sources by pressing CTRL-D or CTRL-F
```sh
FZF_DEFAULT_COMMAND='find . -type f' \
fzf --bind 'ctrl-d:reload(find . -type d),ctrl-f:reload($FZF_DEFAULT_COMMAND)' \
--height=50% --layout=reverse
```
#### 3. Interactive ripgrep integration
The following example uses fzf as the selector interface for ripgrep. We bound
`reload` action to `change` event, so every time you type on fzf, ripgrep
process will restart with the updated query string denoted by the placeholder
expression `{q}`. Also, note that we used `--phony` option so that fzf doesn't
perform any secondary filtering.
```sh
INITIAL_QUERY=""
RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case "
FZF_DEFAULT_COMMAND="$RG_PREFIX '$INITIAL_QUERY'" \
fzf --bind "change:reload:$RG_PREFIX {q} || true" \
--ansi --phony --query "$INITIAL_QUERY" \
--height=50% --layout=reverse
```
If ripgrep doesn't find any matches, it will exit with a non-zero exit status,
and fzf will warn you about it. To suppress the warning message, we added
`|| true` to the command, so that it always exits with 0.
### Preview window
When `--preview` option is set, fzf automatically starts an external process with
the current line as the argument and shows the result in the split window. Your
`$SHELL` is used to execute the command with `$SHELL -c COMMAND`.
When the `--preview` option is set, fzf automatically starts an external process
with the current line as the argument and shows the result in the split window.
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
# {} is replaced to the single-quoted string of the focused line
@@ -546,13 +601,12 @@ fzf --preview 'head -100 {}'
```
Preview window supports ANSI colors, so you can use any program that
syntax-highlights the content of a file.
- Bat: https://github.com/sharkdp/bat
- Highlight: http://www.andre-simon.de/doku/highlight/en/highlight.php
syntax-highlights the content of a file, such as
[Bat](https://github.com/sharkdp/bat) or
[Highlight](http://www.andre-simon.de/doku/highlight/en/highlight.php):
```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
@@ -581,7 +635,7 @@ not a good idea to add `--preview` option to your `$FZF_DEFAULT_OPTS`**.
# *********************
# ** 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
ps -ef | fzf

View File

@@ -77,7 +77,7 @@ while [[ $# -gt 0 ]]; do
if [[ ${#arg} -gt 2 ]]; then
size="${arg:2}"
else
if [[ "$1" =~ ^[0-9%,C]+$ ]]; then
if [[ "$1" =~ ^[0-9%,]+$ ]] || [[ "$1" =~ ^[A-Z]$ ]]; then
size="$1"
shift
else
@@ -136,11 +136,11 @@ if [[ -z "$TMUX" ]]; then
fi
# --height option is not allowed
args=("--no-height" "${args[@]}")
args=("${args[@]}" "--no-height")
# Handle zoomed tmux pane by moving it to a temp window
if tmux list-panes -F '#F' | grep -q Z; then
zoomed=1
# Handle zoomed tmux pane without popup options by moving it to a temp window
if [[ ! "$opt" =~ "-K -E" ]] && tmux list-panes -F '#F' | grep -q Z; then
zoomed_without_popup=1
original_window=$(tmux display-message -p "#{window_id}")
tmp_window=$(tmux new-window -d -P -F "#{window_id}" "bash -c 'while :; do for c in \\| / - '\\;' do sleep 0.2; printf \"\\r\$c fzf-tmux is running\\r\"; done; done'")
tmux swap-pane -t $tmp_window \; select-window -t $tmp_window
@@ -154,16 +154,17 @@ argsf="${TMPDIR:-/tmp}/fzf-args-$id"
fifo1="${TMPDIR:-/tmp}/fzf-fifo1-$id"
fifo2="${TMPDIR:-/tmp}/fzf-fifo2-$id"
fifo3="${TMPDIR:-/tmp}/fzf-fifo3-$id"
tmux_win_opts=( $(tmux show-window-options remain-on-exit \; show-window-options synchronize-panes | sed '/ off/d; s/^/set-window-option /; s/$/ \\;/') )
cleanup() {
\rm -f $argsf $fifo1 $fifo2 $fifo3
# Restore tmux window options
if [[ "${#tmux_win_opts[@]}" -gt 0 ]]; then
eval "tmux ${tmux_win_opts[@]}"
eval "tmux ${tmux_win_opts[*]}"
fi
# Remove temp window if we were zoomed
if [[ -n "$zoomed" ]]; then
# Remove temp window if we were zoomed without popup options
if [[ -n "$zoomed_without_popup" ]]; then
tmux display-message -p "#{window_id}" > /dev/null
tmux swap-pane -t $original_window \; \
select-window -t $original_window \; \
@@ -179,58 +180,45 @@ cleanup() {
trap 'cleanup 1' SIGUSR1
trap 'cleanup' EXIT
envs="env TERM=$TERM "
envs="export TERM=$TERM "
[[ "$opt" =~ "-K -E" ]] && FZF_DEFAULT_OPTS="--margin 0,1 $FZF_DEFAULT_OPTS"
[[ -n "$FZF_DEFAULT_OPTS" ]] && envs="$envs FZF_DEFAULT_OPTS=$(printf %q "$FZF_DEFAULT_OPTS")"
[[ -n "$FZF_DEFAULT_COMMAND" ]] && envs="$envs FZF_DEFAULT_COMMAND=$(printf %q "$FZF_DEFAULT_COMMAND")"
mkfifo -m o+w $fifo2
mkfifo -m o+w $fifo3
echo "$envs;" > "$argsf"
# Build arguments to fzf
opts=""
for arg in "${args[@]}"; do
arg="${arg//\\/\\\\}"
arg="${arg//\"/\\\"}"
arg="${arg//\`/\\\`}"
arg="${arg//$/\\$}"
opts="$opts \"$arg\""
done
opts=$(printf "%q " "${args[@]}")
pppid=$$
echo -n "trap 'kill -SIGUSR1 -$pppid' EXIT SIGINT SIGTERM;" > $argsf
echo -n "trap 'kill -SIGUSR1 -$pppid' EXIT SIGINT SIGTERM;" >> $argsf
close="; trap - EXIT SIGINT SIGTERM $close"
tmux_win_opts=( $(tmux show-window-options remain-on-exit \; show-window-options synchronize-panes | sed '/ off/d; s/^/set-window-option /; s/$/ \\;/') )
export TMUX=$(cut -d , -f 1,2 <<< "$TMUX")
mkfifo -m o+w $fifo2
if [[ "$opt" =~ "-K -E" ]]; then
cat $fifo2 &
if [[ -n "$term" ]] || [[ -t 0 ]]; then
cat <<< "\"$fzf\" $opts > $fifo2; out=\$? $close; exit \$out" >> $argsf
TMUX=$(echo $TMUX | cut -d , -f 1,2) tmux popup -d "$PWD" "${tmux_args[@]}" $opt -R "$envs bash $argsf" > /dev/null 2>&1
else
mkfifo $fifo1
cat <<< "\"$fzf\" $opts < $fifo1 > $fifo2; out=\$? $close; exit \$out" >> $argsf
cat <&0 > $fifo1 &
TMUX=$(echo $TMUX | cut -d , -f 1,2) tmux popup -d "$PWD" "${tmux_args[@]}" $opt -R "$envs bash $argsf" > /dev/null 2>&1
fi
tmux popup -d "$PWD" "${tmux_args[@]}" $opt -R "bash $argsf" > /dev/null 2>&1
exit $?
fi
mkfifo -m o+w $fifo3
if [[ -n "$term" ]] || [[ -t 0 ]]; then
cat <<< "\"$fzf\" $opts > $fifo2; echo \$? > $fifo3 $close" >> $argsf
TMUX=$(echo $TMUX | cut -d , -f 1,2) tmux set-window-option synchronize-panes off \;\
set-window-option remain-on-exit off \;\
split-window $opt "${tmux_args[@]}" "$envs bash -c 'cd $(printf %q "$PWD"); exec -a fzf bash $argsf'" $swap \
> /dev/null 2>&1 || { "$fzf" "${args[@]}"; exit $?; }
else
mkfifo $fifo1
cat <<< "\"$fzf\" $opts < $fifo1 > $fifo2; echo \$? > $fifo3 $close" >> $argsf
TMUX=$(echo $TMUX | cut -d , -f 1,2) tmux set-window-option synchronize-panes off \;\
set-window-option remain-on-exit off \;\
split-window $opt "${tmux_args[@]}" "$envs bash -c 'exec -a fzf bash $argsf'" $swap \
> /dev/null 2>&1 || { "$fzf" "${args[@]}"; exit $?; }
cat <&0 > $fifo1 &
fi
tmux set-window-option synchronize-panes off \;\
set-window-option remain-on-exit off \;\
split-window -c "$PWD" $opt "${tmux_args[@]}" "bash -c 'exec -a fzf bash $argsf'" $swap \
> /dev/null 2>&1 || { "$fzf" "${args[@]}"; exit $?; }
cat $fifo2
exit "$(cat $fifo3)"

View File

@@ -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 Vim integration
Installation
Summary
:FZF[!]
Configuration
Examples
Explanation of g:fzf_colors
fzf#run
fzf#wrap
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*
==============================================================================
@@ -38,12 +80,12 @@ the basic file selector command built on top of them.
- Basic fuzzy file selector
- A reference implementation for those who don't want to write VimScript to
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 whole if we start off with `:FZF` command.
{1} https://github.com/junegunn/fzf.vim
{2} https://github.com/junegunn/fzf.vim
:FZF[!]
@@ -112,8 +154,9 @@ Examples~
\ 'ctrl-v': 'vsplit' }
" Default fzf layout
" - down / up / left / right
" - down / up / left / right / window
let g:fzf_layout = { 'down': '~40%' }
let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
" You can set up fzf window using a Vim command (Neovim or latest Vim 8 required)
let g:fzf_layout = { 'window': 'enew' }
@@ -144,6 +187,51 @@ Examples~
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
==============================================================================
@@ -203,6 +291,7 @@ The following table summarizes the available options.
`options` | string/list | Options to fzf
`dir` | string | Working directory
`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. `verticalaboveleft30new` )
`window` (Vim 8 / Neovim) | dict | (Layout) Popup window settings (e.g. `{'width':0.9,'height':0.6}` )
---------------------------+---------------+----------------------------------------------------------------------
@@ -217,8 +306,8 @@ When `window` entry is a dictionary, fzf will start in a popup window. The
following options are allowed:
- Required:
- `width` [float range [0 ~ 1]]
- `height` [float range [0 ~ 1]]
- `width` [float range [0 ~ 1]] or [integer range [8 ~ ]]
- `height` [float range [0 ~ 1]] or [integer range [4 ~ ]]
- Optional:
- `yoffset` [float default 0.5 range [0 ~ 1]]
- `xoffset` [float default 0.5 range [0 ~ 1]]
@@ -320,6 +409,16 @@ Starting fzf in a popup window~
" - 'rounded' / 'sharp' / 'horizontal' / 'vertical' / 'top' / 'bottom' / 'left' / 'right'
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~
*fzf-hide-statusline*
@@ -328,8 +427,9 @@ When fzf starts in a terminal buffer, the file type of the buffer is set to
`fzf`. So you can set up `FileTypefzf` autocmd to customize the settings of
the window.
For example, if you use the default layout (`{'down':'~40%'}`) on Neovim, you
might want to temporarily disable the statusline for a cleaner look.
For example, if you use a non-popup layout (e.g. `{'down':'40%'}`) on
Neovim, you might want to temporarily disable the statusline for a cleaner
look.
>
if has('nvim') && !exists('g:fzf_layout')
autocmd! FileType fzf

2
go.mod
View File

@@ -1,7 +1,7 @@
module github.com/junegunn/fzf
require (
github.com/gdamore/tcell v1.3.0
github.com/gdamore/tcell v1.4.0
github.com/lucasb-eyer/go-colorful v1.0.3 // indirect
github.com/mattn/go-isatty v0.0.12
github.com/mattn/go-runewidth v0.0.8

5
go.sum
View File

@@ -1,8 +1,8 @@
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell v1.3.0 h1:r35w0JBADPZCVQijYebl6YMWWtHRqVEGt7kL2eBADRM=
github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM=
github.com/gdamore/tcell v1.4.0 h1:vUnHwJRvcPQa3tzi+0QI4U9JINXYJlOz9yiaiPQ2wMU=
github.com/gdamore/tcell v1.4.0/go.mod h1:vxEiSDZdW3L+Uhjii9c3375IlDmR05bzxY404ZVSMo0=
github.com/lucasb-eyer/go-colorful v1.0.2 h1:mCMFu6PgSozg9tDNMMK3g18oJBX7oYGrC09mS6CXfO4=
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
@@ -11,6 +11,7 @@ github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHX
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.8 h1:3tS41NlGYSmhhe/8fhGRzc+z3AYCw1Fe1WAyLuujKs0=
github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-shellwords v1.0.9 h1:eaB5JspOwiKKcHdqcjbfe5lA9cNn/4NRRtddXJCimqk=

20
install
View File

@@ -2,7 +2,7 @@
set -u
version=0.21.1
version=0.23.1
auto_completion=
key_bindings=
update_config=2
@@ -28,9 +28,6 @@ usage: $0 [OPTIONS]
--no-bash Do not set up bash configuration
--no-zsh Do not set up zsh configuration
--no-fish Do not set up fish configuration
--32 Download 32-bit binary
--64 Download 64-bit binary
EOF
}
@@ -56,8 +53,6 @@ for opt in "$@"; do
--no-completion) auto_completion=0 ;;
--update-rc) update_config=1 ;;
--no-update-rc) update_config=0 ;;
--32) binary_arch=386 ;;
--64) binary_arch=amd64 ;;
--bin) ;;
--no-bash) shells=${shells/bash/} ;;
--no-zsh) shells=${shells/zsh/} ;;
@@ -179,24 +174,17 @@ binary_available=1
binary_error=""
case "$archi" in
Darwin\ *64) download fzf-$version-darwin_${binary_arch:-amd64}.tgz ;;
Darwin\ *86) download fzf-$version-darwin_${binary_arch:-386}.tgz ;;
Linux\ armv5*) download fzf-$version-linux_${binary_arch:-arm5}.tgz ;;
Linux\ armv6*) download fzf-$version-linux_${binary_arch:-arm6}.tgz ;;
Linux\ armv7*) download fzf-$version-linux_${binary_arch:-arm7}.tgz ;;
Linux\ armv8*) download fzf-$version-linux_${binary_arch:-arm8}.tgz ;;
Linux\ aarch64*) download fzf-$version-linux_${binary_arch:-arm8}.tgz ;;
Linux\ *64) download fzf-$version-linux_${binary_arch:-amd64}.tgz ;;
Linux\ *86) download fzf-$version-linux_${binary_arch:-386}.tgz ;;
FreeBSD\ *64) download fzf-$version-freebsd_${binary_arch:-amd64}.tgz ;;
FreeBSD\ *86) download fzf-$version-freebsd_${binary_arch:-386}.tgz ;;
OpenBSD\ *64) download fzf-$version-openbsd_${binary_arch:-amd64}.tgz ;;
OpenBSD\ *86) download fzf-$version-openbsd_${binary_arch:-386}.tgz ;;
CYGWIN*\ *64) download fzf-$version-windows_${binary_arch:-amd64}.zip ;;
MINGW*\ *86) download fzf-$version-windows_${binary_arch:-386}.zip ;;
MINGW*\ *64) download fzf-$version-windows_${binary_arch:-amd64}.zip ;;
MSYS*\ *86) download fzf-$version-windows_${binary_arch:-386}.zip ;;
MSYS*\ *64) download fzf-$version-windows_${binary_arch:-amd64}.zip ;;
Windows*\ *86) download fzf-$version-windows_${binary_arch:-386}.zip ;;
Windows*\ *64) download fzf-$version-windows_${binary_arch:-amd64}.zip ;;
*) binary_available=0 binary_error=1 ;;
esac
@@ -384,7 +372,11 @@ fi
if [ $update_config -eq 1 ]; then
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" =~ fish ]] && [ $key_bindings -eq 1 ] && echo ' fzf_key_bindings # fish'
echo

View File

@@ -1,4 +1,4 @@
$version="0.21.1"
$version="0.23.1"
if ([Environment]::Is64BitProcess) {
$binary_arch="amd64"
@@ -57,7 +57,7 @@ function download {
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
(New-Object Net.WebClient).DownloadFile($url, $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("$temp"))
if ($?) {
(Expand-Archive -Path $temp -DestinationPath .); (Remove-Item $temp)
(Microsoft.PowerShell.Archive\Expand-Archive -Path $temp -DestinationPath .); (Remove-Item $temp)
} else {
$binary_error="Failed to download with powershell"
}

View File

@@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
..
.TH fzf-tmux 1 "Apr 2020" "fzf 0.21.1" "fzf-tmux - open fzf in tmux split pane"
.TH fzf-tmux 1 "Oct 2020" "fzf 0.23.1" "fzf-tmux - open fzf in tmux split pane"
.SH NAME
fzf-tmux - open fzf in tmux split pane

View File

@@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
..
.TH fzf 1 "Apr 2020" "fzf 0.21.1" "fzf - a command-line fuzzy finder"
.TH fzf 1 "Oct 2020" "fzf 0.23.1" "fzf - a command-line fuzzy finder"
.SH NAME
fzf - a command-line fuzzy finder
@@ -381,14 +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.
.RE
.TP
.BI "--preview-window=" "[POSITION][:SIZE[%]][:noborder][:wrap][:hidden]"
Determines the layout of the preview window. If the argument contains
\fB:hidden\fR, the preview window will be hidden by default until
\fBtoggle-preview\fR action is triggered. Long lines are truncated by default.
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
execute the command in the background.
.BI "--preview-window=" "[POSITION][:SIZE[%]][:rounded|sharp|noborder][:[no]wrap][:[no]cycle][:[no]hidden][:+SCROLL[-OFFSET]][:default]"
.RS
.B POSITION: (default: right)
@@ -398,11 +391,47 @@ execute the command in the background.
\fBright
.RE
\fRDetermines the layout of the preview window. If the argument contains
\fB:hidden\fR, the preview window will be hidden by default until
\fBtoggle-preview\fR action is triggered. Long lines are truncated by default.
Line wrap can be enabled with \fB:wrap\fR flag. Cyclic scrolling is enabled
with \fB:cycle\fR flag.
If size is given as 0, preview window will not be visible, but fzf will still
execute the command in the background.
To change the style of the border of the preview window, specify one of
\fBrounded\fR (border with rounded edges, default), \fBsharp\fR (border with
sharp edges), or \fBnoborder\fR (no border).
\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 (\fB-INTEGER\fR), or as a denominator form
(\fB-/INTEGER\fR) for specifying a fraction of the preview window height.
\fBdefault\fR resets all options previously set to the default.
.RS
e.g.
\fBfzf --preview="head {}" --preview-window=up:30%
fzf --preview="file {}" --preview-window=down:1\fR
\fB# Non-default scroll window positions and sizes
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 (-5)
git grep --line-number '' |
fzf --delimiter : --preview 'nl {1}' --preview-window +{2}-5
# Preview with bat, matching line in the middle of the window (-/2)
git grep --line-number '' |
fzf --delimiter : \\
--preview 'bat --style=numbers --color=always --highlight-line {2} {1}' \\
--preview-window +{2}-/2\fR
.RE
.SS Scripting
.TP
.BI "-q, --query=" "STR"
@@ -635,12 +664,23 @@ e.g.
or any single character
.SS AVAILABLE EVENTS:
\fIchange\fR (triggered whenever the query string is changed)
.br
\fIchange\fR
.RS
Triggered whenever the query string is changed
e.g.
\fB# Moves cursor to the top (or bottom depending on --layout) whenever the query is changed
fzf --bind change:top\fR
e.g.
\fB# Moves cursor to the top (or bottom depending on --layout) whenever the query is changed
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:
A key or an event can be bound to one or more of the following actions.
@@ -666,7 +706,6 @@ A key or an event can be bound to one or more of the following actions.
\fBend-of-line\fR \fIctrl-e end\fR
\fBexecute(...)\fR (see below for the details)
\fBexecute-silent(...)\fR (see below for the details)
\fRexecute-multi(...)\fR (deprecated in favor of \fB{+}\fR expression)
\fBforward-char\fR \fIctrl-f right\fR
\fBforward-word\fR \fIalt-f shift-right\fR
\fBignore\fR
@@ -679,12 +718,16 @@ A key or an event can be bound to one or more of the following actions.
\fBpage-up\fR \fIpgup\fR
\fBhalf-page-down\fR
\fBhalf-page-up\fR
\fBpreview(...)\fR (see below for the details)
\fBpreview-down\fR \fIshift-down\fR
\fBpreview-up\fR \fIshift-up\fR
\fBpreview-page-down\fR
\fBpreview-page-up\fR
\fBpreview-half-page-down\fR
\fBpreview-half-page-up\fR
\fBprevious-history\fR (\fIctrl-p\fR on \fB--history\fR)
\fBprint-query\fR (print query and exit)
\fBrefresh-preview\fR
\fBreload(...)\fR (see below for the details)
\fBreplace-query\fR (replace query string with the current selection)
\fBselect-all\fR (select all matches)
@@ -771,6 +814,24 @@ e.g.
fzf --bind "change:reload:$RG_PREFIX {q} || true" \\
--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
Junegunn Choi (\fIjunegunn.c@gmail.com\fR)

View File

@@ -115,14 +115,23 @@ function! s:fzf_tempname()
return s:fzf_call('tempname')
endfunction
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_tmux = s:base_dir.'/bin/fzf-tmux'
let s:cpo_save = &cpo
set cpo&vim
function! s:popup_support()
return has('nvim') ? has('nvim-0.4') : has('popupwin') && has('patch-8.2.191')
endfunction
function! s:default_layout()
return s:popup_support()
\ ? { 'window' : { 'width': 0.9, 'height': 0.6, 'highlight': 'Normal' } }
\ : { 'down': '~40%' }
endfunction
function! fzf#install()
if s:is_win && !has('win32unix')
let script = s:base_dir.'/install.ps1'
@@ -145,7 +154,7 @@ function! fzf#install()
endif
endfunction
function! s:fzf_exec()
function! fzf#exec()
if !exists('s:exec')
if executable(s:fzf_go)
let s:exec = s:fzf_go
@@ -154,13 +163,13 @@ function! s:fzf_exec()
elseif input('fzf executable not found. Download binary? (y/n) ') =~? '^y'
redraw
call fzf#install()
return s:fzf_exec()
return fzf#exec()
else
redraw
throw 'fzf executable not found'
endif
endif
return fzf#shellescape(s:exec)
return s:exec
endfunction
function! s:tmux_enabled()
@@ -191,21 +200,6 @@ function! s:escape(path)
return s:is_win ? escape(path, '$') : path
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)
echohl ErrorMsg
echom a:msg
@@ -251,9 +245,13 @@ function! s:common_sink(action, lines) abort
endif
try
let empty = empty(s:fzf_expand('%')) && line('$') == 1 && empty(getline(1)) && !&modified
let autochdir = &autochdir
set noautochdir
" Preserve the current working directory in case it's changed during
" 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
if item[0] != '~' && item !~ (s:is_win ? '^[A-Z]:\' : '^/')
let item = join([cwd, item], (s:is_win ? '\' : '/'))
endif
if empty
execute 'e' s:escape(item)
let empty = 0
@@ -267,7 +265,6 @@ function! s:common_sink(action, lines) abort
endfor
catch /^Vim:Interrupt$/
finally
let &autochdir = autochdir
silent! autocmd! fzf_swap
endtry
endfunction
@@ -312,7 +309,7 @@ function! fzf#wrap(...)
let expects = map(copy(args), 'type(v:val)')
let tidx = 0
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
throw 'Invalid arguments (expected: [name string] [opts dict] [fullscreen boolean])'
endif
@@ -337,7 +334,7 @@ function! fzf#wrap(...)
if !exists('g:fzf_layout') && exists('g:fzf_height')
let opts.down = g:fzf_height
else
let opts = extend(opts, s:validate_layout(get(g:, 'fzf_layout', s:default_layout)))
let opts = extend(opts, s:validate_layout(get(g:, 'fzf_layout', s:default_layout())))
endif
endif
@@ -384,11 +381,11 @@ function! fzf#run(...) abort
try
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 optstr = s:evaluate_opts(get(dict, 'options', ''))
try
let fzf_exec = s:fzf_exec()
let fzf_exec = fzf#shellescape(fzf#exec())
catch
throw v:exception
endtry
@@ -416,7 +413,7 @@ try
let prefix = ''
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') &&
\ !(has('nvim') || s:is_win || has('win32unix') || s:present(dict, 'up', 'left', 'right', 'window')) &&
\ executable('tput') && filereadable('/dev/tty')
@@ -424,7 +421,7 @@ try
let has_nvim_term = has('nvim-0.2.1') || has('nvim') && !s:is_win
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'))
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
let use_height = 0
let use_term = 0
@@ -460,19 +457,21 @@ function! s:present(dict, ...)
endfunction
function! s:fzf_tmux(dict)
let size = ''
for o in ['up', 'down', 'left', 'right']
if s:present(a:dict, o)
let spec = a:dict[o]
if (o == 'up' || o == 'down') && spec[0] == '~'
let size = '-'.o[0].s:calc_size(&lines, spec, a:dict)
else
" Legacy boolean option
let size = '-'.o[0].(spec == 1 ? '' : substitute(spec, '^\~', '', ''))
let size = get(a:dict, 'tmux', '')
if empty(size)
for o in ['up', 'down', 'left', 'right']
if s:present(a:dict, o)
let spec = a:dict[o]
if (o == 'up' || o == 'down') && spec[0] == '~'
let size = '-'.o[0].s:calc_size(&lines, spec, a:dict)
else
" Legacy boolean option
let size = '-'.o[0].(spec == 1 ? '' : substitute(spec, '^\~', '', ''))
endif
break
endif
break
endif
endfor
endfor
endif
return printf('LINES=%d COLUMNS=%d %s %s %s --',
\ &lines, &columns, fzf#shellescape(s:fzf_tmux), size, (has_key(a:dict, 'source') ? '' : '-'))
endfunction
@@ -527,7 +526,7 @@ function! s:dopopd()
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)
endif
unlet w:fzf_pushd
unlet! w:fzf_pushd
endfunction
function! s:xterm_launcher()
@@ -642,6 +641,9 @@ function! s:calc_size(max, val, dict)
endif
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 += stridx(opts, '--border') > stridx(opts, '--no-border') ? 2 : 0
if stridx(opts, '--header') > stridx(opts, '--no-header')
@@ -661,13 +663,15 @@ function! s:split(dict)
\ 'left': ['vertical topleft', 'vertical resize', &columns],
\ 'right': ['vertical botright', 'vertical resize', &columns] }
let ppos = s:getpos()
let is_popup = 0
try
if s:present(a:dict, 'window')
if type(a:dict.window) == type({})
if !has('nvim') && !has('patch-8.2.191')
throw 'Vim 8.2.191 or later is required for pop-up window'
if !s:popup_support()
throw 'Nvim 0.4+ or Vim 8.2.191+ with popupwin feature is required for pop-up window'
end
call s:popup(a:dict.window)
let is_popup = 1
else
execute 'keepalt' a:dict.window
endif
@@ -685,20 +689,22 @@ function! s:split(dict)
endif
execute cmd sz.'new'
execute resz sz
return [ppos, {}]
return [ppos, {}, is_popup]
endif
endfor
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
setlocal winfixwidth winfixheight
if !is_popup
setlocal winfixwidth winfixheight
endif
endtry
endfunction
function! s:execute_term(dict, command, temps) abort
let winrest = winrestcmd()
let pbuf = bufnr('')
let [ppos, winopts] = s:split(a:dict)
let [ppos, winopts, is_popup] = s:split(a:dict)
call s:use_sh()
let b:fzf = a:dict
let fzf = { 'buf': bufnr(''), 'pbuf': pbuf, 'ppos': ppos, 'dict': a:dict, 'temps': a:temps,
@@ -762,11 +768,17 @@ function! s:execute_term(dict, command, temps) abort
if has('nvim')
call termopen(command, fzf)
else
if !len(&bufhidden)
setlocal bufhidden=hide
let term_opts = {'exit_cb': function(fzf.on_exit)}
if is_popup
let term_opts.hidden = 1
else
let term_opts.curwin = 1
endif
let fzf.buf = term_start([&shell, &shellcmdflag, command], {'curwin': 1, 'exit_cb': function(fzf.on_exit)})
if !has('patch-8.0.1261') && !has('nvim') && !s:is_win
let fzf.buf = term_start([&shell, &shellcmdflag, command], term_opts)
if is_popup && exists('#TerminalWinOpen')
doautocmd <nomodeline> TerminalWinOpen
endif
if !has('patch-8.0.1261') && !s:is_win
call term_wait(fzf.buf, 20)
endif
endif
@@ -837,23 +849,22 @@ if has('nvim')
else
function! s:create_popup(hl, opts) abort
let is_frame = has_key(a:opts, 'border')
let buf = is_frame ? '' : term_start(&shell, #{hidden: 1, term_finish: 'close'})
let id = popup_create(buf, #{
let s:popup_create = {buf -> popup_create(buf, #{
\ line: a:opts.row,
\ col: a:opts.col,
\ minwidth: a:opts.width,
\ minheight: a:opts.height,
\ zindex: 50 - is_frame,
\ })
\ })}
if is_frame
let id = s:popup_create('')
call setwinvar(id, '&wincolor', a:hl)
call setbufline(winbufnr(id), 1, a:opts.border)
execute 'autocmd BufWipeout * ++once call popup_close('..id..')'
return winbufnr(id)
else
execute 'autocmd BufWipeout * ++once call term_sendkeys('..buf..', "exit\<CR>")'
autocmd TerminalOpen * ++once call s:popup_create(str2nr(expand('<abuf>')))
endif
return winbufnr(id)
endfunction
endif
@@ -862,9 +873,9 @@ function! s:popup(opts) abort
let ambidouble = &ambiwidth == 'double' ? 2 : 1
" Size and position
let width = min([max([0, float2nr(&columns * a:opts.width)]), &columns])
let width = min([max([8, a:opts.width > 1 ? a:opts.width : float2nr(&columns * a:opts.width)]), &columns])
let width += width % ambidouble
let height = min([max([0, float2nr(&lines * a:opts.height)]), &lines - has('nvim')])
let height = min([max([4, a:opts.height > 1 ? a:opts.height : float2nr(&lines * a:opts.height)]), &lines - has('nvim')])
let row = float2nr(get(a:opts, 'yoffset', 0.5) * (&lines - height))
let col = float2nr(get(a:opts, 'xoffset', 0.5) * (&columns - width))

View File

@@ -249,22 +249,30 @@ _fzf_dir_completion() {
}
_fzf_complete_kill() {
[ -n "${COMP_WORDS[COMP_CWORD]}" ] && return 1
local selected
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' ' ')
selected=${selected% }
printf '\e[5n'
if [ -n "$selected" ]; then
COMPREPLY=( "$selected" )
return 0
local trigger=${FZF_COMPLETION_TRIGGER-'**'}
local cur="${COMP_WORDS[COMP_CWORD]}"
if [[ -z "$cur" ]]; then
COMP_WORDS[$COMP_CWORD]=$trigger
elif [[ "$cur" != *"$trigger" ]]; then
return 1
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_complete +m -- "$@" < <(
cat <(cat ~/.ssh/config ~/.ssh/config.d/* /etc/ssh/ssh_config 2> /dev/null | command grep -i '^\s*host\(name\)\? ' | awk '{for (i = 2; i <= NF; i++) print $1 " " $i}' | command grep -v '[*?]') \
command cat <(command tail -n +1 ~/.ssh/config ~/.ssh/config.d/* /etc/ssh/ssh_config 2> /dev/null | command grep -i '^\s*host\(name\)\? ' | awk '{for (i = 2; i <= NF; i++) print $1 " " $i}' | command grep -v '[*?]') \
<(command grep -oE '^[[a-z0-9.,:-]+' ~/.ssh/known_hosts | tr ',' '\n' | tr -d '[' | awk '{ print $1 " " $1 }') \
<(command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0') |
awk '{if (length($2) > 0) {print $2}}' | sort -u
@@ -296,11 +304,10 @@ a_cmds="
find git grep gunzip gzip hg jar
ln ls mv open rm rsync scp
svn tar unzip zip"
x_cmds="kill"
# Preserve existing completion
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)"
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"
done
# Kill completion
# Kill completion (supports empty completion trigger)
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() {
local kind fn cmd
kind=$1
fn=_fzf_${1}_completion
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
fi
shift

View File

@@ -117,6 +117,7 @@ __fzf_extract_command() {
local token tokens
tokens=(${(z)1})
for token in $tokens; do
token=${(Q)token}
if [[ "$token" =~ [[:alnum:]] && ! "$token" =~ "=" ]]; then
echo "$token"
return
@@ -224,7 +225,7 @@ _fzf_complete_telnet() {
_fzf_complete_ssh() {
_fzf_complete +m -- "$@" < <(
setopt localoptions nonomatch
command cat <(cat ~/.ssh/config ~/.ssh/config.d/* /etc/ssh/ssh_config 2> /dev/null | command grep -i '^\s*host\(name\)\? ' | awk '{for (i = 2; i <= NF; i++) print $1 " " $i}' | command grep -v '[*?]') \
command cat <(command tail -n +1 ~/.ssh/config ~/.ssh/config.d/* /etc/ssh/ssh_config 2> /dev/null | command grep -i '^\s*host\(name\)\? ' | awk '{for (i = 2; i <= NF; i++) print $1 " " $i}' | command grep -v '[*?]') \
<(command grep -oE '^[[a-z0-9.,:-]+' ~/.ssh/known_hosts | tr ',' '\n' | tr -d '[' | awk '{ print $1 " " $1 }') \
<(command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0') |
awk '{if (length($2) > 0) {print $2}}' | sort -u
@@ -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() {
local tokens cmd prefix trigger tail matches lbuf d_cmds
setopt localoptions noshwordsplit noksh_arrays noposixbuiltins
@@ -273,20 +284,21 @@ fzf-completion() {
tokens=(${tokens[0,-2]})
fi
lbuf=$LBUFFER
tail=${LBUFFER:$(( ${#LBUFFER} - ${#trigger} ))}
# Kill completion (do not require trigger sequence)
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' ' ')
if [ -n "$matches" ]; then
LBUFFER="$LBUFFER$matches"
fi
zle reset-prompt
if [ "$cmd" = kill -a ${LBUFFER[-1]} = ' ' ]; then
tail=$trigger
tokens+=$trigger
lbuf="$lbuf$trigger"
fi
# 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})
[ -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
prefix="$prefix" eval _fzf_complete_${cmd} ${(q)lbuf}

View File

@@ -87,9 +87,15 @@ fzf-cd-widget() {
zle redisplay
return 0
fi
cd "$dir"
unset dir # ensure this doesn't end up appearing in prompt expansion
if [ -z "$BUFFER" ]; then
BUFFER="cd ${(q)dir}"
zle accept-line
else
print -sr "cd ${(q)dir}"
cd "$dir"
fi
local ret=$?
unset dir # ensure this doesn't end up appearing in prompt expansion
zle fzf-redraw-prompt
return $ret
}
@@ -100,7 +106,7 @@ bindkey '\ec' fzf-cd-widget
fzf-history-widget() {
local selected num
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)) )
local ret=$?
if [ -n "$selected" ]; then

View File

@@ -405,6 +405,74 @@ var normalized map[rune]rune = map[rune]rune{
0x024E: 'Y', // WITH STROKE, LATIN CAPITAL LETTER
0x028F: 'Y', // , 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

View File

@@ -10,7 +10,7 @@ import (
const (
// Current version
version = "0.21.1"
version = "0.23.1"
// Core
coordinatorDelayMax time.Duration = 100 * time.Millisecond

View File

@@ -80,7 +80,11 @@ const usage = `usage: fzf [options]
Preview
--preview=COMMAND Command to preview highlighted line ({})
--preview-window=OPT Preview window layout (default: right:50%)
[up|down|left|right][:SIZE[%]][:wrap][:hidden]
[up|down|left|right][:SIZE[%]]
[:[no]wrap][:[no]cycle][:[no]hidden]
[:rounded|sharp|noborder]
[:+SCROLL[-OFFSET]]
[:default]
Scripting
-q, --query=STR Start the finder with the given query
@@ -159,9 +163,11 @@ type previewOpts struct {
command string
position windowPosition
size sizeSpec
scroll string
hidden bool
wrap bool
border bool
cycle bool
border tui.BorderShape
}
// Options stores the values of command-line options
@@ -221,6 +227,10 @@ type Options struct {
Version bool
}
func defaultPreviewOpts(command string) previewOpts {
return previewOpts{command, posRight, sizeSpec{50, true}, "", false, false, false, tui.BorderRounded}
}
func defaultOptions() *Options {
return &Options{
Fuzzy: true,
@@ -260,7 +270,7 @@ func defaultOptions() *Options {
ToggleSort: false,
Expect: make(map[int]string),
Keymap: make(map[int][]action),
Preview: previewOpts{"", posRight, sizeSpec{50, true}, false, false, true},
Preview: defaultPreviewOpts(""),
PrintQuery: false,
ReadZero: false,
Printer: func(str string) { fmt.Println(str) },
@@ -464,6 +474,8 @@ func parseKeyChords(str string, message string) map[int]string {
chord = tui.CtrlRightBracket
case "change":
chord = tui.Change
case "backward-eof":
chord = tui.BackwardEOF
case "alt-enter", "alt-return":
chord = tui.CtrlAltM
case "alt-space":
@@ -682,7 +694,7 @@ func init() {
// Backreferences are not supported.
// "~!@#$%^&*;/|".each_char.map { |c| Regexp.escape(c) }.map { |c| "#{c}[^#{c}]*#{c}" }.join('|')
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) {
@@ -694,6 +706,8 @@ func parseKeymap(keymap map[int][]action, str string) {
prefix := symbol + "execute"
if strings.HasPrefix(src[1:], "reload") {
prefix = symbol + "reload"
} else if strings.HasPrefix(src[1:], "preview") {
prefix = symbol + "preview"
} else if src[len(prefix)] == '-' {
c := src[len(prefix)+1]
if c == 's' || c == 'S' {
@@ -754,6 +768,8 @@ func parseKeymap(keymap map[int][]action, str string) {
appendAction(actAcceptNonEmpty)
case "print-query":
appendAction(actPrintQuery)
case "refresh-preview":
appendAction(actRefreshPreview)
case "replace-query":
appendAction(actReplaceQuery)
case "backward-char":
@@ -846,6 +862,10 @@ func parseKeymap(keymap map[int][]action, str string) {
appendAction(actPreviewPageUp)
case "preview-page-down":
appendAction(actPreviewPageDown)
case "preview-half-page-up":
appendAction(actPreviewHalfPageUp)
case "preview-half-page-down":
appendAction(actPreviewHalfPageDown)
default:
t := isExecuteAction(specLower)
if t == actIgnore {
@@ -859,6 +879,8 @@ func parseKeymap(keymap map[int][]action, str string) {
switch t {
case actReload:
offset = len("reload")
case actPreview:
offset = len("preview")
case actExecuteSilent:
offset = len("execute-silent")
case actExecuteMulti:
@@ -896,6 +918,8 @@ func isExecuteAction(str string) actionType {
switch prefix {
case "reload":
return actReload
case "preview":
return actPreview
case "execute":
return actExecute
case "execute-silent":
@@ -976,21 +1000,26 @@ func parseInfoStyle(str string) infoStyle {
}
func parsePreviewWindow(opts *previewOpts, input string) {
// Default
opts.position = posRight
opts.size = sizeSpec{50, true}
opts.hidden = false
opts.wrap = false
tokens := strings.Split(input, ":")
sizeRegex := regexp.MustCompile("^[0-9]+%?$")
offsetRegex := regexp.MustCompile("^\\+([0-9]+|{-?[0-9]+})(-[0-9]+|-/[1-9][0-9]*)?$")
for _, token := range tokens {
switch token {
case "":
case "default":
*opts = defaultPreviewOpts(opts.command)
case "hidden":
opts.hidden = true
case "nohidden":
opts.hidden = false
case "wrap":
opts.wrap = true
case "nowrap":
opts.wrap = false
case "cycle":
opts.cycle = true
case "nocycle":
opts.cycle = false
case "up", "top":
opts.position = posUp
case "down", "bottom":
@@ -999,26 +1028,22 @@ func parsePreviewWindow(opts *previewOpts, input string) {
opts.position = posLeft
case "right":
opts.position = posRight
case "border":
opts.border = true
case "rounded", "border":
opts.border = tui.BorderRounded
case "sharp":
opts.border = tui.BorderSharp
case "noborder":
opts.border = false
opts.border = tui.BorderNone
default:
if sizeRegex.MatchString(token) {
opts.size = parseSize(token, 99, "window size")
} else if offsetRegex.MatchString(token) {
opts.scroll = token[1:]
} else {
errorExit("invalid preview window layout: " + input)
errorExit("invalid preview window option: " + token)
}
}
}
if !opts.size.percent && opts.size.size > 0 {
// Adjust size for border
opts.size.size += 2
// And padding
if opts.position == posLeft || opts.position == posRight {
opts.size.size += 2
}
}
}
func parseMargin(margin string) [4]sizeSpec {
@@ -1260,7 +1285,7 @@ func parseOptions(opts *Options, allArgs []string) {
opts.Preview.command = ""
case "--preview-window":
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[%]][:rounded|sharp|noborder][:wrap][:cycle][:hidden][:+SCROLL[-OFFSET]][:default]"))
case "--height":
opts.Height = parseHeight(nextString(allArgs, &i, "height required: HEIGHT[%]"))
case "--min-height":

View File

@@ -387,23 +387,26 @@ func TestPreviewOpts(t *testing.T) {
opts.Preview.size.size == 50) {
t.Error()
}
opts = optsFor("--preview", "cat {}", "--preview-window=left:15:hidden:wrap")
opts = optsFor("--preview", "cat {}", "--preview-window=left:15:hidden:wrap:+{1}-/2")
if !(opts.Preview.command == "cat {}" &&
opts.Preview.hidden == true &&
opts.Preview.wrap == true &&
opts.Preview.position == posLeft &&
opts.Preview.scroll == "{1}-/2" &&
opts.Preview.size.percent == false &&
opts.Preview.size.size == 15+2+2) {
opts.Preview.size.size == 15) {
t.Error(opts.Preview)
}
opts = optsFor("--preview-window=up:15:wrap:hidden", "--preview-window=down")
opts = optsFor("--preview-window=up:15:wrap:hidden:+{1}-/2", "--preview-window=down", "--preview-window=cycle")
if !(opts.Preview.command == "" &&
opts.Preview.hidden == false &&
opts.Preview.wrap == false &&
opts.Preview.hidden == true &&
opts.Preview.wrap == true &&
opts.Preview.cycle == true &&
opts.Preview.position == posDown &&
opts.Preview.size.percent == true &&
opts.Preview.size.size == 50) {
t.Error(opts.Preview)
opts.Preview.scroll == "{1}-/2" &&
opts.Preview.size.percent == false &&
opts.Preview.size.size == 15) {
t.Error(opts.Preview.size.size)
}
opts = optsFor("--preview-window=up:15:wrap:hidden")
if !(opts.Preview.command == "" &&
@@ -411,7 +414,14 @@ func TestPreviewOpts(t *testing.T) {
opts.Preview.wrap == true &&
opts.Preview.position == posUp &&
opts.Preview.size.percent == false &&
opts.Preview.size.size == 15+2) {
opts.Preview.size.size == 15) {
t.Error(opts.Preview)
}
opts = optsFor("--preview=foo", "--preview-window=up", "--preview-window=default:70%")
if !(opts.Preview.command == "foo" &&
opts.Preview.position == posRight &&
opts.Preview.size.percent == true &&
opts.Preview.size.size == 70) {
t.Error(opts.Preview)
}
}

View File

@@ -33,6 +33,7 @@ type term struct {
inv bool
text []rune
caseSensitive bool
normalize bool
}
// String returns the string representation of a term.
@@ -128,6 +129,8 @@ func BuildPattern(fuzzy bool, fuzzyAlgo algo.Algo, extended bool, caseMode Case,
}
} else {
lowerString := strings.ToLower(asString)
normalize = normalize &&
lowerString == string(algo.NormalizeRunes([]rune(lowerString)))
caseSensitive = caseMode == CaseRespect ||
caseMode == CaseSmart && lowerString != asString
if !caseSensitive {
@@ -173,6 +176,8 @@ func parseTerms(fuzzy bool, caseMode Case, normalize bool, str string) []termSet
lowerText := strings.ToLower(text)
caseSensitive := caseMode == CaseRespect ||
caseMode == CaseSmart && text != lowerText
normalizeTerm := normalize &&
lowerText == string(algo.NormalizeRunes([]rune(lowerText)))
if !caseSensitive {
text = lowerText
}
@@ -222,14 +227,15 @@ func parseTerms(fuzzy bool, caseMode Case, normalize bool, str string) []termSet
set = termSet{}
}
textRunes := []rune(text)
if normalize {
if normalizeTerm {
textRunes = algo.NormalizeRunes(textRunes)
}
set = append(set, term{
typ: typ,
inv: inv,
text: textRunes,
caseSensitive: caseSensitive})
caseSensitive: caseSensitive,
normalize: normalizeTerm})
switchSet = true
}
}
@@ -360,7 +366,7 @@ func (p *Pattern) extendedMatch(item *Item, withPos bool, slab *util.Slab) ([]Of
matched := false
for _, term := range termSet {
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 term.inv {
continue

View File

@@ -23,12 +23,14 @@ import (
// import "github.com/pkg/profile"
var placeholder *regexp.Regexp
var numericPrefix *regexp.Regexp
var activeTempFiles []string
const ellipsis string = ".."
func init() {
placeholder = regexp.MustCompile(`\\?(?:{[+sf]*[0-9,-.]*}|{q}|{\+?f?nf?})`)
numericPrefix = regexp.MustCompile(`^[[:punct:]]*([0-9]+)`)
activeTempFiles = []string{}
}
@@ -64,7 +66,7 @@ type Terminal struct {
initDelay time.Duration
infoStyle infoStyle
spinner []string
prompt string
prompt func()
promptLen int
pointer string
pointerLen int
@@ -224,14 +226,18 @@ const (
actJump
actJumpAccept
actPrintQuery
actRefreshPreview
actReplaceQuery
actToggleSort
actTogglePreview
actTogglePreviewWrap
actPreview
actPreviewUp
actPreviewDown
actPreviewPageUp
actPreviewPageDown
actPreviewHalfPageUp
actPreviewHalfPageDown
actPreviousHistory
actNextHistory
actExecute
@@ -255,6 +261,16 @@ type searchRequest struct {
command *string
}
type previewRequest struct {
template string
list []*Item
}
type previewResult struct {
content string
offset int
}
func toActions(types ...actionType) []action {
actions := make([]action, len(types))
for idx, t := range types {
@@ -326,6 +342,17 @@ func trimQuery(query string) []rune {
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
func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
input := trimQuery(opts.Query)
@@ -343,7 +370,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
delay = initialDelay
}
var previewBox *util.EventBox
if len(opts.Preview.command) > 0 {
if len(opts.Preview.command) > 0 || hasPreviewAction(opts) {
previewBox = util.NewEventBox()
}
strongAttr := tui.Bold
@@ -382,8 +409,8 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
}
renderer = tui.NewLightRenderer(opts.Theme, opts.Black, opts.Mouse, opts.Tabstop, opts.ClearOnExit, false, maxHeightFunc)
}
wordRubout := "[^[:alnum:]][[:alnum:]]"
wordNext := "[[:alnum:]][^[:alnum:]]|(.$)"
wordRubout := "[^\\pL\\pN][\\pL\\pN]"
wordNext := "[\\pL\\pN][^\\pL\\pN]|(.$)"
if opts.FileWord {
sep := regexp.QuoteMeta(string(os.PathSeparator))
wordRubout = fmt.Sprintf("%s[^%s]", sep, sep)
@@ -451,7 +478,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
killChan: make(chan int),
tui: renderer,
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.marker, t.markerLen = t.processTabs([]rune(opts.Marker), 0)
// Pre-calculated empty pointer and marker signs
@@ -461,6 +488,19 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
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 {
return t.infoStyle != infoDefault
}
@@ -574,12 +614,12 @@ const (
maxDisplayWidthCalc = 1024
)
func calculateSize(base int, size sizeSpec, margin int, minSize int) int {
max := base - margin
func calculateSize(base int, size sizeSpec, occupied int, minSize int, pad int) int {
max := base - occupied
if size.percent {
return util.Constrain(int(float64(base)*0.01*size.size), minSize, max)
}
return util.Constrain(int(size.size), minSize, max)
return util.Constrain(int(size.size)+pad, minSize, max)
}
func (t *Terminal) resizeWindows() {
@@ -638,6 +678,8 @@ func (t *Terminal) resizeWindows() {
}
if t.pborder != nil {
t.pborder.Close()
}
if t.pwindow != nil {
t.pwindow.Close()
}
@@ -662,38 +704,51 @@ func (t *Terminal) resizeWindows() {
noBorder := tui.MakeBorderStyle(tui.BorderNone, t.unicode)
if previewVisible {
createPreviewWindow := func(y int, x int, w int, h int) {
previewBorder := tui.MakeBorderStyle(tui.BorderRounded, t.unicode)
if !t.preview.border {
previewBorder = tui.MakeTransparentBorder()
pwidth := w
pheight := h
if t.preview.border != tui.BorderNone {
previewBorder := tui.MakeBorderStyle(t.preview.border, t.unicode)
t.pborder = t.tui.NewWindow(y, x, w, h, true, previewBorder)
pwidth -= 4
pheight -= 2
x += 2
y += 1
} else {
previewBorder := tui.MakeTransparentBorder()
t.pborder = t.tui.NewWindow(y, x, w, h, true, previewBorder)
pwidth -= 4
x += 2
}
t.pborder = t.tui.NewWindow(y, x, w, h, true, previewBorder)
pwidth := w - 4
// ncurses auto-wraps the line when the cursor reaches the right-end of
// the window. To prevent unintended line-wraps, we use the width one
// column larger than the desired value.
if !t.preview.wrap && t.tui.DoesAutoWrap() {
pwidth += 1
}
t.pwindow = t.tui.NewWindow(y+1, x+2, pwidth, h-2, true, noBorder)
t.pwindow = t.tui.NewWindow(y, x, pwidth, pheight, true, noBorder)
}
verticalPad := 2
if t.preview.border == tui.BorderNone {
verticalPad = 0
}
switch t.preview.position {
case posUp:
pheight := calculateSize(height, t.preview.size, minHeight, 3)
pheight := calculateSize(height, t.preview.size, minHeight, 3, verticalPad)
t.window = t.tui.NewWindow(
marginInt[0]+pheight, marginInt[3], width, height-pheight, false, noBorder)
createPreviewWindow(marginInt[0], marginInt[3], width, pheight)
case posDown:
pheight := calculateSize(height, t.preview.size, minHeight, 3)
pheight := calculateSize(height, t.preview.size, minHeight, 3, verticalPad)
t.window = t.tui.NewWindow(
marginInt[0], marginInt[3], width, height-pheight, false, noBorder)
createPreviewWindow(marginInt[0]+height-pheight, marginInt[3], width, pheight)
case posLeft:
pwidth := calculateSize(width, t.preview.size, minWidth, 5)
pwidth := calculateSize(width, t.preview.size, minWidth, 5, 4)
t.window = t.tui.NewWindow(
marginInt[0], marginInt[3]+pwidth, width-pwidth, height, false, noBorder)
createPreviewWindow(marginInt[0], marginInt[3], pwidth, height)
case posRight:
pwidth := calculateSize(width, t.preview.size, minWidth, 5)
pwidth := calculateSize(width, t.preview.size, minWidth, 5, 4)
t.window = t.tui.NewWindow(
marginInt[0], marginInt[3], width-pwidth, height, false, noBorder)
createPreviewWindow(marginInt[0], marginInt[3]+width-pwidth, pwidth, height)
@@ -762,7 +817,7 @@ func (t *Terminal) placeCursor() {
func (t *Terminal) printPrompt() {
t.move(0, 0, true)
t.window.CPrint(tui.ColPrompt, t.strong, t.prompt)
t.prompt()
before, after := t.updatePromptOffset()
t.window.CPrint(tui.ColNormal, t.strong, string(before))
@@ -999,7 +1054,7 @@ func (t *Terminal) printHighlighted(result Result, attr tui.Attr, col1 tui.Color
}
offsets := result.colorOffsets(charOffsets, t.theme, col2, attr, current)
maxWidth := t.window.Width() - 3
maxWidth := t.window.Width() - (t.pointerLen + t.markerLen + 1)
maxe = util.Constrain(maxe+util.Min(maxWidth/2-2, t.hscrollOff), 0, len(text))
displayWidth := t.displayWidthWithLimit(text, 0, maxWidth)
if displayWidth > maxWidth {
@@ -1172,7 +1227,10 @@ func (t *Terminal) refresh() {
windows = append(windows, t.border)
}
if t.hasPreviewWindow() {
windows = append(windows, t.pborder, t.pwindow)
if t.pborder != nil {
windows = append(windows, t.pborder)
}
windows = append(windows, t.pwindow)
}
windows = append(windows, t.window)
t.tui.RefreshWindows(windows)
@@ -1196,7 +1254,8 @@ func findLastMatch(pattern string, str string) int {
if locs == nil {
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 {
@@ -1208,7 +1267,8 @@ func findFirstMatch(pattern string, str string) int {
if loc == nil {
return -1
}
return loc[0]
prefix := []rune(str[:loc[0]])
return len(prefix)
}
func copySlice(slice []rune) []rune {
@@ -1316,6 +1376,50 @@ func cleanTemporaryFiles() {
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, height int) 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
}
if nums[1][0] == '/' {
denom := atopi(nums[1][1:])
if denom == 0 {
return base
}
return base - height/denom
}
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 {
current := allItems[:1]
selected := allItems[1:]
@@ -1414,7 +1518,7 @@ func (t *Terminal) executeCommand(template string, forcePlus bool, background bo
if !valid {
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)
if !background {
cmd.Stdin = os.Stdin
@@ -1422,13 +1526,13 @@ func (t *Terminal) executeCommand(template string, forcePlus bool, background bo
cmd.Stderr = os.Stderr
t.tui.Pause(true)
cmd.Run()
t.tui.Resume(true)
t.tui.Resume(true, false)
t.redraw()
t.refresh()
} else {
t.tui.Pause(false)
cmd.Run()
t.tui.Resume(false)
t.tui.Resume(false, false)
}
cleanTemporaryFiles()
}
@@ -1455,8 +1559,8 @@ func (t *Terminal) currentItem() *Item {
func (t *Terminal) buildPlusList(template string, forcePlus bool) (bool, []*Item) {
current := t.currentItem()
_, plus, query := hasPreviewFlags(template)
if !(query && len(t.input) > 0 || (forcePlus || plus) && len(t.selected) > 0) {
slot, plus, query := hasPreviewFlags(template)
if !(!slot || query && len(t.input) > 0 || (forcePlus || plus) && len(t.selected) > 0) {
return current != nil, []*Item{current, current}
}
@@ -1583,24 +1687,29 @@ func (t *Terminal) Loop() {
if t.hasPreviewer() {
go func() {
for {
var request []*Item
var items []*Item
var commandTemplate string
t.previewBox.Wait(func(events *util.Events) {
for req, value := range *events {
switch req {
case reqPreviewEnqueue:
request = value.([]*Item)
request := value.(previewRequest)
commandTemplate = request.template
items = request.list
}
}
events.Clear()
})
// We don't display preview window if no match
if request[0] != nil {
command := replacePlaceholder(t.preview.command,
t.ansi, t.delimiter, t.printsep, false, string(t.Input()), request)
if items[0] != nil {
command := t.replacePlaceholder(commandTemplate, false, string(t.Input()), items)
offset := 0
cmd := util.ExecCommand(command, true)
if t.pwindow != nil {
height := t.pwindow.Height()
offset = t.evaluateScrollOffset(items, height)
env := os.Environ()
lines := fmt.Sprintf("LINES=%d", t.pwindow.Height())
lines := fmt.Sprintf("LINES=%d", height)
columns := fmt.Sprintf("COLUMNS=%d", t.pwindow.Width())
env = append(env, lines)
env = append(env, "FZF_PREVIEW_"+lines)
@@ -1639,11 +1748,11 @@ func (t *Terminal) Loop() {
cmd.Wait()
finishChan <- true
if out.Len() > 0 || !<-updateChan {
t.reqBox.Set(reqPreviewDisplay, out.String())
t.reqBox.Set(reqPreviewDisplay, previewResult{out.String(), offset})
}
cleanTemporaryFiles()
} else {
t.reqBox.Set(reqPreviewDisplay, "")
t.reqBox.Set(reqPreviewDisplay, previewResult{"", 0})
}
}
}()
@@ -1659,6 +1768,14 @@ func (t *Terminal) Loop() {
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() {
var focusedIndex int32 = minItem.Index()
var version int64 = -1
@@ -1685,11 +1802,7 @@ func (t *Terminal) Loop() {
if focusedIndex != currentIndex || version != t.version {
version = t.version
focusedIndex = currentIndex
if t.isPreviewEnabled() {
_, list := t.buildPlusList(t.preview.command, false)
t.cancelPreview()
t.previewBox.Set(reqPreviewEnqueue, list)
}
refreshPreview(t.preview.command)
}
case reqJump:
if t.merger.Length() == 0 {
@@ -1701,7 +1814,7 @@ func (t *Terminal) Loop() {
case reqRefresh:
t.suppress = false
case reqReinit:
t.tui.Resume(t.fullscreen)
t.tui.Resume(t.fullscreen, true)
t.redraw()
case reqRedraw:
t.redraw()
@@ -1713,9 +1826,10 @@ func (t *Terminal) Loop() {
return exitNoMatch
})
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.offset = 0
t.previewer.offset = util.Constrain(result.offset, 0, t.previewer.lines-1)
t.printPreview()
case reqPreviewRefresh:
t.printPreview()
@@ -1738,6 +1852,7 @@ func (t *Terminal) Loop() {
for looping {
var newCommand *string
changed := false
beof := false
queryChanged := false
event := t.tui.GetChar()
@@ -1754,6 +1869,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 {
if t.cy < t.merger.Length() && t.toggleItem(t.merger.Get(t.cy).item) {
req(reqInfo)
@@ -1765,8 +1888,11 @@ func (t *Terminal) Loop() {
if !t.previewer.more {
return
}
newOffset := util.Constrain(
t.previewer.offset+amount, 0, t.previewer.lines-1)
newOffset := t.previewer.offset + amount
if t.preview.cycle {
newOffset = (newOffset + t.previewer.lines) % t.previewer.lines
}
newOffset = util.Constrain(newOffset, 0, t.previewer.lines-1)
if t.previewer.offset != newOffset {
t.previewer.offset = newOffset
req(reqPreviewRefresh)
@@ -1802,17 +1928,15 @@ func (t *Terminal) Loop() {
return false
case actTogglePreview:
if t.hasPreviewer() {
t.previewer.enabled = !t.previewer.enabled
t.tui.Clear()
t.resizeWindows()
togglePreview(!t.previewer.enabled)
if t.previewer.enabled {
valid, list := t.buildPlusList(t.preview.command, false)
if valid {
t.cancelPreview()
t.previewBox.Set(reqPreviewEnqueue, list)
t.previewBox.Set(reqPreviewEnqueue,
previewRequest{t.preview.command, list})
}
}
req(reqPrompt, reqList, reqInfo, reqHeader)
}
case actTogglePreviewWrap:
if t.hasPreviewWindow() {
@@ -1838,6 +1962,14 @@ func (t *Terminal) Loop() {
if t.hasPreviewWindow() {
scrollPreview(t.pwindow.Height())
}
case actPreviewHalfPageUp:
if t.hasPreviewWindow() {
scrollPreview(-t.pwindow.Height() / 2)
}
case actPreviewHalfPageDown:
if t.hasPreviewWindow() {
scrollPreview(t.pwindow.Height() / 2)
}
case actBeginningOfLine:
t.cx = 0
case actBackwardChar:
@@ -1846,6 +1978,11 @@ func (t *Terminal) Loop() {
}
case actPrintQuery:
req(reqPrintQuery)
case actPreview:
togglePreview(true)
refreshPreview(a.a)
case actRefreshPreview:
refreshPreview(t.preview.command)
case actReplaceQuery:
if t.cy >= 0 && t.cy < t.merger.Length() {
t.input = t.merger.Get(t.cy).item.text.ToRunes()
@@ -1881,6 +2018,7 @@ func (t *Terminal) Loop() {
t.cx++
}
case actBackwardDeleteChar:
beof = len(t.input) == 0
if t.cx > 0 {
t.input = append(t.input[:t.cx-1], t.input[t.cx:]...)
t.cx--
@@ -1973,16 +2111,19 @@ func (t *Terminal) Loop() {
t.vset(0)
req(reqList)
case actUnixLineDiscard:
beof = len(t.input) == 0
if t.cx > 0 {
t.yanked = copySlice(t.input[:t.cx])
t.input = t.input[t.cx:]
t.cx = 0
}
case actUnixWordRubout:
beof = len(t.input) == 0
if t.cx > 0 {
t.rubout("\\s\\S")
}
case actBackwardKillWord:
beof = len(t.input) == 0
if t.cx > 0 {
t.rubout(t.wordRubout)
}
@@ -2118,8 +2259,7 @@ func (t *Terminal) Loop() {
valid = !slot || query
}
if valid {
command := replacePlaceholder(a.a,
t.ansi, t.delimiter, t.printsep, false, string(t.input), list)
command := t.replacePlaceholder(a.a, false, string(t.input), list)
newCommand = &command
}
}
@@ -2145,6 +2285,11 @@ func (t *Terminal) Loop() {
continue
}
}
if onEOFs, prs := t.keymap[tui.BackwardEOF]; beof && prs {
if !doActions(onEOFs, tui.BackwardEOF) {
continue
}
}
} else {
if mapkey == tui.Rune {
if idx := strings.IndexRune(t.jumpLabels, event.Char); idx >= 0 && idx < t.maxItems() && idx < t.merger.Length() {

View File

@@ -25,12 +25,12 @@ const (
Reverse = Attr(1 << 6)
)
func (r *FullscreenRenderer) Init() {}
func (r *FullscreenRenderer) Pause(bool) {}
func (r *FullscreenRenderer) Resume(bool) {}
func (r *FullscreenRenderer) Clear() {}
func (r *FullscreenRenderer) Refresh() {}
func (r *FullscreenRenderer) Close() {}
func (r *FullscreenRenderer) Init() {}
func (r *FullscreenRenderer) Pause(bool) {}
func (r *FullscreenRenderer) Resume(bool, bool) {}
func (r *FullscreenRenderer) Clear() {}
func (r *FullscreenRenderer) Refresh() {}
func (r *FullscreenRenderer) Close() {}
func (r *FullscreenRenderer) DoesAutoWrap() bool { return false }
func (r *FullscreenRenderer) GetChar() Event { return Event{} }

View File

@@ -3,7 +3,6 @@ package tui
import (
"fmt"
"os"
"os/exec"
"regexp"
"strconv"
"strings"
@@ -28,6 +27,7 @@ const (
const consoleDevice string = "/dev/tty"
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) {
r.stderrInternal(str, true)
@@ -125,17 +125,6 @@ func NewLightRenderer(theme *ColorTheme, forceBlack bool, mouse bool, tabstop in
return &r
}
func (r *LightRenderer) defaultTheme() *ColorTheme {
if strings.Contains(os.Getenv("TERM"), "256") {
return Dark256
}
colors, err := exec.Command("tput", "colors").Output()
if err == nil && atoi(strings.TrimSpace(string(colors)), 16) > 16 {
return Dark256
}
return Default16
}
func repeat(r rune, times int) string {
if times > 0 {
return strings.Repeat(string(r), times)
@@ -333,6 +322,13 @@ func (r *LightRenderer) escSequence(sz *int) Event {
if len(r.buffer) < 2 {
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
if r.buffer[1] >= 1 && r.buffer[1] <= 'z'-'a'+1 {
return Event{int(CtrlAltA + r.buffer[1] - 1), 0, nil}
@@ -345,81 +341,81 @@ func (r *LightRenderer) escSequence(sz *int) Event {
switch r.buffer[1] {
case ESC:
return Event{ESC, 0, nil}
case 32:
case ' ':
return Event{AltSpace, 0, nil}
case 47:
case '/':
return Event{AltSlash, 0, nil}
case 98:
case 'b':
return Event{AltB, 0, nil}
case 100:
case 'd':
return Event{AltD, 0, nil}
case 102:
case 'f':
return Event{AltF, 0, nil}
case 127:
return Event{AltBS, 0, nil}
case 91, 79:
case '[', 'O':
if len(r.buffer) < 3 {
return Event{Invalid, 0, nil}
}
*sz = 3
switch r.buffer[2] {
case 68:
case 'D':
if alt {
return Event{AltLeft, 0, nil}
}
return Event{Left, 0, nil}
case 67:
case 'C':
if alt {
// Ugh..
return Event{AltRight, 0, nil}
}
return Event{Right, 0, nil}
case 66:
case 'B':
if alt {
return Event{AltDown, 0, nil}
}
return Event{Down, 0, nil}
case 65:
case 'A':
if alt {
return Event{AltUp, 0, nil}
}
return Event{Up, 0, nil}
case 90:
case 'Z':
return Event{BTab, 0, nil}
case 72:
case 'H':
return Event{Home, 0, nil}
case 70:
case 'F':
return Event{End, 0, nil}
case 77:
case 'M':
return r.mouseSequence(sz)
case 80:
case 'P':
return Event{F1, 0, nil}
case 81:
case 'Q':
return Event{F2, 0, nil}
case 82:
case 'R':
return Event{F3, 0, nil}
case 83:
case 'S':
return Event{F4, 0, nil}
case 49, 50, 51, 52, 53, 54:
case '1', '2', '3', '4', '5', '6':
if len(r.buffer) < 4 {
return Event{Invalid, 0, nil}
}
*sz = 4
switch r.buffer[2] {
case 50:
if r.buffer[3] == 126 {
case '2':
if r.buffer[3] == '~' {
return Event{Insert, 0, nil}
}
if len(r.buffer) > 4 && r.buffer[4] == 126 {
if len(r.buffer) > 4 && r.buffer[4] == '~' {
*sz = 5
switch r.buffer[3] {
case 48:
case '0':
return Event{F9, 0, nil}
case 49:
case '1':
return Event{F10, 0, nil}
case 51:
case '3':
return Event{F11, 0, nil}
case 52:
case '4':
return Event{F12, 0, nil}
}
}
@@ -431,37 +427,37 @@ func (r *LightRenderer) escSequence(sz *int) Event {
return r.GetChar()
}
return Event{Invalid, 0, nil} // INS
case 51:
case '3':
return Event{Del, 0, nil}
case 52:
case '4':
return Event{End, 0, nil}
case 53:
case '5':
return Event{PgUp, 0, nil}
case 54:
case '6':
return Event{PgDn, 0, nil}
case 49:
case '1':
switch r.buffer[3] {
case 126:
case '~':
return Event{Home, 0, nil}
case 49, 50, 51, 52, 53, 55, 56, 57:
if len(r.buffer) == 5 && r.buffer[4] == 126 {
case '1', '2', '3', '4', '5', '7', '8', '9':
if len(r.buffer) == 5 && r.buffer[4] == '~' {
*sz = 5
switch r.buffer[3] {
case 49:
case '1':
return Event{F1, 0, nil}
case 50:
case '2':
return Event{F2, 0, nil}
case 51:
case '3':
return Event{F3, 0, nil}
case 52:
case '4':
return Event{F4, 0, nil}
case 53:
case '5':
return Event{F5, 0, nil}
case 55:
case '7':
return Event{F6, 0, nil}
case 56:
case '8':
return Event{F7, 0, nil}
case 57:
case '9':
return Event{F8, 0, nil}
}
}
@@ -561,7 +557,7 @@ func (r *LightRenderer) Pause(clear bool) {
}
}
func (r *LightRenderer) Resume(clear bool) {
func (r *LightRenderer) Resume(clear bool, sigcont bool) {
r.setupTerminal()
if clear {
if r.fullscreen {
@@ -570,10 +566,10 @@ func (r *LightRenderer) Resume(clear bool) {
r.rmcup()
}
r.flush()
} else if !r.fullscreen && r.mouse {
// NOTE: Resume(false) is only called on SIGCONT after SIGSTOP.
// And It's highly likely that the offset we obtained at the beginning will
// no longer be correct, so we simply disable mouse input.
} else if sigcont && !r.fullscreen && r.mouse {
// NOTE: SIGCONT (Coming back from CTRL-Z):
// It's highly likely that the offset we obtained at the beginning is
// no longer correct, so we simply disable mouse input.
r.csi("?1000l")
r.mouse = false
}

View File

@@ -5,6 +5,8 @@ package tui
import (
"fmt"
"os"
"os/exec"
"strings"
"syscall"
"github.com/junegunn/fzf/src/util"
@@ -15,6 +17,17 @@ func IsLightRendererSupported() bool {
return true
}
func (r *LightRenderer) defaultTheme() *ColorTheme {
if strings.Contains(os.Getenv("TERM"), "256") {
return Dark256
}
colors, err := exec.Command("tput", "colors").Output()
if err == nil && atoi(strings.TrimSpace(string(colors)), 16) > 16 {
return Dark256
}
return Default16
}
func (r *LightRenderer) fd() int {
return int(r.ttyin.Fd())
}

View File

@@ -34,6 +34,14 @@ func IsLightRendererSupported() bool {
return canSetVt100
}
func (r *LightRenderer) defaultTheme() *ColorTheme {
// the getenv check is borrowed from here: https://github.com/gdamore/tcell/commit/0c473b86d82f68226a142e96cc5a34c5a29b3690#diff-b008fcd5e6934bf31bc3d33bf49f47d8R178:
if !IsLightRendererSupported() || os.Getenv("ConEmuPID") != "" || os.Getenv("TCELL_TRUECOLOR") == "disable" {
return Default16
}
return Dark256
}
func (r *LightRenderer) initPlatform() error {
//outHandle := windows.Stdout
outHandle, _ := syscall.Open("CONOUT$", syscall.O_RDWR, 0)

View File

@@ -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 {
r.initScreen()
}

View File

@@ -87,6 +87,7 @@ const (
F12
Change
BackwardEOF
AltSpace
AltSlash
@@ -275,7 +276,7 @@ func MakeTransparentBorder() BorderStyle {
type Renderer interface {
Init()
Pause(clear bool)
Resume(clear bool)
Resume(clear bool, sigcont bool)
Clear()
RefreshWindows(windows []Window)
Refresh()

View File

@@ -1,19 +1,20 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
# http://www.rubydoc.info/github/rest-client/rest-client/RestClient
require 'rest_client'
require 'json'
if ARGV.length < 3
puts "usage: #$0 <token> <version> <files...>"
puts "usage: #{$PROGRAM_NAME} <token> <version> <files...>"
exit 1
end
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
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 }
unless rel
puts "#{version} not found"
@@ -21,25 +22,26 @@ unless rel
end
# 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
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}."
RestClient.delete "#{base}/assets/#{asset_id}",
:authorization => "token #{token}"
RestClient.delete("#{base}/assets/#{asset_id}",
authorization: "token #{token}")
else
puts "#{name} not found"
end
puts "Uploading #{name}"
RestClient.post(
"#{base.sub 'api', 'uploads'}/#{rel['id']}/assets?name=#{name}",
"#{base.sub('api', 'uploads')}/#{rel['id']}/assets?name=#{name}",
File.read(file),
:authorization => "token #{token}",
:content_type => "application/octet-stream")
authorization: "token #{token}",
content_type: 'application/octet-stream'
)
end
end.each(&:join)

File diff suppressed because it is too large Load Diff