debug 1.6.3 → 1.7.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.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +19 -7
- data/Gemfile +0 -0
- data/LICENSE.txt +0 -0
- data/README.md +37 -14
- data/Rakefile +0 -0
- data/TODO.md +0 -0
- data/debug.gemspec +1 -1
- data/exe/rdbg +1 -1
- data/ext/debug/debug.c +15 -1
- data/ext/debug/extconf.rb +0 -0
- data/ext/debug/iseq_collector.c +0 -0
- data/lib/debug/abbrev_command.rb +77 -0
- data/lib/debug/breakpoint.rb +17 -11
- data/lib/debug/client.rb +26 -9
- data/lib/debug/color.rb +0 -0
- data/lib/debug/config.rb +34 -16
- data/lib/debug/console.rb +0 -0
- data/lib/debug/frame_info.rb +0 -0
- data/lib/debug/local.rb +16 -10
- data/lib/debug/open.rb +0 -0
- data/lib/debug/open_nonstop.rb +0 -0
- data/lib/debug/prelude.rb +0 -0
- data/lib/debug/server.rb +25 -21
- data/lib/debug/server_cdp.rb +281 -80
- data/lib/debug/server_dap.rb +109 -37
- data/lib/debug/session.rb +384 -204
- data/lib/debug/source_repository.rb +39 -19
- data/lib/debug/start.rb +1 -1
- data/lib/debug/thread_client.rb +186 -60
- data/lib/debug/tracer.rb +0 -0
- data/lib/debug/version.rb +1 -1
- data/lib/debug.rb +7 -3
- data/misc/README.md.erb +9 -3
- metadata +5 -4
@@ -6,6 +6,22 @@ module DEBUGGER__
|
|
6
6
|
class SourceRepository
|
7
7
|
include Color
|
8
8
|
|
9
|
+
def file_src iseq
|
10
|
+
if (path = (iseq.absolute_path || iseq.path)) && File.exist?(path)
|
11
|
+
File.readlines(path, chomp: true)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def get iseq
|
16
|
+
return unless iseq
|
17
|
+
|
18
|
+
if CONFIG[:show_evaledsrc]
|
19
|
+
orig_src(iseq) || file_src(iseq)
|
20
|
+
else
|
21
|
+
file_src(iseq) || orig_src(iseq)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
9
25
|
if RubyVM.respond_to? :keep_script_lines
|
10
26
|
# Ruby 3.1 and later
|
11
27
|
RubyVM.keep_script_lines = true
|
@@ -29,17 +45,13 @@ module DEBUGGER__
|
|
29
45
|
end
|
30
46
|
end
|
31
47
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
if
|
36
|
-
lines
|
48
|
+
def orig_src iseq
|
49
|
+
lines = iseq.script_lines&.map(&:chomp)
|
50
|
+
line = iseq.first_line
|
51
|
+
if line > 1
|
52
|
+
lines = [*([''] * (line - 1)), *lines]
|
37
53
|
else
|
38
|
-
|
39
|
-
File.readlines(path, chomp: true)
|
40
|
-
else
|
41
|
-
nil
|
42
|
-
end
|
54
|
+
lines
|
43
55
|
end
|
44
56
|
end
|
45
57
|
|
@@ -63,15 +75,22 @@ module DEBUGGER__
|
|
63
75
|
end
|
64
76
|
|
65
77
|
def add iseq, src
|
66
|
-
|
78
|
+
path = (iseq.absolute_path || iseq.path)
|
79
|
+
|
80
|
+
if path && File.exist?(path)
|
67
81
|
reloaded = @files.has_key? path
|
68
|
-
|
69
|
-
|
70
|
-
|
82
|
+
|
83
|
+
if src
|
84
|
+
add_iseq iseq, src
|
85
|
+
return path, reloaded
|
86
|
+
else
|
87
|
+
add_path path
|
88
|
+
return path, reloaded
|
89
|
+
end
|
90
|
+
else
|
71
91
|
add_iseq iseq, src
|
92
|
+
nil
|
72
93
|
end
|
73
|
-
|
74
|
-
nil
|
75
94
|
end
|
76
95
|
|
77
96
|
private def all_iseq iseq, rs = []
|
@@ -87,7 +106,8 @@ module DEBUGGER__
|
|
87
106
|
if line > 1
|
88
107
|
src = ("\n" * (line - 1)) + src
|
89
108
|
end
|
90
|
-
|
109
|
+
|
110
|
+
si = SrcInfo.new(src.each_line.map{|l| l.chomp})
|
91
111
|
all_iseq(iseq).each{|e|
|
92
112
|
e.instance_variable_set(:@debugger_si, si)
|
93
113
|
e.freeze
|
@@ -102,7 +122,7 @@ module DEBUGGER__
|
|
102
122
|
|
103
123
|
private def get_si iseq
|
104
124
|
return unless iseq
|
105
|
-
|
125
|
+
|
106
126
|
if iseq.instance_variable_defined?(:@debugger_si)
|
107
127
|
iseq.instance_variable_get(:@debugger_si)
|
108
128
|
elsif @files.has_key?(path = (iseq.absolute_path || iseq.path))
|
@@ -112,7 +132,7 @@ module DEBUGGER__
|
|
112
132
|
end
|
113
133
|
end
|
114
134
|
|
115
|
-
def
|
135
|
+
def orig_src iseq
|
116
136
|
if si = get_si(iseq)
|
117
137
|
si.src
|
118
138
|
end
|
data/lib/debug/start.rb
CHANGED
data/lib/debug/thread_client.rb
CHANGED
@@ -18,7 +18,7 @@ module DEBUGGER__
|
|
18
18
|
module SkipPathHelper
|
19
19
|
def skip_path?(path)
|
20
20
|
!path ||
|
21
|
-
|
21
|
+
DEBUGGER__.skip? ||
|
22
22
|
ThreadClient.current.management? ||
|
23
23
|
skip_internal_path?(path) ||
|
24
24
|
skip_config_skip_path?(path)
|
@@ -291,8 +291,10 @@ module DEBUGGER__
|
|
291
291
|
end
|
292
292
|
|
293
293
|
if event != :pause
|
294
|
-
|
295
|
-
|
294
|
+
unless bp&.skip_src
|
295
|
+
show_src
|
296
|
+
show_frames CONFIG[:show_frames]
|
297
|
+
end
|
296
298
|
|
297
299
|
set_mode :waiting
|
298
300
|
|
@@ -328,11 +330,15 @@ module DEBUGGER__
|
|
328
330
|
@step_tp.disable if @step_tp
|
329
331
|
|
330
332
|
thread = Thread.current
|
333
|
+
subsession_id = SESSION.subsession_id
|
331
334
|
|
332
335
|
if SUPPORT_TARGET_THREAD
|
333
336
|
@step_tp = TracePoint.new(*events){|tp|
|
334
|
-
|
335
|
-
|
337
|
+
if SESSION.stop_stepping? tp.path, tp.lineno, subsession_id
|
338
|
+
tp.disable
|
339
|
+
next
|
340
|
+
end
|
341
|
+
next if !yield(tp)
|
336
342
|
next if tp.path.start_with?(__dir__)
|
337
343
|
next if tp.path.start_with?('<internal:trace_point>')
|
338
344
|
next unless File.exist?(tp.path) if CONFIG[:skip_nosrc]
|
@@ -347,8 +353,11 @@ module DEBUGGER__
|
|
347
353
|
else
|
348
354
|
@step_tp = TracePoint.new(*events){|tp|
|
349
355
|
next if thread != Thread.current
|
350
|
-
|
351
|
-
|
356
|
+
if SESSION.stop_stepping? tp.path, tp.lineno, subsession_id
|
357
|
+
tp.disable
|
358
|
+
next
|
359
|
+
end
|
360
|
+
next if !yield(tp)
|
352
361
|
next if tp.path.start_with?(__dir__)
|
353
362
|
next if tp.path.start_with?('<internal:trace_point>')
|
354
363
|
next unless File.exist?(tp.path) if CONFIG[:skip_nosrc]
|
@@ -384,15 +393,19 @@ module DEBUGGER__
|
|
384
393
|
end
|
385
394
|
end
|
386
395
|
|
387
|
-
def frame_eval_core src, b
|
396
|
+
def frame_eval_core src, b, binding_location: false
|
388
397
|
saved_target_frames = @target_frames
|
389
398
|
saved_current_frame_index = @current_frame_index
|
390
399
|
|
391
400
|
if b
|
392
|
-
|
401
|
+
file, lineno = b.source_location
|
393
402
|
|
394
403
|
tp_allow_reentry do
|
395
|
-
|
404
|
+
if binding_location
|
405
|
+
b.eval(src, file, lineno)
|
406
|
+
else
|
407
|
+
b.eval(src, "(rdbg)/#{file}")
|
408
|
+
end
|
396
409
|
end
|
397
410
|
else
|
398
411
|
frame_self = current_frame.self
|
@@ -411,16 +424,16 @@ module DEBUGGER__
|
|
411
424
|
[:return_value, "_return"],
|
412
425
|
]
|
413
426
|
|
414
|
-
def frame_eval src, re_raise: false
|
427
|
+
def frame_eval src, re_raise: false, binding_location: false
|
415
428
|
@success_last_eval = false
|
416
429
|
|
417
|
-
b = current_frame
|
430
|
+
b = current_frame&.eval_binding || TOPLEVEL_BINDING
|
418
431
|
|
419
432
|
special_local_variables current_frame do |name, var|
|
420
433
|
b.local_variable_set(name, var) if /\%/ !~ name
|
421
434
|
end
|
422
435
|
|
423
|
-
result = frame_eval_core(src, b)
|
436
|
+
result = frame_eval_core(src, b, binding_location: binding_location)
|
424
437
|
|
425
438
|
@success_last_eval = true
|
426
439
|
result
|
@@ -482,19 +495,28 @@ module DEBUGGER__
|
|
482
495
|
exit!
|
483
496
|
end
|
484
497
|
|
485
|
-
def show_src(frame_index: @current_frame_index, update_line: false, max_lines: CONFIG[:show_src_lines], **options)
|
498
|
+
def show_src(frame_index: @current_frame_index, update_line: false, ignore_show_line: false, max_lines: CONFIG[:show_src_lines], **options)
|
486
499
|
if frame = get_frame(frame_index)
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
frame.show_line = end_line
|
500
|
+
begin
|
501
|
+
if ignore_show_line
|
502
|
+
prev_show_line = frame.show_line
|
503
|
+
frame.show_line = nil
|
492
504
|
end
|
493
505
|
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
506
|
+
start_line, end_line, lines = *get_src(frame, max_lines: max_lines, **options)
|
507
|
+
|
508
|
+
if start_line
|
509
|
+
if update_line
|
510
|
+
frame.show_line = end_line
|
511
|
+
end
|
512
|
+
|
513
|
+
puts "[#{start_line+1}, #{end_line}] in #{frame.pretty_path}" if !update_line && max_lines != 1
|
514
|
+
puts lines[start_line...end_line]
|
515
|
+
else
|
516
|
+
puts "# No sourcefile available for #{frame.path}"
|
517
|
+
end
|
518
|
+
ensure
|
519
|
+
frame.show_line = prev_show_line if prev_show_line
|
498
520
|
end
|
499
521
|
end
|
500
522
|
end
|
@@ -546,27 +568,55 @@ module DEBUGGER__
|
|
546
568
|
end
|
547
569
|
end
|
548
570
|
|
549
|
-
def show_ivars pat
|
550
|
-
if
|
551
|
-
|
552
|
-
|
571
|
+
def show_ivars pat, expr = nil
|
572
|
+
if expr && !expr.empty?
|
573
|
+
_self = frame_eval(expr);
|
574
|
+
elsif _self = current_frame&.self
|
575
|
+
else
|
576
|
+
_self = nil
|
577
|
+
end
|
578
|
+
|
579
|
+
if _self
|
580
|
+
M_INSTANCE_VARIABLES.bind_call(_self).sort.each{|iv|
|
581
|
+
value = M_INSTANCE_VARIABLE_GET.bind_call(_self, iv)
|
553
582
|
puts_variable_info iv, value, pat
|
554
583
|
}
|
555
584
|
end
|
556
585
|
end
|
557
586
|
|
558
|
-
def
|
559
|
-
|
587
|
+
def iter_consts c, names = {}
|
588
|
+
c.constants(false).sort.each{|name|
|
589
|
+
next if names.has_key? name
|
590
|
+
names[name] = nil
|
591
|
+
begin
|
592
|
+
value = c.const_get(name)
|
593
|
+
rescue Exception => e
|
594
|
+
value = e
|
595
|
+
end
|
596
|
+
yield name, value
|
597
|
+
}
|
598
|
+
end
|
599
|
+
|
600
|
+
def get_consts expr = nil, only_self: false, &block
|
601
|
+
if expr && !expr.empty?
|
602
|
+
_self = frame_eval(expr)
|
603
|
+
if M_KIND_OF_P.bind_call(_self, Module)
|
604
|
+
iter_consts _self, &block
|
605
|
+
return
|
606
|
+
else
|
607
|
+
raise "#{_self.inspect} (by #{expr}) is not a Module."
|
608
|
+
end
|
609
|
+
elsif _self = current_frame&.self
|
560
610
|
cs = {}
|
561
|
-
if M_KIND_OF_P.bind_call(
|
562
|
-
cs[
|
611
|
+
if M_KIND_OF_P.bind_call(_self, Module)
|
612
|
+
cs[_self] = :self
|
563
613
|
else
|
564
|
-
|
565
|
-
cs[
|
614
|
+
_self = M_CLASS.bind_call(_self)
|
615
|
+
cs[_self] = :self unless only_self
|
566
616
|
end
|
567
617
|
|
568
618
|
unless only_self
|
569
|
-
|
619
|
+
_self.ancestors.each{|c| break if c == Object; cs[c] = :ancestors}
|
570
620
|
if b = current_frame&.binding
|
571
621
|
b.eval('::Module.nesting').each{|c| cs[c] = :nesting unless cs.has_key? c}
|
572
622
|
end
|
@@ -575,16 +625,17 @@ module DEBUGGER__
|
|
575
625
|
names = {}
|
576
626
|
|
577
627
|
cs.each{|c, _|
|
578
|
-
c
|
579
|
-
next if names.has_key? name
|
580
|
-
names[name] = nil
|
581
|
-
value = c.const_get(name)
|
582
|
-
puts_variable_info name, value, pat
|
583
|
-
}
|
628
|
+
iter_consts c, names, &block
|
584
629
|
}
|
585
630
|
end
|
586
631
|
end
|
587
632
|
|
633
|
+
def show_consts pat, expr = nil, only_self: false
|
634
|
+
get_consts expr, only_self: only_self do |name, value|
|
635
|
+
puts_variable_info name, value, pat
|
636
|
+
end
|
637
|
+
end
|
638
|
+
|
588
639
|
SKIP_GLOBAL_LIST = %i[$= $KCODE $-K $SAFE].freeze
|
589
640
|
def show_globals pat
|
590
641
|
global_variables.sort.each{|name|
|
@@ -643,7 +694,8 @@ module DEBUGGER__
|
|
643
694
|
if editor = (ENV['RUBY_DEBUG_EDITOR'] || ENV['EDITOR'])
|
644
695
|
puts "command: #{editor}"
|
645
696
|
puts " path: #{path}"
|
646
|
-
|
697
|
+
require 'shellwords'
|
698
|
+
system(*Shellwords.split(editor), path)
|
647
699
|
else
|
648
700
|
puts "can not find editor setting: ENV['RUBY_DEBUG_EDITOR'] or ENV['EDITOR']"
|
649
701
|
end
|
@@ -758,7 +810,7 @@ module DEBUGGER__
|
|
758
810
|
case args.first
|
759
811
|
when :method
|
760
812
|
klass_name, op, method_name, cond, cmd, path = args[1..]
|
761
|
-
bp = MethodBreakpoint.new(current_frame
|
813
|
+
bp = MethodBreakpoint.new(current_frame&.eval_binding || TOPLEVEL_BINDING, klass_name, op, method_name, cond: cond, command: cmd, path: path)
|
762
814
|
begin
|
763
815
|
bp.enable
|
764
816
|
rescue NameError => e
|
@@ -814,6 +866,7 @@ module DEBUGGER__
|
|
814
866
|
set_mode :waiting if !waiting?
|
815
867
|
cmds = @q_cmd.pop
|
816
868
|
# pp [self, cmds: cmds]
|
869
|
+
|
817
870
|
break unless cmds
|
818
871
|
ensure
|
819
872
|
set_mode :running
|
@@ -831,8 +884,9 @@ module DEBUGGER__
|
|
831
884
|
|
832
885
|
case step_type
|
833
886
|
when :in
|
887
|
+
iter = iter || 1
|
834
888
|
if @recorder&.replaying?
|
835
|
-
@recorder.step_forward
|
889
|
+
@recorder.step_forward iter
|
836
890
|
raise SuspendReplay
|
837
891
|
else
|
838
892
|
step_tp iter do
|
@@ -845,6 +899,7 @@ module DEBUGGER__
|
|
845
899
|
frame = @target_frames.first
|
846
900
|
path = frame.location.absolute_path || "!eval:#{frame.path}"
|
847
901
|
line = frame.location.lineno
|
902
|
+
label = frame.location.base_label
|
848
903
|
|
849
904
|
if frame.iseq
|
850
905
|
frame.iseq.traceable_lines_norec(lines = {})
|
@@ -856,35 +911,89 @@ module DEBUGGER__
|
|
856
911
|
|
857
912
|
depth = @target_frames.first.frame_depth
|
858
913
|
|
859
|
-
step_tp iter do
|
914
|
+
step_tp iter do |tp|
|
860
915
|
loc = caller_locations(2, 1).first
|
861
916
|
loc_path = loc.absolute_path || "!eval:#{loc.path}"
|
917
|
+
loc_label = loc.base_label
|
918
|
+
loc_depth = DEBUGGER__.frame_depth - 3
|
862
919
|
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
920
|
+
case
|
921
|
+
when loc_depth == depth && loc_label == label
|
922
|
+
true
|
923
|
+
when loc_depth < depth
|
924
|
+
# lower stack depth
|
925
|
+
true
|
926
|
+
when (next_line &&
|
927
|
+
loc_path == path &&
|
928
|
+
(loc_lineno = loc.lineno) > line &&
|
929
|
+
loc_lineno <= next_line)
|
930
|
+
# different frame (maybe block) but the line is before next_line
|
931
|
+
true
|
932
|
+
end
|
870
933
|
end
|
871
934
|
break
|
872
935
|
|
873
936
|
when :finish
|
874
937
|
finish_frames = (iter || 1) - 1
|
875
|
-
|
938
|
+
frame = @target_frames.first
|
939
|
+
goal_depth = frame.frame_depth - finish_frames - (frame.has_return_value ? 1 : 0)
|
876
940
|
|
877
941
|
step_tp nil, [:return, :b_return] do
|
878
942
|
DEBUGGER__.frame_depth - 3 <= goal_depth ? true : false
|
879
943
|
end
|
880
944
|
break
|
881
945
|
|
946
|
+
when :until
|
947
|
+
location = iter&.strip
|
948
|
+
frame = @target_frames.first
|
949
|
+
depth = frame.frame_depth - (frame.has_return_value ? 1 : 0)
|
950
|
+
target_location_label = frame.location.base_label
|
951
|
+
|
952
|
+
case location
|
953
|
+
when nil, /\A(?:(.+):)?(\d+)\z/
|
954
|
+
no_loc = !location
|
955
|
+
file = $1 || frame.location.path
|
956
|
+
line = ($2 || frame.location.lineno + 1).to_i
|
957
|
+
|
958
|
+
step_tp nil, [:line, :return] do |tp|
|
959
|
+
if tp.event == :line
|
960
|
+
next false if no_loc && depth < DEBUGGER__.frame_depth - 3
|
961
|
+
next false unless tp.path.end_with?(file)
|
962
|
+
next false unless tp.lineno >= line
|
963
|
+
true
|
964
|
+
else
|
965
|
+
true if depth >= DEBUGGER__.frame_depth - 3 &&
|
966
|
+
caller_locations(2, 1).first.label == target_location_label
|
967
|
+
# TODO: imcomplete condition
|
968
|
+
end
|
969
|
+
end
|
970
|
+
else
|
971
|
+
pat = location
|
972
|
+
if /\A\/(.+)\/\z/ =~ pat
|
973
|
+
pat = Regexp.new($1)
|
974
|
+
end
|
975
|
+
|
976
|
+
step_tp nil, [:call, :c_call, :return] do |tp|
|
977
|
+
case tp.event
|
978
|
+
when :call, :c_call
|
979
|
+
true if pat === tp.callee_id.to_s
|
980
|
+
else # :return, :b_return
|
981
|
+
true if depth >= DEBUGGER__.frame_depth - 3 &&
|
982
|
+
caller_locations(2, 1).first.label == target_location_label
|
983
|
+
# TODO: imcomplete condition
|
984
|
+
end
|
985
|
+
end
|
986
|
+
end
|
987
|
+
|
988
|
+
break
|
989
|
+
|
882
990
|
when :back
|
991
|
+
iter = iter || 1
|
883
992
|
if @recorder&.can_step_back?
|
884
993
|
unless @recorder.backup_frames
|
885
994
|
@recorder.backup_frames = @target_frames
|
886
995
|
end
|
887
|
-
@recorder.step_back
|
996
|
+
@recorder.step_back iter
|
888
997
|
raise SuspendReplay
|
889
998
|
else
|
890
999
|
puts "Can not step back more."
|
@@ -922,8 +1031,9 @@ module DEBUGGER__
|
|
922
1031
|
when :call
|
923
1032
|
result = frame_eval(eval_src)
|
924
1033
|
when :irb
|
1034
|
+
require 'irb' # prelude's binding.irb doesn't have show_code option
|
925
1035
|
begin
|
926
|
-
result = frame_eval('binding.irb')
|
1036
|
+
result = frame_eval('binding.irb(show_code: false)', binding_location: true)
|
927
1037
|
ensure
|
928
1038
|
# workaround: https://github.com/ruby/debug/issues/308
|
929
1039
|
Reline.prompt_proc = nil if defined? Reline
|
@@ -988,6 +1098,10 @@ module DEBUGGER__
|
|
988
1098
|
when :list
|
989
1099
|
show_src(update_line: true, **(args.first || {}))
|
990
1100
|
|
1101
|
+
when :whereami
|
1102
|
+
show_src ignore_show_line: true
|
1103
|
+
show_frames CONFIG[:show_frames]
|
1104
|
+
|
991
1105
|
when :edit
|
992
1106
|
show_by_editor(args.first)
|
993
1107
|
|
@@ -1003,11 +1117,13 @@ module DEBUGGER__
|
|
1003
1117
|
|
1004
1118
|
when :ivars
|
1005
1119
|
pat = args.shift
|
1006
|
-
|
1120
|
+
expr = args.shift
|
1121
|
+
show_ivars pat, expr
|
1007
1122
|
|
1008
1123
|
when :consts
|
1009
1124
|
pat = args.shift
|
1010
|
-
|
1125
|
+
expr = args.shift
|
1126
|
+
show_consts pat, expr
|
1011
1127
|
|
1012
1128
|
when :globals
|
1013
1129
|
pat = args.shift
|
@@ -1093,6 +1209,8 @@ module DEBUGGER__
|
|
1093
1209
|
end
|
1094
1210
|
event! :result, nil
|
1095
1211
|
|
1212
|
+
when :quit
|
1213
|
+
sleep # wait for SystemExit
|
1096
1214
|
when :dap
|
1097
1215
|
process_dap args
|
1098
1216
|
when :cdp
|
@@ -1107,6 +1225,8 @@ module DEBUGGER__
|
|
1107
1225
|
rescue Exception => e
|
1108
1226
|
pp ["DEBUGGER Exception: #{__FILE__}:#{__LINE__}", e, e.backtrace]
|
1109
1227
|
raise
|
1228
|
+
ensure
|
1229
|
+
@returning = false
|
1110
1230
|
end
|
1111
1231
|
|
1112
1232
|
def debug_event(ev, args)
|
@@ -1187,12 +1307,18 @@ module DEBUGGER__
|
|
1187
1307
|
@tp_recorder.enabled?
|
1188
1308
|
end
|
1189
1309
|
|
1190
|
-
def step_back
|
1191
|
-
@index +=
|
1310
|
+
def step_back iter
|
1311
|
+
@index += iter
|
1312
|
+
if @index > @log.size
|
1313
|
+
@index = @log.size
|
1314
|
+
end
|
1192
1315
|
end
|
1193
1316
|
|
1194
|
-
def step_forward
|
1195
|
-
@index -=
|
1317
|
+
def step_forward iter
|
1318
|
+
@index -= iter
|
1319
|
+
if @index < 0
|
1320
|
+
@index = 0
|
1321
|
+
end
|
1196
1322
|
end
|
1197
1323
|
|
1198
1324
|
def step_reset
|
data/lib/debug/tracer.rb
CHANGED
File without changes
|
data/lib/debug/version.rb
CHANGED
data/lib/debug.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
if ENV['RUBY_DEBUG_LAZY']
|
4
|
+
require_relative 'debug/prelude'
|
5
|
+
else
|
6
|
+
require_relative 'debug/session'
|
7
|
+
return unless defined?(DEBUGGER__)
|
8
|
+
DEBUGGER__::start no_sigint_hook: true, nonstop: true
|
9
|
+
end
|
data/misc/README.md.erb
CHANGED
@@ -498,7 +498,8 @@ There are additional features:
|
|
498
498
|
* `<expr>` without debug command is almost same as `pp <expr>`.
|
499
499
|
* If the input line `<expr>` does *NOT* start with any debug command, the line `<expr>` will be evaluated as a Ruby expression and the result will be printed with `pp` method. So that the input `foo.bar` is same as `pp foo.bar`.
|
500
500
|
* If `<expr>` is recognized as a debug command, of course it is not evaluated as a Ruby expression, but is executed as debug command. For example, you can not evaluate such single letter local variables `i`, `b`, `n`, `c` because they are single letter debug commands. Use `p i` instead.
|
501
|
-
*
|
501
|
+
* So the author (Koichi Sasada) recommends to use `p`, `pp` or `eval` command to evaluate the Ruby expression everytime.
|
502
|
+
* `Enter` without any input repeats the last command (useful when repeating `step`s) for some commands.
|
502
503
|
* `Ctrl-D` is equal to `quit` command.
|
503
504
|
* [debug command compare sheet - Google Sheets](https://docs.google.com/spreadsheets/d/1TlmmUDsvwK4sSIyoMv-io52BUUz__R5wpu-ComXlsw0/edit?usp=sharing)
|
504
505
|
|
@@ -567,11 +568,11 @@ It is useful if you only want to call a debug command and don't want to stop the
|
|
567
568
|
```
|
568
569
|
def initialize
|
569
570
|
@a = 1
|
570
|
-
binding.b do: 'watch @a'
|
571
|
+
binding.b do: 'info \n watch @a'
|
571
572
|
end
|
572
573
|
```
|
573
574
|
|
574
|
-
On this case, register a watch breakpoint for `@a` and continue to run.
|
575
|
+
On this case, execute the `info` command then register a watch breakpoint for `@a` and continue to run. You can also use `;;` instead of `\n` to separate your commands.
|
575
576
|
|
576
577
|
If `pre: 'command'` is specified, the debugger suspends the program and run the `command` as a debug command, and keep suspend.
|
577
578
|
It is useful if you have operations before suspend.
|
@@ -591,6 +592,11 @@ On this case, you can see the result of `bar()` every time you stop there.
|
|
591
592
|
<%= `exe/rdbg --help` %>
|
592
593
|
```
|
593
594
|
|
595
|
+
# Additional Resources
|
596
|
+
|
597
|
+
- [From byebug to ruby/debug](https://st0012.dev/from-byebug-to-ruby-debug) by Stan Lo - A migration guide for `byebug` users.
|
598
|
+
- [ruby/debug cheatsheet](https://st0012.dev/ruby-debug-cheatsheet) by Stan Lo
|
599
|
+
|
594
600
|
# Contributing
|
595
601
|
|
596
602
|
Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/debug.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: debug
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Koichi Sasada
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: irb
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.
|
19
|
+
version: 1.5.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.
|
26
|
+
version: 1.5.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: reline
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -60,6 +60,7 @@ files:
|
|
60
60
|
- ext/debug/extconf.rb
|
61
61
|
- ext/debug/iseq_collector.c
|
62
62
|
- lib/debug.rb
|
63
|
+
- lib/debug/abbrev_command.rb
|
63
64
|
- lib/debug/breakpoint.rb
|
64
65
|
- lib/debug/client.rb
|
65
66
|
- lib/debug/color.rb
|