[ruby/reline] Overhaul io gate structure
(https://github.com/ruby/reline/pull/666) * Overhaul IO gate structure 1. Move IO related classes to `lib/reline/io/` directory. 2. Rename `GeneralIO` to `Dumb`. 3. Use IO classes as instances instead of classes. * Update lib/reline/io/ansi.rb Co-authored-by: tomoya ishida <tomoyapenguin@gmail.com> --------- https://github.com/ruby/reline/commit/dc1518e1ac Co-authored-by: tomoya ishida <tomoyapenguin@gmail.com>
This commit is contained in:
parent
767aa0cdb6
commit
cda69b5910
@ -7,6 +7,7 @@ require 'reline/key_stroke'
|
||||
require 'reline/line_editor'
|
||||
require 'reline/history'
|
||||
require 'reline/terminfo'
|
||||
require 'reline/io'
|
||||
require 'reline/face'
|
||||
require 'rbconfig'
|
||||
|
||||
@ -336,7 +337,7 @@ module Reline
|
||||
line_editor.auto_indent_proc = auto_indent_proc
|
||||
line_editor.dig_perfect_match_proc = dig_perfect_match_proc
|
||||
pre_input_hook&.call
|
||||
unless Reline::IOGate == Reline::GeneralIO
|
||||
unless Reline::IOGate.dumb?
|
||||
@dialog_proc_list.each_pair do |name_sym, d|
|
||||
line_editor.add_dialog_proc(name_sym, d.dialog_proc, d.context)
|
||||
end
|
||||
@ -473,7 +474,7 @@ module Reline
|
||||
end
|
||||
|
||||
private def may_req_ambiguous_char_width
|
||||
@ambiguous_width = 2 if io_gate == Reline::GeneralIO or !STDOUT.tty?
|
||||
@ambiguous_width = 2 if io_gate.dumb? or !STDOUT.tty?
|
||||
return if defined? @ambiguous_width
|
||||
io_gate.move_cursor_column(0)
|
||||
begin
|
||||
@ -573,31 +574,19 @@ module Reline
|
||||
|
||||
# Need to change IOGate when `$stdout.tty?` change from false to true by `$stdout.reopen`
|
||||
# Example: rails/spring boot the application in non-tty, then run console in tty.
|
||||
if ENV['TERM'] != 'dumb' && core.io_gate == Reline::GeneralIO && $stdout.tty?
|
||||
require 'reline/ansi'
|
||||
if ENV['TERM'] != 'dumb' && core.io_gate.dumb? && $stdout.tty?
|
||||
require 'reline/io/ansi'
|
||||
remove_const(:IOGate)
|
||||
const_set(:IOGate, Reline::ANSI)
|
||||
const_set(:IOGate, Reline::ANSI.new)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'reline/general_io'
|
||||
io = Reline::GeneralIO
|
||||
unless ENV['TERM'] == 'dumb'
|
||||
case RbConfig::CONFIG['host_os']
|
||||
when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
||||
require 'reline/windows'
|
||||
tty = (io = Reline::Windows).msys_tty?
|
||||
else
|
||||
tty = $stdout.tty?
|
||||
end
|
||||
end
|
||||
Reline::IOGate = if tty
|
||||
require 'reline/ansi'
|
||||
Reline::ANSI
|
||||
else
|
||||
io
|
||||
end
|
||||
|
||||
Reline::IOGate = Reline::IO.decide_io_gate
|
||||
|
||||
# Deprecated
|
||||
Reline::GeneralIO = Reline::Dumb.new
|
||||
|
||||
Reline::Face.load_initial_configs
|
||||
|
||||
|
@ -1,111 +0,0 @@
|
||||
require 'io/wait'
|
||||
|
||||
class Reline::GeneralIO
|
||||
RESET_COLOR = '' # Do not send color reset sequence
|
||||
|
||||
def self.reset(encoding: nil)
|
||||
@@pasting = false
|
||||
if encoding
|
||||
@@encoding = encoding
|
||||
elsif defined?(@@encoding)
|
||||
remove_class_variable(:@@encoding)
|
||||
end
|
||||
end
|
||||
|
||||
def self.encoding
|
||||
if defined?(@@encoding)
|
||||
@@encoding
|
||||
elsif RUBY_PLATFORM =~ /mswin|mingw/
|
||||
Encoding::UTF_8
|
||||
else
|
||||
Encoding::default_external
|
||||
end
|
||||
end
|
||||
|
||||
def self.win?
|
||||
false
|
||||
end
|
||||
|
||||
def self.set_default_key_bindings(_)
|
||||
end
|
||||
|
||||
@@buf = []
|
||||
@@input = STDIN
|
||||
|
||||
def self.input=(val)
|
||||
@@input = val
|
||||
end
|
||||
|
||||
def self.with_raw_input
|
||||
yield
|
||||
end
|
||||
|
||||
def self.getc(_timeout_second)
|
||||
unless @@buf.empty?
|
||||
return @@buf.shift
|
||||
end
|
||||
c = nil
|
||||
loop do
|
||||
Reline.core.line_editor.handle_signal
|
||||
result = @@input.wait_readable(0.1)
|
||||
next if result.nil?
|
||||
c = @@input.read(1)
|
||||
break
|
||||
end
|
||||
c&.ord
|
||||
end
|
||||
|
||||
def self.ungetc(c)
|
||||
@@buf.unshift(c)
|
||||
end
|
||||
|
||||
def self.get_screen_size
|
||||
[24, 80]
|
||||
end
|
||||
|
||||
def self.cursor_pos
|
||||
Reline::CursorPos.new(1, 1)
|
||||
end
|
||||
|
||||
def self.hide_cursor
|
||||
end
|
||||
|
||||
def self.show_cursor
|
||||
end
|
||||
|
||||
def self.move_cursor_column(val)
|
||||
end
|
||||
|
||||
def self.move_cursor_up(val)
|
||||
end
|
||||
|
||||
def self.move_cursor_down(val)
|
||||
end
|
||||
|
||||
def self.erase_after_cursor
|
||||
end
|
||||
|
||||
def self.scroll_down(val)
|
||||
end
|
||||
|
||||
def self.clear_screen
|
||||
end
|
||||
|
||||
def self.set_screen_size(rows, columns)
|
||||
end
|
||||
|
||||
def self.set_winch_handler(&handler)
|
||||
end
|
||||
|
||||
@@pasting = false
|
||||
|
||||
def self.in_pasting?
|
||||
@@pasting
|
||||
end
|
||||
|
||||
def self.prep
|
||||
end
|
||||
|
||||
def self.deprep(otio)
|
||||
end
|
||||
end
|
45
lib/reline/io.rb
Normal file
45
lib/reline/io.rb
Normal file
@ -0,0 +1,45 @@
|
||||
|
||||
module Reline
|
||||
class IO
|
||||
RESET_COLOR = "\e[0m"
|
||||
|
||||
def self.decide_io_gate
|
||||
if ENV['TERM'] == 'dumb'
|
||||
Reline::Dumb.new
|
||||
else
|
||||
require 'reline/io/ansi'
|
||||
|
||||
case RbConfig::CONFIG['host_os']
|
||||
when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
||||
require 'reline/io/windows'
|
||||
io = Reline::Windows.new
|
||||
if io.msys_tty?
|
||||
Reline::ANSI.new
|
||||
else
|
||||
io
|
||||
end
|
||||
else
|
||||
if $stdout.tty?
|
||||
Reline::ANSI.new
|
||||
else
|
||||
Reline::Dumb.new
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def dumb?
|
||||
false
|
||||
end
|
||||
|
||||
def win?
|
||||
false
|
||||
end
|
||||
|
||||
def reset_color_sequence
|
||||
self.class::RESET_COLOR
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'reline/io/dumb'
|
@ -1,10 +1,7 @@
|
||||
require 'io/console'
|
||||
require 'io/wait'
|
||||
require_relative 'terminfo'
|
||||
|
||||
class Reline::ANSI
|
||||
RESET_COLOR = "\e[0m"
|
||||
|
||||
class Reline::ANSI < Reline::IO
|
||||
CAPNAME_KEY_BINDINGS = {
|
||||
'khome' => :ed_move_to_beg,
|
||||
'kend' => :ed_move_to_end,
|
||||
@ -36,15 +33,18 @@ class Reline::ANSI
|
||||
Reline::Terminfo.setupterm(0, 2)
|
||||
end
|
||||
|
||||
def self.encoding
|
||||
def initialize
|
||||
@input = STDIN
|
||||
@output = STDOUT
|
||||
@buf = []
|
||||
@old_winch_handler = nil
|
||||
end
|
||||
|
||||
def encoding
|
||||
Encoding.default_external
|
||||
end
|
||||
|
||||
def self.win?
|
||||
false
|
||||
end
|
||||
|
||||
def self.set_default_key_bindings(config, allow_terminfo: true)
|
||||
def set_default_key_bindings(config, allow_terminfo: true)
|
||||
set_bracketed_paste_key_bindings(config)
|
||||
set_default_key_bindings_ansi_cursor(config)
|
||||
if allow_terminfo && Reline::Terminfo.enabled?
|
||||
@ -67,13 +67,13 @@ class Reline::ANSI
|
||||
end
|
||||
end
|
||||
|
||||
def self.set_bracketed_paste_key_bindings(config)
|
||||
def set_bracketed_paste_key_bindings(config)
|
||||
[:emacs, :vi_insert, :vi_command].each do |keymap|
|
||||
config.add_default_key_binding_by_keymap(keymap, START_BRACKETED_PASTE.bytes, :bracketed_paste_start)
|
||||
end
|
||||
end
|
||||
|
||||
def self.set_default_key_bindings_ansi_cursor(config)
|
||||
def set_default_key_bindings_ansi_cursor(config)
|
||||
ANSI_CURSOR_KEY_BINDINGS.each do |char, (default_func, modifiers)|
|
||||
bindings = [["\e[#{char}", default_func]] # CSI + char
|
||||
if modifiers[:ctrl]
|
||||
@ -95,7 +95,7 @@ class Reline::ANSI
|
||||
end
|
||||
end
|
||||
|
||||
def self.set_default_key_bindings_terminfo(config)
|
||||
def set_default_key_bindings_terminfo(config)
|
||||
key_bindings = CAPNAME_KEY_BINDINGS.map do |capname, key_binding|
|
||||
begin
|
||||
key_code = Reline::Terminfo.tigetstr(capname)
|
||||
@ -112,7 +112,7 @@ class Reline::ANSI
|
||||
end
|
||||
end
|
||||
|
||||
def self.set_default_key_bindings_comprehensive_list(config)
|
||||
def set_default_key_bindings_comprehensive_list(config)
|
||||
{
|
||||
# Console (80x25)
|
||||
[27, 91, 49, 126] => :ed_move_to_beg, # Home
|
||||
@ -147,37 +147,34 @@ class Reline::ANSI
|
||||
end
|
||||
end
|
||||
|
||||
@@input = STDIN
|
||||
def self.input=(val)
|
||||
@@input = val
|
||||
def input=(val)
|
||||
@input = val
|
||||
end
|
||||
|
||||
@@output = STDOUT
|
||||
def self.output=(val)
|
||||
@@output = val
|
||||
def output=(val)
|
||||
@output = val
|
||||
end
|
||||
|
||||
def self.with_raw_input
|
||||
if @@input.tty?
|
||||
@@input.raw(intr: true) { yield }
|
||||
def with_raw_input
|
||||
if @input.tty?
|
||||
@input.raw(intr: true) { yield }
|
||||
else
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
@@buf = []
|
||||
def self.inner_getc(timeout_second)
|
||||
unless @@buf.empty?
|
||||
return @@buf.shift
|
||||
def inner_getc(timeout_second)
|
||||
unless @buf.empty?
|
||||
return @buf.shift
|
||||
end
|
||||
until @@input.wait_readable(0.01)
|
||||
until @input.wait_readable(0.01)
|
||||
timeout_second -= 0.01
|
||||
return nil if timeout_second <= 0
|
||||
|
||||
Reline.core.line_editor.handle_signal
|
||||
end
|
||||
c = @@input.getbyte
|
||||
(c == 0x16 && @@input.raw(min: 0, time: 0, &:getbyte)) || c
|
||||
c = @input.getbyte
|
||||
(c == 0x16 && @input.raw(min: 0, time: 0, &:getbyte)) || c
|
||||
rescue Errno::EIO
|
||||
# Maybe the I/O has been closed.
|
||||
nil
|
||||
@ -187,7 +184,7 @@ class Reline::ANSI
|
||||
|
||||
START_BRACKETED_PASTE = String.new("\e[200~", encoding: Encoding::ASCII_8BIT)
|
||||
END_BRACKETED_PASTE = String.new("\e[201~", encoding: Encoding::ASCII_8BIT)
|
||||
def self.read_bracketed_paste
|
||||
def read_bracketed_paste
|
||||
buffer = String.new(encoding: Encoding::ASCII_8BIT)
|
||||
until buffer.end_with?(END_BRACKETED_PASTE)
|
||||
c = inner_getc(Float::INFINITY)
|
||||
@ -199,38 +196,38 @@ class Reline::ANSI
|
||||
end
|
||||
|
||||
# if the usage expects to wait indefinitely, use Float::INFINITY for timeout_second
|
||||
def self.getc(timeout_second)
|
||||
def getc(timeout_second)
|
||||
inner_getc(timeout_second)
|
||||
end
|
||||
|
||||
def self.in_pasting?
|
||||
def in_pasting?
|
||||
not empty_buffer?
|
||||
end
|
||||
|
||||
def self.empty_buffer?
|
||||
unless @@buf.empty?
|
||||
def empty_buffer?
|
||||
unless @buf.empty?
|
||||
return false
|
||||
end
|
||||
!@@input.wait_readable(0)
|
||||
!@input.wait_readable(0)
|
||||
end
|
||||
|
||||
def self.ungetc(c)
|
||||
@@buf.unshift(c)
|
||||
def ungetc(c)
|
||||
@buf.unshift(c)
|
||||
end
|
||||
|
||||
def self.retrieve_keybuffer
|
||||
def retrieve_keybuffer
|
||||
begin
|
||||
return unless @@input.wait_readable(0.001)
|
||||
str = @@input.read_nonblock(1024)
|
||||
return unless @input.wait_readable(0.001)
|
||||
str = @input.read_nonblock(1024)
|
||||
str.bytes.each do |c|
|
||||
@@buf.push(c)
|
||||
@buf.push(c)
|
||||
end
|
||||
rescue EOFError
|
||||
end
|
||||
end
|
||||
|
||||
def self.get_screen_size
|
||||
s = @@input.winsize
|
||||
def get_screen_size
|
||||
s = @input.winsize
|
||||
return s if s[0] > 0 && s[1] > 0
|
||||
s = [ENV["LINES"].to_i, ENV["COLUMNS"].to_i]
|
||||
return s if s[0] > 0 && s[1] > 0
|
||||
@ -239,20 +236,20 @@ class Reline::ANSI
|
||||
[24, 80]
|
||||
end
|
||||
|
||||
def self.set_screen_size(rows, columns)
|
||||
@@input.winsize = [rows, columns]
|
||||
def set_screen_size(rows, columns)
|
||||
@input.winsize = [rows, columns]
|
||||
self
|
||||
rescue Errno::ENOTTY
|
||||
self
|
||||
end
|
||||
|
||||
def self.cursor_pos
|
||||
def cursor_pos
|
||||
begin
|
||||
res = +''
|
||||
m = nil
|
||||
@@input.raw do |stdin|
|
||||
@@output << "\e[6n"
|
||||
@@output.flush
|
||||
@input.raw do |stdin|
|
||||
@output << "\e[6n"
|
||||
@output.flush
|
||||
loop do
|
||||
c = stdin.getc
|
||||
next if c.nil?
|
||||
@ -268,7 +265,7 @@ class Reline::ANSI
|
||||
row = m[:row].to_i - 1
|
||||
rescue Errno::ENOTTY
|
||||
begin
|
||||
buf = @@output.pread(@@output.pos, 0)
|
||||
buf = @output.pread(@output.pos, 0)
|
||||
row = buf.count("\n")
|
||||
column = buf.rindex("\n") ? (buf.size - buf.rindex("\n")) - 1 : 0
|
||||
rescue Errno::ESPIPE, IOError
|
||||
@ -281,30 +278,30 @@ class Reline::ANSI
|
||||
Reline::CursorPos.new(column, row)
|
||||
end
|
||||
|
||||
def self.move_cursor_column(x)
|
||||
@@output.write "\e[#{x + 1}G"
|
||||
def move_cursor_column(x)
|
||||
@output.write "\e[#{x + 1}G"
|
||||
end
|
||||
|
||||
def self.move_cursor_up(x)
|
||||
def move_cursor_up(x)
|
||||
if x > 0
|
||||
@@output.write "\e[#{x}A"
|
||||
@output.write "\e[#{x}A"
|
||||
elsif x < 0
|
||||
move_cursor_down(-x)
|
||||
end
|
||||
end
|
||||
|
||||
def self.move_cursor_down(x)
|
||||
def move_cursor_down(x)
|
||||
if x > 0
|
||||
@@output.write "\e[#{x}B"
|
||||
@output.write "\e[#{x}B"
|
||||
elsif x < 0
|
||||
move_cursor_up(-x)
|
||||
end
|
||||
end
|
||||
|
||||
def self.hide_cursor
|
||||
def hide_cursor
|
||||
if Reline::Terminfo.enabled? && Reline::Terminfo.term_supported?
|
||||
begin
|
||||
@@output.write Reline::Terminfo.tigetstr('civis')
|
||||
@output.write Reline::Terminfo.tigetstr('civis')
|
||||
rescue Reline::Terminfo::TerminfoError
|
||||
# civis is undefined
|
||||
end
|
||||
@ -313,10 +310,10 @@ class Reline::ANSI
|
||||
end
|
||||
end
|
||||
|
||||
def self.show_cursor
|
||||
def show_cursor
|
||||
if Reline::Terminfo.enabled? && Reline::Terminfo.term_supported?
|
||||
begin
|
||||
@@output.write Reline::Terminfo.tigetstr('cnorm')
|
||||
@output.write Reline::Terminfo.tigetstr('cnorm')
|
||||
rescue Reline::Terminfo::TerminfoError
|
||||
# cnorm is undefined
|
||||
end
|
||||
@ -325,38 +322,37 @@ class Reline::ANSI
|
||||
end
|
||||
end
|
||||
|
||||
def self.erase_after_cursor
|
||||
@@output.write "\e[K"
|
||||
def erase_after_cursor
|
||||
@output.write "\e[K"
|
||||
end
|
||||
|
||||
# This only works when the cursor is at the bottom of the scroll range
|
||||
# For more details, see https://github.com/ruby/reline/pull/577#issuecomment-1646679623
|
||||
def self.scroll_down(x)
|
||||
def scroll_down(x)
|
||||
return if x.zero?
|
||||
# We use `\n` instead of CSI + S because CSI + S would cause https://github.com/ruby/reline/issues/576
|
||||
@@output.write "\n" * x
|
||||
@output.write "\n" * x
|
||||
end
|
||||
|
||||
def self.clear_screen
|
||||
@@output.write "\e[2J"
|
||||
@@output.write "\e[1;1H"
|
||||
def clear_screen
|
||||
@output.write "\e[2J"
|
||||
@output.write "\e[1;1H"
|
||||
end
|
||||
|
||||
@@old_winch_handler = nil
|
||||
def self.set_winch_handler(&handler)
|
||||
@@old_winch_handler = Signal.trap('WINCH', &handler)
|
||||
def set_winch_handler(&handler)
|
||||
@old_winch_handler = Signal.trap('WINCH', &handler)
|
||||
end
|
||||
|
||||
def self.prep
|
||||
def prep
|
||||
# Enable bracketed paste
|
||||
@@output.write "\e[?2004h" if Reline.core.config.enable_bracketed_paste
|
||||
@output.write "\e[?2004h" if Reline.core.config.enable_bracketed_paste
|
||||
retrieve_keybuffer
|
||||
nil
|
||||
end
|
||||
|
||||
def self.deprep(otio)
|
||||
def deprep(otio)
|
||||
# Disable bracketed paste
|
||||
@@output.write "\e[?2004l" if Reline.core.config.enable_bracketed_paste
|
||||
Signal.trap('WINCH', @@old_winch_handler) if @@old_winch_handler
|
||||
@output.write "\e[?2004l" if Reline.core.config.enable_bracketed_paste
|
||||
Signal.trap('WINCH', @old_winch_handler) if @old_winch_handler
|
||||
end
|
||||
end
|
106
lib/reline/io/dumb.rb
Normal file
106
lib/reline/io/dumb.rb
Normal file
@ -0,0 +1,106 @@
|
||||
require 'io/wait'
|
||||
|
||||
class Reline::Dumb < Reline::IO
|
||||
RESET_COLOR = '' # Do not send color reset sequence
|
||||
|
||||
def initialize(encoding: nil)
|
||||
@input = STDIN
|
||||
@buf = []
|
||||
@pasting = false
|
||||
@encoding = encoding
|
||||
@screen_size = [24, 80]
|
||||
end
|
||||
|
||||
def dumb?
|
||||
true
|
||||
end
|
||||
|
||||
def encoding
|
||||
if @encoding
|
||||
@encoding
|
||||
elsif RUBY_PLATFORM =~ /mswin|mingw/
|
||||
Encoding::UTF_8
|
||||
else
|
||||
Encoding::default_external
|
||||
end
|
||||
end
|
||||
|
||||
def set_default_key_bindings(_)
|
||||
end
|
||||
|
||||
def input=(val)
|
||||
@input = val
|
||||
end
|
||||
|
||||
def with_raw_input
|
||||
yield
|
||||
end
|
||||
|
||||
def getc(_timeout_second)
|
||||
unless @buf.empty?
|
||||
return @buf.shift
|
||||
end
|
||||
c = nil
|
||||
loop do
|
||||
Reline.core.line_editor.handle_signal
|
||||
result = @input.wait_readable(0.1)
|
||||
next if result.nil?
|
||||
c = @input.read(1)
|
||||
break
|
||||
end
|
||||
c&.ord
|
||||
end
|
||||
|
||||
def ungetc(c)
|
||||
@buf.unshift(c)
|
||||
end
|
||||
|
||||
def get_screen_size
|
||||
@screen_size
|
||||
end
|
||||
|
||||
def cursor_pos
|
||||
Reline::CursorPos.new(1, 1)
|
||||
end
|
||||
|
||||
def hide_cursor
|
||||
end
|
||||
|
||||
def show_cursor
|
||||
end
|
||||
|
||||
def move_cursor_column(val)
|
||||
end
|
||||
|
||||
def move_cursor_up(val)
|
||||
end
|
||||
|
||||
def move_cursor_down(val)
|
||||
end
|
||||
|
||||
def erase_after_cursor
|
||||
end
|
||||
|
||||
def scroll_down(val)
|
||||
end
|
||||
|
||||
def clear_screen
|
||||
end
|
||||
|
||||
def set_screen_size(rows, columns)
|
||||
@screen_size = [rows, columns]
|
||||
end
|
||||
|
||||
def set_winch_handler(&handler)
|
||||
end
|
||||
|
||||
def in_pasting?
|
||||
@pasting
|
||||
end
|
||||
|
||||
def prep
|
||||
end
|
||||
|
||||
def deprep(otio)
|
||||
end
|
||||
end
|
@ -1,21 +1,49 @@
|
||||
require 'fiddle/import'
|
||||
|
||||
class Reline::Windows
|
||||
RESET_COLOR = "\e[0m"
|
||||
class Reline::Windows < Reline::IO
|
||||
def initialize
|
||||
@input_buf = []
|
||||
@output_buf = []
|
||||
|
||||
def self.encoding
|
||||
@output = STDOUT
|
||||
@hsg = nil
|
||||
@getwch = Win32API.new('msvcrt', '_getwch', [], 'I')
|
||||
@kbhit = Win32API.new('msvcrt', '_kbhit', [], 'I')
|
||||
@GetKeyState = Win32API.new('user32', 'GetKeyState', ['L'], 'L')
|
||||
@GetConsoleScreenBufferInfo = Win32API.new('kernel32', 'GetConsoleScreenBufferInfo', ['L', 'P'], 'L')
|
||||
@SetConsoleCursorPosition = Win32API.new('kernel32', 'SetConsoleCursorPosition', ['L', 'L'], 'L')
|
||||
@GetStdHandle = Win32API.new('kernel32', 'GetStdHandle', ['L'], 'L')
|
||||
@FillConsoleOutputCharacter = Win32API.new('kernel32', 'FillConsoleOutputCharacter', ['L', 'L', 'L', 'L', 'P'], 'L')
|
||||
@ScrollConsoleScreenBuffer = Win32API.new('kernel32', 'ScrollConsoleScreenBuffer', ['L', 'P', 'P', 'L', 'P'], 'L')
|
||||
@hConsoleHandle = @GetStdHandle.call(STD_OUTPUT_HANDLE)
|
||||
@hConsoleInputHandle = @GetStdHandle.call(STD_INPUT_HANDLE)
|
||||
@GetNumberOfConsoleInputEvents = Win32API.new('kernel32', 'GetNumberOfConsoleInputEvents', ['L', 'P'], 'L')
|
||||
@ReadConsoleInputW = Win32API.new('kernel32', 'ReadConsoleInputW', ['L', 'P', 'L', 'P'], 'L')
|
||||
@GetFileType = Win32API.new('kernel32', 'GetFileType', ['L'], 'L')
|
||||
@GetFileInformationByHandleEx = Win32API.new('kernel32', 'GetFileInformationByHandleEx', ['L', 'I', 'P', 'L'], 'I')
|
||||
@FillConsoleOutputAttribute = Win32API.new('kernel32', 'FillConsoleOutputAttribute', ['L', 'L', 'L', 'L', 'P'], 'L')
|
||||
@SetConsoleCursorInfo = Win32API.new('kernel32', 'SetConsoleCursorInfo', ['L', 'P'], 'L')
|
||||
|
||||
@GetConsoleMode = Win32API.new('kernel32', 'GetConsoleMode', ['L', 'P'], 'L')
|
||||
@SetConsoleMode = Win32API.new('kernel32', 'SetConsoleMode', ['L', 'L'], 'L')
|
||||
@WaitForSingleObject = Win32API.new('kernel32', 'WaitForSingleObject', ['L', 'L'], 'L')
|
||||
|
||||
@legacy_console = getconsolemode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0
|
||||
end
|
||||
|
||||
def encoding
|
||||
Encoding::UTF_8
|
||||
end
|
||||
|
||||
def self.win?
|
||||
def win?
|
||||
true
|
||||
end
|
||||
|
||||
def self.win_legacy_console?
|
||||
@@legacy_console
|
||||
def win_legacy_console?
|
||||
@legacy_console
|
||||
end
|
||||
|
||||
def self.set_default_key_bindings(config)
|
||||
def set_default_key_bindings(config)
|
||||
{
|
||||
[224, 72] => :ed_prev_history, # ↑
|
||||
[224, 80] => :ed_next_history, # ↓
|
||||
@ -129,58 +157,32 @@ class Reline::Windows
|
||||
STD_OUTPUT_HANDLE = -11
|
||||
FILE_TYPE_PIPE = 0x0003
|
||||
FILE_NAME_INFO = 2
|
||||
@@getwch = Win32API.new('msvcrt', '_getwch', [], 'I')
|
||||
@@kbhit = Win32API.new('msvcrt', '_kbhit', [], 'I')
|
||||
@@GetKeyState = Win32API.new('user32', 'GetKeyState', ['L'], 'L')
|
||||
@@GetConsoleScreenBufferInfo = Win32API.new('kernel32', 'GetConsoleScreenBufferInfo', ['L', 'P'], 'L')
|
||||
@@SetConsoleCursorPosition = Win32API.new('kernel32', 'SetConsoleCursorPosition', ['L', 'L'], 'L')
|
||||
@@GetStdHandle = Win32API.new('kernel32', 'GetStdHandle', ['L'], 'L')
|
||||
@@FillConsoleOutputCharacter = Win32API.new('kernel32', 'FillConsoleOutputCharacter', ['L', 'L', 'L', 'L', 'P'], 'L')
|
||||
@@ScrollConsoleScreenBuffer = Win32API.new('kernel32', 'ScrollConsoleScreenBuffer', ['L', 'P', 'P', 'L', 'P'], 'L')
|
||||
@@hConsoleHandle = @@GetStdHandle.call(STD_OUTPUT_HANDLE)
|
||||
@@hConsoleInputHandle = @@GetStdHandle.call(STD_INPUT_HANDLE)
|
||||
@@GetNumberOfConsoleInputEvents = Win32API.new('kernel32', 'GetNumberOfConsoleInputEvents', ['L', 'P'], 'L')
|
||||
@@ReadConsoleInputW = Win32API.new('kernel32', 'ReadConsoleInputW', ['L', 'P', 'L', 'P'], 'L')
|
||||
@@GetFileType = Win32API.new('kernel32', 'GetFileType', ['L'], 'L')
|
||||
@@GetFileInformationByHandleEx = Win32API.new('kernel32', 'GetFileInformationByHandleEx', ['L', 'I', 'P', 'L'], 'I')
|
||||
@@FillConsoleOutputAttribute = Win32API.new('kernel32', 'FillConsoleOutputAttribute', ['L', 'L', 'L', 'L', 'P'], 'L')
|
||||
@@SetConsoleCursorInfo = Win32API.new('kernel32', 'SetConsoleCursorInfo', ['L', 'P'], 'L')
|
||||
|
||||
@@GetConsoleMode = Win32API.new('kernel32', 'GetConsoleMode', ['L', 'P'], 'L')
|
||||
@@SetConsoleMode = Win32API.new('kernel32', 'SetConsoleMode', ['L', 'L'], 'L')
|
||||
@@WaitForSingleObject = Win32API.new('kernel32', 'WaitForSingleObject', ['L', 'L'], 'L')
|
||||
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
|
||||
|
||||
private_class_method def self.getconsolemode
|
||||
private def getconsolemode
|
||||
mode = "\000\000\000\000"
|
||||
@@GetConsoleMode.call(@@hConsoleHandle, mode)
|
||||
@GetConsoleMode.call(@hConsoleHandle, mode)
|
||||
mode.unpack1('L')
|
||||
end
|
||||
|
||||
private_class_method def self.setconsolemode(mode)
|
||||
@@SetConsoleMode.call(@@hConsoleHandle, mode)
|
||||
private def setconsolemode(mode)
|
||||
@SetConsoleMode.call(@hConsoleHandle, mode)
|
||||
end
|
||||
|
||||
@@legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
|
||||
#if @@legacy_console
|
||||
#if @legacy_console
|
||||
# setconsolemode(getconsolemode() | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
|
||||
# @@legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
|
||||
# @legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
|
||||
#end
|
||||
|
||||
@@input_buf = []
|
||||
@@output_buf = []
|
||||
|
||||
@@output = STDOUT
|
||||
|
||||
def self.msys_tty?(io = @@hConsoleInputHandle)
|
||||
def msys_tty?(io = @hConsoleInputHandle)
|
||||
# check if fd is a pipe
|
||||
if @@GetFileType.call(io) != FILE_TYPE_PIPE
|
||||
if @GetFileType.call(io) != FILE_TYPE_PIPE
|
||||
return false
|
||||
end
|
||||
|
||||
bufsize = 1024
|
||||
p_buffer = "\0" * bufsize
|
||||
res = @@GetFileInformationByHandleEx.call(io, FILE_NAME_INFO, p_buffer, bufsize - 2)
|
||||
res = @GetFileInformationByHandleEx.call(io, FILE_NAME_INFO, p_buffer, bufsize - 2)
|
||||
return false if res == 0
|
||||
|
||||
# get pipe name: p_buffer layout is:
|
||||
@ -217,65 +219,63 @@ class Reline::Windows
|
||||
[ { control_keys: :SHIFT, virtual_key_code: VK_TAB }, [27, 91, 90] ],
|
||||
]
|
||||
|
||||
@@hsg = nil
|
||||
|
||||
def self.process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
|
||||
def process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
|
||||
|
||||
# high-surrogate
|
||||
if 0xD800 <= char_code and char_code <= 0xDBFF
|
||||
@@hsg = char_code
|
||||
@hsg = char_code
|
||||
return
|
||||
end
|
||||
# low-surrogate
|
||||
if 0xDC00 <= char_code and char_code <= 0xDFFF
|
||||
if @@hsg
|
||||
char_code = 0x10000 + (@@hsg - 0xD800) * 0x400 + char_code - 0xDC00
|
||||
@@hsg = nil
|
||||
if @hsg
|
||||
char_code = 0x10000 + (@hsg - 0xD800) * 0x400 + char_code - 0xDC00
|
||||
@hsg = nil
|
||||
else
|
||||
# no high-surrogate. ignored.
|
||||
return
|
||||
end
|
||||
else
|
||||
# ignore high-surrogate without low-surrogate if there
|
||||
@@hsg = nil
|
||||
@hsg = nil
|
||||
end
|
||||
|
||||
key = KeyEventRecord.new(virtual_key_code, char_code, control_key_state)
|
||||
|
||||
match = KEY_MAP.find { |args,| key.matches?(**args) }
|
||||
unless match.nil?
|
||||
@@output_buf.concat(match.last)
|
||||
@output_buf.concat(match.last)
|
||||
return
|
||||
end
|
||||
|
||||
# no char, only control keys
|
||||
return if key.char_code == 0 and key.control_keys.any?
|
||||
|
||||
@@output_buf.push("\e".ord) if key.control_keys.include?(:ALT) and !key.control_keys.include?(:CTRL)
|
||||
@output_buf.push("\e".ord) if key.control_keys.include?(:ALT) and !key.control_keys.include?(:CTRL)
|
||||
|
||||
@@output_buf.concat(key.char.bytes)
|
||||
@output_buf.concat(key.char.bytes)
|
||||
end
|
||||
|
||||
def self.check_input_event
|
||||
def check_input_event
|
||||
num_of_events = 0.chr * 8
|
||||
while @@output_buf.empty?
|
||||
while @output_buf.empty?
|
||||
Reline.core.line_editor.handle_signal
|
||||
if @@WaitForSingleObject.(@@hConsoleInputHandle, 100) != 0 # max 0.1 sec
|
||||
if @WaitForSingleObject.(@hConsoleInputHandle, 100) != 0 # max 0.1 sec
|
||||
# prevent for background consolemode change
|
||||
@@legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
|
||||
@legacy_console = getconsolemode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0
|
||||
next
|
||||
end
|
||||
next if @@GetNumberOfConsoleInputEvents.(@@hConsoleInputHandle, num_of_events) == 0 or num_of_events.unpack1('L') == 0
|
||||
next if @GetNumberOfConsoleInputEvents.(@hConsoleInputHandle, num_of_events) == 0 or num_of_events.unpack1('L') == 0
|
||||
input_records = 0.chr * 20 * 80
|
||||
read_event = 0.chr * 4
|
||||
if @@ReadConsoleInputW.(@@hConsoleInputHandle, input_records, 80, read_event) != 0
|
||||
if @ReadConsoleInputW.(@hConsoleInputHandle, input_records, 80, read_event) != 0
|
||||
read_events = read_event.unpack1('L')
|
||||
0.upto(read_events) do |idx|
|
||||
input_record = input_records[idx * 20, 20]
|
||||
event = input_record[0, 2].unpack1('s*')
|
||||
case event
|
||||
when WINDOW_BUFFER_SIZE_EVENT
|
||||
@@winch_handler.()
|
||||
@winch_handler.()
|
||||
when KEY_EVENT
|
||||
key_down = input_record[4, 4].unpack1('l*')
|
||||
repeat_count = input_record[8, 2].unpack1('s*')
|
||||
@ -293,34 +293,34 @@ class Reline::Windows
|
||||
end
|
||||
end
|
||||
|
||||
def self.with_raw_input
|
||||
def with_raw_input
|
||||
yield
|
||||
end
|
||||
|
||||
def self.getc(_timeout_second)
|
||||
def getc(_timeout_second)
|
||||
check_input_event
|
||||
@@output_buf.shift
|
||||
@output_buf.shift
|
||||
end
|
||||
|
||||
def self.ungetc(c)
|
||||
@@output_buf.unshift(c)
|
||||
def ungetc(c)
|
||||
@output_buf.unshift(c)
|
||||
end
|
||||
|
||||
def self.in_pasting?
|
||||
not self.empty_buffer?
|
||||
def in_pasting?
|
||||
not empty_buffer?
|
||||
end
|
||||
|
||||
def self.empty_buffer?
|
||||
if not @@output_buf.empty?
|
||||
def empty_buffer?
|
||||
if not @output_buf.empty?
|
||||
false
|
||||
elsif @@kbhit.call == 0
|
||||
elsif @kbhit.call == 0
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def self.get_console_screen_buffer_info
|
||||
def get_console_screen_buffer_info
|
||||
# CONSOLE_SCREEN_BUFFER_INFO
|
||||
# [ 0,2] dwSize.X
|
||||
# [ 2,2] dwSize.Y
|
||||
@ -334,18 +334,18 @@ class Reline::Windows
|
||||
# [18,2] dwMaximumWindowSize.X
|
||||
# [20,2] dwMaximumWindowSize.Y
|
||||
csbi = 0.chr * 22
|
||||
return if @@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi) == 0
|
||||
return if @GetConsoleScreenBufferInfo.call(@hConsoleHandle, csbi) == 0
|
||||
csbi
|
||||
end
|
||||
|
||||
def self.get_screen_size
|
||||
def get_screen_size
|
||||
unless csbi = get_console_screen_buffer_info
|
||||
return [1, 1]
|
||||
end
|
||||
csbi[0, 4].unpack('SS').reverse
|
||||
end
|
||||
|
||||
def self.cursor_pos
|
||||
def cursor_pos
|
||||
unless csbi = get_console_screen_buffer_info
|
||||
return Reline::CursorPos.new(0, 0)
|
||||
end
|
||||
@ -354,49 +354,49 @@ class Reline::Windows
|
||||
Reline::CursorPos.new(x, y)
|
||||
end
|
||||
|
||||
def self.move_cursor_column(val)
|
||||
@@SetConsoleCursorPosition.call(@@hConsoleHandle, cursor_pos.y * 65536 + val)
|
||||
def move_cursor_column(val)
|
||||
@SetConsoleCursorPosition.call(@hConsoleHandle, cursor_pos.y * 65536 + val)
|
||||
end
|
||||
|
||||
def self.move_cursor_up(val)
|
||||
def move_cursor_up(val)
|
||||
if val > 0
|
||||
y = cursor_pos.y - val
|
||||
y = 0 if y < 0
|
||||
@@SetConsoleCursorPosition.call(@@hConsoleHandle, y * 65536 + cursor_pos.x)
|
||||
@SetConsoleCursorPosition.call(@hConsoleHandle, y * 65536 + cursor_pos.x)
|
||||
elsif val < 0
|
||||
move_cursor_down(-val)
|
||||
end
|
||||
end
|
||||
|
||||
def self.move_cursor_down(val)
|
||||
def move_cursor_down(val)
|
||||
if val > 0
|
||||
return unless csbi = get_console_screen_buffer_info
|
||||
screen_height = get_screen_size.first
|
||||
y = cursor_pos.y + val
|
||||
y = screen_height - 1 if y > (screen_height - 1)
|
||||
@@SetConsoleCursorPosition.call(@@hConsoleHandle, (cursor_pos.y + val) * 65536 + cursor_pos.x)
|
||||
@SetConsoleCursorPosition.call(@hConsoleHandle, (cursor_pos.y + val) * 65536 + cursor_pos.x)
|
||||
elsif val < 0
|
||||
move_cursor_up(-val)
|
||||
end
|
||||
end
|
||||
|
||||
def self.erase_after_cursor
|
||||
def erase_after_cursor
|
||||
return unless csbi = get_console_screen_buffer_info
|
||||
attributes = csbi[8, 2].unpack1('S')
|
||||
cursor = csbi[4, 4].unpack1('L')
|
||||
written = 0.chr * 4
|
||||
@@FillConsoleOutputCharacter.call(@@hConsoleHandle, 0x20, get_screen_size.last - cursor_pos.x, cursor, written)
|
||||
@@FillConsoleOutputAttribute.call(@@hConsoleHandle, attributes, get_screen_size.last - cursor_pos.x, cursor, written)
|
||||
@FillConsoleOutputCharacter.call(@hConsoleHandle, 0x20, get_screen_size.last - cursor_pos.x, cursor, written)
|
||||
@FillConsoleOutputAttribute.call(@hConsoleHandle, attributes, get_screen_size.last - cursor_pos.x, cursor, written)
|
||||
end
|
||||
|
||||
def self.scroll_down(val)
|
||||
def scroll_down(val)
|
||||
return if val < 0
|
||||
return unless csbi = get_console_screen_buffer_info
|
||||
buffer_width, buffer_lines, x, y, attributes, window_left, window_top, window_bottom = csbi.unpack('ssssSssx2s')
|
||||
screen_height = window_bottom - window_top + 1
|
||||
val = screen_height if val > screen_height
|
||||
|
||||
if @@legacy_console || window_left != 0
|
||||
if @legacy_console || window_left != 0
|
||||
# unless ENABLE_VIRTUAL_TERMINAL,
|
||||
# if srWindow.Left != 0 then it's conhost.exe hosted console
|
||||
# and puts "\n" causes horizontal scroll. its glitch.
|
||||
@ -404,11 +404,11 @@ class Reline::Windows
|
||||
scroll_rectangle = [0, val, buffer_width, buffer_lines - val].pack('s4')
|
||||
destination_origin = 0 # y * 65536 + x
|
||||
fill = [' '.ord, attributes].pack('SS')
|
||||
@@ScrollConsoleScreenBuffer.call(@@hConsoleHandle, scroll_rectangle, nil, destination_origin, fill)
|
||||
@ScrollConsoleScreenBuffer.call(@hConsoleHandle, scroll_rectangle, nil, destination_origin, fill)
|
||||
else
|
||||
origin_x = x + 1
|
||||
origin_y = y - window_top + 1
|
||||
@@output.write [
|
||||
@output.write [
|
||||
(origin_y != screen_height) ? "\e[#{screen_height};H" : nil,
|
||||
"\n" * val,
|
||||
(origin_y != screen_height or !x.zero?) ? "\e[#{origin_y};#{origin_x}H" : nil
|
||||
@ -416,49 +416,49 @@ class Reline::Windows
|
||||
end
|
||||
end
|
||||
|
||||
def self.clear_screen
|
||||
if @@legacy_console
|
||||
def clear_screen
|
||||
if @legacy_console
|
||||
return unless csbi = get_console_screen_buffer_info
|
||||
buffer_width, _buffer_lines, attributes, window_top, window_bottom = csbi.unpack('ss@8S@12sx2s')
|
||||
fill_length = buffer_width * (window_bottom - window_top + 1)
|
||||
screen_topleft = window_top * 65536
|
||||
written = 0.chr * 4
|
||||
@@FillConsoleOutputCharacter.call(@@hConsoleHandle, 0x20, fill_length, screen_topleft, written)
|
||||
@@FillConsoleOutputAttribute.call(@@hConsoleHandle, attributes, fill_length, screen_topleft, written)
|
||||
@@SetConsoleCursorPosition.call(@@hConsoleHandle, screen_topleft)
|
||||
@FillConsoleOutputCharacter.call(@hConsoleHandle, 0x20, fill_length, screen_topleft, written)
|
||||
@FillConsoleOutputAttribute.call(@hConsoleHandle, attributes, fill_length, screen_topleft, written)
|
||||
@SetConsoleCursorPosition.call(@hConsoleHandle, screen_topleft)
|
||||
else
|
||||
@@output.write "\e[2J" "\e[H"
|
||||
@output.write "\e[2J" "\e[H"
|
||||
end
|
||||
end
|
||||
|
||||
def self.set_screen_size(rows, columns)
|
||||
def set_screen_size(rows, columns)
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def self.hide_cursor
|
||||
def hide_cursor
|
||||
size = 100
|
||||
visible = 0 # 0 means false
|
||||
cursor_info = [size, visible].pack('Li')
|
||||
@@SetConsoleCursorInfo.call(@@hConsoleHandle, cursor_info)
|
||||
@SetConsoleCursorInfo.call(@hConsoleHandle, cursor_info)
|
||||
end
|
||||
|
||||
def self.show_cursor
|
||||
def show_cursor
|
||||
size = 100
|
||||
visible = 1 # 1 means true
|
||||
cursor_info = [size, visible].pack('Li')
|
||||
@@SetConsoleCursorInfo.call(@@hConsoleHandle, cursor_info)
|
||||
@SetConsoleCursorInfo.call(@hConsoleHandle, cursor_info)
|
||||
end
|
||||
|
||||
def self.set_winch_handler(&handler)
|
||||
@@winch_handler = handler
|
||||
def set_winch_handler(&handler)
|
||||
@winch_handler = handler
|
||||
end
|
||||
|
||||
def self.prep
|
||||
def prep
|
||||
# do nothing
|
||||
nil
|
||||
end
|
||||
|
||||
def self.deprep(otio)
|
||||
def deprep(otio)
|
||||
# do nothing
|
||||
end
|
||||
|
@ -412,7 +412,7 @@ class Reline::LineEditor
|
||||
# do nothing
|
||||
elsif level == :blank
|
||||
Reline::IOGate.move_cursor_column base_x
|
||||
@output.write "#{Reline::IOGate::RESET_COLOR}#{' ' * width}"
|
||||
@output.write "#{Reline::IOGate.reset_color_sequence}#{' ' * width}"
|
||||
else
|
||||
x, w, content = new_items[level]
|
||||
cover_begin = base_x != 0 && new_levels[base_x - 1] == level
|
||||
@ -422,7 +422,7 @@ class Reline::LineEditor
|
||||
content, pos = Reline::Unicode.take_mbchar_range(content, base_x - x, width, cover_begin: cover_begin, cover_end: cover_end, padding: true)
|
||||
end
|
||||
Reline::IOGate.move_cursor_column x + pos
|
||||
@output.write "#{Reline::IOGate::RESET_COLOR}#{content}#{Reline::IOGate::RESET_COLOR}"
|
||||
@output.write "#{Reline::IOGate.reset_color_sequence}#{content}#{Reline::IOGate.reset_color_sequence}"
|
||||
end
|
||||
base_x += width
|
||||
end
|
||||
|
@ -22,29 +22,36 @@ module Reline
|
||||
class <<self
|
||||
def test_mode(ansi: false)
|
||||
@original_iogate = IOGate
|
||||
remove_const('IOGate')
|
||||
const_set('IOGate', ansi ? Reline::ANSI : Reline::GeneralIO)
|
||||
|
||||
if ENV['RELINE_TEST_ENCODING']
|
||||
encoding = Encoding.find(ENV['RELINE_TEST_ENCODING'])
|
||||
else
|
||||
encoding = Encoding::UTF_8
|
||||
end
|
||||
@original_get_screen_size = IOGate.method(:get_screen_size)
|
||||
IOGate.singleton_class.remove_method(:get_screen_size)
|
||||
def IOGate.get_screen_size
|
||||
[24, 80]
|
||||
|
||||
if ansi
|
||||
new_io_gate = ANSI.new
|
||||
# Setting ANSI gate's screen size through set_screen_size will also change the tester's stdin's screen size
|
||||
# Let's avoid that side-effect by stubbing the get_screen_size method
|
||||
new_io_gate.define_singleton_method(:get_screen_size) do
|
||||
[24, 80]
|
||||
end
|
||||
new_io_gate.define_singleton_method(:encoding) do
|
||||
encoding
|
||||
end
|
||||
else
|
||||
new_io_gate = Dumb.new(encoding: encoding)
|
||||
end
|
||||
Reline::GeneralIO.reset(encoding: encoding) unless ansi
|
||||
|
||||
remove_const('IOGate')
|
||||
const_set('IOGate', new_io_gate)
|
||||
core.config.instance_variable_set(:@test_mode, true)
|
||||
core.config.reset
|
||||
end
|
||||
|
||||
def test_reset
|
||||
IOGate.singleton_class.remove_method(:get_screen_size)
|
||||
IOGate.define_singleton_method(:get_screen_size, @original_get_screen_size)
|
||||
remove_const('IOGate')
|
||||
const_set('IOGate', @original_iogate)
|
||||
Reline::GeneralIO.reset
|
||||
Reline.instance_variable_set(:@core, nil)
|
||||
end
|
||||
|
||||
@ -146,7 +153,7 @@ class Reline::TestCase < Test::Unit::TestCase
|
||||
expected.bytesize, byte_pointer,
|
||||
<<~EOM)
|
||||
<#{expected.inspect} (#{expected.encoding.inspect})> expected but was
|
||||
<#{chunk.inspect} (#{chunk.encoding.inspect})> in <Terminal #{Reline::GeneralIO.encoding.inspect}>
|
||||
<#{chunk.inspect} (#{chunk.encoding.inspect})> in <Terminal #{Reline::Dumb.new.encoding.inspect}>
|
||||
EOM
|
||||
end
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
require_relative 'helper'
|
||||
require 'reline/ansi'
|
||||
require 'reline'
|
||||
|
||||
class Reline::ANSI::TestWithTerminfo < Reline::TestCase
|
||||
class Reline::ANSI::WithTerminfoTest < Reline::TestCase
|
||||
def setup
|
||||
Reline.send(:test_mode, ansi: true)
|
||||
@config = Reline::Config.new
|
||||
|
@ -1,7 +1,7 @@
|
||||
require_relative 'helper'
|
||||
require 'reline/ansi'
|
||||
require 'reline'
|
||||
|
||||
class Reline::ANSI::TestWithoutTerminfo < Reline::TestCase
|
||||
class Reline::ANSI::WithoutTerminfoTest < Reline::TestCase
|
||||
def setup
|
||||
Reline.send(:test_mode, ansi: true)
|
||||
@config = Reline::Config.new
|
||||
|
@ -85,15 +85,13 @@ class Reline::Config::Test < Reline::TestCase
|
||||
|
||||
def test_encoding_is_ascii
|
||||
@config.reset
|
||||
Reline.core.io_gate.reset(encoding: Encoding::US_ASCII)
|
||||
Reline.core.io_gate.instance_variable_set(:@encoding, Encoding::US_ASCII)
|
||||
@config = Reline::Config.new
|
||||
|
||||
assert_equal true, @config.convert_meta
|
||||
end
|
||||
|
||||
def test_encoding_is_not_ascii
|
||||
@config.reset
|
||||
Reline.core.io_gate.reset(encoding: Encoding::UTF_8)
|
||||
@config = Reline::Config.new
|
||||
|
||||
assert_equal nil, @config.convert_meta
|
||||
|
@ -4,14 +4,12 @@ require 'stringio'
|
||||
|
||||
class Reline::LineEditor
|
||||
class RenderLineDifferentialTest < Reline::TestCase
|
||||
module TestIO
|
||||
RESET_COLOR = "\e[0m"
|
||||
|
||||
def self.move_cursor_column(col)
|
||||
class TestIO < Reline::IO
|
||||
def move_cursor_column(col)
|
||||
@output << "[COL_#{col}]"
|
||||
end
|
||||
|
||||
def self.erase_after_cursor
|
||||
def erase_after_cursor
|
||||
@output << '[ERASE]'
|
||||
end
|
||||
end
|
||||
@ -24,7 +22,7 @@ class Reline::LineEditor
|
||||
@line_editor.instance_variable_set(:@screen_size, [24, 80])
|
||||
@line_editor.instance_variable_set(:@output, @output)
|
||||
Reline.send(:remove_const, :IOGate)
|
||||
Reline.const_set(:IOGate, TestIO)
|
||||
Reline.const_set(:IOGate, TestIO.new)
|
||||
Reline::IOGate.instance_variable_set(:@output, @output)
|
||||
ensure
|
||||
$VERBOSE = verbose
|
||||
|
@ -375,7 +375,7 @@ class Reline::Test < Reline::TestCase
|
||||
def test_dumb_terminal
|
||||
lib = File.expand_path("../../lib", __dir__)
|
||||
out = IO.popen([{"TERM"=>"dumb"}, Reline.test_rubybin, "-I#{lib}", "-rreline", "-e", "p Reline.core.io_gate"], &:read)
|
||||
assert_equal("Reline::GeneralIO", out.chomp)
|
||||
assert_match(/#<Reline::Dumb/, out.chomp)
|
||||
end
|
||||
|
||||
def test_require_reline_should_not_trigger_winsize
|
||||
@ -389,7 +389,7 @@ class Reline::Test < Reline::TestCase
|
||||
require("reline") && p(Reline.core.io_gate)
|
||||
RUBY
|
||||
out = IO.popen([{}, Reline.test_rubybin, "-I#{lib}", "-e", code], &:read)
|
||||
assert_equal("Reline::ANSI", out.chomp)
|
||||
assert_include(out.chomp, "Reline::ANSI")
|
||||
end
|
||||
|
||||
def win?
|
||||
|
Loading…
x
Reference in New Issue
Block a user