arcadia 0.1.2.1 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README +9 -9
- data/arcadia.rb +770 -770
- data/base/a-contracts-work.rb +219 -0
- data/base/a-contracts.rb +322 -307
- data/base/a-utils.rb +993 -993
- data/conf/arcadia.conf +203 -203
- data/conf/arcadia.res.rb +1325 -1285
- data/ext/ae-complete-code/ae-complete-code.rb +80 -80
- data/ext/ae-doc-code/ae-doc-code.rb +288 -289
- data/ext/ae-editor/ae-editor.conf +105 -101
- data/ext/ae-editor/ae-editor.rb +2287 -2229
- data/ext/ae-event-log/ae-event-log.conf +5 -5
- data/ext/ae-file-history/ae-file-history.rb +2 -2
- data/ext/ae-flag/ae-flag.conf +6 -0
- data/ext/ae-flag/ae-flag.rb +12 -0
- data/ext/ae-inspector/ae-inspector.conf +7 -7
- data/ext/ae-output-event/ae-output-event.conf +15 -15
- data/ext/ae-palette/ae-palette.conf +7 -7
- data/ext/ae-ruby-debug/ae-ruby-debug.conf +20 -0
- data/ext/ae-ruby-debug/ae-ruby-debug.rb +1329 -0
- data/ext/ae-shell/ae-shell.conf +11 -11
- data/ext/ae-shell/ae-shell.rb +50 -51
- metadata +28 -5
- data/ext/ae-shell/ae-shell.rb~~ +0 -49
@@ -1,5 +1,5 @@
|
|
1
|
-
name=event-log
|
2
|
-
active=
|
3
|
-
require=ext/ae-event-log/ae-event-log
|
4
|
-
class=EventLog
|
5
|
-
|
1
|
+
name=event-log
|
2
|
+
active=no
|
3
|
+
require=ext/ae-event-log/ae-event-log
|
4
|
+
class=EventLog
|
5
|
+
|
@@ -127,10 +127,10 @@ class FileH < ArcadiaExt
|
|
127
127
|
if _event.context.file
|
128
128
|
self.add2history(_event.context.file)
|
129
129
|
add_to_tree(_event.context.file)
|
130
|
-
|
130
|
+
end
|
131
131
|
when EditorContract::FILE_AFTER_CLOSE
|
132
132
|
if _event.context.file
|
133
|
-
|
133
|
+
end
|
134
134
|
end
|
135
135
|
end
|
136
136
|
|
@@ -1,7 +1,7 @@
|
|
1
|
-
name=objic
|
2
|
-
label=Object Inspector
|
3
|
-
frame=1.0
|
4
|
-
active=yes
|
5
|
-
require=ext/ae-inspector/ae-inspector
|
6
|
-
class=ObjiController
|
7
|
-
|
1
|
+
name=objic
|
2
|
+
label=Object Inspector
|
3
|
+
frame=1.0
|
4
|
+
active=yes
|
5
|
+
require=ext/ae-inspector/ae-inspector
|
6
|
+
class=ObjiController
|
7
|
+
|
@@ -1,15 +1,15 @@
|
|
1
|
-
name=output2
|
2
|
-
label=Event Log
|
3
|
-
frame=1.1
|
4
|
-
active=
|
5
|
-
require=ext/ae-output/ae-output
|
6
|
-
class=Output
|
7
|
-
MsgContract.channel=CH1
|
8
|
-
|
9
|
-
|
10
|
-
font=courier 10
|
11
|
-
font.bold=courier 10 bold
|
12
|
-
freebsd::font=courier 10
|
13
|
-
freebsd::font.bold=courier 12 bold
|
14
|
-
win::font={Courier New} 9
|
15
|
-
win::font.bold={Courier New} 9 bold
|
1
|
+
name=output2
|
2
|
+
label=Event Log
|
3
|
+
frame=1.1
|
4
|
+
active=no
|
5
|
+
require=ext/ae-output/ae-output
|
6
|
+
class=Output
|
7
|
+
MsgContract.channel=CH1
|
8
|
+
|
9
|
+
|
10
|
+
font=courier 10
|
11
|
+
font.bold=courier 10 bold
|
12
|
+
freebsd::font=courier 10
|
13
|
+
freebsd::font.bold=courier 12 bold
|
14
|
+
win::font={Courier New} 9
|
15
|
+
win::font.bold={Courier New} 9 bold
|
@@ -1,7 +1,7 @@
|
|
1
|
-
name=palette
|
2
|
-
label=Palette
|
3
|
-
frame=0.0
|
4
|
-
active=yes
|
5
|
-
require=ext/ae-palette/ae-palette
|
6
|
-
class=Palette
|
7
|
-
|
1
|
+
name=palette
|
2
|
+
label=Palette
|
3
|
+
frame=0.0
|
4
|
+
active=yes
|
5
|
+
require=ext/ae-palette/ae-palette
|
6
|
+
class=Palette
|
7
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#==============================================================
|
2
|
+
name=ruby-debug
|
3
|
+
label=Ruby Debug
|
4
|
+
frame=1.0
|
5
|
+
active=yes
|
6
|
+
require=ext/ae-ruby-debug/ae-ruby-debug
|
7
|
+
class=RubyDebug
|
8
|
+
#==============================================================
|
9
|
+
server.host=localhost
|
10
|
+
server.port=8989
|
11
|
+
server.timeout=10
|
12
|
+
font=courier 10
|
13
|
+
font.bold=courier 10 bold
|
14
|
+
color.background=#ffffff
|
15
|
+
color.foreground=#000000
|
16
|
+
freebsd::font=courier 10
|
17
|
+
freebsd::font.bold=courier 10 bold
|
18
|
+
win::font={Courier New} 8
|
19
|
+
win::font.bold={Courier New} 8 bold
|
20
|
+
|
@@ -0,0 +1,1329 @@
|
|
1
|
+
#
|
2
|
+
# ae-ruby-debug.rb - Arcadia Ruby ide
|
3
|
+
# by Antonio Galeone <antonio-galeone@rubyforge.org>
|
4
|
+
#
|
5
|
+
|
6
|
+
class RubyDebugView
|
7
|
+
def initialize(_frame, _controller)
|
8
|
+
@frame = _frame
|
9
|
+
@controller = _controller
|
10
|
+
self.build_ui
|
11
|
+
@controller.rdc.add_listener(self)
|
12
|
+
@nodes_to_open = Array.new
|
13
|
+
#@break_hash = Hash.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def build_buttons_set
|
17
|
+
_relief = 'groove'
|
18
|
+
@debug_button_box.add(
|
19
|
+
'name'=>'debug_over',
|
20
|
+
'background' => 'white',
|
21
|
+
'anchor' => 'nw',
|
22
|
+
'command'=>proc{self.debug_send(:step_over)},
|
23
|
+
'helptext'=>'step over',
|
24
|
+
'image'=> TkPhotoImage.new('dat' => D_NEXT_GIF),
|
25
|
+
'relief'=> _relief
|
26
|
+
)
|
27
|
+
@debug_button_box.add(
|
28
|
+
'name'=>'debug_into',
|
29
|
+
'background' => 'white',
|
30
|
+
'anchor' => 'nw',
|
31
|
+
'command'=>proc{self.debug_send(:step_into)},
|
32
|
+
'helptext'=>'step into',
|
33
|
+
'image'=> TkPhotoImage.new('dat' => D_STEP_INTO_GIF),
|
34
|
+
'relief'=>_relief
|
35
|
+
)
|
36
|
+
@debug_button_box.add(
|
37
|
+
'name'=>'debug_out',
|
38
|
+
'background' => 'white',
|
39
|
+
'anchor' => 'nw',
|
40
|
+
'helptext'=>'step out',
|
41
|
+
'command'=>proc{self.debug_send(:step_out)},
|
42
|
+
'image'=> TkPhotoImage.new('dat' => D_STEP_OUT_GIF),
|
43
|
+
'relief'=>_relief
|
44
|
+
)
|
45
|
+
@debug_button_box.add(
|
46
|
+
'name'=>'debug_resume',
|
47
|
+
'background' => 'white',
|
48
|
+
'anchor' => 'nw',
|
49
|
+
'helptext'=>'resume',
|
50
|
+
'image'=> TkPhotoImage.new('dat' => D_RESUME_GIF),
|
51
|
+
'command'=>proc{self.debug_send(:resume)},
|
52
|
+
'relief'=>_relief
|
53
|
+
)
|
54
|
+
|
55
|
+
@debug_button_box.add(
|
56
|
+
'name'=>'debug_quit',
|
57
|
+
'background' => 'white',
|
58
|
+
'anchor' => 'nw',
|
59
|
+
'helptext'=>'quit',
|
60
|
+
'image'=> TkPhotoImage.new('dat' => D_QUIT_GIF),
|
61
|
+
'command'=>proc{self.debug_send(:quit)},
|
62
|
+
'relief'=>_relief
|
63
|
+
)
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
def build_ui
|
68
|
+
_y = 22
|
69
|
+
@debug_button_box = Tk::BWidget::ButtonBox.new(@frame){
|
70
|
+
homogeneous true
|
71
|
+
state 'disabled'
|
72
|
+
#background '#3d7956'
|
73
|
+
}.place('height'=> _y)
|
74
|
+
|
75
|
+
@debug_frame = TkFrame.new(@frame){
|
76
|
+
border 2
|
77
|
+
place(
|
78
|
+
'y'=>_y,
|
79
|
+
'height'=> -_y,
|
80
|
+
'relheight'=> 1,
|
81
|
+
'relwidth'=> 1
|
82
|
+
)
|
83
|
+
}
|
84
|
+
|
85
|
+
self.build_buttons_set
|
86
|
+
|
87
|
+
sf = AGTkOSplittedFrames.new(@debug_frame,70)
|
88
|
+
|
89
|
+
#-------------------------------------------------
|
90
|
+
build_process_panel(sf.top_frame)
|
91
|
+
#-------------------------------------------------
|
92
|
+
|
93
|
+
@enb = Tk::BWidget::NoteBook.new(sf.bottom_frame){
|
94
|
+
tabbevelsize 0
|
95
|
+
internalborderwidth 2
|
96
|
+
activeforeground 'red'
|
97
|
+
activebackground 'yellow'
|
98
|
+
#background 'black'
|
99
|
+
borderwidth 1
|
100
|
+
side $arcadia['conf']['editor.tabs.side']
|
101
|
+
font $arcadia['conf']['editor.tabs.font']
|
102
|
+
place('relwidth' => 1,'relheight' => '1')
|
103
|
+
}
|
104
|
+
_tab_var = @enb.insert('end', 'vars' ,
|
105
|
+
'text'=> 'Variables',
|
106
|
+
'raisecmd'=>proc{}
|
107
|
+
)
|
108
|
+
_tab_breakpoint = @enb.insert('end', 'Breakpoint' ,
|
109
|
+
'text'=> 'Breakpoints',
|
110
|
+
'raisecmd'=>proc{}
|
111
|
+
)
|
112
|
+
# _tab_catchpoint = @enb.insert('end', 'catchpoint' ,
|
113
|
+
# 'text'=> 'catchpoint',
|
114
|
+
# 'raisecmd'=>proc{}
|
115
|
+
# )
|
116
|
+
|
117
|
+
build_var_panel(_tab_var)
|
118
|
+
build_break_panel(_tab_breakpoint)
|
119
|
+
|
120
|
+
@stack_nodes = Array.new
|
121
|
+
@enb.raise('vars')
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
def build_process_panel(_frame)
|
126
|
+
@tree_process = Tk::BWidget::Tree.new(_frame){
|
127
|
+
background '#FFFFFF'
|
128
|
+
relief 'flat'
|
129
|
+
showlines false
|
130
|
+
deltay 15
|
131
|
+
place('relwidth' => 1,'relheight' => '1')
|
132
|
+
}
|
133
|
+
@tree_process.textbind("Double-ButtonPress-1", proc{
|
134
|
+
_selected = @tree_process.selection_get[0]
|
135
|
+
if @tree_process.parent(_selected)=='client'
|
136
|
+
_text = @tree_process.itemcget(_selected, 'text')
|
137
|
+
pos = match_position_from_stack(_text)
|
138
|
+
if pos.length >0
|
139
|
+
EditorContract.instance.open_file(self, 'file'=>pos[0], 'line'=>pos[1])
|
140
|
+
end
|
141
|
+
end
|
142
|
+
})
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
def start_process(_filename)
|
147
|
+
@tree_process.insert('end', 'root' ,'server', {
|
148
|
+
'text' => "Server => #{File.basename(_filename)} at #{@controller.conf('server.host')}:#{@controller.conf('server.port')}",
|
149
|
+
'font' => @controller.conf('font.bold')
|
150
|
+
})
|
151
|
+
@tree_process.insert('end', 'server' ,'client', {
|
152
|
+
'font' => @controller.conf('font.bold'),
|
153
|
+
'text' => "Client"
|
154
|
+
})
|
155
|
+
@tree_process.open_tree('server',true)
|
156
|
+
end
|
157
|
+
|
158
|
+
def tree_var_free
|
159
|
+
@tree_var.delete(@tree_var.nodes('local_var'))
|
160
|
+
@tree_var.delete(@tree_var.nodes('instance_var'))
|
161
|
+
@tree_var.delete(@tree_var.nodes('global_var'))
|
162
|
+
@tree_var.delete(@tree_var.nodes('eval')) if @tree_var.exist?('eval')
|
163
|
+
end
|
164
|
+
|
165
|
+
def tree_process_free
|
166
|
+
@tree_process.delete(@tree_process.nodes('root'))
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
def build_var_panel(_frame)
|
171
|
+
_open_proc = proc do |_arg|
|
172
|
+
inspect_node(_arg) if @nodes_to_open.include?(_arg)
|
173
|
+
end
|
174
|
+
|
175
|
+
@tree_var = Tk::BWidget::Tree.new(_frame){
|
176
|
+
background '#FFFFFF'
|
177
|
+
relief 'flat'
|
178
|
+
showlines true
|
179
|
+
linesfill '#e7de8f'
|
180
|
+
deltay 15
|
181
|
+
opencmd _open_proc
|
182
|
+
# pack('fill'=>'both', :padx=>0, :pady=>0, :expand => 'yes')
|
183
|
+
}.place('relwidth' => 1,'relheight' => '1','bordermode' => 'inside')
|
184
|
+
|
185
|
+
_scrollcommand = proc{|*args| @tree_var.yview(*args)}
|
186
|
+
_scrollbar = TkScrollbar.new(_frame){|s|
|
187
|
+
width 8
|
188
|
+
command _scrollcommand
|
189
|
+
}.pack('side'=>'right', 'fill'=>'y')
|
190
|
+
@tree_var.yscrollcommand proc{|first,last| _scrollbar.set(first,last)}
|
191
|
+
|
192
|
+
@local_on = true
|
193
|
+
@instance_on = true
|
194
|
+
@global_on = false
|
195
|
+
|
196
|
+
_i_on = TkPhotoImage.new('dat' => ON_GIF)
|
197
|
+
_i_off = TkPhotoImage.new('dat' => OFF_GIF)
|
198
|
+
|
199
|
+
_b_relief = 'groove'
|
200
|
+
@b_local_onoff = TkButton.new(@tree_var){
|
201
|
+
image _i_on
|
202
|
+
relief _b_relief
|
203
|
+
state 'disabled'
|
204
|
+
anchor 'nw'
|
205
|
+
}.bind("1",proc{
|
206
|
+
@local_on = !@local_on
|
207
|
+
if @local_on
|
208
|
+
@b_local_onoff.image(_i_on)
|
209
|
+
command_enabled(false)
|
210
|
+
Thread.new{
|
211
|
+
update_variables('local_var', @controller.rdc.variables('local_variables')) #if @tree_var.open?('local_var')
|
212
|
+
command_enabled(true)
|
213
|
+
}
|
214
|
+
else
|
215
|
+
@b_local_onoff.image(_i_off)
|
216
|
+
@tree_var.delete(@tree_var.nodes('local_var'))
|
217
|
+
end
|
218
|
+
})
|
219
|
+
|
220
|
+
@tree_var.insert('end', 'root' ,'local_var', {
|
221
|
+
#'deltax' => 0,
|
222
|
+
#'padx'=>2,
|
223
|
+
'fill'=>'#3f941b',
|
224
|
+
'open'=>true,
|
225
|
+
'anchor'=>'w',
|
226
|
+
'font' => @controller.conf('font.bold'),
|
227
|
+
'text' => "Local variables",
|
228
|
+
'window' => @b_local_onoff
|
229
|
+
})
|
230
|
+
|
231
|
+
@b_instance_onoff = TkButton.new(@tree_var){
|
232
|
+
image _i_on
|
233
|
+
relief _b_relief
|
234
|
+
state 'disabled'
|
235
|
+
anchor 'nw'
|
236
|
+
}.bind("1",proc{
|
237
|
+
@instance_on = !@instance_on
|
238
|
+
if @instance_on
|
239
|
+
@b_instance_onoff.image(_i_on)
|
240
|
+
command_enabled(false)
|
241
|
+
Thread.new{
|
242
|
+
update_variables('instance_var', @controller.rdc.variables('instance_variables')) #if @tree_var.open?('local_var')
|
243
|
+
command_enabled(true)
|
244
|
+
}
|
245
|
+
else
|
246
|
+
@b_instance_onoff.image(_i_off)
|
247
|
+
@tree_var.delete(@tree_var.nodes('instance_var'))
|
248
|
+
end
|
249
|
+
})
|
250
|
+
@tree_var.insert('end', 'root' ,'instance_var', {
|
251
|
+
# 'deltax' => 0,
|
252
|
+
# 'padx'=>2,
|
253
|
+
'fill'=>'#892541',
|
254
|
+
'open'=>true,
|
255
|
+
'anchor'=>'w',
|
256
|
+
'font' => @controller.conf('font.bold'),
|
257
|
+
'text' => "Instance variables",
|
258
|
+
'window' => @b_instance_onoff
|
259
|
+
})
|
260
|
+
|
261
|
+
@b_global_onoff = TkButton.new(@tree_var){
|
262
|
+
image _i_off
|
263
|
+
relief _b_relief
|
264
|
+
state 'disabled'
|
265
|
+
anchor 'nw'
|
266
|
+
}.bind("1",proc{
|
267
|
+
@global_on = !@global_on
|
268
|
+
if @global_on
|
269
|
+
@b_global_onoff.image(_i_on)
|
270
|
+
command_enabled(false)
|
271
|
+
Thread.new{
|
272
|
+
update_variables('global_var', @controller.rdc.variables('global_variables')) #if @tree_var.open?('local_var')
|
273
|
+
command_enabled(true)
|
274
|
+
}
|
275
|
+
else
|
276
|
+
@b_global_onoff.image(_i_off)
|
277
|
+
@tree_var.delete(@tree_var.nodes('global_var'))
|
278
|
+
end
|
279
|
+
})
|
280
|
+
@tree_var.insert('end', 'root' ,'global_var', {
|
281
|
+
'fill'=>'#f94867',
|
282
|
+
'open'=>true,
|
283
|
+
'anchor'=>'w',
|
284
|
+
'font' => @controller.conf('font.bold'),
|
285
|
+
'text' => "Global variables",
|
286
|
+
'window' => @b_global_onoff
|
287
|
+
})
|
288
|
+
|
289
|
+
|
290
|
+
|
291
|
+
end
|
292
|
+
|
293
|
+
def build_break_panel(_tab_breakpoint)
|
294
|
+
@tree_break = Tk::BWidget::Tree.new(_tab_breakpoint){
|
295
|
+
background '#FFFFFF'
|
296
|
+
relief 'flat'
|
297
|
+
showlines true
|
298
|
+
linesfill '#e7de8f'
|
299
|
+
deltay 15
|
300
|
+
}.place('relwidth' => 1,'relheight' => '1')
|
301
|
+
end
|
302
|
+
|
303
|
+
def file2node_name(_file)
|
304
|
+
_s = ""
|
305
|
+
_file.gsub("/",_s).gsub(".",_s).gsub(":",_s).gsub("\\",_s).gsub("-",_s)
|
306
|
+
end
|
307
|
+
|
308
|
+
def line2node_name(_parent, _line)
|
309
|
+
"#{_parent}_#{_line.to_s}"
|
310
|
+
end
|
311
|
+
|
312
|
+
def break_list_add(_file, _line)
|
313
|
+
_file_node = file2node_name(_file)
|
314
|
+
_line_node = line2node_name(_file_node, _line)
|
315
|
+
if !@tree_break.exist?(_file_node)
|
316
|
+
@tree_break.insert('end', 'root' ,_file_node, {
|
317
|
+
'fill'=>'#8080ff',
|
318
|
+
'open'=>true,
|
319
|
+
'anchor'=>'w',
|
320
|
+
'font' => @controller.conf('font.bold'),
|
321
|
+
'text' => _file
|
322
|
+
})
|
323
|
+
end
|
324
|
+
|
325
|
+
if !@tree_break.exist?(_line_node)
|
326
|
+
@tree_break.insert('end', _file_node ,_line_node, {
|
327
|
+
'fill'=>'#f94867',
|
328
|
+
'open'=>true,
|
329
|
+
'anchor'=>'w',
|
330
|
+
'font' => @controller.conf('font.bold'),
|
331
|
+
'text' => "line: #{_line}"
|
332
|
+
})
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
def break_list_del(_file, _line)
|
337
|
+
_file_node = file2node_name(_file)
|
338
|
+
_line_node = line2node_name(_file_node, _line)
|
339
|
+
if @tree_break.exist?(_line_node)
|
340
|
+
@tree_break.delete(_line_node)
|
341
|
+
_bro = @tree_break.nodes(_file_node)
|
342
|
+
if _bro && _bro.length > 0
|
343
|
+
@tree_break.delete(_file_node)
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
def break_list_select(_file, _line)
|
349
|
+
_file_node = file2node_name(_file)
|
350
|
+
_line_node = line2node_name(_file_node, _line)
|
351
|
+
@tree_break.selection_clear
|
352
|
+
if @tree_break.exist?(_line_node)
|
353
|
+
@tree_break.selection_add(_line_node)
|
354
|
+
@tree_break.see(_line_node)
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
|
359
|
+
def break_list_free
|
360
|
+
@tree_break.delete(@tree_break.nodes('root'))
|
361
|
+
end
|
362
|
+
|
363
|
+
def clear
|
364
|
+
tree_var_free
|
365
|
+
tree_process_free
|
366
|
+
break_list_free
|
367
|
+
end
|
368
|
+
|
369
|
+
|
370
|
+
def rdebug_client_update(_command, _result)
|
371
|
+
#MsgContract.instance.out_debug(self,"on command #{_command}")
|
372
|
+
return if !@controller.rdc.is_debugging_ready?
|
373
|
+
begin
|
374
|
+
if _command == 'quit'
|
375
|
+
msg = "Really quit debug ? (y/n)"
|
376
|
+
ans = Tk.messageBox('icon' => 'question', 'type' => 'yesno',
|
377
|
+
'title' => '(Arcadia) Debug', 'message' => msg)
|
378
|
+
if ans == 'yes'
|
379
|
+
debug_send(:quit_yes)
|
380
|
+
clear
|
381
|
+
else
|
382
|
+
debug_send(:quit_no)
|
383
|
+
end
|
384
|
+
elsif _command == 'quit_yes'
|
385
|
+
clear
|
386
|
+
elsif _command == 'quit_no'
|
387
|
+
command_enabled(true)
|
388
|
+
elsif _command != 'where' && _command != 'quit_yes'
|
389
|
+
begin
|
390
|
+
update_position
|
391
|
+
update_variables('local_var', @controller.rdc.variables('local_variables')) if @local_on
|
392
|
+
update_variables('instance_var', @controller.rdc.variables('instance_variables')) if @instance_on
|
393
|
+
#MsgContract.instance.out_debug(self,"on command #{_command}:global_variables")
|
394
|
+
update_variables('global_var', @controller.rdc.variables('global_variables')) if @global_on
|
395
|
+
ensure
|
396
|
+
command_enabled(true) if @controller.rdc.is_debugging_ready? && (!_command.include?('quit') || _command.include?('quit_no'))
|
397
|
+
end
|
398
|
+
end
|
399
|
+
rescue Exception => e
|
400
|
+
MsgContract.instance.out_debug(self,"on command #{_command}:#{e.inspect}")
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
def match_position_from_stack(_line)
|
405
|
+
ret = Array.new
|
406
|
+
_target = _line.sub("-->",'').strip
|
407
|
+
matchline = _target.match(/#[0-9]*.*:([0-9]*)/)
|
408
|
+
line_no = matchline[1].to_i if !matchline.nil? && matchline.length==2
|
409
|
+
matchfile = _target.match(/#[0-9]*.(.*):[0-9]*/)
|
410
|
+
filename = matchfile[1].to_s if !matchfile.nil? && matchfile.length==2
|
411
|
+
if filename && line_no
|
412
|
+
ret << filename << line_no
|
413
|
+
end
|
414
|
+
ret
|
415
|
+
end
|
416
|
+
|
417
|
+
def update_position
|
418
|
+
stack = @controller.rdc.where
|
419
|
+
#MsgContract.instance.out_debug(self,stack)
|
420
|
+
if !stack.nil?
|
421
|
+
stack = stack.split(/\n/)
|
422
|
+
line_no = -1
|
423
|
+
if !stack[0].nil?
|
424
|
+
pos = match_position_from_stack(stack[0])
|
425
|
+
#matchline = stack[0].match(/-->.#[0-9]*.*:([0-9]*)/)
|
426
|
+
##matchline = stack[0].match(/.*:([0-9]*)/)
|
427
|
+
#line_no = matchline[1].to_i if !matchline.nil? && matchline.length==2
|
428
|
+
|
429
|
+
#matchfile = stack[0].match(/-->.#[0-9]*.(.*):[0-9]*/)
|
430
|
+
##matchfile = stack[0].match(/.(.*):[0-9]*/)
|
431
|
+
|
432
|
+
#filename = matchfile[1].to_s if !matchfile.nil? && matchfile.length==2
|
433
|
+
end
|
434
|
+
if pos.length > 0
|
435
|
+
#MsgContract.instance.out_debug(self,"'file'=> #{pos[0]}, 'line'=>#{pos[1]}")
|
436
|
+
_file = File.expand_path(pos[0])
|
437
|
+
DebugContract.instance.debug_step(self, 'file'=> _file, 'line'=>pos[1])
|
438
|
+
break_list_select(_file, pos[1].to_s)
|
439
|
+
end
|
440
|
+
i = 0
|
441
|
+
@tree_process.delete(@stack_nodes)
|
442
|
+
stack.each do |line|
|
443
|
+
_node = "c#{i.to_s}"
|
444
|
+
@tree_process.insert('end', 'client' ,_node, {
|
445
|
+
# 'deltax' => 0,
|
446
|
+
# 'padx'=>2,
|
447
|
+
'font' => @controller.conf('font'),
|
448
|
+
'text' => line,
|
449
|
+
'helptext' => line
|
450
|
+
})
|
451
|
+
@stack_nodes << _node
|
452
|
+
i = i+1
|
453
|
+
end
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
def is_simple_class?(_class)
|
458
|
+
['Numeric','Fixnum','String','FalseClass','TrueClass','NilClass'].include?(_class)
|
459
|
+
# _class == Numeric || _class.superclass == Numeric ||
|
460
|
+
# _class == String || _class.superclass == String ||
|
461
|
+
# _class == FalseClass || _class.superclass == FalseClass||
|
462
|
+
# _class == TrueClass || _class.superclass == TrueClass||
|
463
|
+
# _class == NilClass || _class.superclass == NilClass
|
464
|
+
end
|
465
|
+
|
466
|
+
def show_expression(_exp, _hash)
|
467
|
+
if !@tree_var.exist?('eval')
|
468
|
+
@tree_var.insert('end', 'root' ,'eval', {
|
469
|
+
'fill'=>'#4aadf7',
|
470
|
+
'open'=>true,
|
471
|
+
'anchor'=>'w',
|
472
|
+
'font' => @controller.conf('font.bold'),
|
473
|
+
'text' => "Eval selection"
|
474
|
+
})
|
475
|
+
end
|
476
|
+
update_variables('eval', _hash)
|
477
|
+
end
|
478
|
+
|
479
|
+
def inspect_node(_node)
|
480
|
+
command_enabled(false)
|
481
|
+
begin
|
482
|
+
_var = var_name(_node)
|
483
|
+
_o = @controller.rdc.debug_dump(_var)
|
484
|
+
#@tree_var.delete(@tree_var.nodes(_node))
|
485
|
+
var_deep(_node, _o)
|
486
|
+
ensure
|
487
|
+
command_enabled(true)
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
def var_deep(_var, _hash)
|
492
|
+
# _var_cla = _hash['__CLASS__']
|
493
|
+
# _var_len = _hash['__LENGTH__']
|
494
|
+
# @tree_var.itemconfigure(_var, 'text' => "#{_var_cla}:#{_var_len}")
|
495
|
+
return nil if _hash.nil?
|
496
|
+
return _hash.to_s if _hash.class != Hash
|
497
|
+
_hash.keys.sort.each{|k|
|
498
|
+
v = _hash[k]
|
499
|
+
next if k=='__CLASS__'
|
500
|
+
_complex = v.class == Hash
|
501
|
+
if _complex
|
502
|
+
_text = var_format(k,v['__CLASS__'])
|
503
|
+
elsif (k=='__LENGTH__') && v=='0'
|
504
|
+
_text = '{...}'
|
505
|
+
elsif (k=='__LENGTH__') && v!='0'
|
506
|
+
next
|
507
|
+
else
|
508
|
+
_text = var_format(k,nil,v)
|
509
|
+
end
|
510
|
+
_node = node_name(k, _var)
|
511
|
+
if @tree_var.exist?(_node)
|
512
|
+
@tree_var.itemconfigure(_node, 'text' => _text)
|
513
|
+
else
|
514
|
+
@tree_var.insert('end', _var ,_node, {
|
515
|
+
'font' => @controller.conf('font'),
|
516
|
+
'text' => _text,
|
517
|
+
'helptext' => v,
|
518
|
+
'anchor'=>'w'
|
519
|
+
})
|
520
|
+
end
|
521
|
+
var_deep(_node,v) if _complex
|
522
|
+
}
|
523
|
+
end
|
524
|
+
|
525
|
+
def var_format(_name, _class, _value=nil)
|
526
|
+
if !_value.nil? && !_class.nil?
|
527
|
+
return "#{_name.to_s.strip} => #{_value.to_s.strip} [#{_class.to_s.strip}]"
|
528
|
+
elsif _value.nil? && !_class.nil?
|
529
|
+
return "#{_name.to_s.strip} [#{_class.to_s.strip}]"
|
530
|
+
elsif !_value.nil? && _class.nil?
|
531
|
+
return "#{_name.to_s.strip} => #{_value.to_s.strip}"
|
532
|
+
elsif _value.nil? && _class.nil?
|
533
|
+
return "#{_name.to_s.strip} => {...}"
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
def node_name(_node, _parent)
|
538
|
+
return "#{_parent}@@@#{_node.gsub('$','__S__').gsub('&','__E__').gsub(':','__D__').gsub('!','__A__')}"
|
539
|
+
end
|
540
|
+
|
541
|
+
def var_name(_node)
|
542
|
+
#_parent = @tree_var.parent(_node)
|
543
|
+
#return _node.sub("#{_parent}_", '')
|
544
|
+
return _node.split('@@@')[-1].gsub('__S__','$').gsub('__E__','&').gsub('__D__',':').gsub('__A__','!')
|
545
|
+
end
|
546
|
+
|
547
|
+
def command_enabled(_value)
|
548
|
+
#MsgContract.instance.out_debug(self,"command_enabled= #{_value.to_s}")
|
549
|
+
|
550
|
+
@c_on = _value
|
551
|
+
_value ? _state = 'normal':_state = 'disabled'
|
552
|
+
@debug_button_box.configure(:state=>_state)
|
553
|
+
@b_local_onoff.configure(:state=>_state)
|
554
|
+
@b_instance_onoff.configure(:state=>_state)
|
555
|
+
@b_global_onoff.configure(:state=>_state)
|
556
|
+
Tk.update
|
557
|
+
end
|
558
|
+
|
559
|
+
def update_variables(_parent_node, _var)
|
560
|
+
if _var.keys.sort == @tree_var.nodes(_parent_node).collect! {|x| var_name(x).to_s}.sort
|
561
|
+
_var.each{|k,v|
|
562
|
+
_n = node_name(k, _parent_node)
|
563
|
+
if is_simple_class?(v.value_class)
|
564
|
+
_text = var_format(k,v.value_class,v.value)
|
565
|
+
else
|
566
|
+
_text = var_format(k,v.value_class)
|
567
|
+
end
|
568
|
+
_node = @tree_var.itemconfigure(_n, 'text' => _text)
|
569
|
+
}
|
570
|
+
else
|
571
|
+
@nodes_to_open.clear
|
572
|
+
@tree_var.delete(@tree_var.nodes(_parent_node))
|
573
|
+
#@nodes[_parent_node].clear
|
574
|
+
_var.each{|k,v|
|
575
|
+
_n = node_name(k, _parent_node)
|
576
|
+
if is_simple_class?(v.value_class)
|
577
|
+
#MsgContract.instance.out_simple(self,"#{k} : simple")
|
578
|
+
_text = var_format(k,v.value_class,v.value)
|
579
|
+
_drawcross = 'auto'
|
580
|
+
else
|
581
|
+
#MsgContract.instance.out_simple(self,"#{k} : complex")
|
582
|
+
_text = var_format(k,v.value_class)
|
583
|
+
_drawcross = 'always'
|
584
|
+
@nodes_to_open << _n
|
585
|
+
end
|
586
|
+
@tree_var.insert('end', _parent_node ,_n, {
|
587
|
+
'font' => @controller.conf('font'),
|
588
|
+
'text' => _text,
|
589
|
+
'helptext' => v.value,
|
590
|
+
'drawcross' => _drawcross,
|
591
|
+
'anchor'=>'w'
|
592
|
+
# 'deltax' => 1
|
593
|
+
})
|
594
|
+
#@nodes[_parent_node] << k
|
595
|
+
}
|
596
|
+
end
|
597
|
+
Tk.update
|
598
|
+
end
|
599
|
+
|
600
|
+
def debug_send(_command)
|
601
|
+
if @controller.rdc
|
602
|
+
begin
|
603
|
+
command_enabled(false)
|
604
|
+
#@debug_button_box.configure(:state=>'disabled')
|
605
|
+
Thread.new{@controller.rdc.send(_command)}
|
606
|
+
#@controller.rdc.send(_command)
|
607
|
+
rescue Exception => e
|
608
|
+
MsgContract.instance.out_debug(self,"---> "+e.to_s)
|
609
|
+
end
|
610
|
+
end
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
class RubyDebugException < Exception
|
615
|
+
end
|
616
|
+
|
617
|
+
class RubyDebugServer
|
618
|
+
include Observable
|
619
|
+
RDS_QUIET = 'RDS_QUIET'
|
620
|
+
def initialize(_caller)
|
621
|
+
if _caller.respond_to? :rdebug_server_update
|
622
|
+
ObserverCallback.new(self,_caller,:rdebug_server_update)
|
623
|
+
end
|
624
|
+
end
|
625
|
+
|
626
|
+
def start_session(_filename, _host='localhost', _remote_port='8989')
|
627
|
+
if is_windows?
|
628
|
+
commandLine = "rdebug.cmd --port #{_remote_port} -sw #{_filename}"
|
629
|
+
else
|
630
|
+
commandLine = "rdebug --host #{_host} --port #{_remote_port} -sw #{_filename}"
|
631
|
+
end
|
632
|
+
#MsgContract.instance.out_debug(self,commandLine)
|
633
|
+
begin
|
634
|
+
if is_windows?
|
635
|
+
@tid = Thread.new {
|
636
|
+
Kernel.system(commandLine)
|
637
|
+
Kernel.system('y')
|
638
|
+
notify(RDS_QUIET)
|
639
|
+
}
|
640
|
+
else
|
641
|
+
@pid = Process.fork {
|
642
|
+
Kernel.system(commandLine)
|
643
|
+
Kernel.exit!
|
644
|
+
notify(RDS_QUIET)
|
645
|
+
}
|
646
|
+
end
|
647
|
+
rescue Exception => e
|
648
|
+
MsgContract.instance.out_debug(self,"Error on start_server : #{e.class}:#{e.message}")
|
649
|
+
end
|
650
|
+
end
|
651
|
+
|
652
|
+
def kill
|
653
|
+
begin
|
654
|
+
if is_windows?
|
655
|
+
@tid.join(2)
|
656
|
+
@tid.kill!
|
657
|
+
else
|
658
|
+
Process.kill('QUIT',@pid)
|
659
|
+
end
|
660
|
+
notify(RDS_QUIET)
|
661
|
+
rescue Exception => e
|
662
|
+
MsgContract.instance.out_debug(self,"Error on start_server : #{e.class}:#{e.message}")
|
663
|
+
end
|
664
|
+
end
|
665
|
+
|
666
|
+
def is_windows?
|
667
|
+
!(RUBY_PLATFORM =~ /(win|w)32$/).nil?
|
668
|
+
#RUBY_PLATFORM.include?('win')
|
669
|
+
end
|
670
|
+
|
671
|
+
def notify(_state)
|
672
|
+
changed
|
673
|
+
notify_observers(_state)
|
674
|
+
end
|
675
|
+
|
676
|
+
end
|
677
|
+
|
678
|
+
#Ruby-debug commands
|
679
|
+
|
680
|
+
# * b[reak]
|
681
|
+
# list breakpoints
|
682
|
+
# * b[reak] [file|class:]LINE|METHOD [if expr]
|
683
|
+
# * b[reak] [class.]LINE|METHOD [if expr]
|
684
|
+
# set breakpoint to some position, optionally if expr == true
|
685
|
+
# * cat[ch]
|
686
|
+
# show catchpoint
|
687
|
+
# * cat[ch] EXCEPTION
|
688
|
+
# set catchpoint to an exception
|
689
|
+
# * disp[lay] EXPRESSION add expression into display expression list
|
690
|
+
# * undisp[lay][ nnn]
|
691
|
+
# delete one particular or all display expressions if no expression number given
|
692
|
+
# * del[ete][ nnn]
|
693
|
+
# delete some or all breakpoints (get the number using break)
|
694
|
+
# * c[ont]
|
695
|
+
# run until program ends or hit breakpoint
|
696
|
+
# * r[un]
|
697
|
+
# alias for cont
|
698
|
+
# * s[tep][ nnn]
|
699
|
+
# step (into methods) one line or till line nnn
|
700
|
+
# * n[ext][ nnn]
|
701
|
+
# go over one line or till line nnn
|
702
|
+
# * w[here]
|
703
|
+
# displays stack
|
704
|
+
# * f[rame]
|
705
|
+
# alias for where
|
706
|
+
# * l[ist][ (-|nn-mm)]
|
707
|
+
# list program, - list backwards, nn-mm list given lines. No arguments keeps listing
|
708
|
+
# * up[ nn]
|
709
|
+
# move to higher frame
|
710
|
+
# * down[ nn]
|
711
|
+
# move to lower frame
|
712
|
+
# * fin[ish]
|
713
|
+
# return to outer frame
|
714
|
+
# * q[uit]
|
715
|
+
# exit from debugger
|
716
|
+
# * v[ar] g[lobal]
|
717
|
+
# show global variables
|
718
|
+
# * v[ar] l[ocal]
|
719
|
+
# show local variables
|
720
|
+
# * v[ar] i[nstance] OBJECT
|
721
|
+
# show instance variables of object
|
722
|
+
# * v[ar] c[onst] OBJECT
|
723
|
+
# show constants of object
|
724
|
+
# * m[ethod] i[nstance] OBJECT
|
725
|
+
# show methods of object
|
726
|
+
# * m[ethod] CLASS|MODULE
|
727
|
+
# show instance methods of class or module
|
728
|
+
# * th[read] l[ist]
|
729
|
+
# list all threads
|
730
|
+
# * th[read] c[ur[rent]]
|
731
|
+
# show current thread
|
732
|
+
# * th[read] [sw[itch]] nnn
|
733
|
+
# switch thread context to nnn
|
734
|
+
# * th[read] stop nnn
|
735
|
+
# stop thread nnn
|
736
|
+
# * th[read] resume nnn
|
737
|
+
# resume thread nnn
|
738
|
+
# * p EXPRESSION
|
739
|
+
# evaluate expression and print its value
|
740
|
+
# * pp EXPRESSSION
|
741
|
+
# evaluate expression and print its value
|
742
|
+
# * h[elp]
|
743
|
+
# print this help
|
744
|
+
# * RETURN KEY
|
745
|
+
# redo previous command. Convenient when using list, step, next, up, down,
|
746
|
+
# * EVERYHTING ELSE
|
747
|
+
# evaluate
|
748
|
+
|
749
|
+
|
750
|
+
class RubyDebugClient
|
751
|
+
require 'socket'
|
752
|
+
require 'yaml'
|
753
|
+
include Observable
|
754
|
+
Var = Struct.new("Var",
|
755
|
+
:value,
|
756
|
+
:value_class
|
757
|
+
)
|
758
|
+
|
759
|
+
def initialize(_server='localhost', _port=8989, _timeout=0)
|
760
|
+
@session = nil
|
761
|
+
@server = _server
|
762
|
+
@port = _port
|
763
|
+
@timeout = _timeout.to_i
|
764
|
+
@busy = false
|
765
|
+
@pend = false
|
766
|
+
end
|
767
|
+
|
768
|
+
def add_listener(_caller, _method=:rdebug_client_update)
|
769
|
+
if _caller.respond_to? :rdebug_client_update
|
770
|
+
ObserverCallback.new(self,_caller,:rdebug_client_update)
|
771
|
+
end
|
772
|
+
end
|
773
|
+
|
774
|
+
def notify(_command, _result=nil)
|
775
|
+
#MsgContract.instance.out_debug(self,"notify=>#{_command}")
|
776
|
+
@busy = false
|
777
|
+
changed
|
778
|
+
notify_observers(_command, _result)
|
779
|
+
_result
|
780
|
+
end
|
781
|
+
|
782
|
+
def is_debugging_ready?
|
783
|
+
is_alive? && !is_busy?
|
784
|
+
end
|
785
|
+
|
786
|
+
def is_busy?
|
787
|
+
@busy
|
788
|
+
end
|
789
|
+
|
790
|
+
def is_alive?
|
791
|
+
!@session.nil? && !@session.closed? && !@pend
|
792
|
+
end
|
793
|
+
|
794
|
+
def socket_session
|
795
|
+
if @session.nil?
|
796
|
+
begin
|
797
|
+
#sleep(2)
|
798
|
+
@session = TCPSocket.new(@server, @port)
|
799
|
+
@pend = false
|
800
|
+
rescue Errno::ECONNREFUSED => e
|
801
|
+
sleep(1)
|
802
|
+
@t = @t -1
|
803
|
+
if @t > 0
|
804
|
+
socket_session
|
805
|
+
else
|
806
|
+
MsgContract.instance.out_debug(self,"socket_session : #{e.inspect}")
|
807
|
+
end
|
808
|
+
end
|
809
|
+
end
|
810
|
+
#MsgContract.instance.out_debug(self,"session : #{@session.inspect}")
|
811
|
+
return @session
|
812
|
+
end
|
813
|
+
|
814
|
+
def kill
|
815
|
+
begin
|
816
|
+
@session.close if is_alive?
|
817
|
+
@session = nil
|
818
|
+
rescue Exception => e
|
819
|
+
MsgContract.instance.out_debug(self,"Error on close session : #{e.class}:#{e.message}")
|
820
|
+
end
|
821
|
+
end
|
822
|
+
|
823
|
+
def start_session
|
824
|
+
begin
|
825
|
+
@t = @timeout
|
826
|
+
if socket_session
|
827
|
+
#MsgContract.instance.out_debug(self,"session : #{@session.inspect}")
|
828
|
+
notify('start', read)
|
829
|
+
read("eval require 'yaml'")
|
830
|
+
end
|
831
|
+
return @session
|
832
|
+
rescue Exception => e
|
833
|
+
MsgContract.instance.out_debug(self,"Error on start_session : #{e.class}:#{e.message}")
|
834
|
+
end
|
835
|
+
end
|
836
|
+
|
837
|
+
def stop_session
|
838
|
+
begin
|
839
|
+
quit if is_debugging_ready?
|
840
|
+
@session.close if is_alive?
|
841
|
+
rescue Exception => e
|
842
|
+
MsgContract.instance.out_debug(self,"Error on stop_session : #{e.class}:#{e.inspect}")
|
843
|
+
end
|
844
|
+
end
|
845
|
+
|
846
|
+
# send a command to the debugger via socket
|
847
|
+
def command(_command)
|
848
|
+
#MsgContract.instance.out_debug(self,"command=>#{_command}")
|
849
|
+
begin
|
850
|
+
return false if @busy
|
851
|
+
if is_alive?
|
852
|
+
@busy = true
|
853
|
+
socket_session.puts(_command)
|
854
|
+
else
|
855
|
+
start_session if !@pend
|
856
|
+
end
|
857
|
+
true
|
858
|
+
rescue Errno::ECONNABORTED => e
|
859
|
+
#kill
|
860
|
+
notify("quit_yes")
|
861
|
+
DebugContract.instance.debug_end(self)
|
862
|
+
MsgContract.instance.out_debug(self,"Debugged has finished executing")
|
863
|
+
@session = nil
|
864
|
+
@pend = true
|
865
|
+
false
|
866
|
+
#raise RubyDebugException.new("Debugged has finished executing")
|
867
|
+
rescue Exception => e
|
868
|
+
MsgContract.instance.out_debug(self,"Error on command #{_command}: #{e.class}:#{e.inspect}")
|
869
|
+
false
|
870
|
+
end
|
871
|
+
end
|
872
|
+
private :command
|
873
|
+
|
874
|
+
def read(_command=nil)
|
875
|
+
return nil if _command && !command(_command)
|
876
|
+
socket_session.flush
|
877
|
+
result = ""
|
878
|
+
while _command !='y' && is_alive? && line = socket_session.gets
|
879
|
+
#MsgContract.instance.out_debug(self, "read: letta riga => #{line}")
|
880
|
+
break if line =~ /^PROMPT (.*)$/ || line =~ /.(y\/n)./
|
881
|
+
result << line
|
882
|
+
#break if _command =~ /^eval./
|
883
|
+
end
|
884
|
+
#MsgContract.instance.out_simple(self, "read(#{_command}): result => #{result}")
|
885
|
+
@busy = false
|
886
|
+
result
|
887
|
+
|
888
|
+
rescue Errno::ECONNABORTED
|
889
|
+
raise RubyDebugException.new("Debugged has finished executing")
|
890
|
+
rescue Errno::ECONNRESET
|
891
|
+
raise RubyDebugException.new("Debugged has finished executing")
|
892
|
+
rescue Exception => e
|
893
|
+
raise RubyDebugException.new("Error: on command '#{_command}' => #{e.class} : #{e.inspect}")
|
894
|
+
end
|
895
|
+
private :read
|
896
|
+
|
897
|
+
|
898
|
+
def step_over
|
899
|
+
notify("next", read("next"))
|
900
|
+
end
|
901
|
+
|
902
|
+
def step_into
|
903
|
+
notify("step", read("step"))
|
904
|
+
end
|
905
|
+
|
906
|
+
def step_out
|
907
|
+
notify("fin", read("fin"))
|
908
|
+
end
|
909
|
+
|
910
|
+
def resume
|
911
|
+
notify("cont", read("cont"))
|
912
|
+
end
|
913
|
+
|
914
|
+
def where
|
915
|
+
notify("where", read("where"))
|
916
|
+
end
|
917
|
+
|
918
|
+
def quit
|
919
|
+
notify("quit", read("q"))
|
920
|
+
end
|
921
|
+
|
922
|
+
def quit_yes
|
923
|
+
notify("quit_yes", read("y"))
|
924
|
+
DebugContract.instance.debug_end(self)
|
925
|
+
kill
|
926
|
+
end
|
927
|
+
|
928
|
+
def quit_no
|
929
|
+
notify("quit_no", read("n"))
|
930
|
+
end
|
931
|
+
|
932
|
+
# return the current stack trace
|
933
|
+
def stacktrace
|
934
|
+
notify("backtrace", read("backtrace"))
|
935
|
+
end
|
936
|
+
|
937
|
+
|
938
|
+
def yaml_pseudo_load(_obj)
|
939
|
+
#MsgContract.instance.out_simple(self,"_obj="+_obj.inspect)
|
940
|
+
just_present = @valuobjs.include?(_obj)
|
941
|
+
@valuobjs << _obj
|
942
|
+
if _obj.class == YAML::DomainType
|
943
|
+
#MsgContract.instance.out_simple(self,"_obj DomainType="+_obj.inspect)
|
944
|
+
return _obj.type_id if just_present
|
945
|
+
ret = Hash.new
|
946
|
+
ret['__CLASS__']=_obj.type_id
|
947
|
+
l = _obj.value.length
|
948
|
+
ret['__LENGTH__']= l.to_s
|
949
|
+
if l > 0
|
950
|
+
_obj.value.each{|k,v|
|
951
|
+
ret["@#{k}"]=yaml_pseudo_load(v)
|
952
|
+
}
|
953
|
+
end
|
954
|
+
ret
|
955
|
+
elsif _obj.class == Hash
|
956
|
+
#MsgContract.instance.out_simple(self,"_obj Hash="+_obj.inspect)
|
957
|
+
return 'Hash' if just_present
|
958
|
+
ret = Hash.new
|
959
|
+
ret['__CLASS__']= 'Hash'
|
960
|
+
l = _obj.length
|
961
|
+
ret['__LENGTH__']= l.to_s
|
962
|
+
if l > 0
|
963
|
+
_obj.each{|k,v|
|
964
|
+
ret[k]=yaml_pseudo_load(v)
|
965
|
+
}
|
966
|
+
end
|
967
|
+
ret
|
968
|
+
elsif _obj.class == Array
|
969
|
+
#MsgContract.instance.out_simple(self,"_obj Array="+_obj.inspect)
|
970
|
+
return 'Array' if just_present
|
971
|
+
ret = Hash.new
|
972
|
+
ret['__CLASS__']= 'Array'
|
973
|
+
l = _obj.length
|
974
|
+
ret['__LENGTH__']= l.to_s
|
975
|
+
if l > 0
|
976
|
+
_obj.each_with_index{|v,i|
|
977
|
+
ret[i.to_s]=yaml_pseudo_load(v)
|
978
|
+
}
|
979
|
+
end
|
980
|
+
ret
|
981
|
+
elsif _obj.class == Struct
|
982
|
+
#MsgContract.instance.out_simple(self,"_obj Array="+_obj.inspect)
|
983
|
+
return 'Struct' if just_present
|
984
|
+
ret = Hash.new
|
985
|
+
ret['__CLASS__']= 'Struct'
|
986
|
+
l = _obj.length
|
987
|
+
ret['__LENGTH__']= l.to_s
|
988
|
+
if l > 0
|
989
|
+
|
990
|
+
_obj.members.each{|m|
|
991
|
+
ret[m]=yaml_pseudo_load(_obj[m])
|
992
|
+
}
|
993
|
+
end
|
994
|
+
ret
|
995
|
+
else
|
996
|
+
#MsgContract.instance.out_simple(self,"_obj ="+_obj.inspect)
|
997
|
+
|
998
|
+
_obj
|
999
|
+
end
|
1000
|
+
|
1001
|
+
end
|
1002
|
+
|
1003
|
+
|
1004
|
+
def debug_dump(_exp)
|
1005
|
+
var = nil
|
1006
|
+
if @valuobjs.nil?
|
1007
|
+
@valuobjs = Array.new
|
1008
|
+
else
|
1009
|
+
@valuobjs.clear
|
1010
|
+
end
|
1011
|
+
begin
|
1012
|
+
_str = eval(read("eval YAML::dump(#{_exp})"))
|
1013
|
+
#MsgContract.instance.out_simple(self,"value passato 1 ="+_str.to_s)
|
1014
|
+
_str.gsub!('!ruby/object:', '!')
|
1015
|
+
#MsgContract.instance.out_simple(self,"value passato 2 ="+_str.to_s)
|
1016
|
+
_obj = YAML::load(_str)
|
1017
|
+
var = yaml_pseudo_load(_obj)
|
1018
|
+
rescue Exception => e
|
1019
|
+
MsgContract.instance.out_simple(self,"exception on eval #{_exp} :#{e.inspect}")
|
1020
|
+
var = nil
|
1021
|
+
end
|
1022
|
+
return var
|
1023
|
+
end
|
1024
|
+
|
1025
|
+
|
1026
|
+
# returns the instance variables and there values
|
1027
|
+
def instance_variables_new(_this='self')
|
1028
|
+
command("eval #{_this}.instance_variables")
|
1029
|
+
variables = []
|
1030
|
+
begin
|
1031
|
+
variables = eval(read)
|
1032
|
+
rescue Exception
|
1033
|
+
variables = []
|
1034
|
+
end
|
1035
|
+
@consider = Array.new
|
1036
|
+
variable_values = Hash.new
|
1037
|
+
variables.each do |var|
|
1038
|
+
#next if var != '@objs'
|
1039
|
+
# command("eval require 'pp'; #{var}.pretty_inspect() + '|||' + #{var}.class.to_s")
|
1040
|
+
command("eval YAML::dump(#{var})")
|
1041
|
+
_str = eval read
|
1042
|
+
#MsgContract.instance.out_simple(self,"value passato 1 ="+_str)
|
1043
|
+
|
1044
|
+
_str.gsub!('!ruby/object:', '!')
|
1045
|
+
|
1046
|
+
#MsgContract.instance.out_simple(self,"value passato 2 ="+_str)
|
1047
|
+
|
1048
|
+
_obj = YAML::load(_str)
|
1049
|
+
|
1050
|
+
_xvalue = yaml_pseudo_load(_obj)
|
1051
|
+
if _xvalue.class == Hash
|
1052
|
+
_xclass = _xvalue['__CLASS__']
|
1053
|
+
else
|
1054
|
+
_xclass = _xvalue.class.to_s
|
1055
|
+
end
|
1056
|
+
#_vvv = eval(_value)
|
1057
|
+
|
1058
|
+
#MsgContract.instance.out_simple(self,"vvv class="+_vvv.class.to_s)
|
1059
|
+
|
1060
|
+
#MsgContract.instance.out_simple(self,"value="+_xvalue.inspect)
|
1061
|
+
#MsgContract.instance.out_simple(self,"class="+_xclass)
|
1062
|
+
variable_values[var] = Var.new(_xvalue, _xclass)
|
1063
|
+
end
|
1064
|
+
return variable_values
|
1065
|
+
end
|
1066
|
+
|
1067
|
+
# returns the local variables and there values
|
1068
|
+
def variables(_type)
|
1069
|
+
begin
|
1070
|
+
#variables = read[1..-2].split(', ').collect!{|x| x[1..-2]}
|
1071
|
+
to_eval = read("eval #{_type}")
|
1072
|
+
#MsgContract.instance.out_simple(self,"to_eval="+to_eval.to_s)
|
1073
|
+
variables = eval(to_eval)
|
1074
|
+
#MsgContract.instance.out_simple(self,"variables="+variables.to_s)
|
1075
|
+
rescue Exception => e
|
1076
|
+
variables = []
|
1077
|
+
#p "on command eval #{_type}:#{e.inspect}"
|
1078
|
+
#MsgContract.instance.out_debug(self,"on command eval #{_type}:#{e.inspect}")
|
1079
|
+
end
|
1080
|
+
variables = [] if variables.nil?
|
1081
|
+
variable_values = Hash.new
|
1082
|
+
variables.each do |var|
|
1083
|
+
next if var=='$;'
|
1084
|
+
# command("eval #{var}.to_s + '|||' + #{var}.class.to_s")
|
1085
|
+
# _str = eval(read)
|
1086
|
+
# _value, _class = _str.split('|||')
|
1087
|
+
# variable_values[var] = Var.new(_value, _class)
|
1088
|
+
variable_values[var] = debug_eval(var)
|
1089
|
+
end
|
1090
|
+
return variable_values
|
1091
|
+
end
|
1092
|
+
|
1093
|
+
def debug_eval(_exp)
|
1094
|
+
command("eval #{res=_exp}.to_s + '|||' + #{res}.class.to_s")
|
1095
|
+
_str = eval(read)
|
1096
|
+
_value, _class = _str.split('|||')
|
1097
|
+
return Var.new(_value, _class)
|
1098
|
+
end
|
1099
|
+
|
1100
|
+
# returns the local variables and there values
|
1101
|
+
def local_variables
|
1102
|
+
command("eval local_variables")
|
1103
|
+
variables = []
|
1104
|
+
begin
|
1105
|
+
variables = eval(read)
|
1106
|
+
rescue Exception
|
1107
|
+
variables = []
|
1108
|
+
end
|
1109
|
+
variable_values = Hash.new
|
1110
|
+
variables.each do |var|
|
1111
|
+
command("eval #{var}.to_s + '|||' + #{var}.class.to_s")
|
1112
|
+
_str = eval(read)
|
1113
|
+
_value, _class = _str.split('|||')
|
1114
|
+
variable_values[var] = Var.new(_value, eval(_class))
|
1115
|
+
end
|
1116
|
+
return variable_values
|
1117
|
+
end
|
1118
|
+
|
1119
|
+
|
1120
|
+
# returns the global variables and there values
|
1121
|
+
def global_variables
|
1122
|
+
command("eval global_variables")
|
1123
|
+
variables = []
|
1124
|
+
begin
|
1125
|
+
variables = eval(read)
|
1126
|
+
rescue Exception
|
1127
|
+
variables = []
|
1128
|
+
end
|
1129
|
+
variable_values = Hash.new
|
1130
|
+
variables.each do |var|
|
1131
|
+
command("eval #{var}.to_s")
|
1132
|
+
variable_values[var] = read
|
1133
|
+
end
|
1134
|
+
return variable_values
|
1135
|
+
end
|
1136
|
+
|
1137
|
+
|
1138
|
+
def set_breakpoint(_file, _line)
|
1139
|
+
#_line = _line + 1
|
1140
|
+
text = read("break #{_file}:#{_line}")
|
1141
|
+
breakpoint_no = -1
|
1142
|
+
matches = text.match(/Set breakpoint ([0-9]*)?/)
|
1143
|
+
breakpoint_no = matches[1].to_i if (matches.length == 2)
|
1144
|
+
return breakpoint_no
|
1145
|
+
end
|
1146
|
+
|
1147
|
+
def unset_breakpoint(_id)
|
1148
|
+
read("delete #{_id}")
|
1149
|
+
end
|
1150
|
+
end
|
1151
|
+
|
1152
|
+
class RubyDebug < ArcadiaExt
|
1153
|
+
attr_reader :rds
|
1154
|
+
attr_reader :rdc
|
1155
|
+
def before_build
|
1156
|
+
ArcadiaContractListener.new(self, EditorContract, :do_editor_event)
|
1157
|
+
@breakpoints = Hash.new
|
1158
|
+
@static_breakpoints = Array.new
|
1159
|
+
end
|
1160
|
+
|
1161
|
+
def build
|
1162
|
+
end
|
1163
|
+
|
1164
|
+
def do_editor_event(_event)
|
1165
|
+
case _event.signature
|
1166
|
+
when EditorContract::BREAKPOINT_AFTER_CREATE
|
1167
|
+
self.breakpoint_add(File.expand_path(_event.context.file), _event.context.line)
|
1168
|
+
when EditorContract::BREAKPOINT_AFTER_DELETE
|
1169
|
+
self.breakpoint_del(File.expand_path(_event.context.file), _event.context.line)
|
1170
|
+
when EditorContract::BUFFER_AFTER_RAISE
|
1171
|
+
@raised_file=_event.context.file
|
1172
|
+
when EditorContract::EVAL_EXPRESSION
|
1173
|
+
eval_expression(_event.context.text)
|
1174
|
+
end
|
1175
|
+
end
|
1176
|
+
|
1177
|
+
def eval_expression(_exp)
|
1178
|
+
res = @rdc.debug_eval(_exp) if @rdc && @rdc.is_debugging_ready?
|
1179
|
+
hash = Hash.new
|
1180
|
+
hash[_exp]=res
|
1181
|
+
@rdv.show_expression(_exp, hash) if res
|
1182
|
+
end
|
1183
|
+
|
1184
|
+
def start_debug_server
|
1185
|
+
end
|
1186
|
+
private :start_debug_server
|
1187
|
+
|
1188
|
+
def start_debug_client
|
1189
|
+
end
|
1190
|
+
private :start_debug_client
|
1191
|
+
|
1192
|
+
|
1193
|
+
def breakpoint_suf(_file,_line)
|
1194
|
+
return _line.to_s + "-" + _file.to_s
|
1195
|
+
end
|
1196
|
+
private :breakpoint_suf
|
1197
|
+
|
1198
|
+
def break_name(_file,_line)
|
1199
|
+
"#{_file}:#{_line}"
|
1200
|
+
end
|
1201
|
+
|
1202
|
+
def breakpoint_add_live(_file,_line)
|
1203
|
+
if @rdc
|
1204
|
+
@breakpoints[breakpoint_suf(_file,_line)] = @rdc.set_breakpoint(_file, _line.to_i)
|
1205
|
+
@rdv.break_list_add(_file,_line) if @rdv
|
1206
|
+
end
|
1207
|
+
end
|
1208
|
+
|
1209
|
+
def breakpoint_del_live(_file,_line)
|
1210
|
+
if @rdc
|
1211
|
+
@rdc.unset_breakpoint(@breakpoints.delete(breakpoint_suf(_file,_line)))
|
1212
|
+
@rdv.break_list_del(_file,_line) if @rdv
|
1213
|
+
end
|
1214
|
+
end
|
1215
|
+
|
1216
|
+
def breakpoint_free_live
|
1217
|
+
@breakpoints.clear
|
1218
|
+
@rdv.break_list_free if @rdv
|
1219
|
+
end
|
1220
|
+
|
1221
|
+
def breakpoint_add(_file,_line)
|
1222
|
+
breakpoint_add_live(_file,_line)
|
1223
|
+
@static_breakpoints << {:file=>_file,:line=>_line}
|
1224
|
+
end
|
1225
|
+
#private :breakpoint_add
|
1226
|
+
|
1227
|
+
def breakpoint_del(_file,_line)
|
1228
|
+
breakpoint_del_live(_file,_line)
|
1229
|
+
@static_breakpoints.delete_if{|b| (b[:file]==_file && b[:line]==_line)}
|
1230
|
+
end
|
1231
|
+
#private :breakpoint_del
|
1232
|
+
|
1233
|
+
|
1234
|
+
def can_exit_query
|
1235
|
+
if @rdc
|
1236
|
+
query = (Tk.messageBox('icon' => 'question', 'type' => 'yesno',
|
1237
|
+
'title' => '(Arcadia) Debug',
|
1238
|
+
'message' => "Debug in course, do you want to exit?")=='yes')
|
1239
|
+
if query
|
1240
|
+
debug_quit
|
1241
|
+
return true
|
1242
|
+
else
|
1243
|
+
return false
|
1244
|
+
end
|
1245
|
+
else
|
1246
|
+
return true
|
1247
|
+
end
|
1248
|
+
end
|
1249
|
+
|
1250
|
+
|
1251
|
+
|
1252
|
+
def debug_begin
|
1253
|
+
breakpoint_free_live
|
1254
|
+
DebugContract.instance.debug_begin(self)
|
1255
|
+
end
|
1256
|
+
|
1257
|
+
def debug_last
|
1258
|
+
debug($arcadia['pers']['run.file.last'])
|
1259
|
+
end
|
1260
|
+
|
1261
|
+
def debug_current
|
1262
|
+
debug(@raised_file) if @raised_file!=nil
|
1263
|
+
end
|
1264
|
+
def debugging?
|
1265
|
+
!@rdc.nil? && @rdc.is_alive?
|
1266
|
+
end
|
1267
|
+
def debug(_filename=nil)
|
1268
|
+
if _filename && !debugging?
|
1269
|
+
begin
|
1270
|
+
self.debug_begin
|
1271
|
+
@arcadia['pers']['run.file.last']=_filename
|
1272
|
+
@rds = RubyDebugServer.new(self) if @rds.nil?
|
1273
|
+
@rds.start_session(_filename, conf('server.host'), conf('server.port'))
|
1274
|
+
#MsgContract.instance.out_simple(self,@rds.to_s)
|
1275
|
+
@rdc = RubyDebugClient.new(conf('server.host'), conf('server.port'), conf('server.timeout')) if @rdc.nil?
|
1276
|
+
@rdv = RubyDebugView.new(self.frame, self) if @rdv.nil?
|
1277
|
+
@rdv.start_process(_filename)
|
1278
|
+
if @rdc.start_session
|
1279
|
+
@static_breakpoints.each{|_b|
|
1280
|
+
#MsgContract.instance.out_simple(self," breakpoint_add #{_b[:file]}:#{_b[:line]}")
|
1281
|
+
breakpoint_add_live(_b[:file], _b[:line])
|
1282
|
+
}
|
1283
|
+
end
|
1284
|
+
#MsgContract.instance.out_simple(self,"\n<begin debug>")
|
1285
|
+
|
1286
|
+
rescue Exception => e
|
1287
|
+
MsgContract.instance.out_debug(self,"---> "+e.to_s)
|
1288
|
+
end
|
1289
|
+
end
|
1290
|
+
end
|
1291
|
+
|
1292
|
+
|
1293
|
+
def rdebug_server_update(_state)
|
1294
|
+
case _state
|
1295
|
+
when RubyDebugServer::_RDS_QUIT_
|
1296
|
+
debug_quit
|
1297
|
+
end
|
1298
|
+
p _state
|
1299
|
+
end
|
1300
|
+
|
1301
|
+
def debug_free
|
1302
|
+
self.frame_free
|
1303
|
+
@rdc = nil
|
1304
|
+
@rdv = nil
|
1305
|
+
end
|
1306
|
+
|
1307
|
+
def debug_quit
|
1308
|
+
if @rdc
|
1309
|
+
if @rdc.is_alive?
|
1310
|
+
Thread.new{
|
1311
|
+
Tk.messageBox('icon' => 'info',
|
1312
|
+
'type' => 'ok',
|
1313
|
+
'title' => '(Arcadia) Debug',
|
1314
|
+
'message' => "Debug in course, stop it before exit")
|
1315
|
+
}
|
1316
|
+
else
|
1317
|
+
begin
|
1318
|
+
debug_free
|
1319
|
+
rescue Exception => e
|
1320
|
+
MsgContract.instance.out_debug(self, "debug_quit:---> "+e.to_s)
|
1321
|
+
#@arcadia['shell'].outln("debug_quit:---> "+e.to_s )
|
1322
|
+
end
|
1323
|
+
end
|
1324
|
+
end
|
1325
|
+
end
|
1326
|
+
|
1327
|
+
|
1328
|
+
|
1329
|
+
end
|