debugger 1.4.0 → 1.5.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 (75) hide show
  1. data/CHANGELOG.md +4 -0
  2. data/README.md +9 -3
  3. data/debugger.gemspec +1 -1
  4. data/ext/ruby_debug/192/ruby_debug.c +21 -9
  5. data/ext/ruby_debug/193/ruby_debug.c +15 -5
  6. data/lib/debugger/test.rb +6 -0
  7. data/{test/support → lib/debugger/test}/breakpoint.rb +0 -0
  8. data/{test/support → lib/debugger/test}/context.rb +0 -0
  9. data/{test/support → lib/debugger/test}/matchers.rb +0 -0
  10. data/{test/support → lib/debugger/test}/mocha_extensions.rb +1 -1
  11. data/lib/debugger/test/printer_helpers.rb +8 -0
  12. data/{test/support → lib/debugger/test}/processor.rb +0 -0
  13. data/{test/support → lib/debugger/test}/test_dsl.rb +22 -2
  14. data/{test/support → lib/debugger/test}/test_interface.rb +4 -0
  15. data/lib/debugger/version.rb +1 -1
  16. data/lib/ruby-debug.rb +4 -1
  17. data/lib/ruby-debug/command.rb +18 -6
  18. data/lib/ruby-debug/commands/breakpoints.rb +27 -29
  19. data/lib/ruby-debug/commands/condition.rb +7 -2
  20. data/lib/ruby-debug/commands/continue.rb +1 -2
  21. data/lib/ruby-debug/commands/control.rb +8 -9
  22. data/lib/ruby-debug/commands/display.rb +7 -15
  23. data/lib/ruby-debug/commands/edit.rb +6 -6
  24. data/lib/ruby-debug/commands/enable.rb +6 -7
  25. data/lib/ruby-debug/commands/eval.rb +1 -3
  26. data/lib/ruby-debug/commands/frame.rb +72 -101
  27. data/lib/ruby-debug/commands/info.rb +8 -14
  28. data/lib/ruby-debug/commands/irb.rb +1 -1
  29. data/lib/ruby-debug/commands/jump.rb +6 -6
  30. data/lib/ruby-debug/commands/kill.rb +0 -1
  31. data/lib/ruby-debug/commands/list.rb +4 -4
  32. data/lib/ruby-debug/commands/method.rb +8 -11
  33. data/lib/ruby-debug/commands/quit.rb +1 -1
  34. data/lib/ruby-debug/commands/reload.rb +1 -1
  35. data/lib/ruby-debug/commands/save.rb +1 -1
  36. data/lib/ruby-debug/commands/set.rb +10 -15
  37. data/lib/ruby-debug/commands/show.rb +28 -42
  38. data/lib/ruby-debug/commands/skip.rb +1 -1
  39. data/lib/ruby-debug/commands/source.rb +1 -1
  40. data/lib/ruby-debug/commands/start.rb +26 -0
  41. data/lib/ruby-debug/commands/threads.rb +29 -18
  42. data/lib/ruby-debug/commands/tmate.rb +1 -1
  43. data/lib/ruby-debug/commands/trace.rb +6 -7
  44. data/lib/ruby-debug/commands/variables.rb +36 -19
  45. data/lib/ruby-debug/helper.rb +5 -5
  46. data/lib/ruby-debug/interface.rb +15 -3
  47. data/lib/ruby-debug/printers/base.rb +58 -0
  48. data/lib/ruby-debug/printers/plain.rb +41 -0
  49. data/lib/ruby-debug/printers/texts/base.yml +146 -0
  50. data/lib/ruby-debug/printers/texts/plain.yml +60 -0
  51. data/lib/ruby-debug/processor.rb +56 -47
  52. data/test/breakpoints_test.rb +43 -54
  53. data/test/conditions_test.rb +18 -6
  54. data/test/continue_test.rb +1 -1
  55. data/test/display_test.rb +11 -11
  56. data/test/edit_test.rb +1 -2
  57. data/test/eval_test.rb +5 -6
  58. data/test/finish_test.rb +1 -1
  59. data/test/frame_test.rb +29 -27
  60. data/test/help_test.rb +0 -1
  61. data/test/info_test.rb +10 -14
  62. data/test/irb_test.rb +0 -1
  63. data/test/jump_test.rb +21 -2
  64. data/test/method_test.rb +3 -3
  65. data/test/new/printers/plain_test.rb +84 -0
  66. data/test/reload_test.rb +2 -2
  67. data/test/restart_test.rb +1 -2
  68. data/test/set_test.rb +8 -7
  69. data/test/show_test.rb +22 -22
  70. data/test/source_test.rb +1 -1
  71. data/test/test_helper.rb +2 -1
  72. data/test/thread_test.rb +11 -13
  73. data/test/trace_test.rb +7 -7
  74. data/test/variables_test.rb +33 -15
  75. metadata +20 -12
