debugger-ide 0.0.1 → 0.0.2
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/Gemfile +4 -0
- data/MIT-LICENSE +24 -0
- data/Rakefile +108 -0
- data/lib/ruby-debug-ide.rb +184 -0
- data/lib/ruby-debug/command.rb +173 -0
- data/lib/ruby-debug/commands/breakpoints.rb +129 -0
- data/lib/ruby-debug/commands/catchpoint.rb +52 -0
- data/lib/ruby-debug/commands/condition.rb +51 -0
- data/lib/ruby-debug/commands/control.rb +129 -0
- data/lib/ruby-debug/commands/enable.rb +203 -0
- data/lib/ruby-debug/commands/eval.rb +64 -0
- data/lib/ruby-debug/commands/frame.rb +155 -0
- data/lib/ruby-debug/commands/inspect.rb +24 -0
- data/lib/ruby-debug/commands/jump.rb +73 -0
- data/lib/ruby-debug/commands/load.rb +18 -0
- data/lib/ruby-debug/commands/pause.rb +32 -0
- data/lib/ruby-debug/commands/set_type.rb +47 -0
- data/lib/ruby-debug/commands/stepping.rb +108 -0
- data/lib/ruby-debug/commands/threads.rb +153 -0
- data/lib/ruby-debug/commands/variables.rb +142 -0
- data/lib/ruby-debug/event_processor.rb +74 -0
- data/lib/ruby-debug/helper.rb +33 -0
- data/lib/ruby-debug/interface.rb +39 -0
- data/lib/ruby-debug/printers.rb +2 -0
- data/lib/ruby-debug/processor.rb +152 -0
- data/lib/ruby-debug/xml_printer.rb +268 -0
- metadata +28 -2
@@ -0,0 +1,152 @@
|
|
1
|
+
if RUBY_VERSION < "1.9"
|
2
|
+
require 'ruby-debug/interface'
|
3
|
+
require 'ruby-debug/command'
|
4
|
+
else
|
5
|
+
require_relative 'interface'
|
6
|
+
require_relative 'command'
|
7
|
+
end
|
8
|
+
|
9
|
+
module Debugger
|
10
|
+
|
11
|
+
class ControlCommandProcessor # :nodoc:
|
12
|
+
def initialize(interface)
|
13
|
+
@interface = interface
|
14
|
+
@printer = XmlPrinter.new(@interface)
|
15
|
+
end
|
16
|
+
|
17
|
+
def print(*args)
|
18
|
+
@interface.print(*args)
|
19
|
+
end
|
20
|
+
|
21
|
+
def process_commands
|
22
|
+
@printer.print_debug("Starting command read loop")
|
23
|
+
ctrl_cmd_classes = Command.commands.select{|cmd| cmd.control}
|
24
|
+
state = ControlState.new(@interface)
|
25
|
+
ctrl_cmds = ctrl_cmd_classes.map{|cmd| cmd.new(state, @printer)}
|
26
|
+
|
27
|
+
while input = @interface.read_command
|
28
|
+
# escape % since print_debug might use printf
|
29
|
+
@printer.print_debug "Processing: #{input.gsub('%', '%%')}"
|
30
|
+
# sleep 0.3
|
31
|
+
catch(:debug_error) do
|
32
|
+
if cmd = ctrl_cmds.find{|c| c.match(input) }
|
33
|
+
cmd.execute
|
34
|
+
else
|
35
|
+
process_context_commands(input)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
rescue IOError, Errno::EPIPE
|
40
|
+
@printer.print_error "INTERNAL ERROR!!! #{$!}\n" rescue nil
|
41
|
+
@printer.print_error $!.backtrace.map{|l| "\t#{l}"}.join("\n") rescue nil
|
42
|
+
rescue Exception
|
43
|
+
@printer.print_error "INTERNAL ERROR!!! #{$!}\n" rescue nil
|
44
|
+
@printer.print_error $!.backtrace.map{|l| "\t#{l}"}.join("\n") rescue nil
|
45
|
+
ensure
|
46
|
+
@interface.close
|
47
|
+
end
|
48
|
+
|
49
|
+
def process_context_commands(input)
|
50
|
+
unless Debugger.event_processor.at_line?
|
51
|
+
@printer.print_error "There is no thread suspended at the time and therefore no context to execute '#{input.gsub('%', '%%')}'"
|
52
|
+
return
|
53
|
+
end
|
54
|
+
context = Debugger.event_processor.context
|
55
|
+
file = Debugger.event_processor.file
|
56
|
+
line = Debugger.event_processor.line
|
57
|
+
event_cmds_classes = Command.commands.select{|cmd| cmd.event}
|
58
|
+
state = State.new do |s|
|
59
|
+
s.context = context
|
60
|
+
s.file = file
|
61
|
+
s.line = line
|
62
|
+
s.binding = context.frame_binding(0)
|
63
|
+
s.interface = @interface
|
64
|
+
end
|
65
|
+
event_cmds = event_cmds_classes.map{|cmd| cmd.new(state, @printer) }
|
66
|
+
catch(:debug_error) do
|
67
|
+
splitter[input].each do |input|
|
68
|
+
# escape % since print_debug might use printf
|
69
|
+
@printer.print_debug "Processing context: #{input.gsub('%', '%%')}"
|
70
|
+
if cmd = event_cmds.find{ |c| c.match(input) }
|
71
|
+
if context.dead? && cmd.class.need_context
|
72
|
+
@printer.print_msg "Command is unavailable\n"
|
73
|
+
else
|
74
|
+
cmd.execute
|
75
|
+
end
|
76
|
+
else
|
77
|
+
@printer.print_msg "Unknown command: #{input}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context.thread.run if state.proceed?
|
83
|
+
end
|
84
|
+
|
85
|
+
def splitter
|
86
|
+
return lambda do |str|
|
87
|
+
str.split(/;/).inject([]) do |m, v|
|
88
|
+
if m.empty?
|
89
|
+
m << v
|
90
|
+
else
|
91
|
+
if m.last[-1] == ?\\
|
92
|
+
m.last[-1,1] = ''
|
93
|
+
m.last << ';' << v
|
94
|
+
else
|
95
|
+
m << v
|
96
|
+
end
|
97
|
+
end
|
98
|
+
m
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class State # :nodoc:
|
105
|
+
|
106
|
+
attr_accessor :context, :file, :line, :binding
|
107
|
+
attr_accessor :frame_pos, :previous_line
|
108
|
+
attr_accessor :interface
|
109
|
+
|
110
|
+
def initialize
|
111
|
+
@frame_pos = 0
|
112
|
+
@previous_line = nil
|
113
|
+
@proceed = false
|
114
|
+
yield self
|
115
|
+
end
|
116
|
+
|
117
|
+
def print(*args)
|
118
|
+
@interface.print(*args)
|
119
|
+
end
|
120
|
+
|
121
|
+
def proceed?
|
122
|
+
@proceed
|
123
|
+
end
|
124
|
+
|
125
|
+
def proceed
|
126
|
+
@proceed = true
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
class ControlState # :nodoc:
|
131
|
+
|
132
|
+
def initialize(interface)
|
133
|
+
@interface = interface
|
134
|
+
end
|
135
|
+
|
136
|
+
def proceed
|
137
|
+
end
|
138
|
+
|
139
|
+
def print(*args)
|
140
|
+
@interface.print(*args)
|
141
|
+
end
|
142
|
+
|
143
|
+
def context
|
144
|
+
nil
|
145
|
+
end
|
146
|
+
|
147
|
+
def file
|
148
|
+
print "ERROR: No filename given.\n"
|
149
|
+
throw :debug_error
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,268 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module Debugger
|
5
|
+
|
6
|
+
class XmlPrinter # :nodoc:
|
7
|
+
attr_accessor :interface
|
8
|
+
|
9
|
+
def initialize(interface)
|
10
|
+
@interface = interface
|
11
|
+
end
|
12
|
+
|
13
|
+
def print_msg(*args)
|
14
|
+
msg, *args = args
|
15
|
+
xml_message = CGI.escapeHTML(msg % args)
|
16
|
+
print "<message>#{xml_message}</message>"
|
17
|
+
end
|
18
|
+
|
19
|
+
# Sends debug message to the frontend if XML debug logging flag (--xml-debug) is on.
|
20
|
+
def print_debug(*args)
|
21
|
+
Debugger.print_debug(*args)
|
22
|
+
if Debugger.xml_debug
|
23
|
+
msg, *args = args
|
24
|
+
xml_message = CGI.escapeHTML(msg % args)
|
25
|
+
@interface.print("<message debug='true'>#{xml_message}</message>")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def print_error(*args)
|
30
|
+
print_element("error") do
|
31
|
+
msg, *args = args
|
32
|
+
print CGI.escapeHTML(msg % args)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def print_frames(context, current_frame_id)
|
37
|
+
print_element("frames") do
|
38
|
+
(0...context.stack_size).each do |id|
|
39
|
+
print_frame(context, id, current_frame_id)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def print_current_frame(frame_pos)
|
45
|
+
print_debug "Selected frame no #{frame_pos}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def print_frame(context, frame_id, current_frame_id)
|
49
|
+
# idx + 1: one-based numbering as classic-debugger
|
50
|
+
file = context.frame_file(frame_id)
|
51
|
+
print "<frame no=\'%s\' file=\'%s\' line=\'%s\' #{"current='true' " if frame_id == current_frame_id}/>",
|
52
|
+
frame_id + 1, File.expand_path(file), context.frame_line(frame_id)
|
53
|
+
end
|
54
|
+
|
55
|
+
def print_contexts(contexts)
|
56
|
+
print_element("threads") do
|
57
|
+
contexts.each do |c|
|
58
|
+
print_context(c) unless c.ignored?
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def print_context(context)
|
64
|
+
current = 'current="yes"' if context.thread == Thread.current
|
65
|
+
print "<thread id=\"%s\" status=\"%s\" #{current}/>", context.thnum, context.thread.status
|
66
|
+
end
|
67
|
+
|
68
|
+
def print_variables(vars, kind)
|
69
|
+
print_element("variables") do
|
70
|
+
# print self at top position
|
71
|
+
print_variable('self', yield('self'), kind) if vars.include?('self')
|
72
|
+
vars.sort.each do |v|
|
73
|
+
print_variable(v, yield(v), kind) unless v == 'self'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def print_array(array)
|
79
|
+
print_element("variables") do
|
80
|
+
index = 0
|
81
|
+
array.each { |e|
|
82
|
+
print_variable('[' + index.to_s + ']', e, 'instance')
|
83
|
+
index += 1
|
84
|
+
}
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def print_hash(hash)
|
89
|
+
print_element("variables") do
|
90
|
+
hash.keys.each { | k |
|
91
|
+
if k.class.name == "String"
|
92
|
+
name = '\'' + k + '\''
|
93
|
+
else
|
94
|
+
name = k.to_s
|
95
|
+
end
|
96
|
+
print_variable(name, hash[k], 'instance')
|
97
|
+
}
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def print_variable(name, value, kind)
|
102
|
+
name = name.to_s
|
103
|
+
unless value
|
104
|
+
print("<variable name=\"%s\" kind=\"%s\"/>", CGI.escapeHTML(name), kind)
|
105
|
+
return
|
106
|
+
end
|
107
|
+
if value.is_a?(Array) || value.is_a?(Hash)
|
108
|
+
has_children = !value.empty?
|
109
|
+
unless has_children
|
110
|
+
value_str = "Empty #{value.class}"
|
111
|
+
else
|
112
|
+
value_str = "#{value.class} (#{value.size} element(s))"
|
113
|
+
end
|
114
|
+
else
|
115
|
+
has_children = !value.instance_variables.empty? || !value.class.class_variables.empty?
|
116
|
+
value_str = value.to_s || 'nil' rescue "<#to_s method raised exception: #$!>"
|
117
|
+
unless value_str.is_a?(String)
|
118
|
+
value_str = "ERROR: #{value.class}.to_s method returns #{value_str.class}. Should return String."
|
119
|
+
end
|
120
|
+
if value_str =~ /^\"(.*)"$/
|
121
|
+
value_str = $1
|
122
|
+
end
|
123
|
+
end
|
124
|
+
value_str = "[Binary Data]" if value_str.is_binary_data?
|
125
|
+
print("<variable name=\"%s\" kind=\"%s\" value=\"%s\" type=\"%s\" hasChildren=\"%s\" objectId=\"%#+x\"/>",
|
126
|
+
CGI.escapeHTML(name), kind, CGI.escapeHTML(value_str), value.class,
|
127
|
+
has_children, value.respond_to?(:object_id) ? value.object_id : value.id)
|
128
|
+
end
|
129
|
+
|
130
|
+
def print_breakpoints(breakpoints)
|
131
|
+
print_element 'breakpoints' do
|
132
|
+
breakpoints.sort_by{|b| b.id }.each do |b|
|
133
|
+
print "<breakpoint n=\"%d\" file=\"%s\" line=\"%s\" />", b.id, b.source, b.pos.to_s
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def print_breakpoint_added(b)
|
139
|
+
print "<breakpointAdded no=\"%s\" location=\"%s:%s\"/>", b.id, b.source, b.pos
|
140
|
+
end
|
141
|
+
|
142
|
+
def print_breakpoint_deleted(b)
|
143
|
+
print "<breakpointDeleted no=\"%s\"/>", b.id
|
144
|
+
end
|
145
|
+
|
146
|
+
def print_breakpoint_enabled(b)
|
147
|
+
print "<breakpointEnabled bp_id=\"%s\"/>", b.id
|
148
|
+
end
|
149
|
+
|
150
|
+
def print_breakpoint_disabled(b)
|
151
|
+
print "<breakpointDisabled bp_id=\"%s\"/>", b.id
|
152
|
+
end
|
153
|
+
|
154
|
+
def print_contdition_set(bp_id)
|
155
|
+
print "<conditionSet bp_id=\"%d\"/>", bp_id
|
156
|
+
end
|
157
|
+
|
158
|
+
def print_catchpoint_set(exception_class_name)
|
159
|
+
print "<catchpointSet exception=\"%s\"/>", exception_class_name
|
160
|
+
end
|
161
|
+
|
162
|
+
def print_expressions(exps)
|
163
|
+
print_element "expressions" do
|
164
|
+
exps.each_with_index do |(exp, value), idx|
|
165
|
+
print_expression(exp, value, idx+1)
|
166
|
+
end
|
167
|
+
end unless exps.empty?
|
168
|
+
end
|
169
|
+
|
170
|
+
def print_expression(exp, value, idx)
|
171
|
+
print "<dispay name=\"%s\" value=\"%s\" no=\"%d\" />", exp, value, idx
|
172
|
+
end
|
173
|
+
|
174
|
+
def print_eval(exp, value)
|
175
|
+
print "<eval expression=\"%s\" value=\"%s\" />", CGI.escapeHTML(exp), value
|
176
|
+
end
|
177
|
+
|
178
|
+
def print_pp(value)
|
179
|
+
print value
|
180
|
+
end
|
181
|
+
|
182
|
+
def print_list(b, e, file, line)
|
183
|
+
print "[%d, %d] in %s\n", b, e, file
|
184
|
+
if lines = Debugger.source_for(file)
|
185
|
+
b.upto(e) do |n|
|
186
|
+
if n > 0 && lines[n-1]
|
187
|
+
if n == line
|
188
|
+
print "=> %d %s\n", n, lines[n-1].chomp
|
189
|
+
else
|
190
|
+
print " %d %s\n", n, lines[n-1].chomp
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
else
|
195
|
+
print "No sourcefile available for %s\n", file
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def print_methods(methods)
|
200
|
+
print_element "methods" do
|
201
|
+
methods.each do |method|
|
202
|
+
print "<method name=\"%s\" />", method
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# Events
|
208
|
+
|
209
|
+
def print_breakpoint(n, breakpoint)
|
210
|
+
print("<breakpoint file=\"%s\" line=\"%s\" threadId=\"%d\"/>",
|
211
|
+
breakpoint.source, breakpoint.pos, Debugger.current_context.thnum)
|
212
|
+
end
|
213
|
+
|
214
|
+
def print_catchpoint(exception)
|
215
|
+
context = Debugger.current_context
|
216
|
+
print("<exception file=\"%s\" line=\"%s\" type=\"%s\" message=\"%s\" threadId=\"%d\"/>",
|
217
|
+
context.frame_file(0), context.frame_line(0), exception.class, CGI.escapeHTML(exception.to_s), context.thnum)
|
218
|
+
end
|
219
|
+
|
220
|
+
def print_trace(context, file, line)
|
221
|
+
Debugger::print_debug "trace: location=\"%s:%s\", threadId=%d", file, line, context.thnum
|
222
|
+
# TBD: do we want to clog fronend with the <trace> elements? There are tons of them.
|
223
|
+
# print "<trace file=\"%s\" line=\"%s\" threadId=\"%d\" />", file, line, context.thnum
|
224
|
+
end
|
225
|
+
|
226
|
+
def print_at_line(context, file, line)
|
227
|
+
print "<suspended file=\'%s\' line=\'%s\' threadId=\'%d\' frames=\'%d\'/>",
|
228
|
+
File.expand_path(file), line, context.thnum, context.stack_size
|
229
|
+
end
|
230
|
+
|
231
|
+
def print_exception(exception, binding)
|
232
|
+
print "<processingException type=\"%s\" message=\"%s\"/>",
|
233
|
+
exception.class, CGI.escapeHTML(exception.to_s)
|
234
|
+
end
|
235
|
+
|
236
|
+
def print_inspect(eval_result)
|
237
|
+
print_element("variables") do
|
238
|
+
print_variable("eval_result", eval_result, 'local')
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def print_load_result(file, exception=nil)
|
243
|
+
if exception then
|
244
|
+
print("<loadResult file=\"%s\" exceptionType=\"%s\" exceptionMessage=\"%s\"/>", file, exception.class, CGI.escapeHTML(exception.to_s))
|
245
|
+
else
|
246
|
+
print("<loadResult file=\"%s\" status=\"OK\"/>", file)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def print_element(name)
|
251
|
+
print("<#{name}>")
|
252
|
+
begin
|
253
|
+
yield
|
254
|
+
ensure
|
255
|
+
print("</#{name}>")
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
private
|
260
|
+
|
261
|
+
def print(*params)
|
262
|
+
Debugger::print_debug(*params)
|
263
|
+
@interface.print(*params)
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
267
|
+
|
268
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: debugger-ide
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: debugger
|
@@ -37,7 +37,33 @@ executables:
|
|
37
37
|
extensions: []
|
38
38
|
extra_rdoc_files: []
|
39
39
|
files:
|
40
|
+
- lib/ruby-debug/command.rb
|
41
|
+
- lib/ruby-debug/commands/breakpoints.rb
|
42
|
+
- lib/ruby-debug/commands/catchpoint.rb
|
43
|
+
- lib/ruby-debug/commands/condition.rb
|
44
|
+
- lib/ruby-debug/commands/control.rb
|
45
|
+
- lib/ruby-debug/commands/enable.rb
|
46
|
+
- lib/ruby-debug/commands/eval.rb
|
47
|
+
- lib/ruby-debug/commands/frame.rb
|
48
|
+
- lib/ruby-debug/commands/inspect.rb
|
49
|
+
- lib/ruby-debug/commands/jump.rb
|
50
|
+
- lib/ruby-debug/commands/load.rb
|
51
|
+
- lib/ruby-debug/commands/pause.rb
|
52
|
+
- lib/ruby-debug/commands/set_type.rb
|
53
|
+
- lib/ruby-debug/commands/stepping.rb
|
54
|
+
- lib/ruby-debug/commands/threads.rb
|
55
|
+
- lib/ruby-debug/commands/variables.rb
|
56
|
+
- lib/ruby-debug/event_processor.rb
|
57
|
+
- lib/ruby-debug/helper.rb
|
58
|
+
- lib/ruby-debug/interface.rb
|
59
|
+
- lib/ruby-debug/printers.rb
|
60
|
+
- lib/ruby-debug/processor.rb
|
61
|
+
- lib/ruby-debug/xml_printer.rb
|
62
|
+
- lib/ruby-debug-ide.rb
|
40
63
|
- bin/rdebug-ide
|
64
|
+
- Gemfile
|
65
|
+
- MIT-LICENSE
|
66
|
+
- Rakefile
|
41
67
|
homepage: http://github.com/astashov/debugger-ide
|
42
68
|
licenses: []
|
43
69
|
post_install_message:
|