byebug 3.2.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +125 -99
  4. data/CONTRIBUTING.md +4 -6
  5. data/GUIDE.md +42 -20
  6. data/Gemfile +5 -3
  7. data/README.md +2 -3
  8. data/Rakefile +11 -7
  9. data/bin/byebug +2 -252
  10. data/byebug.gemspec +7 -4
  11. data/ext/byebug/byebug.c +17 -18
  12. data/ext/byebug/byebug.h +4 -5
  13. data/ext/byebug/context.c +37 -39
  14. data/ext/byebug/threads.c +39 -18
  15. data/lib/byebug.rb +2 -110
  16. data/lib/byebug/attacher.rb +23 -0
  17. data/lib/byebug/breakpoint.rb +60 -0
  18. data/lib/byebug/command.rb +62 -70
  19. data/lib/byebug/commands/break.rb +24 -24
  20. data/lib/byebug/commands/catchpoint.rb +18 -10
  21. data/lib/byebug/commands/condition.rb +18 -17
  22. data/lib/byebug/commands/continue.rb +17 -9
  23. data/lib/byebug/commands/delete.rb +19 -13
  24. data/lib/byebug/commands/display.rb +19 -53
  25. data/lib/byebug/commands/edit.rb +7 -4
  26. data/lib/byebug/commands/enable_disable.rb +130 -0
  27. data/lib/byebug/commands/eval.rb +40 -22
  28. data/lib/byebug/commands/finish.rb +13 -4
  29. data/lib/byebug/commands/frame.rb +65 -45
  30. data/lib/byebug/commands/help.rb +17 -18
  31. data/lib/byebug/commands/history.rb +14 -8
  32. data/lib/byebug/commands/info.rb +160 -182
  33. data/lib/byebug/commands/interrupt.rb +4 -1
  34. data/lib/byebug/commands/irb.rb +30 -0
  35. data/lib/byebug/commands/kill.rb +7 -8
  36. data/lib/byebug/commands/list.rb +71 -66
  37. data/lib/byebug/commands/method.rb +14 -6
  38. data/lib/byebug/commands/pry.rb +35 -0
  39. data/lib/byebug/commands/quit.rb +9 -6
  40. data/lib/byebug/commands/reload.rb +5 -2
  41. data/lib/byebug/commands/restart.rb +13 -9
  42. data/lib/byebug/commands/save.rb +17 -17
  43. data/lib/byebug/commands/set.rb +16 -15
  44. data/lib/byebug/commands/show.rb +10 -11
  45. data/lib/byebug/commands/source.rb +11 -5
  46. data/lib/byebug/commands/stepping.rb +38 -24
  47. data/lib/byebug/commands/threads.rb +45 -31
  48. data/lib/byebug/commands/trace.rb +22 -9
  49. data/lib/byebug/commands/undisplay.rb +45 -0
  50. data/lib/byebug/commands/variables.rb +83 -27
  51. data/lib/byebug/context.rb +25 -22
  52. data/lib/byebug/core.rb +82 -0
  53. data/lib/byebug/helper.rb +37 -28
  54. data/lib/byebug/history.rb +8 -4
  55. data/lib/byebug/interface.rb +12 -17
  56. data/lib/byebug/interfaces/local_interface.rb +11 -8
  57. data/lib/byebug/interfaces/remote_interface.rb +11 -8
  58. data/lib/byebug/interfaces/script_interface.rb +9 -6
  59. data/lib/byebug/options.rb +46 -0
  60. data/lib/byebug/processor.rb +7 -1
  61. data/lib/byebug/processors/command_processor.rb +135 -125
  62. data/lib/byebug/processors/control_command_processor.rb +23 -23
  63. data/lib/byebug/remote.rb +17 -26
  64. data/lib/byebug/runner.rb +100 -0
  65. data/lib/byebug/setting.rb +33 -8
  66. data/lib/byebug/settings/autoeval.rb +5 -15
  67. data/lib/byebug/settings/autoirb.rb +4 -1
  68. data/lib/byebug/settings/autolist.rb +5 -2
  69. data/lib/byebug/settings/autoreload.rb +5 -2
  70. data/lib/byebug/settings/autosave.rb +6 -2
  71. data/lib/byebug/settings/basename.rb +7 -2
  72. data/lib/byebug/settings/callstyle.rb +4 -1
  73. data/lib/byebug/settings/forcestep.rb +6 -3
  74. data/lib/byebug/settings/fullpath.rb +5 -2
  75. data/lib/byebug/settings/histfile.rb +5 -3
  76. data/lib/byebug/settings/histsize.rb +5 -3
  77. data/lib/byebug/settings/linetrace.rb +4 -1
  78. data/lib/byebug/settings/listsize.rb +5 -1
  79. data/lib/byebug/settings/post_mortem.rb +21 -13
  80. data/lib/byebug/settings/stack_on_error.rb +6 -2
  81. data/lib/byebug/settings/testing.rb +6 -1
  82. data/lib/byebug/settings/tracing_plus.rb +5 -1
  83. data/lib/byebug/settings/verbose.rb +13 -2
  84. data/lib/byebug/settings/width.rb +4 -1
  85. data/lib/byebug/version.rb +1 -1
  86. data/test/{break_test.rb → commands/break_test.rb} +41 -53
  87. data/test/{condition_test.rb → commands/condition_test.rb} +14 -14
  88. data/test/{continue_test.rb → commands/continue_test.rb} +0 -0
  89. data/test/{delete_test.rb → commands/delete_test.rb} +2 -2
  90. data/test/commands/display_test.rb +37 -0
  91. data/test/{edit_test.rb → commands/edit_test.rb} +0 -0
  92. data/test/{eval_test.rb → commands/eval_test.rb} +1 -0
  93. data/test/{finish_test.rb → commands/finish_test.rb} +11 -1
  94. data/test/{frame_test.rb → commands/frame_test.rb} +12 -16
  95. data/test/{help_test.rb → commands/help_test.rb} +21 -4
  96. data/test/{history_test.rb → commands/history_test.rb} +0 -0
  97. data/test/{info_test.rb → commands/info_test.rb} +5 -55
  98. data/test/{interrupt_test.rb → commands/interrupt_test.rb} +0 -0
  99. data/test/commands/irb_test.rb +28 -0
  100. data/test/{kill_test.rb → commands/kill_test.rb} +1 -1
  101. data/test/{list_test.rb → commands/list_test.rb} +1 -1
  102. data/test/{method_test.rb → commands/method_test.rb} +0 -0
  103. data/test/{post_mortem_test.rb → commands/post_mortem_test.rb} +6 -10
  104. data/test/{pry_test.rb → commands/pry_test.rb} +4 -13
  105. data/test/{quit_test.rb → commands/quit_test.rb} +4 -4
  106. data/test/{reload_test.rb → commands/reload_test.rb} +0 -0
  107. data/test/{restart_test.rb → commands/restart_test.rb} +6 -0
  108. data/test/{save_test.rb → commands/save_test.rb} +2 -2
  109. data/test/{set_test.rb → commands/set_test.rb} +9 -2
  110. data/test/{show_test.rb → commands/show_test.rb} +1 -1
  111. data/test/{source_test.rb → commands/source_test.rb} +3 -3
  112. data/test/{stepping_test.rb → commands/stepping_test.rb} +44 -35
  113. data/test/{thread_test.rb → commands/thread_test.rb} +0 -0
  114. data/test/{trace_test.rb → commands/trace_test.rb} +0 -0
  115. data/test/{display_test.rb → commands/undisplay_test.rb} +7 -45
  116. data/test/{variables_test.rb → commands/variables_test.rb} +10 -1
  117. data/test/debugger_alias_test.rb +2 -2
  118. data/test/runner_test.rb +127 -0
  119. data/test/support/matchers.rb +27 -25
  120. data/test/support/test_interface.rb +9 -5
  121. data/test/support/utils.rb +96 -101
  122. data/test/test_helper.rb +32 -20
  123. metadata +93 -68
  124. data/lib/byebug/commands/enable.rb +0 -154
  125. data/lib/byebug/commands/repl.rb +0 -126
  126. data/test/irb_test.rb +0 -47
  127. data/test/support/breakpoint.rb +0 -13