@@ -8,14 +8,14 @@ module Debugger
8
8
 
9
9
  def execute
10
10
  if not @match[1]
11
- errmsg "\"condition\" must be followed a breakpoint number and expression\n"
11
+ errmsg pr("condition.errors.syntax")
12
12
  else
13
13
  breakpoints = Debugger.breakpoints.sort_by{|b| b.id }
14
14
  largest = breakpoints.inject(0) do |tally, b|
15
15
  tally = b.id if b.id > tally
16
16
  end
17
17
  if 0 == largest
18
- print "No breakpoints have been set.\n"
18
+ print pr("condition.errors.no_breakpoints")
19
19
  return
20
20
  end
21
21
  pos = get_int(@match[1], "Condition", 1, largest)
@@ -23,6 +23,11 @@ module Debugger
23
23
  breakpoints.each do |b|
24
24
  if b.id == pos
25
25
  b.expr = @match[2].empty? ? nil : @match[2]
26
+ if b.expr
27
+ print pr("conditions.set_condition", id: b.id, expr: b.expr)
28
+ else
29
+ print pr("conditions.unset_condition", id: b.id)
30
+ end
26
31
  break
27
32
  end
28
33
  end
@@ -14,8 +14,7 @@ module Debugger
14
14
  line_number = get_int(@match[1], "Continue", 0, nil, 0)
15
15
  return unless line_number
16
16
  unless LineCache.trace_line_numbers(filename).member?(line_number)
17
- errmsg("Line %d is not a stopping point in file \"%s\".\n",
18
- line_number, filename)
17
+ errmsg pr("continue.errors.unstopped_line", line: line_number, file: filename)
19
18
  return
20
19
  end
21
20
  @state.context.set_breakpoint(filename, line_number)
@@ -12,13 +12,13 @@ module Debugger
12
12
 
13
13
  def execute
14
14
  if not defined? Debugger::PROG_SCRIPT
15
- errmsg "Don't know name of debugged program\n"
15
+ errmsg pr("restart.errors.undefined")
16
16
  return
17
17
  end
18
18
  prog_script = Debugger::PROG_SCRIPT
19
19
  if not defined? Debugger::RDEBUG_SCRIPT
20
20
  # FIXME? Should ask for confirmation?
21
- print "Debugger was not called from the outset...\n"
21
+ print_debug pr("restart.debug.outset")
22
22
  rdebug_script = prog_script
23
23
  else
24
24
  rdebug_script = Debugger::RDEBUG_SCRIPT
@@ -26,15 +26,14 @@ module Debugger
26
26
  begin
27
27
  Dir.chdir(Debugger::INITIAL_DIR)
28
28
  rescue
29
- print "Failed to change initial directory #{Debugger::INITIAL_DIR}"
29
+ print_debug pr("restart.debug.change_initial_dir", dir: Debugger::INITIAL_DIR)
30
30
  end
31
31
  if not File.exist?(File.expand_path(prog_script))
32
- errmsg "Ruby program #{prog_script} doesn't exist\n"
32
+ errmsg pr("restart.errors.not_exist", prog: prog_script)
33
33
  return
34
34
  end
35
35
  if not File.executable?(prog_script) and rdebug_script == prog_script
36
- print "Ruby program #{prog_script} doesn't seem to be executable...\n"
37
- print "We'll add a call to Ruby.\n"
36
+ print_debug pr("restart.debug.not_executable", prog: prog_script)
38
37
  ruby = begin defined?(Gem) ? Gem.ruby : "ruby" rescue "ruby" end
39
38
  rdebug_script = "#{ruby} -I#{$:.join(' -I')} #{prog_script}"
40
39
  else
@@ -44,7 +43,7 @@ module Debugger
44
43
  argv = [prog_script] + @match[1].split(/[ \t]+/)
45
44
  else
46
45
  if not defined? Command.settings[:argv]
