irb 1.14.1 → 1.15.1

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.
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.
@@ -34,7 +36,12 @@ module IRB
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
38
  begin
37
- Process.kill("TERM", pid) if pid
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
38
45
  rescue Errno::ESRCH
39
46
  # Pager process already terminated
40
47
  end
@@ -42,12 +49,42 @@ module IRB
42
49
  rescue Errno::EPIPE
43
50
  end
44
51
 
45
- private
46
-
47
52
  def should_page?
48
53
  IRB.conf[:USE_PAGER] && STDIN.tty? && (ENV.key?("TERM") && ENV["TERM"] != "dumb")
49
54
  end
50
55
 
56
+ def page_with_preview(width, height, formatter_proc)
57
+ overflow_callback = ->(lines) do
58
+ modified_output = formatter_proc.call(lines.join, true)
59
+ content, = take_first_page(width, [height - 2, 0].max) {|o| o.write modified_output }
60
+ content = content.chomp
61
+ content = "#{content}\e[0m" if Color.colorable?
62
+ $stdout.puts content
63
+ $stdout.puts 'Preparing full inspection value...'
64
+ end
65
+ out = PageOverflowIO.new(width, height, overflow_callback, delay: 0.1)
66
+ yield out
67
+ content = formatter_proc.call(out.string, out.multipage?)
68
+ if out.multipage?
69
+ page(retain_content: true) do |io|
70
+ io.puts content
71
+ end
72
+ else
73
+ $stdout.puts content
74
+ end
75
+ end
76
+
77
+ def take_first_page(width, height)
78
+ overflow_callback = proc do |lines|
79
+ return lines.join, true
80
+ end
81
+ out = Pager::PageOverflowIO.new(width, height, overflow_callback)
82
+ yield out
83
+ [out.string, false]
84
+ end
85
+
86
+ private
87
+
51
88
  def content_exceeds_screen_height?(content)
52
89
  screen_height, screen_width = begin
53
90
  Reline.get_screen_size
@@ -57,10 +94,10 @@ module IRB
57
94
 
58
95
  pageable_height = screen_height - 3 # leave some space for previous and the current prompt
59
96
 
60
- # If the content has more lines than the pageable height
61
- content.lines.count > pageable_height ||
62
- # Or if the content is a few long lines
63
- pageable_height * screen_width < Reline::Unicode.calculate_width(content, true)
97
+ return true if content.lines.size > pageable_height
98
+
99
+ _, overflow = take_first_page(screen_width, pageable_height) {|out| out.write content }
100
+ overflow
64
101
  end
65
102
 
66
103
  def setup_pager(retain_content:)
@@ -91,5 +128,86 @@ module IRB
91
128
  nil
92
129
  end
93
130
  end
131
+
132
+ # Writable IO that has page overflow callback
133
+ class PageOverflowIO
134
+ attr_reader :string, :first_page_lines
135
+
136
+ # Maximum size of a single cell in terminal
137
+ # Assumed worst case: "\e[1;3;4;9;38;2;255;128;128;48;2;128;128;255mA\e[0m"
138
+ # bold, italic, underline, crossed_out, RGB forgound, RGB background
139
+ MAX_CHAR_PER_CELL = 50
140
+
141
+ def initialize(width, height, overflow_callback, delay: nil)
142
+ @lines = []
143
+ @first_page_lines = nil
144
+ @width = width
145
+ @height = height
146
+ @buffer = +''
147
+ @overflow_callback = overflow_callback
148
+ @col = 0
149
+ @string = +''
150
+ @multipage = false
151
+ @delay_until = (Time.now + delay if delay)
152
+ end
153
+
154
+ def puts(text = '')
155
+ text = text.to_s unless text.is_a?(String)
156
+ write(text)
157
+ write("\n") unless text.end_with?("\n")
158
+ end
159
+
160
+ def write(text)
161
+ text = text.to_s unless text.is_a?(String)
162
+ @string << text
163
+ if @multipage
164
+ if @delay_until && Time.now > @delay_until
165
+ @overflow_callback.call(@first_page_lines)
166
+ @delay_until = nil
167
+ end
168
+ return
169
+ end
170
+
171
+ overflow_size = (@width * (@height - @lines.size) + @width - @col) * MAX_CHAR_PER_CELL
172
+ if text.size >= overflow_size
173
+ text = text[0, overflow_size]
174
+ overflow = true
175
+ end
176
+ @buffer << text
177
+ @col += Reline::Unicode.calculate_width(text, true)
178
+ if text.include?("\n") || @col >= @width
179
+ @buffer.lines.each do |line|
180
+ wrapped_lines = Reline::Unicode.split_by_width(line.chomp, @width).first.compact
181
+ wrapped_lines.pop if wrapped_lines.last == ''
182
+ @lines.concat(wrapped_lines)
183
+ if line.end_with?("\n")
184
+ if @lines.empty? || @lines.last.end_with?("\n")
185
+ @lines << "\n"
186
+ else
187
+ @lines[-1] += "\n"
188
+ end
189
+ end
190
+ end
191
+ @buffer.clear
192
+ @buffer << @lines.pop unless @lines.last.end_with?("\n")
193
+ @col = Reline::Unicode.calculate_width(@buffer, true)
194
+ end
195
+ if overflow || @lines.size > @height || (@lines.size == @height && @col > 0)
196
+ @first_page_lines = @lines.take(@height)
197
+ if !@delay_until || Time.now > @delay_until
198
+ @overflow_callback.call(@first_page_lines)
199
+ @delay_until = nil
200
+ end
201
+ @multipage = true
202
+ end
203
+ end
204
+
205
+ def multipage?
206
+ @multipage
207
+ end
208
+
209
+ alias print write
210
+ alias << write
211
+ end
94
212
  end