@@ -1,25 +1,29 @@
1
1
  module Byebug
2
+ #
3
+ # Custom display utilities.
4
+ #
2
5
  module DisplayFunctions
3
6
  def display_expression(exp)
4
- print "#{exp} = #{bb_warning_eval(exp).inspect}\n"
7
+ "#{exp} = #{bb_warning_eval(exp).inspect}"
5
8
  end
6
9
 
7
10
  def active_display_expressions?
8
- @state.display.select{|d| d[0]}.size > 0
11
+ @state.display.select { |d| d[0] }.size > 0
9
12
  end
10
13
 
11
14
  def print_display_expressions
12
15
  n = 1
13
- for d in @state.display
14
- if d[0]
15
- print "#{n}: "
16
- display_expression(d[1])
17
- end
16
+ @state.display.each do |d|
17
+ puts "#{n}: #{display_expression(d[1])}" if d[0]
18
18
  n += 1
19
19
  end
20
20
  end
21
21
  end
22
22
 
23
+ #
24
+ # Implements the functionality of adding custom expressions to be displayed
25
+ # every time the debugger stops.
26
+ #
23
27
  class AddDisplayCommand < Command
24
28
  self.allow_in_post_mortem = false
25
29
 
@@ -30,8 +34,7 @@ module Byebug
30
34
  def execute
