rb8-trepanning 0.1.3

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 (274) hide show
  1. data/.gitignore +3 -0
  2. data/CHANGES +34 -0
  3. data/ChangeLog +875 -0
  4. data/README.textile +59 -0
  5. data/Rakefile +215 -0
  6. data/app/.gitignore +1 -0
  7. data/app/cmd_parse.kpeg +241 -0
  8. data/app/cmd_parse.rb +212 -0
  9. data/app/cmd_parser.rb +1948 -0
  10. data/app/complete.rb +79 -0
  11. data/app/default.rb +90 -0
  12. data/app/display.rb +148 -0
  13. data/app/eventbuffer.rb +147 -0
  14. data/app/frame.rb +166 -0
  15. data/app/irb.rb +114 -0
  16. data/app/options.rb +200 -0
  17. data/app/run.rb +74 -0
  18. data/app/util.rb +65 -0
  19. data/bin/.gitignore +1 -0
  20. data/bin/trepan8 +115 -0
  21. data/data/.gitignore +1 -0
  22. data/data/irbrc +41 -0
  23. data/interface/.gitignore +1 -0
  24. data/interface/base_intf.rb +109 -0
  25. data/interface/client.rb +82 -0
  26. data/interface/comcodes.rb +20 -0
  27. data/interface/script.rb +110 -0
  28. data/interface/server.rb +147 -0
  29. data/interface/user.rb +165 -0
  30. data/io/base_io.rb +148 -0
  31. data/io/input.rb +158 -0
  32. data/io/null_output.rb +46 -0
  33. data/io/string_array.rb +156 -0
  34. data/io/tcpclient.rb +129 -0
  35. data/io/tcpfns.rb +33 -0
  36. data/io/tcpserver.rb +141 -0
  37. data/lib/debugger.rb +8 -0
  38. data/lib/trepanning.rb +283 -0
  39. data/processor/.gitignore +1 -0
  40. data/processor/command-ruby-debug/breakpoints.rb +155 -0
  41. data/processor/command-ruby-debug/catchpoint.rb +55 -0
  42. data/processor/command-ruby-debug/condition.rb +49 -0
  43. data/processor/command-ruby-debug/control.rb +31 -0
  44. data/processor/command-ruby-debug/display.rb +120 -0
  45. data/processor/command-ruby-debug/enable.rb +202 -0
  46. data/processor/command-ruby-debug/frame.rb +199 -0
  47. data/processor/command-ruby-debug/help.rb +63 -0
  48. data/processor/command-ruby-debug/info.rb +359 -0
  49. data/processor/command-ruby-debug/method.rb +84 -0
  50. data/processor/command-ruby-debug/reload.rb +40 -0
  51. data/processor/command-ruby-debug/save.rb +90 -0
  52. data/processor/command-ruby-debug/set.rb +237 -0
  53. data/processor/command-ruby-debug/show.rb +251 -0
  54. data/processor/command-ruby-debug/source.rb +36 -0
  55. data/processor/command-ruby-debug/threads.rb +189 -0
  56. data/processor/command-ruby-debug/trace.rb +57 -0
  57. data/processor/command-ruby-debug/variables.rb +199 -0
  58. data/processor/command.rb +270 -0
  59. data/processor/command/.gitignore +1 -0
  60. data/processor/command/alias.rb +54 -0
  61. data/processor/command/backtrace.rb +123 -0
  62. data/processor/command/base/cmd.rb +177 -0
  63. data/processor/command/base/subcmd.rb +230 -0
  64. data/processor/command/base/submgr.rb +188 -0
  65. data/processor/command/base/subsubcmd.rb +128 -0
  66. data/processor/command/base/subsubmgr.rb +199 -0
  67. data/processor/command/break.rb +114 -0
  68. data/processor/command/catch.rb +71 -0
  69. data/processor/command/complete.rb +39 -0
  70. data/processor/command/continue.rb +57 -0
  71. data/processor/command/directory.rb +50 -0
  72. data/processor/command/disable.rb +85 -0
  73. data/processor/command/display.rb +78 -0
  74. data/processor/command/down.rb +54 -0
  75. data/processor/command/edit.rb +79 -0
  76. data/processor/command/enable.rb +48 -0
  77. data/processor/command/eval.rb +90 -0
  78. data/processor/command/exit.rb +66 -0
  79. data/processor/command/finish.rb +59 -0
  80. data/processor/command/frame.rb +97 -0
  81. data/processor/command/help.rb +230 -0
  82. data/processor/command/help/.gitignore +1 -0
  83. data/processor/command/help/README +10 -0
  84. data/processor/command/help/command.txt +58 -0
  85. data/processor/command/help/examples.txt +16 -0
  86. data/processor/command/help/filename.txt +40 -0
  87. data/processor/command/help/location.txt +37 -0
  88. data/processor/command/help/suffixes.txt +17 -0
  89. data/processor/command/info.rb +28 -0
  90. data/processor/command/info_subcmd/.gitignore +1 -0
  91. data/processor/command/info_subcmd/args.rb +39 -0
  92. data/processor/command/info_subcmd/breakpoints.rb +80 -0
  93. data/processor/command/info_subcmd/catch.rb +36 -0
  94. data/processor/command/info_subcmd/files.rb +39 -0
  95. data/processor/command/info_subcmd/globals.rb +64 -0
  96. data/processor/command/info_subcmd/line.rb +30 -0
  97. data/processor/command/info_subcmd/locals.rb +69 -0
  98. data/processor/command/info_subcmd/macro.rb +62 -0
  99. data/processor/command/info_subcmd/program.rb +51 -0
  100. data/processor/command/info_subcmd/ruby.rb +57 -0
  101. data/processor/command/info_subcmd/source.rb +74 -0
  102. data/processor/command/info_subcmd/stack.rb +25 -0
  103. data/processor/command/info_subcmd/threads.rb +75 -0
  104. data/processor/command/kill.rb +78 -0
  105. data/processor/command/list.rb +117 -0
  106. data/processor/command/macro.rb +68 -0
  107. data/processor/command/next.rb +79 -0
  108. data/processor/command/parsetree.rb +56 -0
  109. data/processor/command/pp.rb +40 -0
  110. data/processor/command/pr.rb +37 -0
  111. data/processor/command/ps.rb +40 -0
  112. data/processor/command/restart.rb +86 -0
  113. data/processor/command/save.rb +58 -0
  114. data/processor/command/set.rb +47 -0
  115. data/processor/command/set_subcmd/.gitignore +1 -0
  116. data/processor/command/set_subcmd/abbrev.rb +25 -0
  117. data/processor/command/set_subcmd/auto.rb +27 -0
  118. data/processor/command/set_subcmd/auto_subcmd/.gitignore +1 -0
  119. data/processor/command/set_subcmd/auto_subcmd/eval.rb +53 -0
  120. data/processor/command/set_subcmd/auto_subcmd/irb.rb +33 -0
  121. data/processor/command/set_subcmd/auto_subcmd/list.rb +33 -0
  122. data/processor/command/set_subcmd/basename.rb +25 -0
  123. data/processor/command/set_subcmd/callstyle.rb +46 -0
  124. data/processor/command/set_subcmd/confirm.rb +24 -0
  125. data/processor/command/set_subcmd/debug.rb +47 -0
  126. data/processor/command/set_subcmd/different.rb +61 -0
  127. data/processor/command/set_subcmd/highlight.rb +43 -0
  128. data/processor/command/set_subcmd/max.rb +26 -0
  129. data/processor/command/set_subcmd/max_subcmd/list.rb +49 -0
  130. data/processor/command/set_subcmd/max_subcmd/stack.rb +50 -0
  131. data/processor/command/set_subcmd/max_subcmd/string.rb +76 -0
  132. data/processor/command/set_subcmd/max_subcmd/width.rb +49 -0
  133. data/processor/command/set_subcmd/reload.rb +42 -0
  134. data/processor/command/set_subcmd/timer.rb +58 -0
  135. data/processor/command/set_subcmd/trace.rb +37 -0
  136. data/processor/command/set_subcmd/trace_subcmd/buffer.rb +42 -0
  137. data/processor/command/set_subcmd/trace_subcmd/print.rb +41 -0
  138. data/processor/command/shell.rb +139 -0
  139. data/processor/command/show.rb +39 -0
  140. data/processor/command/show_subcmd/.gitignore +1 -0
  141. data/processor/command/show_subcmd/abbrev.rb +20 -0
  142. data/processor/command/show_subcmd/alias.rb +46 -0
  143. data/processor/command/show_subcmd/args.rb +34 -0
  144. data/processor/command/show_subcmd/auto.rb +28 -0
  145. data/processor/command/show_subcmd/auto_subcmd/eval.rb +27 -0
  146. data/processor/command/show_subcmd/auto_subcmd/irb.rb +23 -0
  147. data/processor/command/show_subcmd/auto_subcmd/list.rb +22 -0
  148. data/processor/command/show_subcmd/basename.rb +20 -0
  149. data/processor/command/show_subcmd/callstyle.rb +22 -0
  150. data/processor/command/show_subcmd/confirm.rb +18 -0
  151. data/processor/command/show_subcmd/debug.rb +26 -0
  152. data/processor/command/show_subcmd/debug_subcmd/dbgr.rb +21 -0
  153. data/processor/command/show_subcmd/debug_subcmd/skip.rb +22 -0
  154. data/processor/command/show_subcmd/debug_subcmd/step.rb +22 -0
  155. data/processor/command/show_subcmd/different.rb +26 -0
  156. data/processor/command/show_subcmd/directories.rb +22 -0
  157. data/processor/command/show_subcmd/highlight.rb +24 -0
  158. data/processor/command/show_subcmd/max.rb +27 -0
  159. data/processor/command/show_subcmd/max_subcmd/list.rb +38 -0
  160. data/processor/command/show_subcmd/max_subcmd/stack.rb +36 -0
  161. data/processor/command/show_subcmd/max_subcmd/string.rb +42 -0
  162. data/processor/command/show_subcmd/max_subcmd/width.rb +37 -0
  163. data/processor/command/show_subcmd/reload.rb +18 -0
  164. data/processor/command/show_subcmd/timer.rb +18 -0
  165. data/processor/command/show_subcmd/trace.rb +29 -0
  166. data/processor/command/show_subcmd/trace_subcmd/buffer.rb +65 -0
  167. data/processor/command/show_subcmd/trace_subcmd/print.rb +23 -0
  168. data/processor/command/show_subcmd/version.rb +23 -0
  169. data/processor/command/source.rb +134 -0
  170. data/processor/command/step.rb +81 -0
  171. data/processor/command/tbreak.rb +19 -0
  172. data/processor/command/unalias.rb +44 -0
  173. data/processor/command/undisplay.rb +59 -0
  174. data/processor/command/up.rb +72 -0
  175. data/processor/default.rb +56 -0
  176. data/processor/display.rb +17 -0
  177. data/processor/eval.rb +113 -0
  178. data/processor/eventbuf.rb +105 -0
  179. data/processor/frame.rb +172 -0
  180. data/processor/help.rb +92 -0
  181. data/processor/helper.rb +76 -0
  182. data/processor/hook.rb +134 -0
  183. data/processor/load_cmds.rb +258 -0
  184. data/processor/location.rb +174 -0
  185. data/processor/main.rb +455 -0
  186. data/processor/mock.rb +136 -0
  187. data/processor/msg.rb +61 -0
  188. data/processor/processor.rb +674 -0
  189. data/processor/running.rb +168 -0
  190. data/processor/stepping.rb +18 -0
  191. data/processor/subcmd.rb +161 -0
  192. data/processor/validate.rb +355 -0
  193. data/processor/virtual.rb +34 -0
  194. data/test/data/.gitignore +1 -0
  195. data/test/data/break_bad.cmd +19 -0
  196. data/test/data/break_bad.right +29 -0
  197. data/test/data/break_loop_bug.cmd +5 -0
  198. data/test/data/break_loop_bug.right +15 -0
  199. data/test/data/dollar-0.right +2 -0
  200. data/test/data/dollar-0a.right +2 -0
  201. data/test/data/dollar-0b.right +2 -0
  202. data/test/data/edit.cmd +14 -0
  203. data/test/data/edit.right +24 -0
  204. data/test/data/file-with-space.cmd +6 -0
  205. data/test/data/file-with-space.right +4 -0
  206. data/test/data/printvar.cmd +17 -0
  207. data/test/data/printvar.right +31 -0
  208. data/test/data/raise.cmd +11 -0
  209. data/test/data/raise.right +19 -0
  210. data/test/data/source.cmd +5 -0
  211. data/test/data/source.right +18 -0
  212. data/test/data/stepping-1.9.right +50 -0
  213. data/test/data/stepping.cmd +21 -0
  214. data/test/data/stepping.right +48 -0
  215. data/test/data/trepan8-save.1 +6 -0
  216. data/test/example/bp_loop_issue.rb +3 -0
  217. data/test/example/break-bug.rb +7 -0
  218. data/test/example/brkpt-class-bug.rb +8 -0
  219. data/test/example/classes.rb +11 -0
  220. data/test/example/dollar-0.rb +5 -0
  221. data/test/example/except-bug1.rb +4 -0
  222. data/test/example/except-bug2.rb +7 -0
  223. data/test/example/file with space.rb +1 -0
  224. data/test/example/gcd.rb +18 -0
  225. data/test/example/info-var-bug.rb +47 -0
  226. data/test/example/info-var-bug2.rb +2 -0
  227. data/test/example/null.rb +1 -0
  228. data/test/example/pm-bug.rb +3 -0
  229. data/test/example/pm.rb +11 -0
  230. data/test/example/raise.rb +3 -0
  231. data/test/integration/.gitignore +4 -0
  232. data/test/integration/config.yaml +8 -0
  233. data/test/integration/helper.rb +154 -0
  234. data/test/integration/test-break_bad.rb +26 -0
  235. data/test/integration/test-dollar-0.rb +31 -0
  236. data/test/integration/test-edit.rb +17 -0
  237. data/test/integration/test-file-with-space.rb +26 -0
  238. data/test/integration/test-printvar.rb +17 -0
  239. data/test/integration/test-raise.rb +21 -0
  240. data/test/integration/test-source.rb +16 -0
  241. data/test/integration/test-stepping.rb +24 -0
  242. data/test/unit/.gitignore +1 -0
  243. data/test/unit/cmd-helper.rb +52 -0
  244. data/test/unit/mock-helper.rb +12 -0
  245. data/test/unit/test-app-cmd_parse.rb +97 -0
  246. data/test/unit/test-app-cmd_parser.rb +23 -0
  247. data/test/unit/test-app-complete.rb +39 -0
  248. data/test/unit/test-app-frame.rb +32 -0
  249. data/test/unit/test-app-options.rb +92 -0
  250. data/test/unit/test-app-run.rb +14 -0
  251. data/test/unit/test-app-util.rb +44 -0
  252. data/test/unit/test-base-cmd.rb +45 -0
  253. data/test/unit/test-base-subcmd.rb +57 -0
  254. data/test/unit/test-base-submgr.rb +23 -0
  255. data/test/unit/test-base-subsubcmd.rb +17 -0
  256. data/test/unit/test-cmd-alias.rb +48 -0
  257. data/test/unit/test-cmd-exit.rb +27 -0
  258. data/test/unit/test-cmd-help.rb +104 -0
  259. data/test/unit/test-cmd-kill.rb +46 -0
  260. data/test/unit/test-cmd-source.rb +34 -0
  261. data/test/unit/test-completion.rb +42 -0
  262. data/test/unit/test-intf-user.rb +46 -0
  263. data/test/unit/test-io-input.rb +27 -0
  264. data/test/unit/test-io-tcp.rb +33 -0
  265. data/test/unit/test-io-tcpclient.rb +54 -0
  266. data/test/unit/test-io-tcpfns.rb +17 -0
  267. data/test/unit/test-io-tcpserver.rb +50 -0
  268. data/test/unit/test-proc-eval.rb +36 -0
  269. data/test/unit/test-proc-hook.rb +30 -0
  270. data/test/unit/test-proc-load_cmds.rb +50 -0
  271. data/test/unit/test-proc-location.rb +79 -0
  272. data/test/unit/test-subcmd-help.rb +44 -0
  273. data/trepan8.gemspec +52 -0
  274. metadata +391 -0
