irb 1.14.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.rdoc_options +5 -0
  3. data/CONTRIBUTING.md +52 -0
  4. data/EXTEND_IRB.md +3 -0
  5. data/Gemfile +11 -1
  6. data/README.md +13 -293
  7. data/doc/COMMAND_LINE_OPTIONS.md +69 -0
  8. data/doc/COMPARED_WITH_PRY.md +22 -0
  9. data/doc/Configurations.md +274 -0
  10. data/doc/EXTEND_IRB.md +122 -0
  11. data/doc/Index.md +705 -0
  12. data/doc/irb/irb.rd.ja +1 -1
  13. data/lib/irb/color.rb +251 -162
  14. data/lib/irb/color_printer.rb +10 -9
  15. data/lib/irb/command/base.rb +46 -13
  16. data/lib/irb/command/copy.rb +83 -0
  17. data/lib/irb/command/debug.rb +8 -6
  18. data/lib/irb/command/help.rb +1 -1
  19. data/lib/irb/command/history.rb +1 -1
  20. data/lib/irb/command/internal_helpers.rb +7 -4
  21. data/lib/irb/command/ls.rb +29 -15
  22. data/lib/irb/completion.rb +81 -57
  23. data/lib/irb/context.rb +132 -53
  24. data/lib/irb/debug/ui.rb +2 -4
  25. data/lib/irb/debug.rb +9 -12
  26. data/lib/irb/default_commands.rb +19 -8
  27. data/lib/irb/easter-egg.rb +13 -7
  28. data/lib/irb/ext/multi-irb.rb +2 -0
  29. data/lib/irb/history.rb +84 -55
  30. data/lib/irb/init.rb +7 -2
  31. data/lib/irb/input-method.rb +167 -130
  32. data/lib/irb/inspector.rb +42 -36
  33. data/lib/irb/lc/help-message +2 -2
  34. data/lib/irb/lc/ja/help-message +4 -4
  35. data/lib/irb/nesting_parser.rb +364 -213
  36. data/lib/irb/pager.rb +137 -7
  37. data/lib/irb/ruby-lex.rb +230 -302
  38. data/lib/irb/ruby_logo.aa +79 -37
  39. data/lib/irb/source_finder.rb +15 -22
  40. data/lib/irb/startup_message.rb +83 -0
  41. data/lib/irb/statement.rb +21 -0
  42. data/lib/irb/version.rb +2 -2
  43. data/lib/irb/workspace.rb +22 -31
  44. data/lib/irb.rb +148 -986
  45. data/man/irb.1 +37 -2
  46. metadata +42 -12
  47. data/.document +0 -4
  48. data/Rakefile +0 -54
  49. data/bin/console +0 -6
  50. data/bin/setup +0 -6
  51. data/irb.gemspec +0 -46
data/lib/irb/pager.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'reline'
4
+
3
5
  module IRB
4
6
  # The implementation of this class is borrowed from RDoc's lib/rdoc/ri/driver.rb.
5
7
  # Please do NOT use this class directly outside of IRB.
@@ -33,17 +35,64 @@ module IRB
33
35
  # the `IRB::Abort` exception only interrupts IRB's execution but doesn't affect the pager
34
36
  # So to properly terminate the pager with Ctrl-C, we need to catch `IRB::Abort` and kill the pager process
35
37
  rescue IRB::Abort
36
- Process.kill("TERM", pid) if pid
38
+ begin
39
+ begin
40
+ Process.kill("TERM", pid) if pid
41
+ rescue Errno::EINVAL
42
+ # SIGTERM not supported (windows)
43
+ Process.kill("KILL", pid)
44
+ end
45
+
46
+ begin
47
+ # Wait for the pager process to terminate.
48
+ # Reading next input from Reline before the pager process is fully terminated
49
+ # may cause issues like raw/cooked mode not being controlled properly.
50
+ Process.waitpid(pid) if pid
51
+ rescue Errno::ECHILD, Errno::ESRCH
52
+ end
53
+ rescue Errno::ESRCH
54
+ # Pager process already terminated
55
+ end
37
56
  nil
38
57
  rescue Errno::EPIPE
39
58
  end
40
59
 
41
- private
42
-
43
60
  def should_page?
44
61
  IRB.conf[:USE_PAGER] && STDIN.tty? && (ENV.key?("TERM") && ENV["TERM"] != "dumb")
45
62
  end
46
63
 