31
35
  exp = @match[1]
32
36
  @state.display.push [true, exp]
33
- print "#{@state.display.size}: "
34
- display_expression(exp)
37
+ puts "#{@state.display.size}: #{display_expression(exp)}"
35
38
  end
36
39
 
37
40
  class << self
@@ -40,11 +43,16 @@ module Byebug
40
43
  end
41
44
 
42
45
  def description
43
- %{disp[lay] <expression>\tadd expression into display expression list}
46
+ %(disp[lay] <expression>
47
+
48
+ Add <expression> into display expression list.)
44
49
  end
45
50
  end
46
51
  end
47
52
 
53
+ #
54
+ # Displays the value of enabled expressions.
55
+ #
48
56
  class DisplayCommand < Command
49
57
  self.allow_in_post_mortem = false
50
58
 
@@ -66,49 +74,7 @@ module Byebug
66
74
  end
67
75
 
68
76
  def description
69
- %{disp[lay]\t\tdisplay expression list}
70
- end
71
- end
72
- end
73
-
74
- class DeleteDisplayCommand < Command
75
- self.allow_in_post_mortem = false
76
-
77
- def regexp
78
- /^\s* undisp(?:lay)? (?:\s+(\S+))? \s*$/x
79
- end
80
-
81
- def execute
82
- unless pos = @match[1]
83
- if confirm('Clear all expressions? (y/n) ')
84
- for d in @state.display
85
- d[0] = false
86
- end
87
- end
88
- else
89
- pos = get_int(pos, 'Undisplay')
90
- return unless pos
91
- if @state.display[pos-1]
92
- @state.display[pos-1][0] = nil
93
- else
94
- errmsg "Display expression %d is not defined.\n", pos
95
- end
96
- end
97
- end
98
-
99
- class << self
100
- def names
101
- %w(undisplay)
102
- end
103
-
104
- def description
105
- %{undisp[lay][ nnn]
106
-
107
- Cancel some expressions to be displayed when program stops. Arguments
108
- are the code numbers of the expressions to stop displaying. No
109
- argument means cancel all automatic-display expressions. "delete
110
- display" has the same effect as this command. Do "info display" to see
111
- the current list of code numbers.}
77
+ %(disp[lay] Display expression list.)
112
78
  end
113
79
  end
114
80
  end
@@ -1,4 +1,7 @@
1
1
  module Byebug
2
+ #
3
+ # Edit a file from byebug's prompt.
4
+ #
2
5
  class EditCommand < Command
3
6
  self.allow_in_control = true
4
7
 
@@ -7,13 +10,13 @@ module Byebug
7
10
  end
8
11
 
9
12
  def execute
10
- if not @match[1]
13
+ if !@match[1]
11
14
  unless @state.file
12
15
  return errmsg "We are not in a state that has an associated file.\n"
13
16
  end
14
17
  file = @state.file
15
18
  line = @state.line if @state.line
