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.
- data/.gitignore +3 -0
- data/CHANGES +34 -0
- data/ChangeLog +875 -0
- data/README.textile +59 -0
- data/Rakefile +215 -0
- data/app/.gitignore +1 -0
- data/app/cmd_parse.kpeg +241 -0
- data/app/cmd_parse.rb +212 -0
- data/app/cmd_parser.rb +1948 -0
- data/app/complete.rb +79 -0
- data/app/default.rb +90 -0
- data/app/display.rb +148 -0
- data/app/eventbuffer.rb +147 -0
- data/app/frame.rb +166 -0
- data/app/irb.rb +114 -0
- data/app/options.rb +200 -0
- data/app/run.rb +74 -0
- data/app/util.rb +65 -0
- data/bin/.gitignore +1 -0
- data/bin/trepan8 +115 -0
- data/data/.gitignore +1 -0
- data/data/irbrc +41 -0
- data/interface/.gitignore +1 -0
- data/interface/base_intf.rb +109 -0
- data/interface/client.rb +82 -0
- data/interface/comcodes.rb +20 -0
- data/interface/script.rb +110 -0
- data/interface/server.rb +147 -0
- data/interface/user.rb +165 -0
- data/io/base_io.rb +148 -0
- data/io/input.rb +158 -0
- data/io/null_output.rb +46 -0
- data/io/string_array.rb +156 -0
- data/io/tcpclient.rb +129 -0
- data/io/tcpfns.rb +33 -0
- data/io/tcpserver.rb +141 -0
- data/lib/debugger.rb +8 -0
- data/lib/trepanning.rb +283 -0
- data/processor/.gitignore +1 -0
- data/processor/command-ruby-debug/breakpoints.rb +155 -0
- data/processor/command-ruby-debug/catchpoint.rb +55 -0
- data/processor/command-ruby-debug/condition.rb +49 -0
- data/processor/command-ruby-debug/control.rb +31 -0
- data/processor/command-ruby-debug/display.rb +120 -0
- data/processor/command-ruby-debug/enable.rb +202 -0
- data/processor/command-ruby-debug/frame.rb +199 -0
- data/processor/command-ruby-debug/help.rb +63 -0
- data/processor/command-ruby-debug/info.rb +359 -0
- data/processor/command-ruby-debug/method.rb +84 -0
- data/processor/command-ruby-debug/reload.rb +40 -0
- data/processor/command-ruby-debug/save.rb +90 -0
- data/processor/command-ruby-debug/set.rb +237 -0
- data/processor/command-ruby-debug/show.rb +251 -0
- data/processor/command-ruby-debug/source.rb +36 -0
- data/processor/command-ruby-debug/threads.rb +189 -0
- data/processor/command-ruby-debug/trace.rb +57 -0
- data/processor/command-ruby-debug/variables.rb +199 -0
- data/processor/command.rb +270 -0
- data/processor/command/.gitignore +1 -0
- data/processor/command/alias.rb +54 -0
- data/processor/command/backtrace.rb +123 -0
- data/processor/command/base/cmd.rb +177 -0
- data/processor/command/base/subcmd.rb +230 -0
- data/processor/command/base/submgr.rb +188 -0
- data/processor/command/base/subsubcmd.rb +128 -0
- data/processor/command/base/subsubmgr.rb +199 -0
- data/processor/command/break.rb +114 -0
- data/processor/command/catch.rb +71 -0
- data/processor/command/complete.rb +39 -0
- data/processor/command/continue.rb +57 -0
- data/processor/command/directory.rb +50 -0
- data/processor/command/disable.rb +85 -0
- data/processor/command/display.rb +78 -0
- data/processor/command/down.rb +54 -0
- data/processor/command/edit.rb +79 -0
- data/processor/command/enable.rb +48 -0
- data/processor/command/eval.rb +90 -0
- data/processor/command/exit.rb +66 -0
- data/processor/command/finish.rb +59 -0
- data/processor/command/frame.rb +97 -0
- data/processor/command/help.rb +230 -0
- data/processor/command/help/.gitignore +1 -0
- data/processor/command/help/README +10 -0
- data/processor/command/help/command.txt +58 -0
- data/processor/command/help/examples.txt +16 -0
- data/processor/command/help/filename.txt +40 -0
- data/processor/command/help/location.txt +37 -0
- data/processor/command/help/suffixes.txt +17 -0
- data/processor/command/info.rb +28 -0
- data/processor/command/info_subcmd/.gitignore +1 -0
- data/processor/command/info_subcmd/args.rb +39 -0
- data/processor/command/info_subcmd/breakpoints.rb +80 -0
- data/processor/command/info_subcmd/catch.rb +36 -0
- data/processor/command/info_subcmd/files.rb +39 -0
- data/processor/command/info_subcmd/globals.rb +64 -0
- data/processor/command/info_subcmd/line.rb +30 -0
- data/processor/command/info_subcmd/locals.rb +69 -0
- data/processor/command/info_subcmd/macro.rb +62 -0
- data/processor/command/info_subcmd/program.rb +51 -0
- data/processor/command/info_subcmd/ruby.rb +57 -0
- data/processor/command/info_subcmd/source.rb +74 -0
- data/processor/command/info_subcmd/stack.rb +25 -0
- data/processor/command/info_subcmd/threads.rb +75 -0
- data/processor/command/kill.rb +78 -0
- data/processor/command/list.rb +117 -0
- data/processor/command/macro.rb +68 -0
- data/processor/command/next.rb +79 -0
- data/processor/command/parsetree.rb +56 -0
- data/processor/command/pp.rb +40 -0
- data/processor/command/pr.rb +37 -0
- data/processor/command/ps.rb +40 -0
- data/processor/command/restart.rb +86 -0
- data/processor/command/save.rb +58 -0
- data/processor/command/set.rb +47 -0
- data/processor/command/set_subcmd/.gitignore +1 -0
- data/processor/command/set_subcmd/abbrev.rb +25 -0
- data/processor/command/set_subcmd/auto.rb +27 -0
- data/processor/command/set_subcmd/auto_subcmd/.gitignore +1 -0
- data/processor/command/set_subcmd/auto_subcmd/eval.rb +53 -0
- data/processor/command/set_subcmd/auto_subcmd/irb.rb +33 -0
- data/processor/command/set_subcmd/auto_subcmd/list.rb +33 -0
- data/processor/command/set_subcmd/basename.rb +25 -0
- data/processor/command/set_subcmd/callstyle.rb +46 -0
- data/processor/command/set_subcmd/confirm.rb +24 -0
- data/processor/command/set_subcmd/debug.rb +47 -0
- data/processor/command/set_subcmd/different.rb +61 -0
- data/processor/command/set_subcmd/highlight.rb +43 -0
- data/processor/command/set_subcmd/max.rb +26 -0
- data/processor/command/set_subcmd/max_subcmd/list.rb +49 -0
- data/processor/command/set_subcmd/max_subcmd/stack.rb +50 -0
- data/processor/command/set_subcmd/max_subcmd/string.rb +76 -0
- data/processor/command/set_subcmd/max_subcmd/width.rb +49 -0
- data/processor/command/set_subcmd/reload.rb +42 -0
- data/processor/command/set_subcmd/timer.rb +58 -0
- data/processor/command/set_subcmd/trace.rb +37 -0
- data/processor/command/set_subcmd/trace_subcmd/buffer.rb +42 -0
- data/processor/command/set_subcmd/trace_subcmd/print.rb +41 -0
- data/processor/command/shell.rb +139 -0
- data/processor/command/show.rb +39 -0
- data/processor/command/show_subcmd/.gitignore +1 -0
- data/processor/command/show_subcmd/abbrev.rb +20 -0
- data/processor/command/show_subcmd/alias.rb +46 -0
- data/processor/command/show_subcmd/args.rb +34 -0
- data/processor/command/show_subcmd/auto.rb +28 -0
- data/processor/command/show_subcmd/auto_subcmd/eval.rb +27 -0
- data/processor/command/show_subcmd/auto_subcmd/irb.rb +23 -0
- data/processor/command/show_subcmd/auto_subcmd/list.rb +22 -0
- data/processor/command/show_subcmd/basename.rb +20 -0
- data/processor/command/show_subcmd/callstyle.rb +22 -0
- data/processor/command/show_subcmd/confirm.rb +18 -0
- data/processor/command/show_subcmd/debug.rb +26 -0
- data/processor/command/show_subcmd/debug_subcmd/dbgr.rb +21 -0
- data/processor/command/show_subcmd/debug_subcmd/skip.rb +22 -0
- data/processor/command/show_subcmd/debug_subcmd/step.rb +22 -0
- data/processor/command/show_subcmd/different.rb +26 -0
- data/processor/command/show_subcmd/directories.rb +22 -0
- data/processor/command/show_subcmd/highlight.rb +24 -0
- data/processor/command/show_subcmd/max.rb +27 -0
- data/processor/command/show_subcmd/max_subcmd/list.rb +38 -0
- data/processor/command/show_subcmd/max_subcmd/stack.rb +36 -0
- data/processor/command/show_subcmd/max_subcmd/string.rb +42 -0
- data/processor/command/show_subcmd/max_subcmd/width.rb +37 -0
- data/processor/command/show_subcmd/reload.rb +18 -0
- data/processor/command/show_subcmd/timer.rb +18 -0
- data/processor/command/show_subcmd/trace.rb +29 -0
- data/processor/command/show_subcmd/trace_subcmd/buffer.rb +65 -0
- data/processor/command/show_subcmd/trace_subcmd/print.rb +23 -0
- data/processor/command/show_subcmd/version.rb +23 -0
- data/processor/command/source.rb +134 -0
- data/processor/command/step.rb +81 -0
- data/processor/command/tbreak.rb +19 -0
- data/processor/command/unalias.rb +44 -0
- data/processor/command/undisplay.rb +59 -0
- data/processor/command/up.rb +72 -0
- data/processor/default.rb +56 -0
- data/processor/display.rb +17 -0
- data/processor/eval.rb +113 -0
- data/processor/eventbuf.rb +105 -0
- data/processor/frame.rb +172 -0
- data/processor/help.rb +92 -0
- data/processor/helper.rb +76 -0
- data/processor/hook.rb +134 -0
- data/processor/load_cmds.rb +258 -0
- data/processor/location.rb +174 -0
- data/processor/main.rb +455 -0
- data/processor/mock.rb +136 -0
- data/processor/msg.rb +61 -0
- data/processor/processor.rb +674 -0
- data/processor/running.rb +168 -0
- data/processor/stepping.rb +18 -0
- data/processor/subcmd.rb +161 -0
- data/processor/validate.rb +355 -0
- data/processor/virtual.rb +34 -0
- data/test/data/.gitignore +1 -0
- data/test/data/break_bad.cmd +19 -0
- data/test/data/break_bad.right +29 -0
- data/test/data/break_loop_bug.cmd +5 -0
- data/test/data/break_loop_bug.right +15 -0
- data/test/data/dollar-0.right +2 -0
- data/test/data/dollar-0a.right +2 -0
- data/test/data/dollar-0b.right +2 -0
- data/test/data/edit.cmd +14 -0
- data/test/data/edit.right +24 -0
- data/test/data/file-with-space.cmd +6 -0
- data/test/data/file-with-space.right +4 -0
- data/test/data/printvar.cmd +17 -0
- data/test/data/printvar.right +31 -0
- data/test/data/raise.cmd +11 -0
- data/test/data/raise.right +19 -0
- data/test/data/source.cmd +5 -0
- data/test/data/source.right +18 -0
- data/test/data/stepping-1.9.right +50 -0
- data/test/data/stepping.cmd +21 -0
- data/test/data/stepping.right +48 -0
- data/test/data/trepan8-save.1 +6 -0
- data/test/example/bp_loop_issue.rb +3 -0
- data/test/example/break-bug.rb +7 -0
- data/test/example/brkpt-class-bug.rb +8 -0
- data/test/example/classes.rb +11 -0
- data/test/example/dollar-0.rb +5 -0
- data/test/example/except-bug1.rb +4 -0
- data/test/example/except-bug2.rb +7 -0
- data/test/example/file with space.rb +1 -0
- data/test/example/gcd.rb +18 -0
- data/test/example/info-var-bug.rb +47 -0
- data/test/example/info-var-bug2.rb +2 -0
- data/test/example/null.rb +1 -0
- data/test/example/pm-bug.rb +3 -0
- data/test/example/pm.rb +11 -0
- data/test/example/raise.rb +3 -0
- data/test/integration/.gitignore +4 -0
- data/test/integration/config.yaml +8 -0
- data/test/integration/helper.rb +154 -0
- data/test/integration/test-break_bad.rb +26 -0
- data/test/integration/test-dollar-0.rb +31 -0
- data/test/integration/test-edit.rb +17 -0
- data/test/integration/test-file-with-space.rb +26 -0
- data/test/integration/test-printvar.rb +17 -0
- data/test/integration/test-raise.rb +21 -0
- data/test/integration/test-source.rb +16 -0
- data/test/integration/test-stepping.rb +24 -0
- data/test/unit/.gitignore +1 -0
- data/test/unit/cmd-helper.rb +52 -0
- data/test/unit/mock-helper.rb +12 -0
- data/test/unit/test-app-cmd_parse.rb +97 -0
- data/test/unit/test-app-cmd_parser.rb +23 -0
- data/test/unit/test-app-complete.rb +39 -0
- data/test/unit/test-app-frame.rb +32 -0
- data/test/unit/test-app-options.rb +92 -0
- data/test/unit/test-app-run.rb +14 -0
- data/test/unit/test-app-util.rb +44 -0
- data/test/unit/test-base-cmd.rb +45 -0
- data/test/unit/test-base-subcmd.rb +57 -0
- data/test/unit/test-base-submgr.rb +23 -0
- data/test/unit/test-base-subsubcmd.rb +17 -0
- data/test/unit/test-cmd-alias.rb +48 -0
- data/test/unit/test-cmd-exit.rb +27 -0
- data/test/unit/test-cmd-help.rb +104 -0
- data/test/unit/test-cmd-kill.rb +46 -0
- data/test/unit/test-cmd-source.rb +34 -0
- data/test/unit/test-completion.rb +42 -0
- data/test/unit/test-intf-user.rb +46 -0
- data/test/unit/test-io-input.rb +27 -0
- data/test/unit/test-io-tcp.rb +33 -0
- data/test/unit/test-io-tcpclient.rb +54 -0
- data/test/unit/test-io-tcpfns.rb +17 -0
- data/test/unit/test-io-tcpserver.rb +50 -0
- data/test/unit/test-proc-eval.rb +36 -0
- data/test/unit/test-proc-hook.rb +30 -0
- data/test/unit/test-proc-load_cmds.rb +50 -0
- data/test/unit/test-proc-location.rb +79 -0
- data/test/unit/test-subcmd-help.rb +44 -0
- data/trepan8.gemspec +52 -0
- 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
|