ruby-debug 0.9.3 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/AUTHORS +1 -0
  2. data/CHANGES +41 -0
  3. data/ChangeLog +0 -0
  4. data/README +27 -13
  5. data/Rakefile +220 -0
  6. data/bin/rdebug +116 -42
  7. data/cli/ruby-debug.rb +33 -3
  8. data/cli/ruby-debug/command.rb +49 -12
  9. data/cli/ruby-debug/commands/breakpoints.rb +47 -64
  10. data/cli/ruby-debug/commands/control.rb +41 -13
  11. data/cli/ruby-debug/commands/display.rb +35 -18
  12. data/cli/ruby-debug/commands/enable.rb +159 -0
  13. data/cli/ruby-debug/commands/eval.rb +78 -4
  14. data/cli/ruby-debug/commands/frame.rb +67 -42
  15. data/cli/ruby-debug/commands/help.rb +21 -17
  16. data/cli/ruby-debug/commands/info.rb +210 -0
  17. data/cli/ruby-debug/commands/irb.rb +9 -1
  18. data/cli/ruby-debug/commands/list.rb +11 -8
  19. data/cli/ruby-debug/commands/method.rb +12 -23
  20. data/cli/ruby-debug/commands/script.rb +14 -9
  21. data/cli/ruby-debug/commands/settings.rb +174 -39
  22. data/cli/ruby-debug/commands/show.rb +193 -0
  23. data/cli/ruby-debug/commands/stepping.rb +15 -10
  24. data/cli/ruby-debug/commands/threads.rb +55 -56
  25. data/cli/ruby-debug/commands/variables.rb +27 -27
  26. data/cli/ruby-debug/helper.rb +134 -0
  27. data/cli/ruby-debug/interface.rb +46 -15
  28. data/cli/ruby-debug/processor.rb +156 -25
  29. data/doc/rdebug.1 +236 -0
  30. data/runner.sh +7 -0
  31. data/test/breakpoints.cmd +43 -0
  32. data/test/breakpoints.right +94 -0
  33. data/test/display.cmd +18 -0
  34. data/test/display.right +37 -0
  35. data/test/frame.cmd +21 -0
  36. data/test/frame.right +45 -0
  37. data/test/gcd.rb +18 -0
  38. data/test/help.cmd +12 -0
  39. data/test/help.right +4 -0
  40. data/test/helper.rb +87 -0
  41. data/test/info-var-bug.rb +45 -0
  42. data/test/info-var.cmd +23 -0
  43. data/test/info-var.right +47 -0
  44. data/test/info.cmd +12 -0
  45. data/test/info.right +35 -0
  46. data/test/quit.cmd +9 -0
  47. data/test/quit.right +22 -0
  48. data/test/setshow.cmd +44 -0
  49. data/test/setshow.right +73 -0
  50. data/test/stepping.cmd +17 -0
  51. data/test/stepping.right +40 -0
  52. data/test/tdebug.rb +196 -0
  53. data/test/test-breakpoints.rb +28 -0
  54. data/test/test-columnize.rb +46 -0
  55. data/test/test-display.rb +26 -0
  56. data/test/test-frame.rb +27 -0
  57. data/test/test-help.rb +44 -0
  58. data/test/test-info-var.rb +33 -0
  59. data/test/test-info.rb +28 -0
  60. data/test/test-quit.rb +28 -0
  61. data/test/test-ruby-debug-base.rb +76 -0
  62. data/test/test-setshow.rb +24 -0
  63. data/test/test-stepping.rb +26 -0
  64. metadata +63 -22
@@ -3,28 +3,24 @@ module Debugger
3
3
  def var_list(ary, b = get_binding)
4
4
  ary.sort!
5
5
  for v in ary
6
- print " %s => %s\n", v, debug_eval(v, b).inspect
7
- end
8
- end
9
-
10
- def var_locals(locals)
11
- locals.keys.sort.each do |name|
12
- print " %s => %s\n", name, locals[name]
13
- end
14
- end
15
-
16
- def var_consts(mod)
17
- constants = mod.constants
18
- constants.sort!
19
- for c in constants
20
- print " %s => %s\n", c, mod.const_get(c)
6
+ begin
7
+ s = debug_eval(v, b).inspect
8
+ rescue
9
+ begin
10
+ s = debug_eval(v, b).to_s
11
+ rescue
12
+ s = "*Error in evaluation*"
13
+ end
14
+ end
15
+ if s.size > self.class.settings[:width]
16
+ s[self.class.settings[:width]-3 .. -1] = "..."
17
+ end
18
+ print "%s = %s\n", v, s
21
19
  end
22
20
  end
23
21
  end
24
22
 
25
23
  class VarConstantCommand < Command # :nodoc:
26
- include VarFunctions
27
-
28
24
  def regexp
29
25
  /^\s*v(?:ar)?\s+c(?:onst(?:ant)?)?\s+/
30
26
  end
@@ -34,7 +30,13 @@ module Debugger
34
30
  unless obj.kind_of? Module
35
31
  print "Should be Class/Module: %s\n", @match.post_match
36
32
  else
37
- var_consts(obj)
33
+ constants = debug_eval("#{@match.post_match}.constants")
34
+ constants.sort!
35
+ for c in constants
36
+ next if c =~ /SCRIPT/
37
+ value = obj.const_get(c) rescue "ERROR: #{$!}"
38
+ print " %s => %p\n", c, value
39
+ end
38
40
  end
39
41
  end
40
42
 
@@ -52,8 +54,6 @@ module Debugger
52
54
  end
53
55
 
54
56
  class VarGlobalCommand < Command # :nodoc:
55
- include VarFunctions
56
-
57
57
  def regexp
58
58
  /^\s*v(?:ar)?\s+g(?:lobal)?\s*$/
59
59
  end
@@ -76,14 +76,12 @@ module Debugger
76
76
  end
77
77
 
78
78
  class VarInstanceCommand < Command # :nodoc:
79
- include VarFunctions
80
-
81
79
  def regexp
82
- /^\s*v(?:ar)?\s+i(?:nstance)?\s+/
80
+ /^\s*v(?:ar)?\s+i(?:nstance)?\s*/
83
81
  end
84
82
 
85
83
  def execute
86
- obj = debug_eval(@match.post_match)
84
+ obj = debug_eval(@match.post_match.empty? ? 'self' : @match.post_match)
87
85
  var_list(obj.instance_variables, obj.instance_eval{binding()})
88
86
  end
89
87
 
@@ -101,14 +99,16 @@ module Debugger
101
99
  end
102
100
 
103
101
  class VarLocalCommand < Command # :nodoc:
104
- include VarFunctions
105
-
106
102
  def regexp
107
103
  /^\s*v(?:ar)?\s+l(?:ocal)?\s*$/
108
104
  end
109
105
 
110
106
  def execute
111
- var_locals(@state.context.frame_locals(@state.frame_pos))
107
+ locals = @state.context.frame_locals(@state.frame_pos)
108
+ _self = @state.context.frame_self(@state.frame_pos)
109
+ locals.keys.sort.each do |name|
110
+ print " %s => %p\n", name, locals[name]
111
+ end
112
112
  end
113
113
 
114
114
  class << self
