byebug 3.2.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +125 -99
  4. data/CONTRIBUTING.md +4 -6
  5. data/GUIDE.md +42 -20
  6. data/Gemfile +5 -3
  7. data/README.md +2 -3
  8. data/Rakefile +11 -7
  9. data/bin/byebug +2 -252
  10. data/byebug.gemspec +7 -4
  11. data/ext/byebug/byebug.c +17 -18
  12. data/ext/byebug/byebug.h +4 -5
  13. data/ext/byebug/context.c +37 -39
  14. data/ext/byebug/threads.c +39 -18
  15. data/lib/byebug.rb +2 -110
  16. data/lib/byebug/attacher.rb +23 -0
  17. data/lib/byebug/breakpoint.rb +60 -0
  18. data/lib/byebug/command.rb +62 -70
  19. data/lib/byebug/commands/break.rb +24 -24
  20. data/lib/byebug/commands/catchpoint.rb +18 -10
  21. data/lib/byebug/commands/condition.rb +18 -17
  22. data/lib/byebug/commands/continue.rb +17 -9
  23. data/lib/byebug/commands/delete.rb +19 -13
  24. data/lib/byebug/commands/display.rb +19 -53
  25. data/lib/byebug/commands/edit.rb +7 -4
  26. data/lib/byebug/commands/enable_disable.rb +130 -0
  27. data/lib/byebug/commands/eval.rb +40 -22
  28. data/lib/byebug/commands/finish.rb +13 -4
  29. data/lib/byebug/commands/frame.rb +65 -45
  30. data/lib/byebug/commands/help.rb +17 -18
  31. data/lib/byebug/commands/history.rb +14 -8
  32. data/lib/byebug/commands/info.rb +160 -182
  33. data/lib/byebug/commands/interrupt.rb +4 -1
  34. data/lib/byebug/commands/irb.rb +30 -0
  35. data/lib/byebug/commands/kill.rb +7 -8
  36. data/lib/byebug/commands/list.rb +71 -66
  37. data/lib/byebug/commands/method.rb +14 -6
  38. data/lib/byebug/commands/pry.rb +35 -0
  39. data/lib/byebug/commands/quit.rb +9 -6
  40. data/lib/byebug/commands/reload.rb +5 -2
  41. data/lib/byebug/commands/restart.rb +13 -9
  42. data/lib/byebug/commands/save.rb +17 -17
  43. data/lib/byebug/commands/set.rb +16 -15
  44. data/lib/byebug/commands/show.rb +10 -11
  45. data/lib/byebug/commands/source.rb +11 -5
  46. data/lib/byebug/commands/stepping.rb +38 -24
  47. data/lib/byebug/commands/threads.rb +45 -31
  48. data/lib/byebug/commands/trace.rb +22 -9
  49. data/lib/byebug/commands/undisplay.rb +45 -0
  50. data/lib/byebug/commands/variables.rb +83 -27
  51. data/lib/byebug/context.rb +25 -22
  52. data/lib/byebug/core.rb +82 -0
  53. data/lib/byebug/helper.rb +37 -28
  54. data/lib/byebug/history.rb +8 -4
  55. data/lib/byebug/interface.rb +12 -17
  56. data/lib/byebug/interfaces/local_interface.rb +11 -8
  57. data/lib/byebug/interfaces/remote_interface.rb +11 -8
  58. data/lib/byebug/interfaces/script_interface.rb +9 -6
  59. data/lib/byebug/options.rb +46 -0
  60. data/lib/byebug/processor.rb +7 -1
  61. data/lib/byebug/processors/command_processor.rb +135 -125
  62. data/lib/byebug/processors/control_command_processor.rb +23 -23
  63. data/lib/byebug/remote.rb +17 -26
  64. data/lib/byebug/runner.rb +100 -0
  65. data/lib/byebug/setting.rb +33 -8
  66. data/lib/byebug/settings/autoeval.rb +5 -15
  67. data/lib/byebug/settings/autoirb.rb +4 -1
  68. data/lib/byebug/settings/autolist.rb +5 -2
  69. data/lib/byebug/settings/autoreload.rb +5 -2
  70. data/lib/byebug/settings/autosave.rb +6 -2
  71. data/lib/byebug/settings/basename.rb +7 -2
  72. data/lib/byebug/settings/callstyle.rb +4 -1
  73. data/lib/byebug/settings/forcestep.rb +6 -3
  74. data/lib/byebug/settings/fullpath.rb +5 -2
  75. data/lib/byebug/settings/histfile.rb +5 -3
  76. data/lib/byebug/settings/histsize.rb +5 -3
  77. data/lib/byebug/settings/linetrace.rb +4 -1
  78. data/lib/byebug/settings/listsize.rb +5 -1
  79. data/lib/byebug/settings/post_mortem.rb +21 -13
  80. data/lib/byebug/settings/stack_on_error.rb +6 -2
  81. data/lib/byebug/settings/testing.rb +6 -1
  82. data/lib/byebug/settings/tracing_plus.rb +5 -1
  83. data/lib/byebug/settings/verbose.rb +13 -2
  84. data/lib/byebug/settings/width.rb +4 -1
  85. data/lib/byebug/version.rb +1 -1
  86. data/test/{break_test.rb → commands/break_test.rb} +41 -53
  87. data/test/{condition_test.rb → commands/condition_test.rb} +14 -14
  88. data/test/{continue_test.rb → commands/continue_test.rb} +0 -0
  89. data/test/{delete_test.rb → commands/delete_test.rb} +2 -2
  90. data/test/commands/display_test.rb +37 -0
  91. data/test/{edit_test.rb → commands/edit_test.rb} +0 -0
  92. data/test/{eval_test.rb → commands/eval_test.rb} +1 -0
  93. data/test/{finish_test.rb → commands/finish_test.rb} +11 -1
  94. data/test/{frame_test.rb → commands/frame_test.rb} +12 -16
  95. data/test/{help_test.rb → commands/help_test.rb} +21 -4
  96. data/test/{history_test.rb → commands/history_test.rb} +0 -0
  97. data/test/{info_test.rb → commands/info_test.rb} +5 -55
  98. data/test/{interrupt_test.rb → commands/interrupt_test.rb} +0 -0
  99. data/test/commands/irb_test.rb +28 -0
  100. data/test/{kill_test.rb → commands/kill_test.rb} +1 -1
  101. data/test/{list_test.rb → commands/list_test.rb} +1 -1
  102. data/test/{method_test.rb → commands/method_test.rb} +0 -0
  103. data/test/{post_mortem_test.rb → commands/post_mortem_test.rb} +6 -10
  104. data/test/{pry_test.rb → commands/pry_test.rb} +4 -13
  105. data/test/{quit_test.rb → commands/quit_test.rb} +4 -4
  106. data/test/{reload_test.rb → commands/reload_test.rb} +0 -0
  107. data/test/{restart_test.rb → commands/restart_test.rb} +6 -0
  108. data/test/{save_test.rb → commands/save_test.rb} +2 -2
  109. data/test/{set_test.rb → commands/set_test.rb} +9 -2
  110. data/test/{show_test.rb → commands/show_test.rb} +1 -1
  111. data/test/{source_test.rb → commands/source_test.rb} +3 -3
  112. data/test/{stepping_test.rb → commands/stepping_test.rb} +44 -35
  113. data/test/{thread_test.rb → commands/thread_test.rb} +0 -0
  114. data/test/{trace_test.rb → commands/trace_test.rb} +0 -0
  115. data/test/{display_test.rb → commands/undisplay_test.rb} +7 -45
  116. data/test/{variables_test.rb → commands/variables_test.rb} +10 -1
  117. data/test/debugger_alias_test.rb +2 -2
  118. data/test/runner_test.rb +127 -0
  119. data/test/support/matchers.rb +27 -25
  120. data/test/support/test_interface.rb +9 -5
  121. data/test/support/utils.rb +96 -101
  122. data/test/test_helper.rb +32 -20
  123. metadata +93 -68
  124. data/lib/byebug/commands/enable.rb +0 -154
  125. data/lib/byebug/commands/repl.rb +0 -126
  126. data/test/irb_test.rb +0 -47
  127. data/test/support/breakpoint.rb +0 -13
@@ -1,17 +1,23 @@
1
1
  module Byebug
2
+ #
3
+ # Utilities for the save command.
4
+ #
2
5
  module SaveFunctions
3
6
  # Create a temporary file to write in if file is nil
4
7
  def open_save
5
- require "tempfile"
6
- file = Tempfile.new("byebug-save")
8
+ require 'tempfile'
9
+ file = Tempfile.new('byebug-save')
7
10
  # We want close to not unlink, so redefine.
8
11
  def file.close
9
12
  @tmpfile.close if @tmpfile
10
13
  end
11
- return file
14
+ file
12
15
  end
13
16
  end
14
17
 
18
+ #
19
+ # Save current settings to use them in another debug session.
20
+ #
15
21
  class SaveCommand < Command
16
22
  self.allow_in_control = true
17
23
 
@@ -28,15 +34,10 @@ module Byebug
28
34
  end
29
35
 
30
36
  def save_displays(file)
31
- for d in @state.display
32
- if d[0]
33
- file.puts "display #{d[1]}"
34
- end
35
- end
37
+ @state.display.each { |d| file.puts "display #{d[1]}" if d[0] }
36
38
  end
37
39
 
38
40
  def save_settings(file)
39
- # FIXME put routine in set
40
41
  %w(autoeval autoirb autolist basename testing).each do |setting|
41
42
  file.puts "set #{setting} #{Setting[setting.to_sym]}"
42
43
  end
@@ -47,8 +48,8 @@ module Byebug
47
48
  end
48
49
 
49
50
  def execute
50
- if not @match[1]
51
- file = open_save()
51
+ if !@match[1]
52
+ file = open_save
52
53
  else
53
54
  file = open(@match[1], 'w')
54
55
  end
@@ -56,10 +57,8 @@ module Byebug
56
57
  save_catchpoints(file)
57
58
  save_displays(file)
58
59
  save_settings(file)
59
- print "Saved to '#{file.path}'\n"
60
- if @state and @state.interface
61
- @state.interface.restart_file = file.path
62
- end
60
+ puts "Saved to '#{file.path}'"
61
+ @state.interface.restart_file = file.path if @state && @state.interface
63
62
  file.close
64
63
  end
65
64
 
@@ -69,12 +68,13 @@ module Byebug
69
68
  end
70
69
 
71
70
  def description
72
- %{save[ FILE]
71
+ %(save[ FILE]
73
72
 
74
73
  Saves current byebug state to FILE as a script file. This includes
75
74
  breakpoints, catchpoints, display expressions and some settings. If
76
75
  no filename is given, we will fabricate one.
77
- Use the "source" command in another debug session to restore them.}
76
+
77
+ Use the "source" command in another debug session to restore them.)
78
78
  end
79
79
  end
80
80
  end
@@ -1,4 +1,7 @@
1
1
  module Byebug
2
+ #
3
+ # Change byebug settings.
4
+ #
2
5
  class SetCommand < Command
3
6
  self.allow_in_control = true
4
7
 
@@ -8,34 +11,35 @@ module Byebug
8
11
 
9
12
  def execute
10
13
  key, value = @match[:setting], @match[:value]
11
- return print SetCommand.help if key.nil? && value.nil?
14
+ return puts(SetCommand.help) if key.nil? && value.nil?
12
15
 
13
16
  full_key = Setting.find(key)
14
- return print "Unknown setting :#{key}\n" unless full_key
17
+ return errmsg("Unknown setting :#{key}") unless full_key
15
18
 
16
19
  if !Setting.boolean?(full_key) && value.nil?
17
- return print "You must specify a value for setting :#{key}\n"
20
+ value, err = nil, "You must specify a value for setting :#{key}"
18
21
  elsif Setting.boolean?(full_key)
19
- value = get_onoff(value, key =~ /^no/ ? false : true)
22
+ value, err = get_onoff(value, key =~ /^no/ ? false : true)
20
23
  elsif Setting.integer?(full_key)
21
- return unless value = get_int(value, full_key, 1)
24
+ value, err = get_int(value, full_key, 1)
22
25
  end
26
+ return errmsg(err) if value.nil?
23
27
 
24
28
  Setting[full_key.to_sym] = value
25
29
 
26
- return print Setting.settings[full_key.to_sym].to_s
30
+ puts Setting.settings[full_key.to_sym].to_s
27
31
  end
28
32
 
29
33
  def get_onoff(arg, default)
30
34
  return default if arg.nil?
35
+
31
36
  case arg
32
37
  when '1', 'on', 'true'
33
- return true
38
+ true
34
39
  when '0', 'off', 'false'
35
- return false
40
+ false
36
41
  else
37
- print "Expecting 'on', 1, true, 'off', 0, false. Got: #{arg}.\n"
38
- raise RuntimeError
42
+ [nil, "Expecting 'on', 1, true, 'off', 0, false. Got: #{arg}.\n"]
39
43
  end
40
44
  end
41
45
 
@@ -56,14 +60,11 @@ module Byebug
56
60
  Conversely, you can use "set no<setting> to disable them.
