diff --git a/lib/reline/io/dumb.rb b/lib/reline/io/dumb.rb index 0c04c755d2..59e1630d7e 100644 --- a/lib/reline/io/dumb.rb +++ b/lib/reline/io/dumb.rb @@ -9,9 +9,11 @@ def initialize(encoding: nil) @input = STDIN @output = STDOUT @buf = [] + @output_buffer = nil @pasting = false @encoding = encoding @screen_size = [24, 80] + @first_render = true end def dumb? @@ -43,11 +45,29 @@ def with_raw_input end def write(string) - @output.write(string) + if @output_buffer + @output_buffer << string + else + @output.write(string) + end end def buffered_output + return yield unless tty? + + @output_buffer = +'' yield + + if @first_render || @output_buffer.end_with?("\n") + @output.write(@output_buffer) + @first_render = false + end + ensure + @output_buffer = nil + end + + private def tty? + @input.respond_to?(:tty?) && @input.tty? && @output.respond_to?(:tty?) && @output.tty? end def getc(_timeout_second) @@ -113,6 +133,7 @@ def in_pasting? end def prep + @first_render = true end def deprep(otio) diff --git a/test/reline/test_reline.rb b/test/reline/test_reline.rb index 49c736eb4a..a0a8861e49 100644 --- a/test/reline/test_reline.rb +++ b/test/reline/test_reline.rb @@ -428,6 +428,26 @@ def test_readline_returns_nil_on_piped_stdin_eof assert_include(out, { result: nil }.inspect) end + def test_dumb_tty_buffered_output_keeps_first_and_finished_renders + input = StringIO.new + output = StringIO.new + + [input, output].each do |io| + def io.tty? + true + end + end + io_gate = Reline::Dumb.new + io_gate.input = input + io_gate.output = output + + io_gate.buffered_output { io_gate.write("first render") } + io_gate.buffered_output { io_gate.write("rerender") } + io_gate.buffered_output { io_gate.write("finished render\n") } + + assert_equal("first renderfinished render\n", output.string) + end + def test_read_eof_returns_input pend if win? lib = File.expand_path("../../lib", __dir__)