diff --git a/lib/reline.rb b/lib/reline.rb index fb00b96531..ca4d4d9058 100644 --- a/lib/reline.rb +++ b/lib/reline.rb @@ -17,19 +17,9 @@ module Reline class ConfigEncodingConversionError < StandardError; end - Key = Struct.new(:char, :combined_char, :with_meta) do - def match?(other) - case other - when Reline::Key - (other.char.nil? or char.nil? or char == other.char) and - (other.combined_char.nil? or combined_char.nil? or combined_char == other.combined_char) and - (other.with_meta.nil? or with_meta.nil? or with_meta == other.with_meta) - when Integer, Symbol - (combined_char and combined_char == other) or - (combined_char.nil? and char and char == other) - else - false - end + Key = Struct.new(:char, :method_symbol, :bytes) do + def match?(sym) + method_symbol == sym end alias_method :==, :match? end @@ -349,24 +339,22 @@ def readline(prompt = '', add_hist = false) begin line_editor.set_signal_handlers loop do - read_io(config.keyseq_timeout) { |inputs| - line_editor.set_pasting_state(io_gate.in_pasting?) - inputs.each do |key| - if key.char == :bracketed_paste_start - text = io_gate.read_bracketed_paste - line_editor.insert_pasted_text(text) - line_editor.scroll_into_view - else - line_editor.update(key) - end - end + wait_occurs = false + key = read_io(config.keyseq_timeout) { + line_editor.set_pasting_state(false) + wait_occurs = true + line_editor.rerender } + line_editor.set_pasting_state(!wait_occurs && io_gate.in_pasting?) + if key.method_symbol == :bracketed_paste_start + line_editor.insert_pasted_text(io_gate.read_bracketed_paste) + line_editor.scroll_into_view + else + line_editor.update(key) + end if line_editor.finished? line_editor.render_finished break - else - line_editor.set_pasting_state(io_gate.in_pasting?) - line_editor.rerender end end io_gate.move_cursor_column(0) @@ -378,92 +366,41 @@ def readline(prompt = '', add_hist = false) end end - # GNU Readline waits for "keyseq-timeout" milliseconds to see if the ESC - # is followed by a character, and times out and treats it as a standalone - # ESC if the second character does not arrive. If the second character - # comes before timed out, it is treated as a modifier key with the - # meta-property of meta-key, so that it can be distinguished from - # multibyte characters with the 8th bit turned on. - # - # GNU Readline will wait for the 2nd character with "keyseq-timeout" - # milli-seconds but wait forever after 3rd characters. + # GNU Readline waits for "keyseq-timeout" milliseconds when the input is ambiguous whether it is matching or matched. + # For example, ESC can be a standalone ESC or part of a sequence that starts with ESC. + # GNU Readline also waits for any other amibugous keybindings defined in inputrc. private def read_io(keyseq_timeout, &block) buffer = [] + prev_status = :matching loop do - c = io_gate.getc(Float::INFINITY) - if c == -1 - result = :unmatched + timeout = prev_status == :matching_matched ? keyseq_timeout.fdiv(1000) : Float::INFINITY + block.call unless io_gate.in_pasting? + c = io_gate.getc(timeout) + if c == -1 || c.nil? + if prev_status != :matching_matched + # Input closed + return Reline::Key.new(nil, nil, []) + end + status = :matched else buffer << c - result = key_stroke.match_status(buffer) + status = key_stroke.match_status(buffer) end - case result - when :matched - expanded = key_stroke.expand(buffer).map{ |expanded_c| - Reline::Key.new(expanded_c, expanded_c, false) - } - block.(expanded) - break - when :matching - if buffer.size == 1 - case read_2nd_character_of_key_sequence(keyseq_timeout, buffer, c, block) - when :break then break - when :next then next - end + if status == :matched || (prev_status != :unmatched && status == :unmatched) + expanded, bytes, rest = key_stroke.expand(buffer) + if expanded.is_a?(Array) + rest = expanded + rest end - when :unmatched - if buffer.size == 1 and c == "\e".ord - read_escaped_key(keyseq_timeout, c, block) - else - expanded = buffer.map{ |expanded_c| - Reline::Key.new(expanded_c, expanded_c, false) - } - block.(expanded) + rest.reverse_each { |c| io_gate.ungetc(c) } + buffer = [] + case expanded + when Symbol + return Reline::Key.new(bytes.last, expanded, bytes) + when String + return Reline::Key.new(expanded, :ed_insert, bytes) end - break end - end - end - - private def read_2nd_character_of_key_sequence(keyseq_timeout, buffer, c, block) - succ_c = io_gate.getc(keyseq_timeout.fdiv(1000)) - if succ_c - case key_stroke.match_status(buffer.dup.push(succ_c)) - when :unmatched - if c == "\e".ord - block.([Reline::Key.new(succ_c, succ_c | 0b10000000, true)]) - else - block.([Reline::Key.new(c, c, false), Reline::Key.new(succ_c, succ_c, false)]) - end - return :break - when :matching - io_gate.ungetc(succ_c) - return :next - when :matched - buffer << succ_c - expanded = key_stroke.expand(buffer).map{ |expanded_c| - Reline::Key.new(expanded_c, expanded_c, false) - } - block.(expanded) - return :break - end - else - block.([Reline::Key.new(c, c, false)]) - return :break - end - end - - private def read_escaped_key(keyseq_timeout, c, block) - escaped_c = io_gate.getc(keyseq_timeout.fdiv(1000)) - - if escaped_c.nil? - block.([Reline::Key.new(c, c, false)]) - elsif escaped_c >= 128 # maybe, first byte of multi byte - block.([Reline::Key.new(c, c, false), Reline::Key.new(escaped_c, escaped_c, false)]) - elsif escaped_c == "\e".ord # escape twice - block.([Reline::Key.new(c, c, false), Reline::Key.new(c, c, false)]) - else - block.([Reline::Key.new(escaped_c, escaped_c | 0b10000000, true)]) + prev_status = status end end @@ -547,7 +484,7 @@ def self.encoding_system_needs def self.core @core ||= Core.new { |core| core.config = Reline::Config.new - core.key_stroke = Reline::KeyStroke.new(core.config) + core.key_stroke = Reline::KeyStroke.new(core.config, core.encoding) core.line_editor = Reline::LineEditor.new(core.config, core.encoding) core.basic_word_break_characters = " \t\n`><=;|&{(" diff --git a/lib/reline/config.rb b/lib/reline/config.rb index 62c6d105b3..7bf974bb1b 100644 --- a/lib/reline/config.rb +++ b/lib/reline/config.rb @@ -30,17 +30,20 @@ class InvalidInputrc < RuntimeError def initialize @additional_key_bindings = {} # from inputrc - @additional_key_bindings[:emacs] = {} - @additional_key_bindings[:vi_insert] = {} - @additional_key_bindings[:vi_command] = {} - @oneshot_key_bindings = {} + @additional_key_bindings[:emacs] = Reline::KeyActor::Base.new + @additional_key_bindings[:vi_insert] = Reline::KeyActor::Base.new + @additional_key_bindings[:vi_command] = Reline::KeyActor::Base.new + @oneshot_key_bindings = Reline::KeyActor::Base.new @editing_mode_label = :emacs @keymap_label = :emacs @keymap_prefix = [] @key_actors = {} - @key_actors[:emacs] = Reline::KeyActor::Emacs.new - @key_actors[:vi_insert] = Reline::KeyActor::ViInsert.new - @key_actors[:vi_command] = Reline::KeyActor::ViCommand.new + @key_actors[:emacs] = Reline::KeyActor::Base.new + @key_actors[:vi_insert] = Reline::KeyActor::Base.new + @key_actors[:vi_command] = Reline::KeyActor::Base.new + @key_actors[:emacs].add_mappings(Reline::KeyActor::EMACS_MAPPING) + @key_actors[:vi_insert].add_mappings(Reline::KeyActor::VI_INSERT_MAPPING) + @key_actors[:vi_command].add_mappings(Reline::KeyActor::VI_COMMAND_MAPPING) @vi_cmd_mode_string = '(cmd)' @vi_ins_mode_string = '(ins)' @emacs_mode_string = '@' @@ -62,7 +65,7 @@ def reset end def editing_mode - @key_actors[@editing_mode_label] + @editing_mode_label end def editing_mode=(val) @@ -73,10 +76,6 @@ def editing_mode_is?(*val) val.any?(@editing_mode_label) end - def keymap - @key_actors[@keymap_label] - end - def loaded? @loaded end @@ -133,14 +132,14 @@ def read(file = nil) def key_bindings # The key bindings for each editing mode will be overwritten by the user-defined ones. - kb = @key_actors[@editing_mode_label].default_key_bindings.dup - kb.merge!(@additional_key_bindings[@editing_mode_label]) - kb.merge!(@oneshot_key_bindings) - kb + Reline::KeyActor::Composite.new([@oneshot_key_bindings, @additional_key_bindings[@editing_mode_label], @key_actors[@editing_mode_label]]) end def add_oneshot_key_binding(keystroke, target) - @oneshot_key_bindings[keystroke] = target + # Old IRB sets invalid keystroke [Reline::Key]. We should ignore it. + return unless keystroke.all? { |c| c.is_a?(Integer) } + + @oneshot_key_bindings.add(keystroke, target) end def reset_oneshot_key_bindings @@ -148,11 +147,11 @@ def reset_oneshot_key_bindings end def add_default_key_binding_by_keymap(keymap, keystroke, target) - @key_actors[keymap].default_key_bindings[keystroke] = target + @key_actors[keymap].add(keystroke, target) end def add_default_key_binding(keystroke, target) - @key_actors[@keymap_label].default_key_bindings[keystroke] = target + @key_actors[@keymap_label].add(keystroke, target) end def read_lines(lines, file = nil) @@ -192,7 +191,7 @@ def read_lines(lines, file = nil) func_name = func_name.split.first keystroke, func = bind_key(key, func_name) next unless keystroke - @additional_key_bindings[@keymap_label][@keymap_prefix + keystroke] = func + @additional_key_bindings[@keymap_label].add(@keymap_prefix + keystroke, func) end end unless if_stack.empty? diff --git a/lib/reline/key_actor.rb b/lib/reline/key_actor.rb index ebe09d2009..0ac7604556 100644 --- a/lib/reline/key_actor.rb +++ b/lib/reline/key_actor.rb @@ -2,6 +2,7 @@ module Reline::KeyActor end require 'reline/key_actor/base' +require 'reline/key_actor/composite' require 'reline/key_actor/emacs' require 'reline/key_actor/vi_command' require 'reline/key_actor/vi_insert' diff --git a/lib/reline/key_actor/base.rb b/lib/reline/key_actor/base.rb index 194e98938c..6d5414b1e1 100644 --- a/lib/reline/key_actor/base.rb +++ b/lib/reline/key_actor/base.rb @@ -1,15 +1,36 @@ class Reline::KeyActor::Base - MAPPING = Array.new(256) + def initialize + @matching_bytes = {} + @key_bindings = {} + end - def get_method(key) - self.class::MAPPING[key] + def add_mappings(mappings) + add([27], :ed_ignore) + 128.times do |key| + func = mappings[key] + meta_func = mappings[key | 0b10000000] + add([key], func) unless func == :ed_unassigned + add([27, key], meta_func) unless meta_func == :ed_unassigned + end end - def initialize - @default_key_bindings = {} + def add(key, func) + (1...key.size).each do |size| + @matching_bytes[key.take(size)] = true + end + @key_bindings[key] = func + end + + def matching?(key) + @matching_bytes[key] + end + + def get(key) + @key_bindings[key] end - def default_key_bindings - @default_key_bindings + def clear + @matching_bytes.clear + @key_bindings.clear end end diff --git a/lib/reline/key_actor/composite.rb b/lib/reline/key_actor/composite.rb new file mode 100644 index 0000000000..37e94ce6cf --- /dev/null +++ b/lib/reline/key_actor/composite.rb @@ -0,0 +1,17 @@ +class Reline::KeyActor::Composite + def initialize(key_actors) + @key_actors = key_actors + end + + def matching?(key) + @key_actors.any? { |key_actor| key_actor.matching?(key) } + end + + def get(key) + @key_actors.each do |key_actor| + func = key_actor.get(key) + return func if func + end + nil + end +end diff --git a/lib/reline/key_actor/emacs.rb b/lib/reline/key_actor/emacs.rb index edd88289a3..6c4fa0d1b2 100644 --- a/lib/reline/key_actor/emacs.rb +++ b/lib/reline/key_actor/emacs.rb @@ -1,5 +1,5 @@ -class Reline::KeyActor::Emacs < Reline::KeyActor::Base - MAPPING = [ +module Reline::KeyActor + EMACS_MAPPING = [ # 0 ^@ :em_set_mark, # 1 ^A diff --git a/lib/reline/key_actor/vi_command.rb b/lib/reline/key_actor/vi_command.rb index 06bb0ba8e4..d972c5e67f 100644 --- a/lib/reline/key_actor/vi_command.rb +++ b/lib/reline/key_actor/vi_command.rb @@ -1,5 +1,5 @@ -class Reline::KeyActor::ViCommand < Reline::KeyActor::Base - MAPPING = [ +module Reline::KeyActor + VI_COMMAND_MAPPING = [ # 0 ^@ :ed_unassigned, # 1 ^A diff --git a/lib/reline/key_actor/vi_insert.rb b/lib/reline/key_actor/vi_insert.rb index f8ccf468c6..312df1646b 100644 --- a/lib/reline/key_actor/vi_insert.rb +++ b/lib/reline/key_actor/vi_insert.rb @@ -1,5 +1,5 @@ -class Reline::KeyActor::ViInsert < Reline::KeyActor::Base - MAPPING = [ +module Reline::KeyActor + VI_INSERT_MAPPING = [ # 0 ^@ :ed_unassigned, # 1 ^A diff --git a/lib/reline/key_stroke.rb b/lib/reline/key_stroke.rb index bceffbb53f..a3b993f7d2 100644 --- a/lib/reline/key_stroke.rb +++ b/lib/reline/key_stroke.rb @@ -3,143 +3,80 @@ class Reline::KeyStroke CSI_PARAMETER_BYTES_RANGE = 0x30..0x3f CSI_INTERMEDIATE_BYTES_RANGE = (0x20..0x2f) - def initialize(config) + def initialize(config, encoding) @config = config + @encoding = encoding end - def compress_meta_key(ary) - return ary unless @config.convert_meta - ary.inject([]) { |result, key| - if result.size > 0 and result.last == "\e".ord - result[result.size - 1] = Reline::Key.new(key, key | 0b10000000, true) - else - result << key - end - result - } - end - - def start_with?(me, other) - compressed_me = compress_meta_key(me) - compressed_other = compress_meta_key(other) - i = 0 - loop do - my_c = compressed_me[i] - other_c = compressed_other[i] - other_is_last = (i + 1) == compressed_other.size - me_is_last = (i + 1) == compressed_me.size - if my_c != other_c - if other_c == "\e".ord and other_is_last and my_c.is_a?(Reline::Key) and my_c.with_meta - return true - else - return false - end - elsif other_is_last - return true - elsif me_is_last - return false - end - i += 1 - end - end - - def equal?(me, other) - case me - when Array - compressed_me = compress_meta_key(me) - compressed_other = compress_meta_key(other) - compressed_me.size == compressed_other.size and [compressed_me, compressed_other].transpose.all?{ |i| equal?(i[0], i[1]) } - when Integer - if other.is_a?(Reline::Key) - if other.combined_char == "\e".ord - false - else - other.combined_char == me - end - else - me == other - end - when Reline::Key - if other.is_a?(Integer) - me.combined_char == other + def match_status(input) + matched = key_mapping.get(input) + if key_mapping.matching?(input) + matched ? :matching_matched : :matching + elsif matched + :matched + elsif input[0] == ESC_BYTE + match_unknown_escape_sequence(input, vi_mode: @config.editing_mode_is?(:vi_insert, :vi_command)) + else + s = input.map(&:chr).join.force_encoding(@encoding) + if s.valid_encoding? + s.size == 1 ? :matched : :unmatched else - me == other + # invalid byte sequence can be matching (part of multi-byte character) or matched (broken input to be ignored) + :matching_matched end end end - def match_status(input) - key_mapping.keys.select { |lhs| - start_with?(lhs, input) - }.tap { |it| - return :matched if it.size == 1 && equal?(it[0], input) - return :matching if it.size == 1 && !equal?(it[0], input) - return :matched if it.max_by(&:size)&.size&.< input.size - return :matching if it.size > 1 - } - if key_mapping.keys.any? { |lhs| start_with?(input, lhs) } - :matched - else - match_unknown_escape_sequence(input).first - end + def valid_char_bytes?(bytes) + bytes.map(&:chr).join.force_encoding(@encoding) end def expand(input) - lhs = key_mapping.keys.select { |item| start_with?(input, item) }.sort_by(&:size).last - unless lhs - status, size = match_unknown_escape_sequence(input) - case status + matched_bytes = [] + (1..input.size).each do |i| + bytes = input.take(i) + case match_status(bytes) when :matched - return [:ed_unassigned] + expand(input.drop(size)) - when :matching - return [:ed_unassigned] - else - return input + matched_bytes = bytes + break + when :matching_matched + matched_bytes = bytes end end - rhs = key_mapping[lhs] - case rhs - when String - rhs_bytes = rhs.bytes - expand(expand(rhs_bytes) + expand(input.drop(lhs.size))) - when Symbol - [rhs] + expand(input.drop(lhs.size)) - when Array - rhs - end + func = key_mapping.get(matched_bytes) + return [func, matched_bytes, input.drop(matched_bytes.size)] if func || matched_bytes[0] == ESC_BYTE + + s = input.map(&:chr).join.force_encoding(@encoding) + s = nil unless s.valid_encoding? + [s, input, []] end private - # returns match status of CSI/SS3 sequence and matched length - def match_unknown_escape_sequence(input) + # returns match status of CSI/SS3 sequence + def match_unknown_escape_sequence(input, vi_mode: false) idx = 0 - return [:unmatched, nil] unless input[idx] == ESC_BYTE + return :unmatched unless input[idx] == ESC_BYTE idx += 1 idx += 1 if input[idx] == ESC_BYTE case input[idx] when nil - return [:matching, nil] + return :matching when 91 # == '['.ord - # CSI sequence + # CSI sequence `ESC [ ... char` idx += 1 idx += 1 while idx < input.size && CSI_PARAMETER_BYTES_RANGE.cover?(input[idx]) idx += 1 while idx < input.size && CSI_INTERMEDIATE_BYTES_RANGE.cover?(input[idx]) - input[idx] ? [:matched, idx + 1] : [:matching, nil] when 79 # == 'O'.ord - # SS3 sequence - input[idx + 1] ? [:matched, idx + 2] : [:matching, nil] + # SS3 sequence `ESC O char` + idx += 1 else - if idx == 1 - # `ESC char`, make it :unmatched so that it will be handled correctly in `read_2nd_character_of_key_sequence` - [:unmatched, nil] - else - # `ESC ESC char` - [:matched, idx + 1] - end + # `ESC char` or `ESC ESC char` + return :unmatched if vi_mode end + input[idx + 1] ? :unmatched : input[idx] ? :matched : :matching end def key_mapping diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb index 23ece60220..330a1a4103 100644 --- a/lib/reline/line_editor.rb +++ b/lib/reline/line_editor.rb @@ -261,7 +261,6 @@ def reset_line @line_index = 0 @cache.clear @line_backup_in_history = nil - @multibyte_buffer = String.new(encoding: 'ASCII-8BIT') end def multiline_on @@ -683,10 +682,8 @@ def call(key) @trap_key.each do |t| @config.add_oneshot_key_binding(t, @name) end - elsif @trap_key.is_a?(Array) + else @config.add_oneshot_key_binding(@trap_key, @name) - elsif @trap_key.is_a?(Integer) or @trap_key.is_a?(Reline::Key) - @config.add_oneshot_key_binding([@trap_key], @name) end end dialog_render_info @@ -1002,8 +999,10 @@ def wrap_method_call(method_symbol, method_obj, key, with_operator = false) @drop_terminate_spaces = false end - private def process_key(key, method_symbol) - if key.is_a?(Symbol) + private def process_key(key_struct) + key = key_struct.char + method_symbol = key_struct.method_symbol + if key_struct.bytes[0] == 27 cleanup_waiting elsif @waiting_proc old_byte_pointer = @byte_pointer @@ -1061,37 +1060,10 @@ def wrap_method_call(method_symbol, method_obj, key, with_operator = false) end end @kill_ring.process - else - ed_insert(key) unless @config.editing_mode_is?(:vi_command) end end - private def normal_char(key) - @multibyte_buffer << key.combined_char - if @multibyte_buffer.size > 1 - if @multibyte_buffer.dup.force_encoding(@encoding).valid_encoding? - process_key(@multibyte_buffer.dup.force_encoding(@encoding), nil) - @multibyte_buffer.clear - else - # invalid - return - end - else # single byte - return if key.char >= 128 # maybe, first byte of multi byte - method_symbol = @config.editing_mode.get_method(key.combined_char) - if key.with_meta and method_symbol == :ed_unassigned - if @config.editing_mode_is?(:vi_command, :vi_insert) - # split ESC + key in vi mode - method_symbol = @config.editing_mode.get_method("\e".ord) - process_key("\e".ord, method_symbol) - method_symbol = @config.editing_mode.get_method(key.char) - process_key(key.char, method_symbol) - end - else - process_key(key.combined_char, method_symbol) - end - @multibyte_buffer.clear - end + private def vi_cursor_adjust if @config.editing_mode_is?(:vi_command) and @byte_pointer > 0 and @byte_pointer == current_line.bytesize byte_size = Reline::Unicode.get_prev_mbchar_size(@buffer_of_lines[@line_index], @byte_pointer) @byte_pointer -= byte_size @@ -1112,7 +1084,7 @@ def input_key(key) save_old_buffer @config.reset_oneshot_key_bindings @dialogs.each do |dialog| - if key.char.instance_of?(Symbol) and key.char == dialog.name + if dialog.name && key.method_symbol == dialog.name return end end @@ -1126,12 +1098,8 @@ def input_key(key) end @first_char = false @completion_occurs = false - - if key.char.is_a?(Symbol) - process_key(key.char, key.char) - else - normal_char(key) - end + process_key(key) + vi_cursor_adjust unless @completion_occurs @completion_state = CompletionState::NORMAL @completion_journey_state = nil diff --git a/test/reline/helper.rb b/test/reline/helper.rb index 26fe834482..fd34f286d8 100644 --- a/test/reline/helper.rb +++ b/test/reline/helper.rb @@ -99,35 +99,26 @@ class Reline::TestCase < Test::Unit::TestCase end def input_key_by_symbol(input) - @line_editor.input_key(Reline::Key.new(input, input, false)) + @line_editor.input_key(Reline::Key.new(27, input, "\e[dummy_bytes".bytes)) end def input_keys(input, convert = true) input = convert_str(input) if convert input.chars.each do |c| - if c.bytesize == 1 - eighth_bit = 0b10000000 - byte = c.bytes.first - if byte.allbits?(eighth_bit) - @line_editor.input_key(Reline::Key.new(byte ^ eighth_bit, byte, true)) - else - @line_editor.input_key(Reline::Key.new(byte, byte, false)) - end + unless c.valid_encoding? + # TODO: we should not use "\M-?" in this test. + # For example, "\M-C\M-1" is confusing with "\u{e1}". Use "\eC\e1" instead. + c = "\e" + (c.bytes.first & 0x7f).chr + end + func = @config.key_bindings.get(c.bytes) + if func + @line_editor.input_key(Reline::Key.new(c.bytes.last, func, c.bytes)) else - c.bytes.each do |b| - @line_editor.input_key(Reline::Key.new(b, b, false)) - end + @line_editor.input_key(Reline::Key.new(c, :ed_insert, c.bytes)) end end end - def input_raw_keys(input, convert = true) - input = convert_str(input) if convert - input.bytes.each do |b| - @line_editor.input_key(Reline::Key.new(b, b, false)) - end - end - def assert_line_around_cursor(before, after) before = convert_str(before) after = convert_str(after) @@ -161,7 +152,7 @@ def assert_whole_lines(expected) 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.default_key_bindings[input.bytes]) + assert_equal(method_symbol, @config.key_bindings.get(input.bytes)) end end end diff --git a/test/reline/test_config.rb b/test/reline/test_config.rb index 03e4178f32..44cf6187cd 100644 --- a/test/reline/test_config.rb +++ b/test/reline/test_config.rb @@ -22,6 +22,15 @@ def teardown @config.reset end + def additional_key_bindings(keymap_label) + @config.instance_variable_get(:@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 @@ -99,14 +108,17 @@ def test_encoding_is_not_ascii assert_equal nil, @config.convert_meta end - def test_comment_line - @config.read_lines([" #a: error\n"]) - assert_not_include @config.key_bindings, nil - 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 @@ -243,9 +255,9 @@ def test_nested_if_else $endif "\xC": "O" LINES - keys = [0x1, 0x3, 0x4, 0x6, 0x7, 0xC] - key_bindings = keys.to_h { |k| [[k.ord], ['O'.ord]] } - assert_equal(key_bindings, @config.instance_variable_get(:@additional_key_bindings)[:emacs]) + 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 @@ -284,9 +296,9 @@ def test_if_with_mode $endif LINES - assert_equal({[5] => :history_search_backward}, @config.instance_variable_get(:@additional_key_bindings)[:emacs]) - assert_equal({}, @config.instance_variable_get(:@additional_key_bindings)[:vi_insert]) - assert_equal({}, @config.instance_variable_get(:@additional_key_bindings)[:vi_command]) + 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 @@ -298,9 +310,9 @@ def test_else $endif LINES - assert_equal({[6] => :history_search_forward}, @config.instance_variable_get(:@additional_key_bindings)[:emacs]) - assert_equal({}, @config.instance_variable_get(:@additional_key_bindings)[:vi_insert]) - assert_equal({}, @config.instance_variable_get(:@additional_key_bindings)[:vi_command]) + 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 @@ -312,9 +324,9 @@ def test_if_with_invalid_mode $endif LINES - assert_equal({[6] => :history_search_forward}, @config.instance_variable_get(:@additional_key_bindings)[:emacs]) - assert_equal({}, @config.instance_variable_get(:@additional_key_bindings)[:vi_insert]) - assert_equal({}, @config.instance_variable_get(:@additional_key_bindings)[:vi_command]) + 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 @@ -329,9 +341,9 @@ def test_mode_label_differs_from_keymap_label "\C-e": history-search-backward $endif LINES - assert_equal({[5] => :history_search_backward}, @config.instance_variable_get(:@additional_key_bindings)[:emacs]) - assert_equal({}, @config.instance_variable_get(:@additional_key_bindings)[:vi_insert]) - assert_equal({}, @config.instance_variable_get(:@additional_key_bindings)[:vi_command]) + 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 @@ -342,9 +354,9 @@ def test_if_without_else_condition $endif LINES - assert_equal({}, @config.instance_variable_get(:@additional_key_bindings)[:emacs]) - assert_equal({[5] => :history_search_backward}, @config.instance_variable_get(:@additional_key_bindings)[:vi_insert]) - assert_equal({}, @config.instance_variable_get(:@additional_key_bindings)[:vi_command]) + 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 @@ -355,7 +367,7 @@ def test_default_key_bindings 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 @@ -365,7 +377,7 @@ def test_additional_key_bindings 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 @@ -377,7 +389,7 @@ def test_additional_key_bindings_with_nesting_and_comment_out 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 @@ -392,7 +404,7 @@ def test_additional_key_bindings_for_other_keymap 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 @@ -414,7 +426,7 @@ def test_additional_key_bindings_for_auxiliary_emacs_keymaps "\C-xef".bytes => 'EF'.bytes, "\egh".bytes => 'GH'.bytes, } - assert_equal expected, @config.key_bindings + assert_equal expected, registered_key_bindings(expected.keys) end def test_key_bindings_with_reset @@ -426,7 +438,7 @@ def test_key_bindings_with_reset LINES @config.reset expected = { 'default'.bytes => 'DEFAULT'.bytes, 'additional'.bytes => 'ADDITIONAL'.bytes } - assert_equal expected, @config.key_bindings + assert_equal expected, registered_key_bindings(expected.keys) end def test_history_size diff --git a/test/reline/test_key_actor_emacs.rb b/test/reline/test_key_actor_emacs.rb index 013ca2f7b3..ccf0e9d3a2 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 = '> ' @@ -157,18 +157,18 @@ def test_ed_kill_line end def test_em_kill_line - @line_editor.input_key(Reline::Key.new(:em_kill_line, :em_kill_line, false)) + input_key_by_symbol(:em_kill_line) assert_line_around_cursor('', '') input_keys('abc') - @line_editor.input_key(Reline::Key.new(:em_kill_line, :em_kill_line, false)) + input_key_by_symbol(:em_kill_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)) + input_key_by_symbol(:em_kill_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)) + input_key_by_symbol(:em_kill_line) assert_line_around_cursor('', '') end @@ -273,12 +273,12 @@ def test_ed_clear_screen_with_inputed def test_key_delete input_keys('abc') assert_line_around_cursor('abc', '') - @line_editor.input_key(Reline::Key.new(:key_delete, :key_delete, false)) + input_key_by_symbol(:key_delete) 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)) + input_key_by_symbol(:key_delete) assert_line_around_cursor('', '') refute(@line_editor.finished?) end @@ -287,7 +287,7 @@ def test_key_delete_preserves_cursor input_keys('abc') input_keys("\C-b", false) assert_line_around_cursor('ab', 'c') - @line_editor.input_key(Reline::Key.new(:key_delete, :key_delete, false)) + input_key_by_symbol(:key_delete) assert_line_around_cursor('ab', '') end @@ -731,10 +731,10 @@ def test_em_delete_or_list input_keys("\C-b", false) 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)) + input_key_by_symbol(:em_delete_or_list) 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)) + input_key_by_symbol(:em_delete_or_list) assert_line_around_cursor('foo', '') assert_equal(%w{foo_foo foo_bar foo_baz}, @line_editor.instance_variable_get(:@menu_info).list) end @@ -1409,11 +1409,11 @@ def test_ed_argument_digit_by_meta_num end def test_halfwidth_kana_width_dakuten - input_raw_keys('ガギゲゴ') + input_keys('ガギゲゴ') assert_line_around_cursor('ガギゲゴ', '') input_keys("\C-b\C-b", false) assert_line_around_cursor('ガギ', 'ゲゴ') - input_raw_keys('グ', false) + input_keys('グ', false) assert_line_around_cursor('ガギグ', 'ゲゴ') end diff --git a/test/reline/test_key_actor_vi.rb b/test/reline/test_key_actor_vi.rb index 4deae2dd83..c819f31712 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::KeyActor::ViInsertTest < Reline::TestCase def setup Reline.send(:test_mode) @prompt = '> ' @@ -19,63 +19,63 @@ def teardown def test_vi_command_mode input_keys("\C-[") - assert_instance_of(Reline::KeyActor::ViCommand, @config.editing_mode) + assert_equal(:vi_command, @config.editing_mode) end def test_vi_command_mode_with_input input_keys("abc\C-[") - assert_instance_of(Reline::KeyActor::ViCommand, @config.editing_mode) + assert_equal(:vi_command, @config.editing_mode) assert_line_around_cursor('ab', 'c') end def test_vi_insert - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_equal(:vi_insert, @config.editing_mode) input_keys('i') assert_line_around_cursor('i', '') - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_equal(:vi_insert, @config.editing_mode) input_keys("\C-[") assert_line_around_cursor('', 'i') - assert_instance_of(Reline::KeyActor::ViCommand, @config.editing_mode) + assert_equal(:vi_command, @config.editing_mode) input_keys('i') assert_line_around_cursor('', 'i') - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_equal(:vi_insert, @config.editing_mode) end def test_vi_add - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_equal(:vi_insert, @config.editing_mode) input_keys('a') assert_line_around_cursor('a', '') - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_equal(:vi_insert, @config.editing_mode) input_keys("\C-[") assert_line_around_cursor('', 'a') - assert_instance_of(Reline::KeyActor::ViCommand, @config.editing_mode) + assert_equal(:vi_command, @config.editing_mode) input_keys('a') assert_line_around_cursor('a', '') - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_equal(:vi_insert, @config.editing_mode) end def test_vi_insert_at_bol input_keys('I') assert_line_around_cursor('I', '') - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_equal(:vi_insert, @config.editing_mode) input_keys("12345\C-[hh") assert_line_around_cursor('I12', '345') - assert_instance_of(Reline::KeyActor::ViCommand, @config.editing_mode) + assert_equal(:vi_command, @config.editing_mode) input_keys('I') assert_line_around_cursor('', 'I12345') - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_equal(:vi_insert, @config.editing_mode) end def test_vi_add_at_eol input_keys('A') assert_line_around_cursor('A', '') - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_equal(:vi_insert, @config.editing_mode) input_keys("12345\C-[hh") assert_line_around_cursor('A12', '345') - assert_instance_of(Reline::KeyActor::ViCommand, @config.editing_mode) + assert_equal(:vi_command, @config.editing_mode) input_keys('A') assert_line_around_cursor('A12345', '') - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_equal(:vi_insert, @config.editing_mode) end def test_ed_insert_one @@ -644,7 +644,7 @@ def test_autocompletion_with_upward_navigation 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)) + input_key_by_symbol(:completion_journey_up) assert_line_around_cursor('Readline', '') ensure @config.autocompletion = false @@ -667,7 +667,7 @@ def test_autocompletion_with_upward_navigation_and_menu_complete_backward 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)) + input_key_by_symbol(:menu_complete_backward) assert_line_around_cursor('Readline', '') ensure @config.autocompletion = false @@ -901,11 +901,11 @@ def test_vi_change_to_eol assert_line_around_cursor('abc', '') input_keys("\C-[0C") assert_line_around_cursor('', '') - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_equal(:vi_insert, @config.editing_mode) end def test_vi_motion_operators - assert_instance_of(Reline::KeyActor::ViInsert, @config.editing_mode) + assert_equal(:vi_insert, @config.editing_mode) assert_nothing_raised do input_keys("test = { foo: bar }\C-[BBBldt}b") diff --git a/test/reline/test_key_stroke.rb b/test/reline/test_key_stroke.rb index cd205c7d9e..7eb9a257eb 100644 --- a/test/reline/test_key_stroke.rb +++ b/test/reline/test_key_stroke.rb @@ -23,35 +23,35 @@ def test_match_status }.each_pair do |key, func| 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)) + stroke = Reline::KeyStroke.new(config, Encoding::UTF_8) + assert_equal(:matching_matched, stroke.match_status("a".bytes)) + assert_equal(:matching_matched, 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(:unmatched, stroke.match_status("abz".bytes)) + assert_equal(:unmatched, stroke.match_status("abcx".bytes)) + assert_equal(:unmatched, 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(: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) + stroke = Reline::KeyStroke.new(config, Encoding::UTF_8) sequences = [ - "\e[9abc", "\e[9d", "\e[A", # Up "\e[1;1R", # Cursor position report "\e[15~", # F5 "\eOP", # F1 - "\e\e[A" # Option+Up + "\e\e[A", # Option+Up + "\eX", + "\e\eX" ] sequences.each do |seq| assert_equal(:matched, stroke.match_status(seq.bytes)) - (1...seq.size).each do |i| + assert_equal(:unmatched, stroke.match_status(seq.bytes + [32])) + (2...seq.size).each do |i| assert_equal(:matching, stroke.match_status(seq.bytes.take(i))) end end @@ -61,16 +61,18 @@ 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)) + stroke = Reline::KeyStroke.new(config, Encoding::UTF_8) + assert_equal(['123'.bytes, 'abc'.bytes, 'de'.bytes], stroke.expand('abcde'.bytes)) + assert_equal(['456'.bytes, 'ab'.bytes, 'de'.bytes], stroke.expand('abde'.bytes)) # CSI sequence - assert_equal([:ed_unassigned] + 'bc'.bytes, stroke.expand("\e[1;2;3;4;5abc".bytes)) - assert_equal([:ed_unassigned] + 'BC'.bytes, stroke.expand("\e\e[ABC".bytes)) + assert_equal([nil, "\e[1;2;3;4;5a".bytes, 'bc'.bytes], stroke.expand("\e[1;2;3;4;5abc".bytes)) + assert_equal([nil, "\e\e[A".bytes, 'BC'.bytes], stroke.expand("\e\e[ABC".bytes)) # SS3 sequence - assert_equal([:ed_unassigned] + 'QR'.bytes, stroke.expand("\eOPQR".bytes)) + assert_equal([nil, "\eOP".bytes, 'QR'.bytes], stroke.expand("\eOPQR".bytes)) end def test_oneshot_key_bindings @@ -80,7 +82,7 @@ def test_oneshot_key_bindings }.each_pair do |key, func| config.add_default_key_binding(key.bytes, func.bytes) end - stroke = Reline::KeyStroke.new(config) + stroke = Reline::KeyStroke.new(config, Encoding::UTF_8) assert_equal(:unmatched, stroke.match_status('zzz'.bytes)) assert_equal(:matched, stroke.match_status('abc'.bytes)) end @@ -88,17 +90,14 @@ def test_oneshot_key_bindings 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) + stroke = Reline::KeyStroke.new(config, Encoding::UTF_8) assert_equal(:unmatched, stroke.match_status('da'.bytes)) - assert_equal(:matched, stroke.match_status("\M-da".bytes)) + assert_equal(:matched, stroke.match_status("\eda".bytes)) assert_equal(:unmatched, stroke.match_status([32, 195, 164])) assert_equal(:matched, stroke.match_status([195, 164])) end diff --git a/test/reline/test_macro.rb b/test/reline/test_macro.rb index 04aa6474b4..fb1cc9d6ad 100644 --- a/test/reline/test_macro.rb +++ b/test/reline/test_macro.rb @@ -14,16 +14,8 @@ def teardown Reline.test_reset end - def input_key(char, combined_char = char, with_meta = false) - @line_editor.input_key(Reline::Key.new(char, combined_char, with_meta)) - end - - def input(str) - str.each_byte {|c| input_key(c)} - end - def test_simple_input - input('abc') + input_keys('abc') assert_equal 'abc', @line_editor.line end @@ -31,9 +23,9 @@ def test_alias class << @line_editor alias delete_char ed_delete_prev_char end - input('abc') + input_keys('abc') assert_nothing_raised(ArgumentError) { - input_key(:delete_char) + input_key_by_symbol(:delete_char) } assert_equal 'ab', @line_editor.line end diff --git a/test/reline/test_reline.rb b/test/reline/test_reline.rb index a20a5c9f44..82b8092eaa 100644 --- a/test/reline/test_reline.rb +++ b/test/reline/test_reline.rb @@ -303,12 +303,12 @@ def test_set_input_and_output def test_vi_editing_mode Reline.vi_editing_mode - assert_equal(Reline::KeyActor::ViInsert, Reline.core.config.editing_mode.class) + assert_equal(:vi_insert, Reline.core.config.editing_mode) end def test_emacs_editing_mode Reline.emacs_editing_mode - assert_equal(Reline::KeyActor::Emacs, Reline.core.config.editing_mode.class) + assert_equal(:emacs, Reline.core.config.editing_mode) end def test_add_dialog_proc diff --git a/test/reline/test_reline_key.rb b/test/reline/test_reline_key.rb index 7f9a11394a..e7ca1055fc 100644 --- a/test/reline/test_reline_key.rb +++ b/test/reline/test_reline_key.rb @@ -2,53 +2,18 @@ require "reline" class Reline::TestKey < Reline::TestCase - def setup - Reline.test_mode - 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)) + bytes = "\e[dummy_bytes".bytes + assert(Reline::Key.new('a', :key2, bytes).match?(:key2)) + assert(Reline::Key.new(12, :key1, bytes).match?(:key1)) + assert(Reline::Key.new(12, :key3, bytes).match?(:key3)) + + refute(Reline::Key.new('a', :key2, bytes).match?(:key1)) + refute(Reline::Key.new(12, :key1, bytes).match?(:key2)) + refute(Reline::Key.new(nil, :key3, bytes).match?(:key4)) end - def test_match_other - assert(!Reline::Key.new(:key1, 2, false).match?("key1")) - assert(!Reline::Key.new(nil, nil, false).match?(nil)) + def test_match_symbol_wrongly_used_in_irb + refute(Reline::Key.new(nil, 0xE4, true).match?(:foo)) end end diff --git a/test/reline/yamatanooroti/test_rendering.rb b/test/reline/yamatanooroti/test_rendering.rb index 37a1c1a193..859280bbaa 100644 --- a/test/reline/yamatanooroti/test_rendering.rb +++ b/test/reline/yamatanooroti/test_rendering.rb @@ -274,7 +274,7 @@ def test_esc_input write("\e") # single ESC sleep 1 write("A") - write("B\eAC") # ESC + A (M-A, specified ed_unassigned in Reline::KeyActor::Emacs) + write("B\eAC") # ignore ESC + A close assert_screen(<<~EOC) Multiline REPL.