mirror of
https://github.com/junegunn/fzf.git
synced 2025-11-14 06:13:47 -05:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40d934e378 | ||
|
|
e95d82748f | ||
|
|
30bd0b53db | ||
|
|
1893eca41a | ||
|
|
82067463b8 | ||
|
|
ce9c51d399 | ||
|
|
96176476f3 |
10
CHANGELOG.md
10
CHANGELOG.md
@@ -1,6 +1,16 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
0.11.3
|
||||
------
|
||||
|
||||
- Graceful exit on SIGTERM (#482)
|
||||
- `$SHELL` instead of `sh` for `execute` action and `$FZF_DEFAULT_COMMAND` (#481)
|
||||
- Changes in fuzzy completion API
|
||||
- [`_fzf_compgen_{path,dir}`](https://github.com/junegunn/fzf/commit/9617647)
|
||||
- [`_fzf_complete_COMMAND_post`](https://github.com/junegunn/fzf/commit/8206746)
|
||||
for post-processing
|
||||
|
||||
0.11.2
|
||||
------
|
||||
|
||||
|
||||
@@ -259,6 +259,14 @@ export FZF_COMPLETION_TRIGGER='~~'
|
||||
|
||||
# Options to fzf command
|
||||
export FZF_COMPLETION_OPTS='+c -x'
|
||||
|
||||
# Use ag instead of the default find command for listing candidates.
|
||||
# - The first argument to the function is the base path to start traversal
|
||||
# - Note that ag only lists files not directories
|
||||
# - See the source code (completion.{bash,zsh}) for the details.
|
||||
_fzf_compgen_path() {
|
||||
ag -g "" "$1"
|
||||
}
|
||||
```
|
||||
|
||||
#### Supported commands
|
||||
|
||||
4
install
4
install
@@ -2,8 +2,8 @@
|
||||
|
||||
set -u
|
||||
|
||||
[[ "$@" =~ --pre ]] && version=0.11.2 pre=1 ||
|
||||
version=0.11.2 pre=0
|
||||
[[ "$@" =~ --pre ]] && version=0.11.3 pre=1 ||
|
||||
version=0.11.3 pre=0
|
||||
|
||||
auto_completion=
|
||||
key_bindings=
|
||||
|
||||
@@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
..
|
||||
.TH fzf 1 "Jan 2016" "fzf 0.11.2" "fzf - a command-line fuzzy finder"
|
||||
.TH fzf 1 "Feb 2016" "fzf 0.11.3" "fzf - a command-line fuzzy finder"
|
||||
|
||||
.SH NAME
|
||||
fzf - a command-line fuzzy finder
|
||||
|
||||
@@ -10,6 +10,26 @@
|
||||
# - $FZF_COMPLETION_TRIGGER (default: '**')
|
||||
# - $FZF_COMPLETION_OPTS (default: empty)
|
||||
|
||||
# To use custom commands instead of find, override _fzf_compgen_{path,dir}
|
||||
if ! declare -f _fzf_compgen_path > /dev/null; then
|
||||
_fzf_compgen_path() {
|
||||
echo "$1"
|
||||
\find -L "$1" \
|
||||
-name .git -prune -o -name .svn -prune -o \( -type d -o -type f -o -type l \) \
|
||||
-a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@'
|
||||
}
|
||||
fi
|
||||
|
||||
if ! declare -f _fzf_compgen_dir > /dev/null; then
|
||||
_fzf_compgen_dir() {
|
||||
\find -L "$1" \
|
||||
-name .git -prune -o -name .svn -prune -o -type d \
|
||||
-a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@'
|
||||
}
|
||||
fi
|
||||
|
||||
###########################################################
|
||||
|
||||
_fzf_orig_completion_filter() {
|
||||
sed 's/^\(.*-F\) *\([^ ]*\).* \([^ ]*\)$/export _fzf_orig_completion_\3="\1 %s \3 #\2";/' |
|
||||
awk -F= '{gsub(/[^a-z0-9_= ;]/, "_", $1); print $1"="$2}'
|
||||
@@ -113,7 +133,7 @@ __fzf_generic_path_completion() {
|
||||
[ -z "$dir" ] && dir='.'
|
||||
[ "$dir" != "/" ] && dir="${dir/%\//}"
|
||||
tput sc
|
||||
matches=$(\find -L "$dir" $1 -a -not -path "$dir" -print 2> /dev/null | sed 's@^\./@@' | $fzf $FZF_COMPLETION_OPTS $2 -q "$leftover" | while read item; do
|
||||
matches=$(eval "$1 $(printf %q "$dir")" | $fzf $FZF_COMPLETION_OPTS $2 -q "$leftover" | while read item; do
|
||||
printf "%q$3 " "$item"
|
||||
done)
|
||||
matches=${matches% }
|
||||
@@ -136,15 +156,10 @@ __fzf_generic_path_completion() {
|
||||
fi
|
||||
}
|
||||
|
||||
_fzf_feed_fifo() (
|
||||
rm -f "$fifo"
|
||||
mkfifo "$fifo"
|
||||
cat <&0 > "$fifo" &
|
||||
)
|
||||
|
||||
_fzf_complete() {
|
||||
local fifo cur selected trigger cmd fzf
|
||||
fifo="${TMPDIR:-/tmp}/fzf-complete-fifo-$$"
|
||||
local cur selected trigger cmd fzf post
|
||||
post="$(caller 0 | awk '{print $2}')_post"
|
||||
type -t $post > /dev/null 2>&1 || post=cat
|
||||
[ ${FZF_TMUX:-1} -eq 1 ] && fzf="fzf-tmux -d ${FZF_TMUX_HEIGHT:-40%}" || fzf="fzf"
|
||||
|
||||
cmd=$(echo ${COMP_WORDS[0]} | sed 's/[^a-z0-9_=]/_/g')
|
||||
@@ -153,12 +168,10 @@ _fzf_complete() {
|
||||
if [[ ${cur} == *"$trigger" ]]; then
|
||||
cur=${cur:0:${#cur}-${#trigger}}
|
||||
|
||||
_fzf_feed_fifo "$fifo"
|
||||
tput sc
|
||||
selected=$(eval "cat '$fifo' | $fzf $FZF_COMPLETION_OPTS $1 -q '$cur'" | tr '\n' ' ')
|
||||
selected=$(cat | $fzf $FZF_COMPLETION_OPTS $1 -q "$cur" | $post | tr '\n' ' ')
|
||||
selected=${selected% } # Strip trailing space not to repeat "-o nospace"
|
||||
tput rc
|
||||
rm -f "$fifo"
|
||||
|
||||
if [ -n "$selected" ]; then
|
||||
COMPREPLY=("$selected")
|
||||
@@ -171,21 +184,16 @@ _fzf_complete() {
|
||||
}
|
||||
|
||||
_fzf_path_completion() {
|
||||
__fzf_generic_path_completion \
|
||||
"-name .git -prune -o -name .svn -prune -o ( -type d -o -type f -o -type l )" \
|
||||
"-m" "" "$@"
|
||||
__fzf_generic_path_completion _fzf_compgen_path "-m" "" "$@"
|
||||
}
|
||||
|
||||
# Deprecated. No file only completion.
|
||||
_fzf_file_completion() {
|
||||
__fzf_generic_path_completion \
|
||||
"-name .git -prune -o -name .svn -prune -o ( -type f -o -type l )" \
|
||||
"-m" "" "$@"
|
||||
_fzf_path_completion "$@"
|
||||
}
|
||||
|
||||
_fzf_dir_completion() {
|
||||
__fzf_generic_path_completion \
|
||||
"-name .git -prune -o -name .svn -prune -o -type d" \
|
||||
"" "/" "$@"
|
||||
__fzf_generic_path_completion _fzf_compgen_dir "" "/" "$@"
|
||||
}
|
||||
|
||||
_fzf_complete_kill() {
|
||||
@@ -239,13 +247,12 @@ _fzf_complete_unalias() {
|
||||
# fzf options
|
||||
complete -o default -F _fzf_opts_completion fzf
|
||||
|
||||
d_cmds="cd pushd rmdir"
|
||||
f_cmds="
|
||||
d_cmds="${FZF_COMPLETION_DIR_COMMANDS:-cd pushd rmdir}"
|
||||
a_cmds="
|
||||
awk cat diff diff3
|
||||
emacs emacsclient ex file ftp g++ gcc gvim head hg java
|
||||
javac ld less more mvim nvim patch perl python ruby
|
||||
sed sftp sort source tail tee uniq vi view vim wc xdg-open"
|
||||
a_cmds="
|
||||
sed sftp sort source tail tee uniq vi view vim wc xdg-open
|
||||
basename bunzip2 bzip2 chmod chown curl cp dirname du
|
||||
find git grep gunzip gzip hg jar
|
||||
ln ls mv open rm rsync scp
|
||||
@@ -253,11 +260,11 @@ a_cmds="
|
||||
x_cmds="kill ssh telnet unset unalias export"
|
||||
|
||||
# Preserve existing completion
|
||||
if [ "$_fzf_completion_loaded" != '0.10.8' ]; then
|
||||
if [ "$_fzf_completion_loaded" != '0.11.3' ]; then
|
||||
# Really wish I could use associative array but OSX comes with bash 3.2 :(
|
||||
eval $(complete | \grep '\-F' | \grep -v _fzf_ |
|
||||
\grep -E " ($(echo $d_cmds $f_cmds $a_cmds $x_cmds | sed 's/ /|/g' | sed 's/+/\\+/g'))$" | _fzf_orig_completion_filter)
|
||||
export _fzf_completion_loaded=0.10.8
|
||||
\grep -E " ($(echo $d_cmds $a_cmds $x_cmds | sed 's/ /|/g' | sed 's/+/\\+/g'))$" | _fzf_orig_completion_filter)
|
||||
export _fzf_completion_loaded=0.11.3
|
||||
fi
|
||||
|
||||
if type _completion_loader > /dev/null 2>&1; then
|
||||
@@ -278,21 +285,16 @@ _fzf_defc() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Directory
|
||||
for cmd in $d_cmds; do
|
||||
_fzf_defc "$cmd" _fzf_dir_completion "-o nospace -o plusdirs"
|
||||
done
|
||||
|
||||
# File
|
||||
for cmd in $f_cmds; do
|
||||
_fzf_defc "$cmd" _fzf_file_completion "-o default -o bashdefault"
|
||||
done
|
||||
|
||||
# Anything
|
||||
for cmd in $a_cmds; do
|
||||
_fzf_defc "$cmd" _fzf_path_completion "-o default -o bashdefault"
|
||||
done
|
||||
|
||||
# Directory
|
||||
for cmd in $d_cmds; do
|
||||
_fzf_defc "$cmd" _fzf_dir_completion "-o nospace -o plusdirs"
|
||||
done
|
||||
|
||||
unset _fzf_defc
|
||||
|
||||
# Kill completion
|
||||
@@ -307,4 +309,4 @@ complete -F _fzf_complete_unset -o default -o bashdefault unset
|
||||
complete -F _fzf_complete_export -o default -o bashdefault export
|
||||
complete -F _fzf_complete_unalias -o default -o bashdefault unalias
|
||||
|
||||
unset cmd d_cmds f_cmds a_cmds x_cmds
|
||||
unset cmd d_cmds a_cmds x_cmds
|
||||
|
||||
@@ -10,12 +10,32 @@
|
||||
# - $FZF_COMPLETION_TRIGGER (default: '**')
|
||||
# - $FZF_COMPLETION_OPTS (default: empty)
|
||||
|
||||
# To use custom commands instead of find, override _fzf_compgen_{path,dir}
|
||||
if ! declare -f _fzf_compgen_path > /dev/null; then
|
||||
_fzf_compgen_path() {
|
||||
echo "$1"
|
||||
\find -L "$1" \
|
||||
-name .git -prune -o -name .svn -prune -o \( -type d -o -type f -o -type l \) \
|
||||
-a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@'
|
||||
}
|
||||
fi
|
||||
|
||||
if ! declare -f _fzf_compgen_dir > /dev/null; then
|
||||
_fzf_compgen_dir() {
|
||||
\find -L "$1" \
|
||||
-name .git -prune -o -name .svn -prune -o -type d \
|
||||
-a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@'
|
||||
}
|
||||
fi
|
||||
|
||||
###########################################################
|
||||
|
||||
__fzf_generic_path_completion() {
|
||||
local base lbuf find_opts fzf_opts suffix tail fzf dir leftover matches nnm
|
||||
local base lbuf compgen fzf_opts suffix tail fzf dir leftover matches nnm
|
||||
# (Q) flag removes a quoting level: "foo\ bar" => "foo bar"
|
||||
base=${(Q)1}
|
||||
lbuf=$2
|
||||
find_opts=$3
|
||||
compgen=$3
|
||||
fzf_opts=$4
|
||||
suffix=$5
|
||||
tail=$6
|
||||
@@ -33,7 +53,7 @@ __fzf_generic_path_completion() {
|
||||
[ -z "$dir" ] && dir='.'
|
||||
[ "$dir" != "/" ] && dir="${dir/%\//}"
|
||||
dir=${~dir}
|
||||
matches=$(\find -L "$dir" ${=find_opts} -a -not -path "$dir" -print 2> /dev/null | sed 's@^\./@@' | ${=fzf} ${=FZF_COMPLETION_OPTS} ${=fzf_opts} -q "$leftover" | while read item; do
|
||||
matches=$(eval "$compgen $(printf %q "$dir")" | ${=fzf} ${=FZF_COMPLETION_OPTS} ${=fzf_opts} -q "$leftover" | while read item; do
|
||||
printf "%q$suffix " "$item"
|
||||
done)
|
||||
matches=${matches% }
|
||||
@@ -50,37 +70,29 @@ __fzf_generic_path_completion() {
|
||||
}
|
||||
|
||||
_fzf_path_completion() {
|
||||
__fzf_generic_path_completion "$1" "$2" \
|
||||
"-name .git -prune -o -name .svn -prune -o ( -type d -o -type f -o -type l )" \
|
||||
__fzf_generic_path_completion "$1" "$2" _fzf_compgen_path \
|
||||
"-m" "" " "
|
||||
}
|
||||
|
||||
_fzf_dir_completion() {
|
||||
__fzf_generic_path_completion "$1" "$2" \
|
||||
"-name .git -prune -o -name .svn -prune -o -type d" \
|
||||
__fzf_generic_path_completion "$1" "$2" _fzf_compgen_dir \
|
||||
"" "/" ""
|
||||
}
|
||||
|
||||
_fzf_feed_fifo() (
|
||||
rm -f "$fifo"
|
||||
mkfifo "$fifo"
|
||||
cat <&0 > "$fifo" &
|
||||
)
|
||||
|
||||
_fzf_complete() {
|
||||
local fifo fzf_opts lbuf fzf matches
|
||||
fifo="${TMPDIR:-/tmp}/fzf-complete-fifo-$$"
|
||||
local fzf_opts lbuf fzf matches post
|
||||
fzf_opts=$1
|
||||
lbuf=$2
|
||||
post="${funcstack[2]}_post"
|
||||
type $post > /dev/null 2>&1 || post=cat
|
||||
|
||||
[ ${FZF_TMUX:-1} -eq 1 ] && fzf="fzf-tmux -d ${FZF_TMUX_HEIGHT:-40%}" || fzf="fzf"
|
||||
|
||||
_fzf_feed_fifo "$fifo"
|
||||
matches=$(cat "$fifo" | ${=fzf} ${=FZF_COMPLETION_OPTS} ${=fzf_opts} -q "${(Q)prefix}" | tr '\n' ' ')
|
||||
matches=$(cat | ${=fzf} ${=FZF_COMPLETION_OPTS} ${=fzf_opts} -q "${(Q)prefix}" | $post | tr '\n' ' ')
|
||||
if [ -n "$matches" ]; then
|
||||
LBUFFER="$lbuf$matches"
|
||||
fi
|
||||
zle redisplay
|
||||
rm -f "$fifo"
|
||||
}
|
||||
|
||||
_fzf_complete_telnet() {
|
||||
@@ -145,7 +157,7 @@ fzf-completion() {
|
||||
zle redisplay
|
||||
# Trigger sequence given
|
||||
elif [ ${#tokens} -gt 1 -a "$tail" = "$trigger" ]; then
|
||||
d_cmds=(cd pushd rmdir)
|
||||
d_cmds=(${=FZF_COMPLETION_DIR_COMMANDS:-cd pushd rmdir})
|
||||
|
||||
[ -z "$trigger" ] && prefix=${tokens[-1]} || prefix=${tokens[-1]:0:-${#trigger}}
|
||||
[ -z "${tokens[-1]}" ] && lbuf=$LBUFFER || lbuf=${LBUFFER:0:-${#tokens[-1]}}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
const (
|
||||
// Current version
|
||||
version = "0.11.2"
|
||||
version = "0.11.3"
|
||||
|
||||
// Core
|
||||
coordinatorDelayMax time.Duration = 100 * time.Millisecond
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"bufio"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/junegunn/fzf/src/util"
|
||||
)
|
||||
@@ -59,7 +58,7 @@ func (r *Reader) readFromStdin() {
|
||||
}
|
||||
|
||||
func (r *Reader) readFromCommand(cmd string) {
|
||||
listCommand := exec.Command("sh", "-c", cmd)
|
||||
listCommand := util.ExecCommand(cmd)
|
||||
out, err := listCommand.StdoutPipe()
|
||||
if err != nil {
|
||||
return
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"regexp"
|
||||
"sort"
|
||||
@@ -720,7 +719,7 @@ func quoteEntry(entry string) string {
|
||||
|
||||
func executeCommand(template string, replacement string) {
|
||||
command := strings.Replace(template, "{}", replacement, -1)
|
||||
cmd := exec.Command("sh", "-c", command)
|
||||
cmd := util.ExecCommand(command)
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
@@ -734,7 +733,7 @@ func (t *Terminal) Loop() {
|
||||
<-t.startChan
|
||||
{ // Late initialization
|
||||
intChan := make(chan os.Signal, 1)
|
||||
signal.Notify(intChan, os.Interrupt, os.Kill)
|
||||
signal.Notify(intChan, os.Interrupt, os.Kill, syscall.SIGTERM)
|
||||
go func() {
|
||||
<-intChan
|
||||
t.reqBox.Set(reqQuit, nil)
|
||||
|
||||
@@ -5,6 +5,7 @@ import "C"
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
)
|
||||
@@ -126,3 +127,12 @@ func TrimLen(runes []rune) int {
|
||||
}
|
||||
return i - j + 1
|
||||
}
|
||||
|
||||
// ExecCommand executes the given command with $SHELL
|
||||
func ExecCommand(command string) *exec.Cmd {
|
||||
shell := os.Getenv("SHELL")
|
||||
if len(shell) == 0 {
|
||||
shell = "sh"
|
||||
}
|
||||
return exec.Command(shell, "-c", command)
|
||||
}
|
||||
|
||||
@@ -893,6 +893,22 @@ class TestGoFZF < TestBase
|
||||
File.unlink output rescue nil
|
||||
end
|
||||
|
||||
def test_execute_shell
|
||||
# Custom script to use as $SHELL
|
||||
output = tempname + '.out'
|
||||
File.unlink output rescue nil
|
||||
writelines tempname, ['#!/usr/bin/env bash', "echo $1 / $2 > #{output}"]
|
||||
system "chmod +x #{tempname}"
|
||||
|
||||
tmux.send_keys "echo foo | SHELL=#{tempname} fzf --bind 'enter:execute:{}bar'", :Enter
|
||||
tmux.until { |lines| lines[-2].include? '1/1' }
|
||||
tmux.send_keys :Enter
|
||||
tmux.send_keys 'C-c'
|
||||
assert_equal ['-c / "foo"bar'], File.readlines(output).map(&:chomp)
|
||||
ensure
|
||||
File.unlink output rescue nil
|
||||
end
|
||||
|
||||
def test_cycle
|
||||
tmux.send_keys "seq 8 | #{fzf :cycle}", :Enter
|
||||
tmux.until { |lines| lines[-2].include? '8/8' }
|
||||
@@ -1269,7 +1285,7 @@ module CompletionTest
|
||||
tmux.send_keys 'C-u'
|
||||
tmux.send_keys 'cat /tmp/fzf\ test/**', :Tab, pane: 0
|
||||
tmux.until(1) { |lines| lines.item_count > 0 }
|
||||
tmux.send_keys :Enter
|
||||
tmux.send_keys 'C-K', :Enter
|
||||
tmux.until do |lines|
|
||||
tmux.send_keys 'C-L'
|
||||
lines[-1].end_with?('/tmp/fzf\ test/foobar')
|
||||
@@ -1339,6 +1355,20 @@ module CompletionTest
|
||||
tmux.send_keys 'C-L'
|
||||
lines[-1] == "kill #{pid}"
|
||||
end
|
||||
|
||||
def test_custom_completion
|
||||
tmux.send_keys '_fzf_compgen_path() { echo "\$1"; seq 10; }', :Enter
|
||||
tmux.prepare
|
||||
tmux.send_keys 'ls /tmp/**', :Tab, pane: 0
|
||||
tmux.until(1) { |lines| lines.item_count == 11 }
|
||||
tmux.send_keys :BTab, :BTab, :BTab
|
||||
tmux.until(1) { |lines| lines[-2].include? '(3)' }
|
||||
tmux.send_keys :Enter
|
||||
tmux.until do |lines|
|
||||
tmux.send_keys 'C-L'
|
||||
lines[-1] == "ls /tmp 1 2"
|
||||
end
|
||||
end
|
||||
ensure
|
||||
Process.kill 'KILL', pid.to_i rescue nil if pid
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user