@@ -0,0 +1,134 @@
1
+ module Debugger
2
+
3
+ module ColumnizeFunctions
4
+ # Display a list of strings as a compact set of columns.
5
+ #
6
+ # Each column is only as wide as necessary.
7
+ # Columns are separated by two spaces (one was not legible enough).
8
+ # Adapted from the routine of the same name in cmd.py
9
+ def columnize(list, displaywidth=80)
10
+ if not list.is_a?(Array)
11
+ return "Expecting an Array, got #{list.class}\n"
12
+ end
13
+ if list.size == 0
14
+ return "<empty>\n"
15
+ end
16
+ nonstrings = []
17
+ for str in list do
18
+ nonstrings << str unless str.is_a?(String)
19
+ end
20
+ if nonstrings.size > 0
21
+ return "Nonstrings: %s\n" % nonstrings.map {|non| non.to_s}.join(', ')
22
+ end
23
+ if 1 == list.size
24
+ return "#{list[0]}\n"
25
+ end
26
+ # Try every row count from 1 upwards
27
+ nrows = ncols = 0
28
+ colwidths = []
29
+ 1.upto(list.size) do
30
+ colwidths = []
31
+ nrows += 1
32
+ ncols = (list.size + nrows-1) / nrows
33
+ totwidth = -2
34
+ # Debugger.debugger if nrows > 1
35
+ 0.upto(ncols-1) do |col|
36
+ colwidth = 0
37
+ 0.upto(nrows-1) do |row|
38
+ i = row + nrows*col
39
+ if i >= list.size
40
+ break
41
+ end
42
+ colwidth = [colwidth, list[i].size].max
43
+ end
44
+ colwidths << colwidth
45
+ totwidth += colwidth + 2
46
+ if totwidth > displaywidth
47
+ break
48
+ end
49
+ end
50
+ if totwidth <= displaywidth
51
+ break
52
+ end
53
+ end
54
+ s = ''
55
+ 0.upto(nrows-1) do |row|
56
+ texts = []
57
+ 0.upto(ncols-1) do |col|
58
+ i = row + nrows*col
59
+ if i >= list.size
60
+ x = ""
61
+ else
62
+ x = list[i]
63
+ end
64
+ texts << x
65
+ end
66
+ while texts and texts[-1] == ''
67
+ texts = texts[0..-2]
68
+ end
69
+ 0.upto(texts.size-1) do |col|
70
+ texts[col] = texts[col].ljust(colwidths[col])
71
+ end
72
+ s += "%s\n" % texts.join(" ")
73
+ end
74
+ return s
75
+ end
76
+ end
77
+
78
+ module ParseFunctions
79
+ # Parse 'str' of command 'cmd' as an integer between
80
+ # min and max. If either min or max is nil, that
81
+ # value has no bound.
82
+ def get_int(str, cmd, min=nil, max=nil, default=1)
83
+ return default unless str
84
+ begin
85
+ int = Integer(str)
86
+ if min and int < min
87
+ print "%s argument '%s' needs to at least %s.\n" % [cmd, str, min]
88
+ return nil
89
+ elsif max and int > max
90
+ print "%s argument '%s' needs to at most %s.\n" % [cmd, str, max]
91
+ return nil
92
+ end
93
+ return int
94
+ rescue
95
+ print "%s argument '%s' needs to be a number.\n" % [cmd, str]
96
+ return nil
97
+ end
98
+ end
99
+
100
+ # Return true if arg is 'on' or 1 and false arg is 'off' or 0.
101
+ # Any other value raises RuntimeError.
102
+ def get_onoff(arg, default=nil, print_error=true)
103
+ if arg.nil? or arg == ''
104
+ if default.nil?
105
+ if print_error
106
+ print "Expecting 'on', 1, 'off', or 0. Got nothing.\n"
107
+ raise RuntimeError
108
+ end
109
+ return default
110
+ end
111
+ end
112
+ case arg.downcase
113
+ when '1', 'on'
114
+ return true
115
+ when '0', 'off'
116
+ return false
117
+ else
118
+ if print_error
119
+ print "Expecting 'on', 1, 'off', or 0. Got: %s.\n" % arg.to_s
120
+ raise RuntimeError
121
+ end
122
+ end
123
+ end
124
+
125
+ # Return 'on' or 'off' for supplied parameter. The parmeter should
126
+ # be true, false or nil.
127
+ def show_onoff(bool)
128
+ if not [TrueClass, FalseClass, NilClass].member?(bool.class)
129
+ return "??"
130
+ end
131
+ return bool ? 'on' : 'off'
132
+ end
133
+ end
134
+ end
@@ -1,5 +1,26 @@
1
1
  module Debugger
2
2
  class LocalInterface # :nodoc:
3
+ attr_accessor :histfile
4
+ attr_accessor :history_save
5
+ attr_accessor :history_length
6
+
7
+ unless defined?(FILE_HISTORY)
8
+ FILE_HISTORY = ".rdebug_hist"
9
+ end
10
+ def initialize()
11
+ @history_save = true
12
+ # take gdb's default
13
+ @history_length = ENV["HISTSIZE"] ? ENV["HISTSIZE"].to_i : 256
14
+ @histfile = File.join(ENV["HOME"]||ENV["HOMEPATH"]||".",
15
+ FILE_HISTORY)
16
+ open(@histfile, 'r') do |file|
17
+ file.each do |line|
18
+ line.chomp!
19
+ Readline::HISTORY << line
20
+ end
21
+ end if File.exists?(@histfile)
22
+ end
23
+
3
24
  def read_command(prompt)
4
25
  readline(prompt, true)
5
26
  end
@@ -20,20 +41,13 @@ module Debugger
20
41
  begin
21
42
  require 'readline'
22
43
  class << Debugger
