aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraycabta <aycabta@gmail.com>2019-06-04 06:39:02 +0900
committeraycabta <aycabta@gmail.com>2019-06-04 07:23:36 +0900
commit4b7213a85a6700657b825f8f127ce83a3070bf1d (patch)
treea67ac0525591eefb8a467ee2cf5a731ddcfa2dc2
parentc9b74f9fd95113df903fc34cc1d6ec3fb3160c85 (diff)
downloadruby-4b7213a85a6700657b825f8f127ce83a3070bf1d.tar.gz
Implement transpose-words
-rw-r--r--lib/reline/key_actor/emacs.rb2
-rw-r--r--lib/reline/line_editor.rb13
-rw-r--r--lib/reline/unicode.rb101
-rw-r--r--test/reline/test_key_actor_emacs.rb42
4 files changed, 157 insertions, 1 deletions
diff --git a/lib/reline/key_actor/emacs.rb b/lib/reline/key_actor/emacs.rb
index 7354c9279e..134f424a2c 100644
--- a/lib/reline/key_actor/emacs.rb
+++ b/lib/reline/key_actor/emacs.rb
@@ -489,7 +489,7 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
# 243 M-s
:ed_unassigned,
# 244 M-t
- :ed_unassigned,
+ :ed_transpose_words,
# 245 M-u
:em_upper_case,
# 246 M-v
diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
index 784b8dd7c4..b1769d958a 100644
--- a/lib/reline/line_editor.rb
+++ b/lib/reline/line_editor.rb
@@ -1406,6 +1406,19 @@ class Reline::LineEditor
end
end
+ private def ed_transpose_words(key)
+ left_word_start, middle_start, right_word_start, after_start = Reline::Unicode.ed_transpose_words(@line, @byte_pointer)
+ before = @line.byteslice(0, left_word_start)
+ left_word = @line.byteslice(left_word_start, middle_start - left_word_start)
+ middle = @line.byteslice(middle_start, right_word_start - middle_start)
+ right_word = @line.byteslice(right_word_start, after_start - right_word_start)
+ after = @line.byteslice(after_start, @line.bytesize - after_start)
+ @line = before + right_word + middle + left_word + after
+ from_head_to_left_word = before + right_word + middle + left_word
+ @byte_pointer = from_head_to_left_word.bytesize
+ @cursor = calculate_width(from_head_to_left_word)
+ end
+
private def em_capitol_case(key)
if @line.bytesize > @byte_pointer
byte_size, _, new_str = Reline::Unicode.em_forward_word_with_capitalization(@line, @byte_pointer)
diff --git a/lib/reline/unicode.rb b/lib/reline/unicode.rb
index 5523d4fa31..4b30f044f3 100644
--- a/lib/reline/unicode.rb
+++ b/lib/reline/unicode.rb
@@ -188,6 +188,107 @@ class Reline::Unicode
[byte_size, width]
end
+ def self.ed_transpose_words(line, byte_pointer)
+ right_word_start = nil
+ size = get_next_mbchar_size(line, byte_pointer)
+ mbchar = line.byteslice(byte_pointer, size)
+ if size.zero?
+ # ' aaa bbb [cursor]'
+ byte_size = 0
+ while 0 < (byte_pointer + byte_size)
+ size = get_prev_mbchar_size(line, byte_pointer + byte_size)
+ mbchar = line.byteslice(byte_pointer + byte_size - size, size)
+ break if mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
+ byte_size -= size
+ end
+ while 0 < (byte_pointer + byte_size)
+ size = get_prev_mbchar_size(line, byte_pointer + byte_size)
+ mbchar = line.byteslice(byte_pointer + byte_size - size, size)
+ break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
+ byte_size -= size
+ end
+ right_word_start = byte_pointer + byte_size
+ byte_size = 0
+ while line.bytesize > (byte_pointer + byte_size)
+ size = get_next_mbchar_size(line, byte_pointer + byte_size)
+ mbchar = line.byteslice(byte_pointer + byte_size, size)
+ break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
+ byte_size += size
+ end
+ after_start = byte_pointer + byte_size
+ elsif mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
+ # ' aaa bb[cursor]b'
+ byte_size = 0
+ while 0 < (byte_pointer + byte_size)
+ size = get_prev_mbchar_size(line, byte_pointer + byte_size)
+ mbchar = line.byteslice(byte_pointer + byte_size - size, size)
+ break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
+ byte_size -= size
+ end
+ right_word_start = byte_pointer + byte_size
+ byte_size = 0
+ while line.bytesize > (byte_pointer + byte_size)
+ size = get_next_mbchar_size(line, byte_pointer + byte_size)
+ mbchar = line.byteslice(byte_pointer + byte_size, size)
+ break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
+ byte_size += size
+ end
+ after_start = byte_pointer + byte_size
+ else
+ byte_size = 0
+ while (line.bytesize - 1) > (byte_pointer + byte_size)
+ size = get_next_mbchar_size(line, byte_pointer + byte_size)
+ mbchar = line.byteslice(byte_pointer + byte_size, size)
+ break if mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
+ byte_size += size
+ end
+ if (byte_pointer + byte_size) == (line.bytesize - 1)
+ # ' aaa bbb [cursor] '
+ after_start = line.bytesize
+ while 0 < (byte_pointer + byte_size)
+ size = get_prev_mbchar_size(line, byte_pointer + byte_size)
+ mbchar = line.byteslice(byte_pointer + byte_size - size, size)
+ break if mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
+ byte_size -= size
+ end
+ while 0 < (byte_pointer + byte_size)
+ size = get_prev_mbchar_size(line, byte_pointer + byte_size)
+ mbchar = line.byteslice(byte_pointer + byte_size - size, size)
+ break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
+ byte_size -= size
+ end
+ right_word_start = byte_pointer + byte_size
+ else
+ # ' aaa [cursor] bbb '
+ right_word_start = byte_pointer + byte_size
+ while line.bytesize > (byte_pointer + byte_size)
+ size = get_next_mbchar_size(line, byte_pointer + byte_size)
+ mbchar = line.byteslice(byte_pointer + byte_size, size)
+ break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
+ byte_size += size
+ end
+ after_start = byte_pointer + byte_size
+ end
+ end
+ byte_size = right_word_start - byte_pointer
+ while 0 < (byte_pointer + byte_size)
+ size = get_prev_mbchar_size(line, byte_pointer + byte_size)
+ mbchar = line.byteslice(byte_pointer + byte_size - size, size)
+ break if mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
+ byte_size -= size
+ end
+ middle_start = byte_pointer + byte_size
+ byte_size = middle_start - byte_pointer
+ while 0 < (byte_pointer + byte_size)
+ size = get_prev_mbchar_size(line, byte_pointer + byte_size)
+ mbchar = line.byteslice(byte_pointer + byte_size - size, size)
+ break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
+ byte_size -= size
+ end
+ left_word_start = byte_pointer + byte_size
+ [left_word_start, middle_start, right_word_start, after_start]
+ end
+
def self.vi_big_forward_word(line, byte_pointer)
width = 0
byte_size = 0
diff --git a/test/reline/test_key_actor_emacs.rb b/test/reline/test_key_actor_emacs.rb
index b7dbb709ec..d79627a8c2 100644
--- a/test/reline/test_key_actor_emacs.rb
+++ b/test/reline/test_key_actor_emacs.rb
@@ -819,6 +819,48 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase
assert_line("か\u3099あさ")
end
+ def test_ed_transpose_words
+ input_keys('abc def')
+ assert_line('abc def')
+ assert_byte_pointer_size('abc def')
+ assert_cursor(7)
+ assert_cursor_max(7)
+ input_keys("\M-t", false)
+ assert_line('def abc')
+ assert_byte_pointer_size('def abc')
+ assert_cursor(7)
+ assert_cursor_max(7)
+ input_keys("\C-a\C-k", false)
+ input_keys(' abc def ')
+ input_keys("\C-b" * 4, false)
+ assert_line(' abc def ')
+ assert_byte_pointer_size(' abc de')
+ assert_cursor(8)
+ assert_cursor_max(12)
+ input_keys("\M-t", false)
+ assert_line(' def abc ')
+ assert_byte_pointer_size(' def abc')
+ assert_cursor(9)
+ assert_cursor_max(12)
+ input_keys("\C-a\C-k", false)
+ input_keys(' abc def ')
+ input_keys("\C-b" * 6, false)
+ assert_line(' abc def ')
+ assert_byte_pointer_size(' abc ')
+ assert_cursor(6)
+ assert_cursor_max(12)
+ input_keys("\M-t", false)
+ assert_line(' def abc ')
+ assert_byte_pointer_size(' def abc')
+ assert_cursor(9)
+ assert_cursor_max(12)
+ input_keys("\M-t", false)
+ assert_line(' abc def')
+ assert_byte_pointer_size(' abc def')
+ assert_cursor(12)
+ assert_cursor_max(12)
+ end
+
def test_ed_digit
input_keys('0123')
assert_byte_pointer_size('0123')