ruby-debug 0.9.3 → 0.10.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.
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: