1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Use inputrc data for keystroke setting

This commit is contained in:
aycabta 2019-06-01 09:05:58 +09:00
parent c1e5299787
commit 7df65ef676
8 changed files with 109 additions and 82 deletions

View file

@ -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|

View file

@ -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)

View file

@ -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

View file

@ -1,7 +1,7 @@
require 'timeout'
class Reline::GeneralIO
RAW_KEYSTROKE_CONFIG = {key_mapping: {}.freeze}.freeze
RAW_KEYSTROKE_CONFIG = {}.freeze
@@buf = []

View file

@ -121,6 +121,6 @@ class Reline::KeyStroke
end
def key_mapping
@config[:key_mapping].transform_keys(&:bytes)
@config.key_bindings
end
end

View file

@ -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 = {}

View file

@ -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

View file

@ -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))