summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStan Lo <[email protected]>2023-07-26 09:31:58 +0100
committergit <[email protected]>2023-07-26 08:32:02 +0000
commit283b2fdab4be77d8721d7cf298168eb6e3798490 (patch)
treea660b377328de9a6aee25c859cf212a9e56a1865
parent26aef1c73639718bc00c271ce7176bf3ee565c12 (diff)
[ruby/irb] Page `ls`'s output (https://github.com/ruby/irb/pull/657)
* Page ls command's output * Use Pager.page_content in show_cmds too https://github.com/ruby/irb/commit/82d1687302
-rw-r--r--lib/irb/cmd/ls.rb17
-rw-r--r--lib/irb/cmd/show_cmds.rb4
-rw-r--r--lib/irb/pager.rb25
-rw-r--r--test/irb/test_cmd.rb10
-rw-r--r--test/irb/yamatanooroti/test_rendering.rb48
5 files changed, 96 insertions, 8 deletions
diff --git a/lib/irb/cmd/ls.rb b/lib/irb/cmd/ls.rb
index 063a88d33f..791b1c1b21 100644
--- a/lib/irb/cmd/ls.rb
+++ b/lib/irb/cmd/ls.rb
@@ -1,7 +1,9 @@
# frozen_string_literal: true
require "reline"
+require "stringio"
require_relative "nop"
+require_relative "../pager"
require_relative "../color"
module IRB
@@ -33,7 +35,7 @@ module IRB
o.dump("instance variables", obj.instance_variables)
o.dump("class variables", klass.class_variables)
o.dump("locals", locals)
- nil
+ o.print_result
end
def dump_methods(o, klass, obj)
@@ -77,6 +79,11 @@ module IRB
def initialize(grep: nil)
@grep = grep
@line_width = screen_width - MARGIN.length # right padding
+ @io = StringIO.new
+ end
+
+ def print_result
+ Pager.page_content(@io.string)
end
def dump(name, strs)
@@ -85,12 +92,12 @@ module IRB
return if strs.empty?
# Attempt a single line
- print "#{Color.colorize(name, [:BOLD, :BLUE])}: "
+ @io.print "#{Color.colorize(name, [:BOLD, :BLUE])}: "
if fits_on_line?(strs, cols: strs.size, offset: "#{name}: ".length)
- puts strs.join(MARGIN)
+ @io.puts strs.join(MARGIN)
return
end
- puts
+ @io.puts
# Dump with the largest # of columns that fits on a line
cols = strs.size
@@ -99,7 +106,7 @@ module IRB
end
widths = col_widths(strs, cols: cols)
strs.each_slice(cols) do |ss|
- puts ss.map.with_index { |s, i| "#{MARGIN}%-#{widths[i]}s" % s }.join
+ @io.puts ss.map.with_index { |s, i| "#{MARGIN}%-#{widths[i]}s" % s }.join
end
end
diff --git a/lib/irb/cmd/show_cmds.rb b/lib/irb/cmd/show_cmds.rb
index 1c9f1ea19a..cef6254ca0 100644
--- a/lib/irb/cmd/show_cmds.rb
+++ b/lib/irb/cmd/show_cmds.rb
@@ -29,9 +29,7 @@ module IRB
output.puts
end
- Pager.page do |io|
- io.puts output.string
- end
+ Pager.page_content(output.string)
end
end
end
diff --git a/lib/irb/pager.rb b/lib/irb/pager.rb
index 16066cf273..1194e41f6f 100644
--- a/lib/irb/pager.rb
+++ b/lib/irb/pager.rb
@@ -7,6 +7,16 @@ module IRB
PAGE_COMMANDS = [ENV['RI_PAGER'], ENV['PAGER'], 'less', 'more'].compact.uniq
class << self
+ def page_content(content)
+ if content_exceeds_screen_height?(content)
+ page do |io|
+ io.puts content
+ end
+ else
+ $stdout.puts content
+ end
+ end
+
def page
if STDIN.tty? && pager = setup_pager
begin
@@ -30,6 +40,21 @@ module IRB
private
+ def content_exceeds_screen_height?(content)
+ screen_height, screen_width = begin
+ Reline.get_screen_size
+ rescue Errno::EINVAL
+ [24, 80]
+ end
+
+ pageable_height = screen_height - 3 # leave some space for previous and the current prompt
+
+ # If the content has more lines than the pageable height
+ content.lines.count > pageable_height ||
+ # Or if the content is a few long lines
+ pageable_height * screen_width < Reline::Unicode.calculate_width(content, true)
+ end
+
def setup_pager
require 'shellwords'
diff --git a/test/irb/test_cmd.rb b/test/irb/test_cmd.rb
index 71d64a0ec2..dcea020b1e 100644
--- a/test/irb/test_cmd.rb
+++ b/test/irb/test_cmd.rb
@@ -710,6 +710,16 @@ module TestIRB
end
class LsTest < CommandTestCase
+ def setup
+ STDIN.singleton_class.define_method :tty? do
+ false
+ end
+ end
+
+ def teardown
+ STDIN.singleton_class.remove_method :tty?
+ end
+
def test_ls
out, err = execute_lines(
"class P\n",
diff --git a/test/irb/yamatanooroti/test_rendering.rb b/test/irb/yamatanooroti/test_rendering.rb
index 12467b0913..420339c452 100644
--- a/test/irb/yamatanooroti/test_rendering.rb
+++ b/test/irb/yamatanooroti/test_rendering.rb
@@ -270,6 +270,54 @@ class IRB::RenderingTest < Yamatanooroti::TestCase
assert_match(/foobar/, screen)
end
+ def test_pager_page_content_pages_output_when_it_does_not_fit_in_the_screen_because_of_total_length
+ 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("IRB::Pager.page_content('a' * (80 * 8))\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}/, screen)
+ # because pager is invoked, foobar will not be evaluated
+ assert_not_match(/foobar/, screen)
+ end
+
+ def test_pager_page_content_pages_output_when_it_does_not_fit_in_the_screen_because_of_screen_height
+ 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("IRB::Pager.page_content('a\n' * 8)\n")
+ write("'foo' + 'bar'\n") # eval something to make sure IRB resumes
+ close
+
+ screen = result.join("\n").sub(/\n*\z/, "\n")
+ assert_match(/(a\n){8}/, screen)
+ # because pager is invoked, foobar will not be evaluated
+ assert_not_match(/foobar/, screen)
+ end
+
+ def test_pager_page_content_doesnt_page_output_when_it_fits_in_the_screen
+ 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("IRB::Pager.page_content('a' * (80 * 7))\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}/, screen)
+ # because pager is not invoked, foobar will be evaluated
+ assert_match(/foobar/, screen)
+ end
+
private
def write_irbrc(content)