diff options
author | Ian Thompson <quornian@googlemail.com> | 2008-06-25 17:51:54 +0400 |
---|---|---|
committer | Ian Thompson <quornian@googlemail.com> | 2008-06-25 17:51:54 +0400 |
commit | e68834c75bc3e69641a6332dab071ebaa2d9d1d3 (patch) | |
tree | 38deda31d860f518dde5d52ac58cd667061cf422 /release/scripts/textplugin_suggest.py | |
parent | bdc030c664640db727ea21a1e854bb62032bf705 (diff) |
Added UI for suggestions list. Works with arrow-keys and mouse wheel, accept with Enter, reject with Esc or click elsewhere. Mouse selection not yet supported. The script is called from the File->Text Plugins menu.
Tidied python script, the C suggestions functions and fixed some bugs including suggestions not being freed properly.
Diffstat (limited to 'release/scripts/textplugin_suggest.py')
-rw-r--r-- | release/scripts/textplugin_suggest.py | 128 |
1 files changed, 66 insertions, 62 deletions
diff --git a/release/scripts/textplugin_suggest.py b/release/scripts/textplugin_suggest.py index 77ae0488b1c..9861298209c 100644 --- a/release/scripts/textplugin_suggest.py +++ b/release/scripts/textplugin_suggest.py @@ -6,12 +6,11 @@ Group: 'TextPlugin' Tooltip: 'Suggests completions for the word at the cursor in a python script' """ -import bpy +import bpy, __builtin__, token from Blender import Text from StringIO import StringIO from inspect import * from tokenize import generate_tokens -import token TK_TYPE = 0 TK_TOKEN = 1 @@ -21,32 +20,48 @@ TK_LINE = 4 TK_ROW = 0 TK_COL = 1 +execs = [] # Used to establish the same import context across defs + 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 getBuiltins(): + builtins = [] + bi = dir(__builtin__) + for k in bi: + v = eval(k) + if ismodule(v): t='m' + elif callable(v): t='f' + else: t='v' + builtins.append((k, t)) + return builtins + + +def getKeywords(): + global keywords + return [(k, 'k') for k in keywords] + 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 + lines = txt.asLines() + str = '\n'.join(lines) + readline = StringIO(str).readline + g = generate_tokens(readline) + tokens = [] + for t in g: tokens.append(t) + return tokens + def isNameChar(s): - return s.isalnum() or s in ['_'] + return (s.isalnum() or s == '_') -# Returns words preceding the cursor that are separated by periods as a list in the -# same order + +# 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() @@ -68,7 +83,14 @@ def getCompletionSymbols(txt): def getGlobals(txt): global execs - tokens = getTokens(txt) + # Unfortunately, tokenize may fail if the script leaves brackets or strings + # open. For now we return an empty list, leaving builtins and keywords as + # the only globals. (on the TODO list) + try: + tokens = getTokens(txt) + except: + return [] + globals = dict() for i in range(len(tokens)): @@ -92,6 +114,7 @@ def getGlobals(txt): x = tokens[i][TK_LINE].strip() k = tokens[i][TK_TOKEN] execs.append(x) + exec 'try: '+x+'\nexcept: pass' # Add the symbol name to the return list globals[k] = 'm' @@ -105,16 +128,17 @@ def getGlobals(txt): # Add the import to the execs list x = tokens[i][TK_LINE].strip() execs.append(x) + exec 'try: '+x+'\nexcept: pass' # 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 + exec 'try: import '+parent+'\nexcept: pass' # All submodules, functions, etc. if tokens[i][TK_TOKEN]=='*': # Add each symbol name to the return list - exec "d="+parent+".__dict__.items()" + d = eval(parent).__dict__.items() for k,v in d: if not globals.has_key(k) or not globals[k]: t='v' @@ -130,7 +154,7 @@ def getGlobals(txt): if not globals.has_key(k) or not globals[k]: t='v' try: - exec 'v='+parent+'.'+k + v = eval(parent+'.'+k) if ismodule(v): t='m' elif callable(v): t='f' except: pass @@ -149,35 +173,13 @@ def getGlobals(txt): t='v' globals[k] = t - return globals + return globals.items() -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) + return globals + # Only works for 'static' members (eg. Text.Get) def memberSuggest(txt, cs): @@ -194,28 +196,28 @@ def memberSuggest(txt, cs): suggestions = dict() (row, col) = txt.getCursorPos() - sub = cs[len(cs)-1].lower() - print 'Search:', sub + sub = cs[len(cs)-1] - t=None + m=None pre='.'.join(cs[:-1]) try: - exec "t="+pre + m = eval(pre) except: - print 'Failed to assign '+pre - print execs - print cs + print pre+ ' not found or not imported.' - if t!=None: - for k,v in t.__dict__.items(): + if m!=None: + for k,v in m.__dict__.items(): if ismodule(v): t='m' elif callable(v): t='f' else: t='v' - if k.lower().startswith(sub): - suggestions[k] = t + suggestions[k] = t - l = list(suggestions.items()) - return sorted (l, cmp=cmpi0) + return suggestions.items() + + +def cmp0(x, y): + return cmp(x[0], y[0]) + def main(): txt = bpy.data.texts.active @@ -225,10 +227,12 @@ def main(): if len(cs)<=1: l = globalSuggest(txt, cs) - txt.suggest(l, cs[len(cs)-1]) - + l.extend(getBuiltins()) + l.extend(getKeywords()) else: l = memberSuggest(txt, cs) - txt.suggest(l, cs[len(cs)-1]) + + l.sort(cmp=cmp0) + txt.suggest(l, cs[len(cs)-1]) main() |