Completely remove mouse support
Since the version 0.7.0, fzf internally used Curses.getch() call to take user input, which allowed it to support mouse input as well. However it has turned out that Curses.getch() has introduced glitches that cannot be easily handled (e.g. Try resize the terminal). So I finally decided that it's not worth the trouble and drop the mouse support.
This commit is contained in:
parent
65ae6cabb5
commit
2fb8ae010f
@ -58,7 +58,6 @@ usage: fzf [options]
|
|||||||
-i Case-insensitive match (default: smart-case match)
|
-i Case-insensitive match (default: smart-case match)
|
||||||
+i Case-sensitive match
|
+i Case-sensitive match
|
||||||
+c, --no-color Disable colors
|
+c, --no-color Disable colors
|
||||||
--no-mouse Disable mouse
|
|
||||||
|
|
||||||
Environment variables
|
Environment variables
|
||||||
FZF_DEFAULT_COMMAND Default command to use when input is tty
|
FZF_DEFAULT_COMMAND Default command to use when input is tty
|
||||||
@ -102,9 +101,6 @@ The following readline key bindings should also work as expected.
|
|||||||
If you enable multi-select mode with `-m` option, you can select multiple items
|
If you enable multi-select mode with `-m` option, you can select multiple items
|
||||||
with TAB or Shift-TAB key.
|
with TAB or Shift-TAB key.
|
||||||
|
|
||||||
You can also use mouse. Click on an item to select it or shift-click to select
|
|
||||||
multiple items. Use mouse wheel to move the cursor up and down.
|
|
||||||
|
|
||||||
### Extended-search mode
|
### Extended-search mode
|
||||||
|
|
||||||
With `-x` or `--extended` option, fzf will start in "extended-search mode".
|
With `-x` or `--extended` option, fzf will start in "extended-search mode".
|
||||||
|
196
fzf
196
fzf
@ -7,7 +7,7 @@
|
|||||||
# / __/ / /_/ __/
|
# / __/ / /_/ __/
|
||||||
# /_/ /___/_/ Fuzzy finder for your shell
|
# /_/ /___/_/ Fuzzy finder for your shell
|
||||||
#
|
#
|
||||||
# Version: 0.7.3 (March 5, 2014)
|
# Version: 0.8.0 (March 6, 2014)
|
||||||
#
|
#
|
||||||
# Author: Junegunn Choi
|
# Author: Junegunn Choi
|
||||||
# URL: https://github.com/junegunn/fzf
|
# URL: https://github.com/junegunn/fzf
|
||||||
@ -50,7 +50,7 @@ end
|
|||||||
|
|
||||||
class FZF
|
class FZF
|
||||||
C = Curses
|
C = Curses
|
||||||
attr_reader :rxflag, :sort, :color, :mouse, :multi, :query, :filter, :extended
|
attr_reader :rxflag, :sort, :color, :multi, :query, :filter, :extended
|
||||||
|
|
||||||
class AtomicVar
|
class AtomicVar
|
||||||
def initialize value
|
def initialize value
|
||||||
@ -79,9 +79,7 @@ class FZF
|
|||||||
@color = true
|
@color = true
|
||||||
@multi = false
|
@multi = false
|
||||||
@extended = nil
|
@extended = nil
|
||||||
@mouse = true
|
|
||||||
@filter = nil
|
@filter = nil
|
||||||
@pending = nil
|
|
||||||
|
|
||||||
argv =
|
argv =
|
||||||
if opts = ENV['FZF_DEFAULT_OPTS']
|
if opts = ENV['FZF_DEFAULT_OPTS']
|
||||||
@ -102,7 +100,6 @@ class FZF
|
|||||||
when '+i' then @rxflag = 0
|
when '+i' then @rxflag = 0
|
||||||
when '-c', '--color' then @color = true
|
when '-c', '--color' then @color = true
|
||||||
when '+c', '--no-color' then @color = false
|
when '+c', '--no-color' then @color = false
|
||||||
when '--no-mouse' then @mouse = false
|
|
||||||
when '+s', '--no-sort' then @sort = nil
|
when '+s', '--no-sort' then @sort = nil
|
||||||
when '-q', '--query'
|
when '-q', '--query'
|
||||||
usage 1, 'query string required' unless query = argv.shift
|
usage 1, 'query string required' unless query = argv.shift
|
||||||
@ -129,11 +126,11 @@ class FZF
|
|||||||
|
|
||||||
@source = source.clone
|
@source = source.clone
|
||||||
@mtx = Mutex.new
|
@mtx = Mutex.new
|
||||||
@rmtx = Mutex.new
|
|
||||||
@cv = ConditionVariable.new
|
@cv = ConditionVariable.new
|
||||||
@events = {}
|
@events = {}
|
||||||
@new = []
|
@new = []
|
||||||
@queue = Queue.new
|
@queue = Queue.new
|
||||||
|
@pending = nil
|
||||||
|
|
||||||
unless @filter
|
unless @filter
|
||||||
@query ||= AtomicVar.new('')
|
@query ||= AtomicVar.new('')
|
||||||
@ -207,7 +204,6 @@ class FZF
|
|||||||
-i Case-insensitive match (default: smart-case match)
|
-i Case-insensitive match (default: smart-case match)
|
||||||
+i Case-sensitive match
|
+i Case-sensitive match
|
||||||
+c, --no-color Disable colors
|
+c, --no-color Disable colors
|
||||||
--no-mouse Disable mouse
|
|
||||||
|
|
||||||
Environment variables
|
Environment variables
|
||||||
FZF_DEFAULT_COMMAND Default command to use when input is tty
|
FZF_DEFAULT_COMMAND Default command to use when input is tty
|
||||||
@ -510,11 +506,6 @@ class FZF
|
|||||||
|
|
||||||
def init_screen
|
def init_screen
|
||||||
C.init_screen
|
C.init_screen
|
||||||
if @mouse
|
|
||||||
C.mouseinterval 0
|
|
||||||
C.mousemask C::ALL_MOUSE_EVENTS
|
|
||||||
end
|
|
||||||
C.stdscr.keypad(true)
|
|
||||||
C.start_color
|
C.start_color
|
||||||
dbg =
|
dbg =
|
||||||
if C.respond_to?(:use_default_colors)
|
if C.respond_to?(:use_default_colors)
|
||||||
@ -524,7 +515,6 @@ class FZF
|
|||||||
C::COLOR_BLACK
|
C::COLOR_BLACK
|
||||||
end
|
end
|
||||||
C.raw
|
C.raw
|
||||||
C.nonl
|
|
||||||
C.noecho
|
C.noecho
|
||||||
|
|
||||||
if @color
|
if @color
|
||||||
@ -582,7 +572,6 @@ class FZF
|
|||||||
exit 1
|
exit 1
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
$stdin.reopen IO.open(IO.sysopen('/dev/tty'), 'r') if curses
|
|
||||||
@source
|
@source
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -722,10 +711,8 @@ class FZF
|
|||||||
Thread.new do
|
Thread.new do
|
||||||
begin
|
begin
|
||||||
while blk = @queue.shift
|
while blk = @queue.shift
|
||||||
@rmtx.synchronize do
|
blk.call
|
||||||
blk.call
|
refresh
|
||||||
refresh
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
@main.raise e
|
@main.raise e
|
||||||
@ -757,54 +744,67 @@ class FZF
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_mouse st, *states
|
def get_input actions
|
||||||
states.any? { |s| s & st > 0 }
|
@tty ||= IO.open(IO.sysopen('/dev/tty'), 'r')
|
||||||
end
|
|
||||||
|
|
||||||
def to_printable ch
|
|
||||||
if ch.is_a?(Fixnum)
|
|
||||||
# Ruby 1.8
|
|
||||||
if (ch.chr rescue '') =~ /[[:print:]]/
|
|
||||||
ch = ch.chr
|
|
||||||
elsif (nch = num_unicode_bytes(ch)) > 1
|
|
||||||
chs = [ch]
|
|
||||||
(nch - 1).times do |i|
|
|
||||||
chs << getch_nb
|
|
||||||
end
|
|
||||||
# UTF-8 TODO Ruby 1.8
|
|
||||||
ch = chs.pack('C*').force_encoding('UTF-8')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
ch.is_a?(String) && ch =~ /[[:print:]]/ && ch
|
|
||||||
end
|
|
||||||
|
|
||||||
def getch_nb
|
|
||||||
@rmtx.synchronize { C.getch }
|
|
||||||
end
|
|
||||||
|
|
||||||
def getch
|
|
||||||
if pending = @pending
|
if pending = @pending
|
||||||
@pending = nil
|
@pending = nil
|
||||||
return pending
|
return pending
|
||||||
end
|
end
|
||||||
|
|
||||||
C.stdscr.timeout = -1
|
str = ''
|
||||||
c = C.getch
|
while true
|
||||||
C.stdscr.timeout = 0
|
ord =
|
||||||
if ch = to_printable(c)
|
if str.empty?
|
||||||
chs = [ch]
|
@tty.getc.ord
|
||||||
while AFTER_1_9 && c = getch_nb
|
|
||||||
if ch = to_printable(c)
|
|
||||||
chs << ch
|
|
||||||
else
|
else
|
||||||
@pending = c
|
begin
|
||||||
break
|
ord = @tty.read_nonblock(1).ord
|
||||||
|
if (nb = num_unicode_bytes(ord)) > 1
|
||||||
|
ords = [ord]
|
||||||
|
(nb - 1).times do |_|
|
||||||
|
ords << @tty.read_nonblock(1).ord
|
||||||
|
end
|
||||||
|
# UTF-8 TODO Ruby 1.8
|
||||||
|
ords.pack('C*').force_encoding('UTF-8')
|
||||||
|
else
|
||||||
|
ord
|
||||||
|
end
|
||||||
|
rescue Exception
|
||||||
|
return str
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ord =
|
||||||
|
case ord = (@tty.read_nonblock(1).ord rescue :esc)
|
||||||
|
when 91
|
||||||
|
case (@tty.read_nonblock(1).ord rescue nil)
|
||||||
|
when 68 then ctrl(:b)
|
||||||
|
when 67 then ctrl(:f)
|
||||||
|
when 66 then ctrl(:j)
|
||||||
|
when 65 then ctrl(:k)
|
||||||
|
when 90 then :stab
|
||||||
|
else next
|
||||||
|
end
|
||||||
|
when 'b', 98 then :alt_b
|
||||||
|
when 'f', 102 then :alt_f
|
||||||
|
when :esc then :esc
|
||||||
|
else next
|
||||||
|
end if ord == 27
|
||||||
|
|
||||||
|
if actions.has_key?(ord)
|
||||||
|
if str.empty?
|
||||||
|
return ord
|
||||||
|
else
|
||||||
|
@pending = ord
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
else
|
||||||
|
unless ord.is_a? String
|
||||||
|
ord = [ord].pack('U*')
|
||||||
|
end
|
||||||
|
str << ord if ord =~ /[[:print:]]/
|
||||||
end
|
end
|
||||||
chs
|
|
||||||
else
|
|
||||||
c
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -841,13 +841,7 @@ class FZF
|
|||||||
else
|
else
|
||||||
@selects[sel] = 1
|
@selects[sel] = 1
|
||||||
end
|
end
|
||||||
vselect { |v|
|
vselect { |v| v + (o == :stab ? 1 : -1) }
|
||||||
v + case o
|
|
||||||
when :select then 0
|
|
||||||
when C::KEY_BTAB then 1
|
|
||||||
else -1
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
},
|
},
|
||||||
ctrl(:b) => proc { cursor = [0, cursor - 1].max; nil },
|
ctrl(:b) => proc { cursor = [0, cursor - 1].max; nil },
|
||||||
@ -859,76 +853,26 @@ class FZF
|
|||||||
nil
|
nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
actions[C::KEY_UP] = actions[ctrl(:p)] = actions[ctrl(:k)]
|
actions[ctrl(:p)] = actions[ctrl(:k)]
|
||||||
actions[C::KEY_DOWN] = actions[ctrl(:n)] = actions[ctrl(:j)]
|
actions[ctrl(:n)] = actions[ctrl(:j)]
|
||||||
actions[C::KEY_LEFT] = actions[ctrl(:b)]
|
actions[:stab] = actions[ctrl(:i)]
|
||||||
actions[C::KEY_RIGHT] = actions[ctrl(:f)]
|
actions[127] = actions[ctrl(:h)]
|
||||||
actions[C::KEY_BTAB] = actions[:select] = actions[ctrl(:i)]
|
|
||||||
actions[C::KEY_BACKSPACE] = actions[127] = actions[ctrl(:h)]
|
|
||||||
actions[ctrl(:q)] = actions[ctrl(:g)] = actions[ctrl(:c)] = actions[:esc]
|
actions[ctrl(:q)] = actions[ctrl(:g)] = actions[ctrl(:c)] = actions[:esc]
|
||||||
|
|
||||||
emit(:key) { [@query.get, cursor] } unless @query.empty?
|
emit(:key) { [@query.get, cursor] } unless @query.empty?
|
||||||
pmv = nil
|
|
||||||
while true
|
while true
|
||||||
@cursor_x.set cursor
|
@cursor_x.set cursor
|
||||||
render { print_input }
|
render { print_input }
|
||||||
|
|
||||||
case ch = getch
|
if key = get_input(actions)
|
||||||
when C::KEY_MOUSE
|
upd = actions.fetch(key, proc { |str|
|
||||||
if m = C.getmouse
|
input.insert cursor, str
|
||||||
st = m.bstate
|
cursor += str.length
|
||||||
if test_mouse(st, C::BUTTON1_PRESSED, C::BUTTON1_RELEASED)
|
}).call(key)
|
||||||
if m.y == cursor_y
|
|
||||||
# TODO Wide-characters
|
# Dispatch key event
|
||||||
cursor = [0, [input.length, m.x - 2].min].max
|
emit(:key) { [@query.set(input.dup), cursor] } if upd
|
||||||
elsif m.x > 1 && m.y <= max_items
|
|
||||||
vselect { |v|
|
|
||||||
tv = max_items - m.y - 1
|
|
||||||
if test_mouse(st, C::BUTTON1_RELEASED)
|
|
||||||
if test_mouse(st, C::BUTTON_SHIFT)
|
|
||||||
ch = :select
|
|
||||||
elsif pmv == tv
|
|
||||||
ch = ctrl(:m)
|
|
||||||
end
|
|
||||||
pmv = tv
|
|
||||||
end
|
|
||||||
tv
|
|
||||||
}
|
|
||||||
end
|
|
||||||
elsif test_mouse(st, 0x8000000, C::BUTTON2_PRESSED)
|
|
||||||
ch = C::KEY_DOWN
|
|
||||||
elsif test_mouse(st, C::BUTTON4_PRESSED)
|
|
||||||
ch = C::KEY_UP
|
|
||||||
end
|
|
||||||
end
|
|
||||||
when 27
|
|
||||||
C.stdscr.timeout = 0
|
|
||||||
ch = # Typeahead arrow keys
|
|
||||||
case ch2 = getch_nb
|
|
||||||
when '[', 91
|
|
||||||
case ch3 = getch_nb
|
|
||||||
when 'D', 68 then ctrl(:b)
|
|
||||||
when 'C', 67 then ctrl(:f)
|
|
||||||
when 'B', 66 then ctrl(:j)
|
|
||||||
when 'A', 65 then ctrl(:k)
|
|
||||||
else ch3
|
|
||||||
end
|
|
||||||
when 'b', 98 then :alt_b
|
|
||||||
when 'f', 102 then :alt_f
|
|
||||||
when nil then :esc
|
|
||||||
else ch2
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
upd = actions.fetch(ch, proc { |ch|
|
|
||||||
if ch.is_a? Array
|
|
||||||
input.insert cursor, ch.join
|
|
||||||
cursor += ch.length
|
|
||||||
end
|
|
||||||
}).call(ch)
|
|
||||||
|
|
||||||
# Dispatch key event
|
|
||||||
emit(:key) { [@query.set(input.dup), cursor] } if upd
|
|
||||||
end
|
end
|
||||||
ensure
|
ensure
|
||||||
C.close_screen
|
C.close_screen
|
||||||
|
@ -20,7 +20,6 @@ class TestFZF < MiniTest::Unit::TestCase
|
|||||||
assert_equal false, fzf.multi
|
assert_equal false, fzf.multi
|
||||||
assert_equal true, fzf.color
|
assert_equal true, fzf.color
|
||||||
assert_equal nil, fzf.rxflag
|
assert_equal nil, fzf.rxflag
|
||||||
assert_equal true, fzf.mouse
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_environment_variables
|
def test_environment_variables
|
||||||
@ -29,7 +28,7 @@ class TestFZF < MiniTest::Unit::TestCase
|
|||||||
fzf = FZF.new []
|
fzf = FZF.new []
|
||||||
assert_equal 20000, fzf.sort
|
assert_equal 20000, fzf.sort
|
||||||
|
|
||||||
ENV['FZF_DEFAULT_OPTS'] = '-x -m -s 10000 -q " hello world " +c --no-mouse -f "goodbye world"'
|
ENV['FZF_DEFAULT_OPTS'] = '-x -m -s 10000 -q " hello world " +c -f "goodbye world"'
|
||||||
fzf = FZF.new []
|
fzf = FZF.new []
|
||||||
assert_equal 10000, fzf.sort
|
assert_equal 10000, fzf.sort
|
||||||
assert_equal ' hello world ',
|
assert_equal ' hello world ',
|
||||||
@ -39,17 +38,15 @@ class TestFZF < MiniTest::Unit::TestCase
|
|||||||
assert_equal :fuzzy, fzf.extended
|
assert_equal :fuzzy, fzf.extended
|
||||||
assert_equal true, fzf.multi
|
assert_equal true, fzf.multi
|
||||||
assert_equal false, fzf.color
|
assert_equal false, fzf.color
|
||||||
assert_equal false, fzf.mouse
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_option_parser
|
def test_option_parser
|
||||||
# Long opts
|
# Long opts
|
||||||
fzf = FZF.new %w[--sort=2000 --no-color --multi +i --query hello
|
fzf = FZF.new %w[--sort=2000 --no-color --multi +i --query hello
|
||||||
--filter=howdy --extended-exact --no-mouse]
|
--filter=howdy --extended-exact]
|
||||||
assert_equal 2000, fzf.sort
|
assert_equal 2000, fzf.sort
|
||||||
assert_equal true, fzf.multi
|
assert_equal true, fzf.multi
|
||||||
assert_equal false, fzf.color
|
assert_equal false, fzf.color
|
||||||
assert_equal false, fzf.mouse
|
|
||||||
assert_equal 0, fzf.rxflag
|
assert_equal 0, fzf.rxflag
|
||||||
assert_equal 'hello', fzf.query.get
|
assert_equal 'hello', fzf.query.get
|
||||||
assert_equal 'howdy', fzf.filter
|
assert_equal 'howdy', fzf.filter
|
||||||
@ -61,7 +58,6 @@ class TestFZF < MiniTest::Unit::TestCase
|
|||||||
assert_equal nil, fzf.sort
|
assert_equal nil, fzf.sort
|
||||||
assert_equal false, fzf.multi
|
assert_equal false, fzf.multi
|
||||||
assert_equal true, fzf.color
|
assert_equal true, fzf.color
|
||||||
assert_equal true, fzf.mouse
|
|
||||||
assert_equal 1, fzf.rxflag
|
assert_equal 1, fzf.rxflag
|
||||||
assert_equal 'b', fzf.filter
|
assert_equal 'b', fzf.filter
|
||||||
assert_equal 'hello', fzf.query.get
|
assert_equal 'hello', fzf.query.get
|
||||||
|
Loading…
x
Reference in New Issue
Block a user