summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStan Lo <[email protected]>2023-11-30 15:22:17 +0000
committergit <[email protected]>2023-11-30 15:22:22 +0000
commitf193f96d31ffcd02d91f135ba765d92c23b52c55 (patch)
tree758eb77f0fc698b691dfa9275bdd3d48c12af3bf
parentcc393b4f80be7eccdc84785f684dc7899b0510e4 (diff)
[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
-rw-r--r--lib/irb.rb8
-rw-r--r--lib/irb/pager.rb23
-rw-r--r--test/irb/helper.rb14
-rw-r--r--test/irb/test_context.rb1
-rw-r--r--test/irb/test_debug_cmd.rb4
-rw-r--r--test/irb/test_irb.rb5
-rw-r--r--test/irb/yamatanooroti/test_rendering.rb37
7 files changed, 67 insertions, 25 deletions
diff --git a/lib/irb.rb b/lib/irb.rb
index 66149eb455..1ba335c087 100644
--- a/lib/irb.rb
+++ b/lib/irb.rb
@@ -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
diff --git a/lib/irb/pager.rb b/lib/irb/pager.rb
index e38d97e3c7..a0db5e93b4 100644
--- a/lib/irb/pager.rb
+++ b/lib/irb/pager.rb
@@ -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
diff --git a/test/irb/helper.rb b/test/irb/helper.rb
index ede48be649..38bdbb4c31 100644
--- a/test/irb/helper.rb
+++ b/test/irb/helper.rb
@@ -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
diff --git a/test/irb/test_context.rb b/test/irb/test_context.rb
index f4a19ee3c4..79186f13a1 100644
--- a/test/irb/test_context.rb
+++ b/test/irb/test_context.rb
@@ -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)
diff --git a/test/irb/test_debug_cmd.rb b/test/irb/test_debug_cmd.rb
index 53d40f7297..0fb45af478 100644
--- a/test/irb/test_debug_cmd.rb
+++ b/test/irb/test_debug_cmd.rb
@@ -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
diff --git a/test/irb/test_irb.rb b/test/irb/test_irb.rb
index e6eb3d5da1..fb8b5c2bfa 100644
--- a/test/irb/test_irb.rb
+++ b/test/irb/test_irb.rb
@@ -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
diff --git a/test/irb/yamatanooroti/test_rendering.rb b/test/irb/yamatanooroti/test_rendering.rb
index ca8176dfe6..b18b95bbbd 100644
--- a/test/irb/yamatanooroti/test_rendering.rb
+++ b/test/irb/yamatanooroti/test_rendering.rb
@@ -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