irb 1.9.1 → 1.10.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ed98e2ce49cea18e608a64f8e5f5e310064a373b944de0474d49e21613b5be6
4
- data.tar.gz: 679dea24c5f90242c1f0f427b42bc0d90caafb6ad8ec73da6d11181bb5645f9f
3
+ metadata.gz: ce85a9eb69af7fbbb8cb41a6d34029502d2b6712d916b7a3823176e2769cdcf8
4
+ data.tar.gz: 711b52081eb0a97eee4901844b33e8cf9657316c8dde29c9eeb41d3a6998f78e
5
5
  SHA512:
6
- metadata.gz: 41a6d57dc51eb6d17c6aa3c7a635d576d4d21d3e5b6eab92becb3862060fae0fdbd34cc0975bca219a7cc6c5808657b417f5aae1dc9606649fe4f82bcce8c467
7
- data.tar.gz: d7499712f5310d00f6a47b8581749c1e34a69fe3984cb3efbe9d1ce1825d65dcfd471e17831cee56ca3dda7d0a17cabc5b36f6511f151c1b7472b9042e9c173f
6
+ metadata.gz: 300f29f4e769be7ede8371fc7f667fb543eb7d8dd9249b062993074c2bdbb5808a3322cb4bb6a0ff58bd79c2d6e82a3bbac0f78b6a117e0095c63fbfe9431fb8
7
+ data.tar.gz: 997b64b19a2902c6a9bc47ee4aff909b133f13e829456cc4fe4cf33b6ca425c8619f58ffda7be71bdd3dde1b91e2d23ba24bad9e9045b612fc190e6ac3fa42e7
data/Gemfile CHANGED
@@ -16,9 +16,9 @@ gem "reline", github: "ruby/reline" if ENV["WITH_LATEST_RELINE"] == "true"
16
16
  gem "rake"
17
17
  gem "test-unit"
18
18
  gem "test-unit-ruby-core"
19
- gem "debug", github: "ruby/debug"
20
19
 
21
- if RUBY_VERSION >= "3.0.0"
22
- gem "rbs"
23
- gem "prism", ">= 0.17.1"
20
+ gem "debug", github: "ruby/debug", platforms: [:mri, :mswin]
21
+
22
+ if RUBY_VERSION >= "3.0.0" && !is_truffleruby
23
+ gem "repl_type_completor"
24
24
  end
data/README.md CHANGED
@@ -119,6 +119,7 @@ IRB
119
119
  source Loads a given file in the current session.
120
120
  irb_info Show information about IRB.
121
121
  show_cmds List all available commands and their description.
122
+ history Shows the input history. `-g [query]` or `-G [query]` allows you to filter the output.
122
123
 
123
124
  Multi-irb (DEPRECATED)
124
125
  irb Start a child IRB.
@@ -237,11 +238,11 @@ However, there are also some limitations to be aware of:
237
238
 
238
239
  ## Type Based Completion
239
240
 
240
- IRB's default completion `IRB::RegexpCompletor` uses Regexp. IRB has another experimental completion `IRB::TypeCompletion` that uses type analysis.
241
+ IRB's default completion `IRB::RegexpCompletor` uses Regexp. IRB has another experimental completion `IRB::TypeCompletor` that uses type analysis.
241
242
 
242
- ### How to Enable IRB::TypeCompletion
243
+ ### How to Enable IRB::TypeCompletor
243
244
 
244
- To enable IRB::TypeCompletion, run IRB with `--type-completor` option
245
+ To enable IRB::TypeCompletor, run IRB with `--type-completor` option
245
246
  ```
246
247
  $ irb --type-completor
247
248
  ```
@@ -249,14 +250,14 @@ Or write the code below to IRB's rc-file.
249
250
  ```ruby
250
251
  IRB.conf[:COMPLETOR] = :type # default is :regexp
251
252
  ```
252
- You also need `gem prism` and `gem rbs` to use this feature.
253
+ You also need `gem repl_type_completor` to use this feature.
253
254
 
254
255
  To check if it's enabled, type `irb_info` into IRB and see the `Completion` section.