47
- errmsg "Arguments have not been set. Use 'set args' to set them.\n"
46
+ errmsg pr("restart.errors.no_args")
48
47
  return
49
48
  else
50
49
  argv = Command.settings[:argv]
@@ -54,10 +53,10 @@ module Debugger
54
53
 
55
54
  # An execv would be preferable to the "exec" below.
56
55
  cmd = rdebug_script + args
57
- print "Re exec'ing:\n\t#{cmd}\n"
56
+ print pr("restart.success", cmd: cmd)
58
57
  exec cmd
59
58
  rescue Errno::EOPNOTSUPP
60
- print "Restart command is not available at this time.\n"
59
+ print pr("restart.errors.not_available")
61
60
  end
62
61
 
63
62
  class << self
@@ -1,22 +1,15 @@
1
1
  module Debugger
2
2
  module DisplayFunctions # :nodoc:
3
3
  def display_expression(exp)
4
- print "%s = %s\n", exp, debug_silent_eval(exp).to_s
4
+ print pr("display.result", n: @state.display.size, exp: exp, result: debug_silent_eval(exp))
5
5
  end
6
6
 
7
- def active_display_expressions?
8
- @state.display.select{|d| d[0]}.size > 0
9
- end
10
-
11
7
  def print_display_expressions
12
- n = 1
13
- for d in @state.display
14
- if d[0]
15
- print "%d: ", n
16
- display_expression(d[1])
17
- end
18
- n += 1
8
+ result = prc("display.result", @state.display) do |item, index|
9
+ is_active, expression = item
10
+ {n: index + 1, exp: expression, result: debug_silent_eval(expression)} if is_active
19
11
  end
12
+ print result
20
13
  end
21
14
  end
22
15
 
@@ -28,7 +21,6 @@ module Debugger
28
21
  def execute
29
22
  exp = @match[1]
30
23
  @state.display.push [true, exp]
31
- print "%d: ", @state.display.size
32
24
  display_expression(exp)
33
25
  end
34
26
 
@@ -84,7 +76,7 @@ module Debugger
84
76
 
85
77
  def execute
86
78
  unless pos = @match[1]
87
- if confirm("Clear all expressions? (y/n) ")
79
+ if confirm(pr("display.confirmations.clear_all"))
88
80
  for d in @state.display
89
81
  d[0] = false
90
82
  end
@@ -95,7 +87,7 @@ module Debugger
95
87
  if @state.display[pos-1]
96
88
  @state.display[pos-1][0] = nil
97
89
  else
98
- errmsg "Display expression %d is not defined.\n", pos
90
+ errmsg pr("display.errors.undefined", expr: pos)
99
91
  end
100
92
  end
101
93
  end
@@ -4,29 +4,29 @@ module Debugger
4
4
  def regexp
5
5
  /^\s* ed(?:it)? (?:\s+(.*))?$/ix
6
6
  end
7
-
7
+
8
8
  def execute
9
9
  if not @match[1] or @match[1].strip.empty?
10
10
  unless @state.context
11
- errmsg "We are not in a state that has an associated file.\n"
12
- return
11
+ errmsg pr("edit.errors.state")
12
+ return
13
13
  end
14
14
  file = @state.file
15
15
  line_number = @state.line
16
16
  elsif @pos_match = /([^:]+)[:]([0-9]+)/.match(@match[1])
17
17
  file, line_number = @pos_match.captures
18
18
  else
19
- errmsg "Invalid file/line number specification: #{@match[1]}\n"
19
+ errmsg pr("edit.errors.file_line", file_line: @match[1])
20
20
  return
21
21
  end
22
22
  editor = ENV['EDITOR'] || 'ex'
23
23
  if File.readable?(file)
24
24
  system("#{editor} +#{line_number} #{file}")
25
25
  else
26
- errmsg "File \"#{file}\" is not readable.\n"
26
+ errmsg pr("edit.errors.not_readable", file: file)
27
27
  end
28
28
  end
29
-
29
+
30
30
  class << self
31
31
  def help_command
32
32
  'edit'
@@ -7,7 +7,7 @@ module Debugger
7
7
  tally = b.id if b.id > tally
8
8
  end
9
9
  if 0 == largest
10
- errmsg "No breakpoints have been set.\n"
10
+ errmsg pr("toggle.errors.no_breakpoints")
11
11
  return
