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
data/processor/help.rb
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
|
|
2
|
+
module Trepan
|
|
3
|
+
# class SubHelp
|
|
4
|
+
# def initialize(name, dir)
|
|
5
|
+
# @name = name
|
|
6
|
+
# @dir = dir
|
|
7
|
+
# load_sub_help_files(dir)
|
|
8
|
+
# end
|
|
9
|
+
|
|
10
|
+
# def load_sub_help_files(dir)
|
|
11
|
+
# Dir.glob(dir, '*.txt').each do |txt|
|
|
12
|
+
# basename = File.basename(txt, '.txt')
|
|
13
|
+
# @list << basename
|
|
14
|
+
# end
|
|
15
|
+
# end if File.directory?(dir)
|
|
16
|
+
|
|
17
|
+
# def summary_help
|
|
18
|
+
# section "List of #{@name} help"
|
|
19
|
+
# msg @list
|
|
20
|
+
# end
|
|
21
|
+
# end
|
|
22
|
+
|
|
23
|
+
module Help
|
|
24
|
+
|
|
25
|
+
def abbrev_stringify(name, min_abbrev)
|
|
26
|
+
"(#{name[0..min_abbrev-1]})#{name[min_abbrev..-1]}"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def summary_help(subcmd)
|
|
30
|
+
# Set class constant SHORT_HELP to be the first line of HELP
|
|
31
|
+
# unless it has been defined in the class already.
|
|
32
|
+
# The below was the simplest way I could find to do this since
|
|
33
|
+
# we are the super class but want to set the subclass's constant.
|
|
34
|
+
# defined? didn't seem to work here.
|
|
35
|
+
c = subcmd.class.constants
|
|
36
|
+
if c.member?('HELP') and !c.member?('SHORT_HELP')
|
|
37
|
+
short_help = subcmd.class.const_get('HELP').split("\n")[0].chomp('.')
|
|
38
|
+
subcmd.class.const_set(:SHORT_HELP, short_help)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
' %-12s -- %s' %
|
|
42
|
+
[abbrev_stringify(obj_const(subcmd, :NAME),
|
|
43
|
+
obj_const(subcmd, :MIN_ABBREV)),
|
|
44
|
+
obj_const(subcmd, :SHORT_HELP)]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# We were given cmd without a subcommand; cmd is something
|
|
48
|
+
# like "show", "info" or "set". Generally this means list
|
|
49
|
+
# all of the subcommands.
|
|
50
|
+
def summary_list(name, subcmds)
|
|
51
|
+
msg "List of #{name} commands (with minimum abbreviation in parenthesis):"
|
|
52
|
+
subcmds.list.each do |subcmd_name|
|
|
53
|
+
# Some commands have lots of output.
|
|
54
|
+
# they are excluded here because 'in_list' is false.
|
|
55
|
+
msg summary_help(subcmds.subcmds[subcmd_name])
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# Error message when subcommand asked for but doesn't exist
|
|
61
|
+
def undefined_subcmd(cmd, subcmd)
|
|
62
|
+
errmsg(('Undefined "%s" subcommand: "%s". ' +
|
|
63
|
+
"Try \"help %s *.\"") % [cmd, subcmd, cmd])
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
if __FILE__ == $0
|
|
70
|
+
class TestClass
|
|
71
|
+
include Trepan::Help
|
|
72
|
+
HELP = 'TestClass HELP.
|
|
73
|
+
|
|
74
|
+
Long description goes here.'
|
|
75
|
+
MIN_ABBREV = 1
|
|
76
|
+
NAME = File.basename(__FILE__)
|
|
77
|
+
def obj_const(obj, name)
|
|
78
|
+
obj.class.const_get(name)
|
|
79
|
+
end
|
|
80
|
+
def msg(mess)
|
|
81
|
+
puts mess
|
|
82
|
+
end
|
|
83
|
+
def errmsg(mess)
|
|
84
|
+
puts "***#{mess}"
|
|
85
|
+
end
|
|
86
|
+
def initialize
|
|
87
|
+
puts summary_help(self)
|
|
88
|
+
undefined_subcmd('foo', 'bar')
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
TestClass.new
|
|
92
|
+
end
|
data/processor/helper.rb
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
module Trepan
|
|
2
|
+
|
|
3
|
+
def inside_emacs?
|
|
4
|
+
ENV['EMACS'] || ENV['INSIDE_EMACS']
|
|
5
|
+
end
|
|
6
|
+
module_function :inside_emacs?
|
|
7
|
+
|
|
8
|
+
module ParseFunctions
|
|
9
|
+
Position_regexp = '(?:(\d+)|(.+?)[:.#]([^.:\s]+))' unless
|
|
10
|
+
defined? Position_regexp
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# Parse 'str' of command 'cmd' as an integer between
|
|
14
|
+
# min and max. If either min or max is nil, that
|
|
15
|
+
# value has no bound.
|
|
16
|
+
def get_int(str, cmd, min=nil, max=nil, default=1)
|
|
17
|
+
return default unless str
|
|
18
|
+
begin
|
|
19
|
+
int = Integer(str)
|
|
20
|
+
if min and int < min
|
|
21
|
+
print "%s argument '%s' needs to at least %s.\n" % [cmd, str, min]
|
|
22
|
+
return nil
|
|
23
|
+
elsif max and int > max
|
|
24
|
+
print "%s argument '%s' needs to at most %s.\n" % [cmd, str, max]
|
|
25
|
+
return nil
|
|
26
|
+
end
|
|
27
|
+
return int
|
|
28
|
+
rescue
|
|
29
|
+
print "%s argument '%s' needs to be a number.\n" % [cmd, str]
|
|
30
|
+
return nil
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Return true if arg is 'on' or 1 and false arg is 'off' or 0.
|
|
35
|
+
# Any other value raises RuntimeError.
|
|
36
|
+
def get_onoff(arg, default=nil, print_error=true)
|
|
37
|
+
if arg.nil? or arg == ''
|
|
38
|
+
if default.nil?
|
|
39
|
+
if print_error
|
|
40
|
+
print "Expecting 'on', 1, 'off', or 0. Got nothing.\n"
|
|
41
|
+
raise RuntimeError
|
|
42
|
+
end
|
|
43
|
+
return default
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
case arg.downcase
|
|
47
|
+
when '1', 'on'
|
|
48
|
+
return true
|
|
49
|
+
when '0', 'off'
|
|
50
|
+
return false
|
|
51
|
+
else
|
|
52
|
+
if print_error
|
|
53
|
+
print "Expecting 'on', 1, 'off', or 0. Got: %s.\n" % arg.to_s
|
|
54
|
+
raise RuntimeError
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Return 'on' or 'off' for supplied parameter. The parmeter should
|
|
60
|
+
# be true, false or nil.
|
|
61
|
+
def show_onoff(bool)
|
|
62
|
+
if not [TrueClass, FalseClass, NilClass].member?(bool.class)
|
|
63
|
+
return "??"
|
|
64
|
+
end
|
|
65
|
+
return bool ? 'on' : 'off'
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Return true if code is syntactically correct for Ruby.
|
|
69
|
+
def syntax_valid?(code)
|
|
70
|
+
eval("BEGIN {return true}\n#{code}", nil, "", 0)
|
|
71
|
+
rescue Exception
|
|
72
|
+
false
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
end
|
|
76
|
+
end
|
data/processor/hook.rb
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
|
|
2
|
+
require 'rubygems'; require 'require_relative'
|
|
3
|
+
require_relative 'virtual'
|
|
4
|
+
|
|
5
|
+
class Trepan::CmdProcessor < Trepan::VirtualCmdProcessor
|
|
6
|
+
# Command processor hooks.
|
|
7
|
+
attr_reader :autodis_hook
|
|
8
|
+
attr_reader :autoirb_hook
|
|
9
|
+
attr_reader :autolist_hook
|
|
10
|
+
attr_reader :debug_dbgr_hook
|
|
11
|
+
attr_reader :display_hook
|
|
12
|
+
attr_reader :timer_hook
|
|
13
|
+
attr_reader :trace_hook
|
|
14
|
+
attr_reader :tracebuf_hook
|
|
15
|
+
attr_reader :unconditional_prehooks
|
|
16
|
+
attr_reader :cmdloop_posthooks
|
|
17
|
+
attr_reader :cmdloop_prehooks
|
|
18
|
+
|
|
19
|
+
# Used to time how long a debugger action takes
|
|
20
|
+
attr_accessor :time_last
|
|
21
|
+
|
|
22
|
+
class Hook
|
|
23
|
+
attr_accessor :list
|
|
24
|
+
|
|
25
|
+
def initialize(list=[])
|
|
26
|
+
@list = list
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def delete_by_name(delete_name)
|
|
30
|
+
@list.delete_if {|hook_name, priority, hook| hook_name == delete_name}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def empty?
|
|
34
|
+
@list.empty?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def insert(priority, name, hook)
|
|
38
|
+
insert_loc = @list.size # at end
|
|
39
|
+
@list.each_with_index do |entry, index|
|
|
40
|
+
n, p, h = entry
|
|
41
|
+
if priority > p
|
|
42
|
+
insert_loc = index
|
|
43
|
+
break
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
@list.insert(insert_loc, [name, priority, hook])
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def insert_if_new(priority, name, hook)
|
|
50
|
+
insert(priority, name, hook) unless
|
|
51
|
+
@list.find {|try_name, try_priority, try_hook| try_name == name}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Run each function in `hooks' with args
|
|
55
|
+
def run(*args)
|
|
56
|
+
@list.each do |name, priority, hook|
|
|
57
|
+
hook.call(name, *args)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Could add delete_at and delete if necessary.
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def hook_initialize(commands)
|
|
65
|
+
@cmdloop_posthooks = Hook.new
|
|
66
|
+
@cmdloop_prehooks = Hook.new
|
|
67
|
+
@unconditional_prehooks = Hook.new
|
|
68
|
+
|
|
69
|
+
irb_cmd = commands['irb']
|
|
70
|
+
@autoirb_hook = ['autoirb',
|
|
71
|
+
Proc.new{|*args| irb_cmd.run(['irb']) if irb_cmd}]
|
|
72
|
+
|
|
73
|
+
@debug_dbgr_hook = ['dbgdbgr',
|
|
74
|
+
Proc.new{|*args|
|
|
75
|
+
if settings[:debugdbgr]
|
|
76
|
+
$trepan_cmdproc = self
|
|
77
|
+
$trepan_frame = @frame
|
|
78
|
+
else
|
|
79
|
+
$trepan_cmdproc = nil
|
|
80
|
+
$trepan_frame = nil
|
|
81
|
+
end}]
|
|
82
|
+
|
|
83
|
+
display_cmd = commands['display']
|
|
84
|
+
@display_hook = ['display',
|
|
85
|
+
Proc.new{|*args| display_cmd.run(['display']) if display_cmd}]
|
|
86
|
+
|
|
87
|
+
# FIXME: generalize for any command run
|
|
88
|
+
dis_cmd = commands['disassemble']
|
|
89
|
+
@autodis_hook = ['autodis',
|
|
90
|
+
Proc.new{|*args| dis_cmd.run(['disassemble']) if dis_cmd}]
|
|
91
|
+
|
|
92
|
+
list_cmd = commands['list']
|
|
93
|
+
@autolist_hook = ['autolist',
|
|
94
|
+
Proc.new{|*args| list_cmd.run(['list']) if list_cmd}]
|
|
95
|
+
|
|
96
|
+
@timer_hook = ['timer',
|
|
97
|
+
Proc.new{|*args|
|
|
98
|
+
now = Time.now
|
|
99
|
+
msg("%g seconds" %
|
|
100
|
+
(now - @time_last)) if @time_last
|
|
101
|
+
@time_last = now
|
|
102
|
+
}]
|
|
103
|
+
@timer_posthook = ['timer', Proc.new{|*args| @time_last = Time.now}]
|
|
104
|
+
@trace_hook = ['trace',
|
|
105
|
+
Proc.new{|*args| print_location}]
|
|
106
|
+
@tracebuf_hook = ['tracebuffer',
|
|
107
|
+
Proc.new{|*args| @eventbuf.append(@event, @frame,
|
|
108
|
+
nil)}]
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
if __FILE__ == $0
|
|
113
|
+
# Demo it.
|
|
114
|
+
hooks = Trepan::CmdProcessor::Hook.new
|
|
115
|
+
hooks.run(5)
|
|
116
|
+
hook1 = Proc.new {|name, a| puts "#{name} called with #{a}"}
|
|
117
|
+
hooks = Trepan::CmdProcessor::Hook.new()
|
|
118
|
+
hooks.insert(-1, 'hook1', hook1)
|
|
119
|
+
p hooks.list
|
|
120
|
+
hooks.insert_if_new(-1, 'hook1', hook1)
|
|
121
|
+
puts '-' * 30
|
|
122
|
+
p hooks.list
|
|
123
|
+
hooks.run(10)
|
|
124
|
+
puts '-' * 30
|
|
125
|
+
hooks.insert(-1, 'hook2', hook1)
|
|
126
|
+
hooks.run(20)
|
|
127
|
+
puts '-' * 30
|
|
128
|
+
hooks.delete_by_name('hook2')
|
|
129
|
+
hooks.run(30)
|
|
130
|
+
puts '-' * 30
|
|
131
|
+
hooks.delete_by_name('hook1')
|
|
132
|
+
hooks.run(30)
|
|
133
|
+
puts '-' * 30
|
|
134
|
+
end
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
|
|
3
|
+
require 'tmpdir'
|
|
4
|
+
|
|
5
|
+
# Part of Trepan::CmdProcess that loads up debugger commands from
|
|
6
|
+
# builtin and user directories.
|
|
7
|
+
# Sets @commands, @aliases, @macros
|
|
8
|
+
require 'rubygems'; require 'require_relative'
|
|
9
|
+
require_relative '../app/complete'
|
|
10
|
+
require_relative 'virtual'
|
|
11
|
+
class Trepan::CmdProcessor < Trepan::VirtualCmdProcessor
|
|
12
|
+
|
|
13
|
+
attr_reader :aliases # Hash[String] of command names
|
|
14
|
+
# indexed by alias name
|
|
15
|
+
attr_reader :commands # Hash[String] of command objects
|
|
16
|
+
# indexed by name
|
|
17
|
+
attr_reader :macros # Hash[String] of Proc objects
|
|
18
|
+
# indexed by macro name.
|
|
19
|
+
attr_reader :leading_str # leading part of string. Used in
|
|
20
|
+
# command completion
|
|
21
|
+
|
|
22
|
+
# "initialize" for multi-file class. Called from main.rb's "initialize".
|
|
23
|
+
def load_cmds_initialize
|
|
24
|
+
@commands = {}
|
|
25
|
+
@aliases = {}
|
|
26
|
+
@macros = {}
|
|
27
|
+
|
|
28
|
+
cmd_dirs = [ File.join(File.dirname(__FILE__), 'command') ]
|
|
29
|
+
cmd_dirs << @settings[:user_cmd_dir] if @settings[:user_cmd_dir]
|
|
30
|
+
cmd_dirs.each do |cmd_dir|
|
|
31
|
+
load_debugger_commands(cmd_dir) if File.directory?(cmd_dir)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Loads in debugger commands by require'ing each ruby file in the
|
|
36
|
+
# 'command' directory. Then a new instance of each class of the
|
|
37
|
+
# form Trepan::xxCommand is added to @commands and that array
|
|
38
|
+
# is returned.
|
|
39
|
+
def load_debugger_commands(file_or_dir)
|
|
40
|
+
if File.directory?(file_or_dir)
|
|
41
|
+
dir = File.expand_path(file_or_dir)
|
|
42
|
+
# change $0 so it doesn't get in the way of __FILE__ = $0
|
|
43
|
+
old_dollar0 = $0
|
|
44
|
+
$0 = ''
|
|
45
|
+
Dir.glob(File.join(dir, '*.rb')).each do |rb|
|
|
46
|
+
# We use require so that multiple calls have no effect.
|
|
47
|
+
require rb
|
|
48
|
+
end
|
|
49
|
+
$0 = old_dollar0
|
|
50
|
+
elsif File.readable?(file_or_dir)
|
|
51
|
+
# We use load in case we are reloading.
|
|
52
|
+
# 'require' would not be effective here
|
|
53
|
+
load file_or_dir
|
|
54
|
+
else
|
|
55
|
+
return false
|
|
56
|
+
end
|
|
57
|
+
# Instantiate each Command class found by the above require(s).
|
|
58
|
+
Trepan::Command.constants.grep(/.Command$/).each do |name|
|
|
59
|
+
klass = Trepan::Command.const_get(name)
|
|
60
|
+
cmd = klass.send(:new, self)
|
|
61
|
+
|
|
62
|
+
# Add to list of commands and aliases.
|
|
63
|
+
cmd_name = klass.const_get(:NAME)
|
|
64
|
+
if klass.constants.member?('ALIASES') ||
|
|
65
|
+
klass.constants.member?(:ALIASES)
|
|
66
|
+
aliases= klass.const_get('ALIASES') || klass.const_get(:ALIASES)
|
|
67
|
+
aliases.each {|a| @aliases[a] = cmd_name}
|
|
68
|
+
end
|
|
69
|
+
@commands[cmd_name] = cmd
|
|
70
|
+
end
|
|
71
|
+
return true
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def load_debugger_command(command_file)
|
|
75
|
+
return unless File.readable?(command_file)
|
|
76
|
+
load command_file
|
|
77
|
+
Trepan::Command.constants.grep(/.Command$/).each do |command|
|
|
78
|
+
setup_command(command)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Looks up cmd_array[0] in @commands and runs that. We do lots of
|
|
83
|
+
# validity testing on cmd_array.
|
|
84
|
+
def run_cmd(cmd_array)
|
|
85
|
+
unless cmd_array.is_a?(Array)
|
|
86
|
+
errmsg "run_cmd argument should be an Array, got: #{cmd_array.class}"
|
|
87
|
+
return
|
|
88
|
+
end
|
|
89
|
+
if cmd_array.detect{|item| !item.is_a?(String)}
|
|
90
|
+
errmsg "run_cmd argument Array should only contain strings. " +
|
|
91
|
+
"Got #{cmd_array.inspect}"
|
|
92
|
+
return
|
|
93
|
+
end
|
|
94
|
+
if cmd_array.empty?
|
|
95
|
+
errmsg "run_cmd Array should have at least one item. " +
|
|
96
|
+
"Got: #{cmd_array.inspect}"
|
|
97
|
+
return
|
|
98
|
+
end
|
|
99
|
+
cmd_name = cmd_array[0]
|
|
100
|
+
if @commands.member?(cmd_name)
|
|
101
|
+
@commands[cmd_name].run(cmd_array)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def save_commands(opts)
|
|
106
|
+
save_filename = opts[:filename] ||
|
|
107
|
+
File.join(Dir.tmpdir, "trepanning-save-#{$$}.txt")
|
|
108
|
+
begin
|
|
109
|
+
save_file = File.open(save_filename, 'w')
|
|
110
|
+
rescue => exc
|
|
111
|
+
errmsg("Can't open #{save_filename} for writing.")
|
|
112
|
+
errmsg("System reports: #{exc.inspect}")
|
|
113
|
+
return nil
|
|
114
|
+
end
|
|
115
|
+
save_file.puts "#\n# Commands to restore trepanning environment\n#\n"
|
|
116
|
+
@commands.each do |cmd_name, cmd_obj|
|
|
117
|
+
cmd_obj.save_command if cmd_obj.respond_to?(:save_command)
|
|
118
|
+
next unless cmd_obj.is_a?(Trepan::SubcommandMgr)
|
|
119
|
+
cmd_obj.subcmds.subcmds.each do |subcmd_name, subcmd_obj|
|
|
120
|
+
save_file.puts subcmd_obj.save_command if
|
|
121
|
+
subcmd_obj.respond_to?(:save_command)
|
|
122
|
+
next unless subcmd_obj.is_a?(Trepan::SubSubcommandMgr)
|
|
123
|
+
subcmd_obj.subcmds.subcmds.each do |subsubcmd_name, subsubcmd_obj|
|
|
124
|
+
save_file.puts subsubcmd_obj.save_command if
|
|
125
|
+
subsubcmd_obj.respond_to?(:save_command)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
save_file.puts "!FileUtils.rm #{save_filename.inspect}" if
|
|
130
|
+
opts[:erase]
|
|
131
|
+
save_file.close
|
|
132
|
+
|
|
133
|
+
return save_filename
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Instantiate a Trepan::Command and extract info: the NAME, ALIASES
|
|
137
|
+
# and store the command in @commands.
|
|
138
|
+
def setup_command(command)
|
|
139
|
+
# Note: there is probably a non-eval way to instantiate the
|
|
140
|
+
# command, but I don't know it. And eval works.
|
|
141
|
+
klass = self.instance_eval("Trepan::Command::#{command}")
|
|
142
|
+
cmd = klass.send(:new, self)
|
|
143
|
+
|
|
144
|
+
# Add to list of commands and aliases.
|
|
145
|
+
cmd_name = klass.const_get(:NAME)
|
|
146
|
+
if klass.constants.member?(:ALIASES)
|
|
147
|
+
aliases= klass.const_get(:ALIASES)
|
|
148
|
+
aliases.each {|a| @aliases[a] = cmd_name}
|
|
149
|
+
end
|
|
150
|
+
@commands[cmd_name] = cmd
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Handle initial completion. We draw from the commands, aliases,
|
|
154
|
+
# and macros for completion. However we won't include aliases which
|
|
155
|
+
# are prefixes of other commands.
|
|
156
|
+
def complete(str, last_token)
|
|
157
|
+
@leading_str = str
|
|
158
|
+
next_blank_pos, token = Trepan::Complete.next_token(str, 0)
|
|
159
|
+
return [''] if token.empty? && !last_token.empty?
|
|
160
|
+
match_pairs = Trepan::Complete.complete_token_with_next(@commands,
|
|
161
|
+
token)
|
|
162
|
+
match_hash = {}
|
|
163
|
+
match_pairs.each do |pair|
|
|
164
|
+
match_hash[pair[0]] = pair[1]
|
|
165
|
+
end
|
|
166
|
+
alias_pairs = Trepan::Complete.
|
|
167
|
+
complete_token_filtered_with_next(@aliases, token, match_hash,
|
|
168
|
+
@commands)
|
|
169
|
+
match_pairs += alias_pairs
|
|
170
|
+
if str[next_blank_pos..-1].empty?
|
|
171
|
+
return match_pairs.map{|pair| pair[0]}.sort
|
|
172
|
+
else
|
|
173
|
+
alias_pairs.each do |pair|
|
|
174
|
+
match_hash[pair[0]] = pair[1]
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
if match_pairs.size > 1
|
|
178
|
+
# FIXME: figure out what to do here.
|
|
179
|
+
# Matched multiple items in the middle of the string
|
|
180
|
+
# We can't handle this so do nothing.
|
|
181
|
+
return []
|
|
182
|
+
# return match_pairs.map do |name, cmd|
|
|
183
|
+
# ["#{name} #{args[1..-1].join(' ')}"]
|
|
184
|
+
# end
|
|
185
|
+
end
|
|
186
|
+
# match_pairs.size == 1
|
|
187
|
+
next_complete(str, next_blank_pos, match_pairs[0][1], last_token)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def next_complete(str, next_blank_pos, cmd, last_token)
|
|
191
|
+
next_blank_pos, token = Trepan::Complete.next_token(str, next_blank_pos)
|
|
192
|
+
return [] if token.empty? && !last_token.empty?
|
|
193
|
+
|
|
194
|
+
if cmd.respond_to?(:complete_token_with_next)
|
|
195
|
+
match_pairs = cmd.complete_token_with_next(token)
|
|
196
|
+
return [] if match_pairs.empty?
|
|
197
|
+
if str[next_blank_pos..-1].rstrip.empty? &&
|
|
198
|
+
(token.empty? || token == last_token)
|
|
199
|
+
return match_pairs.map { |completion, junk| completion }
|
|
200
|
+
else
|
|
201
|
+
if match_pairs.size == 1
|
|
202
|
+
return next_complete(str, next_blank_pos, match_pairs[0][1],
|
|
203
|
+
last_token)
|
|
204
|
+
else
|
|
205
|
+
# FIXME: figure out what to do here.
|
|
206
|
+
# Matched multiple items in the middle of the string
|
|
207
|
+
# We can't handle this so do nothing.
|
|
208
|
+
return []
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
elsif cmd.respond_to?(:complete)
|
|
212
|
+
matches = cmd.complete(token)
|
|
213
|
+
return [] if matches.empty?
|
|
214
|
+
if str[next_blank_pos..-1].rstrip.empty? &&
|
|
215
|
+
(token.empty? || token == last_token)
|
|
216
|
+
return matches
|
|
217
|
+
else
|
|
218
|
+
# FIXME: figure out what to do here.
|
|
219
|
+
# Matched multiple items in the middle of the string
|
|
220
|
+
# We can't handle this so do nothing.
|
|
221
|
+
return []
|
|
222
|
+
end
|
|
223
|
+
else
|
|
224
|
+
return []
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
if __FILE__ == $0
|
|
230
|
+
require_relative '../interface/user' # user interface (includes I/O)
|
|
231
|
+
cmdproc = Trepan::CmdProcessor.new([], nil)
|
|
232
|
+
cmddir = File.join(File.dirname(__FILE__), 'command')
|
|
233
|
+
cmdproc.instance_variable_set('@settings', {})
|
|
234
|
+
cmdproc.interfaces = [Trepan::UserInterface.new(nil, nil,
|
|
235
|
+
:history_save=>false)]
|
|
236
|
+
cmdproc.load_cmds_initialize
|
|
237
|
+
require 'columnize'
|
|
238
|
+
puts Columnize.columnize(cmdproc.commands.keys.sort)
|
|
239
|
+
puts '=' * 20
|
|
240
|
+
puts Columnize.columnize(cmdproc.aliases.keys.sort)
|
|
241
|
+
puts '=' * 20
|
|
242
|
+
|
|
243
|
+
def cmdproc.errmsg(mess)
|
|
244
|
+
puts "** #{mess}"
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def cmdproc.msg(mess)
|
|
248
|
+
puts mess
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
cmdproc.run_cmd('foo') # Invalid - not an Array
|
|
252
|
+
cmdproc.run_cmd([]) # Invalid - empty Array
|
|
253
|
+
cmdproc.run_cmd(['list', 5]) # Invalid - nonstring arg
|
|
254
|
+
p cmdproc.complete("d", 'd')
|
|
255
|
+
require 'ruby-debug'; Debugger.start; debugger
|
|
256
|
+
p cmdproc.complete("sho d", 'd')
|
|
257
|
+
p cmdproc.complete('', '')
|
|
258
|
+
end
|