feat(SublimeText2.WebPackages): cache packages
This commit is contained in:
@@ -0,0 +1,228 @@
|
||||
# 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))
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,159 @@
|
||||
'''
|
||||
@author Sergey Chikuyonok (serge.che@gmail.com)
|
||||
@link http://chikuyonok.ru
|
||||
'''
|
||||
import sys
|
||||
import os.path
|
||||
import re
|
||||
|
||||
is_python3 = sys.version_info[0] > 2
|
||||
|
||||
try:
|
||||
if is_python3:
|
||||
import urllib.request as urllib2
|
||||
else:
|
||||
import urllib2
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
def is_url(path):
|
||||
return re.match(r'^https?://', path, re.IGNORECASE)
|
||||
|
||||
def read_http(url, size=-1, mode=None):
|
||||
response = urllib2.urlopen(url, timeout=5)
|
||||
return response.read(size)
|
||||
|
||||
def read_file(path, size=-1, mode='rb'):
|
||||
kwargs = {}
|
||||
if is_python3 and 'b' not in mode:
|
||||
kwargs['encoding'] = 'utf-8'
|
||||
|
||||
with open(path, mode, **kwargs) as fp:
|
||||
return fp.read(size)
|
||||
|
||||
class File():
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def _read(self, path, size, mode='rb'):
|
||||
reader = is_url(path) and read_http or read_file
|
||||
return reader(path, size, mode)
|
||||
|
||||
def read(self, path, size, callback=None):
|
||||
"""
|
||||
Read file content and return it
|
||||
@param path: File's relative or absolute path
|
||||
@type path: str
|
||||
@return: str
|
||||
"""
|
||||
|
||||
try:
|
||||
content = self._read(path, size)
|
||||
|
||||
# return as array of character codes since PyV8 may corrupt
|
||||
# binary data when python string is translated into JS string
|
||||
if is_python3:
|
||||
content = [ch for ch in content]
|
||||
else:
|
||||
content = [ord(ch) for ch in content]
|
||||
|
||||
except Exception as e:
|
||||
return callback(str(e), None)
|
||||
|
||||
callback(None, content)
|
||||
|
||||
def read_text(self, path, size, callback=None):
|
||||
"""
|
||||
Read file content and return it
|
||||
@param path: File's relative or absolute path
|
||||
@type path: str
|
||||
@return: str
|
||||
"""
|
||||
|
||||
try:
|
||||
content = self._read(path, size, 'r')
|
||||
if not is_python3:
|
||||
content = content.decode('utf-8')
|
||||
except Exception as e:
|
||||
return callback(str(e), None)
|
||||
|
||||
callback(None, content)
|
||||
|
||||
def locate_file(self, editor_file, file_name):
|
||||
"""
|
||||
Locate <code>file_name</code> file that relates to <code>editor_file</code>.
|
||||
File name may be absolute or relative path
|
||||
|
||||
@type editor_file: str
|
||||
@type file_name: str
|
||||
@return String or None if <code>file_name</code> cannot be located
|
||||
"""
|
||||
if is_url(file_name):
|
||||
return file_name
|
||||
|
||||
result = None
|
||||
|
||||
previous_parent = ''
|
||||
parent = os.path.dirname(editor_file)
|
||||
while parent and os.path.exists(parent) and parent != previous_parent:
|
||||
tmp = self.create_path(parent, file_name)
|
||||
if os.path.exists(tmp):
|
||||
result = tmp
|
||||
break
|
||||
|
||||
previous_parent = parent
|
||||
parent = os.path.dirname(parent)
|
||||
|
||||
return result
|
||||
|
||||
def create_path(self, parent, file_name):
|
||||
"""
|
||||
Creates absolute path by concatenating <code>parent</code> and <code>file_name</code>.
|
||||
If <code>parent</code> points to file, its parent directory is used
|
||||
|
||||
@type parent: str
|
||||
@type file_name: str
|
||||
@return: str
|
||||
"""
|
||||
result = ''
|
||||
file_name = file_name.lstrip('/')
|
||||
|
||||
if os.path.exists(parent):
|
||||
if os.path.isfile(parent):
|
||||
parent = os.path.dirname(parent)
|
||||
|
||||
result = os.path.normpath(os.path.join(parent, file_name))
|
||||
|
||||
return result
|
||||
|
||||
def save(self, file, content):
|
||||
"""
|
||||
Saves <code>content</code> as <code>file</code>
|
||||
|
||||
@param file: File's asolute path
|
||||
@type file: str
|
||||
@param content: File content
|
||||
@type content: str
|
||||
"""
|
||||
try:
|
||||
fp = open(file, 'wb')
|
||||
except:
|
||||
fdirs, fname = os.path.split(file)
|
||||
if fdirs:
|
||||
os.makedirs(fdirs)
|
||||
fp = open(file, 'wb')
|
||||
|
||||
fp.write(content)
|
||||
fp.close()
|
||||
|
||||
def get_ext(self, file):
|
||||
"""
|
||||
Returns file extention in lower case
|
||||
@type file: str
|
||||
@return: str
|
||||
"""
|
||||
ext = os.path.splitext(file)[1]
|
||||
if ext:
|
||||
ext = ext[1:]
|
||||
|
||||
return ext.lower()
|
@@ -0,0 +1,97 @@
|
||||
var console = {
|
||||
log: function(msg) {
|
||||
log(msg);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Simple function alias to run Emmet action.
|
||||
* <code>editorProxy</code> object should be defined
|
||||
* in concrete plugin implementation.
|
||||
*/
|
||||
function pyRunAction(name) {
|
||||
return emmet.require('actions').run(name, editorProxy);
|
||||
}
|
||||
|
||||
function pyLoadSystemSnippets(data) {
|
||||
emmet.require('bootstrap').loadSystemSnippets(data);
|
||||
}
|
||||
|
||||
function pyLoadUserData(data) {
|
||||
emmet.require('bootstrap').loadUserData(data);
|
||||
}
|
||||
|
||||
function pyLoadExtensions(fileList) {
|
||||
fileList = _.toArray(fileList);
|
||||
emmet.require('bootstrap').loadExtensions(fileList);
|
||||
}
|
||||
|
||||
function pyResetUserData() {
|
||||
emmet.require('bootstrap').resetUserData();
|
||||
}
|
||||
|
||||
emmet.define('file', function(require, _) {
|
||||
return {
|
||||
_parseParams: function(args) {
|
||||
var params = {
|
||||
path: args[0],
|
||||
size: -1
|
||||
};
|
||||
|
||||
args = _.rest(args);
|
||||
params.callback = _.last(args);
|
||||
args = _.initial(args);
|
||||
if (args.length) {
|
||||
params.size = args[0];
|
||||
}
|
||||
|
||||
return params;
|
||||
},
|
||||
|
||||
read: function(path, size, callback) {
|
||||
var params = this._parseParams(arguments);
|
||||
|
||||
try {
|
||||
pyFile.read(params.path, params.size, function(err, content) {
|
||||
if (err) {
|
||||
return params.callback(err, content);
|
||||
}
|
||||
|
||||
content = _.map(content || [], function(b) {
|
||||
return String.fromCharCode(b);
|
||||
}).join('');
|
||||
params.callback(null, content);
|
||||
});
|
||||
} catch(e) {
|
||||
params.callback(e);
|
||||
}
|
||||
},
|
||||
|
||||
readText: function() {
|
||||
var params = this._parseParams(arguments);
|
||||
try {
|
||||
pyFile.read_text(params.path, params.size, params.callback);
|
||||
} catch(e) {
|
||||
params.callback(e);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
locateFile: function(editorFile, fileName) {
|
||||
return pyFile.locate_file(editorFile, fileName);
|
||||
},
|
||||
|
||||
createPath: function(parent, fileName) {
|
||||
return pyFile.create_path(parent, fileName);
|
||||
},
|
||||
|
||||
save: function(file, content) {
|
||||
return pyFile.save(file, content);
|
||||
},
|
||||
|
||||
getExt: function(file) {
|
||||
var m = (file || '').match(/\.([\w\-]+)$/);
|
||||
return m ? m[1].toLowerCase() : '';
|
||||
}
|
||||
};
|
||||
});
|
@@ -0,0 +1,591 @@
|
||||
# coding=utf-8
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
import json
|
||||
import re
|
||||
import threading
|
||||
import subprocess
|
||||
import tempfile
|
||||
import collections
|
||||
import platform
|
||||
import semver
|
||||
import time
|
||||
import zipfile
|
||||
|
||||
is_python3 = sys.version_info[0] > 2
|
||||
|
||||
if is_python3:
|
||||
import urllib.request as url_req
|
||||
import urllib.error as url_err
|
||||
import urllib.parse as url_parse
|
||||
else:
|
||||
import urllib
|
||||
import urllib2
|
||||
url_req = urllib2
|
||||
url_err = urllib2
|
||||
url_parse = urllib2
|
||||
|
||||
CHECK_INTERVAL = 60 * 60 * 24
|
||||
|
||||
# PACKAGES_URL = 'https://api.github.com/repos/emmetio/pyv8-binaries/downloads'
|
||||
PACKAGES_URL = 'https://api.github.com/repos/emmetio/pyv8-binaries/contents'
|
||||
|
||||
def load(dest_path, delegate=None):
|
||||
"""
|
||||
Main function that attempts to load or update PyV8 binary.
|
||||
First, it loads list of available PyV8 modules and check if
|
||||
PyV8 should be downloaded or updated.
|
||||
@param dest_path: Path where PyV8 lib should be downloaded
|
||||
@param delegate: instance of LoaderDelegate that will receive
|
||||
loader progress events
|
||||
@returns: `True` if download progress was initiated
|
||||
"""
|
||||
if delegate is None:
|
||||
delegate = LoaderDelegate()
|
||||
|
||||
config = get_loader_config(dest_path)
|
||||
|
||||
if 'PyV8' in sys.modules and (config['skip_update'] or time.time() < config['last_update'] + CHECK_INTERVAL):
|
||||
# No need to load anything: user already has PyV8 binary
|
||||
# or decided to disable update process
|
||||
delegate.log('No need to update PyV8')
|
||||
return False
|
||||
|
||||
def on_complete(result, *args, **kwargs):
|
||||
if result is not None:
|
||||
# Most recent version was downloaded
|
||||
config['last_id'] = result
|
||||
if 'PyV8' not in sys.modules:
|
||||
# PyV8 is not loaded yet, we can safely unpack it
|
||||
unpack_pyv8(dest_path)
|
||||
|
||||
config['last_update'] = time.time()
|
||||
save_loader_config(dest_path, config)
|
||||
delegate.on_complete(*args, **kwargs)
|
||||
|
||||
# try to download most recent version of PyV8
|
||||
# As PyV8 for Sublime Text spreads the world, it's possible
|
||||
# that multiple distinct PyV8Loader's may start doing the same
|
||||
# job at the same time. In this case, we should check if there's
|
||||
# already a thread that load PyV8 and hook on existing thread
|
||||
# rather that creating a new one
|
||||
thread = None
|
||||
thread_exists = False
|
||||
for t in threading.enumerate():
|
||||
if hasattr(t, 'is_pyv8_thread'):
|
||||
print('PyV8: Reusing thread')
|
||||
thread = t
|
||||
thread_exists = True
|
||||
break
|
||||
|
||||
if not thread:
|
||||
print('PyV8: Creating new thread')
|
||||
thread = PyV8Loader(get_arch(), dest_path, config, delegate=delegate)
|
||||
thread.start()
|
||||
|
||||
delegate.on_start()
|
||||
|
||||
# watch on download progress
|
||||
prog = ThreadProgress(thread, delegate, thread_exists)
|
||||
prog.on('complete', on_complete if not thread_exists else delegate.on_complete)
|
||||
prog.on('error', delegate.on_error)
|
||||
|
||||
def get_arch():
|
||||
"Returns architecture name for PyV8 binary"
|
||||
suffix = is_python3 and '-p3' or ''
|
||||
p = lambda a: '%s%s' % (a, suffix)
|
||||
is_64bit = sys.maxsize > 2**32
|
||||
system_name = platform.system()
|
||||
if system_name == 'Darwin':
|
||||
if semver.match(platform.mac_ver()[0], '<10.7.0'):
|
||||
return p('mac106')
|
||||
|
||||
return p('osx')
|
||||
if system_name == 'Windows':
|
||||
return p('win64') if is_64bit else p('win32')
|
||||
if system_name == 'Linux':
|
||||
return p('linux64') if is_64bit else p('linux32')
|
||||
|
||||
def get_loader_config(path):
|
||||
config = {
|
||||
"last_id": 0,
|
||||
"last_update": 0,
|
||||
"skip_update": False
|
||||
}
|
||||
|
||||
config_path = os.path.join(path, 'config.json')
|
||||
if os.path.exists(config_path):
|
||||
with open(config_path) as fd:
|
||||
for k,v in json.load(fd).items():
|
||||
config[k] = v
|
||||
|
||||
return config
|
||||
|
||||
def save_loader_config(path, data):
|
||||
config_path = os.path.join(path, 'config.json')
|
||||
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
fp = open(config_path, 'w')
|
||||
fp.write(json.dumps(data))
|
||||
fp.close()
|
||||
|
||||
def clean_old_data():
|
||||
for f in os.listdir('.'):
|
||||
if f.lower() != 'config.json' and f.lower() != 'pack.zip':
|
||||
try:
|
||||
os.remove(f)
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
def unpack_pyv8(package_dir):
|
||||
f = os.path.join(package_dir, 'pack.zip')
|
||||
if not os.path.exists(f):
|
||||
return
|
||||
|
||||
package_zip = zipfile.ZipFile(f, 'r')
|
||||
|
||||
root_level_paths = []
|
||||
last_path = None
|
||||
for path in package_zip.namelist():
|
||||
last_path = path
|
||||
if path.find('/') in [len(path) - 1, -1]:
|
||||
root_level_paths.append(path)
|
||||
if path[0] == '/' or path.find('../') != -1 or path.find('..\\') != -1:
|
||||
raise 'The PyV8 package contains files outside of the package dir and cannot be safely installed.'
|
||||
|
||||
if last_path and len(root_level_paths) == 0:
|
||||
root_level_paths.append(last_path[0:last_path.find('/') + 1])
|
||||
|
||||
prev_dir = os.getcwd()
|
||||
os.chdir(package_dir)
|
||||
|
||||
clean_old_data()
|
||||
|
||||
# Here we don't use .extractall() since it was having issues on OS X
|
||||
skip_root_dir = len(root_level_paths) == 1 and \
|
||||
root_level_paths[0].endswith('/')
|
||||
extracted_paths = []
|
||||
for path in package_zip.namelist():
|
||||
dest = path
|
||||
|
||||
if not is_python3:
|
||||
try:
|
||||
if not isinstance(dest, unicode):
|
||||
dest = unicode(dest, 'utf-8', 'strict')
|
||||
except UnicodeDecodeError:
|
||||
dest = unicode(dest, 'cp1252', 'replace')
|
||||
|
||||
if os.name == 'nt':
|
||||
regex = ':|\*|\?|"|<|>|\|'
|
||||
if re.search(regex, dest) != None:
|
||||
print ('%s: Skipping file from package named %s due to ' +
|
||||
'an invalid filename') % (__name__, path)
|
||||
continue
|
||||
|
||||
# If there was only a single directory in the package, we remove
|
||||
# that folder name from the paths as we extract entries
|
||||
if skip_root_dir:
|
||||
dest = dest[len(root_level_paths[0]):]
|
||||
|
||||
if os.name == 'nt':
|
||||
dest = dest.replace('/', '\\')
|
||||
else:
|
||||
dest = dest.replace('\\', '/')
|
||||
|
||||
dest = os.path.join(package_dir, dest)
|
||||
|
||||
def add_extracted_dirs(dir):
|
||||
while dir not in extracted_paths:
|
||||
extracted_paths.append(dir)
|
||||
dir = os.path.dirname(dir)
|
||||
if dir == package_dir:
|
||||
break
|
||||
|
||||
if path.endswith('/'):
|
||||
if not os.path.exists(dest):
|
||||
os.makedirs(dest)
|
||||
add_extracted_dirs(dest)
|
||||
else:
|
||||
dest_dir = os.path.dirname(dest)
|
||||
if not os.path.exists(dest_dir):
|
||||
os.makedirs(dest_dir)
|
||||
add_extracted_dirs(dest_dir)
|
||||
extracted_paths.append(dest)
|
||||
try:
|
||||
open(dest, 'wb').write(package_zip.read(path))
|
||||
except (IOError, UnicodeDecodeError):
|
||||
print ('%s: Skipping file from package named %s due to ' +
|
||||
'an invalid filename') % (__name__, path)
|
||||
package_zip.close()
|
||||
|
||||
os.chdir(prev_dir)
|
||||
os.remove(f)
|
||||
|
||||
class LoaderDelegate():
|
||||
"""
|
||||
Abstract class used to display PyV8 binary download progress,
|
||||
and provide some settings for downloader
|
||||
"""
|
||||
def __init__(self, settings={}):
|
||||
self.settings = settings
|
||||
|
||||
def on_start(self, *args, **kwargs):
|
||||
"Invoked when download process is initiated"
|
||||
pass
|
||||
|
||||
def on_progress(self, *args, **kwargs):
|
||||
"Invoked on download progress"
|
||||
pass
|
||||
|
||||
def on_complete(self, *args, **kwargs):
|
||||
"Invoked when download process was finished successfully"
|
||||
pass
|
||||
|
||||
def on_error(self, *args, **kwargs):
|
||||
"Invoked when error occured during download process"
|
||||
pass
|
||||
|
||||
def setting(self, name, default=None):
|
||||
"Returns specified setting name"
|
||||
return self.settings[name] if name in self.settings else default
|
||||
|
||||
def log(self, message):
|
||||
pass
|
||||
|
||||
class ThreadProgress():
|
||||
def __init__(self, thread, delegate, is_background=False):
|
||||
self.thread = thread
|
||||
self.delegate = delegate
|
||||
self.is_background = is_background
|
||||
self._callbacks = {}
|
||||
threading.Timer(0, self.run).start()
|
||||
|
||||
def run(self):
|
||||
if not self.thread.is_alive():
|
||||
if self.thread.exit_code != 0:
|
||||
return self.trigger('error', exit_code=self.thread.exit_code, progress=self)
|
||||
|
||||
return self.trigger('complete', result=self.thread.result, progress=self)
|
||||
|
||||
self.trigger('progress', progress=self)
|
||||
threading.Timer(0.1, self.run).start()
|
||||
|
||||
def on(self, event_name, callback):
|
||||
if event_name not in self._callbacks:
|
||||
self._callbacks[event_name] = []
|
||||
|
||||
if isinstance(callback, collections.Callable):
|
||||
self._callbacks[event_name].append(callback)
|
||||
|
||||
return self
|
||||
|
||||
def trigger(self, event_name, *args, **kwargs):
|
||||
if event_name in self._callbacks:
|
||||
for c in self._callbacks[event_name]:
|
||||
c(*args, **kwargs)
|
||||
|
||||
if self.delegate and hasattr(self.delegate, 'on_%s' % event_name):
|
||||
getattr(self.delegate, 'on_%s' % event_name)(*args, **kwargs)
|
||||
|
||||
return self
|
||||
|
||||
class BinaryNotFoundError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class NonCleanExitError(Exception):
|
||||
def __init__(self, returncode):
|
||||
self.returncode = returncode
|
||||
|
||||
def __str__(self):
|
||||
return repr(self.returncode)
|
||||
|
||||
|
||||
class CliDownloader():
|
||||
def __init__(self, settings):
|
||||
self.settings = settings
|
||||
|
||||
def find_binary(self, name):
|
||||
for dir in os.environ['PATH'].split(os.pathsep):
|
||||
path = os.path.join(dir, name)
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
|
||||
raise BinaryNotFoundError('The binary %s could not be located' % name)
|
||||
|
||||
def execute(self, args):
|
||||
proc = subprocess.Popen(args, stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
|
||||
output = proc.stdout.read()
|
||||
returncode = proc.wait()
|
||||
if returncode != 0:
|
||||
error = NonCleanExitError(returncode)
|
||||
error.output = output
|
||||
raise error
|
||||
return output
|
||||
|
||||
class WgetDownloader(CliDownloader):
|
||||
def __init__(self, settings):
|
||||
self.settings = settings
|
||||
self.wget = self.find_binary('wget')
|
||||
|
||||
def clean_tmp_file(self):
|
||||
os.remove(self.tmp_file)
|
||||
|
||||
def download(self, url, error_message, timeout, tries):
|
||||
if not self.wget:
|
||||
return False
|
||||
|
||||
self.tmp_file = tempfile.NamedTemporaryFile().name
|
||||
command = [self.wget, '--connect-timeout=' + str(int(timeout)), '-o',
|
||||
self.tmp_file, '-O', '-', '-U', 'Emmet PyV8 Loader',
|
||||
'--no-check-certificate']
|
||||
|
||||
command.append(url)
|
||||
|
||||
if self.settings.get('http_proxy'):
|
||||
os.putenv('http_proxy', self.settings.get('http_proxy'))
|
||||
if not self.settings.get('https_proxy'):
|
||||
os.putenv('https_proxy', self.settings.get('http_proxy'))
|
||||
if self.settings.get('https_proxy'):
|
||||
os.putenv('https_proxy', self.settings.get('https_proxy'))
|
||||
|
||||
while tries > 0:
|
||||
tries -= 1
|
||||
try:
|
||||
result = self.execute(command)
|
||||
self.clean_tmp_file()
|
||||
return result
|
||||
except NonCleanExitError as e:
|
||||
error_line = ''
|
||||
with open(self.tmp_file) as f:
|
||||
for line in list(f):
|
||||
if re.search('ERROR[: ]|failed: ', line):
|
||||
error_line = line
|
||||
break
|
||||
|
||||
if e.returncode == 8:
|
||||
regex = re.compile('^.*ERROR (\d+):.*', re.S)
|
||||
if re.sub(regex, '\\1', error_line) == '503':
|
||||
# GitHub and BitBucket seem to rate limit via 503
|
||||
print('%s: Downloading %s was rate limited, trying again' % (__name__, url))
|
||||
continue
|
||||
error_string = 'HTTP error ' + re.sub('^.*? ERROR ', '',
|
||||
error_line)
|
||||
|
||||
elif e.returncode == 4:
|
||||
error_string = re.sub('^.*?failed: ', '', error_line)
|
||||
# GitHub and BitBucket seem to time out a lot
|
||||
if error_string.find('timed out') != -1:
|
||||
print('%s: Downloading %s timed out, trying again' % (__name__, url))
|
||||
continue
|
||||
|
||||
else:
|
||||
error_string = re.sub('^.*?(ERROR[: ]|failed: )', '\\1',
|
||||
error_line)
|
||||
|
||||
error_string = re.sub('\\.?\s*\n\s*$', '', error_string)
|
||||
print('%s: %s %s downloading %s.' % (__name__, error_message,
|
||||
error_string, url))
|
||||
self.clean_tmp_file()
|
||||
break
|
||||
return False
|
||||
|
||||
|
||||
class CurlDownloader(CliDownloader):
|
||||
def __init__(self, settings):
|
||||
self.settings = settings
|
||||
self.curl = self.find_binary('curl')
|
||||
|
||||
def download(self, url, error_message, timeout, tries):
|
||||
if not self.curl:
|
||||
return False
|
||||
command = [self.curl, '-f', '--user-agent', 'Emmet PyV8 Loader',
|
||||
'--connect-timeout', str(int(timeout)), '-sS']
|
||||
|
||||
command.append(url)
|
||||
|
||||
if self.settings.get('http_proxy'):
|
||||
os.putenv('http_proxy', self.settings.get('http_proxy'))
|
||||
if not self.settings.get('https_proxy'):
|
||||
os.putenv('HTTPS_PROXY', self.settings.get('http_proxy'))
|
||||
if self.settings.get('https_proxy'):
|
||||
os.putenv('HTTPS_PROXY', self.settings.get('https_proxy'))
|
||||
|
||||
while tries > 0:
|
||||
tries -= 1
|
||||
try:
|
||||
return self.execute(command)
|
||||
except NonCleanExitError as e:
|
||||
if e.returncode == 22:
|
||||
code = re.sub('^.*?(\d+)\s*$', '\\1', e.output)
|
||||
if code == '503':
|
||||
# GitHub and BitBucket seem to rate limit via 503
|
||||
print('%s: Downloading %s was rate limited, trying again' % (__name__, url))
|
||||
continue
|
||||
error_string = 'HTTP error ' + code
|
||||
elif e.returncode == 6:
|
||||
error_string = 'URL error host not found'
|
||||
elif e.returncode == 28:
|
||||
# GitHub and BitBucket seem to time out a lot
|
||||
print('%s: Downloading %s timed out, trying again' % (__name__, url))
|
||||
continue
|
||||
else:
|
||||
error_string = e.output.rstrip()
|
||||
|
||||
print('%s: %s %s downloading %s.' % (__name__, error_message, error_string, url))
|
||||
break
|
||||
return False
|
||||
|
||||
|
||||
class UrlLib2Downloader():
|
||||
def __init__(self, settings):
|
||||
self.settings = settings
|
||||
|
||||
def download(self, url, error_message, timeout, tries):
|
||||
http_proxy = self.settings.get('http_proxy')
|
||||
https_proxy = self.settings.get('https_proxy')
|
||||
if http_proxy or https_proxy:
|
||||
proxies = {}
|
||||
if http_proxy:
|
||||
proxies['http'] = http_proxy
|
||||
if not https_proxy:
|
||||
proxies['https'] = http_proxy
|
||||
if https_proxy:
|
||||
proxies['https'] = https_proxy
|
||||
proxy_handler = url_req.ProxyHandler(proxies)
|
||||
else:
|
||||
proxy_handler = url_req.ProxyHandler()
|
||||
handlers = [proxy_handler]
|
||||
|
||||
# secure_url_match = re.match('^https://([^/]+)', url)
|
||||
# if secure_url_match != None:
|
||||
# secure_domain = secure_url_match.group(1)
|
||||
# bundle_path = self.check_certs(secure_domain, timeout)
|
||||
# if not bundle_path:
|
||||
# return False
|
||||
# handlers.append(VerifiedHTTPSHandler(ca_certs=bundle_path))
|
||||
url_req.install_opener(url_req.build_opener(*handlers))
|
||||
|
||||
while tries > 0:
|
||||
tries -= 1
|
||||
try:
|
||||
request = url_req.Request(url, headers={"User-Agent":
|
||||
"Emmet PyV8 Loader"})
|
||||
http_file = url_req.urlopen(request, timeout=timeout)
|
||||
return http_file.read()
|
||||
|
||||
except url_err.HTTPError as e:
|
||||
# Bitbucket and Github ratelimit using 503 a decent amount
|
||||
if str(e.code) == '503':
|
||||
print('%s: Downloading %s was rate limited, trying again' % (__name__, url))
|
||||
continue
|
||||
print('%s: %s HTTP error %s downloading %s.' % (__name__, error_message, str(e.code), url))
|
||||
|
||||
except url_err.URLError as e:
|
||||
# Bitbucket and Github timeout a decent amount
|
||||
if str(e.reason) == 'The read operation timed out' or \
|
||||
str(e.reason) == 'timed out':
|
||||
print('%s: Downloading %s timed out, trying again' % (__name__, url))
|
||||
continue
|
||||
print('%s: %s URL error %s downloading %s.' % (__name__, error_message, str(e.reason), url))
|
||||
break
|
||||
return False
|
||||
|
||||
class PyV8Loader(threading.Thread):
|
||||
def __init__(self, arch, download_path, config, delegate=None):
|
||||
self.arch = arch
|
||||
self.config = config
|
||||
self.download_path = download_path
|
||||
self.exit_code = 0
|
||||
self.result = None
|
||||
self.delegate = delegate or LoaderDelegate()
|
||||
self.is_pyv8_thread = True
|
||||
|
||||
threading.Thread.__init__(self)
|
||||
self.delegate.log('Creating thread')
|
||||
|
||||
def download_url(self, url, error_message):
|
||||
# TODO add settings
|
||||
has_ssl = 'ssl' in sys.modules and hasattr(url_req, 'HTTPSHandler')
|
||||
is_ssl = re.search('^https://', url) != None
|
||||
|
||||
if (is_ssl and has_ssl) or not is_ssl:
|
||||
downloader = UrlLib2Downloader(self.delegate.settings)
|
||||
else:
|
||||
for downloader_class in [CurlDownloader, WgetDownloader]:
|
||||
try:
|
||||
downloader = downloader_class(self.delegate.settings)
|
||||
break
|
||||
except BinaryNotFoundError:
|
||||
pass
|
||||
|
||||
if not downloader:
|
||||
self.delegate.log('Unable to download PyV8 binary due to invalid downloader')
|
||||
return False
|
||||
|
||||
timeout = self.delegate.settings.get('timeout', 60)
|
||||
# timeout = 3
|
||||
return downloader.download(url.replace(' ', '%20'), error_message, timeout, 3)
|
||||
|
||||
def run(self):
|
||||
# get list of available packages first
|
||||
self.delegate.log('Loading %s' % PACKAGES_URL)
|
||||
try:
|
||||
packages = self.download_url(PACKAGES_URL, 'Unable to download packages list.')
|
||||
except Exception as e:
|
||||
self.delegate.log('Unable to download file: %s' % e)
|
||||
self.exit_code = 4
|
||||
return
|
||||
|
||||
if not packages:
|
||||
self.exit_code = 1
|
||||
return
|
||||
|
||||
if isinstance(packages, bytes):
|
||||
packages = packages.decode('utf-8')
|
||||
|
||||
files = json.loads(packages)
|
||||
|
||||
# find package for current architecture
|
||||
cur_item = None
|
||||
bundle_name = 'pyv8-%s.zip' % self.arch
|
||||
for item in files:
|
||||
if bundle_name == item['name']:
|
||||
cur_item = item
|
||||
break
|
||||
|
||||
if not cur_item:
|
||||
self.delegate.log('Unable to find binary for %s architecture' % self.arch)
|
||||
self.exit_code = 2
|
||||
return
|
||||
|
||||
if cur_item['sha'] == self.config['last_id']:
|
||||
self.delegate.log('You have the most recent PyV8 binary')
|
||||
return
|
||||
|
||||
url = 'https://raw.github.com/emmetio/pyv8-binaries/master/%s' % cur_item['name']
|
||||
self.delegate.log('Loading PyV8 binary from %s' % url)
|
||||
package = self.download_url(url, 'Unable to download package from %s' % url)
|
||||
if not package:
|
||||
self.exit_code = 3
|
||||
return
|
||||
|
||||
# we should only save downloaded package and delegate module
|
||||
# loading/unloading to main thread since improper PyV8 unload
|
||||
# may cause editor crash
|
||||
try:
|
||||
os.makedirs(self.download_path)
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
fp = open(os.path.join(self.download_path, 'pack.zip'), 'wb')
|
||||
fp.write(package)
|
||||
fp.close()
|
||||
|
||||
self.result = cur_item['sha']
|
||||
# Done!
|
||||
|
@@ -0,0 +1,25 @@
|
||||
import sys
|
||||
import imp
|
||||
|
||||
# Dependecy reloader for Emmet plugin
|
||||
# The original idea is borrowed from
|
||||
# https://github.com/wbond/sublime_package_control/blob/master/package_control/reloader.py
|
||||
|
||||
reload_mods = []
|
||||
for mod in sys.modules:
|
||||
if mod.startswith('emmet') and sys.modules[mod] != None:
|
||||
reload_mods.append(mod)
|
||||
|
||||
mods_load_order = [
|
||||
'emmet.semver',
|
||||
'emmet.pyv8loader',
|
||||
'emmet_completions.trackers',
|
||||
'emmet_completions.meta',
|
||||
'emmet_completions',
|
||||
'emmet.file',
|
||||
'emmet.context'
|
||||
]
|
||||
|
||||
for mod in mods_load_order:
|
||||
if mod in reload_mods:
|
||||
imp.reload(sys.modules[mod])
|
@@ -0,0 +1,83 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import re
|
||||
|
||||
_REGEX = re.compile('^(?P<major>[0-9]+)'
|
||||
'\.(?P<minor>[0-9]+)'
|
||||
'\.(?P<patch>[0-9]+)'
|
||||
'(\-(?P<prerelease>[0-9A-Za-z]+(\.[0-9A-Za-z]+)*))?'
|
||||
'(\+(?P<build>[0-9A-Za-z]+(\.[0-9A-Za-z]+)*))?$')
|
||||
|
||||
if 'cmp' not in __builtins__:
|
||||
cmp = lambda a,b: (a > b) - (a < b)
|
||||
|
||||
def parse(version):
|
||||
"""
|
||||
Parse version to major, minor, patch, pre-release, build parts.
|
||||
"""
|
||||
match = _REGEX.match(version)
|
||||
if match is None:
|
||||
raise ValueError('%s is not valid SemVer string' % version)
|
||||
|
||||
verinfo = match.groupdict()
|
||||
|
||||
verinfo['major'] = int(verinfo['major'])
|
||||
verinfo['minor'] = int(verinfo['minor'])
|
||||
verinfo['patch'] = int(verinfo['patch'])
|
||||
|
||||
return verinfo
|
||||
|
||||
|
||||
def compare(ver1, ver2):
|
||||
def nat_cmp(a, b):
|
||||
a, b = a or '', b or ''
|
||||
convert = lambda text: text.isdigit() and int(text) or text.lower()
|
||||
alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
|
||||
return cmp(alphanum_key(a), alphanum_key(b))
|
||||
|
||||
def compare_by_keys(d1, d2):
|
||||
for key in ['major', 'minor', 'patch']:
|
||||
v = cmp(d1.get(key), d2.get(key))
|
||||
if v:
|
||||
return v
|
||||
rc1, rc2 = d1.get('prerelease'), d2.get('prerelease')
|
||||
build1, build2 = d1.get('build'), d2.get('build')
|
||||
rccmp = nat_cmp(rc1, rc2)
|
||||
buildcmp = nat_cmp(build1, build2)
|
||||
if not (rc1 or rc2):
|
||||
return buildcmp
|
||||
elif not rc1:
|
||||
return 1
|
||||
elif not rc2:
|
||||
return -1
|
||||
return rccmp or buildcmp or 0
|
||||
|
||||
v1, v2 = parse(ver1), parse(ver2)
|
||||
|
||||
return compare_by_keys(v1, v2)
|
||||
|
||||
|
||||
def match(version, match_expr):
|
||||
prefix = match_expr[:2]
|
||||
if prefix in ('>=', '<=', '=='):
|
||||
match_version = match_expr[2:]
|
||||
elif prefix and prefix[0] in ('>', '<', '='):
|
||||
prefix = prefix[0]
|
||||
match_version = match_expr[1:]
|
||||
else:
|
||||
raise ValueError("match_expr parameter should be in format <op><ver>, "
|
||||
"where <op> is one of ['<', '>', '==', '<=', '>=']. "
|
||||
"You provided: %r" % match_expr)
|
||||
|
||||
possibilities_dict = {
|
||||
'>': (1,),
|
||||
'<': (-1,),
|
||||
'==': (0,),
|
||||
'>=': (0, 1),
|
||||
'<=': (-1, 0)
|
||||
}
|
||||
|
||||
possibilities = possibilities_dict[prefix]
|
||||
cmp_res = compare(version, match_version)
|
||||
|
||||
return cmp_res in possibilities
|
@@ -0,0 +1,846 @@
|
||||
{
|
||||
"variables": {
|
||||
"lang": "en",
|
||||
"locale": "en-US",
|
||||
"charset": "UTF-8",
|
||||
"indentation": "\t",
|
||||
"newline": "\n"
|
||||
},
|
||||
|
||||
"css": {
|
||||
"filters": "html",
|
||||
"snippets": {
|
||||
"@i": "@import url(|);",
|
||||
"@import": "@import url(|);",
|
||||
"@m": "@media ${1:screen} {\n\t|\n}",
|
||||
"@media": "@media ${1:screen} {\n\t|\n}",
|
||||
"@f": "@font-face {\n\tfont-family:|;\n\tsrc:url(|);\n}",
|
||||
"@f+": "@font-face {\n\tfont-family: '${1:FontName}';\n\tsrc: url('${2:FileName}.eot');\n\tsrc: url('${2:FileName}.eot?#iefix') format('embedded-opentype'),\n\t\t url('${2:FileName}.woff') format('woff'),\n\t\t url('${2:FileName}.ttf') format('truetype'),\n\t\t url('${2:FileName}.svg#${1:FontName}') format('svg');\n\tfont-style: ${3:normal};\n\tfont-weight: ${4:normal};\n}",
|
||||
|
||||
"@kf": "@-webkit-keyframes ${1:identifier} {\n\t${2:from} { ${3} }${6}\n\t${4:to} { ${5} }\n}\n@-o-keyframes ${1:identifier} {\n\t${2:from} { ${3} }${6}\n\t${4:to} { ${5} }\n}\n@-moz-keyframes ${1:identifier} {\n\t${2:from} { ${3} }${6}\n\t${4:to} { ${5} }\n}\n@keyframes ${1:identifier} {\n\t${2:from} { ${3} }${6}\n\t${4:to} { ${5} }\n}",
|
||||
|
||||
|
||||
"anim": "animation:|;",
|
||||
"anim-": "animation:${1:name} ${2:duration} ${3:timing-function} ${4:delay} ${5:iteration-count} ${6:direction} ${7:fill-mode};",
|
||||
"animdel": "animation-delay:${1:time};",
|
||||
|
||||
"animdir": "animation-direction:${1:normal};",
|
||||
"animdir:n": "animation-direction:normal;",
|
||||
"animdir:r": "animation-direction:reverse;",
|
||||
"animdir:a": "animation-direction:alternate;",
|
||||
"animdir:ar": "animation-direction:alternate-reverse;",
|
||||
|
||||
"animdur": "animation-duration:${1:0}s;",
|
||||
|
||||
"animfm": "animation-fill-mode:${1:both};",
|
||||
"animfm:f": "animation-fill-mode:forwards;",
|
||||
"animfm:b": "animation-fill-mode:backwards;",
|
||||
"animfm:bt": "animation-fill-mode:both;",
|
||||
"animfm:bh": "animation-fill-mode:both;",
|
||||
|
||||
"animic": "animation-iteration-count:${1:1};",
|
||||
"animic:i": "animation-iteration-count:infinite;",
|
||||
|
||||
"animn": "animation-name:${1:none};",
|
||||
|
||||
"animps": "animation-play-state:${1:running};",
|
||||
"animps:p": "animation-play-state:paused;",
|
||||
"animps:r": "animation-play-state:running;",
|
||||
|
||||
"animtf": "animation-timing-function:${1:linear};",
|
||||
"animtf:e": "animation-timing-function:ease;",
|
||||
"animtf:ei": "animation-timing-function:ease-in;",
|
||||
"animtf:eo": "animation-timing-function:ease-out;",
|
||||
"animtf:eio": "animation-timing-function:ease-in-out;",
|
||||
"animtf:l": "animation-timing-function:linear;",
|
||||
"animtf:cb": "animation-timing-function:cubic-bezier(${1:0.1}, ${2:0.7}, ${3:1.0}, ${3:0.1});",
|
||||
|
||||
"ap": "appearance:${none};",
|
||||
|
||||
"!": "!important",
|
||||
"pos": "position:${1:relative};",
|
||||
"pos:s": "position:static;",
|
||||
"pos:a": "position:absolute;",
|
||||
"pos:r": "position:relative;",
|
||||
"pos:f": "position:fixed;",
|
||||
"t": "top:|;",
|
||||
"t:a": "top:auto;",
|
||||
"r": "right:|;",
|
||||
"r:a": "right:auto;",
|
||||
"b": "bottom:|;",
|
||||
"b:a": "bottom:auto;",
|
||||
"l": "left:|;",
|
||||
"l:a": "left:auto;",
|
||||
"z": "z-index:|;",
|
||||
"z:a": "z-index:auto;",
|
||||
"fl": "float:${1:left};",
|
||||
"fl:n": "float:none;",
|
||||
"fl:l": "float:left;",
|
||||
"fl:r": "float:right;",
|
||||
"cl": "clear:${1:both};",
|
||||
"cl:n": "clear:none;",
|
||||
"cl:l": "clear:left;",
|
||||
"cl:r": "clear:right;",
|
||||
"cl:b": "clear:both;",
|
||||
|
||||
"colm": "columns:|;",
|
||||
"colmc": "column-count:|;",
|
||||
"colmf": "column-fill:|;",
|
||||
"colmg": "column-gap:|;",
|
||||
"colmr": "column-rule:|;",
|
||||
"colmrc": "column-rule-color:|;",
|
||||
"colmrs": "column-rule-style:|;",
|
||||
"colmrw": "column-rule-width:|;",
|
||||
"colms": "column-span:|;",
|
||||
"colmw": "column-width:|;",
|
||||
|
||||
"d": "display:${1:block};",
|
||||
"d:n": "display:none;",
|
||||
"d:b": "display:block;",
|
||||
"d:i": "display:inline;",
|
||||
"d:ib": "display:inline-block;",
|
||||
"d:li": "display:list-item;",
|
||||
"d:ri": "display:run-in;",
|
||||
"d:cp": "display:compact;",
|
||||
"d:tb": "display:table;",
|
||||
"d:itb": "display:inline-table;",
|
||||
"d:tbcp": "display:table-caption;",
|
||||
"d:tbcl": "display:table-column;",
|
||||
"d:tbclg": "display:table-column-group;",
|
||||
"d:tbhg": "display:table-header-group;",
|
||||
"d:tbfg": "display:table-footer-group;",
|
||||
"d:tbr": "display:table-row;",
|
||||
"d:tbrg": "display:table-row-group;",
|
||||
"d:tbc": "display:table-cell;",
|
||||
"d:rb": "display:ruby;",
|
||||
"d:rbb": "display:ruby-base;",
|
||||
"d:rbbg": "display:ruby-base-group;",
|
||||
"d:rbt": "display:ruby-text;",
|
||||
"d:rbtg": "display:ruby-text-group;",
|
||||
"v": "visibility:${1:hidden};",
|
||||
"v:v": "visibility:visible;",
|
||||
"v:h": "visibility:hidden;",
|
||||
"v:c": "visibility:collapse;",
|
||||
"ov": "overflow:${1:hidden};",
|
||||
"ov:v": "overflow:visible;",
|
||||
"ov:h": "overflow:hidden;",
|
||||
"ov:s": "overflow:scroll;",
|
||||
"ov:a": "overflow:auto;",
|
||||
"ovx": "overflow-x:${1:hidden};",
|
||||
"ovx:v": "overflow-x:visible;",
|
||||
"ovx:h": "overflow-x:hidden;",
|
||||
"ovx:s": "overflow-x:scroll;",
|
||||
"ovx:a": "overflow-x:auto;",
|
||||
"ovy": "overflow-y:${1:hidden};",
|
||||
"ovy:v": "overflow-y:visible;",
|
||||
"ovy:h": "overflow-y:hidden;",
|
||||
"ovy:s": "overflow-y:scroll;",
|
||||
"ovy:a": "overflow-y:auto;",
|
||||
"ovs": "overflow-style:${1:scrollbar};",
|
||||
"ovs:a": "overflow-style:auto;",
|
||||
"ovs:s": "overflow-style:scrollbar;",
|
||||
"ovs:p": "overflow-style:panner;",
|
||||
"ovs:m": "overflow-style:move;",
|
||||
"ovs:mq": "overflow-style:marquee;",
|
||||
"zoo": "zoom:1;",
|
||||
"zm": "zoom:1;",
|
||||
"cp": "clip:|;",
|
||||
"cp:a": "clip:auto;",
|
||||
"cp:r": "clip:rect(${1:top} ${2:right} ${3:bottom} ${4:left});",
|
||||
"bxz": "box-sizing:${1:border-box};",
|
||||
"bxz:cb": "box-sizing:content-box;",
|
||||
"bxz:bb": "box-sizing:border-box;",
|
||||
"bxsh": "box-shadow:${1:inset }${2:hoff} ${3:voff} ${4:blur} ${5:color};",
|
||||
"bxsh:r": "box-shadow:${1:inset }${2:hoff} ${3:voff} ${4:blur} ${5:spread }rgb(${6:0}, ${7:0}, ${8:0});",
|
||||
"bxsh:ra": "box-shadow:${1:inset }${2:h} ${3:v} ${4:blur} ${5:spread }rgba(${6:0}, ${7:0}, ${8:0}, .${9:5});",
|
||||
"bxsh:n": "box-shadow:none;",
|
||||
"m": "margin:|;",
|
||||
"m:a": "margin:auto;",
|
||||
"mt": "margin-top:|;",
|
||||
"mt:a": "margin-top:auto;",
|
||||
"mr": "margin-right:|;",
|
||||
"mr:a": "margin-right:auto;",
|
||||
"mb": "margin-bottom:|;",
|
||||
"mb:a": "margin-bottom:auto;",
|
||||
"ml": "margin-left:|;",
|
||||
"ml:a": "margin-left:auto;",
|
||||
"p": "padding:|;",
|
||||
"pt": "padding-top:|;",
|
||||
"pr": "padding-right:|;",
|
||||
"pb": "padding-bottom:|;",
|
||||
"pl": "padding-left:|;",
|
||||
"w": "width:|;",
|
||||
"w:a": "width:auto;",
|
||||
"h": "height:|;",
|
||||
"h:a": "height:auto;",
|
||||
"maw": "max-width:|;",
|
||||
"maw:n": "max-width:none;",
|
||||
"mah": "max-height:|;",
|
||||
"mah:n": "max-height:none;",
|
||||
"miw": "min-width:|;",
|
||||
"mih": "min-height:|;",
|
||||
"mar": "max-resolution:${1:res};",
|
||||
"mir": "min-resolution:${1:res};",
|
||||
"ori": "orientation:|;",
|
||||
"ori:l": "orientation:landscape;",
|
||||
"ori:p": "orientation:portrait;",
|
||||
"ol": "outline:|;",
|
||||
"ol:n": "outline:none;",
|
||||
"olo": "outline-offset:|;",
|
||||
"olw": "outline-width:|;",
|
||||
"ols": "outline-style:|;",
|
||||
"olc": "outline-color:#${1:000};",
|
||||
"olc:i": "outline-color:invert;",
|
||||
"bd": "border:|;",
|
||||
"bd+": "border:${1:1px} ${2:solid} ${3:#000};",
|
||||
"bd:n": "border:none;",
|
||||
"bdbk": "border-break:${1:close};",
|
||||
"bdbk:c": "border-break:close;",
|
||||
"bdcl": "border-collapse:|;",
|
||||
"bdcl:c": "border-collapse:collapse;",
|
||||
"bdcl:s": "border-collapse:separate;",
|
||||
"bdc": "border-color:#${1:000};",
|
||||
"bdc:t": "border-color:transparent;",
|
||||
"bdi": "border-image:url(|);",
|
||||
"bdi:n": "border-image:none;",
|
||||
"bdti": "border-top-image:url(|);",
|
||||
"bdti:n": "border-top-image:none;",
|
||||
"bdri": "border-right-image:url(|);",
|
||||
"bdri:n": "border-right-image:none;",
|
||||
"bdbi": "border-bottom-image:url(|);",
|
||||
"bdbi:n": "border-bottom-image:none;",
|
||||
"bdli": "border-left-image:url(|);",
|
||||
"bdli:n": "border-left-image:none;",
|
||||
"bdci": "border-corner-image:url(|);",
|
||||
"bdci:n": "border-corner-image:none;",
|
||||
"bdci:c": "border-corner-image:continue;",
|
||||
"bdtli": "border-top-left-image:url(|);",
|
||||
"bdtli:n": "border-top-left-image:none;",
|
||||
"bdtli:c": "border-top-left-image:continue;",
|
||||
"bdtri": "border-top-right-image:url(|);",
|
||||
"bdtri:n": "border-top-right-image:none;",
|
||||
"bdtri:c": "border-top-right-image:continue;",
|
||||
"bdbri": "border-bottom-right-image:url(|);",
|
||||
"bdbri:n": "border-bottom-right-image:none;",
|
||||
"bdbri:c": "border-bottom-right-image:continue;",
|
||||
"bdbli": "border-bottom-left-image:url(|);",
|
||||
"bdbli:n": "border-bottom-left-image:none;",
|
||||
"bdbli:c": "border-bottom-left-image:continue;",
|
||||
"bdf": "border-fit:${1:repeat};",
|
||||
"bdf:c": "border-fit:clip;",
|
||||
"bdf:r": "border-fit:repeat;",
|
||||
"bdf:sc": "border-fit:scale;",
|
||||
"bdf:st": "border-fit:stretch;",
|
||||
"bdf:ow": "border-fit:overwrite;",
|
||||
"bdf:of": "border-fit:overflow;",
|
||||
"bdf:sp": "border-fit:space;",
|
||||
"bdlen": "border-length:|;",
|
||||
"bdlen:a": "border-length:auto;",
|
||||
"bdsp": "border-spacing:|;",
|
||||
"bds": "border-style:|;",
|
||||
"bds:n": "border-style:none;",
|
||||
"bds:h": "border-style:hidden;",
|
||||
"bds:dt": "border-style:dotted;",
|
||||
"bds:ds": "border-style:dashed;",
|
||||
"bds:s": "border-style:solid;",
|
||||
"bds:db": "border-style:double;",
|
||||
"bds:dtds": "border-style:dot-dash;",
|
||||
"bds:dtdtds": "border-style:dot-dot-dash;",
|
||||
"bds:w": "border-style:wave;",
|
||||
"bds:g": "border-style:groove;",
|
||||
"bds:r": "border-style:ridge;",
|
||||
"bds:i": "border-style:inset;",
|
||||
"bds:o": "border-style:outset;",
|
||||
"bdw": "border-width:|;",
|
||||
"bdtw": "border-top-width:|;",
|
||||
"bdrw": "border-right-width:|;",
|
||||
"bdbw": "border-bottom-width:|;",
|
||||
"bdlw": "border-left-width:|;",
|
||||
"bdt": "border-top:|;",
|
||||
"bt": "border-top:|;",
|
||||
"bdt+": "border-top:${1:1px} ${2:solid} ${3:#000};",
|
||||
"bdt:n": "border-top:none;",
|
||||
"bdts": "border-top-style:|;",
|
||||
"bdts:n": "border-top-style:none;",
|
||||
"bdtc": "border-top-color:#${1:000};",
|
||||
"bdtc:t": "border-top-color:transparent;",
|
||||
"bdr": "border-right:|;",
|
||||
"br": "border-right:|;",
|
||||
"bdr+": "border-right:${1:1px} ${2:solid} ${3:#000};",
|
||||
"bdr:n": "border-right:none;",
|
||||
"bdrst": "border-right-style:|;",
|
||||
"bdrst:n": "border-right-style:none;",
|
||||
"bdrc": "border-right-color:#${1:000};",
|
||||
"bdrc:t": "border-right-color:transparent;",
|
||||
"bdb": "border-bottom:|;",
|
||||
"bb": "border-bottom:|;",
|
||||
"bdb+": "border-bottom:${1:1px} ${2:solid} ${3:#000};",
|
||||
"bdb:n": "border-bottom:none;",
|
||||
"bdbs": "border-bottom-style:|;",
|
||||
"bdbs:n": "border-bottom-style:none;",
|
||||
"bdbc": "border-bottom-color:#${1:000};",
|
||||
"bdbc:t": "border-bottom-color:transparent;",
|
||||
"bdl": "border-left:|;",
|
||||
"bl": "border-left:|;",
|
||||
"bdl+": "border-left:${1:1px} ${2:solid} ${3:#000};",
|
||||
"bdl:n": "border-left:none;",
|
||||
"bdls": "border-left-style:|;",
|
||||
"bdls:n": "border-left-style:none;",
|
||||
"bdlc": "border-left-color:#${1:000};",
|
||||
"bdlc:t": "border-left-color:transparent;",
|
||||
"bdrs": "border-radius:|;",
|
||||
"bdtrrs": "border-top-right-radius:|;",
|
||||
"bdtlrs": "border-top-left-radius:|;",
|
||||
"bdbrrs": "border-bottom-right-radius:|;",
|
||||
"bdblrs": "border-bottom-left-radius:|;",
|
||||
"bg": "background:|;",
|
||||
"bg+": "background:${1:#fff} url(${2}) ${3:0} ${4:0} ${5:no-repeat};",
|
||||
"bg:n": "background:none;",
|
||||
"bg:ie": "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${1:x}.png',sizingMethod='${2:crop}');",
|
||||
"bgc": "background-color:#${1:fff};",
|
||||
"bgc:t": "background-color:transparent;",
|
||||
"bgi": "background-image:url(|);",
|
||||
"bgi:n": "background-image:none;",
|
||||
"bgr": "background-repeat:|;",
|
||||
"bgr:n": "background-repeat:no-repeat;",
|
||||
"bgr:x": "background-repeat:repeat-x;",
|
||||
"bgr:y": "background-repeat:repeat-y;",
|
||||
"bgr:sp": "background-repeat:space;",
|
||||
"bgr:rd": "background-repeat:round;",
|
||||
"bga": "background-attachment:|;",
|
||||
"bga:f": "background-attachment:fixed;",
|
||||
"bga:s": "background-attachment:scroll;",
|
||||
"bgp": "background-position:${1:0} ${2:0};",
|
||||
"bgpx": "background-position-x:|;",
|
||||
"bgpy": "background-position-y:|;",
|
||||
"bgbk": "background-break:|;",
|
||||
"bgbk:bb": "background-break:bounding-box;",
|
||||
"bgbk:eb": "background-break:each-box;",
|
||||
"bgbk:c": "background-break:continuous;",
|
||||
"bgcp": "background-clip:${1:padding-box};",
|
||||
"bgcp:bb": "background-clip:border-box;",
|
||||
"bgcp:pb": "background-clip:padding-box;",
|
||||
"bgcp:cb": "background-clip:content-box;",
|
||||
"bgcp:nc": "background-clip:no-clip;",
|
||||
"bgo": "background-origin:|;",
|
||||
"bgo:pb": "background-origin:padding-box;",
|
||||
"bgo:bb": "background-origin:border-box;",
|
||||
"bgo:cb": "background-origin:content-box;",
|
||||
"bgsz": "background-size:|;",
|
||||
"bgsz:a": "background-size:auto;",
|
||||
"bgsz:ct": "background-size:contain;",
|
||||
"bgsz:cv": "background-size:cover;",
|
||||
"c": "color:#${1:000};",
|
||||
"c:r": "color:rgb(${1:0}, ${2:0}, ${3:0});",
|
||||
"c:ra": "color:rgba(${1:0}, ${2:0}, ${3:0}, .${4:5});",
|
||||
"cm": "/* |${child} */",
|
||||
"cnt": "content:'|';",
|
||||
"cnt:n": "content:normal;",
|
||||
"cnt:oq": "content:open-quote;",
|
||||
"cnt:noq": "content:no-open-quote;",
|
||||
"cnt:cq": "content:close-quote;",
|
||||
"cnt:ncq": "content:no-close-quote;",
|
||||
"cnt:a": "content:attr(|);",
|
||||
"cnt:c": "content:counter(|);",
|
||||
"cnt:cs": "content:counters(|);",
|
||||
|
||||
|
||||
"tbl": "table-layout:|;",
|
||||
"tbl:a": "table-layout:auto;",
|
||||
"tbl:f": "table-layout:fixed;",
|
||||
"cps": "caption-side:|;",
|
||||
"cps:t": "caption-side:top;",
|
||||
"cps:b": "caption-side:bottom;",
|
||||
"ec": "empty-cells:|;",
|
||||
"ec:s": "empty-cells:show;",
|
||||
"ec:h": "empty-cells:hide;",
|
||||
"lis": "list-style:|;",
|
||||
"lis:n": "list-style:none;",
|
||||
"lisp": "list-style-position:|;",
|
||||
"lisp:i": "list-style-position:inside;",
|
||||
"lisp:o": "list-style-position:outside;",
|
||||
"list": "list-style-type:|;",
|
||||
"list:n": "list-style-type:none;",
|
||||
"list:d": "list-style-type:disc;",
|
||||
"list:c": "list-style-type:circle;",
|
||||
"list:s": "list-style-type:square;",
|
||||
"list:dc": "list-style-type:decimal;",
|
||||
"list:dclz": "list-style-type:decimal-leading-zero;",
|
||||
"list:lr": "list-style-type:lower-roman;",
|
||||
"list:ur": "list-style-type:upper-roman;",
|
||||
"lisi": "list-style-image:|;",
|
||||
"lisi:n": "list-style-image:none;",
|
||||
"q": "quotes:|;",
|
||||
"q:n": "quotes:none;",
|
||||
"q:ru": "quotes:'\\00AB' '\\00BB' '\\201E' '\\201C';",
|
||||
"q:en": "quotes:'\\201C' '\\201D' '\\2018' '\\2019';",
|
||||
"ct": "content:|;",
|
||||
"ct:n": "content:normal;",
|
||||
"ct:oq": "content:open-quote;",
|
||||
"ct:noq": "content:no-open-quote;",
|
||||
"ct:cq": "content:close-quote;",
|
||||
"ct:ncq": "content:no-close-quote;",
|
||||
"ct:a": "content:attr(|);",
|
||||
"ct:c": "content:counter(|);",
|
||||
"ct:cs": "content:counters(|);",
|
||||
"coi": "counter-increment:|;",
|
||||
"cor": "counter-reset:|;",
|
||||
"va": "vertical-align:${1:top};",
|
||||
"va:sup": "vertical-align:super;",
|
||||
"va:t": "vertical-align:top;",
|
||||
"va:tt": "vertical-align:text-top;",
|
||||
"va:m": "vertical-align:middle;",
|
||||
"va:bl": "vertical-align:baseline;",
|
||||
"va:b": "vertical-align:bottom;",
|
||||
"va:tb": "vertical-align:text-bottom;",
|
||||
"va:sub": "vertical-align:sub;",
|
||||
"ta": "text-align:${1:left};",
|
||||
"ta:l": "text-align:left;",
|
||||
"ta:c": "text-align:center;",
|
||||
"ta:r": "text-align:right;",
|
||||
"ta:j": "text-align:justify;",
|
||||
"ta-lst": "text-align-last:|;",
|
||||
"tal:a": "text-align-last:auto;",
|
||||
"tal:l": "text-align-last:left;",
|
||||
"tal:c": "text-align-last:center;",
|
||||
"tal:r": "text-align-last:right;",
|
||||
"td": "text-decoration:${1:none};",
|
||||
"td:n": "text-decoration:none;",
|
||||
"td:u": "text-decoration:underline;",
|
||||
"td:o": "text-decoration:overline;",
|
||||
"td:l": "text-decoration:line-through;",
|
||||
"te": "text-emphasis:|;",
|
||||
"te:n": "text-emphasis:none;",
|
||||
"te:ac": "text-emphasis:accent;",
|
||||
"te:dt": "text-emphasis:dot;",
|
||||
"te:c": "text-emphasis:circle;",
|
||||
"te:ds": "text-emphasis:disc;",
|
||||
"te:b": "text-emphasis:before;",
|
||||
"te:a": "text-emphasis:after;",
|
||||
"th": "text-height:|;",
|
||||
"th:a": "text-height:auto;",
|
||||
"th:f": "text-height:font-size;",
|
||||
"th:t": "text-height:text-size;",
|
||||
"th:m": "text-height:max-size;",
|
||||
"ti": "text-indent:|;",
|
||||
"ti:-": "text-indent:-9999px;",
|
||||
"tj": "text-justify:|;",
|
||||
"tj:a": "text-justify:auto;",
|
||||
"tj:iw": "text-justify:inter-word;",
|
||||
"tj:ii": "text-justify:inter-ideograph;",
|
||||
"tj:ic": "text-justify:inter-cluster;",
|
||||
"tj:d": "text-justify:distribute;",
|
||||
"tj:k": "text-justify:kashida;",
|
||||
"tj:t": "text-justify:tibetan;",
|
||||
"tov": "text-overflow:${ellipsis};",
|
||||
"tov:e": "text-overflow:ellipsis;",
|
||||
"tov:c": "text-overflow:clip;",
|
||||
"to": "text-outline:|;",
|
||||
"to+": "text-outline:${1:0} ${2:0} ${3:#000};",
|
||||
"to:n": "text-outline:none;",
|
||||
"tr": "text-replace:|;",
|
||||
"tr:n": "text-replace:none;",
|
||||
"tt": "text-transform:${1:uppercase};",
|
||||
"tt:n": "text-transform:none;",
|
||||
"tt:c": "text-transform:capitalize;",
|
||||
"tt:u": "text-transform:uppercase;",
|
||||
"tt:l": "text-transform:lowercase;",
|
||||
"tw": "text-wrap:|;",
|
||||
"tw:n": "text-wrap:normal;",
|
||||
"tw:no": "text-wrap:none;",
|
||||
"tw:u": "text-wrap:unrestricted;",
|
||||
"tw:s": "text-wrap:suppress;",
|
||||
"tsh": "text-shadow:${1:hoff} ${2:voff} ${3:blur} ${4:#000};",
|
||||
"tsh:r": "text-shadow:${1:h} ${2:v} ${3:blur} rgb(${4:0}, ${5:0}, ${6:0});",
|
||||
"tsh:ra": "text-shadow:${1:h} ${2:v} ${3:blur} rgba(${4:0}, ${5:0}, ${6:0}, .${7:5});",
|
||||
"tsh+": "text-shadow:${1:0} ${2:0} ${3:0} ${4:#000};",
|
||||
"tsh:n": "text-shadow:none;",
|
||||
"trf": "transform:|;",
|
||||
"trf:skx": "transform: skewX(${1:angle});",
|
||||
"trf:sky": "transform: skewY(${1:angle});",
|
||||
"trf:sc": "transform: scale(${1:x}, ${2:y});",
|
||||
"trf:scx": "transform: scaleX(${1:x});",
|
||||
"trf:scy": "transform: scaleY(${1:y});",
|
||||
"trf:r": "transform: rotate(${1:angle});",
|
||||
"trf:t": "transform: translate(${1:x}, ${2:y});",
|
||||
"trf:tx": "transform: translateX(${1:x});",
|
||||
"trf:ty": "transform: translateY(${1:y});",
|
||||
"trfo": "transform-origin:|;",
|
||||
"trfs": "transform-style:${1:preserve-3d};",
|
||||
"trs": "transition:${1:prop} ${2:time};",
|
||||
"trsde": "transition-delay:${1:time};",
|
||||
"trsdu": "transition-duration:${1:time};",
|
||||
"trsp": "transition-property:${1:prop};",
|
||||
"trstf": "transition-timing-function:${1:tfunc};",
|
||||
"lh": "line-height:|;",
|
||||
"whs": "white-space:|;",
|
||||
"whs:n": "white-space:normal;",
|
||||
"whs:p": "white-space:pre;",
|
||||
"whs:nw": "white-space:nowrap;",
|
||||
"whs:pw": "white-space:pre-wrap;",
|
||||
"whs:pl": "white-space:pre-line;",
|
||||
"whsc": "white-space-collapse:|;",
|
||||
"whsc:n": "white-space-collapse:normal;",
|
||||
"whsc:k": "white-space-collapse:keep-all;",
|
||||
"whsc:l": "white-space-collapse:loose;",
|
||||
"whsc:bs": "white-space-collapse:break-strict;",
|
||||
"whsc:ba": "white-space-collapse:break-all;",
|
||||
"wob": "word-break:|;",
|
||||
"wob:n": "word-break:normal;",
|
||||
"wob:k": "word-break:keep-all;",
|
||||
"wob:l": "word-break:loose;",
|
||||
"wob:bs": "word-break:break-strict;",
|
||||
"wob:ba": "word-break:break-all;",
|
||||
"wos": "word-spacing:|;",
|
||||
"wow": "word-wrap:|;",
|
||||
"wow:nm": "word-wrap:normal;",
|
||||
"wow:n": "word-wrap:none;",
|
||||
"wow:u": "word-wrap:unrestricted;",
|
||||
"wow:s": "word-wrap:suppress;",
|
||||
"lts": "letter-spacing:|;",
|
||||
"f": "font:|;",
|
||||
"f+": "font:${1:1em} ${2:Arial,sans-serif};",
|
||||
"fw": "font-weight:|;",
|
||||
"fw:n": "font-weight:normal;",
|
||||
"fw:b": "font-weight:bold;",
|
||||
"fw:br": "font-weight:bolder;",
|
||||
"fw:lr": "font-weight:lighter;",
|
||||
"fs": "font-style:${italic};",
|
||||
"fs:n": "font-style:normal;",
|
||||
"fs:i": "font-style:italic;",
|
||||
"fs:o": "font-style:oblique;",
|
||||
"fv": "font-variant:|;",
|
||||
"fv:n": "font-variant:normal;",
|
||||
"fv:sc": "font-variant:small-caps;",
|
||||
"fz": "font-size:|;",
|
||||
"fza": "font-size-adjust:|;",
|
||||
"fza:n": "font-size-adjust:none;",
|
||||
"ff": "font-family:|;",
|
||||
"ff:s": "font-family:serif;",
|
||||
"ff:ss": "font-family:sans-serif;",
|
||||
"ff:c": "font-family:cursive;",
|
||||
"ff:f": "font-family:fantasy;",
|
||||
"ff:m": "font-family:monospace;",
|
||||
"fef": "font-effect:|;",
|
||||
"fef:n": "font-effect:none;",
|
||||
"fef:eg": "font-effect:engrave;",
|
||||
"fef:eb": "font-effect:emboss;",
|
||||
"fef:o": "font-effect:outline;",
|
||||
"fem": "font-emphasize:|;",
|
||||
"femp": "font-emphasize-position:|;",
|
||||
"femp:b": "font-emphasize-position:before;",
|
||||
"femp:a": "font-emphasize-position:after;",
|
||||
"fems": "font-emphasize-style:|;",
|
||||
"fems:n": "font-emphasize-style:none;",
|
||||
"fems:ac": "font-emphasize-style:accent;",
|
||||
"fems:dt": "font-emphasize-style:dot;",
|
||||
"fems:c": "font-emphasize-style:circle;",
|
||||
"fems:ds": "font-emphasize-style:disc;",
|
||||
"fsm": "font-smooth:|;",
|
||||
"fsm:a": "font-smooth:auto;",
|
||||
"fsm:n": "font-smooth:never;",
|
||||
"fsm:aw": "font-smooth:always;",
|
||||
"fst": "font-stretch:|;",
|
||||
"fst:n": "font-stretch:normal;",
|
||||
"fst:uc": "font-stretch:ultra-condensed;",
|
||||
"fst:ec": "font-stretch:extra-condensed;",
|
||||
"fst:c": "font-stretch:condensed;",
|
||||
"fst:sc": "font-stretch:semi-condensed;",
|
||||
"fst:se": "font-stretch:semi-expanded;",
|
||||
"fst:e": "font-stretch:expanded;",
|
||||
"fst:ee": "font-stretch:extra-expanded;",
|
||||
"fst:ue": "font-stretch:ultra-expanded;",
|
||||
"op": "opacity:|;",
|
||||
"op:ie": "filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);",
|
||||
"op:ms": "-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=100)';",
|
||||
"rsz": "resize:|;",
|
||||
"rsz:n": "resize:none;",
|
||||
"rsz:b": "resize:both;",
|
||||
"rsz:h": "resize:horizontal;",
|
||||
"rsz:v": "resize:vertical;",
|
||||
"cur": "cursor:${pointer};",
|
||||
"cur:a": "cursor:auto;",
|
||||
"cur:d": "cursor:default;",
|
||||
"cur:c": "cursor:crosshair;",
|
||||
"cur:ha": "cursor:hand;",
|
||||
"cur:he": "cursor:help;",
|
||||
"cur:m": "cursor:move;",
|
||||
"cur:p": "cursor:pointer;",
|
||||
"cur:t": "cursor:text;",
|
||||
"pgbb": "page-break-before:|;",
|
||||
"pgbb:au": "page-break-before:auto;",
|
||||
"pgbb:al": "page-break-before:always;",
|
||||
"pgbb:l": "page-break-before:left;",
|
||||
"pgbb:r": "page-break-before:right;",
|
||||
"pgbi": "page-break-inside:|;",
|
||||
"pgbi:au": "page-break-inside:auto;",
|
||||
"pgbi:av": "page-break-inside:avoid;",
|
||||
"pgba": "page-break-after:|;",
|
||||
"pgba:au": "page-break-after:auto;",
|
||||
"pgba:al": "page-break-after:always;",
|
||||
"pgba:l": "page-break-after:left;",
|
||||
"pgba:r": "page-break-after:right;",
|
||||
"orp": "orphans:|;",
|
||||
"us": "user-select:${none};",
|
||||
"wid": "widows:|;",
|
||||
"wfsm": "-webkit-font-smoothing:${antialiased};",
|
||||
"wfsm:a": "-webkit-font-smoothing:antialiased;",
|
||||
"wfsm:s": "-webkit-font-smoothing:subpixel-antialiased;",
|
||||
"wfsm:sa": "-webkit-font-smoothing:subpixel-antialiased;",
|
||||
"wfsm:n": "-webkit-font-smoothing:none;"
|
||||
}
|
||||
},
|
||||
|
||||
"html": {
|
||||
"filters": "html",
|
||||
"profile": "html",
|
||||
"snippets": {
|
||||
"!!!": "<!doctype html>",
|
||||
"!!!4t": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">",
|
||||
"!!!4s": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">",
|
||||
"!!!xt": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">",
|
||||
"!!!xs": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">",
|
||||
"!!!xxs": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">",
|
||||
|
||||
"c": "<!-- |${child} -->",
|
||||
"cc:ie6": "<!--[if lte IE 6]>\n\t${child}|\n<![endif]-->",
|
||||
"cc:ie": "<!--[if IE]>\n\t${child}|\n<![endif]-->",
|
||||
"cc:noie": "<!--[if !IE]><!-->\n\t${child}|\n<!--<![endif]-->"
|
||||
},
|
||||
|
||||
"abbreviations": {
|
||||
"!": "html:5",
|
||||
"a": "<a href=\"\">",
|
||||
"a:link": "<a href=\"http://|\">",
|
||||
"a:mail": "<a href=\"mailto:|\">",
|
||||
"abbr": "<abbr title=\"\">",
|
||||
"acronym": "<acronym title=\"\">",
|
||||
"base": "<base href=\"\" />",
|
||||
"basefont": "<basefont/>",
|
||||
"br": "<br/>",
|
||||
"frame": "<frame/>",
|
||||
"hr": "<hr/>",
|
||||
"bdo": "<bdo dir=\"\">",
|
||||
"bdo:r": "<bdo dir=\"rtl\">",
|
||||
"bdo:l": "<bdo dir=\"ltr\">",
|
||||
"col": "<col/>",
|
||||
"link": "<link rel=\"stylesheet\" href=\"\" />",
|
||||
"link:css": "<link rel=\"stylesheet\" href=\"${1:style}.css\" />",
|
||||
"link:print": "<link rel=\"stylesheet\" href=\"${1:print}.css\" media=\"print\" />",
|
||||
"link:favicon": "<link rel=\"shortcut icon\" type=\"image/x-icon\" href=\"${1:favicon.ico}\" />",
|
||||
"link:touch": "<link rel=\"apple-touch-icon\" href=\"${1:favicon.png}\" />",
|
||||
"link:rss": "<link rel=\"alternate\" type=\"application/rss+xml\" title=\"RSS\" href=\"${1:rss.xml}\" />",
|
||||
"link:atom": "<link rel=\"alternate\" type=\"application/atom+xml\" title=\"Atom\" href=\"${1:atom.xml}\" />",
|
||||
"meta": "<meta/>",
|
||||
"meta:utf": "<meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\" />",
|
||||
"meta:win": "<meta http-equiv=\"Content-Type\" content=\"text/html;charset=windows-1251\" />",
|
||||
"meta:vp": "<meta name=\"viewport\" content=\"width=${1:device-width}, user-scalable=${2:no}, initial-scale=${3:1.0}, maximum-scale=${4:1.0}, minimum-scale=${5:1.0}\" />",
|
||||
"meta:compat": "<meta http-equiv=\"X-UA-Compatible\" content=\"${1:IE=7}\" />",
|
||||
"style": "<style>",
|
||||
"script": "<script>",
|
||||
"script:src": "<script src=\"\">",
|
||||
"img": "<img src=\"\" alt=\"\" />",
|
||||
"iframe": "<iframe src=\"\" frameborder=\"0\">",
|
||||
"embed": "<embed src=\"\" type=\"\" />",
|
||||
"object": "<object data=\"\" type=\"\">",
|
||||
"param": "<param name=\"\" value=\"\" />",
|
||||
"map": "<map name=\"\">",
|
||||
"area": "<area shape=\"\" coords=\"\" href=\"\" alt=\"\" />",
|
||||
"area:d": "<area shape=\"default\" href=\"\" alt=\"\" />",
|
||||
"area:c": "<area shape=\"circle\" coords=\"\" href=\"\" alt=\"\" />",
|
||||
"area:r": "<area shape=\"rect\" coords=\"\" href=\"\" alt=\"\" />",
|
||||
"area:p": "<area shape=\"poly\" coords=\"\" href=\"\" alt=\"\" />",
|
||||
"form": "<form action=\"\">",
|
||||
"form:get": "<form action=\"\" method=\"get\">",
|
||||
"form:post": "<form action=\"\" method=\"post\">",
|
||||
"label": "<label for=\"\">",
|
||||
"input": "<input type=\"${1:text}\" />",
|
||||
"inp": "<input type=\"${1:text}\" name=\"\" id=\"\" />",
|
||||
"input:hidden": "input[type=hidden name]",
|
||||
"input:h": "input:hidden",
|
||||
"input:text": "inp",
|
||||
"input:t": "inp",
|
||||
"input:search": "inp[type=search]",
|
||||
"input:email": "inp[type=email]",
|
||||
"input:url": "inp[type=url]",
|
||||
"input:password": "inp[type=password]",
|
||||
"input:p": "input:password",
|
||||
"input:datetime": "inp[type=datetime]",
|
||||
"input:date": "inp[type=date]",
|
||||
"input:datetime-local": "inp[type=datetime-local]",
|
||||
"input:month": "inp[type=month]",
|
||||
"input:week": "inp[type=week]",
|
||||
"input:time": "inp[type=time]",
|
||||
"input:number": "inp[type=number]",
|
||||
"input:color": "inp[type=color]",
|
||||
"input:checkbox": "inp[type=checkbox]",
|
||||
"input:c": "input:checkbox",
|
||||
"input:radio": "inp[type=radio]",
|
||||
"input:r": "input:radio",
|
||||
"input:range": "inp[type=range]",
|
||||
"input:file": "inp[type=file]",
|
||||
"input:f": "input:file",
|
||||
"input:submit": "<input type=\"submit\" value=\"\" />",
|
||||
"input:s": "input:submit",
|
||||
"input:image": "<input type=\"image\" src=\"\" alt=\"\" />",
|
||||
"input:i": "input:image",
|
||||
"input:button": "<input type=\"button\" value=\"\" />",
|
||||
"input:b": "input:button",
|
||||
"isindex": "<isindex/>",
|
||||
"input:reset": "input:button[type=reset]",
|
||||
"select": "<select name=\"\" id=\"\">",
|
||||
"option": "<option value=\"\">",
|
||||
"textarea": "<textarea name=\"\" id=\"\" cols=\"${1:30}\" rows=\"${2:10}\">",
|
||||
"menu:context": "menu[type=context]>",
|
||||
"menu:c": "menu:context",
|
||||
"menu:toolbar": "menu[type=toolbar]>",
|
||||
"menu:t": "menu:toolbar",
|
||||
"video": "<video src=\"\">",
|
||||
"audio": "<audio src=\"\">",
|
||||
"html:xml": "<html xmlns=\"http://www.w3.org/1999/xhtml\">",
|
||||
"keygen": "<keygen/>",
|
||||
"command": "<command/>",
|
||||
|
||||
"bq": "blockquote",
|
||||
"acr": "acronym",
|
||||
"fig": "figure",
|
||||
"figc": "figcaption",
|
||||
"ifr": "iframe",
|
||||
"emb": "embed",
|
||||
"obj": "object",
|
||||
"src": "source",
|
||||
"cap": "caption",
|
||||
"colg": "colgroup",
|
||||
"fst": "fieldset",
|
||||
"btn": "button",
|
||||
"btn:b": "button[type=button]",
|
||||
"btn:r": "button[type=reset]",
|
||||
"btn:s": "button[type=submit]",
|
||||
"optg": "optgroup",
|
||||
"opt": "option",
|
||||
"tarea": "textarea",
|
||||
"leg": "legend",
|
||||
"sect": "section",
|
||||
"art": "article",
|
||||
"hdr": "header",
|
||||
"ftr": "footer",
|
||||
"adr": "address",
|
||||
"dlg": "dialog",
|
||||
"str": "strong",
|
||||
"prog": "progress",
|
||||
"fset": "fieldset",
|
||||
"datag": "datagrid",
|
||||
"datal": "datalist",
|
||||
"kg": "keygen",
|
||||
"out": "output",
|
||||
"det": "details",
|
||||
"cmd": "command",
|
||||
"doc": "html>(head>meta[charset=UTF-8]+title{${1:Document}})+body",
|
||||
"doc4": "html>(head>meta[http-equiv=\"Content-Type\" content=\"text/html;charset=${charset}\"]+title{${1:Document}})+body",
|
||||
|
||||
"html:4t": "!!!4t+doc4[lang=${lang}]",
|
||||
"html:4s": "!!!4s+doc4[lang=${lang}]",
|
||||
"html:xt": "!!!xt+doc4[xmlns=http://www.w3.org/1999/xhtml xml:lang=${lang}]",
|
||||
"html:xs": "!!!xs+doc4[xmlns=http://www.w3.org/1999/xhtml xml:lang=${lang}]",
|
||||
"html:xxs": "!!!xxs+doc4[xmlns=http://www.w3.org/1999/xhtml xml:lang=${lang}]",
|
||||
"html:5": "!!!+doc[lang=${lang}]",
|
||||
|
||||
"ol+": "ol>li",
|
||||
"ul+": "ul>li",
|
||||
"dl+": "dl>dt+dd",
|
||||
"map+": "map>area",
|
||||
"table+": "table>tr>td",
|
||||
"colgroup+": "colgroup>col",
|
||||
"colg+": "colgroup>col",
|
||||
"tr+": "tr>td",
|
||||
"select+": "select>option",
|
||||
"optgroup+": "optgroup>option",
|
||||
"optg+": "optgroup>option"
|
||||
}
|
||||
},
|
||||
|
||||
"xml": {
|
||||
"extends": "html",
|
||||
"profile": "xml",
|
||||
"filters": "html"
|
||||
},
|
||||
|
||||
"xsl": {
|
||||
"extends": "html",
|
||||
"profile": "xml",
|
||||
"filters": "html, xsl",
|
||||
"abbreviations": {
|
||||
"tm": "<xsl:template match=\"\" mode=\"\">",
|
||||
"tmatch": "tm",
|
||||
"tn": "<xsl:template name=\"\">",
|
||||
"tname": "tn",
|
||||
"call": "<xsl:call-template name=\"\"/>",
|
||||
"ap": "<xsl:apply-templates select=\"\" mode=\"\"/>",
|
||||
"api": "<xsl:apply-imports/>",
|
||||
"imp": "<xsl:import href=\"\"/>",
|
||||
"inc": "<xsl:include href=\"\"/>",
|
||||
|
||||
"ch": "<xsl:choose>",
|
||||
"xsl:when": "<xsl:when test=\"\">",
|
||||
"wh": "xsl:when",
|
||||
"ot": "<xsl:otherwise>",
|
||||
"if": "<xsl:if test=\"\">",
|
||||
|
||||
"par": "<xsl:param name=\"\">",
|
||||
"pare": "<xsl:param name=\"\" select=\"\"/>",
|
||||
"var": "<xsl:variable name=\"\">",
|
||||
"vare": "<xsl:variable name=\"\" select=\"\"/>",
|
||||
"wp": "<xsl:with-param name=\"\" select=\"\"/>",
|
||||
"key": "<xsl:key name=\"\" match=\"\" use=\"\"/>",
|
||||
|
||||
"elem": "<xsl:element name=\"\">",
|
||||
"attr": "<xsl:attribute name=\"\">",
|
||||
"attrs": "<xsl:attribute-set name=\"\">",
|
||||
|
||||
"cp": "<xsl:copy select=\"\"/>",
|
||||
"co": "<xsl:copy-of select=\"\"/>",
|
||||
"val": "<xsl:value-of select=\"\"/>",
|
||||
"each": "<xsl:for-each select=\"\">",
|
||||
"for": "each",
|
||||
"tex": "<xsl:text></xsl:text>",
|
||||
|
||||
"com": "<xsl:comment>",
|
||||
"msg": "<xsl:message terminate=\"no\">",
|
||||
"fall": "<xsl:fallback>",
|
||||
"num": "<xsl:number value=\"\"/>",
|
||||
"nam": "<namespace-alias stylesheet-prefix=\"\" result-prefix=\"\"/>",
|
||||
"pres": "<xsl:preserve-space elements=\"\"/>",
|
||||
"strip": "<xsl:strip-space elements=\"\"/>",
|
||||
"proc": "<xsl:processing-instruction name=\"\">",
|
||||
"sort": "<xsl:sort select=\"\" order=\"\"/>",
|
||||
|
||||
"choose+": "xsl:choose>xsl:when+xsl:otherwise",
|
||||
"xsl": "!!!+xsl:stylesheet[version=1.0 xmlns:xsl=http://www.w3.org/1999/XSL/Transform]>{\n|}"
|
||||
},
|
||||
"snippets": {
|
||||
"!!!": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||||
}
|
||||
},
|
||||
|
||||
"haml": {
|
||||
"filters": "haml",
|
||||
"extends": "html",
|
||||
"profile": "xml"
|
||||
},
|
||||
|
||||
"scss": {
|
||||
"extends": "css"
|
||||
},
|
||||
|
||||
"sass": {
|
||||
"extends": "css"
|
||||
},
|
||||
|
||||
"less": {
|
||||
"extends": "css"
|
||||
},
|
||||
|
||||
"stylus": {
|
||||
"extends": "css"
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user