Skip to content

Commit

Permalink
Refactor handling key in LineEditor (#799)
Browse files Browse the repository at this point in the history
Simplify the complicated flow of waiting_proc, wrap_method_call and run_for_operation
  • Loading branch information
tompng authored Jan 3, 2025
1 parent e6eb5d2 commit 72c0ec0
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 66 deletions.
113 changes: 47 additions & 66 deletions lib/reline/line_editor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -911,28 +911,36 @@ def dialog_proc_scope_completion_journey_data
)
end

private def run_for_operators(key, method_symbol, &block)
private def run_for_operators(key, method_symbol)
# Reject multibyte input (converted to ed_insert) in vi_command mode
return if method_symbol == :ed_insert && @config.editing_mode_is?(:vi_command) && !@waiting_proc

if ARGUMENT_DIGIT_METHODS.include?(method_symbol) && !@waiting_proc
wrap_method_call(method_symbol, key, false)
return
end

if @vi_waiting_operator
if VI_MOTIONS.include?(method_symbol)
if @waiting_proc || VI_MOTIONS.include?(method_symbol)
old_byte_pointer = @byte_pointer
@vi_arg = (@vi_arg || 1) * @vi_waiting_operator_arg
block.(true)
wrap_method_call(method_symbol, key, true)
unless @waiting_proc
byte_pointer_diff = @byte_pointer - old_byte_pointer
@byte_pointer = old_byte_pointer
method_obj = method(@vi_waiting_operator)
wrap_method_call(@vi_waiting_operator, method_obj, byte_pointer_diff)
__send__(@vi_waiting_operator, byte_pointer_diff)
cleanup_waiting
end
else
# Ignores operator when not motion is given.
block.(false)
wrap_method_call(method_symbol, key, false)
cleanup_waiting
end
@vi_arg = nil
else
block.(false)
wrap_method_call(method_symbol, key, false)
end
@vi_arg = nil
@kill_ring.process
end

private def argumentable?(method_obj)
Expand All @@ -945,20 +953,23 @@ def dialog_proc_scope_completion_journey_data
method_obj and method_obj.parameters.any? { |param| param[0] == :key and param[1] == :inclusive }
end

def wrap_method_call(method_symbol, method_obj, key, with_operator = false)
if @config.editing_mode_is?(:emacs, :vi_insert) and @vi_waiting_operator.nil?
not_insertion = method_symbol != :ed_insert
process_insert(force: not_insertion)
def wrap_method_call(method_symbol, key, with_operator)
if @waiting_proc
@waiting_proc.call(key)
return
end

return unless respond_to?(method_symbol, true)
method_obj = method(method_symbol)
if @vi_arg and argumentable?(method_obj)
if with_operator and inclusive?(method_obj)
method_obj.(key, arg: @vi_arg, inclusive: true)
if inclusive?(method_obj)
method_obj.(key, arg: @vi_arg, inclusive: with_operator)
else
method_obj.(key, arg: @vi_arg)
end
else
if with_operator and inclusive?(method_obj)
method_obj.(key, inclusive: true)
if inclusive?(method_obj)
method_obj.(key, inclusive: with_operator)
else
method_obj.(key)
end
Expand All @@ -984,50 +995,9 @@ def wrap_method_call(method_symbol, method_obj, key, with_operator = false)
cleanup_waiting unless VI_WAITING_ACCEPT_METHODS.include?(method_symbol) || VI_MOTIONS.include?(method_symbol)
end

if @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
method_obj = method(@vi_waiting_operator)
wrap_method_call(@vi_waiting_operator, method_obj, byte_pointer_diff)
cleanup_waiting
end
@kill_ring.process
return
end

# Reject multibyte input (converted to ed_insert) in vi_command mode
return if method_symbol == :ed_insert && @config.editing_mode_is?(:vi_command)
process_insert(force: method_symbol != :ed_insert)

if method_symbol and respond_to?(method_symbol, true)
method_obj = method(method_symbol)
end
if @vi_arg
if ARGUMENT_DIGIT_METHODS.include?(method_symbol)
ed_argument_digit(key)
else
if argumentable?(method_obj)
run_for_operators(key, method_symbol) do |with_operator|
wrap_method_call(method_symbol, method_obj, key, with_operator)
end
elsif method_obj
wrap_method_call(method_symbol, method_obj, key)
end
@kill_ring.process
@vi_arg = nil
end
elsif method_obj
if method_symbol == :ed_argument_digit
wrap_method_call(method_symbol, method_obj, key)
else
run_for_operators(key, method_symbol) do |with_operator|
wrap_method_call(method_symbol, method_obj, key, with_operator)
end
end
@kill_ring.process
end
run_for_operators(key, method_symbol)
end

def update(key)
Expand All @@ -1049,11 +1019,8 @@ def input_key(key)
finish
return
end
@dialogs.each do |dialog|
if key.method_symbol == dialog.name
return
end
end
return if @dialogs.any? { |dialog| dialog.name == key.method_symbol }

@completion_occurs = false

process_key(key.char, key.method_symbol)
Expand Down Expand Up @@ -1413,9 +1380,16 @@ def finish

insert_text(str)
end
alias_method :ed_digit, :ed_insert
alias_method :self_insert, :ed_insert

private def ed_digit(key)
if @vi_arg
ed_argument_digit(key)
else
ed_insert(key)
end
end

private def insert_raw_char(str, arg: 1)
arg.times do
if str == "\C-j" or str == "\C-m"
Expand Down Expand Up @@ -1461,7 +1435,14 @@ def finish
@byte_pointer = 0
end
alias_method :beginning_of_line, :ed_move_to_beg
alias_method :vi_zero, :ed_move_to_beg

private def vi_zero(key)
if @vi_arg
ed_argument_digit(key)
else
ed_move_to_beg(key)
end
end

private def ed_move_to_end(key)
@byte_pointer = current_line.bytesize
Expand Down
10 changes: 10 additions & 0 deletions test/reline/test_key_actor_emacs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1502,6 +1502,16 @@ def test_ed_argument_digit_by_meta_num
assert_line_around_cursor('abcd', '')
end

def test_ed_digit_with_ed_argument_digit
input_keys('1' * 30)
assert_line_around_cursor('1' * 30, '')
input_keys("\M-2", false)
input_keys('3')
input_keys("\C-h", false)
input_keys('4')
assert_line_around_cursor('1' * 7 + '4', '')
end

def test_halfwidth_kana_width_dakuten
omit "This test is for UTF-8 but the locale is #{Reline.core.encoding}" if Reline.core.encoding != Encoding::UTF_8
input_raw_keys('ガギゲゴ')
Expand Down

0 comments on commit 72c0ec0

Please sign in to comment.