byebug 3.2.0 → 3.3.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/.rubocop.yml +3 -0
- data/CHANGELOG.md +125 -99
- data/CONTRIBUTING.md +4 -6
- data/GUIDE.md +42 -20
- data/Gemfile +5 -3
- data/README.md +2 -3
- data/Rakefile +11 -7
- data/bin/byebug +2 -252
- data/byebug.gemspec +7 -4
- data/ext/byebug/byebug.c +17 -18
- data/ext/byebug/byebug.h +4 -5
- data/ext/byebug/context.c +37 -39
- data/ext/byebug/threads.c +39 -18
- data/lib/byebug.rb +2 -110
- data/lib/byebug/attacher.rb +23 -0
- data/lib/byebug/breakpoint.rb +60 -0
- data/lib/byebug/command.rb +62 -70
- data/lib/byebug/commands/break.rb +24 -24
- data/lib/byebug/commands/catchpoint.rb +18 -10
- data/lib/byebug/commands/condition.rb +18 -17
- data/lib/byebug/commands/continue.rb +17 -9
- data/lib/byebug/commands/delete.rb +19 -13
- data/lib/byebug/commands/display.rb +19 -53
- data/lib/byebug/commands/edit.rb +7 -4
- data/lib/byebug/commands/enable_disable.rb +130 -0
- data/lib/byebug/commands/eval.rb +40 -22
- data/lib/byebug/commands/finish.rb +13 -4
- data/lib/byebug/commands/frame.rb +65 -45
- data/lib/byebug/commands/help.rb +17 -18
- data/lib/byebug/commands/history.rb +14 -8
- data/lib/byebug/commands/info.rb +160 -182
- data/lib/byebug/commands/interrupt.rb +4 -1
- data/lib/byebug/commands/irb.rb +30 -0
- data/lib/byebug/commands/kill.rb +7 -8
- data/lib/byebug/commands/list.rb +71 -66
- data/lib/byebug/commands/method.rb +14 -6
- data/lib/byebug/commands/pry.rb +35 -0
- data/lib/byebug/commands/quit.rb +9 -6
- data/lib/byebug/commands/reload.rb +5 -2
- data/lib/byebug/commands/restart.rb +13 -9
- data/lib/byebug/commands/save.rb +17 -17
- data/lib/byebug/commands/set.rb +16 -15
- data/lib/byebug/commands/show.rb +10 -11
- data/lib/byebug/commands/source.rb +11 -5
- data/lib/byebug/commands/stepping.rb +38 -24
- data/lib/byebug/commands/threads.rb +45 -31
- data/lib/byebug/commands/trace.rb +22 -9
- data/lib/byebug/commands/undisplay.rb +45 -0
- data/lib/byebug/commands/variables.rb +83 -27
- data/lib/byebug/context.rb +25 -22
- data/lib/byebug/core.rb +82 -0
- data/lib/byebug/helper.rb +37 -28
- data/lib/byebug/history.rb +8 -4
- data/lib/byebug/interface.rb +12 -17
- data/lib/byebug/interfaces/local_interface.rb +11 -8
- data/lib/byebug/interfaces/remote_interface.rb +11 -8
- data/lib/byebug/interfaces/script_interface.rb +9 -6
- data/lib/byebug/options.rb +46 -0
- data/lib/byebug/processor.rb +7 -1
- data/lib/byebug/processors/command_processor.rb +135 -125
- data/lib/byebug/processors/control_command_processor.rb +23 -23
- data/lib/byebug/remote.rb +17 -26
- data/lib/byebug/runner.rb +100 -0
- data/lib/byebug/setting.rb +33 -8
- data/lib/byebug/settings/autoeval.rb +5 -15
- data/lib/byebug/settings/autoirb.rb +4 -1
- data/lib/byebug/settings/autolist.rb +5 -2
- data/lib/byebug/settings/autoreload.rb +5 -2
- data/lib/byebug/settings/autosave.rb +6 -2
- data/lib/byebug/settings/basename.rb +7 -2
- data/lib/byebug/settings/callstyle.rb +4 -1
- data/lib/byebug/settings/forcestep.rb +6 -3
- data/lib/byebug/settings/fullpath.rb +5 -2
- data/lib/byebug/settings/histfile.rb +5 -3
- data/lib/byebug/settings/histsize.rb +5 -3
- data/lib/byebug/settings/linetrace.rb +4 -1
- data/lib/byebug/settings/listsize.rb +5 -1
- data/lib/byebug/settings/post_mortem.rb +21 -13
- data/lib/byebug/settings/stack_on_error.rb +6 -2
- data/lib/byebug/settings/testing.rb +6 -1
- data/lib/byebug/settings/tracing_plus.rb +5 -1
- data/lib/byebug/settings/verbose.rb +13 -2
- data/lib/byebug/settings/width.rb +4 -1
- data/lib/byebug/version.rb +1 -1
- data/test/{break_test.rb → commands/break_test.rb} +41 -53
- data/test/{condition_test.rb → commands/condition_test.rb} +14 -14
- data/test/{continue_test.rb → commands/continue_test.rb} +0 -0
- data/test/{delete_test.rb → commands/delete_test.rb} +2 -2
- data/test/commands/display_test.rb +37 -0
- data/test/{edit_test.rb → commands/edit_test.rb} +0 -0
- data/test/{eval_test.rb → commands/eval_test.rb} +1 -0
- data/test/{finish_test.rb → commands/finish_test.rb} +11 -1
- data/test/{frame_test.rb → commands/frame_test.rb} +12 -16
- data/test/{help_test.rb → commands/help_test.rb} +21 -4
- data/test/{history_test.rb → commands/history_test.rb} +0 -0
- data/test/{info_test.rb → commands/info_test.rb} +5 -55
- data/test/{interrupt_test.rb → commands/interrupt_test.rb} +0 -0
- data/test/commands/irb_test.rb +28 -0
- data/test/{kill_test.rb → commands/kill_test.rb} +1 -1
- data/test/{list_test.rb → commands/list_test.rb} +1 -1
- data/test/{method_test.rb → commands/method_test.rb} +0 -0
- data/test/{post_mortem_test.rb → commands/post_mortem_test.rb} +6 -10
- data/test/{pry_test.rb → commands/pry_test.rb} +4 -13
- data/test/{quit_test.rb → commands/quit_test.rb} +4 -4
- data/test/{reload_test.rb → commands/reload_test.rb} +0 -0
- data/test/{restart_test.rb → commands/restart_test.rb} +6 -0
- data/test/{save_test.rb → commands/save_test.rb} +2 -2
- data/test/{set_test.rb → commands/set_test.rb} +9 -2
- data/test/{show_test.rb → commands/show_test.rb} +1 -1
- data/test/{source_test.rb → commands/source_test.rb} +3 -3
- data/test/{stepping_test.rb → commands/stepping_test.rb} +44 -35
- data/test/{thread_test.rb → commands/thread_test.rb} +0 -0
- data/test/{trace_test.rb → commands/trace_test.rb} +0 -0
- data/test/{display_test.rb → commands/undisplay_test.rb} +7 -45
- data/test/{variables_test.rb → commands/variables_test.rb} +10 -1
- data/test/debugger_alias_test.rb +2 -2
- data/test/runner_test.rb +127 -0
- data/test/support/matchers.rb +27 -25
- data/test/support/test_interface.rb +9 -5
- data/test/support/utils.rb +96 -101
- data/test/test_helper.rb +32 -20
- metadata +93 -68
- data/lib/byebug/commands/enable.rb +0 -154
- data/lib/byebug/commands/repl.rb +0 -126
- data/test/irb_test.rb +0 -47
- data/test/support/breakpoint.rb +0 -13
@@ -9,17 +9,13 @@ module Byebug
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def switch_to_frame(frame_no)
|
12
|
-
|
13
|
-
abs_frame_no = Context.stack_size + frame_no
|
14
|
-
else
|
15
|
-
abs_frame_no = frame_no
|
16
|
-
end
|
12
|
+
frame_no >= 0 ? frame_no : Context.stack_size + frame_no
|
17
13
|
end
|
18
14
|
|
19
15
|
def navigate_to_frame(jump_no)
|
20
16
|
return if jump_no == 0
|
21
17
|
total_jumps, current_jumps, new_pos = jump_no.abs, 0, @state.frame_pos
|
22
|
-
step = jump_no/total_jumps
|
18
|
+
step = jump_no / total_jumps
|
23
19
|
loop do
|
24
20
|
new_pos += step
|
25
21
|
return new_pos if new_pos < 0 || new_pos >= Context.stack_size
|
@@ -29,21 +25,22 @@ module Byebug
|
|
29
25
|
current_jumps += 1
|
30
26
|
break if current_jumps == total_jumps
|
31
27
|
end
|
32
|
-
|
28
|
+
new_pos
|
33
29
|
end
|
34
30
|
|
35
31
|
def adjust_frame(frame_pos, absolute)
|
36
32
|
if absolute
|
37
33
|
abs_frame_pos = switch_to_frame(frame_pos)
|
38
|
-
return errmsg
|
34
|
+
return errmsg("Can't navigate to c-frame") if c_frame?(abs_frame_pos)
|
39
35
|
else
|
40
36
|
abs_frame_pos = navigate_to_frame(frame_pos)
|
41
37
|
end
|
42
38
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
39
|
+
if abs_frame_pos >= Context.stack_size
|
40
|
+
return errmsg("Can't navigate beyond the oldest frame")
|
41
|
+
elsif abs_frame_pos < 0
|
42
|
+
return errmsg("Can't navigate beyond the newest frame")
|
43
|
+
end
|
47
44
|
|
48
45
|
@state.frame_pos = abs_frame_pos
|
49
46
|
@state.file = @state.context.frame_file @state.frame_pos
|
@@ -54,14 +51,14 @@ module Byebug
|
|
54
51
|
|
55
52
|
def get_frame_class(style, pos)
|
56
53
|
frame_class = style == 'short' ? '' : "#{@state.context.frame_class pos}"
|
57
|
-
|
54
|
+
frame_class == '' ? '' : "#{frame_class}."
|
58
55
|
end
|
59
56
|
|
60
57
|
def get_frame_block_and_method(pos)
|
61
58
|
frame_deco_regexp = /((?:block(?: \(\d+ levels\))?|rescue) in )?(.+)/
|
62
59
|
frame_deco_method = "#{@state.context.frame_method pos}"
|
63
60
|
frame_block_and_method = frame_deco_regexp.match(frame_deco_method)[1..2]
|
64
|
-
|
61
|
+
frame_block_and_method.map { |x| x.nil? ? '' : x }
|
65
62
|
end
|
66
63
|
|
67
64
|
def get_frame_args(style, pos)
|
@@ -71,18 +68,19 @@ module Byebug
|
|
71
68
|
locals = @state.context.frame_locals pos if style == 'long'
|
72
69
|
my_args = args.map do |arg|
|
73
70
|
case arg[0]
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
71
|
+
when :block
|
72
|
+
prefix, default = '&', 'block'
|
73
|
+
when :rest
|
74
|
+
prefix, default = '*', 'args'
|
75
|
+
else
|
76
|
+
prefix, default = '', nil
|
80
77
|
end
|
78
|
+
|
81
79
|
klass = style == 'long' && arg[1] ? "##{locals[arg[1]].class}" : ''
|
82
80
|
"#{prefix}#{arg[1] || default}#{klass}"
|
83
81
|
end
|
84
82
|
|
85
|
-
|
83
|
+
"(#{my_args.join(', ')})"
|
86
84
|
end
|
87
85
|
|
88
86
|
def get_frame_call(prefix, pos)
|
@@ -94,10 +92,10 @@ module Byebug
|
|
94
92
|
|
95
93
|
max_call_str_size = Setting[:width] - prefix.size
|
96
94
|
if call_str.size > max_call_str_size
|
97
|
-
call_str = call_str[0..max_call_str_size - 5] +
|
95
|
+
call_str = call_str[0..max_call_str_size - 5] + '...)'
|
98
96
|
end
|
99
97
|
|
100
|
-
|
98
|
+
call_str
|
101
99
|
end
|
102
100
|
|
103
101
|
def print_backtrace
|
@@ -119,36 +117,43 @@ module Byebug
|
|
119
117
|
end
|
120
118
|
end
|
121
119
|
|
120
|
+
require 'pathname'
|
121
|
+
|
122
122
|
def shortpath(fullpath)
|
123
|
-
|
124
|
-
|
123
|
+
components = Pathname(fullpath).each_filename.to_a
|
124
|
+
return File.join(components) if components.size <= 2
|
125
|
+
|
126
|
+
File.join('...', components[-3..-1])
|
125
127
|
end
|
126
128
|
|
127
129
|
def print_frame(pos, mark_current = true)
|
128
|
-
fullpath = @state.context.frame_file
|
130
|
+
fullpath = @state.context.frame_file(pos)
|
129
131
|
file = Setting[:fullpath] ? fullpath : shortpath(fullpath)
|
130
|
-
line = @state.context.frame_line
|
132
|
+
line = @state.context.frame_line(pos)
|
131
133
|
|
132
134
|
if mark_current
|
133
135
|
frame_str = (pos == @state.frame_pos) ? '--> ' : ' '
|
134
136
|
else
|
135
|
-
frame_str =
|
137
|
+
frame_str = ''
|
136
138
|
end
|
137
139
|
frame_str += c_frame?(pos) ? ' ͱ-- ' : ''
|
138
140
|
|
139
|
-
frame_str +=
|
141
|
+
frame_str += format('#%-2d ', pos)
|
140
142
|
frame_str += get_frame_call frame_str, pos
|
141
143
|
file_line = "at #{CommandProcessor.canonic_file(file)}:#{line}"
|
142
144
|
if frame_str.size + file_line.size + 1 > Setting[:width]
|
143
|
-
frame_str += "\n #{file_line}
|
145
|
+
frame_str += "\n #{file_line}"
|
144
146
|
else
|
145
|
-
frame_str += " #{file_line}
|
147
|
+
frame_str += " #{file_line}"
|
146
148
|
end
|
147
149
|
|
148
|
-
|
150
|
+
puts frame_str
|
149
151
|
end
|
150
152
|
end
|
151
153
|
|
154
|
+
#
|
155
|
+
# Show current backtrace.
|
156
|
+
#
|
152
157
|
class WhereCommand < Command
|
153
158
|
def regexp
|
154
159
|
/^\s* (?:w(?:here)?|bt|backtrace) \s*$/x
|
@@ -164,26 +169,30 @@ module Byebug
|
|
164
169
|
end
|
165
170
|
|
166
171
|
def description
|
167
|
-
%
|
172
|
+
%(w[here]|bt|backtrace Display stack frames.
|
168
173
|
|
169
174
|
Print the entire stack frame. Each frame is numbered; the most recent
|
170
175
|
frame is 0. A frame number can be referred to in the "frame" command;
|
171
176
|
"up" and "down" add or subtract respectively to frame numbers shown.
|
172
177
|
The position of the current frame is marked with -->. C-frames hang
|
173
178
|
from their most immediate Ruby frame to indicate that they are not
|
174
|
-
navigable
|
179
|
+
navigable.)
|
175
180
|
end
|
176
181
|
end
|
177
182
|
end
|
178
183
|
|
184
|
+
#
|
185
|
+
# Move the current frame up in the backtrace.
|
186
|
+
#
|
179
187
|
class UpCommand < Command
|
180
188
|
def regexp
|
181
189
|
/^\s* u(?:p)? (?:\s+(\S+))? \s*$/x
|
182
190
|
end
|
183
191
|
|
184
192
|
def execute
|
185
|
-
pos =
|
186
|
-
return unless pos
|
193
|
+
pos, err = parse_steps(@match[1], 'Up')
|
194
|
+
return errmsg(err) unless pos
|
195
|
+
|
187
196
|
adjust_frame(pos, false)
|
188
197
|
end
|
189
198
|
|
@@ -193,19 +202,23 @@ module Byebug
|
|
193
202
|
end
|
194
203
|
|
195
204
|
def description
|
196
|
-
%
|
205
|
+
%(up[ count] Move to higher frame.)
|
197
206
|
end
|
198
207
|
end
|
199
208
|
end
|
200
209
|
|
210
|
+
#
|
211
|
+
# Move the current frame down in the backtrace.
|
212
|
+
#
|
201
213
|
class DownCommand < Command
|
202
214
|
def regexp
|
203
215
|
/^\s* down (?:\s+(\S+))? \s*$/x
|
204
216
|
end
|
205
217
|
|
206
218
|
def execute
|
207
|
-
pos =
|
208
|
-
return unless pos
|
219
|
+
pos, err = parse_steps(@match[1], 'Down')
|
220
|
+
return errmsg(err) unless pos
|
221
|
+
|
209
222
|
adjust_frame(-pos, false)
|
210
223
|
end
|
211
224
|
|
@@ -215,11 +228,14 @@ module Byebug
|
|
215
228
|
end
|
216
229
|
|
217
230
|
def description
|
218
|
-
%
|
231
|
+
%(down[ count] Move to lower frame.)
|
219
232
|
end
|
220
233
|
end
|
221
234
|
end
|
222
235
|
|
236
|
+
#
|
237
|
+
# Move to specific frames in the backtrace.
|
238
|
+
#
|
223
239
|
class FrameCommand < Command
|
224
240
|
def regexp
|
225
241
|
/^\s* f(?:rame)? (?:\s+(\S+))? \s*$/x
|
@@ -227,7 +243,10 @@ module Byebug
|
|
227
243
|
|
228
244
|
def execute
|
229
245
|
return print_frame @state.frame_pos unless @match[1]
|
230
|
-
|
246
|
+
|
247
|
+
pos, err = get_int(@match[1], 'Frame')
|
248
|
+
return errmsg(err) unless pos
|
249
|
+
|
231
250
|
adjust_frame(pos, true)
|
232
251
|
end
|
233
252
|
|
@@ -237,17 +256,18 @@ module Byebug
|
|
237
256
|
end
|
238
257
|
|
239
258
|
def description
|
240
|
-
%
|
259
|
+
%(f[rame][ frame-number]
|
241
260
|
|
242
261
|
Move the current frame to the specified frame number, or the 0 if no
|
243
262
|
frame-number has been given.
|
244
263
|
|
245
|
-
A negative number indicates position from the other end, so
|
246
|
-
moves to the oldest frame, and "frame 0" moves to the
|
264
|
+
A negative number indicates position from the other end, so
|
265
|
+
"frame -1" moves to the oldest frame, and "frame 0" moves to the
|
266
|
+
newest frame.
|
247
267
|
|
248
268
|
Without an argument, the command prints the current stack frame. Since
|
249
269
|
the current position is redisplayed, it may trigger a resyncronization
|
250
|
-
if there is a front end also watching over things.
|
270
|
+
if there is a front end also watching over things.)
|
251
271
|
end
|
252
272
|
end
|
253
273
|
end
|
data/lib/byebug/commands/help.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
module Byebug
|
2
|
+
#
|
3
|
+
# Ask for help from byebug's prompt.
|
4
|
+
#
|
2
5
|
class HelpCommand < Command
|
3
6
|
include Columnize
|
4
7
|
|
@@ -12,24 +15,18 @@ module Byebug
|
|
12
15
|
if @match[1]
|
13
16
|
args = @match[1].split
|
14
17
|
cmds = @state.commands.select { |cmd| cmd.names.include?(args[0]) }
|
15
|
-
|
16
|
-
|
17
|
-
help = help.split("\n").map{|l| l.gsub(/^ +/, '')}
|
18
|
-
help.shift if help.first && help.first.empty?
|
19
|
-
help.pop if help.last && help.last.empty?
|
20
|
-
return print help.join("\n") + "\n"
|
21
|
-
else
|
22
|
-
return errmsg "Undefined command: \"#{args[0]}\". Try \"help\".\n" if
|
23
|
-
args[0]
|
18
|
+
if cmds.empty?
|
19
|
+
return errmsg("Undefined command: \"#{args[0]}\". Try \"help\"")
|
24
20
|
end
|
25
|
-
end
|
26
21
|
|
27
|
-
|
22
|
+
return puts(cmds.map { |cmd| cmd.help(args[1..-1]) }.join("\n"))
|
23
|
+
end
|
28
24
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
25
|
+
puts "byebug help v#{VERSION}" unless Setting[:testing]
|
26
|
+
puts "Type \"help <command-name>\" for help on a specific command\n"
|
27
|
+
puts 'Available commands:'
|
28
|
+
cmds = @state.commands.map { |cmd| cmd.names }.flatten.uniq.sort
|
29
|
+
puts columnize(cmds, Setting[:width])
|
33
30
|
end
|
34
31
|
|
35
32
|
class << self
|
@@ -38,9 +35,11 @@ module Byebug
|
|
38
35
|
end
|
39
36
|
|
40
37
|
def description
|
41
|
-
%
|
42
|
-
|
43
|
-
|
38
|
+
%(h[elp][ <command>[ <subcommand>]]
|
39
|
+
|
40
|
+
"help" alone prints this help.
|
41
|
+
"help <command>" prints help on <command>.
|
42
|
+
"help <command> <subcommand> prints help on <subcommand>.)
|
44
43
|
end
|
45
44
|
end
|
46
45
|
end
|
@@ -1,18 +1,24 @@
|
|
1
1
|
module Byebug
|
2
|
+
#
|
3
|
+
# Show history of byebug commands.
|
4
|
+
#
|
2
5
|
class HistoryCommand < Command
|
3
6
|
def regexp
|
4
7
|
/^\s* hist(?:ory)? (?:\s+(?<num_cmds>.+))? \s*$/x
|
5
8
|
end
|
6
9
|
|
7
10
|
def execute
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
12
|
-
print History.to_s(size || Setting[:histsize])
|
13
|
-
else
|
14
|
-
errmsg "Not currently saving history. Enable it with \"set autosave\"\n"
|
11
|
+
unless Setting[:autosave]
|
12
|
+
return errmsg('Not currently saving history. ' \
|
13
|
+
"Enable it with \"set autosave\"")
|
15
14
|
end
|
15
|
+
|
16
|
+
if @match[:num_cmds]
|
17
|
+
size, err = get_int(@match[:num_cmds], 'history', 1, Setting[:histsize])
|
18
|
+
return errmsg(err) unless size
|
19
|
+
end
|
20
|
+
|
21
|
+
puts History.to_s(size || Setting[:histsize])
|
16
22
|
end
|
17
23
|
|
18
24
|
class << self
|
@@ -21,7 +27,7 @@ module Byebug
|
|
21
27
|
end
|
22
28
|
|
23
29
|
def description
|
24
|
-
%
|
30
|
+
%(hist[ory] [num_cmds] Show byebug's command history.)
|
25
31
|
end
|
26
32
|
end
|
27
33
|
end
|
data/lib/byebug/commands/info.rb
CHANGED
@@ -1,81 +1,17 @@
|
|
1
1
|
module Byebug
|
2
|
+
#
|
3
|
+
# Utility methods to assist the info command
|
4
|
+
#
|
2
5
|
module InfoFunctions
|
3
|
-
def info_catch(*
|
4
|
-
return
|
6
|
+
def info_catch(*_args)
|
7
|
+
return puts('No frame selected.') unless @state.context
|
5
8
|
|
6
|
-
if Byebug.catchpoints
|
7
|
-
Byebug.catchpoints.each do |exception,
|
8
|
-
|
9
|
+
if Byebug.catchpoints && !Byebug.catchpoints.empty?
|
10
|
+
Byebug.catchpoints.each do |exception, _hits|
|
11
|
+
puts("#{exception}: #{exception.is_a?(Class)}")
|
9
12
|
end
|
10
13
|
else
|
11
|
-
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
class InfoCommand < Command
|
17
|
-
include Columnize
|
18
|
-
self.allow_in_control = true
|
19
|
-
|
20
|
-
Subcommands = [
|
21
|
-
['args' , 1, 'Argument variables of current stack frame' ],
|
22
|
-
['breakpoints' , 1, 'Status of user-settable breakpoints',
|
23
|
-
'Without argument, list info about all ' \
|
24
|
-
'breakpoints. With an integer argument, ' \
|
25
|
-
'list info on that breakpoint.' ],
|
26
|
-
['catch' , 3, 'Exceptions that can be caught in the ' \
|
27
|
-
'current stack frame' ],
|
28
|
-
['display' , 2, 'Expressions to display when program stops' ],
|
29
|
-
['file' , 4, 'Info about a particular file read in',
|
30
|
-
'After the file name is supplied, you can' \
|
31
|
-
'list file attributes that you wish to ' \
|
32
|
-
'see. Attributes include: "all", "basic",' \
|
33
|
-
' "breakpoint", "lines", "mtime", "path" ' \
|
34
|
-
'and "sha1".' ],
|
35
|
-
['files' , 5, 'File names and timestamps of files read in' ],
|
36
|
-
['global_variables' , 2, 'Global variables' ],
|
37
|
-
['instance_variables', 2, 'Instance variables in current stack frame' ],
|
38
|
-
['line' , 2, 'Line number and file name of current ' \
|
39
|
-
'position in source file' ],
|
40
|
-
['locals' , 2, 'Local variables of the current stack frame' ],
|
41
|
-
['program' , 2, 'Execution status of the program' ],
|
42
|
-
['variables' , 1, 'Local and instance variables of the ' \
|
43
|
-
'current stack frame' ]
|
44
|
-
].map do |name, min, help|
|
45
|
-
Subcmd.new(name, min, help)
|
46
|
-
end unless defined?(Subcommands)
|
47
|
-
|
48
|
-
InfoFileSubcommands = [
|
49
|
-
['all' , 1, 'All file information available - breakpoints, ' \
|
50
|
-
'lines, mtime, path and sha1' ],
|
51
|
-
['basic' , 2, 'basic information - path, number of lines' ],
|
52
|
-
['breakpoints', 2, 'Show trace line numbers',
|
53
|
-
'These are the line number where a breakpoint ' \
|
54
|
-
'can be set.' ],
|
55
|
-
['lines' , 1, 'Show number of lines in the file' ],
|
56
|
-
['mtime' , 1, 'Show modification time of file' ],
|
57
|
-
['path' , 4, 'Show full file path name for file' ],
|
58
|
-
['sha1' , 1, 'Show SHA1 hash of contents of the file' ]
|
59
|
-
].map do |name, min, help|
|
60
|
-
Subcmd.new(name, min, help)
|
61
|
-
end unless defined?(InfoFileSubcommands)
|
62
|
-
|
63
|
-
def regexp
|
64
|
-
/^\s* i(?:nfo)? (?:\s+(.+))? \s*$/x
|
65
|
-
end
|
66
|
-
|
67
|
-
def execute
|
68
|
-
return print InfoCommand.help(nil) unless @match[1]
|
69
|
-
|
70
|
-
args = @match[1].split(/[ \t]+/)
|
71
|
-
param = args.shift
|
72
|
-
subcmd = Command.find(Subcommands, param)
|
73
|
-
return errmsg "Unknown info command #{param}\n" unless subcmd
|
74
|
-
|
75
|
-
if @state.context
|
76
|
-
send("info_#{subcmd.name}", *args)
|
77
|
-
else
|
78
|
-
errmsg "info_#{subcmd.name} not available without a context.\n"
|
14
|
+
puts 'No exceptions set to be caught.'
|
79
15
|
end
|
80
16
|
end
|
81
17
|
|
@@ -86,104 +22,81 @@ module Byebug
|
|
86
22
|
|
87
23
|
args.map do |_, name|
|
88
24
|
s = "#{name} = #{locals[name].inspect}"
|
89
|
-
s[Setting[:width]-3..-1] =
|
90
|
-
|
25
|
+
s[Setting[:width] - 3..-1] = '...' if s.size > Setting[:width]
|
26
|
+
puts s
|
91
27
|
end
|
92
28
|
end
|
93
29
|
|
94
30
|
def info_breakpoint(brkpt)
|
95
31
|
expr = brkpt.expr.nil? ? '' : " if #{brkpt.expr}"
|
96
|
-
|
97
|
-
|
32
|
+
y_n = brkpt.enabled? ? 'y' : 'n'
|
33
|
+
interp = format('%-3d %-3s at %s:%s%s',
|
34
|
+
brkpt.id, y_n, brkpt.source, brkpt.pos, expr)
|
35
|
+
puts interp
|
98
36
|
hits = brkpt.hit_count
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
37
|
+
return unless hits > 0
|
38
|
+
|
39
|
+
s = (hits > 1) ? 's' : ''
|
40
|
+
puts "\tbreakpoint already hit #{hits} time#{s}"
|
103
41
|
end
|
104
|
-
private :info_breakpoint
|
105
42
|
|
106
43
|
def info_breakpoints(*args)
|
107
|
-
return
|
44
|
+
return puts('No breakpoints.') if Byebug.breakpoints.empty?
|
108
45
|
|
109
|
-
brkpts = Byebug.breakpoints.sort_by{|b| b.id}
|
46
|
+
brkpts = Byebug.breakpoints.sort_by { |b| b.id }
|
110
47
|
unless args.empty?
|
111
|
-
indices = args.map{|a| a.to_i}
|
112
|
-
brkpts = brkpts.select{|b| indices.member?(b.id)}
|
113
|
-
return errmsg
|
114
|
-
brkpts.empty?
|
48
|
+
indices = args.map { |a| a.to_i }
|
49
|
+
brkpts = brkpts.select { |b| indices.member?(b.id) }
|
50
|
+
return errmsg('No breakpoints found among list given') if brkpts.empty?
|
115
51
|
end
|
116
|
-
|
52
|
+
|
53
|
+
puts 'Num Enb What'
|
117
54
|
brkpts.each { |b| info_breakpoint(b) }
|
118
55
|
end
|
119
56
|
|
120
|
-
def info_display(*
|
121
|
-
return
|
122
|
-
@state.display.find{|d| d[0]}
|
57
|
+
def info_display(*_args)
|
58
|
+
return puts('There are no auto-display expressions now.') unless
|
59
|
+
@state.display.find { |d| d[0] }
|
123
60
|
|
124
|
-
|
125
|
-
|
61
|
+
puts 'Auto-display expressions now in effect:'
|
62
|
+
puts 'Num Enb Expression'
|
126
63
|
n = 1
|
127
|
-
|
128
|
-
|
64
|
+
@state.display.each do |d|
|
65
|
+
puts(format('%3d: %s %s', n, d[0] ? 'y' : 'n', d[1]))
|
129
66
|
n += 1
|
130
67
|
end
|
131
68
|
end
|
132
69
|
|
133
70
|
def info_file_path(file)
|
134
|
-
|
71
|
+
s = "File #{file}"
|
135
72
|
path = File.expand_path(file)
|
136
|
-
|
73
|
+
s = "#{s} - #{path}" if path && path != file
|
74
|
+
puts s
|
137
75
|
end
|
138
|
-
private :info_file_path
|
139
76
|
|
140
77
|
def info_file_lines(file)
|
141
78
|
lines = File.foreach(file)
|
142
|
-
|
79
|
+
puts "\t#{lines.count} lines" if lines
|
143
80
|
end
|
144
|
-
private :info_file_lines
|
145
81
|
|
146
82
|
def info_file_breakpoints(file)
|
147
83
|
breakpoints = LineCache.trace_line_numbers(file)
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
84
|
+
return unless breakpoints
|
85
|
+
|
86
|
+
puts "\tbreakpoint line numbers:"
|
87
|
+
puts columnize(breakpoints.to_a.sort, Setting[:width])
|
152
88
|
end
|
153
|
-
private :info_file_breakpoints
|
154
89
|
|
155
90
|
def info_file_mtime(file)
|
156
91
|
stat = File.stat(file)
|
157
|
-
|
92
|
+
puts "\t#{stat.mtime}" if stat
|
158
93
|
end
|
159
|
-
private :info_file_mtime
|
160
94
|
|
161
95
|
def info_file_sha1(file)
|
162
|
-
|
163
|
-
end
|
164
|
-
private :info_file_sha1
|
165
|
-
|
166
|
-
def info_file(*args)
|
167
|
-
return info_files unless args[0]
|
168
|
-
|
169
|
-
subcmd = Command.find(InfoFileSubcommands, args[1] || 'basic')
|
170
|
-
return errmsg "Invalid parameter #{args[1]}\n" unless subcmd
|
171
|
-
|
172
|
-
if %w(all basic).member?(subcmd.name)
|
173
|
-
info_file_path(args[0])
|
174
|
-
info_file_lines(args[0])
|
175
|
-
if subcmd.name == 'all'
|
176
|
-
info_file_breakpoints(args[0])
|
177
|
-
info_file_mtime(args[0])
|
178
|
-
info_file_sha1(args[0])
|
179
|
-
end
|
180
|
-
else
|
181
|
-
print "File #{args[0]}\n" if subcmd.name != 'path'
|
182
|
-
send("info_file_#{subcmd.name}", args[0])
|
183
|
-
end
|
96
|
+
puts "\t#{Digest::SHA1.hexdigest(file)}"
|
184
97
|
end
|
185
98
|
|
186
|
-
def info_files(*
|
99
|
+
def info_files(*_args)
|
187
100
|
files = SCRIPT_LINES__.keys
|
188
101
|
files.uniq.sort.each do |file|
|
189
102
|
info_file_path(file)
|
@@ -191,18 +104,8 @@ module Byebug
|
|
191
104
|
end
|
192
105
|
end
|
193
106
|
|
194
|
-
def
|
195
|
-
|
196
|
-
var_list(obj.instance_variables)
|
197
|
-
end
|
198
|
-
|
199
|
-
def info_line(*args)
|
200
|
-
print "Line #{@state.line} of \"#{@state.file}\"\n"
|
201
|
-
end
|
202
|
-
|
203
|
-
def info_locals(*args)
|
204
|
-
locals = @state.context.frame_locals
|
205
|
-
print_hash(locals)
|
107
|
+
def info_line(*_args)
|
108
|
+
puts "Line #{@state.line} of \"#{@state.file}\""
|
206
109
|
end
|
207
110
|
|
208
111
|
def print_hash(vars)
|
@@ -211,55 +114,130 @@ module Byebug
|
|
211
114
|
s = "#{name} = #{vars[name].inspect}"
|
212
115
|
rescue
|
213
116
|
begin
|
214
|
-
|
215
|
-
|
216
|
-
|
117
|
+
s = "#{name} = #{vars[name]}"
|
118
|
+
rescue
|
119
|
+
s = "#{name} = *Error in evaluation*"
|
217
120
|
end
|
218
121
|
end
|
219
|
-
s[Setting[:width]-3..-1] =
|
220
|
-
|
122
|
+
s[Setting[:width] - 3..-1] = '...' if s.size > Setting[:width]
|
123
|
+
puts s
|
221
124
|
end
|
222
125
|
end
|
223
|
-
private :print_hash
|
224
126
|
|
225
127
|
def info_stop_reason(stop_reason)
|
226
128
|
case stop_reason
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
129
|
+
when :step
|
130
|
+
puts "It stopped after stepping, next'ing or initial start."
|
131
|
+
when :breakpoint
|
132
|
+
puts 'It stopped at a breakpoint.'
|
133
|
+
when :catchpoint
|
134
|
+
puts 'It stopped at a catchpoint.'
|
135
|
+
else
|
136
|
+
puts "Unknown reason: #{@state.context.stop_reason}"
|
235
137
|
end
|
236
138
|
end
|
237
|
-
private :info_stop_reason
|
238
139
|
|
239
|
-
def info_program(*
|
140
|
+
def info_program(*_args)
|
240
141
|
if @state.context.dead?
|
241
|
-
|
242
|
-
|
243
|
-
return
|
142
|
+
puts 'The program crashed.'
|
143
|
+
excpt = Byebug.last_exception
|
144
|
+
return puts("Exception: #{excpt.inspect}") if excpt
|
244
145
|
end
|
245
146
|
|
246
|
-
|
147
|
+
puts 'Program stopped. '
|
247
148
|
info_stop_reason @state.context.stop_reason
|
248
149
|
end
|
249
150
|
|
250
|
-
def
|
251
|
-
var_global
|
252
|
-
end
|
253
|
-
|
254
|
-
def info_variables(*args)
|
151
|
+
def info_variables(*_args)
|
255
152
|
locals = @state.context.frame_locals
|
256
153
|
locals[:self] = @state.context.frame_self(@state.frame_pos)
|
257
154
|
print_hash(locals)
|
258
155
|
|
259
156
|
obj = bb_eval('self')
|
260
|
-
var_list(obj.instance_variables, obj.instance_eval{binding
|
157
|
+
var_list(obj.instance_variables, obj.instance_eval { binding })
|
261
158
|
var_class_self
|
262
159
|
end
|
160
|
+
end
|
161
|
+
|
162
|
+
#
|
163
|
+
# Show info about different aspects of the debugger.
|
164
|
+
#
|
165
|
+
class InfoCommand < Command
|
166
|
+
include Columnize
|
167
|
+
self.allow_in_control = true
|
168
|
+
|
169
|
+
Subcommands = [
|
170
|
+
['args', 1, 'Argument variables of current stack frame'],
|
171
|
+
['breakpoints', 1, 'Status of user-settable breakpoints',
|
172
|
+
'Without argument, list info about all breakpoints. With an integer ' \
|
173
|
+
'argument, list info on that breakpoint.'],
|
174
|
+
['catch', 3, 'Exceptions that can be caught in the current stack frame'],
|
175
|
+
['display', 2, 'Expressions to display when program stops'],
|
176
|
+
['file', 4, 'Info about a particular file read in',
|
177
|
+
'After the file name is supplied, you can list file attributes that ' \
|
178
|
+
'you wish to see. Attributes include: "all", "basic", "breakpoint", ' \
|
179
|
+
'"lines", "mtime", "path" and "sha1".'],
|
180
|
+
['files', 5, 'File names and timestamps of files read in'],
|
181
|
+
['line', 2, 'Line number and file name of current position in source ' \
|
182
|
+
'file.'],
|
183
|
+
['program', 2, 'Execution status of the program']
|
184
|
+
].map do |name, min, help|
|
185
|
+
Subcmd.new(name, min, help)
|
186
|
+
end unless defined?(Subcommands)
|
187
|
+
|
188
|
+
InfoFileSubcommands = [
|
189
|
+
['all', 1, 'All file information available - breakpoints, lines, ' \
|
190
|
+
'mtime, path and sha1'],
|
191
|
+
['basic', 2, 'basic information - path, number of lines'],
|
192
|
+
['breakpoints', 2, 'Show trace line numbers',
|
193
|
+
'These are the line number where a breakpoint can be set.'],
|
194
|
+
['lines', 1, 'Show number of lines in the file'],
|
195
|
+
['mtime', 1, 'Show modification time of file'],
|
196
|
+
['path', 4, 'Show full file path name for file'],
|
197
|
+
['sha1', 1, 'Show SHA1 hash of contents of the file']
|
198
|
+
].map do |name, min, help|
|
199
|
+
Subcmd.new(name, min, help)
|
200
|
+
end unless defined?(InfoFileSubcommands)
|
201
|
+
|
202
|
+
def info_file(*args)
|
203
|
+
return info_files unless args[0]
|
204
|
+
|
205
|
+
mode = args[1] || 'basic'
|
206
|
+
subcmd = Command.find(InfoFileSubcommands, mode)
|
207
|
+
return errmsg "Invalid parameter #{args[1]}\n" unless subcmd
|
208
|
+
|
209
|
+
if %w(all basic).member?(subcmd.name)
|
210
|
+
info_file_path(args[0])
|
211
|
+
info_file_lines(args[0])
|
212
|
+
if subcmd.name == 'all'
|
213
|
+
info_file_breakpoints(args[0])
|
214
|
+
info_file_mtime(args[0])
|
215
|
+
info_file_sha1(args[0])
|
216
|
+
end
|
217
|
+
else
|
218
|
+
puts("File #{args[0]}") if subcmd.name != 'path'
|
219
|
+
send("info_file_#{subcmd.name}", args[0])
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def regexp
|
224
|
+
/^\s* i(?:nfo)? (?:\s+(.+))? \s*$/x
|
225
|
+
end
|
226
|
+
|
227
|
+
def execute
|
228
|
+
return puts(InfoCommand.help) unless @match[1]
|
229
|
+
|
230
|
+
args = @match[1].split(/[ \t]+/)
|
231
|
+
param = args.shift
|
232
|
+
subcmd = Command.find(Subcommands, param)
|
233
|
+
return errmsg "Unknown info command #{param}\n" unless subcmd
|
234
|
+
|
235
|
+
if @state.context
|
236
|
+
send("info_#{subcmd.name}", *args)
|
237
|
+
else
|
238
|
+
errmsg "info_#{subcmd.name} not available without a context.\n"
|
239
|
+
end
|
240
|
+
end
|
263
241
|
|
264
242
|
class << self
|
265
243
|
def names
|
@@ -267,25 +245,25 @@ module Byebug
|
|
267
245
|
end
|
268
246
|
|
269
247
|
def description
|
270
|
-
|
248
|
+
<<-EOD.gsub(/^ {8}/, '')
|
271
249
|
|
272
|
-
|
250
|
+
info[ subcommand]
|
251
|
+
|
252
|
+
Generic command for showing things about the program being debugged.
|
253
|
+
|
254
|
+
EOD
|
273
255
|
end
|
274
256
|
|
275
|
-
def help(
|
276
|
-
return description + format_subcmds
|
257
|
+
def help(subcmds = [])
|
258
|
+
return description + format_subcmds if subcmds.empty?
|
277
259
|
|
278
|
-
|
260
|
+
subcmd = subcmds.first
|
261
|
+
return format_subcmd(subcmd) unless 'file' == subcmd && subcmds[2]
|
279
262
|
|
280
|
-
|
281
|
-
|
282
|
-
if subsubcmd
|
283
|
-
str += "\nInvalid \"file\" attribute \"#{args[2]}\"."
|
284
|
-
else
|
285
|
-
str += "\n" + subsubcmd.short_help + '.'
|
286
|
-
end
|
263
|
+
subsubcmd = Command.find(InfoFileSubcommands, subcmds[2])
|
264
|
+
return "\nInvalid \"file\" attribute \"#{args[2]}\"." unless subsubcmd
|
287
265
|
|
288
|
-
|
266
|
+
subsubcmd.short_help
|
289
267
|
end
|
290
268
|
end
|
291
269
|
end
|