57
61
 
58
62
  You can see these environment settings with the "show" command.
59
-
60
63
  EOD
61
64
  end
62
65
 
63
- def help(setting = nil)
64
- return "set #{setting.to_sym} <value>\n\n#{setting.help}" if setting
65
-
66
- description + Setting.format()
66
+ def help(subcmds = [])
67
+ Setting.help('set', subcmds.first)
67
68
  end
68
69
  end
69
70
  end
@@ -1,4 +1,7 @@
1
1
  module Byebug
2
+ #
3
+ # Show byebug settings.
4
+ #
2
5
  class ShowCommand < Command
3
6
  self.allow_in_control = true
4
7
 
@@ -8,14 +11,12 @@ module Byebug
8
11
 
9
12
  def execute
10
13
  key = @match[:setting]
11
- return print ShowCommand.help if key.nil?
14
+ return puts(self.class.help) if key.nil?
12
15
 
13
16
  full_key = Setting.find(key)
14
- if full_key
15
- print Setting.settings[full_key.to_sym].to_s
16
- else
17
- print "Unknown setting :#{key}\n"
18
- end
17
+ return errmsg("Unknown setting :#{key}") unless full_key
18
+
19
+ puts Setting.settings[full_key.to_sym].to_s
19
20
  end
20
21
 
21
22
  class << self
@@ -24,7 +25,7 @@ module Byebug
24
25
  end
25
26
 
26
27
  def description
27
- <<-EOD.gsub(/^ /, '')
28
+ <<-EOD.gsub(/^ {8}/, '')
28
29
 
29
30
  show <setting> <value>
30
31
 
@@ -34,10 +35,8 @@ module Byebug
34
35
  EOD
35
36
  end
36
37
 
37
- def help(setting = nil)
38
- return "show #{setting.to_sym} <value>\n\n#{setting.help}" if setting
39
-
40
- description + Setting.format()
38
+ def help(subcmds = [])
39
+ Setting.help('show', subcmds.first)
41
40
  end
42
41
  end
43
42
  end
@@ -1,4 +1,9 @@
1
1
  module Byebug
2
+ #
3
+ # Execute a file containing byebug commands.
4
+ #
5
+ # It can be used to restore a previously saved debugging session.
6
+ #
2
7
  class SourceCommand < Command
3
8
  self.allow_in_control = true
4
9
 
@@ -7,13 +12,12 @@ module Byebug
7
12
  end
8
13
 
9
14
  def execute
10
- return print SourceCommand.help(nil) if
11
- SourceCommand.names.include?(@match[0])
15
+ return puts(self.class.help) if self.class.names.include?(@match[0])
12
16
 
13
17
  file = File.expand_path(@match[1]).strip
14
- return errmsg "File \"#{file}\" not found\n" unless File.exist?(file)
18
+ return errmsg("File \"#{file}\" not found") unless File.exist?(file)
15
19
 
16
- if @state and @state.interface
20
+ if @state && @state.interface
17
21
  @state.interface.command_queue += File.open(file).readlines
18
22
  else
19
23
  Byebug.run_script(file, @state)
@@ -26,7 +30,9 @@ module Byebug
26
30
  end
27
31
 
28
32
  def description
29
- %{source FILE\texecutes a file containing byebug commands}
33
+ %(source <file>
34
+
35
+ Executes file <file> containing byebug commands.)
30
36
  end
31
37
  end
32
38
  end
@@ -3,19 +3,24 @@ module Byebug
3
3
  # Mixin to assist command parsing
4
4
  #
5
5
  module SteppingFunctions
6
- def parse_stepping_args(command_name, match)
7
- if match[1].nil?
8
- force = Setting[:forcestep]
9
- elsif match[1] == '+'
10
- force = true
11
- elsif match[1] == '-'
12
- force = false
6
+ def parse_force(str)
7
+ return Setting[:forcestep] unless str
8
+
9
+ case str
10
+ when '+' then
11
+ true
12
+ when '-' then
13
+ false
13
14
  end
14
- steps = get_int(match[2], command_name, 1)
15
- return [steps, force]
16
15
  end
17
16
  end
18
17
 
18
+ #
19
+ # Implements the next functionality.
20
+ #
21
+ # Allows the user the continue execution until the next instruction in the
22
+ # current frame.
23
+ #
19
24
  class NextCommand < Command
20
25
  self.allow_in_post_mortem = false
21
26
 
