byebug 4.0.5 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +72 -34
  3. data/CONTRIBUTING.md +26 -31
  4. data/README.md +3 -3
  5. data/lib/byebug/breakpoint.rb +2 -1
  6. data/lib/byebug/command.rb +27 -49
  7. data/lib/byebug/commands/break.rb +21 -15
  8. data/lib/byebug/commands/catch.rb +9 -15
  9. data/lib/byebug/commands/condition.rb +12 -15
  10. data/lib/byebug/commands/continue.rb +8 -11
  11. data/lib/byebug/commands/delete.rb +9 -12
  12. data/lib/byebug/commands/disable.rb +32 -0
  13. data/lib/byebug/commands/disable/breakpoints.rb +38 -0
  14. data/lib/byebug/commands/disable/display.rb +39 -0
  15. data/lib/byebug/commands/display.rb +18 -51
  16. data/lib/byebug/commands/down.rb +39 -0
  17. data/lib/byebug/commands/edit.rb +8 -14
  18. data/lib/byebug/commands/enable.rb +25 -0
  19. data/lib/byebug/commands/enable/breakpoints.rb +38 -0
  20. data/lib/byebug/commands/enable/display.rb +39 -0
  21. data/lib/byebug/commands/eval.rb +10 -192
  22. data/lib/byebug/commands/finish.rb +11 -12
  23. data/lib/byebug/commands/frame.rb +17 -182
  24. data/lib/byebug/commands/help.rb +18 -18
  25. data/lib/byebug/commands/history.rb +9 -10
  26. data/lib/byebug/commands/info.rb +17 -190
  27. data/lib/byebug/commands/info/args.rb +39 -0
  28. data/lib/byebug/commands/info/breakpoints.rb +59 -0
  29. data/lib/byebug/commands/info/catch.rb +39 -0
  30. data/lib/byebug/commands/info/display.rb +42 -0
  31. data/lib/byebug/commands/info/file.rb +81 -0
  32. data/lib/byebug/commands/info/line.rb +31 -0
  33. data/lib/byebug/commands/info/program.rb +51 -0
  34. data/lib/byebug/commands/interrupt.rb +5 -9
  35. data/lib/byebug/commands/irb.rb +5 -9
  36. data/lib/byebug/commands/kill.rb +6 -12
  37. data/lib/byebug/commands/list.rb +47 -19
  38. data/lib/byebug/commands/method.rb +8 -14
  39. data/lib/byebug/commands/next.rb +36 -0
  40. data/lib/byebug/commands/pp.rb +41 -0
  41. data/lib/byebug/commands/pry.rb +5 -9
  42. data/lib/byebug/commands/ps.rb +44 -0
  43. data/lib/byebug/commands/putl.rb +43 -0
  44. data/lib/byebug/commands/quit.rb +8 -12
  45. data/lib/byebug/commands/restart.rb +6 -12
  46. data/lib/byebug/commands/save.rb +30 -39
  47. data/lib/byebug/commands/set.rb +19 -21
  48. data/lib/byebug/commands/show.rb +10 -16
  49. data/lib/byebug/commands/source.rb +6 -12
  50. data/lib/byebug/commands/step.rb +36 -0
  51. data/lib/byebug/commands/thread.rb +13 -130
  52. data/lib/byebug/commands/thread/current.rb +35 -0
  53. data/lib/byebug/commands/thread/list.rb +41 -0
  54. data/lib/byebug/commands/thread/resume.rb +45 -0
  55. data/lib/byebug/commands/thread/stop.rb +41 -0
  56. data/lib/byebug/commands/thread/switch.rb +43 -0
  57. data/lib/byebug/commands/tracevar.rb +8 -14
  58. data/lib/byebug/commands/undisplay.rb +12 -15
  59. data/lib/byebug/commands/untracevar.rb +5 -11
  60. data/lib/byebug/commands/up.rb +39 -0
  61. data/lib/byebug/commands/var.rb +15 -94
  62. data/lib/byebug/commands/var/all.rb +37 -0
  63. data/lib/byebug/commands/var/const.rb +38 -0
  64. data/lib/byebug/commands/var/global.rb +33 -0
  65. data/lib/byebug/commands/var/instance.rb +35 -0
  66. data/lib/byebug/commands/var/local.rb +35 -0
  67. data/lib/byebug/commands/where.rb +47 -0
  68. data/lib/byebug/core.rb +10 -0
  69. data/lib/byebug/helpers/eval.rb +47 -0
  70. data/lib/byebug/helpers/file.rb +46 -0
  71. data/lib/byebug/helpers/frame.rb +76 -0
  72. data/lib/byebug/helpers/parse.rb +74 -0
  73. data/lib/byebug/helpers/string.rb +24 -0
  74. data/lib/byebug/helpers/thread.rb +53 -0
  75. data/lib/byebug/helpers/toggle.rb +56 -0
  76. data/lib/byebug/helpers/var.rb +45 -0
  77. data/lib/byebug/history.rb +2 -4
  78. data/lib/byebug/interface.rb +5 -3
  79. data/lib/byebug/interfaces/local_interface.rb +3 -1
  80. data/lib/byebug/interfaces/remote_interface.rb +3 -1
  81. data/lib/byebug/interfaces/test_interface.rb +6 -2
  82. data/lib/byebug/printers/plain.rb +1 -1
  83. data/lib/byebug/processors/command_processor.rb +9 -11
  84. data/lib/byebug/processors/control_command_processor.rb +1 -1
  85. data/lib/byebug/remote.rb +3 -0
  86. data/lib/byebug/runner.rb +5 -3
  87. data/lib/byebug/setting.rb +2 -18
  88. data/lib/byebug/settings/savefile.rb +21 -0
  89. data/lib/byebug/states/regular_state.rb +15 -6
  90. data/lib/byebug/subcommand_list.rb +33 -0
  91. data/lib/byebug/subcommands.rb +53 -0
  92. data/lib/byebug/version.rb +1 -1
  93. metadata +45 -6
  94. data/lib/byebug/commands/enable_disable.rb +0 -132
  95. data/lib/byebug/commands/stepping.rb +0 -75
  96. data/lib/byebug/helper.rb +0 -131