23
- FILE_HISTORY = ".rdebug_hist"
24
- save_file = File.join(ENV["HOME"]||ENV["HOMEPATH"], FILE_HISTORY)
25
- open(save_file, 'r') do |file|
26
- file.each do |line|
27
- line.chomp!
28
- Readline::HISTORY << line
29
- end
30
- end if File.exists?(save_file)
31
-
32
44
  define_method(:save_history) do
33
- open(save_file, 'w') do |file|
34
- Readline::HISTORY.to_a.last(500).each do |line|
45
+ @histfile ||= File.join(ENV["HOME"]||ENV["HOMEPATH"]||".",
46
+ FILE_HISTORY)
47
+ open(@histfile, 'w') do |file|
48
+ Readline::HISTORY.to_a.last(@history_length).each do |line|
35
49
  file.puts line unless line.strip.empty?
36
- end
50
+ end if @history_save
37
51
  end rescue nil
38
52
  end
39
53
  public :save_history
@@ -45,6 +59,8 @@ module Debugger
45
59
  end
46
60
  rescue LoadError
47
61
  def readline(prompt, hist)
62
+ @histfile = ''
63
+ @hist_save = false
48
64
  STDOUT.print prompt
49
65
  STDOUT.flush
50
66
  line = STDIN.gets
@@ -56,8 +72,15 @@ module Debugger
56
72
  end
57
73
 
58
74
  class RemoteInterface # :nodoc:
75
+ attr_accessor :histfile
76
+ attr_accessor :history_save
77
+ attr_accessor :history_length
78
+
59
79
  def initialize(socket)
60
80
  @socket = socket
81
+ @history_save = false
82
+ @history_length = 256
83
+ @histfile = ''
61
84
  end
62
85
 
63
86
  def read_command(prompt)
@@ -88,19 +111,27 @@ module Debugger
88
111
  end
89
112
 
90
113
  class ScriptInterface # :nodoc:
91
- def initialize(file, out)
114
+ attr_accessor :histfile
115
+ attr_accessor :history_save
116
+ attr_accessor :history_length
117
+ def initialize(file, out, verbose=false)
92
118
  @file = file.respond_to?(:gets) ? file : open(file)
93
119
  @out = out
120
+ @verbose = verbose
121
+ @history_save = false
122
+ @history_length = 256 # take gdb default
123
+ @histfile = ''
94
124
  end
95
125
 
96
126
  def read_command(prompt)
97
127
  while result = @file.gets
128
+ puts "# #{result}" if @verbose
98
129
  next if result =~ /^\s*#/
99
130
  next if result.strip.empty?
100
131
  break
101
132
  end
102
133
  raise IOError unless result
103
- result
134
+ result.chomp!
104
135
  end
105
136
 
106
137
  def confirm(prompt)
@@ -108,7 +139,7 @@ module Debugger
108
139
  end
109
140
 
110
141
  def print(*args)
111
- @out.print(*args)
142
+ @out.printf(*args)
112
143
  end
113
144
 
114
145
  def close
@@ -2,16 +2,28 @@ require 'ruby-debug/interface'
2
2
  require 'ruby-debug/command'
3
3
 
4
4
  module Debugger
5
+
6
+ annotate = 0
7
+
5
8
  class CommandProcessor # :nodoc:
6
9
  attr_accessor :interface
7
10
  attr_reader :display
8
11
 
12
+ @@Show_breakpoints_postcmd = ["break", "tbreak", "disable", "enable",
13
+ "condition", "clear", "delete"]
14
+ @@Show_annotations_preloop = ["step", "continue", "next", "finish"]
15
+ @@Show_annotations_postcmd = ["down", "frame", "up"]
16
+
9
17
  def initialize(interface = LocalInterface.new)
10
18
  @interface = interface
11
19
  @display = []
20
+
12
21
  @mutex = Mutex.new
13
22
  @last_cmd = nil
14
23
  @actions = []
24
+ @last_file = nil # Filename the last time we stopped
25
+ @last_line = nil # line number the last time we stopped
26
+ @output_annotation_in_progress = false
15
27
  end
16
28
 
17
29
  def interface=(interface)
@@ -21,6 +33,27 @@ module Debugger
21
33
  end
22
34
  end
23
35
 
36
+ require 'pathname' # For cleanpath
37
+
38
+ # Regularize file name.
39
+ # This is also used as a common funnel place if basename is
40
+ # desired or if we are working remotely and want to change the
41
+ # basename. Or we are eliding filenames.
42
+ def self.canonic_file(filename)
43
+ # For now we want resolved filenames
44
+ if Command.settings[:basename]
45
+ File.basename(filename)
46
+ else
47
+ # Cache this?
48
+ Pathname.new(filename).cleanpath.to_s
49
+ end
50
+ end
51
+
52
+ def self.print_location_and_text(file, line)
53
+ print "#{"\032\032" if ENV['EMACS']}#{canonic_file(file)}:#{line}\n" +
54
+ "#{Debugger.line_at(file, line)}"
55
+ end
56
+
24
57
  def self.protect(mname)
25
58
  alias_method "__#{mname}", mname
26
59
  module_eval %{
@@ -39,13 +72,31 @@ module Debugger
39
72
  end
40
73
 
41
74
  def at_breakpoint(context, breakpoint)
75
+ if @output_annotation_in_progress
76
+ print "\032\032\n"
77
+ @output_annotation_in_progress = false
78
+ end
79
+
42
80
  n = Debugger.breakpoints.index(breakpoint) + 1
81
+ print("\032\032%s:%s\n",
82
+ CommandProcessor.canonic_file(breakpoint.source),
83
+ breakpoint.pos) if ENV['EMACS']
43
84
  print "Breakpoint %d at %s:%s\n", n, breakpoint.source, breakpoint.pos
44
85
  end
45
86
  protect :at_breakpoint
46
87
 
47
88
  def at_catchpoint(context, excpt)
48
- print "Catchpoint at %s:%d: `%s' (%s)\n", context.frame_file(1), context.frame_line(1), excpt, excpt.class
89
+ if @output_annotation_in_progress
90
+ print "\032\032\n"
91
+ @output_annotation_in_progress = false
92
+ end
93
+
94
+ print "\032\032%s:%d\n",
95
+ CommandProcessor.canonic_file(context.frame_file(1)),
96
+ context.frame_line(1) if ENV['EMACS']
97
+ print "Catchpoint at %s:%d: `%s' (%s)\n",
98
+ CommandProcessor.canonic_file(context.frame_file(1)),
99
+ context.frame_line(1), excpt, excpt.class
49
100
  fs = context.stack_size
50
101
  tb = caller(0)[-fs..-1]
51
102
  if tb
@@ -57,18 +108,37 @@ module Debugger
57
108
  protect :at_catchpoint
58
109
 
59
110
  def at_tracing(context, file, line)
60
- print "Tracing(%d):%s:%s %s", context.thnum, file, line, Debugger.line_at(file, line)
111
+ if @output_annotation_in_progress
112
+ print "\032\032\n"
113
+ @output_annotation_in_progress = false
114
+ end
115
+
116
+ @last_file = CommandProcessor.canonic_file(file)
117
+ file = CommandProcessor.canonic_file(file)
118
+ unless file == @last_file and @last_line == line and
119
+ Command.settings[:tracing_plus]
120
+ print "Tracing(%d):%s:%s %s",
121
+ context.thnum, file, line, Debugger.line_at(file, line)
122
+ @last_file = file
123
+ @last_line = line
124
+ end
125
+ always_run(context, file, line, 2)
61
126
  end
62
127
  protect :at_tracing
63
128
 
64
129
  def at_line(context, file, line)
65
- print "#{"\032\032" if ENV['EMACS']}%s:%d %s", file, line, Debugger.line_at(file, line)
66
130
  process_commands(context, file, line)
67
131
  end
68
132
  protect :at_line
69
133
 
70
134
  private
71
-
135
+
136
+ # Callers of this routine should make sure to use comma to
137
+ # separate format argments rather than %. Otherwise it seems that
138
+ # if the string you want to print has format specifier, which
139
+ # could happen if you are trying to show say a source-code line
140
+ # with "puts" or "print" in it, this print routine will give an
141
+ # error saying it is looking for more arguments.
72
142
  def print(*args)
73
143
  @interface.print(*args)
74
144
  end
@@ -80,8 +150,10 @@ module Debugger
80
150
  "(rdb:%d) " % context.thnum
81
151
  end
82
152
  end
83
-
84
- def process_commands(context, file, line)
153
+
154
+ # Run these commands, for example display commands or possibly
155
+ # the list or irb in an "autolist" or "autoirb".
156
+ def always_run(context, file, line, run_level)
85
157
  event_cmds = Command.commands.select{|cmd| cmd.event }
86
158
  state = State.new do |s|
87
159
  s.context = context
@@ -95,7 +167,18 @@ module Debugger
95
167
  @interface.state = state if @interface.respond_to?('state=')
96
168
 
97
169
  commands = event_cmds.map{|cmd| cmd.new(state) }
98
- commands.select{|cmd| cmd.class.always_run }.each{|cmd| cmd.execute }
170
+ commands.select{|cmd| cmd.class.always_run >= run_level}.each{|cmd| cmd.execute }
171
+ return state, commands
172
+ end
173
+
174
+ # Handle debugger commands
175
+ def process_commands(context, file, line)
176
+ if @output_annotation_in_progress
177
+ print "\032\032\n"
178
+ @output_annotation_in_progress = false
179
+ end
180
+
181
+ state, commands = always_run(context, file, line, 1)
99
182
 
100
183
  splitter = lambda do |str|
101
184
  str.split(/;/).inject([]) do |m, v|
@@ -112,35 +195,83 @@ module Debugger
112
195
  m
113
196
  end
114
197
  end
115
-
198
+
199
+ preloop(commands, context)
200
+ CommandProcessor.print_location_and_text(file, line)
116
201
  while !state.proceed? and input = @interface.read_command(prompt(context))
117
202
  catch(:debug_error) do
118
-
119
203
  if input == ""
120
204
  next unless @last_cmd
121
205
  input = @last_cmd
122
206
  else
123
207
  @last_cmd = input
124
208
  end
125
-
126
- splitter[input].each do |input|
127
- if cmd = commands.find{ |c| c.match(input) }
128
- if context.dead? && cmd.class.need_context
129
- print "Command is unavailable\n"
130
- else
131
- cmd.execute
132
- end
133
- else
134
- unknown_cmd = commands.find{|cmd| cmd.class.unknown }
135
- if unknown_cmd
136
- unknown_cmd.execute
137
- else
138
- print "Unknown command\n"
139
- end
140
- end
209
+ splitter[input].each do |cmd|
210
+ one_cmd(commands, context, cmd)
211
+ postcmd(commands, context, cmd)
141
212
  end
142
213
  end
143
214
  end
215
+
216
+ if Debugger.annotate and Debugger.annotate > 2
217
+ print "\032\032starting\n"
218
+ @output_annotation_in_progress = true
219
+ end
220
+ end # process_commands
221
+
222
+ def one_cmd(commands, context, input)
223
+ if cmd = commands.find{ |c| c.match(input) }
224
+ if context.dead? && cmd.class.need_context
225
+ print "Command is unavailable\n"
226
+ else
227
+ cmd.execute
228
+ end
229
+ else
230
+ unknown_cmd = commands.find{|cmd| cmd.class.unknown }
231
+ if unknown_cmd
232
+ unknown_cmd.execute
233
+ else
234
+ print "Unknown command\n"
235
+ end
236
+ end
237
+ end
238
+
239
+ def postcmd(commands, context, cmd)
240
+ if Debugger.annotate and Debugger.annotate > 0
241
+ # FIXME: need to cannonicalize command names
242
+ # e.g. b vs. break
243
+ # and break out the command name "break 10"
244
+ # until then we'll refresh always
245
+ # cmd = @last_cmd unless cmd
246
+ #if @@Show_breakpoints_postcmd.member?(cmd)
247
+ annotation('breakpoints', commands, context, "info breakpoints") unless
248
+ Debugger.breakpoints.empty?
249
+ annotation('display', commands, context, "display")
250
+ # end
251
+ # if @@Show_annotations_postcmd.member?(cmd)
252
+ annotation('stack', commands, context, "where") if
253
+ context.stack_size > 0
254
+ annotation('variables', commands, context, "info variables")
255
+ # end
256
+ end
257
+ end
258
+
259
+ def preloop(commands, context)
260
+ if Debugger.annotate and Debugger.annotate > 0
261
+ # if we are here, the stack frames have changed outside the
262
+ # command loop (e.g. after a "continue" command), so we show
263
+ # the annotations again
264
+ annotation('breakpoints', commands, context, "info breakpoints")
265
+ annotation('stack', commands, context, "where")
266
+ annotation('variables', commands, context, "info variables")
267
+ annotation('display', commands, context, "display")
268
+ end
269
+ end
270
+
271
+ def annotation(label, commands, context, cmd)
272
+ print "\032\032#{label}\n"
273
+ one_cmd(commands, context, cmd)
274
+ print "\032\032\n"
144
275
  end
145
276
 
146
277
  class State # :nodoc: