Use inputrc data for keystroke setting

This commit is contained in:
aycabta 2019-06-01 09:05:58 +09:00
Родитель c1e5299787
Коммит 7df65ef676
8 изменённых файлов: 109 добавлений и 82 удалений

Просмотреть файл

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