255
256
  ```
256
257
  irb(main):001> irb_info
257
258
  ...
258
259
  # Enabled
259
- Completion: Autocomplete, TypeCompletion::Completor(Prism: 0.17.1, RBS: 3.3.0)
260
+ Completion: Autocomplete, ReplTypeCompletor: 0.1.0, Prism: 0.18.0, RBS: 3.3.0
260
261
  # Not enabled
261
262
  Completion: Autocomplete, RegexpCompletor
262
263
  ...
@@ -265,7 +266,7 @@ If you have `sig/` directory or `rbs_collection.lock.yaml` in current directory,
265
266
 
266
267
  ### Advantage over Default IRB::RegexpCompletor
267
268
 
268
- IRB::TypeCompletion can autocomplete chained methods, block parameters and more if type information is available.
269
+ IRB::TypeCompletor can autocomplete chained methods, block parameters and more if type information is available.
269
270
  These are some examples IRB::RegexpCompletor cannot complete.
270
271
 
271
272
  ```ruby
@@ -287,11 +288,11 @@ As a trade-off, completion calculation takes more time than IRB::RegexpCompletor
287
288
 
288
289
  ### Difference between Steep's Completion
289
290
 
290
- Compared with Steep, IRB::TypeCompletion has some difference and limitations.
291
+ Compared with Steep, IRB::TypeCompletor has some difference and limitations.
291
292
  ```ruby
292
293
  [0, 'a'].sample.
293
294
  # Steep completes intersection of Integer methods and String methods
294
- # IRB::TypeCompletion completes both Integer and String methods
295
+ # IRB::TypeCompletor completes both Integer and String methods
295
296
  ```
296
297
 
297
298
  Some features like type narrowing is not implemented.
@@ -301,7 +302,7 @@ def f(arg = [0, 'a'].sample)
301
302
  arg. # Completes both Integer and String methods
302
303
  ```
303
304
 
304
- Unlike other static type checker, IRB::TypeCompletion uses runtime information to provide better completion.
305
+ Unlike other static type checker, IRB::TypeCompletor uses runtime information to provide better completion.
305
306
  ```ruby
306
307
  irb(main):001> a = [1]
307
308
  => [1]
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ Rake::TestTask.new(:test) do |t|
5
5
  t.libs << "test" << "test/lib"
6
6
  t.libs << "lib"
7
7
  t.ruby_opts << "-rhelper"
8
- t.test_files = FileList["test/irb/test_*.rb", "test/irb/type_completion/test_*.rb"]
8
+ t.test_files = FileList["test/irb/**/test_*.rb"]
9
9
  end
10
10
 
11
11
  # To make sure they have been correctly setup for Ruby CI.
@@ -13,7 +13,7 @@ desc "Run each irb test file in isolation."
13
13
  task :test_in_isolation do
14
14
  failed = false
15
15
 
16
- FileList["test/irb/test_*.rb", "test/irb/type_completion/test_*.rb"].each do |test_file|
16
+ FileList["test/irb/**/test_*.rb"].each do |test_file|
17
17
  ENV["TEST"] = test_file
18
18
  begin
19
19
  Rake::Task["test"].execute
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+ require_relative "nop"
5
+ require_relative "../pager"
6
+
7
+ module IRB
8
+ # :stopdoc:
9
+
10
+ module ExtendCommand
11
+ class History < Nop
12
+ category "IRB"
13
+ description "Shows the input history. `-g [query]` or `-G [query]` allows you to filter the output."
14
+
15
+ def self.transform_args(args)
16
+ match = args&.match(/(-g|-G)\s+(?<grep>.+)\s*\n\z/)
17
+ return unless match
18
+
19
+ "grep: #{Regexp.new(match[:grep]).inspect}"
20
+ end
21
+
22
+ def execute(grep: nil)
23
+ formatted_inputs = irb_context.io.class::HISTORY.each_with_index.reverse_each.filter_map do |input, index|
24
+ next if grep && !input.match?(grep)
25
+
26
+ header = "#{index}: "
27
+
28
+ first_line, *other_lines = input.split("\n")
29
+ first_line = "#{header}#{first_line}"
30
+
31
+ truncated_lines = other_lines.slice!(1..) # Show 1 additional line (2 total)
32
+ other_lines << "..." if truncated_lines&.any?
33
+
34
+ other_lines.map! do |line|
35
+ " " * header.length + line
36
+ end
37
+
38
+ [first_line, *other_lines].join("\n") + "\n"
39
+ end
40
+
41
+ Pager.page_content(formatted_inputs.join)
42
+ end
43
+ end
44
+ end
45
+
46
+ # :startdoc:
47
+ end
@@ -16,6 +16,12 @@ module IRB
16
16
  commands_info = IRB::ExtendCommandBundle.all_commands_info