12
12
  end
13
13
  args.each do |pos|
@@ -18,11 +18,12 @@ module Debugger
18
18
  enabled = ("Enable" == is_enable)
19
19
  if enabled
20
20
  unless syntax_valid?(b.expr)
21
- errmsg("Expression \"#{b.expr}\" syntactically incorrect; breakpoint remains disabled.\n")
21
+ errmsg pr("toggle.errors.expression", expr: b.expr)
22
22
  break
23
23
  end
24
24
  end
25
25
  b.enabled = ("Enable" == is_enable)
26
+ print(pr("toggle.breakpoint_#{enabled ? "enabled" : "disabled"}", id: b.id))
26
27
  break
27
28
  end
28
29
  end
@@ -31,7 +32,7 @@ module Debugger
31
32
 
32
33
  def enable_disable_display(is_enable, args)
33
34
  if 0 == @state.display.size
34
- errmsg "No display expressions have been set.\n"
35
+ errmsg pr("toggle.errors.no_display")
35
36
  return
36
37
  end
37
38
  args.each do |pos|
@@ -64,8 +65,7 @@ Do \"info display\" to see current list of code numbers."],
64
65
 
65
66
  def execute
66
67
  if not @match[1]
67
- errmsg "\"enable\" must be followed \"display\", \"breakpoints\"" +
68
- " or breakpoint numbers.\n"
68
+ errmsg pr("toggle.errors.syntax", toggle: "enable")
69
69
  else
70
70
  args = @match[1].split(/[ \t]+/)
71
71
  param = args.shift
@@ -140,8 +140,7 @@ Do \"info display\" to see current list of code numbers."],
140
140
 
141
141
  def execute
142
142
  if not @match[1]
143
- errmsg "\"disable\" must be followed \"display\", \"breakpoints\"" +
144
- " or breakpoint numbers.\n"
143
+ errmsg pr("toggle.errors.syntax", toggle: "disable")
145
144
  else
146
145
  args = @match[1].split(/[ \t]+/)
147
146
  param = args.shift
@@ -23,8 +23,6 @@ module Debugger
23
23
  end
24
24
 
25
25
  class EvalCommand < Command # :nodoc:
26
- self.allow_in_control = true
27
-
28
26
  register_setting_get(:autoeval) do
29
27
  EvalCommand.unknown
30
28
  end
@@ -44,7 +42,7 @@ module Debugger
44
42
  def execute
45
43
  expr = @match ? @match.post_match : @input
46
44
  run_with_binding do |b|
47
- print "%s\n", debug_eval(expr, b).inspect
45
+ print pr("eval.result", expr: expr, result: debug_eval(expr, b).inspect)
48
46
  end
49
47
  end
50
48
 
@@ -14,24 +14,23 @@ module Debugger
14
14
  end
15
15
 
16
16
  if abs_frame_pos >= context.stack_size then
17
- errmsg "Adjusting would put us beyond the oldest (initial) frame.\n"
17
+ errmsg pr("frame.errors.too_low")
18
18
  return
19
19
  elsif abs_frame_pos < 0 then
20
- errmsg "Adjusting would put us beyond the newest (innermost) frame.\n"
20
+ errmsg pr("frame.errors.too_high")
21
21
  return
22
22
  end
23
23
  if @state.frame_pos != abs_frame_pos then
24
24
  @state.previous_line = nil
25
25
  @state.frame_pos = abs_frame_pos
26
26
  end
27
-
28
27
  @state.file = context.frame_file(@state.frame_pos)
29
28
  @state.line = context.frame_line(@state.frame_pos)
30
-
31
- print_frame(@state.frame_pos, true)
29
+
30
+ print_frame(nil, @state.frame_pos, true)
32
31
  end
33
-
34
- def get_frame_call(prefix, pos, context)
32
+
33
+ def get_frame_call(prefix_size, pos, context)
35
34
  id = context.frame_method(pos)
36
35
  klass = context.frame_class(pos)
37
36
  call_str = ""
@@ -42,19 +41,19 @@ module Debugger
42
41
  if Command.settings[:callstyle] == :tracked
43
42
  arg_info = context.frame_args_info(pos)
44
43
  end
45
- call_str << "#{klass}."
44
+ call_str << "#{klass}."
46
45
  end
47
46
  call_str << id.id2name
48
47
  if args.any?
49
48
  call_str << "("