16
- elsif @pos_match = /([^:]+)[:]([0-9]+)/.match(@match[1])
19
+ elsif (@pos_match = /([^:]+)[:]([0-9]+)/.match(@match[1]))
17
20
  file, line = @pos_match.captures
18
21
  elsif File.exist?(@match[1])
19
22
  file = @match[1]
@@ -37,11 +40,11 @@ module Byebug
37
40
  end
38
41
 
39
42
  def description
40
- %{edit[ file:lineno]\tEdit specified file.
43
+ %(edit[ file:lineno] Edit specified files.
41
44
 
42
45
  With no argument, edits file containing most recent line listed.
43
46
  Editing targets can also be specified to start editing at a specific
44
- line in a specific file.}
47
+ line in a specific file.)
45
48
  end
46
49
  end
47
50
  end
@@ -0,0 +1,130 @@
1
+ module Byebug
2
+ #
3
+ # Mixin to assist command parsing
4
+ #
5
+ module EnableDisableFunctions
6
+ def enable_disable_breakpoints(is_enable, args)
7
+ return errmsg('No breakpoints have been set') if Breakpoint.none?
8
+
9
+ all_breakpoints = Byebug.breakpoints.sort_by { |b| b.id }
10
+ if args.empty?
11
+ selected_breakpoints = all_breakpoints
12
+ else
13
+ selected_ids = []
14
+ args.each do |pos|
15
+ last_id = all_breakpoints.last.id
16
+ pos, err = get_int(pos, "#{is_enable} breakpoints", 1, last_id)
17
+ return errmsg(err) unless pos
18
+
19
+ selected_ids << pos
20
+ end
21
+ selected_breakpoints = all_breakpoints.select do
22
+ |b| selected_ids.include?(b.id)
23
+ end
24
+ end
25
+
26
+ selected_breakpoints.each do |b|
27
+ enabled = ('enable' == is_enable)
28
+ if enabled && !syntax_valid?(b.expr)
29
+ return errmsg("Expression \"#{b.expr}\" syntactically incorrect; " \
30
+ 'breakpoint remains disabled.')
31
+ end
32
+
33
+ b.enabled = enabled
34
+ end
35
+ end
36
+
37
+ def enable_disable_display(is_enable, args)
38
+ if 0 == @state.display.size
39
+ return errmsg('No display expressions have been set')
40
+ end
41
+
42
+ args.each do |pos|
43
+ pos, err = get_int(pos, "#{is_enable} display", 1, @state.display.size)
44
+ return errmsg(err) unless pos
45
+
46
+ @state.display[pos - 1][0] = ('enable' == is_enable)
47
+ end
48
+ end
49
+ end
50
+
51
+ #
52
+ # Enabling or disabling custom display expressions or breakpoints.
53
+ #
54
+ class EnableDisableCommand < Command
55
+ Subcommands = [
56
+ ['breakpoints', 2, 'Enable/disable breakpoints. Give breakpoint ' \
57
+ 'numbers (separated by spaces) as arguments or no ' \
58
+ 'argument at all if you want to enable/disable ' \
59
+ 'every breakpoint'],
60
+ ['display', 2, 'Enable/disable some expressions to be displayed when ' \
61
+ ' when program stops. Arguments are the code numbers ' \
62
+ 'of the expressions to resume/stop displaying. Do ' \
63
+ '"info display" to see the current list of code ' \
64
+ 'numbers']
65
+ ].map do |name, min, help|
66
+ Subcmd.new(name, min, help)
67
+ end unless defined?(Subcommands)
68
+
69
+ def regexp
70
+ /^\s* (dis|en)(?:able)? (?:\s+(.+))? \s*$/x
71
+ end
72
+
73
+ def execute
74
+ cmd = @match[1] == 'dis' ? 'disable' : 'enable'
75
+
76
+ return errmsg("\"#{cmd}\" must be followed by \"display\", " \
77
+ "\"breakpoints\" or breakpoint ids") unless @match[2]
78
+
79
+ args = @match[2].split(/[ \t]+/)
80
+ param = args.shift
81
+ subcmd = Command.find(Subcommands, param)
82
+ if subcmd
83
+ send("#{cmd}_#{subcmd.name}", args)
84
+ else
85
+ send("#{cmd}_breakpoints", args.unshift(param))
86
+ end
87
+ end
88
+
89
+ def enable_breakpoints(args)
90
+ enable_disable_breakpoints('enable', args)
91
+ end
92
+
93
+ def enable_display(args)
94
+ enable_disable_display('enable', args)
95
+ end
96
+
97
+ def disable_breakpoints(args)
98
+ enable_disable_breakpoints('disable', args)
99
+ end
100
+
101
+ def disable_display(args)
102
+ enable_disable_display('disable', args)
103
+ end
104
+
105
+ class << self
106
+ def names
107
+ %w((en|dis)able)
108
+ end
109
+
110
+ def description
111
+ %{(en|dis)[able][[ (breakpoints|display)][ n1[ n2[ ...[ nn]]]]]
112
+
113
+ Enables or disables breakpoints or displays.
114
+
115
+ "enable" by itself enables all breakpoints, just like
116
+ "enable breakpoints". On the other side, "disable" or
117
+ "disable breakpoints" disable all breakpoints.
118
+
119
+ You can also specify a space separated list of breakpoint numbers to
120
+ enable or disable specific breakpoints. You can use either
121
+ "enable <id1> ... <idn>" or "enable breakpoints <id1> ... <idn>" and
122
+ the same with "disable".
123
+
124
+ If instead of "breakpoints" you specify "display", the command will
125
+ work exactly the same way, but displays will get enabled/disabled
126
+ instead of breakpoints.}
127
+ end
128
+ end
129
+ end
130
+ end
@@ -1,6 +1,10 @@
1
+ require 'English'
1
2
  require 'pp'
