irb 1.14.3 → 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 (48) 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 -310
  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 +35 -0
  16. data/lib/irb/command/copy.rb +83 -0
  17. data/lib/irb/command/history.rb +1 -1
  18. data/lib/irb/command/internal_helpers.rb +6 -3
  19. data/lib/irb/command/ls.rb +6 -4
  20. data/lib/irb/completion.rb +69 -52
  21. data/lib/irb/context.rb +100 -64
  22. data/lib/irb/debug.rb +3 -3
  23. data/lib/irb/default_commands.rb +4 -1
  24. data/lib/irb/easter-egg.rb +3 -1
  25. data/lib/irb/ext/multi-irb.rb +2 -0
  26. data/lib/irb/history.rb +4 -0
  27. data/lib/irb/init.rb +6 -1
  28. data/lib/irb/input-method.rb +158 -122
  29. data/lib/irb/inspector.rb +12 -7
  30. data/lib/irb/lc/help-message +2 -2
  31. data/lib/irb/lc/ja/help-message +1 -1
  32. data/lib/irb/nesting_parser.rb +362 -213
  33. data/lib/irb/pager.rb +127 -6
  34. data/lib/irb/ruby-lex.rb +225 -299
  35. data/lib/irb/ruby_logo.aa +4 -0
  36. data/lib/irb/source_finder.rb +12 -18
  37. data/lib/irb/startup_message.rb +83 -0
  38. data/lib/irb/statement.rb +21 -0
  39. data/lib/irb/version.rb +2 -2
  40. data/lib/irb/workspace.rb +9 -0
  41. data/lib/irb.rb +112 -927
  42. data/man/irb.1 +2 -0
  43. metadata +42 -12
  44. data/.document +0 -8
  45. data/Rakefile +0 -52
  46. data/bin/console +0 -6
  47. data/bin/setup +0 -6
  48. data/irb.gemspec +0 -46
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'prism'
4
+
3
5
  module IRB
4
6
  module Command
5
7
  # Internal use only, for default command's backward compatibility.
@@ -7,9 +9,10 @@ module IRB
7
9
  def unwrap_string_literal(str)
8
10
  return if str.empty?
9
11
 
10
- sexp = Ripper.sexp(str)
11
- if sexp && sexp.size == 2 && sexp.last&.first&.first == :string_literal
12
- @irb_context.workspace.binding.eval(str).to_s
12
+ result = Prism.parse(str)
13
+ body = result.value.statements.body
14
+ if result.success? && body.size == 1 && body.first.is_a?(Prism::StringNode)
15
+ body.first.unescaped
13
16
  else
14
17
  str
15
18
  end
@@ -55,11 +55,13 @@ module IRB
55
55
 
56
56
  o = Output.new(grep: grep)
57
57
 
58
- klass = (obj.class == Class || obj.class == Module ? obj : obj.class)
58
+ klass = Kernel.instance_method(:class).bind(obj).call
59
+ obj_is_class_or_module = Module === obj
60
+ klass = obj_is_class_or_module ? obj : klass
59
61
 
60
- o.dump("constants", obj.constants) if obj.respond_to?(:constants)
62
+ o.dump("constants", obj.constants) if obj_is_class_or_module
61
63
  dump_methods(o, klass, obj)
62
- o.dump("instance variables", obj.instance_variables)
64
+ o.dump("instance variables", Kernel.instance_method(:instance_variables).bind(obj).call)
63
65
  o.dump("class variables", klass.class_variables)
64
66
  o.dump("locals", locals) if locals
65
67
  o.print_result
@@ -67,7 +69,7 @@ module IRB
67
69
  end
68
70
 
69
71
  def dump_methods(o, klass, obj)
70
- singleton_class = begin obj.singleton_class; rescue TypeError; nil end
72
+ singleton_class = begin Kernel.instance_method(:singleton_class).bind(obj).call; rescue TypeError; nil end
71
73
  dumped_mods = Array.new
72
74
  ancestors = klass.ancestors
73
75
  ancestors = ancestors.reject { |c| c >= Object } if klass < Object
