arcadia 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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