Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package fzf for openSUSE:Factory checked in at 2021-12-25 20:16:41 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/fzf (Old) and /work/SRC/openSUSE:Factory/.fzf.new.2520 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "fzf" Sat Dec 25 20:16:41 2021 rev:21 rq:942381 version:0.29.0 Changes: -------- --- /work/SRC/openSUSE:Factory/fzf/fzf.changes 2021-11-17 01:15:22.878191043 +0100 +++ /work/SRC/openSUSE:Factory/.fzf.new.2520/fzf.changes 2021-12-25 20:17:05.813271640 +0100 @@ -1,0 +2,16 @@ +Fri Dec 24 22:54:43 UTC 2021 - Matej Cepl <mc...@suse.com> + +- Update to 0.29.0: + - Added `change-preview(...)` action to change the `--preview` command + - cf. `preview(...)` is a one-off action that doesn't change the + default preview command + - Added `change-preview-window(...)` action + - You can rotate through the different options separated by `|` + ```sh + fzf --preview 'cat {}' --preview-window right:40% \ + --bind 'ctrl-/:change-preview-window(right,70%|down,40%,border-top|hidden|)' + ``` + - Fixed rendering of the prompt line when overflow occurs with + `--info=inline` + +------------------------------------------------------------------- Old: ---- 0.28.0.tar.gz New: ---- 0.29.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ fzf.spec ++++++ --- /var/tmp/diff_new_pack.mArBfJ/_old 2021-12-25 20:17:06.389272109 +0100 +++ /var/tmp/diff_new_pack.mArBfJ/_new 2021-12-25 20:17:06.397272115 +0100 @@ -17,7 +17,7 @@ Name: fzf -Version: 0.28.0 +Version: 0.29.0 Release: 0 Summary: A command-line fuzzy finder License: MIT ++++++ 0.28.0.tar.gz -> 0.29.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.28.0/ADVANCED.md new/fzf-0.29.0/ADVANCED.md --- old/fzf-0.28.0/ADVANCED.md 2021-11-03 17:05:07.000000000 +0100 +++ new/fzf-0.29.0/ADVANCED.md 2021-12-24 17:46:01.000000000 +0100 @@ -429,30 +429,34 @@ Kubernetes pods. ```bash -#!/usr/bin/env bash - -read -ra tokens < <( - kubectl get pods --all-namespaces | - fzf --info=inline --layout=reverse --header-lines=1 --border \ +pods() { + FZF_DEFAULT_COMMAND="kubectl get pods --all-namespaces" \ + fzf --info=inline --layout=reverse --header-lines=1 \ --prompt "$(kubectl config current-context | sed 's/-context$//')> " \ - --header $'Press CTRL-O to open log in editor\n\n' \ - --bind ctrl-/:toggle-preview \ - --bind 'ctrl-o:execute:${EDITOR:-vim} <(kubectl logs --namespace {1} {2}) > /dev/tty' \ - --preview-window up,follow \ - --preview 'kubectl logs --follow --tail=100000 --namespace {1} {2}' "$@" -) -[ ${#tokens} -gt 1 ] && - kubectl exec -it --namespace "${tokens[0]}" "${tokens[1]}" -- bash + --header $'??? Enter (kubectl exec) ??? CTRL-O (open log in editor) ??? CTRL-R (reload) ???\n\n' \ + --bind 'ctrl-/:change-preview-window(80%,border-bottom|hidden|)' \ + --bind 'enter:execute:kubectl exec -it --namespace {1} {2} -- bash > /dev/tty' \ + --bind 'ctrl-o:execute:${EDITOR:-vim} <(kubectl logs --all-containers --namespace {1} {2}) > /dev/tty' \ + --bind 'ctrl-r:reload:$FZF_DEFAULT_COMMAND' \ + --preview-window up:follow \ + --preview 'kubectl logs --follow --all-containers --tail=10000 --namespace {1} {2}' "$@" +} ```  - The preview window will *"log tail"* the pod - Holding on to a large amount of log will consume a lot of memory. So we - limited the initial log amount with `--tail=100000`. -- With `execute` binding, you can press CTRL-O to open the log in your editor - without leaving fzf -- Select a pod (with an enter key) to `kubectl exec` into it + limited the initial log amount with `--tail=10000`. +- `execute` bindings allow you to run any command without leaving fzf + - Press enter key on a pod to `kubectl exec` into it + - Press CTRL-O to open the log in your editor +- Press CTRL-R to reload the pod list +- Press CTRL-/ repeatedly to to rotate through a different sets of preview + window options + 1. `80%,border-bottom` + 1. `hidden` + 1. Empty string after `|` translates to the default options from `--preview-window` Key bindings for git objects ---------------------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.28.0/CHANGELOG.md new/fzf-0.29.0/CHANGELOG.md --- old/fzf-0.28.0/CHANGELOG.md 2021-11-03 17:05:07.000000000 +0100 +++ new/fzf-0.29.0/CHANGELOG.md 2021-12-24 17:46:01.000000000 +0100 @@ -1,6 +1,19 @@ CHANGELOG ========= +0.29.0 +------ +- Added `change-preview(...)` action to change the `--preview` command + - cf. `preview(...)` is a one-off action that doesn't change the default + preview command +- Added `change-preview-window(...)` action + - You can rotate through the different options separated by `|` + ```sh + fzf --preview 'cat {}' --preview-window right:40% \ + --bind 'ctrl-/:change-preview-window(right,70%|down,40%,border-top|hidden|)' + ``` +- Fixed rendering of the prompt line when overflow occurs with `--info=inline` + 0.28.0 ------ - Added `--header-first` option to print header before the prompt line diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.28.0/Dockerfile new/fzf-0.29.0/Dockerfile --- old/fzf-0.28.0/Dockerfile 2021-11-03 17:05:07.000000000 +0100 +++ new/fzf-0.29.0/Dockerfile 2021-12-24 17:46:01.000000000 +0100 @@ -1,4 +1,4 @@ -FROM archlinux/base:latest +FROM archlinux RUN pacman -Sy && pacman --noconfirm -S awk git tmux zsh fish ruby procps go make gcc RUN gem install --no-document -v 5.14.2 minitest RUN echo '. /usr/share/bash-completion/completions/git' >> ~/.bashrc diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.28.0/README.md new/fzf-0.29.0/README.md --- old/fzf-0.28.0/README.md 2021-11-03 17:05:07.000000000 +0100 +++ new/fzf-0.29.0/README.md 2021-12-24 17:46:01.000000000 +0100 @@ -86,7 +86,7 @@ ### Using Homebrew -You can use [Homebrew](http://brew.sh/) (on macOS or Linux) +You can use [Homebrew](https://brew.sh/) (on macOS or Linux) to install fzf. ```sh @@ -131,6 +131,8 @@ > > Refer to the package documentation for more information. (e.g. `apt-cache > show fzf`) +[](https://repology.org/project/fzf/versions) + ### Windows Pre-built binaries for Windows can be downloaded [here][bin]. fzf is also diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.28.0/install new/fzf-0.29.0/install --- old/fzf-0.28.0/install 2021-11-03 17:05:07.000000000 +0100 +++ new/fzf-0.29.0/install 2021-12-24 17:46:01.000000000 +0100 @@ -2,7 +2,7 @@ set -u -version=0.28.0 +version=0.29.0 auto_completion= key_bindings= update_config=2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.28.0/install.ps1 new/fzf-0.29.0/install.ps1 --- old/fzf-0.28.0/install.ps1 2021-11-03 17:05:07.000000000 +0100 +++ new/fzf-0.29.0/install.ps1 2021-12-24 17:46:01.000000000 +0100 @@ -1,4 +1,4 @@ -$version="0.28.0" +$version="0.29.0" $fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.28.0/main.go new/fzf-0.29.0/main.go --- old/fzf-0.28.0/main.go 2021-11-03 17:05:07.000000000 +0100 +++ new/fzf-0.29.0/main.go 2021-12-24 17:46:01.000000000 +0100 @@ -5,7 +5,7 @@ "github.com/junegunn/fzf/src/protector" ) -var version string = "0.28" +var version string = "0.29" var revision string = "devel" func main() { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.28.0/man/man1/fzf-tmux.1 new/fzf-0.29.0/man/man1/fzf-tmux.1 --- old/fzf-0.28.0/man/man1/fzf-tmux.1 2021-11-03 17:05:07.000000000 +0100 +++ new/fzf-0.29.0/man/man1/fzf-tmux.1 2021-12-24 17:46:01.000000000 +0100 @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. .. -.TH fzf-tmux 1 "Nov 2021" "fzf 0.28.0" "fzf-tmux - open fzf in tmux split pane" +.TH fzf-tmux 1 "Dec 2021" "fzf 0.29.0" "fzf-tmux - open fzf in tmux split pane" .SH NAME fzf-tmux - open fzf in tmux split pane diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.28.0/man/man1/fzf.1 new/fzf-0.29.0/man/man1/fzf.1 --- old/fzf-0.28.0/man/man1/fzf.1 2021-11-03 17:05:07.000000000 +0100 +++ new/fzf-0.29.0/man/man1/fzf.1 2021-12-24 17:46:01.000000000 +0100 @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. .. -.TH fzf 1 "Nov 2021" "fzf 0.28.0" "fzf - a command-line fuzzy finder" +.TH fzf 1 "Dec 2021" "fzf 0.29.0" "fzf - a command-line fuzzy finder" .SH NAME fzf - a command-line fuzzy finder @@ -810,77 +810,79 @@ A key or an event can be bound to one or more of the following actions. \fBACTION: DEFAULT BINDINGS (NOTES): - \fBabort\fR \fIctrl-c ctrl-g ctrl-q esc\fR - \fBaccept\fR \fIenter double-click\fR - \fBaccept-non-empty\fR (same as \fBaccept\fR except that it prevents fzf from exiting without selection) - \fBbackward-char\fR \fIctrl-b left\fR - \fBbackward-delete-char\fR \fIctrl-h bspace\fR - \fBbackward-delete-char/eof\fR (same as \fBbackward-delete-char\fR except aborts fzf if query is empty) - \fBbackward-kill-word\fR \fIalt-bs\fR - \fBbackward-word\fR \fIalt-b shift-left\fR - \fBbeginning-of-line\fR \fIctrl-a home\fR - \fBcancel\fR (clear query string if not empty, abort fzf otherwise) - \fBchange-prompt(...)\fR (change prompt to the given string) - \fBclear-screen\fR \fIctrl-l\fR - \fBclear-selection\fR (clear multi-selection) - \fBclose\fR (close preview window if open, abort fzf otherwise) - \fBclear-query\fR (clear query string) - \fBdelete-char\fR \fIdel\fR - \fBdelete-char/eof\fR \fIctrl-d\fR (same as \fBdelete-char\fR except aborts fzf if query is empty) + \fBabort\fR \fIctrl-c ctrl-g ctrl-q esc\fR + \fBaccept\fR \fIenter double-click\fR + \fBaccept-non-empty\fR (same as \fBaccept\fR except that it prevents fzf from exiting without selection) + \fBbackward-char\fR \fIctrl-b left\fR + \fBbackward-delete-char\fR \fIctrl-h bspace\fR + \fBbackward-delete-char/eof\fR (same as \fBbackward-delete-char\fR except aborts fzf if query is empty) + \fBbackward-kill-word\fR \fIalt-bs\fR + \fBbackward-word\fR \fIalt-b shift-left\fR + \fBbeginning-of-line\fR \fIctrl-a home\fR + \fBcancel\fR (clear query string if not empty, abort fzf otherwise) + \fBchange-preview(...)\fR (change \fB--preview\fR option) + \fBchange-preview-window(...)\fR (change \fB--preview-window\fR option; rotate through the multiple option sets separated by '|') + \fBchange-prompt(...)\fR (change prompt to the given string) + \fBclear-screen\fR \fIctrl-l\fR + \fBclear-selection\fR (clear multi-selection) + \fBclose\fR (close preview window if open, abort fzf otherwise) + \fBclear-query\fR (clear query string) + \fBdelete-char\fR \fIdel\fR + \fBdelete-char/eof\fR \fIctrl-d\fR (same as \fBdelete-char\fR except aborts fzf if query is empty) \fBdeselect\fR - \fBdeselect-all\fR (deselect all matches) - \fBdisable-search\fR (disable search functionality) - \fBdown\fR \fIctrl-j ctrl-n down\fR - \fBenable-search\fR (enable search functionality) - \fBend-of-line\fR \fIctrl-e end\fR - \fBexecute(...)\fR (see below for the details) - \fBexecute-silent(...)\fR (see below for the details) - \fBfirst\fR (move to the first match) - \fBforward-char\fR \fIctrl-f right\fR - \fBforward-word\fR \fIalt-f shift-right\fR + \fBdeselect-all\fR (deselect all matches) + \fBdisable-search\fR (disable search functionality) + \fBdown\fR \fIctrl-j ctrl-n down\fR + \fBenable-search\fR (enable search functionality) + \fBend-of-line\fR \fIctrl-e end\fR + \fBexecute(...)\fR (see below for the details) + \fBexecute-silent(...)\fR (see below for the details) + \fBfirst\fR (move to the first match) + \fBforward-char\fR \fIctrl-f right\fR + \fBforward-word\fR \fIalt-f shift-right\fR \fBignore\fR - \fBjump\fR (EasyMotion-like 2-keystroke movement) - \fBjump-accept\fR (jump and accept) + \fBjump\fR (EasyMotion-like 2-keystroke movement) + \fBjump-accept\fR (jump and accept) \fBkill-line\fR - \fBkill-word\fR \fIalt-d\fR - \fBlast\fR (move to the last match) - \fBnext-history\fR (\fIctrl-n\fR on \fB--history\fR) - \fBpage-down\fR \fIpgdn\fR - \fBpage-up\fR \fIpgup\fR + \fBkill-word\fR \fIalt-d\fR + \fBlast\fR (move to the last match) + \fBnext-history\fR (\fIctrl-n\fR on \fB--history\fR) + \fBpage-down\fR \fIpgdn\fR + \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(...)\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 \fBpreview-bottom\fR \fBpreview-top\fR - \fBprevious-history\fR (\fIctrl-p\fR on \fB--history\fR) - \fBprint-query\fR (print query and exit) - \fBput\fR (put the character to the prompt) + \fBprevious-history\fR (\fIctrl-p\fR on \fB--history\fR) + \fBprint-query\fR (print query and exit) + \fBput\fR (put the character to the prompt) \fBrefresh-preview\fR - \fBreload(...)\fR (see below for the details) - \fBreplace-query\fR (replace query string with the current selection) + \fBreload(...)\fR (see below for the details) + \fBreplace-query\fR (replace query string with the current selection) \fBselect\fR - \fBselect-all\fR (select all matches) - \fBtoggle\fR (\fIright-click\fR) - \fBtoggle-all\fR (toggle all matches) - \fBtoggle+down\fR \fIctrl-i (tab)\fR - \fBtoggle-in\fR (\fB--layout=reverse*\fR ? \fBtoggle+up\fR : \fBtoggle+down\fR) - \fBtoggle-out\fR (\fB--layout=reverse*\fR ? \fBtoggle+down\fR : \fBtoggle+up\fR) + \fBselect-all\fR (select all matches) + \fBtoggle\fR (\fIright-click\fR) + \fBtoggle-all\fR (toggle all matches) + \fBtoggle+down\fR \fIctrl-i (tab)\fR + \fBtoggle-in\fR (\fB--layout=reverse*\fR ? \fBtoggle+up\fR : \fBtoggle+down\fR) + \fBtoggle-out\fR (\fB--layout=reverse*\fR ? \fBtoggle+down\fR : \fBtoggle+up\fR) \fBtoggle-preview\fR \fBtoggle-preview-wrap\fR - \fBtoggle-search\fR (toggle search functionality) + \fBtoggle-search\fR (toggle search functionality) \fBtoggle-sort\fR - \fBtoggle+up\fR \fIbtab (shift-tab)\fR - \fBunbind(...)\fR (unbind bindings) - \fBunix-line-discard\fR \fIctrl-u\fR - \fBunix-word-rubout\fR \fIctrl-w\fR - \fBup\fR \fIctrl-k ctrl-p up\fR - \fByank\fR \fIctrl-y\fR + \fBtoggle+up\fR \fIbtab (shift-tab)\fR + \fBunbind(...)\fR (unbind bindings) + \fBunix-line-discard\fR \fIctrl-u\fR + \fBunix-word-rubout\fR \fIctrl-w\fR + \fBup\fR \fIctrl-k ctrl-p up\fR + \fByank\fR \fIctrl-y\fR .SS ACTION COMPOSITION @@ -970,7 +972,6 @@ option. e.g. - # Default preview command with an extra preview binding fzf --preview 'file {}' --bind '?:preview:cat {}' @@ -981,6 +982,22 @@ # Preview window hidden by default, it appears when you first hit '?' fzf --bind '?:preview:cat {}' --preview-window hidden +.SS CHANGE PREVIEW WINDOW ATTRIBUTES + +\fBchange-preview-window\fR action can be used to change the properties of the +preview window. Unlike the \fB--preview-window\fR option, you can specify +multiple sets of options separated by '|' characters. + +e.g. + # Rotate through the options using CTRL-/ + fzf --preview 'cat {}' --bind 'ctrl-/:change-preview-window(right,70%|down,40%,border-horizontal|hidden|right)' + + # The default properties given by `--preview-window` are inherited, so an empty string in the list is interpreted as the default + fzf --preview 'cat {}' --preview-window 'right,40%,border-left' --bind 'ctrl-/:change-preview-window(70%|down,border-top|hidden|)' + + # This is equivalent to toggle-preview action + fzf --preview 'cat {}' --bind 'ctrl-/:change-preview-window(hidden|)' + .SH AUTHOR Junegunn Choi (\fijunegun...@gmail.com\fR) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.28.0/plugin/fzf.vim new/fzf-0.29.0/plugin/fzf.vim --- old/fzf-0.28.0/plugin/fzf.vim 2021-11-03 17:05:07.000000000 +0100 +++ new/fzf-0.29.0/plugin/fzf.vim 2021-12-24 17:46:01.000000000 +0100 @@ -444,6 +444,12 @@ return [shell, shellslash, shellcmdflag, shellxquote] endfunction +function! s:writefile(...) + if call('writefile', a:000) == -1 + throw 'Failed to write temporary file. Check if you can write to the path tempname() returns.' + endif +endfunction + function! fzf#run(...) abort try let [shell, shellslash, shellcmdflag, shellxquote] = s:use_sh() @@ -471,7 +477,7 @@ let source_command = source elseif type == 3 let temps.input = s:fzf_tempname() - call writefile(source, temps.input) + call s:writefile(source, temps.input) let source_command = (s:is_win ? 'type ' : 'cat ').fzf#shellescape(temps.input) else throw 'Invalid source type' @@ -515,7 +521,7 @@ call s:callback(dict, lines) return lines finally - if len(source_command) + if exists('source_command') && len(source_command) if len(prev_default_command) let $FZF_DEFAULT_COMMAND = prev_default_command else @@ -660,7 +666,7 @@ endif if s:is_win let batchfile = s:fzf_tempname().'.bat' - call writefile(s:wrap_cmds(command), batchfile) + call s:writefile(s:wrap_cmds(command), batchfile) let command = batchfile let a:temps.batchfile = batchfile if has('nvim') @@ -678,7 +684,7 @@ endif elseif has('win32unix') && $TERM !=# 'cygwin' let shellscript = s:fzf_tempname() - call writefile([command], shellscript) + call s:writefile([command], shellscript) let command = 'cmd.exe /C '.fzf#shellescape('set "TERM=" & start /WAIT sh -c '.shellscript) let a:temps.shellscript = shellscript endif @@ -877,7 +883,7 @@ call s:pushd(a:dict) if s:is_win let fzf.temps.batchfile = s:fzf_tempname().'.bat' - call writefile(s:wrap_cmds(a:command), fzf.temps.batchfile) + call s:writefile(s:wrap_cmds(a:command), fzf.temps.batchfile) let command = fzf.temps.batchfile else let command = a:command diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.28.0/shell/key-bindings.bash new/fzf-0.29.0/shell/key-bindings.bash --- old/fzf-0.28.0/shell/key-bindings.bash 2021-11-03 17:05:07.000000000 +0100 +++ new/fzf-0.29.0/shell/key-bindings.bash 2021-12-24 17:46:01.000000000 +0100 @@ -41,7 +41,7 @@ local cmd dir cmd="${FZF_ALT_C_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \ -o -type d -print 2> /dev/null | cut -b3-"}" - dir=$(eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_ALT_C_OPTS" $(__fzfcmd) +m) && printf 'cd %q' "$dir" + dir=$(eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_ALT_C_OPTS" $(__fzfcmd) +m) && printf 'cd -- %q' "$dir" } __fzf_history__() { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.28.0/shell/key-bindings.fish new/fzf-0.29.0/shell/key-bindings.fish --- old/fzf-0.28.0/shell/key-bindings.fish 2021-11-03 17:05:07.000000000 +0100 +++ new/fzf-0.29.0/shell/key-bindings.fish 2021-12-24 17:46:01.000000000 +0100 @@ -87,7 +87,7 @@ eval "$FZF_ALT_C_COMMAND | "(__fzfcmd)' +m --query "'$fzf_query'"' | read -l result if [ -n "$result" ] - cd $result + cd -- $result # Remove last token from commandline. commandline -t "" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.28.0/shell/key-bindings.zsh new/fzf-0.29.0/shell/key-bindings.zsh --- old/fzf-0.28.0/shell/key-bindings.zsh 2021-11-03 17:05:07.000000000 +0100 +++ new/fzf-0.29.0/shell/key-bindings.zsh 2021-12-24 17:46:01.000000000 +0100 @@ -79,7 +79,7 @@ return 0 fi zle push-line # Clear buffer. Auto-restored on next prompt. - BUFFER="cd ${(q)dir}" + BUFFER="cd -- ${(q)dir}" zle accept-line local ret=$? unset dir # ensure this doesn't end up appearing in prompt expansion diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.28.0/src/options.go new/fzf-0.29.0/src/options.go --- old/fzf-0.28.0/src/options.go 2021-11-03 17:05:07.000000000 +0100 +++ new/fzf-0.29.0/src/options.go 2021-12-24 17:46:01.000000000 +0100 @@ -176,6 +176,14 @@ headerLines int } +func (a previewOpts) sameLayout(b previewOpts) bool { + return a.size == b.size && a.position == b.position && a.border == b.border && a.hidden == b.hidden +} + +func (a previewOpts) sameContentLayout(b previewOpts) bool { + return a.wrap == b.wrap && a.headerLines == b.headerLines +} + // Options stores the values of command-line options type Options struct { Fuzzy bool @@ -216,7 +224,7 @@ Filter *string ToggleSort bool Expect map[tui.Event]string - Keymap map[tui.Event][]action + Keymap map[tui.Event][]*action Preview previewOpts PrintQuery bool ReadZero bool @@ -279,7 +287,7 @@ Filter: nil, ToggleSort: false, Expect: make(map[tui.Event]string), - Keymap: make(map[tui.Event][]action), + Keymap: make(map[tui.Event][]*action), Preview: defaultPreviewOpts(""), PrintQuery: false, ReadZero: false, @@ -787,10 +795,10 @@ // 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|preview|change-prompt|unbind):.+|[:+](execute(?:-multi|-silent)?|reload|preview|change-prompt|unbind)(\([^)]*\)|\[[^\]]*\]|~[^~]*~|![^!]*!|@[^@]*@|\#[^\#]*\#|\$[^\$]*\$|%[^%]*%|\^[^\^]*\^|&[^&]*&|\*[^\*]*\*|;[^;]*;|/[^/]*/|\|[^\|]*\|)`) + `(?si)[:+](execute(?:-multi|-silent)?|reload|preview|change-prompt|change-preview-window|change-preview|unbind):.+|[:+](execute(?:-multi|-silent)?|reload|preview|change-prompt|change-preview-window|change-preview|unbind)(\([^)]*\)|\[[^\]]*\]|~[^~]*~|![^!]*!|@[^@]*@|\#[^\#]*\#|\$[^\$]*\$|%[^%]*%|\^[^\^]*\^|&[^&]*&|\*[^\*]*\*|;[^;]*;|/[^/]*/|\|[^\|]*\|)`) } -func parseKeymap(keymap map[tui.Event][]action, str string) { +func parseKeymap(keymap map[tui.Event][]*action, str string) { masked := executeRegexp.ReplaceAllStringFunc(str, func(src string) string { symbol := ":" if strings.HasPrefix(src, "+") { @@ -799,6 +807,10 @@ prefix := symbol + "execute" if strings.HasPrefix(src[1:], "reload") { prefix = symbol + "reload" + } else if strings.HasPrefix(src[1:], "change-preview-window") { + prefix = symbol + "change-preview-window" + } else if strings.HasPrefix(src[1:], "change-preview") { + prefix = symbol + "change-preview" } else if strings.HasPrefix(src[1:], "preview") { prefix = symbol + "preview" } else if strings.HasPrefix(src[1:], "unbind") { @@ -842,7 +854,7 @@ idx2 := len(pair[0]) + 1 specs := strings.Split(pair[1], "+") - actions := make([]action, 0, len(specs)) + actions := make([]*action, 0, len(specs)) appendAction := func(types ...actionType) { actions = append(actions, toActions(types...)...) } @@ -1002,6 +1014,10 @@ offset = len("reload") case actPreview: offset = len("preview") + case actChangePreviewWindow: + offset = len("change-preview-window") + case actChangePreview: + offset = len("change-preview") case actChangePrompt: offset = len("change-prompt") case actUnbind: @@ -1017,17 +1033,22 @@ if spec[offset] == ':' { if specIndex == len(specs)-1 { actionArg = spec[offset+1:] - actions = append(actions, action{t: t, a: actionArg}) + actions = append(actions, &action{t: t, a: actionArg}) } else { prevSpec = spec + "+" continue } } else { actionArg = spec[offset+1 : len(spec)-1] - actions = append(actions, action{t: t, a: actionArg}) + actions = append(actions, &action{t: t, a: actionArg}) } if t == actUnbind { parseKeyChords(actionArg, "unbind target required") + } else if t == actChangePreviewWindow { + opts := previewOpts{} + for _, arg := range strings.Split(actionArg, "|") { + parsePreviewWindow(&opts, arg) + } } } } @@ -1053,6 +1074,10 @@ return actUnbind case "preview": return actPreview + case "change-preview-window": + return actChangePreviewWindow + case "change-preview": + return actChangePreview case "change-prompt": return actChangePrompt case "execute": @@ -1065,7 +1090,7 @@ return actIgnore } -func parseToggleSort(keymap map[tui.Event][]action, str string) { +func parseToggleSort(keymap map[tui.Event][]*action, str string) { keys := parseKeyChords(str, "key name required") if len(keys) != 1 { errorExit("multiple keys specified") @@ -1633,10 +1658,28 @@ // Extend the default key map keymap := defaultKeymap() for key, actions := range opts.Keymap { + var lastChangePreviewWindow *action for _, act := range actions { - if act.t == actToggleSort { + switch act.t { + case actToggleSort: + // To display "+S"/"-S" on info line opts.ToggleSort = true + case actChangePreviewWindow: + lastChangePreviewWindow = act + } + } + // Re-organize actions so that we only keep the last change-preview-window + // and it comes first in the list. + // * change-preview-window(up,+10)+preview(sleep 3; cat {})+change-preview-window(up,+20) + // -> change-preview-window(up,+20)+preview(sleep 3; cat {}) + if lastChangePreviewWindow != nil { + reordered := []*action{lastChangePreviewWindow} + for _, act := range actions { + if act.t != actChangePreviewWindow { + reordered = append(reordered, act) + } } + actions = reordered } keymap[key] = actions } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.28.0/src/terminal.go new/fzf-0.29.0/src/terminal.go --- old/fzf-0.28.0/src/terminal.go 2021-11-03 17:05:07.000000000 +0100 +++ new/fzf-0.29.0/src/terminal.go 2021-12-24 17:46:01.000000000 +0100 @@ -4,6 +4,7 @@ "bufio" "fmt" "io/ioutil" + "math" "os" "os/signal" "regexp" @@ -104,88 +105,89 @@ // Terminal represents terminal input/output type Terminal struct { - initDelay time.Duration - infoStyle infoStyle - spinner []string - prompt func() - promptLen int - pointer string - pointerLen int - pointerEmpty string - marker string - markerLen int - markerEmpty string - queryLen [2]int - layout layoutType - fullscreen bool - keepRight bool - hscroll bool - hscrollOff int - scrollOff int - wordRubout string - wordNext string - cx int - cy int - offset int - xoffset int - yanked []rune - input []rune - multi int - sort bool - toggleSort bool - delimiter Delimiter - expect map[tui.Event]string - keymap map[tui.Event][]action - pressed string - printQuery bool - history *History - cycle bool - headerFirst bool - headerLines int - header []string - header0 []string - ansi bool - tabstop int - margin [4]sizeSpec - padding [4]sizeSpec - strong tui.Attr - unicode bool - borderShape tui.BorderShape - cleanExit bool - paused bool - border tui.Window - window tui.Window - pborder tui.Window - pwindow tui.Window - count int - progress int - reading bool - running bool - failed *string - jumping jumpMode - jumpLabels string - printer func(string) - printsep string - merger *Merger - selected map[int32]selectedItem - version int64 - reqBox *util.EventBox - previewOpts previewOpts - previewer previewer - previewed previewed - previewBox *util.EventBox - eventBox *util.EventBox - mutex sync.Mutex - initFunc func() - prevLines []itemLine - suppress bool - sigstop bool - startChan chan bool - killChan chan int - slab *util.Slab - theme *tui.ColorTheme - tui tui.Renderer - executing *util.AtomicBool + initDelay time.Duration + infoStyle infoStyle + spinner []string + prompt func() + promptLen int + pointer string + pointerLen int + pointerEmpty string + marker string + markerLen int + markerEmpty string + queryLen [2]int + layout layoutType + fullscreen bool + keepRight bool + hscroll bool + hscrollOff int + scrollOff int + wordRubout string + wordNext string + cx int + cy int + offset int + xoffset int + yanked []rune + input []rune + multi int + sort bool + toggleSort bool + delimiter Delimiter + expect map[tui.Event]string + keymap map[tui.Event][]*action + pressed string + printQuery bool + history *History + cycle bool + headerFirst bool + headerLines int + header []string + header0 []string + ansi bool + tabstop int + margin [4]sizeSpec + padding [4]sizeSpec + strong tui.Attr + unicode bool + borderShape tui.BorderShape + cleanExit bool + paused bool + border tui.Window + window tui.Window + pborder tui.Window + pwindow tui.Window + count int + progress int + reading bool + running bool + failed *string + jumping jumpMode + jumpLabels string + printer func(string) + printsep string + merger *Merger + selected map[int32]selectedItem + version int64 + reqBox *util.EventBox + initialPreviewOpts previewOpts + previewOpts previewOpts + previewer previewer + previewed previewed + previewBox *util.EventBox + eventBox *util.EventBox + mutex sync.Mutex + initFunc func() + prevLines []itemLine + suppress bool + sigstop bool + startChan chan bool + killChan chan int + slab *util.Slab + theme *tui.ColorTheme + tui tui.Renderer + executing *util.AtomicBool } type selectedItem struct { @@ -216,6 +218,7 @@ reqRefresh reqReinit reqRedraw + reqFullRedraw reqClose reqPrintQuery reqPreviewEnqueue @@ -286,6 +289,8 @@ actTogglePreview actTogglePreviewWrap actPreview + actChangePreview + actChangePreviewWindow actPreviewTop actPreviewBottom actPreviewUp @@ -324,9 +329,10 @@ } type previewRequest struct { - template string - pwindow tui.Window - list []*Item + template string + pwindow tui.Window + scrollOffset int + list []*Item } type previewResult struct { @@ -336,16 +342,16 @@ spinner string } -func toActions(types ...actionType) []action { - actions := make([]action, len(types)) +func toActions(types ...actionType) []*action { + actions := make([]*action, len(types)) for idx, t := range types { - actions[idx] = action{t: t, a: ""} + actions[idx] = &action{t: t, a: ""} } return actions } -func defaultKeymap() map[tui.Event][]action { - keymap := make(map[tui.Event][]action) +func defaultKeymap() map[tui.Event][]*action { + keymap := make(map[tui.Event][]*action) add := func(e tui.EventType, a actionType) { keymap[e.AsEvent()] = toActions(a) } @@ -416,7 +422,7 @@ func hasPreviewAction(opts *Options) bool { for _, actions := range opts.Keymap { for _, action := range actions { - if action.t == actPreview { + if action.t == actPreview || action.t == actChangePreview { return true } } @@ -496,72 +502,73 @@ wordNext = fmt.Sprintf("[^%s]%s|(.$)", sep, sep) } t := Terminal{ - initDelay: delay, - infoStyle: opts.InfoStyle, - spinner: makeSpinner(opts.Unicode), - queryLen: [2]int{0, 0}, - layout: opts.Layout, - fullscreen: fullscreen, - keepRight: opts.KeepRight, - hscroll: opts.Hscroll, - hscrollOff: opts.HscrollOff, - scrollOff: opts.ScrollOff, - wordRubout: wordRubout, - wordNext: wordNext, - cx: len(input), - cy: 0, - offset: 0, - xoffset: 0, - yanked: []rune{}, - input: input, - multi: opts.Multi, - sort: opts.Sort > 0, - toggleSort: opts.ToggleSort, - delimiter: opts.Delimiter, - expect: opts.Expect, - keymap: opts.Keymap, - pressed: "", - printQuery: opts.PrintQuery, - history: opts.History, - margin: opts.Margin, - padding: opts.Padding, - unicode: opts.Unicode, - borderShape: opts.BorderShape, - cleanExit: opts.ClearOnExit, - paused: opts.Phony, - strong: strongAttr, - cycle: opts.Cycle, - headerFirst: opts.HeaderFirst, - headerLines: opts.HeaderLines, - header: header, - header0: header, - ansi: opts.Ansi, - tabstop: opts.Tabstop, - reading: true, - running: true, - failed: nil, - jumping: jumpDisabled, - jumpLabels: opts.JumpLabels, - printer: opts.Printer, - printsep: opts.PrintSep, - merger: EmptyMerger, - selected: make(map[int32]selectedItem), - reqBox: util.NewEventBox(), - previewOpts: opts.Preview, - previewer: previewer{0, []string{}, 0, showPreviewWindow, false, true, false, ""}, - previewed: previewed{0, 0, 0, false}, - previewBox: previewBox, - eventBox: eventBox, - mutex: sync.Mutex{}, - suppress: true, - sigstop: false, - slab: util.MakeSlab(slab16Size, slab32Size), - theme: opts.Theme, - startChan: make(chan bool, 1), - killChan: make(chan int), - tui: renderer, - initFunc: func() { renderer.Init() }, - executing: util.NewAtomicBool(false)} + initDelay: delay, + infoStyle: opts.InfoStyle, + spinner: makeSpinner(opts.Unicode), + queryLen: [2]int{0, 0}, + layout: opts.Layout, + fullscreen: fullscreen, + keepRight: opts.KeepRight, + hscroll: opts.Hscroll, + hscrollOff: opts.HscrollOff, + scrollOff: opts.ScrollOff, + wordRubout: wordRubout, + wordNext: wordNext, + cx: len(input), + cy: 0, + offset: 0, + xoffset: 0, + yanked: []rune{}, + input: input, + multi: opts.Multi, + sort: opts.Sort > 0, + toggleSort: opts.ToggleSort, + delimiter: opts.Delimiter, + expect: opts.Expect, + keymap: opts.Keymap, + pressed: "", + printQuery: opts.PrintQuery, + history: opts.History, + margin: opts.Margin, + padding: opts.Padding, + unicode: opts.Unicode, + borderShape: opts.BorderShape, + cleanExit: opts.ClearOnExit, + paused: opts.Phony, + strong: strongAttr, + cycle: opts.Cycle, + headerFirst: opts.HeaderFirst, + headerLines: opts.HeaderLines, + header: header, + header0: header, + ansi: opts.Ansi, + tabstop: opts.Tabstop, + reading: true, + running: true, + failed: nil, + jumping: jumpDisabled, + jumpLabels: opts.JumpLabels, + printer: opts.Printer, + printsep: opts.PrintSep, + merger: EmptyMerger, + selected: make(map[int32]selectedItem), + reqBox: util.NewEventBox(), + initialPreviewOpts: opts.Preview, + previewOpts: opts.Preview, + previewer: previewer{0, []string{}, 0, showPreviewWindow, false, true, false, ""}, + previewed: previewed{0, 0, 0, false}, + previewBox: previewBox, + eventBox: eventBox, + mutex: sync.Mutex{}, + suppress: true, + sigstop: false, + slab: util.MakeSlab(slab16Size, slab32Size), + theme: opts.Theme, + startChan: make(chan bool, 1), + killChan: make(chan int), + tui: renderer, + initFunc: func() { renderer.Init() }, + executing: util.NewAtomicBool(false)} 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) @@ -703,7 +710,7 @@ } func (t *Terminal) displayWidth(runes []rune) int { - width, _ := util.RunesWidth(runes, 0, t.tabstop, 0) + width, _ := util.RunesWidth(runes, 0, t.tabstop, math.MaxInt32) return width } @@ -1191,7 +1198,7 @@ func (t *Terminal) trimRight(runes []rune, width int) ([]rune, bool) { // We start from the beginning to handle tab characters - width, overflowIdx := util.RunesWidth(runes, 0, t.tabstop, width) + _, overflowIdx := util.RunesWidth(runes, 0, t.tabstop, width) if overflowIdx >= 0 { return runes[:overflowIdx], true } @@ -1642,9 +1649,14 @@ template, t.ansi, t.delimiter, t.printsep, forcePlus, input, list) } -func (t *Terminal) evaluateScrollOffset(list []*Item, height int) int { +func (t *Terminal) evaluateScrollOffset() int { + if t.pwindow == nil { + return 0 + } + + // We only need the current item to calculate the scroll offset offsetExpr := offsetTrimCharsRegex.ReplaceAllString( - t.replacePlaceholder(t.previewOpts.scroll, false, "", list), "") + t.replacePlaceholder(t.previewOpts.scroll, false, "", []*Item{t.currentItem(), nil}), "") atoi := func(s string) int { n, e := strconv.Atoi(s) @@ -1655,20 +1667,21 @@ } base := -1 + height := util.Max(0, t.pwindow.Height()-t.previewOpts.headerLines) for _, component := range offsetComponentRegex.FindAllString(offsetExpr, -1) { if strings.HasPrefix(component, "-/") { component = component[1:] } if component[0] == '/' { denom := atoi(component[1:]) - if denom == 0 { - return base + if denom != 0 { + base -= height / denom } - return base - height/denom + break } base += atoi(component) } - return base + return util.Max(0, base) } func replacePlaceholder(template string, stripAnsi bool, delimiter Delimiter, printsep string, forcePlus bool, query string, allItems []*Item) string { @@ -1767,8 +1780,10 @@ }) } -func (t *Terminal) redraw() { - t.tui.Clear() +func (t *Terminal) redraw(clear bool) { + if clear { + t.tui.Clear() + } t.tui.Refresh() t.printAll() } @@ -1788,7 +1803,7 @@ t.tui.Pause(true) cmd.Run() t.tui.Resume(true, false) - t.redraw() + t.redraw(true) t.refresh() } else { t.tui.Pause(false) @@ -1933,7 +1948,7 @@ go func() { for { <-resizeChan - t.reqBox.Set(reqRedraw, nil) + t.reqBox.Set(reqFullRedraw, nil) } }() @@ -1972,12 +1987,14 @@ var items []*Item var commandTemplate string var pwindow tui.Window + initialOffset := 0 t.previewBox.Wait(func(events *util.Events) { for req, value := range *events { switch req { case reqPreviewEnqueue: request := value.(previewRequest) commandTemplate = request.template + initialOffset = request.scrollOffset items = request.list pwindow = request.pwindow } @@ -1989,11 +2006,9 @@ if items[0] != nil { _, query := t.Input() command := t.replacePlaceholder(commandTemplate, false, string(query), items) - initialOffset := 0 cmd := util.ExecCommand(command, true) if pwindow != nil { height := pwindow.Height() - initialOffset = util.Max(0, t.evaluateScrollOffset(items, util.Max(0, height-t.previewOpts.headerLines))) env := os.Environ() lines := fmt.Sprintf("LINES=%d", height) columns := fmt.Sprintf("COLUMNS=%d", pwindow.Width()) @@ -2128,7 +2143,7 @@ if len(command) > 0 && t.isPreviewEnabled() { _, list := t.buildPlusList(command, false) t.cancelPreview() - t.previewBox.Set(reqPreviewEnqueue, previewRequest{command, t.pwindow, list}) + t.previewBox.Set(reqPreviewEnqueue, previewRequest{command, t.pwindow, t.evaluateScrollOffset(), list}) } } @@ -2183,9 +2198,11 @@ t.suppress = false case reqReinit: t.tui.Resume(t.fullscreen, t.sigstop) - t.redraw() + t.redraw(true) case reqRedraw: - t.redraw() + t.redraw(false) + case reqFullRedraw: + t.redraw(true) case reqClose: exit(func() int { if t.output() { @@ -2253,13 +2270,15 @@ } } } - togglePreview := func(enabled bool) { + togglePreview := func(enabled bool) bool { if t.previewer.enabled != enabled { t.previewer.enabled = enabled - t.tui.Clear() + // We need to immediately update t.pwindow so we don't use reqRedraw t.resizeWindows() req(reqPrompt, reqList, reqInfo, reqHeader) + return true } + return false } toggle := func() bool { current := t.currentItem() @@ -2296,12 +2315,12 @@ } } - actionsFor := func(eventType tui.EventType) []action { + actionsFor := func(eventType tui.EventType) []*action { return t.keymap[eventType.AsEvent()] } - var doAction func(action) bool - doActions := func(actions []action) bool { + var doAction func(*action) bool + doActions := func(actions []*action) bool { for _, action := range actions { if !doAction(action) { return false @@ -2309,7 +2328,7 @@ } return true } - doAction = func(a action) bool { + doAction = func(a *action) bool { switch a.t { case actIgnore: case actExecute, actExecuteSilent: @@ -2327,7 +2346,7 @@ if valid { t.cancelPreview() t.previewBox.Set(reqPreviewEnqueue, - previewRequest{t.previewOpts.command, t.pwindow, list}) + previewRequest{t.previewOpts.command, t.pwindow, t.evaluateScrollOffset(), list}) } } } @@ -2489,14 +2508,14 @@ } case actToggleIn: if t.layout != layoutDefault { - return doAction(action{t: actToggleUp}) + return doAction(&action{t: actToggleUp}) } - return doAction(action{t: actToggleDown}) + return doAction(&action{t: actToggleDown}) case actToggleOut: if t.layout != layoutDefault { - return doAction(action{t: actToggleDown}) + return doAction(&action{t: actToggleDown}) } - return doAction(action{t: actToggleUp}) + return doAction(&action{t: actToggleUp}) case actToggleDown: if t.multi > 0 && t.merger.Length() > 0 && toggle() { t.vmove(-1, true) @@ -2520,7 +2539,7 @@ req(reqClose) } case actClearScreen: - req(reqRedraw) + req(reqFullRedraw) case actClearQuery: t.input = []rune{} t.cx = 0 @@ -2707,6 +2726,45 @@ for key := range keys { delete(t.keymap, key) } + case actChangePreview: + if t.previewOpts.command != a.a { + togglePreview(len(a.a) > 0) + t.previewOpts.command = a.a + refreshPreview(t.previewOpts.command) + } + case actChangePreviewWindow: + currentPreviewOpts := t.previewOpts + + // Reset preview options and apply the additional options + t.previewOpts = t.initialPreviewOpts + + // Split window options + tokens := strings.Split(a.a, "|") + parsePreviewWindow(&t.previewOpts, tokens[0]) + if len(tokens) > 1 { + a.a = strings.Join(append(tokens[1:], tokens[0]), "|") + } + + if t.previewOpts.hidden { + togglePreview(false) + } else { + // Full redraw + if !currentPreviewOpts.sameLayout(t.previewOpts) { + if togglePreview(true) { + refreshPreview(t.previewOpts.command) + } else { + req(reqRedraw) + } + } else if !currentPreviewOpts.sameContentLayout(t.previewOpts) { + t.previewed.version = 0 + req(reqPreviewRefresh) + } + + // Adjust scroll offset + if t.hasPreviewWindow() && currentPreviewOpts.scroll != t.previewOpts.scroll { + scrollPreviewTo(t.evaluateScrollOffset()) + } + } } return true } @@ -2714,7 +2772,7 @@ if t.jumping == jumpDisabled { actions := t.keymap[event.Comparable()] if len(actions) == 0 && event.Type == tui.Rune { - doAction(action{t: actRune}) + doAction(&action{t: actRune}) } else if !doActions(actions) { continue } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.28.0/src/util/util.go new/fzf-0.29.0/src/util/util.go --- old/fzf-0.28.0/src/util/util.go 2021-11-03 17:05:07.000000000 +0100 +++ new/fzf-0.29.0/src/util/util.go 2021-12-24 17:46:01.000000000 +0100 @@ -26,7 +26,7 @@ w = runewidth.StringWidth(s) + strings.Count(s, "\n") } width += w - if limit > 0 && width > limit { + if width > limit { return width, idx } idx += len(rs) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.28.0/src/util/util_test.go new/fzf-0.29.0/src/util/util_test.go --- old/fzf-0.28.0/src/util/util_test.go 2021-11-03 17:05:07.000000000 +0100 +++ new/fzf-0.29.0/src/util/util_test.go 2021-12-24 17:46:01.000000000 +0100 @@ -38,3 +38,19 @@ t.Error("Expected: false") } } + +func TestRunesWidth(t *testing.T) { + for _, args := range [][]int{ + {100, 5, -1}, + {3, 4, 3}, + {0, 1, 0}, + } { + width, overflowIdx := RunesWidth([]rune("hello"), 0, 0, args[0]) + if width != args[1] { + t.Errorf("Expected width: %d, actual: %d", args[1], width) + } + if overflowIdx != args[2] { + t.Errorf("Expected overflow index: %d, actual: %d", args[2], overflowIdx) + } + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.28.0/test/test_go.rb new/fzf-0.29.0/test/test_go.rb --- old/fzf-0.28.0/test/test_go.rb 2021-11-03 17:05:07.000000000 +0100 +++ new/fzf-0.29.0/test/test_go.rb 2021-12-24 17:46:01.000000000 +0100 @@ -2142,6 +2142,72 @@ assert_equal expected.chomp, lines.take(6).join("\n") end end + + def test_change_preview_window + tmux.send_keys "seq 1000 | #{FZF} --preview 'echo [[{}]]' --preview-window border-none --bind '" \ + 'a:change-preview(echo __{}__),' \ + 'b:change-preview-window(down)+change-preview(echo =={}==)+change-preview-window(up),' \ + 'c:change-preview(),d:change-preview-window(hidden),' \ + "e:preview(printf ::%${FZF_PREVIEW_COLUMNS}s{})+change-preview-window(up),f:change-preview-window(up,wrap)'", :Enter + tmux.until { |lines| assert_equal 1000, lines.item_count } + tmux.until { |lines| assert_includes lines[0], '[[1]]' } + + # change-preview action permanently changes the preview command set by --preview + tmux.send_keys 'a' + tmux.until { |lines| assert_includes lines[0], '__1__' } + tmux.send_keys :Up + tmux.until { |lines| assert_includes lines[0], '__2__' } + + # When multiple change-preview-window actions are bound to a single key, + # the last one wins and the updated options are immediately applied to the new preview + tmux.send_keys 'b' + tmux.until { |lines| assert_equal '==2==', lines[0] } + tmux.send_keys :Up + tmux.until { |lines| assert_equal '==3==', lines[0] } + + # change-preview with an empty preview command closes the preview window + tmux.send_keys 'c' + tmux.until { |lines| refute_includes lines[0], '==' } + + # change-preview again to re-open the preview window + tmux.send_keys 'a' + tmux.until { |lines| assert_equal '__3__', lines[0] } + + # Hide the preview window with hidden flag + tmux.send_keys 'd' + tmux.until { |lines| refute_includes lines[0], '__3__' } + + # One-off preview + tmux.send_keys 'e' + tmux.until do |lines| + assert_equal '::', lines[0] + refute_includes lines[1], '3' + end + + # Wrapped + tmux.send_keys 'f' + tmux.until do |lines| + assert_equal '::', lines[0] + assert_equal ' 3', lines[1] + end + end + + def test_change_preview_window_rotate + tmux.send_keys "seq 100 | #{FZF} --preview-window left,border-none --preview 'echo hello' --bind '" \ + "a:change-preview-window(right|down|up|hidden|)'", :Enter + 3.times do + tmux.until { |lines| lines[0].start_with?('hello') } + tmux.send_keys 'a' + tmux.until { |lines| lines[0].end_with?('hello') } + tmux.send_keys 'a' + tmux.until { |lines| lines[-1].start_with?('hello') } + tmux.send_keys 'a' + tmux.until { |lines| assert_equal 'hello', lines[0] } + tmux.send_keys 'a' + tmux.until { |lines| refute_includes lines[0], 'hello' } + tmux.send_keys 'a' + end + end end module TestShell ++++++ vendor.tar.xz ++++++