@@ -0,0 +1 @@
1
+ /*~
@@ -0,0 +1,54 @@
1
+ # Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
2
+ require 'rubygems'; require 'require_relative'
3
+ require_relative 'base/cmd'
4
+
5
+ class Trepan::Command::AliasCommand < Trepan::Command
6
+
7
+ unless defined?(HELP)
8
+ NAME = File.basename(__FILE__, '.rb')
9
+ HELP = <<-HELP
10
+ #{NAME} ALIAS COMMAND
11
+
12
+ Add an alias for a COMMAND
13
+
14
+ See also 'unalias' and 'show #{NAME}'.
15
+ HELP
16
+
17
+ CATEGORY = 'support'
18
+ MAX_ARGS = 2 # Need at most this many
19
+ NEED_STACK = true
20
+ SHORT_HELP = 'Add an alias for a debugger command'
21
+ end
22
+
23
+ # Run command.
24
+ def run(args)
25
+ if args.size == 1
26
+ @proc.commands['show'].run(%W(show #{NAME}))
27
+ elsif args.size == 2
28
+ @proc.commands['show'].run(%W(show #{NAME} #{args[1]}))
29
+ else
30
+ junk, al, command = args
31
+ old_command = @proc.aliases[al]
32
+ if @proc.commands.member?(command)
33
+ @proc.aliases[al] = command
34
+ if old_command
35
+ msg("Alias '#{al}' for command '#{command}' replaced old " +
36
+ "alias for '#{old_command}'.")
37
+ else
38
+ msg "New alias '#{al}' for command '#{command}' created."
39
+ end
40
+ else
41
+ errmsg "You must alias to a command name, and '#{command}' isn't one."
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ if __FILE__ == $0
48
+ # Demo it.
49
+ require_relative '../mock'
50
+ dbgr, cmd = MockDebugger::setup
51
+ cmd.run %W(#{cmd.name} yy foo)
52
+ cmd.run [cmd.name]
53
+ cmd.run %W(cmd.name yy alias)
54
+ end
@@ -0,0 +1,123 @@
1
+ require 'rubygems'; require 'require_relative'
2
+ require_relative './base/cmd'
3
+
4
+ class Trepan::Command::BacktraceCommand < Trepan::Command
5
+ unless defined?(ALIASES)
6
+ ALIASES = %w(bt where)
7
+ CATEGORY = 'stack'
8
+ MAX_ARGS = 2 # Need at most this many
9
+ NAME = File.basename(__FILE__, '.rb')
10
+ HELP = <<-HELP
11
+ #{NAME}
12
+
13
+ Print the entire stack frame. Each frame is numbered, the most recent
14
+ frame is 0. frame number can be referred to in the "frame" command;
15
+ "up" and "down" add or subtract respectively to frame numbers shown.
16
+ The position of the current frame is marked with -->.
17
+
18
+ See also 'set hidelevel'.
19
+ HELP
20
+ NEED_STACK = true
21
+ SHORT_HELP = 'Show the current call stack'
22
+ end
23
+
24
+ def complete(prefix)
25
+ @proc.frame_complete(prefix, nil)
26
+ end
27
+
28
+ def print_frame(pos, adjust = false, context=@proc.state.context)
29
+ frame = @proc.frame
30
+ file = frame.file
31
+ line = frame.line
32
+ klass = frame.klass
33
+
34
+ frame_num = "#%d " % pos
35
+ opts = {
36
+ :maxwidth => settings[:maxwidth],
37
+ :callstyle => settings[:callstyle]
38
+ }
39
+
40
+ # FIXME There seem to be bugs in showing call if
41
+ # pos != 0
42
+ call_str = (pos == 0) ? @proc.frame.call_string(opts) : ''
43
+
44
+ file_line = "at line %s:%d" % [@proc.canonic_file(file), line]
45
+ str = frame_num
46
+ unless call_str.empty?
47
+ str += call_str + ' '
48
+ if call_str.size + frame_num.size + file_line.size > settings[:maxwidth]
49
+ str += "\n "
50
+ end
51
+ end
52
+ str += file_line
53
+ str
54
+ end
55
+
56
+ # Check if call stack is truncated. This can happen if
57
+ # Trepan.start is not called low enough in the call stack. An
58
+ # array of additional callstack lines from caller is returned if
59
+ # definitely truncated, false if not, and nil if we don't know.
60
+ #
61
+ # We determine truncation based on a passed in sentinal set via
62
+ # caller which can be nil.
63
+ #
64
+ # First we see if we can find our position in caller. If so, then
65
+ # we compare context position to that in caller using sentinal
66
+ # as a place to start ignoring additional caller entries. sentinal
67
+ # is set by rdebug, but if it's not set, i.e. nil then additional
68
+ # entries are presumably ones that we haven't recorded in context
69
+ def truncated_callstack?(context, sentinal=nil, cs=caller)
70
+ frame = @proc.frame
71
+ recorded_size = context.stack_size
72
+ to_find_fl = "#{frame.file}:#{frame.line}"
73
+ top_discard = false
74
+ cs.each_with_index do |fl, i|
75
+ fl.gsub!(/in `.*'$/, '')
76
+ fl.gsub!(/:$/, '')
77
+ if fl == to_find_fl
78
+ top_discard = i
79
+ break
80
+ end
81
+ end
82
+ if top_discard
83
+ cs = cs[top_discard..-1]
84
+ return false unless cs
85
+ return cs unless sentinal
86
+ if cs.size > recorded_size+2 && cs[recorded_size+2] != sentinal
87
+ # caller seems to truncate recursive calls and we don't.
88
+ # See if we can find sentinal in the first 0..recorded_size+1 entries
89
+ return false if cs[0..recorded_size+1].any?{ |f| f==sentinal }
90
+ return cs
91
+ end
92
+ return false
93
+ end
94
+ return nil
95
+ end
96
+
97
+ # This method runs the command
98
+ def run(args)
99
+ save_index = @proc.frame.index
100
+ (0...@proc.stack_size).each do |idx|
101
+ @proc.frame.index = idx
102
+ if idx == save_index
103
+ str = '--> '
104
+ else
105
+ str = ' '
106
+ end
107
+ str += print_frame(idx)
108
+ msg str
109
+ end
110
+ @proc.frame.index = save_index
111
+ if truncated_callstack?(@proc.state.context, Trepan.start_sentinal)
112
+ msg "Warning: saved frames may be incomplete;"
113
+ msg "compare debugger backtrace (bt) with Ruby caller(0)."
114
+ end
115
+ end
116
+ end
117
+
118
+ if __FILE__ == $0
119
+ # Demo it.
120
+ require_relative '../mock'
121
+ dbgr, cmd = MockDebugger::setup
122
+ cmd.run([cmd.name])
123
+ end
@@ -0,0 +1,177 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
3
+ # Base class of all commands. Code common to all commands is here.
4
+ # Note: don't end classname with Command (capital C) since main
5
+ # will think this a command name like QuitCommand
6
+ require 'rubygems'; require 'require_relative'
7
+ require 'columnize'
8
+ require_relative '../../../app/complete'
9
+ ## require 'rubygems'; require 'ruby-debug'; Debugger.start
10
+
11
+ module Trepan
12
+ class Command
13
+ attr_accessor :core, :proc
14
+
15
+ unless defined?(MIN_ARGS)
16
+ MIN_ARGS = 0 # run()'s args array must be at least this many
17
+ MAX_ARGS = nil # run()'s args array must be at least this many
18
+ NEED_STACK = false # We'll say that commands which need a stack
19
+ # to run have to declare that and those that
20
+ # don't don't have to mention it.
21
+ end
22
+
23
+ def initialize(proc)
24
+ @name = my_const(:NAME)
25
+ @proc = proc
26
+ end
27
+
28
+ def category
29
+ my_const(:CATEGORY)
30
+ end
31
+
32
+ # List commands arranged in an aligned columns
33
+ def columnize_commands(commands)
34
+ width = settings[:maxwidth]
35
+ Columnize::columnize(commands, width, ' ' * 4,
36
+ true, true, ' ' * 2).chomp
37
+ end
38
+
39
+ def columnize_numbers(commands)
40
+ width = settings[:maxwidth]
41
+ Columnize::columnize(commands, width, ', ',
42
+ false, false, ' ' * 2).chomp
43
+ end
44
+
45
+ # FIXME: probably there is a way to do the delegation to proc methods
46
+ # without having type it all out.
47
+
48
+ def confirm(message, default)
49
+ @proc.confirm(message, default)
50
+ end
51
+
52
+ def errmsg(message, opts={})
53
+ @proc.errmsg(message, opts)
54
+ end
55
+
56
+ def obj_const(obj, name)
57
+ obj.class.const_get(name)
58
+ end
59
+
60
+ def msg(message, opts={})
61
+ @proc.msg(message, opts)
62
+ end
63
+
64
+ # Convenience short-hand for @dbgr.intf[-1].msg_nocr
65
+ def msg_nocr(msg, opts={})
66
+ @proc.msg_nocr(msg, opts)
67
+ end
68
+
69
+ def my_const(name)
70
+ # Set class constant SHORT_HELP to be the first line of HELP
71
+ # unless it has been defined in the class already.
72
+ # The below was the simplest way I could find to do this since
73
+ # we are the super class but want to set the subclass's constant.
74
+ # defined? didn't seem to work here.
75
+ c = self.class.constants
76
+ if (c.member?('HELP') || c.member?(:HELP)) and
77
+ !(c.member?('SHORT_HELP') || c.member?(:SHORT_HELP))
78
+ help = self.class.const_get(:HELP) || self.class.const_get('HELP')
79
+ short_help = help.split("\n")[0].chomp('.')
80
+ self.class.const_set(:SHORT_HELP, short_help)
81
+ end
82
+ self.class.const_get(name)
83
+ end
84
+
85
+ def name
86
+ self.class.const_get(:NAME)
87
+ end
88
+
89
+ # The method that implements the debugger command.
90
+ def run(*args)
91
+ raise RuntimeError, 'You need to define this method elsewhere'
92
+ end
93
+
94
+ def section(message, opts={})
95
+ ## debugger
96
+ @proc.section(message, opts)
97
+ end
98
+
99
+ def settings
100
+ @proc.settings
101
+ end
102
+
103
+ def short_help
104
+ help_constant_sym = if self.class.constants.member?('SHORT_HELP')
105
+ :SHORT_HELP
106
+ else :HELP
107
+ end
108
+ my_const(help_constant_sym)
109
+ end
110
+
111
+ # Define a method called 'complete' on the singleton class.
112
+ def self.completion(ary)
113
+ self.send(:define_method,
114
+ :complete,
115
+ Proc.new {|prefix|
116
+ Trepan::Complete.complete_token(ary, prefix) })
117
+ end
118
+
119
+ # From reference debugger
120
+ def run_code(str)
121
+ @proc.dbgr.current_frame.run(str)
122
+ end
123
+
124
+ def current_method
125
+ @proc.frame.method
126
+ end
127
+
128
+ def current_frame
129
+ @proc.frame
130
+ end
131
+
132
+ def variables
133
+ @proc.variables
134
+ end
135
+
136
+ def listen(step=false)
137
+ @proc.listen(step)
138
+ end
139
+
140
+ end
141
+ end
142
+ if __FILE__ == $0
143
+ module Trepan
144
+ class CmdProcessor
145
+ def initialize(dbgr)
146
+ end
147
+ def confirm(message, default)
148
+ p ['confirm: ', message, default]
149
+ end
150
+ def errmsg(message, opts)
151
+ p ['err:', message, opts]
152
+ end
153
+ def msg(message, opts)
154
+ p [message, opts]
155
+ end
156
+ def msg_nocr(message, opts)
157
+ p ['nocr: ', message, opts]
158
+ end
159
+ def section(message, opts)
160
+ p ['section: ', message, opts]
161
+ end
162
+ end
163
+ class Command::Test < Trepan::Command
164
+ NAME = 'test'
165
+ CATEGORY = 'testcategory'
166
+ completion %w(a aa ab ba aac)
167
+ end
168
+ end
169
+ proc = Trepan::CmdProcessor.new(nil)
170
+ cmd = Trepan::Command::Test.new(proc)
171
+ %w(confirm errmsg msg msg_nocr section).each do |meth|
172
+ cmd.send(meth, 'test', nil)
173
+ end
174
+ p cmd.complete('aa')
175
+ cmd.instance_variable_set('@completions', %w(aardvark apple))
176
+ p cmd.complete('aa')
177
+ end
@@ -0,0 +1,230 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
3
+ # A base class for debugger subcommands.
4
+ #
5
+ # Note: don't end classname with Command (capital C) since main
6
+ # will think this a command name like QuitCommand
7
+ # ^
8
+
9
+ # Base Class for Trepan subcommands. We pull in some helper
10
+ # functions for command from module cmdfns.
11
+
12
+ require 'rubygems'; require 'require_relative'
13
+ require_relative 'cmd'
14
+
15
+ module Trepan
16
+
17
+ class Subcommand < Command
18
+
19
+ NotImplementedMessage =
20
+ "This method must be overridden in a subclass" unless
21
+ defined?(NotImplementedMessage)
22
+
23
+ attr_reader :name
24
+
25
+ unless defined?(IN_LIST)
26
+ IN_LIST = true # Show item in help list of commands
27
+ RUN_CMD = true # Run subcommand for those subcommands like "show"
28
+ # which append current settings to list output.
29
+ MIN_ABBREV = 1
30
+ NEED_STACK = false
31
+ NAME = 'your_command_name'
32
+ end
33
+
34
+
35
+ # cmd contains the command object that this
36
+ # command is invoked through. A debugger field gives access to
37
+ # the stack frame and I/O.
38
+ def initialize(cmd)
39
+ @cmd = cmd
40
+
41
+ # Convenience class access. We don't expect that any of these
42
+ # will change over the course of the program execution like
43
+ # errmsg(), msg(), and msg_nocr() might. (See the note below
44
+ # on these latter 3 methods.)
45
+ #
46
+ @core = cmd.core
47
+ @proc = cmd.proc
48
+ # @dbgr = cmd.dbgr
49
+
50
+ # By default the name of the subcommand will be the name of the
51
+ # last part of module (e.g. "args" in "info.args" or "basename"
52
+ # in "shows.basename"). However it *is* possible for one to change
53
+ # that -- perhaps one may want to put several subcommands into
54
+ # a single file. So in those cases, one will have to set @name
55
+ # accordingly by other means.
56
+ @name = my_const(:NAME).to_sym
57
+
58
+ end
59
+
60
+ # Convenience short-hand for @proc.confirm
61
+ def confirm(msg, default=false)
62
+ return(@proc.confirm(msg, default))
63
+ end
64
+
65
+ def prefix
66
+ my_const('PREFIX')
67
+ end
68
+
69
+ # Set a Boolean-valued debugger setting.
70
+ def run_set_bool(args, default=true)
71
+ onoff_arg = args.size < 3 ? 'on' : args[2]
72
+ begin
73
+ settings[subcmd_setting_key] = @proc.get_onoff(onoff_arg)
74
+ run_show_bool
75
+ rescue NameError, TypeError
76
+ end
77
+ end
78
+
79
+ # set an Integer-valued debugger setting.
80
+ def run_set_int(arg, msg_on_error, min_value=nil, max_value=nil)
81
+ if arg.strip.empty?
82
+ errmsg('You need to supply a number.')
83
+ return
84
+ end
85
+ val = @proc.get_an_int(arg,
86
+ :max_value => max_value,
87
+ :min_value => min_value,
88
+ :msg_on_error => msg_on_error
89
+ )
90
+ if val
91
+ settings[subcmd_setting_key] = val
92
+ run_show_int
93
+ end
94
+ end
95
+
96
+ # Generic subcommand showing a boolean-valued debugger setting.
97
+ def run_show_bool(what=nil)
98
+ val = show_onoff(settings[subcmd_setting_key])
99
+ what = @name unless what
100
+ msg("%s is %s." % [what, val])
101
+ end
102
+
103
+ # Generic subcommand integer value display
104
+ def run_show_int(what=nil)
105
+ val = settings[subcmd_setting_key]
106
+ what = self.class.const_get(:PREFIX)[1..-1].join(' ') unless what
107
+ msg("%s is %d." % [what, val])
108
+ end
109
+
110
+ # Generic subcommand value display. Pass in a hash which may
111
+ # which optionally contain:
112
+ #
113
+ # :name - the String name of key in settings to use. If :value
114
+ # (described below) is set, then setting :name does
115
+ # nothing.
116
+ #
117
+ # :what - the String name of what we are showing. If none is
118
+ # given, then we use the part of the SHORT_HELP string.
119
+ #
120
+ # :value - a String value associated with "what" above. If none
121
+ # is given, then we pick up the value from settings.
122
+ #
123
+ def run_show_val(opts={})
124
+ what = opts.member?(:what) ? opts[:what] : string_in_show
125
+ name = opts.member?(:name) ? opts[:name] : @name
126
+ val = opts.member?(:value) ? opts[:value] : settings[name]
127
+ msg("%s is %s." % [what, val])
128
+ end
129
+
130
+ def save_command_from_settings
131
+ ["#{subcmd_prefix_string} #{settings[subcmd_setting_key]}"]
132
+ end
133
+
134
+ def settings
135
+ @proc.settings
136
+ end
137
+
138
+ def subcmd_prefix_string
139
+ self.class.const_get(:PREFIX).join(' ')
140
+ end
141
+
142
+ def subcmd_setting_key
143
+ self.class.const_get(:PREFIX)[1..-1].join('').to_sym
144
+ end
145
+
146
+ # Return 'on' for true and 'off' for false, and ?? for anything else.
147
+ def show_onoff(bool)
148
+ case(bool)
149
+ when true; return 'on'
150
+ when false; return 'off'
151
+ when nil; return 'unset'
152
+ else return '??'
153
+ end
154
+ end
155
+
156
+ def string_in_show
157
+ my_const(:SHORT_HELP)['Show '.size .. -1].capitalize
158
+ end
159
+
160
+ def summary_help(subcmd_name)
161
+ msg_nocr("%-12s: %s" % [subcmd_name, my_const(:SHORT_HELP)])
162
+ end
163
+ end
164
+
165
+ class SetBoolSubcommand < Subcommand
166
+ completion %w(on off)
167
+
168
+ def run(args)
169
+ run_set_bool(args)
170
+ end
171
+
172
+ def save_command
173
+ val = settings[subcmd_setting_key] ? 'on' : 'off'
174
+ ["#{subcmd_prefix_string} #{val}"]
175
+ end
176
+ end
177
+
178
+ class ShowBoolSubcommand < Subcommand
179
+ def run(args)
180
+ run_show_bool(string_in_show)
181
+ end
182
+ end
183
+
184
+ class ShowIntSubcommand < Subcommand
185
+ def run(args)
186
+ doc =
187
+ if self.respond_to?(:short_help)
188
+ short_help
189
+ else
190
+ my_const(:HELP)[5..-2].capitalize
191
+ end
192
+ run_show_int(doc)
193
+ end
194
+ end
195
+
196
+ end
197
+
198
+ module Trepanning
199
+ module Subcommand
200
+ module_function
201
+ def set_name_prefix(__file__, klass)
202
+ dirname = File.basename(File.dirname(File.expand_path(__file__)))
203
+ name = File.basename(__file__, '.rb')
204
+ klass.const_set(:NAME, name)
205
+ prefix = klass.const_set(:PREFIX, %W(#{dirname[0...-'_subcmd'.size]} #{name}))
206
+ klass.const_set(:CMD, prefix.join(' '))
207
+ end
208
+ end
209
+ end
210
+
211
+ if __FILE__ == $0
212
+ # Demo it.
213
+ require_relative '../../mock'
214
+ dbgr = MockDebugger::MockDebugger.new
215
+ # cmds = dbgr.core.processor.commands
216
+ # p cmds.keys
217
+ # subcmd = Trepan::Subcommand.new(cmds['exit'])
218
+ # def subcmd.msg(message)
219
+ # puts message
220
+ # end
221
+ # def subcmd.errmsg(message)
222
+ # puts message
223
+ # end
224
+ # p subcmd.settings
225
+ # p subcmd.show_onoff(subcmd.settings[:autoeval])
226
+ # subcmd.run_set_int('', 'Just a test')
227
+ class Trepan::Subcommand::Foo < Trepan::Subcommand
228
+ Trepanning::Subcommand.set_name_prefix(__FILE__, self)
229
+ end
230
+ end