3
11
This repository has been archived on 2024-05-16. You can view files and clone it, but cannot push or open issues or pull requests.
blender-addons-contrib/development_class_viewer.py

204 lines
6.2 KiB
Python

# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
bl_info = {
"name": "Class Viewer",
"author": "Mackraken", "batFinger"
"version": (0, 1, 3),
"blender": (2, 80, 0),
"location": "Text Editor > Toolbar, Text Editor > Right Click",
"warning": "",
"description": "List classes and definitions of a text block",
"doc_url": "https://sites.google.com/site/aleonserra/home/scripts/class-viewer",
"tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
"category": "Development"}
import bpy
from bpy.types import (
Operator,
Menu,
)
from bpy.props import IntProperty
# lists all defs, comment or classes
# space = current text editor
# sort = sort result
# tipo = kind of struct to look for
# escape = character right next to the class or def name
# note: GPL license block is skipped from the comment entries now
def getfunc(space, sort, tipo="def ", escape=""):
defs, license_clean, return_lists = [], [], []
if space.type == "TEXT_EDITOR" and space.text is not None:
txt = space.text
line_block_start, line_block_end = None, None
for i, l in enumerate(txt.lines):
try:
line = l.body
except:
line = ""
if tipo == "# ":
linex, line_c = "", ""
if tipo in line:
# find the license block
block_start = line.find("BEGIN GPL LICENSE BLOCK")
if block_start != -1:
line_block_start = i + 1
block_end = line.find("END GPL LICENSE BLOCK")
if block_end != -1:
line_block_end = i + 1
end = line.find(escape)
# use line partition, get the last tuple element as it is the comment
line_c = line.partition("#")[2]
# strip the spaces from the left if any and
# cut the comment at the 60 characters length max
linex = line_c[:60].lstrip() if len(line_c) > 60 else line_c.lstrip()
if end == 0:
func = linex
else:
func = linex.rstrip(escape)
defs.append([func, i + 1])
elif line[0: len(tipo)] == tipo:
end = line.find(escape)
if end == 0:
func = line[len(tipo)::]
else:
func = line[len(tipo):end]
defs.append([func, i + 1])
if line_block_start and line_block_end:
# note : the slice should keep the first line of the license block
license_clean = defs[line_block_start: line_block_end]
return_lists = [line for line in defs if line not in license_clean] if license_clean else defs
if sort:
return_lists.sort()
return return_lists
def draw_menus(layout, space, tipo, escape):
items = getfunc(space, 1, tipo, escape)
if not items:
layout.label(text="Not found", icon="INFO")
return
for it in items:
layout.operator("text.jumptoline", text="{}".format(it[0])).line = it[1]
class BaseCheckPoll():
@classmethod
def poll(cls, context):
if context.area.spaces[0].type != "TEXT_EDITOR":
return False
else:
return context.area.spaces[0].text is not None
class TEXT_OT_Jumptoline(Operator, BaseCheckPoll):
bl_label = "Jump"
bl_idname = "text.jumptoline"
bl_description = "Jump to line containing the text"
__doc__ = "Jump to line containing the passed line integer. Used by the Class Viewer add-on"
line: IntProperty(default=-1)
def execute(self, context):
if self.line == -1:
self.report({'WARNING'}, "No valid line found. Operation Cancelled")
return {'CANCELLED'}
bpy.ops.text.jump(line=self.line)
self.report({'INFO'}, "Jump to line: {}".format(self.line))
return {'FINISHED'}
class CommentsMenu(Menu, BaseCheckPoll):
bl_idname = "OBJECT_MT_select_comments"
bl_label = "Comments"
def draw(self, context):
layout = self.layout
space = context.area.spaces[0]
draw_menus(layout, space, "# ", "\n")
class DefsMenu(Menu, BaseCheckPoll):
bl_idname = "OBJECT_MT_select_defs"
bl_label = "Definitions"
def draw(self, context):
layout = self.layout
space = context.area.spaces[0]
draw_menus(layout, space, "def ", "(")
class ClassesMenu(Menu, BaseCheckPoll):
bl_idname = "OBJECT_MT_select_classes"
bl_label = "Classes"
def draw(self, context):
layout = self.layout
space = context.area.spaces[0]
draw_menus(layout, space, "class ", "(")
def menu_development_class_view(self, context):
self.layout.separator()
self.layout.menu("OBJECT_MT_select_comments", icon='SHORTDISPLAY')
self.layout.menu("OBJECT_MT_select_defs", icon='FILE_TEXT')
self.layout.menu("OBJECT_MT_select_classes", icon='SCRIPTPLUGINS')
classes = (
TEXT_OT_Jumptoline,
ClassesMenu,
DefsMenu,
CommentsMenu,
)
def register():
for cls in classes:
bpy.utils.register_class(cls)
bpy.types.TEXT_MT_context_menu.append(menu_development_class_view)
def unregister():
for cls in classes:
bpy.utils.unregister_class(cls)
bpy.types.TEXT_MT_context_menu.remove(menu_development_class_view)
if __name__ == "__main__":
register()