@@ -0,0 +1,46 @@
1
+ module Byebug
2
+ module Helpers
3
+ #
4
+ # Utilities for interaction with files
5
+ #
6
+ module FileHelper
7
+ #
8
+ # Reads lines of source file +filename+ into an array
9
+ #
10
+ def get_lines(filename)
11
+ File.foreach(filename).reduce([]) { |a, e| a << e.chomp }
12
+ end
13
+
14
+ #
15
+ # Reads line number +lineno+ from file named +filename+
16
+ #
17
+ def get_line(filename, lineno)
18
+ File.open(filename) do |f|
19
+ f.gets until f.lineno == lineno - 1
20
+ f.gets
21
+ end
22
+ end
23
+
24
+ #
25
+ # Returns the number of lines in file +filename+ in a portable,
26
+ # one-line-at-a-time way.
27
+ #
28
+ def n_lines(filename)
29
+ File.foreach(filename).reduce(0) { |a, _e| a + 1 }
30
+ end
31
+
32
+ #
33
+ # Regularize file name.
34
+ #
35
+ def normalize(filename)
36
+ return filename if ['(irb)', '-e'].include?(filename)
37
+
38
+ return File.basename(filename) if Setting[:basename]
39
+
40
+ path = File.expand_path(filename)
41
+
42
+ File.exist?(path) ? File.realpath(path) : filename
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,76 @@
1
+ module Byebug
2
+ module Helpers
3
+ #
4
+ # Utilities to assist frame navigation
5
+ #
6
+ module FrameHelper
7
+ def switch_to_frame(frame_no)
8
+ frame_no >= 0 ? frame_no : @state.context.stack_size + frame_no
9
+ end
10
+
11
+ def navigate_to_frame(jump_no)
12
+ return if jump_no == 0
13
+
14
+ current_jumps = 0
15
+ current_pos = @state.frame
16
+
17
+ loop do
18
+ current_pos += direction(jump_no)
19
+ break if current_pos < 0 || current_pos >= @state.context.stack_size
20
+
21
+ next if @state.c_frame?(current_pos)
22
+
23
+ current_jumps += 1
24
+ break if current_jumps == jump_no.abs
25
+ end
26
+
27
+ current_pos
28
+ end
29
+
30
+ def adjust_frame(frame, absolute)
31
+ if absolute
32
+ abs_frame = switch_to_frame(frame)
33
+ if @state.c_frame?(abs_frame)
34
+ return errmsg(pr('frame.errors.c_frame'))
35
+ end
36
+ else
37
+ abs_frame = navigate_to_frame(frame)
38
+ end
39
+
40
+ if abs_frame >= @state.context.stack_size
41
+ return errmsg(pr('frame.errors.too_low'))
42
+ elsif abs_frame < 0
43
+ return errmsg(pr('frame.errors.too_high'))
44
+ end
45
+
46
+ @state.frame = abs_frame
47
+ @state.file = @state.context.frame_file(@state.frame)
48
+ @state.line = @state.context.frame_line(@state.frame)
49
+ @state.prev_line = nil
50
+ end
51
+
52
+ def get_pr_arguments(frame_no)
53
+ file = @state.frame_file(frame_no)
54
+ full_path = File.expand_path(file)
55
+ line = @state.frame_line(frame_no)
56
+ call = @state.frame_call(frame_no)
57
+ mark = @state.frame_mark(frame_no)
58
+ pos = @state.frame_pos(frame_no)
59
+
60
+ { mark: mark, pos: pos, call: call, file: file, line: line,
61
+ full_path: full_path }
62
+ end
63
+
64
+ private
65
+
66
+ #
67
+ # @param [Integer] A positive or negative integer
68
+ #
69
+ # @return [Integer] +1 if step is positive / -1 if negative
70
+ #
71
+ def direction(step)
72
+ step / step.abs
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,74 @@
1
+ module Byebug
2
+ module Helpers
3
+ #
4
+ # Utilities to assist command parsing
5
+ #
6
+ module ParseHelper
7
+ #
8
+ # Parses +str+ of command +cmd+ as an integer between +min+ and +max+.
9
+ #
10
+ # If either +min+ or +max+ is nil, that value has no bound.
11
+ #
12
+ # TODO: Remove the `cmd` parameter. It has nothing to do with the methods
13
+ # purpose.
14
+ #
15
+ def get_int(str, cmd, min = nil, max = nil)
16
+ if str !~ /\A-?[0-9]+\z/
17
+ err = pr('parse.errors.int.not_number', cmd: cmd, str: str)
18
+ return nil, errmsg(err)
19
+ end
20
+
21
+ int = str.to_i
22
+ if min && int < min
23
+ err = pr('parse.errors.int.too_low', cmd: cmd, str: str, min: min)
24
+ return min, errmsg(err)
25
+ elsif max && int > max
26
+ err = pr('parse.errors.int.too_high', cmd: cmd, str: str, max: max)
27
+ return max, errmsg(err)
28
+ end
29
+
30
+ int
31
+ end
32
+
33
+ #
34
+ # @return true if code is syntactically correct for Ruby, false otherwise
35
+ #
36
+ def syntax_valid?(code)
37
+ return true unless code
38
+
39
+ without_stderr do
40
+ begin
41
+ RubyVM::InstructionSequence.compile(code)
42
+ true
43
+ rescue SyntaxError
44
+ false
45
+ end
46
+ end
47
+ end
48
+
49
+ #
50
+ # Temporarily disable output to $stderr
51
+ #
52
+ def without_stderr
53
+ stderr = $stderr
54
+ $stderr.reopen(IO::NULL)
55
+
56
+ yield
57
+ ensure
58
+ $stderr.reopen(stderr)
59
+ end
60
+
61
+ #
62
+ # @return +str+ as an integer or 1 if +str+ is empty.
63
+ #
64
+ def parse_steps(str, cmd)
65
+ return 1 unless str
66
+
67
+ steps, err = get_int(str, cmd, 1)
68
+ return nil, err unless steps
69
+
70
+ steps
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,24 @@
1
+ module Byebug
2
+ module Helpers
3
+ #
4
+ # Utilities for interaction with strings
5
+ #
6
+ module StringHelper
7
+ #
8
+ # Converts +str+ from an_underscored-or-dasherized_string to
9
+ # ACamelizedString.
10
+ #
11
+ def camelize(str)
12
+ str.dup.split(/[_-]/).map(&:capitalize).join('')
13
+ end
14
+
15
+ #
16
+ # Improves indentation and spacing in +str+ for readability in Byebug's
17
+ # command prompt.
18
+ #
19
+ def prettify(str)
20
+ "\n" + str.gsub(/^ {6}/, '') + "\n"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,53 @@
1
+ module Byebug
2
+ module Helpers
3
+ #
4
+ # Utilities for thread subcommands
5
+ #
6
+ module ThreadHelper
7
+ def display_context(context)
8
+ puts pr('thread.context', thread_arguments(context))
9
+ end
10
+
11
+ def thread_arguments(context)
12
+ status_flag = if context.suspended?
13
+ '$'
14
+ else
15
+ context.thread == Thread.current ? '+' : ' '
16
+ end
17
+ debug_flag = context.ignored? ? '!' : ' '
18
+
19
+ if context == Byebug.current_context
20
+ file_line = "#{@state.file}:#{@state.line}"
21
+ else
22
+ backtrace = context.thread.backtrace_locations
23
+ if backtrace && backtrace[0]
24
+ file_line = "#{backtrace[0].path}:#{backtrace[0].lineno}"
25
+ end
26
+ end
27
+
28
+ {
29
+ status_flag: status_flag,
30
+ debug_flag: debug_flag,
31
+ id: context.thnum,
32
+ thread: context.thread.inspect,
33
+ file_line: file_line || '',
34
+ pid: Process.pid,
35
+ status: context.thread.status,
36
+ current: (context.thread == Thread.current)
37
+ }
38
+ end
39
+
40
+ def context_from_thread(thnum)
41
+ ctx = Byebug.contexts.find { |c| c.thnum.to_s == thnum }
42
+
43
+ err = case
44
+ when ctx.nil? then pr('thread.errors.no_thread')
45
+ when ctx == @state.context then pr('thread.errors.current_thread')
46
+ when ctx.ignored? then pr('thread.errors.ignored', arg: thnum)
47
+ end
48
+
49
+ [ctx, err]
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,56 @@
1
+ require 'byebug/helpers/parse'
2
+
3
+ module Byebug
4
+ module Helpers
5
+ #
6
+ # Utilities to assist breakpoint/display enabling/disabling.
7
+ #
8
+ module ToggleHelper
9
+ include ParseHelper
10
+
11
+ def enable_disable_breakpoints(is_enable, args)
12
+ return errmsg(pr('toggle.errors.no_breakpoints')) if Breakpoint.none?
13
+
14
+ all_breakpoints = Byebug.breakpoints.sort_by(&:id)
15
+ if args.nil?
16
+ selected_breakpoints = all_breakpoints
17
+ else
18
+ selected_ids = []
19
+ args.split(/ +/).each do |pos|
20
+ last_id = all_breakpoints.last.id
21
+ pos, err = get_int(pos, "#{is_enable} breakpoints", 1, last_id)
22
+ return errmsg(err) unless pos
23
+
24
+ selected_ids << pos
25
+ end
26
+ selected_breakpoints = all_breakpoints.select do |b|
27
+ selected_ids.include?(b.id)
28
+ end
29
+ end
30
+
31
+ selected_breakpoints.each do |b|
32
+ enabled = ('enable' == is_enable)
33
+ if enabled && !syntax_valid?(b.expr)
34
+ return errmsg(pr('toggle.errors.expression', expr: b.expr))
35
+ end
36
+
37
+ b.enabled = enabled
38
+ end
39
+ end
40
+
41
+ def enable_disable_display(is_enable, args)
42
+ display = @state.display
43
+ return errmsg(pr('toggle.errors.no_display')) if 0 == display.size
44
+
45
+ selected_displays = args.nil? ? [1..display.size + 1] : args.split(/ +/)
46
+
47
+ selected_displays.each do |pos|
48
+ pos, err = get_int(pos, "#{is_enable} display", 1, display.size)
49
+ return errmsg(err) unless err.nil?
50
+
51
+ display[pos - 1][0] = ('enable' == is_enable)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,45 @@
1
+ module Byebug
2
+ module Helpers
3
+ #
4
+ # Utilities for variable subcommands
5
+ #
6
+ module VarHelper
7
+ def var_list(ary, b = get_binding)
8
+ vars = ary.sort.map do |v|
9
+ s = begin
10
+ b.eval(v.to_s).inspect
11
+ rescue
12
+ begin
13
+ b.eval(v.to_s).to_s
14
+ rescue
15
+ '*Error in evaluation*'
16
+ end
17
+ end
18
+ [v, s]
19
+ end
20
+ puts prv(vars, 'instance')
21
+ end
22
+
23
+ def var_global
24
+ globals = global_variables.reject do |v|
25
+ [:$IGNORECASE, :$=, :$KCODE, :$-K, :$binding].include?(v)
26
+ end
27
+
28
+ var_list(globals)
29
+ end
30
+
31
+ def var_instance(str)
32
+ obj = bb_warning_eval(str || 'self')
33
+
34
+ var_list(obj.instance_variables, obj.instance_eval { binding })
35
+ end
36
+
37
+ def var_local
38
+ locals = @state.context.frame_locals
39
+ cur_self = @state.context.frame_self(@state.frame)
40
+ locals[:self] = cur_self unless cur_self.to_s == 'main'
41
+ puts prv(locals.keys.sort.map { |k| [k, locals[k]] }, 'instance')
42
+ end
43
+ end
44
+ end
45
+ end
@@ -27,7 +27,7 @@ module Byebug
27
27
  def restore
