Compare commits

...

48 Commits
0.8.6 ... 0.8.9

Author SHA1 Message Date
Junegunn Choi
4ceb520c1d Merge pull request #115 from JackDanger/sleep-when-curses-is-unavailable
Sleep when curses is unavailable
2015-01-02 15:28:33 +09:00
Jack Danger Canty
d761ea5158 Sleep when curses is unavailable
When the curses gem is not installed and the session is running inside
tmux the user will see a flash of an opened and closed tmux pane but
will not have a chance to read the error message.
2015-01-01 22:23:37 -08:00
Junegunn Choi
7ba93d9f83 Merge pull request #113 from thedrow/patch-1
Use travis' new build workers
2014-12-29 01:03:04 +09:00
Omer Katz
b34f93f307 Use travis' new build workers
They boot faster and since we don't use root we can use them.
2014-12-28 17:11:13 +02:00
Junegunn Choi
ec040d82dd Improve word motions: ALT-B, ALT-F, ALT-D, ALT-BS (#112) 2014-12-24 13:27:39 +09:00
Junegunn Choi
00190677d4 Add support for ALT-D and ALT-BS key bindings
https://github.com/junegunn/fzf/issues/111#issuecomment-67832143
2014-12-23 12:22:19 +09:00
Junegunn Choi
d38f7a5eb5 Merge pull request #109 from brettanomyces/reorder_fish_history
Reverse the order of fish history
2014-12-13 11:10:29 +09:00
brettanomyces
ee433ef6e9 reverse history for fish shell 2014-12-13 11:54:35 +13:00
Junegunn Choi
d89c9e94ba Handle dynamically loaded completion functions (#107 / #79) 2014-12-05 00:24:25 +09:00
Junegunn Choi
7e2dfef930 Merge pull request #106 from jagajaga/master
Change `/bin/bash` to `/usr/bin/env bash`
2014-12-01 18:19:33 +09:00
Arseniy Seroka
0296fcb5cd bash -> env bash 2014-11-30 23:04:15 +03:00
Junegunn Choi
80819f3c44 Merge pull request #104 from junegunn/add-with-nth
Add --with-nth option
2014-11-04 23:30:11 +09:00
Junegunn Choi
7571baadb4 Fix test failure on Ruby 1.8.7
Hashes are unordered on Ruby 1.8
2014-11-04 19:32:31 +09:00
Junegunn Choi
da03a66e69 Add test cases for --with-nth option 2014-11-04 19:01:15 +09:00
Junegunn Choi
3c47b7fa5f Fix --with-nth option on --multi 2014-11-03 23:58:10 +09:00
Junegunn Choi
ba9365c438 Fix --with-nth option on Ruby 1.8 2014-11-03 23:48:37 +09:00
Junegunn Choi
db37e67575 Skip failing tests on Ruby 1.8 2014-11-01 14:52:29 +09:00
Junegunn Choi
76a3ef8c37 Add --with-nth option (#102) 2014-11-01 14:49:05 +09:00
Junegunn Choi
6fd6fff3a6 [vim] Ignore 'dir' option if empty
This makes it easier to override FZF command like follows:

    autocmd VimEnter * command! -nargs=? -bang -complete=dir FZF call fzf#run({
          \ 'sink': 'tabe',
          \ 'dir': <q-args>,
          \ 'options': '-m',
          \ 'tmux_height': empty('<bang>') ? '40%' : '' })
2014-10-15 13:22:00 +09:00
Junegunn Choi
d1387bf512 Use IO.console when possible 2014-10-07 11:49:40 +09:00
Junegunn Choi
4c923a2d19 [uninstall] Remove both patterns of source command (#97)
- `[ -f ~/.fzf.${shell} ] && source ~/.fzf.${shell}"`
- `source ~/.fzf.${shell}"`
2014-09-18 19:21:58 +09:00
Junegunn Choi
4ee85f11e8 [install] Join line numbers when multiple matches found 2014-09-18 19:03:01 +09:00
Junegunn Choi
829c7f909c Merge branch 'mjwhitta-master' 2014-09-18 18:49:43 +09:00
Miles Whittaker
990fa00660 Check before sourcing, no longer need to remove 2014-09-18 00:01:39 -04:00
Miles Whittaker
77592825f0 Sometimes users prefer . instead of source
So only check for file name
2014-09-17 23:55:28 -04:00
Miles Whittaker
ce53b9b2a5 Ignore user-defined grep aliases 2014-09-14 00:53:53 -04:00
Junegunn Choi
175fe158ed Add vim-plug recipe 2014-09-02 13:06:05 +09:00
Junegunn Choi
80efafcceb Fix ALT-C keybinding to include symlinked directories
Related #95.
2014-08-31 03:22:51 +09:00
Junegunn Choi
b241409e4b Merge pull request #95 from Neki/topic/resolve_symlinks
Follow symlinks when using bash autocompletion.
2014-08-30 22:33:21 +09:00
Benoît Faucon
11967be017 Follow symlinks when using bash autocompletion. 2014-08-30 14:56:30 +02:00
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
9 changed files with 534 additions and 184 deletions

10
.travis.yml Normal file
View File

@@ -0,0 +1,10 @@
language: ruby
sudo: false
rvm:
- "1.8.7"
- "1.9.3"
- "2.0.0"
- "2.1.1"
install: gem install curses minitest

View File

@@ -51,8 +51,12 @@ Once you have cloned the repository, add the following line to your .vimrc.
set rtp+=~/.fzf
```
Or you may use any Vim plugin manager, such as
[vim-plug](https://github.com/junegunn/vim-plug).
Or you may use [vim-plug](https://github.com/junegunn/vim-plug) to manage fzf
inside Vim:
```vim
Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': 'yes \| ./install' }
```
Usage
-----
@@ -61,38 +65,39 @@ Usage
usage: fzf [options]
Search
-x, --extended Extended-search mode
-e, --extended-exact Extended-search mode (exact match)
-i Case-insensitive match (default: smart-case match)
+i Case-sensitive match
-n, --nth=N[,..] Comma-separated list of field index expressions
for limiting search scope. Each can be a non-zero
integer or a range expression ([BEGIN]..[END])
-d, --delimiter=STR Field delimiter regex for --nth (default: AWK-style)
-x, --extended Extended-search mode
-e, --extended-exact Extended-search mode (exact match)
-i Case-insensitive match (default: smart-case match)
+i Case-sensitive match
-n, --nth=N[,..] Comma-separated list of field index expressions
for limiting search scope. Each can be a non-zero
integer or a range expression ([BEGIN]..[END])
--with-nth=N[,..] Transform the item using index expressions for search
-d, --delimiter=STR Field delimiter regex for --nth (default: AWK-style)
Search result
-s, --sort=MAX Maximum number of matched items to sort (default: 1000)
+s, --no-sort Do not sort the result. Keep the sequence unchanged.
-s, --sort=MAX Maximum number of matched items to sort (default: 1000)
+s, --no-sort Do not sort the result. Keep the sequence unchanged.
Interface
-m, --multi Enable multi-select with tab/shift-tab
--no-mouse Disable mouse
+c, --no-color Disable colors
+2, --no-256 Disable 256-color
--black Use black background
--reverse Reverse orientation
--prompt=STR Input prompt (default: '> ')
-m, --multi Enable multi-select with tab/shift-tab
--no-mouse Disable mouse
+c, --no-color Disable colors
+2, --no-256 Disable 256-color
--black Use black background
--reverse Reverse orientation
--prompt=STR Input prompt (default: '> ')
Scripting
-q, --query=STR Start the finder with the given query
-1, --select-1 Automatically select the only match
-0, --exit-0 Exit immediately when there's no match
-f, --filter=STR Filter mode. Do not start interactive finder.
--print-query Print query as the first line
-q, --query=STR Start the finder with the given query
-1, --select-1 Automatically select the only match
-0, --exit-0 Exit immediately when there's no match
-f, --filter=STR Filter mode. Do not start interactive finder.
--print-query Print query as the first line
Environment variables
FZF_DEFAULT_COMMAND Default command to use when input is tty
FZF_DEFAULT_OPTS Defaults options. (e.g. "-x -m --sort 10000")
FZF_DEFAULT_COMMAND Default command to use when input is tty
FZF_DEFAULT_OPTS Defaults options. (e.g. "-x -m --sort 10000")
```
fzf will launch curses-based finder, read the list from STDIN, and write the
@@ -270,6 +275,14 @@ ssh **<TAB>
telnet **<TAB>
```
#### Environment variables / Aliases
```sh
unset **<TAB>
export **<TAB>
unalias **<TAB>
```
#### Settings
```sh
@@ -464,7 +477,7 @@ speed of the traversal.
```sh
# Copy the original fzf function to __fzf
declare -f __fzf > /dev/null ||
eval "$(echo "__fzf() {"; declare -f fzf | grep -v '^{' | tail -n +2)"
eval "$(echo "__fzf() {"; declare -f fzf | \grep -v '^{' | tail -n +2)"
# Use git ls-tree when possible
fzf() {

View File

@@ -6,3 +6,4 @@ Rake::TestTask.new(:test) do |test|
test.verbose = true
end
task :default => :test

206
fzf
View File

@@ -7,7 +7,7 @@
# / __/ / /_/ __/
# /_/ /___/_/ Fuzzy finder for your shell
#
# Version: 0.8.6 (Jun 30, 2014)
# Version: 0.8.9 (Dec 24, 2014)
#
# Author: Junegunn Choi
# URL: https://github.com/junegunn/fzf
@@ -36,8 +36,14 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
begin
require 'curses'
rescue LoadError
$stderr.puts 'curses gem is not installed. Try `gem install curses`.'
sleep 1
exit 1
end
require 'thread'
require 'curses'
require 'set'
unless String.method_defined? :force_encoding
@@ -48,11 +54,34 @@ unless String.method_defined? :force_encoding
end
end
class String
attr_accessor :orig
def tokenize delim, nth
unless delim
# AWK default
prefix_length = (index(/\S/) || 0) rescue 0
tokens = scan(/\S+\s*/) rescue []
else
prefix_length = 0
tokens = 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
class FZF
C = Curses
attr_reader :rxflag, :sort, :nth, :color, :black, :ansi256, :reverse, :prompt,
:mouse, :multi, :query, :select1, :exit0, :filter, :extended,
:print_query
:print_query, :with_nth
def sync
@shr_mtx.synchronize { yield }
@@ -90,6 +119,7 @@ class FZF
@exit0 = false
@filter = nil
@nth = nil
@with_nth = nil
@delim = nil
@reverse = false
@prompt = '> '
@@ -143,6 +173,11 @@ class FZF
@nth = parse_nth nth
when /^-n([0-9,-\.]+)$/, /^--nth=([0-9,-\.]+)$/
@nth = parse_nth $1
when '--with-nth'
usage 1, 'field expression required' unless nth = argv.shift
@with_nth = parse_nth nth
when /^--with-nth=([0-9,-\.]+)$/
@with_nth = parse_nth $1
when '-d', '--delimiter'
usage 1, 'delimiter required' unless delim = argv.shift
@delim = FZF.build_delim_regex delim
@@ -176,6 +211,7 @@ class FZF
@queue = Queue.new
@pending = nil
@rev_dir = @reverse ? -1 : 1
@stdout = $stdout.clone
unless @filter
# Shared variables: needs protection
@@ -195,7 +231,7 @@ class FZF
end
def parse_nth nth
nth.split(',').map { |expr|
ranges = nth.split(',').map { |expr|
x = proc { usage 1, "invalid field expression: #{expr}" }
first, second = expr.split('..', 2)
x.call if !first.empty? && first.to_i == 0 ||
@@ -210,6 +246,7 @@ class FZF
Range.new(*[first, second].map { |e| e > 0 ? e - 1 : e })
}
ranges == [0..-1] ? nil : ranges
end
def FZF.build_delim_regex delim
@@ -217,6 +254,10 @@ class FZF
Regexp.compile "(?:.*?#{delim})|(?:.+?$)"
end
def burp string, orig = nil
@stdout.puts(orig || string.orig || string)
end
def start
if @filter
start_reader.join
@@ -231,7 +272,7 @@ class FZF
if loaded
if @select1 && len == 1
puts @query if @print_query
puts empty ? matches.first : matches.first.first
burp(empty ? matches.first : matches.first.first)
exit 0
elsif @exit0 && len == 0
puts @query if @print_query
@@ -307,39 +348,40 @@ class FZF
$stderr.puts %[usage: fzf [options]
Search
-x, --extended Extended-search mode
-e, --extended-exact Extended-search mode (exact match)
-i Case-insensitive match (default: smart-case match)
+i Case-sensitive match
-n, --nth=N[,..] Comma-separated list of field index expressions
for limiting search scope. Each can be a non-zero
integer or a range expression ([BEGIN]..[END])
-d, --delimiter=STR Field delimiter regex for --nth (default: AWK-style)
-x, --extended Extended-search mode
-e, --extended-exact Extended-search mode (exact match)
-i Case-insensitive match (default: smart-case match)
+i Case-sensitive match
-n, --nth=N[,..] Comma-separated list of field index expressions
for limiting search scope. Each can be a non-zero
integer or a range expression ([BEGIN]..[END])
--with-nth=N[,..] Transform the item using index expressions for search
-d, --delimiter=STR Field delimiter regex for --nth (default: AWK-style)
Search result
-s, --sort=MAX Maximum number of matched items to sort (default: 1000)
+s, --no-sort Do not sort the result. Keep the sequence unchanged.
-s, --sort=MAX Maximum number of matched items to sort (default: 1000)
+s, --no-sort Do not sort the result. Keep the sequence unchanged.
Interface
-m, --multi Enable multi-select with tab/shift-tab
--no-mouse Disable mouse
+c, --no-color Disable colors
+2, --no-256 Disable 256-color
--black Use black background
--reverse Reverse orientation
--prompt=STR Input prompt (default: '> ')
-m, --multi Enable multi-select with tab/shift-tab
--no-mouse Disable mouse
+c, --no-color Disable colors
+2, --no-256 Disable 256-color
--black Use black background
--reverse Reverse orientation
--prompt=STR Input prompt (default: '> ')
Scripting
-q, --query=STR Start the finder with the given query
-1, --select-1 Automatically select the only match
-0, --exit-0 Exit immediately when there's no match
-f, --filter=STR Filter mode. Do not start interactive finder.
--print-query Print query as the first line
-q, --query=STR Start the finder with the given query
-1, --select-1 Automatically select the only match
-0, --exit-0 Exit immediately when there's no match
-f, --filter=STR Filter mode. Do not start interactive finder.
--print-query Print query as the first line
Environment variables
FZF_DEFAULT_COMMAND Default command to use when input is tty
FZF_DEFAULT_OPTS Defaults options. (e.g. "-x -m --sort 10000")] + $/ + $/
exit x
FZF_DEFAULT_COMMAND Default command to use when input is tty
FZF_DEFAULT_OPTS Defaults options. (e.g. "-x -m --sort 10000")] + $/ + $/
exit x
end
def emit event
@@ -361,7 +403,8 @@ class FZF
end if str
end
def addstr_safe str
C.addstr str.gsub("\0", '')
str = str.gsub("\0", '') rescue str
C.addstr str
end
def print_input
@@ -514,7 +557,6 @@ class FZF
end
def init_screen
@stdout = $stdout.clone
$stdout.reopen($stderr)
C.init_screen
@@ -589,14 +631,28 @@ class FZF
end
Thread.new do
while line = stream.gets
emit(:new) { @new << line.chomp }
if @with_nth
while line = stream.gets
emit(:new) { @new << transform(line) }
end
else
while line = stream.gets
emit(:new) { @new << line.chomp }
end
end
emit(:loaded) { true }
@spinner.clear if @spinner
end
end
def transform line
line = line.chomp
mut = (line =~ / $/ ? line : line + ' ').
tokenize(@delim, @with_nth).map { |e| e.last }.join('').sub(/ *$/, '')
mut.orig = line
mut
end
def start_search &callback
Thread.new do
lists = []
@@ -688,7 +744,8 @@ class FZF
def pick
sync do
[*@matches.fetch(@ycur, [])][0]
item = @matches[@ycur]
item.is_a?(Array) ? item[0] : item
end
end
@@ -835,7 +892,13 @@ class FZF
end
def get_input actions
@tty ||= IO.open(IO.sysopen('/dev/tty'), 'r')
@tty ||=
begin
require 'io/console'
IO.console
rescue LoadError
IO.open(IO.sysopen('/dev/tty'), 'r')
end
if pending = @pending
@pending = nil
@@ -882,6 +945,8 @@ class FZF
case read_nbs
when [59, 50, 68] then ctrl(:a)
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)
end
when 52 then read_nb; ctrl(:e)
@@ -891,8 +956,10 @@ class FZF
get_mouse
end
when 'b', 98 then :alt_b
when 'd', 100 then :alt_d
when 'f', 102 then :alt_f
when :esc then :esc
when 127 then :alt_bs
else next
end if ord == 27
@@ -948,7 +1015,20 @@ class FZF
yanked = ''
mouse_event = MouseEvent.new
backword = proc {
cursor = (input[0, cursor].rindex(/\s\S/) || -1) + 1
cursor = (input[0, cursor].rindex(/[^[:alnum:]][[:alnum:]]/) || -1) + 1
nil
}
forward = proc {
cursor += (input[cursor..-1].index(/([[:alnum:]][^[:alnum:]])|(.$)/) || -1) + 1
nil
}
rubout = proc { |regex|
pcursor = cursor
cursor = (input[0, cursor].rindex(regex) || -1) + 1
if pcursor > cursor
yanked = input[cursor...pcursor]
input = input[0...cursor] + input[pcursor..-1]
end
}
actions = {
:esc => proc { exit 1 },
@@ -972,12 +1052,7 @@ class FZF
ctrl(:e) => proc { cursor = input.length; nil },
ctrl(:j) => proc { vselect { |v| v - @rev_dir } },
ctrl(:k) => proc { vselect { |v| v + @rev_dir } },
ctrl(:w) => proc {
pcursor = cursor
backword.call
yanked = input[cursor...pcursor] if pcursor > cursor
input = input[0...cursor] + input[pcursor..-1]
},
ctrl(:w) => proc { rubout.call /\s\S/ },
ctrl(:y) => proc { actions[:default].call yanked },
ctrl(:h) => proc { input[cursor -= 1] = '' if cursor > 0 },
ctrl(:i) => proc { |o|
@@ -986,7 +1061,7 @@ class FZF
if @selects.has_key? sel
@selects.delete sel
else
@selects[sel] = 1
@selects[sel] = sel.orig
end
end
vselect { |v| v + case o
@@ -1002,10 +1077,19 @@ class FZF
:del => proc { input[cursor] = '' if input.length > cursor },
:pgup => proc { vselect { |v| v + @rev_dir * (max_items - 1) } },
:pgdn => proc { vselect { |v| v - @rev_dir * (max_items - 1) } },
:alt_b => proc { backword.call; nil },
:alt_bs => proc { rubout.call /[^[:alnum:]][[:alnum:]]/ },
:alt_b => proc { backword.call },
:alt_d => proc {
pcursor = cursor
forward.call
if cursor > pcursor
yanked = input[pcursor...cursor]
input = input[0...pcursor] + input[cursor..-1]
cursor = pcursor
end
},
:alt_f => proc {
cursor += (input[cursor..-1].index(/(\S\s)|(.$)/) || -1) + 1
nil
forward.call
},
:default => proc { |val|
case val
@@ -1066,10 +1150,10 @@ class FZF
@stdout.puts q if @print_query
if got
if selects.empty?
@stdout.puts got
burp got
else
selects.each do |sel, _|
@stdout.puts sel
selects.each do |sel, orig|
burp sel, orig
end
end
end
@@ -1094,27 +1178,15 @@ class FZF
end
def tokenize str
@tokens_cache[str] ||=
unless @delim
# AWK default
prefix_length = str[/^\s+/].length rescue 0
[prefix_length, (str.strip.scan(/\S+\s*/) rescue [])]
else
prefix_length = 0
[prefix_length, (str.scan(@delim) rescue [])]
end
@tokens_cache[str] ||= str.tokenize(@delim, @nth)
end
def do_match str, pat
if @nth
prefix_length, tokens = tokenize str
@nth.each do |n|
if (range = tokens[n]) && (token = range.join) &&
(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)
tokenize(str).each do |pair|
prefix_length, token = pair
if md = token.match(pat) rescue nil
return MatchData.new(md.offset(0).map { |o| o + prefix_length })
end
end
nil

View File

@@ -8,12 +8,35 @@
# - $FZF_COMPLETION_TRIGGER (default: '**')
# - $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() {
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
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
--sort|-s)
@@ -30,8 +53,25 @@ _fzf_opts_completion() {
return 0
}
_fzf_generic_completion() {
local cur base dir leftover matches trigger cmd orig
_fzf_handle_dynamic_completion() {
local cmd orig ret
cmd="$1"
shift
orig=$(eval "echo \$_fzf_orig_completion_$cmd")
if [ -n "$orig" ] && type "$orig" > /dev/null 2>&1; 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
}
_fzf_path_completion() {
local cur base dir leftover matches trigger cmd
cmd=$(echo ${COMP_WORDS[0]} | sed 's/[^a-z0-9_=]/_/g')
COMPREPLY=()
trigger=${FZF_COMPLETION_TRIGGER:-**}
@@ -47,7 +87,7 @@ _fzf_generic_completion() {
leftover=${leftover/#\/}
[ "$dir" = './' ] && dir=''
tput sc
matches=$(find "$dir"* $1 2> /dev/null | fzf $FZF_COMPLETION_OPTS $2 -q "$leftover" | while read item; do
matches=$(find -L "$dir"* $1 2> /dev/null | fzf $FZF_COMPLETION_OPTS $2 -q "$leftover" | while read item; do
printf '%q ' "$item"
done)
matches=${matches% }
@@ -65,25 +105,48 @@ _fzf_generic_completion() {
else
shift
shift
orig=$(eval "echo \$_fzf_orig_completion_$cmd")
[ -n "$orig" ] && type "$orig" > /dev/null && $orig "$@"
_fzf_handle_dynamic_completion "$cmd" "$@"
fi
}
_fzf_list_completion() {
local cur selected trigger cmd src
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
_fzf_handle_dynamic_completion "$cmd" "$@"
fi
}
_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" \
"-m" "$@"
}
_fzf_file_completion() {
_fzf_generic_completion \
_fzf_path_completion \
"-name .git -prune -o -name .svn -prune -o -type f -print -o -type l -print" \
"-m" "$@"
}
_fzf_dir_completion() {
_fzf_generic_completion \
_fzf_path_completion \
"-name .git -prune -o -name .svn -prune -o -type d -print" \
"" "$@"
}
@@ -103,40 +166,27 @@ _fzf_kill_completion() {
}
_fzf_telnet_completion() {
local cur selected trigger
trigger=${FZF_COMPLETION_TRIGGER:-**}
cur="${COMP_WORDS[COMP_CWORD]}"
[[ ${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_list_completion '+m' "$@" << "EOF"
\grep -v '^\s*\(#\|$\)' /etc/hosts | awk '{if (length($2) > 0) {print $2}}' | sort -u
EOF
}
_fzf_ssh_completion() {
local cur selected trigger
trigger=${FZF_COMPLETION_TRIGGER:-**}
cur="${COMP_WORDS[COMP_CWORD]}"
[[ ${cur} == *"$trigger" ]] || return 1
cur=${cur:0:${#cur}-${#trigger}}
_fzf_list_completion '+m' "$@" << "EOF"
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
EOF
}
tput sc
selected=$(cat \
<(cat ~/.ssh/config /etc/ssh/ssh_config 2> /dev/null | grep -i ^host) \
<(grep -v '^\s*\(#\|$\)' /etc/hosts) | \
awk '{print $2}' | sort -u | fzf $FZF_COMPLETION_OPTS -q "$cur")
tput rc
_fzf_env_var_completion() {
_fzf_list_completion '-m' "$@" << "EOF"
declare -xp | sed 's/=.*//' | sed 's/.* //'
EOF
}
if [ -n "$selected" ]; then
COMPREPLY=("$selected")
return 0
fi
_fzf_alias_completion() {
_fzf_list_completion '-m' "$@" << "EOF"
alias | sed 's/=.*//' | sed 's/.* //'
EOF
}
# fzf options
@@ -153,15 +203,18 @@ a_cmds="
find git grep gunzip gzip hg jar
ln ls mv open rm rsync scp
svn tar unzip zip"
x_cmds="kill ssh telnet unset unalias export"
# 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 :(
eval $(complete | grep '\-F' | grep -v _fzf_ |
grep -E -w "$(echo $d_cmds $f_cmds $a_cmds | sed 's/ /|/g' | sed 's/+/\\+/g')" |
sed -E 's/.*-F *([^ ]*).* ([^ ]*)$/export _fzf_orig_completion_\2=\1;/' |
sed 's/[^a-z0-9_= ;]/_/g')
export _fzf_completion_loaded=0.8.6
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.8.6-1
fi
if type _completion_loader > /dev/null 2>&1; then
_fzf_completion_loader=1
fi
# Directory
@@ -186,4 +239,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_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

46
install
View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
cd `dirname $BASH_SOURCE`
fzf_base=`pwd`
@@ -28,7 +28,11 @@ if [ $? -eq 0 ]; then
else
echo "Not found"
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
echo
echo "Failed to install 'curses' gem."
@@ -122,13 +126,13 @@ __fsel_tmux() {
__fcd() {
local dir
dir=$(command find ${1:-*} -path '*/\.*' -prune -o -type d -print 2> /dev/null | fzf +m) && printf 'cd %q' "$dir"
dir=$(command find -L ${1:-*} -path '*/\.*' -prune -o -type d -print 2> /dev/null | fzf +m) && printf 'cd %q' "$dir"
}
__use_tmux=0
[ -n "$TMUX_PANE" -a ${FZF_TMUX:-1} -ne 0 -a ${LINES:-40} -gt 15 ] && __use_tmux=1
if [ -z "$(set -o | grep '^vi.*on')" ]; then
if [ -z "$(set -o | \grep '^vi.*on')" ]; then
# Required to refresh the prompt after fzf
bind '"\er": redraw-current-line'
@@ -140,7 +144,7 @@ if [ -z "$(set -o | grep '^vi.*on')" ]; then
fi
# 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
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"'
# 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"'
# ALT-C - cd into the selected directory
@@ -210,7 +214,7 @@ bindkey '^T' fzf-file-widget
# ALT-C - cd into the selected directory
fzf-cd-widget() {
cd "${$(set -o nonomatch; command find * -path '*/\.*' -prune \
cd "${$(set -o nonomatch; command find -L * -path '*/\.*' -prune \
-o -type d -print 2> /dev/null | fzf):-.}"
zle reset-prompt
}
@@ -219,7 +223,7 @@ bindkey '\ec' fzf-cd-widget
# CTRL-R - Paste the selected command from history into the command line
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 -N fzf-history-widget
@@ -264,7 +268,7 @@ function fzf_key_bindings
end
function __fzf_list_dir
command find * -path '*/\.*' -prune -o -type d -print 2> /dev/null
command find -L * -path '*/\.*' -prune -o -type d -print 2> /dev/null
end
function __fzf_escape
@@ -290,8 +294,16 @@ function fzf_key_bindings
rm -f $TMPDIR/fzf.result
end
function __fzf_reverse
if which tac > /dev/null
tac $argv
else
tail -r $argv
end
end
function __fzf_ctrl_r
history | fzf +s +m > $TMPDIR/fzf.result
history | __fzf_reverse | fzf +s +m > $TMPDIR/fzf.result
and commandline (cat $TMPDIR/fzf.result)
commandline -f repaint
rm -f $TMPDIR/fzf.result
@@ -312,7 +324,7 @@ function fzf_key_bindings
else
set height 40%
end
if echo $height | grep -q -E '%$'
if echo $height | \grep -q -E '%$'
echo "-p "(echo $height | sed 's/%$//')
else
echo "-l $height"
@@ -333,19 +345,23 @@ append_line() {
echo "Update $2:"
echo " - $1"
[ -f "$2" ] || touch "$2"
line=$(grep -nF "$1" "$2" | sed 's/:.*//')
if [ $# -lt 3 ]; then
line=$(\grep -nF "$1" "$2" | sed 's/:.*//' | tr '\n' ' ')
else
line=$(\grep -nF "$3" "$2" | sed 's/:.*//' | tr '\n' ' ')
fi
if [ -n "$line" ]; then
echo " - Already exists (line #$line)"
echo " - Already exists: line #$line"
else
echo "$1" >> "$2"
echo " - Added"
echo " + Added"
fi
echo
}
echo
for shell in bash zsh; do
append_line "source ~/.fzf.${shell}" ~/.${shell}rc
append_line "[ -f ~/.fzf.${shell} ] && source ~/.fzf.${shell}" ~/.${shell}rc "~/.fzf.${shell}"
done
if [ $key_bindings -eq 0 -a $has_fish -eq 1 ]; then

View File

@@ -113,7 +113,7 @@ function! s:tmux_splittable(dict)
endfunction
function! s:pushd(dict)
if has_key(a:dict, 'dir')
if !empty(get(a:dict, 'dir', ''))
let a:dict.prev_dir = getcwd()
execute 'chdir '.s:escape(a:dict.dir)
endif
@@ -148,11 +148,18 @@ function! s:execute(dict, command, temps)
endif
endfunction
function! s:execute_tmux(dict, command, temps)
if has_key(a:dict, 'dir')
let command = 'cd '.s:escape(a:dict.dir).' && '.a:command
function! s:env_var(name)
if exists('$'.a:name)
return a:name . "='". substitute(expand('$'.a:name), "'", "'\\\\''", 'g') . "' "
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 !empty(get(a:dict, 'dir', ''))
let command = 'cd '.s:escape(a:dict.dir).' && '.command
endif
let splitopt = '-v'

View File

@@ -1,14 +1,59 @@
#!/usr/bin/env ruby
# encoding: utf-8
require 'rubygems'
require 'curses'
require 'timeout'
require 'stringio'
require 'minitest/autorun'
require 'tempfile'
$LOAD_PATH.unshift File.expand_path('../..', __FILE__)
ENV['FZF_EXECUTABLE'] = '0'
load 'fzf'
class MockTTY
def initialize
@buffer = ''
@mutex = Mutex.new
@condv = ConditionVariable.new
end
def read_nonblock sz
@mutex.synchronize do
take sz
end
end
def take sz
if @buffer.length >= sz
ret = @buffer[0, sz]
@buffer = @buffer[sz..-1]
ret
end
end
def getc
sleep 0.1
while true
@mutex.synchronize do
if char = take(1)
return char
else
@condv.wait(@mutex)
end
end
end
end
def << str
@mutex.synchronize do
@buffer << str
@condv.broadcast
end
self
end
end
class TestFZF < MiniTest::Unit::TestCase
def setup
ENV.delete 'FZF_DEFAULT_SORT'
@@ -24,6 +69,7 @@ class TestFZF < MiniTest::Unit::TestCase
assert_equal nil, fzf.rxflag
assert_equal true, fzf.mouse
assert_equal nil, fzf.nth
assert_equal nil, fzf.with_nth
assert_equal true, fzf.color
assert_equal false, fzf.black
assert_equal true, fzf.ansi256
@@ -46,7 +92,7 @@ class TestFZF < MiniTest::Unit::TestCase
ENV['FZF_DEFAULT_OPTS'] =
'-x -m -s 10000 -q " hello world " +c +2 --select-1 -0 ' <<
'--no-mouse -f "goodbye world" --black --nth=3,-1,2 --reverse --print-query'
'--no-mouse -f "goodbye world" --black --with-nth=3,-3..,2 --nth=3,-1,2 --reverse --print-query'
fzf = FZF.new []
assert_equal 10000, fzf.sort
assert_equal ' hello world ',
@@ -64,13 +110,14 @@ class TestFZF < MiniTest::Unit::TestCase
assert_equal true, fzf.reverse
assert_equal true, fzf.print_query
assert_equal [2..2, -1..-1, 1..1], fzf.nth
assert_equal [2..2, -3..-1, 1..1], fzf.with_nth
end
def test_option_parser
# Long opts
fzf = FZF.new %w[--sort=2000 --no-color --multi +i --query hello --select-1
--exit-0 --filter=howdy --extended-exact
--no-mouse --no-256 --nth=1 --reverse --prompt (hi)
--no-mouse --no-256 --nth=1 --with-nth=.. --reverse --prompt (hi)
--print-query]
assert_equal 2000, fzf.sort
assert_equal true, fzf.multi
@@ -85,6 +132,7 @@ class TestFZF < MiniTest::Unit::TestCase
assert_equal 'howdy', fzf.filter
assert_equal :exact, fzf.extended
assert_equal [0..0], fzf.nth
assert_equal nil, fzf.with_nth
assert_equal true, fzf.reverse
assert_equal '(hi)', fzf.prompt
assert_equal true, fzf.print_query
@@ -167,13 +215,12 @@ class TestFZF < MiniTest::Unit::TestCase
end
end
# FIXME Only on 1.9 or above
def test_width
fzf = FZF.new []
assert_equal 5, fzf.width('abcde')
assert_equal 4, fzf.width('한글')
assert_equal 5, fzf.width('한글.')
end
end if RUBY_VERSION >= '1.9'
def test_trim
fzf = FZF.new []
@@ -186,7 +233,7 @@ class TestFZF < MiniTest::Unit::TestCase
assert_equal ['가나a', 6], fzf.trim('가나ab라마바사.', 5, false)
assert_equal ['가나ab', 5], fzf.trim('가나ab라마바사.', 6, false)
assert_equal ['가나ab', 5], fzf.trim('가나ab라마바사.', 7, false)
end
end if RUBY_VERSION >= '1.9'
def test_format
fzf = FZF.new []
@@ -562,28 +609,41 @@ class TestFZF < MiniTest::Unit::TestCase
assert_equal [[list[0], [[8, 9]]]], matcher.match(list, '^s', '', '')
end
def stream_for str
def stream_for str, delay = 0
StringIO.new(str).tap do |sio|
sio.instance_eval do
alias org_gets gets
def gets
org_gets.tap { |e| sleep 0.5 unless e.nil? }
org_gets.tap { |e| sleep(@delay) unless e.nil? }
end
def reopen _
end
end
sio.instance_variable_set :@delay, delay
end
end
def assert_fzf_output opts, given, expected
stream = stream_for given
output = StringIO.new
output = stream_for ''
def sorted_lines line
line.split($/).sort
end
begin
tty = MockTTY.new
$stdout = output
FZF.new(opts, stream).start
fzf = FZF.new(opts, stream)
fzf.instance_variable_set :@tty, tty
thr = block_given? && Thread.new { yield tty }
fzf.start
thr && thr.join
rescue SystemExit => e
assert_equal 0, e.status
assert_equal expected, output.string.chomp
assert_equal sorted_lines(expected), sorted_lines(output.string)
ensure
$stdout = STDOUT
end
@@ -612,15 +672,12 @@ class TestFZF < MiniTest::Unit::TestCase
end
def test_select_1_ambiguity
stream = stream_for "Hello\nWorld"
begin
Timeout::timeout(3) do
FZF.new(%w[--query=o --select-1], stream).start
Timeout::timeout(0.5) do
assert_fzf_output %w[--query=o --select-1], "hello\nworld", "should not match"
end
flunk 'Should not reach here'
rescue Exception => e
rescue Timeout::Error
Curses.close_screen
assert_instance_of Timeout::Error, e
end
end
@@ -637,6 +694,32 @@ class TestFZF < MiniTest::Unit::TestCase
assert_fzf_output %w[--exit-0], '', ''
end
def test_with_nth
source = "hello world\nbatman"
assert_fzf_output %w[-0 -1 --with-nth=2,1 -x -q ^worl],
source, 'hello world'
assert_fzf_output %w[-0 -1 --with-nth=2,1 -x -q llo$],
source, 'hello world'
assert_fzf_output %w[-0 -1 --with-nth=.. -x -q llo$],
source, ''
assert_fzf_output %w[-0 -1 --with-nth=2,2,2,..,1 -x -q worlworlworlhellworlhell],
source, 'hello world'
assert_fzf_output %w[-0 -1 --with-nth=1,1,-1,1 -x -q batbatbatbat],
source, 'batman'
end
def test_with_nth_transform
fzf = FZF.new %w[--with-nth 2..,1]
assert_equal 'my world hello', fzf.transform('hello my world')
assert_equal 'my world hello', fzf.transform('hello my world')
assert_equal 'my world hello', fzf.transform('hello my world ')
fzf = FZF.new %w[--with-nth 2,-1,2]
assert_equal 'my world my', fzf.transform('hello my world')
assert_equal 'world world world', fzf.transform('hello world')
assert_equal 'world world world', fzf.transform('hello world ')
end
def test_ranking_overlap_match_regions
list = [
'1 3 4 2',
@@ -681,5 +764,87 @@ class TestFZF < MiniTest::Unit::TestCase
# **[***** #] => [******# ]
assert_equal [true, 0, 6], fzf.constrain(2, 10, 7, 10)
end
def test_invalid_utf8
tmp = Tempfile.new('fzf')
tmp << 'hello ' << [0xff].pack('C*') << ' world' << $/ << [0xff].pack('C*')
tmp.close
begin
Timeout::timeout(0.5) do
FZF.new(%w[-n..,1,2.. -q^ -x], File.open(tmp.path)).start
end
rescue Timeout::Error
Curses.close_screen
end
ensure
tmp.unlink
end
def test_with_nth_mock_tty
# Manual selection with input
assert_fzf_output ["--with-nth=2,1"], "hello world", "hello world" do |tty|
tty << "world"
tty << "hell"
tty << "\r"
end
# Manual selection without input
assert_fzf_output ["--with-nth=2,1"], "hello world", "hello world" do |tty|
tty << "\r"
end
# Manual selection with input and --multi
lines = "hello world\ngoodbye world"
assert_fzf_output %w[-m --with-nth=2,1], lines, lines do |tty|
tty << "o"
tty << "\e[Z\e[Z"
tty << "\r"
end
# Manual selection without input and --multi
assert_fzf_output %w[-m --with-nth=2,1], lines, lines do |tty|
tty << "\e[Z\e[Z"
tty << "\r"
end
# ALT-D
assert_fzf_output %w[--print-query], "", "hello baby = world" do |tty|
tty << "hello world baby"
tty << alt(:b) << alt(:b) << alt(:d)
tty << ctrl(:e) << " = " << ctrl(:y)
tty << "\r"
end
# ALT-BACKSPACE
assert_fzf_output %w[--print-query], "", "hello baby = world " do |tty|
tty << "hello world baby"
tty << alt(:b) << alt(127.chr)
tty << ctrl(:e) << " = " << ctrl(:y)
tty << "\r"
end
# Word-movements
assert_fzf_output %w[--print-query], "", "ello!_orld!~ foo=?" do |tty|
tty << "hello_world==baby?"
tty << alt(:b) << ctrl(:d)
tty << alt(:b) << ctrl(:d)
tty << alt(:b) << ctrl(:d)
tty << alt(:f) << '!'
tty << alt(:f) << '!'
tty << alt(:d) << '~'
tty << " foo=bar foo=bar"
tty << ctrl(:w)
tty << alt(127.chr)
tty << "\r"
end
end
def alt chr
"\e#{chr}"
end
def ctrl char
char.to_s.ord - 'a'.ord + 1
end
end

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
confirm() {
while [ 1 ]; do
@@ -18,18 +18,24 @@ remove() {
}
remove_line() {
src=$(readlink "$2")
src=$(readlink "$1")
if [ $? -eq 0 ]; then
echo "Remove from $2 ($src):"
echo "Remove from $1 ($src):"
else
src=$2
echo "Remove from $2:"
src=$1
echo "Remove from $1:"
fi
shift
line_no=1
match=0
while [ 1 ]; do
line=$(sed -n "$line_no,\$p" "$src" | grep -m1 -nF "$1") || break
while [ -n "$1" ]; do
line=$(sed -n "$line_no,\$p" "$src" | \grep -m1 -nF "$1")
if [ $? -ne 0 ]; then
shift
line_no=1
continue
fi
line_no=$(( $(sed 's/:.*//' <<< "$line") + line_no - 1 ))
content=$(sed 's/^[0-9]*://' <<< "$line")
match=1
@@ -50,12 +56,14 @@ remove_line() {
for shell in bash zsh; do
remove ~/.fzf.${shell}
remove_line "source ~/.fzf.${shell}" ~/.${shell}rc
remove_line ~/.${shell}rc \
"[ -f ~/.fzf.${shell} ] && source ~/.fzf.${shell}" \
"source ~/.fzf.${shell}"
done
bind_file=~/.config/fish/functions/fish_user_key_bindings.fish
if [ -f "$bind_file" ]; then
remove_line "fzf_key_bindings" "$bind_file"
remove_line "$bind_file" "fzf_key_bindings"
fi
if [ -d ~/.config/fish/functions ]; then