Attachment 'pythonoutline.py'
Download 1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # This file is part of the Python Outline Plugin for Gedit
5 # Copyright (C) 2007 Dieter Verfaillie <dieterv@optionexplicit.be>
6 #
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
21
22 import os
23
24 import gtk
25 import gedit
26
27 import compiler
28 import gc
29 import glob
30 import time
31
32
33 class TreeModelASTVisitor(compiler.visitor.ASTVisitor):
34 defaulticon = None
35
36 moduleicon = gtk.Window().render_icon(gtk.STOCK_COPY, gtk.ICON_SIZE_MENU)
37 importicon = gtk.Window().render_icon(gtk.STOCK_JUMP_TO, gtk.ICON_SIZE_MENU)
38 classicon = gtk.Window().render_icon(gtk.STOCK_FILE, gtk.ICON_SIZE_MENU)
39 functionicon = gtk.Window().render_icon(gtk.STOCK_EXECUTE, gtk.ICON_SIZE_MENU)
40
41 def __init__(self, treemodel):
42 compiler.visitor.ASTVisitor.__init__(self)
43
44 self.treemodel = treemodel
45
46 def walkChildren(self, node, parent=None):
47 for child in node.getChildNodes():
48 child.parent = node
49 self.dispatch(child, parent)
50
51 def default(self, node, parent=None):
52 self.walkChildren(node, parent)
53
54
55 class OutlineTreeModelASTVisitor(TreeModelASTVisitor):
56 def __init__(self, treemodel):
57 TreeModelASTVisitor.__init__(self, treemodel)
58
59 def visitAssAttr(self, node, parent=None):
60 if hasattr(node.expr, 'name'):
61 if node.expr.name == 'self':
62 iter = self.treemodel.append(parent, (self.defaulticon, 'self.' + node.attrname, node.__class__.__name__, node.lineno, None))
63
64 def visitAssName(self, node, parent=None):
65 if hasattr(node.parent, 'parent'):
66 if not hasattr(node.parent.parent, 'parent'):
67 iter = self.treemodel.append(parent, (self.defaulticon, node.name, node.__class__.__name__, node.lineno, None))
68
69 def visitClass(self, node, parent=None):
70 iter = self.treemodel.append(parent, (self.classicon, node.name, node.__class__.__name__, node.lineno, node.doc))
71 self.walkChildren(node.code, iter)
72
73 def visitDecorators(self, node, parent=None):
74 iter = self.treemodel.append(parent, (self.defaulticon, None, node.__class__.__name__, node.lineno, None))
75 self.walkChildren(node, iter)
76
77 def visitFrom(self, node, parent=None):
78 for name in node.names:
79 if name[1] is None:
80 self.treemodel.append(parent, (self.importicon, name[0] + ' (' + node.modname + ')', node.__class__.__name__, node.lineno, None))
81 else:
82 self.treemodel.append(parent, (self.importicon, name[1] + ' = ' + name[0] + ' (' + node.modname + ')', node.__class__.__name__, node.lineno, None))
83
84 def visitFunction(self, node, parent=None):
85 iter = self.treemodel.append(parent, (self.functionicon, node.name, node.__class__.__name__, node.lineno, node.doc))
86 self.walkChildren(node, iter)
87
88 def visitImport(self, node, parent=None):
89 for name in node.names:
90 if name[1] is None:
91 self.treemodel.append(parent, (self.importicon, name[0], node.__class__.__name__, node.lineno, None))
92 else:
93 self.treemodel.append(parent, (self.importicon, name[1] + ' = ' + name[0], node.__class__.__name__, node.lineno, None))
94
95 def visitName(self, node, parent=None):
96 if node.parent.__class__.__name__ in ['Class', 'Function']:
97 self.treemodel.append(parent, (self.defaulticon, node.name, node.__class__.__name__, node.lineno, None))
98
99
100 class OutlineBox(gtk.VBox):
101 def __init__(self):
102 gtk.VBox.__init__(self)
103
104 scrolledwindow = gtk.ScrolledWindow()
105 scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
106 scrolledwindow.show()
107 self.pack_start(scrolledwindow, True, True, 0)
108
109 self.treeview = gtk.TreeView()
110 self.treeview.set_rules_hint(True)
111 self.treeview.set_headers_visible(False)
112 self.treeview.set_enable_search(True)
113 self.treeview.set_reorderable(False)
114 self.treeselection = self.treeview.get_selection()
115 self.treeselection.connect('changed', self.on_selection_changed)
116 scrolledwindow.add(self.treeview)
117
118 col = gtk.TreeViewColumn()
119 col.set_title('name')
120 col.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
121 col.set_expand(True)
122 render_pixbuf = gtk.CellRendererPixbuf()
123 render_pixbuf.set_property('xalign', 0.5)
124 render_pixbuf.set_property('yalign', 0.5)
125 render_pixbuf.set_property('xpad', 2)
126 render_pixbuf.set_property('ypad', 2)
127 col.pack_start(render_pixbuf, expand=False)
128 col.add_attribute(render_pixbuf, 'pixbuf', 0)
129 render_text = gtk.CellRendererText()
130 render_text.set_property('xalign', 0)
131 render_text.set_property('yalign', 0.5)
132 col.pack_start(render_text, expand=True)
133 col.add_attribute(render_text, 'text', 1)
134 self.treeview.append_column(col)
135 self.treeview.set_search_column(1)
136
137 self.label = gtk.Label()
138 self.pack_end(self.label, False)
139
140 self.expand_classes = False
141 self.expand_functions = False
142
143 self.show_all()
144
145 def on_toggle_expand_classes(self, action):
146 self.expand_classes = action.get_active()
147
148 def on_toggle_expand_functions(self, action):
149 self.expand_functions = action.get_active()
150
151 def on_row_has_child_toggled(self, treemodel, path, iter):
152 if self.expand_classes and treemodel.get_value(iter, 2) == 'Class':
153 self.treeview.expand_row(path, False)
154 elif self.expand_functions and treemodel.get_value(iter, 2) == 'Function':
155 self.treeview.expand_row(path, False)
156
157 def on_selection_changed(self, selection):
158 model, iter = selection.get_selected()
159 if iter:
160 lineno = model.get_value(iter, 3)
161 if lineno:
162 lineno = int(lineno) -1
163 linestartiter = self.buffer.get_iter_at_line(lineno)
164 lineenditer = self.buffer.get_iter_at_line(lineno)
165 lineenditer.forward_line()
166 line = self.buffer.get_text(linestartiter, lineenditer)
167 name = model.get_value(iter, 1)
168 start = line.find(name)
169 if start > -1:
170 end = start + len(name)
171 self.buffer.select_range(
172 self.buffer.get_iter_at_line_offset(lineno, start),
173 self.buffer.get_iter_at_line_offset(lineno, end))
174 self.view.scroll_to_cursor()
175 else:
176 #Todo: scroll view to lineno
177 pass
178
179 def create_treemodel(self):
180 treemodel = gtk.TreeStore(gtk.gdk.Pixbuf, str, str, str, str)
181 handler = treemodel.connect('row-has-child-toggled', self.on_row_has_child_toggled)
182 return treemodel, handler
183
184 def parse(self, view, buffer):
185 self.view = view
186 self.buffer = buffer
187
188 startTime = time.time()
189
190 treemodel, handler = self.create_treemodel()
191 self.treeview.set_model(treemodel)
192 self.treeview.freeze_child_notify()
193
194 visitor = OutlineTreeModelASTVisitor(treemodel)
195
196 try:
197 bounds = self.buffer.get_bounds()
198 mod = compiler.parse(self.buffer.get_text(bounds[0], bounds[1]).replace('\r', '\n') + '\n')
199 visitor.preorder(mod, visitor, None)
200 del bounds, mod, visitor
201 except SyntaxError:
202 pass
203 finally:
204 gc.collect()
205
206 treemodel.disconnect(handler)
207 self.treeview.thaw_child_notify()
208
209 stopTime = time.time()
210 self.label.set_text('Outline created in ' + str(float(stopTime - startTime)) + ' s')
211
212
213 class PythonOutlinePluginInstance(object):
214 def __init__(self, plugin, window):
215 self._window = window
216 self._plugin = plugin
217
218 self._insert_panel()
219
220 def deactivate(self):
221 self._remove_panel
222
223 self._window = None
224 self._plugin = None
225
226 def update_ui(self):
227 document = self._window.get_active_document()
228 if document:
229 uri = str(document.get_uri())
230 if document.get_mime_type() == 'text/x-python' or uri.endswith('.py') or uri.endswith('.pyw'):
231 self.outlinebox.parse(self._window.get_active_view(), document)
232 else:
233 treemodel, handler = self.outlinebox.create_treemodel()
234 self.outlinebox.treeview.set_model(treemodel)
235
236 def _insert_panel(self):
237 self.panel = self._window.get_side_panel()
238 self.outlinebox = OutlineBox()
239 self.panel.add_item(self.outlinebox, "Python Outline", gtk.STOCK_REFRESH)
240
241 def _remove_panel(self):
242 self.panel.destroy()
243
244
245 class PythonOutlinePlugin(gedit.Plugin):
246 def __init__(self):
247 gedit.Plugin.__init__(self)
248 self._instances = {}
249
250 def activate(self, window):
251 self._instances[window] = PythonOutlinePluginInstance(self, window)
252
253 def deactivate(self, window):
254 self._instances[window].deactivate()
255 del self._instances[window]
256
257 def update_ui(self, window):
258 self._instances[window].update_ui()
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.