ruby-debug-ide 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,153 @@
1
+ module Debugger
2
+ class ThreadListCommand < Command # :nodoc:
3
+ self.control = true
4
+ def regexp
5
+ /^\s*th(?:read)?\s+l(?:ist)?\s*$/
6
+ end
7
+
8
+ def execute
9
+ contexts = Debugger.contexts.sort_by{|c| c.thnum}
10
+ print_contexts(contexts)
11
+ end
12
+
13
+ class << self
14
+ def help_command
15
+ 'thread'
16
+ end
17
+
18
+ def help(cmd)
19
+ %{
20
+ th[read] l[ist]\t\t\tlist all threads
21
+ }
22
+ end
23
+ end
24
+ end
25
+
26
+ class ThreadSwitchCommand < Command # :nodoc:
27
+ self.control = true
28
+ self.need_context = true
29
+
30
+ def regexp
31
+ /^\s*th(?:read)?\s+(?:sw(?:itch)?\s+)?(\d+)\s*$/
32
+ end
33
+
34
+ def execute
35
+ c = get_context(@match[1].to_i)
36
+ case
37
+ when c == @state.context
38
+ print_msg "It's the current thread."
39
+ when c.ignored?
40
+ print_msg "Can't switch to the debugger thread."
41
+ else
42
+ print_context(c)
43
+ c.stop_next = 1
44
+ c.thread.run
45
+ @state.proceed
46
+ end
47
+ end
48
+
49
+ class << self
50
+ def help_command
51
+ 'thread'
52
+ end
53
+
54
+ def help(cmd)
55
+ %{
56
+ th[read] [sw[itch]] <nnn>\tswitch thread context to nnn
57
+ }
58
+ end
59
+ end
60
+ end
61
+
62
+ class ThreadStopCommand < Command # :nodoc:
63
+ self.control = true
64
+ self.need_context = true
65
+
66
+ def regexp
67
+ /^\s*th(?:read)?\s+stop\s+(\d+)\s*$/
68
+ end
69
+
70
+ def execute
71
+ c = get_context(@match[1].to_i)
72
+ case
73
+ when c == @state.context
74
+ print_msg "It's the current thread."
75
+ when c.ignored?
76
+ print_msg "Can't stop the debugger thread."
77
+ else
78
+ c.suspend
79
+ print_context(c)
80
+ end
81
+ end
82
+
83
+ class << self
84
+ def help_command
85
+ 'thread'
86
+ end
87
+
88
+ def help(cmd)
89
+ %{
90
+ th[read] stop <nnn>\t\tstop thread nnn
91
+ }
92
+ end
93
+ end
94
+ end
95
+
96
+ class ThreadCurrentCommand < Command # :nodoc:
97
+ self.need_context = true
98
+
99
+ def regexp
100
+ /^\s*th(?:read)?\s+c(?:ur(?:rent)?)?\s*$/
101
+ end
102
+
103
+ def execute
104
+ print_context(@state.context)
105
+ end
106
+
107
+ class << self
108
+ def help_command
109
+ 'thread'
110
+ end
111
+
112
+ def help(cmd)
113
+ %{
114
+ th[read] c[ur[rent]]\t\tshow current thread
115
+ }
116
+ end
117
+ end
118
+ end
119
+
120
+ class ThreadResumeCommand < Command # :nodoc:
121
+ self.control = true
122
+ self.need_context = true
123
+
124
+ def regexp
125
+ /^\s*th(?:read)?\s+resume\s+(\d+)\s*$/
126
+ end
127
+
128
+ def execute
129
+ c = get_context(@match[1].to_i)
130
+ case
131
+ when c == @state.context
132
+ print_msg "It's the current thread."
133
+ when c.ignored?
134
+ print_msg "Can't resume the debugger thread."
135
+ else
136
+ c.resume
137
+ print_context(c)
138
+ end
139
+ end
140
+
141
+ class << self
142
+ def help_command
143
+ 'thread'
144
+ end
145
+
146
+ def help(cmd)
147
+ %{
148
+ th[read] resume <nnn>\t\tresume thread nnn
149
+ }
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,123 @@
1
+ module Debugger
2
+ class VarConstantCommand < Command # :nodoc:
3
+ def regexp
4
+ /^\s*v(?:ar)?\s+c(?:onst(?:ant)?)?\s+/
5
+ end
6
+
7
+ def execute
8
+ obj = debug_eval(@match.post_match)
9
+ unless obj.kind_of? Module
10
+ print_msg "Should be Class/Module: %s", @match.post_match
11
+ else
12
+ print_variables(obj.constants, "constant") do |var|
13
+ obj.const_get(var)
14
+ end
15
+ end
16
+ end
17
+
18
+ class << self
19
+ def help_command
20
+ 'var'
21
+ end
22
+
23
+ def help(cmd)
24
+ %{
25
+ v[ar] c[onst] <object>\t\tshow constants of object
26
+ }
27
+ end
28
+ end
29
+ end
30
+
31
+ class VarGlobalCommand < Command # :nodoc:
32
+ def regexp
33
+ /^\s*v(?:ar)?\s+g(?:lobal)?\s*$/
34
+ end
35
+
36
+ def execute
37
+ print_variables(global_variables, 'global') do |var|
38
+ debug_eval(var)
39
+ end
40
+ end
41
+
42
+ class << self
43
+ def help_command
44
+ 'var'
45
+ end
46
+
47
+ def help(cmd)
48
+ %{
49
+ v[ar] g[lobal]\t\t\tshow global variables
50
+ }
51
+ end
52
+ end
53
+ end
54
+
55
+ class VarInstanceCommand < Command # :nodoc:
56
+ def regexp
57
+ # id will be read as first match, name as post match
58
+ /^\s*v(?:ar)?\s+i(?:nstance)?\s+((?:[\\+-]0x)[\dabcdef]+)?/
59
+ end
60
+
61
+ def execute
62
+ if (@match[1])
63
+ obj = ObjectSpace._id2ref(@match[1].hex) rescue nil
64
+ unless obj
65
+ # TODO: ensure that empty variables frame will be printed
66
+ @printer.print_msg("Unknown object id : %s", @match[1])
67
+ end
68
+ else
69
+ obj = debug_eval(@match.post_match)
70
+ end
71
+ return unless obj
72
+ if (obj.class.name == "Array") then
73
+ print_array(obj)
74
+ elsif (obj.class.name == "Hash") then
75
+ print_hash(obj)
76
+ else
77
+ b = obj.instance_eval{binding()}
78
+ print_variables(obj.instance_variables, 'instance') do |var|
79
+ debug_eval(var, b)
80
+ end
81
+ end
82
+ end
83
+
84
+ class << self
85
+ def help_command
86
+ 'var'
87
+ end
88
+
89
+ def help(cmd)
90
+ %{
91
+ v[ar] i[nstance] <object>\tshow instance variables of object, object can be given by its id or an expression
92
+ }
93
+ end
94
+ end
95
+ end
96
+
97
+ class VarLocalCommand < Command # :nodoc:
98
+ def regexp
99
+ /^\s*v(?:ar)?\s+l(?:ocal)?\s*$/
100
+ end
101
+
102
+ def execute
103
+ locals = @state.context.frame_locals(@state.frame_pos)
104
+ _self = @state.context.frame_self(@state.frame_pos)
105
+ locals['self'] = _self unless _self.to_s == "main"
106
+ print_variables(locals.keys, 'local') do |var|
107
+ locals[var]
108
+ end
109
+ end
110
+
111
+ class << self
112
+ def help_command
113
+ 'var'
114
+ end
115
+
116
+ def help(cmd)
117
+ %{
118
+ v[ar] l[ocal]\t\t\tshow local variables
119
+ }
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,45 @@
1
+ require 'ruby-debug/xml_printer'
2
+ module Debugger
3
+
4
+ class EventProcessor
5
+
6
+ attr_accessor :line, :file, :context
7
+
8
+ def initialize(interface)
9
+ @printer = XmlPrinter.new(interface)
10
+ @line = nil
11
+ @file = nil
12
+ end
13
+
14
+ def at_breakpoint(context, breakpoint)
15
+ n = Debugger.breakpoints.index(breakpoint) + 1
16
+ @printer.print_breakpoint n, breakpoint
17
+ end
18
+
19
+ def at_catchpoint(context, excpt)
20
+ @printer.print_catchpoint(excpt)
21
+ end
22
+
23
+ def at_tracing(context, file, line)
24
+ @printer.print_trace(context, file, line)
25
+ end
26
+
27
+ def at_line(context, file, line)
28
+ @printer.print_at_line(file, line) if context.nil? || context.stop_reason == :step
29
+ @line=line
30
+ @file =file
31
+ @context = context
32
+ @printer.print_debug("Stopping Thread %s", context.thread.to_s)
33
+ @printer.print_debug("Threads equal: %s", Thread.current == context.thread)
34
+ Thread.stop
35
+ @printer.print_debug("Resumed Thread %s", context.thread.to_s)
36
+ @line=nil
37
+ @file = nil
38
+ @context = nil
39
+ end
40
+
41
+ def at_line?
42
+ @line
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,118 @@
1
+ module Debugger
2
+ class LocalInterface # :nodoc:
3
+ def read_command(prompt)
4
+ readline(prompt, true)
5
+ end
6
+
7
+ def confirm(prompt)
8
+ readline(prompt, false)
9
+ end
10
+
11
+ def print(*args)
12
+ STDOUT.printf(*args)
13
+ end
14
+
15
+ def close
16
+ end
17
+
18
+ private
19
+
20
+ begin
21
+ require 'readline'
22
+ class << Debugger
23
+ FILE_HISTORY = ".rdebug_hist"
24
+ save_file = File.join(ENV["HOME"]||ENV["HOMEPATH"], FILE_HISTORY)
25
+ open(save_file, 'r') do |file|
26
+ file.each do |line|
27
+ line.chomp!
28
+ Readline::HISTORY << line
29
+ end
30
+ end if File.exists?(save_file)
31
+
32
+ define_method(:save_history) do
33
+ open(save_file, 'w') do |file|
34
+ Readline::HISTORY.to_a.last(500).each do |line|
35
+ file.puts line unless line.strip.empty?
36
+ end
37
+ end rescue nil
38
+ end
39
+ public :save_history
40
+ end
41
+ Debugger.debug_at_exit { Debugger.save_history }
42
+
43
+ def readline(prompt, hist)
44
+ Readline::readline(prompt, hist)
45
+ end
46
+ rescue LoadError
47
+ def readline(prompt, hist)
48
+ STDOUT.print prompt
49
+ STDOUT.flush
50
+ line = STDIN.gets
51
+ exit unless line
52
+ line.chomp!
53
+ line
54
+ end
55
+ end
56
+ end
57
+
58
+ class RemoteInterface # :nodoc:
59
+ def initialize(socket)
60
+ @socket = socket
61
+ end
62
+
63
+ def read_command(prompt)
64
+ send_command "PROMPT #{prompt}"
65
+ end
66
+
67
+ def confirm(prompt)
68
+ send_command "CONFIRM #{prompt}"
69
+ end
70
+
71
+ def print(*args)
72
+ @socket.printf(*args)
73
+ end
74
+
75
+ def close
76
+ @socket.close
77
+ rescue Exception
78
+ end
79
+
80
+ private
81
+
82
+ def send_command(msg)
83
+ @socket.puts msg
84
+ result = @socket.gets
85
+ raise IOError unless result
86
+ result.chomp
87
+ end
88
+ end
89
+
90
+ class ScriptInterface # :nodoc:
91
+ def initialize(file, out)
92
+ @file = file.respond_to?(:gets) ? file : open(file)
93
+ @out = out
94
+ end
95
+
96
+ def read_command(prompt)
97
+ while result = @file.gets
98
+ next if result =~ /^\s*#/
99
+ next if result.strip.empty?
100
+ break
101
+ end
102
+ raise IOError unless result
103
+ result
104
+ end
105
+
106
+ def confirm(prompt)
107
+ 'y'
108
+ end
109
+
110
+ def print(*args)
111
+ @out.print(*args)
112
+ end
113
+
114
+ def close
115
+ @file.close
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,2 @@
1
+ require 'ruby-debug/printers/plain_printer'
2
+ require 'ruby-debug/printers/xml_printer'
@@ -0,0 +1,155 @@
1
+ require 'ruby-debug/interface'
2
+ require 'ruby-debug/command'
3
+
4
+ module Debugger
5
+
6
+ class ControlCommandProcessor # :nodoc:
7
+ def initialize(interface)
8
+ @interface = interface
9
+ @printer = XmlPrinter.new(@interface)
10
+ end
11
+
12
+ def print(*args)
13
+ @interface.print(*args)
14
+ end
15
+
16
+ def process_commands
17
+ @printer.print_debug("Starting command read loop")
18
+ control_cmds = Command.commands.select{|cmd| cmd.control }
19
+ state = ControlState.new(@interface, control_cmds)
20
+ commands = control_cmds.map{|cmd| cmd.new(state, @printer) }
21
+
22
+ while input = @interface.read_command("")
23
+ # escape % since print_debug might use printf
24
+ @printer.print_debug "Processing: #{input.gsub('%', '%%')}"
25
+ catch(:debug_error) do
26
+ if cmd = commands.find{|c| c.match(input) }
27
+ cmd.execute
28
+ else
29
+ process_context_commands(input)
30
+ #@printer.print_msg "Unknown command"
31
+ end
32
+ end
33
+ end
34
+ rescue IOError, Errno::EPIPE
35
+ rescue Exception
36
+ @printer.print_error "INTERNAL ERROR!!! #{$!}\n" rescue nil
37
+ @printer.print_error $!.backtrace.map{|l| "\t#{l}"}.join("\n") rescue nil
38
+ ensure
39
+ @interface.close
40
+ end
41
+
42
+ def process_context_commands(input)
43
+ unless Debugger.processor.at_line?
44
+ @printer.print_error "There is no thread suspended at the time and therefore no context to execute '#{input.gsub('%', '%%')}'"
45
+ return
46
+ end
47
+ context = Debugger.processor.context
48
+ file = Debugger.processor.file
49
+ line = Debugger.processor.line
50
+ event_cmds = Command.commands.select{|cmd| cmd.event }
51
+ state = State.new do |s|
52
+ s.context = context
53
+ s.file = file
54
+ s.line = line
55
+ s.binding = context.frame_binding(0)
56
+ s.display = display
57
+ s.interface = @interface
58
+ s.commands = event_cmds
59
+ end
60
+ commands = event_cmds.map{|cmd| cmd.new(state, @printer) }
61
+ catch(:debug_error) do
62
+
63
+ splitter[input].each do |input|
64
+ # escape % since print_debug might use printf
65
+ @printer.print_debug "Processing context: #{input.gsub('%', '%%')}"
66
+ if cmd = commands.find{ |c| c.match(input) }
67
+ if context.dead? && cmd.class.need_context
68
+ @printer.print_msg "Command is unavailable\n"
69
+ else
70
+ cmd.execute
71
+ end
72
+ else
73
+ @printer.print_msg "Unknown command: #{input}"
74
+ end
75
+ end
76
+ end
77
+
78
+ context.thread.run if state.proceed?
79
+ end
80
+
81
+ def splitter
82
+ return lambda do |str|
83
+ str.split(/;/).inject([]) do |m, v|
84
+ if m.empty?
85
+ m << v
86
+ else
87
+ if m.last[-1] == ?\\
88
+ m.last[-1,1] = ''
89
+ m.last << ';' << v
90
+ else
91
+ m << v
92
+ end
93
+ end
94
+ m
95
+ end
96
+ end
97
+ end
98
+ end
99
+ class State # :nodoc:
100
+ attr_accessor :context, :file, :line, :binding
101
+ attr_accessor :frame_pos, :previous_line, :display
102
+ attr_accessor :interface, :commands
103
+
104
+ def initialize
105
+ @frame_pos = 0
106
+ @previous_line = nil
107
+ @proceed = false
108
+ yield self
109
+ end
110
+
111
+ def print(*args)
112
+ @interface.print(*args)
113
+ end
114
+
115
+ def confirm(*args)
116
+ @interface.confirm(*args)
117
+ end
118
+
119
+ def proceed?
120
+ @proceed
121
+ end
122
+
123
+ def proceed
124
+ @proceed = true
125
+ end
126
+ end
127
+
128
+ class ControlState # :nodoc:
129
+ attr_reader :commands
130
+ def initialize(interface, commands)
131
+ @interface = interface
132
+ @commands = commands
133
+ end
134
+
135
+ def proceed
136
+ end
137
+
138
+ def print(*args)
139
+ @interface.print(*args)
140
+ end
141
+
142
+ def confirm(*args)
143
+ 'y'
144
+ end
145
+
146
+ def context
147
+ nil
148
+ end
149
+
150
+ def file
151
+ print "ERROR: No filename given.\n"
152
+ throw :debug_error
153
+ end
154
+ end
155
+ end