[ruby/irb] Page evaluation result's output

(https://github.com/ruby/irb/pull/784)

* Page evaluation result's output

This will make it easier to work with long output that exceeds the terminal's height.

* Use consistent TERM in rendering tests

This makes sure we get consistent result on all platforms.

https://github.com/ruby/irb/commit/4fedce93d3
This commit is contained in:
Stan Lo 2023-11-30 15:22:17 +00:00 коммит произвёл git
Родитель cc393b4f80
Коммит f193f96d31
7 изменённых файлов: 67 добавлений и 25 удалений

Просмотреть файл

@ -20,6 +20,7 @@ require_relative "irb/color"
require_relative "irb/version"
require_relative "irb/easter-egg"
require_relative "irb/debug"
require_relative "irb/pager"
# IRB stands for "interactive Ruby" and is a tool to interactively execute Ruby
# expressions read from the standard input.
@ -859,11 +860,12 @@ module IRB
end
end
end
if multiline_p && @context.newline_before_multiline_output?
printf @context.return_format, "\n#{str}"
else
printf @context.return_format, str
str = "\n" + str
end
Pager.page_content(format(@context.return_format, str), retain_content: true)
end
# Outputs the local variables to this current session, including

Просмотреть файл

@ -7,9 +7,9 @@ module IRB
PAGE_COMMANDS = [ENV['RI_PAGER'], ENV['PAGER'], 'less', 'more'].compact.uniq
class << self
def page_content(content)
def page_content(content, **options)
if content_exceeds_screen_height?(content)
page do |io|
page(**options) do |io|
io.puts content
end
else
@ -17,8 +17,8 @@ module IRB
end
end
def page
if IRB.conf[:USE_PAGER] && STDIN.tty? && pager = setup_pager
def page(retain_content: false)
if IRB.conf[:USE_PAGER] && STDIN.tty? && pager = setup_pager(retain_content: retain_content)
begin
pid = pager.pid
yield pager
@ -55,19 +55,20 @@ module IRB
pageable_height * screen_width < Reline::Unicode.calculate_width(content, true)
end
def setup_pager
def setup_pager(retain_content:)
require 'shellwords'
PAGE_COMMANDS.each do |pager|
pager = Shellwords.split(pager)
next if pager.empty?
PAGE_COMMANDS.each do |pager_cmd|
cmd = Shellwords.split(pager_cmd)
next if cmd.empty?
if pager.first == 'less'
pager << '-R' unless pager.include?('-R')
if cmd.first == 'less'
cmd << '-R' unless cmd.include?('-R')
cmd << '-X' if retain_content && !cmd.include?('-X')
end
begin
io = IO.popen(pager, 'w')
io = IO.popen(cmd, 'w')
rescue
next
end

Просмотреть файл

@ -93,6 +93,10 @@ module TestIRB
if ruby_core?
omit "This test works only under ruby/irb"
end
write_rc <<~RUBY
IRB.conf[:USE_PAGER] = false
RUBY
end
def teardown
@ -197,8 +201,14 @@ module TestIRB
end
def write_rc(content)
@irbrc = Tempfile.new('irbrc')
@tmpfiles << @irbrc
# Append irbrc content if a tempfile for it already exists
if @irbrc
@irbrc = File.open(@irbrc, "a")
else
@irbrc = Tempfile.new('irbrc')
@tmpfiles << @irbrc
end
@irbrc.write(content)
@irbrc.close
@envs['IRBRC'] = @irbrc.path

Просмотреть файл

@ -11,6 +11,7 @@ module TestIRB
IRB.init_config(nil)
IRB.conf[:USE_SINGLELINE] = false
IRB.conf[:VERBOSE] = false
IRB.conf[:USE_PAGER] = false
workspace = IRB::WorkSpace.new(Object.new)
@context = IRB::Context.new(nil, workspace, TestInputMethod.new)

Просмотреть файл

@ -346,10 +346,6 @@ module TestIRB
end
def test_show_cmds_display_different_content_when_debugger_is_enabled
write_rc <<~RUBY
IRB.conf[:USE_PAGER] = false
RUBY
write_ruby <<~'ruby'
binding.irb
ruby

Просмотреть файл

@ -6,10 +6,6 @@ require_relative "helper"
module TestIRB
class InputTest < IntegrationTestCase
def test_symbol_aliases_are_handled_correctly
write_rc <<~RUBY
IRB.conf[:USE_PAGER] = false
RUBY
write_ruby <<~'RUBY'
class Foo
end
@ -26,7 +22,6 @@ module TestIRB
def test_symbol_aliases_are_handled_correctly_with_singleline_mode
write_rc <<~RUBY
IRB.conf[:USE_PAGER] = false
IRB.conf[:USE_SINGLELINE] = true
RUBY

Просмотреть файл

@ -10,6 +10,8 @@ end
class IRB::RenderingTest < Yamatanooroti::TestCase
def setup
@original_term = ENV['TERM']
ENV['TERM'] = "xterm-256color"
@pwd = Dir.pwd
suffix = '%010d' % Random.rand(0..65535)
@tmpdir = File.join(File.expand_path(Dir.tmpdir), "test_irb_#{$$}_#{suffix}")
@ -27,6 +29,7 @@ class IRB::RenderingTest < Yamatanooroti::TestCase
def teardown
FileUtils.rm_rf(@tmpdir)
ENV['IRBRC'] = @irbrc_backup
ENV['TERM'] = @original_term
ENV.delete('RELINE_TEST_PROMPT') if ENV['RELINE_TEST_PROMPT']
end
@ -377,6 +380,40 @@ class IRB::RenderingTest < Yamatanooroti::TestCase
assert_match(/foobar/, screen)
end
def test_long_evaluation_output_is_paged
write_irbrc <<~'LINES'
puts 'start IRB'
require "irb/pager"
LINES
start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB')
write("'a' * 80 * 11\n")
write("'foo' + 'bar'\n") # eval something to make sure IRB resumes
close
screen = result.join("\n").sub(/\n*\z/, "\n")
assert_match(/(a{80}\n){8}/, screen)
# because pager is invoked, foobar will not be evaluated
assert_not_match(/foobar/, screen)
end
def test_long_evaluation_output_is_preserved_after_paging
write_irbrc <<~'LINES'
puts 'start IRB'
require "irb/pager"
LINES
start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB')
write("'a' * 80 * 11\n")
write("q") # quit pager
write("'foo' + 'bar'\n") # eval something to make sure IRB resumes
close
screen = result.join("\n").sub(/\n*\z/, "\n")
# confirm pager has exited
assert_match(/foobar/, screen)
# confirm output is preserved
assert_match(/(a{80}\n){6}/, screen)
end
def test_debug_integration_hints_debugger_commands
write_irbrc <<~'LINES'
IRB.conf[:USE_COLORIZE] = false