byebug 3.4.2 → 3.5.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/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
|