diff options
author | aycabta <aycabta@gmail.com> | 2019-06-05 11:29:41 +0900 |
---|---|---|
committer | aycabta <aycabta@gmail.com> | 2019-06-05 11:29:59 +0900 |
commit | c75a3356b39c5a6ede275f38d5d869dbcd5dba93 (patch) | |
tree | 6d714b78977289f2d51d47faddf2a8e0f83205ec /lib/reline.rb | |
parent | 7c776038ec3e620625b7fe3e78638afe936f9a5d (diff) |
Move I/O access from Reline::KeyStroke to Reline
Diffstat (limited to 'lib/reline.rb')
-rw-r--r-- | lib/reline.rb | 77 |
1 files changed, 75 insertions, 2 deletions
diff --git a/lib/reline.rb b/lib/reline.rb index cafaf578a0..49e99d2d65 100644 --- a/lib/reline.rb +++ b/lib/reline.rb @@ -22,6 +22,7 @@ module Reline CursorPos = Struct.new(:x, :y) @@config = Reline::Config.new + @@key_stroke = Reline::KeyStroke.new(@@config) @@line_editor = Reline::LineEditor.new(@@config) @@ambiguous_width = nil @@ -331,10 +332,9 @@ module Reline end end - key_stroke = Reline::KeyStroke.new(@@config) begin loop do - key_stroke.read_io(@@config.keyseq_timeout) { |inputs| + read_io(@@config.keyseq_timeout) { |inputs| inputs.each { |c| @@line_editor.input_key(c) @@line_editor.rerender @@ -353,6 +353,79 @@ module Reline Reline::IOGate.deprep(otio) end + # 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 = @@key_stroke.match_status(buffer) + case result + when :matched + block.(@@key_stroke.expand(buffer).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 @@key_stroke.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(keyseq_timeout, buffer, block) + else + block.(buffer.map{ |c| Reline::Key.new(c, c, false) }) + end + break + end + end + end + + def read_escaped_key(keyseq_timeout, 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 + end + def may_req_ambiguous_char_width @@ambiguous_width = 2 if Reline::IOGate == Reline::GeneralIO or STDOUT.is_a?(File) return if @@ambiguous_width |