Old: Class Viewer for coding

Hi.

This is a script lists all classes and definitions at the text editor into a menu, where you can select and go to the line where the class or def is.
http://vimeo.com/22053084user6644080/classviewerExample Video (old version)

Download site


Use:
1.-Install as a regular addon.
2.-Load any script at text editor.
3.-Right click to pop up the class viewer menu.

Defs - List all functions.
Classes - Lists all classes.
Comments - You can jump to any line if you insert a comment with 3 pounds followed by a space.
Example: ### This is function does something.
Go to line.
Search text.

Tested on 2.56 35566
Thanks to RickyBlender and batFinger for explain me some code for the layout.

Updates:
-Added go to line
-Added search text.

-Corrected classes identification
-Added to contextual right_click Menu
-Fixed error when a non valid character is found.

This a very useful add-on, especially for large scripts that are several thousand lines long.

Some suggestions:

  • Have the update buttons update both the classes and the defs, so I don’t need to press both buttons.
  • Remove the print() statement at line 42 (probably a leftover from developing the script).
  • When calling getfunc() in lines 126 and 131 add a space to “def” and “class”. That way you won’t get false positives with lines like:
classical = "old"

Of course you’ll also need to remove the +1 in line 41 if you do that.

  • Have an option to sort the items alphabetically, as an additional option to the current way they’re displayed.
  • Remove the Jump buttons and automatically jump to the section as soon as the user selects any of the items. (might be impossible with the current api, but I’d love to see this)

Sorry for the long list of suggestions, it’s just that this add-on has a lot of potential and will make my coding work a lot easier. Excellent script!

Tried it with SVN 360** , works … very nice!

indeed after def there MUST be a space (the print does not disturb me?)

Excellent script.

Was thinking about something similar to emulate expanding/collapsing of hierarchy using XML and XSL. Your script shows me how to do the parts i had no idea about. Actually I don’t need to bother anymore this solves my navigation hassles for when my spaghetti gets long and tangled.

A question:How to list the arguments of FloatProperty for instance… like autocomplete does? I tried to work it out from the autocomplete pys but got a bit lost.

found it

bottom header text edtior view menu and select properties

how do you open the left window for text editor
this was too fast in your video?

like to see more things like get to the line for selected class

but also would be nice for functions in the script too!

i was thinking about having something like that a few weehs after working ona very long script
always using the find command to go between different class and functions!LOL

i’m glad you made one should make life easier for scripting

do you have updated version?

i got an error like this

", line 39, in getfunc
line = l.body
UnicodeDecodeError: ‘utf8’ codec can’t decode byte 0x92 in position 60: invalid
start byte

what can i do with this ?

Thanks for the comments ill update all your your suggestions. (false positives fixed and published)
@RickyBlender
To open the tool panel Press Ctrl+F(find a word) .
Ill figure it out about pagecode, You can try making the text “internal”, if this doesnt solve that error please let me know.
@Crouch
Thats a good idea just 1 update buttom, easy todo.

As i said in another thread i dont know very much about UILayout and i think this can be improved a lot. Things like listing underlying defs into a class or maybe another kind of layout.

I tried to “update” and jump automatically. Auto update was impossible to me. Auto Jump can be done but causes the scroll to go anywhere.

any idea about this
UnicodeDecodeError: ‘utf8’

error ?

waiting for your upate

I dont know how to encode text in Blender yet, can you send me your text to reproduce the exception?
Also did you make the text “internal”?
Ill look to correct that.

Was playing around with your script to put it onto the right click menu …



# ##### 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",
    'version': (0, 0, 2),
    'blender': (2, 5, 6),
    'api': 35566,
    'location': "Text Editor > Toolbar",
    'warning': "",
    'description': "List text's classes and definitions",
    'wiki_url': "mailto:[email protected]",
    'category': "Development"}

import bpy


def getfunc(space, tipo="def "):
    
    text = space.text
        
    defs = []
    for i, l in enumerate(text.lines):
        line = l.body
        if line[0:len(tipo)]==tipo:
            func = line[len(tipo):line.find("(")]
            print(tipo, func)
            defs.append([func, i+1])
    return defs

def update(items, col):
    for i in range(0, len(col)):
        col.remove(0)
        
    for i, item in enumerate(items):
        if len(col)<i+1:
            col.add()
        col[i].name = item[0]
        
        col[i].myint = item[1]

    
class PropertyGroup(bpy.types.PropertyGroup):
    pass
 
bpy.utils.register_class(PropertyGroup) 
 
 

 
## create CollectionProperty and link it to the property class
bpy.types.Scene.myCollection = bpy.props.CollectionProperty(type = PropertyGroup)
bpy.types.Scene.myCollection_index = bpy.props.IntProperty(min = -1, default = -1)

bpy.types.Scene.classCollection = bpy.props.CollectionProperty(type = PropertyGroup)
bpy.types.Scene.classCollection_index = bpy.props.IntProperty(min = -1, default = -1)


## create Properties for the collection entries:
PropertyGroup.mystring = bpy.props.StringProperty()
PropertyGroup.myint = bpy.props.IntProperty(default = False)

class OBJECT_OT_Jumptoline(bpy.types.Operator):
    bl_label = "Jump"
    bl_idname = "collection.jump"
    __doc__ = "Simple Custom Button"
    line = bpy.props.IntProperty(default=-1)
    add = bpy.props.BoolProperty(default=True)
    
    @classmethod
    def poll(cls, context):
        return context.area.active_space.text!=None
    
    def execute(self, context):
        scn = context.scene
        if self.line >= 0:
            return bpy.ops.text.jump(line=self.line)
        add = self.add
        
        if add:
            collection = scn.myCollection
            index = scn.myCollection_index
        else:
            collection = scn.classCollection
            index = scn.classCollection_index
        if index<len(collection):
            num = collection[index].myint
            bpy.ops.text.jump(line=num)
        return {'FINISHED'}
 
 
