Compare commits

..

18 Commits
0.8.6 ... 0.8.7

Author SHA1 Message Date
Junegunn Choi
6ee811ea03 Update version 2014-08-17 02:21:34 +09:00
Junegunn Choi
d5e7303a25 Change --nth option for CTRL-R key binding (#90)
Remove `1` from --nth option. With the change you can no more use `$`
anchor to match the tail of a command index. But it makes search
around 15% faster.

    jg@jg:~> time cat history | fzf +s -n..,1,2.. -f fzf > /dev/nul
    real    0m2.929s
    user    0m2.766s
    sys     0m0.154s

    jg@jg:~> time cat history | fzf +s -n2..,.. -f fzf > /dev/null
    real    0m2.535s
    user    0m2.422s
    sys     0m0.112s
2014-08-17 00:29:57 +09:00
Junegunn Choi
2924fd3e23 Add regression test case for #91 2014-08-17 00:22:22 +09:00
Junegunn Choi
75b44aac13 Ignore UTF-8 Error (#91) 2014-08-16 19:52:56 +09:00
Junegunn Choi
86c73105ee Improve performance of --nth option (#90 contd.) 2014-08-15 04:01:37 +09:00
Junegunn Choi
2d00abc7cb Improve performance of --nth option (#90) 2014-08-15 03:02:07 +09:00
Junegunn Choi
1e07b3b1c2 [vim] Apply FZF_DEFAULT_{OPTS,COMMAND} when using tmux splits (#87)
Fixed escaping bug of the previous commit
2014-08-08 03:23:24 +09:00
Junegunn Choi
4313c1c25c Revert "[vim] Apply FZF_DEFAULT_{OPTS,COMMAND} when using tmux splits (#87)"
This reverts commit cc9938d4c9.
2014-08-08 03:13:40 +09:00
Junegunn Choi
cc9938d4c9 [vim] Apply FZF_DEFAULT_{OPTS,COMMAND} when using tmux splits (#87) 2014-08-08 02:45:11 +09:00
Junegunn Choi
a54784cd53 Display 'gem install curses' when curses cannot be loaded 2014-07-27 01:08:30 +09:00
Junegunn Choi
22989b0488 Update version number 2014-07-18 13:21:15 +09:00
Junegunn Choi
892aa1e78b Merge pull request #80 from wilywampa/master
Add control + left/right key mappings
2014-07-18 13:20:42 +09:00
Jacob Niehus
b9ab7d2413 Add control + left/right key mappings 2014-07-17 21:09:21 -07:00
Junegunn Choi
69b2a0a733 Suppress error message from bash-completion 2014-07-18 00:25:12 +09:00
Junegunn Choi
13cd4ed546 Handle dynamically loaded completion functions (#79)
On Ubuntu/Debian, completion functions can be dynamically loaded via
_completion_loader. Since those functions are not visible when
fzf-completion.bash is loaded, we need this special hack to make it
possible to fail back to the original completion function when trigger
sequence is not found.
2014-07-18 00:22:49 +09:00
Sencer Selcuk
7261d3afcd allow installation with sudo privileges 2014-07-15 12:12:05 +09:00
Junegunn Choi
84fc73ad9c [bash-completion] unset / unalias / export 2014-07-14 12:48:31 +09:00
Junegunn Choi
4103f5c3cc [bash-completion] Remove -E option from sed
Old versions of sed does not have -E option
2014-07-11 01:09:06 +09:00
6 changed files with 167 additions and 68 deletions

View File

@@ -270,6 +270,14 @@ ssh **<TAB>
telnet **<TAB> telnet **<TAB>
``` ```
#### Environment variables / Aliases
```sh
unset **<TAB>
export **<TAB>
unalias **<TAB>
```
#### Settings #### Settings
```sh ```sh

42
fzf
View File

@@ -7,7 +7,7 @@
# / __/ / /_/ __/ # / __/ / /_/ __/
# /_/ /___/_/ Fuzzy finder for your shell # /_/ /___/_/ Fuzzy finder for your shell
# #
# Version: 0.8.6 (Jun 30, 2014) # Version: 0.8.7 (Aug 17, 2014)
# #
# Author: Junegunn Choi # Author: Junegunn Choi
# URL: https://github.com/junegunn/fzf # URL: https://github.com/junegunn/fzf
@@ -36,8 +36,13 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
require 'thread' begin
require 'curses' require 'curses'
rescue LoadError
$stderr.puts 'curses gem is not installed. Try `gem install curses`.'
exit 1
end
require 'thread'
require 'set' require 'set'
unless String.method_defined? :force_encoding unless String.method_defined? :force_encoding
@@ -361,7 +366,8 @@ class FZF
end if str end if str
end end
def addstr_safe str def addstr_safe str
C.addstr str.gsub("\0", '') str = str.gsub("\0", '') rescue str
C.addstr str
end end
def print_input def print_input
@@ -882,6 +888,8 @@ class FZF
case read_nbs case read_nbs
when [59, 50, 68] then ctrl(:a) when [59, 50, 68] then ctrl(:a)
when [59, 50, 67] then ctrl(:e) when [59, 50, 67] then ctrl(:e)
when [59, 53, 68] then :alt_b
when [59, 53, 67] then :alt_f
when [126] then ctrl(:a) when [126] then ctrl(:a)
end end
when 52 then read_nb; ctrl(:e) when 52 then read_nb; ctrl(:e)
@@ -1095,26 +1103,32 @@ class FZF
def tokenize str def tokenize str
@tokens_cache[str] ||= @tokens_cache[str] ||=
begin
unless @delim unless @delim
# AWK default # AWK default
prefix_length = str[/^\s+/].length rescue 0 prefix_length = (str.index(/\S/) || 0) rescue 0
[prefix_length, (str.strip.scan(/\S+\s*/) rescue [])] tokens = str.scan(/\S+\s*/) rescue []
else else
prefix_length = 0 prefix_length = 0
[prefix_length, (str.scan(@delim) rescue [])] tokens = str.scan(@delim) rescue []
end
@nth.map { |n|
if n.begin == 0 && n.end == -1
[prefix_length, tokens.join]
elsif part = tokens[n]
[prefix_length + (tokens[0...(n.begin)] || []).join.length,
part.join]
end
}.compact
end end
end end
def do_match str, pat def do_match str, pat
if @nth if @nth
prefix_length, tokens = tokenize str tokenize(str).each do |pair|
prefix_length, token = pair
@nth.each do |n| if md = token.match(pat) rescue nil
if (range = tokens[n]) && (token = range.join) && return MatchData.new(md.offset(0).map { |o| o + prefix_length })
(md = token.sub(/\s+$/, '').match(pat) rescue nil)
prefix_length += (tokens[0...(n.begin)] || []).join.length
offset = md.offset(0).map { |o| o + prefix_length }
return MatchData.new(offset)
end end
end end
nil nil

View File

@@ -8,12 +8,35 @@
# - $FZF_COMPLETION_TRIGGER (default: '**') # - $FZF_COMPLETION_TRIGGER (default: '**')
# - $FZF_COMPLETION_OPTS (default: empty) # - $FZF_COMPLETION_OPTS (default: empty)
_fzf_orig_completion_filter() {
sed 's/.*-F *\([^ ]*\).* \([^ ]*\)$/export _fzf_orig_completion_\2=\1;/' |
sed 's/[^a-z0-9_= ;]/_/g'
}
_fzf_opts_completion() { _fzf_opts_completion() {
local cur prev opts local cur prev opts
COMPREPLY=() COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}" cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}" prev="${COMP_WORDS[COMP_CWORD-1]}"
opts="-m --multi -x --extended -s --sort +s +i +c --no-color" opts="
-x --extended
-e --extended-exact
-i +i
-n --nth
-d --delimiter
-s --sort +s
-m --multi
--no-mouse
+c --no-color
+2 --no-256
--black
--reverse
--prompt
-q --query
-1 --select-1
-0 --exit-0
-f --filter
--print-query"
case "${prev}" in case "${prev}" in
--sort|-s) --sort|-s)
@@ -30,7 +53,7 @@ _fzf_opts_completion() {
return 0 return 0
} }
_fzf_generic_completion() { _fzf_path_completion() {
local cur base dir leftover matches trigger cmd orig local cur base dir leftover matches trigger cmd orig
cmd=$(echo ${COMP_WORDS[0]} | sed 's/[^a-z0-9_=]/_/g') cmd=$(echo ${COMP_WORDS[0]} | sed 's/[^a-z0-9_=]/_/g')
COMPREPLY=() COMPREPLY=()
@@ -66,24 +89,57 @@ _fzf_generic_completion() {
shift shift
shift shift
orig=$(eval "echo \$_fzf_orig_completion_$cmd") orig=$(eval "echo \$_fzf_orig_completion_$cmd")
[ -n "$orig" ] && type "$orig" > /dev/null && $orig "$@" [ -n "$orig" ] && type "$orig" > /dev/null 2>&1 && $orig "$@"
fi
}
_fzf_list_completion() {
local cur selected trigger cmd src ret
read -r src
cmd=$(echo ${COMP_WORDS[0]} | sed 's/[^a-z0-9_=]/_/g')
trigger=${FZF_COMPLETION_TRIGGER:-**}
cur="${COMP_WORDS[COMP_CWORD]}"
if [[ ${cur} == *"$trigger" ]]; then
cur=${cur:0:${#cur}-${#trigger}}
tput sc
selected=$(eval "$src | fzf $FZF_COMPLETION_OPTS $1 -q '$cur'" | tr '\n' ' ')
selected=${selected% }
tput rc
if [ -n "$selected" ]; then
COMPREPLY=("$selected")
return 0
fi
else
shift
orig=$(eval "echo \$_fzf_orig_completion_$cmd")
if [ -n "$orig" ] && type "$orig" > /dev/null; then
$orig "$@"
elif [ -n "$_fzf_completion_loader" ]; then
_completion_loader "$@"
ret=$?
eval $(complete | grep "\-F.* $cmd$" | _fzf_orig_completion_filter)
source $BASH_SOURCE
return $ret
fi
fi fi
} }
_fzf_all_completion() { _fzf_all_completion() {
_fzf_generic_completion \ _fzf_path_completion \
"-name .git -prune -o -name .svn -prune -o -type d -print -o -type f -print -o -type l -print" \ "-name .git -prune -o -name .svn -prune -o -type d -print -o -type f -print -o -type l -print" \
"-m" "$@" "-m" "$@"
} }
_fzf_file_completion() { _fzf_file_completion() {
_fzf_generic_completion \ _fzf_path_completion \
"-name .git -prune -o -name .svn -prune -o -type f -print -o -type l -print" \ "-name .git -prune -o -name .svn -prune -o -type f -print -o -type l -print" \
"-m" "$@" "-m" "$@"
} }
_fzf_dir_completion() { _fzf_dir_completion() {
_fzf_generic_completion \ _fzf_path_completion \
"-name .git -prune -o -name .svn -prune -o -type d -print" \ "-name .git -prune -o -name .svn -prune -o -type d -print" \
"" "$@" "" "$@"
} }
@@ -103,40 +159,27 @@ _fzf_kill_completion() {
} }
_fzf_telnet_completion() { _fzf_telnet_completion() {
local cur selected trigger _fzf_list_completion '+m' "$@" << "EOF"
trigger=${FZF_COMPLETION_TRIGGER:-**} grep -v '^\s*\(#\|$\)' /etc/hosts | awk '{if (length($2) > 0) {print $2}}' | sort -u
cur="${COMP_WORDS[COMP_CWORD]}" EOF
[[ ${cur} == *"$trigger" ]] || return 1
cur=${cur:0:${#cur}-${#trigger}}
tput sc
selected=$(grep -v '^\s*\(#\|$\)' /etc/hosts | awk '{print $2}' | sort -u | fzf $FZF_COMPLETION_OPTS -q "$cur")
tput rc
if [ -n "$selected" ]; then
COMPREPLY=("$selected")
return 0
fi
} }
_fzf_ssh_completion() { _fzf_ssh_completion() {
local cur selected trigger _fzf_list_completion '+m' "$@" << "EOF"
trigger=${FZF_COMPLETION_TRIGGER:-**} cat <(cat ~/.ssh/config /etc/ssh/ssh_config 2> /dev/null | grep -i ^host | grep -v '*') <(grep -v '^\s*\(#\|$\)' /etc/hosts) | awk '{print $2}' | sort -u
cur="${COMP_WORDS[COMP_CWORD]}" EOF
[[ ${cur} == *"$trigger" ]] || return 1 }
cur=${cur:0:${#cur}-${#trigger}}
tput sc _fzf_env_var_completion() {
selected=$(cat \ _fzf_list_completion '-m' "$@" << "EOF"
<(cat ~/.ssh/config /etc/ssh/ssh_config 2> /dev/null | grep -i ^host) \ declare -xp | sed 's/=.*//' | sed 's/.* //'
<(grep -v '^\s*\(#\|$\)' /etc/hosts) | \ EOF
awk '{print $2}' | sort -u | fzf $FZF_COMPLETION_OPTS -q "$cur") }
tput rc
if [ -n "$selected" ]; then _fzf_alias_completion() {
COMPREPLY=("$selected") _fzf_list_completion '-m' "$@" << "EOF"
return 0 alias | sed 's/=.*//' | sed 's/.* //'
fi EOF
} }
# fzf options # fzf options
@@ -153,15 +196,18 @@ a_cmds="
find git grep gunzip gzip hg jar find git grep gunzip gzip hg jar
ln ls mv open rm rsync scp ln ls mv open rm rsync scp
svn tar unzip zip" svn tar unzip zip"
x_cmds="kill ssh telnet unset unalias export"
# Preserve existing completion # Preserve existing completion
if [ "$_fzf_completion_loaded" != '0.8.6' ]; then if [ "$_fzf_completion_loaded" != '0.8.6-1' ]; then
# Really wish I could use associative array but OSX comes with bash 3.2 :( # Really wish I could use associative array but OSX comes with bash 3.2 :(
eval $(complete | grep '\-F' | grep -v _fzf_ | eval $(complete | grep '\-F' | grep -v _fzf_ |
grep -E -w "$(echo $d_cmds $f_cmds $a_cmds | sed 's/ /|/g' | sed 's/+/\\+/g')" | grep -E " ($(echo $d_cmds $f_cmds $a_cmds $x_cmds | sed 's/ /|/g' | sed 's/+/\\+/g'))$" | _fzf_orig_completion_filter)
sed -E 's/.*-F *([^ ]*).* ([^ ]*)$/export _fzf_orig_completion_\2=\1;/' | export _fzf_completion_loaded=0.8.6-1
sed 's/[^a-z0-9_= ;]/_/g') fi
export _fzf_completion_loaded=0.8.6
if type _completion_loader > /dev/null 2>&1; then
_fzf_completion_loader=1
fi fi
# Directory # Directory
@@ -186,4 +232,9 @@ complete -F _fzf_kill_completion -o nospace -o default -o bashdefault kill
complete -F _fzf_ssh_completion -o default -o bashdefault ssh complete -F _fzf_ssh_completion -o default -o bashdefault ssh
complete -F _fzf_telnet_completion -o default -o bashdefault telnet complete -F _fzf_telnet_completion -o default -o bashdefault telnet
unset cmd d_cmds f_cmds a_cmds # Environment variables / Aliases
complete -F _fzf_env_var_completion -o default -o bashdefault unset
complete -F _fzf_env_var_completion -o default -o bashdefault export
complete -F _fzf_alias_completion -o default -o bashdefault unalias
unset cmd d_cmds f_cmds a_cmds x_cmds

12
install
View File

@@ -28,7 +28,11 @@ if [ $? -eq 0 ]; then
else else
echo "Not found" echo "Not found"
echo "Installing 'curses' gem ... " echo "Installing 'curses' gem ... "
/usr/bin/env gem install curses -v 1.0.0 --user-install if (( EUID )); then
/usr/bin/env gem install curses --user-install
else
/usr/bin/env gem install curses
fi
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo echo
echo "Failed to install 'curses' gem." echo "Failed to install 'curses' gem."
@@ -140,7 +144,7 @@ if [ -z "$(set -o | grep '^vi.*on')" ]; then
fi fi
# CTRL-R - Paste the selected command from history into the command line # CTRL-R - Paste the selected command from history into the command line
bind '"\C-r": " \C-e\C-u$(HISTTIMEFORMAT= history | fzf +s +m -n..,1,2.. | sed \"s/ *[0-9]* *//\")\e\C-e\er"' bind '"\C-r": " \C-e\C-u$(HISTTIMEFORMAT= history | fzf +s +m -n2..,.. | sed \"s/ *[0-9]* *//\")\e\C-e\er"'
# ALT-C - cd into the selected directory # ALT-C - cd into the selected directory
bind '"\ec": " \C-e\C-u$(__fcd)\e\C-e\er\C-m"' bind '"\ec": " \C-e\C-u$(__fcd)\e\C-e\er\C-m"'
@@ -158,7 +162,7 @@ else
bind -m vi-command '"\C-t": "i\C-t"' bind -m vi-command '"\C-t": "i\C-t"'
# CTRL-R - Paste the selected command from history into the command line # CTRL-R - Paste the selected command from history into the command line
bind '"\C-r": "\eddi$(HISTTIMEFORMAT= history | fzf +s +m -n..,1,2.. | sed \"s/ *[0-9]* *//\")\C-x\C-e\e$a\C-x\C-r"' bind '"\C-r": "\eddi$(HISTTIMEFORMAT= history | fzf +s +m -n2..,.. | sed \"s/ *[0-9]* *//\")\C-x\C-e\e$a\C-x\C-r"'
bind -m vi-command '"\C-r": "i\C-r"' bind -m vi-command '"\C-r": "i\C-r"'
# ALT-C - cd into the selected directory # ALT-C - cd into the selected directory
@@ -219,7 +223,7 @@ bindkey '\ec' fzf-cd-widget
# CTRL-R - Paste the selected command from history into the command line # CTRL-R - Paste the selected command from history into the command line
fzf-history-widget() { fzf-history-widget() {
LBUFFER=$(fc -l 1 | fzf +s +m -n..,1,2.. | sed "s/ *[0-9*]* *//") LBUFFER=$(fc -l 1 | fzf +s +m -n2..,.. | sed "s/ *[0-9*]* *//")
zle redisplay zle redisplay
} }
zle -N fzf-history-widget zle -N fzf-history-widget

View File

@@ -148,11 +148,18 @@ function! s:execute(dict, command, temps)
endif endif
endfunction endfunction
function! s:execute_tmux(dict, command, temps) function! s:env_var(name)
if has_key(a:dict, 'dir') if exists('$'.a:name)
let command = 'cd '.s:escape(a:dict.dir).' && '.a:command return a:name . "='". substitute(expand('$'.a:name), "'", "'\\\\''", 'g') . "' "
else else
let command = a:command return ''
endif
endfunction
function! s:execute_tmux(dict, command, temps)
let command = s:env_var('FZF_DEFAULT_OPTS').s:env_var('FZF_DEFAULT_COMMAND').a:command
if has_key(a:dict, 'dir')
let command = 'cd '.s:escape(a:dict.dir).' && '.command
endif endif
let splitopt = '-v' let splitopt = '-v'

View File

@@ -5,6 +5,7 @@ require 'curses'
require 'timeout' require 'timeout'
require 'stringio' require 'stringio'
require 'minitest/autorun' require 'minitest/autorun'
require 'tempfile'
$LOAD_PATH.unshift File.expand_path('../..', __FILE__) $LOAD_PATH.unshift File.expand_path('../..', __FILE__)
ENV['FZF_EXECUTABLE'] = '0' ENV['FZF_EXECUTABLE'] = '0'
load 'fzf' load 'fzf'
@@ -614,7 +615,7 @@ class TestFZF < MiniTest::Unit::TestCase
def test_select_1_ambiguity def test_select_1_ambiguity
stream = stream_for "Hello\nWorld" stream = stream_for "Hello\nWorld"
begin begin
Timeout::timeout(3) do Timeout::timeout(2) do
FZF.new(%w[--query=o --select-1], stream).start FZF.new(%w[--query=o --select-1], stream).start
end end
flunk 'Should not reach here' flunk 'Should not reach here'
@@ -681,5 +682,19 @@ class TestFZF < MiniTest::Unit::TestCase
# **[***** #] => [******# ] # **[***** #] => [******# ]
assert_equal [true, 0, 6], fzf.constrain(2, 10, 7, 10) assert_equal [true, 0, 6], fzf.constrain(2, 10, 7, 10)
end end
def test_invalid_utf8
tmp = Tempfile.new('fzf')
tmp << 'hello ' << [0xff].pack('C*') << ' world' << $/ << [0xff].pack('C*')
tmp.close
begin
Timeout::timeout(1) do
FZF.new(%w[-n..,1,2.. -q^ -x], File.open(tmp.path)).start
end
rescue Timeout::Error
end
ensure
tmp.unlink
end
end end