Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'release/scripts/bpymodules/BPyTextPlugin.py')
-rw-r--r--release/scripts/bpymodules/BPyTextPlugin.py814
1 files changed, 0 insertions, 814 deletions
diff --git a/release/scripts/bpymodules/BPyTextPlugin.py b/release/scripts/bpymodules/BPyTextPlugin.py
deleted file mode 100644
index cd5a085de37..00000000000
--- a/release/scripts/bpymodules/BPyTextPlugin.py
+++ /dev/null
@@ -1,814 +0,0 @@
-"""The BPyTextPlugin Module
-
-Use get_cached_descriptor(txt) to retrieve information about the script held in
-the txt Text object.
-
-Use print_cache_for(txt) to print the information to the console.
-
-Use line, cursor = current_line(txt) to get the logical line and cursor position
-
-Use get_targets(line, cursor) to find out what precedes the cursor:
- aaa.bbb.cc|c.ddd -> ['aaa', 'bbb', 'cc']
-
-Use resolve_targets(txt, targets) to turn a target list into a usable object if
-one is found to match.
-"""
-
-import bpy, sys, os
-import __builtin__, tokenize
-from Blender.sys import time
-from tokenize import generate_tokens, TokenError, \
- COMMENT, DEDENT, INDENT, NAME, NEWLINE, NL, STRING, NUMBER
-
-class Definition:
- """Describes a definition or defined object through its name, line number
- and docstring. This is the base class for definition based descriptors.
- """
-
- def __init__(self, name, lineno, doc=''):
- self.name = name
- self.lineno = lineno
- self.doc = doc
-
-class ScriptDesc:
- """Describes a script through lists of further descriptor objects (classes,
- defs, vars) and dictionaries to built-in types (imports). If a script has
- not been fully parsed, its incomplete flag will be set. The time of the last
- parse is held by the time field and the name of the text object from which
- it was parsed, the name field.
- """
-
- def __init__(self, name, imports, classes, defs, vars, incomplete=False):
- self.name = name
- self.imports = imports
- self.classes = classes
- self.defs = defs
- self.vars = vars
- self.incomplete = incomplete
- self.parse_due = 0
-
- def set_delay(self, delay):
- self.parse_due = time() + delay
-
-class ClassDesc(Definition):
- """Describes a class through lists of further descriptor objects (defs and
- vars). The name of the class is held by the name field and the line on
- which it is defined is held in lineno.
- """
-
- def __init__(self, name, parents, defs, vars, lineno, doc=''):
- Definition.__init__(self, name, lineno, doc)
- self.parents = parents
- self.defs = defs
- self.vars = vars
-
-class FunctionDesc(Definition):
- """Describes a function through its name and list of parameters (name,
- params) and the line on which it is defined (lineno).
- """
-
- def __init__(self, name, params, lineno, doc=''):
- Definition.__init__(self, name, lineno, doc)
- self.params = params
-
-class VarDesc(Definition):
- """Describes a variable through its name and type (if ascertainable) and the
- line on which it is defined (lineno). If no type can be determined, type
- will equal None.
- """
-
- def __init__(self, name, type, lineno):
- Definition.__init__(self, name, lineno)
- self.type = type # None for unknown (supports: dict/list/str)
-
-# Context types
-CTX_UNSET = -1
-CTX_NORMAL = 0
-CTX_SINGLE_QUOTE = 1
-CTX_DOUBLE_QUOTE = 2
-CTX_COMMENT = 3
-
-# Python keywords
-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' ]
-
-# Module file extensions
-MODULE_EXTS = ['.py', '.pyc', '.pyo', '.pyw', '.pyd']
-
-ModuleType = type(__builtin__)
-NoneScriptDesc = ScriptDesc('', dict(), dict(), dict(), dict(), True)
-
-_modules = {}
-_modules_updated = 0
-_parse_cache = dict()
-
-def _load_module_names():
- """Searches the sys.path for module files and lists them, along with
- sys.builtin_module_names, in the global dict _modules.
- """
-
- global _modules
-
- for n in sys.builtin_module_names:
- _modules[n] = None
- for p in sys.path:
- if p == '': p = os.curdir
- if not os.path.isdir(p): continue
- for f in os.listdir(p):
- for ext in MODULE_EXTS:
- if f.endswith(ext):
- _modules[f[:-len(ext)]] = None
- break
-
-_load_module_names()
-
-def _trim_doc(doc):
- """Trims the quotes from a quoted STRING token (eg. "'''text'''" -> "text")
- """
-
- l = len(doc)
- i = 0
- while i < l/2 and (doc[i] == "'" or doc[i] == '"'):
- i += 1
- return doc[i:-i]
-
-def resolve_targets(txt, targets):
- """Attempts to return a useful object for the locally or externally defined
- entity described by targets. If the object is local (defined in txt), a
- Definition instance is returned. If the object is external (imported or
- built in), the object itself is returned. If no object can be found, None is
- returned.
- """
-
- count = len(targets)
- if count==0: return None
-
- obj = None
- local = None
- i = 1
-
- desc = get_cached_descriptor(txt)
- b = targets[0].find('(')
- if b==-1: b = None # Trick to let us use [:b] and get the whole string
-
- if desc.classes.has_key(targets[0][:b]):
- local = desc.classes[targets[0][:b]]
- elif desc.defs.has_key(targets[0]):
- local = desc.defs[targets[0]]
- elif desc.vars.has_key(targets[0]):
- obj = desc.vars[targets[0]].type
-
- if local:
- while i < count:
- b = targets[i].find('(')
- if b==-1: b = None
- if hasattr(local, 'classes') and local.classes.has_key(targets[i][:b]):
- local = local.classes[targets[i][:b]]
- elif hasattr(local, 'defs') and local.defs.has_key(targets[i]):
- local = local.defs[targets[i]]
- elif hasattr(local, 'vars') and local.vars.has_key(targets[i]):
- obj = local.vars[targets[i]].type
- local = None
- i += 1
- break
- else:
- local = None
- break
- i += 1
-
- if local: return local
-
- if not obj:
- if desc.imports.has_key(targets[0]):
- obj = desc.imports[targets[0]]
- else:
- builtins = get_builtins()
- if builtins.has_key(targets[0]):
- obj = builtins[targets[0]]
-
- while obj and i < count:
- if hasattr(obj, targets[i]):
- obj = getattr(obj, targets[i])
- else:
- obj = None
- break
- i += 1
-
- return obj
-
-def get_cached_descriptor(txt, force_parse=0):
- """Returns the cached ScriptDesc for the specified Text object 'txt'. If the
- script has not been parsed in the last 'period' seconds it will be reparsed
- to obtain this descriptor.
-
- Specifying TP_AUTO for the period (default) will choose a period based on the
- size of the Text object. Larger texts are parsed less often.
- """
-
- global _parse_cache
-
- parse = True
- key = hash(txt)
- if not force_parse and _parse_cache.has_key(key):
- desc = _parse_cache[key]
- if desc.parse_due > time():
- parse = desc.incomplete
-
- if parse:
- desc = parse_text(txt)
-
- return desc
-
-def parse_text(txt):
- """Parses an entire script's text and returns a ScriptDesc instance
- containing information about the script.
-
- If the text is not a valid Python script (for example if brackets are left
- open), parsing may fail to complete. However, if this occurs, no exception
- is thrown. Instead the returned ScriptDesc instance will have its incomplete
- flag set and information processed up to this point will still be accessible.
- """
-
- start_time = time()
- txt.reset()
- tokens = generate_tokens(txt.readline) # Throws TokenError
-
- curl, cursor = txt.getCursorPos()
- linen = curl + 1 # Token line numbers are one-based
-
- imports = dict()
- imp_step = 0
-
- classes = dict()
- cls_step = 0
-
- defs = dict()
- def_step = 0
-
- vars = dict()
- var1_step = 0
- var2_step = 0
- var3_step = 0
- var_accum = dict()
- var_forflag = False
-
- indent = 0
- prev_type = -1
- prev_text = ''
- incomplete = False
-
- while True:
- try:
- type, text, start, end, line = tokens.next()
- except StopIteration:
- break
- except (TokenError, IndentationError):
- incomplete = True
- break
-
- # Skip all comments and line joining characters
- if type == COMMENT or type == NL:
- continue
-
- #################
- ## Indentation ##
- #################
-
- if type == INDENT:
- indent += 1
- elif type == DEDENT:
- indent -= 1
-
- #########################
- ## Module importing... ##
- #########################
-
- imp_store = False
-
- # Default, look for 'from' or 'import' to start
- if imp_step == 0:
- if text == 'from':
- imp_tmp = []
- imp_step = 1
- elif text == 'import':
- imp_from = None
- imp_tmp = []
- imp_step = 2
-
- # Found a 'from', create imp_from in form '???.???...'
- elif imp_step == 1:
- if text == 'import':
- imp_from = '.'.join(imp_tmp)
- imp_tmp = []
- imp_step = 2
- elif type == NAME:
- imp_tmp.append(text)
- elif text != '.':
- imp_step = 0 # Invalid syntax
-
- # Found 'import', imp_from is populated or None, create imp_name
- elif imp_step == 2:
- if text == 'as':
- imp_name = '.'.join(imp_tmp)
- imp_step = 3
- elif type == NAME or text == '*':
- imp_tmp.append(text)
- elif text != '.':
- imp_name = '.'.join(imp_tmp)
- imp_symb = imp_name
- imp_store = True
-
- # Found 'as', change imp_symb to this value and go back to step 2
- elif imp_step == 3:
- if type == NAME:
- imp_symb = text
- else:
- imp_store = True
-
- # Both imp_name and imp_symb have now been populated so we can import
- if imp_store:
-
- # Handle special case of 'import *'
- if imp_name == '*':
- parent = get_module(imp_from)
- imports.update(parent.__dict__)
-
- else:
- # Try importing the name as a module
- try:
- if imp_from:
- module = get_module(imp_from +'.'+ imp_name)
- else:
- module = get_module(imp_name)
- except (ImportError, ValueError, AttributeError, TypeError):
- # Try importing name as an attribute of the parent
- try:
- module = __import__(imp_from, globals(), locals(), [imp_name])
- imports[imp_symb] = getattr(module, imp_name)
- except (ImportError, ValueError, AttributeError, TypeError):
- pass
- else:
- imports[imp_symb] = module
-
- # More to import from the same module?
- if text == ',':
- imp_tmp = []
- imp_step = 2
- else:
- imp_step = 0
-
- ###################
- ## Class parsing ##
- ###################
-
- # If we are inside a class then def and variable parsing should be done
- # for the class. Otherwise the definitions are considered global
-
- # Look for 'class'
- if cls_step == 0:
- if text == 'class':
- cls_name = None
- cls_lineno = start[0]
- cls_indent = indent
- cls_step = 1
-
- # Found 'class', look for cls_name followed by '(' parents ')'
- elif cls_step == 1:
- if not cls_name:
- if type == NAME:
- cls_name = text
- cls_sline = False
- cls_parents = dict()
- cls_defs = dict()
- cls_vars = dict()
- elif type == NAME:
- if classes.has_key(text):
- parent = classes[text]
- cls_parents[text] = parent
- cls_defs.update(parent.defs)
- cls_vars.update(parent.vars)
- elif text == ':':
- cls_step = 2
-
- # Found 'class' name ... ':', now check if it's a single line statement
- elif cls_step == 2:
- if type == NEWLINE:
- cls_sline = False
- else:
- cls_sline = True
- cls_doc = ''
- cls_step = 3
-
- elif cls_step == 3:
- if not cls_doc and type == STRING:
- cls_doc = _trim_doc(text)
- if cls_sline:
- if type == NEWLINE:
- classes[cls_name] = ClassDesc(cls_name, cls_parents, cls_defs, cls_vars, cls_lineno, cls_doc)
- cls_step = 0
- else:
- if type == DEDENT and indent <= cls_indent:
- classes[cls_name] = ClassDesc(cls_name, cls_parents, cls_defs, cls_vars, cls_lineno, cls_doc)
- cls_step = 0
-
- #################
- ## Def parsing ##
- #################
-
- # Look for 'def'
- if def_step == 0:
- if text == 'def':
- def_name = None
- def_lineno = start[0]
- def_step = 1
-
- # Found 'def', look for def_name followed by '('
- elif def_step == 1:
- if type == NAME:
- def_name = text
- def_params = []
- elif def_name and text == '(':
- def_step = 2
-
- # Found 'def' name '(', now identify the parameters upto ')'
- # TODO: Handle ellipsis '...'
- elif def_step == 2:
- if type == NAME:
- def_params.append(text)
- elif text == ':':
- def_step = 3
-
- # Found 'def' ... ':', now check if it's a single line statement
- elif def_step == 3:
- if type == NEWLINE:
- def_sline = False
- else:
- def_sline = True
- def_doc = ''
- def_step = 4
-
- elif def_step == 4:
- if type == STRING:
- def_doc = _trim_doc(text)
- newdef = None
- if def_sline:
- if type == NEWLINE:
- newdef = FunctionDesc(def_name, def_params, def_lineno, def_doc)
- else:
- if type == NAME:
- newdef = FunctionDesc(def_name, def_params, def_lineno, def_doc)
- if newdef:
- if cls_step > 0: # Parsing a class
- cls_defs[def_name] = newdef
- else:
- defs[def_name] = newdef
- def_step = 0
-
- ##########################
- ## Variable assignation ##
- ##########################
-
- if cls_step > 0: # Parsing a class
- # Look for 'self.???'
- if var1_step == 0:
- if text == 'self':
- var1_step = 1
- elif var1_step == 1:
- if text == '.':
- var_name = None
- var1_step = 2
- else:
- var1_step = 0
- elif var1_step == 2:
- if type == NAME:
- var_name = text
- if cls_vars.has_key(var_name):
- var_step = 0
- else:
- var1_step = 3
- elif var1_step == 3:
- if text == '=':
- var1_step = 4
- elif text != ',':
- var1_step = 0
- elif var1_step == 4:
- var_type = None
- if type == NUMBER:
- close = end[1]
- if text.find('.') != -1: var_type = float
- else: var_type = int
- elif type == STRING:
- close = end[1]
- var_type = str
- elif text == '[':
- close = line.find(']', end[1])
- var_type = list
- elif text == '(':
- close = line.find(')', end[1])
- var_type = tuple
- elif text == '{':
- close = line.find('}', end[1])
- var_type = dict
- elif text == 'dict':
- close = line.find(')', end[1])
- var_type = dict
- if var_type and close+1 < len(line):
- if line[close+1] != ' ' and line[close+1] != '\t':
- var_type = None
- cls_vars[var_name] = VarDesc(var_name, var_type, start[0])
- var1_step = 0
-
- elif def_step > 0: # Parsing a def
- # Look for 'global ???[,???]'
- if var2_step == 0:
- if text == 'global':
- var2_step = 1
- elif var2_step == 1:
- if type == NAME:
- if not vars.has_key(text):
- vars[text] = VarDesc(text, None, start[0])
- elif text != ',' and type != NL:
- var2_step == 0
-
- else: # In global scope
- if var3_step == 0:
- # Look for names
- if text == 'for':
- var_accum = dict()
- var_forflag = True
- elif text == '=' or (var_forflag and text == 'in'):
- var_forflag = False
- var3_step = 1
- elif type == NAME:
- if prev_text != '.' and not vars.has_key(text):
- var_accum[text] = VarDesc(text, None, start[0])
- elif not text in [',', '(', ')', '[', ']']:
- var_accum = dict()
- var_forflag = False
- elif var3_step == 1:
- if len(var_accum) != 1:
- var_type = None
- vars.update(var_accum)
- else:
- var_name = var_accum.keys()[0]
- var_type = None
- if type == NUMBER:
- if text.find('.') != -1: var_type = float
- else: var_type = int
- elif type == STRING: var_type = str
- elif text == '[': var_type = list
- elif text == '(': var_type = tuple
- elif text == '{': var_type = dict
- vars[var_name] = VarDesc(var_name, var_type, start[0])
- var3_step = 0
-
- #######################
- ## General utilities ##
- #######################
-
- prev_type = type
- prev_text = text
-
- desc = ScriptDesc(txt.name, imports, classes, defs, vars, incomplete)
- desc.set_delay(10 * (time()-start_time) + 0.05)
-
- global _parse_cache
- _parse_cache[hash(txt)] = desc
- return desc
-
-def get_modules(since=1):
- """Returns the set of built-in modules and any modules that have been
- imported into the system upto 'since' seconds ago.
- """
-
- global _modules, _modules_updated
-
- t = time()
- if _modules_updated < t - since:
- _modules.update(sys.modules)
- _modules_updated = t
- return _modules.keys()
-
-def suggest_cmp(x, y):
- """Use this method when sorting a list of suggestions.
- """
-
- return cmp(x[0].upper(), y[0].upper())
-
-def get_module(name):
- """Returns the module specified by its name. The module itself is imported
- by this method and, as such, any initialization code will be executed.
- """
-
- mod = __import__(name)
- components = name.split('.')
- for comp in components[1:]:
- mod = getattr(mod, comp)
- return mod
-
-def type_char(v):
- """Returns the character used to signify the type of a variable. Use this
- method to identify the type character for an item in a suggestion list.
-
- The following values are returned:
- 'm' if the parameter is a module
- 'f' if the parameter is callable
- 'v' if the parameter is variable or otherwise indeterminable
-
- """
-
- if isinstance(v, ModuleType):
- return 'm'
- elif callable(v):
- return 'f'
- else:
- return 'v'
-
-def get_context(txt):
- """Establishes the context of the cursor in the given Blender Text object
-
- Returns one of:
- CTX_NORMAL - Cursor is in a normal context
- CTX_SINGLE_QUOTE - Cursor is inside a single quoted string
- CTX_DOUBLE_QUOTE - Cursor is inside a double quoted string
- CTX_COMMENT - Cursor is inside a comment
-
- """
-
- l, cursor = txt.getCursorPos()
- lines = txt.asLines(0, l+1)
-
- # FIXME: This method is too slow in large files for it to be called as often
- # as it is. So for lines below the 1000th line we do this... (quorn)
- if l > 1000: return CTX_NORMAL
-
- # Detect context (in string or comment)
- in_str = CTX_NORMAL
- for line in lines:
- if l == 0:
- end = cursor
- else:
- end = len(line)
- l -= 1
-
- # Comments end at new lines
- if in_str == CTX_COMMENT:
- in_str = CTX_NORMAL
-
- for i in range(end):
- if in_str == 0:
- if line[i] == "'": in_str = CTX_SINGLE_QUOTE
- elif line[i] == '"': in_str = CTX_DOUBLE_QUOTE
- elif line[i] == '#': in_str = CTX_COMMENT
- else:
- if in_str == CTX_SINGLE_QUOTE:
- if line[i] == "'":
- in_str = CTX_NORMAL
- # In again if ' escaped, out again if \ escaped, and so on
- for a in range(i-1, -1, -1):
- if line[a] == '\\': in_str = 1-in_str
- else: break
- elif in_str == CTX_DOUBLE_QUOTE:
- if line[i] == '"':
- in_str = CTX_NORMAL
- # In again if " escaped, out again if \ escaped, and so on
- for a in range(i-1, -1, -1):
- if line[i-a] == '\\': in_str = 2-in_str
- else: break
-
- return in_str
-
-def current_line(txt):
- """Extracts the Python script line at the cursor in the Blender Text object
- provided and cursor position within this line as the tuple pair (line,
- cursor).
- """
-
- lineindex, cursor = txt.getCursorPos()
- lines = txt.asLines()
- line = lines[lineindex]
-
- # Join previous lines to this line if spanning
- i = lineindex - 1
- while i > 0:
- earlier = lines[i].rstrip()
- if earlier.endswith('\\'):
- line = earlier[:-1] + ' ' + line
- cursor += len(earlier)
- i -= 1
-
- # Join later lines while there is an explicit joining character
- i = lineindex
- while i < len(lines)-1 and lines[i].rstrip().endswith('\\'):
- later = lines[i+1].strip()
- line = line + ' ' + later[:-1]
- i += 1
-
- return line, cursor
-
-def get_targets(line, cursor):
- """Parses a period separated string of valid names preceding the cursor and
- returns them as a list in the same order.
- """
-
- brk = 0
- targets = []
- j = cursor
- i = j-1
- while i >= 0:
- if line[i] == ')': brk += 1
- elif brk:
- if line[i] == '(': brk -= 1
- else:
- if line[i] == '.':
- targets.insert(0, line[i+1:j]); j=i
- elif not (line[i].isalnum() or line[i] == '_' or line[i] == '.'):
- break
- i -= 1
- targets.insert(0, line[i+1:j])
- return targets
-
-def get_defs(txt):
- """Returns a dictionary which maps definition names in the source code to
- a list of their parameter names.
-
- The line 'def doit(one, two, three): print one' for example, results in the
- mapping 'doit' : [ 'one', 'two', 'three' ]
- """
-
- return get_cached_descriptor(txt).defs
-
-def get_vars(txt):
- """Returns a dictionary of variable names found in the specified Text
- object. This method locates all names followed directly by an equal sign:
- 'a = ???' or indirectly as part of a tuple/list assignment or inside a
- 'for ??? in ???:' block.
- """
-
- return get_cached_descriptor(txt).vars
-
-def get_imports(txt):
- """Returns a dictionary which maps symbol names in the source code to their
- respective modules.
-
- The line 'from Blender import Text as BText' for example, results in the
- mapping 'BText' : <module 'Blender.Text' (built-in)>
-
- Note that this method imports the modules to provide this mapping as as such
- will execute any initilization code found within.
- """
-
- return get_cached_descriptor(txt).imports
-
-def get_builtins():
- """Returns a dictionary of built-in modules, functions and variables."""
-
- return __builtin__.__dict__
-
-
-#################################
-## Debugging utility functions ##
-#################################
-
-def print_cache_for(txt, period=sys.maxint):
- """Prints out the data cached for a given Text object. If no period is
- given the text will not be reparsed and the cached version will be returned.
- Otherwise if the period has expired the text will be reparsed.
- """
-
- desc = get_cached_descriptor(txt, period)
- print '================================================'
- print 'Name:', desc.name, '('+str(hash(txt))+')'
- print '------------------------------------------------'
- print 'Defs:'
- for name, ddesc in desc.defs.items():
- print ' ', name, ddesc.params, ddesc.lineno
- print ' ', ddesc.doc
- print '------------------------------------------------'
- print 'Vars:'
- for name, vdesc in desc.vars.items():
- print ' ', name, vdesc.type, vdesc.lineno
- print '------------------------------------------------'
- print 'Imports:'
- for name, item in desc.imports.items():
- print ' ', name.ljust(15), item
- print '------------------------------------------------'
- print 'Classes:'
- for clsnme, clsdsc in desc.classes.items():
- print ' *********************************'
- print ' Name:', clsnme
- print ' ', clsdsc.doc
- print ' ---------------------------------'
- print ' Defs:'
- for name, ddesc in clsdsc.defs.items():
- print ' ', name, ddesc.params, ddesc.lineno
- print ' ', ddesc.doc
- print ' ---------------------------------'
- print ' Vars:'
- for name, vdesc in clsdsc.vars.items():
- print ' ', name, vdesc.type, vdesc.lineno
- print ' *********************************'
- print '================================================'