arcadia 0.2.0 → 0.3.0

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