Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package fzf for openSUSE:Factory checked in at 2023-05-01 18:51:18 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/fzf (Old) and /work/SRC/openSUSE:Factory/.fzf.new.1533 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "fzf" Mon May 1 18:51:18 2023 rev:33 rq:1083792 version:0.40.0 Changes: -------- --- /work/SRC/openSUSE:Factory/fzf/fzf.changes 2023-04-19 17:44:34.680751628 +0200 +++ /work/SRC/openSUSE:Factory/.fzf.new.1533/fzf.changes 2023-05-01 18:51:20.661413319 +0200 @@ -1,0 +2,34 @@ +Sun Apr 30 21:45:37 UTC 2023 - Matej Cepl <mc...@suse.com> + +- Update to version 0.40.0: + - Added `zero` event that is triggered when there's no match + ```sh + # Reload the candidate list when there's no match + echo $RANDOM | fzf --bind 'zero:reload(echo $RANDOM)+clear-query' --height 3 + ``` + - New actions + - Added `track` action which makes fzf track the current item when the + search result is updated. If the user manually moves the cursor, or the + item is not in the updated search result, tracking is automatically + disabled. Tracking is useful when you want to see the surrounding items + by deleting the query string. + ```sh + # Narrow down the list with a query, point to a command, + # and hit CTRL-T to see its surrounding commands. + export FZF_CTRL_R_OPTS=" + --preview 'echo {}' --preview-window up:3:hidden:wrap + --bind 'ctrl-/:toggle-preview' + --bind 'ctrl-t:track+clear-query' + --bind 'ctrl-y:execute-silent(echo -n {2..} | pbcopy)+abort' + --color header:italic + --header 'Press CTRL-Y to copy command into clipboard'" + ``` + - Added `change-header(...)` + - Added `transform-header(...)` + - Added `toggle-track` action + - Fixed `--track` behavior when used with `--tac` + - However, using `--track` with `--tac` is not recommended. The resulting + behavior can be very confusing. + - Bug fixes and improvements + +------------------------------------------------------------------- Old: ---- fzf-0.39.0.tar.gz New: ---- fzf-0.40.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ fzf.spec ++++++ --- /var/tmp/diff_new_pack.XLAq6A/_old 2023-05-01 18:51:21.381417594 +0200 +++ /var/tmp/diff_new_pack.XLAq6A/_new 2023-05-01 18:51:21.385417618 +0200 @@ -18,7 +18,7 @@ %global _lto_cflags %nil Name: fzf -Version: 0.39.0 +Version: 0.40.0 Release: 0 Summary: A command-line fuzzy finder License: MIT ++++++ fzf-0.39.0.tar.gz -> fzf-0.40.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.39.0/CHANGELOG.md new/fzf-0.40.0/CHANGELOG.md --- old/fzf-0.39.0/CHANGELOG.md 2023-04-02 16:33:37.000000000 +0200 +++ new/fzf-0.40.0/CHANGELOG.md 2023-04-30 18:59:21.000000000 +0200 @@ -1,6 +1,38 @@ CHANGELOG ========= +0.40.0 +------ +- Added `zero` event that is triggered when there's no match + ```sh + # Reload the candidate list when there's no match + echo $RANDOM | fzf --bind 'zero:reload(echo $RANDOM)+clear-query' --height 3 + ``` +- New actions + - Added `track` action which makes fzf track the current item when the + search result is updated. If the user manually moves the cursor, or the + item is not in the updated search result, tracking is automatically + disabled. Tracking is useful when you want to see the surrounding items + by deleting the query string. + ```sh + # Narrow down the list with a query, point to a command, + # and hit CTRL-T to see its surrounding commands. + export FZF_CTRL_R_OPTS=" + --preview 'echo {}' --preview-window up:3:hidden:wrap + --bind 'ctrl-/:toggle-preview' + --bind 'ctrl-t:track+clear-query' + --bind 'ctrl-y:execute-silent(echo -n {2..} | pbcopy)+abort' + --color header:italic + --header 'Press CTRL-Y to copy command into clipboard'" + ``` + - Added `change-header(...)` + - Added `transform-header(...)` + - Added `toggle-track` action +- Fixed `--track` behavior when used with `--tac` + - However, using `--track` with `--tac` is not recommended. The resulting + behavior can be very confusing. +- Bug fixes and improvements + 0.39.0 ------ - Added `one` event that is triggered when there's only one match @@ -176,7 +208,7 @@ - Added color name `preview-label` for `--preview-label` (defaults to `label` for `--border-label`) - Better support for (Windows) terminals where each box-drawing character - takes 2 columns. Set `RUNEWIDTH_EASTASIAN` environment variable to `1`. + takes 2 columns. Set `RUNEWIDTH_EASTASIAN` environment variable to `0` or `1`. - On Vim, the variable will be automatically set if `&ambiwidth` is `double` - Behavior changes - fzf will always execute the preview command if the command template diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.39.0/bin/fzf-tmux new/fzf-0.40.0/bin/fzf-tmux --- old/fzf-0.39.0/bin/fzf-tmux 2023-04-02 16:33:37.000000000 +0200 +++ new/fzf-0.40.0/bin/fzf-tmux 2023-04-30 18:59:21.000000000 +0200 @@ -180,7 +180,7 @@ envs="export TERM=$TERM " if [[ "$opt" =~ "-E" ]]; then tmux_version=$(tmux -V | sed 's/[^0-9.]//g') - if [[ $(bc -l <<< "$tmux_version > 3.2") = 1 ]]; then + if [[ $(awk '{print ($1 > 3.2)}' <<< "$tmux_version" 2> /dev/null || bc -l <<< "$tmux_version > 3.2") = 1 ]]; then FZF_DEFAULT_OPTS="--border $FZF_DEFAULT_OPTS" opt="-B $opt" elif [[ $tmux_version = 3.2 ]]; then diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.39.0/go.mod new/fzf-0.40.0/go.mod --- old/fzf-0.39.0/go.mod 2023-04-02 16:33:37.000000000 +0200 +++ new/fzf-0.40.0/go.mod 2023-04-30 18:59:21.000000000 +0200 @@ -7,8 +7,8 @@ github.com/mattn/go-shellwords v1.0.12 github.com/rivo/uniseg v0.4.4 github.com/saracen/walker v0.1.3 - golang.org/x/sys v0.6.0 - golang.org/x/term v0.6.0 + golang.org/x/sys v0.7.0 + golang.org/x/term v0.7.0 ) require ( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.39.0/go.sum new/fzf-0.40.0/go.sum --- old/fzf-0.39.0/go.sum 2023-04-02 16:33:37.000000000 +0200 +++ new/fzf-0.40.0/go.sum 2023-04-30 18:59:21.000000000 +0200 @@ -32,12 +32,12 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.39.0/install new/fzf-0.40.0/install --- old/fzf-0.39.0/install 2023-04-02 16:33:37.000000000 +0200 +++ new/fzf-0.40.0/install 2023-04-30 18:59:21.000000000 +0200 @@ -2,7 +2,7 @@ set -u -version=0.39.0 +version=0.40.0 auto_completion= key_bindings= update_config=2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.39.0/install.ps1 new/fzf-0.40.0/install.ps1 --- old/fzf-0.39.0/install.ps1 2023-04-02 16:33:37.000000000 +0200 +++ new/fzf-0.40.0/install.ps1 2023-04-30 18:59:21.000000000 +0200 @@ -1,4 +1,4 @@ -$version="0.39.0" +$version="0.40.0" $fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.39.0/main.go new/fzf-0.40.0/main.go --- old/fzf-0.39.0/main.go 2023-04-02 16:33:37.000000000 +0200 +++ new/fzf-0.40.0/main.go 2023-04-30 18:59:21.000000000 +0200 @@ -5,7 +5,7 @@ "github.com/junegunn/fzf/src/protector" ) -var version string = "0.39" +var version string = "0.40" var revision string = "devel" func main() { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.39.0/man/man1/fzf-tmux.1 new/fzf-0.40.0/man/man1/fzf-tmux.1 --- old/fzf-0.39.0/man/man1/fzf-tmux.1 2023-04-02 16:33:37.000000000 +0200 +++ new/fzf-0.40.0/man/man1/fzf-tmux.1 2023-04-30 18:59:21.000000000 +0200 @@ -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 "Apr 2023" "fzf 0.39.0" "fzf-tmux - open fzf in tmux split pane" +.TH fzf-tmux 1 "May 2023" "fzf 0.40.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.39.0/man/man1/fzf.1 new/fzf-0.40.0/man/man1/fzf.1 --- old/fzf-0.39.0/man/man1/fzf.1 2023-04-02 16:33:37.000000000 +0200 +++ new/fzf-0.40.0/man/man1/fzf.1 2023-04-30 18:59:21.000000000 +0200 @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. .. -.TH fzf 1 "Apr 2023" "fzf 0.39.0" "fzf - a command-line fuzzy finder" +.TH fzf 1 "May 2023" "fzf 0.40.0" "fzf - a command-line fuzzy finder" .SH NAME fzf - a command-line fuzzy finder @@ -94,7 +94,10 @@ .TP .B "--track" Make fzf track the current selection when the result list is updated. -This can be useful when browsing logs using fzf with sorting disabled. +This can be useful when browsing logs using fzf with sorting disabled. It is +not recommended to use this option with \fB--tac\fR as the resulting behavior +can be confusing. Also, consider using \fBtrack\fR action instead of this +option. .RS e.g. @@ -241,8 +244,9 @@ .br If you use a terminal emulator where each box-drawing character takes -2 columns, try setting \fBRUNEWIDTH_EASTASIAN\fR to \fB1\fR. If the border is -still not properly rendered, set \fB--no-unicode\fR. +2 columns, try setting \fBRUNEWIDTH_EASTASIAN\fR environment variable to +\fB0\fR or \fB1\fR. If the border is still not properly rendered, set +\fB--no-unicode\fR. .TP .BI "--border-label" [=LABEL] @@ -1004,6 +1008,17 @@ \fB# Automatically select the only match seq 10 | fzf --bind one:accept\fR .RE +\fIzero\fR +.RS +Triggered when there's no match. \fBzero:abort\fR binding is comparable to +\fB--exit-0\fR option, but the difference is that \fB--exit-0\fR is only +effective before the interactive finder starts but \fBzero\fR event is +triggered by the interactive finder. + +e.g. + \fB# Reload the candidate list when there's no match + echo $RANDOM | fzf --bind 'zero:reload(echo $RANDOM)+clear-query' --height 3\fR +.RE \fIbackward-eof\fR .RS @@ -1030,6 +1045,7 @@ \fBbeginning-of-line\fR \fIctrl-a home\fR \fBcancel\fR (clear query string if not empty, abort fzf otherwise) \fBchange-border-label(...)\fR (change \fB--border-label\fR to the given string) + \fBchange-header(...)\fR (change header to the given string; doesn't affect \fB--header-lines\fR) \fBchange-preview(...)\fR (change \fB--preview\fR option) \fBchange-preview-label(...)\fR (change \fB--preview-label\fR to the given string) \fBchange-preview-window(...)\fR (change \fB--preview-window\fR option; rotate through the multiple option sets separated by '|') @@ -1097,8 +1113,11 @@ \fBtoggle-preview-wrap\fR \fBtoggle-search\fR (toggle search functionality) \fBtoggle-sort\fR + \fBtoggle-track\fR \fBtoggle+up\fR \fIbtab (shift-tab)\fR + \fBtrack\fR (track the current item; automatically disabled if focus changes) \fBtransform-border-label(...)\fR (transform border label using an external command) + \fBtransform-header(...)\fR (transform header using an external command) \fBtransform-preview-label(...)\fR (transform preview label using an external command) \fBtransform-prompt(...)\fR (transform prompt string using an external command) \fBtransform-query(...)\fR (transform query string using an external command) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.39.0/plugin/fzf.vim new/fzf-0.40.0/plugin/fzf.vim --- old/fzf-0.39.0/plugin/fzf.vim 2023-04-02 16:33:37.000000000 +0200 +++ new/fzf-0.40.0/plugin/fzf.vim 2023-04-30 18:59:21.000000000 +0200 @@ -164,7 +164,7 @@ if has_key(s:versions, a:bin) return s:versions[a:bin] end - let command = (&shell =~ 'powershell' ? '&' : '') . s:fzf_call('shellescape', a:bin) . ' --version --no-height' + let command = (&shell =~ 'powershell\|pwsh' ? '&' : '') . s:fzf_call('shellescape', a:bin) . ' --version --no-height' let output = systemlist(command) if v:shell_error || empty(output) return '' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.39.0/src/core.go new/fzf-0.40.0/src/core.go --- old/fzf-0.39.0/src/core.go 2023-04-02 16:33:37.000000000 +0200 +++ new/fzf-0.40.0/src/core.go 2023-04-30 18:59:21.000000000 +0200 @@ -299,10 +299,12 @@ case EvtSearchNew: var command *string + var changed bool switch val := value.(type) { case searchRequest: sort = val.sort command = val.command + changed = val.changed if command != nil { useSnapshot = val.sync } @@ -314,10 +316,17 @@ } else { restart(*command) } + } + if !changed { break } if !useSnapshot { - snapshot, _ = chunkList.Snapshot() + newSnapshot, _ := chunkList.Snapshot() + // We want to avoid showing empty list when reload is triggered + // and the query string is changed at the same time i.e. command != nil && changed + if command == nil || len(newSnapshot) > 0 { + snapshot = newSnapshot + } } reset := !useSnapshot && clearCache() matcher.Reset(snapshot, input(reset), true, !reading, sort, reset) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.39.0/src/merger.go new/fzf-0.40.0/src/merger.go --- old/fzf-0.39.0/src/merger.go 2023-04-02 16:33:37.000000000 +0200 +++ new/fzf-0.40.0/src/merger.go 2023-04-30 18:59:21.000000000 +0200 @@ -60,17 +60,30 @@ return mg.count } +func (mg *Merger) First() Result { + if mg.tac && !mg.sorted { + return mg.Get(mg.count - 1) + } + return mg.Get(0) +} + // FindIndex returns the index of the item with the given item index func (mg *Merger) FindIndex(itemIndex int32) int { + index := -1 if mg.pass { - return int(itemIndex) - } - for i := 0; i < mg.count; i++ { - if mg.Get(i).item.Index() == itemIndex { - return i + index = int(itemIndex) + if mg.tac { + index = mg.count - index - 1 + } + } else { + for i := 0; i < mg.count; i++ { + if mg.Get(i).item.Index() == itemIndex { + index = i + break + } } } - return -1 + return index } // Get returns the pointer to the Result object indexed by the given integer diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.39.0/src/options.go new/fzf-0.40.0/src/options.go --- old/fzf-0.39.0/src/options.go 2023-04-02 16:33:37.000000000 +0200 +++ new/fzf-0.40.0/src/options.go 2023-04-30 18:59:21.000000000 +0200 @@ -165,6 +165,14 @@ return [4]sizeSpec{} } +type trackOption int + +const ( + trackDisabled trackOption = iota + trackEnabled + trackCurrent +) + type windowPosition int const ( @@ -267,7 +275,7 @@ WithNth []Range Delimiter Delimiter Sort int - Track bool + Track trackOption Tac bool Criteria []criterion Multi int @@ -340,7 +348,7 @@ WithNth: make([]Range, 0), Delimiter: Delimiter{}, Sort: 1000, - Track: false, + Track: trackDisabled, Tac: false, Criteria: []criterion{byScore, byLength}, Multi: 0, @@ -624,6 +632,8 @@ add(tui.Focus) case "one": add(tui.One) + case "zero": + add(tui.Zero) case "alt-enter", "alt-return": chords[tui.CtrlAltKey('m')] = key case "alt-space": @@ -927,7 +937,7 @@ func init() { executeRegexp = regexp.MustCompile( - `(?si)[:+](become|execute(?:-multi|-silent)?|reload(?:-sync)?|preview|(?:change|transform)-(?:query|prompt|border-label|preview-label)|change-preview-window|change-preview|(?:re|un)bind|pos|put)`) + `(?si)[:+](become|execute(?:-multi|-silent)?|reload(?:-sync)?|preview|(?:change|transform)-(?:header|query|prompt|border-label|preview-label)|change-preview-window|change-preview|(?:re|un)bind|pos|put)`) splitRegexp = regexp.MustCompile("[,:]+") actionNameRegexp = regexp.MustCompile("(?i)^[a-z-]+") } @@ -1083,6 +1093,10 @@ appendAction(actToggleAll) case "toggle-search": appendAction(actToggleSearch) + case "toggle-track": + appendAction(actToggleTrack) + case "track": + appendAction(actTrack) case "select": appendAction(actSelect) case "select-all": @@ -1247,6 +1261,8 @@ return actPreview case "change-border-label": return actChangeBorderLabel + case "change-header": + return actChangeHeader case "change-preview-label": return actChangePreviewLabel case "change-preview-window": @@ -1271,6 +1287,8 @@ return actTransformBorderLabel case "transform-preview-label": return actTransformPreviewLabel + case "transform-header": + return actTransformHeader case "transform-prompt": return actTransformPrompt case "transform-query": @@ -1568,9 +1586,9 @@ case "+s", "--no-sort": opts.Sort = 0 case "--track": - opts.Track = true + opts.Track = trackEnabled case "--no-track": - opts.Track = false + opts.Track = trackDisabled case "--tac": opts.Tac = true case "--no-tac": diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.39.0/src/terminal.go new/fzf-0.40.0/src/terminal.go --- old/fzf-0.39.0/src/terminal.go 2023-04-02 16:33:37.000000000 +0200 +++ new/fzf-0.40.0/src/terminal.go 2023-04-30 18:59:21.000000000 +0200 @@ -3,6 +3,7 @@ import ( "bufio" "fmt" + "io" "io/ioutil" "math" "os" @@ -183,7 +184,7 @@ multi int sort bool toggleSort bool - track bool + track trackOption delimiter Delimiter expect map[tui.Event]string keymap map[tui.Event][]*action @@ -310,6 +311,7 @@ actBackwardWord actCancel actChangeBorderLabel + actChangeHeader actChangePreviewLabel actChangePrompt actChangeQuery @@ -337,6 +339,8 @@ actToggleUp actToggleIn actToggleOut + actToggleTrack + actTrack actDown actUp actPageUp @@ -355,6 +359,7 @@ actTogglePreview actTogglePreviewWrap actTransformBorderLabel + actTransformHeader actTransformPreviewLabel actTransformPrompt actTransformQuery @@ -403,6 +408,7 @@ sort bool sync bool command *string + changed bool } type previewRequest struct { @@ -623,7 +629,7 @@ cycle: opts.Cycle, headerFirst: opts.HeaderFirst, headerLines: opts.HeaderLines, - header: header, + header: []string{}, header0: header, ellipsis: opts.Ellipsis, ansi: opts.Ansi, @@ -882,10 +888,21 @@ return reversed } +func (t *Terminal) changeHeader(header string) bool { + lines := strings.Split(strings.TrimSuffix(header, "\n"), "\n") + switch t.layout { + case layoutDefault, layoutReverseList: + lines = reverseStringArray(lines) + } + needFullRedraw := len(t.header0) != len(lines) + t.header0 = lines + return needFullRedraw +} + // UpdateHeader updates the header func (t *Terminal) UpdateHeader(header []string) { t.mutex.Lock() - t.header = append(append([]string{}, t.header0...), header...) + t.header = header t.mutex.Unlock() t.reqBox.Set(reqHeader, nil) } @@ -907,8 +924,12 @@ func (t *Terminal) UpdateList(merger *Merger, reset bool) { t.mutex.Lock() var prevIndex int32 = -1 - if !reset && t.track && t.merger.Length() > 0 { - prevIndex = t.merger.Get(t.cy).item.Index() + if !reset && t.track != trackDisabled { + if t.merger.Length() > 0 { + prevIndex = t.merger.Get(t.cy).item.Index() + } else if merger.Length() > 0 { + prevIndex = merger.First().item.Index() + } } t.progress = 100 t.merger = merger @@ -916,7 +937,7 @@ t.selected = make(map[int32]selectedItem) t.version++ } - if t.hasLoadActions && t.triggerLoad { + if t.triggerLoad { t.triggerLoad = false t.eventChan <- tui.Load.AsEvent() } @@ -927,15 +948,27 @@ if i >= 0 { t.cy = i t.offset = t.cy - pos + } else if t.track == trackCurrent { + t.track = trackDisabled + t.cy = pos + t.offset = 0 } else if t.cy > count { // Try to keep the vertical position when the list shrinks t.cy = count - util.Min(count, t.maxItems()) + pos } } - if !t.reading && t.merger.Length() == 1 { - one := tui.One.AsEvent() - if _, prs := t.keymap[one]; prs { - t.eventChan <- one + if !t.reading { + switch t.merger.Length() { + case 0: + zero := tui.Zero.AsEvent() + if _, prs := t.keymap[zero]; prs { + t.eventChan <- zero + } + case 1: + one := tui.One.AsEvent() + if _, prs := t.keymap[one]; prs { + t.eventChan <- one + } } } t.mutex.Unlock() @@ -1340,7 +1373,7 @@ case layoutDefault: y = h - y - 1 case layoutReverseList: - n := 2 + len(t.header) + n := 2 + len(t.header0) + len(t.header) if t.noInfoLine() { n-- } @@ -1460,6 +1493,9 @@ output += " -S" } } + if t.track != trackDisabled { + output += " +T" + } if t.multi > 0 { if t.multi == maxMulti { output += fmt.Sprintf(" (%d)", len(t.selected)) @@ -1485,7 +1521,7 @@ } func (t *Terminal) printHeader() { - if len(t.header) == 0 { + if len(t.header0)+len(t.header) == 0 { return } max := t.window.Height() @@ -1496,7 +1532,7 @@ } } var state *ansiState - for idx, lineStr := range t.header { + for idx, lineStr := range append(append([]string{}, t.header0...), t.header...) { line := idx if !t.headerFirst { line++ @@ -1530,7 +1566,7 @@ if t.layout == layoutDefault { i = maxy - 1 - j } - line := i + 2 + len(t.header) + line := i + 2 + len(t.header0) + len(t.header) if t.noInfoLine() { line-- } @@ -1836,7 +1872,7 @@ if ansi != nil { ansi.lbg = -1 } - line = strings.TrimSuffix(line, "\n") + line = strings.TrimRight(line, "\r\n") if lineNo >= height || t.pwindow.Y() == height-1 && t.pwindow.X() > 0 { t.previewed.filled = true t.previewer.scrollable = true @@ -2268,12 +2304,12 @@ t.printAll() } -func (t *Terminal) executeCommand(template string, forcePlus bool, background bool, captureFirstLine bool) string { +func (t *Terminal) executeCommand(template string, forcePlus bool, background bool, capture bool, firstLineOnly bool) string { line := "" valid, list := t.buildPlusList(template, forcePlus) - // captureFirstLine is used for transform-{prompt,query} and we don't want to + // 'capture' is used for transform-* and we don't want to // return an empty string in those cases - if !valid && !captureFirstLine { + if !valid && !capture { return line } command := t.replacePlaceholder(template, forcePlus, string(t.input), list) @@ -2290,12 +2326,17 @@ t.redraw() t.refresh() } else { - if captureFirstLine { + if capture { out, _ := cmd.StdoutPipe() reader := bufio.NewReader(out) cmd.Start() - line, _ = reader.ReadString('\n') - line = strings.TrimRight(line, "\r\n") + if firstLineOnly { + line, _ = reader.ReadString('\n') + line = strings.TrimRight(line, "\r\n") + } else { + bytes, _ := io.ReadAll(reader) + line = string(bytes) + } cmd.Wait() } else { cmd.Run() @@ -2706,6 +2747,10 @@ currentIndex = currentItem.Index() } focusChanged := focusedIndex != currentIndex + if focusChanged && t.track == trackCurrent { + t.track = trackDisabled + t.printInfo() + } if onFocus != nil && focusChanged { t.serverChan <- onFocus } @@ -2818,7 +2863,7 @@ } select { case event = <-t.eventChan: - needBarrier = event != tui.Load.AsEvent() + needBarrier = !event.Is(tui.Load, tui.One, tui.Zero) case actions = <-t.serverChan: event = tui.Invalid.AsEvent() needBarrier = false @@ -2913,9 +2958,9 @@ } } case actExecute, actExecuteSilent: - t.executeCommand(a.a, false, a.t == actExecuteSilent, false) + t.executeCommand(a.a, false, a.t == actExecuteSilent, false, false) case actExecuteMulti: - t.executeCommand(a.a, true, false, false) + t.executeCommand(a.a, true, false, false, false) case actInvalid: t.mutex.Unlock() return false @@ -2949,11 +2994,11 @@ req(reqPreviewRefresh) } case actTransformPrompt: - prompt := t.executeCommand(a.a, false, true, true) + prompt := t.executeCommand(a.a, false, true, true, true) t.prompt, t.promptLen = t.parsePrompt(prompt) req(reqPrompt) case actTransformQuery: - query := t.executeCommand(a.a, false, true, true) + query := t.executeCommand(a.a, false, true, true, true) t.input = []rune(query) t.cx = len(t.input) case actToggleSort: @@ -3002,6 +3047,19 @@ case actChangeQuery: t.input = []rune(a.a) t.cx = len(t.input) + case actTransformHeader: + header := t.executeCommand(a.a, false, true, true, false) + if t.changeHeader(header) { + req(reqFullRedraw) + } else { + req(reqHeader) + } + case actChangeHeader: + if t.changeHeader(a.a) { + req(reqFullRedraw) + } else { + req(reqHeader) + } case actChangeBorderLabel: if t.border != nil { t.borderLabel, t.borderLabelLen = t.ansiLabelPrinter(a.a, &tui.ColBorderLabel, false) @@ -3014,13 +3072,13 @@ } case actTransformBorderLabel: if t.border != nil { - label := t.executeCommand(a.a, false, true, true) + label := t.executeCommand(a.a, false, true, true, true) t.borderLabel, t.borderLabelLen = t.ansiLabelPrinter(label, &tui.ColBorderLabel, false) req(reqRedrawBorderLabel) } case actTransformPreviewLabel: if t.pborder != nil { - label := t.executeCommand(a.a, false, true, true) + label := t.executeCommand(a.a, false, true, true, true) t.previewLabel, t.previewLabelLen = t.ansiLabelPrinter(label, &tui.ColPreviewLabel, false) req(reqRedrawPreviewLabel) } @@ -3270,6 +3328,19 @@ t.paused = !t.paused changed = !t.paused req(reqPrompt) + case actToggleTrack: + switch t.track { + case trackEnabled: + t.track = trackDisabled + case trackDisabled: + t.track = trackEnabled + } + req(reqInfo) + case actTrack: + if t.track == trackDisabled { + t.track = trackCurrent + } + req(reqInfo) case actEnableSearch: t.paused = false changed = true @@ -3347,7 +3418,7 @@ // Translate coordinates mx -= t.window.Left() my -= t.window.Top() - min := 2 + len(t.header) + min := 2 + len(t.header0) + len(t.header) if t.noInfoLine() { min-- } @@ -3552,7 +3623,7 @@ t.mutex.Unlock() // Must be unlocked before touching reqBox if changed || newCommand != nil { - t.eventBox.Set(EvtSearchNew, searchRequest{sort: t.sort, sync: reloadSync, command: newCommand}) + t.eventBox.Set(EvtSearchNew, searchRequest{sort: t.sort, sync: reloadSync, command: newCommand, changed: changed}) } for _, event := range events { t.reqBox.Set(event, nil) @@ -3616,7 +3687,7 @@ } func (t *Terminal) maxItems() int { - max := t.window.Height() - 2 - len(t.header) + max := t.window.Height() - 2 - len(t.header0) - len(t.header) if t.noInfoLine() { max++ } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.39.0/src/tui/tui.go new/fzf-0.40.0/src/tui/tui.go --- old/fzf-0.39.0/src/tui/tui.go 2023-04-02 16:33:37.000000000 +0200 +++ new/fzf-0.40.0/src/tui/tui.go 2023-04-30 18:59:21.000000000 +0200 @@ -94,6 +94,7 @@ Load Focus One + Zero AltBS @@ -283,6 +284,15 @@ MouseEvent *MouseEvent } +func (e Event) Is(types ...EventType) bool { + for _, t := range types { + if e.Type == t { + return true + } + } + return false +} + type MouseEvent struct { Y int X int diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.39.0/test/test_go.rb new/fzf-0.40.0/test/test_go.rb --- old/fzf-0.39.0/test/test_go.rb 2023-04-02 16:33:37.000000000 +0200 +++ new/fzf-0.40.0/test/test_go.rb 2023-04-30 18:59:21.000000000 +0200 @@ -1865,6 +1865,67 @@ tmux.until { |lines| assert_equal '>', lines.last } end + def test_change_and_transform_header + [ + 'space:change-header:$(seq 4)', + 'space:transform-header:seq 4' + ].each_with_index do |binding, i| + tmux.send_keys %(seq 3 | #{FZF} --header-lines 2 --header bar --bind "#{binding}"), :Enter + expected = <<~OUTPUT + > 3 + 2 + 1 + bar + 1/1 + > + OUTPUT + tmux.until { assert_block(expected, _1) } + tmux.send_keys :Space + expected = <<~OUTPUT + > 3 + 2 + 1 + 1 + 2 + 3 + 4 + 1/1 + > + OUTPUT + tmux.until { assert_block(expected, _1) } + next unless i.zero? + + teardown + setup + end + end + + def test_change_header + tmux.send_keys %(seq 3 | #{FZF} --header-lines 2 --header bar --bind "space:change-header:$(seq 4)"), :Enter + expected = <<~OUTPUT + > 3 + 2 + 1 + bar + 1/1 + > + OUTPUT + tmux.until { assert_block(expected, _1) } + tmux.send_keys :Space + expected = <<~OUTPUT + > 3 + 2 + 1 + 1 + 2 + 3 + 4 + 1/1 + > + OUTPUT + tmux.until { assert_block(expected, _1) } + end + def test_change_query tmux.send_keys %(: | #{FZF} --query foo --bind space:change-query:foobar), :Enter tmux.until { |lines| assert_equal 0, lines.item_count } @@ -2681,7 +2742,7 @@ end def test_track - tmux.send_keys "seq 1000 | #{FZF} --query 555 --track", :Enter + tmux.send_keys "seq 1000 | #{FZF} --query 555 --track --bind t:toggle-track", :Enter tmux.until do |lines| assert_equal 1, lines.match_count assert_includes lines, '> 555' @@ -2701,20 +2762,97 @@ assert_equal 1000, lines.match_count assert_equal '> 555', lines[index] end + tmux.send_keys '555' + tmux.until do |lines| + assert_equal 1, lines.match_count + assert_includes lines, '> 555' + assert_includes lines[-2], '+T' + end + tmux.send_keys 't' + tmux.until do |lines| + refute_includes lines[-2], '+T' + end + tmux.send_keys :BSpace + tmux.until do |lines| + assert_equal 28, lines.match_count + assert_includes lines, '> 55' + end + tmux.send_keys :BSpace + tmux.until do |lines| + assert_equal 271, lines.match_count + assert_includes lines, '> 5' + end + tmux.send_keys 't' + tmux.until do |lines| + assert_includes lines[-2], '+T' + end + tmux.send_keys :BSpace + tmux.until do |lines| + assert_equal 1000, lines.match_count + assert_includes lines, '> 5' + end + end + + def test_track_action + tmux.send_keys "seq 1000 | #{FZF} --query 555 --bind t:track", :Enter + tmux.until do |lines| + assert_equal 1, lines.match_count + assert_includes lines, '> 555' + end + tmux.send_keys :BSpace + tmux.until do |lines| + assert_equal 28, lines.match_count + assert_includes lines, '> 55' + end + tmux.send_keys :t + tmux.until do |lines| + assert_includes lines[-2], '+T' + end + tmux.send_keys :BSpace + tmux.until do |lines| + assert_equal 271, lines.match_count + assert_includes lines, '> 55' + end + + # Automatically disabled when the tracking item is no longer visible + tmux.send_keys '4' + tmux.until do |lines| + assert_equal 28, lines.match_count + refute_includes lines[-2], '+T' + end + tmux.send_keys :BSpace + tmux.until do |lines| + assert_equal 271, lines.match_count + assert_includes lines, '> 5' + end + tmux.send_keys :t + tmux.until do |lines| + assert_includes lines[-2], '+T' + end + tmux.send_keys :Up + tmux.until do |lines| + refute_includes lines[-2], '+T' + end end - def test_one - tmux.send_keys "seq 10 | #{FZF} --bind 'one:preview:echo {} is the only match'", :Enter + def test_one_and_zero + tmux.send_keys "seq 10 | #{FZF} --bind 'zero:preview(echo no match),one:preview(echo {} is the only match)'", :Enter tmux.send_keys '1' tmux.until do |lines| assert_equal 2, lines.match_count refute(lines.any? { _1.include?('only match') }) + refute(lines.any? { _1.include?('no match') }) end tmux.send_keys '0' tmux.until do |lines| assert_equal 1, lines.match_count assert(lines.any? { _1.include?('only match') }) end + tmux.send_keys '0' + tmux.until do |lines| + assert_equal 0, lines.match_count + assert(lines.any? { _1.include?('no match') }) + end end def test_height_range_with_exit_0 @@ -2723,6 +2861,11 @@ tmux.send_keys :c tmux.until { |lines| assert_equal 0, lines.match_count } end + + def test_reload_and_change + tmux.send_keys "(echo foo; echo bar) | #{FZF} --bind 'load:reload-sync(sleep 60)+change-query(bar)'", :Enter + tmux.until { |lines| assert_equal 1, lines.match_count } + end end module TestShell ++++++ vendor.tar.zst ++++++ Binary files /var/tmp/diff_new_pack.XLAq6A/_old and /var/tmp/diff_new_pack.XLAq6A/_new differ