mirror of
https://github.com/Llewellynvdm/fzf.git
synced 2024-12-23 11:29:01 +00:00
Implement multi-select mode (#3)
This commit is contained in:
parent
11a1010e9e
commit
ddf6e5ef1e
@ -71,6 +71,7 @@ Usage
|
|||||||
```
|
```
|
||||||
usage: fzf [options]
|
usage: fzf [options]
|
||||||
|
|
||||||
|
-m, --multi Enable multi-select
|
||||||
-s, --sort=MAX Maximum number of matched items to sort. Default: 500
|
-s, --sort=MAX Maximum number of matched items to sort. Default: 500
|
||||||
+s, --no-sort Keep the sequence unchanged.
|
+s, --no-sort Keep the sequence unchanged.
|
||||||
+i Case-sensitive match
|
+i Case-sensitive match
|
||||||
@ -110,6 +111,9 @@ The following readline key bindings should also work as expected.
|
|||||||
- CTRL-B / CTRL-F
|
- CTRL-B / CTRL-F
|
||||||
- CTRL-W / CTRL-U
|
- CTRL-W / CTRL-U
|
||||||
|
|
||||||
|
If you enable multi-select mode with `-m` option, you can select multiple items
|
||||||
|
with TAB key.
|
||||||
|
|
||||||
Usage as Vim plugin
|
Usage as Vim plugin
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
50
fzf
50
fzf
@ -10,7 +10,7 @@
|
|||||||
# URL: https://github.com/junegunn/fzf
|
# URL: https://github.com/junegunn/fzf
|
||||||
# Author: Junegunn Choi
|
# Author: Junegunn Choi
|
||||||
# License: MIT
|
# License: MIT
|
||||||
# Last update: November 4, 2013
|
# Last update: November 10, 2013
|
||||||
#
|
#
|
||||||
# Copyright (c) 2013 Junegunn Choi
|
# Copyright (c) 2013 Junegunn Choi
|
||||||
#
|
#
|
||||||
@ -38,6 +38,7 @@
|
|||||||
def usage x
|
def usage x
|
||||||
puts %[usage: fzf [options]
|
puts %[usage: fzf [options]
|
||||||
|
|
||||||
|
-m, --multi Enable multi-select
|
||||||
-s, --sort=MAX Maximum number of matched items to sort. Default: 500.
|
-s, --sort=MAX Maximum number of matched items to sort. Default: 500.
|
||||||
+s, --no-sort Do not sort the result. Keep the sequence unchanged.
|
+s, --no-sort Do not sort the result. Keep the sequence unchanged.
|
||||||
+i Case-sensitive match
|
+i Case-sensitive match
|
||||||
@ -50,8 +51,9 @@ $stdout.reopen($stderr)
|
|||||||
|
|
||||||
usage 0 unless (%w[--help -h] & ARGV).empty?
|
usage 0 unless (%w[--help -h] & ARGV).empty?
|
||||||
@rxflag = ARGV.delete('+i') ? 0 : Regexp::IGNORECASE
|
@rxflag = ARGV.delete('+i') ? 0 : Regexp::IGNORECASE
|
||||||
@sort = (ARGV.delete('+s') || ARGV.delete('--no-sort')) ? nil : 500
|
@sort = %w[+s --no-sort].map { |e| ARGV.delete e }.compact.empty? ? 500 : nil
|
||||||
@color = (ARGV.delete('+c') || ARGV.delete('--no-color')).nil?
|
@color = %w[+c --no-color].map { |e| ARGV.delete e }.compact.empty?
|
||||||
|
@multi = !%w[-m --multi].map { |e| ARGV.delete e }.compact.empty?
|
||||||
rest = ARGV.join ' '
|
rest = ARGV.join ' '
|
||||||
if sort = rest.match(/(-s|--sort=?) ?([0-9]+)/)
|
if sort = rest.match(/(-s|--sort=?) ?([0-9]+)/)
|
||||||
usage 1 unless @sort
|
usage 1 unless @sort
|
||||||
@ -74,6 +76,7 @@ require 'curses'
|
|||||||
@cursor_x = 0
|
@cursor_x = 0
|
||||||
@vcursor = 0
|
@vcursor = 0
|
||||||
@events = {}
|
@events = {}
|
||||||
|
@selects = {} # ordered >= 1.9
|
||||||
|
|
||||||
case RUBY_PLATFORM
|
case RUBY_PLATFORM
|
||||||
when /darwin/
|
when /darwin/
|
||||||
@ -180,7 +183,7 @@ def print_input
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def print_info msg = nil
|
def print_info selected, msg = nil
|
||||||
@fan ||= '-\|/-\|/'.split(//)
|
@fan ||= '-\|/-\|/'.split(//)
|
||||||
C.setpos cursor_y - 1, 0
|
C.setpos cursor_y - 1, 0
|
||||||
C.clrtoeol
|
C.clrtoeol
|
||||||
@ -194,6 +197,7 @@ def print_info msg = nil
|
|||||||
end
|
end
|
||||||
C.attron color(:info, false) do
|
C.attron color(:info, false) do
|
||||||
C.addstr "#{prefix}#{@matches.length}/#{@count}"
|
C.addstr "#{prefix}#{@matches.length}/#{@count}"
|
||||||
|
C.addstr " (#{selected})" if selected > 0
|
||||||
C.addstr msg if msg
|
C.addstr msg if msg
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -329,6 +333,7 @@ searcher = Thread.new {
|
|||||||
events = {}
|
events = {}
|
||||||
fcache = {}
|
fcache = {}
|
||||||
matches = []
|
matches = []
|
||||||
|
selects = {}
|
||||||
mcount = 0 # match count
|
mcount = 0 # match count
|
||||||
plcount = 0 # prev list count
|
plcount = 0 # prev list count
|
||||||
q = ''
|
q = ''
|
||||||
@ -355,15 +360,18 @@ searcher = Thread.new {
|
|||||||
@new = []
|
@new = []
|
||||||
fcache = {}
|
fcache = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if events[:select]
|
||||||
|
selects = @selects.dup
|
||||||
|
end
|
||||||
end#mtx
|
end#mtx
|
||||||
|
|
||||||
new_search = events[:key] || events[:new]
|
new_search = events[:key] || events.delete(:new)
|
||||||
user_input = events[:key] || events[:vcursor]
|
user_input = events[:key] || events[:vcursor] || events.delete(:select)
|
||||||
progress = 0
|
progress = 0
|
||||||
started_at = Time.now
|
started_at = Time.now
|
||||||
|
|
||||||
if new_search && !@lists.empty?
|
if new_search && !@lists.empty?
|
||||||
events.delete :new
|
|
||||||
q = events.delete(:key) || q
|
q = events.delete(:key) || q
|
||||||
|
|
||||||
unless q.empty?
|
unless q.empty?
|
||||||
@ -392,7 +400,7 @@ searcher = Thread.new {
|
|||||||
found.concat(cache[q] ||= q.empty? ? list : begin
|
found.concat(cache[q] ||= q.empty? ? list : begin
|
||||||
if progress < 100 && Time.now - started_at > 0.5
|
if progress < 100 && Time.now - started_at > 0.5
|
||||||
@smtx.synchronize do
|
@smtx.synchronize do
|
||||||
print_info " (#{progress}%)"
|
print_info selects.length, " (#{progress}%)"
|
||||||
refresh
|
refresh
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -482,7 +490,9 @@ searcher = Thread.new {
|
|||||||
C.setpos row, 0
|
C.setpos row, 0
|
||||||
C.clrtoeol
|
C.clrtoeol
|
||||||
cprint chosen ? '>' : ' ', color(:red, true)
|
cprint chosen ? '>' : ' ', color(:red, true)
|
||||||
cprint ' ', chosen ? color(:chosen) : 0
|
selected = selects.include?([*item][0])
|
||||||
|
cprint selected ? '>' : ' ',
|
||||||
|
chosen ? color(:chosen) : (selected ? color(:red, true) : 0)
|
||||||
|
|
||||||
C.attron color(:chosen, true) if chosen
|
C.attron color(:chosen, true) if chosen
|
||||||
|
|
||||||
@ -497,7 +507,7 @@ searcher = Thread.new {
|
|||||||
C.attroff color(:chosen, true) if chosen
|
C.attroff color(:chosen, true) if chosen
|
||||||
end
|
end
|
||||||
|
|
||||||
print_info if !@lists.empty? || events[:loaded]
|
print_info selects.length if !@lists.empty? || events[:loaded]
|
||||||
refresh
|
refresh
|
||||||
end
|
end
|
||||||
end#while
|
end#while
|
||||||
@ -532,6 +542,18 @@ begin
|
|||||||
cursor = ridx
|
cursor = ridx
|
||||||
},
|
},
|
||||||
127 => proc { input[cursor -= 1] = '' if cursor > 0 },
|
127 => proc { input[cursor -= 1] = '' if cursor > 0 },
|
||||||
|
9 => proc {
|
||||||
|
emit(:select) {
|
||||||
|
if sel = [*@matches.fetch(@vcursor, [])][0]
|
||||||
|
if @selects.has_key? sel
|
||||||
|
@selects.delete sel
|
||||||
|
else
|
||||||
|
@selects[sel] = 1
|
||||||
|
end
|
||||||
|
@vcursor = [0, @vcursor - 1].max
|
||||||
|
end
|
||||||
|
} if @multi
|
||||||
|
},
|
||||||
:left => proc { cursor = [0, cursor - 1].max },
|
:left => proc { cursor = [0, cursor - 1].max },
|
||||||
:right => proc { cursor = [input.length, cursor + 1].min },
|
:right => proc { cursor = [input.length, cursor + 1].min },
|
||||||
}
|
}
|
||||||
@ -576,6 +598,12 @@ begin
|
|||||||
end
|
end
|
||||||
ensure
|
ensure
|
||||||
C.close_screen
|
C.close_screen
|
||||||
stdout.puts got if got
|
if got
|
||||||
|
@selects.delete got
|
||||||
|
@selects.each do |sel, _|
|
||||||
|
stdout.puts sel
|
||||||
|
end
|
||||||
|
stdout.puts got
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
Gem::Specification.new do |spec|
|
Gem::Specification.new do |spec|
|
||||||
spec.name = 'fzf'
|
spec.name = 'fzf'
|
||||||
spec.version = '0.2.2'
|
spec.version = '0.3.0'
|
||||||
spec.authors = ['Junegunn Choi']
|
spec.authors = ['Junegunn Choi']
|
||||||
spec.email = ['junegunn.c@gmail.com']
|
spec.email = ['junegunn.c@gmail.com']
|
||||||
spec.description = %q{Fuzzy finder for your shell}
|
spec.description = %q{Fuzzy finder for your shell}
|
||||||
|
Loading…
Reference in New Issue
Block a user