trepanning 0.1.2 → 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 (123) hide show
  1. data/ChangeLog +354 -0
  2. data/NEWS +21 -0
  3. data/Rakefile +27 -20
  4. data/app/cmd_parse.kpeg +20 -4
  5. data/app/cmd_parse.rb +11 -10
  6. data/app/cmd_parser.rb +119 -55
  7. data/app/complete.rb +1 -0
  8. data/app/core.rb +3 -3
  9. data/app/disassemble.rb +13 -3
  10. data/app/file.rb +2 -1
  11. data/app/frame.rb +3 -1
  12. data/app/mock.rb +3 -0
  13. data/app/options.rb +48 -31
  14. data/app/util.rb +50 -0
  15. data/interface/base_intf.rb +4 -0
  16. data/interface/client.rb +4 -0
  17. data/interface/script.rb +1 -1
  18. data/interface/server.rb +4 -0
  19. data/interface/user.rb +5 -0
  20. data/io/input.rb +3 -2
  21. data/io/null_output.rb +7 -1
  22. data/processor/breakpoint.rb +3 -2
  23. data/processor/command/base/subcmd.rb +1 -1
  24. data/processor/command/base/submgr.rb +4 -1
  25. data/processor/command/base/subsubcmd.rb +2 -2
  26. data/processor/command/base/subsubmgr.rb +1 -1
  27. data/processor/command/break.rb +7 -3
  28. data/processor/command/complete.rb +1 -0
  29. data/processor/command/continue.rb +1 -1
  30. data/processor/command/disassemble.rb +1 -1
  31. data/processor/command/edit.rb +35 -14
  32. data/processor/command/enable.rb +5 -3
  33. data/processor/command/eval.rb +35 -14
  34. data/processor/command/exit.rb +2 -0
  35. data/processor/command/help.rb +0 -9
  36. data/processor/command/help/command.txt +37 -27
  37. data/processor/command/help/examples.txt +16 -0
  38. data/processor/command/help/suffixes.txt +17 -0
  39. data/processor/command/info.rb +1 -1
  40. data/processor/command/info_subcmd/args.rb +7 -13
  41. data/processor/command/info_subcmd/breakpoints.rb +8 -2
  42. data/processor/command/info_subcmd/frame.rb +2 -0
  43. data/processor/command/info_subcmd/globals.rb +63 -0
  44. data/processor/command/info_subcmd/iseq.rb +3 -1
  45. data/processor/command/info_subcmd/locals.rb +16 -15
  46. data/processor/command/{show_subcmd → info_subcmd}/macro.rb +7 -7
  47. data/processor/command/info_subcmd/program.rb +2 -0
  48. data/processor/command/info_subcmd/registers.rb +5 -1
  49. data/processor/command/info_subcmd/registers_subcmd/dfp.rb +2 -3
  50. data/processor/command/info_subcmd/registers_subcmd/helper.rb +8 -9
  51. data/processor/command/info_subcmd/registers_subcmd/lfp.rb +10 -5
  52. data/processor/command/info_subcmd/registers_subcmd/pc.rb +9 -4
  53. data/processor/command/info_subcmd/registers_subcmd/sp.rb +4 -5
  54. data/processor/command/info_subcmd/ruby.rb +3 -1
  55. data/processor/command/info_subcmd/source.rb +78 -0
  56. data/processor/command/info_subcmd/stack.rb +23 -0
  57. data/processor/command/kill.rb +4 -6
  58. data/processor/command/list.rb +118 -120
  59. data/processor/command/macro.rb +1 -1
  60. data/processor/command/parsetree.rb +56 -0
  61. data/processor/command/pp.rb +40 -0
  62. data/processor/command/pr.rb +1 -2
  63. data/processor/command/quit.rb +2 -1
  64. data/processor/command/set_subcmd/abbrev.rb +24 -0
  65. data/processor/command/set_subcmd/auto_subcmd/eval.rb +1 -2
  66. data/processor/command/set_subcmd/auto_subcmd/irb.rb +2 -3
  67. data/processor/command/set_subcmd/auto_subcmd/list.rb +2 -3
  68. data/processor/command/set_subcmd/highlight.rb +8 -2
  69. data/processor/command/set_subcmd/reload.rb +41 -0
  70. data/processor/command/set_subcmd/timer.rb +8 -18
  71. data/processor/command/set_subcmd/trace.rb +2 -2
  72. data/processor/command/set_subcmd/trace_subcmd/buffer.rb +2 -2
  73. data/processor/command/set_subcmd/trace_subcmd/print.rb +3 -3
  74. data/processor/command/{irb.rb → shell.rb} +9 -6
  75. data/processor/command/show_subcmd/abbrev.rb +19 -0
  76. data/processor/command/show_subcmd/directories.rb +21 -0
  77. data/processor/command/show_subcmd/hidelevel.rb +1 -1
  78. data/processor/command/show_subcmd/highlight.rb +2 -1
  79. data/processor/command/show_subcmd/reload.rb +17 -0
  80. data/processor/command/show_subcmd/timer.rb +17 -0
  81. data/processor/command/show_subcmd/trace_subcmd/buffer.rb +1 -1
  82. data/processor/command/source.rb +15 -14
  83. data/processor/command/tbreak.rb +20 -0
  84. data/processor/command/watchg.rb +114 -0
  85. data/processor/default.rb +43 -41
  86. data/processor/display.rb +3 -2
  87. data/processor/eval.rb +5 -3
  88. data/processor/eventbuf.rb +3 -2
  89. data/processor/frame.rb +12 -3
  90. data/processor/hook.rb +3 -2
  91. data/processor/load_cmds.rb +186 -179
  92. data/processor/location.rb +154 -159
  93. data/processor/main.rb +44 -16
  94. data/processor/mock.rb +0 -11
  95. data/processor/msg.rb +3 -1
  96. data/processor/running.rb +3 -2
  97. data/processor/validate.rb +25 -4
  98. data/processor/virtual.rb +32 -0
  99. data/test/data/debugger-stop.right +1 -0
  100. data/test/data/fname-with-blank.right +1 -0
  101. data/test/example/gcd.rb +1 -0
  102. data/test/functional/{test-trace-var.rb → test-watchg.rb} +15 -4
  103. data/test/unit/cmd-helper.rb +0 -3
  104. data/test/unit/test-app-cmd_parser.rb +2 -2
  105. data/test/unit/test-app-file.rb +1 -0
  106. data/test/unit/test-app-frame.rb +1 -1
  107. data/test/unit/test-app-util.rb +21 -0
  108. data/test/unit/test-base-cmd.rb +4 -6
  109. data/test/unit/test-base-subcmd.rb +1 -4
  110. data/test/unit/test-base-submgr.rb +1 -2
  111. data/test/unit/test-base-subsubcmd.rb +0 -4
  112. data/test/unit/test-cmd-edit.rb +33 -0
  113. data/test/unit/test-cmd-parse_list_cmd.rb +33 -0
  114. data/test/unit/test-completion.rb +1 -1
  115. data/test/unit/test-proc-frame.rb +4 -1
  116. data/test/unit/test-proc-load_cmds.rb +2 -1
  117. data/test/unit/test-proc-location.rb +9 -26
  118. data/test/unit/test-proc-main.rb +1 -4
  119. data/test/unit/test-proc-validate.rb +28 -18
  120. data/test/unit/test-subcmd-help.rb +0 -4
  121. data/trepanning.gemspec +1 -1
  122. metadata +27 -10
  123. data/processor/command/set_subcmd/trace_subcmd/var.rb +0 -57
data/processor/hook.rb CHANGED
@@ -1,6 +1,7 @@
1
- # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
1
+ # Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
2
+ require_relative 'virtual'
2
3
  class Trepan
3
- class CmdProcessor
4
+ class CmdProcessor < VirtualCmdProcessor
4
5
  # Command processor hooks.
5
6
  attr_reader :autoirb_hook
6
7
  attr_reader :autolist_hook
@@ -6,208 +6,215 @@ require 'tmpdir'
6
6
  # builtin and user directories.
7
7
  # Sets @commands, @aliases, @macros
8
8
  require_relative '../app/complete'
9
- class Trepan
10
- class CmdProcessor
11
-
12
- attr_reader :aliases # Hash[String] of command names
13
- # indexed by alias name
14
- attr_reader :commands # Hash[String] of command objects
15
- # indexed by name
16
- attr_reader :macros # Hash[String] of Proc objects
17
- # indexed by macro name.
18
-
19
- # "initialize" for multi-file class. Called from main.rb's "initialize".
20
- def load_cmds_initialize
21
- @commands = {}
22
- @aliases = {}
23
- @macros = {}
24
-
25
- cmd_dirs = [ File.join(File.dirname(__FILE__), 'command') ]
26
- cmd_dirs << @settings[:user_cmd_dir] if @settings[:user_cmd_dir]
27
- cmd_dirs.each do |cmd_dir|
28
- load_debugger_commands(cmd_dir) if File.directory?(cmd_dir)
29
- end
9
+ require_relative 'virtual'
10
+ class Trepan::CmdProcessor < Trepan::VirtualCmdProcessor
11
+
12
+ attr_reader :aliases # Hash[String] of command names
13
+ # indexed by alias name
14
+ attr_reader :commands # Hash[String] of command objects
15
+ # indexed by name
16
+ attr_reader :macros # Hash[String] of Proc objects
17
+ # indexed by macro name.
18
+ attr_reader :leading_str # leading part of string. Used in
19
+ # command completion
20
+
21
+ # "initialize" for multi-file class. Called from main.rb's "initialize".
22
+ def load_cmds_initialize
23
+ @commands = {}
24
+ @aliases = {}
25
+ @macros = {}
26
+
27
+ cmd_dirs = [ File.join(File.dirname(__FILE__), 'command') ]
28
+ cmd_dirs << @settings[:user_cmd_dir] if @settings[:user_cmd_dir]
29
+ cmd_dirs.each do |cmd_dir|
30
+ load_debugger_commands(cmd_dir) if File.directory?(cmd_dir)
30
31
  end
32
+ end
31
33
 
32
- # Loads in debugger commands by require'ing each ruby file in the
33
- # 'command' directory. Then a new instance of each class of the
34
- # form Trepan::xxCommand is added to @commands and that array
35
- # is returned.
36
- def load_debugger_commands(file_or_dir)
37
- if File.directory?(file_or_dir)
38
- dir = File.expand_path(file_or_dir)
39
- Dir.glob(File.join(dir, '*.rb')).each do |rb|
40
- # We use require so that multiple calls have no effect.
41
- require rb
42
- end
43
- elsif File.readable?(file_or_dir)
44
- # We use load in case we are reloading.
45
- # 'require' would not be effective here
46
- load file_or_dir
47
- else
48
- return false
49
- end
50
- Trepan::Command.constants.grep(/.Command$/).each do |command|
51
- setup_command(command)
34
+ # Loads in debugger commands by require'ing each ruby file in the
35
+ # 'command' directory. Then a new instance of each class of the
36
+ # form Trepan::xxCommand is added to @commands and that array
37
+ # is returned.
38
+ def load_debugger_commands(file_or_dir)
39
+ if File.directory?(file_or_dir)
40
+ dir = File.expand_path(file_or_dir)
41
+ # change $0 so it doesn't get in the way of __FILE__ = $0
42
+ old_dollar0 = $0
43
+ $0 = ''
44
+ Dir.glob(File.join(dir, '*.rb')).each do |rb|
45
+ # We use require so that multiple calls have no effect.
46
+ require rb
52
47
  end
53
- return true
48
+ $0 = old_dollar0
49
+ elsif File.readable?(file_or_dir)
50
+ # We use load in case we are reloading.
51
+ # 'require' would not be effective here
52
+ load file_or_dir
53
+ else
54
+ return false
55
+ end
56
+ # Instantiate each Command class found by the above require(s).
57
+ Trepan::Command.constants.grep(/.Command$/).each do |command|
58
+ setup_command(command)
54
59
  end
60
+ return true
61
+ end
55
62
 
56
- def load_debugger_command(command_file)
57
- return unless File.readable?(command_file)
58
- load command_file
59
- Trepan::Command.constants.grep(/.Command$/).each do |command|
60
- setup_command(command)
61
- end
63
+ def load_debugger_command(command_file)
64
+ return unless File.readable?(command_file)
65
+ load command_file
66
+ Trepan::Command.constants.grep(/.Command$/).each do |command|
67
+ setup_command(command)
62
68
  end
69
+ end
63
70
 
64
- # Looks up cmd_array[0] in @commands and runs that. We do lots of
65
- # validity testing on cmd_array.
66
- def run_cmd(cmd_array)
67
- unless cmd_array.is_a?(Array)
68
- errmsg "run_cmd argument should be an Array, got: #{cmd_array.class}"
69
- return
70
- end
71
- if cmd_array.detect{|item| !item.is_a?(String)}
72
- errmsg "run_cmd argument Array should only contain strings. " +
73
- "Got #{cmd_array.inspect}"
74
- return
75
- end
76
- if cmd_array.empty?
77
- errmsg "run_cmd Array should have at least one item. " +
78
- "Got: #{cmd_array.inspect}"
79
- return
80
- end
81
- cmd_name = cmd_array[0]
82
- if @commands.member?(cmd_name)
83
- @commands[cmd_name].run(cmd_array)
84
- end
71
+ # Looks up cmd_array[0] in @commands and runs that. We do lots of
72
+ # validity testing on cmd_array.
73
+ def run_cmd(cmd_array)
74
+ unless cmd_array.is_a?(Array)
75
+ errmsg "run_cmd argument should be an Array, got: #{cmd_array.class}"
76
+ return
77
+ end
78
+ if cmd_array.detect{|item| !item.is_a?(String)}
79
+ errmsg "run_cmd argument Array should only contain strings. " +
80
+ "Got #{cmd_array.inspect}"
81
+ return
82
+ end
83
+ if cmd_array.empty?
84
+ errmsg "run_cmd Array should have at least one item. " +
85
+ "Got: #{cmd_array.inspect}"
86
+ return
87
+ end
88
+ cmd_name = cmd_array[0]
89
+ if @commands.member?(cmd_name)
90
+ @commands[cmd_name].run(cmd_array)
85
91
  end
92
+ end
86
93
 
87
- def save_commands(opts)
88
- save_filename = opts[:filename] ||
89
- File.join(Dir.tmpdir, Dir::Tmpname.make_tmpname(['trepanning-save', '.txt'], nil))
90
- begin
91
- save_file = File.open(save_filename, 'w')
92
- rescue => exc
93
- errmsg("Can't open #{save_filename} for writing.")
94
- errmsg("System reports: #{exc.inspect}")
95
- return nil
96
- end
97
- save_file.puts "#\n# Commands to restore trepanning environment\n#\n"
98
- @commands.each do |cmd_name, cmd_obj|
99
- cmd_obj.save_command if cmd_obj.respond_to?(:save_command)
100
- next unless cmd_obj.is_a?(Trepan::SubcommandMgr)
101
- cmd_obj.subcmds.subcmds.each do |subcmd_name, subcmd_obj|
102
- save_file.puts subcmd_obj.save_command if
103
- subcmd_obj.respond_to?(:save_command)
104
- next unless subcmd_obj.is_a?(Trepan::SubSubcommandMgr)
105
- subcmd_obj.subcmds.subcmds.each do |subsubcmd_name, subsubcmd_obj|
106
- save_file.puts subsubcmd_obj.save_command if
107
- subsubcmd_obj.respond_to?(:save_command)
108
- end
94
+ def save_commands(opts)
95
+ save_filename = opts[:filename] ||
96
+ File.join(Dir.tmpdir, Dir::Tmpname.make_tmpname(['trepanning-save', '.txt'], nil))
97
+ begin
98
+ save_file = File.open(save_filename, 'w')
99
+ rescue => exc
100
+ errmsg("Can't open #{save_filename} for writing.")
101
+ errmsg("System reports: #{exc.inspect}")
102
+ return nil
103
+ end
104
+ save_file.puts "#\n# Commands to restore trepanning environment\n#\n"
105
+ @commands.each do |cmd_name, cmd_obj|
106
+ cmd_obj.save_command if cmd_obj.respond_to?(:save_command)
107
+ next unless cmd_obj.is_a?(Trepan::SubcommandMgr)
108
+ cmd_obj.subcmds.subcmds.each do |subcmd_name, subcmd_obj|
109
+ save_file.puts subcmd_obj.save_command if
110
+ subcmd_obj.respond_to?(:save_command)
111
+ next unless subcmd_obj.is_a?(Trepan::SubSubcommandMgr)
112
+ subcmd_obj.subcmds.subcmds.each do |subsubcmd_name, subsubcmd_obj|
113
+ save_file.puts subsubcmd_obj.save_command if
114
+ subsubcmd_obj.respond_to?(:save_command)
109
115
  end
110
116
  end
111
- save_file.puts "!FileUtils.rm #{save_filename.inspect}" if
112
- opts[:erase]
113
- save_file.close
114
-
115
- return save_filename
116
- end
117
-
118
- # Instantiate a Trepan::Command and extract info: the NAME, ALIASES
119
- # and store the command in @commands.
120
- def setup_command(command)
121
- # Note: there is probably a non-eval way to instantiate the
122
- # command, but I don't know it. And eval works.
123
- klass = self.instance_eval("Trepan::Command::#{command}")
124
- cmd = klass.send(:new, self)
125
-
126
- # Add to list of commands and aliases.
127
- cmd_name = klass.const_get(:NAME)
128
- if klass.constants.member?(:ALIASES)
129
- aliases= klass.const_get(:ALIASES)
130
- aliases.each {|a| @aliases[a] = cmd_name}
131
- end
132
- @commands[cmd_name] = cmd
133
- end
134
-
135
- # Handle initial completion. We draw from the commands, aliases,
136
- # and macros for completion. However we won't include aliases which
137
- # are prefixes of other commands.
138
- def complete(str, last_token)
139
- next_blank_pos, token = Trepan::Complete.next_token(str, 0)
140
- return [''] if token.empty? && !last_token.empty?
141
- match_pairs = Trepan::Complete.complete_token_with_next(@commands,
142
- token)
143
- match_hash = {}
144
- match_pairs.each do |pair|
117
+ end
118
+ save_file.puts "!FileUtils.rm #{save_filename.inspect}" if
119
+ opts[:erase]
120
+ save_file.close
121
+
122
+ return save_filename
123
+ end
124
+
125
+ # Instantiate a Trepan::Command and extract info: the NAME, ALIASES
126
+ # and store the command in @commands.
127
+ def setup_command(command)
128
+ # Note: there is probably a non-eval way to instantiate the
129
+ # command, but I don't know it. And eval works.
130
+ klass = self.instance_eval("Trepan::Command::#{command}")
131
+ cmd = klass.send(:new, self)
132
+
133
+ # Add to list of commands and aliases.
134
+ cmd_name = klass.const_get(:NAME)
135
+ if klass.constants.member?(:ALIASES)
136
+ aliases= klass.const_get(:ALIASES)
137
+ aliases.each {|a| @aliases[a] = cmd_name}
138
+ end
139
+ @commands[cmd_name] = cmd
140
+ end
141
+
142
+ # Handle initial completion. We draw from the commands, aliases,
143
+ # and macros for completion. However we won't include aliases which
144
+ # are prefixes of other commands.
145
+ def complete(str, last_token)
146
+ @leading_str = str
147
+ next_blank_pos, token = Trepan::Complete.next_token(str, 0)
148
+ return [''] if token.empty? && !last_token.empty?
149
+ match_pairs = Trepan::Complete.complete_token_with_next(@commands,
150
+ token)
151
+ match_hash = {}
152
+ match_pairs.each do |pair|
153
+ match_hash[pair[0]] = pair[1]
154
+ end
155
+ alias_pairs = Trepan::Complete.
156
+ complete_token_filtered_with_next(@aliases, token, match_hash,
157
+ @commands)
158
+ match_pairs += alias_pairs
159
+ if str[next_blank_pos..-1].empty?
160
+ return match_pairs.map{|pair| pair[0]}.sort
161
+ else
162
+ alias_pairs.each do |pair|
145
163
  match_hash[pair[0]] = pair[1]
146
164
  end
147
- alias_pairs = Trepan::Complete.
148
- complete_token_filtered_with_next(@aliases, token, match_hash,
149
- @commands)
150
- match_pairs += alias_pairs
151
- if str[next_blank_pos..-1].empty?
152
- return match_pairs.map{|pair| pair[0]}.sort
165
+ end
166
+ if match_pairs.size > 1
167
+ # FIXME: figure out what to do here.
168
+ # Matched multiple items in the middle of the string
169
+ # We can't handle this so do nothing.
170
+ return []
171
+ # return match_pairs.map do |name, cmd|
172
+ # ["#{name} #{args[1..-1].join(' ')}"]
173
+ # end
174
+ end
175
+ # match_pairs.size == 1
176
+ next_complete(str, next_blank_pos, match_pairs[0][1], last_token)
177
+ end
178
+
179
+ def next_complete(str, next_blank_pos, cmd, last_token)
180
+ next_blank_pos, token = Trepan::Complete.next_token(str, next_blank_pos)
181
+ return [] if token.empty? && !last_token.empty?
182
+
183
+ if cmd.respond_to?(:complete_token_with_next)
184
+ match_pairs = cmd.complete_token_with_next(token)
185
+ return [] if match_pairs.empty?
186
+ if str[next_blank_pos..-1].rstrip.empty? &&
187
+ (token.empty? || token == last_token)
188
+ return match_pairs.map { |completion, junk| completion }
153
189
  else
154
- alias_pairs.each do |pair|
155
- match_hash[pair[0]] = pair[1]
156
- end
157
- end
158
- if match_pairs.size > 1
159
- # FIXME: figure out what to do here.
160
- # Matched multiple items in the middle of the string
161
- # We can't handle this so do nothing.
162
- return []
163
- # return match_pairs.map do |name, cmd|
164
- # ["#{name} #{args[1..-1].join(' ')}"]
165
- # end
166
- end
167
- # match_pairs.size == 1
168
- next_complete(str, next_blank_pos, match_pairs[0][1], last_token)
169
- end
170
-
171
- def next_complete(str, next_blank_pos, cmd, last_token)
172
- # debugger if 8 == next_blank_pos
173
- next_blank_pos, token = Trepan::Complete.next_token(str, next_blank_pos)
174
- return [] if token.empty? && !last_token.empty?
175
-
176
- if cmd.respond_to?(:complete_token_with_next)
177
- match_pairs = cmd.complete_token_with_next(token)
178
- return [] if match_pairs.empty?
179
- if str[next_blank_pos..-1].rstrip.empty? &&
180
- (token.empty? || token == last_token)
181
- return match_pairs.map { |completion, junk| completion }
182
- else
183
- if match_pairs.size == 1
184
- return next_complete(str, next_blank_pos, match_pairs[0][1],
185
- last_token)
186
- else
187
- # FIXME: figure out what to do here.
188
- # Matched multiple items in the middle of the string
189
- # We can't handle this so do nothing.
190
- return []
191
- end
192
- end
193
- elsif cmd.respond_to?(:complete)
194
- matches = cmd.complete(token)
195
- return [] if matches.empty?
196
- if str[next_blank_pos..-1].rstrip.empty? &&
197
- (token.empty? || token == last_token)
198
- return matches
190
+ if match_pairs.size == 1
191
+ return next_complete(str, next_blank_pos, match_pairs[0][1],
192
+ last_token)
199
193
  else
200
194
  # FIXME: figure out what to do here.
201
195
  # Matched multiple items in the middle of the string
202
196
  # We can't handle this so do nothing.
203
197
  return []
204
198
  end
199
+ end
200
+ elsif cmd.respond_to?(:complete)
201
+ matches = cmd.complete(token)
202
+ return [] if matches.empty?
203
+ if str[next_blank_pos..-1].rstrip.empty? &&
204
+ (token.empty? || token == last_token)
205
+ return matches
205
206
  else