17
17
  commands_grouped_by_categories = commands_info.group_by { |cmd| cmd[:category] }
18
18
 
19
+ user_aliases = irb_context.instance_variable_get(:@user_aliases)
20
+
21
+ commands_grouped_by_categories["Aliases"] = user_aliases.map do |alias_name, target|
22
+ { display_name: alias_name, description: "Alias for `#{target}`" }
23
+ end
24
+
19
25
  if irb_context.with_debugger
20
26
  # Remove the original "Debugging" category
21
27
  commands_grouped_by_categories.delete("Debugging")
@@ -27,11 +27,18 @@ module IRB
27
27
  puts "Error: Expected a string but got #{str.inspect}"
28
28
  return
29
29
  end
30
-
31
- source = SourceFinder.new(@irb_context).find_source(str)
30
+ if str.include? " -s"
31
+ str, esses = str.split(" -")
32
+ s_count = esses.count("^s").zero? ? esses.size : 1
33
+ source = SourceFinder.new(@irb_context).find_source(str, s_count)
34
+ else
35
+ source = SourceFinder.new(@irb_context).find_source(str)
36
+ end
32
37
 
33
38
  if source
34
39
  show_source(source)
40
+ elsif s_count
41
+ puts "Error: Couldn't locate a super definition for #{str}"
35
42
  else
36
43
  puts "Error: Couldn't locate a definition for #{str}"
37
44
  end
@@ -93,6 +93,27 @@ module IRB
93
93
  end
94
94
  end
95
95
 
96
+ class TypeCompletor < BaseCompletor # :nodoc:
97
+ def initialize(context)
98
+ @context = context
99
+ end
100
+
101
+ def inspect
102
+ ReplTypeCompletor.info
103
+ end
104
+
105
+ def completion_candidates(preposing, target, _postposing, bind:)
106
+ result = ReplTypeCompletor.analyze(preposing + target, binding: bind, filename: @context.irb_path)
107
+ return [] unless result
108
+ result.completion_candidates.map { target + _1 }
109
+ end
110
+
111
+ def doc_namespace(preposing, matched, _postposing, bind:)
112
+ result = ReplTypeCompletor.analyze(preposing + matched, binding: bind, filename: @context.irb_path)
113
+ result&.doc_namespace('')
114
+ end
115
+ end
116
+
96
117
  class RegexpCompletor < BaseCompletor # :nodoc:
97
118
  using Module.new {
98
119
  refine ::Binding do
data/lib/irb/context.rb CHANGED
@@ -146,9 +146,21 @@ module IRB
146
146
  @newline_before_multiline_output = true
147
147
  end
148
148
 
149
- @command_aliases = IRB.conf[:COMMAND_ALIASES]
149
+ @user_aliases = IRB.conf[:COMMAND_ALIASES].dup
150
+ @command_aliases = @user_aliases.merge(KEYWORD_ALIASES)
150
151
  end
151
152
 
153
+ # because all input will eventually be evaluated as Ruby code,
154
+ # command names that conflict with Ruby keywords need special workaround
155
+ # we can remove them once we implemented a better command system for IRB
156
+ KEYWORD_ALIASES = {
157
+ :break => :irb_break,
158
+ :catch => :irb_catch,
159
+ :next => :irb_next,
160
+ }.freeze
161
+
162
+ private_constant :KEYWORD_ALIASES
163
+
152
164
  private def build_completor
153
165
  completor_type = IRB.conf[:COMPLETOR]
154
166
  case completor_type
@@ -164,26 +176,22 @@ module IRB
164
176
  RegexpCompletor.new
165
177
  end
166
178
 
167
- TYPE_COMPLETION_REQUIRED_PRISM_VERSION = '0.17.1'
168
-
169
179
  private def build_type_completor
170
- unless Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.0.0') && RUBY_ENGINE != 'truffleruby'
171
- warn 'TypeCompletion requires RUBY_VERSION >= 3.0.0'
180
+ if RUBY_ENGINE == 'truffleruby'
181
+ # Avoid SynatxError. truffleruby does not support endless method definition yet.
182
+ warn 'TypeCompletor is not supported on TruffleRuby yet'
172
183
  return
173
184
  end
185
+
174
186
  begin
175
- require 'prism'
187
+ require 'repl_type_completor'
176
188
  rescue LoadError => e
177
- warn "TypeCompletion requires Prism: #{e.message}"
189
+ warn "TypeCompletor requires `gem repl_type_completor`: #{e.message}"
178
190
  return
179
191
  end
180
- unless Gem::Version.new(Prism::VERSION) >= Gem::Version.new(TYPE_COMPLETION_REQUIRED_PRISM_VERSION)
181
- warn "TypeCompletion requires Prism::VERSION >= #{TYPE_COMPLETION_REQUIRED_PRISM_VERSION}"
182
- return
183
- end
184
- require 'irb/type_completion/completor'
185
- TypeCompletion::Types.preload_in_thread
186
- TypeCompletion::Completor.new
192
+
193
+ ReplTypeCompletor.preload_rbs
194
+ TypeCompletor.new(self)
187
195
  end
188
196
 
189
197
  def save_history=(val)
data/lib/irb/debug.rb CHANGED
@@ -57,6 +57,24 @@ module IRB
57
57
  DEBUGGER__::ThreadClient.prepend(SkipPathHelperForIRB)
58
58
  end
59
59
 
60
+ if !@output_modifier_defined && !DEBUGGER__::CONFIG[:no_hint]
61
+ irb_output_modifier_proc = Reline.output_modifier_proc
62
+
63
+ Reline.output_modifier_proc = proc do |output, complete:|
64
+ unless output.strip.empty?
65
+ cmd = output.split(/\s/, 2).first
66
+
67
+ if !complete && DEBUGGER__.commands.key?(cmd)
68
+ output = output.sub(/\n$/, " # debug command\n")
69
+ end
70
+ end
71
+
72
+ irb_output_modifier_proc.call(output, complete: complete)
73
+ end
74
+
75
+ @output_modifier_defined = true
76
+ end
77
+
60
78
  true
61
79
  end
62
80
 
@@ -191,6 +191,12 @@ module IRB # :nodoc:
191
191
  [
192
192
  :irb_show_cmds, :ShowCmds, "cmd/show_cmds",
193
193
  [:show_cmds, NO_OVERRIDE],
194
+ ],
195
+
196
+ [
197
+ :irb_history, :History, "cmd/history",
198
+ [:history, NO_OVERRIDE],
199
+ [:hist, NO_OVERRIDE],
194
200
  ]
195
201
  ]
196
202
 
data/lib/irb/history.rb CHANGED
@@ -60,7 +60,7 @@ module IRB
60
60
  end
61
61
 
62
62
  File.open(history_file, (append_history ? 'a' : 'w'), 0o600, encoding: IRB.conf[:LC_MESSAGES]&.encoding) do |f|
63
- hist = history.map{ |l| l.split("\n").join("\\\n") }
63
+ hist = history.map{ |l| l.scrub.split("\n").join("\\\n") }
64
64
  unless append_history
65
65
  begin
66
66
  hist = hist.last(num) if hist.size > num and num > 0
data/lib/irb/init.rb CHANGED
@@ -82,6 +82,7 @@ module IRB # :nodoc:
82
82
  @CONF[:USE_LOADER] = false
83
83
  @CONF[:IGNORE_SIGINT] = true
84
84
  @CONF[:IGNORE_EOF] = false
85
+ @CONF[:USE_PAGER] = true
85
86
  @CONF[:EXTRA_DOC_DIRS] = []
86
87
  @CONF[:ECHO] = nil
87
88
  @CONF[:ECHO_ON_ASSIGNMENT] = nil
@@ -188,10 +189,6 @@ module IRB # :nodoc:
188
189
  # Symbol aliases
189
190
  :'$' => :show_source,
190
191
  :'@' => :whereami,