28
28
  return unless File.exist?(Setting[:histfile])
29
29
 
30
- File.readlines(Setting[:histfile]).reverse.each { |l| push(l.chomp) }
30
+ File.readlines(Setting[:histfile]).reverse_each { |l| push(l.chomp) }
31
31
  end
32
32
 
33
33
  #
@@ -85,9 +85,7 @@ module Byebug
85
85
  # Array of ids of the last n commands.
86
86
  #
87
87
  def last_ids(n)
88
- from, to = 1 + self.size - n, self.size
89
-
90
- (from..to).to_a
88
+ (1 + size - n..size).to_a
91
89
  end
92
90
 
93
91
  #
@@ -1,5 +1,5 @@
1
1
  require 'byebug/history'
2
- require 'byebug/helper'
2
+ require 'byebug/helpers/file'
3
3
 
4
4
  #
5
5
  # Namespace for all of byebug's code
@@ -11,11 +11,14 @@ module Byebug
11
11
  # Contains common functionality to all implemented interfaces.
12
12
  #
13
13
  class Interface
14
+ include Helpers::FileHelper
15
+
14
16
  attr_accessor :command_queue, :history
15
17
  attr_reader :input, :output, :error
16
18
 
17
19
  def initialize
18
- @command_queue, @history = [], History.new
20
+ @command_queue = []
21
+ @history = History.new
19
22
  end
20
23
 
21
24
  #
@@ -31,7 +34,6 @@ module Byebug
31
34
  command_queue.shift
32
35
  end
33
36
 
34
- include FileFunctions
35
37
  #
36
38
  # Pushes lines in +filename+ to the command queue.
37
39
  #
@@ -5,7 +5,9 @@ module Byebug
5
5
  class LocalInterface < Interface
6
6
  def initialize
7
7
  super()
8
- @input, @output, @error = STDIN, STDOUT, STDERR
8
+ @input = STDIN
9
+ @output = STDOUT
10
+ @error = STDERR
9
11
  end
10
12
 
11
13
  #
@@ -7,7 +7,9 @@ module Byebug
7
7
  class RemoteInterface < Interface
8
8
  def initialize(socket)
9
9
  super()
10
- @input, @output, @error = socket, socket, socket
10
+ @input = socket
11
+ @output = socket
12
+ @error = socket
11
13
  end
12
14
 
13
15
  def read_command(prompt)