irb 1.7.1 → 1.13.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|