191
- # Keyword aliases
192
- :break => :irb_break,
193
- :catch => :irb_catch,
194
- :next => :irb_next,
195
192
  }
196
193
  end
197
194
 
@@ -285,6 +282,8 @@ module IRB # :nodoc:
285
282
  end
286
283
  when "--noinspect"
287
284
  @CONF[:INSPECT_MODE] = false
285
+ when "--no-pager"
286
+ @CONF[:USE_PAGER] = false
288
287
  when "--singleline", "--readline", "--legacy"
289
288
  @CONF[:USE_SINGLELINE] = true
290
289
  when "--nosingleline", "--noreadline"
@@ -22,6 +22,7 @@ Usage: irb.rb [options] [programfile] [arguments]
22
22
  Show truncated result on assignment (default).
23
23
  --inspect Use 'inspect' for output.
24
24
  --noinspect Don't use 'inspect' for output.
25
+ --no-pager Don't use pager.
25
26
  --multiline Use multiline editor module (default).
26
27
  --nomultiline Don't use multiline editor module.
27
28
  --singleline Use single line editor module.
data/lib/irb/pager.rb CHANGED
@@ -7,9 +7,9 @@ module IRB
7
7
  PAGE_COMMANDS = [ENV['RI_PAGER'], ENV['PAGER'], 'less', 'more'].compact.uniq
8
8
 
9
9
  class << self
10
- def page_content(content)
10
+ def page_content(content, **options)
11
11
  if content_exceeds_screen_height?(content)
12
- page do |io|
12
+ page(**options) do |io|
13
13
  io.puts content
14
14
  end
15
15
  else
@@ -17,8 +17,8 @@ module IRB
17
17
  end
18
18
  end
19
19
 
20
- def page
21
- if STDIN.tty? && pager = setup_pager
20
+ def page(retain_content: false)
21
+ if should_page? && pager = setup_pager(retain_content: retain_content)
22
22
  begin
23
23
  pid = pager.pid
24
24
  yield pager
@@ -40,6 +40,10 @@ module IRB
40
40
 
41
41
  private
42
42
 
43
+ def should_page?
44
+ IRB.conf[:USE_PAGER] && STDIN.tty? && (ENV.key?("TERM") && ENV["TERM"] != "dumb")
45
+ end
46
+
43
47
  def content_exceeds_screen_height?(content)
44
48
  screen_height, screen_width = begin
45
49
  Reline.get_screen_size
@@ -55,19 +59,20 @@ module IRB
55
59
  pageable_height * screen_width < Reline::Unicode.calculate_width(content, true)
56
60
  end
57
61
 
58
- def setup_pager
62
+ def setup_pager(retain_content:)
59
63
  require 'shellwords'
60
64
 
61
- PAGE_COMMANDS.each do |pager|
62
- pager = Shellwords.split(pager)
63
- next if pager.empty?
65
+ PAGE_COMMANDS.each do |pager_cmd|
66
+ cmd = Shellwords.split(pager_cmd)
67
+ next if cmd.empty?
64
68
 
65
- if pager.first == 'less' || pager.first == 'more'
66
- pager << '-R' unless pager.include?('-R')
69
+ if cmd.first == 'less'
70
+ cmd << '-R' unless cmd.include?('-R')
71
+ cmd << '-X' if retain_content && !cmd.include?('-X')
67
72
  end
68
73
 
69
74
  begin
70
- io = IO.popen(pager, 'w')
75
+ io = IO.popen(cmd, 'w')
71
76
  rescue
72
77
  next
73
78
  end
@@ -16,7 +16,7 @@ module IRB
16
16
  @irb_context = irb_context
17
17
  end
18
18
 
19
- def find_source(signature)
19
+ def find_source(signature, s_count = nil)
20
20
  context_binding = @irb_context.workspace.binding
21
21
  case signature
22
22
  when /\A[A-Z]\w*(::[A-Z]\w*)*\z/ # Const::Name
@@ -26,14 +26,13 @@ module IRB
26
26
  when /\A(?<owner>[A-Z]\w*(::[A-Z]\w*)*)#(?<method>[^ :.]+)\z/ # Class#method
27
27
  owner = eval(Regexp.last_match[:owner], context_binding)
28
28
  method = Regexp.last_match[:method]
