1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
20 "name": "Class Viewer",
21 "author": "Mackraken", "batFinger"
23 "blender": (2, 80, 0),
24 "location": "Text Editor > Toolbar, Text Editor > Right Click",
26 "description": "List classes and definitions of a text block",
27 "doc_url": "https://sites.google.com/site/aleonserra/home/scripts/class-viewer",
28 "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
29 "category": "Development"}
33 from bpy
.types
import (
37 from bpy
.props
import IntProperty
39 # lists all defs, comment or classes
40 # space = current text editor
42 # tipo = kind of struct to look for
43 # escape = character right next to the class or def name
44 # note: GPL license block is skipped from the comment entries now
47 def getfunc(space
, sort
, tipo
="def ", escape
=""):
48 defs
, license_clean
, return_lists
= [], [], []
50 if space
.type == "TEXT_EDITOR" and space
.text
is not None:
52 line_block_start
, line_block_end
= None, None
54 for i
, l
in enumerate(txt
.lines
):
60 linex
, line_c
= "", ""
62 # find the license block
63 block_start
= line
.find("BEGIN GPL LICENSE BLOCK")
65 line_block_start
= i
+ 1
67 block_end
= line
.find("END GPL LICENSE BLOCK")
69 line_block_end
= i
+ 1
71 end
= line
.find(escape
)
72 # use line partition, get the last tuple element as it is the comment
73 line_c
= line
.partition("#")[2]
74 # strip the spaces from the left if any and
75 # cut the comment at the 60 characters length max
76 linex
= line_c
[:60].lstrip() if len(line_c
) > 60 else line_c
.lstrip()
80 func
= linex
.rstrip(escape
)
82 defs
.append([func
, i
+ 1])
84 elif line
[0: len(tipo
)] == tipo
:
85 end
= line
.find(escape
)
87 func
= line
[len(tipo
)::]
89 func
= line
[len(tipo
):end
]
90 defs
.append([func
, i
+ 1])
92 if line_block_start
and line_block_end
:
93 # note : the slice should keep the first line of the license block
94 license_clean
= defs
[line_block_start
: line_block_end
]
96 return_lists
= [line
for line
in defs
if line
not in license_clean
] if license_clean
else defs
103 def draw_menus(layout
, space
, tipo
, escape
):
105 items
= getfunc(space
, 1, tipo
, escape
)
107 layout
.label(text
="Not found", icon
="INFO")
111 layout
.operator("text.jumptoline", text
="{}".format(it
[0])).line
= it
[1]
114 class BaseCheckPoll():
116 def poll(cls
, context
):
117 if context
.area
.spaces
[0].type != "TEXT_EDITOR":
120 return context
.area
.spaces
[0].text
is not None
123 class TEXT_OT_Jumptoline(Operator
, BaseCheckPoll
):
125 bl_idname
= "text.jumptoline"
126 bl_description
= "Jump to line containing the text"
127 __doc__
= "Jump to line containing the passed line integer. Used by the Class Viewer add-on"
129 line
: IntProperty(default
=-1)
131 def execute(self
, context
):
133 self
.report({'WARNING'}, "No valid line found. Operation Cancelled")
136 bpy
.ops
.text
.jump(line
=self
.line
)
137 self
.report({'INFO'}, "Jump to line: {}".format(self
.line
))
142 class CommentsMenu(Menu
, BaseCheckPoll
):
143 bl_idname
= "OBJECT_MT_select_comments"
144 bl_label
= "Comments"
146 def draw(self
, context
):
148 space
= context
.area
.spaces
[0]
149 draw_menus(layout
, space
, "# ", "\n")
152 class DefsMenu(Menu
, BaseCheckPoll
):
153 bl_idname
= "OBJECT_MT_select_defs"
154 bl_label
= "Definitions"
156 def draw(self
, context
):
158 space
= context
.area
.spaces
[0]
159 draw_menus(layout
, space
, "def ", "(")
162 class ClassesMenu(Menu
, BaseCheckPoll
):
163 bl_idname
= "OBJECT_MT_select_classes"
166 def draw(self
, context
):
168 space
= context
.area
.spaces
[0]
169 draw_menus(layout
, space
, "class ", "(")
172 def menu_development_class_view(self
, context
):
173 self
.layout
.separator()
175 self
.layout
.menu("OBJECT_MT_select_comments", icon
='SHORTDISPLAY')
176 self
.layout
.menu("OBJECT_MT_select_defs", icon
='FILE_TEXT')
177 self
.layout
.menu("OBJECT_MT_select_classes", icon
='SCRIPTPLUGINS')
190 bpy
.utils
.register_class(cls
)
192 bpy
.types
.TEXT_MT_context_menu
.append(menu_development_class_view
)
197 bpy
.utils
.unregister_class(cls
)
199 bpy
.types
.TEXT_MT_context_menu
.remove(menu_development_class_view
)
202 if __name__
== "__main__":