irb 1.7.1 → 1.13.2
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.
- checksums.yaml +4 -4
- data/.document +1 -1
- data/Gemfile +10 -1
- data/README.md +265 -20
- data/Rakefile +13 -10
- data/doc/irb/irb.rd.ja +1 -3
- data/irb.gemspec +2 -1
- data/lib/irb/cmd/nop.rb +3 -52
- data/lib/irb/color.rb +4 -2
- data/lib/irb/command/backtrace.rb +17 -0
- data/lib/irb/command/base.rb +62 -0
- data/lib/irb/command/break.rb +17 -0
- data/lib/irb/command/catch.rb +17 -0
- data/lib/irb/command/chws.rb +40 -0
- data/lib/irb/command/context.rb +16 -0
- data/lib/irb/{cmd → command}/continue.rb +3 -3
- data/lib/irb/command/debug.rb +71 -0
- data/lib/irb/{cmd → command}/delete.rb +3 -3
- data/lib/irb/command/disable_irb.rb +19 -0
- data/lib/irb/command/edit.rb +63 -0
- data/lib/irb/command/exit.rb +18 -0
- data/lib/irb/{cmd → command}/finish.rb +3 -3
- data/lib/irb/command/force_exit.rb +18 -0
- data/lib/irb/command/help.rb +83 -0
- data/lib/irb/command/history.rb +45 -0
- data/lib/irb/command/info.rb +17 -0
- data/lib/irb/command/internal_helpers.rb +27 -0
- data/lib/irb/{cmd → command}/irb_info.rb +7 -7
- data/lib/irb/{cmd → command}/load.rb +23 -8
- data/lib/irb/{cmd → command}/ls.rb +42 -19
- data/lib/irb/{cmd → command}/measure.rb +18 -17
- data/lib/irb/{cmd → command}/next.rb +3 -3
- data/lib/irb/command/pushws.rb +65 -0
- data/lib/irb/command/show_doc.rb +51 -0
- data/lib/irb/command/show_source.rb +74 -0
- data/lib/irb/{cmd → command}/step.rb +3 -3
- data/lib/irb/command/subirb.rb +123 -0
- data/lib/irb/{cmd → command}/whereami.rb +3 -5
- data/lib/irb/command.rb +23 -0
- data/lib/irb/completion.rb +133 -102
- data/lib/irb/context.rb +182 -66
- data/lib/irb/debug/ui.rb +103 -0
- data/lib/irb/{cmd/debug.rb → debug.rb} +53 -59
- data/lib/irb/default_commands.rb +265 -0
- data/lib/irb/easter-egg.rb +16 -6
- data/lib/irb/ext/change-ws.rb +6 -8
- data/lib/irb/ext/{history.rb → eval_history.rb} +7 -7
- data/lib/irb/ext/loader.rb +4 -4
- data/lib/irb/ext/multi-irb.rb +5 -5
- data/lib/irb/ext/tracer.rb +12 -51
- data/lib/irb/ext/use-loader.rb +6 -8
- data/lib/irb/ext/workspaces.rb +10 -34
- data/lib/irb/frame.rb +1 -1
- data/lib/irb/help.rb +3 -3
- data/lib/irb/helper_method/base.rb +16 -0
- data/lib/irb/helper_method/conf.rb +11 -0
- data/lib/irb/helper_method.rb +29 -0
- data/lib/irb/{ext/save-history.rb → history.rb} +20 -58
- data/lib/irb/init.rb +154 -58
- data/lib/irb/input-method.rb +238 -203
- data/lib/irb/inspector.rb +3 -3
- data/lib/irb/lc/error.rb +1 -11
- data/lib/irb/lc/help-message +4 -0
- data/lib/irb/lc/ja/error.rb +1 -11
- data/lib/irb/lc/ja/help-message +13 -0
- data/lib/irb/locale.rb +2 -2
- data/lib/irb/nesting_parser.rb +13 -3
- data/lib/irb/notifier.rb +1 -1
- data/lib/irb/output-method.rb +2 -8
- data/lib/irb/pager.rb +91 -0
- data/lib/irb/ruby-lex.rb +391 -471
- data/lib/irb/ruby_logo.aa +43 -0
- data/lib/irb/source_finder.rb +139 -0
- data/lib/irb/statement.rb +80 -0
- data/lib/irb/version.rb +3 -3
- data/lib/irb/workspace.rb +24 -4
- data/lib/irb/ws-for-case-2.rb +1 -1
- data/lib/irb/xmp.rb +3 -3
- data/lib/irb.rb +1232 -604
- data/man/irb.1 +7 -0
- metadata +60 -32
- data/lib/irb/cmd/backtrace.rb +0 -21
- data/lib/irb/cmd/break.rb +0 -21
- data/lib/irb/cmd/catch.rb +0 -21
- data/lib/irb/cmd/chws.rb +0 -36
- data/lib/irb/cmd/edit.rb +0 -61
- data/lib/irb/cmd/help.rb +0 -23
- data/lib/irb/cmd/info.rb +0 -21
- data/lib/irb/cmd/pushws.rb +0 -45
- data/lib/irb/cmd/show_cmds.rb +0 -39
- data/lib/irb/cmd/show_doc.rb +0 -48
- data/lib/irb/cmd/show_source.rb +0 -113
- data/lib/irb/cmd/subirb.rb +0 -66
- data/lib/irb/extend-command.rb +0 -356
- data/lib/irb/src_encoding.rb +0 -7
data/lib/irb/context.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# frozen_string_literal:
|
1
|
+
# frozen_string_literal: true
|
2
2
|
#
|
3
3
|
# irb/context.rb - irb context
|
4
4
|
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
|
@@ -22,10 +22,11 @@ module IRB
|
|
22
22
|
# +other+:: uses this as InputMethod
|
23
23
|
def initialize(irb, workspace = nil, input_method = nil)
|
24
24
|
@irb = irb
|
25
|
+
@workspace_stack = []
|
25
26
|
if workspace
|
26
|
-
@
|
27
|
+
@workspace_stack << workspace
|
27
28
|
else
|
28
|
-
@
|
29
|
+
@workspace_stack << WorkSpace.new
|
29
30
|
end
|
30
31
|
@thread = Thread.current
|
31
32
|
|
@@ -61,7 +62,7 @@ module IRB
|
|
61
62
|
@io = nil
|
62
63
|
|
63
64
|
self.inspect_mode = IRB.conf[:INSPECT_MODE]
|
64
|
-
self.use_tracer = IRB.conf[:USE_TRACER]
|
65
|
+
self.use_tracer = IRB.conf[:USE_TRACER]
|
65
66
|
self.use_loader = IRB.conf[:USE_LOADER] if IRB.conf[:USE_LOADER]
|
66
67
|
self.eval_history = IRB.conf[:EVAL_HISTORY] if IRB.conf[:EVAL_HISTORY]
|
67
68
|
|
@@ -72,33 +73,34 @@ module IRB
|
|
72
73
|
|
73
74
|
self.prompt_mode = IRB.conf[:PROMPT_MODE]
|
74
75
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
@irb_name =
|
76
|
+
@irb_name = IRB.conf[:IRB_NAME]
|
77
|
+
|
78
|
+
unless IRB.conf[:SINGLE_IRB] or !defined?(IRB::JobManager)
|
79
|
+
@irb_name = @irb_name + "#" + IRB.JobManager.n_jobs.to_s
|
79
80
|
end
|
80
|
-
|
81
|
+
|
82
|
+
self.irb_path = "(" + @irb_name + ")"
|
81
83
|
|
82
84
|
case input_method
|
83
85
|
when nil
|
84
86
|
@io = nil
|
85
87
|
case use_multiline?
|
86
88
|
when nil
|
87
|
-
if
|
89
|
+
if term_interactive? && IRB.conf[:PROMPT_MODE] != :INF_RUBY && !use_singleline?
|
88
90
|
# Both of multiline mode and singleline mode aren't specified.
|
89
|
-
@io = RelineInputMethod.new
|
91
|
+
@io = RelineInputMethod.new(build_completor)
|
90
92
|
else
|
91
93
|
@io = nil
|
92
94
|
end
|
93
95
|
when false
|
94
96
|
@io = nil
|
95
97
|
when true
|
96
|
-
@io = RelineInputMethod.new
|
98
|
+
@io = RelineInputMethod.new(build_completor)
|
97
99
|
end
|
98
100
|
unless @io
|
99
101
|
case use_singleline?
|
100
102
|
when nil
|
101
|
-
if (defined?(ReadlineInputMethod) &&
|
103
|
+
if (defined?(ReadlineInputMethod) && term_interactive? &&
|
102
104
|
IRB.conf[:PROMPT_MODE] != :INF_RUBY)
|
103
105
|
@io = ReadlineInputMethod.new
|
104
106
|
else
|
@@ -121,16 +123,14 @@ module IRB
|
|
121
123
|
when '-'
|
122
124
|
@io = FileInputMethod.new($stdin)
|
123
125
|
@irb_name = '-'
|
124
|
-
|
126
|
+
self.irb_path = '-'
|
125
127
|
when String
|
126
128
|
@io = FileInputMethod.new(input_method)
|
127
129
|
@irb_name = File.basename(input_method)
|
128
|
-
|
130
|
+
self.irb_path = input_method
|
129
131
|
else
|
130
132
|
@io = input_method
|
131
133
|
end
|
132
|
-
self.save_history = IRB.conf[:SAVE_HISTORY] if IRB.conf[:SAVE_HISTORY]
|
133
|
-
|
134
134
|
@extra_doc_dirs = IRB.conf[:EXTRA_DOC_DIRS]
|
135
135
|
|
136
136
|
@echo = IRB.conf[:ECHO]
|
@@ -148,18 +148,112 @@ module IRB
|
|
148
148
|
@newline_before_multiline_output = true
|
149
149
|
end
|
150
150
|
|
151
|
-
@
|
151
|
+
@user_aliases = IRB.conf[:COMMAND_ALIASES].dup
|
152
|
+
@command_aliases = @user_aliases.merge(KEYWORD_ALIASES)
|
153
|
+
end
|
154
|
+
|
155
|
+
private def term_interactive?
|
156
|
+
return true if ENV['TEST_IRB_FORCE_INTERACTIVE']
|
157
|
+
STDIN.tty? && ENV['TERM'] != 'dumb'
|
158
|
+
end
|
159
|
+
|
160
|
+
# because all input will eventually be evaluated as Ruby code,
|
161
|
+
# command names that conflict with Ruby keywords need special workaround
|
162
|
+
# we can remove them once we implemented a better command system for IRB
|
163
|
+
KEYWORD_ALIASES = {
|
164
|
+
:break => :irb_break,
|
165
|
+
:catch => :irb_catch,
|
166
|
+
:next => :irb_next,
|
167
|
+
}.freeze
|
168
|
+
|
169
|
+
private_constant :KEYWORD_ALIASES
|
170
|
+
|
171
|
+
def use_tracer=(val)
|
172
|
+
require_relative "ext/tracer" if val
|
173
|
+
IRB.conf[:USE_TRACER] = val
|
174
|
+
end
|
175
|
+
|
176
|
+
def eval_history=(val)
|
177
|
+
self.class.remove_method(__method__)
|
178
|
+
require_relative "ext/eval_history"
|
179
|
+
__send__(__method__, val)
|
180
|
+
end
|
181
|
+
|
182
|
+
def use_loader=(val)
|
183
|
+
self.class.remove_method(__method__)
|
184
|
+
require_relative "ext/use-loader"
|
185
|
+
__send__(__method__, val)
|
186
|
+
end
|
187
|
+
|
188
|
+
private def build_completor
|
189
|
+
completor_type = IRB.conf[:COMPLETOR]
|
190
|
+
case completor_type
|
191
|
+
when :regexp
|
192
|
+
return RegexpCompletor.new
|
193
|
+
when :type
|
194
|
+
completor = build_type_completor
|
195
|
+
return completor if completor
|
196
|
+
else
|
197
|
+
warn "Invalid value for IRB.conf[:COMPLETOR]: #{completor_type}"
|
198
|
+
end
|
199
|
+
# Fallback to RegexpCompletor
|
200
|
+
RegexpCompletor.new
|
201
|
+
end
|
202
|
+
|
203
|
+
private def build_type_completor
|
204
|
+
if RUBY_ENGINE == 'truffleruby'
|
205
|
+
# Avoid SyntaxError. truffleruby does not support endless method definition yet.
|
206
|
+
warn 'TypeCompletor is not supported on TruffleRuby yet'
|
207
|
+
return
|
208
|
+
end
|
209
|
+
|
210
|
+
begin
|
211
|
+
require 'repl_type_completor'
|
212
|
+
rescue LoadError => e
|
213
|
+
warn "TypeCompletor requires `gem repl_type_completor`: #{e.message}"
|
214
|
+
return
|
215
|
+
end
|
216
|
+
|
217
|
+
ReplTypeCompletor.preload_rbs
|
218
|
+
TypeCompletor.new(self)
|
219
|
+
end
|
220
|
+
|
221
|
+
def save_history=(val)
|
222
|
+
IRB.conf[:SAVE_HISTORY] = val
|
223
|
+
end
|
224
|
+
|
225
|
+
def save_history
|
226
|
+
IRB.conf[:SAVE_HISTORY]
|
227
|
+
end
|
228
|
+
|
229
|
+
# A copy of the default <code>IRB.conf[:HISTORY_FILE]</code>
|
230
|
+
def history_file
|
231
|
+
IRB.conf[:HISTORY_FILE]
|
232
|
+
end
|
233
|
+
|
234
|
+
# Set <code>IRB.conf[:HISTORY_FILE]</code> to the given +hist+.
|
235
|
+
def history_file=(hist)
|
236
|
+
IRB.conf[:HISTORY_FILE] = hist
|
237
|
+
end
|
238
|
+
|
239
|
+
# Workspace in the current context.
|
240
|
+
def workspace
|
241
|
+
@workspace_stack.last
|
242
|
+
end
|
243
|
+
|
244
|
+
# Replace the current workspace with the given +workspace+.
|
245
|
+
def replace_workspace(workspace)
|
246
|
+
@workspace_stack.pop
|
247
|
+
@workspace_stack.push(workspace)
|
152
248
|
end
|
153
249
|
|
154
250
|
# The top-level workspace, see WorkSpace#main
|
155
251
|
def main
|
156
|
-
|
252
|
+
workspace.main
|
157
253
|
end
|
158
254
|
|
159
255
|
# The toplevel workspace, see #home_workspace
|
160
256
|
attr_reader :workspace_home
|
161
|
-
# WorkSpace in the current context.
|
162
|
-
attr_accessor :workspace
|
163
257
|
# The current thread in this context.
|
164
258
|
attr_reader :thread
|
165
259
|
# The current input method.
|
@@ -180,9 +274,27 @@ module IRB
|
|
180
274
|
# Can be either name from <code>IRB.conf[:IRB_NAME]</code>, or the number of
|
181
275
|
# the current job set by JobManager, such as <code>irb#2</code>
|
182
276
|
attr_accessor :irb_name
|
183
|
-
|
184
|
-
#
|
185
|
-
|
277
|
+
|
278
|
+
# Can be one of the following:
|
279
|
+
# - the #irb_name surrounded by parenthesis
|
280
|
+
# - the +input_method+ passed to Context.new
|
281
|
+
# - the file path of the current IRB context in a binding.irb session
|
282
|
+
attr_reader :irb_path
|
283
|
+
|
284
|
+
# Sets @irb_path to the given +path+ as well as @eval_path
|
285
|
+
# @eval_path is used for evaluating code in the context of IRB session
|
286
|
+
# It's the same as irb_path, but with the IRB name postfix
|
287
|
+
# This makes sure users can distinguish the methods defined in the IRB session
|
288
|
+
# from the methods defined in the current file's context, especially with binding.irb
|
289
|
+
def irb_path=(path)
|
290
|
+
@irb_path = path
|
291
|
+
|
292
|
+
if File.exist?(path)
|
293
|
+
@eval_path = "#{path}(#{IRB.conf[:IRB_NAME]})"
|
294
|
+
else
|
295
|
+
@eval_path = path
|
296
|
+
end
|
297
|
+
end
|
186
298
|
|
187
299
|
# Whether multiline editor mode is enabled or not.
|
188
300
|
#
|
@@ -203,18 +315,29 @@ module IRB
|
|
203
315
|
attr_reader :prompt_mode
|
204
316
|
# Standard IRB prompt.
|
205
317
|
#
|
206
|
-
# See IRB@
|
318
|
+
# See {Custom Prompts}[rdoc-ref:IRB@Custom+Prompts] for more information.
|
207
319
|
attr_accessor :prompt_i
|
208
320
|
# IRB prompt for continuated strings.
|
209
321
|
#
|
210
|
-
# See IRB@
|
322
|
+
# See {Custom Prompts}[rdoc-ref:IRB@Custom+Prompts] for more information.
|
211
323
|
attr_accessor :prompt_s
|
212
324
|
# IRB prompt for continuated statement. (e.g. immediately after an +if+)
|
213
325
|
#
|
214
|
-
# See IRB@
|
326
|
+
# See {Custom Prompts}[rdoc-ref:IRB@Custom+Prompts] for more information.
|
215
327
|
attr_accessor :prompt_c
|
216
|
-
|
217
|
-
|
328
|
+
|
329
|
+
# TODO: Remove this when developing v2.0
|
330
|
+
def prompt_n
|
331
|
+
warn "IRB::Context#prompt_n is deprecated and will be removed in the next major release."
|
332
|
+
""
|
333
|
+
end
|
334
|
+
|
335
|
+
# TODO: Remove this when developing v2.0
|
336
|
+
def prompt_n=(_)
|
337
|
+
warn "IRB::Context#prompt_n= is deprecated and will be removed in the next major release."
|
338
|
+
""
|
339
|
+
end
|
340
|
+
|
218
341
|
# Can be either the default <code>IRB.conf[:AUTO_INDENT]</code>, or the
|
219
342
|
# mode set by #prompt_mode=
|
220
343
|
#
|
@@ -322,13 +445,13 @@ module IRB
|
|
322
445
|
# The default value is 16.
|
323
446
|
#
|
324
447
|
# Can also be set using the +--back-trace-limit+ command line option.
|
325
|
-
#
|
326
|
-
# See IRB@Command+line+options for more command line options.
|
327
448
|
attr_accessor :back_trace_limit
|
328
449
|
|
329
450
|
# User-defined IRB command aliases
|
330
451
|
attr_accessor :command_aliases
|
331
452
|
|
453
|
+
attr_accessor :with_debugger
|
454
|
+
|
332
455
|
# Alias for #use_multiline
|
333
456
|
alias use_multiline? use_multiline
|
334
457
|
# Alias for #use_singleline
|
@@ -372,9 +495,7 @@ module IRB
|
|
372
495
|
# StdioInputMethod or RelineInputMethod or ReadlineInputMethod, see #io
|
373
496
|
# for more information.
|
374
497
|
def prompting?
|
375
|
-
verbose? ||
|
376
|
-
@io.kind_of?(RelineInputMethod) ||
|
377
|
-
(defined?(ReadlineInputMethod) && @io.kind_of?(ReadlineInputMethod)))
|
498
|
+
verbose? || @io.prompting?
|
378
499
|
end
|
379
500
|
|
380
501
|
# The return value of the last statement evaluated.
|
@@ -384,19 +505,18 @@ module IRB
|
|
384
505
|
# to #last_value.
|
385
506
|
def set_last_value(value)
|
386
507
|
@last_value = value
|
387
|
-
|
508
|
+
workspace.local_variable_set :_, value
|
388
509
|
end
|
389
510
|
|
390
511
|
# Sets the +mode+ of the prompt in this context.
|
391
512
|
#
|
392
|
-
# See IRB@
|
513
|
+
# See {Custom Prompts}[rdoc-ref:IRB@Custom+Prompts] for more information.
|
393
514
|
def prompt_mode=(mode)
|
394
515
|
@prompt_mode = mode
|
395
516
|
pconf = IRB.conf[:PROMPT][mode]
|
396
517
|
@prompt_i = pconf[:PROMPT_I]
|
397
518
|
@prompt_s = pconf[:PROMPT_S]
|
398
519
|
@prompt_c = pconf[:PROMPT_C]
|
399
|
-
@prompt_n = pconf[:PROMPT_N]
|
400
520
|
@return_format = pconf[:RETURN]
|
401
521
|
@return_format = "%s\n" if @return_format == nil
|
402
522
|
if ai = pconf.include?(:AUTO_INDENT)
|
@@ -428,8 +548,6 @@ module IRB
|
|
428
548
|
#
|
429
549
|
# Can also be set using the +--inspect+ and +--noinspect+ command line
|
430
550
|
# options.
|
431
|
-
#
|
432
|
-
# See IRB@Command+line+options for more command line options.
|
433
551
|
def inspect_mode=(opt)
|
434
552
|
|
435
553
|
if i = Inspector::INSPECTORS[opt]
|
@@ -473,45 +591,55 @@ module IRB
|
|
473
591
|
@inspect_mode
|
474
592
|
end
|
475
593
|
|
476
|
-
def evaluate(
|
594
|
+
def evaluate(statement, line_no) # :nodoc:
|
477
595
|
@line_no = line_no
|
478
|
-
result = nil
|
479
596
|
|
597
|
+
case statement
|
598
|
+
when Statement::EmptyInput
|
599
|
+
return
|
600
|
+
when Statement::Expression
|
601
|
+
result = evaluate_expression(statement.code, line_no)
|
602
|
+
set_last_value(result)
|
603
|
+
when Statement::Command
|
604
|
+
statement.command_class.execute(self, statement.arg)
|
605
|
+
set_last_value(nil)
|
606
|
+
end
|
607
|
+
|
608
|
+
nil
|
609
|
+
end
|
610
|
+
|
611
|
+
def from_binding?
|
612
|
+
@irb.from_binding
|
613
|
+
end
|
614
|
+
|
615
|
+
def evaluate_expression(code, line_no) # :nodoc:
|
616
|
+
result = nil
|
480
617
|
if IRB.conf[:MEASURE] && IRB.conf[:MEASURE_CALLBACKS].empty?
|
481
618
|
IRB.set_measure_callback
|
482
619
|
end
|
483
620
|
|
484
621
|
if IRB.conf[:MEASURE] && !IRB.conf[:MEASURE_CALLBACKS].empty?
|
485
622
|
last_proc = proc do
|
486
|
-
result =
|
623
|
+
result = workspace.evaluate(code, @eval_path, line_no)
|
487
624
|
end
|
488
625
|
IRB.conf[:MEASURE_CALLBACKS].inject(last_proc) do |chain, item|
|
489
626
|
_name, callback, arg = item
|
490
627
|
proc do
|
491
|
-
callback.(self,
|
628
|
+
callback.(self, code, line_no, arg) do
|
492
629
|
chain.call
|
493
630
|
end
|
494
631
|
end
|
495
632
|
end.call
|
496
633
|
else
|
497
|
-
result =
|
634
|
+
result = workspace.evaluate(code, @eval_path, line_no)
|
498
635
|
end
|
499
|
-
|
500
|
-
set_last_value(result)
|
636
|
+
result
|
501
637
|
end
|
502
638
|
|
503
639
|
def inspect_last_value # :nodoc:
|
504
640
|
@inspect_method.inspect_value(@last_value)
|
505
641
|
end
|
506
642
|
|
507
|
-
alias __exit__ exit
|
508
|
-
# Exits the current session, see IRB.irb_exit
|
509
|
-
def exit(ret = 0)
|
510
|
-
IRB.irb_exit(@irb, ret)
|
511
|
-
rescue UncaughtThrowError
|
512
|
-
super
|
513
|
-
end
|
514
|
-
|
515
643
|
NOPRINTING_IVARS = ["@last_value"] # :nodoc:
|
516
644
|
NO_INSPECTING_IVARS = ["@irb", "@io"] # :nodoc:
|
517
645
|
IDNAME_IVARS = ["@prompt_mode"] # :nodoc:
|
@@ -542,17 +670,5 @@ module IRB
|
|
542
670
|
def local_variables # :nodoc:
|
543
671
|
workspace.binding.local_variables
|
544
672
|
end
|
545
|
-
|
546
|
-
# Return true if it's aliased from the argument and it's not an identifier.
|
547
|
-
def symbol_alias?(command)
|
548
|
-
return nil if command.match?(/\A\w+\z/)
|
549
|
-
command_aliases.key?(command.to_sym)
|
550
|
-
end
|
551
|
-
|
552
|
-
# Return true if the command supports transforming args
|
553
|
-
def transform_args?(command)
|
554
|
-
command = command_aliases.fetch(command.to_sym, command)
|
555
|
-
ExtendCommandBundle.load_command(command)&.respond_to?(:transform_args)
|
556
|
-
end
|
557
673
|
end
|
558
674
|
end
|
data/lib/irb/debug/ui.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'io/console/size'
|
2
|
+
require 'debug/console'
|
3
|
+
|
4
|
+
module IRB
|
5
|
+
module Debug
|
6
|
+
class UI < DEBUGGER__::UI_Base
|
7
|
+
def initialize(irb)
|
8
|
+
@irb = irb
|
9
|
+
end
|
10
|
+
|
11
|
+
def remote?
|
12
|
+
false
|
13
|
+
end
|
14
|
+
|
15
|
+
def activate session, on_fork: false
|
16
|
+
end
|
17
|
+
|
18
|
+
def deactivate
|
19
|
+
end
|
20
|
+
|
21
|
+
def width
|
22
|
+
if (w = IO.console_size[1]) == 0 # for tests PTY
|
23
|
+
80
|
24
|
+
else
|
25
|
+
w
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def quit n
|
30
|
+
yield
|
31
|
+
exit n
|
32
|
+
end
|
33
|
+
|
34
|
+
def ask prompt
|
35
|
+
setup_interrupt do
|
36
|
+
print prompt
|
37
|
+
($stdin.gets || '').strip
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def puts str = nil
|
42
|
+
case str
|
43
|
+
when Array
|
44
|
+
str.each{|line|
|
45
|
+
$stdout.puts line.chomp
|
46
|
+
}
|
47
|
+
when String
|
48
|
+
str.each_line{|line|
|
49
|
+
$stdout.puts line.chomp
|
50
|
+
}
|
51
|
+
when nil
|
52
|
+
$stdout.puts
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def readline _
|
57
|
+
setup_interrupt do
|
58
|
+
tc = DEBUGGER__::SESSION.instance_variable_get(:@tc)
|
59
|
+
cmd = @irb.debug_readline(tc.current_frame.binding || TOPLEVEL_BINDING)
|
60
|
+
|
61
|
+
case cmd
|
62
|
+
when nil # when user types C-d
|
63
|
+
"continue"
|
64
|
+
else
|
65
|
+
cmd
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def setup_interrupt
|
71
|
+
DEBUGGER__::SESSION.intercept_trap_sigint false do
|
72
|
+
current_thread = Thread.current # should be session_server thread
|
73
|
+
|
74
|
+
prev_handler = trap(:INT){
|
75
|
+
current_thread.raise Interrupt
|
76
|
+
}
|
77
|
+
|
78
|
+
yield
|
79
|
+
ensure
|
80
|
+
trap(:INT, prev_handler)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def after_fork_parent
|
85
|
+
parent_pid = Process.pid
|
86
|
+
|
87
|
+
at_exit{
|
88
|
+
DEBUGGER__::SESSION.intercept_trap_sigint_end
|
89
|
+
trap(:SIGINT, :IGNORE)
|
90
|
+
|
91
|
+
if Process.pid == parent_pid
|
92
|
+
# only check child process from its parent
|
93
|
+
begin
|
94
|
+
# wait for all child processes to keep terminal
|
95
|
+
Process.waitpid
|
96
|
+
rescue Errno::ESRCH, Errno::ECHILD
|
97
|
+
end
|
98
|
+
end
|
99
|
+
}
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -1,34 +1,13 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module IRB
|
4
|
-
|
5
|
-
|
6
|
-
module ExtendCommand
|
7
|
-
class Debug < Nop
|
8
|
-
category "Debugging"
|
9
|
-
description "Start the debugger of debug.gem."
|
10
|
-
|
11
|
-
BINDING_IRB_FRAME_REGEXPS = [
|
12
|
-
'<internal:prelude>',
|
13
|
-
binding.method(:irb).source_location.first,
|
14
|
-
].map { |file| /\A#{Regexp.escape(file)}:\d+:in `irb'\z/ }
|
15
|
-
IRB_DIR = File.expand_path('..', __dir__)
|
16
|
-
|
17
|
-
def execute(pre_cmds: nil, do_cmds: nil)
|
18
|
-
unless binding_irb?
|
19
|
-
puts "`debug` command is only available when IRB is started with binding.irb"
|
20
|
-
return
|
21
|
-
end
|
22
|
-
|
23
|
-
unless setup_debugger
|
24
|
-
puts <<~MSG
|
25
|
-
You need to install the debug gem before using this command.
|
26
|
-
If you use `bundle exec`, please add `gem "debug"` into your Gemfile.
|
27
|
-
MSG
|
28
|
-
return
|
29
|
-
end
|
4
|
+
module Debug
|
5
|
+
IRB_DIR = File.expand_path('..', __dir__)
|
30
6
|
|
7
|
+
class << self
|
8
|
+
def insert_debug_break(pre_cmds: nil, do_cmds: nil)
|
31
9
|
options = { oneshot: true, hook_call: false }
|
10
|
+
|
32
11
|
if pre_cmds || do_cmds
|
33
12
|
options[:command] = ['irb', pre_cmds, do_cmds]
|
34
13
|
end
|
@@ -41,37 +20,29 @@ module IRB
|
|
41
20
|
# a TracePoint on #debug_break.
|
42
21
|
file, lineno = IRB::Irb.instance_method(:debug_break).source_location
|
43
22
|
DEBUGGER__::SESSION.add_line_breakpoint(file, lineno + 1, **options)
|
44
|
-
# exit current Irb#run call
|
45
|
-
throw :IRB_EXIT
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
def binding_irb?
|
51
|
-
caller.any? do |frame|
|
52
|
-
BINDING_IRB_FRAME_REGEXPS.any? do |regexp|
|
53
|
-
frame.match?(regexp)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
module SkipPathHelperForIRB
|
59
|
-
def skip_internal_path?(path)
|
60
|
-
# The latter can be removed once https://github.com/ruby/debug/issues/866 is resolved
|
61
|
-
super || path.match?(IRB_DIR) || path.match?('<internal:prelude>')
|
62
|
-
end
|
63
23
|
end
|
64
24
|
|
65
|
-
def
|
25
|
+
def setup(irb)
|
26
|
+
# When debug session is not started at all
|
66
27
|
unless defined?(DEBUGGER__::SESSION)
|
67
28
|
begin
|
68
29
|
require "debug/session"
|
69
30
|
rescue LoadError # debug.gem is not written in Gemfile
|
70
31
|
return false unless load_bundled_debug_gem
|
71
32
|
end
|
72
|
-
DEBUGGER__.
|
33
|
+
DEBUGGER__::CONFIG.set_config
|
34
|
+
configure_irb_for_debugger(irb)
|
35
|
+
|
36
|
+
DEBUGGER__.initialize_session{ IRB::Debug::UI.new(irb) }
|
37
|
+
end
|
38
|
+
|
39
|
+
# When debug session was previously started but not by IRB
|
40
|
+
if defined?(DEBUGGER__::SESSION) && !irb.context.with_debugger
|
41
|
+
configure_irb_for_debugger(irb)
|
42
|
+
DEBUGGER__::SESSION.reset_ui(IRB::Debug::UI.new(irb))
|
73
43
|
end
|
74
44
|
|
45
|
+
# Apply patches to debug gem so it skips IRB frames
|
75
46
|
unless DEBUGGER__.respond_to?(:capture_frames_without_irb)
|
76
47
|
DEBUGGER__.singleton_class.send(:alias_method, :capture_frames_without_irb, :capture_frames)
|
77
48
|
|
@@ -86,9 +57,43 @@ module IRB
|
|
86
57
|
DEBUGGER__::ThreadClient.prepend(SkipPathHelperForIRB)
|
87
58
|
end
|
88
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
|
+
|
89
78
|
true
|
90
79
|
end
|
91
80
|
|
81
|
+
private
|
82
|
+
|
83
|
+
def configure_irb_for_debugger(irb)
|
84
|
+
require 'irb/debug/ui'
|
85
|
+
IRB.instance_variable_set(:@debugger_irb, irb)
|
86
|
+
irb.context.with_debugger = true
|
87
|
+
irb.context.irb_name += ":rdbg"
|
88
|
+
end
|
89
|
+
|
90
|
+
module SkipPathHelperForIRB
|
91
|
+
def skip_internal_path?(path)
|
92
|
+
# The latter can be removed once https://github.com/ruby/debug/issues/866 is resolved
|
93
|
+
super || path.match?(IRB_DIR) || path.match?('<internal:prelude>')
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
92
97
|
# This is used when debug.gem is not written in Gemfile. Even if it's not
|
93
98
|
# installed by `bundle install`, debug.gem is installed by default because
|
94
99
|
# it's a bundled gem. This method tries to activate and load that.
|
@@ -121,16 +126,5 @@ module IRB
|
|
121
126
|
end
|
122
127
|
end
|
123
128
|
end
|
124
|
-
|
125
|
-
class DebugCommand < Debug
|
126
|
-
def self.category
|
127
|
-
"Debugging"
|
128
|
-
end
|
129
|
-
|
130
|
-
def self.description
|
131
|
-
command_name = self.name.split("::").last.downcase
|
132
|
-
"Start the debugger of debug.gem and run its `#{command_name}` command."
|
133
|
-
end
|
134
|
-
end
|
135
129
|
end
|
136
130
|
end
|