29
- if owner.respond_to?(:instance_method)
30
- methods = owner.instance_methods + owner.private_instance_methods
31
- file, line = owner.instance_method(method).source_location if methods.include?(method.to_sym)
32
- end
29
+ return unless owner.respond_to?(:instance_method)
30
+ file, line = method_target(owner, s_count, method, "owner")
33
31
  when /\A((?<receiver>.+)(\.|::))?(?<method>[^ :.]+)\z/ # method, receiver.method, receiver::method
34
32
  receiver = eval(Regexp.last_match[:receiver] || 'self', context_binding)
35
33
  method = Regexp.last_match[:method]
36
- file, line = receiver.method(method).source_location if receiver.respond_to?(method, true)
34
+ return unless receiver.respond_to?(method, true)
35
+ file, line = method_target(receiver, s_count, method, "receiver")
37
36
  end
38
37
  if file && line && File.exist?(file)
39
38
  Source.new(file: file, first_line: line, last_line: find_end(file, line))
@@ -60,5 +59,26 @@ module IRB
60
59
  end
61
60
  first_line
62
61
  end
62
+
63
+ def method_target(owner_receiver, s_count, method, type)
64
+ case type
65
+ when "owner"
66
+ target_method = owner_receiver.instance_method(method)
67
+ return target_method.source_location unless s_count
68
+ when "receiver"
69
+ if s_count
70
+ target_method = owner_receiver.class.instance_method(method)
71
+ else
72
+ target_method = method
73
+ return owner_receiver.method(method).source_location
74
+ end
75
+ end
76
+ s_count.times do |s|
77
+ target_method = target_method.super_method if target_method
78
+ end
79
+ target_method.nil? ? nil : target_method.source_location
80
+ rescue NameError
81
+ nil
82
+ end
63
83
  end
64
84
  end
data/lib/irb/version.rb CHANGED
@@ -5,7 +5,7 @@
5
5
  #
6
6
 
7
7
  module IRB # :nodoc:
8
- VERSION = "1.9.1"
8
+ VERSION = "1.10.1"
9
9
  @RELEASE_VERSION = VERSION
10
- @LAST_UPDATE_DATE = "2023-11-21"
10
+ @LAST_UPDATE_DATE = "2023-12-05"
11
11
  end
data/lib/irb.rb CHANGED
@@ -20,6 +20,7 @@ require_relative "irb/color"
20
20
  require_relative "irb/version"
21
21
  require_relative "irb/easter-egg"
22
22
  require_relative "irb/debug"
23
+ require_relative "irb/pager"
23
24
 
24
25
  # IRB stands for "interactive Ruby" and is a tool to interactively execute Ruby
25
26
  # expressions read from the standard input.
@@ -697,7 +698,7 @@ module IRB
697
698
  end
698
699
 
699
700
  def handle_exception(exc)
700
- if exc.backtrace && exc.backtrace[0] =~ /\/irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ &&
701
+ if exc.backtrace[0] =~ /\/irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ &&
701
702
  !(SyntaxError === exc) && !(EncodingError === exc)
702
703
  # The backtrace of invalid encoding hash (ex. {"\xAE": 1}) raises EncodingError without lineno.
703
704
  irb_bug = true
@@ -705,45 +706,49 @@ module IRB
705
706
  irb_bug = false
706
707
  end
707
708
 
708
- if exc.backtrace
709
- order = nil
710
- if RUBY_VERSION < '3.0.0'
711
- if STDOUT.tty?
712
- message = exc.full_message(order: :bottom)
713
- order = :bottom
714
- else
715
- message = exc.full_message(order: :top)
716
- order = :top
717
- end
718
- else # '3.0.0' <= RUBY_VERSION
709
+ if RUBY_VERSION < '3.0.0'
710
+ if STDOUT.tty?
711
+ message = exc.full_message(order: :bottom)
712
+ order = :bottom
713
+ else
719
714
  message = exc.full_message(order: :top)
720
715
  order = :top
721
716
  end
