arcadia 0.1.2.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/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
|