207
+ # FIXME: figure out what to do here.
208
+ # Matched multiple items in the middle of the string
209
+ # We can't handle this so do nothing.
206
210
  return []
207
211
  end
212
+ else
213
+ return []
208
214
  end
209
215
  end
210
216
  end
217
+
211
218
  if __FILE__ == $0
212
219
  class Trepan::CmdProcessor
213
220
  def initialize(core, settings={})
@@ -235,7 +242,7 @@ if __FILE__ == $0
235
242
  cmdproc.run_cmd('foo') # Invalid - not an Array
236
243
  cmdproc.run_cmd([]) # Invalid - empty Array
237
244
  cmdproc.run_cmd(['list', 5]) # Invalid - nonstring arg
238
- p cmdproc.complete("d")
239
- p cmdproc.complete("sho d")
240
- p cmdproc.complete('')
245
+ p cmdproc.complete("d", 'd')
246
+ p cmdproc.complete("sho d", 'd')
247
+ p cmdproc.complete('', '')
241
248
  end
@@ -1,183 +1,180 @@
1
1
  # Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
2
+ require 'rubygems'
2
3
  require 'linecache'
3
4
  require 'pathname' # For cleanpath
4
5
  require_relative 'msg'
5
6
  require_relative '../app/frame'
6
- class Trepan
7
- class CmdProcessor
8
- attr_accessor :reload_on_change
9
- include Frame
7
+ require_relative 'virtual'
8
+ class Trepan::CmdProcessor < Trepan::VirtualCmdProcessor
9
+ include Trepan::Frame
10
10
 
11
- def location_initialize
12
- @reload_on_change = nil
13
- end
14
-
15
- def canonic_container(container)
16
- [container[0], canonic_file(container[1])]
17
- end
18
-
19
- def canonic_file(filename)
20
- # For now we want resolved filenames
21
- @settings[:basename] ? File.basename(filename) :
22
- # Cache this?
23
- File.expand_path(Pathname.new(filename).cleanpath.to_s)
24
- end
25
-
26
- # Return the text to the current source line.
27
- # FIXME: loc_and_text should call this rather than the other
28
- # way around.
29
- def current_source_text
30
- opts = {:reload_on_change => @reload_on_change}
31
- junk1, junk2, text, found_line =
32
- loc_and_text('', frame, frame.source_location[0],
33
- frame.source_container, opts)
34
- text
35
- end
36
-
37
- def resolve_file_with_dir(path_suffix)
38
- @settings[:directory].split(/:/).each do |dir|
39
- dir =
40
- if '$cwd' == dir
41
- Dir.pwd
42
- elsif '$cdir' == dir
43
- RubyVM::OS_STARTUP_DIR
44
- else
45
- dir
46
- end
47
- next unless dir && File.directory?(dir)
48
- try_file = File.join(dir, path_suffix)
49
- return try_file if File.readable?(try_file)
50
- end
51
- nil
11
+ def canonic_container(container)
12
+ [container[0], canonic_file(container[1])]
13
+ end
14
+
15
+ def canonic_file(filename, resolve=true)
16
+ # For now we want resolved filenames
17
+ if @settings[:basename]
18
+ File.basename(filename)
19
+ elsif resolve
20
+ filename = LineCache::map_file(filename)
21
+ File.expand_path(Pathname.new(filename).cleanpath.to_s)
22
+ else
23
+ filename
52
24
  end
25
+ end
53
26
 
54
- # Get line +line_number+ from file named +filename+. Return ''
55
- # if there was a problem. Leading blanks are stripped off.
56
- def line_at(filename, line_number,
57
- opts = {
58
- :reload_on_change => @reload_on_change,
59
- :output => @settings[:highlight]
60
- })
61
- line = LineCache::getline(filename, line_number, opts)
62
-
63
- unless line
64
- # Try using search directories (set with command "directory")
65
- if filename[0..0] != File::SEPARATOR
66
- try_filename = resolve_file_with_dir(filename)
67
- if try_filename &&
68
- line = LineCache::getline(try_filename, line_number, opts)
69
- LineCache::remap_file(filename, try_filename)
70
- end
27
+ # Return the text to the current source line.
28
+ # FIXME: loc_and_text should call this rather than the other
29
+ # way around.
30
+ def current_source_text
31
+ opts = {:reload_on_change => @reload}
32
+ junk1, junk2, text, found_line =
33
+ loc_and_text('', frame, frame.source_location[0],
34
+ frame.source_container, opts)
35
+ text
36
+ end
37
+
38
+ def resolve_file_with_dir(path_suffix)
39
+ @settings[:directory].split(/:/).each do |dir|
40
+ dir =
41
+ if '$cwd' == dir
42
+ Dir.pwd
43
+ elsif '$cdir' == dir
44
+ RubyVM::OS_STARTUP_DIR
45
+ else
46
+ dir
71
47
  end