## create operator to add or remove entries to/from  the Collection
class OBJECT_OT_add_remove_Collection_Items(bpy.types.Operator):
    bl_label = "Add or Remove"
    bl_idname = "collection.add_remove"
    __doc__ = "Simple Custom Button"
 
 
 
    add = bpy.props.BoolProperty(default = True)
    @classmethod
    def poll(cls, context):
        return context.area.active_space.text!=None
    
    def invoke(self, context, event):
        add = self.add
        scn = context.scene
        
        # updates the list
        space = context.area.active_space
        if add:
            
            collection = scn.myCollection   
            defs = getfunc(space, "def ")
            update(defs, collection)
            
        else:
            collection = scn.classCollection
            classes = getfunc(space, "class ")
            update(classes, collection)

        return {'FINISHED'} 
 
class OBJECT_PT_defViewer(bpy.types.Panel):
 
    bl_label = "Def Viewer"
    bl_space_type = "TEXT_EDITOR"
    bl_region_type = "UI"
    #bl_context = "object"
     
    def draw(self, context):
        scn = context.scene
        layout = self.layout
      
        ##show collection in Panel:
        row = layout.row()
        row.label("defs")
        row.operator("collection.jump")
        row.operator("collection.add_remove", text="Update")
        
        row = layout.row()
        row.template_list(scn, "myCollection", scn, "myCollection_index")
        

class OBJECT_PT_ClassViewer(bpy.types.Panel):
 
    bl_label = "Class Viewer"
    bl_space_type = "TEXT_EDITOR"
    bl_region_type = "UI"
    #bl_context = "object"
    
    
    def draw(self, context):
        scn = context.scene
        layout = self.layout
        
        row = layout.row()
        row.label("classes")
        row.operator("collection.jump").add=False
        row.operator("collection.add_remove", text="Update").add=False
        
        row = layout.row()
        row.template_list(scn, "classCollection", scn, "classCollection_index")
        


class ClassMenu(bpy.types.Menu):
    bl_idname = "OBJECT_MT_select_class"
    bl_label = "Select"

    def draw(self, context):
        scn = context.scene
        layout = self.layout
        for x in context.scene.classCollection:
            layout.operator("collection.jump",text=x.name).line = x.myint

def GotoClasses(self, context): 
    self.layout.menu("OBJECT_MT_select_class", text="Classes", icon='PLUGIN') 

            

classes = [OBJECT_PT_defViewer, 
            OBJECT_PT_ClassViewer,
            OBJECT_OT_add_remove_Collection_Items,
            ClassMenu,
            OBJECT_OT_Jumptoline]
def register():
    for c in classes:
        bpy.utils.register_class(c)
    bpy.types.TEXT_MT_toolbox.append(GotoClasses) 


def unregister():
    for c in classes:
        bpy.utils.unregister_class(c)
    bpy.types.TEXT_MT_toolbox.append(GotoClasses)
if __name__ == "__main__":
    register()

Thats very cool.

Ricky ive found your problem. There is a “special” character at line 2985 that Blender doesnt like. Remove all those characters and will work fine.


Ive also made some updates to the script with some of your suggestions. Hope you like them.

Cheers.

Aw shucks thanks for the tag… could read 99% Mac, 1%bat

While i was playing around with it i was trying

layout.operator(“text.jump”).line=line rather than collection.jump

If you use it in the Menu class you get a nice goto line popup. If you add it here



def AddMenuItems(self, context):
    self.layout.menu("OBJECT_MT_select_class", text="Classes", icon='PLUGIN')
    self.layout.menu("OBJECT_MT_select_defs", text="Defs", icon='PLUGIN')
    self.layout.operator("text.jump",text="goto")  # go to the line the user selects

No menu, with or without .line=line. there must be a subclass or something to give it that behaviour… be a handy little extra.

Well, the advantage is that text.jump its already there and we dont need collection.jump for displaying menus. Thats ok.

Ive noticed that if we use menus we dont need to write Class or Defs collections, templates lists does need them and i didnt want to remove those panels because large scripts with many functions can make the menu go off the screen and you are not able to select all the items.

A little problem I noticed with the latest version: context.area (line 50) doesn’t always exist. For instance if you enable the script in your default starting .blend, context.area returns None on startup. So context.area.active_space fails and after that the entire script falls apart.
There are also other cases when context.area doesn’t exist (switching fullscreen mode for example), so a general check would be nice. Something simple like this works fine:

    scn = context.scene
    if not context.area:
        return
    space = context.area.active_space

Thanks again for the add-on and your active work on it.

I noticed that, ive updated the polls functions in all classes, and some if statements to correct that.
It still may content some bugs, please tell me if it doesnt work.

Nice AddOn.

The only thing that confused me was when I ran the code and then switched to another text document it was still showing me the definitions and classes for the previous text document. It would be nice if the script could detect when you have switched text documents and do an automatic update for you.

Thanks Atom, panels at the toolbar doesnt update until you press the update button, but right click menu inside your text does. If it doesnt try to download the script again there have been many changes and corrected some errors.

Ive just added a little update. When the addon finds non valid characters it will still work.

Updated for 2.58, i had to remove a lot of functions and the toolbox panels. Right click still works

Cya.