diff options
Diffstat (limited to 'test/reline')
-rw-r--r-- | test/reline/helper.rb | 121 | ||||
-rw-r--r-- | test/reline/test_ansi_with_terminfo.rb | 112 | ||||
-rw-r--r-- | test/reline/test_ansi_without_terminfo.rb | 77 | ||||
-rw-r--r-- | test/reline/test_config.rb | 271 | ||||
-rw-r--r-- | test/reline/test_face.rb | 257 | ||||
-rw-r--r-- | test/reline/test_history.rb | 2 | ||||
-rw-r--r-- | test/reline/test_key_actor_emacs.rb | 2059 | ||||
-rw-r--r-- | test/reline/test_key_actor_vi.rb | 1354 | ||||
-rw-r--r-- | test/reline/test_key_stroke.rb | 68 | ||||
-rw-r--r-- | test/reline/test_line_editor.rb | 183 | ||||
-rw-r--r-- | test/reline/test_macro.rb | 3 | ||||
-rw-r--r-- | test/reline/test_reline.rb | 74 | ||||
-rw-r--r-- | test/reline/test_reline_key.rb | 50 | ||||
-rw-r--r-- | test/reline/test_string_processing.rb | 14 | ||||
-rw-r--r-- | test/reline/test_terminfo.rb | 2 | ||||
-rw-r--r-- | test/reline/test_unicode.rb | 67 | ||||
-rw-r--r-- | test/reline/test_within_pipe.rb | 9 | ||||
-rwxr-xr-x | test/reline/yamatanooroti/multiline_repl | 64 | ||||
-rw-r--r-- | test/reline/yamatanooroti/termination_checker.rb | 38 | ||||
-rw-r--r-- | test/reline/yamatanooroti/test_rendering.rb | 726 |
20 files changed, 2949 insertions, 2602 deletions
diff --git a/test/reline/helper.rb b/test/reline/helper.rb index e8b8e3a6e1..3d7dc7d812 100644 --- a/test/reline/helper.rb +++ b/test/reline/helper.rb @@ -5,33 +5,84 @@ ENV['TERM'] = 'xterm' # for some CI environments require 'reline' require 'test/unit' +begin + require 'rbconfig' +rescue LoadError +end + +begin + # This should exist and available in load path when this file is mirrored to ruby/ruby and running at there + if File.exist?(File.expand_path('../../tool/lib/envutil.rb', __dir__)) + require 'envutil' + end +rescue LoadError +end + module Reline class <<self - def test_mode - remove_const('IOGate') if const_defined?('IOGate') - const_set('IOGate', Reline::GeneralIO) - if ENV['RELINE_TEST_ENCODING'] - encoding = Encoding.find(ENV['RELINE_TEST_ENCODING']) - else - encoding = Encoding::UTF_8 + def test_mode(ansi: false) + @original_iogate = IOGate + + if ENV['RELINE_TEST_ENCODING'] + encoding = Encoding.find(ENV['RELINE_TEST_ENCODING']) + else + encoding = Encoding::UTF_8 + end + + if ansi + new_io_gate = ANSI.new + # Setting ANSI gate's screen size through set_screen_size will also change the tester's stdin's screen size + # Let's avoid that side-effect by stubbing the get_screen_size method + new_io_gate.define_singleton_method(:get_screen_size) do + [24, 80] + end + new_io_gate.define_singleton_method(:encoding) do + encoding end - Reline::GeneralIO.reset(encoding: encoding) - send(:core).config.instance_variable_set(:@test_mode, true) - send(:core).config.reset + else + new_io_gate = Dumb.new(encoding: encoding) + end + + remove_const('IOGate') + const_set('IOGate', new_io_gate) + core.config.instance_variable_set(:@test_mode, true) + core.config.reset end def test_reset + remove_const('IOGate') + const_set('IOGate', @original_iogate) Reline.instance_variable_set(:@core, nil) end - end -end -def start_pasting - Reline::GeneralIO.start_pasting -end + # Return a executable name to spawn Ruby process. In certain build configuration, + # "ruby" may not be available. + def test_rubybin + # When this test suite is running in ruby/ruby, prefer EnvUtil result over original implementation + if const_defined?(:EnvUtil) + return EnvUtil.rubybin + end -def finish_pasting - Reline::GeneralIO.finish_pasting + # The following is a simplified port of EnvUtil.rubybin in ruby/ruby + if ruby = ENV["RUBY"] + return ruby + end + ruby = "ruby" + exeext = RbConfig::CONFIG["EXEEXT"] + rubyexe = (ruby + exeext if exeext and !exeext.empty?) + if File.exist? ruby and File.executable? ruby and !File.directory? ruby + return File.expand_path(ruby) + end + if rubyexe and File.exist? rubyexe and File.executable? rubyexe + return File.expand_path(rubyexe) + end + if defined?(RbConfig.ruby) + RbConfig.ruby + else + "ruby" + end + end + end end class Reline::TestCase < Test::Unit::TestCase @@ -45,7 +96,7 @@ class Reline::TestCase < Test::Unit::TestCase end }.join rescue Encoding::UndefinedConversionError, Encoding::InvalidByteSequenceError - input.unicode_normalize!(:nfc) + input = input.unicode_normalize(:nfc) if normalized options[:undef] = :replace options[:replace] = '?' @@ -84,9 +135,14 @@ class Reline::TestCase < Test::Unit::TestCase end end - def assert_line(expected) - expected = convert_str(expected) - assert_equal(expected, @line_editor.line) + def assert_line_around_cursor(before, after) + before = convert_str(before) + after = convert_str(after) + line = @line_editor.current_line + byte_pointer = @line_editor.instance_variable_get(:@byte_pointer) + actual_before = line.byteslice(0, byte_pointer) + actual_after = line.byteslice(byte_pointer..) + assert_equal([before, after], [actual_before, actual_after]) end def assert_byte_pointer_size(expected) @@ -97,29 +153,22 @@ class Reline::TestCase < Test::Unit::TestCase expected.bytesize, byte_pointer, <<~EOM) <#{expected.inspect} (#{expected.encoding.inspect})> expected but was - <#{chunk.inspect} (#{chunk.encoding.inspect})> in <Terminal #{Reline::GeneralIO.encoding.inspect}> + <#{chunk.inspect} (#{chunk.encoding.inspect})> in <Terminal #{Reline::Dumb.new.encoding.inspect}> EOM end - def assert_cursor(expected) - assert_equal(expected, @line_editor.instance_variable_get(:@cursor)) - end - - def assert_cursor_max(expected) - assert_equal(expected, @line_editor.instance_variable_get(:@cursor_max)) - end - def assert_line_index(expected) assert_equal(expected, @line_editor.instance_variable_get(:@line_index)) end def assert_whole_lines(expected) - previous_line_index = @line_editor.instance_variable_get(:@previous_line_index) - if previous_line_index - lines = @line_editor.whole_lines(index: previous_line_index) - else - lines = @line_editor.whole_lines + assert_equal(expected, @line_editor.whole_lines) + end + + def assert_key_binding(input, method_symbol, editing_modes = [:emacs, :vi_insert, :vi_command]) + editing_modes.each do |editing_mode| + @config.editing_mode = editing_mode + assert_equal(method_symbol, @config.editing_mode.get(input.bytes)) end - assert_equal(expected, lines) end end diff --git a/test/reline/test_ansi_with_terminfo.rb b/test/reline/test_ansi_with_terminfo.rb new file mode 100644 index 0000000000..3adda10716 --- /dev/null +++ b/test/reline/test_ansi_with_terminfo.rb @@ -0,0 +1,112 @@ +require_relative 'helper' +require 'reline' + +class Reline::ANSI::WithTerminfoTest < Reline::TestCase + def setup + Reline.send(:test_mode, ansi: true) + @config = Reline::Config.new + Reline.core.io_gate.set_default_key_bindings(@config, allow_terminfo: true) + end + + def teardown + Reline.test_reset + end + + # Home key + def test_khome + assert_key_binding(Reline::Terminfo.tigetstr('khome'), :ed_move_to_beg) + rescue Reline::Terminfo::TerminfoError => e + omit e.message + end + + # End key + def test_kend + assert_key_binding(Reline::Terminfo.tigetstr('kend'), :ed_move_to_end) + rescue Reline::Terminfo::TerminfoError => e + omit e.message + end + + # Delete key + def test_kdch1 + assert_key_binding(Reline::Terminfo.tigetstr('kdch1'), :key_delete) + rescue Reline::Terminfo::TerminfoError => e + omit e.message + end + + # PgUp key + def test_kpp + assert_key_binding(Reline::Terminfo.tigetstr('kpp'), :ed_search_prev_history) + rescue Reline::Terminfo::TerminfoError => e + omit e.message + end + + # PgDn key + def test_knp + assert_key_binding(Reline::Terminfo.tigetstr('knp'), :ed_search_next_history) + rescue Reline::Terminfo::TerminfoError => e + omit e.message + end + + # Up arrow key + def test_kcuu1 + assert_key_binding(Reline::Terminfo.tigetstr('kcuu1'), :ed_prev_history) + rescue Reline::Terminfo::TerminfoError => e + omit e.message + end + + # Down arrow key + def test_kcud1 + assert_key_binding(Reline::Terminfo.tigetstr('kcud1'), :ed_next_history) + rescue Reline::Terminfo::TerminfoError => e + omit e.message + end + + # Right arrow key + def test_kcuf1 + assert_key_binding(Reline::Terminfo.tigetstr('kcuf1'), :ed_next_char) + rescue Reline::Terminfo::TerminfoError => e + omit e.message + end + + # Left arrow key + def test_kcub1 + assert_key_binding(Reline::Terminfo.tigetstr('kcub1'), :ed_prev_char) + rescue Reline::Terminfo::TerminfoError => e + omit e.message + end + + # Home and End; always mapped regardless of terminfo enabled or not + def test_home_end + assert_key_binding("\e[H", :ed_move_to_beg) + assert_key_binding("\e[F", :ed_move_to_end) + end + + # Arrow; always mapped regardless of terminfo enabled or not + def test_arrow + assert_key_binding("\e[A", :ed_prev_history) + assert_key_binding("\e[B", :ed_next_history) + assert_key_binding("\e[C", :ed_next_char) + assert_key_binding("\e[D", :ed_prev_char) + end + + # Ctrl+arrow and Meta+arrow; always mapped regardless of terminfo enabled or not + def test_extended + assert_key_binding("\e[1;5C", :em_next_word) # Ctrl+→ + assert_key_binding("\e[1;5D", :ed_prev_word) # Ctrl+← + assert_key_binding("\e[1;3C", :em_next_word) # Meta+→ + assert_key_binding("\e[1;3D", :ed_prev_word) # Meta+← + assert_key_binding("\e\e[C", :em_next_word) # Meta+→ + assert_key_binding("\e\e[D", :ed_prev_word) # Meta+← + end + + # Shift-Tab; always mapped regardless of terminfo enabled or not + def test_shift_tab + assert_key_binding("\e[Z", :completion_journey_up, [:emacs, :vi_insert]) + end + + # A few emacs bindings that are always mapped regardless of terminfo enabled or not + def test_more_emacs + assert_key_binding("\e ", :em_set_mark, [:emacs]) + assert_key_binding("\C-x\C-x", :em_exchange_mark, [:emacs]) + end +end if Reline::Terminfo.enabled? && Reline::Terminfo.term_supported? diff --git a/test/reline/test_ansi_without_terminfo.rb b/test/reline/test_ansi_without_terminfo.rb new file mode 100644 index 0000000000..2db14cf0a0 --- /dev/null +++ b/test/reline/test_ansi_without_terminfo.rb @@ -0,0 +1,77 @@ +require_relative 'helper' +require 'reline' + +class Reline::ANSI::WithoutTerminfoTest < Reline::TestCase + def setup + Reline.send(:test_mode, ansi: true) + @config = Reline::Config.new + Reline.core.io_gate.set_default_key_bindings(@config, allow_terminfo: false) + end + + def teardown + Reline.test_reset + end + + def test_home + assert_key_binding("\e[1~", :ed_move_to_beg) # Console (80x25) + assert_key_binding("\e[H", :ed_move_to_beg) # KDE + assert_key_binding("\e[7~", :ed_move_to_beg) # urxvt / exoterm + assert_key_binding("\eOH", :ed_move_to_beg) # GNOME + end + + def test_end + assert_key_binding("\e[4~", :ed_move_to_end) # Console (80x25) + assert_key_binding("\e[F", :ed_move_to_end) # KDE + assert_key_binding("\e[8~", :ed_move_to_end) # urxvt / exoterm + assert_key_binding("\eOF", :ed_move_to_end) # GNOME + end + + def test_delete + assert_key_binding("\e[3~", :key_delete) + end + + def test_up_arrow + assert_key_binding("\e[A", :ed_prev_history) # Console (80x25) + assert_key_binding("\eGA", :ed_prev_history) # KDE + assert_key_binding("\eOA", :ed_prev_history) + end + + def test_down_arrow + assert_key_binding("\e[B", :ed_next_history) # Console (80x25) + assert_key_binding("\eGB", :ed_next_history) # KDE + assert_key_binding("\eOB", :ed_next_history) + end + + def test_right_arrow + assert_key_binding("\e[C", :ed_next_char) # Console (80x25) + assert_key_binding("\eGC", :ed_next_char) # KDE + assert_key_binding("\eOC", :ed_next_char) + end + + def test_left_arrow + assert_key_binding("\e[D", :ed_prev_char) # Console (80x25) + assert_key_binding("\eGD", :ed_prev_char) # KDE + assert_key_binding("\eOD", :ed_prev_char) + end + + # Ctrl+arrow and Meta+arrow; always mapped regardless of terminfo enabled or not + def test_extended + assert_key_binding("\e[1;5C", :em_next_word) # Ctrl+→ + assert_key_binding("\e[1;5D", :ed_prev_word) # Ctrl+← + assert_key_binding("\e[1;3C", :em_next_word) # Meta+→ + assert_key_binding("\e[1;3D", :ed_prev_word) # Meta+← + assert_key_binding("\e\e[C", :em_next_word) # Meta+→ + assert_key_binding("\e\e[D", :ed_prev_word) # Meta+← + end + + # Shift-Tab; always mapped regardless of terminfo enabled or not + def test_shift_tab + assert_key_binding("\e[Z", :completion_journey_up, [:emacs, :vi_insert]) + end + + # A few emacs bindings that are always mapped regardless of terminfo enabled or not + def test_more_emacs + assert_key_binding("\e ", :em_set_mark, [:emacs]) + assert_key_binding("\C-x\C-x", :em_exchange_mark, [:emacs]) + end +end diff --git a/test/reline/test_config.rb b/test/reline/test_config.rb index e00a47c705..68a102a599 100644 --- a/test/reline/test_config.rb +++ b/test/reline/test_config.rb @@ -13,6 +13,7 @@ class Reline::Config::Test < Reline::TestCase Dir.chdir(@tmpdir) Reline.test_mode @config = Reline::Config.new + @inputrc_backup = ENV['INPUTRC'] end def teardown @@ -20,14 +21,28 @@ class Reline::Config::Test < Reline::TestCase FileUtils.rm_rf(@tmpdir) Reline.test_reset @config.reset + ENV['INPUTRC'] = @inputrc_backup + end + + def get_config_variable(variable) + @config.instance_variable_get(variable) + end + + def additional_key_bindings(keymap_label) + get_config_variable(:@additional_key_bindings)[keymap_label].instance_variable_get(:@key_bindings) + end + + def registered_key_bindings(keys) + key_bindings = @config.key_bindings + keys.to_h { |key| [key, key_bindings.get(key)] } end def test_read_lines @config.read_lines(<<~LINES.lines) - set bell-style on + set show-mode-in-prompt on LINES - assert_equal :audible, @config.instance_variable_get(:@bell_style) + assert_equal true, get_config_variable(:@show_mode_in_prompt) end def test_read_lines_with_variable @@ -35,7 +50,7 @@ class Reline::Config::Test < Reline::TestCase set disable-completion on LINES - assert_equal true, @config.instance_variable_get(:@disable_completion) + assert_equal true, get_config_variable(:@disable_completion) end def test_string_value @@ -44,7 +59,7 @@ class Reline::Config::Test < Reline::TestCase set emacs-mode-string Emacs LINES - assert_equal 'Emacs', @config.instance_variable_get(:@emacs_mode_string) + assert_equal 'Emacs', get_config_variable(:@emacs_mode_string) end def test_string_value_with_brackets @@ -53,7 +68,7 @@ class Reline::Config::Test < Reline::TestCase set emacs-mode-string [Emacs] LINES - assert_equal '[Emacs]', @config.instance_variable_get(:@emacs_mode_string) + assert_equal '[Emacs]', get_config_variable(:@emacs_mode_string) end def test_string_value_with_brackets_and_quotes @@ -62,7 +77,7 @@ class Reline::Config::Test < Reline::TestCase set emacs-mode-string "[Emacs]" LINES - assert_equal '[Emacs]', @config.instance_variable_get(:@emacs_mode_string) + assert_equal '[Emacs]', get_config_variable(:@emacs_mode_string) end def test_string_value_with_parens @@ -71,7 +86,7 @@ class Reline::Config::Test < Reline::TestCase set emacs-mode-string (Emacs) LINES - assert_equal '(Emacs)', @config.instance_variable_get(:@emacs_mode_string) + assert_equal '(Emacs)', get_config_variable(:@emacs_mode_string) end def test_string_value_with_parens_and_quotes @@ -80,33 +95,34 @@ class Reline::Config::Test < Reline::TestCase set emacs-mode-string "(Emacs)" LINES - assert_equal '(Emacs)', @config.instance_variable_get(:@emacs_mode_string) + assert_equal '(Emacs)', get_config_variable(:@emacs_mode_string) end def test_encoding_is_ascii @config.reset - Reline::IOGate.reset(encoding: Encoding::US_ASCII) + Reline.core.io_gate.instance_variable_set(:@encoding, Encoding::US_ASCII) @config = Reline::Config.new assert_equal true, @config.convert_meta end def test_encoding_is_not_ascii - @config.reset - Reline::IOGate.reset(encoding: Encoding::UTF_8) @config = Reline::Config.new - assert_equal nil, @config.convert_meta - end - - def test_comment_line - @config.read_lines([" #a: error\n"]) - assert_not_include @config.key_bindings, nil + assert_equal false, @config.convert_meta end def test_invalid_keystroke - @config.read_lines(["a: error\n"]) - assert_not_include @config.key_bindings, nil + @config.read_lines(<<~LINES.lines) + #"a": comment + a: error + "b": no-error + LINES + key_bindings = additional_key_bindings(:emacs) + assert_not_include key_bindings, 'a'.bytes + assert_not_include key_bindings, nil + assert_not_include key_bindings, [] + assert_include key_bindings, 'b'.bytes end def test_bind_key @@ -150,55 +166,104 @@ class Reline::Config::Test < Reline::TestCase def test_include File.open('included_partial', 'wt') do |f| f.write(<<~PARTIAL_LINES) - set bell-style on + set show-mode-in-prompt on PARTIAL_LINES end @config.read_lines(<<~LINES.lines) $include included_partial LINES - assert_equal :audible, @config.instance_variable_get(:@bell_style) + assert_equal true, get_config_variable(:@show_mode_in_prompt) + end + + def test_include_expand_path + home_backup = ENV['HOME'] + File.open('included_partial', 'wt') do |f| + f.write(<<~PARTIAL_LINES) + set show-mode-in-prompt on + PARTIAL_LINES + end + ENV['HOME'] = Dir.pwd + @config.read_lines(<<~LINES.lines) + $include ~/included_partial + LINES + + assert_equal true, get_config_variable(:@show_mode_in_prompt) + ensure + ENV['HOME'] = home_backup end def test_if @config.read_lines(<<~LINES.lines) $if Ruby - set bell-style audible + set vi-cmd-mode-string (cmd) $else - set bell-style visible + set vi-cmd-mode-string [cmd] $endif LINES - assert_equal :audible, @config.instance_variable_get(:@bell_style) + assert_equal '(cmd)', get_config_variable(:@vi_cmd_mode_string) end def test_if_with_false @config.read_lines(<<~LINES.lines) $if Python - set bell-style audible + set vi-cmd-mode-string (cmd) $else - set bell-style visible + set vi-cmd-mode-string [cmd] $endif LINES - assert_equal :visible, @config.instance_variable_get(:@bell_style) + assert_equal '[cmd]', get_config_variable(:@vi_cmd_mode_string) end def test_if_with_indent %w[Ruby Reline].each do |cond| @config.read_lines(<<~LINES.lines) - set bell-style none + set vi-cmd-mode-string {cmd} $if #{cond} - set bell-style audible + set vi-cmd-mode-string (cmd) $else - set bell-style visible + set vi-cmd-mode-string [cmd] $endif LINES - assert_equal :audible, @config.instance_variable_get(:@bell_style) + assert_equal '(cmd)', get_config_variable(:@vi_cmd_mode_string) end end + def test_nested_if_else + @config.read_lines(<<~LINES.lines) + $if Ruby + "\x1": "O" + $if NotRuby + "\x2": "X" + $else + "\x3": "O" + $if Ruby + "\x4": "O" + $else + "\x5": "X" + $endif + "\x6": "O" + $endif + "\x7": "O" + $else + "\x8": "X" + $if NotRuby + "\x9": "X" + $else + "\xA": "X" + $endif + "\xB": "X" + $endif + "\xC": "O" + LINES + keys = [0x1, 0x3, 0x4, 0x6, 0x7, 0xC] + key_bindings = keys.to_h { |k| [[k], ['O'.ord]] } + assert_equal(key_bindings, additional_key_bindings(:emacs)) + end + def test_unclosed_if e = assert_raise(Reline::Config::InvalidInputrc) do @config.read_lines(<<~LINES.lines, "INPUTRC") @@ -226,6 +291,78 @@ class Reline::Config::Test < Reline::TestCase assert_equal "INPUTRC:1: unmatched endif", e.message end + def test_if_with_mode + @config.read_lines(<<~LINES.lines) + $if mode=emacs + "\C-e": history-search-backward # comment + $else + "\C-f": history-search-forward + $endif + LINES + + assert_equal({[5] => :history_search_backward}, additional_key_bindings(:emacs)) + assert_equal({}, additional_key_bindings(:vi_insert)) + assert_equal({}, additional_key_bindings(:vi_command)) + end + + def test_else + @config.read_lines(<<~LINES.lines) + $if mode=vi + "\C-e": history-search-backward # comment + $else + "\C-f": history-search-forward + $endif + LINES + + assert_equal({[6] => :history_search_forward}, additional_key_bindings(:emacs)) + assert_equal({}, additional_key_bindings(:vi_insert)) + assert_equal({}, additional_key_bindings(:vi_command)) + end + + def test_if_with_invalid_mode + @config.read_lines(<<~LINES.lines) + $if mode=vim + "\C-e": history-search-backward + $else + "\C-f": history-search-forward # comment + $endif + LINES + + assert_equal({[6] => :history_search_forward}, additional_key_bindings(:emacs)) + assert_equal({}, additional_key_bindings(:vi_insert)) + assert_equal({}, additional_key_bindings(:vi_command)) + end + + def test_mode_label_differs_from_keymap_label + @config.read_lines(<<~LINES.lines) + # Sets mode_label and keymap_label to vi + set editing-mode vi + # Change keymap_label to emacs. mode_label is still vi. + set keymap emacs + # condition=true because current mode_label is vi + $if mode=vi + # sets keybinding to current keymap_label=emacs + "\C-e": history-search-backward + $endif + LINES + assert_equal({[5] => :history_search_backward}, additional_key_bindings(:emacs)) + assert_equal({}, additional_key_bindings(:vi_insert)) + assert_equal({}, additional_key_bindings(:vi_command)) + end + + def test_if_without_else_condition + @config.read_lines(<<~LINES.lines) + set editing-mode vi + $if mode=vi + "\C-e": history-search-backward + $endif + LINES + + assert_equal({}, additional_key_bindings(:emacs)) + assert_equal({[5] => :history_search_backward}, additional_key_bindings(:vi_insert)) + assert_equal({}, additional_key_bindings(:vi_command)) + end + def test_default_key_bindings @config.add_default_key_binding('abcd'.bytes, 'EFGH'.bytes) @config.read_lines(<<~'LINES'.lines) @@ -234,7 +371,7 @@ class Reline::Config::Test < Reline::TestCase LINES expected = { 'abcd'.bytes => 'ABCD'.bytes, 'ijkl'.bytes => 'IJKL'.bytes } - assert_equal expected, @config.key_bindings + assert_equal expected, registered_key_bindings(expected.keys) end def test_additional_key_bindings @@ -244,7 +381,7 @@ class Reline::Config::Test < Reline::TestCase LINES expected = { 'ef'.bytes => 'EF'.bytes, 'gh'.bytes => 'GH'.bytes } - assert_equal expected, @config.key_bindings + assert_equal expected, registered_key_bindings(expected.keys) end def test_additional_key_bindings_with_nesting_and_comment_out @@ -256,7 +393,7 @@ class Reline::Config::Test < Reline::TestCase LINES expected = { 'ef'.bytes => 'EF'.bytes, 'gh'.bytes => 'GH'.bytes } - assert_equal expected, @config.key_bindings + assert_equal expected, registered_key_bindings(expected.keys) end def test_additional_key_bindings_for_other_keymap @@ -271,7 +408,41 @@ class Reline::Config::Test < Reline::TestCase LINES expected = { 'cd'.bytes => 'CD'.bytes } - assert_equal expected, @config.key_bindings + assert_equal expected, registered_key_bindings(expected.keys) + end + + def test_additional_key_bindings_for_auxiliary_emacs_keymaps + @config.read_lines(<<~'LINES'.lines) + set keymap emacs + "ab": "AB" + set keymap emacs-standard + "cd": "CD" + set keymap emacs-ctlx + "ef": "EF" + set keymap emacs-meta + "gh": "GH" + set editing-mode emacs # keymap changes to be emacs + LINES + + expected = { + 'ab'.bytes => 'AB'.bytes, + 'cd'.bytes => 'CD'.bytes, + "\C-xef".bytes => 'EF'.bytes, + "\egh".bytes => 'GH'.bytes, + } + assert_equal expected, registered_key_bindings(expected.keys) + end + + def test_key_bindings_with_reset + # @config.reset is called after each readline. + # inputrc file is read once, so key binding shouldn't be cleared by @config.reset + @config.add_default_key_binding('default'.bytes, 'DEFAULT'.bytes) + @config.read_lines(<<~'LINES'.lines) + "additional": "ADDITIONAL" + LINES + @config.reset + expected = { 'default'.bytes => 'DEFAULT'.bytes, 'additional'.bytes => 'ADDITIONAL'.bytes } + assert_equal expected, registered_key_bindings(expected.keys) end def test_history_size @@ -279,7 +450,7 @@ class Reline::Config::Test < Reline::TestCase set history-size 5000 LINES - assert_equal 5000, @config.instance_variable_get(:@history_size) + assert_equal 5000, get_config_variable(:@history_size) history = Reline::History.new(@config) history << "a\n" assert_equal 1, history.size @@ -304,6 +475,17 @@ class Reline::Config::Test < Reline::TestCase ENV['INPUTRC'] = inputrc_backup end + def test_inputrc_raw_value + @config.read_lines(<<~'LINES'.lines) + set editing-mode vi ignored-string + set vi-ins-mode-string aaa aaa + set vi-cmd-mode-string bbb ccc # comment + LINES + assert_equal :vi_insert, get_config_variable(:@editing_mode_label) + assert_equal 'aaa aaa', @config.vi_ins_mode_string + assert_equal 'bbb ccc # comment', @config.vi_cmd_mode_string + end + def test_inputrc_with_utf8 # This file is encoded by UTF-8 so this heredoc string is also UTF-8. @config.read_lines(<<~'LINES'.lines) @@ -386,4 +568,21 @@ class Reline::Config::Test < Reline::TestCase ENV['XDG_CONFIG_HOME'] = xdg_config_home_backup ENV['HOME'] = home_backup end + + def test_reload + inputrc = "#{@tmpdir}/inputrc" + ENV['INPUTRC'] = inputrc + + File.write(inputrc, "set emacs-mode-string !") + @config.read + assert_equal '!', @config.emacs_mode_string + + File.write(inputrc, "set emacs-mode-string ?") + @config.reload + assert_equal '?', @config.emacs_mode_string + + File.write(inputrc, "") + @config.reload + assert_equal '@', @config.emacs_mode_string + end end diff --git a/test/reline/test_face.rb b/test/reline/test_face.rb new file mode 100644 index 0000000000..8fa2be8fa4 --- /dev/null +++ b/test/reline/test_face.rb @@ -0,0 +1,257 @@ +# frozen_string_literal: true + +require_relative 'helper' + +class Reline::Face::Test < Reline::TestCase + RESET_SGR = "\e[0m" + + def setup + @colorterm_backup = ENV['COLORTERM'] + ENV['COLORTERM'] = 'truecolor' + end + + def teardown + Reline::Face.reset_to_initial_configs + ENV['COLORTERM'] = @colorterm_backup + end + + class WithInsufficientSetupTest < self + def setup + super + Reline::Face.config(:my_insufficient_config) do |face| + end + @face = Reline::Face[:my_insufficient_config] + end + + def test_my_insufficient_config_line + assert_equal RESET_SGR, @face[:default] + assert_equal RESET_SGR, @face[:enhanced] + assert_equal RESET_SGR, @face[:scrollbar] + end + + def test_my_insufficient_configs + my_configs = Reline::Face.configs[:my_insufficient_config] + assert_equal( + { + default: { style: :reset, escape_sequence: RESET_SGR }, + enhanced: { style: :reset, escape_sequence: RESET_SGR }, + scrollbar: { style: :reset, escape_sequence: RESET_SGR } + }, + my_configs + ) + end + end + + class WithSetupTest < self + def setup + super + Reline::Face.config(:my_config) do |face| + face.define :default, foreground: :blue + face.define :enhanced, foreground: "#FF1020", background: :black, style: [:bold, :underlined] + end + Reline::Face.config(:another_config) do |face| + face.define :another_label, foreground: :red + end + @face = Reline::Face[:my_config] + end + + def test_now_there_are_four_configs + assert_equal %i(default completion_dialog my_config another_config), Reline::Face.configs.keys + end + + def test_resetting_config_discards_user_defined_configs + Reline::Face.reset_to_initial_configs + assert_equal %i(default completion_dialog), Reline::Face.configs.keys + end + + def test_my_configs + my_configs = Reline::Face.configs[:my_config] + assert_equal( + { + default: { + escape_sequence: "#{RESET_SGR}\e[34m", foreground: :blue + }, + enhanced: { + background: :black, + foreground: "#FF1020", + style: [:bold, :underlined], + escape_sequence: "\e[0m\e[38;2;255;16;32;40;1;4m" + }, + scrollbar: { + style: :reset, + escape_sequence: "\e[0m" + } + }, + my_configs + ) + end + + def test_my_config_line + assert_equal "#{RESET_SGR}\e[34m", @face[:default] + end + + def test_my_config_enhanced + assert_equal "#{RESET_SGR}\e[38;2;255;16;32;40;1;4m", @face[:enhanced] + end + + def test_not_respond_to_another_label + assert_equal false, @face.respond_to?(:another_label) + end + end + + class WithoutSetupTest < self + def test_my_config_default + Reline::Face.config(:my_config) do |face| + # do nothing + end + face = Reline::Face[:my_config] + assert_equal RESET_SGR, face[:default] + end + + def test_style_does_not_exist + face = Reline::Face[:default] + assert_raise ArgumentError do + face[:style_does_not_exist] + end + end + + def test_invalid_keyword + assert_raise ArgumentError do + Reline::Face.config(:invalid_config) do |face| + face.define :default, invalid_keyword: :red + end + end + end + + def test_invalid_foreground_name + assert_raise ArgumentError do + Reline::Face.config(:invalid_config) do |face| + face.define :default, foreground: :invalid_name + end + end + end + + def test_invalid_background_name + assert_raise ArgumentError do + Reline::Face.config(:invalid_config) do |face| + face.define :default, background: :invalid_name + end + end + end + + def test_invalid_style_name + assert_raise ArgumentError do + Reline::Face.config(:invalid_config) do |face| + face.define :default, style: :invalid_name + end + end + end + + def test_private_constants + [:SGR_PARAMETER, :Config, :CONFIGS].each do |name| + assert_equal false, Reline::Face.constants.include?(name) + end + end + end + + class ConfigTest < self + def setup + super + @config = Reline::Face.const_get(:Config).new(:my_config) { } + end + + def teardown + super + Reline::Face.instance_variable_set(:@force_truecolor, nil) + end + + def test_rgb? + assert_equal true, @config.send(:rgb_expression?, "#FFFFFF") + end + + def test_invalid_rgb? + assert_equal false, @config.send(:rgb_expression?, "FFFFFF") + assert_equal false, @config.send(:rgb_expression?, "#FFFFF") + end + + def test_format_to_sgr_preserves_order + assert_equal( + "#{RESET_SGR}\e[37;41;1;3m", + @config.send(:format_to_sgr, foreground: :white, background: :red, style: [:bold, :italicized]) + ) + + assert_equal( + "#{RESET_SGR}\e[37;1;3;41m", + @config.send(:format_to_sgr, foreground: :white, style: [:bold, :italicized], background: :red) + ) + end + + def test_format_to_sgr_with_reset + assert_equal( + RESET_SGR, + @config.send(:format_to_sgr, style: :reset) + ) + assert_equal( + "#{RESET_SGR}\e[37;0;41m", + @config.send(:format_to_sgr, foreground: :white, style: :reset, background: :red) + ) + end + + def test_format_to_sgr_with_single_style + assert_equal( + "#{RESET_SGR}\e[37;41;1m", + @config.send(:format_to_sgr, foreground: :white, background: :red, style: :bold) + ) + end + + def test_truecolor + ENV['COLORTERM'] = 'truecolor' + assert_equal true, Reline::Face.truecolor? + ENV['COLORTERM'] = '24bit' + assert_equal true, Reline::Face.truecolor? + ENV['COLORTERM'] = nil + assert_equal false, Reline::Face.truecolor? + Reline::Face.force_truecolor + assert_equal true, Reline::Face.truecolor? + end + + def test_sgr_rgb_truecolor + ENV['COLORTERM'] = 'truecolor' + assert_equal "38;2;255;255;255", @config.send(:sgr_rgb, :foreground, "#ffffff") + assert_equal "48;2;18;52;86", @config.send(:sgr_rgb, :background, "#123456") + end + + def test_sgr_rgb_256color + ENV['COLORTERM'] = nil + assert_equal '38;5;231', @config.send(:sgr_rgb, :foreground, '#ffffff') + assert_equal '48;5;16', @config.send(:sgr_rgb, :background, '#000000') + # Color steps are [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff] + assert_equal '38;5;24', @config.send(:sgr_rgb, :foreground, '#005f87') + assert_equal '38;5;67', @config.send(:sgr_rgb, :foreground, '#5f87af') + assert_equal '48;5;110', @config.send(:sgr_rgb, :background, '#87afd7') + assert_equal '48;5;153', @config.send(:sgr_rgb, :background, '#afd7ff') + # Boundary values are [0x30, 0x73, 0x9b, 0xc3, 0xeb] + assert_equal '38;5;24', @config.send(:sgr_rgb, :foreground, '#2f729a') + assert_equal '38;5;67', @config.send(:sgr_rgb, :foreground, '#30739b') + assert_equal '48;5;110', @config.send(:sgr_rgb, :background, '#9ac2ea') + assert_equal '48;5;153', @config.send(:sgr_rgb, :background, '#9bc3eb') + end + + def test_force_truecolor_reconfigure + ENV['COLORTERM'] = nil + + Reline::Face.config(:my_config) do |face| + face.define :default, foreground: '#005f87' + face.define :enhanced, background: '#afd7ff' + end + + assert_equal "\e[0m\e[38;5;24m", Reline::Face[:my_config][:default] + assert_equal "\e[0m\e[48;5;153m", Reline::Face[:my_config][:enhanced] + + Reline::Face.force_truecolor + + assert_equal "\e[0m\e[38;2;0;95;135m", Reline::Face[:my_config][:default] + assert_equal "\e[0m\e[48;2;175;215;255m", Reline::Face[:my_config][:enhanced] + end + end +end diff --git a/test/reline/test_history.rb b/test/reline/test_history.rb index 53360409bc..ddf8fb1472 100644 --- a/test/reline/test_history.rb +++ b/test/reline/test_history.rb @@ -297,7 +297,7 @@ class Reline::History::Test < Reline::TestCase end def get_default_internal_encoding - if encoding = Reline::IOGate.encoding + if encoding = Reline.core.encoding encoding elsif RUBY_PLATFORM =~ /mswin|mingw/ Encoding.default_internal || Encoding::UTF_8 diff --git a/test/reline/test_key_actor_emacs.rb b/test/reline/test_key_actor_emacs.rb index 40b26e5058..4dddf9c890 100644 --- a/test/reline/test_key_actor_emacs.rb +++ b/test/reline/test_key_actor_emacs.rb @@ -1,6 +1,6 @@ require_relative 'helper' -class Reline::KeyActor::Emacs::Test < Reline::TestCase +class Reline::KeyActor::EmacsTest < Reline::TestCase def setup Reline.send(:test_mode) @prompt = '> ' @@ -8,7 +8,7 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase @config.autocompletion = false Reline::HISTORY.instance_variable_set(:@config, @config) Reline::HISTORY.clear - @encoding = Reline::IOGate.encoding + @encoding = Reline.core.encoding @line_editor = Reline::LineEditor.new(@config, @encoding) @line_editor.reset(@prompt, encoding: @encoding) end @@ -19,1234 +19,699 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase def test_ed_insert_one input_keys('a') - assert_line('a') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(1) + assert_line_around_cursor('a', '') end def test_ed_insert_two input_keys('ab') - assert_line('ab') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('ab', '') end def test_ed_insert_mbchar_one input_keys('か') - assert_line('か') - assert_byte_pointer_size('か') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('か', '') end def test_ed_insert_mbchar_two input_keys('かき') - assert_line('かき') - assert_byte_pointer_size('かき') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('かき', '') end def test_ed_insert_for_mbchar_by_plural_code_points input_keys("か\u3099") - assert_line("か\u3099") - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor("か\u3099", '') end def test_ed_insert_for_plural_mbchar_by_plural_code_points input_keys("か\u3099き\u3099") - assert_line("か\u3099き\u3099") - assert_byte_pointer_size("か\u3099き\u3099") - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor("か\u3099き\u3099", '') end def test_move_next_and_prev input_keys('abd') - assert_byte_pointer_size('abd') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('abd', '') input_keys("\C-b", false) - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(3) + assert_line_around_cursor('ab', 'd') input_keys("\C-b", false) - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(3) + assert_line_around_cursor('a', 'bd') input_keys("\C-f", false) - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(3) + assert_line_around_cursor('ab', 'd') input_keys('c') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(4) - assert_line('abcd') + assert_line_around_cursor('abc', 'd') end def test_move_next_and_prev_for_mbchar input_keys('かきけ') - assert_byte_pointer_size('かきけ') - assert_cursor(6) - assert_cursor_max(6) + assert_line_around_cursor('かきけ', '') input_keys("\C-b", false) - assert_byte_pointer_size('かき') - assert_cursor(4) - assert_cursor_max(6) + assert_line_around_cursor('かき', 'け') input_keys("\C-b", false) - assert_byte_pointer_size('か') - assert_cursor(2) - assert_cursor_max(6) + assert_line_around_cursor('か', 'きけ') input_keys("\C-f", false) - assert_byte_pointer_size('かき') - assert_cursor(4) - assert_cursor_max(6) + assert_line_around_cursor('かき', 'け') input_keys('く') - assert_byte_pointer_size('かきく') - assert_cursor(6) - assert_cursor_max(8) - assert_line('かきくけ') + assert_line_around_cursor('かきく', 'け') end def test_move_next_and_prev_for_mbchar_by_plural_code_points input_keys("か\u3099き\u3099け\u3099") - assert_byte_pointer_size("か\u3099き\u3099け\u3099") - assert_cursor(6) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099き\u3099け\u3099", '') input_keys("\C-b", false) - assert_byte_pointer_size("か\u3099き\u3099") - assert_cursor(4) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099き\u3099", "け\u3099") input_keys("\C-b", false) - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099", "き\u3099け\u3099") input_keys("\C-f", false) - assert_byte_pointer_size("か\u3099き\u3099") - assert_cursor(4) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099き\u3099", "け\u3099") input_keys("く\u3099") - assert_byte_pointer_size("か\u3099き\u3099く\u3099") - assert_cursor(6) - assert_cursor_max(8) - assert_line("か\u3099き\u3099く\u3099け\u3099") + assert_line_around_cursor("か\u3099き\u3099く\u3099", "け\u3099") end def test_move_to_beg_end input_keys('bcd') - assert_byte_pointer_size('bcd') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('bcd', '') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) + assert_line_around_cursor('', 'bcd') input_keys('a') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(4) + assert_line_around_cursor('a', 'bcd') input_keys("\C-e", false) - assert_byte_pointer_size('abcd') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('abcd', '') input_keys('e') - assert_byte_pointer_size('abcde') - assert_cursor(5) - assert_cursor_max(5) - assert_line('abcde') + assert_line_around_cursor('abcde', '') end def test_ed_newline_with_cr input_keys('ab') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('ab', '') refute(@line_editor.finished?) input_keys("\C-m", false) - assert_line('ab') + assert_line_around_cursor('ab', '') assert(@line_editor.finished?) end def test_ed_newline_with_lf input_keys('ab') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('ab', '') refute(@line_editor.finished?) input_keys("\C-j", false) - assert_line('ab') + assert_line_around_cursor('ab', '') assert(@line_editor.finished?) end def test_em_delete_prev_char input_keys('ab') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('ab', '') input_keys("\C-h", false) - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(1) - assert_line('a') + assert_line_around_cursor('a', '') end def test_em_delete_prev_char_for_mbchar input_keys('かき') - assert_byte_pointer_size('かき') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('かき', '') input_keys("\C-h", false) - assert_byte_pointer_size('か') - assert_cursor(2) - assert_cursor_max(2) - assert_line('か') + assert_line_around_cursor('か', '') end def test_em_delete_prev_char_for_mbchar_by_plural_code_points input_keys("か\u3099き\u3099") - assert_byte_pointer_size("か\u3099き\u3099") - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor("か\u3099き\u3099", '') input_keys("\C-h", false) - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(2) - assert_line("か\u3099") + assert_line_around_cursor("か\u3099", '') end def test_ed_quoted_insert input_keys("ab\C-v\C-acd") - assert_line("ab\C-acd") - assert_byte_pointer_size("ab\C-acd") - assert_cursor(6) - assert_cursor_max(6) + assert_line_around_cursor("ab\C-acd", '') input_keys("\C-q\C-b") - assert_line("ab\C-acd\C-b") - assert_byte_pointer_size("ab\C-acd\C-b") - assert_cursor(8) - assert_cursor_max(8) + assert_line_around_cursor("ab\C-acd\C-b", '') end def test_ed_kill_line input_keys("\C-k", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys('abc') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('abc', '') input_keys("\C-k", false) - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(3) - assert_line('abc') + assert_line_around_cursor('abc', '') input_keys("\C-b\C-k", false) - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) - assert_line('ab') + assert_line_around_cursor('ab', '') end def test_em_kill_line @line_editor.input_key(Reline::Key.new(:em_kill_line, :em_kill_line, false)) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys('abc') @line_editor.input_key(Reline::Key.new(:em_kill_line, :em_kill_line, false)) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys('abc') input_keys("\C-b", false) @line_editor.input_key(Reline::Key.new(:em_kill_line, :em_kill_line, false)) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys('abc') input_keys("\C-a", false) @line_editor.input_key(Reline::Key.new(:em_kill_line, :em_kill_line, false)) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_ed_move_to_beg input_keys('abd') - assert_byte_pointer_size('abd') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('abd', '') input_keys("\C-b", false) - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(3) + assert_line_around_cursor('ab', 'd') input_keys('c') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(4) + assert_line_around_cursor('abc', 'd') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(4) + assert_line_around_cursor('', 'abcd') input_keys('012') - assert_byte_pointer_size('012') - assert_cursor(3) - assert_cursor_max(7) - assert_line('012abcd') + assert_line_around_cursor('012', 'abcd') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(7) + assert_line_around_cursor('', '012abcd') input_keys('ABC') - assert_byte_pointer_size('ABC') - assert_cursor(3) - assert_cursor_max(10) - assert_line('ABC012abcd') + assert_line_around_cursor('ABC', '012abcd') input_keys("\C-f" * 10 + "\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(10) + assert_line_around_cursor('', 'ABC012abcd') input_keys('a') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(11) - assert_line('aABC012abcd') + assert_line_around_cursor('a', 'ABC012abcd') end def test_ed_move_to_beg_with_blank input_keys(' abc') - assert_byte_pointer_size(' abc') - assert_cursor(5) - assert_cursor_max(5) + assert_line_around_cursor(' abc', '') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) + assert_line_around_cursor('', ' abc') end def test_ed_move_to_end input_keys('abd') - assert_byte_pointer_size('abd') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('abd', '') input_keys("\C-b", false) - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(3) + assert_line_around_cursor('ab', 'd') input_keys('c') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(4) + assert_line_around_cursor('abc', 'd') input_keys("\C-e", false) - assert_byte_pointer_size('abcd') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('abcd', '') input_keys('012') - assert_byte_pointer_size('abcd012') - assert_cursor(7) - assert_cursor_max(7) - assert_line('abcd012') + assert_line_around_cursor('abcd012', '') input_keys("\C-e", false) - assert_byte_pointer_size('abcd012') - assert_cursor(7) - assert_cursor_max(7) + assert_line_around_cursor('abcd012', '') input_keys('ABC') - assert_byte_pointer_size('abcd012ABC') - assert_cursor(10) - assert_cursor_max(10) - assert_line('abcd012ABC') + assert_line_around_cursor('abcd012ABC', '') input_keys("\C-b" * 10 + "\C-e", false) - assert_byte_pointer_size('abcd012ABC') - assert_cursor(10) - assert_cursor_max(10) + assert_line_around_cursor('abcd012ABC', '') input_keys('a') - assert_byte_pointer_size('abcd012ABCa') - assert_cursor(11) - assert_cursor_max(11) - assert_line('abcd012ABCa') + assert_line_around_cursor('abcd012ABCa', '') end def test_em_delete input_keys('ab') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('ab', '') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(2) + assert_line_around_cursor('', 'ab') input_keys("\C-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(1) - assert_line('b') + assert_line_around_cursor('', 'b') end def test_em_delete_for_mbchar input_keys('かき') - assert_byte_pointer_size('かき') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('かき', '') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(4) + assert_line_around_cursor('', 'かき') input_keys("\C-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(2) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(2) - assert_line('き') + assert_line_around_cursor('', 'き') end def test_em_delete_for_mbchar_by_plural_code_points input_keys("か\u3099き\u3099") - assert_byte_pointer_size("か\u3099き\u3099") - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor("か\u3099き\u3099", '') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(4) + assert_line_around_cursor('', "か\u3099き\u3099") input_keys("\C-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(2) - assert_line("き\u3099") + assert_line_around_cursor('', "き\u3099") + end + + def test_em_delete_ends_editing + input_keys("\C-d") # quit from inputing + assert_nil(@line_editor.line) + assert(@line_editor.finished?) end def test_ed_clear_screen - refute(@line_editor.instance_variable_get(:@cleared)) + @line_editor.instance_variable_get(:@rendered_screen).lines = [[]] input_keys("\C-l", false) - assert(@line_editor.instance_variable_get(:@cleared)) + assert_empty(@line_editor.instance_variable_get(:@rendered_screen).lines) end def test_ed_clear_screen_with_inputed input_keys('abc') input_keys("\C-b", false) - refute(@line_editor.instance_variable_get(:@cleared)) - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(3) + @line_editor.instance_variable_get(:@rendered_screen).lines = [[]] + assert_line_around_cursor('ab', 'c') input_keys("\C-l", false) - assert(@line_editor.instance_variable_get(:@cleared)) - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(3) - assert_line('abc') + assert_empty(@line_editor.instance_variable_get(:@rendered_screen).lines) + assert_line_around_cursor('ab', 'c') + end + + def test_key_delete + input_keys('abc') + assert_line_around_cursor('abc', '') + @line_editor.input_key(Reline::Key.new(:key_delete, :key_delete, false)) + assert_line_around_cursor('abc', '') + end + + def test_key_delete_does_not_end_editing + @line_editor.input_key(Reline::Key.new(:key_delete, :key_delete, false)) + assert_line_around_cursor('', '') + refute(@line_editor.finished?) end - def test_ed_delete_next_char + def test_key_delete_preserves_cursor input_keys('abc') - assert_cursor(3) - assert_cursor_max(3) + input_keys("\C-b", false) + assert_line_around_cursor('ab', 'c') @line_editor.input_key(Reline::Key.new(:key_delete, :key_delete, false)) - assert_cursor(3) - assert_cursor_max(3) - assert_line('abc') + assert_line_around_cursor('ab', '') end def test_em_next_word - assert_byte_pointer_size('') - assert_cursor(0) + assert_line_around_cursor('', '') input_keys('abc def{bbb}ccc') input_keys("\C-a\M-F", false) - assert_byte_pointer_size('abc') - assert_cursor(3) + assert_line_around_cursor('abc', ' def{bbb}ccc') input_keys("\M-F", false) - assert_byte_pointer_size('abc def') - assert_cursor(7) + assert_line_around_cursor('abc def', '{bbb}ccc') input_keys("\M-F", false) - assert_byte_pointer_size('abc def{bbb') - assert_cursor(11) + assert_line_around_cursor('abc def{bbb', '}ccc') input_keys("\M-F", false) - assert_byte_pointer_size('abc def{bbb}ccc') - assert_cursor(15) + assert_line_around_cursor('abc def{bbb}ccc', '') input_keys("\M-F", false) - assert_byte_pointer_size('abc def{bbb}ccc') - assert_cursor(15) + assert_line_around_cursor('abc def{bbb}ccc', '') end def test_em_next_word_for_mbchar - assert_cursor(0) + assert_line_around_cursor('', '') input_keys('あいう かきく{さしす}たちつ') input_keys("\C-a\M-F", false) - assert_byte_pointer_size('あいう') - assert_cursor(6) + assert_line_around_cursor('あいう', ' かきく{さしす}たちつ') input_keys("\M-F", false) - assert_byte_pointer_size('あいう かきく') - assert_cursor(13) + assert_line_around_cursor('あいう かきく', '{さしす}たちつ') input_keys("\M-F", false) - assert_byte_pointer_size('あいう かきく{さしす') - assert_cursor(20) + assert_line_around_cursor('あいう かきく{さしす', '}たちつ') input_keys("\M-F", false) - assert_byte_pointer_size('あいう かきく{さしす}たちつ') - assert_cursor(27) + assert_line_around_cursor('あいう かきく{さしす}たちつ', '') input_keys("\M-F", false) - assert_byte_pointer_size('あいう かきく{さしす}たちつ') - assert_cursor(27) + assert_line_around_cursor('あいう かきく{さしす}たちつ', '') end def test_em_next_word_for_mbchar_by_plural_code_points - assert_cursor(0) + assert_line_around_cursor("", "") input_keys("あいう か\u3099き\u3099く\u3099{さしす}たちつ") input_keys("\C-a\M-F", false) - assert_byte_pointer_size("あいう") - assert_cursor(6) + assert_line_around_cursor("あいう", " か\u3099き\u3099く\u3099{さしす}たちつ") input_keys("\M-F", false) - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099") - assert_cursor(13) + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099", "{さしす}たちつ") input_keys("\M-F", false) - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{さしす") - assert_cursor(20) + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす", "}たちつ") input_keys("\M-F", false) - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{さしす}たちつ") - assert_cursor(27) + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}たちつ", "") input_keys("\M-F", false) - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{さしす}たちつ") - assert_cursor(27) + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}たちつ", "") end def test_em_prev_word input_keys('abc def{bbb}ccc') - assert_byte_pointer_size('abc def{bbb}ccc') - assert_cursor(15) + assert_line_around_cursor('abc def{bbb}ccc', '') input_keys("\M-B", false) - assert_byte_pointer_size('abc def{bbb}') - assert_cursor(12) + assert_line_around_cursor('abc def{bbb}', 'ccc') input_keys("\M-B", false) - assert_byte_pointer_size('abc def{') - assert_cursor(8) + assert_line_around_cursor('abc def{', 'bbb}ccc') input_keys("\M-B", false) - assert_byte_pointer_size('abc ') - assert_cursor(4) + assert_line_around_cursor('abc ', 'def{bbb}ccc') input_keys("\M-B", false) - assert_byte_pointer_size('') - assert_cursor(0) + assert_line_around_cursor('', 'abc def{bbb}ccc') input_keys("\M-B", false) - assert_byte_pointer_size('') - assert_cursor(0) + assert_line_around_cursor('', 'abc def{bbb}ccc') end def test_em_prev_word_for_mbchar input_keys('あいう かきく{さしす}たちつ') - assert_byte_pointer_size('あいう かきく{さしす}たちつ') - assert_cursor(27) + assert_line_around_cursor('あいう かきく{さしす}たちつ', '') input_keys("\M-B", false) - assert_byte_pointer_size('あいう かきく{さしす}') - assert_cursor(21) + assert_line_around_cursor('あいう かきく{さしす}', 'たちつ') input_keys("\M-B", false) - assert_byte_pointer_size('あいう かきく{') - assert_cursor(14) + assert_line_around_cursor('あいう かきく{', 'さしす}たちつ') input_keys("\M-B", false) - assert_byte_pointer_size('あいう ') - assert_cursor(7) + assert_line_around_cursor('あいう ', 'かきく{さしす}たちつ') input_keys("\M-B", false) - assert_byte_pointer_size('') - assert_cursor(0) + assert_line_around_cursor('', 'あいう かきく{さしす}たちつ') input_keys("\M-B", false) - assert_byte_pointer_size('') - assert_cursor(0) + assert_line_around_cursor('', 'あいう かきく{さしす}たちつ') end def test_em_prev_word_for_mbchar_by_plural_code_points input_keys("あいう か\u3099き\u3099く\u3099{さしす}たちつ") - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{さしす}たちつ") - assert_cursor(27) + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}たちつ", "") input_keys("\M-B", false) - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{さしす}") - assert_cursor(21) + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}", "たちつ") input_keys("\M-B", false) - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{") - assert_cursor(14) + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{", "さしす}たちつ") input_keys("\M-B", false) - assert_byte_pointer_size('あいう ') - assert_cursor(7) + assert_line_around_cursor("あいう ", "か\u3099き\u3099く\u3099{さしす}たちつ") input_keys("\M-B", false) - assert_byte_pointer_size('') - assert_cursor(0) + assert_line_around_cursor("", "あいう か\u3099き\u3099く\u3099{さしす}たちつ") input_keys("\M-B", false) - assert_byte_pointer_size('') - assert_cursor(0) + assert_line_around_cursor("", "あいう か\u3099き\u3099く\u3099{さしす}たちつ") end def test_em_delete_next_word input_keys('abc def{bbb}ccc') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(15) + assert_line_around_cursor('', 'abc def{bbb}ccc') input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(12) - assert_line(' def{bbb}ccc') + assert_line_around_cursor('', ' def{bbb}ccc') input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(8) - assert_line('{bbb}ccc') + assert_line_around_cursor('', '{bbb}ccc') input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(4) - assert_line('}ccc') + assert_line_around_cursor('', '}ccc') input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_em_delete_next_word_for_mbchar input_keys('あいう かきく{さしす}たちつ') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(27) + assert_line_around_cursor('', 'あいう かきく{さしす}たちつ') input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(21) - assert_line(' かきく{さしす}たちつ') + assert_line_around_cursor('', ' かきく{さしす}たちつ') input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(14) - assert_line('{さしす}たちつ') + assert_line_around_cursor('', '{さしす}たちつ') input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(7) - assert_line('}たちつ') + assert_line_around_cursor('', '}たちつ') input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_em_delete_next_word_for_mbchar_by_plural_code_points input_keys("あいう か\u3099き\u3099く\u3099{さしす}たちつ") input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(27) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(27) + assert_line_around_cursor('', "あいう か\u3099き\u3099く\u3099{さしす}たちつ") input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(21) - assert_line(" か\u3099き\u3099く\u3099{さしす}たちつ") + assert_line_around_cursor('', " か\u3099き\u3099く\u3099{さしす}たちつ") input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(14) - assert_line('{さしす}たちつ') + assert_line_around_cursor('', '{さしす}たちつ') input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(7) - assert_line('}たちつ') + assert_line_around_cursor('', '}たちつ') input_keys("\M-d", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_ed_delete_prev_word input_keys('abc def{bbb}ccc') - assert_byte_pointer_size('abc def{bbb}ccc') - assert_cursor(15) - assert_cursor_max(15) + assert_line_around_cursor('abc def{bbb}ccc', '') input_keys("\M-\C-H", false) - assert_byte_pointer_size('abc def{bbb}') - assert_cursor(12) - assert_cursor_max(12) - assert_line('abc def{bbb}') + assert_line_around_cursor('abc def{bbb}', '') input_keys("\M-\C-H", false) - assert_byte_pointer_size('abc def{') - assert_cursor(8) - assert_cursor_max(8) - assert_line('abc def{') + assert_line_around_cursor('abc def{', '') input_keys("\M-\C-H", false) - assert_byte_pointer_size('abc ') - assert_cursor(4) - assert_cursor_max(4) - assert_line('abc ') + assert_line_around_cursor('abc ', '') input_keys("\M-\C-H", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_ed_delete_prev_word_for_mbchar input_keys('あいう かきく{さしす}たちつ') - assert_byte_pointer_size('あいう かきく{さしす}たちつ') - assert_cursor(27) - assert_cursor_max(27) + assert_line_around_cursor('あいう かきく{さしす}たちつ', '') input_keys("\M-\C-H", false) - assert_byte_pointer_size('あいう かきく{さしす}') - assert_cursor(21) - assert_cursor_max(21) - assert_line('あいう かきく{さしす}') + assert_line_around_cursor('あいう かきく{さしす}', '') input_keys("\M-\C-H", false) - assert_byte_pointer_size('あいう かきく{') - assert_cursor(14) - assert_cursor_max(14) - assert_line('あいう かきく{') + assert_line_around_cursor('あいう かきく{', '') input_keys("\M-\C-H", false) - assert_byte_pointer_size('あいう ') - assert_cursor(7) - assert_cursor_max(7) - assert_line('あいう ') + assert_line_around_cursor('あいう ', '') input_keys("\M-\C-H", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_ed_delete_prev_word_for_mbchar_by_plural_code_points input_keys("あいう か\u3099き\u3099く\u3099{さしす}たちつ") - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{さしす}たちつ") - assert_cursor(27) - assert_cursor_max(27) + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}たちつ", '') input_keys("\M-\C-H", false) - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{さしす}") - assert_cursor(21) - assert_cursor_max(21) - assert_line("あいう か\u3099き\u3099く\u3099{さしす}") + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}", '') input_keys("\M-\C-H", false) - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{") - assert_cursor(14) - assert_cursor_max(14) - assert_line("あいう か\u3099き\u3099く\u3099{") + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{", '') input_keys("\M-\C-H", false) - assert_byte_pointer_size("あいう ") - assert_cursor(7) - assert_cursor_max(7) - assert_line('あいう ') + assert_line_around_cursor('あいう ', '') input_keys("\M-\C-H", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_ed_transpose_chars input_keys('abc') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) + assert_line_around_cursor('', 'abc') input_keys("\C-t", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) - assert_line('abc') + assert_line_around_cursor('', 'abc') input_keys("\C-f\C-t", false) - assert_byte_pointer_size('ba') - assert_cursor(2) - assert_cursor_max(3) - assert_line('bac') + assert_line_around_cursor('ba', 'c') input_keys("\C-t", false) - assert_byte_pointer_size('bca') - assert_cursor(3) - assert_cursor_max(3) - assert_line('bca') + assert_line_around_cursor('bca', '') input_keys("\C-t", false) - assert_byte_pointer_size('bac') - assert_cursor(3) - assert_cursor_max(3) - assert_line('bac') + assert_line_around_cursor('bac', '') end def test_ed_transpose_chars_for_mbchar input_keys('あかさ') input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', 'あかさ') input_keys("\C-t", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) - assert_line('あかさ') + assert_line_around_cursor('', 'あかさ') input_keys("\C-f\C-t", false) - assert_byte_pointer_size('かあ') - assert_cursor(4) - assert_cursor_max(6) - assert_line('かあさ') + assert_line_around_cursor('かあ', 'さ') input_keys("\C-t", false) - assert_byte_pointer_size('かさあ') - assert_cursor(6) - assert_cursor_max(6) - assert_line('かさあ') + assert_line_around_cursor('かさあ', '') input_keys("\C-t", false) - assert_byte_pointer_size('かあさ') - assert_cursor(6) - assert_cursor_max(6) - assert_line('かあさ') + assert_line_around_cursor('かあさ', '') end def test_ed_transpose_chars_for_mbchar_by_plural_code_points input_keys("あか\u3099さ") input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', "あか\u3099さ") input_keys("\C-t", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) - assert_line("あか\u3099さ") + assert_line_around_cursor('', "あか\u3099さ") input_keys("\C-f\C-t", false) - assert_byte_pointer_size("か\u3099あ") - assert_cursor(4) - assert_cursor_max(6) - assert_line("か\u3099あさ") + assert_line_around_cursor("か\u3099あ", 'さ') input_keys("\C-t", false) - assert_byte_pointer_size("か\u3099さあ") - assert_cursor(6) - assert_cursor_max(6) - assert_line("か\u3099さあ") + assert_line_around_cursor("か\u3099さあ", '') input_keys("\C-t", false) - assert_byte_pointer_size("か\u3099あさ") - assert_cursor(6) - assert_cursor_max(6) - assert_line("か\u3099あさ") + assert_line_around_cursor("か\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) + assert_line_around_cursor('abc def', '') input_keys("\M-t", false) - assert_line('def abc') - assert_byte_pointer_size('def abc') - assert_cursor(7) - assert_cursor_max(7) + assert_line_around_cursor('def abc', '') 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) + assert_line_around_cursor(' abc de', 'f ') input_keys("\M-t", false) - assert_line(' def abc ') - assert_byte_pointer_size(' def abc') - assert_cursor(9) - assert_cursor_max(12) + assert_line_around_cursor(' def abc', ' ') 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) + assert_line_around_cursor(' abc ', 'def ') input_keys("\M-t", false) - assert_line(' def abc ') - assert_byte_pointer_size(' def abc') - assert_cursor(9) - assert_cursor_max(12) + assert_line_around_cursor(' def abc', ' ') input_keys("\M-t", false) - assert_line(' abc def') - assert_byte_pointer_size(' abc def') - assert_cursor(12) - assert_cursor_max(12) + assert_line_around_cursor(' abc def', '') end def test_ed_transpose_words_for_mbchar input_keys('あいう かきく') - assert_line('あいう かきく') - assert_byte_pointer_size('あいう かきく') - assert_cursor(13) - assert_cursor_max(13) + assert_line_around_cursor('あいう かきく', '') input_keys("\M-t", false) - assert_line('かきく あいう') - assert_byte_pointer_size('かきく あいう') - assert_cursor(13) - assert_cursor_max(13) + assert_line_around_cursor('かきく あいう', '') input_keys("\C-a\C-k", false) input_keys(' あいう かきく ') input_keys("\C-b" * 4, false) - assert_line(' あいう かきく ') - assert_byte_pointer_size(' あいう かき') - assert_cursor(13) - assert_cursor_max(18) + assert_line_around_cursor(' あいう かき', 'く ') input_keys("\M-t", false) - assert_line(' かきく あいう ') - assert_byte_pointer_size(' かきく あいう') - assert_cursor(15) - assert_cursor_max(18) + assert_line_around_cursor(' かきく あいう', ' ') input_keys("\C-a\C-k", false) input_keys(' あいう かきく ') input_keys("\C-b" * 6, false) - assert_line(' あいう かきく ') - assert_byte_pointer_size(' あいう ') - assert_cursor(9) - assert_cursor_max(18) + assert_line_around_cursor(' あいう ', 'かきく ') input_keys("\M-t", false) - assert_line(' かきく あいう ') - assert_byte_pointer_size(' かきく あいう') - assert_cursor(15) - assert_cursor_max(18) + assert_line_around_cursor(' かきく あいう', ' ') input_keys("\M-t", false) - assert_line(' あいう かきく') - assert_byte_pointer_size(' あいう かきく') - assert_cursor(18) - assert_cursor_max(18) + assert_line_around_cursor(' あいう かきく', '') end def test_ed_transpose_words_with_one_word input_keys('abc ') - assert_line('abc ') - assert_byte_pointer_size('abc ') - assert_cursor(5) - assert_cursor_max(5) + assert_line_around_cursor('abc ', '') input_keys("\M-t", false) - assert_line('abc ') - assert_byte_pointer_size('abc ') - assert_cursor(5) - assert_cursor_max(5) + assert_line_around_cursor('abc ', '') input_keys("\C-b", false) - assert_line('abc ') - assert_byte_pointer_size('abc ') - assert_cursor(4) - assert_cursor_max(5) + assert_line_around_cursor('abc ', ' ') input_keys("\M-t", false) - assert_line('abc ') - assert_byte_pointer_size('abc ') - assert_cursor(4) - assert_cursor_max(5) + assert_line_around_cursor('abc ', ' ') input_keys("\C-b" * 2, false) - assert_line('abc ') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(5) + assert_line_around_cursor('ab', 'c ') input_keys("\M-t", false) - assert_line('abc ') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(5) + assert_line_around_cursor('ab', 'c ') input_keys("\M-t", false) - assert_line('abc ') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(5) + assert_line_around_cursor('ab', 'c ') end def test_ed_transpose_words_with_one_word_for_mbchar input_keys('あいう ') - assert_line('あいう ') - assert_byte_pointer_size('あいう ') - assert_cursor(8) - assert_cursor_max(8) + assert_line_around_cursor('あいう ', '') input_keys("\M-t", false) - assert_line('あいう ') - assert_byte_pointer_size('あいう ') - assert_cursor(8) - assert_cursor_max(8) + assert_line_around_cursor('あいう ', '') input_keys("\C-b", false) - assert_line('あいう ') - assert_byte_pointer_size('あいう ') - assert_cursor(7) - assert_cursor_max(8) + assert_line_around_cursor('あいう ', ' ') input_keys("\M-t", false) - assert_line('あいう ') - assert_byte_pointer_size('あいう ') - assert_cursor(7) - assert_cursor_max(8) + assert_line_around_cursor('あいう ', ' ') input_keys("\C-b" * 2, false) - assert_line('あいう ') - assert_byte_pointer_size('あい') - assert_cursor(4) - assert_cursor_max(8) + assert_line_around_cursor('あい', 'う ') input_keys("\M-t", false) - assert_line('あいう ') - assert_byte_pointer_size('あい') - assert_cursor(4) - assert_cursor_max(8) + assert_line_around_cursor('あい', 'う ') input_keys("\M-t", false) - assert_line('あいう ') - assert_byte_pointer_size('あい') - assert_cursor(4) - assert_cursor_max(8) + assert_line_around_cursor('あい', 'う ') end def test_ed_digit input_keys('0123') - assert_byte_pointer_size('0123') - assert_cursor(4) - assert_cursor_max(4) - assert_line('0123') + assert_line_around_cursor('0123', '') end def test_ed_next_and_prev_char input_keys('abc') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('abc', '') input_keys("\C-b", false) - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(3) + assert_line_around_cursor('ab', 'c') input_keys("\C-b", false) - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(3) + assert_line_around_cursor('a', 'bc') input_keys("\C-b", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) + assert_line_around_cursor('', 'abc') input_keys("\C-b", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) + assert_line_around_cursor('', 'abc') input_keys("\C-f", false) - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(3) + assert_line_around_cursor('a', 'bc') input_keys("\C-f", false) - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(3) + assert_line_around_cursor('ab', 'c') input_keys("\C-f", false) - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('abc', '') input_keys("\C-f", false) - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('abc', '') end def test_ed_next_and_prev_char_for_mbchar input_keys('あいう') - assert_byte_pointer_size('あいう') - assert_cursor(6) - assert_cursor_max(6) + assert_line_around_cursor('あいう', '') input_keys("\C-b", false) - assert_byte_pointer_size('あい') - assert_cursor(4) - assert_cursor_max(6) + assert_line_around_cursor('あい', 'う') input_keys("\C-b", false) - assert_byte_pointer_size('あ') - assert_cursor(2) - assert_cursor_max(6) + assert_line_around_cursor('あ', 'いう') input_keys("\C-b", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', 'あいう') input_keys("\C-b", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', 'あいう') input_keys("\C-f", false) - assert_byte_pointer_size('あ') - assert_cursor(2) - assert_cursor_max(6) + assert_line_around_cursor('あ', 'いう') input_keys("\C-f", false) - assert_byte_pointer_size('あい') - assert_cursor(4) - assert_cursor_max(6) + assert_line_around_cursor('あい', 'う') input_keys("\C-f", false) - assert_byte_pointer_size('あいう') - assert_cursor(6) - assert_cursor_max(6) + assert_line_around_cursor('あいう', '') input_keys("\C-f", false) - assert_byte_pointer_size('あいう') - assert_cursor(6) - assert_cursor_max(6) + assert_line_around_cursor('あいう', '') end def test_ed_next_and_prev_char_for_mbchar_by_plural_code_points input_keys("か\u3099き\u3099く\u3099") - assert_byte_pointer_size("か\u3099き\u3099く\u3099") - assert_cursor(6) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099き\u3099く\u3099", '') input_keys("\C-b", false) - assert_byte_pointer_size("か\u3099き\u3099") - assert_cursor(4) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099き\u3099", "く\u3099") input_keys("\C-b", false) - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099", "き\u3099く\u3099") input_keys("\C-b", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', "か\u3099き\u3099く\u3099") input_keys("\C-b", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', "か\u3099き\u3099く\u3099") input_keys("\C-f", false) - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099", "き\u3099く\u3099") input_keys("\C-f", false) - assert_byte_pointer_size("か\u3099き\u3099") - assert_cursor(4) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099き\u3099", "く\u3099") input_keys("\C-f", false) - assert_byte_pointer_size("か\u3099き\u3099く\u3099") - assert_cursor(6) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099き\u3099く\u3099", '') input_keys("\C-f", false) - assert_byte_pointer_size("か\u3099き\u3099く\u3099") - assert_cursor(6) - assert_cursor_max(6) + assert_line_around_cursor("か\u3099き\u3099く\u3099", '') end def test_em_capitol_case input_keys('abc def{bbb}ccc') input_keys("\C-a\M-c", false) - assert_byte_pointer_size('Abc') - assert_cursor(3) - assert_cursor_max(15) - assert_line('Abc def{bbb}ccc') + assert_line_around_cursor('Abc', ' def{bbb}ccc') input_keys("\M-c", false) - assert_byte_pointer_size('Abc Def') - assert_cursor(7) - assert_cursor_max(15) - assert_line('Abc Def{bbb}ccc') + assert_line_around_cursor('Abc Def', '{bbb}ccc') input_keys("\M-c", false) - assert_byte_pointer_size('Abc Def{Bbb') - assert_cursor(11) - assert_cursor_max(15) - assert_line('Abc Def{Bbb}ccc') + assert_line_around_cursor('Abc Def{Bbb', '}ccc') input_keys("\M-c", false) - assert_byte_pointer_size('Abc Def{Bbb}Ccc') - assert_cursor(15) - assert_cursor_max(15) - assert_line('Abc Def{Bbb}Ccc') + assert_line_around_cursor('Abc Def{Bbb}Ccc', '') end def test_em_capitol_case_with_complex_example input_keys('{}#* AaA!!!cCc ') input_keys("\C-a\M-c", false) - assert_byte_pointer_size('{}#* Aaa') - assert_cursor(11) - assert_cursor_max(20) - assert_line('{}#* Aaa!!!cCc ') + assert_line_around_cursor('{}#* Aaa', '!!!cCc ') input_keys("\M-c", false) - assert_byte_pointer_size('{}#* Aaa!!!Ccc') - assert_cursor(17) - assert_cursor_max(20) - assert_line('{}#* Aaa!!!Ccc ') + assert_line_around_cursor('{}#* Aaa!!!Ccc', ' ') input_keys("\M-c", false) - assert_byte_pointer_size('{}#* Aaa!!!Ccc ') - assert_cursor(20) - assert_cursor_max(20) - assert_line('{}#* Aaa!!!Ccc ') + assert_line_around_cursor('{}#* Aaa!!!Ccc ', '') end def test_em_lower_case input_keys('AbC def{bBb}CCC') input_keys("\C-a\M-l", false) - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(15) - assert_line('abc def{bBb}CCC') + assert_line_around_cursor('abc', ' def{bBb}CCC') input_keys("\M-l", false) - assert_byte_pointer_size('abc def') - assert_cursor(7) - assert_cursor_max(15) - assert_line('abc def{bBb}CCC') + assert_line_around_cursor('abc def', '{bBb}CCC') input_keys("\M-l", false) - assert_byte_pointer_size('abc def{bbb') - assert_cursor(11) - assert_cursor_max(15) - assert_line('abc def{bbb}CCC') + assert_line_around_cursor('abc def{bbb', '}CCC') input_keys("\M-l", false) - assert_byte_pointer_size('abc def{bbb}ccc') - assert_cursor(15) - assert_cursor_max(15) - assert_line('abc def{bbb}ccc') + assert_line_around_cursor('abc def{bbb}ccc', '') end def test_em_lower_case_with_complex_example input_keys('{}#* AaA!!!cCc ') input_keys("\C-a\M-l", false) - assert_byte_pointer_size('{}#* aaa') - assert_cursor(11) - assert_cursor_max(20) - assert_line('{}#* aaa!!!cCc ') + assert_line_around_cursor('{}#* aaa', '!!!cCc ') input_keys("\M-l", false) - assert_byte_pointer_size('{}#* aaa!!!ccc') - assert_cursor(17) - assert_cursor_max(20) - assert_line('{}#* aaa!!!ccc ') + assert_line_around_cursor('{}#* aaa!!!ccc', ' ') input_keys("\M-l", false) - assert_byte_pointer_size('{}#* aaa!!!ccc ') - assert_cursor(20) - assert_cursor_max(20) - assert_line('{}#* aaa!!!ccc ') + assert_line_around_cursor('{}#* aaa!!!ccc ', '') end def test_em_upper_case input_keys('AbC def{bBb}CCC') input_keys("\C-a\M-u", false) - assert_byte_pointer_size('ABC') - assert_cursor(3) - assert_cursor_max(15) - assert_line('ABC def{bBb}CCC') + assert_line_around_cursor('ABC', ' def{bBb}CCC') input_keys("\M-u", false) - assert_byte_pointer_size('ABC DEF') - assert_cursor(7) - assert_cursor_max(15) - assert_line('ABC DEF{bBb}CCC') + assert_line_around_cursor('ABC DEF', '{bBb}CCC') input_keys("\M-u", false) - assert_byte_pointer_size('ABC DEF{BBB') - assert_cursor(11) - assert_cursor_max(15) - assert_line('ABC DEF{BBB}CCC') + assert_line_around_cursor('ABC DEF{BBB', '}CCC') input_keys("\M-u", false) - assert_byte_pointer_size('ABC DEF{BBB}CCC') - assert_cursor(15) - assert_cursor_max(15) - assert_line('ABC DEF{BBB}CCC') + assert_line_around_cursor('ABC DEF{BBB}CCC', '') end def test_em_upper_case_with_complex_example input_keys('{}#* AaA!!!cCc ') input_keys("\C-a\M-u", false) - assert_byte_pointer_size('{}#* AAA') - assert_cursor(11) - assert_cursor_max(20) - assert_line('{}#* AAA!!!cCc ') + assert_line_around_cursor('{}#* AAA', '!!!cCc ') input_keys("\M-u", false) - assert_byte_pointer_size('{}#* AAA!!!CCC') - assert_cursor(17) - assert_cursor_max(20) - assert_line('{}#* AAA!!!CCC ') + assert_line_around_cursor('{}#* AAA!!!CCC', ' ') input_keys("\M-u", false) - assert_byte_pointer_size('{}#* AAA!!!CCC ') - assert_cursor(20) - assert_cursor_max(20) - assert_line('{}#* AAA!!!CCC ') + assert_line_around_cursor('{}#* AAA!!!CCC ', '') end def test_em_delete_or_list @@ -1261,28 +726,16 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase } } input_keys('fooo') - assert_byte_pointer_size('fooo') - assert_cursor(4) - assert_cursor_max(4) - assert_line('fooo') + assert_line_around_cursor('fooo', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-b", false) - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(4) - assert_line('fooo') + assert_line_around_cursor('foo', 'o') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) @line_editor.input_key(Reline::Key.new(:em_delete_or_list, :em_delete_or_list, false)) - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) @line_editor.input_key(Reline::Key.new(:em_delete_or_list, :em_delete_or_list, false)) - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') assert_equal(%w{foo_foo foo_bar foo_baz}, @line_editor.instance_variable_get(:@menu_info).list) end @@ -1297,22 +750,13 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase } } input_keys('foo_') - assert_byte_pointer_size('foo_') - assert_cursor(4) - assert_cursor_max(4) - assert_line('foo_') + assert_line_around_cursor('foo_', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size('foo_') - assert_cursor(4) - assert_cursor_max(4) - assert_line('foo_') + assert_line_around_cursor('foo_', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size('foo_') - assert_cursor(4) - assert_cursor_max(4) - assert_line('foo_') + assert_line_around_cursor('foo_', '') assert_equal(%w{foo_foo foo_bar}, @line_editor.instance_variable_get(:@menu_info).list) end @@ -1328,36 +772,63 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase } } input_keys('fo') - assert_byte_pointer_size('fo') - assert_cursor(2) - assert_cursor_max(2) - assert_line('fo') + assert_line_around_cursor('fo', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size('foo_') - assert_cursor(4) - assert_cursor_max(4) - assert_line('foo_') + assert_line_around_cursor('foo_', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size('foo_') - assert_cursor(4) - assert_cursor_max(4) - assert_line('foo_') + assert_line_around_cursor('foo_', '') assert_equal(%w{foo_foo foo_bar foo_baz}, @line_editor.instance_variable_get(:@menu_info).list) input_keys('a') input_keys("\C-i", false) - assert_byte_pointer_size('foo_a') - assert_cursor(5) - assert_cursor_max(5) - assert_line('foo_a') + assert_line_around_cursor('foo_a', '') input_keys("\C-h", false) input_keys('b') input_keys("\C-i", false) - assert_byte_pointer_size('foo_ba') - assert_cursor(6) - assert_cursor_max(6) - assert_line('foo_ba') + assert_line_around_cursor('foo_ba', '') + input_keys("\C-h") + input_key_by_symbol(:complete) + assert_line_around_cursor('foo_ba', '') + input_keys("\C-h", false) + input_key_by_symbol(:menu_complete) + assert_line_around_cursor('foo_bar', '') + input_key_by_symbol(:menu_complete) + assert_line_around_cursor('foo_baz', '') + input_keys("\C-h", false) + input_key_by_symbol(:menu_complete_backward) + assert_line_around_cursor('foo_baz', '') + input_key_by_symbol(:menu_complete_backward) + assert_line_around_cursor('foo_bar', '') + end + + def test_autocompletion + @config.autocompletion = true + @line_editor.completion_proc = proc { |word| + %w{ + Readline + Regexp + RegexpError + }.map { |i| + i.encode(@encoding) + } + } + input_keys('Re') + assert_line_around_cursor('Re', '') + input_keys("\C-i", false) + assert_line_around_cursor('Readline', '') + input_keys("\C-i", false) + assert_line_around_cursor('Regexp', '') + input_key_by_symbol(:completion_journey_up) + assert_line_around_cursor('Readline', '') + input_key_by_symbol(:complete) + assert_line_around_cursor('Regexp', '') + input_key_by_symbol(:menu_complete_backward) + assert_line_around_cursor('Readline', '') + input_key_by_symbol(:menu_complete) + assert_line_around_cursor('Regexp', '') + ensure + @config.autocompletion = false end def test_completion_with_indent @@ -1372,22 +843,13 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase } } input_keys(' fo') - assert_byte_pointer_size(' fo') - assert_cursor(4) - assert_cursor_max(4) - assert_line(' fo') + assert_line_around_cursor(' fo', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size(' foo_') - assert_cursor(6) - assert_cursor_max(6) - assert_line(' foo_') + assert_line_around_cursor(' foo_', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size(' foo_') - assert_cursor(6) - assert_cursor_max(6) - assert_line(' foo_') + assert_line_around_cursor(' foo_', '') assert_equal(%w{foo_foo foo_bar foo_baz}, @line_editor.instance_variable_get(:@menu_info).list) end @@ -1403,22 +865,13 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase } } input_keys(' "".fo') - assert_byte_pointer_size(' "".fo') - assert_cursor(7) - assert_cursor_max(7) - assert_line(' "".fo') + assert_line_around_cursor(' "".fo', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size(' "".foo_') - assert_cursor(9) - assert_cursor_max(9) - assert_line(' "".foo_') + assert_line_around_cursor(' "".foo_', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size(' "".foo_') - assert_cursor(9) - assert_cursor_max(9) - assert_line(' "".foo_') + assert_line_around_cursor(' "".foo_', '') assert_equal(%w{"".foo_foo "".foo_bar "".foo_baz}, @line_editor.instance_variable_get(:@menu_info).list) end @@ -1436,54 +889,33 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase matched = m } input_keys('fo') - assert_byte_pointer_size('fo') - assert_cursor(2) - assert_cursor_max(2) - assert_line('fo') + assert_line_around_cursor('fo', '') assert_equal(Reline::LineEditor::CompletionState::NORMAL, @line_editor.instance_variable_get(:@completion_state)) assert_equal(nil, matched) input_keys("\C-i", false) - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') assert_equal(Reline::LineEditor::CompletionState::MENU_WITH_PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state)) assert_equal(nil, matched) input_keys("\C-i", false) - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') assert_equal(Reline::LineEditor::CompletionState::PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state)) assert_equal(nil, matched) input_keys("\C-i", false) - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') assert_equal(Reline::LineEditor::CompletionState::PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state)) assert_equal('foo', matched) matched = nil input_keys('_') input_keys("\C-i", false) - assert_byte_pointer_size('foo_bar') - assert_cursor(7) - assert_cursor_max(7) - assert_line('foo_bar') + assert_line_around_cursor('foo_bar', '') assert_equal(Reline::LineEditor::CompletionState::MENU_WITH_PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state)) assert_equal(nil, matched) input_keys("\C-i", false) - assert_byte_pointer_size('foo_bar') - assert_cursor(7) - assert_cursor_max(7) - assert_line('foo_bar') + assert_line_around_cursor('foo_bar', '') assert_equal(Reline::LineEditor::CompletionState::PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state)) assert_equal(nil, matched) input_keys("\C-i", false) - assert_byte_pointer_size('foo_bar') - assert_cursor(7) - assert_cursor_max(7) - assert_line('foo_bar') + assert_line_around_cursor('foo_bar', '') assert_equal(Reline::LineEditor::CompletionState::PERFECT_MATCH, @line_editor.instance_variable_get(:@completion_state)) assert_equal('foo_bar', matched) end @@ -1500,43 +932,25 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase } } input_keys('fo') - assert_byte_pointer_size('fo') - assert_cursor(2) - assert_cursor_max(2) - assert_line('fo') + assert_line_around_cursor('fo', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size('foo_') - assert_cursor(4) - assert_cursor_max(4) - assert_line('foo_') + assert_line_around_cursor('foo_', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size('foo_') - assert_cursor(4) - assert_cursor_max(4) - assert_line('foo_') + assert_line_around_cursor('foo_', '') assert_equal(%w{foo_foo foo_bar}, @line_editor.instance_variable_get(:@menu_info).list) @config.completion_ignore_case = true input_keys("\C-i", false) - assert_byte_pointer_size('foo_') - assert_cursor(4) - assert_cursor_max(4) - assert_line('foo_') + assert_line_around_cursor('foo_', '') assert_equal(%w{foo_foo foo_bar Foo_baz}, @line_editor.instance_variable_get(:@menu_info).list) input_keys('a') input_keys("\C-i", false) - assert_byte_pointer_size('foo_a') - assert_cursor(5) - assert_cursor_max(5) - assert_line('foo_a') + assert_line_around_cursor('foo_a', '') input_keys("\C-h", false) input_keys('b') input_keys("\C-i", false) - assert_byte_pointer_size('foo_ba') - assert_cursor(6) - assert_cursor_max(6) - assert_line('foo_ba') + assert_line_around_cursor('foo_ba', '') end def test_completion_in_middle_of_line @@ -1551,17 +965,11 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase } } input_keys('abcde fo ABCDE') - assert_line('abcde fo ABCDE') + assert_line_around_cursor('abcde fo ABCDE', '') input_keys("\C-b" * 6 + "\C-i", false) - assert_byte_pointer_size('abcde foo_') - assert_cursor(10) - assert_cursor_max(16) - assert_line('abcde foo_ ABCDE') + assert_line_around_cursor('abcde foo_', ' ABCDE') input_keys("\C-b" * 2 + "\C-i", false) - assert_byte_pointer_size('abcde foo_') - assert_cursor(10) - assert_cursor_max(18) - assert_line('abcde foo_o_ ABCDE') + assert_line_around_cursor('abcde foo_', 'o_ ABCDE') end def test_completion_with_nil_value @@ -1577,125 +985,65 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase } @config.completion_ignore_case = true input_keys('fo') - assert_byte_pointer_size('fo') - assert_cursor(2) - assert_cursor_max(2) - assert_line('fo') + assert_line_around_cursor('fo', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size('foo_') - assert_cursor(4) - assert_cursor_max(4) - assert_line('foo_') + assert_line_around_cursor('foo_', '') assert_equal(nil, @line_editor.instance_variable_get(:@menu_info)) input_keys("\C-i", false) - assert_byte_pointer_size('foo_') - assert_cursor(4) - assert_cursor_max(4) - assert_line('foo_') + assert_line_around_cursor('foo_', '') assert_equal(%w{foo_foo foo_bar Foo_baz}, @line_editor.instance_variable_get(:@menu_info).list) input_keys('a') input_keys("\C-i", false) - assert_byte_pointer_size('foo_a') - assert_cursor(5) - assert_cursor_max(5) - assert_line('foo_a') + assert_line_around_cursor('foo_a', '') input_keys("\C-h", false) input_keys('b') input_keys("\C-i", false) - assert_byte_pointer_size('foo_ba') - assert_cursor(6) - assert_cursor_max(6) - assert_line('foo_ba') + assert_line_around_cursor('foo_ba', '') end def test_em_kill_region input_keys('abc def{bbb}ccc ddd ') - assert_byte_pointer_size('abc def{bbb}ccc ddd ') - assert_cursor(26) - assert_cursor_max(26) - assert_line('abc def{bbb}ccc ddd ') + assert_line_around_cursor('abc def{bbb}ccc ddd ', '') input_keys("\C-w", false) - assert_byte_pointer_size('abc def{bbb}ccc ') - assert_cursor(20) - assert_cursor_max(20) - assert_line('abc def{bbb}ccc ') + assert_line_around_cursor('abc def{bbb}ccc ', '') input_keys("\C-w", false) - assert_byte_pointer_size('abc ') - assert_cursor(6) - assert_cursor_max(6) - assert_line('abc ') + assert_line_around_cursor('abc ', '') input_keys("\C-w", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys("\C-w", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_em_kill_region_mbchar input_keys('あ い う{う}う ') - assert_byte_pointer_size('あ い う{う}う ') - assert_cursor(21) - assert_cursor_max(21) - assert_line('あ い う{う}う ') + assert_line_around_cursor('あ い う{う}う ', '') input_keys("\C-w", false) - assert_byte_pointer_size('あ い ') - assert_cursor(10) - assert_cursor_max(10) - assert_line('あ い ') + assert_line_around_cursor('あ い ', '') input_keys("\C-w", false) - assert_byte_pointer_size('あ ') - assert_cursor(5) - assert_cursor_max(5) - assert_line('あ ') + assert_line_around_cursor('あ ', '') input_keys("\C-w", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_vi_search_prev Reline::HISTORY.concat(%w{abc 123 AAA}) - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-ra\C-j") - assert_line('abc') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) + assert_line_around_cursor('', 'abc') end def test_larger_histories_than_history_size history_size = @config.history_size @config.history_size = 2 Reline::HISTORY.concat(%w{abc 123 AAA}) - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-p") - assert_line('AAA') - assert_byte_pointer_size('AAA') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('AAA', '') input_keys("\C-p") - assert_line('123') - assert_byte_pointer_size('123') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('123', '') input_keys("\C-p") - assert_line('123') - assert_byte_pointer_size('123') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('123', '') ensure @config.history_size = history_size end @@ -1706,25 +1054,13 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase '12aa', '1234' # new ]) - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-r123") - assert_line('1234') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) # doesn't determine yet + assert_line_around_cursor('1234', '') input_keys("\C-ha") - assert_line('12aa') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('12aa', '') input_keys("\C-h3") - assert_line('1235') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('1235', '') end def test_search_history_to_front @@ -1733,25 +1069,13 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase '12aa', '1234' # new ]) - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-s123") - assert_line('1235') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) # doesn't determine yet + assert_line_around_cursor('1235', '') input_keys("\C-ha") - assert_line('12aa') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('12aa', '') input_keys("\C-h3") - assert_line('1234') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('1234', '') end def test_search_history_front_and_back @@ -1760,30 +1084,15 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase '12aa', '1234' # new ]) - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-s12") - assert_line('1235') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) # doesn't determine yet + assert_line_around_cursor('1235', '') input_keys("\C-s") - assert_line('12aa') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('12aa', '') input_keys("\C-r") - assert_line('12aa') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('12aa', '') input_keys("\C-r") - assert_line('1235') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('1235', '') end def test_search_history_back_and_front @@ -1792,30 +1101,15 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase '12aa', '1234' # new ]) - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-r12") - assert_line('1234') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) # doesn't determine yet + assert_line_around_cursor('1234', '') input_keys("\C-r") - assert_line('12aa') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('12aa', '') input_keys("\C-s") - assert_line('12aa') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('12aa', '') input_keys("\C-s") - assert_line('1234') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('1234', '') end def test_search_history_to_back_in_the_middle_of_histories @@ -1824,20 +1118,11 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase '12aa', '1234' # new ]) - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-p\C-p") - assert_line('12aa') - assert_byte_pointer_size('12aa') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('12aa', '') input_keys("\C-r123") - assert_line('1235') - assert_byte_pointer_size('1235') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('1235', '') end def test_search_history_twice @@ -1846,20 +1131,11 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase '12aa', '1234' # new ]) - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-r123") - assert_line('1234') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) # doesn't determine yet + assert_line_around_cursor('1234', '') input_keys("\C-r") - assert_line('1235') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('1235', '') end def test_search_history_by_last_determined @@ -1868,35 +1144,17 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase '12aa', '1234' # new ]) - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-r123") - assert_line('1234') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) # doesn't determine yet + assert_line_around_cursor('1234', '') input_keys("\C-j") - assert_line('1234') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(4) + assert_line_around_cursor('', '1234') input_keys("\C-k") # delete - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-r") - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-r") - assert_line('1235') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('1235', '') end def test_search_history_with_isearch_terminator @@ -1908,76 +1166,40 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase '12aa', '1234' # new ]) - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys("\C-r12a") - assert_line('12aa') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) # doesn't determine yet + assert_line_around_cursor('12aa', '') input_keys('Y') - assert_line('12aa') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(4) + assert_line_around_cursor('', '12aa') input_keys('x') - assert_line('x12aa') - assert_byte_pointer_size('x') - assert_cursor(1) - assert_cursor_max(5) + assert_line_around_cursor('x', '12aa') end def test_em_set_mark_and_em_exchange_mark input_keys('aaa bbb ccc ddd') - assert_byte_pointer_size('aaa bbb ccc ddd') - assert_cursor(15) - assert_cursor_max(15) - assert_line('aaa bbb ccc ddd') + assert_line_around_cursor('aaa bbb ccc ddd', '') input_keys("\C-a\M-F\M-F", false) - assert_byte_pointer_size('aaa bbb') - assert_cursor(7) - assert_cursor_max(15) - assert_line('aaa bbb ccc ddd') + assert_line_around_cursor('aaa bbb', ' ccc ddd') assert_equal(nil, @line_editor.instance_variable_get(:@mark_pointer)) input_keys("\x00", false) # C-Space - assert_byte_pointer_size('aaa bbb') - assert_cursor(7) - assert_cursor_max(15) - assert_line('aaa bbb ccc ddd') + assert_line_around_cursor('aaa bbb', ' ccc ddd') assert_equal([7, 0], @line_editor.instance_variable_get(:@mark_pointer)) input_keys("\C-a", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(15) - assert_line('aaa bbb ccc ddd') + assert_line_around_cursor('', 'aaa bbb ccc ddd') assert_equal([7, 0], @line_editor.instance_variable_get(:@mark_pointer)) input_key_by_symbol(:em_exchange_mark) - assert_byte_pointer_size('aaa bbb') - assert_cursor(7) - assert_cursor_max(15) - assert_line('aaa bbb ccc ddd') + assert_line_around_cursor('aaa bbb', ' ccc ddd') assert_equal([0, 0], @line_editor.instance_variable_get(:@mark_pointer)) end def test_em_exchange_mark_without_mark input_keys('aaa bbb ccc ddd') - assert_byte_pointer_size('aaa bbb ccc ddd') - assert_cursor(15) - assert_cursor_max(15) - assert_line('aaa bbb ccc ddd') + assert_line_around_cursor('aaa bbb ccc ddd', '') input_keys("\C-a\M-f", false) - assert_byte_pointer_size('aaa') - assert_cursor(3) - assert_cursor_max(15) - assert_line('aaa bbb ccc ddd') + assert_line_around_cursor('aaa', ' bbb ccc ddd') assert_equal(nil, @line_editor.instance_variable_get(:@mark_pointer)) input_key_by_symbol(:em_exchange_mark) - assert_byte_pointer_size('aaa') - assert_cursor(3) - assert_cursor_max(15) - assert_line('aaa bbb ccc ddd') + assert_line_around_cursor('aaa', ' bbb ccc ddd') assert_equal(nil, @line_editor.instance_variable_get(:@mark_pointer)) end @@ -1988,7 +1210,7 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase $VERBOSE = verbose @line_editor.output_modifier_proc = proc { |output| Reline::Unicode.escape_for_print(output) } input_keys("abcdef\n") - result = @line_editor.__send__(:modify_lines, @line_editor.whole_lines) + result = @line_editor.__send__(:modify_lines, @line_editor.whole_lines, @line_editor.finished?) $/ = nil assert_equal(['abcdef'], result) ensure @@ -2006,20 +1228,11 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase input_keys('123') # The ed_search_prev_history doesn't have default binding @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('123') - assert_cursor(3) - assert_cursor_max(5) - assert_line('12345') + assert_line_around_cursor('123', '45') @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('123') - assert_cursor(3) - assert_cursor_max(5) - assert_line('12356') + assert_line_around_cursor('123', '56') @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('123') - assert_cursor(3) - assert_cursor_max(5) - assert_line('12356') + assert_line_around_cursor('123', '56') end def test_ed_search_prev_history_with_empty @@ -2029,26 +1242,22 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase '12345' # new ]) # The ed_search_prev_history doesn't have default binding - @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) - assert_line('12345') - @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) - assert_line('12aaa') - @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) - assert_line('12356') - @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) - assert_line('12356') + input_key_by_symbol(:ed_search_prev_history) + assert_line_around_cursor('12345', '') + input_key_by_symbol(:ed_search_prev_history) + assert_line_around_cursor('12aaa', '') + input_key_by_symbol(:ed_search_prev_history) + assert_line_around_cursor('12356', '') + input_key_by_symbol(:ed_search_next_history) + assert_line_around_cursor('12aaa', '') + input_key_by_symbol(:ed_prev_char) + input_key_by_symbol(:ed_next_char) + assert_line_around_cursor('12aaa', '') + input_key_by_symbol(:ed_search_prev_history) + assert_line_around_cursor('12aaa', '') + 3.times { input_key_by_symbol(:ed_prev_char) } + input_key_by_symbol(:ed_search_prev_history) + assert_line_around_cursor('12', '356') end def test_ed_search_prev_history_without_match @@ -2060,10 +1269,7 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase input_keys('ABC') # The ed_search_prev_history doesn't have default binding @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('ABC') - assert_cursor(3) - assert_cursor_max(3) - assert_line('ABC') + assert_line_around_cursor('ABC', '') end def test_ed_search_next_history @@ -2075,30 +1281,15 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase input_keys('123') # The ed_search_prev_history and ed_search_next_history doesn't have default binding @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('123') - assert_cursor(3) - assert_cursor_max(5) - assert_line('12345') + assert_line_around_cursor('123', '45') @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('123') - assert_cursor(3) - assert_cursor_max(5) - assert_line('12356') + assert_line_around_cursor('123', '56') @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('123') - assert_cursor(3) - assert_cursor_max(5) - assert_line('12356') + assert_line_around_cursor('123', '56') @line_editor.__send__(:ed_search_next_history, "\C-n".ord) - assert_byte_pointer_size('123') - assert_cursor(3) - assert_cursor_max(5) - assert_line('12345') + assert_line_around_cursor('123', '45') @line_editor.__send__(:ed_search_next_history, "\C-n".ord) - assert_byte_pointer_size('123') - assert_cursor(3) - assert_cursor_max(5) - assert_line('12345') + assert_line_around_cursor('123', '45') end def test_ed_search_next_history_with_empty @@ -2108,134 +1299,83 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase '12345' # new ]) # The ed_search_prev_history and ed_search_next_history doesn't have default binding - @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) - assert_line('12345') - @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) - assert_line('12aaa') - @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) - assert_line('12356') - @line_editor.__send__(:ed_search_next_history, "\C-n".ord) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) - assert_line('12aaa') - @line_editor.__send__(:ed_search_next_history, "\C-n".ord) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) - assert_line('12345') - @line_editor.__send__(:ed_search_next_history, "\C-n".ord) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + input_key_by_symbol(:ed_search_prev_history) + assert_line_around_cursor('12345', '') + input_key_by_symbol(:ed_search_prev_history) + assert_line_around_cursor('12aaa', '') + input_key_by_symbol(:ed_search_prev_history) + assert_line_around_cursor('12356', '') + input_key_by_symbol(:ed_search_next_history) + assert_line_around_cursor('12aaa', '') + input_key_by_symbol(:ed_search_next_history) + assert_line_around_cursor('12345', '') + input_key_by_symbol(:ed_search_prev_history) + assert_line_around_cursor('12aaa', '') + input_key_by_symbol(:ed_prev_char) + input_key_by_symbol(:ed_next_char) + input_key_by_symbol(:ed_search_next_history) + assert_line_around_cursor('12aaa', '') + 3.times { input_key_by_symbol(:ed_prev_char) } + input_key_by_symbol(:ed_search_next_history) + assert_line_around_cursor('12', '345') + 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 def test_ed_insert_for_include_zwj_emoji - omit "This test is for UTF-8 but the locale is #{Reline::IOGate.encoding}" if Reline::IOGate.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 # U+1F468 U+200D U+1F469 U+200D U+1F467 U+200D U+1F466 is family: man, woman, girl, boy "👨👩👧👦" input_keys("\u{1F468}") # U+1F468 is man "👨" - assert_line("\u{1F468}") - assert_byte_pointer_size("\u{1F468}") - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('👨', '') input_keys("\u200D") # U+200D is ZERO WIDTH JOINER - assert_line("\u{1F468 200D}") - assert_byte_pointer_size("\u{1F468 200D}") - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('👨', '') input_keys("\u{1F469}") # U+1F469 is woman "👩" - assert_line("\u{1F468 200D 1F469}") - assert_byte_pointer_size("\u{1F468 200D 1F469}") - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('👨👩', '') input_keys("\u200D") # U+200D is ZERO WIDTH JOINER - assert_line("\u{1F468 200D 1F469 200D}") - assert_byte_pointer_size("\u{1F468 200D 1F469 200D}") - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('👨👩', '') input_keys("\u{1F467}") # U+1F467 is girl "👧" - assert_line("\u{1F468 200D 1F469 200D 1F467}") - assert_byte_pointer_size("\u{1F468 200D 1F469 200D 1F467}") - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('👨👩👧', '') input_keys("\u200D") # U+200D is ZERO WIDTH JOINER - assert_line("\u{1F468 200D 1F469 200D 1F467 200D}") - assert_byte_pointer_size("\u{1F468 200D 1F469 200D 1F467 200D}") - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('👨👩👧', '') input_keys("\u{1F466}") # U+1F466 is boy "👦" - assert_line("\u{1F468 200D 1F469 200D 1F467 200D 1F466}") - assert_byte_pointer_size("\u{1F468 200D 1F469 200D 1F467 200D 1F466}") - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('👨👩👧👦', '') # U+1F468 U+200D U+1F469 U+200D U+1F467 U+200D U+1F466 is family: man, woman, girl, boy "👨👩👧👦" input_keys("\u{1F468 200D 1F469 200D 1F467 200D 1F466}") - assert_line("\u{1F468 200D 1F469 200D 1F467 200D 1F466 1F468 200D 1F469 200D 1F467 200D 1F466}") - assert_byte_pointer_size("\u{1F468 200D 1F469 200D 1F467 200D 1F466 1F468 200D 1F469 200D 1F467 200D 1F466}") - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('👨👩👧👦👨👩👧👦', '') end def test_ed_insert_for_include_valiation_selector - omit "This test is for UTF-8 but the locale is #{Reline::IOGate.encoding}" if Reline::IOGate.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 # U+0030 U+FE00 is DIGIT ZERO + VARIATION SELECTOR-1 "0︀" input_keys("\u0030") # U+0030 is DIGIT ZERO - assert_line("\u0030") - assert_byte_pointer_size("\u0030") - assert_cursor(1) - assert_cursor_max(1) + assert_line_around_cursor('0', '') input_keys("\uFE00") # U+FE00 is VARIATION SELECTOR-1 - assert_line("\u{0030 FE00}") - assert_byte_pointer_size("\u{0030 FE00}") - assert_cursor(1) - assert_cursor_max(1) + assert_line_around_cursor('0︀', '') end def test_em_yank_pop input_keys("def hoge\C-w\C-b\C-f\C-w", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys("\C-y", false) - assert_byte_pointer_size('def ') - assert_cursor(4) - assert_cursor_max(4) - assert_line('def ') + assert_line_around_cursor('def ', '') input_keys("\M-\C-y", false) - assert_byte_pointer_size('hoge') - assert_cursor(4) - assert_cursor_max(4) - assert_line('hoge') + assert_line_around_cursor('hoge', '') end def test_em_kill_region_with_kill_ring input_keys("def hoge\C-b\C-b\C-b\C-b", false) - assert_byte_pointer_size('def ') - assert_cursor(4) - assert_cursor_max(8) - assert_line('def hoge') + assert_line_around_cursor('def ', 'hoge') input_keys("\C-k\C-w", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys("\C-y", false) - assert_byte_pointer_size('def hoge') - assert_cursor(8) - assert_cursor_max(8) - assert_line('def hoge') + assert_line_around_cursor('def hoge', '') end def test_ed_search_prev_next_history_in_multibyte @@ -2251,104 +1391,237 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase assert_whole_lines(['def foo', ' 12345', 'end']) assert_line_index(1) assert_whole_lines(['def foo', ' 12345', 'end']) - assert_byte_pointer_size(' 123') - assert_cursor(5) - assert_cursor_max(7) - assert_line(' 12345') + assert_line_around_cursor(' 123', '45') @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) assert_line_index(2) assert_whole_lines(['def hoge', ' 67890', ' 12345', 'end']) - assert_byte_pointer_size(' 123') - assert_cursor(5) - assert_cursor_max(7) - assert_line(' 12345') + assert_line_around_cursor(' 123', '45') @line_editor.__send__(:ed_search_prev_history, "\C-p".ord) assert_line_index(2) assert_whole_lines(['def hoge', ' 67890', ' 12345', 'end']) - assert_byte_pointer_size(' 123') - assert_cursor(5) - assert_cursor_max(7) - assert_line(' 12345') + assert_line_around_cursor(' 123', '45') @line_editor.__send__(:ed_search_next_history, "\C-n".ord) assert_line_index(1) assert_whole_lines(['def foo', ' 12345', 'end']) - assert_byte_pointer_size(' 123') - assert_cursor(5) - assert_cursor_max(7) - assert_line(' 12345') + assert_line_around_cursor(' 123', '45') @line_editor.__send__(:ed_search_next_history, "\C-n".ord) assert_line_index(1) assert_whole_lines(['def foo', ' 12345', 'end']) - assert_byte_pointer_size(' 123') - assert_cursor(5) - assert_cursor_max(7) - assert_line(' 12345') + assert_line_around_cursor(' 123', '45') end def test_ignore_NUL_by_ed_quoted_insert input_keys(%Q{"\C-v\C-@"}, false) - assert_byte_pointer_size('""') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('""', '') end def test_ed_argument_digit_by_meta_num input_keys('abcdef') - assert_byte_pointer_size('abcdef') - assert_cursor(6) - assert_cursor_max(6) - assert_line('abcdef') + assert_line_around_cursor('abcdef', '') input_keys("\M-2", false) input_keys("\C-h", false) - assert_byte_pointer_size('abcd') - assert_cursor(4) - assert_cursor_max(4) - assert_line('abcd') + assert_line_around_cursor('abcd', '') end def test_halfwidth_kana_width_dakuten input_raw_keys('ガギゲゴ') - assert_byte_pointer_size('ガギゲゴ') - assert_cursor(8) - assert_cursor_max(8) + assert_line_around_cursor('ガギゲゴ', '') input_keys("\C-b\C-b", false) - assert_byte_pointer_size('ガギ') - assert_cursor(4) - assert_cursor_max(8) + assert_line_around_cursor('ガギ', 'ゲゴ') input_raw_keys('グ', false) - assert_byte_pointer_size('ガギグ') - assert_cursor(6) - assert_cursor_max(10) - assert_line('ガギグゲゴ') + assert_line_around_cursor('ガギグ', 'ゲゴ') end def test_input_unknown_char input_keys('') # U+0378 (unassigned) - assert_line('') - assert_byte_pointer_size('') - assert_cursor(1) - assert_cursor_max(1) + assert_line_around_cursor('', '') end def test_unix_line_discard input_keys("\C-u", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys('abc') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('abc', '') input_keys("\C-b\C-u", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(1) - assert_line('c') + assert_line_around_cursor('', 'c') input_keys("\C-f\C-u", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') + end + + def test_vi_editing_mode + @line_editor.__send__(:vi_editing_mode, nil) + assert(@config.editing_mode_is?(:vi_insert)) + end + + def test_undo + input_keys("\C-_", false) + assert_line_around_cursor('', '') + input_keys("aあb\C-h\C-h\C-h", false) + assert_line_around_cursor('', '') + input_keys("\C-_", false) + assert_line_around_cursor('a', '') + input_keys("\C-_", false) + assert_line_around_cursor('aあ', '') + input_keys("\C-_", false) + assert_line_around_cursor('aあb', '') + input_keys("\C-_", false) + assert_line_around_cursor('aあ', '') + input_keys("\C-_", false) + assert_line_around_cursor('a', '') + input_keys("\C-_", false) + assert_line_around_cursor('', '') + end + + def test_undo_with_cursor_position + input_keys("abc\C-b\C-h", false) + assert_line_around_cursor('a', 'c') + input_keys("\C-_", false) + assert_line_around_cursor('ab', 'c') + input_keys("あいう\C-b\C-h", false) + assert_line_around_cursor('abあ', 'うc') + input_keys("\C-_", false) + assert_line_around_cursor('abあい', 'うc') + end + + def test_undo_with_multiline + @line_editor.multiline_on + @line_editor.confirm_multiline_termination_proc = proc {} + input_keys("1\n2\n3", false) + assert_whole_lines(["1", "2", "3"]) + assert_line_index(2) + assert_line_around_cursor('3', '') + input_keys("\C-p\C-h\C-h", false) + assert_whole_lines(["1", "3"]) + assert_line_index(0) + assert_line_around_cursor('1', '') + input_keys("\C-_", false) + assert_whole_lines(["1", "", "3"]) + assert_line_index(1) + assert_line_around_cursor('', '') + input_keys("\C-_", false) + assert_whole_lines(["1", "2", "3"]) + assert_line_index(1) + assert_line_around_cursor('2', '') + input_keys("\C-_", false) + assert_whole_lines(["1", "2", ""]) + assert_line_index(2) + assert_line_around_cursor('', '') + input_keys("\C-_", false) + assert_whole_lines(["1", "2"]) + assert_line_index(1) + assert_line_around_cursor('2', '') + end + + def test_undo_with_many_times + str = "a" + "b" * 99 + input_keys(str, false) + 100.times { input_keys("\C-_", false) } + assert_line_around_cursor('a', '') + input_keys("\C-_", false) + assert_line_around_cursor('a', '') + end + + def test_redo + input_keys("aあb", false) + assert_line_around_cursor('aあb', '') + input_keys("\M-\C-_", false) + assert_line_around_cursor('aあb', '') + input_keys("\C-_", false) + assert_line_around_cursor('aあ', '') + input_keys("\C-_", false) + assert_line_around_cursor('a', '') + input_keys("\M-\C-_", false) + assert_line_around_cursor('aあ', '') + input_keys("\M-\C-_", false) + assert_line_around_cursor('aあb', '') + input_keys("\C-_", false) + assert_line_around_cursor('aあ', '') + input_keys("c", false) + assert_line_around_cursor('aあc', '') + input_keys("\M-\C-_", false) + assert_line_around_cursor('aあc', '') + end + + def test_redo_with_cursor_position + input_keys("abc\C-b\C-h", false) + assert_line_around_cursor('a', 'c') + input_keys("\M-\C-_", false) + assert_line_around_cursor('a', 'c') + input_keys("\C-_", false) + assert_line_around_cursor('ab', 'c') + input_keys("\M-\C-_", false) + assert_line_around_cursor('a', 'c') + end + + def test_redo_with_multiline + @line_editor.multiline_on + @line_editor.confirm_multiline_termination_proc = proc {} + input_keys("1\n2\n3", false) + assert_whole_lines(["1", "2", "3"]) + assert_line_index(2) + assert_line_around_cursor('3', '') + + input_keys("\C-_", false) + assert_whole_lines(["1", "2", ""]) + assert_line_index(2) + assert_line_around_cursor('', '') + + input_keys("\C-_", false) + assert_whole_lines(["1", "2"]) + assert_line_index(1) + assert_line_around_cursor('2', '') + + input_keys("\M-\C-_", false) + assert_whole_lines(["1", "2", ""]) + assert_line_index(2) + assert_line_around_cursor('', '') + + input_keys("\M-\C-_", false) + assert_whole_lines(["1", "2", "3"]) + assert_line_index(2) + assert_line_around_cursor('3', '') + + input_keys("\C-p\C-h\C-h", false) + assert_whole_lines(["1", "3"]) + assert_line_index(0) + assert_line_around_cursor('1', '') + + input_keys("\C-n", false) + assert_whole_lines(["1", "3"]) + assert_line_index(1) + assert_line_around_cursor('3', '') + + input_keys("\C-_", false) + assert_whole_lines(["1", "", "3"]) + assert_line_index(1) + assert_line_around_cursor('', '') + + input_keys("\C-_", false) + assert_whole_lines(["1", "2", "3"]) + assert_line_index(1) + assert_line_around_cursor('2', '') + + input_keys("\M-\C-_", false) + assert_whole_lines(["1", "", "3"]) + assert_line_index(1) + assert_line_around_cursor('', '') + + input_keys("\M-\C-_", false) + assert_whole_lines(["1", "3"]) + assert_line_index(1) + assert_line_around_cursor('3', '') + end + + def test_redo_with_many_times + str = "a" + "b" * 98 + "c" + input_keys(str, false) + 100.times { input_keys("\C-_", false) } + assert_line_around_cursor('a', '') + input_keys("\C-_", false) + assert_line_around_cursor('a', '') + 100.times { input_keys("\M-\C-_", false) } + assert_line_around_cursor(str, '') + input_keys("\M-\C-_", false) + assert_line_around_cursor(str, '') end end diff --git a/test/reline/test_key_actor_vi.rb b/test/reline/test_key_actor_vi.rb index b3d49c9bbb..07ca873ce3 100644 --- a/test/reline/test_key_actor_vi.rb +++ b/test/reline/test_key_actor_vi.rb @@ -1,6 +1,6 @@ require_relative 'helper' -class Reline::KeyActor::ViInsert::Test < Reline::TestCase +class Reline::ViInsertTest < Reline::TestCase def setup Reline.send(:test_mode) @prompt = '> ' @@ -8,967 +8,534 @@ class Reline::KeyActor::ViInsert::Test < Reline::TestCase @config.read_lines(<<~LINES.split(/(?<=\n)/)) set editing-mode vi LINES - @encoding = Reline::IOGate.encoding + @encoding = Reline.core.encoding @line_editor = Reline::LineEditor.new(@config, @encoding) @line_editor.reset(@prompt, encoding: @encoding) end + def editing_mode_label + @config.instance_variable_get(:@editing_mode_label) + end + def teardown Reline.test_reset end def test_vi_command_mode input_keys("\C-[") - assert_instance_of(Reline::KeyActor::ViCommand, @config.editing_mode) + assert_equal(:vi_command, editing_mode_label) end def test_vi_command_mode_with_input input_keys("abc\C-[") - assert_instance_of(Reline::KeyActor::ViCommand, @config.editing_mode) - assert_line('abc') + assert_equal(:vi_command, editing_mode_label) + assert_line_around_cursor('ab', 'c') end def test_vi_insert - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_equal(:vi_insert, editing_mode_label) input_keys('i') - assert_line('i') - assert_cursor(1) - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_line_around_cursor('i', '') + assert_equal(:vi_insert, editing_mode_label) input_keys("\C-[") - assert_line('i') - assert_cursor(0) - assert_instance_of(Reline::KeyActor::ViCommand, @config.editing_mode) + assert_line_around_cursor('', 'i') + assert_equal(:vi_command, editing_mode_label) input_keys('i') - assert_line('i') - assert_cursor(0) - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_line_around_cursor('', 'i') + assert_equal(:vi_insert, editing_mode_label) end def test_vi_add - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_equal(:vi_insert, editing_mode_label) input_keys('a') - assert_line('a') - assert_cursor(1) - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_line_around_cursor('a', '') + assert_equal(:vi_insert, editing_mode_label) input_keys("\C-[") - assert_line('a') - assert_cursor(0) - assert_instance_of(Reline::KeyActor::ViCommand, @config.editing_mode) + assert_line_around_cursor('', 'a') + assert_equal(:vi_command, editing_mode_label) input_keys('a') - assert_line('a') - assert_cursor(1) - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_line_around_cursor('a', '') + assert_equal(:vi_insert, editing_mode_label) end def test_vi_insert_at_bol input_keys('I') - assert_line('I') - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_line_around_cursor('I', '') + assert_equal(:vi_insert, editing_mode_label) input_keys("12345\C-[hh") - assert_line('I12345') - assert_byte_pointer_size('I12') - assert_cursor(3) - assert_cursor_max(6) - assert_instance_of(Reline::KeyActor::ViCommand, @config.editing_mode) + assert_line_around_cursor('I12', '345') + assert_equal(:vi_command, editing_mode_label) input_keys('I') - assert_line('I12345') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_line_around_cursor('', 'I12345') + assert_equal(:vi_insert, editing_mode_label) end def test_vi_add_at_eol input_keys('A') - assert_line('A') - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_line_around_cursor('A', '') + assert_equal(:vi_insert, editing_mode_label) input_keys("12345\C-[hh") - assert_line('A12345') - assert_byte_pointer_size('A12') - assert_cursor(3) - assert_cursor_max(6) - assert_instance_of(Reline::KeyActor::ViCommand, @config.editing_mode) + assert_line_around_cursor('A12', '345') + assert_equal(:vi_command, editing_mode_label) input_keys('A') - assert_line('A12345') - assert_byte_pointer_size('A12345') - assert_cursor(6) - assert_cursor_max(6) - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_line_around_cursor('A12345', '') + assert_equal(:vi_insert, editing_mode_label) end def test_ed_insert_one input_keys('a') - assert_line('a') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(1) + assert_line_around_cursor('a', '') end def test_ed_insert_two input_keys('ab') - assert_line('ab') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('ab', '') end def test_ed_insert_mbchar_one input_keys('か') - assert_line('か') - assert_byte_pointer_size('か') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('か', '') end def test_ed_insert_mbchar_two input_keys('かき') - assert_line('かき') - assert_byte_pointer_size('かき') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('かき', '') end def test_ed_insert_for_mbchar_by_plural_code_points input_keys("か\u3099") - assert_line("か\u3099") - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor("か\u3099", '') end def test_ed_insert_for_plural_mbchar_by_plural_code_points input_keys("か\u3099き\u3099") - assert_line("か\u3099き\u3099") - assert_byte_pointer_size("か\u3099き\u3099") - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor("か\u3099き\u3099", '') end def test_ed_next_char input_keys("abcdef\C-[0") - assert_line('abcdef') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', 'abcdef') input_keys('l') - assert_line('abcdef') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(6) + assert_line_around_cursor('a', 'bcdef') input_keys('2l') - assert_line('abcdef') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(6) + assert_line_around_cursor('abc', 'def') end def test_ed_prev_char input_keys("abcdef\C-[") - assert_line('abcdef') - assert_byte_pointer_size('abcde') - assert_cursor(5) - assert_cursor_max(6) + assert_line_around_cursor('abcde', 'f') input_keys('h') - assert_line('abcdef') - assert_byte_pointer_size('abcd') - assert_cursor(4) - assert_cursor_max(6) + assert_line_around_cursor('abcd', 'ef') input_keys('2h') - assert_line('abcdef') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(6) + assert_line_around_cursor('ab', 'cdef') end def test_history Reline::HISTORY.concat(%w{abc 123 AAA}) input_keys("\C-[") - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys('k') - assert_line('AAA') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) + assert_line_around_cursor('', 'AAA') input_keys('2k') - assert_line('abc') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) + assert_line_around_cursor('', 'abc') input_keys('j') - assert_line('123') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) + assert_line_around_cursor('', '123') input_keys('2j') - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') end def test_vi_paste_prev input_keys("abcde\C-[3h") - assert_line('abcde') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(5) + assert_line_around_cursor('a', 'bcde') input_keys('P') - assert_line('abcde') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(5) + assert_line_around_cursor('a', 'bcde') input_keys('d$') - assert_line('a') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(1) + assert_line_around_cursor('', 'a') input_keys('P') - assert_line('bcdea') - assert_byte_pointer_size('bcd') - assert_cursor(3) - assert_cursor_max(5) + assert_line_around_cursor('bcd', 'ea') input_keys('2P') - assert_line('bcdbcdbcdeeea') - assert_byte_pointer_size('bcdbcdbcd') - assert_cursor(9) - assert_cursor_max(13) + assert_line_around_cursor('bcdbcdbcd', 'eeea') end def test_vi_paste_next input_keys("abcde\C-[3h") - assert_line('abcde') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(5) + assert_line_around_cursor('a', 'bcde') input_keys('p') - assert_line('abcde') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(5) + assert_line_around_cursor('a', 'bcde') input_keys('d$') - assert_line('a') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(1) + assert_line_around_cursor('', 'a') input_keys('p') - assert_line('abcde') - assert_byte_pointer_size('abcd') - assert_cursor(4) - assert_cursor_max(5) + assert_line_around_cursor('abcd', 'e') input_keys('2p') - assert_line('abcdebcdebcde') - assert_byte_pointer_size('abcdebcdebcd') - assert_cursor(12) - assert_cursor_max(13) + assert_line_around_cursor('abcdebcdebcd', 'e') end def test_vi_paste_prev_for_mbchar input_keys("あいうえお\C-[3h") - assert_line('あいうえお') - assert_byte_pointer_size('あ') - assert_cursor(2) - assert_cursor_max(10) + assert_line_around_cursor('あ', 'いうえお') input_keys('P') - assert_line('あいうえお') - assert_byte_pointer_size('あ') - assert_cursor(2) - assert_cursor_max(10) + assert_line_around_cursor('あ', 'いうえお') input_keys('d$') - assert_line('あ') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(2) + assert_line_around_cursor('', 'あ') input_keys('P') - assert_line('いうえおあ') - assert_byte_pointer_size('いうえ') - assert_cursor(6) - assert_cursor_max(10) + assert_line_around_cursor('いうえ', 'おあ') input_keys('2P') - assert_line('いうえいうえいうえおおおあ') - assert_byte_pointer_size('いうえいうえいうえ') - assert_cursor(18) - assert_cursor_max(26) + assert_line_around_cursor('いうえいうえいうえ', 'おおおあ') end def test_vi_paste_next_for_mbchar input_keys("あいうえお\C-[3h") - assert_line('あいうえお') - assert_byte_pointer_size('あ') - assert_cursor(2) - assert_cursor_max(10) + assert_line_around_cursor('あ', 'いうえお') input_keys('p') - assert_line('あいうえお') - assert_byte_pointer_size('あ') - assert_cursor(2) - assert_cursor_max(10) + assert_line_around_cursor('あ', 'いうえお') input_keys('d$') - assert_line('あ') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(2) + assert_line_around_cursor('', 'あ') input_keys('p') - assert_line('あいうえお') - assert_byte_pointer_size('あいうえ') - assert_cursor(8) - assert_cursor_max(10) + assert_line_around_cursor('あいうえ', 'お') input_keys('2p') - assert_line('あいうえおいうえおいうえお') - assert_byte_pointer_size('あいうえおいうえおいうえ') - assert_cursor(24) - assert_cursor_max(26) + assert_line_around_cursor('あいうえおいうえおいうえ', 'お') end def test_vi_paste_prev_for_mbchar_by_plural_code_points input_keys("か\u3099き\u3099く\u3099け\u3099こ\u3099\C-[3h") - assert_line("か\u3099き\u3099く\u3099け\u3099こ\u3099") - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(10) + assert_line_around_cursor("か\u3099", "き\u3099く\u3099け\u3099こ\u3099") input_keys('P') - assert_line("か\u3099き\u3099く\u3099け\u3099こ\u3099") - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(10) + assert_line_around_cursor("か\u3099", "き\u3099く\u3099け\u3099こ\u3099") input_keys('d$') - assert_line("か\u3099") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(2) + assert_line_around_cursor('', "か\u3099") input_keys('P') - assert_line("き\u3099く\u3099け\u3099こ\u3099か\u3099") - assert_byte_pointer_size("き\u3099く\u3099け\u3099") - assert_cursor(6) - assert_cursor_max(10) + assert_line_around_cursor("き\u3099く\u3099け\u3099", "こ\u3099か\u3099") input_keys('2P') - assert_line("き\u3099く\u3099け\u3099き\u3099く\u3099け\u3099き\u3099く\u3099け\u3099こ\u3099こ\u3099こ\u3099か\u3099") - assert_byte_pointer_size("き\u3099く\u3099け\u3099き\u3099く\u3099け\u3099き\u3099く\u3099け\u3099") - assert_cursor(18) - assert_cursor_max(26) + assert_line_around_cursor("き\u3099く\u3099け\u3099き\u3099く\u3099け\u3099き\u3099く\u3099け\u3099", "こ\u3099こ\u3099こ\u3099か\u3099") end def test_vi_paste_next_for_mbchar_by_plural_code_points input_keys("か\u3099き\u3099く\u3099け\u3099こ\u3099\C-[3h") - assert_line("か\u3099き\u3099く\u3099け\u3099こ\u3099") - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(10) + assert_line_around_cursor("か\u3099", "き\u3099く\u3099け\u3099こ\u3099") input_keys('p') - assert_line("か\u3099き\u3099く\u3099け\u3099こ\u3099") - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(10) + assert_line_around_cursor("か\u3099", "き\u3099く\u3099け\u3099こ\u3099") input_keys('d$') - assert_line("か\u3099") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(2) + assert_line_around_cursor('', "か\u3099") input_keys('p') - assert_line("か\u3099き\u3099く\u3099け\u3099こ\u3099") - assert_byte_pointer_size("か\u3099き\u3099く\u3099け\u3099") - assert_cursor(8) - assert_cursor_max(10) + assert_line_around_cursor("か\u3099き\u3099く\u3099け\u3099", "こ\u3099") input_keys('2p') - assert_line("か\u3099き\u3099く\u3099け\u3099こ\u3099き\u3099く\u3099け\u3099こ\u3099き\u3099く\u3099け\u3099こ\u3099") - assert_byte_pointer_size("か\u3099き\u3099く\u3099け\u3099こ\u3099き\u3099く\u3099け\u3099こ\u3099き\u3099く\u3099け\u3099") - assert_cursor(24) - assert_cursor_max(26) + assert_line_around_cursor("か\u3099き\u3099く\u3099け\u3099こ\u3099き\u3099く\u3099け\u3099こ\u3099き\u3099く\u3099け\u3099", "こ\u3099") end def test_vi_prev_next_word input_keys("aaa b{b}b ccc\C-[0") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(13) + assert_line_around_cursor('', 'aaa b{b}b ccc') input_keys('w') - assert_byte_pointer_size('aaa ') - assert_cursor(4) - assert_cursor_max(13) + assert_line_around_cursor('aaa ', 'b{b}b ccc') input_keys('w') - assert_byte_pointer_size('aaa b') - assert_cursor(5) - assert_cursor_max(13) + assert_line_around_cursor('aaa b', '{b}b ccc') input_keys('w') - assert_byte_pointer_size('aaa b{') - assert_cursor(6) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{', 'b}b ccc') input_keys('w') - assert_byte_pointer_size('aaa b{b') - assert_cursor(7) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b', '}b ccc') input_keys('w') - assert_byte_pointer_size('aaa b{b}') - assert_cursor(8) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}', 'b ccc') input_keys('w') - assert_byte_pointer_size('aaa b{b}b ') - assert_cursor(10) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}b ', 'ccc') input_keys('w') - assert_byte_pointer_size('aaa b{b}b cc') - assert_cursor(12) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}b cc', 'c') input_keys('b') - assert_byte_pointer_size('aaa b{b}b ') - assert_cursor(10) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}b ', 'ccc') input_keys('b') - assert_byte_pointer_size('aaa b{b}') - assert_cursor(8) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}', 'b ccc') input_keys('b') - assert_byte_pointer_size('aaa b{b') - assert_cursor(7) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b', '}b ccc') input_keys('b') - assert_byte_pointer_size('aaa b{') - assert_cursor(6) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{', 'b}b ccc') input_keys('b') - assert_byte_pointer_size('aaa b') - assert_cursor(5) - assert_cursor_max(13) + assert_line_around_cursor('aaa b', '{b}b ccc') input_keys('b') - assert_byte_pointer_size('aaa ') - assert_cursor(4) - assert_cursor_max(13) + assert_line_around_cursor('aaa ', 'b{b}b ccc') input_keys('b') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(13) + assert_line_around_cursor('', 'aaa b{b}b ccc') input_keys('3w') - assert_byte_pointer_size('aaa b{') - assert_cursor(6) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{', 'b}b ccc') input_keys('3w') - assert_byte_pointer_size('aaa b{b}b ') - assert_cursor(10) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}b ', 'ccc') input_keys('3w') - assert_byte_pointer_size('aaa b{b}b cc') - assert_cursor(12) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}b cc', 'c') input_keys('3b') - assert_byte_pointer_size('aaa b{b') - assert_cursor(7) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b', '}b ccc') input_keys('3b') - assert_byte_pointer_size('aaa ') - assert_cursor(4) - assert_cursor_max(13) + assert_line_around_cursor('aaa ', 'b{b}b ccc') input_keys('3b') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(13) + assert_line_around_cursor('', 'aaa b{b}b ccc') end def test_vi_end_word input_keys("aaa b{b}}}b ccc\C-[0") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(19) + assert_line_around_cursor('', 'aaa b{b}}}b ccc') input_keys('e') - assert_byte_pointer_size('aa') - assert_cursor(2) - assert_cursor_max(19) + assert_line_around_cursor('aa', 'a b{b}}}b ccc') input_keys('e') - assert_byte_pointer_size('aaa ') - assert_cursor(6) - assert_cursor_max(19) + assert_line_around_cursor('aaa ', 'b{b}}}b ccc') input_keys('e') - assert_byte_pointer_size('aaa b') - assert_cursor(7) - assert_cursor_max(19) + assert_line_around_cursor('aaa b', '{b}}}b ccc') input_keys('e') - assert_byte_pointer_size('aaa b{') - assert_cursor(8) - assert_cursor_max(19) + assert_line_around_cursor('aaa b{', 'b}}}b ccc') input_keys('e') - assert_byte_pointer_size('aaa b{b}}') - assert_cursor(11) - assert_cursor_max(19) + assert_line_around_cursor('aaa b{b}}', '}b ccc') input_keys('e') - assert_byte_pointer_size('aaa b{b}}}') - assert_cursor(12) - assert_cursor_max(19) + assert_line_around_cursor('aaa b{b}}}', 'b ccc') input_keys('e') - assert_byte_pointer_size('aaa b{b}}}b cc') - assert_cursor(18) - assert_cursor_max(19) + assert_line_around_cursor('aaa b{b}}}b cc', 'c') input_keys('e') - assert_byte_pointer_size('aaa b{b}}}b cc') - assert_cursor(18) - assert_cursor_max(19) + assert_line_around_cursor('aaa b{b}}}b cc', 'c') input_keys('03e') - assert_byte_pointer_size('aaa b') - assert_cursor(7) - assert_cursor_max(19) + assert_line_around_cursor('aaa b', '{b}}}b ccc') input_keys('3e') - assert_byte_pointer_size('aaa b{b}}}') - assert_cursor(12) - assert_cursor_max(19) + assert_line_around_cursor('aaa b{b}}}', 'b ccc') input_keys('3e') - assert_byte_pointer_size('aaa b{b}}}b cc') - assert_cursor(18) - assert_cursor_max(19) + assert_line_around_cursor('aaa b{b}}}b cc', 'c') end def test_vi_prev_next_big_word input_keys("aaa b{b}b ccc\C-[0") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(13) + assert_line_around_cursor('', 'aaa b{b}b ccc') input_keys('W') - assert_byte_pointer_size('aaa ') - assert_cursor(4) - assert_cursor_max(13) + assert_line_around_cursor('aaa ', 'b{b}b ccc') input_keys('W') - assert_byte_pointer_size('aaa b{b}b ') - assert_cursor(10) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}b ', 'ccc') input_keys('W') - assert_byte_pointer_size('aaa b{b}b cc') - assert_cursor(12) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}b cc', 'c') input_keys('B') - assert_byte_pointer_size('aaa b{b}b ') - assert_cursor(10) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}b ', 'ccc') input_keys('B') - assert_byte_pointer_size('aaa ') - assert_cursor(4) - assert_cursor_max(13) + assert_line_around_cursor('aaa ', 'b{b}b ccc') input_keys('B') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(13) + assert_line_around_cursor('', 'aaa b{b}b ccc') input_keys('2W') - assert_byte_pointer_size('aaa b{b}b ') - assert_cursor(10) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}b ', 'ccc') input_keys('2W') - assert_byte_pointer_size('aaa b{b}b cc') - assert_cursor(12) - assert_cursor_max(13) + assert_line_around_cursor('aaa b{b}b cc', 'c') input_keys('2B') - assert_byte_pointer_size('aaa ') - assert_cursor(4) - assert_cursor_max(13) + assert_line_around_cursor('aaa ', 'b{b}b ccc') input_keys('2B') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(13) + assert_line_around_cursor('', 'aaa b{b}b ccc') end def test_vi_end_big_word input_keys("aaa b{b}}}b ccc\C-[0") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(19) + assert_line_around_cursor('', 'aaa b{b}}}b ccc') input_keys('E') - assert_byte_pointer_size('aa') - assert_cursor(2) - assert_cursor_max(19) + assert_line_around_cursor('aa', 'a b{b}}}b ccc') input_keys('E') - assert_byte_pointer_size('aaa b{b}}}') - assert_cursor(12) - assert_cursor_max(19) + assert_line_around_cursor('aaa b{b}}}', 'b ccc') input_keys('E') - assert_byte_pointer_size('aaa b{b}}}b cc') - assert_cursor(18) - assert_cursor_max(19) + assert_line_around_cursor('aaa b{b}}}b cc', 'c') input_keys('E') - assert_byte_pointer_size('aaa b{b}}}b cc') - assert_cursor(18) - assert_cursor_max(19) + assert_line_around_cursor('aaa b{b}}}b cc', 'c') end def test_ed_quoted_insert input_keys("ab\C-v\C-acd") - assert_line("ab\C-acd") - assert_byte_pointer_size("ab\C-acd") - assert_cursor(6) - assert_cursor_max(6) + assert_line_around_cursor("ab\C-acd", '') end def test_ed_quoted_insert_with_vi_arg input_keys("ab\C-[3\C-v\C-aacd") - assert_line("a\C-a\C-a\C-abcd") - assert_byte_pointer_size("a\C-a\C-a\C-abcd") - assert_cursor(10) - assert_cursor_max(10) + assert_line_around_cursor("a\C-a\C-a\C-abcd", '') end def test_vi_replace_char input_keys("abcdef\C-[03l") - assert_line('abcdef') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(6) + assert_line_around_cursor('abc', 'def') input_keys('rz') - assert_line('abczef') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(6) + assert_line_around_cursor('abc', 'zef') input_keys('2rx') - assert_line('abcxxf') - assert_byte_pointer_size('abcxx') - assert_cursor(5) - assert_cursor_max(6) + assert_line_around_cursor('abcxx', 'f') end def test_vi_replace_char_with_mbchar input_keys("あいうえお\C-[0l") - assert_line('あいうえお') - assert_byte_pointer_size('あ') - assert_cursor(2) - assert_cursor_max(10) + assert_line_around_cursor('あ', 'いうえお') input_keys('rx') - assert_line('あxうえお') - assert_byte_pointer_size('あ') - assert_cursor(2) - assert_cursor_max(9) + assert_line_around_cursor('あ', 'xうえお') input_keys('l2ry') - assert_line('あxyyお') - assert_byte_pointer_size('あxyy') - assert_cursor(5) - assert_cursor_max(7) + assert_line_around_cursor('あxyy', 'お') end def test_vi_next_char input_keys("abcdef\C-[0") - assert_line('abcdef') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', 'abcdef') input_keys('fz') - assert_line('abcdef') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', 'abcdef') input_keys('fe') - assert_line('abcdef') - assert_byte_pointer_size('abcd') - assert_cursor(4) - assert_cursor_max(6) + assert_line_around_cursor('abcd', 'ef') end def test_vi_to_next_char input_keys("abcdef\C-[0") - assert_line('abcdef') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', 'abcdef') input_keys('tz') - assert_line('abcdef') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', 'abcdef') input_keys('te') - assert_line('abcdef') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(6) + assert_line_around_cursor('abc', 'def') 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) + assert_line_around_cursor('abcde', 'f') input_keys('Fz') - assert_line('abcdef') - assert_byte_pointer_size('abcde') - assert_cursor(5) - assert_cursor_max(6) + assert_line_around_cursor('abcde', 'f') input_keys('Fa') - assert_line('abcdef') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', 'abcdef') 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) + assert_line_around_cursor('abcde', 'f') input_keys('Tz') - assert_line('abcdef') - assert_byte_pointer_size('abcde') - assert_cursor(5) - assert_cursor_max(6) + assert_line_around_cursor('abcde', 'f') input_keys('Ta') - assert_line('abcdef') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(6) + assert_line_around_cursor('a', 'bcdef') end def test_vi_delete_next_char input_keys("abc\C-[h") - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(3) - assert_line('abc') + assert_line_around_cursor('a', 'bc') input_keys('x') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(2) - assert_line('ac') + assert_line_around_cursor('a', 'c') input_keys('x') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(1) - assert_line('a') + assert_line_around_cursor('', 'a') input_keys('x') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys('x') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_vi_delete_next_char_for_mbchar input_keys("あいう\C-[h") - assert_byte_pointer_size('あ') - assert_cursor(2) - assert_cursor_max(6) - assert_line('あいう') + assert_line_around_cursor('あ', 'いう') input_keys('x') - assert_byte_pointer_size('あ') - assert_cursor(2) - assert_cursor_max(4) - assert_line('あう') + assert_line_around_cursor('あ', 'う') input_keys('x') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(2) - assert_line('あ') + assert_line_around_cursor('', 'あ') input_keys('x') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys('x') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_vi_delete_next_char_for_mbchar_by_plural_code_points input_keys("か\u3099き\u3099く\u3099\C-[h") - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(6) - assert_line("か\u3099き\u3099く\u3099") + assert_line_around_cursor("か\u3099", "き\u3099く\u3099") input_keys('x') - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(4) - assert_line("か\u3099く\u3099") + assert_line_around_cursor("か\u3099", "く\u3099") input_keys('x') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(2) - assert_line("か\u3099") + assert_line_around_cursor('', "か\u3099") input_keys('x') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys('x') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_vi_delete_prev_char input_keys('ab') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('ab', '') input_keys("\C-h") - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(1) - assert_line('a') + assert_line_around_cursor('a', '') end def test_vi_delete_prev_char_for_mbchar input_keys('かき') - assert_byte_pointer_size('かき') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('かき', '') input_keys("\C-h") - assert_byte_pointer_size('か') - assert_cursor(2) - assert_cursor_max(2) - assert_line('か') + assert_line_around_cursor('か', '') end def test_vi_delete_prev_char_for_mbchar_by_plural_code_points input_keys("か\u3099き\u3099") - assert_byte_pointer_size("か\u3099き\u3099") - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor("か\u3099き\u3099", '') input_keys("\C-h") - assert_byte_pointer_size("か\u3099") - assert_cursor(2) - assert_cursor_max(2) - assert_line("か\u3099") + assert_line_around_cursor("か\u3099", '') end def test_ed_delete_prev_char input_keys("abcdefg\C-[h") - assert_byte_pointer_size('abcde') - assert_cursor(5) - assert_cursor_max(7) - assert_line('abcdefg') + assert_line_around_cursor('abcde', 'fg') input_keys('X') - assert_byte_pointer_size('abcd') - assert_cursor(4) - assert_cursor_max(6) - assert_line('abcdfg') + assert_line_around_cursor('abcd', 'fg') input_keys('3X') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(3) - assert_line('afg') + assert_line_around_cursor('a', 'fg') input_keys('p') - assert_byte_pointer_size('abcd') - assert_cursor(4) - assert_cursor_max(6) - assert_line('afbcdg') + assert_line_around_cursor('afbc', 'dg') end def test_ed_delete_prev_word input_keys('abc def{bbb}ccc') - assert_byte_pointer_size('abc def{bbb}ccc') - assert_cursor(15) - assert_cursor_max(15) + assert_line_around_cursor('abc def{bbb}ccc', '') input_keys("\C-w") - assert_byte_pointer_size('abc def{bbb}') - assert_cursor(12) - assert_cursor_max(12) - assert_line('abc def{bbb}') + assert_line_around_cursor('abc def{bbb}', '') input_keys("\C-w") - assert_byte_pointer_size('abc def{') - assert_cursor(8) - assert_cursor_max(8) - assert_line('abc def{') + assert_line_around_cursor('abc def{', '') input_keys("\C-w") - assert_byte_pointer_size('abc ') - assert_cursor(4) - assert_cursor_max(4) - assert_line('abc ') + assert_line_around_cursor('abc ', '') input_keys("\C-w") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_ed_delete_prev_word_for_mbchar input_keys('あいう かきく{さしす}たちつ') - assert_byte_pointer_size('あいう かきく{さしす}たちつ') - assert_cursor(27) - assert_cursor_max(27) + assert_line_around_cursor('あいう かきく{さしす}たちつ', '') input_keys("\C-w") - assert_byte_pointer_size('あいう かきく{さしす}') - assert_cursor(21) - assert_cursor_max(21) - assert_line('あいう かきく{さしす}') + assert_line_around_cursor('あいう かきく{さしす}', '') input_keys("\C-w") - assert_byte_pointer_size('あいう かきく{') - assert_cursor(14) - assert_cursor_max(14) - assert_line('あいう かきく{') + assert_line_around_cursor('あいう かきく{', '') input_keys("\C-w") - assert_byte_pointer_size('あいう ') - assert_cursor(7) - assert_cursor_max(7) - assert_line('あいう ') + assert_line_around_cursor('あいう ', '') input_keys("\C-w") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_ed_delete_prev_word_for_mbchar_by_plural_code_points input_keys("あいう か\u3099き\u3099く\u3099{さしす}たちつ") - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{さしす}たちつ") - assert_cursor(27) - assert_cursor_max(27) + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}たちつ", '') input_keys("\C-w") - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{さしす}") - assert_cursor(21) - assert_cursor_max(21) - assert_line("あいう か\u3099き\u3099く\u3099{さしす}") + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{さしす}", '') input_keys("\C-w") - assert_byte_pointer_size("あいう か\u3099き\u3099く\u3099{") - assert_cursor(14) - assert_cursor_max(14) - assert_line("あいう か\u3099き\u3099く\u3099{") + assert_line_around_cursor("あいう か\u3099き\u3099く\u3099{", '') input_keys("\C-w") - assert_byte_pointer_size('あいう ') - assert_cursor(7) - assert_cursor_max(7) - assert_line('あいう ') + assert_line_around_cursor('あいう ', '') input_keys("\C-w") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_ed_newline_with_cr input_keys('ab') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('ab', '') refute(@line_editor.finished?) input_keys("\C-m") - assert_line('ab') + assert_line_around_cursor('ab', '') assert(@line_editor.finished?) end def test_ed_newline_with_lf input_keys('ab') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('ab', '') refute(@line_editor.finished?) input_keys("\C-j") - assert_line('ab') + assert_line_around_cursor('ab', '') assert(@line_editor.finished?) end def test_vi_list_or_eof input_keys("\C-d") # quit from inputing - assert_line(nil) + assert_nil(@line_editor.line) assert(@line_editor.finished?) end def test_vi_list_or_eof_with_non_empty_line input_keys('ab') - assert_byte_pointer_size('ab') - assert_cursor(2) - assert_cursor_max(2) + assert_line_around_cursor('ab', '') refute(@line_editor.finished?) input_keys("\C-d") - assert_line('ab') + assert_line_around_cursor('ab', '') assert(@line_editor.finished?) end @@ -982,40 +549,19 @@ class Reline::KeyActor::ViInsert::Test < Reline::TestCase } } input_keys('foo') - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') input_keys("\C-n") - assert_byte_pointer_size('foo_bar') - assert_cursor(7) - assert_cursor_max(7) - assert_line('foo_bar') + assert_line_around_cursor('foo_bar', '') input_keys("\C-n") - assert_byte_pointer_size('foo_bar_baz') - assert_cursor(11) - assert_cursor_max(11) - assert_line('foo_bar_baz') + assert_line_around_cursor('foo_bar_baz', '') input_keys("\C-n") - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') input_keys("\C-n") - assert_byte_pointer_size('foo_bar') - assert_cursor(7) - assert_cursor_max(7) - assert_line('foo_bar') + assert_line_around_cursor('foo_bar', '') input_keys("_\C-n") - assert_byte_pointer_size('foo_bar_baz') - assert_cursor(11) - assert_cursor_max(11) - assert_line('foo_bar_baz') + assert_line_around_cursor('foo_bar_baz', '') input_keys("\C-n") - assert_byte_pointer_size('foo_bar_') - assert_cursor(8) - assert_cursor_max(8) - assert_line('foo_bar_') + assert_line_around_cursor('foo_bar_', '') end def test_completion_journey_reverse @@ -1028,40 +574,19 @@ class Reline::KeyActor::ViInsert::Test < Reline::TestCase } } input_keys('foo') - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') input_keys("\C-p") - assert_byte_pointer_size('foo_bar_baz') - assert_cursor(11) - assert_cursor_max(11) - assert_line('foo_bar_baz') + assert_line_around_cursor('foo_bar_baz', '') input_keys("\C-p") - assert_byte_pointer_size('foo_bar') - assert_cursor(7) - assert_cursor_max(7) - assert_line('foo_bar') + assert_line_around_cursor('foo_bar', '') input_keys("\C-p") - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') input_keys("\C-p") - assert_byte_pointer_size('foo_bar_baz') - assert_cursor(11) - assert_cursor_max(11) - assert_line('foo_bar_baz') + assert_line_around_cursor('foo_bar_baz', '') input_keys("\C-h\C-p") - assert_byte_pointer_size('foo_bar_baz') - assert_cursor(11) - assert_cursor_max(11) - assert_line('foo_bar_baz') + assert_line_around_cursor('foo_bar_baz', '') input_keys("\C-p") - assert_byte_pointer_size('foo_bar_ba') - assert_cursor(10) - assert_cursor_max(10) - assert_line('foo_bar_ba') + assert_line_around_cursor('foo_bar_ba', '') end def test_completion_journey_in_middle_of_line @@ -1074,42 +599,21 @@ class Reline::KeyActor::ViInsert::Test < Reline::TestCase } } input_keys('abcde fo ABCDE') - assert_line('abcde fo ABCDE') + assert_line_around_cursor('abcde fo ABCDE', '') input_keys("\C-[" + 'h' * 5 + "i\C-n") - assert_byte_pointer_size('abcde foo_bar') - assert_cursor(13) - assert_cursor_max(19) - assert_line('abcde foo_bar ABCDE') + assert_line_around_cursor('abcde foo_bar', ' ABCDE') input_keys("\C-n") - assert_byte_pointer_size('abcde foo_bar_baz') - assert_cursor(17) - assert_cursor_max(23) - assert_line('abcde foo_bar_baz ABCDE') + assert_line_around_cursor('abcde foo_bar_baz', ' ABCDE') input_keys("\C-n") - assert_byte_pointer_size('abcde fo') - assert_cursor(8) - assert_cursor_max(14) - assert_line('abcde fo ABCDE') + assert_line_around_cursor('abcde fo', ' ABCDE') input_keys("\C-n") - assert_byte_pointer_size('abcde foo_bar') - assert_cursor(13) - assert_cursor_max(19) - assert_line('abcde foo_bar ABCDE') + assert_line_around_cursor('abcde foo_bar', ' ABCDE') input_keys("_\C-n") - assert_byte_pointer_size('abcde foo_bar_baz') - assert_cursor(17) - assert_cursor_max(23) - assert_line('abcde foo_bar_baz ABCDE') + assert_line_around_cursor('abcde foo_bar_baz', ' ABCDE') input_keys("\C-n") - assert_byte_pointer_size('abcde foo_bar_') - assert_cursor(14) - assert_cursor_max(20) - assert_line('abcde foo_bar_ ABCDE') + assert_line_around_cursor('abcde foo_bar_', ' ABCDE') input_keys("\C-n") - assert_byte_pointer_size('abcde foo_bar_baz') - assert_cursor(17) - assert_cursor_max(23) - assert_line('abcde foo_bar_baz ABCDE') + assert_line_around_cursor('abcde foo_bar_baz', ' ABCDE') end def test_completion @@ -1122,15 +626,55 @@ class Reline::KeyActor::ViInsert::Test < Reline::TestCase } } input_keys('foo') - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') input_keys("\C-i") - assert_byte_pointer_size('foo_bar') - assert_cursor(7) - assert_cursor_max(7) - assert_line('foo_bar') + assert_line_around_cursor('foo_bar', '') + end + + def test_autocompletion_with_upward_navigation + @config.autocompletion = true + @line_editor.completion_proc = proc { |word| + %w{ + Readline + Regexp + RegexpError + }.map { |i| + i.encode(@encoding) + } + } + input_keys('Re') + assert_line_around_cursor('Re', '') + input_keys("\C-i", false) + assert_line_around_cursor('Readline', '') + input_keys("\C-i", false) + assert_line_around_cursor('Regexp', '') + @line_editor.input_key(Reline::Key.new(:completion_journey_up, :completion_journey_up, false)) + assert_line_around_cursor('Readline', '') + ensure + @config.autocompletion = false + end + + def test_autocompletion_with_upward_navigation_and_menu_complete_backward + @config.autocompletion = true + @line_editor.completion_proc = proc { |word| + %w{ + Readline + Regexp + RegexpError + }.map { |i| + i.encode(@encoding) + } + } + input_keys('Re') + assert_line_around_cursor('Re', '') + input_keys("\C-i", false) + assert_line_around_cursor('Readline', '') + input_keys("\C-i", false) + assert_line_around_cursor('Regexp', '') + @line_editor.input_key(Reline::Key.new(:menu_complete_backward, :menu_complete_backward, false)) + assert_line_around_cursor('Readline', '') + ensure + @config.autocompletion = false end def test_completion_with_disable_completion @@ -1144,314 +688,250 @@ class Reline::KeyActor::ViInsert::Test < Reline::TestCase } } input_keys('foo') - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') input_keys("\C-i") - assert_byte_pointer_size('foo') - assert_cursor(3) - assert_cursor_max(3) - assert_line('foo') + assert_line_around_cursor('foo', '') end def test_vi_first_print input_keys("abcde\C-[^") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) + assert_line_around_cursor('', 'abcde') input_keys("0\C-ki") input_keys(" abcde\C-[^") - assert_byte_pointer_size(' ') - assert_cursor(1) - assert_cursor_max(6) + assert_line_around_cursor(' ', 'abcde') input_keys("0\C-ki") input_keys(" abcde ABCDE \C-[^") - assert_byte_pointer_size(' ') - assert_cursor(3) - assert_cursor_max(17) + assert_line_around_cursor(' ', 'abcde ABCDE ') end def test_ed_move_to_beg input_keys("abcde\C-[0") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(5) + assert_line_around_cursor('', 'abcde') input_keys("0\C-ki") input_keys(" abcde\C-[0") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(6) + assert_line_around_cursor('', ' abcde') input_keys("0\C-ki") input_keys(" abcde ABCDE \C-[0") - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(17) + assert_line_around_cursor('', ' abcde ABCDE ') + end + + def test_vi_to_column + input_keys("a一二三\C-[0") + input_keys('1|') + assert_line_around_cursor('', 'a一二三') + input_keys('2|') + assert_line_around_cursor('a', '一二三') + input_keys('3|') + assert_line_around_cursor('a', '一二三') + input_keys('4|') + assert_line_around_cursor('a一', '二三') + input_keys('9|') + assert_line_around_cursor('a一二', '三') end def test_vi_delete_meta input_keys("aaa bbb ccc ddd eee\C-[02w") - assert_byte_pointer_size('aaa bbb ') - assert_cursor(8) - assert_cursor_max(19) - assert_line('aaa bbb ccc ddd eee') + assert_line_around_cursor('aaa bbb ', 'ccc ddd eee') input_keys('dw') - assert_byte_pointer_size('aaa bbb ') - assert_cursor(8) - assert_cursor_max(15) - assert_line('aaa bbb ddd eee') + assert_line_around_cursor('aaa bbb ', 'ddd eee') input_keys('db') - assert_byte_pointer_size('aaa ') - assert_cursor(4) - assert_cursor_max(11) - assert_line('aaa ddd eee') + assert_line_around_cursor('aaa ', 'ddd eee') + end + + def test_vi_delete_meta_nothing + input_keys("foo\C-[0") + assert_line_around_cursor('', 'foo') + input_keys('dhp') + assert_line_around_cursor('', 'foo') end def test_vi_delete_meta_with_vi_next_word_at_eol input_keys("foo bar\C-[0w") - assert_byte_pointer_size('foo ') - assert_cursor(4) - assert_cursor_max(7) - assert_line('foo bar') + assert_line_around_cursor('foo ', 'bar') input_keys('w') - assert_byte_pointer_size('foo ba') - assert_cursor(6) - assert_cursor_max(7) - assert_line('foo bar') + assert_line_around_cursor('foo ba', 'r') input_keys('0dw') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) - assert_line('bar') + assert_line_around_cursor('', 'bar') input_keys('dw') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') end def test_vi_delete_meta_with_vi_next_char input_keys("aaa bbb ccc ___ ddd\C-[02w") - assert_byte_pointer_size('aaa bbb ') - assert_cursor(8) - assert_cursor_max(19) - assert_line('aaa bbb ccc ___ ddd') + assert_line_around_cursor('aaa bbb ', 'ccc ___ ddd') input_keys('df_') - assert_byte_pointer_size('aaa bbb ') - assert_cursor(8) - assert_cursor_max(14) - assert_line('aaa bbb __ ddd') + assert_line_around_cursor('aaa bbb ', '__ ddd') end def test_vi_delete_meta_with_arg - input_keys("aaa bbb ccc\C-[02w") - assert_byte_pointer_size('aaa bbb ') - assert_cursor(8) - assert_cursor_max(11) - assert_line('aaa bbb ccc') + input_keys("aaa bbb ccc ddd\C-[03w") + assert_line_around_cursor('aaa bbb ccc ', 'ddd') input_keys('2dl') - assert_byte_pointer_size('aaa bbb ') - assert_cursor(8) - assert_cursor_max(9) - assert_line('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 def test_vi_change_meta input_keys("aaa bbb ccc ddd eee\C-[02w") - assert_byte_pointer_size('aaa bbb ') - assert_cursor(8) - assert_cursor_max(19) - assert_line('aaa bbb ccc ddd eee') + assert_line_around_cursor('aaa bbb ', 'ccc ddd eee') input_keys('cwaiueo') - assert_byte_pointer_size('aaa bbb aiueo') - assert_cursor(13) - assert_cursor_max(21) - assert_line('aaa bbb aiueo ddd eee') + assert_line_around_cursor('aaa bbb aiueo', ' ddd eee') input_keys("\C-[") - assert_byte_pointer_size('aaa bbb aiue') - assert_cursor(12) - assert_cursor_max(21) - assert_line('aaa bbb aiueo ddd eee') + assert_line_around_cursor('aaa bbb aiue', 'o ddd eee') input_keys('cb') - assert_byte_pointer_size('aaa bbb ') - assert_cursor(8) - assert_cursor_max(17) - assert_line('aaa bbb o ddd eee') + assert_line_around_cursor('aaa bbb ', 'o ddd eee') end def test_vi_change_meta_with_vi_next_word input_keys("foo bar baz\C-[0w") - assert_byte_pointer_size('foo ') - assert_cursor(5) - assert_cursor_max(13) - assert_line('foo bar baz') + assert_line_around_cursor('foo ', 'bar baz') input_keys('cwhoge') - assert_byte_pointer_size('foo hoge') - assert_cursor(9) - assert_cursor_max(14) - assert_line('foo hoge baz') + assert_line_around_cursor('foo hoge', ' baz') input_keys("\C-[") - assert_byte_pointer_size('foo hog') - assert_cursor(8) - assert_cursor_max(14) - assert_line('foo hoge baz') + assert_line_around_cursor('foo hog', 'e baz') + 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 input_keys("abc\C-[h") - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(3) - assert_line('abc') + assert_line_around_cursor('a', 'bc') input_keys('@') - assert_byte_pointer_size('a') - assert_cursor(1) - assert_cursor_max(3) - assert_line('abc') + assert_line_around_cursor('a', 'bc') end def test_vi_yank - input_keys("foo bar\C-[0") - assert_line('foo bar') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(7) + input_keys("foo bar\C-[2h") + assert_line_around_cursor('foo ', 'bar') input_keys('y3l') - assert_line('foo bar') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(7) + assert_line_around_cursor('foo ', 'bar') input_keys('P') - assert_line('foofoo bar') - assert_byte_pointer_size('fo') - assert_cursor(2) - assert_cursor_max(10) + 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 + + def test_vi_yank_nothing + input_keys("foo\C-[0") + assert_line_around_cursor('', 'foo') + input_keys('yhp') + assert_line_around_cursor('', 'foo') end def test_vi_end_word_with_operator input_keys("foo bar\C-[0") - assert_line('foo bar') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(7) + assert_line_around_cursor('', 'foo bar') input_keys('de') - assert_line(' bar') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(4) + assert_line_around_cursor('', ' bar') input_keys('de') - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys('de') - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') end def test_vi_end_big_word_with_operator input_keys("aaa b{b}}}b\C-[0") - assert_line('aaa b{b}}}b') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(13) + assert_line_around_cursor('', 'aaa b{b}}}b') input_keys('dE') - assert_line(' b{b}}}b') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(10) + assert_line_around_cursor('', ' b{b}}}b') input_keys('dE') - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') input_keys('dE') - assert_line('') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) + assert_line_around_cursor('', '') end def test_vi_next_char_with_operator input_keys("foo bar\C-[0") - assert_line('foo bar') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(7) + assert_line_around_cursor('', 'foo bar') input_keys('df ') - assert_line('bar') - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(3) - end - - def test_pasting - start_pasting - input_keys('ab') - finish_pasting - input_keys('c') - assert_line('abc') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(3) - end - - def test_pasting_fullwidth - start_pasting - input_keys('あ') - finish_pasting - input_keys('い') - assert_line('あい') - assert_byte_pointer_size('あい') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('', 'bar') end def test_ed_delete_next_char_at_eol input_keys('"あ"') - assert_line('"あ"') - assert_byte_pointer_size('"あ"') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('"あ"', '') input_keys("\C-[") - assert_line('"あ"') - assert_byte_pointer_size('"あ') - assert_cursor(3) - assert_cursor_max(4) + assert_line_around_cursor('"あ', '"') input_keys('xa"') - assert_line('"あ"') - assert_byte_pointer_size('"あ"') - assert_cursor(4) - assert_cursor_max(4) + assert_line_around_cursor('"あ"', '') end def test_vi_kill_line_prev input_keys("\C-u", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys('abc') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(3) + assert_line_around_cursor('abc', '') input_keys("\C-u", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(0) - assert_line('') + assert_line_around_cursor('', '') input_keys('abc') input_keys("\C-[\C-u", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(1) - assert_line('c') + assert_line_around_cursor('', 'c') input_keys("\C-u", false) - assert_byte_pointer_size('') - assert_cursor(0) - assert_cursor_max(1) - assert_line('c') + assert_line_around_cursor('', 'c') + end + + def test_vi_change_to_eol + input_keys("abcdef\C-[2hC") + assert_line_around_cursor('abc', '') + input_keys("\C-[0C") + assert_line_around_cursor('', '') + assert_equal(:vi_insert, editing_mode_label) + end + + def test_vi_motion_operators + assert_equal(:vi_insert, editing_mode_label) + + assert_nothing_raised do + input_keys("test = { foo: bar }\C-[BBBldt}b") + end + end + + def test_emacs_editing_mode + @line_editor.__send__(:emacs_editing_mode, nil) + assert(@config.editing_mode_is?(:emacs)) end end diff --git a/test/reline/test_key_stroke.rb b/test/reline/test_key_stroke.rb index d377a1e972..ec70a05957 100644 --- a/test/reline/test_key_stroke.rb +++ b/test/reline/test_key_stroke.rb @@ -24,27 +24,56 @@ class Reline::KeyStroke::Test < Reline::TestCase config.add_default_key_binding(key.bytes, func.bytes) end stroke = Reline::KeyStroke.new(config) - assert_equal(:matching, stroke.match_status("a".bytes)) - assert_equal(:matching, stroke.match_status("ab".bytes)) - assert_equal(:matched, stroke.match_status("abc".bytes)) - assert_equal(:matched, stroke.match_status("abz".bytes)) - assert_equal(:matched, stroke.match_status("abx".bytes)) - assert_equal(:matched, stroke.match_status("ac".bytes)) - assert_equal(:matched, stroke.match_status("aa".bytes)) - assert_equal(:matched, stroke.match_status("x".bytes)) - assert_equal(:unmatched, stroke.match_status("m".bytes)) - assert_equal(:matched, stroke.match_status("abzwabk".bytes)) + assert_equal(Reline::KeyStroke::MATCHING_MATCHED, stroke.match_status("a".bytes)) + assert_equal(Reline::KeyStroke::MATCHING_MATCHED, stroke.match_status("ab".bytes)) + assert_equal(Reline::KeyStroke::MATCHED, stroke.match_status("abc".bytes)) + assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status("abz".bytes)) + assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status("abcx".bytes)) + assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status("aa".bytes)) + assert_equal(Reline::KeyStroke::MATCHED, stroke.match_status("x".bytes)) + assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status("xa".bytes)) + end + + def test_match_unknown + config = Reline::Config.new + config.add_default_key_binding("\e[9abc".bytes, 'x') + stroke = Reline::KeyStroke.new(config) + sequences = [ + "\e[9abc", + "\e[9d", + "\e[A", # Up + "\e[1;1R", # Cursor position report + "\e[15~", # F5 + "\eOP", # F1 + "\e\e[A", # Option+Up + "\eX", + "\e\eX" + ] + sequences.each do |seq| + assert_equal(Reline::KeyStroke::MATCHED, stroke.match_status(seq.bytes)) + assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status(seq.bytes + [32])) + (2...seq.size).each do |i| + assert_equal(Reline::KeyStroke::MATCHING, stroke.match_status(seq.bytes.take(i))) + end + end end def test_expand config = Reline::Config.new { 'abc' => '123', + 'ab' => '456' }.each_pair do |key, func| config.add_default_key_binding(key.bytes, func.bytes) end stroke = Reline::KeyStroke.new(config) - assert_equal('123'.bytes, stroke.expand('abc'.bytes)) + assert_equal(['123'.bytes.map { |c| Reline::Key.new(c, c, false) }, 'de'.bytes], stroke.expand('abcde'.bytes)) + assert_equal(['456'.bytes.map { |c| Reline::Key.new(c, c, false) }, 'de'.bytes], stroke.expand('abde'.bytes)) + # CSI sequence + assert_equal([[], 'bc'.bytes], stroke.expand("\e[1;2;3;4;5abc".bytes)) + assert_equal([[], 'BC'.bytes], stroke.expand("\e\e[ABC".bytes)) + # SS3 sequence + assert_equal([[], 'QR'.bytes], stroke.expand("\eOPQR".bytes)) end def test_oneshot_key_bindings @@ -55,25 +84,22 @@ class Reline::KeyStroke::Test < Reline::TestCase config.add_default_key_binding(key.bytes, func.bytes) end stroke = Reline::KeyStroke.new(config) - assert_equal(:unmatched, stroke.match_status('zzz'.bytes)) - assert_equal(:matched, stroke.match_status('abc'.bytes)) + assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status('zzz'.bytes)) + assert_equal(Reline::KeyStroke::MATCHED, stroke.match_status('abc'.bytes)) end def test_with_reline_key config = Reline::Config.new { - [ - Reline::Key.new(100, 228, true), # Alt+d - Reline::Key.new(97, 97, false) # a - ] => 'abc', + "\eda".bytes => 'abc', # Alt+d a [195, 164] => 'def' }.each_pair do |key, func| config.add_oneshot_key_binding(key, func.bytes) end stroke = Reline::KeyStroke.new(config) - assert_equal(:unmatched, stroke.match_status('da'.bytes)) - assert_equal(:matched, stroke.match_status("\M-da".bytes)) - assert_equal(:unmatched, stroke.match_status([32, 195, 164])) - assert_equal(:matched, stroke.match_status([195, 164])) + assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status('da'.bytes)) + assert_equal(Reline::KeyStroke::MATCHED, stroke.match_status("\eda".bytes)) + assert_equal(Reline::KeyStroke::UNMATCHED, stroke.match_status([32, 195, 164])) + assert_equal(Reline::KeyStroke::MATCHED, stroke.match_status([195, 164])) end end diff --git a/test/reline/test_line_editor.rb b/test/reline/test_line_editor.rb new file mode 100644 index 0000000000..1859da8199 --- /dev/null +++ b/test/reline/test_line_editor.rb @@ -0,0 +1,183 @@ +require_relative 'helper' +require 'reline/line_editor' +require 'stringio' + +class Reline::LineEditor + class RenderLineDifferentialTest < Reline::TestCase + class TestIO < Reline::IO + def move_cursor_column(col) + @output << "[COL_#{col}]" + end + + def erase_after_cursor + @output << '[ERASE]' + end + end + + def setup + verbose, $VERBOSE = $VERBOSE, nil + @line_editor = Reline::LineEditor.new(nil, Encoding::UTF_8) + @original_iogate = Reline::IOGate + @output = StringIO.new + @line_editor.instance_variable_set(:@screen_size, [24, 80]) + @line_editor.instance_variable_set(:@output, @output) + Reline.send(:remove_const, :IOGate) + Reline.const_set(:IOGate, TestIO.new) + Reline::IOGate.instance_variable_set(:@output, @output) + ensure + $VERBOSE = verbose + end + + def assert_output(expected) + @output.reopen(+'') + yield + actual = @output.string + assert_equal(expected, actual.gsub("\e[0m", '')) + end + + def teardown + Reline.send(:remove_const, :IOGate) + Reline.const_set(:IOGate, @original_iogate) + end + + def test_line_increase_decrease + assert_output '[COL_0]bb' do + @line_editor.render_line_differential([[0, 1, 'a']], [[0, 2, 'bb']]) + end + + assert_output '[COL_0]b[COL_1][ERASE]' do + @line_editor.render_line_differential([[0, 2, 'aa']], [[0, 1, 'b']]) + end + end + + def test_dialog_appear_disappear + assert_output '[COL_3]dialog' do + @line_editor.render_line_differential([[0, 1, 'a']], [[0, 1, 'a'], [3, 6, 'dialog']]) + end + + assert_output '[COL_3]dialog' do + @line_editor.render_line_differential([[0, 10, 'a' * 10]], [[0, 10, 'a' * 10], [3, 6, 'dialog']]) + end + + assert_output '[COL_1][ERASE]' do + @line_editor.render_line_differential([[0, 1, 'a'], [3, 6, 'dialog']], [[0, 1, 'a']]) + end + + assert_output '[COL_3]aaaaaa' do + @line_editor.render_line_differential([[0, 10, 'a' * 10], [3, 6, 'dialog']], [[0, 10, 'a' * 10]]) + end + end + + def test_dialog_change + assert_output '[COL_3]DIALOG' do + @line_editor.render_line_differential([[0, 2, 'a'], [3, 6, 'dialog']], [[0, 2, 'a'], [3, 6, 'DIALOG']]) + end + + assert_output '[COL_3]DIALOG' do + @line_editor.render_line_differential([[0, 10, 'a' * 10], [3, 6, 'dialog']], [[0, 10, 'a' * 10], [3, 6, 'DIALOG']]) + end + end + + def test_update_under_dialog + assert_output '[COL_0]b[COL_1] ' do + @line_editor.render_line_differential([[0, 2, 'aa'], [4, 6, 'dialog']], [[0, 1, 'b'], [4, 6, 'dialog']]) + end + + assert_output '[COL_0]bbb[COL_9]b' do + @line_editor.render_line_differential([[0, 10, 'a' * 10], [3, 6, 'dialog']], [[0, 10, 'b' * 10], [3, 6, 'dialog']]) + end + + assert_output '[COL_0]b[COL_1] [COL_9][ERASE]' do + @line_editor.render_line_differential([[0, 10, 'a' * 10], [3, 6, 'dialog']], [[0, 1, 'b'], [3, 6, 'dialog']]) + end + end + + def test_dialog_move + assert_output '[COL_3]dialog[COL_9][ERASE]' do + @line_editor.render_line_differential([[0, 1, 'a'], [4, 6, 'dialog']], [[0, 1, 'a'], [3, 6, 'dialog']]) + end + + assert_output '[COL_4] [COL_5]dialog' do + @line_editor.render_line_differential([[0, 1, 'a'], [4, 6, 'dialog']], [[0, 1, 'a'], [5, 6, 'dialog']]) + end + + assert_output '[COL_2]dialog[COL_8]a' do + @line_editor.render_line_differential([[0, 10, 'a' * 10], [3, 6, 'dialog']], [[0, 10, 'a' * 10], [2, 6, 'dialog']]) + end + + assert_output '[COL_2]a[COL_3]dialog' do + @line_editor.render_line_differential([[0, 10, 'a' * 10], [2, 6, 'dialog']], [[0, 10, 'a' * 10], [3, 6, 'dialog']]) + end + end + + def test_multibyte + base = [0, 12, '一二三一二三'] + left = [0, 3, 'LLL'] + right = [9, 3, 'RRR'] + front = [3, 6, 'FFFFFF'] + # 一 FFFFFF 三 + # 一二三一二三 + assert_output '[COL_2]二三一二' do + @line_editor.render_line_differential([base, front], [base, nil]) + end + + # LLLFFFFFF 三 + # LLL 三一二三 + assert_output '[COL_3] 三一二' do + @line_editor.render_line_differential([base, left, front], [base, left, nil]) + end + + # 一 FFFFFFRRR + # 一二三一 RRR + assert_output '[COL_2]二三一 ' do + @line_editor.render_line_differential([base, right, front], [base, right, nil]) + end + + # LLLFFFFFFRRR + # LLL 三一 RRR + assert_output '[COL_3] 三一 ' do + @line_editor.render_line_differential([base, left, right, front], [base, left, right, nil]) + end + end + + def test_complicated + state_a = [nil, [19, 7, 'bbbbbbb'], [15, 8, 'cccccccc'], [10, 5, 'ddddd'], [18, 4, 'eeee'], [1, 3, 'fff'], [17, 2, 'gg'], [7, 1, 'h']] + state_b = [[5, 9, 'aaaaaaaaa'], nil, [15, 8, 'cccccccc'], nil, [18, 4, 'EEEE'], [25, 4, 'ffff'], [17, 2, 'gg'], [2, 2, 'hh']] + # state_a: " fff h dddddccggeeecbbb" + # state_b: " hh aaaaaaaaa ccggEEEc ffff" + + assert_output '[COL_1] [COL_2]hh[COL_5]aaaaaaaaa[COL_14] [COL_19]EEE[COL_23] [COL_25]ffff' do + @line_editor.render_line_differential(state_a, state_b) + end + + assert_output '[COL_1]fff[COL_5] [COL_7]h[COL_8] [COL_10]ddddd[COL_19]eee[COL_23]bbb[COL_26][ERASE]' do + @line_editor.render_line_differential(state_b, state_a) + end + end + end + + def test_menu_info_format + list = %w[aa b c d e f g hhh i j k] + col3 = [ + 'aa e i', + 'b f j', + 'c g k', + 'd hhh' + ] + col2 = [ + 'aa g', + 'b hhh', + 'c i', + 'd j', + 'e k', + 'f' + ] + assert_equal(col3, Reline::LineEditor::MenuInfo.new(list).lines(19)) + assert_equal(col3, Reline::LineEditor::MenuInfo.new(list).lines(15)) + assert_equal(col2, Reline::LineEditor::MenuInfo.new(list).lines(14)) + assert_equal(col2, Reline::LineEditor::MenuInfo.new(list).lines(10)) + assert_equal(list, Reline::LineEditor::MenuInfo.new(list).lines(9)) + assert_equal(list, Reline::LineEditor::MenuInfo.new(list).lines(0)) + assert_equal([], Reline::LineEditor::MenuInfo.new([]).lines(10)) + end +end diff --git a/test/reline/test_macro.rb b/test/reline/test_macro.rb index 76a677c834..04aa6474b4 100644 --- a/test/reline/test_macro.rb +++ b/test/reline/test_macro.rb @@ -4,9 +4,8 @@ class Reline::MacroTest < Reline::TestCase def setup Reline.send(:test_mode) @config = Reline::Config.new - @encoding = Reline::IOGate.encoding + @encoding = Reline.core.encoding @line_editor = Reline::LineEditor.new(@config, @encoding) - @line_editor.instance_variable_set(:@screen_size, [24, 80]) @output = @line_editor.output = File.open(IO::NULL, "w") end diff --git a/test/reline/test_reline.rb b/test/reline/test_reline.rb index 0d45c5da54..515805467d 100644 --- a/test/reline/test_reline.rb +++ b/test/reline/test_reline.rb @@ -8,6 +8,7 @@ class Reline::Test < Reline::TestCase end def setup + Reline.send(:test_mode) Reline.output_modifier_proc = nil Reline.completion_proc = nil Reline.prompt_proc = nil @@ -284,7 +285,7 @@ class Reline::Test < Reline::TestCase input, to_write = IO.pipe to_read, output = IO.pipe unless Reline.__send__(:input=, input) - omit "Setting to input is not effective on #{Reline::IOGate}" + omit "Setting to input is not effective on #{Reline.core.io_gate}" end Reline.output = output @@ -302,12 +303,12 @@ class Reline::Test < Reline::TestCase def test_vi_editing_mode Reline.vi_editing_mode - assert_equal(Reline::KeyActor::ViInsert, Reline.send(:core).config.editing_mode.class) + assert_equal(:vi_insert, Reline.core.config.instance_variable_get(:@editing_mode_label)) end def test_emacs_editing_mode Reline.emacs_editing_mode - assert_equal(Reline::KeyActor::Emacs, Reline.send(:core).config.editing_mode.class) + assert_equal(:emacs, Reline.core.config.instance_variable_get(:@editing_mode_label)) end def test_add_dialog_proc @@ -321,6 +322,9 @@ class Reline::Test < Reline::TestCase d = Reline.dialog_proc(:test_proc) assert_equal(dummy_proc_2, d.dialog_proc) + Reline.add_dialog_proc(:test_proc, nil) + assert_nil(Reline.dialog_proc(:test_proc)) + l = lambda {} Reline.add_dialog_proc(:test_lambda, l) d = Reline.dialog_proc(:test_lambda) @@ -368,10 +372,70 @@ class Reline::Test < Reline::TestCase # TODO in Reline::Core end + def test_dumb_terminal + lib = File.expand_path("../../lib", __dir__) + out = IO.popen([{"TERM"=>"dumb"}, Reline.test_rubybin, "-I#{lib}", "-rreline", "-e", "p Reline.core.io_gate"], &:read) + assert_match(/#<Reline::Dumb/, out.chomp) + end + + def test_print_prompt_before_everything_else + pend if win? + lib = File.expand_path("../../lib", __dir__) + code = "p Reline::IOGate.class; p Reline.readline 'prompt> '" + out = IO.popen([Reline.test_rubybin, "-I#{lib}", "-rreline", "-e", code], "r+") do |io| + io.write "abc\n" + io.close_write + io.read + end + assert_match(/\AReline::ANSI\nprompt> /, out) + end + + def test_read_eof_returns_input + pend if win? + lib = File.expand_path("../../lib", __dir__) + code = "p result: Reline.readline" + out = IO.popen([Reline.test_rubybin, "-I#{lib}", "-rreline", "-e", code], "r+") do |io| + io.write "a\C-a" + io.close_write + io.read + end + assert_include(out, { result: 'a' }.inspect) + end + + def test_read_eof_returns_nil_if_empty + pend if win? + lib = File.expand_path("../../lib", __dir__) + code = "p result: Reline.readline" + out = IO.popen([Reline.test_rubybin, "-I#{lib}", "-rreline", "-e", code], "r+") do |io| + io.write "a\C-h" + io.close_write + io.read + end + assert_include(out, { result: nil }.inspect) + end + + def test_require_reline_should_not_trigger_winsize + pend if win? + lib = File.expand_path("../../lib", __dir__) + code = <<~RUBY + require "io/console" + def STDIN.tty?; true; end + def STDOUT.tty?; true; end + def STDIN.winsize; raise; end + require("reline") && p(Reline.core.io_gate) + RUBY + out = IO.popen([{}, Reline.test_rubybin, "-I#{lib}", "-e", code], &:read) + assert_include(out.chomp, "Reline::ANSI") + end + + def win? + /mswin|mingw/.match?(RUBY_PLATFORM) + end + def get_reline_encoding - if encoding = Reline::IOGate.encoding + if encoding = Reline.core.encoding encoding - elsif RUBY_PLATFORM =~ /mswin|mingw/ + elsif win? Encoding::UTF_8 else Encoding::default_external diff --git a/test/reline/test_reline_key.rb b/test/reline/test_reline_key.rb index fb700a6f2e..1e6b9fcb6c 100644 --- a/test/reline/test_reline_key.rb +++ b/test/reline/test_reline_key.rb @@ -2,52 +2,10 @@ require_relative 'helper' require "reline" class Reline::TestKey < Reline::TestCase - def setup - end - - def teardown - Reline.test_reset - end - - def test_match_key - assert(Reline::Key.new(1, 2, false).match?(Reline::Key.new(1, 2, false))) - assert(Reline::Key.new(1, 2, false).match?(Reline::Key.new(nil, 2, false))) - assert(Reline::Key.new(1, 2, false).match?(Reline::Key.new(1, 2, nil))) - - assert(Reline::Key.new(nil, 2, false).match?(Reline::Key.new(nil, 2, false))) - assert(Reline::Key.new(1, nil, false).match?(Reline::Key.new(1, nil, false))) - assert(Reline::Key.new(1, 2, nil).match?(Reline::Key.new(1, 2, nil))) - - assert(Reline::Key.new(nil, 2, false).match?(Reline::Key.new(nil, 2, false))) - assert(Reline::Key.new(1, nil, false).match?(Reline::Key.new(1, nil, false))) - assert(Reline::Key.new(1, 2, nil).match?(Reline::Key.new(1, 2, nil))) - - assert(!Reline::Key.new(1, 2, false).match?(Reline::Key.new(3, 1, false))) - assert(!Reline::Key.new(1, 2, false).match?(Reline::Key.new(1, 3, false))) - assert(!Reline::Key.new(1, 2, false).match?(Reline::Key.new(1, 3, true))) - end - - def test_match_integer - assert(Reline::Key.new(1, 2, false).match?(2)) - assert(Reline::Key.new(nil, 2, false).match?(2)) - assert(Reline::Key.new(1, nil, false).match?(1)) - - assert(!Reline::Key.new(1, 2, false).match?(1)) - assert(!Reline::Key.new(1, nil, false).match?(2)) - assert(!Reline::Key.new(nil, nil, false).match?(1)) - end - def test_match_symbol - assert(Reline::Key.new(:key1, :key2, false).match?(:key2)) - assert(Reline::Key.new(:key1, nil, false).match?(:key1)) - - assert(!Reline::Key.new(:key1, :key2, false).match?(:key1)) - assert(!Reline::Key.new(:key1, nil, false).match?(:key2)) - assert(!Reline::Key.new(nil, nil, false).match?(:key1)) - end - - def test_match_other - assert(!Reline::Key.new(:key1, 2, false).match?("key1")) - assert(!Reline::Key.new(nil, nil, false).match?(nil)) + assert(Reline::Key.new(:key1, :key1, false).match?(:key1)) + refute(Reline::Key.new(:key1, :key1, false).match?(:key2)) + refute(Reline::Key.new(:key1, :key1, false).match?(nil)) + refute(Reline::Key.new(1, 1, false).match?(:key1)) end end diff --git a/test/reline/test_string_processing.rb b/test/reline/test_string_processing.rb index 5db97545da..c9b9e38643 100644 --- a/test/reline/test_string_processing.rb +++ b/test/reline/test_string_processing.rb @@ -6,7 +6,7 @@ class Reline::LineEditor::StringProcessingTest < Reline::TestCase @prompt = '> ' @config = Reline::Config.new Reline::HISTORY.instance_variable_set(:@config, @config) - @encoding = Reline::IOGate.encoding + @encoding = Reline.core.encoding @line_editor = Reline::LineEditor.new(@config, @encoding) @line_editor.reset(@prompt, encoding: @encoding) end @@ -30,10 +30,7 @@ class Reline::LineEditor::StringProcessingTest < Reline::TestCase @line_editor.instance_variable_set(:@is_multiline, true) @line_editor.instance_variable_set(:@buffer_of_lines, buf) - @line_editor.instance_variable_set(:@line, buf[1]) @line_editor.instance_variable_set(:@byte_pointer, 3) - @line_editor.instance_variable_set(:@cursor, 3) - @line_editor.instance_variable_set(:@cursor_max, 11) @line_editor.instance_variable_set(:@line_index, 1) @line_editor.instance_variable_set(:@completion_proc, proc { |target| assert_equal('p', target) @@ -42,10 +39,7 @@ class Reline::LineEditor::StringProcessingTest < Reline::TestCase @line_editor.instance_variable_set(:@is_multiline, true) @line_editor.instance_variable_set(:@buffer_of_lines, buf) - @line_editor.instance_variable_set(:@line, buf[1]) @line_editor.instance_variable_set(:@byte_pointer, 6) - @line_editor.instance_variable_set(:@cursor, 6) - @line_editor.instance_variable_set(:@cursor_max, 11) @line_editor.instance_variable_set(:@line_index, 1) @line_editor.instance_variable_set(:@completion_proc, proc { |target, pre, post| assert_equal('puts', target) @@ -54,10 +48,7 @@ class Reline::LineEditor::StringProcessingTest < Reline::TestCase }) @line_editor.__send__(:call_completion_proc) - @line_editor.instance_variable_set(:@line, buf[0]) @line_editor.instance_variable_set(:@byte_pointer, 6) - @line_editor.instance_variable_set(:@cursor, 6) - @line_editor.instance_variable_set(:@cursor_max, 8) @line_editor.instance_variable_set(:@line_index, 0) @line_editor.instance_variable_set(:@completion_proc, proc { |target, pre, post| assert_equal('ho', target) @@ -66,10 +57,7 @@ class Reline::LineEditor::StringProcessingTest < Reline::TestCase }) @line_editor.__send__(:call_completion_proc) - @line_editor.instance_variable_set(:@line, buf[2]) @line_editor.instance_variable_set(:@byte_pointer, 1) - @line_editor.instance_variable_set(:@cursor, 1) - @line_editor.instance_variable_set(:@cursor_max, 3) @line_editor.instance_variable_set(:@line_index, 2) @line_editor.instance_variable_set(:@completion_proc, proc { |target, pre, post| assert_equal('e', target) diff --git a/test/reline/test_terminfo.rb b/test/reline/test_terminfo.rb index dda9b32495..4e59c54838 100644 --- a/test/reline/test_terminfo.rb +++ b/test/reline/test_terminfo.rb @@ -58,4 +58,4 @@ class Reline::Terminfo::Test < Reline::TestCase assert_raise(Reline::Terminfo::TerminfoError) { Reline::Terminfo.tigetnum('unknown') } assert_raise(Reline::Terminfo::TerminfoError) { Reline::Terminfo.tigetnum(nil) } end -end if Reline::Terminfo.enabled? +end if Reline::Terminfo.enabled? && Reline::Terminfo.term_supported? diff --git a/test/reline/test_unicode.rb b/test/reline/test_unicode.rb index 1233e034e8..deba4d4681 100644 --- a/test/reline/test_unicode.rb +++ b/test/reline/test_unicode.rb @@ -18,8 +18,75 @@ class Reline::Unicode::Test < Reline::TestCase assert_equal 2, Reline::Unicode.calculate_width('√', true) end + def test_csi_regexp + csi_sequences = ["\e[m", "\e[1m", "\e[12;34m", "\e[12;34H"] + assert_equal(csi_sequences, "text#{csi_sequences.join('text')}text".scan(Reline::Unicode::CSI_REGEXP)) + end + + def test_osc_regexp + osc_sequences = ["\e]1\a", "\e]0;OSC\a", "\e]1\e\\", "\e]0;OSC\e\\"] + separator = "text\atext" + assert_equal(osc_sequences, "#{separator}#{osc_sequences.join(separator)}#{separator}".scan(Reline::Unicode::OSC_REGEXP)) + end + + def test_split_by_width + assert_equal [['abc', nil, 'de'], 2], Reline::Unicode.split_by_width('abcde', 3) + assert_equal [['abc', nil, 'def', nil, ''], 3], Reline::Unicode.split_by_width('abcdef', 3) + assert_equal [['ab', nil, 'あd', nil, 'ef'], 3], Reline::Unicode.split_by_width('abあdef', 3) + assert_equal [["ab\1zero\2c", nil, 'def', nil, ''], 3], Reline::Unicode.split_by_width("ab\1zero\2cdef", 3) + assert_equal [["\e[31mabc", nil, "\e[31md\e[42mef", nil, "\e[31m\e[42mg"], 3], Reline::Unicode.split_by_width("\e[31mabcd\e[42mefg", 3) + assert_equal [["ab\e]0;1\ac", nil, "\e]0;1\ad"], 2], Reline::Unicode.split_by_width("ab\e]0;1\acd", 3) + end + + def test_split_by_width_csi_reset_sgr_optimization + assert_equal [["\e[1ma\e[mb\e[2mc", nil, "\e[2md\e[0me\e[3mf", nil, "\e[3mg"], 3], Reline::Unicode.split_by_width("\e[1ma\e[mb\e[2mcd\e[0me\e[3mfg", 3) + assert_equal [["\e[1ma\1\e[mzero\e[0m\2\e[2mb", nil, "\e[1m\e[2mc"], 2], Reline::Unicode.split_by_width("\e[1ma\1\e[mzero\e[0m\2\e[2mbc", 2) + end + def test_take_range assert_equal 'cdef', Reline::Unicode.take_range('abcdefghi', 2, 4) + assert_equal 'あde', Reline::Unicode.take_range('abあdef', 2, 4) + assert_equal "\1zero\2cdef", Reline::Unicode.take_range("ab\1zero\2cdef", 2, 4) + assert_equal "b\1zero\2cde", Reline::Unicode.take_range("ab\1zero\2cdef", 1, 4) + assert_equal "\e[31mcd\e[42mef", Reline::Unicode.take_range("\e[31mabcd\e[42mefg", 2, 4) + assert_equal "\e]0;1\acd", Reline::Unicode.take_range("ab\e]0;1\acd", 2, 3) assert_equal 'いう', Reline::Unicode.take_range('あいうえお', 2, 4) end + + def test_calculate_width + assert_equal 9, Reline::Unicode.calculate_width('abcdefghi') + assert_equal 9, Reline::Unicode.calculate_width('abcdefghi', true) + assert_equal 7, Reline::Unicode.calculate_width('abあdef') + assert_equal 7, Reline::Unicode.calculate_width('abあdef', true) + assert_equal 14, Reline::Unicode.calculate_width("ab\1zero\2cdef") + assert_equal 6, Reline::Unicode.calculate_width("ab\1zero\2cdef", true) + assert_equal 19, Reline::Unicode.calculate_width("\e[31mabcd\e[42mefg") + assert_equal 7, Reline::Unicode.calculate_width("\e[31mabcd\e[42mefg", true) + assert_equal 12, Reline::Unicode.calculate_width("ab\e]0;1\acd") + assert_equal 4, Reline::Unicode.calculate_width("ab\e]0;1\acd", true) + assert_equal 10, Reline::Unicode.calculate_width('あいうえお') + assert_equal 10, Reline::Unicode.calculate_width('あいうえお', true) + end + + def test_take_mbchar_range + assert_equal ['cdef', 2, 4], Reline::Unicode.take_mbchar_range('abcdefghi', 2, 4) + assert_equal ['cdef', 2, 4], Reline::Unicode.take_mbchar_range('abcdefghi', 2, 4, padding: true) + assert_equal ['cdef', 2, 4], Reline::Unicode.take_mbchar_range('abcdefghi', 2, 4, cover_begin: true) + assert_equal ['cdef', 2, 4], Reline::Unicode.take_mbchar_range('abcdefghi', 2, 4, cover_end: true) + assert_equal ['いう', 2, 4], Reline::Unicode.take_mbchar_range('あいうえお', 2, 4) + assert_equal ['いう', 2, 4], Reline::Unicode.take_mbchar_range('あいうえお', 2, 4, padding: true) + assert_equal ['いう', 2, 4], Reline::Unicode.take_mbchar_range('あいうえお', 2, 4, cover_begin: true) + assert_equal ['いう', 2, 4], Reline::Unicode.take_mbchar_range('あいうえお', 2, 4, cover_end: true) + assert_equal ['う', 4, 2], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4) + assert_equal [' う ', 3, 4], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4, padding: true) + assert_equal ['いう', 2, 4], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4, cover_begin: true) + assert_equal ['うえ', 4, 4], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4, cover_end: true) + assert_equal ['いう ', 2, 5], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4, cover_begin: true, padding: true) + assert_equal [' うえ', 3, 5], Reline::Unicode.take_mbchar_range('あいうえお', 3, 4, cover_end: true, padding: true) + assert_equal [' うえお ', 3, 10], Reline::Unicode.take_mbchar_range('あいうえお', 3, 10, padding: true) + assert_equal [" \e[41mうえお\e[0m ", 3, 10], Reline::Unicode.take_mbchar_range("あい\e[41mうえお", 3, 10, padding: true) + assert_equal ["\e[41m \e[42mい\e[43m ", 1, 4], Reline::Unicode.take_mbchar_range("\e[41mあ\e[42mい\e[43mう", 1, 4, padding: true) + assert_equal ["\e[31mc\1ABC\2d\e[0mef", 2, 4], Reline::Unicode.take_mbchar_range("\e[31mabc\1ABC\2d\e[0mefghi", 2, 4) + assert_equal ["\e[41m \e[42mい\e[43m ", 1, 4], Reline::Unicode.take_mbchar_range("\e[41mあ\e[42mい\e[43mう", 1, 4, padding: true) + end end diff --git a/test/reline/test_within_pipe.rb b/test/reline/test_within_pipe.rb index 43a66f45f4..4f05255301 100644 --- a/test/reline/test_within_pipe.rb +++ b/test/reline/test_within_pipe.rb @@ -3,14 +3,14 @@ require_relative 'helper' class Reline::WithinPipeTest < Reline::TestCase def setup Reline.send(:test_mode) - @encoding = Reline::IOGate.encoding + @encoding = Reline.core.encoding @input_reader, @writer = IO.pipe(@encoding) Reline.input = @input_reader @reader, @output_writer = IO.pipe(@encoding) @output = Reline.output = @output_writer - @config = Reline.send(:core).config - @config.keyseq_timeout *= 600 if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # for --jit-wait CI - @line_editor = Reline.send(:core).line_editor + @config = Reline.core.config + @config.keyseq_timeout *= 600 if defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? # for --jit-wait CI + @line_editor = Reline.core.line_editor end def teardown @@ -23,7 +23,6 @@ class Reline::WithinPipeTest < Reline::TestCase @reader.close @output_writer.close @config.reset - @config.reset_default_key_bindings Reline.test_reset end diff --git a/test/reline/yamatanooroti/multiline_repl b/test/reline/yamatanooroti/multiline_repl index d27d216652..8b82be60f4 100755 --- a/test/reline/yamatanooroti/multiline_repl +++ b/test/reline/yamatanooroti/multiline_repl @@ -9,14 +9,10 @@ require 'optparse' require_relative 'termination_checker' opt = OptionParser.new -opt.on('--prompt-list-cache-timeout VAL') { |v| - Reline::LineEditor.__send__(:remove_const, :PROMPT_LIST_CACHE_TIMEOUT) - Reline::LineEditor::PROMPT_LIST_CACHE_TIMEOUT = v.to_f -} opt.on('--dynamic-prompt') { Reline.prompt_proc = proc { |lines| lines.each_with_index.map { |l, i| - '[%04d]> ' % i + "\e[1m[%04d]>\e[m " % i } } } @@ -39,8 +35,46 @@ opt.on('--dynamic-prompt-with-newline') { } } } +opt.on('--broken-dynamic-prompt-assert-no-escape-sequence') { + Reline.prompt_proc = proc { |lines| + has_escape_sequence = lines.join.include?("\e") + (lines.size + 1).times.map { |i| + has_escape_sequence ? 'error>' : '[%04d]> ' % i + } + } +} +opt.on('--color-bold') { + Reline.output_modifier_proc = ->(output, complete:){ + output.gsub(/./) { |c| "\e[1m#{c}\e[0m" } + } +} +opt.on('--dynamic-prompt-show-line') { + Reline.prompt_proc = proc { |lines| + lines.map { |l| + '[%4.4s]> ' % l + } + } +} + +def assert_auto_indent_params(lines, line_index, byte_pointer, is_newline) + raise 'Wrong lines type' unless lines.all?(String) + + line = lines[line_index] + raise 'Wrong line_index value' unless line + + # The condition `byte_pointer <= line.bytesize` is not satisfied. Maybe bug. + # Instead, loose constraint `byte_pointer <= line.bytesize + 1` seems to be satisfied when is_newline is false. + return if is_newline + + raise 'byte_pointer out of bounds' unless byte_pointer <= line.bytesize + 1 + raise 'Invalid byte_pointer' unless line.byteslice(0, byte_pointer).valid_encoding? +end + opt.on('--auto-indent') { - AutoIndent.new + Reline.auto_indent_proc = lambda do |lines, line_index, byte_pointer, is_newline| + assert_auto_indent_params(lines, line_index, byte_pointer, is_newline) + AutoIndent.calculate_indent(lines, line_index, byte_pointer, is_newline) + end } opt.on('--dialog VAL') { |v| Reline.add_dialog_proc(:simple_dialog, lambda { @@ -98,7 +132,7 @@ opt.on('--dialog VAL') { |v| if v.include?('alt-scrollbar') scrollbar = true end - Reline::DialogRenderInfo.new(pos: cursor_pos, contents: contents, height: height, scrollbar: scrollbar) + Reline::DialogRenderInfo.new(pos: cursor_pos, contents: contents, height: height, scrollbar: scrollbar, face: :completion_dialog) }) if v.include?('alt-scrollbar') ENV['RELINE_ALT_SCROLLBAR'] = '1' @@ -109,12 +143,21 @@ opt.on('--complete') { %w{String ScriptError SyntaxError Signal}.select{ |c| c.start_with?(target) } } } +opt.on('--complete-menu-with-perfect-match') { + Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil| + %w{abs abs2}.select{ |c| c.start_with?(target) } + } +} opt.on('--autocomplete') { Reline.autocompletion = true Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil| %w{String Struct Symbol ScriptError SyntaxError Signal}.select{ |c| c.start_with?(target) } } } +opt.on('--autocomplete-empty') { + Reline.autocompletion = true + Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil| [] } +} opt.on('--autocomplete-long') { Reline.autocompletion = true Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil| @@ -145,7 +188,7 @@ opt.on('--autocomplete-long') { opt.on('--autocomplete-super-long') { Reline.autocompletion = true Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil| - c = 'A' + c = +'A' 2000.times.map{ s = "Str_#{c}"; c.succ!; s }.select{ |c| c.start_with?(target) } } } @@ -179,10 +222,9 @@ rescue end begin - prompt = ENV['RELINE_TEST_PROMPT'] || 'prompt> ' + prompt = ENV['RELINE_TEST_PROMPT'] || "\e[1mprompt>\e[m " puts 'Multiline REPL.' - checker = TerminationChecker.new - while code = Reline.readmultiline(prompt, true) { |code| checker.terminated?(code) } + while code = Reline.readmultiline(prompt, true) { |code| TerminationChecker.terminated?(code) } case code.chomp when 'exit', 'quit', 'q' exit 0 diff --git a/test/reline/yamatanooroti/termination_checker.rb b/test/reline/yamatanooroti/termination_checker.rb index 24fb24c4b1..b97c798c59 100644 --- a/test/reline/yamatanooroti/termination_checker.rb +++ b/test/reline/yamatanooroti/termination_checker.rb @@ -1,30 +1,26 @@ require 'ripper' -require 'irb/ruby-lex' -class TerminationChecker < RubyLex - def terminated?(code) - code.gsub!(/\n*$/, '').concat("\n") - @tokens = self.class.ripper_lex_without_warning(code) - continue = process_continue - code_block_open = check_code_block(code) - indent = process_nesting_level - ltype = process_literal_type - if code_block_open or ltype or continue or indent > 0 - false - else - true - end +module TerminationChecker + def self.terminated?(code) + Ripper.sexp(code) ? true : false end end -class AutoIndent < RubyLex - def initialize - set_input(self) - context = Struct.new(:auto_indent_mode, :workspace).new(true, nil) - set_auto_indent(context) +module AutoIndent + def self.calculate_indent(lines, line_index, byte_pointer, is_newline) + if is_newline + 2 * nesting_level(lines[0..line_index - 1]) + else + lines = lines.dup + lines[line_index] = lines[line_index]&.byteslice(0, byte_pointer) + prev_level = nesting_level(lines[0..line_index - 1]) + level = nesting_level(lines[0..line_index]) + 2 * level if level < prev_level + end end - def auto_indent(&block) - Reline.auto_indent_proc = block + def self.nesting_level(lines) + code = lines.join("\n") + code.scan(/if|def|\(|\[|\{/).size - code.scan(/end|\)|\]|\}/).size end end diff --git a/test/reline/yamatanooroti/test_rendering.rb b/test/reline/yamatanooroti/test_rendering.rb index c383112131..c90d3d6a7f 100644 --- a/test/reline/yamatanooroti/test_rendering.rb +++ b/test/reline/yamatanooroti/test_rendering.rb @@ -3,7 +3,34 @@ require 'reline' begin require 'yamatanooroti' - class Reline::TestRendering < Yamatanooroti::TestCase + class Reline::RenderingTest < Yamatanooroti::TestCase + + FACE_CONFIGS = { no_config: "", valid_config: <<~VALID_CONFIG, incomplete_config: <<~INCOMPLETE_CONFIG } + require "reline" + Reline::Face.config(:completion_dialog) do |face| + face.define :default, foreground: :white, background: :blue + face.define :enhanced, foreground: :white, background: :magenta + face.define :scrollbar, foreground: :white, background: :blue + end + VALID_CONFIG + require "reline" + Reline::Face.config(:completion_dialog) do |face| + face.define :default, foreground: :white, background: :black + face.define :scrollbar, foreground: :white, background: :cyan + end + INCOMPLETE_CONFIG + + def iterate_over_face_configs(&block) + FACE_CONFIGS.each do |config_name, face_config| + config_file = Tempfile.create(%w{face_config- .rb}) + config_file.write face_config + block.call(config_name, config_file) + config_file.close + ensure + File.delete(config_file) + end + end + def setup @pwd = Dir.pwd suffix = '%010d' % Random.rand(0..65535) @@ -170,9 +197,12 @@ begin LINES start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') write(":a\n\C-[k") + write("i\n:a") + write("\C-[h") close assert_screen(<<~EOC) - Multiline REPL. + (ins)prompt> :a + => :a (ins)prompt> :a => :a (cmd)prompt> :a @@ -237,6 +267,21 @@ begin EOC end + def test_esc_input + omit if Reline::IOGate.win? + start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') + write("def\C-aabc") + write("\e") # single ESC + sleep 1 + write("A") + write("B\eAC") # ESC + A (M-A, specified ed_unassigned in Reline::KeyActor::Emacs) + close + assert_screen(<<~EOC) + Multiline REPL. + prompt> abcABCdef + EOC + end + def test_prompt_with_escape_sequence ENV['RELINE_TEST_PROMPT'] = "\1\e[30m\2prompt> \1\e[m\2" start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') @@ -264,6 +309,21 @@ begin EOC end + def test_readline_with_multiline_input + start_terminal(5, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dynamic-prompt}, startup_message: 'Multiline REPL.') + write("def foo\n bar\nend\n") + write("Reline.readline('prompt> ')\n") + write("\C-p\C-p") + close + assert_screen(<<~EOC) + => :foo + [0000]> Reline.readline('prompt> ') + prompt> def foo + bar + end + EOC + end + def test_multiline_and_autowrap start_terminal(10, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') write("def aaaaaaaaaa\n 33333333\n end\C-a\C-pputs\C-e\e\C-m888888888888888") @@ -281,6 +341,23 @@ begin EOC end + def test_multiline_add_new_line_and_autowrap + start_terminal(10, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') + write("def aaaaaaaaaa") + write("\n") + write(" bbbbbbbbbbbb") + write("\n") + close + assert_screen(<<~EOC) + Multiline REPL. + prompt> def aaaaaaaa + aa + prompt> bbbbbbbbbb + bb + prompt> + EOC + end + def test_clear start_terminal(10, 15, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') write("3\C-l") @@ -405,6 +482,9 @@ begin write("def a\n 8\nend\ndef b\n 3\nend\C-s8") close assert_screen(<<~EOC) + prompt> 8 + prompt> end + => :a (i-search)`8'def a (i-search)`8' 8 (i-search)`8'end @@ -416,6 +496,9 @@ begin write("def a\n 8\nend\ndef b\n 3\nend\C-r8\C-j") close assert_screen(<<~EOC) + prompt> 8 + prompt> end + => :a prompt> def a prompt> 8 prompt> end @@ -436,39 +519,34 @@ begin EOC end - def test_prompt_list_caching - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --prompt-list-cache-timeout 10 --dynamic-prompt}, startup_message: 'Multiline REPL.') + def test_broken_prompt_list + start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --broken-dynamic-prompt}, startup_message: 'Multiline REPL.') write("def hoge\n 3\nend") close assert_screen(<<~EOC) Multiline REPL. [0000]> def hoge [0001]> 3 - [0002]> end + [0001]> end EOC end - def test_broken_prompt_list - start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --broken-dynamic-prompt}, startup_message: 'Multiline REPL.') - write("def hoge\n 3\nend") + def test_no_escape_sequence_passed_to_dynamic_prompt + start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete --color-bold --broken-dynamic-prompt-assert-no-escape-sequence}, startup_message: 'Multiline REPL.') + write("%[ S") + write("\n") close assert_screen(<<~EOC) Multiline REPL. - [0000]> def hoge - [0001]> 3 - [0001]> end + [0000]> %[ S + [0001]> EOC end - def test_enable_bracketed_paste - omit if Reline::IOGate.win? - write_inputrc <<~LINES - set enable-bracketed-paste on - LINES + def test_bracketed_paste + omit if Reline.core.io_gate.win? start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') - write("\e[200~,") - write("def hoge\n 3\nend") - write("\e[200~.") + write("\e[200~def hoge\r\t3\rend\e[201~") close assert_screen(<<~EOC) Multiline REPL. @@ -478,6 +556,35 @@ begin EOC end + def test_bracketed_paste_with_undo + omit if Reline.core.io_gate.win? + start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') + write("abc") + write("\e[200~def hoge\r\t3\rend\e[201~") + write("\C-_") + close + assert_screen(<<~EOC) + Multiline REPL. + prompt> abc + EOC + end + + def test_bracketed_paste_with_redo + omit if Reline.core.io_gate.win? + start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') + write("abc") + write("\e[200~def hoge\r\t3\rend\e[201~") + write("\C-_") + write("\M-\C-_") + close + assert_screen(<<~EOC) + Multiline REPL. + prompt> abcdef hoge + prompt> 3 + prompt> end + EOC + end + def test_backspace_until_returns_to_initial start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') write("ABC") @@ -632,6 +739,31 @@ begin EOC end + def test_longer_than_screen_height_nearest_cursor_with_scroll_back + start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') + write(<<~EOC.chomp) + if 1 + if 2 + if 3 + if 4 + puts + end + end + end + end + EOC + write("\C-p" * 4 + "\C-e" + "\C-p" * 4) + write("2") + close + assert_screen(<<~EOC) + prompt> if 12 + prompt> if 2 + prompt> if 3 + prompt> if 4 + prompt> puts + EOC + end + def test_update_cursor_correctly_when_just_cursor_moving start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') write("def hoge\n 01234678") @@ -649,6 +781,66 @@ begin EOC end + def test_auto_indent + start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.') + "def hoge\nputs(\n1,\n2\n)\nend".lines do |line| + write line + end + close + assert_screen(<<~EOC) + Multiline REPL. + prompt> def hoge + prompt> puts( + prompt> 1, + prompt> 2 + prompt> ) + prompt> end + EOC + end + + def test_auto_indent_when_inserting_line + start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.') + write 'aa(bb(cc(dd(ee(' + write "\C-b" * 5 + "\n" + close + assert_screen(<<~EOC) + Multiline REPL. + prompt> aa(bb(cc(d + prompt> d(ee( + EOC + end + + def test_auto_indent_multibyte_insert_line + start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.') + write "if true\n" + write "あいうえお\n" + 4.times { write "\C-b\C-b\C-b\C-b\e\r" } + close + assert_screen(<<~EOC) + Multiline REPL. + prompt> if true + prompt> あ + prompt> い + prompt> う + prompt> え + prompt> お + prompt> + EOC + end + + def test_newline_after_wrong_indent + start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.') + write "if 1\n aa" + write "\n" + close + assert_screen(<<~EOC) + Multiline REPL. + prompt> if 1 + prompt> aa + prompt> + EOC + end + def test_suppress_auto_indent_just_after_pasted start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.') write("def hoge\n [[\n 3]]\ned") @@ -678,6 +870,20 @@ begin EOC end + def test_auto_indent_with_various_spaces + start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.') + write "(\n\C-v" + write "\C-k\n\C-v" + write "\C-k)" + close + assert_screen(<<~EOC) + Multiline REPL. + prompt> ( + prompt> ^K + prompt> ) + EOC + end + def test_autowrap_in_the_middle_of_a_line start_terminal(5, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') write("def abcdefg; end\C-b\C-b\C-b\C-b\C-b") @@ -763,18 +969,42 @@ begin EOC end - def test_with_newline - omit if Reline::IOGate.win? + def test_nontty + omit if Reline.core.io_gate.win? + cmd = %Q{ruby -e 'puts(%Q{ello\C-ah\C-e})' | ruby -I#{@pwd}/lib -rreline -e 'p Reline.readline(%{> })' | ruby -e 'print STDIN.read'} + start_terminal(40, 50, ['bash', '-c', cmd]) + sleep 1 + close rescue nil + assert_screen(<<~'EOC') + > hello + "hello" + EOC + end + + def test_eof_with_newline + omit if Reline.core.io_gate.win? cmd = %Q{ruby -e 'print(%Q{abc def \\e\\r})' | ruby -I#{@pwd}/lib -rreline -e 'p Reline.readline(%{> })'} start_terminal(40, 50, ['bash', '-c', cmd]) sleep 1 - close + close rescue nil assert_screen(<<~'EOC') > abc def "abc def " EOC end + def test_eof_without_newline + omit if Reline.core.io_gate.win? + cmd = %Q{ruby -e 'print(%{hello})' | ruby -I#{@pwd}/lib -rreline -e 'p Reline.readline(%{> })'} + start_terminal(40, 50, ['bash', '-c', cmd]) + sleep 1 + close rescue nil + assert_screen(<<~'EOC') + > hello + "hello" + EOC + end + def test_em_set_mark_and_em_exchange_mark start_terminal(10, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') write("aaa bbb ccc ddd\M-b\M-b\M-\x20\M-b\C-x\C-xX\C-x\C-xY") @@ -785,6 +1015,18 @@ begin EOC end + def test_multiline_completion + start_terminal(10, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete}, startup_message: 'Multiline REPL.') + write("def hoge\n St\n St\C-p\t") + close + assert_screen(<<~'EOC') + Multiline REPL. + prompt> def hoge + prompt> String + prompt> St + EOC + end + def test_completion_journey_2nd_line write_inputrc <<~LINES set editing-mode vi @@ -812,44 +1054,127 @@ begin EOC end - def test_simple_dialog - start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple}, startup_message: 'Multiline REPL.') - write('a') - write('b') - write('c') - write("\C-h") + def test_completion_menu_is_displayed_horizontally + start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete}, startup_message: 'Multiline REPL.') + write("S\t\t") close assert_screen(<<~'EOC') Multiline REPL. - prompt> ab - Ruby is... - A dynamic, open source programming - language with a focus on simplicity - and productivity. It has an elegant - syntax that is natural to read and - easy to write. + prompt> S + ScriptError String + Signal SyntaxError EOC end - def test_simple_dialog_at_right_edge - start_terminal(20, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple}, startup_message: 'Multiline REPL.') - write('a') - write('b') - write('c') - write("\C-h") + def test_show_all_if_ambiguous_on + write_inputrc <<~LINES + set show-all-if-ambiguous on + LINES + start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete}, startup_message: 'Multiline REPL.') + write("S\t") + close + assert_screen(<<~'EOC') + Multiline REPL. + prompt> S + ScriptError String + Signal SyntaxError + EOC + end + + def test_show_all_if_ambiguous_on_and_menu_with_perfect_match + write_inputrc <<~LINES + set show-all-if-ambiguous on + LINES + start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --complete-menu-with-perfect-match}, startup_message: 'Multiline REPL.') + write("a\t") close assert_screen(<<~'EOC') Multiline REPL. - prompt> ab - Ruby is... - A dynamic, open source programming - language with a focus on simplicity - and productivity. It has an elegant - syntax that is natural to read and - easy to write. + prompt> abs + abs abs2 EOC end + def test_simple_dialog + iterate_over_face_configs do |config_name, config_file| + start_terminal(20, 50, %W{ruby -I#{@pwd}/lib -r#{config_file.path} #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple}, startup_message: 'Multiline REPL.') + write('a') + write('b') + write('c') + write("\C-h") + close + assert_screen(<<~'EOC', "Failed with `#{config_name}` in Face") + Multiline REPL. + prompt> ab + Ruby is... + A dynamic, open source programming + language with a focus on simplicity + and productivity. It has an elegant + syntax that is natural to read and + easy to write. + EOC + end + end + + def test_simple_dialog_at_right_edge + iterate_over_face_configs do |config_name, config_file| + start_terminal(20, 40, %W{ruby -I#{@pwd}/lib -r#{config_file.path} #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple}, startup_message: 'Multiline REPL.') + write('a') + write('b') + write('c') + write("\C-h") + close + assert_screen(<<~'EOC') + Multiline REPL. + prompt> ab + Ruby is... + A dynamic, open source programming + language with a focus on simplicity + and productivity. It has an elegant + syntax that is natural to read and + easy to write. + EOC + end + end + + def test_dialog_scroll_pushup_condition + iterate_over_face_configs do |config_name, config_file| + start_terminal(10, 50, %W{ruby -I#{@pwd}/lib -r#{config_file.path} #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') + write("\n" * 10) + write("if 1\n sSts\nend") + write("\C-p\C-h\C-e\C-h") + close + assert_screen(<<~'EOC') + prompt> + prompt> + prompt> + prompt> + prompt> + prompt> + prompt> if 1 + prompt> St + prompt> enString + Struct + EOC + end + end + + def test_simple_dialog_with_scroll_screen + iterate_over_face_configs do |config_name, config_file| + start_terminal(5, 50, %W{ruby -I#{@pwd}/lib -r#{config_file.path} #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog simple}, startup_message: 'Multiline REPL.') + write("if 1\n 2\n 3\n 4\n 5\n 6") + write("\C-p\C-n\C-p\C-p\C-p#") + close + assert_screen(<<~'EOC') + prompt> 2 + prompt> 3# + prompt> 4 + prompt> 5 Ruby is... + prompt> 6 A dynamic, open source programming + EOC + end + end + def test_autocomplete_at_bottom start_terminal(15, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') write('def hoge' + "\C-m" * 10 + "end\C-p ") @@ -896,11 +1221,53 @@ begin assert_screen(<<~'EOC') Multiline REPL. prompt> St - r String + r + String + Struct + EOC + end + + def test_autocomplete_target_at_end_of_line + start_terminal(20, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') + write(' ') + write('Str') + write("\C-i") + close + assert_screen(<<~'EOC') + Multiline REPL. + prompt> Str + ing String + Struct + EOC + end + + def test_autocomplete_completed_input_is_wrapped + start_terminal(20, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') + write(' ') + write('Str') + write("\C-i") + close + assert_screen(<<~'EOC') + Multiline REPL. + prompt> Stri + ng String Struct EOC end + def test_force_insert_before_autocomplete + start_terminal(20, 20, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') + write('Sy') + write(";St\t\t") + close + assert_screen(<<~'EOC') + Multiline REPL. + prompt> Sy;Struct + String + Struct + EOC + end + def test_simple_dialog_with_scroll_key start_terminal(20, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog long,scrollkey}, startup_message: 'Multiline REPL.') write('a') @@ -1003,6 +1370,32 @@ begin EOC end + def test_autocomplete_empty_string + start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') + write("\C-i") + close + assert_screen(<<~'EOC') + Multiline REPL. + prompt> String + String █ + Struct ▀ + Symbol + EOC + end + + def test_paste_code_with_tab_indent_does_not_fail + start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-empty}, startup_message: 'Multiline REPL.') + write("2.times do\n\tputs\n\tputs\nend") + close + assert_screen(<<~'EOC') + Multiline REPL. + prompt> 2.times do + prompt> puts + prompt> puts + prompt> end + EOC + end + def test_autocomplete_after_2nd_line start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') write("def hoge\n Str") @@ -1031,6 +1424,23 @@ begin EOC end + def test_rerender_multiple_dialog + start_terminal(20, 60, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete --dialog simple}, startup_message: 'Multiline REPL.') + write("if\n abcdef\n 123456\n 456789\nend\C-p\C-p\C-p\C-p Str") + write("\t") + close + assert_screen(<<~'EOC') + Multiline REPL. + prompt> if String + prompt> aStringRuby is... + prompt> 1StructA dynamic, open source programming + prompt> 456789 language with a focus on simplicity + prompt> end and productivity. It has an elegant + syntax that is natural to read and + easy to write. + EOC + end + def test_autocomplete_long_with_scrollbar start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-long}, startup_message: 'Multiline REPL.') write('S') @@ -1081,6 +1491,32 @@ begin EOC end + def test_autocomplete_super_long_scroll_to_bottom + start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-super-long}, startup_message: 'Multiline REPL.') + shift_tab = [27, 91, 90] + write('S' + shift_tab.map(&:chr).join) + close + assert_screen(<<~'EOC') + Multiline REPL. + prompt> Str_BXX + Str_BXJ + Str_BXK + Str_BXL + Str_BXM + Str_BXN + Str_BXO + Str_BXP + Str_BXQ + Str_BXR + Str_BXS + Str_BXT + Str_BXU + Str_BXV + Str_BXW + Str_BXX▄ + EOC + end + def test_autocomplete_super_long_and_backspace start_terminal(20, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete-super-long}, startup_message: 'Multiline REPL.') shift_tab = [27, 91, 90] @@ -1090,15 +1526,15 @@ begin assert_screen(<<~'EOC') Multiline REPL. prompt> Str_BX - Str_BX - Str_BXA - Str_BXB - Str_BXC - Str_BXD - Str_BXE - Str_BXF - Str_BXG - Str_BXH + Str_BX █ + Str_BXA█ + Str_BXB█ + Str_BXC█ + Str_BXD█ + Str_BXE█ + Str_BXF█ + Str_BXG█ + Str_BXH█ Str_BXI Str_BXJ Str_BXK @@ -1142,7 +1578,7 @@ begin Multiline R EPL. prompt> Sym - String + String █ Struct █ Symbol █ StopIterat█ @@ -1201,21 +1637,21 @@ begin def test_scroll_at_bottom_for_dialog start_terminal(10, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') - write("\n\n\n\n\n\n") - write("def hoge\n\n\n\n\n\n\nend\C-p\C-p\C-p\C-e") + write("\n\n\n\n\n\n\n\n\n\n\n") + write("def hoge\n\nend\C-p\C-e") write(" S") close assert_screen(<<~'EOC') - prompt> def hoge prompt> prompt> prompt> + prompt> + prompt> + prompt> def hoge prompt> S - prompt> String - prompt> Struct - prompt> enSymbol - ScriptError - Signal + prompt> enString █ + Struct ▀ + Symbol EOC end @@ -1255,32 +1691,49 @@ begin EOC end + def test_lines_passed_to_dynamic_prompt + start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dynamic-prompt-show-line}, startup_message: 'Multiline REPL.') + write("if true") + write("\n") + close + assert_screen(<<~EOC) + Multiline REPL. + [if t]> if true + [ ]> + EOC + end + def test_clear_dialog_when_just_move_cursor_at_last_line start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') - write("class A\n 3\nend\n") - write("\C-p\C-p\C-p\C-e\C-hS") + write("class A\n 3\nend\n\n\n") + write("\C-p\C-p\C-e; S") write("\C-n") - write("1") + write(";") close assert_screen(<<~'EOC') prompt> 3 prompt> end => 3 - prompt> class S - prompt> 31 - prompt> end + prompt> + prompt> + prompt> class A + prompt> 3; S + prompt> end; EOC end def test_clear_dialog_when_adding_new_line_to_end_of_buffer start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') - write("class A\n def a\n 3\n end\nend") + write("class A\n def a\n 3\n 3\n end\nend") write("\n") write("class S") write("\n") write(" 3") close assert_screen(<<~'EOC') + prompt> def a + prompt> 3 + prompt> 3 prompt> end prompt> end => :a @@ -1298,6 +1751,7 @@ begin write(" 3") close assert_screen(<<~'EOC') + prompt> 3 prompt> end prompt> end => :a @@ -1333,6 +1787,130 @@ begin EOC end + def test_bracket_newline_indent + start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.') + write("[\n") + write("1") + close + assert_screen(<<~EOC) + Multiline REPL. + prompt> [ + prompt> 1 + EOC + end + + def test_repeated_input_delete + start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') + write("a\C-h" * 4000) + close + assert_screen(<<~'EOC') + Multiline REPL. + prompt> + EOC + end + + def test_exit_with_ctrl_d + start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.') + begin + write("\C-d") + close + rescue EOFError + # EOFError is raised when process terminated. + end + assert_screen(<<~EOC) + Multiline REPL. + prompt> + EOC + end + + def test_print_before_readline + code = <<~RUBY + puts 'Multiline REPL.' + 2.times do + print 'a' * 10 + Reline.readline '>' + end + RUBY + start_terminal(6, 30, ['ruby', "-I#{@pwd}/lib", '-rreline', '-e', code], startup_message: 'Multiline REPL.') + write "x\n" + close + assert_screen(<<~EOC) + Multiline REPL. + >x + > + EOC + end + + def test_pre_input_hook_with_redisplay + code = <<~'RUBY' + puts 'Multiline REPL.' + Reline.pre_input_hook = -> do + Reline.insert_text 'abc' + Reline.redisplay # Reline doesn't need this but Readline requires calling redisplay + end + Reline.readline('prompt> ') + RUBY + start_terminal(6, 30, ['ruby', "-I#{@pwd}/lib", '-rreline', '-e', code], startup_message: 'Multiline REPL.') + assert_screen(<<~EOC) + Multiline REPL. + prompt> abc + EOC + end + + def test_pre_input_hook_with_multiline_text_insert + # Frequently used pattern of pre_input_hook + code = <<~'RUBY' + puts 'Multiline REPL.' + Reline.pre_input_hook = -> do + Reline.insert_text "abc\nef" + end + Reline.readline('>') + RUBY + start_terminal(6, 30, ['ruby', "-I#{@pwd}/lib", '-rreline', '-e', code], startup_message: 'Multiline REPL.') + write("\C-ad") + assert_screen(<<~EOC) + Multiline REPL. + >abc + def + EOC + end + + def test_thread_safe + start_terminal(6, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --auto-indent}, startup_message: 'Multiline REPL.') + write("[Thread.new{Reline.readline'>'},Thread.new{Reline.readmultiline('>'){true}}].map(&:join).size\n") + write("exit\n") + write("exit\n") + write("42\n") + close + assert_screen(<<~EOC) + >exit + >exit + => 2 + prompt> 42 + => 42 + prompt> + EOC + end + + def test_stop_continue + pidfile = Tempfile.create('pidfile') + rubyfile = Tempfile.create('rubyfile') + rubyfile.write <<~RUBY + File.write(#{pidfile.path.inspect}, Process.pid) + p Reline.readmultiline('>'){false} + RUBY + rubyfile.close + start_terminal(40, 50, ['bash']) + write "ruby -I#{@pwd}/lib -rreline #{rubyfile.path}\n" + write "abc\ndef\nhi" + pid = pidfile.tap(&:rewind).read.to_i + Process.kill(:STOP, pid) unless pid.zero? + write "fg\n" + write "\ebg" + close + assert_include result.join("\n"), ">abc\n>def\n>ghi\n" + end + def write_inputrc(content) File.open(@inputrc_file, 'w') do |f| f.write content |