@@ -8,30 +8,33 @@
8
8
  require_relative 'ruby-lex'
9
9
 
10
10
  module IRB
11
+ class DocumentTarget # :nodoc:
12
+ attr_reader :name
13
+
14
+ def initialize(name)
15
+ @name = name
16
+ end
17
+ end
18
+
19
+ class CommandDocument < DocumentTarget # :nodoc:
20
+ end
21
+
22
+ # Represents a method/class documentation target. May hold multiple names
23
+ # when the receiver is ambiguous (e.g. `{}.any?` could be Hash#any? or Proc#any?).
24
+ # The dialog popup uses only the first name; the full-screen display renders all.
25
+ class MethodDocument < DocumentTarget # :nodoc:
26
+ attr_reader :names
27
+
28
+ def initialize(*names)
29
+ super(names.first)
30
+ @names = names
31
+ end
32
+ end
33
+
11
34
  class BaseCompletor # :nodoc:
12
35
 
13
36
  # Set of reserved words used by Ruby, you should not use these for
14
37
  # constants or variables
15
- ReservedWords = %w[
16
- __ENCODING__ __LINE__ __FILE__
17
- BEGIN END
18
- alias and
19
- begin break
20
- case class
21
- def defined? do
22
- else elsif end ensure
23
- false for
24
- if in
25
- module
26
- next nil not
27
- or
28
- redo rescue retry return
29
- self super
30
- then true
31
- undef unless until
32
- when while
33
- yield
34
- ]
35
38
 
36
39
  HELP_COMMAND_PREPOSING = /\Ahelp\s+/
37
40
 
@@ -60,13 +63,13 @@ module IRB
60
63
 
61
64
  def retrieve_gem_and_system_load_path
62
65
  candidates = (GEM_PATHS | $LOAD_PATH)
63
- candidates.map do |p|
66
+ candidates.filter_map do |p|
64
67
  if p.respond_to?(:to_path)
65
68
  p.to_path
66
69
  else
67
70
  String(p) rescue nil
68
71
  end
69
- end.compact.sort
72
+ end.sort
70
73
  end
71
74
 
72
75
  def retrieve_files_to_require_from_load_path
@@ -96,6 +99,12 @@ module IRB
96
99
  end
97
100
  end
98
101
 
102
+ def command_document_target(preposing, matched)
103
+ if preposing.empty? && IRB::Command.command_names.include?(matched)
104
+ CommandDocument.new(matched)
105
+ end
106
+ end
107
+
99
108
  def retrieve_files_to_require_relative_from_current_dir