72
- end
73
- line ? line.lstrip.chomp : line
48
+ next unless dir && File.directory?(dir)
49
+ try_file = File.join(dir, path_suffix)
50
+ return try_file if File.readable?(try_file)
74
51
  end
75
-
76
- def loc_and_text(loc, frame, line_no, source_container,
77
- opts = {
78
- :reload_on_change => @reload_on_change,
79
- :output => @settings[:highlight]
80
- })
81
- found_line = true
82
- ## FIXME: condition is too long.
83
- if source_container[0] == 'string' && frame.iseq && frame.iseq.eval_source
84
- file = LineCache::map_iseq(frame.iseq)
85
- text = LineCache::getline(frame.iseq, line_no, opts)
86
- loc += " remapped #{canonic_file(file)}:#{line_no}"
87
- elsif source_container[0] != 'file'
88
- via = loc
89
- while source_container[0] != 'file' && frame.prev do
90
- frame = frame.prev
91
- source_container = frame_container(frame, false)
92
- end
93
- if source_container[0] == 'file'
94
- line_no = frame.source_location[0]
95
- filename = source_container[1]
96
- loc += " via #{canonic_file(filename)}:#{line_no}"
97
- text = line_at(filename, line_no, opts)
98
- found_line = false
99
- end
100
- else
101
- container = source_container[1]
102
- map_file, map_line = LineCache::map_file_line(container, line_no)
103
- if [container, line_no] != [map_file, map_line]
104
- loc += " remapped #{canonic_file(map_file)}:#{map_line}"
52
+ nil
53
+ end
54
+
55
+ # Get line +line_number+ from file named +filename+. Return ''
56
+ # if there was a problem. Leading blanks are stripped off.
57
+ def line_at(filename, line_number,
58
+ opts = {
59
+ :reload_on_change => @settings[:reload],
60
+ :output => @settings[:highlight]
61
+ })
62
+ line = LineCache::getline(filename, line_number, opts)
63
+
64
+ unless line
65
+ # Try using search directories (set with command "directory")
66
+ if filename[0..0] != File::SEPARATOR
67
+ try_filename = resolve_file_with_dir(filename)
68
+ if try_filename &&
69
+ line = LineCache::getline(try_filename, line_number, opts)
70
+ LineCache::remap_file(filename, try_filename)
105
71
  end
106
-
107
- text = line_at(container, line_no, opts)
108
72
  end
109
- [loc, line_no, text, found_line]
110
73
  end
74
+ line ? line.lstrip.chomp : line
75
+ end
111
76
 
112
- def print_location
113
- if %w(c-call call).member?(@event)
114
- # FIXME: Fix Ruby so we don't need this workaround?
115
- # See also where.rb
116
- opts = {}
117
- opts[:class] = @core.hook_arg if
118
- 'CFUNC' == @frame.type && @core.hook_arg && 0 == @frame_index
119
- msg format_stack_call(@frame, opts)
120
- elsif 'raise' == @event
121
- msg @core.hook_arg.inspect if @core.hook_arg # Exception object
122
- end
123
-
124
- text = nil
125
- source_container = frame_container(@frame, false)
126
- ev = if @event.nil? || 0 != @frame_index
127
- ' '
128
- else
129
- (EVENT2ICON[@event] || @event)
130
- end
131
- @line_no = frame_line
132
-
133
- loc = source_location_info(source_container, @line_no, @frame)
134
- loc, @line_no, text, found_line =
135
- loc_and_text(loc, @frame, @line_no, source_container)
136
-
137
- ip_str = @frame.iseq ? " @#{frame.pc_offset}" : ''
138
- msg "#{ev} (#{loc}#{ip_str})"
139
-
140
- if %w(return c-return).member?(@event)
141
- retval = Trepan::Frame.value_returned(@frame, @event)
142
- msg 'R=> %s' % retval.inspect
77
+ def loc_and_text(loc, frame, line_no, source_container,
78
+ opts = {
79
+ :reload_on_change => @settings[:reload],
80
+ :output => @settings[:highlight]
81
+ })
82
+ found_line = true
83
+ ## FIXME: condition is too long.
84
+ if source_container[0] == 'string' && frame.iseq && frame.iseq.eval_source
85
+ file = LineCache::map_iseq(frame.iseq)
86
+ text = LineCache::getline(frame.iseq, line_no, opts)
87
+ loc += " remapped #{canonic_file(file)}:#{line_no}"
88
+ elsif source_container[0] != 'file'
89
+ via = loc
90
+ while source_container[0] != 'file' && frame.prev do
91
+ frame = frame.prev
92
+ source_container = frame_container(frame, false)
143
93
  end
144
-
145
- if text && !text.strip.empty?
146
- msg text
147
- @line_no -= 1
94
+ if source_container[0] == 'file'
95
+ line_no = frame.source_location[0]
96
+ filename = source_container[1]
97
+ loc += " via #{canonic_file(filename)}:#{line_no}"
98
+ text = line_at(filename, line_no, opts)
99
+ found_line = false
148
100
  end