722
- message = convert_invalid_byte_sequence(message, exc.message.encoding)
723
- message = encode_with_invalid_byte_sequence(message, IRB.conf[:LC_MESSAGES].encoding) unless message.encoding.to_s.casecmp?(IRB.conf[:LC_MESSAGES].encoding.to_s)
724
- message = message.gsub(/((?:^\t.+$\n)+)/) { |m|
725
- case order
726
- when :top
727
- lines = m.split("\n")
728
- when :bottom
729
- lines = m.split("\n").reverse
730
- end
731
- unless irb_bug
732
- lines = lines.map { |l| @context.workspace.filter_backtrace(l) }.compact
733
- if lines.size > @context.back_trace_limit
734
- omit = lines.size - @context.back_trace_limit
735
- lines = lines[0..(@context.back_trace_limit - 1)]
736
- lines << "\t... %d levels..." % omit
737
- end
717
+ else # '3.0.0' <= RUBY_VERSION
718
+ message = exc.full_message(order: :top)
719
+ order = :top
720
+ end
721
+ message = convert_invalid_byte_sequence(message, exc.message.encoding)
722
+ message = encode_with_invalid_byte_sequence(message, IRB.conf[:LC_MESSAGES].encoding) unless message.encoding.to_s.casecmp?(IRB.conf[:LC_MESSAGES].encoding.to_s)
723
+ message = message.gsub(/((?:^\t.+$\n)+)/) { |m|
724
+ case order
725
+ when :top
726
+ lines = m.split("\n")
727
+ when :bottom
728
+ lines = m.split("\n").reverse
729
+ end
730
+ unless irb_bug
731
+ lines = lines.map { |l| @context.workspace.filter_backtrace(l) }.compact
732
+ if lines.size > @context.back_trace_limit
733
+ omit = lines.size - @context.back_trace_limit
734
+ lines = lines[0..(@context.back_trace_limit - 1)]
735
+ lines << "\t... %d levels..." % omit
738
736
  end
739
- lines = lines.reverse if order == :bottom
740
- lines.map{ |l| l + "\n" }.join
741
- }
742
- # The "<top (required)>" in "(irb)" may be the top level of IRB so imitate the main object.
743
- message = message.gsub(/\(irb\):(?<num>\d+):in `<(?<frame>top \(required\))>'/) { "(irb):#{$~[:num]}:in `<main>'" }
744
- puts message
737
+ end
738
+ lines = lines.reverse if order == :bottom
739
+ lines.map{ |l| l + "\n" }.join
740
+ }
741
+ # The "<top (required)>" in "(irb)" may be the top level of IRB so imitate the main object.
742
+ message = message.gsub(/\(irb\):(?<num>\d+):in `<(?<frame>top \(required\))>'/) { "(irb):#{$~[:num]}:in `<main>'" }
743
+ puts message
744
+ puts 'Maybe IRB bug!' if irb_bug
745
+ rescue Exception => handler_exc
746
+ begin
747
+ puts exc.inspect
748
+ puts "backtraces are hidden because #{handler_exc} was raised when processing them"
749
+ rescue Exception
750
+ puts 'Uninspectable exception occurred'
745
751
  end
746
- print "Maybe IRB bug!\n" if irb_bug
747
752
  end
748
753
 
749
754
  # Evaluates the given block using the given +path+ as the Context#irb_path
@@ -855,11 +860,12 @@ module IRB
855
860
  end
856
861
  end
857
862
  end
863
+
858
864
  if multiline_p && @context.newline_before_multiline_output?
859
- printf @context.return_format, "\n#{str}"
860
- else
861
- printf @context.return_format, str
865
+ str = "\n" + str
862
866
  end
867
+
868
+ Pager.page_content(format(@context.return_format, str), retain_content: true)
863
869
  end
864
870
 
865
871
  # Outputs the local variables to this current session, including
@@ -926,9 +932,11 @@ module IRB
926
932
  when "N"
927
933
  @context.irb_name
928
934
  when "m"
929
- truncate_prompt_main(@context.main.to_s)
935
+ main_str = @context.main.to_s rescue "!#{$!.class}"
936
+ truncate_prompt_main(main_str)
930
937
  when "M"
931
- truncate_prompt_main(@context.main.inspect)
938
+ main_str = @context.main.inspect rescue "!#{$!.class}"
939
+ truncate_prompt_main(main_str)
932
940
  when "l"
933
941
  ltype
934
942
  when "i"