100
109
  @files_from_current_dir ||= Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: '.').map { |path|
101
110
  path.sub(/\.(rb|#{RbConfig::CONFIG['DLEXT']})\z/, '')
@@ -127,12 +136,21 @@ module IRB
127
136
 
128
137
  return commands unless result
129
138
 
130
- commands | result.completion_candidates.map { target + _1 }
139
+ encoded_candidates = result.completion_candidates.filter_map do |i|
140
+ encoded = i.encode(Encoding.default_external)
141
+ target + encoded
142
+ rescue Encoding::UndefinedConversionError
143
+ # If the string cannot be converted, we just ignore it
144
+ nil
145
+ end
146
+ commands | encoded_candidates
131
147
  end
132
148
 
133
149
  def doc_namespace(preposing, matched, _postposing, bind:)
134
- result = ReplTypeCompletor.analyze(preposing + matched, binding: bind, filename: @context.irb_path)
135
- result&.doc_namespace('')
150
+ command_document_target(preposing, matched) || begin
151
+ result = ReplTypeCompletor.analyze(preposing + matched, binding: bind, filename: @context.irb_path)
152
+ result&.doc_namespace('')
153
+ end
136
154
  end
137
155
  end
138
156
 
@@ -179,28 +197,15 @@ module IRB
179
197
  else
180
198
  return nil # It's not String literal
181
199
  end
182
- tokens = RubyLex.ripper_lex_without_warning(preposing.gsub(/\s*\z/, ''))
183
- tok = nil
184
- tokens.reverse_each do |t|
185
- unless [:on_lparen, :on_sp, :on_ignored_sp, :on_nl, :on_ignored_nl, :on_comment].include?(t.event)
186
- tok = t
187
- break
188
- end
189
- end
190
- return unless tok&.event == :on_ident && tok.state == Ripper::EXPR_CMDARG
191
-
192
- case tok.tok
193
- when 'require'
194
- retrieve_files_to_require_from_load_path.select { |path|
195
- path.start_with?(actual_target)
196
- }.map { |path|
197
- quote + path
200
+
201
+ case preposing
202
+ when /(^|[^\w])require\(? *\z/
203
+ retrieve_files_to_require_from_load_path.filter_map { |path|
204
+ quote + path if path.start_with?(actual_target)
198
205
  }
199
- when 'require_relative'
200
- retrieve_files_to_require_relative_from_current_dir.select { |path|
201
- path.start_with?(actual_target)
202
- }.map { |path|
203
- quote + path
206
+ when /(^|[^\w])require_relative\(? *\z/
207
+ retrieve_files_to_require_relative_from_current_dir.filter_map { |path|
208
+ quote + path if path.start_with?(actual_target)
204
209
  }
205
210
  end
206
211
  end
@@ -218,12 +223,17 @@ module IRB
218
223
  # It doesn't make sense to propose commands with other preposing
219
224
  commands = [] unless preposing.empty?
220
225
 
221
- completion_data = retrieve_completion_data(target, bind: bind, doc_namespace: false).compact.map{ |i| i.encode(Encoding.default_external) }
226
+ completion_data = retrieve_completion_data(target, bind: bind, doc_namespace: false).compact.filter_map do |i|
227
+ i.encode(Encoding.default_external)
228
+ rescue Encoding::UndefinedConversionError
229
+ # If the string cannot be converted, we just ignore it
230
+ nil
231
+ end
222
232
  commands | completion_data
223
233
  end
224
234
 
225
- def doc_namespace(_preposing, matched, _postposing, bind:)
226
- retrieve_completion_data(matched, bind: bind, doc_namespace: true)
235
+ def doc_namespace(preposing, matched, _postposing, bind:)
236
+ command_document_target(preposing, matched) || retrieve_completion_data(matched, bind: bind, doc_namespace: true)
227
237
  end
228
238
 
229
239
  def retrieve_completion_data(input, bind:, doc_namespace:)
@@ -287,7 +297,7 @@ module IRB
287
297
  nil
288
298
  else
289
299
  sym = $1
290
- candidates = Symbol.all_symbols.collect do |s|
300
+ candidates = Symbol.all_symbols.filter_map do |s|
291
301
  s.inspect
292
302
  rescue EncodingError
293
303
  # ignore
@@ -459,12 +469,19 @@ module IRB
459
469
  eval("#{perfect_match_var}.class.name", bind) rescue nil
460
470
  else
461
471
  candidates = (bind.eval_methods | bind.eval_private_methods | bind.local_variables | bind.eval_instance_variables | bind.eval_class_constants).collect{|m| m.to_s}
462
- candidates |= ReservedWords
472
+ candidates |= RubyLex::RESERVED_WORDS.map(&:to_s)
463
473
  candidates.find{ |i| i == input }
464
474
  end
465
475
  else
466
476
  candidates = (bind.eval_methods | bind.eval_private_methods | bind.local_variables | bind.eval_instance_variables | bind.eval_class_constants).collect{|m| m.to_s}
467
- candidates |= ReservedWords
477
+ candidates |= RubyLex::RESERVED_WORDS.map(&:to_s)
478
+
479
+ target_encoding = Encoding.default_external
480
+ candidates = candidates.compact.filter_map do |candidate|
481
+ candidate.encoding == target_encoding ? candidate : candidate.encode(target_encoding)
482
+ rescue EncodingError
483
+ nil
484
+ end
468
485
  candidates.grep(/^#{Regexp.quote(input)}/).sort
469
486
  end
470
487
  end
data/lib/irb/context.rb CHANGED
@@ -155,11 +155,6 @@ module IRB
155
155
  @command_aliases = IRB.conf[:COMMAND_ALIASES].dup
156
156
  end
157
157
 
158
- private def term_interactive?
159
- return true if ENV['TEST_IRB_FORCE_INTERACTIVE']
160
- STDIN.tty? && ENV['TERM'] != 'dumb'
161
- end
162
-
163
158
  def use_tracer=(val)
164
159
  require_relative "ext/tracer" if val
165
160
  IRB.conf[:USE_TRACER] = val
@@ -177,45 +172,6 @@ module IRB
177
172
  __send__(__method__, val)
178
173
  end
179
174
 
180
- private def build_completor
181
- completor_type = IRB.conf[:COMPLETOR]
182
-
183
- # Gem repl_type_completor is added to bundled gems in Ruby 3.4.
184
- # Use :type as default completor only in Ruby 3.4 or later.
185
- verbose = !!completor_type
186
- completor_type ||= RUBY_VERSION >= '3.4' ? :type : :regexp
187
-
188
- case completor_type
189
- when :regexp
190
- return RegexpCompletor.new
191
- when :type
192
- completor = build_type_completor(verbose: verbose)
193
- return completor if completor
194
- else
195
- warn "Invalid value for IRB.conf[:COMPLETOR]: #{completor_type}"
196
- end
197
- # Fallback to RegexpCompletor
198
- RegexpCompletor.new
199
- end
200
-
201
- private def build_type_completor(verbose:)
202
- if RUBY_ENGINE == 'truffleruby'
203
- # Avoid SyntaxError. truffleruby does not support endless method definition yet.
204
- warn 'TypeCompletor is not supported on TruffleRuby yet' if verbose
205
- return
206
- end
207
-
208
- begin
209
- require 'repl_type_completor'
210
- rescue LoadError => e
211
- warn "TypeCompletor requires `gem repl_type_completor`: #{e.message}" if verbose
212
- return
213
- end
214
-
215
- ReplTypeCompletor.preload_rbs
216
- TypeCompletor.new(self)
217
- end
218
-
219
175
  def save_history=(val)
220
176
  IRB.conf[:SAVE_HISTORY] = val
221
177
  end
@@ -308,6 +264,8 @@ module IRB
308
264
  attr_reader :use_autocomplete
309
265
  # A copy of the default <code>IRB.conf[:INSPECT_MODE]</code>
310
266
  attr_reader :inspect_mode
267
+ # Inspector for the current context
268
+ attr_reader :inspect_method
311
269
 
312
270
  # A copy of the default <code>IRB.conf[:PROMPT_MODE]</code>
313
271
  attr_reader :prompt_mode
@@ -600,6 +558,8 @@ module IRB
600
558
  set_last_value(result)
601
559
  when Statement::Command
602
560
  statement.command_class.execute(self, statement.arg)
561
+ when Statement::IncorrectAlias
562
+ warn statement.message
603
563
  end
604
564
 
605
565
  nil
@@ -633,37 +593,63 @@ module IRB
633
593
  result
634
594
  end
635
595
 
636
- def parse_command(code)
596
+ def parse_input(code, is_assignment_expression)
637
597
  command_name, arg = code.strip.split(/\s+/, 2)
638
- return unless code.lines.size == 1 && command_name
639
-
640
598
  arg ||= ''
641
- command = command_name.to_sym
642
- # Command aliases are always command. example: $, @
643
- if (alias_name = command_aliases[command])
644
- return [alias_name, arg]
599
+
600
+ # command can only be 1 line
601
+ if code.lines.size != 1 ||
602
+ # command name is required
603
+ command_name.nil? ||
604
+ # local variable have precedence over command
605
+ local_variables.include?(command_name.to_sym) ||
606
+ # assignment expression is not a command
607
+ (is_assignment_expression ||
608
+ (arg.start_with?(ASSIGN_OPERATORS_REGEXP) && !arg.start_with?(/==|=~/)))
609
+ return Statement::Expression.new(code, is_assignment_expression)
645
610
  end
646
611
 
647
- # Assignment-like expression is not a command
648
- return if arg.start_with?(ASSIGN_OPERATORS_REGEXP) && !arg.start_with?(/==|=~/)
612
+ command = command_name.to_sym
649
613
 
650
- # Local variable have precedence over command
651
- return if local_variables.include?(command)
614
+ # Check command aliases
615
+ if aliased_name = command_aliases[command]
616
+ if command_class = Command.load_command(aliased_name)
617
+ command = aliased_name
618
+ elsif HelperMethod.helper_methods[aliased_name]
619
+ message = <<~MESSAGE
620
+ Using command alias `#{command}` for helper method `#{aliased_name}` is not supported.
621
+ Please check the value of `IRB.conf[:COMMAND_ALIASES]`.
622
+ MESSAGE
623
+ return Statement::IncorrectAlias.new(message)
624
+ else
625
+ message = <<~MESSAGE
626
+ You're trying to use command alias `#{command}` for command `#{aliased_name}`, but `#{aliased_name}` does not exist.
627
+ Please check the value of `IRB.conf[:COMMAND_ALIASES]`.
628
+ MESSAGE
629
+ return Statement::IncorrectAlias.new(message)
630
+ end
631
+ else
632
+ command_class = Command.load_command(command)
633
+ end
652
634
 
653
- # Check visibility
654
- public_method = !!KERNEL_PUBLIC_METHOD.bind_call(main, command) rescue false
655
- private_method = !public_method && !!KERNEL_METHOD.bind_call(main, command) rescue false
656
- if Command.execute_as_command?(command, public_method: public_method, private_method: private_method)
657
- [command, arg]
635
+ if command_class
636
+ # Check whether the command conflicts with existing methods
637
+ public_method = !!KERNEL_PUBLIC_METHOD.bind_call(main, command) rescue false
638
+ private_method = !public_method && !!KERNEL_METHOD.bind_call(main, command) rescue false
639
+ if Command.execute_as_command?(command, public_method: public_method, private_method: private_method)
640
+ return Statement::Command.new(code, command_class, arg)
641
+ end
658
642
  end
643
+ Statement::Expression.new(code, is_assignment_expression)
659
644
  end
660
645
 
661
646
  def colorize_input(input, complete:)
662
647
  if IRB.conf[:USE_COLORIZE] && IRB::Color.colorable?
663
648
  lvars = local_variables || []
664
- if parse_command(input)
649
+ parsed_input = parse_input(input, false)
650
+ if parsed_input.is_a?(Statement::Command)
665
651
  name, sep, arg = input.split(/(\s+)/, 2)
666
- arg = IRB::Color.colorize_code(arg, complete: complete, local_variables: lvars)
652
+ arg = IRB::Color.colorize_code(arg, complete: complete, local_variables: lvars) if arg
667
653
  "#{IRB::Color.colorize(name, [:BOLD])}\e[m#{sep}#{arg}"
668
654
  else
669
655
  IRB::Color.colorize_code(input, complete: complete, local_variables: lvars)
@@ -673,8 +659,12 @@ module IRB
673
659
  end
674
660
  end
675
661
 
676
- def inspect_last_value # :nodoc:
677
- @inspect_method.inspect_value(@last_value)
662
+ def inspect_last_value(output = +'') # :nodoc:
663
+ @inspect_method.inspect_value(@last_value, output)
664
+ end
665
+
666
+ def inspector_support_stream_output?
667
+ @inspect_method.support_stream_output?
678
668
  end
679
669
 
680
670
  NOPRINTING_IVARS = ["@last_value"] # :nodoc:
@@ -712,5 +702,51 @@ module IRB
712
702
  main_object = main
713
703
  Object === main_object ? main_object.__send__(method_name) : Object.instance_method(method_name).bind_call(main_object)
714
704
  end
705
+
706
+ private
707
+
708
+ def term_interactive?
709
+ return true if ENV['TEST_IRB_FORCE_INTERACTIVE']
710
+ STDIN.tty? && ENV['TERM'] != 'dumb'
711
+ end
712
+
713
+ def build_completor
714
+ completor_type = IRB.conf[:COMPLETOR]
715
+
716
+ # Gem repl_type_completor is added to bundled gems in Ruby 3.4.
717
+ # Use :type as default completor only in Ruby 3.4 or later.
718
+ verbose = !!completor_type
719
+ completor_type ||= RUBY_VERSION >= '3.4' ? :type : :regexp
720
+
721
+ case completor_type
722
+ when :regexp
723
+ return RegexpCompletor.new
724
+ when :type
725
+ completor = build_type_completor(verbose: verbose)
726
+ return completor if completor
727
+ else
728
+ warn "Invalid value for IRB.conf[:COMPLETOR]: #{completor_type}"
729
+ end
730
+ # Fallback to RegexpCompletor
731
+ RegexpCompletor.new
732
+ end
733
+
734
+ def build_type_completor(verbose:)
735
+ if RUBY_ENGINE == 'truffleruby'
736
+ # Avoid SyntaxError. truffleruby does not support endless method definition yet.
737
+ warn 'TypeCompletor is not supported on TruffleRuby yet' if verbose
738
+ return
739
+ end
740
+
741
+ begin
742
+ require 'repl_type_completor'
743
+ rescue LoadError => e
744
+ warn "TypeCompletor requires `gem repl_type_completor`: #{e.message}" if verbose
745
+ return
746
+ end
747
+
748
+ ReplTypeCompletor.preload_rbs
749
+ TypeCompletor.new(self)
750
+ end
715
751
  end
716
752
  end
data/lib/irb/debug.rb CHANGED
@@ -49,7 +49,7 @@ module IRB
49
49
  def DEBUGGER__.capture_frames(*args)
50
50
  frames = capture_frames_without_irb(*args)
51
51
  frames.reject! do |frame|
52
- frame.realpath&.start_with?(IRB_DIR) || frame.path == "<internal:prelude>"
52
+ frame.realpath&.start_with?(IRB_DIR) || frame.path&.start_with?("<internal:")
53
53
  end
54
54
  frames
55
55
  end
@@ -60,7 +60,7 @@ module IRB
60
60
  if !DEBUGGER__::CONFIG[:no_hint] && irb.context.io.is_a?(RelineInputMethod)
61
61
  Reline.output_modifier_proc = proc do |input, complete:|
62
62
  unless input.strip.empty?
63
- cmd = input.split(/\s/, 2).first
63
+ cmd = input[/\S+/]
64
64
 
65
65
  if !complete && DEBUGGER__.commands.key?(cmd)
66
66
  input = input.sub(/\n$/, " # debug command\n")
@@ -87,7 +87,7 @@ module IRB
87
87
  module SkipPathHelperForIRB
88
88
  def skip_internal_path?(path)
89
89
  # The latter can be removed once https://github.com/ruby/debug/issues/866 is resolved
90
- super || path.match?(IRB_DIR) || path.match?('<internal:prelude>')
90
+ super || path&.match?(IRB_DIR) || path&.match?('<internal:prelude>')
91
91
  end
92
92
  end
93
93
 
@@ -9,6 +9,7 @@ require_relative "command/cd"
9
9
  require_relative "command/chws"
10
10
  require_relative "command/context"
11
11
  require_relative "command/continue"
12
+ require_relative "command/copy"
12
13
  require_relative "command/debug"
13
14
  require_relative "command/delete"
14
15
  require_relative "command/disable_irb"
@@ -218,7 +219,8 @@ module IRB
218
219
  )
219
220
 
220
221
  _register_with_aliases(:irb_show_doc, Command::ShowDoc,
221
- [:show_doc, NO_OVERRIDE]
222
+ [:show_doc, NO_OVERRIDE],
223
+ [:ri, NO_OVERRIDE]
222
224
  )
223
225
 
224
226
  _register_with_aliases(:irb_info, Command::IrbInfo)
@@ -249,6 +251,7 @@ module IRB
249
251
  )
250
252
 
251
253
  register(:cd, Command::CD)
254
+ register(:copy, Command::Copy)
252
255
  end
253
256
 
254
257
  ExtendCommand = Command
@@ -121,12 +121,13 @@ module IRB
121
121
  interrupted = false
122
122
  prev_trap = trap("SIGINT") { interrupted = true }
123
123
  canvas = Canvas.new(Reline.get_screen_size)
124
+ otio = Reline::IOGate.prep
124
125
  Reline::IOGate.set_winch_handler do
125
126
  canvas = Canvas.new(Reline.get_screen_size)
126
127
  end
127
128
  ruby_model = RubyModel.new
128
129
  print "\e[?25l" # hide cursor
129
- 0.step do |i| # TODO (0..).each needs Ruby 2.6 or later
130
+ (0..).each do |i|
130
131
  buff = canvas.draw do
131
132
  ruby_model.render_frame(i) do |p1, p2|
132
133
  canvas.line(p1, p2)
@@ -139,6 +140,7 @@ module IRB
139
140
  end
140
141
  rescue Interrupt
141
142
  ensure
143
+ Reline::IOGate.deprep(otio)
142
144
  print "\e[?25h" # show cursor
143
145
  trap("SIGINT", prev_trap)
144
146
  end
@@ -65,6 +65,7 @@ module IRB
65
65
  @current_job = irb
66
66
  th.run
67
67
  Thread.stop
68
+ Thread.pass
68
69
  @current_job = irb(Thread.current)
69
70
  end
70
71
 
@@ -220,6 +221,7 @@ module IRB
220
221
  end
221
222
  end
222
223
  Thread.stop
224
+ Thread.pass
223
225
  @JobManager.current_job = @JobManager.irb(Thread.current)
224
226
  end
225
227
 
data/lib/irb/history.rb CHANGED
@@ -2,9 +2,13 @@ require "pathname"
2
2
 
3
3
  module IRB
4
4
  module History
5
+ DEFAULT_ENTRY_LIMIT = 1000
6
+
5
7
  class << self
6
8
  # Integer representation of <code>IRB.conf[:HISTORY_FILE]</code>.
7
9
  def save_history
10
+ return 0 if IRB.conf[:SAVE_HISTORY] == false
11
+ return DEFAULT_ENTRY_LIMIT if IRB.conf[:SAVE_HISTORY] == true
8
12
  IRB.conf[:SAVE_HISTORY].to_i
9
13
  end
10
14
 
data/lib/irb/init.rb CHANGED
@@ -87,13 +87,14 @@ module IRB # :nodoc:
87
87
  @CONF[:IGNORE_SIGINT] = true
88
88
  @CONF[:IGNORE_EOF] = false
89
89
  @CONF[:USE_PAGER] = true
90
+ @CONF[:SHOW_BANNER] = true
90
91
  @CONF[:EXTRA_DOC_DIRS] = []
91
92
  @CONF[:ECHO] = nil
92
93
  @CONF[:ECHO_ON_ASSIGNMENT] = nil
93
94
  @CONF[:VERBOSE] = nil
94
95
 
95
96
  @CONF[:EVAL_HISTORY] = nil
96
- @CONF[:SAVE_HISTORY] = 1000
97
+ @CONF[:SAVE_HISTORY] = History::DEFAULT_ENTRY_LIMIT
97
98
 
98
99
  @CONF[:BACK_TRACE_LIMIT] = 16
99
100
 
@@ -194,6 +195,8 @@ module IRB # :nodoc:
194
195
  :'$' => :show_source,
195
196
  :'@' => :whereami,
196
197
  }
198
+
199
+ @CONF[:COPY_COMMAND] = ENV.fetch("IRB_COPY_COMMAND", nil)
197
200
  end
198
201
 
199
202
  def IRB.set_measure_callback(type = nil, arg = nil, &block)
@@ -343,6 +346,8 @@ module IRB # :nodoc:
343
346
  opt = $1 || argv.shift
344
347
  prompt_mode = opt.upcase.tr("-", "_").intern
345
348
  @CONF[:PROMPT_MODE] = prompt_mode
349
+ when "--nobanner"
350
+ @CONF[:SHOW_BANNER] = false
346
351
  when "--noprompt"
347
352
  @CONF[:PROMPT_MODE] = :NULL
348
353
  when "--script"