Files
ChocolateyPackages/EthanBrown.SublimeText2.WebPackages/tools/PackageCache/Emmet/emmet/context.py
2013-04-04 08:54:25 -04:00

229 lines
5.3 KiB
Python

# coding=utf-8
import sys
import os
import os.path
import codecs
import json
import gc
import imp
import re
from file import File
BASE_PATH = os.path.abspath(os.path.dirname(__file__))
is_python3 = sys.version_info[0] > 2
core_files = ['emmet-app.js', 'python-wrapper.js']
def should_use_unicode():
"""
WinXP unable to eval JS in unicode object (while other OSes requires it)
This function checks if we have to use unicode when reading files
"""
ctx = PyV8.JSContext()
ctx.enter()
use_unicode = True
try:
ctx.eval(u'(function(){return;})()')
except:
use_unicode = False
ctx.leave()
return use_unicode
def make_path(filename):
return os.path.normpath(os.path.join(BASE_PATH, filename))
def js_log(message):
print(message)
def js_file_reader(file_path, use_unicode=True):
if use_unicode:
f = codecs.open(file_path, 'r', 'utf-8')
else:
f = open(file_path, 'r')
content = f.read()
f.close()
return content
def import_pyv8():
# Importing non-existing modules is a bit tricky in Python:
# if we simply call `import PyV8` and module doesn't exists,
# Python will cache this failed import and will always
# throw exception even if this module appear in PYTHONPATH.
# To prevent this, we have to manually test if
# PyV8.py(c) exists in PYTHONPATH before importing PyV8
if 'PyV8' in sys.modules:
# PyV8 was loaded by ST2, create global alias
if 'PyV8' not in globals():
globals()['PyV8'] = __import__('PyV8')
return
loaded = False
f, pathname, description = imp.find_module('PyV8')
bin_f, bin_pathname, bin_description = imp.find_module('_PyV8')
if f:
try:
imp.acquire_lock()
globals()['_PyV8'] = imp.load_module('_PyV8', bin_f, bin_pathname, bin_description)
globals()['PyV8'] = imp.load_module('PyV8', f, pathname, description)
imp.release_lock()
loaded = True
finally:
# Since we may exit via an exception, close fp explicitly.
if f:
f.close()
if bin_f:
bin_f.close()
if not loaded:
raise ImportError('No PyV8 module found')
class Context():
"""
Creates Emmet JS core context.
Before instantiating this class, make sure PyV8
is available in `sys.path`
@param files: Additional files to load with JS core
@param path: Path to Emmet extensions
@param contrib: Python objects to contribute to JS execution context
@param pyv8_path: Location of PyV8 binaries
"""
def __init__(self, files=[], ext_path=None, contrib=None, logger=None, reader=js_file_reader):
self.logger = logger
self.reader = reader
try:
import_pyv8()
except ImportError as e:
pass
self._ctx = None
self._contrib = contrib
self._should_load_extension = True
# detect reader encoding
self._use_unicode = None
self._core_files = [] + core_files + files
self._ext_path = None
self.set_ext_path(ext_path)
self._user_data = None
def log(self, message):
if self.logger:
self.logger(message)
def get_ext_path(self):
return self._ext_path
def set_ext_path(self, val):
try:
if val and val[:1] == '~':
val = os.path.expanduser(val)
val = os.path.abspath(val)
except Exception as e:
return
if val == self._ext_path:
return
self._ext_path = val
self.reset()
def load_extensions(self, path=None):
if path is None:
path = self._ext_path;
if path and os.path.isdir(path):
ext_files = []
self.log('Loading Emmet extensions from %s' % self._ext_path)
for dirname, dirnames, filenames in os.walk(self._ext_path):
for filename in filenames:
if filename[0] != '.':
ext_files.append(os.path.join(dirname, filename))
self.js().locals.pyLoadExtensions(ext_files)
def js(self):
"Returns JS context"
if not self._ctx:
try:
import_pyv8()
except ImportError as e:
return None
if 'PyV8' not in sys.modules:
# Binary is not available yet
return None
if self._use_unicode is None:
self._use_unicode = should_use_unicode()
glue = u'\n' if self._use_unicode else '\n'
core_src = [self.read_js_file(make_path(f)) for f in self._core_files]
self._ctx = PyV8.JSContext()
self._ctx.enter()
self._ctx.eval(glue.join(core_src))
# for f in self._core_files:
# self._ctx.eval(self.read_js_file(make_path(f)), name=f, line=0, col=0)
# load default snippets
self._ctx.locals.pyLoadSystemSnippets(self.read_js_file(make_path('snippets.json')))
# expose some methods
self._ctx.locals.log = js_log
self._ctx.locals.pyFile = File()
if self._contrib:
for k in self._contrib:
self._ctx.locals[k] = self._contrib[k]
else:
self._ctx.enter()
if self._should_load_extension:
self._ctx.locals.pyResetUserData()
self._should_load_extension = False
self.load_extensions()
if self._user_data:
self._ctx.locals.pyLoadUserData(self._user_data)
self._user_data = None
return self._ctx
def load_user_data(self, data):
"Loads user data payload from JSON"
self._user_data = data
# self.js().locals.pyLoadUserData(data)
def reset(self):
"Resets JS execution context"
if self._ctx:
self._ctx.leave()
self._ctx = None
try:
PyV8.JSEngine.collect()
gc.collect()
except:
pass
self._should_load_extension = True
def read_js_file(self, file_path):
return self.reader(file_path, self._use_unicode)
def eval(self, source):
self.js().eval(source)
def eval_js_file(self, file_path):
self.eval(self.read_js_file(file_path))