Added "scripts/modules" as permanent module search path.
- added bpy.sys as a python module - with bpy.sys.expandpath() - moved bpy.ops into scripts/modules - moved autocomplete into its own module from space_console.py
This commit is contained in:
211
release/scripts/modules/autocomplete.py
Normal file
211
release/scripts/modules/autocomplete.py
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
|
||||||
|
|
||||||
|
def execute(bcon):
|
||||||
|
'''
|
||||||
|
This function has been taken from a BGE console autocomp I wrote a while ago
|
||||||
|
the dictionaty bcon is not needed but it means I can copy and paste from the old func
|
||||||
|
which works ok for now.
|
||||||
|
|
||||||
|
'bcon' dictionary keys, set by the caller
|
||||||
|
* 'cursor' - index of the editing character (int)
|
||||||
|
* 'edit_text' - text string for editing (string)
|
||||||
|
* 'scrollback' - text to add to the scrollback, options are added here. (text)
|
||||||
|
* 'namespace' - namespace, (dictionary)
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
def is_delimiter(ch):
|
||||||
|
'''
|
||||||
|
For skipping words
|
||||||
|
'''
|
||||||
|
if ch == '_':
|
||||||
|
return False
|
||||||
|
if ch.isalnum():
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def is_delimiter_autocomp(ch):
|
||||||
|
'''
|
||||||
|
When autocompleteing will earch back and
|
||||||
|
'''
|
||||||
|
if ch in '._[] "\'':
|
||||||
|
return False
|
||||||
|
if ch.isalnum():
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def do_autocomp(autocomp_prefix, autocomp_members):
|
||||||
|
'''
|
||||||
|
return text to insert and a list of options
|
||||||
|
'''
|
||||||
|
autocomp_members = [v for v in autocomp_members if v.startswith(autocomp_prefix)]
|
||||||
|
|
||||||
|
print("AUTO: '%s'" % autocomp_prefix)
|
||||||
|
print("MEMBERS: '%s'" % str(autocomp_members))
|
||||||
|
|
||||||
|
if not autocomp_prefix:
|
||||||
|
return '', autocomp_members
|
||||||
|
elif len(autocomp_members) > 1:
|
||||||
|
# find a common string between all members after the prefix
|
||||||
|
# 'ge' [getA, getB, getC] --> 'get'
|
||||||
|
|
||||||
|
# get the shortest member
|
||||||
|
min_len = min([len(v) for v in autocomp_members])
|
||||||
|
|
||||||
|
autocomp_prefix_ret = ''
|
||||||
|
|
||||||
|
for i in range(len(autocomp_prefix), min_len):
|
||||||
|
char_soup = set()
|
||||||
|
for v in autocomp_members:
|
||||||
|
char_soup.add(v[i])
|
||||||
|
|
||||||
|
if len(char_soup) > 1:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
autocomp_prefix_ret += char_soup.pop()
|
||||||
|
|
||||||
|
return autocomp_prefix_ret, autocomp_members
|
||||||
|
elif len(autocomp_members) == 1:
|
||||||
|
if autocomp_prefix == autocomp_members[0]:
|
||||||
|
# the variable matched the prefix exactly
|
||||||
|
# add a '.' so you can quickly continue.
|
||||||
|
# Could try add [] or other possible extensions rather then '.' too if we had the variable.
|
||||||
|
return '.', []
|
||||||
|
else:
|
||||||
|
# finish off the of the word word
|
||||||
|
return autocomp_members[0][len(autocomp_prefix):], []
|
||||||
|
else:
|
||||||
|
return '', []
|
||||||
|
|
||||||
|
|
||||||
|
def BCon_PrevChar(bcon):
|
||||||
|
cursor = bcon['cursor']-1
|
||||||
|
if cursor<0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
return bcon['edit_text'][cursor]
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def BCon_NextChar(bcon):
|
||||||
|
try:
|
||||||
|
return bcon['edit_text'][bcon['cursor']]
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def BCon_cursorLeft(bcon):
|
||||||
|
bcon['cursor'] -= 1
|
||||||
|
if bcon['cursor'] < 0:
|
||||||
|
bcon['cursor'] = 0
|
||||||
|
|
||||||
|
def BCon_cursorRight(bcon):
|
||||||
|
bcon['cursor'] += 1
|
||||||
|
if bcon['cursor'] > len(bcon['edit_text']):
|
||||||
|
bcon['cursor'] = len(bcon['edit_text'])
|
||||||
|
|
||||||
|
def BCon_AddScrollback(bcon, text):
|
||||||
|
|
||||||
|
bcon['scrollback'] = bcon['scrollback'] + text
|
||||||
|
|
||||||
|
|
||||||
|
def BCon_cursorInsertChar(bcon, ch):
|
||||||
|
if bcon['cursor']==0:
|
||||||
|
bcon['edit_text'] = ch + bcon['edit_text']
|
||||||
|
elif bcon['cursor']==len(bcon['edit_text']):
|
||||||
|
bcon['edit_text'] = bcon['edit_text'] + ch
|
||||||
|
else:
|
||||||
|
bcon['edit_text'] = bcon['edit_text'][:bcon['cursor']] + ch + bcon['edit_text'][bcon['cursor']:]
|
||||||
|
|
||||||
|
bcon['cursor']
|
||||||
|
if bcon['cursor'] > len(bcon['edit_text']):
|
||||||
|
bcon['cursor'] = len(bcon['edit_text'])
|
||||||
|
BCon_cursorRight(bcon)
|
||||||
|
|
||||||
|
|
||||||
|
TEMP_NAME = '___tempname___'
|
||||||
|
|
||||||
|
cursor_orig = bcon['cursor']
|
||||||
|
|
||||||
|
ch = BCon_PrevChar(bcon)
|
||||||
|
while ch != None and (not is_delimiter(ch)):
|
||||||
|
ch = BCon_PrevChar(bcon)
|
||||||
|
BCon_cursorLeft(bcon)
|
||||||
|
|
||||||
|
if ch != None:
|
||||||
|
BCon_cursorRight(bcon)
|
||||||
|
|
||||||
|
#print (cursor_orig, bcon['cursor'])
|
||||||
|
|
||||||
|
cursor_base = bcon['cursor']
|
||||||
|
|
||||||
|
autocomp_prefix = bcon['edit_text'][cursor_base:cursor_orig]
|
||||||
|
|
||||||
|
print("PREFIX:'%s'" % autocomp_prefix)
|
||||||
|
|
||||||
|
# Get the previous word
|
||||||
|
if BCon_PrevChar(bcon)=='.':
|
||||||
|
BCon_cursorLeft(bcon)
|
||||||
|
ch = BCon_PrevChar(bcon)
|
||||||
|
while ch != None and is_delimiter_autocomp(ch)==False:
|
||||||
|
ch = BCon_PrevChar(bcon)
|
||||||
|
BCon_cursorLeft(bcon)
|
||||||
|
|
||||||
|
cursor_new = bcon['cursor']
|
||||||
|
|
||||||
|
if ch != None:
|
||||||
|
cursor_new+=1
|
||||||
|
|
||||||
|
pytxt = bcon['edit_text'][cursor_new:cursor_base-1].strip()
|
||||||
|
print("AUTOCOMP EVAL: '%s'" % pytxt)
|
||||||
|
#try:
|
||||||
|
if pytxt:
|
||||||
|
bcon['console'].runsource(TEMP_NAME + '=' + pytxt, '<input>', 'single')
|
||||||
|
# print val
|
||||||
|
else: ##except:
|
||||||
|
val = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
val = bcon['namespace'][TEMP_NAME]
|
||||||
|
del bcon['namespace'][TEMP_NAME]
|
||||||
|
except:
|
||||||
|
val = None
|
||||||
|
|
||||||
|
if val:
|
||||||
|
autocomp_members = dir(val)
|
||||||
|
|
||||||
|
autocomp_prefix_ret, autocomp_members = do_autocomp(autocomp_prefix, autocomp_members)
|
||||||
|
|
||||||
|
bcon['cursor'] = cursor_orig
|
||||||
|
for v in autocomp_prefix_ret:
|
||||||
|
BCon_cursorInsertChar(bcon, v)
|
||||||
|
cursor_orig = bcon['cursor']
|
||||||
|
|
||||||
|
if autocomp_members:
|
||||||
|
BCon_AddScrollback(bcon, ', '.join(autocomp_members))
|
||||||
|
|
||||||
|
del val
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Autocomp global namespace
|
||||||
|
autocomp_members = bcon['namespace'].keys()
|
||||||
|
|
||||||
|
if autocomp_prefix:
|
||||||
|
autocomp_members = [v for v in autocomp_members if v.startswith(autocomp_prefix)]
|
||||||
|
|
||||||
|
autocomp_prefix_ret, autocomp_members = do_autocomp(autocomp_prefix, autocomp_members)
|
||||||
|
|
||||||
|
bcon['cursor'] = cursor_orig
|
||||||
|
for v in autocomp_prefix_ret:
|
||||||
|
BCon_cursorInsertChar(bcon, v)
|
||||||
|
cursor_orig = bcon['cursor']
|
||||||
|
|
||||||
|
if autocomp_members:
|
||||||
|
BCon_AddScrollback(bcon, ', '.join(autocomp_members))
|
||||||
|
|
||||||
|
bcon['cursor'] = cursor_orig
|
||||||
12
release/scripts/modules/bpy_sys.py
Normal file
12
release/scripts/modules/bpy_sys.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import bpy
|
||||||
|
import os
|
||||||
|
|
||||||
|
def expandpath(path):
|
||||||
|
if path.startswith("//"):
|
||||||
|
return os.path.join(os.path.dirname(bpy.data.filename), path[2:])
|
||||||
|
|
||||||
|
return path
|
||||||
|
|
||||||
|
import types
|
||||||
|
bpy.sys = types.ModuleType("bpy.sys")
|
||||||
|
bpy.sys.expandpath = expandpath
|
||||||
@@ -1,9 +1,5 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
import bpy_ops # XXX - should not need to do this
|
|
||||||
del bpy_ops
|
|
||||||
|
|
||||||
class CONSOLE_HT_header(bpy.types.Header):
|
class CONSOLE_HT_header(bpy.types.Header):
|
||||||
__space_type__ = 'CONSOLE'
|
__space_type__ = 'CONSOLE'
|
||||||
|
|
||||||
@@ -184,212 +180,6 @@ class CONSOLE_OT_exec(bpy.types.Operator):
|
|||||||
return ('FINISHED',)
|
return ('FINISHED',)
|
||||||
|
|
||||||
|
|
||||||
def autocomp(bcon):
|
|
||||||
'''
|
|
||||||
This function has been taken from a BGE console autocomp I wrote a while ago
|
|
||||||
the dictionaty bcon is not needed but it means I can copy and paste from the old func
|
|
||||||
which works ok for now.
|
|
||||||
|
|
||||||
could be moved into its own module.
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
def is_delimiter(ch):
|
|
||||||
'''
|
|
||||||
For skipping words
|
|
||||||
'''
|
|
||||||
if ch == '_':
|
|
||||||
return False
|
|
||||||
if ch.isalnum():
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def is_delimiter_autocomp(ch):
|
|
||||||
'''
|
|
||||||
When autocompleteing will earch back and
|
|
||||||
'''
|
|
||||||
if ch in '._[] "\'':
|
|
||||||
return False
|
|
||||||
if ch.isalnum():
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def do_autocomp(autocomp_prefix, autocomp_members):
|
|
||||||
'''
|
|
||||||
return text to insert and a list of options
|
|
||||||
'''
|
|
||||||
autocomp_members = [v for v in autocomp_members if v.startswith(autocomp_prefix)]
|
|
||||||
|
|
||||||
print("AUTO: '%s'" % autocomp_prefix)
|
|
||||||
print("MEMBERS: '%s'" % str(autocomp_members))
|
|
||||||
|
|
||||||
if not autocomp_prefix:
|
|
||||||
return '', autocomp_members
|
|
||||||
elif len(autocomp_members) > 1:
|
|
||||||
# find a common string between all members after the prefix
|
|
||||||
# 'ge' [getA, getB, getC] --> 'get'
|
|
||||||
|
|
||||||
# get the shortest member
|
|
||||||
min_len = min([len(v) for v in autocomp_members])
|
|
||||||
|
|
||||||
autocomp_prefix_ret = ''
|
|
||||||
|
|
||||||
for i in range(len(autocomp_prefix), min_len):
|
|
||||||
char_soup = set()
|
|
||||||
for v in autocomp_members:
|
|
||||||
char_soup.add(v[i])
|
|
||||||
|
|
||||||
if len(char_soup) > 1:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
autocomp_prefix_ret += char_soup.pop()
|
|
||||||
|
|
||||||
return autocomp_prefix_ret, autocomp_members
|
|
||||||
elif len(autocomp_members) == 1:
|
|
||||||
if autocomp_prefix == autocomp_members[0]:
|
|
||||||
# the variable matched the prefix exactly
|
|
||||||
# add a '.' so you can quickly continue.
|
|
||||||
# Could try add [] or other possible extensions rather then '.' too if we had the variable.
|
|
||||||
return '.', []
|
|
||||||
else:
|
|
||||||
# finish off the of the word word
|
|
||||||
return autocomp_members[0][len(autocomp_prefix):], []
|
|
||||||
else:
|
|
||||||
return '', []
|
|
||||||
|
|
||||||
|
|
||||||
def BCon_PrevChar(bcon):
|
|
||||||
cursor = bcon['cursor']-1
|
|
||||||
if cursor<0:
|
|
||||||
return None
|
|
||||||
|
|
||||||
try:
|
|
||||||
return bcon['edit_text'][cursor]
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def BCon_NextChar(bcon):
|
|
||||||
try:
|
|
||||||
return bcon['edit_text'][bcon['cursor']]
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def BCon_cursorLeft(bcon):
|
|
||||||
bcon['cursor'] -= 1
|
|
||||||
if bcon['cursor'] < 0:
|
|
||||||
bcon['cursor'] = 0
|
|
||||||
|
|
||||||
def BCon_cursorRight(bcon):
|
|
||||||
bcon['cursor'] += 1
|
|
||||||
if bcon['cursor'] > len(bcon['edit_text']):
|
|
||||||
bcon['cursor'] = len(bcon['edit_text'])
|
|
||||||
|
|
||||||
def BCon_AddScrollback(bcon, text):
|
|
||||||
|
|
||||||
bcon['scrollback'] = bcon['scrollback'] + text
|
|
||||||
|
|
||||||
|
|
||||||
def BCon_cursorInsertChar(bcon, ch):
|
|
||||||
if bcon['cursor']==0:
|
|
||||||
bcon['edit_text'] = ch + bcon['edit_text']
|
|
||||||
elif bcon['cursor']==len(bcon['edit_text']):
|
|
||||||
bcon['edit_text'] = bcon['edit_text'] + ch
|
|
||||||
else:
|
|
||||||
bcon['edit_text'] = bcon['edit_text'][:bcon['cursor']] + ch + bcon['edit_text'][bcon['cursor']:]
|
|
||||||
|
|
||||||
bcon['cursor']
|
|
||||||
if bcon['cursor'] > len(bcon['edit_text']):
|
|
||||||
bcon['cursor'] = len(bcon['edit_text'])
|
|
||||||
BCon_cursorRight(bcon)
|
|
||||||
|
|
||||||
|
|
||||||
TEMP_NAME = '___tempname___'
|
|
||||||
|
|
||||||
cursor_orig = bcon['cursor']
|
|
||||||
|
|
||||||
ch = BCon_PrevChar(bcon)
|
|
||||||
while ch != None and (not is_delimiter(ch)):
|
|
||||||
ch = BCon_PrevChar(bcon)
|
|
||||||
BCon_cursorLeft(bcon)
|
|
||||||
|
|
||||||
if ch != None:
|
|
||||||
BCon_cursorRight(bcon)
|
|
||||||
|
|
||||||
#print (cursor_orig, bcon['cursor'])
|
|
||||||
|
|
||||||
cursor_base = bcon['cursor']
|
|
||||||
|
|
||||||
autocomp_prefix = bcon['edit_text'][cursor_base:cursor_orig]
|
|
||||||
|
|
||||||
print("PREFIX:'%s'" % autocomp_prefix)
|
|
||||||
|
|
||||||
# Get the previous word
|
|
||||||
if BCon_PrevChar(bcon)=='.':
|
|
||||||
BCon_cursorLeft(bcon)
|
|
||||||
ch = BCon_PrevChar(bcon)
|
|
||||||
while ch != None and is_delimiter_autocomp(ch)==False:
|
|
||||||
ch = BCon_PrevChar(bcon)
|
|
||||||
BCon_cursorLeft(bcon)
|
|
||||||
|
|
||||||
cursor_new = bcon['cursor']
|
|
||||||
|
|
||||||
if ch != None:
|
|
||||||
cursor_new+=1
|
|
||||||
|
|
||||||
pytxt = bcon['edit_text'][cursor_new:cursor_base-1].strip()
|
|
||||||
print("AUTOCOMP EVAL: '%s'" % pytxt)
|
|
||||||
#try:
|
|
||||||
if pytxt:
|
|
||||||
bcon['console'].runsource(TEMP_NAME + '=' + pytxt, '<input>', 'single')
|
|
||||||
# print val
|
|
||||||
else: ##except:
|
|
||||||
val = None
|
|
||||||
|
|
||||||
try:
|
|
||||||
val = bcon['namespace'][TEMP_NAME]
|
|
||||||
del bcon['namespace'][TEMP_NAME]
|
|
||||||
except:
|
|
||||||
val = None
|
|
||||||
|
|
||||||
if val:
|
|
||||||
autocomp_members = dir(val)
|
|
||||||
|
|
||||||
autocomp_prefix_ret, autocomp_members = do_autocomp(autocomp_prefix, autocomp_members)
|
|
||||||
|
|
||||||
bcon['cursor'] = cursor_orig
|
|
||||||
for v in autocomp_prefix_ret:
|
|
||||||
BCon_cursorInsertChar(bcon, v)
|
|
||||||
cursor_orig = bcon['cursor']
|
|
||||||
|
|
||||||
if autocomp_members:
|
|
||||||
BCon_AddScrollback(bcon, ', '.join(autocomp_members))
|
|
||||||
|
|
||||||
del val
|
|
||||||
|
|
||||||
else:
|
|
||||||
# Autocomp global namespace
|
|
||||||
autocomp_members = bcon['namespace'].keys()
|
|
||||||
|
|
||||||
if autocomp_prefix:
|
|
||||||
autocomp_members = [v for v in autocomp_members if v.startswith(autocomp_prefix)]
|
|
||||||
|
|
||||||
autocomp_prefix_ret, autocomp_members = do_autocomp(autocomp_prefix, autocomp_members)
|
|
||||||
|
|
||||||
bcon['cursor'] = cursor_orig
|
|
||||||
for v in autocomp_prefix_ret:
|
|
||||||
BCon_cursorInsertChar(bcon, v)
|
|
||||||
cursor_orig = bcon['cursor']
|
|
||||||
|
|
||||||
if autocomp_members:
|
|
||||||
BCon_AddScrollback(bcon, ', '.join(autocomp_members))
|
|
||||||
|
|
||||||
bcon['cursor'] = cursor_orig
|
|
||||||
|
|
||||||
|
|
||||||
class CONSOLE_OT_autocomplete(bpy.types.Operator):
|
class CONSOLE_OT_autocomplete(bpy.types.Operator):
|
||||||
'''Evaluate the namespace up until the cursor and give a list of options or complete the name if there is only one.'''
|
'''Evaluate the namespace up until the cursor and give a list of options or complete the name if there is only one.'''
|
||||||
__idname__ = "console.autocomplete"
|
__idname__ = "console.autocomplete"
|
||||||
@@ -425,7 +215,8 @@ class CONSOLE_OT_autocomplete(bpy.types.Operator):
|
|||||||
|
|
||||||
# This function isnt aware of the text editor or being an operator
|
# This function isnt aware of the text editor or being an operator
|
||||||
# just does the autocomp then copy its results back
|
# just does the autocomp then copy its results back
|
||||||
autocomp(bcon)
|
import autocomplete
|
||||||
|
autocomplete.execute(bcon)
|
||||||
|
|
||||||
# Now we need to copy back the line from blender back into the text editor.
|
# Now we need to copy back the line from blender back into the text editor.
|
||||||
# This will change when we dont use the text editor anymore
|
# This will change when we dont use the text editor anymore
|
||||||
|
|||||||
@@ -211,9 +211,6 @@ bpy.types.register(INFO_MT_help)
|
|||||||
|
|
||||||
# Help operators
|
# Help operators
|
||||||
|
|
||||||
import bpy_ops # XXX - should not need to do this
|
|
||||||
del bpy_ops
|
|
||||||
|
|
||||||
class HelpOperator(bpy.types.Operator):
|
class HelpOperator(bpy.types.Operator):
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
try: import webbrowser
|
try: import webbrowser
|
||||||
|
|||||||
@@ -176,7 +176,34 @@ static void bpy_init_modules( void )
|
|||||||
PyDict_SetItemString(PySys_GetObject("modules"), "bpy", mod);
|
PyDict_SetItemString(PySys_GetObject("modules"), "bpy", mod);
|
||||||
Py_DECREF(mod);
|
Py_DECREF(mod);
|
||||||
|
|
||||||
|
/* add our own modules dir */
|
||||||
|
{
|
||||||
|
char *modpath= BLI_gethome_folder("scripts/modules", BLI_GETHOME_ALL);
|
||||||
|
|
||||||
|
if(modpath) {
|
||||||
|
PyObject *sys_path= PySys_GetObject("path"); /* borrow */
|
||||||
|
PyObject *py_modpath= PyUnicode_FromString(modpath);
|
||||||
|
PyList_Insert(sys_path, 0, py_modpath); /* add first */
|
||||||
|
Py_DECREF(py_modpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
mod= PyImport_ImportModuleLevel("bpy_ops", NULL, NULL, NULL, 0); /* adds its self to bpy.ops */
|
||||||
|
if(mod) {
|
||||||
|
Py_DECREF(mod);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyErr_Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
mod= PyImport_ImportModuleLevel("bpy_sys", NULL, NULL, NULL, 0); /* adds its self to bpy.sys */
|
||||||
|
if(mod) {
|
||||||
|
Py_DECREF(mod);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyErr_Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* stand alone utility modules not related to blender directly */
|
/* stand alone utility modules not related to blender directly */
|
||||||
Geometry_Init();
|
Geometry_Init();
|
||||||
Mathutils_Init();
|
Mathutils_Init();
|
||||||
|
|||||||
Reference in New Issue
Block a user