64
+ def page_with_preview(width, height, formatter_proc)
65
+ overflow_callback = ->(lines) do
66
+ modified_output = formatter_proc.call(lines.join, true)
67
+ content, = take_first_page(width, [height - 2, 0].max) {|o| o.write modified_output }
68
+ content = content.chomp
69
+ content = "#{content}\e[0m" if Color.colorable?
70
+ $stdout.puts content
71
+ $stdout.puts 'Preparing full inspection value...'
72
+ end
73
+ out = PageOverflowIO.new(width, height, overflow_callback, delay: 0.1)
74
+ yield out
75
+ content = formatter_proc.call(out.string, out.multipage?)
76
+ if out.multipage?
77
+ page(retain_content: true) do |io|
78
+ io.puts content
79
+ end
80
+ else
81
+ $stdout.puts content
82
+ end
83
+ end
84
+
85
+ def take_first_page(width, height)
86
+ overflow_callback = proc do |lines|
87
+ return lines.join, true
88
+ end
89
+ out = Pager::PageOverflowIO.new(width, height, overflow_callback)
90
+ yield out
91
+ [out.string, false]
92
+ end
93
+
94
+ private
95
+
47
96
  def content_exceeds_screen_height?(content)
48
97
  screen_height, screen_width = begin
49
98
  Reline.get_screen_size
@@ -53,10 +102,10 @@ module IRB
53
102
 
54
103
  pageable_height = screen_height - 3 # leave some space for previous and the current prompt
55
104
 
56
- # If the content has more lines than the pageable height
57
- content.lines.count > pageable_height ||
58
- # Or if the content is a few long lines
59
- pageable_height * screen_width < Reline::Unicode.calculate_width(content, true)
105
+ return true if content.lines.size > pageable_height
106
+
107
+ _, overflow = take_first_page(screen_width, pageable_height) {|out| out.write content }
108
+ overflow
60
109
  end
61
110
 
62
111
  def setup_pager(retain_content:)
@@ -87,5 +136,86 @@ module IRB
87
136
  nil
88
137
  end
89
138
  end
139
+
140
+ # Writable IO that has page overflow callback
141
+ class PageOverflowIO
142
+ attr_reader :string, :first_page_lines
143
+
144
+ # Maximum size of a single cell in terminal
145
+ # Assumed worst case: "\e[1;3;4;9;38;2;255;128;128;48;2;128;128;255mA\e[0m"
146
+ # bold, italic, underline, crossed_out, RGB forgound, RGB background
147
+ MAX_CHAR_PER_CELL = 50
148
+
149
+ def initialize(width, height, overflow_callback, delay: nil)
150
+ @lines = []
151
+ @first_page_lines = nil
152
+ @width = width
153
+ @height = height
154
+ @buffer = +''
155
+ @overflow_callback = overflow_callback
156
+ @col = 0
157
+ @string = +''
158
+ @multipage = false
159
+ @delay_until = (Time.now + delay if delay)
160
+ end
161
+
162
+ def puts(text = '')
163
+ text = text.to_s unless text.is_a?(String)
164
+ write(text)
165
+ write("\n") unless text.end_with?("\n")
166
+ end
167
+
168
+ def write(text)
169
+ text = text.to_s unless text.is_a?(String)
170
+ @string << text
171
+ if @multipage
172
+ if @delay_until && Time.now > @delay_until
173
+ @overflow_callback.call(@first_page_lines)
174
+ @delay_until = nil
175
+ end
176
+ return
177
+ end
178
+
179
+ overflow_size = (@width * (@height - @lines.size) + @width - @col) * MAX_CHAR_PER_CELL
180
+ if text.size >= overflow_size
181
+ text = text[0, overflow_size]
182
+ overflow = true
183
+ end
184
+ @buffer << text
185
+ @col += Reline::Unicode.calculate_width(text, true)
186
+ if text.include?("\n") || @col >= @width
187
+ @buffer.lines.each do |line|
188
+ wrapped_lines = Reline::Unicode.split_by_width(line.chomp, @width).first.compact
189
+ wrapped_lines.pop if wrapped_lines.last == ''
190
+ @lines.concat(wrapped_lines)
191
+ if line.end_with?("\n")
192
+ if @lines.empty? || @lines.last.end_with?("\n")
193
+ @lines << "\n"
194
+ else
195
+ @lines[-1] += "\n"
196
+ end
197
+ end
198
+ end
199
+ @buffer.clear
200
+ @buffer << @lines.pop if !@lines.empty? && !@lines.last.end_with?("\n")
201
+ @col = Reline::Unicode.calculate_width(@buffer, true)
202
+ end
203
+ if overflow || @lines.size > @height || (@lines.size == @height && @col > 0)
204
+ @first_page_lines = @lines.take(@height)
205
+ if !@delay_until || Time.now > @delay_until
206
+ @overflow_callback.call(@first_page_lines)
207
+ @delay_until = nil
208
+ end
209
+ @multipage = true
210
+ end
211
+ end
212
+
213
+ def multipage?
214
+ @multipage
215
+ end
216
+
217
+ alias print write
218
+ alias << write
219
+ end
90
220
  end
91
221
  end