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