@@ -24,9 +29,10 @@ module Byebug
24
29
  end
25
30
 
26
31
  def execute
27
- steps, force = parse_stepping_args("Next", @match)
28
- return unless steps
29
- @state.context.step_over steps, @state.frame_pos, force
32
+ steps, err = parse_steps(@match[2], 'Next')
33
+ return errmsg(err) unless steps
34
+
35
+ @state.context.step_over(steps, @state.frame_pos, parse_force(@match[1]))
30
36
  @state.proceed
31
37
  end
32
38
 
@@ -36,14 +42,21 @@ module Byebug
36
42
  end
37
43
 
38
44
  def description
39
- %{n[ext][+-]?[ nnn]\tstep over once or nnn times,
40
- \t\t'+' forces to move to another line.
41
- \t\t'-' is the opposite of '+' and disables the :forcestep setting.
42
- }
45
+ %(n[ext][+-]?[ nnn]
46
+
47
+ Steps over once or nnn times.
48
+ '+' forces to move to another line.
49
+ '-' is the opposite of '+' and disables the :forcestep setting.)
43
50
  end
44
51
  end
45
52
  end
46
53
 
54
+ #
55
+ # Implements the step functionality.
56
+ #
57
+ # Allows the user the continue execution until the next instruction, possibily
58
+ # in a different frame. Use step to step into method calls or blocks.
59
+ #
47
60
  class StepCommand < Command
48
61
  self.allow_in_post_mortem = false
49
62
 
@@ -52,9 +65,10 @@ module Byebug
52
65
  end
53
66
 
54
67
  def execute
55
- steps, force = parse_stepping_args("Step", @match)
56
- return unless steps
57
- @state.context.step_into steps, force
68
+ steps, err = parse_steps(@match[2], 'Steps')
69
+ return errmsg(err) unless steps
70
+
71
+ @state.context.step_into(steps, parse_force(@match[1]))
58
72
  @state.proceed
59
73
  end
60
74
 
@@ -64,11 +78,11 @@ module Byebug
64
78
  end
65
79
 
66
80
  def description
67
- %{
68
- s[tep][+-]?[ nnn]\tstep (into methods) once or nnn times
69
- \t\t'+' forces to move to another line.
70
- \t\t'-' is the opposite of '+' and disables the :forcestep setting.
71
- }
81
+ %{s[tep][+-]?[ nnn]
82
+
83
+ Steps (into methods) once or nnn times.
84
+ '+' forces to move to another line.
85
+ '-' is the opposite of '+' and disables the :forcestep setting.}
72
86
  end
73
87
  end
74
88
  end
@@ -1,17 +1,22 @@
1
1
  module Byebug
2
+ #
3
+ # Utilities to assist commands related to threads.
4
+ #
2
5
  module ThreadFunctions
3
6
  def display_context(context, should_show_top_frame = true)
4
7
  args = thread_arguments(context, should_show_top_frame)
5
- print "%s%s%d %s\t%s\n", args[:status_flag], args[:debug_flag], args[:id],
6
- args[:thread], args[:file_line]
8
+ interp = format("%s%s%d %s\t%s",
9
+ args[:status_flag], args[:debug_flag], args[:id],
10
+ args[:thread], args[:file_line])
11
+ puts interp
7
12
  end
8
13
 
9
14
  def thread_arguments(context, should_show_top_frame = true)
10
15
  status_flag = if context.suspended?
11
- "$"
12
- else
13
- context.thread == Thread.current ? '+' : ' '
14
- end
16
+ '$'
17
+ else
18
+ context.thread == Thread.current ? '+' : ' '
19
+ end
15
20
  debug_flag = context.ignored? ? '!' : ' '
16
21
  if should_show_top_frame
17
22
  if context.thread == Thread.current && !context.dead?
@@ -36,19 +41,18 @@ module Byebug
36
41
  end
37
42
 
38
43
  def parse_thread_num(subcmd, arg)
39
- if '' == arg
40
- errmsg "\"#{subcmd}\" needs a thread number"
41
- nil
42
- else
43
- thread_num = get_int(arg, subcmd, 1)
44
- return nil unless thread_num
45
- get_context(thread_num)
46
- end
44
+ return errmsg("\"#{subcmd}\" needs a thread number") if '' == arg
45
+
46
+ thread_num, err = get_int(arg, subcmd, 1)
47
+ return errmsg(err) unless thread_num
48
+
49
+ Byebug.contexts.find { |c| c.thnum == thnum }
47
50
  end
