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-11-13 22:21:15 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/fzf (Old) and /work/SRC/openSUSE:Factory/.fzf.new.17445 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "fzf" Mon Nov 13 22:21:15 2023 rev:38 rq:1125249 version:0.44.0 Changes: -------- --- /work/SRC/openSUSE:Factory/fzf/fzf.changes 2023-10-16 22:33:27.556849403 +0200 +++ /work/SRC/openSUSE:Factory/.fzf.new.17445/fzf.changes 2023-11-13 22:24:53.948401696 +0100 @@ -1,0 +2,8 @@ +Sun Nov 12 13:20:53 UTC 2023 - Soc Virnyl Estela <uncomfy+openbuildserv...@uncomfyhalomacro.pl> + +- Update to version 0.44.0: + * experimental sixel support added in fzf-preview.sh script + * HTTP server can be configured to accept remote connections + * Bug fixes + +------------------------------------------------------------------- Old: ---- fzf-0.43.0.tar.gz New: ---- fzf-0.44.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ fzf.spec ++++++ --- /var/tmp/diff_new_pack.5bIbgx/_old 2023-11-13 22:24:54.636427028 +0100 +++ /var/tmp/diff_new_pack.5bIbgx/_new 2023-11-13 22:24:54.640427175 +0100 @@ -18,7 +18,7 @@ %global _lto_cflags %{nil} Name: fzf -Version: 0.43.0 +Version: 0.44.0 Release: 0 Summary: A command-line fuzzy finder License: MIT ++++++ fzf-0.43.0.tar.gz -> fzf-0.44.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/BUILD.md new/fzf-0.44.0/BUILD.md --- old/fzf-0.43.0/BUILD.md 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/BUILD.md 2023-11-12 14:08:08.000000000 +0100 @@ -6,7 +6,7 @@ ### Prerequisites -- Go 1.17 or above +- Go 1.18 or above ### Using Makefile diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/CHANGELOG.md new/fzf-0.44.0/CHANGELOG.md --- old/fzf-0.43.0/CHANGELOG.md 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/CHANGELOG.md 2023-11-12 14:08:08.000000000 +0100 @@ -1,9 +1,37 @@ CHANGELOG ========= +0.44.0 +------ +- (Experimental) Sixel image support in preview window (not available on Windows) + - [bin/fzf-preview.sh](bin/fzf-preview.sh) is added to demonstrate how to + display an image using Kitty image protocol or Sixel. You can use it + like so: + ```sh + fzf --preview='fzf-preview.sh {}' + ``` +- (Experimental) iTerm2 inline image protocol support in preview window (not available on Windows) + ```sh + # Using https://iterm2.com/utilities/imgcat + fzf --preview 'imgcat -W $FZF_PREVIEW_COLUMNS -H $FZF_PREVIEW_LINES {}' + ``` +- HTTP server can be configured to accept remote connections + ```sh + # FZF_API_KEY is required for a non-localhost listen address + export FZF_API_KEY="$(head -c 32 /dev/urandom | base64)" + fzf --listen 0.0.0.0:6266 + ``` + - To allow remote process execution, use `--listen-unsafe` instead + (`execute*`, `reload*`, `become`, `preview`, `change-preview`, `transform-*`) + ```sh + fzf --listen-unsafe 0.0.0.0:6266 + ``` +- Bug fixes + 0.43.0 ------ - (Experimental) Added support for Kitty image protocol in the preview window + (not available on Windows) ```sh fzf --preview=' if file --mime-type {} | grep -qF image/; then diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/Makefile new/fzf-0.44.0/Makefile --- old/fzf-0.43.0/Makefile 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/Makefile 2023-11-12 14:08:08.000000000 +0100 @@ -93,6 +93,10 @@ goreleaser build --rm-dist --snapshot --skip-post-hooks release: + # Make sure that the tests pass and the build works + TAGS=tcell make test + make test build clean + ifndef GITHUB_TOKEN $(error GITHUB_TOKEN is not defined) endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/README.md new/fzf-0.44.0/README.md --- old/fzf-0.43.0/README.md 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/README.md 2023-11-12 14:08:08.000000000 +0100 @@ -26,7 +26,7 @@ If you'd like to sponsor this project, please visit https://github.com/sponsors/junegunn. -<!-- sponsors --><a href="https://github.com/miyanokomiya"><img src="https://github.com/miyanokomiya.png" width="60px" alt="miyanokomiya" /></a><a href="https://github.com/jonhoo"><img src="https://github.com/jonhoo.png" width="60px" alt="Jon Gjengset" /></a><a href="https://github.com/AceofSpades5757"><img src="https://github.com/AceofSpades5757.png" width="60px" alt="Kyle L. Davis" /></a><a href="https://github.com/Frederick888"><img src="https://github.com/Frederick888.png" width="60px" alt="Frederick Zhang" /></a><a href="https://github.com/moritzdietz"><img src="https://github.com/moritzdietz.png" width="60px" alt="Moritz Dietz" /></a><a href="https://github.com/mikker"><img src="https://github.com/mikker.png" width="60px" alt="Mikkel Malmberg" /></a><a href="https://github.com/pldubouilh"><img src="https://github.com/pldubouilh.png" width="60px" alt="Pierre Dubouilh" /></a><a href="https://github.com/rcorre"><img src="https://github.com/rcorre.png" width="60px" alt="Ryan Roden -Corrent" /></a><a href="https://github.com/blissdev"><img src="https://github.com/blissdev.png" width="60px" alt="Jordan Arentsen" /></a><a href="https://github.com/mislav"><img src="https://github.com/mislav.png" width="60px" alt="Mislav MarohniÄ" /></a><a href="https://github.com/aexvir"><img src="https://github.com/aexvir.png" width="60px" alt="Alex Viscreanu" /></a><a href="https://github.com/dbalatero"><img src="https://github.com/dbalatero.png" width="60px" alt="David Balatero" /></a><a href="https://github.com/comatory"><img src="https://github.com/comatory.png" width="60px" alt="Ondrej Synacek" /></a><a href="https://github.com/moobar"><img src="https://github.com/moobar.png" width="60px" alt="" /></a><a href="https://github.com/majjoha"><img src="https://github.com/majjoha.png" width="60px" alt="Mathias Jean Johansen" /></a><a href="https://github.com/benelan"><img src="https://github.com/benelan.png" width="60px" alt="Ben Elan" /></a><a href="https://github.com/jryom"><i mg src="https://github.com/jryom.png" width="60px" alt="Jesper" /></a><a href="https://github.com/nmrnv"><img src="https://github.com/nmrnv.png" width="60px" alt="Nikolay Marinov" /></a><a href="https://github.com/pawelduda"><img src="https://github.com/pawelduda.png" width="60px" alt="PaweÅ Duda" /></a><a href="https://github.com/slezica"><img src="https://github.com/slezica.png" width="60px" alt="Santiago Lezica" /></a><a href="https://github.com/pbwn"><img src="https://github.com/pbwn.png" width="60px" alt="" /></a><a href="https://github.com/timgluz"><img src="https://github.com/timgluz.png" width="60px" alt="Timo Sulg" /></a><a href="https://github.com/seanmorton"><img src="https://github.com/seanmorton.png" width="60px" alt="Sean Morton" /></a><a href="https://github.com/pyrho"><img src="https://github.com/pyrho.png" width="60px" alt="Damien Rajon" /></a><a href="https://github.com/ArtBIT"><img src="https://github.com/ArtBIT.png" width="60px" alt="ArtBIT" /></a><a href="https ://github.com/da-moon"><img src="https://github.com/da-moon.png" width="60px" alt="" /></a><a href="https://github.com/hovissimo"><img src="https://github.com/hovissimo.png" width="60px" alt="Hovis" /></a><a href="https://github.com/dariusjonda"><img src="https://github.com/dariusjonda.png" width="60px" alt="Darius Jonda" /></a><a href="https://github.com/cristiand391"><img src="https://github.com/cristiand391.png" width="60px" alt="Cristian Dominguez" /></a><a href="https://github.com/eliangcs"><img src="https://github.com/eliangcs.png" width="60px" alt="Chang-Hung Liang" /></a><a href="https://github.com/raveensrk"><img src="https://github.com/raveensrk.png" width="60px" alt="Raveen Kumar" /></a><a href="https://github.com/asphaltbuffet"><img src="https://github.com/asphaltbuffet.png" width="60px" alt="Ben Lechlitner" /></a><a href="https://github.com/yash1th"><img src="https://github.com/yash1th.png" width="60px" alt="yash" /></a><a href="https://github.com/kg8m"><img src="https: //github.com/kg8m.png" width="60px" alt="Takumi KAGIYAMA" /></a><a href="https://github.com/polm"><img src="https://github.com/polm.png" width="60px" alt="Paul O'Leary McCann" /></a><a href="https://github.com/rbeeger"><img src="https://github.com/rbeeger.png" width="60px" alt="Robert Beeger" /></a><a href="https://github.com/veebch"><img src="https://github.com/veebch.png" width="60px" alt="VEEB Projects" /></a><!-- sponsors --> +<!-- sponsors --><a href="https://github.com/miyanokomiya"><img src="https://github.com/miyanokomiya.png" width="60px" alt="miyanokomiya" /></a><a href="https://github.com/jonhoo"><img src="https://github.com/jonhoo.png" width="60px" alt="Jon Gjengset" /></a><a href="https://github.com/AceofSpades5757"><img src="https://github.com/AceofSpades5757.png" width="60px" alt="Kyle L. Davis" /></a><a href="https://github.com/Frederick888"><img src="https://github.com/Frederick888.png" width="60px" alt="Frederick Zhang" /></a><a href="https://github.com/moritzdietz"><img src="https://github.com/moritzdietz.png" width="60px" alt="Moritz Dietz" /></a><a href="https://github.com/mikker"><img src="https://github.com/mikker.png" width="60px" alt="Mikkel Malmberg" /></a><a href="https://github.com/pldubouilh"><img src="https://github.com/pldubouilh.png" width="60px" alt="Pierre Dubouilh" /></a><a href="https://github.com/rcorre"><img src="https://github.com/rcorre.png" width="60px" alt="Ryan Roden -Corrent" /></a><a href="https://github.com/blissdev"><img src="https://github.com/blissdev.png" width="60px" alt="Jordan Arentsen" /></a><a href="https://github.com/mislav"><img src="https://github.com/mislav.png" width="60px" alt="Mislav MarohniÄ" /></a><a href="https://github.com/aexvir"><img src="https://github.com/aexvir.png" width="60px" alt="Alex Viscreanu" /></a><a href="https://github.com/dbalatero"><img src="https://github.com/dbalatero.png" width="60px" alt="David Balatero" /></a><a href="https://github.com/comatory"><img src="https://github.com/comatory.png" width="60px" alt="Ondrej Synacek" /></a><a href="https://github.com/moobar"><img src="https://github.com/moobar.png" width="60px" alt="" /></a><a href="https://github.com/carlfriedrich"><img src="https://github.com/carlfriedrich.png" width="60px" alt="Tim" /></a><a href="https://github.com/majjoha"><img src="https://github.com/majjoha.png" width="60px" alt="Mathias Jean Johansen" /></a><a href="https://github.com/be nelan"><img src="https://github.com/benelan.png" width="60px" alt="Ben Elan" /></a><a href="https://github.com/jryom"><img src="https://github.com/jryom.png" width="60px" alt="Jesper" /></a><a href="https://github.com/nmrnv"><img src="https://github.com/nmrnv.png" width="60px" alt="Nikolay Marinov" /></a><a href="https://github.com/pawelduda"><img src="https://github.com/pawelduda.png" width="60px" alt="PaweÅ Duda" /></a><a href="https://github.com/slezica"><img src="https://github.com/slezica.png" width="60px" alt="Santiago Lezica" /></a><a href="https://github.com/pbwn"><img src="https://github.com/pbwn.png" width="60px" alt="" /></a><a href="https://github.com/timgluz"><img src="https://github.com/timgluz.png" width="60px" alt="Timo Sulg" /></a><a href="https://github.com/seanmorton"><img src="https://github.com/seanmorton.png" width="60px" alt="Sean Morton" /></a><a href="https://github.com/pyrho"><img src="https://github.com/pyrho.png" width="60px" alt="Damien Rajon" /></a><a href="https://github.com/ArtBIT"><img src="https://github.com/ArtBIT.png" width="60px" alt="ArtBIT" /></a><a href="https://github.com/da-moon"><img src="https://github.com/da-moon.png" width="60px" alt="" /></a><a href="https://github.com/hovissimo"><img src="https://github.com/hovissimo.png" width="60px" alt="Hovis" /></a><a href="https://github.com/dariusjonda"><img src="https://github.com/dariusjonda.png" width="60px" alt="Darius Jonda" /></a><a href="https://github.com/cristiand391"><img src="https://github.com/cristiand391.png" width="60px" alt="Cristian Dominguez" /></a><a href="https://github.com/eliangcs"><img src="https://github.com/eliangcs.png" width="60px" alt="Chang-Hung Liang" /></a><a href="https://github.com/raveensrk"><img src="https://github.com/raveensrk.png" width="60px" alt="Raveen Kumar" /></a><a href="https://github.com/asphaltbuffet"><img src="https://github.com/asphaltbuffet.png" width="60px" alt="Ben Lechlitner" /></a><a href="https://github.com/yash1th"><i mg src="https://github.com/yash1th.png" width="60px" alt="yash" /></a><a href="https://github.com/looshch"><img src="https://github.com/looshch.png" width="60px" alt="george looshch" /></a><a href="https://github.com/kg8m"><img src="https://github.com/kg8m.png" width="60px" alt="Takumi KAGIYAMA" /></a><a href="https://github.com/polm"><img src="https://github.com/polm.png" width="60px" alt="Paul O'Leary McCann" /></a><a href="https://github.com/rbeeger"><img src="https://github.com/rbeeger.png" width="60px" alt="Robert Beeger" /></a><a href="https://github.com/veebch"><img src="https://github.com/veebch.png" width="60px" alt="VEEB Projects" /></a><a href="https://github.com/y3ro"><img src="https://github.com/y3ro.png" width="60px" alt="Yerai" /></a><a href="https://github.com/khuedoan"><img src="https://github.com/khuedoan.png" width="60px" alt="Khue Doan" /></a><a href="https://github.com/yowayb"><img src="https://github.com/yowayb.png" width="60px" alt="Yoway Buorn" /></a><a href= "https://github.com/td0m"><img src="https://github.com/td0m.png" width="60px" alt="Dominik Tarnowski" /></a><a href="https://github.com/yutao-li"><img src="https://github.com/yutao-li.png" width="60px" alt="master_lee" /></a><a href="https://github.com/scalisi"><img src="https://github.com/scalisi.png" width="60px" alt="Josh Scalisi" /></a><a href="https://github.com/alecbcs"><img src="https://github.com/alecbcs.png" width="60px" alt="Alec Scott" /></a><a href="https://github.com/the-shank"><img src="https://github.com/the-shank.png" width="60px" alt="theshank" /></a><a href="https://github.com/thnxdev"><img src="https://github.com/thnxdev.png" width="60px" alt="thanks.dev" /></a><a href="https://github.com/hasefumi23"><img src="https://github.com/hasefumi23.png" width="60px" alt="" /></a><!-- sponsors --> Table of Contents ----------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/bin/fzf-preview.sh new/fzf-0.44.0/bin/fzf-preview.sh --- old/fzf-0.43.0/bin/fzf-preview.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/fzf-0.44.0/bin/fzf-preview.sh 2023-11-12 14:08:08.000000000 +0100 @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +# +# The purpose of this script is to demonstrate how to preview a file or an +# image in the preview window of fzf. +# +# Dependencies: +# - https://github.com/sharkdp/bat +# - https://github.com/hpjansson/chafa +# - https://iterm2.com/utilities/imgcat + +if [[ $# -ne 1 ]]; then + >&2 echo "usage: $0 FILENAME" + exit 1 +fi + +file=${1/#\~\//$HOME/} +type=$(file --dereference --mime -- "$file") + +if [[ ! $type =~ image/ ]]; then + if [[ $type =~ =binary ]]; then + file "$1" + exit + fi + + # Sometimes bat is installed as batcat. + if command -v batcat > /dev/null; then + batname="batcat" + elif command -v bat > /dev/null; then + batname="bat" + else + cat "$1" + exit + fi + + ${batname} --style="${BAT_STYLE:-numbers}" --color=always --pager=never -- "$file" + exit +fi + +dim=${FZF_PREVIEW_COLUMNS}x${FZF_PREVIEW_LINES} +if [[ $dim = x ]]; then + dim=$(stty size < /dev/tty | awk '{print $2 "x" $1}') +elif ! [[ $KITTY_WINDOW_ID ]] && (( FZF_PREVIEW_TOP + FZF_PREVIEW_LINES == $(stty size < /dev/tty | awk '{print $1}') )); then + # Avoid scrolling issue when the Sixel image touches the bottom of the screen + # * https://github.com/junegunn/fzf/issues/2544 + dim=${FZF_PREVIEW_COLUMNS}x$((FZF_PREVIEW_LINES - 1)) +fi + +# 1. Use kitty icat on kitty terminal +if [[ $KITTY_WINDOW_ID ]]; then + # 1. 'memory' is the fastest option but if you want the image to be scrollable, + # you have to use 'stream'. + # + # 2. The last line of the output is the ANSI reset code without newline. + # This confuses fzf and makes it render scroll offset indicator. + # So we remove the last line and append the reset code to its previous line. + kitty icat --clear --transfer-mode=memory --stdin=no --place="$dim@0x0" "$file" | sed '$d' | sed $'$s/$/\e[m/' + +# 2. Use chafa with Sixel output +elif command -v chafa > /dev/null; then + chafa -f sixel -s "$dim" "$file" + # Add a new line character so that fzf can display multiple images in the preview window + echo + +# 3. If chafa is not found but imgcat is available, use it on iTerm2 +elif command -v imgcat > /dev/null; then + # NOTE: We should use https://iterm2.com/utilities/it2check to check if the + # user is running iTerm2. But for the sake of simplicity, we just assume + # that's the case here. + imgcat -W "${dim%%x*}" -H "${dim##*x}" "$file" + +# 4. Cannot find any suitable method to preview the image +else + file "$file" +fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/go.mod new/fzf-0.44.0/go.mod --- old/fzf-0.43.0/go.mod 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/go.mod 2023-11-12 14:08:08.000000000 +0100 @@ -7,7 +7,7 @@ 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.13.0 + golang.org/x/sys v0.14.0 golang.org/x/term v0.13.0 ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/go.sum new/fzf-0.44.0/go.sum --- old/fzf-0.43.0/go.sum 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/go.sum 2023-11-12 14:08:08.000000000 +0100 @@ -23,7 +23,6 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -32,8 +31,8 @@ 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.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/install new/fzf-0.44.0/install --- old/fzf-0.43.0/install 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/install 2023-11-12 14:08:08.000000000 +0100 @@ -2,7 +2,7 @@ set -u -version=0.43.0 +version=0.44.0 auto_completion= key_bindings= update_config=2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/install.ps1 new/fzf-0.44.0/install.ps1 --- old/fzf-0.43.0/install.ps1 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/install.ps1 2023-11-12 14:08:08.000000000 +0100 @@ -1,4 +1,4 @@ -$version="0.43.0" +$version="0.44.0" $fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/main.go new/fzf-0.44.0/main.go --- old/fzf-0.43.0/main.go 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/main.go 2023-11-12 14:08:08.000000000 +0100 @@ -5,7 +5,7 @@ "github.com/junegunn/fzf/src/protector" ) -var version string = "0.43" +var version string = "0.44" var revision string = "devel" func main() { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/man/man1/fzf-tmux.1 new/fzf-0.44.0/man/man1/fzf-tmux.1 --- old/fzf-0.43.0/man/man1/fzf-tmux.1 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/man/man1/fzf-tmux.1 2023-11-12 14:08:08.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 "Oct 2023" "fzf 0.43.0" "fzf-tmux - open fzf in tmux split pane" +.TH fzf-tmux 1 "Nov 2023" "fzf 0.44.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.43.0/man/man1/fzf.1 new/fzf-0.44.0/man/man1/fzf.1 --- old/fzf-0.43.0/man/man1/fzf.1 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/man/man1/fzf.1 2023-11-12 14:08:08.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 "Oct 2023" "fzf 0.43.0" "fzf - a command-line fuzzy finder" +.TH fzf 1 "Nov 2023" "fzf 0.44.0" "fzf - a command-line fuzzy finder" .SH NAME fzf - a command-line fuzzy finder @@ -548,6 +548,9 @@ by the default shell, so prefer to refer to the ones with \fBFZF_PREVIEW_\fR prefix.) +fzf also exports \fB$FZF_PREVIEW_TOP\fR and \fB$FZF_PREVIEW_LEFT\fR so that +the preview command can determine the position of the preview window. + A placeholder expression starting with \fB+\fR flag will be replaced to the space-separated list of the selected lines (or the current line if no selection was made) individually quoted. @@ -592,17 +595,13 @@ sleep 0.01 done'\fR -Since 0.43.0, fzf has experimental support for Kitty graphics protocol, -so if you use Kitty, you can make fzf display an image in the preview window. +fzf has experimental support for Kitty graphics protocol and Sixel graphics. +The following example uses https://github.com/junegunn/fzf/blob/master/bin/fzf-preview.sh +script to render an image using either of the protocols inside the preview window. e.g. - \fBfzf --preview=' - if file --mime-type {} | grep -qF "image/"; then - kitty icat --clear --transfer-mode=memory --stdin=no --place=${FZF_PREVIEW_COLUMNS}x${FZF_PREVIEW_LINES}@0x0 {} | sed \\$d - else - bat --color=always {} - fi - '\fR + \fBfzf --preview='fzf-preview.sh {}' + .RE .TP @@ -794,14 +793,19 @@ e.g. \fBfzf --multi | fzf --sync\fR .RE .TP -.B "--listen[=HTTP_PORT]" -Start HTTP server on the given port. It allows external processes to send -actions to perform via POST method. If the port number is omitted or given as -0, fzf will choose the port automatically and export it as \fBFZF_PORT\fR -environment variable to the child processes started via \fBexecute\fR and -\fBexecute-silent\fR actions. If \fBFZF_API_KEY\fR environment variable is -set, the server would require sending an API key with the same value in the -\fBx-api-key\fR HTTP header. +.B "--listen[=[ADDR:]PORT]" "--listen-unsafe[=[ADDR:]PORT]" +Start HTTP server and listen on the given address. It allows external processes +to send actions to perform via POST method. + +- If the port number is omitted or given as 0, fzf will automatically choose +a port and export it as \fBFZF_PORT\fR environment variable to the child processes + +- If \fBFZF_API_KEY\fR environment variable is set, the server would require +sending an API key with the same value in the \fBx-api-key\fR HTTP header + +- \fBFZF_API_KEY\fR is required for a non-localhost listen address + +- To allow remote process execution, use \fB--listen-unsafe\fR e.g. \fB# Start HTTP server on port 6266 @@ -813,8 +817,12 @@ # Send action to the server curl -XPOST localhost:6266 -d 'reload(seq 100)+change-prompt(hundred> )' - # Start HTTP server on port 6266 and send an authenticated action + # Start HTTP server on port 6266 with remote connections allowed + # * Listening on non-localhost address requires using an API key export FZF_API_KEY="$(head -c 32 /dev/urandom | base64)" + fzf --listen 0.0.0.0:6266 + + # Send an authenticated action curl -XPOST localhost:6266 -H "x-api-key: $FZF_API_KEY" -d 'change-query(yo)' # Choose port automatically and export it as $FZF_PORT to the child process diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/shell/completion.bash new/fzf-0.44.0/shell/completion.bash --- old/fzf-0.43.0/shell/completion.bash 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/shell/completion.bash 2023-11-12 14:08:08.000000000 +0100 @@ -423,8 +423,8 @@ __fzf_list_hosts() { command cat <(command tail -n +1 ~/.ssh/config ~/.ssh/config.d/* /etc/ssh/ssh_config 2> /dev/null | command grep -i '^\s*host\(name\)\? ' | command awk '{for (i = 2; i <= NF; i++) print $1 " " $i}' | command grep -v '[*?%]') \ <(command grep -oE '^[[a-z0-9.,:-]+' ~/.ssh/known_hosts 2> /dev/null | command tr ',' '\n' | command tr -d '[' | command awk '{ print $1 " " $1 }') \ - <(command grep -v '^\s*\(#\|$\)' /etc/hosts 2> /dev/null | command grep -Fv '0.0.0.0') | - command awk '{if (length($2) > 0) {print $2}}' | command sort -u + <(command grep -v '^\s*\(#\|$\)' /etc/hosts 2> /dev/null | command grep -Fv '0.0.0.0' | command sed 's/#.*//') | + command awk '{for (i = 2; i <= NF; i++) print $i}' | command sort -u } fi @@ -481,7 +481,7 @@ svn tar unzip zip" # Preserve existing completion -__fzf_orig_completion < <(complete -p $d_cmds $a_cmds 2> /dev/null) +__fzf_orig_completion < <(complete -p $d_cmds $a_cmds ssh 2> /dev/null) if type _completion_loader > /dev/null 2>&1; then _fzf_completion_loader=1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/shell/completion.zsh new/fzf-0.44.0/shell/completion.zsh --- old/fzf-0.43.0/shell/completion.zsh 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/shell/completion.zsh 2023-11-12 14:08:08.000000000 +0100 @@ -226,8 +226,8 @@ setopt localoptions nonomatch 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 2> /dev/null | tr ',' '\n' | tr -d '[' | awk '{ print $1 " " $1 }') \ - <(command grep -v '^\s*\(#\|$\)' /etc/hosts 2> /dev/null | command grep -Fv '0.0.0.0') | - awk '{if (length($2) > 0) {print $2}}' | sort -u + <(command grep -v '^\s*\(#\|$\)' /etc/hosts 2> /dev/null | command grep -Fv '0.0.0.0' | command sed 's/#.*//') | + awk '{for (i = 2; i <= NF; i++) print $i}' | sort -u } fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/src/options.go new/fzf-0.44.0/src/options.go --- old/fzf-0.43.0/src/options.go 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/src/options.go 2023-11-12 14:08:08.000000000 +0100 @@ -118,7 +118,8 @@ --read0 Read input delimited by ASCII NUL characters --print0 Print output delimited by ASCII NUL characters --sync Synchronous search for multi-staged filtering - --listen[=HTTP_PORT] Start HTTP server to receive actions (POST /) + --listen[=[ADDR:]PORT] Start HTTP server to receive actions (POST /) + (To allow remote process execution, use --listen-unsafe) --version Display version information and exit Environment variables @@ -334,7 +335,8 @@ PreviewLabel labelOpts Unicode bool Tabstop int - ListenPort *int + ListenAddr *listenAddress + Unsafe bool ClearOnExit bool Version bool } @@ -404,6 +406,7 @@ Tabstop: 8, BorderLabel: labelOpts{}, PreviewLabel: labelOpts{}, + Unsafe: false, ClearOnExit: true, Version: false} } @@ -1832,11 +1835,21 @@ nextString(allArgs, &i, "padding required (TRBL / TB,RL / T,RL,B / T,R,B,L)")) case "--tabstop": opts.Tabstop = nextInt(allArgs, &i, "tab stop required") - case "--listen": - port := optionalNumeric(allArgs, &i, 0) - opts.ListenPort = &port - case "--no-listen": - opts.ListenPort = nil + case "--listen", "--listen-unsafe": + given, str := optionalNextString(allArgs, &i) + addr := defaultListenAddr + if given { + var err error + err, addr = parseListenAddress(str) + if err != nil { + errorExit(err.Error()) + } + } + opts.ListenAddr = &addr + opts.Unsafe = arg == "--listen-unsafe" + case "--no-listen", "--no-listen-unsafe": + opts.ListenAddr = nil + opts.Unsafe = false case "--clear": opts.ClearOnExit = true case "--no-clear": @@ -1927,8 +1940,19 @@ } else if match, value := optString(arg, "--tabstop="); match { opts.Tabstop = atoi(value) } else if match, value := optString(arg, "--listen="); match { - port := atoi(value) - opts.ListenPort = &port + err, addr := parseListenAddress(value) + if err != nil { + errorExit(err.Error()) + } + opts.ListenAddr = &addr + opts.Unsafe = false + } else if match, value := optString(arg, "--listen-unsafe="); match { + err, addr := parseListenAddress(value) + if err != nil { + errorExit(err.Error()) + } + opts.ListenAddr = &addr + opts.Unsafe = true } else if match, value := optString(arg, "--hscroll-off="); match { opts.HscrollOff = atoi(value) } else if match, value := optString(arg, "--scroll-off="); match { @@ -1958,10 +1982,6 @@ errorExit("tab stop must be a positive integer") } - if opts.ListenPort != nil && (*opts.ListenPort < 0 || *opts.ListenPort > 65535) { - errorExit("invalid listen port") - } - if len(opts.JumpLabels) == 0 { errorExit("empty jump labels") } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/src/protector/protector_openbsd.go new/fzf-0.44.0/src/protector/protector_openbsd.go --- old/fzf-0.43.0/src/protector/protector_openbsd.go 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/src/protector/protector_openbsd.go 2023-11-12 14:08:08.000000000 +0100 @@ -6,5 +6,5 @@ // Protect calls OS specific protections like pledge on OpenBSD func Protect() { - unix.PledgePromises("stdio rpath tty proc exec") + unix.PledgePromises("stdio rpath tty proc exec inet") } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/src/server.go new/fzf-0.44.0/src/server.go --- old/fzf-0.43.0/src/server.go 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/src/server.go 2023-11-12 14:08:08.000000000 +0100 @@ -40,30 +40,63 @@ responseChannel chan string } -func startHttpServer(port int, actionChannel chan []*action, responseChannel chan string) (error, int) { - if port < 0 { - return nil, port +type listenAddress struct { + host string + port int +} + +func (addr listenAddress) IsLocal() bool { + return addr.host == "localhost" || addr.host == "127.0.0.1" +} + +var defaultListenAddr = listenAddress{"localhost", 0} + +func parseListenAddress(address string) (error, listenAddress) { + parts := strings.SplitN(address, ":", 3) + if len(parts) == 1 { + parts = []string{"localhost", parts[0]} } + if len(parts) != 2 { + return fmt.Errorf("invalid listen address: %s", address), defaultListenAddr + } + portStr := parts[len(parts)-1] + port, err := strconv.Atoi(portStr) + if err != nil || port < 0 || port > 65535 { + return fmt.Errorf("invalid listen port: %s", portStr), defaultListenAddr + } + if len(parts[0]) == 0 { + parts[0] = "localhost" + } + return nil, listenAddress{parts[0], port} +} - listener, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", port)) +func startHttpServer(address listenAddress, actionChannel chan []*action, responseChannel chan string) (error, int) { + host := address.host + port := address.port + apiKey := os.Getenv("FZF_API_KEY") + if !address.IsLocal() && len(apiKey) == 0 { + return fmt.Errorf("FZF_API_KEY is required to allow remote access"), port + } + addrStr := fmt.Sprintf("%s:%d", host, port) + listener, err := net.Listen("tcp", addrStr) if err != nil { - return fmt.Errorf("port not available: %d", port), port + return fmt.Errorf("failed to listen on %s", addrStr), port } if port == 0 { addr := listener.Addr().String() - parts := strings.SplitN(addr, ":", 2) + parts := strings.Split(addr, ":") if len(parts) < 2 { return fmt.Errorf("cannot extract port: %s", addr), port } var err error - port, err = strconv.Atoi(parts[1]) + port, err = strconv.Atoi(parts[len(parts)-1]) if err != nil { return err, port } } server := httpServer{ - apiKey: []byte(os.Getenv("FZF_API_KEY")), + apiKey: []byte(apiKey), actionChannel: actionChannel, responseChannel: responseChannel, } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/src/terminal.go new/fzf-0.44.0/src/terminal.go --- old/fzf-0.43.0/src/terminal.go 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/src/terminal.go 2023-11-12 14:08:08.000000000 +0100 @@ -65,7 +65,9 @@ // Parts of the preview output that should be passed through to the terminal // * https://github.com/tmux/tmux/wiki/FAQ#what-is-the-passthrough-escape-sequence-and-how-do-i-use-it // * https://sw.kovidgoyal.net/kitty/graphics-protocol - passThroughRegex = regexp.MustCompile(`\x1bPtmux;\x1b\x1b.*?[^\x1b]\x1b\\|\x1b_G.*?\x1b\\`) + // * https://en.wikipedia.org/wiki/Sixel + // * https://iterm2.com/documentation-images.html + passThroughRegex = regexp.MustCompile(`\x1bPtmux;\x1b\x1b.*?[^\x1b]\x1b\\|\x1b(_G|P[0-9;]*q).*?\x1b\\\r?|\x1b]1337;.*?\a`) } type jumpMode int @@ -120,10 +122,13 @@ } type previewed struct { - version int64 - numLines int - offset int - filled bool + version int64 + numLines int + offset int + filled bool + image bool + wipe bool + wireframe bool } type eachLine struct { @@ -231,7 +236,9 @@ margin [4]sizeSpec padding [4]sizeSpec unicode bool + listenAddr *listenAddress listenPort *int + listenUnsafe bool borderShape tui.BorderShape cleanExit bool paused bool @@ -277,6 +284,7 @@ theme *tui.ColorTheme tui tui.Renderer executing *util.AtomicBool + termSize tui.TermSize } type selectedItem struct { @@ -307,6 +315,7 @@ reqRefresh reqReinit reqFullRedraw + reqResize reqRedrawBorderLabel reqRedrawPreviewLabel reqClose @@ -429,6 +438,26 @@ actResponse ) +func processExecution(action actionType) bool { + switch action { + case actTransformBorderLabel, + actTransformHeader, + actTransformPreviewLabel, + actTransformPrompt, + actTransformQuery, + actPreview, + actChangePreview, + actExecute, + actExecuteSilent, + actExecuteMulti, + actReload, + actReloadSync, + actBecome: + return true + } + return false +} + type placeholderFlags struct { plus bool preserveSpace bool @@ -446,7 +475,7 @@ type previewRequest struct { template string - pwindow tui.Window + pwindowSize tui.TermSize scrollOffset int list []*Item } @@ -580,7 +609,7 @@ } var previewBox *util.EventBox // We need to start previewer if HTTP server is enabled even when --preview option is not specified - if len(opts.Preview.command) > 0 || hasPreviewAction(opts) || opts.ListenPort != nil { + if len(opts.Preview.command) > 0 || hasPreviewAction(opts) || opts.ListenAddr != nil { previewBox = util.NewEventBox() } var renderer tui.Renderer @@ -653,7 +682,8 @@ margin: opts.Margin, padding: opts.Padding, unicode: opts.Unicode, - listenPort: opts.ListenPort, + listenAddr: opts.ListenAddr, + listenUnsafe: opts.Unsafe, borderShape: opts.BorderShape, borderWidth: 1, borderLabel: nil, @@ -686,7 +716,7 @@ initialPreviewOpts: opts.Preview, previewOpts: opts.Preview, previewer: previewer{0, []string{}, 0, false, true, disabledState, "", []bool{}}, - previewed: previewed{0, 0, 0, false}, + previewed: previewed{0, 0, 0, false, false, false, false}, previewBox: previewBox, eventBox: eventBox, mutex: sync.Mutex{}, @@ -742,8 +772,8 @@ _, t.hasLoadActions = t.keymap[tui.Load.AsEvent()] - if t.listenPort != nil { - err, port := startHttpServer(*t.listenPort, t.serverInputChan, t.serverOutputChan) + if t.listenAddr != nil { + err, port := startHttpServer(*t.listenAddr, t.serverInputChan, t.serverOutputChan) if err != nil { errorExit(err.Error()) } @@ -1301,10 +1331,6 @@ if previewOpts.hidden { return } - // Put scrollbar closer to the right border for consistent look - if t.borderShape.HasRight() { - width++ - } if previewOpts.position == posUp { t.window = t.tui.NewWindow( marginInt[0]+pheight, marginInt[3], width, height-pheight, false, noBorder) @@ -1933,11 +1959,21 @@ } func (t *Terminal) renderPreviewArea(unchanged bool) { - if unchanged { + if t.previewed.wipe && t.previewed.version != t.previewer.version { + t.previewed.wipe = false + t.pwindow.Erase() + } else if unchanged { t.pwindow.MoveAndClear(0, 0) // Clear scroll offset display } else { t.previewed.filled = false - t.pwindow.Erase() + // We don't erase the window here to avoid flickering during scroll. + // However, tcell renderer uses double-buffering technique and there's no + // flickering. So we just erase the window and make the rest of the code + // simpler. + if !t.pwindow.EraseMaybe() { + t.pwindow.DrawBorder() + t.pwindow.Move(0, 0) + } } height := t.pwindow.Height() @@ -1967,10 +2003,32 @@ t.renderPreviewScrollbar(headerLines, barLength, barStart) } +func (t *Terminal) makeImageBorder(width int, top bool) string { + tl := "â" + tr := "â" + v := "â" + h := "â" + if !t.unicode { + tl = "+" + tr = "+" + h = "-" + v = "|" + } + repeat := util.Max(0, width-2) + if top { + return tl + strings.Repeat(h, repeat) + tr + } + return v + strings.Repeat(" ", repeat) + v +} + func (t *Terminal) renderPreviewText(height int, lines []string, lineNo int, unchanged bool) { maxWidth := t.pwindow.Width() var ansi *ansiState spinnerRedraw := t.pwindow.Y() == 0 + wiped := false + image := false + wireframe := false +Loop: for _, line := range lines { var lbg tui.Color = -1 if ansi != nil { @@ -1988,16 +2046,76 @@ t.previewer.scrollable = true break } else if lineNo >= 0 { + x := t.pwindow.X() + y := t.pwindow.Y() if spinnerRedraw && lineNo > 0 { spinnerRedraw = false - y := t.pwindow.Y() - x := t.pwindow.X() t.renderPreviewSpinner() t.pwindow.Move(y, x) } - for _, passThrough := range passThroughs { + for idx, passThrough := range passThroughs { + // Handling Sixel/iTerm image + requiredLines := 0 + isSixel := strings.HasPrefix(passThrough, "\x1bP") + isItermImage := strings.HasPrefix(passThrough, "\x1b]1337;") + isImage := isSixel || isItermImage + if isImage { + t.previewed.wipe = true + // NOTE: We don't have a good way to get the height of an iTerm image, + // so we assume that it requires the full height of the preview + // window. + requiredLines = height + + if isSixel && t.termSize.PxHeight > 0 { + rows := strings.Count(passThrough, "-") + requiredLines = int(math.Ceil(float64(rows*6*t.termSize.Lines) / float64(t.termSize.PxHeight))) + } + } + + // Render wireframe when the image cannot be displayed entirely + if requiredLines > 0 && y+requiredLines > height { + top := true + for ; y < height; y++ { + t.pwindow.MoveAndClear(y, 0) + t.pwindow.CFill(tui.ColPreview.Fg(), tui.ColPreview.Bg(), tui.AttrRegular, t.makeImageBorder(maxWidth, top)) + top = false + } + wireframe = true + t.previewed.filled = true + t.previewer.scrollable = true + break Loop + } + + // Clear previous wireframe or any other text + if (t.previewed.wireframe || isImage && !t.previewed.image) && !wiped { + wiped = true + for i := y + 1; i < height; i++ { + t.pwindow.MoveAndClear(i, 0) + } + } + image = image || isImage + if idx == 0 { + t.pwindow.MoveAndClear(y, x) + } else { + t.pwindow.Move(y, x) + } t.tui.PassThrough(passThrough) + + if requiredLines > 0 { + if y+requiredLines == height { + t.pwindow.Move(height-1, maxWidth-1) + t.previewed.filled = true + break Loop + } else { + t.pwindow.MoveAndClear(y+requiredLines, 0) + } + } } + + if len(passThroughs) > 0 && len(line) == 0 { + continue + } + var fillRet tui.FillReturn prefixWidth := 0 _, _, ansi = extractColor(line, ansi, func(str string, ansi *ansiState) bool { @@ -2038,6 +2156,8 @@ } lineNo++ } + t.previewed.image = image + t.previewed.wireframe = wireframe } func (t *Terminal) renderPreviewScrollbar(yoff int, barLength int, barStart int) { @@ -2085,7 +2205,7 @@ unchanged := (t.previewed.filled || numLines == t.previewed.numLines) && t.previewer.version == t.previewed.version && t.previewer.offset == t.previewed.offset - t.previewer.scrollable = t.previewer.offset > 0 || numLines > height + t.previewer.scrollable = t.previewer.offset > t.previewOpts.headerLines || numLines > height t.renderPreviewArea(unchanged) t.renderPreviewSpinner() t.previewed.numLines = numLines @@ -2571,6 +2691,19 @@ t.killPreview(exitCancel) } +func (t *Terminal) pwindowSize() tui.TermSize { + if t.pwindow == nil { + return tui.TermSize{} + } + size := tui.TermSize{Lines: t.pwindow.Height(), Columns: t.pwindow.Width()} + + if t.termSize.PxWidth > 0 { + size.PxWidth = size.Columns * t.termSize.PxWidth / t.termSize.Columns + size.PxHeight = size.Lines * t.termSize.PxHeight / t.termSize.Lines + } + return size +} + // Loop is called to start Terminal I/O func (t *Terminal) Loop() { // prof := profile.Start(profile.ProfilePath("/tmp/")) @@ -2622,12 +2755,13 @@ go func() { for { <-resizeChan - t.reqBox.Set(reqFullRedraw, nil) + t.reqBox.Set(reqResize, nil) } }() t.mutex.Lock() t.initFunc() + t.termSize = t.tui.Size() t.resizeWindows(false) t.printPrompt() t.printInfo() @@ -2660,7 +2794,7 @@ for { var items []*Item var commandTemplate string - var pwindow tui.Window + var pwindowSize tui.TermSize initialOffset := 0 t.previewBox.Wait(func(events *util.Events) { for req, value := range *events { @@ -2670,7 +2804,7 @@ commandTemplate = request.template initialOffset = request.scrollOffset items = request.list - pwindow = request.pwindow + pwindowSize = request.pwindowSize } } events.Clear() @@ -2682,14 +2816,15 @@ command := t.replacePlaceholder(commandTemplate, false, string(query), items) cmd := util.ExecCommand(command, true) env := t.environ() - if pwindow != nil { - height := pwindow.Height() - lines := fmt.Sprintf("LINES=%d", height) - columns := fmt.Sprintf("COLUMNS=%d", pwindow.Width()) + if pwindowSize.Lines > 0 { + lines := fmt.Sprintf("LINES=%d", pwindowSize.Lines) + columns := fmt.Sprintf("COLUMNS=%d", pwindowSize.Columns) env = append(env, lines) env = append(env, "FZF_PREVIEW_"+lines) env = append(env, columns) env = append(env, "FZF_PREVIEW_"+columns) + env = append(env, fmt.Sprintf("FZF_PREVIEW_TOP=%d", t.tui.Top()+t.pwindow.Top())) + env = append(env, fmt.Sprintf("FZF_PREVIEW_LEFT=%d", t.pwindow.Left())) } cmd.Env = env @@ -2817,7 +2952,7 @@ if len(command) > 0 && t.canPreview() { _, list := t.buildPlusList(command, false) t.cancelPreview() - t.previewBox.Set(reqPreviewEnqueue, previewRequest{command, t.pwindow, t.evaluateScrollOffset(), list}) + t.previewBox.Set(reqPreviewEnqueue, previewRequest{command, t.pwindowSize(), t.evaluateScrollOffset(), list}) } } @@ -2885,7 +3020,10 @@ case reqReinit: t.tui.Resume(t.fullscreen, t.sigstop) t.redraw() - case reqFullRedraw: + case reqResize, reqFullRedraw: + if req == reqResize { + t.termSize = t.tui.Size() + } wasHidden := t.pwindow == nil t.redraw() if wasHidden && t.hasPreviewWindow() { @@ -2974,8 +3112,18 @@ select { case event = <-t.eventChan: needBarrier = !event.Is(tui.Load, tui.One, tui.Zero) - case actions = <-t.serverInputChan: + case serverActions := <-t.serverInputChan: event = tui.Invalid.AsEvent() + if t.listenAddr == nil || t.listenAddr.IsLocal() || t.listenUnsafe { + actions = serverActions + } else { + for _, action := range serverActions { + if !processExecution(action.t) { + actions = append(actions, action) + } + } + } + needBarrier = false } } @@ -3102,8 +3250,12 @@ if valid { t.cancelPreview() t.previewBox.Set(reqPreviewEnqueue, - previewRequest{t.previewOpts.command, t.pwindow, t.evaluateScrollOffset(), list}) + previewRequest{t.previewOpts.command, t.pwindowSize(), t.evaluateScrollOffset(), list}) } + } else { + // Discard the preview content so that it won't accidentally appear + // when preview window is re-enabled and previewDelay is triggered + t.previewer.lines = nil } } case actTogglePreviewWrap: @@ -3158,6 +3310,7 @@ } case actBeginningOfLine: t.cx = 0 + t.xoffset = 0 case actBackwardChar: if t.cx > 0 { t.cx-- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/src/terminal_unix.go new/fzf-0.44.0/src/terminal_unix.go --- old/fzf-0.43.0/src/terminal_unix.go 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/src/terminal_unix.go 2023-11-12 14:08:08.000000000 +0100 @@ -7,6 +7,8 @@ "os/signal" "strings" "syscall" + + "golang.org/x/sys/unix" ) func notifyOnResize(resizeChan chan<- os.Signal) { @@ -14,7 +16,12 @@ } func notifyStop(p *os.Process) { - p.Signal(syscall.SIGSTOP) + pid := p.Pid + pgid, err := unix.Getpgid(pid) + if err == nil { + pid = pgid * -1 + } + unix.Kill(pid, syscall.SIGSTOP) } func notifyOnCont(resizeChan chan<- os.Signal) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/src/tui/dummy.go new/fzf-0.44.0/src/tui/dummy.go --- old/fzf-0.43.0/src/tui/dummy.go 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/src/tui/dummy.go 2023-11-12 14:08:08.000000000 +0100 @@ -38,8 +38,10 @@ func (r *FullscreenRenderer) NeedScrollbarRedraw() bool { return false } func (r *FullscreenRenderer) Refresh() {} func (r *FullscreenRenderer) Close() {} +func (r *FullscreenRenderer) Size() TermSize { return TermSize{} } func (r *FullscreenRenderer) GetChar() Event { return Event{} } +func (r *FullscreenRenderer) Top() int { return 0 } func (r *FullscreenRenderer) MaxX() int { return 0 } func (r *FullscreenRenderer) MaxY() int { return 0 } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/src/tui/light.go new/fzf-0.44.0/src/tui/light.go --- old/fzf-0.43.0/src/tui/light.go 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/src/tui/light.go 2023-11-12 14:08:08.000000000 +0100 @@ -32,8 +32,7 @@ var offsetRegexpBegin *regexp.Regexp = regexp.MustCompile("^\x1b\\[[0-9]+;[0-9]+R") func (r *LightRenderer) PassThrough(str string) { - r.queued.WriteString(str) - r.flush() + r.queued.WriteString("\x1b7" + str + "\x1b8") } func (r *LightRenderer) stderr(str string) { @@ -403,7 +402,7 @@ return Event{F3, 0, nil} case 'S': return Event{F4, 0, nil} - case '1', '2', '3', '4', '5', '6': + case '1', '2', '3', '4', '5', '6', '7', '8': if len(r.buffer) < 4 { return Event{Invalid, 0, nil} } @@ -454,6 +453,10 @@ return Event{PgUp, 0, nil} case '6': return Event{PgDn, 0, nil} + case '7': + return Event{Home, 0, nil} + case '8': + return Event{End, 0, nil} case '1': switch r.buffer[3] { case '~': @@ -721,6 +724,10 @@ r.restoreTerminal() } +func (r *LightRenderer) Top() int { + return r.yoffset +} + func (r *LightRenderer) MaxX() int { return r.width } @@ -756,6 +763,10 @@ return w } +func (w *LightWindow) DrawBorder() { + w.drawBorder(false) +} + func (w *LightWindow) DrawHBorder() { w.drawBorder(true) } @@ -1088,14 +1099,21 @@ } func (w *LightWindow) FinishFill() { - w.MoveAndClear(w.posy, w.posx) + if w.posy < w.height { + w.MoveAndClear(w.posy, w.posx) + } for y := w.posy + 1; y < w.height; y++ { w.MoveAndClear(y, 0) } } func (w *LightWindow) Erase() { - w.drawBorder(false) - // We don't erase the window here to avoid flickering during scroll + w.DrawBorder() + w.Move(0, 0) + w.FinishFill() w.Move(0, 0) } + +func (w *LightWindow) EraseMaybe() bool { + return false +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/src/tui/light_unix.go new/fzf-0.44.0/src/tui/light_unix.go --- old/fzf-0.43.0/src/tui/light_unix.go 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/src/tui/light_unix.go 2023-11-12 14:08:08.000000000 +0100 @@ -10,6 +10,7 @@ "syscall" "github.com/junegunn/fzf/src/util" + "golang.org/x/sys/unix" "golang.org/x/term" ) @@ -108,3 +109,11 @@ } return int(b[0]), true } + +func (r *LightRenderer) Size() TermSize { + ws, err := unix.IoctlGetWinsize(int(r.ttyin.Fd()), unix.TIOCGWINSZ) + if err != nil { + return TermSize{} + } + return TermSize{int(ws.Row), int(ws.Col), int(ws.Xpixel), int(ws.Ypixel)} +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/src/tui/light_windows.go new/fzf-0.44.0/src/tui/light_windows.go --- old/fzf-0.43.0/src/tui/light_windows.go 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/src/tui/light_windows.go 2023-11-12 14:08:08.000000000 +0100 @@ -110,16 +110,24 @@ return windows.SetConsoleMode(windows.Handle(r.outHandle), r.origStateOutput) } -func (r *LightRenderer) updateTerminalSize() { +func (r *LightRenderer) Size() TermSize { + var w, h int var bufferInfo windows.ConsoleScreenBufferInfo if err := windows.GetConsoleScreenBufferInfo(windows.Handle(r.outHandle), &bufferInfo); err != nil { - r.width = getEnv("COLUMNS", defaultWidth) - r.height = r.maxHeightFunc(getEnv("LINES", defaultHeight)) + w = getEnv("COLUMNS", defaultWidth) + h = r.maxHeightFunc(getEnv("LINES", defaultHeight)) } else { - r.width = int(bufferInfo.Window.Right - bufferInfo.Window.Left) - r.height = r.maxHeightFunc(int(bufferInfo.Window.Bottom - bufferInfo.Window.Top)) + w = int(bufferInfo.Window.Right - bufferInfo.Window.Left) + h = r.maxHeightFunc(int(bufferInfo.Window.Bottom - bufferInfo.Window.Top)) } + return TermSize{h, w, 0, 0} +} + +func (r *LightRenderer) updateTerminalSize() { + size := r.Size() + r.width = size.Columns + r.height = size.Lines } func (r *LightRenderer) findOffset() (row int, col int) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/src/tui/tcell.go new/fzf-0.44.0/src/tui/tcell.go --- old/fzf-0.43.0/src/tui/tcell.go 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/src/tui/tcell.go 2023-11-12 14:08:08.000000000 +0100 @@ -100,7 +100,7 @@ func (r *FullscreenRenderer) PassThrough(str string) { // No-op - // https://github.com/gdamore/tcell/issues/363#issuecomment-680665073 + // https://github.com/gdamore/tcell/pull/650#issuecomment-1806442846 } func (r *FullscreenRenderer) Resize(maxHeightFunc func(int) int) {} @@ -172,6 +172,10 @@ initTheme(r.theme, r.defaultTheme(), r.forceBlack) } +func (r *FullscreenRenderer) Top() int { + return 0 +} + func (r *FullscreenRenderer) MaxX() int { ncols, _ := _screen.Size() return int(ncols) @@ -203,6 +207,12 @@ // noop } +// TODO: Pixel width and height not implemented +func (r *FullscreenRenderer) Size() TermSize { + cols, lines := _screen.Size() + return TermSize{lines, cols, 0, 0} +} + func (r *FullscreenRenderer) GetChar() Event { ev := _screen.PollEvent() switch ev := ev.(type) { @@ -541,9 +551,15 @@ } func (w *TcellWindow) Erase() { + w.drawBorder(false) fill(w.left-1, w.top, w.width+1, w.height-1, w.normal, ' ') } +func (w *TcellWindow) EraseMaybe() bool { + w.Erase() + return true +} + func (w *TcellWindow) Enclose(y int, x int) bool { return x >= w.left && x < (w.left+w.width) && y >= w.top && y < (w.top+w.height) @@ -692,6 +708,10 @@ return w.fillString(str, NewColorPair(fg, bg, a)) } +func (w *TcellWindow) DrawBorder() { + w.drawBorder(false) +} + func (w *TcellWindow) DrawHBorder() { w.drawBorder(true) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/src/tui/tui.go new/fzf-0.44.0/src/tui/tui.go --- old/fzf-0.43.0/src/tui/tui.go 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/src/tui/tui.go 2023-11-12 14:08:08.000000000 +0100 @@ -473,6 +473,13 @@ bottomRight: ' '} } +type TermSize struct { + Lines int + Columns int + PxWidth int + PxHeight int +} + type Renderer interface { Init() Resize(maxHeightFunc func(int) int) @@ -487,9 +494,12 @@ GetChar() Event + Top() int MaxX() int MaxY() int + Size() TermSize + NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window } @@ -499,6 +509,7 @@ Width() int Height() int + DrawBorder() DrawHBorder() Refresh() FinishFill() @@ -515,6 +526,7 @@ Fill(text string) FillReturn CFill(fg Color, bg Color, attr Attr, text string) FillReturn Erase() + EraseMaybe() bool } type FullscreenRenderer struct { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.43.0/typos.toml new/fzf-0.44.0/typos.toml --- old/fzf-0.43.0/typos.toml 2023-10-14 18:56:05.000000000 +0200 +++ new/fzf-0.44.0/typos.toml 2023-11-12 14:08:08.000000000 +0100 @@ -4,6 +4,7 @@ fo = "fo" enew = "enew" tabe = "tabe" +Iterm = "Iterm" [files] extend-exclude = ["README.md"] ++++++ vendor.tar.zst ++++++ Binary files /var/tmp/diff_new_pack.5bIbgx/_old and /var/tmp/diff_new_pack.5bIbgx/_new differ