149
- unless found_line
150
- # Can't find source line, so give assembly as consolation.
151
- # This great idea comes from the Rubinius reference debugger.
152
- run_command('disassemble')
101
+ else
102
+ container = source_container[1]
103
+ map_file, map_line = LineCache::map_file_line(container, line_no)
104
+ if [container, line_no] != [map_file, map_line]
105
+ loc += " remapped #{canonic_file(map_file)}:#{map_line}"
153
106
  end
107
+
108
+ text = line_at(container, line_no, opts)
109
+ end
110
+ [loc, line_no, text, found_line]
111
+ end
112
+
113
+ def print_location
114
+ if %w(c-call call).member?(@event)
115
+ # FIXME: Fix Ruby so we don't need this workaround?
116
+ # See also where.rb
117
+ opts = {}
118
+ opts[:class] = @core.hook_arg if
119
+ 'CFUNC' == @frame.type && @core.hook_arg && 0 == @frame_index
120
+ msg format_stack_call(@frame, opts)
121
+ elsif 'raise' == @event
122
+ msg @core.hook_arg.inspect if @core.hook_arg # Exception object
123
+ end
124
+
125
+ text = nil
126
+ source_container = frame_container(@frame, false)
127
+ ev = if @event.nil? || 0 != @frame_index
128
+ ' '
129
+ else
130
+ (EVENT2ICON[@event] || @event)
131
+ end
132
+ @line_no = frame_line
133
+
134
+ loc = source_location_info(source_container, @line_no, @frame)
135
+ loc, @line_no, text, found_line =
136
+ loc_and_text(loc, @frame, @line_no, source_container)
137
+
138
+ ip_str = @frame.iseq ? " @#{frame.pc_offset}" : ''
139
+ msg "#{ev} (#{loc}#{ip_str})"
140
+
141
+ if %w(return c-return).member?(@event)
142
+ retval = Trepan::Frame.value_returned(@frame, @event)
143
+ msg 'R=> %s' % retval.inspect
144
+ end
145
+
146
+ if text && !text.strip.empty?
147
+ msg text
148
+ @line_no -= 1
149
+ end
150
+ unless found_line
151
+ # Can't find source line, so give assembly as consolation.
152
+ # This great idea comes from the Rubinius reference debugger.
153
+ run_command('disassemble')
154
154
  end
155
-
156
- def source_location_info(source_container, line_no, frame)
157
- filename = source_container[1]
158
- ## FIXME: condition is too long.
159
- canonic_filename =
160
- if 'string' == source_container[0] && frame.iseq &&
161
- frame.iseq.eval_source
162
- eval_str = frame.iseq.eval_source
163
- 'eval "' + safe_repr(eval_str.gsub(/\n/,';'), 15) + '"'
164
- else
165
- canonic_file(filename)
166
- end
167
- loc = "#{canonic_filename}:#{line_no}"
168
- return loc
169
- end # source_location_info
170
-
171
155
  end
156
+
157
+ def source_location_info(source_container, line_no, frame)
158
+ filename = source_container[1]
159
+ ## FIXME: condition is too long.
160
+ canonic_filename =
161
+ if 'string' == source_container[0] && frame.iseq &&
162
+ frame.iseq.eval_source
163
+ eval_str = frame.iseq.eval_source
164
+ 'eval "' + safe_repr(eval_str.gsub(/\n/,';'), 15) + '"'
165
+ else
166
+ canonic_file(filename, false)
167
+ end
168
+ loc = "#{canonic_filename}:#{line_no}"
169
+ return loc
170
+ end # source_location_info
172
171
  end
173
172
 
174
- if __FILE__ == $0 && caller.size == 0 && ARGV.size > 0
173
+ if __FILE__ == $0 && caller.size == 0
175
174
  # Demo it.
176
175
  require 'thread_frame'
177
176
  require_relative 'frame'
178
177
  require_relative '../app/mock'
179
- require_relative 'main' # Have to include before defining CmdProcessor!
180
- # FIXME
181
178
  class Trepan::CmdProcessor
182
179
  def errmsg(msg)
183
180
  puts msg
@@ -193,15 +190,13 @@ if __FILE__ == $0 && caller.size == 0 && ARGV.size > 0
193
190
  proc.frame_setup(RubyVM::ThreadFrame.current)
194
191
  proc.frame_initialize
195
192
 
196
- proc.location_initialize
197
193
  puts proc.canonic_file(__FILE__)
198
- proc.instance_variable_set('@settings', {:basename => true})
194
+ proc.settings[:basename] = true
199
195
  puts proc.canonic_file(__FILE__)
200
196
  puts proc.current_source_text
201
197
  xx = eval <<-END
202
198
  proc.frame_initialize
203
199
  proc.frame_setup(RubyVM::ThreadFrame.current)
204
- proc.location_initialize
205
- proc.current_source_text
200
+ puts proc.current_source_text
206
201
  END
207
202
  end