byebug 11.0.1

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.
Files changed (132) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +897 -0
  3. data/CONTRIBUTING.md +58 -0
  4. data/GUIDE.md +1806 -0
  5. data/LICENSE +23 -0
  6. data/README.md +199 -0
  7. data/exe/byebug +6 -0
  8. data/ext/byebug/breakpoint.c +517 -0
  9. data/ext/byebug/byebug.c +905 -0
  10. data/ext/byebug/byebug.h +143 -0
  11. data/ext/byebug/context.c +673 -0
  12. data/ext/byebug/extconf.rb +12 -0
  13. data/ext/byebug/locker.c +96 -0
  14. data/ext/byebug/threads.c +230 -0
  15. data/lib/byebug.rb +3 -0
  16. data/lib/byebug/attacher.rb +48 -0
  17. data/lib/byebug/breakpoint.rb +111 -0
  18. data/lib/byebug/command.rb +111 -0
  19. data/lib/byebug/command_list.rb +34 -0
  20. data/lib/byebug/commands.rb +40 -0
  21. data/lib/byebug/commands/break.rb +112 -0
  22. data/lib/byebug/commands/catch.rb +78 -0
  23. data/lib/byebug/commands/condition.rb +55 -0
  24. data/lib/byebug/commands/continue.rb +68 -0
  25. data/lib/byebug/commands/debug.rb +38 -0
  26. data/lib/byebug/commands/delete.rb +55 -0
  27. data/lib/byebug/commands/disable.rb +33 -0
  28. data/lib/byebug/commands/disable/breakpoints.rb +42 -0
  29. data/lib/byebug/commands/disable/display.rb +43 -0
  30. data/lib/byebug/commands/display.rb +66 -0
  31. data/lib/byebug/commands/down.rb +45 -0
  32. data/lib/byebug/commands/edit.rb +69 -0
  33. data/lib/byebug/commands/enable.rb +33 -0
  34. data/lib/byebug/commands/enable/breakpoints.rb +42 -0
  35. data/lib/byebug/commands/enable/display.rb +43 -0
  36. data/lib/byebug/commands/finish.rb +57 -0
  37. data/lib/byebug/commands/frame.rb +57 -0
  38. data/lib/byebug/commands/help.rb +64 -0
  39. data/lib/byebug/commands/history.rb +39 -0
  40. data/lib/byebug/commands/info.rb +37 -0
  41. data/lib/byebug/commands/info/breakpoints.rb +65 -0
  42. data/lib/byebug/commands/info/display.rb +49 -0
  43. data/lib/byebug/commands/info/file.rb +80 -0
  44. data/lib/byebug/commands/info/line.rb +35 -0
  45. data/lib/byebug/commands/info/program.rb +49 -0
  46. data/lib/byebug/commands/interrupt.rb +34 -0
  47. data/lib/byebug/commands/irb.rb +50 -0
  48. data/lib/byebug/commands/kill.rb +45 -0
  49. data/lib/byebug/commands/list.rb +159 -0
  50. data/lib/byebug/commands/method.rb +53 -0
  51. data/lib/byebug/commands/next.rb +40 -0
  52. data/lib/byebug/commands/pry.rb +41 -0
  53. data/lib/byebug/commands/quit.rb +42 -0
  54. data/lib/byebug/commands/restart.rb +64 -0
  55. data/lib/byebug/commands/save.rb +72 -0
  56. data/lib/byebug/commands/set.rb +79 -0
  57. data/lib/byebug/commands/show.rb +45 -0
  58. data/lib/byebug/commands/skip.rb +85 -0
  59. data/lib/byebug/commands/source.rb +40 -0
  60. data/lib/byebug/commands/step.rb +40 -0
  61. data/lib/byebug/commands/thread.rb +34 -0
  62. data/lib/byebug/commands/thread/current.rb +37 -0
  63. data/lib/byebug/commands/thread/list.rb +43 -0
  64. data/lib/byebug/commands/thread/resume.rb +45 -0
  65. data/lib/byebug/commands/thread/stop.rb +43 -0
  66. data/lib/byebug/commands/thread/switch.rb +46 -0
  67. data/lib/byebug/commands/tracevar.rb +54 -0
  68. data/lib/byebug/commands/undisplay.rb +51 -0
  69. data/lib/byebug/commands/untracevar.rb +36 -0
  70. data/lib/byebug/commands/up.rb +45 -0
  71. data/lib/byebug/commands/var.rb +37 -0
  72. data/lib/byebug/commands/var/all.rb +41 -0
  73. data/lib/byebug/commands/var/args.rb +39 -0
  74. data/lib/byebug/commands/var/const.rb +49 -0
  75. data/lib/byebug/commands/var/global.rb +37 -0
  76. data/lib/byebug/commands/var/instance.rb +39 -0
  77. data/lib/byebug/commands/var/local.rb +39 -0
  78. data/lib/byebug/commands/where.rb +53 -0
  79. data/lib/byebug/context.rb +157 -0
  80. data/lib/byebug/core.rb +115 -0
  81. data/lib/byebug/errors.rb +29 -0
  82. data/lib/byebug/frame.rb +185 -0
  83. data/lib/byebug/helpers/bin.rb +47 -0
  84. data/lib/byebug/helpers/eval.rb +126 -0
  85. data/lib/byebug/helpers/file.rb +63 -0
  86. data/lib/byebug/helpers/frame.rb +75 -0
  87. data/lib/byebug/helpers/parse.rb +75 -0
  88. data/lib/byebug/helpers/path.rb +40 -0
  89. data/lib/byebug/helpers/reflection.rb +19 -0
  90. data/lib/byebug/helpers/string.rb +33 -0
  91. data/lib/byebug/helpers/thread.rb +67 -0
  92. data/lib/byebug/helpers/toggle.rb +62 -0
  93. data/lib/byebug/helpers/var.rb +54 -0
  94. data/lib/byebug/history.rb +130 -0
  95. data/lib/byebug/interface.rb +146 -0
  96. data/lib/byebug/interfaces/local_interface.rb +44 -0
  97. data/lib/byebug/interfaces/remote_interface.rb +50 -0
  98. data/lib/byebug/interfaces/script_interface.rb +33 -0
  99. data/lib/byebug/interfaces/test_interface.rb +67 -0
  100. data/lib/byebug/option_setter.rb +95 -0
  101. data/lib/byebug/printers/base.rb +68 -0
  102. data/lib/byebug/printers/plain.rb +44 -0
  103. data/lib/byebug/printers/texts/base.yml +115 -0
  104. data/lib/byebug/printers/texts/plain.yml +33 -0
  105. data/lib/byebug/processors/command_processor.rb +173 -0
  106. data/lib/byebug/processors/control_processor.rb +24 -0
  107. data/lib/byebug/processors/post_mortem_processor.rb +18 -0
  108. data/lib/byebug/processors/script_processor.rb +49 -0
  109. data/lib/byebug/remote.rb +85 -0
  110. data/lib/byebug/remote/client.rb +57 -0
  111. data/lib/byebug/remote/server.rb +47 -0
  112. data/lib/byebug/runner.rb +198 -0
  113. data/lib/byebug/setting.rb +79 -0
  114. data/lib/byebug/settings/autoirb.rb +29 -0
  115. data/lib/byebug/settings/autolist.rb +29 -0
  116. data/lib/byebug/settings/autopry.rb +29 -0
  117. data/lib/byebug/settings/autosave.rb +17 -0
  118. data/lib/byebug/settings/basename.rb +16 -0
  119. data/lib/byebug/settings/callstyle.rb +20 -0
  120. data/lib/byebug/settings/fullpath.rb +16 -0
  121. data/lib/byebug/settings/histfile.rb +20 -0
  122. data/lib/byebug/settings/histsize.rb +20 -0
  123. data/lib/byebug/settings/linetrace.rb +22 -0
  124. data/lib/byebug/settings/listsize.rb +21 -0
  125. data/lib/byebug/settings/post_mortem.rb +27 -0
  126. data/lib/byebug/settings/savefile.rb +20 -0
  127. data/lib/byebug/settings/stack_on_error.rb +15 -0
  128. data/lib/byebug/settings/width.rb +20 -0
  129. data/lib/byebug/source_file_formatter.rb +71 -0
  130. data/lib/byebug/subcommands.rb +54 -0
  131. data/lib/byebug/version.rb +8 -0
  132. metadata +199 -0
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Byebug
4
+ module Helpers
5
+ #
6
+ # Utilities for interaction with files
7
+ #
8
+ module FileHelper
9
+ #
10
+ # Reads lines of source file +filename+ into an array
11
+ #
12
+ def get_lines(filename)
13
+ File.foreach(filename).reduce([]) { |acc, elem| acc << elem.chomp }
14
+ end
15
+
16
+ #
17
+ # Reads line number +lineno+ from file named +filename+
18
+ #
19
+ def get_line(filename, lineno)
20
+ File.open(filename) do |f|
21
+ f.gets until f.lineno == lineno - 1
22
+ f.gets
23
+ end
24
+ end
25
+
26
+ #
27
+ # Returns the number of lines in file +filename+ in a portable,
28
+ # one-line-at-a-time way.
29
+ #
30
+ def n_lines(filename)
31
+ File.foreach(filename).reduce(0) { |acc, _elem| acc + 1 }
32
+ end
33
+
34
+ #
35
+ # Regularize file name.
36
+ #
37
+ def normalize(filename)
38
+ return filename if virtual_file?(filename)
39
+
40
+ return File.basename(filename) if Setting[:basename]
41
+
42
+ File.exist?(filename) ? File.realpath(filename) : filename
43
+ end
44
+
45
+ #
46
+ # A short version of a long path
47
+ #
48
+ def shortpath(fullpath)
49
+ components = Pathname(fullpath).each_filename.to_a
50
+ return fullpath if components.size <= 2
51
+
52
+ File.join("...", components[-3..-1])
53
+ end
54
+
55
+ #
56
+ # True for special files like -e, false otherwise
57
+ #
58
+ def virtual_file?(name)
59
+ ["(irb)", "-e", "(byebug)", "(eval)"].include?(name)
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Byebug
4
+ module Helpers
5
+ #
6
+ # Utilities to assist frame navigation
7
+ #
8
+ module FrameHelper
9
+ def switch_to_frame(frame)
10
+ new_frame = index_from_start(frame)
11
+ return frame_err("c_frame") if Frame.new(context, new_frame).c_frame?
12
+
13
+ adjust_frame(new_frame)
14
+ end
15
+
16
+ def jump_frames(steps)
17
+ adjust_frame(navigate_to_frame(steps))
18
+ end
19
+
20
+ private
21
+
22
+ def adjust_frame(new_frame)
23
+ return frame_err("too_low") if new_frame >= context.stack_size
24
+ return frame_err("too_high") if new_frame.negative?
25
+
26
+ context.frame = new_frame
27
+ processor.prev_line = nil
28
+ end
29
+
30
+ def navigate_to_frame(jump_no)
31
+ current_jumps = 0
32
+ current_pos = context.frame.pos
33
+
34
+ loop do
35
+ current_pos += direction(jump_no)
36
+ break if out_of_bounds?(current_pos)
37
+
38
+ next if Frame.new(context, current_pos).c_frame?
39
+
40
+ current_jumps += 1
41
+ break if current_jumps == jump_no.abs
42
+ end
43
+
44
+ current_pos
45
+ end
46
+
47
+ def out_of_bounds?(pos)
48
+ !(0...context.stack_size).cover?(pos)
49
+ end
50
+
51
+ def frame_err(msg)
52
+ errmsg(pr("frame.errors.#{msg}"))
53
+ end
54
+
55
+ #
56
+ # @param step [Integer] A positive or negative integer
57
+ #
58
+ # @return [Integer] +1 if step is positive / -1 if negative
59
+ #
60
+ def direction(step)
61
+ step / step.abs
62
+ end
63
+
64
+ #
65
+ # Convert a possibly negative index to a positive index from the start
66
+ # of the callstack. -1 is the last position in the stack and so on.
67
+ #
68
+ # @param i [Integer] Integer to be converted in a proper positive index.
69
+ #
70
+ def index_from_start(index)
71
+ index >= 0 ? index : context.stack_size + index
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Byebug
4
+ module Helpers
5
+ #
6
+ # Utilities to assist command parsing
7
+ #
8
+ module ParseHelper
9
+ #
10
+ # Parses +str+ of command +cmd+ as an integer between +min+ and +max+.
11
+ #
12
+ # If either +min+ or +max+ is nil, that value has no bound.
13
+ #
14
+ # @todo Remove the `cmd` parameter. It has nothing to do with the method's
15
+ # purpose.
16
+ #
17
+ def get_int(str, cmd, min = nil, max = nil)
18
+ return nil, pr("parse.errors.int.not_number", cmd: cmd, str: str) if str !~ /\A-?[0-9]+\z/
19
+
20
+ int = str.to_i
21
+ if min && int < min
22
+ err = pr("parse.errors.int.too_low", cmd: cmd, str: str, min: min)
23
+ return nil, err
24
+ elsif max && int > max
25
+ err = pr("parse.errors.int.too_high", cmd: cmd, str: str, max: max)
26
+ return nil, err
27
+ end
28
+
29
+ int
30
+ end
31
+
32
+ #
33
+ # @return true if code is syntactically correct for Ruby, false otherwise
34
+ #
35
+ def syntax_valid?(code)
36
+ return true unless code
37
+
38
+ without_stderr do
39
+ begin
40
+ RubyVM::InstructionSequence.compile(code)
41
+ true
42
+ rescue SyntaxError
43
+ false
44
+ end
45
+ end
46
+ end
47
+
48
+ #
49
+ # @return +str+ as an integer or 1 if +str+ is empty.
50
+ #
51
+ def parse_steps(str, cmd)
52
+ return 1 unless str
53
+
54
+ steps, err = get_int(str, cmd, 1)
55
+ return nil, err unless steps
56
+
57
+ steps
58
+ end
59
+
60
+ private
61
+
62
+ #
63
+ # Temporarily disable output to $stderr
64
+ #
65
+ def without_stderr
66
+ old_stderr = $stderr
67
+ $stderr = StringIO.new
68
+
69
+ yield
70
+ ensure
71
+ $stderr = old_stderr
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Byebug
4
+ module Helpers
5
+ #
6
+ # Utilities for managing gem paths
7
+ #
8
+ module PathHelper
9
+ def bin_file
10
+ @bin_file ||= File.join(root_path, "exe", "byebug")
11
+ end
12
+
13
+ def root_path
14
+ @root_path ||= File.expand_path(File.join("..", "..", ".."), __dir__)
15
+ end
16
+
17
+ def lib_files
18
+ @lib_files ||= glob_for("lib")
19
+ end
20
+
21
+ def test_files
22
+ @test_files ||= glob_for("test")
23
+ end
24
+
25
+ def gem_files
26
+ @gem_files ||= [bin_file] + lib_files
27
+ end
28
+
29
+ def all_files
30
+ @all_files ||= gem_files + test_files
31
+ end
32
+
33
+ private
34
+
35
+ def glob_for(dir)
36
+ Dir.glob(File.join(root_path, dir, "**", "*.rb"))
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Byebug
4
+ module Helpers
5
+ #
6
+ # Reflection utilitie
7
+ #
8
+ module ReflectionHelper
9
+ #
10
+ # List of "command" classes in the including module
11
+ #
12
+ def commands
13
+ constants(false)
14
+ .map { |const| const_get(const, false) }
15
+ .select { |c| c.is_a?(Class) && c.name =~ /[a-z]Command$/ }
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Byebug
4
+ module Helpers
5
+ #
6
+ # Utilities for interaction with strings
7
+ #
8
+ module StringHelper
9
+ #
10
+ # Converts +str+ from an_underscored-or-dasherized_string to
11
+ # ACamelizedString.
12
+ #
13
+ def camelize(str)
14
+ str.dup.split(/[_-]/).map(&:capitalize).join("")
15
+ end
16
+
17
+ #
18
+ # Improves indentation and spacing in +str+ for readability in Byebug's
19
+ # command prompt.
20
+ #
21
+ def prettify(str)
22
+ "\n" + deindent(str) + "\n"
23
+ end
24
+
25
+ #
26
+ # Removes a number of leading whitespace for each input line.
27
+ #
28
+ def deindent(str, leading_spaces: 6)
29
+ str.gsub(/^ {#{leading_spaces}}/, "")
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Byebug
4
+ module Helpers
5
+ #
6
+ # Utilities for thread subcommands
7
+ #
8
+ module ThreadHelper
9
+ def display_context(ctx)
10
+ puts pr("thread.context", thread_arguments(ctx))
11
+ end
12
+
13
+ def thread_arguments(ctx)
14
+ {
15
+ status_flag: status_flag(ctx),
16
+ debug_flag: debug_flag(ctx),
17
+ id: ctx.thnum,
18
+ thread: ctx.thread.inspect,
19
+ file_line: location(ctx),
20
+ pid: Process.pid,
21
+ status: ctx.thread.status,
22
+ current: current_thread?(ctx)
23
+ }
24
+ end
25
+
26
+ def current_thread?(ctx)
27
+ ctx.thread == Thread.current
28
+ end
29
+
30
+ def context_from_thread(thnum)
31
+ ctx = Byebug.contexts.find { |c| c.thnum.to_s == thnum }
32
+
33
+ err = if ctx.nil?
34
+ pr("thread.errors.no_thread")
35
+ elsif ctx == context
36
+ pr("thread.errors.current_thread")
37
+ elsif ctx.ignored?
38
+ pr("thread.errors.ignored", arg: thnum)
39
+ end
40
+
41
+ [ctx, err]
42
+ end
43
+
44
+ private
45
+
46
+ # @todo Check whether it is Byebug.current_context or context
47
+ def location(ctx)
48
+ return context.location if ctx == Byebug.current_context
49
+
50
+ backtrace = ctx.thread.backtrace_locations
51
+ return "" unless backtrace && backtrace[0]
52
+
53
+ "#{backtrace[0].path}:#{backtrace[0].lineno}"
54
+ end
55
+
56
+ def status_flag(ctx)
57
+ return "$" if ctx.suspended?
58
+
59
+ current_thread?(ctx) ? "+" : " "
60
+ end
61
+
62
+ def debug_flag(ctx)
63
+ ctx.ignored? ? "!" : " "
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "byebug/helpers/parse"
4
+
5
+ module Byebug
6
+ module Helpers
7
+ #
8
+ # Utilities to assist breakpoint/display enabling/disabling.
9
+ #
10
+ module ToggleHelper
11
+ include ParseHelper
12
+
13
+ def enable_disable_breakpoints(is_enable, args)
14
+ raise pr("toggle.errors.no_breakpoints") if Breakpoint.none?
15
+
16
+ select_breakpoints(is_enable, args).each do |b|
17
+ enabled = (is_enable == "enable")
18
+ raise pr("toggle.errors.expression", expr: b.expr) if enabled && !syntax_valid?(b.expr)
19
+
20
+ puts pr("toggle.messages.toggled", bpnum: b.id,
21
+ endis: enabled ? "en" : "dis")
22
+ b.enabled = enabled
23
+ end
24
+ end
25
+
26
+ def enable_disable_display(is_enable, args)
27
+ raise pr("toggle.errors.no_display") if n_displays.zero?
28
+
29
+ selected_displays = args ? args.split(/ +/) : [1..n_displays + 1]
30
+
31
+ selected_displays.each do |pos|
32
+ pos, err = get_int(pos, "#{is_enable} display", 1, n_displays)
33
+ raise err unless err.nil?
34
+
35
+ Byebug.displays[pos - 1][0] = (is_enable == "enable")
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def select_breakpoints(is_enable, args)
42
+ all_breakpoints = Byebug.breakpoints.sort_by(&:id)
43
+ return all_breakpoints if args.nil?
44
+
45
+ selected_ids = []
46
+ args.split(/ +/).each do |pos|
47
+ last_id = all_breakpoints.last.id
48
+ pos, err = get_int(pos, "#{is_enable} breakpoints", 1, last_id)
49
+ raise(ArgumentError, err) unless pos
50
+
51
+ selected_ids << pos
52
+ end
53
+
54
+ all_breakpoints.select { |b| selected_ids.include?(b.id) }
55
+ end
56
+
57
+ def n_displays
58
+ Byebug.displays.size
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "byebug/helpers/eval"
4
+
5
+ module Byebug
6
+ module Helpers
7
+ #
8
+ # Utilities for variable subcommands
9
+ #
10
+ module VarHelper
11
+ include EvalHelper
12
+
13
+ def var_list(ary, binding = context.frame._binding)
14
+ vars = ary.sort.map do |name|
15
+ [name, safe_inspect(silent_eval(name.to_s, binding))]
16
+ end
17
+
18
+ puts prv(vars, "instance")
19
+ end
20
+
21
+ def var_global
22
+ globals = global_variables.reject do |v|
23
+ %i[$IGNORECASE $= $KCODE $-K $binding].include?(v)
24
+ end
25
+
26
+ var_list(globals)
27
+ end
28
+
29
+ def var_instance(str)
30
+ obj = warning_eval(str || "self")
31
+
32
+ var_list(obj.instance_variables, obj.instance_eval { binding })
33
+ end
34
+
35
+ def var_local
36
+ locals = context.frame.locals
37
+ cur_self = context.frame._self
38
+ locals[:self] = cur_self unless cur_self.to_s == "main"
39
+ puts prv(locals.keys.sort.map { |k| [k, locals[k]] }, "instance")
40
+ end
41
+
42
+ def var_args
43
+ args = context.frame.args
44
+ return if args == [[:rest]]
45
+
46
+ all_locals = context.frame.locals
47
+ arg_values = args.map { |arg| arg[1] }
48
+
49
+ locals = all_locals.select { |k, _| arg_values.include?(k) }
50
+ puts prv(locals.keys.sort.map { |k| [k, locals[k]] }, "instance")
51
+ end
52
+ end
53
+ end
54
+ end