зеркало из https://github.com/github/ruby.git
Support Meta key in Reline
This commit is contained in:
Родитель
2d34087a38
Коммит
eb4e774711
|
@ -1,4 +1,5 @@
|
|||
require 'io/console'
|
||||
require 'timeout'
|
||||
require 'reline/version'
|
||||
require 'reline/config'
|
||||
require 'reline/key_actor'
|
||||
|
@ -6,6 +7,8 @@ require 'reline/key_stroke'
|
|||
require 'reline/line_editor'
|
||||
|
||||
module Reline
|
||||
Key = Struct.new('Key', :char, :combined_char, :with_meta)
|
||||
|
||||
extend self
|
||||
FILENAME_COMPLETION_PROC = nil
|
||||
USERNAME_COMPLETION_PROC = nil
|
||||
|
@ -321,8 +324,7 @@ module Reline
|
|||
key_stroke = Reline::KeyStroke.new(config)
|
||||
begin
|
||||
loop do
|
||||
c = Reline::IOGate.getc
|
||||
key_stroke.input_to!(c)&.then { |inputs|
|
||||
key_stroke.read_io(@@config.keyseq_timeout) { |inputs|
|
||||
inputs.each { |c|
|
||||
@@line_editor.input_key(c)
|
||||
@@line_editor.rerender
|
||||
|
|
|
@ -9,7 +9,11 @@ class Reline::ANSI
|
|||
@@output = val
|
||||
end
|
||||
|
||||
@@buf = []
|
||||
def self.getc
|
||||
unless @@buf.empty?
|
||||
return @@buf.shift
|
||||
end
|
||||
c = nil
|
||||
loop do
|
||||
result = select([@@input], [], [], 0.1)
|
||||
|
@ -20,6 +24,10 @@ class Reline::ANSI
|
|||
c&.ord
|
||||
end
|
||||
|
||||
def self.ungetc(c)
|
||||
@@buf.unshift(c)
|
||||
end
|
||||
|
||||
def self.get_screen_size
|
||||
@@input.winsize
|
||||
rescue Errno::ENOTTY
|
||||
|
|
|
@ -16,6 +16,7 @@ class Reline::Config
|
|||
history-size
|
||||
horizontal-scroll-mode
|
||||
input-meta
|
||||
keyseq-timeout
|
||||
mark-directories
|
||||
mark-modified-lines
|
||||
mark-symlinked-directories
|
||||
|
@ -44,6 +45,7 @@ class Reline::Config
|
|||
@key_actors[:vi_insert] = Reline::KeyActor::ViInsert.new
|
||||
@key_actors[:vi_command] = Reline::KeyActor::ViCommand.new
|
||||
@history_size = 500
|
||||
@keyseq_timeout = 500
|
||||
end
|
||||
|
||||
def reset
|
||||
|
@ -178,6 +180,8 @@ class Reline::Config
|
|||
when 'vi-insert'
|
||||
@keymap_label = :vi_insert
|
||||
end
|
||||
when 'keyseq-timeout'
|
||||
@keyseq_timeout = value.to_i
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -8,6 +8,9 @@ class Reline::GeneralIO
|
|||
end
|
||||
|
||||
def self.getc
|
||||
unless @@buf.empty?
|
||||
return @@buf.shift
|
||||
end
|
||||
c = nil
|
||||
loop do
|
||||
result = select([@@input], [], [], 0.1)
|
||||
|
@ -18,6 +21,10 @@ class Reline::GeneralIO
|
|||
c&.ord
|
||||
end
|
||||
|
||||
def self.ungetc(c)
|
||||
@@buf.unshift(c)
|
||||
end
|
||||
|
||||
def self.get_screen_size
|
||||
[1, 1]
|
||||
end
|
||||
|
|
|
@ -277,13 +277,13 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
|
|||
# 137 M-^I
|
||||
:ed_unassigned,
|
||||
# 138 M-^J
|
||||
:ed_unassigned,
|
||||
:key_newline,
|
||||
# 139 M-^K
|
||||
:ed_unassigned,
|
||||
# 140 M-^L
|
||||
:ed_clear_screen,
|
||||
# 141 M-^M
|
||||
:ed_unassigned,
|
||||
:key_newline,
|
||||
# 142 M-^N
|
||||
:ed_unassigned,
|
||||
# 143 M-^O
|
||||
|
|
|
@ -257,261 +257,261 @@ class Reline::KeyActor::ViInsert < Reline::KeyActor::Base
|
|||
# 127 ^?
|
||||
:vi_delete_prev_char,
|
||||
# 128 M-^@
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 129 M-^A
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 130 M-^B
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 131 M-^C
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 132 M-^D
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 133 M-^E
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 134 M-^F
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 135 M-^G
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 136 M-^H
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 137 M-^I
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 138 M-^J
|
||||
:ed_insert,
|
||||
:key_newline,
|
||||
# 139 M-^K
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 140 M-^L
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 141 M-^M
|
||||
:ed_insert,
|
||||
:key_newline,
|
||||
# 142 M-^N
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 143 M-^O
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 144 M-^P
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 145 M-^Q
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 146 M-^R
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 147 M-^S
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 148 M-^T
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 149 M-^U
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 150 M-^V
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 151 M-^W
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 152 M-^X
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 153 M-^Y
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 154 M-^Z
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 155 M-^[
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 156 M-^\
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 157 M-^]
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 158 M-^^
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 159 M-^_
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 160 M-SPACE
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 161 M-!
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 162 M-"
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 163 M-#
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 164 M-$
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 165 M-%
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 166 M-&
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 167 M-'
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 168 M-(
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 169 M-)
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 170 M-*
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 171 M-+
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 172 M-,
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 173 M--
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 174 M-.
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 175 M-/
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 176 M-0
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 177 M-1
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 178 M-2
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 179 M-3
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 180 M-4
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 181 M-5
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 182 M-6
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 183 M-7
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 184 M-8
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 185 M-9
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 186 M-:
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 187 M-;
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 188 M-<
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 189 M-=
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 190 M->
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 191 M-?
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 192 M-@
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 193 M-A
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 194 M-B
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 195 M-C
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 196 M-D
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 197 M-E
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 198 M-F
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 199 M-G
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 200 M-H
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 201 M-I
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 202 M-J
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 203 M-K
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 204 M-L
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 205 M-M
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 206 M-N
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 207 M-O
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 208 M-P
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 209 M-Q
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 210 M-R
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 211 M-S
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 212 M-T
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 213 M-U
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 214 M-V
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 215 M-W
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 216 M-X
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 217 M-Y
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 218 M-Z
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 219 M-[
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 220 M-\
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 221 M-]
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 222 M-^
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 223 M-_
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 223 M-`
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 224 M-a
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 225 M-b
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 226 M-c
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 227 M-d
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 228 M-e
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 229 M-f
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 230 M-g
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 231 M-h
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 232 M-i
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 233 M-j
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 234 M-k
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 235 M-l
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 236 M-m
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 237 M-n
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 238 M-o
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 239 M-p
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 240 M-q
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 241 M-r
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 242 M-s
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 243 M-t
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 244 M-u
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 245 M-v
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 246 M-w
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 247 M-x
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 248 M-y
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 249 M-z
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 250 M-{
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 251 M-|
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 252 M-}
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 253 M-~
|
||||
:ed_insert,
|
||||
:ed_unassigned,
|
||||
# 254 M-^?
|
||||
:ed_insert
|
||||
:ed_unassigned
|
||||
# 255
|
||||
# EOF
|
||||
]
|
||||
|
|
|
@ -13,30 +13,81 @@ class Reline::KeyStroke
|
|||
|
||||
def initialize(config)
|
||||
@config = config
|
||||
@buffer = []
|
||||
end
|
||||
|
||||
def input_to(bytes)
|
||||
case match_status(bytes)
|
||||
when :matching
|
||||
nil
|
||||
when :matched
|
||||
expand(bytes)
|
||||
when :unmatched
|
||||
bytes
|
||||
# Keystrokes of GNU Readline will timeout it with the specification of
|
||||
# "keyseq-timeout" when waiting for the 2nd character after the 1st one.
|
||||
# If the 2nd character comes after 1st ESC without timeout it has a
|
||||
# meta-property of meta-key to discriminate modified key with meta-key
|
||||
# from multibyte characters that come with 8th bit on.
|
||||
#
|
||||
# GNU Readline will wait for the 2nd character with "keyseq-timeout"
|
||||
# milli-seconds but wait forever after 3rd characters.
|
||||
def read_io(keyseq_timeout, &block)
|
||||
buffer = []
|
||||
loop do
|
||||
c = Reline::IOGate.getc
|
||||
buffer << c
|
||||
result = match_status(buffer)
|
||||
case result
|
||||
when :matched
|
||||
block.(expand(bytes).map{ |c| Reline::Key.new(c, c, false) })
|
||||
break
|
||||
when :matching
|
||||
if buffer.size == 1
|
||||
begin
|
||||
succ_c = nil
|
||||
Timeout.timeout(keyseq_timeout / 1000.0) {
|
||||
succ_c = Reline::IOGate.getc
|
||||
}
|
||||
rescue Timeout::Error # cancel matching only when first byte
|
||||
block.([Reline::Key.new(c, c, false)])
|
||||
break
|
||||
else
|
||||
if match_status(buffer.dup.push(succ_c)) == :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
|
||||
break
|
||||
else
|
||||
Reline::IOGate.ungetc(succ_c)
|
||||
end
|
||||
end
|
||||
end
|
||||
when :unmatched
|
||||
if buffer.size == 1 and c == "\e".ord
|
||||
read_escaped_key(buffer, block)
|
||||
else
|
||||
block.(buffer.map{ |c| Reline::Key.new(c, c, false) })
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def input_to!(bytes)
|
||||
if bytes.nil?
|
||||
return @buffer.push(nil)&.tap { clear }
|
||||
def read_escaped_key(buffer, block)
|
||||
begin
|
||||
escaped_c = nil
|
||||
Timeout.timeout(keyseq_timeout / 1000.0) {
|
||||
escaped_c = Reline::IOGate.getc
|
||||
}
|
||||
rescue Timeout::Error # independent ESC
|
||||
block.([Reline::Key.new(c, c, false)])
|
||||
else
|
||||
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)])
|
||||
end
|
||||
end
|
||||
@buffer.concat Array(bytes)
|
||||
input_to(@buffer)&.tap { clear }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def match_status(input)
|
||||
key_mapping.keys.select { |lhs|
|
||||
lhs.start_with? input
|
||||
|
@ -53,6 +104,8 @@ class Reline::KeyStroke
|
|||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def expand(input)
|
||||
lhs = key_mapping.keys.select { |lhs| input.start_with? lhs }.sort_by(&:size).reverse.first
|
||||
return input unless lhs
|
||||
|
@ -70,8 +123,4 @@ class Reline::KeyStroke
|
|||
def key_mapping
|
||||
@config[:key_mapping].transform_keys(&:bytes)
|
||||
end
|
||||
|
||||
def clear
|
||||
@buffer = []
|
||||
end
|
||||
end
|
||||
|
|
|
@ -104,7 +104,6 @@ class Reline::LineEditor
|
|||
@kill_ring = Reline::KillRing.new
|
||||
@vi_clipboard = ''
|
||||
@vi_arg = nil
|
||||
@meta_prefix = false
|
||||
@waiting_proc = nil
|
||||
@waiting_operator_proc = nil
|
||||
@completion_journey_data = nil
|
||||
|
@ -625,31 +624,38 @@ class Reline::LineEditor
|
|||
|
||||
private def normal_char(key)
|
||||
method_symbol = method_obj = nil
|
||||
@multibyte_buffer << key
|
||||
@multibyte_buffer << key.combined_char
|
||||
if @multibyte_buffer.size > 1
|
||||
if @multibyte_buffer.dup.force_encoding(@encoding).valid_encoding?
|
||||
key = @multibyte_buffer.dup.force_encoding(@encoding)
|
||||
process_key(@multibyte_buffer.dup.force_encoding(@encoding), nil, nil)
|
||||
@multibyte_buffer.clear
|
||||
else
|
||||
# invalid
|
||||
return
|
||||
end
|
||||
else # single byte
|
||||
return if key >= 128 # maybe, first byte of multi byte
|
||||
if @meta_prefix
|
||||
key |= 0b10000000 if key.nobits?(0b10000000)
|
||||
@meta_prefix = false
|
||||
end
|
||||
method_symbol = @config.editing_mode.get_method(key)
|
||||
if key.allbits?(0b10000000) and method_symbol == :ed_unassigned
|
||||
return # This is unknown input
|
||||
end
|
||||
if method_symbol and respond_to?(method_symbol, true)
|
||||
method_obj = method(method_symbol)
|
||||
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)
|
||||
if method_symbol and respond_to?(method_symbol, true)
|
||||
method_obj = method(method_symbol)
|
||||
end
|
||||
process_key("\e".ord, method_symbol, method_obj)
|
||||
method_symbol = @config.editing_mode.get_method(key.char)
|
||||
if method_symbol and respond_to?(method_symbol, true)
|
||||
method_obj = method(method_symbol)
|
||||
end
|
||||
process_key(key.char, method_symbol, method_obj)
|
||||
else
|
||||
if method_symbol and respond_to?(method_symbol, true)
|
||||
method_obj = method(method_symbol)
|
||||
end
|
||||
process_key(key.combined_char, method_symbol, method_obj)
|
||||
end
|
||||
@multibyte_buffer.clear
|
||||
end
|
||||
process_key(key, method_symbol, method_obj)
|
||||
if @config.editing_mode_is?(:vi_command) and @cursor > 0 and @cursor == @cursor_max
|
||||
byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
|
||||
@byte_pointer -= byte_size
|
||||
|
@ -660,7 +666,7 @@ class Reline::LineEditor
|
|||
end
|
||||
|
||||
def input_key(key)
|
||||
if key.nil?
|
||||
if key.nil? or key.char.nil?
|
||||
if @first_char
|
||||
@line = nil
|
||||
end
|
||||
|
@ -669,30 +675,20 @@ class Reline::LineEditor
|
|||
end
|
||||
@first_char = false
|
||||
completion_occurs = false
|
||||
if @config.editing_mode_is?(:emacs, :vi_insert) and key == "\C-i".ord
|
||||
if @config.editing_mode_is?(:emacs, :vi_insert) and key.char == "\C-i".ord
|
||||
result = @completion_proc&.(@line)
|
||||
if result.is_a?(Array)
|
||||
completion_occurs = true
|
||||
complete(result)
|
||||
end
|
||||
elsif @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key)
|
||||
elsif @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key.char)
|
||||
result = @completion_proc&.(@line)
|
||||
if result.is_a?(Array)
|
||||
completion_occurs = true
|
||||
move_completed_list(result, "\C-p".ord == key ? :up : :down)
|
||||
move_completed_list(result, "\C-p".ord == key.char ? :up : :down)
|
||||
end
|
||||
elsif @config.editing_mode_is?(:emacs) and key == "\e".ord # meta key
|
||||
if @meta_prefix
|
||||
# escape twice
|
||||
@meta_prefix = false
|
||||
@kill_ring.process
|
||||
else
|
||||
@meta_prefix = true
|
||||
end
|
||||
elsif @config.editing_mode_is?(:vi_command) and key == "\e".ord
|
||||
# suppress ^[ when command_mode
|
||||
elsif Symbol === key and respond_to?(key, true)
|
||||
process_key(key, key, method(key))
|
||||
elsif Symbol === key.char and respond_to?(key.char, true)
|
||||
process_key(key.char, key.char, method(key.char))
|
||||
else
|
||||
normal_char(key)
|
||||
end
|
||||
|
@ -823,6 +819,15 @@ class Reline::LineEditor
|
|||
end
|
||||
end
|
||||
|
||||
private def key_newline(key)
|
||||
if @is_multiline
|
||||
next_line = @line.byteslice(@byte_pointer, @line.bytesize - @byte_pointer)
|
||||
cursor_line = @line.byteslice(0, @byte_pointer)
|
||||
insert_new_line(cursor_line, next_line)
|
||||
@cursor = 0
|
||||
end
|
||||
end
|
||||
|
||||
private def ed_insert(key)
|
||||
if key.instance_of?(String)
|
||||
width = Reline::Unicode.get_mbchar_width(key)
|
||||
|
|
|
@ -101,6 +101,10 @@ class Reline::Windows
|
|||
end
|
||||
end
|
||||
|
||||
def self.ungetc(c)
|
||||
@@buf.unshift(c)
|
||||
end
|
||||
|
||||
def self.get_screen_size
|
||||
csbi = 0.chr * 24
|
||||
@@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi)
|
||||
|
|
|
@ -40,13 +40,13 @@ class Reline::TestCase < Test::Unit::TestCase
|
|||
eighth_bit = 0b10000000
|
||||
byte = c.bytes.first
|
||||
if byte.allbits?(eighth_bit)
|
||||
@line_editor.input_key("\e".ord)
|
||||
byte ^= 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
|
||||
@line_editor.input_key(byte)
|
||||
else
|
||||
c.bytes.each do |b|
|
||||
@line_editor.input_key(b)
|
||||
@line_editor.input_key(Reline::Key.new(b, b, false))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,12 +4,16 @@ class Reline::KeyStroke::Test < Reline::TestCase
|
|||
using Module.new {
|
||||
refine Array do
|
||||
def as_s
|
||||
map(&:chr).join
|
||||
join
|
||||
end
|
||||
|
||||
def to_keys
|
||||
map{ |b| Reline::Key.new(b, b, false) }
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
def test_input_to!
|
||||
def test_match_status
|
||||
config = {
|
||||
key_mapping: {
|
||||
"a" => "xx",
|
||||
|
@ -19,33 +23,15 @@ class Reline::KeyStroke::Test < Reline::TestCase
|
|||
}
|
||||
}
|
||||
stroke = Reline::KeyStroke.new(config)
|
||||
result = ("abzwabk".bytes).map { |char|
|
||||
stroke.input_to!(char)&.then { |result|
|
||||
"#{result.as_s}"
|
||||
}
|
||||
}
|
||||
assert_equal(result, [nil, nil, "yz", "w", nil, nil, "yk"])
|
||||
end
|
||||
|
||||
def test_input_to
|
||||
config = {
|
||||
key_mapping: {
|
||||
"a" => "xx",
|
||||
"ab" => "y",
|
||||
"abc" => "z",
|
||||
"x" => "rr"
|
||||
}
|
||||
}
|
||||
stroke = Reline::KeyStroke.new(config)
|
||||
assert_equal(stroke.input_to("a".bytes)&.as_s, nil)
|
||||
assert_equal(stroke.input_to("ab".bytes)&.as_s, nil)
|
||||
assert_equal(stroke.input_to("abc".bytes)&.as_s, "z")
|
||||
assert_equal(stroke.input_to("abz".bytes)&.as_s, "yz")
|
||||
assert_equal(stroke.input_to("abx".bytes)&.as_s, "yrr")
|
||||
assert_equal(stroke.input_to("ac".bytes)&.as_s, "rrrrc")
|
||||
assert_equal(stroke.input_to("aa".bytes)&.as_s, "rrrrrrrr")
|
||||
assert_equal(stroke.input_to("x".bytes)&.as_s, "rr")
|
||||
assert_equal(stroke.input_to("m".bytes)&.as_s, "m")
|
||||
assert_equal(stroke.input_to("abzwabk".bytes)&.as_s, "yzwabk")
|
||||
assert_equal(:matching, stroke.match_status("a".bytes))
|
||||
assert_equal(:matching, 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(:matched, stroke.match_status("x".bytes))
|
||||
assert_equal(:unmatched, stroke.match_status("m".bytes))
|
||||
assert_equal(:matched, stroke.match_status("abzwabk".bytes))
|
||||
end
|
||||
end
|
||||
|
|
Загрузка…
Ссылка в новой задаче