Class: IRB::Pager

Inherits:
Object show all
Defined in:
lib/irb/pager.rb

Overview

The implementation of this class is borrowed from RDoc’s lib/rdoc/ri/driver.rb. Please do NOT use this class directly outside of IRB.

Defined Under Namespace

Classes: PageOverflowIO

Constant Summary collapse

PAGE_COMMANDS =
[ENV['RI_PAGER'], ENV['PAGER'], 'less', 'more'].compact.uniq

Class Method Summary collapse

Class Method Details

.page(retain_content: false) ⇒ Object



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/irb/pager.rb', line 22

def page(retain_content: false)
  if should_page? && pager = setup_pager(retain_content: retain_content)
    begin
      pid = pager.pid
      yield pager
    ensure
      pager.close
    end
  else
    yield $stdout
  end
# When user presses Ctrl-C, IRB would raise `IRB::Abort`
# But since Pager is implemented by running paging commands like `less` in another process with `IO.popen`,
# the `IRB::Abort` exception only interrupts IRB's execution but doesn't affect the pager
# So to properly terminate the pager with Ctrl-C, we need to catch `IRB::Abort` and kill the pager process
rescue IRB::Abort
  begin
    begin
      Process.kill("TERM", pid) if pid
    rescue Errno::EINVAL
      # SIGTERM not supported (windows)
      Process.kill("KILL", pid)
    end

    begin
      # Wait for the pager process to terminate.
      # Reading next input from Reline before the pager process is fully terminated
      # may cause issues like raw/cooked mode not being controlled properly.
      Process.waitpid(pid) if pid
    rescue Errno::ECHILD, Errno::ESRCH
    end
  rescue Errno::ESRCH
    # Pager process already terminated
  end
  nil
rescue Errno::EPIPE
end

.page_content(content, **options) ⇒ Object



12
13
14
15
16
17
18
19
20
# File 'lib/irb/pager.rb', line 12

def page_content(content, **options)
  if content_exceeds_screen_height?(content)
    page(**options) do |io|
      io.puts content
    end
  else
    $stdout.puts content
  end
end

.page_with_preview(width, height, formatter_proc) {|out| ... } ⇒ Object

Yields:

  • (out)


64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/irb/pager.rb', line 64

def page_with_preview(width, height, formatter_proc)
  overflow_callback = ->(lines) do
    modified_output = formatter_proc.call(lines.join, true)
    content, = take_first_page(width, [height - 2, 0].max) {|o| o.write modified_output }
    content = content.chomp
    content = "#{content}\e[0m" if Color.colorable?
    $stdout.puts content
    $stdout.puts 'Preparing full inspection value...'
  end
  out = PageOverflowIO.new(width, height, overflow_callback, delay: 0.1)
  yield out
  content = formatter_proc.call(out.string, out.multipage?)
  if out.multipage?
    page(retain_content: true) do |io|
      io.puts content
    end
  else
    $stdout.puts content
  end
end

.should_page?Boolean

Returns:

  • (Boolean)


60
61
62
# File 'lib/irb/pager.rb', line 60

def should_page?
  IRB.conf[:USE_PAGER] && STDIN.tty? && (ENV.key?("TERM") && ENV["TERM"] != "dumb")
end

.take_first_page(width, height) {|out| ... } ⇒ Object

Yields:

  • (out)


85
86
87
88
89
90
91
92
# File 'lib/irb/pager.rb', line 85

def take_first_page(width, height)
  overflow_callback = proc do |lines|
    return lines.join, true
  end
  out = Pager::PageOverflowIO.new(width, height, overflow_callback)
  yield out
  [out.string, false]
end