[ruby/reline] Refactor waiting_proc and waiting_operator_proc
(https://github.com/ruby/reline/pull/649) * Fix waiting_proc precedence * Fix waiting_operator bugs * Add waiting_proc and vi_waiting_operator test * Fix vi waiting operator arg number vi_arg and vi_waiting_operator_arg should be multiplied * Implement `yy` copies whole line in vi_command mode * Simplify incremental search cancel test * Add complex vi test with waiting_proc and vi_waiting_operator, split test input https://github.com/ruby/reline/commit/777dffae1c
This commit is contained in:
parent
8d5d6ec6e7
commit
1648c4436e
@ -229,8 +229,8 @@ class Reline::LineEditor
|
|||||||
@vi_clipboard = ''
|
@vi_clipboard = ''
|
||||||
@vi_arg = nil
|
@vi_arg = nil
|
||||||
@waiting_proc = nil
|
@waiting_proc = nil
|
||||||
@waiting_operator_proc = nil
|
@vi_waiting_operator = nil
|
||||||
@waiting_operator_vi_arg = nil
|
@vi_waiting_operator_arg = nil
|
||||||
@completion_journey_state = nil
|
@completion_journey_state = nil
|
||||||
@completion_state = CompletionState::NORMAL
|
@completion_state = CompletionState::NORMAL
|
||||||
@completion_occurs = false
|
@completion_occurs = false
|
||||||
@ -936,37 +936,23 @@ class Reline::LineEditor
|
|||||||
end
|
end
|
||||||
|
|
||||||
private def run_for_operators(key, method_symbol, &block)
|
private def run_for_operators(key, method_symbol, &block)
|
||||||
if @waiting_operator_proc
|
if @vi_waiting_operator
|
||||||
if VI_MOTIONS.include?(method_symbol)
|
if VI_MOTIONS.include?(method_symbol)
|
||||||
old_byte_pointer = @byte_pointer
|
old_byte_pointer = @byte_pointer
|
||||||
@vi_arg = @waiting_operator_vi_arg if @waiting_operator_vi_arg&.> 1
|
@vi_arg = (@vi_arg || 1) * @vi_waiting_operator_arg
|
||||||
block.(true)
|
block.(true)
|
||||||
unless @waiting_proc
|
unless @waiting_proc
|
||||||
byte_pointer_diff = @byte_pointer - old_byte_pointer
|
byte_pointer_diff = @byte_pointer - old_byte_pointer
|
||||||
@byte_pointer = old_byte_pointer
|
@byte_pointer = old_byte_pointer
|
||||||
@waiting_operator_proc.(byte_pointer_diff)
|
send(@vi_waiting_operator, byte_pointer_diff)
|
||||||
else
|
cleanup_waiting
|
||||||
old_waiting_proc = @waiting_proc
|
|
||||||
old_waiting_operator_proc = @waiting_operator_proc
|
|
||||||
current_waiting_operator_proc = @waiting_operator_proc
|
|
||||||
@waiting_proc = proc { |k|
|
|
||||||
old_byte_pointer = @byte_pointer
|
|
||||||
old_waiting_proc.(k)
|
|
||||||
byte_pointer_diff = @byte_pointer - old_byte_pointer
|
|
||||||
@byte_pointer = old_byte_pointer
|
|
||||||
current_waiting_operator_proc.(byte_pointer_diff)
|
|
||||||
@waiting_operator_proc = old_waiting_operator_proc
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
# Ignores operator when not motion is given.
|
# Ignores operator when not motion is given.
|
||||||
block.(false)
|
block.(false)
|
||||||
|
cleanup_waiting
|
||||||
end
|
end
|
||||||
@waiting_operator_proc = nil
|
@vi_arg = nil
|
||||||
@waiting_operator_vi_arg = nil
|
|
||||||
if @vi_arg
|
|
||||||
@vi_arg = nil
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
block.(false)
|
block.(false)
|
||||||
end
|
end
|
||||||
@ -983,7 +969,7 @@ class Reline::LineEditor
|
|||||||
end
|
end
|
||||||
|
|
||||||
def wrap_method_call(method_symbol, method_obj, key, with_operator = false)
|
def wrap_method_call(method_symbol, method_obj, key, with_operator = false)
|
||||||
if @config.editing_mode_is?(:emacs, :vi_insert) and @waiting_proc.nil? and @waiting_operator_proc.nil?
|
if @config.editing_mode_is?(:emacs, :vi_insert) and @vi_waiting_operator.nil?
|
||||||
not_insertion = method_symbol != :ed_insert
|
not_insertion = method_symbol != :ed_insert
|
||||||
process_insert(force: not_insertion)
|
process_insert(force: not_insertion)
|
||||||
end
|
end
|
||||||
@ -1002,11 +988,32 @@ class Reline::LineEditor
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private def cleanup_waiting
|
||||||
|
@waiting_proc = nil
|
||||||
|
@vi_waiting_operator = nil
|
||||||
|
@vi_waiting_operator_arg = nil
|
||||||
|
@searching_prompt = nil
|
||||||
|
@drop_terminate_spaces = false
|
||||||
|
end
|
||||||
|
|
||||||
private def process_key(key, method_symbol)
|
private def process_key(key, method_symbol)
|
||||||
|
if key.is_a?(Symbol)
|
||||||
|
cleanup_waiting
|
||||||
|
elsif @waiting_proc
|
||||||
|
old_byte_pointer = @byte_pointer
|
||||||
|
@waiting_proc.call(key)
|
||||||
|
if @vi_waiting_operator
|
||||||
|
byte_pointer_diff = @byte_pointer - old_byte_pointer
|
||||||
|
@byte_pointer = old_byte_pointer
|
||||||
|
send(@vi_waiting_operator, byte_pointer_diff)
|
||||||
|
cleanup_waiting
|
||||||
|
end
|
||||||
|
@kill_ring.process
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
if method_symbol and respond_to?(method_symbol, true)
|
if method_symbol and respond_to?(method_symbol, true)
|
||||||
method_obj = method(method_symbol)
|
method_obj = method(method_symbol)
|
||||||
else
|
|
||||||
method_obj = nil
|
|
||||||
end
|
end
|
||||||
if method_symbol and key.is_a?(Symbol)
|
if method_symbol and key.is_a?(Symbol)
|
||||||
if @vi_arg and argumentable?(method_obj)
|
if @vi_arg and argumentable?(method_obj)
|
||||||
@ -1028,8 +1035,6 @@ class Reline::LineEditor
|
|||||||
run_for_operators(key, method_symbol) do |with_operator|
|
run_for_operators(key, method_symbol) do |with_operator|
|
||||||
wrap_method_call(method_symbol, method_obj, key, with_operator)
|
wrap_method_call(method_symbol, method_obj, key, with_operator)
|
||||||
end
|
end
|
||||||
elsif @waiting_proc
|
|
||||||
@waiting_proc.(key)
|
|
||||||
elsif method_obj
|
elsif method_obj
|
||||||
wrap_method_call(method_symbol, method_obj, key)
|
wrap_method_call(method_symbol, method_obj, key)
|
||||||
else
|
else
|
||||||
@ -1040,9 +1045,6 @@ class Reline::LineEditor
|
|||||||
@vi_arg = nil
|
@vi_arg = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elsif @waiting_proc
|
|
||||||
@waiting_proc.(key)
|
|
||||||
@kill_ring.process
|
|
||||||
elsif method_obj
|
elsif method_obj
|
||||||
if method_symbol == :ed_argument_digit
|
if method_symbol == :ed_argument_digit
|
||||||
wrap_method_call(method_symbol, method_obj, key)
|
wrap_method_call(method_symbol, method_obj, key)
|
||||||
@ -2325,46 +2327,63 @@ class Reline::LineEditor
|
|||||||
@byte_pointer = 0
|
@byte_pointer = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
private def vi_change_meta(key, arg: 1)
|
private def vi_change_meta(key, arg: nil)
|
||||||
@drop_terminate_spaces = true
|
if @vi_waiting_operator
|
||||||
@waiting_operator_proc = proc { |byte_pointer_diff|
|
set_current_line('', 0) if @vi_waiting_operator == :vi_change_meta_confirm && arg.nil?
|
||||||
if byte_pointer_diff > 0
|
@vi_waiting_operator = nil
|
||||||
line, cut = byteslice!(current_line, @byte_pointer, byte_pointer_diff)
|
@vi_waiting_operator_arg = nil
|
||||||
elsif byte_pointer_diff < 0
|
else
|
||||||
line, cut = byteslice!(current_line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
|
@drop_terminate_spaces = true
|
||||||
end
|
@vi_waiting_operator = :vi_change_meta_confirm
|
||||||
set_current_line(line)
|
@vi_waiting_operator_arg = arg || 1
|
||||||
copy_for_vi(cut)
|
end
|
||||||
@byte_pointer += byte_pointer_diff if byte_pointer_diff < 0
|
|
||||||
@config.editing_mode = :vi_insert
|
|
||||||
@drop_terminate_spaces = false
|
|
||||||
}
|
|
||||||
@waiting_operator_vi_arg = arg
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private def vi_delete_meta(key, arg: 1)
|
private def vi_change_meta_confirm(byte_pointer_diff)
|
||||||
@waiting_operator_proc = proc { |byte_pointer_diff|
|
vi_delete_meta_confirm(byte_pointer_diff)
|
||||||
if byte_pointer_diff > 0
|
@config.editing_mode = :vi_insert
|
||||||
line, cut = byteslice!(current_line, @byte_pointer, byte_pointer_diff)
|
@drop_terminate_spaces = false
|
||||||
elsif byte_pointer_diff < 0
|
|
||||||
line, cut = byteslice!(current_line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
|
|
||||||
end
|
|
||||||
copy_for_vi(cut)
|
|
||||||
set_current_line(line || '', @byte_pointer + (byte_pointer_diff < 0 ? byte_pointer_diff : 0))
|
|
||||||
}
|
|
||||||
@waiting_operator_vi_arg = arg
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private def vi_yank(key, arg: 1)
|
private def vi_delete_meta(key, arg: nil)
|
||||||
@waiting_operator_proc = proc { |byte_pointer_diff|
|
if @vi_waiting_operator
|
||||||
if byte_pointer_diff > 0
|
set_current_line('', 0) if @vi_waiting_operator == :vi_delete_meta_confirm && arg.nil?
|
||||||
cut = current_line.byteslice(@byte_pointer, byte_pointer_diff)
|
@vi_waiting_operator = nil
|
||||||
elsif byte_pointer_diff < 0
|
@vi_waiting_operator_arg = nil
|
||||||
cut = current_line.byteslice(@byte_pointer + byte_pointer_diff, -byte_pointer_diff)
|
else
|
||||||
end
|
@vi_waiting_operator = :vi_delete_meta_confirm
|
||||||
copy_for_vi(cut)
|
@vi_waiting_operator_arg = arg || 1
|
||||||
}
|
end
|
||||||
@waiting_operator_vi_arg = arg
|
end
|
||||||
|
|
||||||
|
private def vi_delete_meta_confirm(byte_pointer_diff)
|
||||||
|
if byte_pointer_diff > 0
|
||||||
|
line, cut = byteslice!(current_line, @byte_pointer, byte_pointer_diff)
|
||||||
|
elsif byte_pointer_diff < 0
|
||||||
|
line, cut = byteslice!(current_line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
|
||||||
|
end
|
||||||
|
copy_for_vi(cut)
|
||||||
|
set_current_line(line || '', @byte_pointer + (byte_pointer_diff < 0 ? byte_pointer_diff : 0))
|
||||||
|
end
|
||||||
|
|
||||||
|
private def vi_yank(key, arg: nil)
|
||||||
|
if @vi_waiting_operator
|
||||||
|
copy_for_vi(current_line) if @vi_waiting_operator == :vi_yank_confirm && arg.nil?
|
||||||
|
@vi_waiting_operator = nil
|
||||||
|
@vi_waiting_operator_arg = nil
|
||||||
|
else
|
||||||
|
@vi_waiting_operator = :vi_yank_confirm
|
||||||
|
@vi_waiting_operator_arg = arg || 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private def vi_yank_confirm(byte_pointer_diff)
|
||||||
|
if byte_pointer_diff > 0
|
||||||
|
cut = current_line.byteslice(@byte_pointer, byte_pointer_diff)
|
||||||
|
elsif byte_pointer_diff < 0
|
||||||
|
cut = current_line.byteslice(@byte_pointer + byte_pointer_diff, -byte_pointer_diff)
|
||||||
|
end
|
||||||
|
copy_for_vi(cut)
|
||||||
end
|
end
|
||||||
|
|
||||||
private def vi_list_or_eof(key)
|
private def vi_list_or_eof(key)
|
||||||
|
@ -1309,6 +1309,14 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase
|
|||||||
assert_line_around_cursor('', '')
|
assert_line_around_cursor('', '')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_incremental_search_history_cancel_by_symbol_key
|
||||||
|
# ed_prev_char should move cursor left and cancel incremental search
|
||||||
|
input_keys("abc\C-r")
|
||||||
|
input_key_by_symbol(:ed_prev_char)
|
||||||
|
input_keys('d')
|
||||||
|
assert_line_around_cursor('abd', 'c')
|
||||||
|
end
|
||||||
|
|
||||||
# Unicode emoji test
|
# Unicode emoji test
|
||||||
def test_ed_insert_for_include_zwj_emoji
|
def test_ed_insert_for_include_zwj_emoji
|
||||||
omit "This test is for UTF-8 but the locale is #{Reline.core.encoding}" if Reline.core.encoding != Encoding::UTF_8
|
omit "This test is for UTF-8 but the locale is #{Reline.core.encoding}" if Reline.core.encoding != Encoding::UTF_8
|
||||||
|
@ -739,10 +739,16 @@ class Reline::KeyActor::ViInsert::Test < Reline::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_vi_delete_meta_with_arg
|
def test_vi_delete_meta_with_arg
|
||||||
input_keys("aaa bbb ccc\C-[02w")
|
input_keys("aaa bbb ccc ddd\C-[03w")
|
||||||
assert_line_around_cursor('aaa bbb ', 'ccc')
|
assert_line_around_cursor('aaa bbb ccc ', 'ddd')
|
||||||
input_keys('2dl')
|
input_keys('2dl')
|
||||||
assert_line_around_cursor('aaa bbb ', 'c')
|
assert_line_around_cursor('aaa bbb ccc ', 'd')
|
||||||
|
input_keys('d2h')
|
||||||
|
assert_line_around_cursor('aaa bbb cc', 'd')
|
||||||
|
input_keys('2d3h')
|
||||||
|
assert_line_around_cursor('aaa ', 'd')
|
||||||
|
input_keys('dd')
|
||||||
|
assert_line_around_cursor('', '')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_vi_change_meta
|
def test_vi_change_meta
|
||||||
@ -765,6 +771,45 @@ class Reline::KeyActor::ViInsert::Test < Reline::TestCase
|
|||||||
assert_line_around_cursor('foo hog', 'e baz')
|
assert_line_around_cursor('foo hog', 'e baz')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_vi_waiting_operator_with_waiting_proc
|
||||||
|
input_keys("foo foo foo foo foo\C-[0")
|
||||||
|
input_keys('2d3fo')
|
||||||
|
assert_line_around_cursor('', ' foo foo')
|
||||||
|
input_keys('fo')
|
||||||
|
assert_line_around_cursor(' f', 'oo foo')
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_vi_waiting_operator_cancel
|
||||||
|
input_keys("aaa bbb ccc\C-[02w")
|
||||||
|
assert_line_around_cursor('aaa bbb ', 'ccc')
|
||||||
|
# dc dy should cancel delete_meta
|
||||||
|
input_keys('dch')
|
||||||
|
input_keys('dyh')
|
||||||
|
# cd cy should cancel change_meta
|
||||||
|
input_keys('cdh')
|
||||||
|
input_keys('cyh')
|
||||||
|
# yd yc should cancel yank_meta
|
||||||
|
# P should not paste yanked text because yank_meta is canceled
|
||||||
|
input_keys('ydhP')
|
||||||
|
input_keys('ychP')
|
||||||
|
assert_line_around_cursor('aa', 'a bbb ccc')
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cancel_waiting_with_symbol_key
|
||||||
|
input_keys("aaa bbb lll\C-[0")
|
||||||
|
assert_line_around_cursor('', 'aaa bbb lll')
|
||||||
|
# ed_next_char should move cursor right and cancel vi_next_char
|
||||||
|
input_keys('f')
|
||||||
|
input_key_by_symbol(:ed_next_char)
|
||||||
|
input_keys('l')
|
||||||
|
assert_line_around_cursor('aa', 'a bbb lll')
|
||||||
|
# ed_next_char should move cursor right and cancel delete_meta
|
||||||
|
input_keys('d')
|
||||||
|
input_key_by_symbol(:ed_next_char)
|
||||||
|
input_keys('l')
|
||||||
|
assert_line_around_cursor('aaa ', 'bbb lll')
|
||||||
|
end
|
||||||
|
|
||||||
def test_unimplemented_vi_command_should_be_no_op
|
def test_unimplemented_vi_command_should_be_no_op
|
||||||
input_keys("abc\C-[h")
|
input_keys("abc\C-[h")
|
||||||
assert_line_around_cursor('a', 'bc')
|
assert_line_around_cursor('a', 'bc')
|
||||||
@ -773,12 +818,16 @@ class Reline::KeyActor::ViInsert::Test < Reline::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_vi_yank
|
def test_vi_yank
|
||||||
input_keys("foo bar\C-[0")
|
input_keys("foo bar\C-[2h")
|
||||||
assert_line_around_cursor('', 'foo bar')
|
assert_line_around_cursor('foo ', 'bar')
|
||||||
input_keys('y3l')
|
input_keys('y3l')
|
||||||
assert_line_around_cursor('', 'foo bar')
|
assert_line_around_cursor('foo ', 'bar')
|
||||||
input_keys('P')
|
input_keys('P')
|
||||||
assert_line_around_cursor('fo', 'ofoo bar')
|
assert_line_around_cursor('foo ba', 'rbar')
|
||||||
|
input_keys('3h3yhP')
|
||||||
|
assert_line_around_cursor('foofo', 'o barbar')
|
||||||
|
input_keys('yyP')
|
||||||
|
assert_line_around_cursor('foofofoofoo barba', 'ro barbar')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_vi_end_word_with_operator
|
def test_vi_end_word_with_operator
|
||||||
|
Loading…
x
Reference in New Issue
Block a user