diff --git a/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/.editorconfig b/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/.editorconfig new file mode 100644 index 0000000..b722c2e --- /dev/null +++ b/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/.editorconfig @@ -0,0 +1,9 @@ +# editorconfig.org +root = true + +[*] +indent_style = tab +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/.gitattributes b/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/.gitattributes new file mode 100644 index 0000000..176a458 --- /dev/null +++ b/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/.gitattributes @@ -0,0 +1 @@ +* text=auto diff --git a/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/EditorConfig.py b/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/EditorConfig.py new file mode 100644 index 0000000..54d2ae7 --- /dev/null +++ b/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/EditorConfig.py @@ -0,0 +1,71 @@ +import sublime_plugin +from editorconfig import get_properties, EditorConfigError + + +LINE_ENDINGS = { + 'lf': 'unix', + 'crlf': 'windows', + 'cr': 'cr' +} + +CHARSETS = { + 'latin1': 'Western (ISO 8859-1)', + 'utf-8': 'utf-8', + 'utf-8-bom': 'utf-8 with bom', + 'utf-16be': 'utf-16 be', + 'utf-16le': 'utf-16 le' +} + +class EditorConfig(sublime_plugin.EventListener): + def on_load(self, view): + self.init(view, False) + + def on_pre_save(self, view): + self.init(view, True) + + def init(self, view, pre_save): + path = view.file_name() + if not path: + return + try: + config = get_properties(path) + except EditorConfigError: + print 'Error occurred while getting EditorConfig properties' + else: + if config: + if pre_save: + self.apply_charset(view, config) + else: + self.apply_config(view, config) + + def apply_charset(self, view, config): + charset = config.get('charset') + if charset in CHARSETS: + view.set_encoding(CHARSETS[charset]) + + def apply_config(self, view, config): + settings = view.settings() + indent_style = config.get('indent_style') + indent_size = config.get('indent_size') + end_of_line = config.get('end_of_line') + trim_trailing_whitespace = config.get('trim_trailing_whitespace') + insert_final_newline = config.get('insert_final_newline') + if indent_style == 'space': + settings.set('translate_tabs_to_spaces', True) + elif indent_style == 'tab': + settings.set('translate_tabs_to_spaces', False) + if indent_size: + try: + settings.set('tab_size', int(indent_size)) + except ValueError: + pass + if end_of_line in LINE_ENDINGS: + view.set_line_endings(LINE_ENDINGS[end_of_line]) + if trim_trailing_whitespace == 'true': + settings.set('trim_trailing_white_space_on_save', True) + elif trim_trailing_whitespace == 'false': + settings.set('trim_trailing_white_space_on_save', False) + if insert_final_newline == 'true': + settings.set('ensure_newline_at_eof_on_save', True) + elif insert_final_newline == 'false': + settings.set('ensure_newline_at_eof_on_save', False) diff --git a/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/editorconfig/__init__.py b/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/editorconfig/__init__.py new file mode 100644 index 0000000..e3a577a --- /dev/null +++ b/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/editorconfig/__init__.py @@ -0,0 +1,19 @@ +"""EditorConfig Python Core""" + +from editorconfig.versiontools import join_version + +VERSION = (0, 11, 1, "final") + +__all__ = ['get_properties', 'EditorConfigError', 'exceptions'] + +__version__ = join_version(VERSION) + + +def get_properties(filename): + """Locate and parse EditorConfig files for the given filename""" + handler = EditorConfigHandler(filename) + return handler.get_configurations() + + +from editorconfig.handler import EditorConfigHandler +from editorconfig.exceptions import * diff --git a/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/editorconfig/compat.py b/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/editorconfig/compat.py new file mode 100644 index 0000000..ebd0405 --- /dev/null +++ b/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/editorconfig/compat.py @@ -0,0 +1,18 @@ +"""EditorConfig Python2/Python3/Jython compatibility utilities""" +import sys +import types + +__all__ = ['slice', 'u'] + + +if sys.version_info[0] == 2: + slice = types.SliceType +else: + slice = slice + + +if sys.version_info[0] == 2: + import codecs + u = lambda s: codecs.unicode_escape_decode(s)[0] +else: + u = lambda s: s diff --git a/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/editorconfig/exceptions.py b/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/editorconfig/exceptions.py new file mode 100644 index 0000000..545732b --- /dev/null +++ b/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/editorconfig/exceptions.py @@ -0,0 +1,27 @@ +"""EditorConfig exception classes + +Licensed under PSF License (see LICENSE.txt file). + +""" + + +class EditorConfigError(Exception): + """Parent class of all exceptions raised by EditorConfig""" + + +try: + from ConfigParser import ParsingError as _ParsingError +except: + from configparser import ParsingError as _ParsingError + + +class ParsingError(_ParsingError, EditorConfigError): + """Error raised if an EditorConfig file could not be parsed""" + + +class PathError(ValueError, EditorConfigError): + """Error raised if invalid filepath is specified""" + + +class VersionError(ValueError, EditorConfigError): + """Error raised if invalid version number is specified""" diff --git a/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/editorconfig/fnmatch.py b/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/editorconfig/fnmatch.py new file mode 100644 index 0000000..a1d5f10 --- /dev/null +++ b/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/editorconfig/fnmatch.py @@ -0,0 +1,126 @@ +"""Filename matching with shell patterns. + +fnmatch(FILENAME, PATTERN) matches according to the local convention. +fnmatchcase(FILENAME, PATTERN) always takes case in account. + +The functions operate by translating the pattern into a regular +expression. They cache the compiled regular expressions for speed. + +The function translate(PATTERN) returns a regular expression +corresponding to PATTERN. (It does not compile it.) + +Based on code from fnmatch.py file distributed with Python 2.6. + +Licensed under PSF License (see LICENSE.txt file). + +Changes to original fnmatch module: +- translate function supports ``*`` and ``**`` similarly to fnmatch C library +""" + +import os +import re + +__all__ = ["fnmatch", "fnmatchcase", "translate"] + +_cache = {} + + +def fnmatch(name, pat): + """Test whether FILENAME matches PATTERN. + + Patterns are Unix shell style: + + - ``*`` matches everything except path separator + - ``**`` matches everything + - ``?`` matches any single character + - ``[seq]`` matches any character in seq + - ``[!seq]`` matches any char not in seq + - ``{s1,s2,s3}`` matches any of the strings given (separated by commas) + + An initial period in FILENAME is not special. + Both FILENAME and PATTERN are first case-normalized + if the operating system requires it. + If you don't want this, use fnmatchcase(FILENAME, PATTERN). + """ + + name = os.path.normcase(name).replace(os.sep, "/") + return fnmatchcase(name, pat) + + +def fnmatchcase(name, pat): + """Test whether FILENAME matches PATTERN, including case. + + This is a version of fnmatch() which doesn't case-normalize + its arguments. + """ + + if not pat in _cache: + res = translate(pat) + _cache[pat] = re.compile(res) + return _cache[pat].match(name) is not None + + +def translate(pat): + """Translate a shell PATTERN to a regular expression. + + There is no way to quote meta-characters. + """ + + i, n = 0, len(pat) + res = '' + escaped = False + while i < n: + c = pat[i] + i = i + 1 + if c == '*': + j = i + if j < n and pat[j] == '*': + res = res + '.*' + else: + res = res + '[^/]*' + elif c == '?': + res = res + '.' + elif c == '[': + j = i + if j < n and pat[j] == '!': + j = j + 1 + if j < n and pat[j] == ']': + j = j + 1 + while j < n and (pat[j] != ']' or escaped): + escaped = pat[j] == '\\' and not escaped + j = j + 1 + if j >= n: + res = res + '\\[' + else: + stuff = pat[i:j] + i = j + 1 + if stuff[0] == '!': + stuff = '^' + stuff[1:] + elif stuff[0] == '^': + stuff = '\\' + stuff + res = '%s[%s]' % (res, stuff) + elif c == '{': + j = i + groups = [] + while j < n and pat[j] != '}': + k = j + while k < n and (pat[k] not in (',', '}') or escaped): + escaped = pat[k] == '\\' and not escaped + k = k + 1 + group = pat[j:k] + for char in (',', '}', '\\'): + group = group.replace('\\' + char, char) + groups.append(group) + j = k + if j < n and pat[j] == ',': + j = j + 1 + if j < n and pat[j] == '}': + groups.append('') + if j >= n or len(groups) < 2: + res = res + '\\{' + else: + res = '%s(%s)' % (res, '|'.join(map(re.escape, groups))) + i = j + 1 + else: + res = res + re.escape(c) + return res + '\Z(?ms)' diff --git a/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/editorconfig/handler.py b/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/editorconfig/handler.py new file mode 100644 index 0000000..6bab2be --- /dev/null +++ b/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/editorconfig/handler.py @@ -0,0 +1,125 @@ +"""EditorConfig file handler + +Provides ``EditorConfigHandler`` class for locating and parsing +EditorConfig files relevant to a given filepath. + +Licensed under PSF License (see LICENSE.txt file). + +""" + +import os + +from editorconfig import VERSION +from editorconfig.ini import EditorConfigParser +from editorconfig.exceptions import PathError, VersionError + + +__all__ = ['EditorConfigHandler'] + + +def get_filenames(path, filename): + """Yield full filepath for filename in each directory in and above path""" + path_list = [] + while True: + path_list.append(os.path.join(path, filename)) + newpath = os.path.dirname(path) + if path == newpath: + break + path = newpath + return path_list + + +class EditorConfigHandler(object): + + """ + Allows locating and parsing of EditorConfig files for given filename + + In addition to the constructor a single public method is provided, + ``get_configurations`` which returns the EditorConfig options for + the ``filepath`` specified to the constructor. + + """ + + def __init__(self, filepath, conf_filename='.editorconfig', version=None): + """Create EditorConfigHandler for matching given filepath""" + self.filepath = filepath + self.conf_filename = conf_filename + self.version = version + self.options = None + + def get_configurations(self): + + """ + Find EditorConfig files and return all options matching filepath + + Special exceptions that may be raised by this function include: + + - ``VersionError``: self.version is invalid EditorConfig version + - ``PathError``: self.filepath is not a valid absolute filepath + - ``ParsingError``: improperly formatted EditorConfig file found + + """ + + self.check_assertions() + path, filename = os.path.split(self.filepath) + conf_files = get_filenames(path, self.conf_filename) + + # Attempt to find and parse every EditorConfig file in filetree + for filename in conf_files: + parser = EditorConfigParser(self.filepath) + parser.read(filename) + + # Merge new EditorConfig file's options into current options + old_options = self.options + self.options = parser.options + if old_options: + self.options.update(old_options) + + # Stop parsing if parsed file has a ``root = true`` option + if parser.root_file: + break + + self.preprocess_values() + return self.options + + def check_assertions(self): + + """Raise error if filepath or version have invalid values""" + + # Raise ``PathError`` if filepath isn't an absolute path + if not os.path.isabs(self.filepath): + raise PathError("Input file must be a full path name.") + + # Raise ``VersionError`` if version specified is greater than current + if self.version is not None and self.version[:3] > VERSION[:3]: + raise VersionError( + "Required version is greater than the current version.") + + def preprocess_values(self): + + """Preprocess option values for consumption by plugins""" + + opts = self.options + + # Lowercase option value for certain options + for name in ["end_of_line", "indent_style", "indent_size", + "insert_final_newline", "trim_trailing_whitespace", "charset"]: + if name in opts: + opts[name] = opts[name].lower() + + # Set indent_size to "tab" if indent_size is unspecified and + # indent_style is set to "tab". + if (opts.get("indent_style") == "tab" and + not "indent_size" in opts and self.version >= VERSION[:3]): + opts["indent_size"] = "tab" + + # Set tab_width to indent_size if indent_size is specified and + # tab_width is unspecified + if ("indent_size" in opts and "tab_width" not in opts and + opts["indent_size"] != "tab"): + opts["tab_width"] = opts["indent_size"] + + # Set indent_size to tab_width if indent_size is "tab" + if ("indent_size" in opts and "tab_width" in opts and + opts["indent_size"] == "tab"): + opts["indent_size"] = opts["tab_width"] diff --git a/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/editorconfig/ini.py b/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/editorconfig/ini.py new file mode 100644 index 0000000..3f58fed --- /dev/null +++ b/EthanBrown.SublimeText2.GitPackages/tools/PackageCache/EditorConfig/editorconfig/ini.py @@ -0,0 +1,150 @@ +"""EditorConfig file parser + +Based on code from ConfigParser.py file distributed with Python 2.6. + +Licensed under PSF License (see LICENSE.txt file). + +Changes to original ConfigParser: + +- Special characters can be used in section names +- Octothorpe can be used for comments (not just at beginning of line) +- Only track INI options in sections that match target filename +- Stop parsing files with when ``root = true`` is found + +""" + +import re +from codecs import open +import posixpath +from os import sep +from os.path import normcase, dirname + +from editorconfig.exceptions import ParsingError +from editorconfig.fnmatch import fnmatch +from editorconfig.odict import OrderedDict +from editorconfig.compat import u + + +__all__ = ["ParsingError", "EditorConfigParser"] + + +class EditorConfigParser(object): + + """Parser for EditorConfig-style configuration files + + Based on RawConfigParser from ConfigParser.py in Python 2.6. + """ + + # Regular expressions for parsing section headers and options. + # Allow ``]`` and escaped ``;`` and ``#`` characters in section headers + SECTCRE = re.compile( + r'\s*\[' # [ + r'(?P
([^#;]|\\#|\\;)+)' # very permissive! + r'\]' # ] + ) + # Regular expression for parsing option name/values. + # Allow any amount of whitespaces, followed by separator + # (either ``:`` or ``=``), followed by any amount of whitespace and then + # any characters to eol + OPTCRE = re.compile( + r'\s*(?P