50
49
  args.each_with_index do |name, i|
51
- case Command.settings[:callstyle]
50
+ case Command.settings[:callstyle]
52
51
  when :short
53
52
  call_str += "%s, " % [name]
54
53
  when :last
55
54
  klass = locals[name].class
56
55
  if klass.inspect.size > 20+3
57
- klass = klass.inspect[0..20]+"..."
56
+ klass = klass.inspect[0..20]+"..."
58
57
  end
59
58
  call_str += "%s#%s, " % [name, klass]
60
59
  when :tracked
@@ -64,91 +63,72 @@ module Debugger
64
63
  call_str += "%s, " % name
65
64
  end
66
65
  end
67
- if call_str.size > self.class.settings[:width] - prefix.size
66
+ if call_str.size > self.class.settings[:width] - prefix_size
68
67
  # Strip off trailing ', ' if any but add stuff for later trunc
69
68
  call_str[-2..-1] = ",...XX"
70
69
  break
71
70
  end
72
71
  end
73
- call_str[-2..-1] = ")" # Strip off trailing ', ' if any
72
+ call_str[-2..-1] = ")" # Strip off trailing ', ' if any
74
73
  end
75
74
  end
76
75
  return call_str
77
76
  end
78
77
 
79
- def print_frame(pos, adjust = false, context=@state.context)
80
- file = context.frame_file(pos)
81
- line = context.frame_line(pos)
82
- klass = context.frame_class(pos)
83
-
84
- unless Command.settings[:full_path]
85
- path_components = file.split(/[\\\/]/)
86
- if path_components.size > 3
87
- path_components[0...-3] = '...'
88
- file = path_components.join(File::ALT_SEPARATOR || File::SEPARATOR)
78
+ def print_frame(mark, pos, adjust = false, context = @state.context)
79
+ if print_frame?(context, pos)
80
+ print pr("frame.line", get_pr_arguments(mark, pos, context))
81
+ if ENV['EMACS'] && adjust
82
+ fmt = (Debugger.annotate.to_i > 1 ?
83
+ "\032\032source %s:%d\n" : "\032\032%s:%d\n")
84
+ print fmt % [file, line]
89
85
  end
90
86
  end
91
-
92
- frame_num = "#%d " % pos
93
- call_str = get_frame_call(frame_num, pos, context)
94
- file_line = "at line %s:%d\n" % [CommandProcessor.canonic_file(file), line]
95
- print frame_num
96
- unless call_str.empty?
97
- print call_str
98
- print ' '
99
- if call_str.size + frame_num.size + file_line.size > self.class.settings[:width]
100
- print "\n "
101
- end
102
- end
103
- print file_line
104
- if ENV['EMACS'] && adjust
105
- fmt = (Debugger.annotate.to_i > 1 ?
106
- "\032\032source %s:%d\n" : "\032\032%s:%d\n")
107
- print fmt % [CommandProcessor.canonic_file(file), line]
108
- end
109
87
  end
110
88
 
