aboutsummaryrefslogtreecommitdiffstats
path: root/lib/reline
diff options
context:
space:
mode:
authortomoya ishida <tomoyapenguin@gmail.com>2023-07-08 17:41:26 +0900
committergit <svn-admin@ruby-lang.org>2023-07-08 08:41:30 +0000
commit02f9b685e82ebde33a74e59e3e884db709a11d10 (patch)
tree8372ffa6a92f0e2d783cbf6bc5d055eb32872170 /lib/reline
parent8b2a0ec8df6a09361fd835b792a5d200bc0e66af (diff)
downloadruby-02f9b685e82ebde33a74e59e3e884db709a11d10.tar.gz
[ruby/reline] Ignore unhandled escape sequences
(https://github.com/ruby/reline/pull/522) * Add unassigned escape sequence matcher to KeyStroke * Do not insert ESC and unassigned ESC+key to input buffer
Diffstat (limited to 'lib/reline')
-rw-r--r--lib/reline/key_stroke.rb57
-rw-r--r--lib/reline/line_editor.rb15
2 files changed, 60 insertions, 12 deletions
diff --git a/lib/reline/key_stroke.rb b/lib/reline/key_stroke.rb
index c1c61513a9..bceffbb53f 100644
--- a/lib/reline/key_stroke.rb
+++ b/lib/reline/key_stroke.rb
@@ -1,4 +1,8 @@
class Reline::KeyStroke
+ ESC_BYTE = 27
+ CSI_PARAMETER_BYTES_RANGE = 0x30..0x3f
+ CSI_INTERMEDIATE_BYTES_RANGE = (0x20..0x2f)
+
def initialize(config)
@config = config
end
@@ -73,17 +77,26 @@ class Reline::KeyStroke
return :matched if it.max_by(&:size)&.size&.< input.size
return :matching if it.size > 1
}
- key_mapping.keys.select { |lhs|
- start_with?(input, lhs)
- }.tap { |it|
- return it.size > 0 ? :matched : :unmatched
- }
+ if key_mapping.keys.any? { |lhs| start_with?(input, lhs) }
+ :matched
+ else
+ match_unknown_escape_sequence(input).first
+ end
end
def expand(input)
- input = compress_meta_key(input)
lhs = key_mapping.keys.select { |item| start_with?(input, item) }.sort_by(&:size).last
- return input unless lhs
+ unless lhs
+ status, size = match_unknown_escape_sequence(input)
+ case status
+ when :matched
+ return [:ed_unassigned] + expand(input.drop(size))
+ when :matching
+ return [:ed_unassigned]
+ else
+ return input
+ end
+ end
rhs = key_mapping[lhs]
case rhs
@@ -99,6 +112,36 @@ class Reline::KeyStroke
private
+ # returns match status of CSI/SS3 sequence and matched length
+ def match_unknown_escape_sequence(input)
+ idx = 0
+ return [:unmatched, nil] unless input[idx] == ESC_BYTE
+ idx += 1
+ idx += 1 if input[idx] == ESC_BYTE
+
+ case input[idx]
+ when nil
+ return [:matching, nil]
+ when 91 # == '['.ord
+ # CSI sequence
+ 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]
+ 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
+ end
+ end
+
def key_mapping
@config.key_bindings
end
diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
index 4030902139..7ad56a39f8 100644
--- a/lib/reline/line_editor.rb
+++ b/lib/reline/line_editor.rb
@@ -1514,11 +1514,13 @@ class Reline::LineEditor
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
- # split ESC + key
- 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)
+ 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
@@ -3290,4 +3292,7 @@ class Reline::LineEditor
@mark_pointer = new_pointer
end
alias_method :exchange_point_and_mark, :em_exchange_mark
+
+ private def em_meta_next(key)
+ end
end