2
3
 
3
4
  module Byebug
5
+ #
6
+ # Utilities used by the eval command
7
+ #
4
8
  module EvalFunctions
5
9
  def run_with_binding
6
10
  binding = get_binding
@@ -8,6 +12,9 @@ module Byebug
8
12
  end
9
13
  end
10
14
 
15
+ #
16
+ # Evaluation of expressions from byebug's prompt.
17
+ #
11
18
  class EvalCommand < Command
12
19
  self.allow_in_control = true
13
20
 
@@ -24,13 +31,13 @@ module Byebug
24
31
  expr = @match ? @match.post_match : @input
25
32
  run_with_binding do |b|
26
33
  if Setting[:stack_on_error]
27
- print "#{bb_eval(expr, b).inspect}\n"
34
+ puts "#{bb_eval(expr, b).inspect}"
28
35
  else
29
- print "#{bb_warning_eval(expr, b).inspect}\n"
36
+ puts "#{bb_warning_eval(expr, b).inspect}"
30
37
  end
31
38
  end
32
39
  rescue
33
- print "#{$!.class} Exception: #{$!.message}\n"
40
+ puts "#{$ERROR_INFO.class} Exception: #{$ERROR_INFO.message}"
34
41
  end
35
42
 
36
43
  class << self
@@ -39,15 +46,19 @@ module Byebug
39
46
  end
40
47
 
41
48
  def description
42
- %{(p|e[val]) expression
49
+ %{(p|e[val]) <expression>
50
+
51
+ Evaluates <expression> and prints its value.
43
52
 
44
- Evaluate expression and print its value
45
53
  * NOTE - unknown input is automatically evaluated, to turn this off
46
- use 'set noautoeval'}
54
+ use 'set noautoeval'.}
47
55
  end
48
56
  end
49
57
  end
50
58
 
59
+ #
60
+ # Evaluation and pretty printing from byebug's prompt.
61
+ #
51
62
  class PPCommand < Command
52
63
  self.allow_in_control = true
53
64
 
@@ -64,9 +75,9 @@ module Byebug
64
75
  PP.pp(bb_warning_eval(@match.post_match, b), out)
65
76
  end
66
77
  end
67
- print out.string
78
+ puts out.string
68
79
  rescue
69
- out.puts $!.message
80
+ out.puts $ERROR_INFO.message
70
81
  end
71
82
 
72
83
  class << self
@@ -75,11 +86,16 @@ module Byebug
75
86
  end
76
87
 
77
88
  def description
78
- %{pp expression\tevaluate expression and pretty-print its value}
89
+ %(pp <expression>
90
+
91
+ Evaluates <expression> and pretty-prints its value.)
79
92
  end