111
- # Check if call stack is truncated. This can happen if
112
- # Debugger.start is not called low enough in the call stack. An
113
- # array of additional callstack lines from caller is returned if
114
- # definitely truncated, false if not, and nil if we don't know.
115
- #
116
- # We determine truncation based on a passed in sentinal set via
117
- # caller which can be nil.
118
- #
119
- # First we see if we can find our position in caller. If so, then
120
- # we compare context position to that in caller using sentinal
121
- # as a place to start ignoring additional caller entries. sentinal
122
- # is set by rdebug, but if it's not set, i.e. nil then additional
123
- # entries are presumably ones that we haven't recorded in context
124
- def truncated_callstack?(context, sentinal=nil, cs=caller)
125
- recorded_size = context.stack_size
126
- to_find_fl = "#{context.frame_file(0)}:#{context.frame_line(0)}"
127
- top_discard = false
128
- cs.each_with_index do |fl, i|
129
- fl.gsub!(/in `.*'$/, '')
130
- fl.gsub!(/:$/, '')
131
- if fl == to_find_fl
132
- top_discard = i
133
- break
134
- end
135
- end
136
- if top_discard
137
- cs = cs[top_discard..-1]
138
- return false unless cs
139
- return cs unless sentinal
140
- if cs.size > recorded_size+2 && cs[recorded_size+2] != sentinal
141
- # caller seems to truncate recursive calls and we don't.
142
- # See if we can find sentinal in the first 0..recorded_size+1 entries
143
- return false if cs[0..recorded_size+1].any?{ |f| f==sentinal }
144
- return cs
89
+ private
90
+
91
+ def get_pr_arguments(mark, pos, context)
92
+ if print_frame?(context, pos)
93
+ mark = if mark == true
94
+ "--> "
95
+ elsif mark == false
96
+ " "
97
+ else
98
+ mark
99
+ end
100
+
101
+ line = context.frame_line(pos)
102
+
103
+ file = context.frame_file(pos)
104
+ unless Command.settings[:full_path]
105
+ path_components = file.split(/[\\\/]/)
106
+ if path_components.size > 3
107
+ path_components[0...-3] = '...'
108
+ file = path_components.join(File::ALT_SEPARATOR || File::SEPARATOR)
109
+ end
110
+ end
111
+ file = CommandProcessor.canonic_file(file)
112
+
113
+ call_str = get_frame_call("##{pos}".size, pos, context)
114
+ call_str = unless call_str.empty?
115
+ padding = 10
116
+ approx_line_width = call_str.size + pos.to_s.size + file.to_s.size + line.to_s.size + padding
117
+ if approx_line_width > self.class.settings[:width]
118
+ call_str + "\n" + (" " * (mark.to_s.size + pos.to_s.size + 2))
119
+ else
120
+ call_str + " "
121
+ end
122
+ else
123
+ " "
124
+ end
125
+ {mark: mark, pos: pos, call_str: call_str, file: file, line: line}
145
126
  end
146
- return false
147
127
  end
148
- return nil
149
- end
150
-
151
128
 
129
+ def print_frame?(context, pos)
130
+ context.frame_line(pos) && context.frame_file(pos)
131
+ end
152
132
  end
153
133
 
154
134
  # Implements debugger "where" or "backtrace" command.
@@ -158,18 +138,9 @@ module Debugger
158
138
  end
159
139
 
160
140
  def execute
161
- (0...@state.context.stack_size).each do |idx|
162
- if idx == @state.frame_pos
163
- print "--> "
164
- else
165
- print " "
166
- end
167
- print_frame(idx)
168
-
169
- end
170
- if truncated_callstack?(@state.context, Debugger.start_sentinal)
171
- # print "Warning: saved frames may be incomplete; compare with caller(0).\n"
172
- end
141
+ print(prc("frame.line", (0...@state.context.stack_size)) do |item, _|
142
+ get_pr_arguments(item == @state.frame_pos, item, @state.context)
143
+ end)
173
144
  end
174
145
 
175
146
  class << self
@@ -181,18 +152,18 @@ module Debugger
181
152
  s = if cmd == 'where'
182
153
  %{
183
154
  w[here]\tdisplay stack frames
184
- }
185
- else
155
+ }
156
+ else
186
157
  %{
187
158
  bt|backtrace\t\talias for where - display stack frames
188
- }
189
- end
159
+ }
160
+ end
190
161
  s += %{
191
162
  Print the entire stack frame. Each frame is numbered, the most recent
192
163
  frame is 0. frame number can be referred to in the "frame" command;
193
164
  "up" and "down" add or subtract respectively to frame numbers shown.
194
- The position of the current frame is marked with -->. }
195
- end
165
+ The position of the current frame is marked with -->. }
166
+ end
196
167
  end
197
168
  end
198
169
 
@@ -243,11 +214,11 @@ The position of the current frame is marked with -->. }
243
214
  end
244
215
  end
245
216
  end
246
-
217
+
247
218
  class FrameCommand < Command # :nodoc:
248
219
  def regexp
249
- / ^\s*
250
- f(?:rame)?
220
+ / ^\s*
221
+ f(?:rame)?
251
222
  (?: \s+ (\S+))? \s*
252
223
  (?: thread \s+ (.*))? \s*
253
224
  $/x
@@ -290,10 +261,10 @@ The position of the current frame is marked with -->. }
290
261
  Without an argument, the command prints the current stack
291
262
  frame. Since the current position is redisplayed, it may trigger a
292
263
  resyncronization if there is a front end also watching over
293
- things.
264
+ things.
294
265
 
295
266
  If a thread number is given then we set the context for evaluating
296
- expressions to that frame of that thread.
267
+ expressions to that frame of that thread.
297
268
  }
298
269
  end
299
270
  end