зеркало из https://github.com/github/ruby.git
Use inputrc data for keystroke setting
This commit is contained in:
Родитель
c1e5299787
Коммит
7df65ef676
|
@ -326,9 +326,12 @@ module Reline
|
|||
@@line_editor.pre_input_hook = @@pre_input_hook
|
||||
@@line_editor.rerender
|
||||
|
||||
config = Reline::IOGate::RAW_KEYSTROKE_CONFIG
|
||||
@@config.reset_default_key_bindings
|
||||
Reline::IOGate::RAW_KEYSTROKE_CONFIG.each_pair do |key, func|
|
||||
@@config.add_default_key_binding(key, func)
|
||||
end
|
||||
|
||||
key_stroke = Reline::KeyStroke.new(config)
|
||||
key_stroke = Reline::KeyStroke.new(@@config)
|
||||
begin
|
||||
loop do
|
||||
key_stroke.read_io(@@config.keyseq_timeout) { |inputs|
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
class Reline::ANSI
|
||||
RAW_KEYSTROKE_CONFIG = {
|
||||
key_mapping: {
|
||||
[27, 91, 65] => :ed_prev_history, # ↑
|
||||
[27, 91, 66] => :ed_next_history, # ↓
|
||||
[27, 91, 67] => :ed_next_char, # →
|
||||
[27, 91, 68] => :ed_prev_char, # ←
|
||||
[27, 91, 51, 126] => :key_delete, # Del
|
||||
[27, 91, 49, 126] => :ed_move_to_beg, # Home
|
||||
[27, 91, 52, 126] => :ed_move_to_end, # End
|
||||
}.each_key(&:freeze).freeze,
|
||||
}.freeze
|
||||
[27, 91, 65] => :ed_prev_history, # ↑
|
||||
[27, 91, 66] => :ed_next_history, # ↓
|
||||
[27, 91, 67] => :ed_next_char, # →
|
||||
[27, 91, 68] => :ed_prev_char, # ←
|
||||
[27, 91, 51, 126] => :key_delete, # Del
|
||||
[27, 91, 49, 126] => :ed_move_to_beg, # Home
|
||||
[27, 91, 52, 126] => :ed_move_to_end, # End
|
||||
}.each_key(&:freeze).freeze
|
||||
|
||||
@@input = STDIN
|
||||
def self.input=(val)
|
||||
|
|
|
@ -36,6 +36,8 @@ class Reline::Config
|
|||
end
|
||||
|
||||
def initialize
|
||||
@additional_key_bindings = {}
|
||||
@default_key_bindings = {}
|
||||
@skip_section = nil
|
||||
@if_stack = []
|
||||
@editing_mode_label = :emacs
|
||||
|
@ -52,6 +54,8 @@ class Reline::Config
|
|||
if editing_mode_is?(:vi_command)
|
||||
@editing_mode_label = :vi_insert
|
||||
end
|
||||
@additional_key_bindings = {}
|
||||
@default_key_bindings = {}
|
||||
end
|
||||
|
||||
def editing_mode
|
||||
|
@ -88,8 +92,23 @@ class Reline::Config
|
|||
self
|
||||
end
|
||||
|
||||
def key_bindings
|
||||
# override @default_key_bindings with @additional_key_bindings
|
||||
@default_key_bindings.merge(@additional_key_bindings)
|
||||
end
|
||||
|
||||
def add_default_key_binding(keystroke, target)
|
||||
@default_key_bindings[keystroke] = target
|
||||
end
|
||||
|
||||
def reset_default_key_bindings
|
||||
@default_key_bindings = {}
|
||||
end
|
||||
|
||||
def read_lines(lines)
|
||||
lines.each do |line|
|
||||
next if line.start_with?('#')
|
||||
|
||||
line = line.chomp.gsub(/^\s*/, '')
|
||||
if line[0, 1] == '$'
|
||||
handle_directive(line[1..-1])
|
||||
|
@ -106,7 +125,8 @@ class Reline::Config
|
|||
|
||||
if line =~ /\s*(.*)\s*:\s*(.*)\s*$/
|
||||
key, func_name = $1, $2
|
||||
bind_key(key, func_name)
|
||||
keystroke, func = bind_key(key, func_name)
|
||||
@additional_key_bindings[keystroke] = func
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -187,59 +207,57 @@ class Reline::Config
|
|||
|
||||
def bind_key(key, func_name)
|
||||
if key =~ /"(.*)"/
|
||||
keyseq = parse_keyseq($1).force_encoding('ASCII-8BIT')
|
||||
keyseq = parse_keyseq($1)
|
||||
else
|
||||
keyseq = nil
|
||||
end
|
||||
if func_name =~ /"(.*)"/
|
||||
func = parse_keyseq($1).force_encoding('ASCII-8BIT')
|
||||
func = parse_keyseq($1)
|
||||
else
|
||||
func = func_name.to_sym # It must be macro.
|
||||
func = func_name.tr(?-, ?_).to_sym # It must be macro.
|
||||
end
|
||||
[keyseq, func]
|
||||
end
|
||||
|
||||
def key_notation_to_char(notation)
|
||||
def key_notation_to_code(notation)
|
||||
case notation
|
||||
when /\\C-([A-Za-z_])/
|
||||
(1 + $1.downcase.ord - ?a.ord).chr('ASCII-8BIT')
|
||||
(1 + $1.downcase.ord - ?a.ord)
|
||||
when /\\M-([0-9A-Za-z_])/
|
||||
modified_key = $1
|
||||
code =
|
||||
case $1
|
||||
when /[0-9]/
|
||||
?\M-0.bytes.first + (modified_key.ord - ?0.ord)
|
||||
when /[A-Z]/
|
||||
?\M-A.bytes.first + (modified_key.ord - ?A.ord)
|
||||
when /[a-z]/
|
||||
?\M-a.bytes.first + (modified_key.ord - ?a.ord)
|
||||
end
|
||||
code.chr('ASCII-8BIT')
|
||||
case $1
|
||||
when /[0-9]/
|
||||
?\M-0.bytes.first + (modified_key.ord - ?0.ord)
|
||||
when /[A-Z]/
|
||||
?\M-A.bytes.first + (modified_key.ord - ?A.ord)
|
||||
when /[a-z]/
|
||||
?\M-a.bytes.first + (modified_key.ord - ?a.ord)
|
||||
end
|
||||
when /\\C-M-[A-Za-z_]/, /\\M-C-[A-Za-z_]/
|
||||
# 129 M-^A
|
||||
when /\\(\d{1,3})/ then $1.to_i(8).chr # octal
|
||||
when /\\x(\h{1,2})/ then $1.to_i(16).chr # hexadecimal
|
||||
when "\\e" then ?\e
|
||||
when "\\\\" then ?\\
|
||||
when "\\\"" then ?"
|
||||
when "\\'" then ?'
|
||||
when "\\a" then ?\a
|
||||
when "\\b" then ?\b
|
||||
when "\\d" then ?\d
|
||||
when "\\f" then ?\f
|
||||
when "\\n" then ?\n
|
||||
when "\\r" then ?\r
|
||||
when "\\t" then ?\t
|
||||
when "\\v" then ?\v
|
||||
else notation
|
||||
when /\\(\d{1,3})/ then $1.to_i(8) # octal
|
||||
when /\\x(\h{1,2})/ then $1.to_i(16) # hexadecimal
|
||||
when "\\e" then ?\e.ord
|
||||
when "\\\\" then ?\\.ord
|
||||
when "\\\"" then ?".ord
|
||||
when "\\'" then ?'.ord
|
||||
when "\\a" then ?\a.ord
|
||||
when "\\b" then ?\b.ord
|
||||
when "\\d" then ?\d.ord
|
||||
when "\\f" then ?\f.ord
|
||||
when "\\n" then ?\n.ord
|
||||
when "\\r" then ?\r.ord
|
||||
when "\\t" then ?\t.ord
|
||||
when "\\v" then ?\v.ord
|
||||
else notation.ord
|
||||
end
|
||||
end
|
||||
|
||||
def parse_keyseq(str)
|
||||
# TODO: Control- and Meta-
|
||||
ret = String.new(encoding: 'ASCII-8BIT')
|
||||
ret = []
|
||||
while str =~ /(\\C-[A-Za-z_]|\\M-[0-9A-Za-z_]|\\C-M-[A-Za-z_]|\\M-C-[A-Za-z_]|\\e|\\\\|\\"|\\'|\\a|\\b|\\d|\\f|\\n|\\r|\\t|\\v|\\\d{1,3}|\\x\h{1,2}|.)/
|
||||
ret << key_notation_to_char($&)
|
||||
ret << key_notation_to_code($&)
|
||||
str = $'
|
||||
end
|
||||
ret
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'timeout'
|
||||
|
||||
class Reline::GeneralIO
|
||||
RAW_KEYSTROKE_CONFIG = {key_mapping: {}.freeze}.freeze
|
||||
RAW_KEYSTROKE_CONFIG = {}.freeze
|
||||
|
||||
@@buf = []
|
||||
|
||||
|
|
|
@ -121,6 +121,6 @@ class Reline::KeyStroke
|
|||
end
|
||||
|
||||
def key_mapping
|
||||
@config[:key_mapping].transform_keys(&:bytes)
|
||||
@config.key_bindings
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,16 +2,14 @@ require 'fiddle/import'
|
|||
|
||||
class Reline::Windows
|
||||
RAW_KEYSTROKE_CONFIG = {
|
||||
key_mapping: {
|
||||
[224, 72] => :ed_prev_history, # ↑
|
||||
[224, 80] => :ed_next_history, # ↓
|
||||
[224, 77] => :ed_next_char, # →
|
||||
[224, 75] => :ed_prev_char, # ←
|
||||
[224, 83] => :key_delete, # Del
|
||||
[224, 71] => :ed_move_to_beg, # Home
|
||||
[224, 79] => :ed_move_to_end, # End
|
||||
}.each_key(&:freeze).freeze,
|
||||
}.freeze
|
||||
[224, 72] => :ed_prev_history, # ↑
|
||||
[224, 80] => :ed_next_history, # ↓
|
||||
[224, 77] => :ed_next_char, # →
|
||||
[224, 75] => :ed_prev_char, # ←
|
||||
[224, 83] => :key_delete, # Del
|
||||
[224, 71] => :ed_move_to_beg, # Home
|
||||
[224, 79] => :ed_move_to_end, # End
|
||||
}.each_key(&:freeze).freeze
|
||||
|
||||
class Win32API
|
||||
DLL = {}
|
||||
|
|
|
@ -28,42 +28,40 @@ class Reline::Config::Test < Reline::TestCase
|
|||
end
|
||||
|
||||
def test_bind_key
|
||||
key, func = @config.bind_key('"input"', '"abcde"')
|
||||
|
||||
assert_equal 'input', key
|
||||
assert_equal 'abcde', func
|
||||
assert_equal ['input'.bytes, 'abcde'.bytes], @config.bind_key('"input"', '"abcde"')
|
||||
end
|
||||
|
||||
def test_bind_key_with_macro
|
||||
key, func = @config.bind_key('"input"', 'abcde')
|
||||
|
||||
assert_equal 'input', key
|
||||
assert_equal :abcde, func
|
||||
assert_equal ['input'.bytes, :abcde], @config.bind_key('"input"', 'abcde')
|
||||
end
|
||||
|
||||
def test_bind_key_with_escaped_chars
|
||||
assert_equal ['input', "\e \\ \" ' \a \b \d \f \n \r \t \v"], @config.bind_key('"input"', '"\\e \\\\ \\" \\\' \\a \\b \\d \\f \\n \\r \\t \\v"')
|
||||
key, func =
|
||||
assert_equal ['input'.bytes, "\e \\ \" ' \a \b \d \f \n \r \t \v".bytes], @config.bind_key('"input"', '"\\e \\\\ \\" \\\' \\a \\b \\d \\f \\n \\r \\t \\v"')
|
||||
end
|
||||
|
||||
def test_bind_key_with_ctrl_chars
|
||||
assert_equal ['input', "\C-h\C-h"], @config.bind_key('"input"', '"\C-h\C-H"')
|
||||
assert_equal ['input'.bytes, "\C-h\C-h".bytes], @config.bind_key('"input"', '"\C-h\C-H"')
|
||||
end
|
||||
|
||||
def test_bind_key_with_meta_chars
|
||||
assert_equal ['input', "\M-h\M-H".force_encoding('ASCII-8BIT')], @config.bind_key('"input"', '"\M-h\M-H"')
|
||||
assert_equal ['input'.bytes, "\M-h\M-H".bytes], @config.bind_key('"input"', '"\M-h\M-H"')
|
||||
end
|
||||
|
||||
def test_bind_key_with_octal_number
|
||||
assert_equal ['input', "\1"], @config.bind_key('"input"', '"\1"')
|
||||
assert_equal ['input', "\12"], @config.bind_key('"input"', '"\12"')
|
||||
assert_equal ['input', "\123"], @config.bind_key('"input"', '"\123"')
|
||||
assert_equal ['input', ["\123", '4'].join], @config.bind_key('"input"', '"\1234"')
|
||||
input = %w{i n p u t}.map(&:ord)
|
||||
assert_equal [input, "\1".bytes], @config.bind_key('"input"', '"\1"')
|
||||
assert_equal [input, "\12".bytes], @config.bind_key('"input"', '"\12"')
|
||||
assert_equal [input, "\123".bytes], @config.bind_key('"input"', '"\123"')
|
||||
assert_equal [input, "\123".bytes + '4'.bytes], @config.bind_key('"input"', '"\1234"')
|
||||
end
|
||||
|
||||
def test_bind_key_with_hexadecimal_number
|
||||
assert_equal ['input', "\x4"], @config.bind_key('"input"', '"\x4"')
|
||||
assert_equal ['input', "\x45"], @config.bind_key('"input"', '"\x45"')
|
||||
assert_equal ['input', ["\x45", '6'].join], @config.bind_key('"input"', '"\x456"')
|
||||
input = %w{i n p u t}.map(&:ord)
|
||||
assert_equal [input, "\x4".bytes], @config.bind_key('"input"', '"\x4"')
|
||||
assert_equal [input, "\x45".bytes], @config.bind_key('"input"', '"\x45"')
|
||||
assert_equal [input, "\x45".bytes + '6'.bytes], @config.bind_key('"input"', '"\x456"')
|
||||
end
|
||||
|
||||
def test_include
|
||||
|
@ -115,4 +113,15 @@ class Reline::Config::Test < Reline::TestCase
|
|||
|
||||
assert_equal :audible, @config.instance_variable_get(:@bell_style)
|
||||
end
|
||||
|
||||
def test_default_key_bindings
|
||||
@config.add_default_key_binding('abcd'.bytes, 'EFGH'.bytes)
|
||||
@config.read_lines(<<~'LINES'.split(/(?<=\n)/))
|
||||
"abcd": "ABCD"
|
||||
"ijkl": "IJKL"
|
||||
LINES
|
||||
|
||||
expected = { 'abcd'.bytes => 'ABCD'.bytes, 'ijkl'.bytes => 'IJKL'.bytes }
|
||||
assert_equal expected, @config.key_bindings
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,14 +14,15 @@ class Reline::KeyStroke::Test < Reline::TestCase
|
|||
}
|
||||
|
||||
def test_match_status
|
||||
config = {
|
||||
key_mapping: {
|
||||
"a" => "xx",
|
||||
"ab" => "y",
|
||||
"abc" => "z",
|
||||
"x" => "rr"
|
||||
}
|
||||
}
|
||||
config = Reline::Config.new
|
||||
{
|
||||
"a" => "xx",
|
||||
"ab" => "y",
|
||||
"abc" => "z",
|
||||
"x" => "rr"
|
||||
}.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))
|
||||
|
|
Загрузка…
Ссылка в новой задаче