95
213
  end
@@ -125,9 +125,8 @@ module IRB
125
125
  end
126
126
 
127
127
  def eval_receiver_or_owner(code)
128
- context_binding = @irb_context.workspace.binding
129
- eval(code, context_binding)
130
- rescue NameError
128
+ @irb_context.workspace.binding.eval(code)
129
+ rescue Exception
131
130
  raise EvaluationError
132
131
  end
133
132
 
data/lib/irb/statement.rb CHANGED
@@ -54,6 +54,27 @@ module IRB
54
54
  end
55
55
  end
56
56
 
57
+ class IncorrectAlias < Statement
58
+ attr_reader :message
59
+
60
+ def initialize(message)
61
+ @code = ""
62
+ @message = message
63
+ end
64
+
65
+ def should_be_handled_by_debugger?
66
+ false
67
+ end
68
+
69
+ def is_assignment?
70
+ false
71
+ end
72
+
73
+ def suppresses_echo?
74
+ true
75
+ end
76
+ end
77
+
57
78
  class Command < Statement
58
79
  attr_reader :command_class, :arg
59
80
 
data/lib/irb/version.rb CHANGED
@@ -5,7 +5,7 @@
5
5
  #
6
6
 
7
7
  module IRB # :nodoc:
8
- VERSION = "1.14.1"
8
+ VERSION = "1.15.1"
9
9
  @RELEASE_VERSION = VERSION
10
- @LAST_UPDATE_DATE = "2024-09-25"
10
+ @LAST_UPDATE_DATE = "2025-01-22"
11
11
  end
data/lib/irb/workspace.rb CHANGED
@@ -4,8 +4,6 @@
4
4
  # by Keiju ISHITSUKA(keiju@ruby-lang.org)
5
5
  #
6
6
 
7
- require "delegate"
8
-
9
7
  require_relative "helper_method"
10
8
 
11
9
  IRB::TOPLEVEL_BINDING = binding
@@ -16,7 +14,7 @@ module IRB # :nodoc:
16
14
  # set self to main if specified, otherwise
17
15
  # inherit main from TOPLEVEL_BINDING.
18
16
  def initialize(*main)
19
- if main[0].kind_of?(Binding)
17
+ if Binding === main[0]
20
18
  @binding = main.shift
21
19
  elsif IRB.conf[:SINGLE_IRB]
22
20
  @binding = TOPLEVEL_BINDING
@@ -70,37 +68,16 @@ EOF
70
68
  unless main.empty?
71
69
  case @main
72
70
  when Module
73
- @binding = eval("IRB.conf[:__MAIN__].module_eval('binding', __FILE__, __LINE__)", @binding, __FILE__, __LINE__)
71
+ @binding = eval("::IRB.conf[:__MAIN__].module_eval('::Kernel.binding', __FILE__, __LINE__)", @binding, __FILE__, __LINE__)
74
72
  else
75
73
  begin
76
- @binding = eval("IRB.conf[:__MAIN__].instance_eval('binding', __FILE__, __LINE__)", @binding, __FILE__, __LINE__)
74
+ @binding = eval("::IRB.conf[:__MAIN__].instance_eval('::Kernel.binding', __FILE__, __LINE__)", @binding, __FILE__, __LINE__)
77
75
  rescue TypeError
78
76
  fail CantChangeBinding, @main.inspect
79
77
  end
80
78
  end
81
79
  end
82
80
 
83
- case @main
84
- when Object
85
- use_delegator = @main.frozen?
86
- else
87
- use_delegator = true
88
- end
89
-
90
- if use_delegator
91
- @main = SimpleDelegator.new(@main)
92
- IRB.conf[:__MAIN__] = @main
93
- @main.singleton_class.class_eval do
94
- private
95
- define_method(:binding, Kernel.instance_method(:binding))
96
- define_method(:local_variables, Kernel.instance_method(:local_variables))
97
- # Define empty method to avoid delegator warning, will be overridden.
98
- define_method(:exit) {|*a, &b| }
99
- define_method(:exit!) {|*a, &b| }
100
- end
101
- @binding = eval("IRB.conf[:__MAIN__].instance_eval('binding', __FILE__, __LINE__)", @binding, *@binding.source_location)
102
- end
103
-
104
81
  @binding.local_variable_set(:_, nil)
105
82
  end
106
83
 
@@ -111,6 +88,9 @@ EOF
111
88
  attr_reader :main
112
89
 
113
90
  def load_helper_methods_to_main
91
+ # Do not load helper methods to frozen objects and BasicObject
92
+ return unless Object === @main && !@main.frozen?
93
+
114
94
  ancestors = class<<main;ancestors;end
115
95
  main.extend ExtendCommandBundle if !ancestors.include?(ExtendCommandBundle)
116
96
  main.extend HelpersContainer if !ancestors.include?(HelpersContainer)