summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraycabta <aycabta@gmail.com>2020-01-17 20:17:23 +0900
committeraycabta <aycabta@gmail.com>2020-01-20 19:13:19 +0900
commit3b407abe9b8da640dc07617d3dacac0057ca597f (patch)
tree1879e0fc8c59739d4559f7d4ea71a69178c597f2
parentb17797a6940cb196c9893edc088828b49772554c (diff)
[ruby/reline] Implement vi_prev_char and vi_to_prev_char
https://github.com/ruby/reline/commit/0ad3ee63fa
-rw-r--r--lib/reline/line_editor.rb48
-rw-r--r--test/reline/test_key_actor_vi.rb36
2 files changed, 84 insertions, 0 deletions
diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
index 6890fa544a..9518a054fd 100644
--- a/lib/reline/line_editor.rb
+++ b/lib/reline/line_editor.rb
@@ -2131,6 +2131,54 @@ class Reline::LineEditor
@waiting_proc = nil
end
+ private def vi_prev_char(key, arg: 1)
+ @waiting_proc = ->(key_for_proc) { search_prev_char(key_for_proc, arg) }
+ end
+
+ private def vi_to_prev_char(key, arg: 1)
+ @waiting_proc = ->(key_for_proc) { search_prev_char(key_for_proc, arg, true) }
+ end
+
+ private def search_prev_char(key, arg, need_next_char = false)
+ if key.instance_of?(String)
+ inputed_char = key
+ else
+ inputed_char = key.chr
+ end
+ prev_total = nil
+ total = nil
+ found = false
+ @line.byteslice(0..@byte_pointer).grapheme_clusters.reverse_each do |mbchar|
+ # total has [byte_size, cursor]
+ unless total
+ # skip cursor point
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ total = [mbchar.bytesize, width]
+ else
+ if inputed_char == mbchar
+ arg -= 1
+ if arg.zero?
+ found = true
+ break
+ end
+ end
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ prev_total = total
+ total = [total.first + mbchar.bytesize, total.last + width]
+ end
+ end
+ if not need_next_char and found and total
+ byte_size, width = total
+ @byte_pointer -= byte_size
+ @cursor -= width
+ elsif need_next_char and found and prev_total
+ byte_size, width = prev_total
+ @byte_pointer -= byte_size
+ @cursor -= width
+ end
+ @waiting_proc = nil
+ end
+
private def vi_join_lines(key, arg: 1)
if @is_multiline and @buffer_of_lines.size > @line_index + 1
@cursor = calculate_width(@line)
diff --git a/test/reline/test_key_actor_vi.rb b/test/reline/test_key_actor_vi.rb
index d23bdb7769..00d34536d0 100644
--- a/test/reline/test_key_actor_vi.rb
+++ b/test/reline/test_key_actor_vi.rb
@@ -651,6 +651,42 @@ class Reline::KeyActor::ViInsert::Test < Reline::TestCase
assert_cursor_max(6)
end
+ def test_vi_prev_char
+ input_keys("abcdef\C-[")
+ assert_line('abcdef')
+ assert_byte_pointer_size('abcde')
+ assert_cursor(5)
+ assert_cursor_max(6)
+ input_keys('Fz')
+ assert_line('abcdef')
+ assert_byte_pointer_size('abcde')
+ assert_cursor(5)
+ assert_cursor_max(6)
+ input_keys('Fa')
+ assert_line('abcdef')
+ assert_byte_pointer_size('')
+ assert_cursor(0)
+ assert_cursor_max(6)
+ end
+
+ def test_vi_to_prev_char
+ input_keys("abcdef\C-[")
+ assert_line('abcdef')
+ assert_byte_pointer_size('abcde')
+ assert_cursor(5)
+ assert_cursor_max(6)
+ input_keys('Tz')
+ assert_line('abcdef')
+ assert_byte_pointer_size('abcde')
+ assert_cursor(5)
+ assert_cursor_max(6)
+ input_keys('Ta')
+ assert_line('abcdef')
+ assert_byte_pointer_size('a')
+ assert_cursor(1)
+ assert_cursor_max(6)
+ end
+
def test_vi_delete_next_char
input_keys("abc\C-[h")
assert_byte_pointer_size('a')