80
93
  end
81
94
  end
82
95
 
96
+ #
97
+ # Evaluation, pretty printing and columnizing from byebug's prompt.
98
+ #
83
99
  class PutLCommand < Command
84
100
  include Columnize
85
101
  self.allow_in_control = true
@@ -97,15 +113,15 @@ module Byebug
97
113
  vals = bb_warning_eval(@match.post_match, b)
98
114
  end
99
115
  if vals.is_a?(Array)
100
- vals = vals.map{|item| item.to_s}
101
- print "#{columnize(vals, Setting[:width])}\n"
116
+ vals = vals.map { |item| item.to_s }
117
+ puts "#{columnize(vals, Setting[:width])}"
102
118
  else
103
119
  PP.pp(vals, out)
104
- print out.string
120
+ puts out.string
105
121
  end
106
122
  end
107
123
  rescue
108
- out.puts $!.message
124
+ out.puts $ERROR_INFO.message
109
125
  end
110
126
 
111
127
  class << self
@@ -114,13 +130,16 @@ module Byebug
114
130
  end
115
131
 
116
132
  def description
117
- %{putl expression
133
+ %(putl <expression>
118
134
 
119
- Evaluate expression, an array, and columnize its value}
135
+ Evaluates <expression>, an array, and columnize its value.)
120
136
  end
121
137
  end
122
138
  end
123
139
 
140
+ #
141
+ # Evaluation, pretty printing, columnizing and sorting from byebug's prompt
142
+ #
124
143
  class PSCommand < Command
125
144
  include Columnize
126
145
  self.allow_in_control = true
@@ -138,15 +157,15 @@ module Byebug
138
157
  vals = bb_warning_eval(@match.post_match, b)
139
158
  end
140
159
  if vals.is_a?(Array)
141
- vals = vals.map{|item| item.to_s}
142
- print "#{columnize(vals.sort!, Setting[:width])}\n"
160
+ vals = vals.map { |item| item.to_s }
161
+ puts "#{columnize(vals.sort!, Setting[:width])}"
143
162
  else
144
163
  PP.pp(vals, out)
145
- print out.string
164
+ puts out.string
146
165
  end
147
166
  end
148
167
  rescue
149
- out.puts $!.message
168
+ out.puts $ERROR_INFO.message
150
169
  end
151
170
 
152
171
  class << self
@@ -155,11 +174,10 @@ module Byebug
155
174
  end
156
175
 
157
176
  def description
158
- %{ps expression
177
+ %(ps <expression>
159
178
 
160
- Evaluate expression, an array, sort and columnize its value}
179
+ Evaluates <expression>, an array, sort and columnize its value.)
161
180
  end
162
181
  end
163
182
  end
164
-
165
183
  end
@@ -1,4 +1,9 @@
1
1
  module Byebug
2
+ #
3
+ # Implements the finish functionality.
4
+ #
5
+ # Allows the user to continue execution until certain frames are finished.
6
+ #
2
7
  class FinishCommand < Command
3
8
  self.allow_in_post_mortem = false
4
9
 
@@ -8,8 +13,12 @@ module Byebug
8
13
 
9
14
  def execute
10
15
  max_frames = Context.stack_size - @state.frame_pos
11
- n_frames = get_int(@match[1], 'finish', 0, max_frames - 1, 1)
12
- return nil unless n_frames
16
+ if @match[1]
17
+ n_frames, err = get_int(@match[1], 'finish', 0, max_frames - 1)
18
+ return errmsg(err) unless n_frames
19
+ else
20
+ n_frames = 1
21
+ end
13
22
 
14
23
  force = n_frames == 0 ? true : false
15
24
  @state.context.step_out(@state.frame_pos + n_frames, force)
@@ -23,11 +32,11 @@ module Byebug
23
32
  end
24
33
 
25
34
  def description
26
- %{fin[ish][ n_frames]\tExecute until frame returns.
35
+ %(fin[ish][ n_frames] Execute until frame returns.
27
36
 
28
37
  If no number is given, we run until the current frame returns. If a
29
38
  number of frames `n_frames` is given, then we run until `n_frames`
30
- return from the current position.}
39
+ return from the current position.)
31
40
  end
32
41
  end
33
42
  end