[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [15343] branches/soc-2008-quorn: Text plugin basis with plugin for suggestions/completions.
Ian Thompson
quornian at googlemail.com
Tue Jun 24 17:25:32 CEST 2008
Revision: 15343
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=15343
Author: quorn
Date: 2008-06-24 17:25:25 +0200 (Tue, 24 Jun 2008)
Log Message:
-----------
Text plugin basis with plugin for suggestions/completions. The suggest plugin works for imported global variables, methods, modules and module members. For example typing:
import Blender
from Blender import *
| <- cursor here suggests globals
Blender.Draw.gl| <- cursor here suggests all Draw members starting gl
Currently suggestions are listed in the console when the space is redrawn but will be presented as a menu-style list soon. Also to add are shortcut/activation keys to allow plugins to respond to certain key strokes.
Modified Paths:
--------------
branches/soc-2008-quorn/source/blender/python/BPY_interface.c
branches/soc-2008-quorn/source/blender/python/BPY_menus.c
branches/soc-2008-quorn/source/blender/python/BPY_menus.h
branches/soc-2008-quorn/source/blender/python/api2_2x/Text.c
branches/soc-2008-quorn/source/blender/python/api2_2x/doc/Text.py
branches/soc-2008-quorn/source/blender/src/drawtext.c
branches/soc-2008-quorn/source/blender/src/header_text.c
branches/soc-2008-quorn/source/blender/src/usiblender.c
Added Paths:
-----------
branches/soc-2008-quorn/release/scripts/textplugin_suggest.py
branches/soc-2008-quorn/source/blender/blenkernel/BKE_suggestions.h
branches/soc-2008-quorn/source/blender/blenkernel/intern/suggestions.c
Added: branches/soc-2008-quorn/release/scripts/textplugin_suggest.py
===================================================================
--- branches/soc-2008-quorn/release/scripts/textplugin_suggest.py (rev 0)
+++ branches/soc-2008-quorn/release/scripts/textplugin_suggest.py 2008-06-24 15:25:25 UTC (rev 15343)
@@ -0,0 +1,234 @@
+#!BPY
+"""
+Name: 'Suggest'
+Blender: 243
+Group: 'TextPlugin'
+Tooltip: 'Suggests completions for the word at the cursor in a python script'
+"""
+
+import bpy
+from Blender import Text
+from StringIO import StringIO
+from inspect import *
+from tokenize import generate_tokens
+import token
+
+TK_TYPE = 0
+TK_TOKEN = 1
+TK_START = 2 #(srow, scol)
+TK_END = 3 #(erow, ecol)
+TK_LINE = 4
+TK_ROW = 0
+TK_COL = 1
+
+keywords = ['and', 'del', 'from', 'not', 'while', 'as', 'elif', 'global',
+ 'or', 'with', 'assert', 'else', 'if', 'pass', 'yield',
+ 'break', 'except', 'import', 'print', 'class', 'exec', 'in',
+ 'raise', 'continue', 'finally', 'is', 'return', 'def', 'for',
+ 'lambda', 'try' ]
+
+execs = [] # Used to establish the same import context across defs (import is scope sensitive)
+
+def getTokens(txt):
+ global tokens_cached
+ if tokens_cached==None:
+ lines = txt.asLines()
+ str = '\n'.join(lines)
+ readline = StringIO(str).readline
+ g = generate_tokens(readline)
+ tokens = []
+ for t in g: tokens.append(t)
+ tokens_cached = tokens
+ return tokens_cached
+tokens_cached = None
+
+def isNameChar(s):
+ return s.isalnum() or s in ['_']
+
+# Returns words preceding the cursor that are separated by periods as a list in the
+# same order
+def getCompletionSymbols(txt):
+ (l, c)= txt.getCursorPos()
+ lines = txt.asLines()
+ line = lines[l]
+ a=0
+ for a in range(1, c+1):
+ if not isNameChar(line[c-a]) and line[c-a]!='.':
+ a -= 1
+ break
+ return line[c-a:c].split('.')
+
+
+# Returns a list of tuples of symbol names and their types (name, type) where
+# type is one of:
+# m (module/class) Has its own members (includes classes)
+# v (variable) Has a type which may have its own members
+# f (function) Callable and may have a return type (with its own members)
+# It also updates the global import context (via execs)
+def getGlobals(txt):
+ global execs
+
+ tokens = getTokens(txt)
+ globals = dict()
+ for i in range(len(tokens)):
+
+ # Handle all import statements
+ if i>=1 and tokens[i-1][TK_TOKEN]=='import':
+
+ # Find 'from' if it exists
+ fr= -1
+ for a in range(1, i):
+ if tokens[i-a][TK_TYPE]==token.NEWLINE: break
+ if tokens[i-a][TK_TOKEN]=='from':
+ fr=i-a
+ break
+
+ # Handle: import ___[,___]
+ if fr<0:
+
+ while True:
+ if tokens[i][TK_TYPE]==token.NAME:
+ # Add the import to the execs list
+ x = tokens[i][TK_LINE].strip()
+ k = tokens[i][TK_TOKEN]
+ execs.append(x)
+
+ # Add the symbol name to the return list
+ globals[k] = 'm'
+ elif tokens[i][TK_TOKEN]!=',':
+ break
+ i += 1
+
+ # Handle statement: from ___[.___] import ___[,___]
+ else: # fr>=0:
+
+ # Add the import to the execs list
+ x = tokens[i][TK_LINE].strip()
+ execs.append(x)
+
+ # Import parent module so we can process it for sub modules
+ parent = ''.join([t[TK_TOKEN] for t in tokens[fr+1:i-1]])
+ exec "import "+parent
+
+ # All submodules, functions, etc.
+ if tokens[i][TK_TOKEN]=='*':
+
+ # Add each symbol name to the return list
+ exec "d="+parent+".__dict__.items()"
+ for k,v in d:
+ if not globals.has_key(k) or not globals[k]:
+ t='v'
+ if ismodule(v): t='m'
+ elif callable(v): t='f'
+ globals[k] = t
+
+ # Specific function, submodule, etc.
+ else:
+ while True:
+ if tokens[i][TK_TYPE]==token.NAME:
+ k = tokens[i][TK_TOKEN]
+ if not globals.has_key(k) or not globals[k]:
+ t='v'
+ try:
+ exec 'v='+parent+'.'+k
+ if ismodule(v): t='m'
+ elif callable(v): t='f'
+ except: pass
+ globals[k] = t
+ elif tokens[i][TK_TOKEN]!=',':
+ break
+ i += 1
+
+ elif tokens[i][TK_TYPE]==token.NAME and tokens[i][TK_TOKEN] not in keywords and (i==0 or tokens[i-1][TK_TOKEN]!='.'):
+ k = tokens[i][TK_TOKEN]
+ if not globals.has_key(k) or not globals[k]:
+ t=None
+ if (i>0 and tokens[i-1][TK_TOKEN]=='def'):
+ t='f'
+ else:
+ t='v'
+ globals[k] = t
+
+ return globals
+
+def cmpi0(x, y):
+ return cmp(x[0].lower(), y[0].lower())
+
+def globalSuggest(txt, cs):
+ global execs
+
+ suggestions = dict()
+ (row, col) = txt.getCursorPos()
+ globals = getGlobals(txt)
+
+ # Sometimes we have conditional includes which will fail if the module
+ # cannot be found. So we protect outselves in a try block
+ for x in execs:
+ exec 'try: '+x+'\nexcept: pass'
+
+ if len(cs)==0:
+ sub = ''
+ else:
+ sub = cs[0].lower()
+ print 'Search:', sub
+
+ for k,t in globals.items():
+ if k.lower().startswith(sub):
+ suggestions[k] = t
+
+ l = list(suggestions.items())
+ return sorted (l, cmp=cmpi0)
+
+# Only works for 'static' members (eg. Text.Get)
+def memberSuggest(txt, cs):
+ global execs
+
+ # Populate the execs for imports
+ getGlobals(txt)
+
+ # Sometimes we have conditional includes which will fail if the module
+ # cannot be found. So we protect outselves in a try block
+ for x in execs:
+ exec 'try: '+x+'\nexcept: pass'
+
+ suggestions = dict()
+ (row, col) = txt.getCursorPos()
+
+ sub = cs[len(cs)-1].lower()
+ print 'Search:', sub
+
+ t=None
+ pre='.'.join(cs[:-1])
+ try:
+ exec "t="+pre
+ except:
+ print 'Failed to assign '+pre
+ print execs
+ print cs
+
+ if t!=None:
+ for k,v in t.__dict__.items():
+ if ismodule(v): t='m'
+ elif callable(v): t='f'
+ else: t='v'
+ if k.lower().startswith(sub):
+ suggestions[k] = t
+
+ l = list(suggestions.items())
+ return sorted (l, cmp=cmpi0)
+
+def main():
+ txt = bpy.data.texts.active
+ if txt==None: return
+
+ cs = getCompletionSymbols(txt)
+
+ if len(cs)<=1:
+ l = globalSuggest(txt, cs)
+ txt.suggest(l, cs[len(cs)-1])
+
+ else:
+ l = memberSuggest(txt, cs)
+ txt.suggest(l, cs[len(cs)-1])
+
+main()
Added: branches/soc-2008-quorn/source/blender/blenkernel/BKE_suggestions.h
===================================================================
--- branches/soc-2008-quorn/source/blender/blenkernel/BKE_suggestions.h (rev 0)
+++ branches/soc-2008-quorn/source/blender/blenkernel/BKE_suggestions.h 2008-06-24 15:25:25 UTC (rev 15343)
@@ -0,0 +1,77 @@
+/**
+ * $Id: $
+ *
+ * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2008, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef BKE_SUGGESTIONS_H
+#define BKE_SUGGESTIONS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ****************************************************************************
+Suggestions must be added in sorted order (no attempt is made to sort the list)
+The list is then divided up based on the prefix provided by update_suggestions:
+Example:
+ Prefix: ab
+ aaa <-- first
+ aab
+ aba <-- firstmatch
+ abb <-- lastmatch
+ baa
+ bab <-- last
+**************************************************************************** */
+
+struct Text;
+
+typedef struct SuggItem {
+ struct SuggItem *prev, *next;
+ char *name;
+ char type;
+} SuggItem;
+
+typedef struct SuggList {
+ SuggItem *first, *last;
+ SuggItem *firstmatch, *lastmatch;
+} SuggList;
+
+void free_suggestions();
+
+void add_suggestion(const char *name, char type);
+void update_suggestions(const char *prefix);
+SuggItem *suggest_first();
+SuggItem *suggest_last();
+
+void set_suggest_text(Text *text);
+void clear_suggest_text();
+short is_suggest_active(Text *text);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Added: branches/soc-2008-quorn/source/blender/blenkernel/intern/suggestions.c
===================================================================
--- branches/soc-2008-quorn/source/blender/blenkernel/intern/suggestions.c (rev 0)
+++ branches/soc-2008-quorn/source/blender/blenkernel/intern/suggestions.c 2008-06-24 15:25:25 UTC (rev 15343)
@@ -0,0 +1,125 @@
+/**
+ * $Id: $
+ *
+ * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2008, Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+#include "BLI_blenlib.h"
+#include "DNA_text_types.h"
+#include "BKE_text.h"
+#include "BKE_suggestions.h"
+
+static SuggList suggestions= {NULL, NULL, NULL, NULL};
+static Text *suggText = NULL;
+
+void free_suggestions() {
+ SuggItem *item;
+ for (item = suggestions.last; item; item=item->prev)
+ MEM_freeN(item);
+ suggestions.first = suggestions.last = NULL;
+ suggestions.firstmatch = suggestions.lastmatch = NULL;
+}
+
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list