byebug 3.4.2 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/GUIDE.md +88 -15
- data/lib/byebug/attacher.rb +1 -0
- data/lib/byebug/commands/enable_disable.rb +1 -1
- data/lib/byebug/commands/frame.rb +1 -1
- data/lib/byebug/commands/history.rb +3 -6
- data/lib/byebug/commands/list.rb +60 -50
- data/lib/byebug/commands/pry.rb +1 -8
- data/lib/byebug/commands/restart.rb +1 -6
- data/lib/byebug/commands/save.rb +5 -19
- data/lib/byebug/commands/undisplay.rb +2 -2
- data/lib/byebug/core.rb +11 -19
- data/lib/byebug/helper.rb +2 -2
- data/lib/byebug/history.rb +86 -26
- data/lib/byebug/interface.rb +13 -2
- data/lib/byebug/interfaces/local_interface.rb +4 -12
- data/lib/byebug/interfaces/remote_interface.rb +0 -3
- data/lib/byebug/processors/command_processor.rb +45 -22
- data/lib/byebug/runner.rb +7 -4
- data/lib/byebug/version.rb +1 -1
- data/test/commands/history_test.rb +35 -19
- data/test/commands/list_test.rb +8 -24
- data/test/commands/pry_test.rb +1 -8
- data/test/commands/restart_test.rb +4 -22
- data/test/commands/save_test.rb +4 -4
- data/test/commands/set_test.rb +1 -0
- data/test/runner_test.rb +26 -19
- data/test/support/test_interface.rb +19 -15
- data/test/test_helper.rb +2 -5
- metadata +2 -2
data/lib/byebug/helper.rb
CHANGED
@@ -34,9 +34,9 @@ module Byebug
|
|
34
34
|
|
35
35
|
int = str.to_i
|
36
36
|
if min && int < min
|
37
|
-
return
|
37
|
+
return min, "\"#{cmd}\" argument \"#{str}\" needs to be at least #{min}"
|
38
38
|
elsif max && int > max
|
39
|
-
return
|
39
|
+
return max, "\"#{cmd}\" argument \"#{str}\" needs to be at most #{max}"
|
40
40
|
end
|
41
41
|
|
42
42
|
int
|
data/lib/byebug/history.rb
CHANGED
@@ -5,38 +5,98 @@ module Byebug
|
|
5
5
|
# Handles byebug's history of commands.
|
6
6
|
#
|
7
7
|
class History
|
8
|
-
|
9
|
-
def load
|
10
|
-
open(Setting[:histfile], 'r') do |file|
|
11
|
-
file.each do |line|
|
12
|
-
line.chomp!
|
13
|
-
Readline::HISTORY << line
|
14
|
-
end
|
15
|
-
end if File.exist?(Setting[:histfile])
|
16
|
-
end
|
8
|
+
attr_accessor :size
|
17
9
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
file.puts line unless line.strip.empty?
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
10
|
+
def initialize
|
11
|
+
self.size = 0
|
12
|
+
end
|
25
13
|
|
26
|
-
|
27
|
-
|
28
|
-
|
14
|
+
#
|
15
|
+
# Restores history from disk.
|
16
|
+
#
|
17
|
+
def restore
|
18
|
+
return unless File.exist?(Setting[:histfile])
|
29
19
|
|
30
|
-
|
31
|
-
|
20
|
+
File.readlines(Setting[:histfile]).reverse.each { |l| push(l.chomp) }
|
21
|
+
end
|
32
22
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
23
|
+
#
|
24
|
+
# Saves history to disk.
|
25
|
+
#
|
26
|
+
def save
|
27
|
+
n_cmds = Setting[:histsize] > self.size ? self.size : Setting[:histsize]
|
37
28
|
|
38
|
-
|
29
|
+
open(Setting[:histfile], 'w') do |file|
|
30
|
+
n_cmds.times { file.puts(pop) }
|
39
31
|
end
|
32
|
+
|
33
|
+
clear
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Discards history.
|
38
|
+
#
|
39
|
+
def clear
|
40
|
+
self.size.times { pop }
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Adds a new command to Readline's history.
|
45
|
+
#
|
46
|
+
def push(cmd)
|
47
|
+
self.size += 1
|
48
|
+
Readline::HISTORY.push(cmd)
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
# Removes a command from Readline's history.
|
53
|
+
#
|
54
|
+
def pop
|
55
|
+
self.size -= 1
|
56
|
+
Readline::HISTORY.pop
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Prints the requested numbers of history entries.
|
61
|
+
#
|
62
|
+
def to_s(n_cmds)
|
63
|
+
show_size = n_cmds ? specific_max_size(n_cmds) : default_max_size
|
64
|
+
|
65
|
+
commands = Readline::HISTORY.to_a.last(show_size)
|
66
|
+
|
67
|
+
(self.size - show_size + 1..self.size).to_a.zip(commands).map do |l|
|
68
|
+
format("%5d %s", l[0], l[1])
|
69
|
+
end.join("\n") + "\n"
|
70
|
+
end
|
71
|
+
|
72
|
+
#
|
73
|
+
# Max number of commands to be displayed when no size has been specified.
|
74
|
+
#
|
75
|
+
# Never more than Setting[:histsize].
|
76
|
+
#
|
77
|
+
def default_max_size
|
78
|
+
[Setting[:histsize], self.size].min
|
79
|
+
end
|
80
|
+
|
81
|
+
#
|
82
|
+
# Max number of commands to be displayed when a size has been specified.
|
83
|
+
#
|
84
|
+
# The only bound here is not showing more items than available.
|
85
|
+
#
|
86
|
+
def specific_max_size(number)
|
87
|
+
[self.size, number].min
|
88
|
+
end
|
89
|
+
|
90
|
+
#
|
91
|
+
# Whether a specific command should not be stored in history.
|
92
|
+
#
|
93
|
+
# For now, empty lines and consecutive duplicates.
|
94
|
+
#
|
95
|
+
def ignore?(buf)
|
96
|
+
return true if /^\s*$/ =~ buf
|
97
|
+
return false if Readline::HISTORY.length == 0
|
98
|
+
|
99
|
+
Readline::HISTORY[Readline::HISTORY.length - 1] == buf
|
40
100
|
end
|
41
101
|
end
|
42
102
|
end
|
data/lib/byebug/interface.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'byebug/history'
|
2
|
+
|
1
3
|
#
|
2
4
|
# Namespace for all of byebug's code
|
3
5
|
#
|
@@ -8,10 +10,10 @@ module Byebug
|
|
8
10
|
# Contains common functionality to all implemented interfaces.
|
9
11
|
#
|
10
12
|
class Interface
|
11
|
-
attr_accessor :command_queue, :
|
13
|
+
attr_accessor :command_queue, :history
|
12
14
|
|
13
15
|
def initialize
|
14
|
-
@command_queue, @
|
16
|
+
@command_queue, @history = [], History.new
|
15
17
|
end
|
16
18
|
|
17
19
|
#
|
@@ -21,6 +23,15 @@ module Byebug
|
|
21
23
|
def errmsg(message)
|
22
24
|
print("*** #{message}\n")
|
23
25
|
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
#
|
30
|
+
# Stores <cmd> in commands history.
|
31
|
+
#
|
32
|
+
def save_history(cmd)
|
33
|
+
@history.push(cmd) unless @history.ignore?(cmd)
|
34
|
+
end
|
24
35
|
end
|
25
36
|
|
26
37
|
require 'byebug/interfaces/local_interface'
|
@@ -1,17 +1,8 @@
|
|
1
|
-
require 'byebug/history'
|
2
|
-
|
3
1
|
module Byebug
|
4
2
|
#
|
5
3
|
# Interface class for standard byebug use.
|
6
4
|
#
|
7
5
|
class LocalInterface < Interface
|
8
|
-
attr_reader :history
|
9
|
-
|
10
|
-
def initialize
|
11
|
-
super
|
12
|
-
History.load
|
13
|
-
end
|
14
|
-
|
15
6
|
def read_command(prompt)
|
16
7
|
readline(prompt, true)
|
17
8
|
end
|
@@ -25,16 +16,17 @@ module Byebug
|
|
25
16
|
end
|
26
17
|
|
27
18
|
def close
|
28
|
-
History.save
|
29
19
|
end
|
30
20
|
|
31
21
|
private
|
32
22
|
|
33
23
|
def readline(prompt, hist)
|
34
|
-
Readline.readline(prompt,
|
24
|
+
line = Readline.readline(prompt, false)
|
35
25
|
rescue Interrupt
|
36
|
-
puts
|
26
|
+
puts('^C')
|
37
27
|
retry
|
28
|
+
ensure
|
29
|
+
save_history(line) unless !hist
|
38
30
|
end
|
39
31
|
end
|
40
32
|
end
|
@@ -127,10 +127,11 @@ module Byebug
|
|
127
127
|
Setting[:autolist] = false if ['(irb)', '-e'].include?(file)
|
128
128
|
|
129
129
|
# Bind commands to the current state.
|
130
|
-
commands = cmds.map
|
131
|
-
|
132
|
-
|
133
|
-
|
130
|
+
commands = cmds.map do |cmd_class|
|
131
|
+
cmd = cmd_class.new(state)
|
132
|
+
cmd.execute if cmd.class.always_run >= run_level
|
133
|
+
cmd
|
134
|
+
end
|
134
135
|
|
135
136
|
[state, commands]
|
136
137
|
end
|
@@ -158,24 +159,24 @@ module Byebug
|
|
158
159
|
# Handle byebug commands.
|
159
160
|
#
|
160
161
|
def process_commands(context, file, line)
|
161
|
-
state, commands =
|
162
|
+
state, commands = preloop(context, file, line)
|
162
163
|
|
163
|
-
|
164
|
-
Thread.current.thread_variable_set('state', state)
|
165
|
-
else
|
166
|
-
Thread.current.thread_variable_set('state', nil)
|
167
|
-
end
|
164
|
+
repl(state, commands, context)
|
168
165
|
|
169
|
-
|
170
|
-
|
166
|
+
postloop
|
167
|
+
end
|
171
168
|
|
169
|
+
#
|
170
|
+
# Main byebug's REPL
|
171
|
+
#
|
172
|
+
def repl(state, commands, context)
|
172
173
|
until state.proceed?
|
173
174
|
input = if @interface.command_queue.empty?
|
174
175
|
@interface.read_command(prompt(context))
|
175
176
|
else
|
176
177
|
@interface.command_queue.shift
|
177
178
|
end
|
178
|
-
|
179
|
+
return unless input
|
179
180
|
|
180
181
|
if input == ''
|
181
182
|
next unless @last_cmd
|
@@ -183,6 +184,7 @@ module Byebug
|
|
183
184
|
else
|
184
185
|
@last_cmd = input
|
185
186
|
end
|
187
|
+
|
186
188
|
split_commands(input).each do |cmd|
|
187
189
|
one_cmd(commands, context, cmd)
|
188
190
|
end
|
@@ -215,24 +217,45 @@ module Byebug
|
|
215
217
|
end
|
216
218
|
|
217
219
|
#
|
218
|
-
# Tasks to do before processor loop
|
220
|
+
# Tasks to do before processor loop.
|
219
221
|
#
|
220
|
-
def preloop(
|
222
|
+
def preloop(context, file, line)
|
223
|
+
state, commands = always_run(context, file, line, 1)
|
224
|
+
|
225
|
+
if Setting[:testing]
|
226
|
+
Thread.current.thread_variable_set('state', state)
|
227
|
+
else
|
228
|
+
Thread.current.thread_variable_set('state', nil)
|
229
|
+
end
|
230
|
+
|
221
231
|
@context_was_dead = true if context.dead? && !@context_was_dead
|
222
|
-
|
232
|
+
if @context_was_dead
|
233
|
+
puts 'The program finished.'
|
234
|
+
@context_was_dead = false
|
235
|
+
end
|
223
236
|
|
224
|
-
puts
|
225
|
-
|
237
|
+
puts(state.location) if Setting[:autolist] == 0
|
238
|
+
|
239
|
+
@interface.history.restore if Setting[:autosave]
|
240
|
+
|
241
|
+
[state, commands]
|
242
|
+
end
|
243
|
+
|
244
|
+
#
|
245
|
+
# Tasks to do after processor loop.
|
246
|
+
#
|
247
|
+
def postloop
|
248
|
+
Setting[:autosave] ? @interface.history.save : @interface.history.clear
|
226
249
|
end
|
227
250
|
|
228
251
|
class State
|
229
|
-
attr_accessor :commands, :context, :display, :file, :frame_pos
|
230
|
-
|
252
|
+
attr_accessor :commands, :context, :display, :file, :frame_pos,
|
253
|
+
:interface, :line, :prev_line
|
231
254
|
|
232
255
|
def initialize(commands, context, display, file, interface, line)
|
233
256
|
@commands, @context, @display = commands, context, display
|
234
|
-
@file, @
|
235
|
-
@
|
257
|
+
@file, @frame_pos, @interface = file, 0, interface
|
258
|
+
@line, @prev_line, @proceed = line, nil, false
|
236
259
|
end
|
237
260
|
|
238
261
|
extend Forwardable
|
data/lib/byebug/runner.rb
CHANGED
@@ -35,10 +35,7 @@ module Byebug
|
|
35
35
|
# Used for restarts.
|
36
36
|
#
|
37
37
|
def debugged_program_from_argv
|
38
|
-
if ARGV.empty?
|
39
|
-
Byebug.puts 'You must specify a program to debug...'
|
40
|
-
abort
|
41
|
-
end
|
38
|
+
abort_with_err('You must specify a program to debug...') if ARGV.empty?
|
42
39
|
|
43
40
|
prog_script_try = which(ARGV.first)
|
44
41
|
if prog_script_try == which('ruby')
|
@@ -49,6 +46,11 @@ module Byebug
|
|
49
46
|
prog_script_try
|
50
47
|
end
|
51
48
|
|
49
|
+
def abort_with_err(msg)
|
50
|
+
Byebug.errmsg(msg)
|
51
|
+
abort
|
52
|
+
end
|
53
|
+
|
52
54
|
#
|
53
55
|
# Starts byebug to debug a program
|
54
56
|
#
|
@@ -66,6 +68,7 @@ module Byebug
|
|
66
68
|
end
|
67
69
|
|
68
70
|
Byebug.debugged_program = debugged_program_from_argv
|
71
|
+
abort_with_err("The script doesn't exist") unless Byebug.debugged_program
|
69
72
|
|
70
73
|
# Set up trace hook for byebug
|
71
74
|
Byebug.start
|
data/lib/byebug/version.rb
CHANGED
@@ -3,43 +3,59 @@ module Byebug
|
|
3
3
|
def setup
|
4
4
|
@example = -> do
|
5
5
|
byebug
|
6
|
+
a = 2
|
7
|
+
a = 3
|
6
8
|
end
|
7
9
|
|
8
10
|
super
|
11
|
+
end
|
9
12
|
|
10
|
-
|
11
|
-
|
13
|
+
def test_history_displays_latest_records_from_readline_history
|
14
|
+
enter 'show', 'history'
|
15
|
+
debug_proc(@example)
|
16
|
+
check_output_includes("1 show\n 2 history")
|
12
17
|
end
|
13
18
|
|
14
|
-
def
|
15
|
-
|
19
|
+
def test_history_n_displays_whole_history_if_n_is_bigger_than_history_size
|
20
|
+
enter 'show', 'history 3'
|
21
|
+
debug_proc(@example)
|
22
|
+
|
23
|
+
check_output_includes("1 show\n 2 history 3")
|
16
24
|
end
|
17
25
|
|
18
|
-
def
|
19
|
-
enter '
|
26
|
+
def test_history_n_displays_lastest_n_records_from_readline_history
|
27
|
+
enter 'show width', 'show autolist', 'history 2'
|
28
|
+
debug_proc(@example)
|
29
|
+
|
30
|
+
check_output_includes("2 show autolist\n 3 history 2")
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_history_does_not_save_empty_commands
|
34
|
+
enter 'show', 'show width', '', 'history 3'
|
20
35
|
debug_proc(@example)
|
21
|
-
|
22
|
-
|
36
|
+
|
37
|
+
check_output_includes("1 show\n 2 show width\n 3 history 3")
|
23
38
|
end
|
24
39
|
|
25
|
-
def
|
26
|
-
enter '
|
40
|
+
def test_history_does_not_save_duplicated_consecutive_commands
|
41
|
+
enter 'show', 'show width', 'show width', 'history 3'
|
27
42
|
debug_proc(@example)
|
28
|
-
|
43
|
+
|
44
|
+
check_output_includes("1 show\n 2 show width\n 3 history 3")
|
29
45
|
end
|
30
46
|
|
31
|
-
def
|
32
|
-
enter 'history 2'
|
47
|
+
def test_cmds_from_previous_repls_are_remembered_if_autosave_enabled
|
48
|
+
enter 'set autosave', 'next', 'history 2'
|
33
49
|
debug_proc(@example)
|
34
|
-
|
35
|
-
|
50
|
+
|
51
|
+
check_output_includes("2 next\n 3 history 2")
|
36
52
|
end
|
37
53
|
|
38
|
-
def
|
39
|
-
enter 'set noautosave', 'history'
|
54
|
+
def test_cmds_from_previous_repls_are_not_remembered_if_autosave_disabled
|
55
|
+
enter 'set noautosave', 'next', 'history 2'
|
40
56
|
debug_proc(@example)
|
41
|
-
|
42
|
-
|
57
|
+
|
58
|
+
check_output_includes("1 history 2")
|
43
59
|
end
|
44
60
|
end
|
45
61
|
end
|