Class: RuDebug::Page
- Inherits:
-
Object
- Object
- RuDebug::Page
- Defined in:
- lib/rudebug/page/browser.rb,
lib/rudebug/page.rb,
lib/rudebug/page/shell.rb,
lib/rudebug/page/source_code.rb
Overview
This is all very complex because we can only send and receive strings via the network. (ruby-breakpoint can return DRbObject proxies which we could in theory work on directly, but that is not true for ruby-debug.)
Defined Under Namespace
Classes: CodeFile
Instance Attribute Summary collapse
-
#code_notebook ⇒ Object
readonly
Returns the value of attribute code_notebook.
-
#files_combobox ⇒ Object
readonly
Returns the value of attribute files_combobox.
-
#glade_file ⇒ Object
readonly
Returns the value of attribute glade_file.
-
#session ⇒ Object
readonly
Returns the value of attribute session.
Instance Method Summary collapse
- #activate_file(name) ⇒ Object
-
#attribute_for(iter) ⇒ Object
Attribute description.
- #attributes_for(klass, virtual) ⇒ Object
- #can_expand?(iter, klass, pid) ⇒ Boolean
-
#class_for(iter) ⇒ Object
Class string.
- #close ⇒ Object
- #continue ⇒ Object
- #create_default_tag(buffer, size = nil, more = {}) ⇒ Object
- #dummy_attribute ⇒ Object
- #eval_data(code, needs_ref = false) ⇒ Object
- #generic_step(method) ⇒ Object
- #highlight_inspect(string, buffer, condition = true) ⇒ Object
-
#initialize(parent, session) ⇒ Page
constructor
A new instance of Page.
- #initialize_browser ⇒ Object
- #initialize_shell ⇒ Object
- #initialize_source_code ⇒ Object
- #is_cyclic?(iter) ⇒ Boolean
-
#is_virtual?(iter) ⇒ Boolean
Virtual attributes are attributes that don’t really exist that way.
- #load_browser ⇒ Object
- #load_current_code ⇒ Object
-
#load_data(treeview, parent_iter = nil) ⇒ Object
TODO: Refresh functionality?.
-
#oid_for(iter) ⇒ Object
Object id.
- #on_browser_treeview_cursor_changed(treeview) ⇒ Object
- #on_browser_treeview_row_expanded(treeview, iter, path) ⇒ Object
- #on_code_combobox_changed(combobox) ⇒ Object
- #on_shell_in_button_pressed(button) ⇒ Object (also: #on_shell_in_entry_activate)
- #on_shell_in_entry_changed(shell_in) ⇒ Object
- #on_shell_in_entry_key_press_event(shell_in, event) ⇒ Object
- #on_view_to_shell_btn_clicked(button) ⇒ Object
- #pid_to_obj(pid) ⇒ Object
- #root_code ⇒ Object
- #shell_in_change_text(text) ⇒ Object
- #step_into ⇒ Object
- #step_over ⇒ Object
- #update_location(name, line) ⇒ Object
- #update_title(title) ⇒ Object
-
#value_for(iter) ⇒ Object
Value string.
Constructor Details
#initialize(parent, session) ⇒ Page
Returns a new instance of Page.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/rudebug/page.rb', line 4 def initialize(parent, session) @parent = parent @session = session @glade_file = parent.glade_file @glade = GladeXML.new(@glade_file, "session-hpaned") do |handler| method(handler) rescue lambda { |*args| p [handler, *args] } end @page = @glade["session-hpaned"] initialize_browser() initialize_source_code() initialize_shell() load_browser() load_current_code() label = Gtk::Label.new(session.title) @parent.notebook.prepend_page(@page, label) end |
Instance Attribute Details
#code_notebook ⇒ Object (readonly)
Returns the value of attribute code_notebook.
4 5 6 |
# File 'lib/rudebug/page/source_code.rb', line 4 def code_notebook @code_notebook end |
#files_combobox ⇒ Object (readonly)
Returns the value of attribute files_combobox.
4 5 6 |
# File 'lib/rudebug/page/source_code.rb', line 4 def files_combobox @files_combobox end |
#glade_file ⇒ Object (readonly)
Returns the value of attribute glade_file.
2 3 4 |
# File 'lib/rudebug/page.rb', line 2 def glade_file @glade_file end |
#session ⇒ Object (readonly)
Returns the value of attribute session.
2 3 4 |
# File 'lib/rudebug/page.rb', line 2 def session @session end |
Instance Method Details
#activate_file(name) ⇒ Object
24 25 26 27 28 29 30 31 |
# File 'lib/rudebug/page/source_code.rb', line 24 def activate_file(name) activate_idx = nil @files_combobox.model.each_with_index do |(model, path, iter), idx| activate_idx = idx if iter[0] == name end @files_combobox.active = activate_idx if activate_idx end |
#attribute_for(iter) ⇒ Object
Attribute description
56 57 58 |
# File 'lib/rudebug/page/browser.rb', line 56 def attribute_for(iter) # Attribute description iter[0] end |
#attributes_for(klass, virtual) ⇒ Object
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/rudebug/page/browser.rb', line 166 def attributes_for(klass, virtual) code_parts = [] hash_code = code_parts << if !virtual then %< (%1$s.methods(false).empty?() ? [] : [ [ "eigenclass", false, #{eval_data("class << %1$s; self; end")} ]] ) + (%1$s.is_a?(Module) ? [] : [ [ "class", false, #{eval_data("%1$s.class")} ]] ) + (%1$s.instance_variables.empty?() ? [] : [ [ "ivars", true, #{eval_data(%< $rudebug.to_pairs(%1$s.instance_variables.sort) do |rudebug_ivar| %1$s.instance_variable_get(rudebug_ivar) end>, true) }] ]) + (!%1$s.respond_to?(:size) ? [] : [ [ "size", true, #{eval_data("%1$s.size rescue 'error'")} ]] )> end code_parts << if klass == "Binding" or klass == "Proc" then %<[ [ "location", true, #{eval_data("eval('[__FILE__, __LINE__]', %1$s).join(':')", true)} ], [ "self", false, #{eval_data("eval('self', %1$s)")} ], [ "lvars", true, #{eval_data(%< $rudebug.to_pairs( (eval('local_variables', %1$s) + (eval('$~.nil?', %1$s) ? [] : ['$~']) + (eval('$_.nil?', %1$s) ? [] : ['$_']) - ['_', 'bp', 'client'] ).sort ) do |rudebug_lvar| eval(rudebug_lvar, %1$s) end>, true) }], [ "caller", true, #{eval_data(%<$rudebug.to_list(eval('caller', %1$s))>, true)} ]]> elsif klass == "Array" then %< (0 .. %1$s.size - 1).map do |rudebug_idx| [ rudebug_idx.inspect, false, #{eval_data("%1$s[rudebug_idx]")} ] end> elsif klass == "Hash" then %< %1$s.map do |rudebug_key, rudebug_val| [ rudebug_key.inspect, false, #{eval_data("rudebug_val")} ] end> elsif klass == "$rudebug::Pairs" then %< %1$s.map do |rudebug_key, rudebug_val| [ rudebug_key.to_s, true, #{eval_data("rudebug_val")} ] end> elsif klass == "Class" then %< (%1$s == Object ? [] : [ [ "superclass", true, #{eval_data("%1$s.superclass")} ]] )> elsif klass == "Object" then %< (%1$s != ENV ? [] : %1$s.map do |rudebug_key, rudebug_val| [ rudebug_key.inspect, true, #{eval_data("rudebug_val", true)} ] end )> end code_parts << if klass == "Class" or klass == "Module" then %<[ [ "modules", true, #{eval_data("%1$s.included_modules", true)} ], [ "constants", true, #{eval_data(%< $rudebug.to_pairs(%1$s.constants.sort) do |rudebug_const| %1$s.const_get(rudebug_const) end>, true) }], [ "imethods", true, #{eval_data(%< $rudebug.to_pairs(%1$s.instance_methods(false).sort) do |rudebug_imethod| %1$s.instance_method(rudebug_imethod) end>, true) }]]> end code_parts.compact.map { |part| part.strip }.join(" + ") end |
#can_expand?(iter, klass, pid) ⇒ Boolean
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 |
# File 'lib/rudebug/page/browser.rb', line 266 def (iter, klass, pid) # No cyclic nodes return false if is_cyclic?(iter) code_template = attributes_for(klass, is_virtual?(iter)) # Short-circuit empty attributes (optimization) return false if code_template == "" #puts "template: %s" % code_template code = code_template % pid_to_obj(pid) #puts "code: %s" % code result = @session.eval(code) #p result #p [code, result] attributes = eval(result) !attributes.empty? end |
#class_for(iter) ⇒ Object
Class string
68 69 70 |
# File 'lib/rudebug/page/browser.rb', line 68 def class_for(iter) # Class string iter[3] end |
#close ⇒ Object
65 66 67 68 69 70 |
# File 'lib/rudebug/page.rb', line 65 def close() page_num = @parent.notebook.page_num(@page) if page_num != -1 then @parent.notebook.remove_page(page_num) end end |
#continue ⇒ Object
53 54 55 |
# File 'lib/rudebug/page.rb', line 53 def continue() generic_step(:continue) end |
#create_default_tag(buffer, size = nil, more = {}) ⇒ Object
26 27 28 29 30 |
# File 'lib/rudebug/page.rb', line 26 def create_default_tag(buffer, size = nil, more = {}) size ||= 10 = { "font" => "Andale Mono %d" % size }.merge(more) buffer.create_tag("default", ) end |
#dummy_attribute ⇒ Object
106 107 108 |
# File 'lib/rudebug/page/browser.rb', line 106 def dummy_attribute() "DUMMY" end |
#eval_data(code, needs_ref = false) ⇒ Object
161 162 163 164 |
# File 'lib/rudebug/page/browser.rb', line 161 def eval_data(code, needs_ref = false) ref = needs_ref ? "$rudebug.add_ref(#{code})" : code "$rudebug.inspect_obj((#{code})), (#{code}).class.to_s, (#{ref}).object_id" end |
#generic_step(method) ⇒ Object
32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/rudebug/page.rb', line 32 def generic_step(method) result = @session.__send__(method) if result.nil? then close() else update_location(*result) load_browser() title = result.join(":") # TODO: Query from server? update_title(title) end return result end |
#highlight_inspect(string, buffer, condition = true) ⇒ Object
46 47 48 49 50 51 52 53 |
# File 'lib/rudebug/page/source_code.rb', line 46 def highlight_inspect(string, buffer, condition = true) # Heuristics ftw! if condition and string[0, 1] != "#" then Syntax.gtk_highlight(string, buffer) else buffer.insert(buffer.end_iter, string, "default") end end |
#initialize_browser ⇒ Object
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/rudebug/page/browser.rb', line 5 def initialize_browser() @browser_treeview = @glade["browser-treeview"] @object_view = @glade["object-view"] @object_buf = @object_view.buffer @view_to_shell = @glade["view-to-shell-btn"] @browser_store = Gtk::TreeStore.new(String, String, Integer, String, TrueClass) @browser_treeview.model = @browser_store @browser_treeview.rules_hint = true renderer = Gtk::CellRendererText.new create_default_tag(@object_buf, 10) col = Gtk::TreeViewColumn.new("Attribute", renderer, :text => 0) col.sizing = Gtk::TreeViewColumn::FIXED col.reorderable = false col. = true col.resizable = true @browser_treeview.append_column(col) renderer = Gtk::CellRendererText.new() renderer.size_points = 8 renderer.ellipsize = Pango::ELLIPSIZE_MIDDLE col = Gtk::TreeViewColumn.new("Value", renderer, :text => 1) col.sizing = Gtk::TreeViewColumn::FIXED col.reorderable = false col. = true col.resizable = true @browser_treeview.append_column(col) renderer = Gtk::CellRendererText.new col = Gtk::TreeViewColumn.new("OID", nil, :text => 2) col.visible = false @browser_treeview.append_column(col) renderer = Gtk::CellRendererText.new col = Gtk::TreeViewColumn.new("Class", renderer, :text => 3) col.visible = false @browser_treeview.append_column(col) renderer = Gtk::CellRendererText.new col = Gtk::TreeViewColumn.new("Virtual", renderer, :text => 4) col.visible = false @browser_treeview.append_column(col) @browser_treeview.headers_visible = true @browser_treeview.headers_clickable = false @browser_treeview.enable_search = false end |
#initialize_shell ⇒ Object
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# File 'lib/rudebug/page/shell.rb', line 2 def initialize_shell() @shell_out_view = @glade["shell-out-view"] @shell_out = @shell_out_view.buffer @shell_in = @glade["shell-in-entry"] @shell_in.grab_focus create_default_tag(@shell_out, 12) @shell_out.insert(@shell_out.end_iter, "Interactive session shell for %s" % @session.title, "default") @shell_out_view.cursor_visible = false @shell_out_end = @shell_out.create_mark(nil, @shell_out.end_iter, false) @shell_history = [] @shell_history_idx = -1 @shell_history_ignore_change = false end |
#initialize_source_code ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 |
# File 'lib/rudebug/page/source_code.rb', line 6 def initialize_source_code() @code_notebook = @glade["code-notebook"] @files_combobox = @glade["code-combobox"] model = @files_combobox.model model.set_default_sort_func do |iter1, iter2| iter1[0].downcase <=> iter2[0].downcase end model.set_sort_column_id(Gtk::TreeSortable::DEFAULT_SORT_COLUMN_ID) @code_notebook.remove_page(0) @files = {} end |
#is_cyclic?(iter) ⇒ Boolean
282 283 284 285 286 287 288 289 290 |
# File 'lib/rudebug/page/browser.rb', line 282 def is_cyclic?(iter) value = value_for(iter) while iter = iter.parent return true if value_for(iter) == value end return false end |
#is_virtual?(iter) ⇒ Boolean
Virtual attributes are attributes that don’t really exist that way. They are just information we poll for the user and should not get information like classes and so on.
75 76 77 |
# File 'lib/rudebug/page/browser.rb', line 75 def is_virtual?(iter) # Virtual attribute? iter[4] end |
#load_browser ⇒ Object
52 53 54 |
# File 'lib/rudebug/page/browser.rb', line 52 def load_browser() load_data(@browser_treeview) end |
#load_current_code ⇒ Object
39 40 41 42 43 44 |
# File 'lib/rudebug/page/source_code.rb', line 39 def load_current_code() name = @session.current_file line = @session.current_line update_location(name, line) end |
#load_data(treeview, parent_iter = nil) ⇒ Object
TODO: Refresh functionality?
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/rudebug/page/browser.rb', line 120 def load_data(treeview, parent_iter = nil) store = treeview.model code = nil if parent_iter.nil? then treeview.model.clear code = root_code() % [] else dummy = parent_iter.first_child if attribute_for(dummy) == dummy_attribute() then # Remove dummy store.remove(parent_iter.first_child) parent_class = class_for(parent_iter) pid = oid_for(parent_iter) code_template = attributes_for(parent_class, is_virtual?(parent_iter)) code = code_template % pid_to_obj(pid) end end if code then attributes = eval(@session.eval(code)) attributes.each do |(attribute, virtual, value, klass, oid)| iter = store.append(parent_iter) iter[0], iter[1], iter[2], iter[3], iter[4] = attribute, value, oid, klass, virtual if (iter, klass, oid) then dummy_iter = store.append(iter) dummy_iter[0] = dummy_attribute() end end if parent_iter then treeview.collapse_row(parent_iter.path) treeview.(parent_iter.path, false) end end end |
#oid_for(iter) ⇒ Object
Object id
64 65 66 |
# File 'lib/rudebug/page/browser.rb', line 64 def oid_for(iter) # Object id iter[2] end |
#on_browser_treeview_cursor_changed(treeview) ⇒ Object
79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/rudebug/page/browser.rb', line 79 def on_browser_treeview_cursor_changed(treeview) path, column = *treeview.cursor # We don't care about selected column iter = treeview.model.get_iter(path) text = [ value_for(iter), #class_for(iter) ].join("\n\n") @object_buf.text = "" highlight_inspect(text, @object_buf) @session.eval("$rudebug.selected = %s" % pid_to_obj(oid_for(iter))) @view_to_shell.sensitive = true end |
#on_browser_treeview_row_expanded(treeview, iter, path) ⇒ Object
110 111 112 |
# File 'lib/rudebug/page/browser.rb', line 110 def (treeview, iter, path) load_data(treeview, iter) end |
#on_code_combobox_changed(combobox) ⇒ Object
19 20 21 22 |
# File 'lib/rudebug/page/source_code.rb', line 19 def on_code_combobox_changed(combobox) name = combobox.active_text @files[name].activate end |
#on_shell_in_button_pressed(button) ⇒ Object Also known as: on_shell_in_entry_activate
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/rudebug/page/shell.rb', line 20 def () input = @shell_in.text result = begin @session.eval(input) rescue Connection::RemoteException => exception error = true exception. end @shell_out.insert(@shell_out.end_iter, "\n\n>> ", "default") Syntax.gtk_highlight(input, @shell_out) marker = error ? "" : "=> " @shell_out.insert(@shell_out.end_iter, "\n%s" % marker, "default") highlight_inspect(result, @shell_out, !error) @shell_out_view.scroll_to_mark(@shell_out_end, 0, true, 1, 1) @shell_in.text = "" @shell_history.unshift(input) @shell_history.uniq! end |
#on_shell_in_entry_changed(shell_in) ⇒ Object
86 87 88 89 90 |
# File 'lib/rudebug/page/shell.rb', line 86 def on_shell_in_entry_changed(shell_in) unless @shell_history_ignore_change @shell_history_idx = -1 end end |
#on_shell_in_entry_key_press_event(shell_in, event) ⇒ Object
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/rudebug/page/shell.rb', line 46 def on_shell_in_entry_key_press_event(shell_in, event) case event.keyval when Gdk::Keyval::GDK_Up then if @shell_history.size > 0 then if @shell_history_idx == -1 then text = @shell_in.text if !text.strip.empty? then old_size = @shell_history.size @shell_history.unshift(text) @shell_history.uniq! @shell_history_idx += 1 if old_size != @shell_history.size end end @shell_history_idx += 1 if @shell_history_idx < @shell_history.size - 1 shell_in_change_text(@shell_history[@shell_history_idx]) end when Gdk::Keyval::GDK_Down then if @shell_history_idx > 0 then @shell_history_idx -= 1 shell_in_change_text(@shell_history[@shell_history_idx]) end else return false end return true end |
#on_view_to_shell_btn_clicked(button) ⇒ Object
94 95 96 97 98 99 100 |
# File 'lib/rudebug/page/browser.rb', line 94 def on_view_to_shell_btn_clicked() @shell_in.delete_selection @shell_in.insert_at_cursor("$rudebug.selected") @shell_in.grab_focus sel_start, sel_end = *@shell_in.selection_bounds @shell_in.select_region(sel_end, sel_end) end |
#pid_to_obj(pid) ⇒ Object
114 115 116 |
# File 'lib/rudebug/page/browser.rb', line 114 def pid_to_obj(pid) "ObjectSpace._id2ref(%s)" % pid end |
#root_code ⇒ Object
102 103 104 |
# File 'lib/rudebug/page/browser.rb', line 102 def root_code() "[['context', false, #{eval_data("binding")}]]" end |
#shell_in_change_text(text) ⇒ Object
78 79 80 81 82 83 84 |
# File 'lib/rudebug/page/shell.rb', line 78 def shell_in_change_text(text) @shell_history_ignore_change = true @shell_in.text = text @shell_in.position = -1 ensure @shell_history_ignore_change = false end |
#step_into ⇒ Object
57 58 59 |
# File 'lib/rudebug/page.rb', line 57 def step_into() generic_step(:step_into) end |
#step_over ⇒ Object
61 62 63 |
# File 'lib/rudebug/page.rb', line 61 def step_over() generic_step(:step_over) end |
#update_location(name, line) ⇒ Object
33 34 35 36 37 |
# File 'lib/rudebug/page/source_code.rb', line 33 def update_location(name, line) file = @files[name] ||= CodeFile.new(self, name) file.place_marker(line) activate_file(name) end |
#update_title(title) ⇒ Object
47 48 49 50 51 |
# File 'lib/rudebug/page.rb', line 47 def update_title(title) @parent.notebook.set_tab_label_text(@page, title) @parent.notebook.(@page, title) @parent.pages[title] = self end |
#value_for(iter) ⇒ Object
Value string
60 61 62 |
# File 'lib/rudebug/page/browser.rb', line 60 def value_for(iter) # Value string iter[1] end |