byebug 3.5.1 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +4 -1
- data/.rubocop.yml +18 -1
- data/.travis.yml +21 -1
- data/CHANGELOG.md +356 -308
- data/CONTRIBUTING.md +31 -15
- data/GUIDE.md +859 -475
- data/Gemfile +8 -10
- data/LICENSE +1 -1
- data/README.md +41 -45
- data/Rakefile +30 -28
- data/byebug.gemspec +18 -18
- data/ext/byebug/breakpoint.c +88 -75
- data/ext/byebug/byebug.c +253 -252
- data/ext/byebug/byebug.h +53 -53
- data/ext/byebug/context.c +188 -159
- data/ext/byebug/extconf.rb +9 -6
- data/ext/byebug/locker.c +53 -11
- data/ext/byebug/threads.c +137 -39
- data/lib/byebug/attacher.rb +7 -2
- data/lib/byebug/breakpoint.rb +30 -0
- data/lib/byebug/command.rb +36 -32
- data/lib/byebug/commands/break.rb +49 -48
- data/lib/byebug/commands/catch.rb +64 -0
- data/lib/byebug/commands/condition.rb +13 -9
- data/lib/byebug/commands/continue.rb +8 -4
- data/lib/byebug/commands/delete.rb +10 -4
- data/lib/byebug/commands/display.rb +33 -25
- data/lib/byebug/commands/edit.rb +18 -13
- data/lib/byebug/commands/enable_disable.rb +26 -24
- data/lib/byebug/commands/eval.rb +77 -35
- data/lib/byebug/commands/finish.rb +9 -5
- data/lib/byebug/commands/frame.rb +66 -125
- data/lib/byebug/commands/help.rb +14 -21
- data/lib/byebug/commands/history.rb +5 -1
- data/lib/byebug/commands/info.rb +41 -106
- data/lib/byebug/commands/interrupt.rb +6 -2
- data/lib/byebug/commands/irb.rb +5 -2
- data/lib/byebug/commands/kill.rb +6 -2
- data/lib/byebug/commands/list.rb +21 -14
- data/lib/byebug/commands/method.rb +17 -9
- data/lib/byebug/commands/pry.rb +13 -3
- data/lib/byebug/commands/quit.rb +10 -5
- data/lib/byebug/commands/restart.rb +12 -19
- data/lib/byebug/commands/save.rb +10 -6
- data/lib/byebug/commands/set.rb +15 -14
- data/lib/byebug/commands/show.rb +8 -8
- data/lib/byebug/commands/source.rb +14 -8
- data/lib/byebug/commands/stepping.rb +15 -29
- data/lib/byebug/commands/threads.rb +73 -49
- data/lib/byebug/commands/tracevar.rb +56 -0
- data/lib/byebug/commands/undisplay.rb +8 -4
- data/lib/byebug/commands/untracevar.rb +38 -0
- data/lib/byebug/commands/var.rb +107 -0
- data/lib/byebug/context.rb +78 -42
- data/lib/byebug/core.rb +78 -40
- data/lib/byebug/helper.rb +58 -42
- data/lib/byebug/history.rb +12 -1
- data/lib/byebug/interface.rb +91 -11
- data/lib/byebug/interfaces/local_interface.rb +12 -19
- data/lib/byebug/interfaces/remote_interface.rb +12 -15
- data/lib/byebug/interfaces/script_interface.rb +14 -18
- data/lib/byebug/interfaces/test_interface.rb +54 -0
- data/lib/byebug/printers/base.rb +64 -0
- data/lib/byebug/printers/plain.rb +53 -0
- data/lib/byebug/processor.rb +20 -1
- data/lib/byebug/processors/command_processor.rb +57 -172
- data/lib/byebug/processors/control_command_processor.rb +16 -43
- data/lib/byebug/remote.rb +13 -7
- data/lib/byebug/runner.rb +102 -54
- data/lib/byebug/setting.rb +45 -68
- data/lib/byebug/settings/autoeval.rb +2 -0
- data/lib/byebug/settings/autoirb.rb +3 -0
- data/lib/byebug/settings/autolist.rb +3 -0
- data/lib/byebug/settings/autosave.rb +2 -0
- data/lib/byebug/settings/basename.rb +2 -0
- data/lib/byebug/settings/callstyle.rb +2 -0
- data/lib/byebug/settings/fullpath.rb +2 -0
- data/lib/byebug/settings/histfile.rb +2 -0
- data/lib/byebug/settings/histsize.rb +2 -0
- data/lib/byebug/settings/linetrace.rb +2 -0
- data/lib/byebug/settings/listsize.rb +2 -0
- data/lib/byebug/settings/post_mortem.rb +7 -2
- data/lib/byebug/settings/stack_on_error.rb +2 -0
- data/lib/byebug/settings/verbose.rb +2 -0
- data/lib/byebug/settings/width.rb +2 -0
- data/lib/byebug/state.rb +12 -0
- data/lib/byebug/states/control_state.rb +26 -0
- data/lib/byebug/states/regular_state.rb +178 -0
- data/lib/byebug/version.rb +1 -1
- metadata +24 -109
- data/lib/byebug/commands/catchpoint.rb +0 -53
- data/lib/byebug/commands/reload.rb +0 -29
- data/lib/byebug/commands/trace.rb +0 -50
- data/lib/byebug/commands/variables.rb +0 -206
- data/lib/byebug/options.rb +0 -46
- data/lib/byebug/settings/autoreload.rb +0 -12
- data/lib/byebug/settings/forcestep.rb +0 -14
- data/lib/byebug/settings/testing.rb +0 -12
- data/lib/byebug/settings/tracing_plus.rb +0 -11
- data/test/commands/break_test.rb +0 -364
- data/test/commands/condition_test.rb +0 -85
- data/test/commands/continue_test.rb +0 -47
- data/test/commands/delete_test.rb +0 -26
- data/test/commands/display_test.rb +0 -37
- data/test/commands/edit_test.rb +0 -52
- data/test/commands/eval_test.rb +0 -89
- data/test/commands/finish_test.rb +0 -74
- data/test/commands/frame_test.rb +0 -223
- data/test/commands/help_test.rb +0 -66
- data/test/commands/history_test.rb +0 -61
- data/test/commands/info_test.rb +0 -238
- data/test/commands/interrupt_test.rb +0 -45
- data/test/commands/irb_test.rb +0 -28
- data/test/commands/kill_test.rb +0 -50
- data/test/commands/list_test.rb +0 -174
- data/test/commands/method_test.rb +0 -52
- data/test/commands/post_mortem_test.rb +0 -71
- data/test/commands/pry_test.rb +0 -26
- data/test/commands/quit_test.rb +0 -53
- data/test/commands/reload_test.rb +0 -39
- data/test/commands/restart_test.rb +0 -46
- data/test/commands/save_test.rb +0 -67
- data/test/commands/set_test.rb +0 -140
- data/test/commands/show_test.rb +0 -76
- data/test/commands/source_test.rb +0 -46
- data/test/commands/stepping_test.rb +0 -192
- data/test/commands/thread_test.rb +0 -164
- data/test/commands/trace_test.rb +0 -71
- data/test/commands/undisplay_test.rb +0 -75
- data/test/commands/variables_test.rb +0 -105
- data/test/debugger_alias_test.rb +0 -7
- data/test/runner_test.rb +0 -150
- data/test/support/matchers.rb +0 -65
- data/test/support/test_interface.rb +0 -59
- data/test/support/utils.rb +0 -122
- data/test/test_helper.rb +0 -58
data/lib/byebug/interface.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'byebug/history'
|
2
|
+
require 'byebug/helper'
|
2
3
|
|
3
4
|
#
|
4
5
|
# Namespace for all of byebug's code
|
@@ -11,30 +12,109 @@ module Byebug
|
|
11
12
|
#
|
12
13
|
class Interface
|
13
14
|
attr_accessor :command_queue, :history
|
15
|
+
attr_reader :input, :output, :error
|
14
16
|
|
15
17
|
def initialize
|
16
18
|
@command_queue, @history = [], History.new
|
17
19
|
end
|
18
20
|
|
19
21
|
#
|
20
|
-
#
|
21
|
-
#
|
22
|
+
# Pops a command from the input stream.
|
23
|
+
#
|
24
|
+
def read_command(prompt)
|
25
|
+
return command_queue.shift unless command_queue.empty?
|
26
|
+
|
27
|
+
cmds = read_input(prompt)
|
28
|
+
return unless cmds
|
29
|
+
|
30
|
+
command_queue.concat(cmds)
|
31
|
+
command_queue.shift
|
32
|
+
end
|
33
|
+
|
34
|
+
include FileFunctions
|
35
|
+
#
|
36
|
+
# Pushes lines in +filename+ to the command queue.
|
37
|
+
#
|
38
|
+
def read_file(filename)
|
39
|
+
command_queue.concat(get_lines(filename))
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Reads a new line from the interface's input stream.
|
44
|
+
#
|
45
|
+
def read_input(prompt, save_hist = true)
|
46
|
+
line = readline(prompt)
|
47
|
+
return unless line
|
48
|
+
|
49
|
+
history.push(line) if save_hist
|
50
|
+
|
51
|
+
split_commands(line)
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Prints an error message to the error stream.
|
22
56
|
#
|
23
57
|
def errmsg(message)
|
24
|
-
print("*** #{message}\n")
|
58
|
+
error.print("*** #{message}\n")
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# Prints an output message to the output stream.
|
63
|
+
#
|
64
|
+
def puts(message)
|
65
|
+
output.puts(message)
|
25
66
|
end
|
26
67
|
|
27
|
-
|
68
|
+
def print(message)
|
69
|
+
output.print(message)
|
70
|
+
end
|
28
71
|
|
29
72
|
#
|
30
|
-
#
|
73
|
+
# Confirms user introduced an affirmative response to the input stream.
|
31
74
|
#
|
32
|
-
def
|
33
|
-
|
75
|
+
def confirm(prompt)
|
76
|
+
readline(prompt) == 'y'
|
34
77
|
end
|
35
|
-
end
|
36
78
|
|
37
|
-
|
38
|
-
|
39
|
-
|
79
|
+
def close
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# Saves or clears history according to +autosave+ setting.
|
84
|
+
#
|
85
|
+
def autosave
|
86
|
+
Setting[:autosave] ? history.save : history.clear
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# Restores history according to +autosave+ setting.
|
91
|
+
#
|
92
|
+
def autorestore
|
93
|
+
history.restore if Setting[:autosave]
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
#
|
99
|
+
# Splits a command line of the form "cmd1 ; cmd2 ; ... ; cmdN" into an
|
100
|
+
# array of commands: [cmd1, cmd2, ..., cmdN]
|
101
|
+
#
|
102
|
+
def split_commands(cmd_line)
|
103
|
+
return [''] if cmd_line.empty?
|
104
|
+
|
105
|
+
cmd_line.split(/;/).each_with_object([]) do |v, m|
|
106
|
+
if m.empty? || m.last[-1] != '\\'
|
107
|
+
m << v
|
108
|
+
next
|
109
|
+
end
|
110
|
+
|
111
|
+
m.last[-1, 1] = ''
|
112
|
+
m.last << ';' << v
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
40
116
|
end
|
117
|
+
|
118
|
+
require 'byebug/interfaces/local_interface'
|
119
|
+
require 'byebug/interfaces/script_interface'
|
120
|
+
require 'byebug/interfaces/remote_interface'
|
@@ -3,30 +3,23 @@ module Byebug
|
|
3
3
|
# Interface class for standard byebug use.
|
4
4
|
#
|
5
5
|
class LocalInterface < Interface
|
6
|
-
def
|
7
|
-
|
6
|
+
def initialize
|
7
|
+
super()
|
8
|
+
@input, @output, @error = STDIN, STDOUT, STDERR
|
8
9
|
end
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
def readline(prompt, hist)
|
24
|
-
line = Readline.readline(prompt, false)
|
11
|
+
#
|
12
|
+
# Reads a single line of input using Readline. If Ctrl-C is pressed in the
|
13
|
+
# middle of input, the line is reset to only the prompt and we ask for input
|
14
|
+
# again.
|
15
|
+
#
|
16
|
+
# @param prompt Prompt to be displayed.
|
17
|
+
#
|
18
|
+
def readline(prompt)
|
19
|
+
Readline.readline(prompt, false)
|
25
20
|
rescue Interrupt
|
26
21
|
puts('^C')
|
27
22
|
retry
|
28
|
-
ensure
|
29
|
-
save_history(line) if hist
|
30
23
|
end
|
31
24
|
end
|
32
25
|
end
|
@@ -7,32 +7,29 @@ module Byebug
|
|
7
7
|
class RemoteInterface < Interface
|
8
8
|
def initialize(socket)
|
9
9
|
super()
|
10
|
-
@
|
10
|
+
@input, @output, @error = socket, socket, socket
|
11
11
|
end
|
12
12
|
|
13
|
-
def
|
14
|
-
|
15
|
-
rescue IOError
|
13
|
+
def read_command(prompt)
|
14
|
+
super("PROMPT #{prompt}")
|
16
15
|
end
|
17
16
|
|
18
17
|
def confirm(prompt)
|
19
|
-
|
18
|
+
super("CONFIRM #{prompt}")
|
20
19
|
end
|
21
20
|
|
22
|
-
def
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
def puts(message)
|
27
|
-
@socket.puts(message)
|
21
|
+
def close
|
22
|
+
output.close
|
23
|
+
rescue IOError
|
24
|
+
errmsg('Error closing the interface...')
|
28
25
|
end
|
29
26
|
|
30
|
-
|
27
|
+
def readline(prompt)
|
28
|
+
output.puts(prompt)
|
31
29
|
|
32
|
-
|
33
|
-
@socket.puts msg
|
34
|
-
result = @socket.gets
|
30
|
+
result = input.gets
|
35
31
|
fail IOError unless result
|
32
|
+
|
36
33
|
result.chomp
|
37
34
|
end
|
38
35
|
end
|
@@ -3,31 +3,27 @@ module Byebug
|
|
3
3
|
# Interface class for command execution from script files.
|
4
4
|
#
|
5
5
|
class ScriptInterface < Interface
|
6
|
-
def initialize(file,
|
6
|
+
def initialize(file, verbose = false)
|
7
7
|
super()
|
8
|
-
@
|
9
|
-
@
|
8
|
+
@input = File.open(file)
|
9
|
+
@output = verbose ? STDOUT : StringIO.new
|
10
|
+
@error = verbose ? STDERR : StringIO.new
|
10
11
|
end
|
11
12
|
|
12
|
-
def read_command(
|
13
|
-
|
14
|
-
puts "# #{result}" if @verbose
|
15
|
-
next if result =~ /^\s*#/
|
16
|
-
next if result.strip.empty?
|
17
|
-
return result.chomp
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def confirm(_prompt)
|
22
|
-
'y'
|
13
|
+
def read_command(prompt)
|
14
|
+
readline(prompt, false)
|
23
15
|
end
|
24
16
|
|
25
|
-
def
|
26
|
-
|
17
|
+
def close
|
18
|
+
input.close
|
27
19
|
end
|
28
20
|
|
29
|
-
def
|
30
|
-
|
21
|
+
def readline(*)
|
22
|
+
while (result = input.gets)
|
23
|
+
output.puts "+ #{result}"
|
24
|
+
next if result =~ /^\s*#/
|
25
|
+
return result.chomp
|
26
|
+
end
|
31
27
|
end
|
32
28
|
end
|
33
29
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Byebug
|
2
|
+
#
|
3
|
+
# Custom interface for easier assertions
|
4
|
+
#
|
5
|
+
class TestInterface < Interface
|
6
|
+
attr_accessor :test_block
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
super()
|
10
|
+
@input, @output, @error = [], [], []
|
11
|
+
end
|
12
|
+
|
13
|
+
def errmsg(message)
|
14
|
+
error.concat(message.to_s.split("\n"))
|
15
|
+
end
|
16
|
+
|
17
|
+
def print(message)
|
18
|
+
output.concat(message.to_s.split("\n"))
|
19
|
+
end
|
20
|
+
|
21
|
+
def puts(message)
|
22
|
+
output.concat(message.to_s.split("\n"))
|
23
|
+
end
|
24
|
+
|
25
|
+
def read_command(prompt)
|
26
|
+
cmd = super(prompt)
|
27
|
+
|
28
|
+
return cmd unless cmd.nil? && test_block
|
29
|
+
|
30
|
+
test_block.call
|
31
|
+
self.test_block = nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def clear
|
35
|
+
@input, @output, @error = [], [], []
|
36
|
+
history.clear
|
37
|
+
end
|
38
|
+
|
39
|
+
def inspect
|
40
|
+
[
|
41
|
+
'Input:', input.join("\n"),
|
42
|
+
'Output:', output.join("\n"),
|
43
|
+
'Error:', error.join("\n")
|
44
|
+
].join("\n")
|
45
|
+
end
|
46
|
+
|
47
|
+
def readline(prompt)
|
48
|
+
puts(prompt)
|
49
|
+
|
50
|
+
cmd = input.shift
|
51
|
+
cmd.is_a?(Proc) ? cmd.call : cmd
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Byebug
|
4
|
+
module Printers
|
5
|
+
class Base
|
6
|
+
class MissedPath < StandardError; end
|
7
|
+
class MissedArgument < StandardError; end
|
8
|
+
|
9
|
+
SEPARATOR = '.'
|
10
|
+
|
11
|
+
def type
|
12
|
+
self.class.name.split('::').last.downcase
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def locate(path)
|
18
|
+
result = nil
|
19
|
+
contents.each do |_, contents|
|
20
|
+
result = parts(path).reduce(contents) do |r, part|
|
21
|
+
r && r.key?(part) ? r[part] : nil
|
22
|
+
end
|
23
|
+
break if result
|
24
|
+
end
|
25
|
+
fail MissedPath, "Can't find part path '#{path}'" unless result
|
26
|
+
result
|
27
|
+
end
|
28
|
+
|
29
|
+
def translate(string, args = {})
|
30
|
+
# they may contain #{} string interpolation
|
31
|
+
string.gsub(/\|\w+$/, '').gsub(/([^#]?){([^}]*)}/) do
|
32
|
+
key = Regexp.last_match[2].to_s
|
33
|
+
unless args.key?(key.to_sym)
|
34
|
+
fail MissedArgument, "Missed argument #{key} for '#{string}'"
|
35
|
+
end
|
36
|
+
|
37
|
+
"#{Regexp.last_match[1]}#{args[key.to_sym]}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def parts(path)
|
42
|
+
path.split(SEPARATOR)
|
43
|
+
end
|
44
|
+
|
45
|
+
def contents
|
46
|
+
@contents ||= contents_files.each_with_object({}) do |filename, hash|
|
47
|
+
hash[filename] = YAML.load_file(filename) || {}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def array_of_args(collection, &block)
|
52
|
+
collection_with_index = collection.each.with_index
|
53
|
+
collection_with_index.each_with_object([]) do |(item, index), array|
|
54
|
+
args = block.call(item, index)
|
55
|
+
array << args if args
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def contents_files
|
60
|
+
[File.expand_path(File.join('..', 'texts', 'base.yml'), __FILE__)]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'byebug/printers/base'
|
2
|
+
|
3
|
+
module Byebug
|
4
|
+
module Printers
|
5
|
+
class Plain < Base
|
6
|
+
include Columnize
|
7
|
+
|
8
|
+
def print(path, args = {})
|
9
|
+
message = translate(locate(path), args)
|
10
|
+
tail = parts(path).include?('confirmations') ? ' (y/n) ' : "\n"
|
11
|
+
message << tail
|
12
|
+
end
|
13
|
+
|
14
|
+
def print_collection(path, collection, &block)
|
15
|
+
modifier = get_modifier(path)
|
16
|
+
lines = array_of_args(collection, &block).map do |args|
|
17
|
+
print(path, args)
|
18
|
+
end
|
19
|
+
|
20
|
+
if modifier == 'c'
|
21
|
+
columnize(lines.map { |l| l.gsub(/\n$/, '') }, Setting[:width])
|
22
|
+
else
|
23
|
+
lines.join('')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def print_variables(variables)
|
28
|
+
print_collection('variable.variable', variables) do |(key, value), _|
|
29
|
+
value = value.nil? ? 'nil' : value.to_s
|
30
|
+
if "#{key} = #{value}".size > Setting[:width]
|
31
|
+
key_size = "#{key} = ".size
|
32
|
+
value = value[0..Setting[:width] - key_size - 4] + '...'
|
33
|
+
end
|
34
|
+
|
35
|
+
{ key: key, value: value }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def get_modifier(path)
|
42
|
+
modifier_regexp = /\|(\w+)$/
|
43
|
+
modifier_match = locate(path).match(modifier_regexp)
|
44
|
+
modifier_match && modifier_match[1]
|
45
|
+
end
|
46
|
+
|
47
|
+
def contents_files
|
48
|
+
[File.expand_path(File.join('..', 'texts', 'plain.yml'), __FILE__)] +
|
49
|
+
super
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/byebug/processor.rb
CHANGED
@@ -16,9 +16,28 @@ module Byebug
|
|
16
16
|
rescue
|
17
17
|
nil
|
18
18
|
end
|
19
|
+
|
20
|
+
def self.load_commands
|
21
|
+
Dir.glob(File.expand_path('../commands/*.rb', __FILE__)).each do |file|
|
22
|
+
require file
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.load_settings
|
27
|
+
Dir.glob(File.expand_path('../settings/*.rb', __FILE__)).each do |file|
|
28
|
+
require file
|
29
|
+
end
|
30
|
+
|
31
|
+
Byebug.constants.grep(/[a-z]Setting/).map do |name|
|
32
|
+
setting = Byebug.const_get(name).new
|
33
|
+
Byebug::Setting.settings[setting.to_sym] = setting
|
34
|
+
end
|
35
|
+
end
|
19
36
|
end
|
37
|
+
|
38
|
+
Processor.load_commands
|
39
|
+
Processor.load_settings
|
20
40
|
end
|
21
41
|
|
22
|
-
require 'byebug/command'
|
23
42
|
require 'byebug/processors/command_processor'
|
24
43
|
require 'byebug/processors/control_command_processor'
|