Skip to content

Commit

Permalink
Reline::ANSI is general io. Reline::GeneralIO is not.
Browse files Browse the repository at this point in the history
Reline::ANSI has a partial non-tty supporting code. It should be a general io.
Reline::GeneralIO should be renamed because it is actually not a general io but an unusable io only for test usage.
  • Loading branch information
tompng committed Mar 23, 2024
1 parent 9685db5 commit 9621e0b
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 44 deletions.
44 changes: 14 additions & 30 deletions lib/reline.rb
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,6 @@ def get_screen_size
Reline::DEFAULT_DIALOG_CONTEXT = Array.new

def readmultiline(prompt = '', add_hist = false, &confirm_multiline_termination)
Reline.update_iogate
io_gate.with_raw_input do
unless confirm_multiline_termination
raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
Expand All @@ -288,8 +287,9 @@ def readmultiline(prompt = '', add_hist = false, &confirm_multiline_termination)
end

def readline(prompt = '', add_hist = false)
Reline.update_iogate
inner_readline(prompt, add_hist, false)
io_gate.with_raw_input do
inner_readline(prompt, add_hist, false)
end

line = line_editor.line.dup
line.taint if RUBY_VERSION < '2.7'
Expand Down Expand Up @@ -473,7 +473,7 @@ def ambiguous_width
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 == Reline::TestDumbIO || !STDIN.tty? || !STDOUT.tty?
return if defined? @ambiguous_width
io_gate.move_cursor_column(0)
begin
Expand Down Expand Up @@ -567,38 +567,22 @@ def self.ungetc(c)
def self.line_editor
core.line_editor
end

def self.update_iogate
return if core.config.test_mode

# 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'
remove_const(:IOGate)
const_set(:IOGate, Reline::ANSI)
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
require 'reline/test_dumb_io'
if ENV['TERM'] == 'dumb'
io = Reline::TestDumbIO
elsif /mswin|msys|mingw|cygwin|bccwin|wince|emc/.match?(RbConfig::CONFIG['host_os'])
require 'reline/windows'
io = Reline::Windows unless Reline::Windows.msys_tty?
end
Reline::IOGate = if tty
unless io
require 'reline/ansi'
Reline::ANSI
else
io
io = Reline::ANSI
end

Reline::IOGate = io

Reline::Face.load_initial_configs

Reline::HISTORY = Reline::History.new(Reline.core.config)
17 changes: 11 additions & 6 deletions lib/reline/ansi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,25 +149,28 @@ def self.output=(val)
end

def self.with_raw_input
@@input.raw { yield }
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
end
until c = @@input.raw(intr: true) { @@input.wait_readable(0.1) && @@input.getbyte }
until @@input.wait_readable(0.1)
timeout_second -= 0.1
return nil if timeout_second <= 0
Reline.core.line_editor.resize
end
(c == 0x16 && @@input.raw(min: 0, time: 0, &:getbyte)) || c
c = @@input.getbyte
(c == 0x16 && @@input.tty? && @@input.raw(min: 0, time: 0, &:getbyte)) || c
rescue Errno::EIO
# Maybe the I/O has been closed.
nil
rescue Errno::ENOTTY
nil
end

@@in_bracketed_paste_mode = false
Expand Down Expand Up @@ -255,6 +258,8 @@ def self.cursor_pos
begin
res = +''
m = nil
raise Errno::ENOTTY unless @@input.tty? && @@output.tty?

@@input.raw do |stdin|
@@output << "\e[6n"
@@output.flush
Expand All @@ -276,7 +281,7 @@ def self.cursor_pos
buf = @@output.pread(@@output.pos, 0)
row = buf.count("\n")
column = buf.rindex("\n") ? (buf.size - buf.rindex("\n")) - 1 : 0
rescue Errno::ESPIPE
rescue Errno::ESPIPE, IOError
# Just returns column 1 for ambiguous width because this I/O is not
# tty and can't seek.
row = 0
Expand Down
3 changes: 3 additions & 0 deletions lib/reline/line_editor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,7 @@ def update_dialogs(key = nil)
def render_finished
clear_rendered_lines
render_full_content
@output.flush
end

def clear_rendered_lines
Expand Down Expand Up @@ -507,6 +508,7 @@ def render_differential
Reline::IOGate.move_cursor_column wrapped_cursor_x
Reline::IOGate.move_cursor_down y - cursor_y
@rendered_screen.cursor_y = y
@output.flush
new_lines.size - y
end

Expand Down Expand Up @@ -1091,6 +1093,7 @@ def input_key(key)
end
end
if key.char.nil?
process_insert(force: true)
if @first_char
@eof = true
end
Expand Down
2 changes: 1 addition & 1 deletion lib/reline/general_io.rb → lib/reline/test_dumb_io.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require 'io/wait'

class Reline::GeneralIO
class Reline::TestDumbIO
def self.reset(encoding: nil)
@@pasting = false
if encoding
Expand Down
12 changes: 6 additions & 6 deletions test/reline/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class <<self
def test_mode(ansi: false)
@original_iogate = IOGate
remove_const('IOGate')
const_set('IOGate', ansi ? Reline::ANSI : Reline::GeneralIO)
const_set('IOGate', ansi ? Reline::ANSI : Reline::TestDumbIO)
if ENV['RELINE_TEST_ENCODING']
encoding = Encoding.find(ENV['RELINE_TEST_ENCODING'])
else
Expand All @@ -34,7 +34,7 @@ def test_mode(ansi: false)
def IOGate.get_screen_size
[24, 80]
end
Reline::GeneralIO.reset(encoding: encoding) unless ansi
Reline::TestDumbIO.reset(encoding: encoding) unless ansi
core.config.instance_variable_set(:@test_mode, true)
core.config.reset
end
Expand All @@ -44,7 +44,7 @@ def test_reset
IOGate.define_singleton_method(:get_screen_size, @original_get_screen_size)
remove_const('IOGate')
const_set('IOGate', @original_iogate)
Reline::GeneralIO.reset
Reline::TestDumbIO.reset
Reline.instance_variable_set(:@core, nil)
end

Expand Down Expand Up @@ -79,11 +79,11 @@ def test_rubybin
end

def start_pasting
Reline::GeneralIO.start_pasting
Reline::TestDumbIO.start_pasting
end

def finish_pasting
Reline::GeneralIO.finish_pasting
Reline::TestDumbIO.finish_pasting
end

class Reline::TestCase < Test::Unit::TestCase
Expand Down Expand Up @@ -149,7 +149,7 @@ def assert_byte_pointer_size(expected)
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::TestDumbIO.encoding.inspect}>
EOM
end

Expand Down
2 changes: 1 addition & 1 deletion test/reline/test_reline.rb
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ def test_read_io
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_equal("Reline::TestDumbIO", out.chomp)
end

def get_reline_encoding
Expand Down

0 comments on commit 9621e0b

Please sign in to comment.