diff --git a/lib/reline.rb b/lib/reline.rb index 53adf1ad4d..9dca0ef3ec 100644 --- a/lib/reline.rb +++ b/lib/reline.rb @@ -58,7 +58,7 @@ class Core attr_accessor :key_stroke attr_accessor :line_editor attr_accessor :last_incremental_search - attr_reader :output + attr_reader :input, :output extend Forwardable def_delegators :config, @@ -66,6 +66,7 @@ class Core :autocompletion= def initialize + self.input = STDIN self.output = STDOUT @mutex = Mutex.new @dialog_proc_list = {} @@ -175,6 +176,7 @@ def dialog_proc(name_sym) def input=(val) raise TypeError unless val.respond_to?(:getc) or val.nil? + @input = val if val.respond_to?(:getc) && io_gate.respond_to?(:input=) io_gate.input = val end @@ -290,6 +292,10 @@ def readline(_prompt = '', _add_history = false, prompt: _prompt, add_history: _ end end + private def terminal? + input.respond_to?(:tty?) && input.tty? && output.respond_to?(:tty?) && output.tty? + end + private def inner_readline(prompt, add_history, multiline, rprompt: nil, &confirm_multiline_termination) if ENV['RELINE_STDERR_TTY'] if io_gate.win? @@ -333,8 +339,12 @@ def readline(_prompt = '', _add_history = false, prompt: _prompt, add_history: _ end end - line_editor.update_dialogs - line_editor.rerender + if terminal? + line_editor.update_dialogs + line_editor.rerender + else + output.write(prompt) + end begin line_editor.set_signal_handlers @@ -354,13 +364,18 @@ def readline(_prompt = '', _add_history = false, prompt: _prompt, add_history: _ end } if line_editor.finished? - line_editor.render_finished + if terminal? + line_editor.render_finished + else + line = line_editor.line + output.write("#{line}\n") if line + end break - else + elsif terminal? line_editor.rerender end end - io_gate.move_cursor_column(0) + io_gate.move_cursor_column(0) if terminal? rescue Errno::EIO # Maybe the I/O has been closed. ensure diff --git a/test/reline/test_reline.rb b/test/reline/test_reline.rb index 49c736eb4a..f99faf3b1f 100644 --- a/test/reline/test_reline.rb +++ b/test/reline/test_reline.rb @@ -420,12 +420,22 @@ def test_dumb_terminal def test_readline_reads_piped_stdin out = readline_from_piped_stdin("input\n") - assert_include(out, { result: 'input' }.inspect) + assert_equal(">input\n#{ { result: 'input' }.inspect }\n", out) + end + + def test_readline_with_dumb_terminal_outputs_plain_piped_stdin + out = readline_from_dumb_terminal_piped_stdin("input\n") + assert_equal("> input\n#{ { result: 'input' }.inspect }\n", out) end def test_readline_returns_nil_on_piped_stdin_eof out = readline_from_piped_stdin("") - assert_include(out, { result: nil }.inspect) + assert_equal(">#{ { result: nil }.inspect }\n", out) + end + + def test_readline_with_dumb_terminal_outputs_plain_piped_stdin_eof + out = readline_from_dumb_terminal_piped_stdin("") + assert_equal("> #{ { result: nil }.inspect }\n", out) end def test_read_eof_returns_input @@ -488,6 +498,17 @@ def readline_from_piped_stdin(stdin) end end + def readline_from_dumb_terminal_piped_stdin(stdin) + lib = File.expand_path("../../lib", __dir__) + code = "p result: Reline.readline('> ')" + + IO.popen([{"TERM" => "dumb"}, Reline.test_rubybin, "-I#{lib}", "-rreline", "-e", code], "r+") do |io| + io.write stdin + io.close_write + io.read + end + end + def test_tty_ambiguous_width omit unless defined?(PTY) ruby_file = Tempfile.create('rubyfile')