48
51
 
49
52
  def parse_thread_num_for_cmd(subcmd, arg)
50
53
  c = parse_thread_num(subcmd, arg)
51
- return nil unless c
54
+ return unless c
55
+
52
56
  case
53
57
  when nil == c
54
58
  errmsg 'No such thread'
@@ -57,13 +61,14 @@ module Byebug
57
61
  when c.ignored?
58
62
  errmsg "Can't #{subcmd} thread #{arg}"
59
63
  else
60
- return c
64
+ c
61
65
  end
62
- return nil
63
66
  end
64
-
65
67
  end
66
68
 
69
+ #
70
+ # List current threads.
71
+ #
67
72
  class ThreadListCommand < Command
68
73
  self.allow_in_control = true
69
74
 
@@ -82,13 +87,14 @@ module Byebug
82
87
  end
83
88
 
84
89
  def description
85
- %{
86
- th[read] l[ist]\t\t\tlist all threads
87
- }
90
+ %(th[read] l[ist] Lists all threads.)
88
91
  end
89
92
  end
90
93
  end
91
94
 
95
+ #
96
+ # Show current thread.
97
+ #
92
98
  class ThreadCurrentCommand < Command
93
99
  def regexp
94
100
  /^\s* th(?:read)? \s+ (?:cur(?:rent)?)? \s*$/x
@@ -104,11 +110,14 @@ module Byebug
104
110
  end
105
111
 
106
112
  def description
107
- %{th[read] [cur[rent]]\t\tshow current thread}
113
+ %(th[read] [cur[rent]] Shows current thread.)
108
114
  end
109
115
  end
110
116
  end
111
117
 
118
+ #
119
+ # Stop execution of a thread.
120
+ #
112
121
  class ThreadStopCommand < Command
113
122
  self.allow_in_control = true
114
123
  self.allow_in_post_mortem = false
@@ -120,6 +129,7 @@ module Byebug
120
129
  def execute
121
130
  c = parse_thread_num_for_cmd('thread stop', @match[1])
122
131
  return unless c
132
+
123
133
  c.suspend
124
134
  display_context(c)
125
135
  end
@@ -130,11 +140,14 @@ module Byebug
130
140
  end
131
141
 
132
142
  def description
133
- %{th[read] stop <nnn>\t\tstop thread nnn}
143
+ %(th[read] stop <n> Stops thread <n>.)
134
144
  end
135
145
  end
136
146
  end
137
147
 
148
+ #
149
+ # Resume execution of a thread.
150
+ #
138
151
  class ThreadResumeCommand < Command
139
152
  self.allow_in_control = true
140
153
  self.allow_in_post_mortem = false
@@ -146,10 +159,7 @@ module Byebug
146
159
  def execute
147
160
  c = parse_thread_num_for_cmd('thread resume', @match[1])
148
161
  return unless c
149
- if !c.suspended?
150
- errmsg 'Already running'
151
- return
152
- end
162
+ return errmsg('Already running') unless c.suspended?
153
163
  c.resume
154
164
  display_context(c)
155
165
  end
@@ -160,11 +170,14 @@ module Byebug
160
170
  end
161
171
 
162
172
  def description
163
- %{th[read] resume <nnn>\t\tresume thread nnn}
173
+ %(th[read] resume <n> Resumes thread <n>.)
164
174
  end
165
175
  end
166
176
  end
167
177
 
178
+ #
179
+ # Switch execution to a different thread.
180
+ #
168
181
  class ThreadSwitchCommand < Command
169
182
  self.allow_in_control = true
170
183
  self.allow_in_post_mortem = false
@@ -175,11 +188,12 @@ module Byebug
175
188
 
176
189
  def execute
177
190
  if @match[1] =~ /switch/
178
- errmsg '"thread switch" needs a thread number'
179
- return
191
+ return errmsg('"thread switch" needs a thread number')
180
192
  end
193
+
181
194
  c = parse_thread_num_for_cmd('thread switch', @match[1])
182
195
  return unless c
196
+
183
197
  display_context(c)
184
198
  c.step_into 1
185
199
  c.thread.run
@@ -192,7 +206,7 @@ module Byebug
192
206
  end
193
207
 
194
208
  def description
195
- %{th[read] [sw[itch]] <nnn>\tswitch thread context to nnn}
209
+ %(th[read] [sw[itch]] <nnn> Switches thread context to <n>.)
196
210
  end
197
211
  end
198
212
  end