colorSchemeTool.py (795 lines of code) (raw):
import colorsys
import xml.etree.cElementTree as ET
import plistlib
import os.path
import sys
import re
default_attributes = {}
all_attributes = []
all_colors = {}
IGNORE_COLOR = (None, None, None)
IGNORE_COLOR_VALUE = "#IGNORE_COLOR"
# http://effbot.org/zone/element-lib.htm#prettyprint
def indent(elem, level=0):
i = "\n" + level*" "
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = i + " "
if not elem.tail or not elem.tail.strip():
elem.tail = i
for elem in elem:
indent(elem, level+1)
if not elem.tail or not elem.tail.strip():
elem.tail = i
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
def capitalize_colors(elem):
if len(elem):
for elem in elem:
if elem.get("value") is not None:
elem.set("value", elem.get("value").upper())
capitalize_colors(elem)
def hex_to_rgb(color):
l = len(color)
r = int(color[l-6:l-4], 16) / 256 if l >= 6 else 0
g = int(color[l-4:l-2], 16) / 256 if l >= 4 else 0
b = int(color[l-2:l], 16) / 256
return r, g, b
def hex_to_yiq(color):
return colorsys.rgb_to_yiq(*hex_to_rgb(color))
def rgb256_to_hex(r, g, b):
return "{0:02x}{1:02x}{2:02x}".format(r, g, b)
def rgb_to_hex(r, g, b):
r = min(int(r * 256), 255)
g = min(int(g * 256), 255)
b = min(int(b * 256), 255)
return rgb256_to_hex(r, g, b)
class AttributeValue:
def __init__(self, foreground=None, background=None, foreground_rgb=None, background_rgb=None,
font_style=0, effect_type=0):
if foreground_rgb:
self.foreground = rgb256_to_hex(*foreground_rgb)
else:
self.foreground = foreground
if background_rgb:
self.background = rgb256_to_hex(*background_rgb)
else:
self.background = background
self.font_style = font_style
self.error_stripe = None
self.effect_color = None
self.effect_type = effect_type
self.inherited = False
class DerivedAttributeValue:
def __init__(self, parent=None, default_fore=None, default_back=None, default_font=0, error_stripe=None):
self.parent = parent
self.default_fore = default_fore
self.default_back = default_back
self.default_font = default_font
self.default_effect_color = None
self.error_stripe = error_stripe
self.effect_type = None
@property
def inverted(self):
p = self.parent
while not p.value.background:
p = p.parent
py, pi, pq = hex_to_yiq(p.value.background)
return py < 0.5
@property
def inherited(self):
return self.parent.id != 'TEXT' and isinstance(self.parent.value, AttributeValue)
def transform(self, default_value, add_luma=0.0):
if default_value == IGNORE_COLOR_VALUE:
return IGNORE_COLOR_VALUE
if self.inverted:
dy, di, dq = hex_to_yiq(default_value)
dy = 1 - dy
if dy < 0.5:
dy += add_luma
r, g, b = colorsys.yiq_to_rgb(dy, di, dq)
return rgb_to_hex(r, g, b)
return default_value
@property
def foreground(self):
if self.inherited:
return self.parent.value.foreground
if self.default_fore and self.default_fore != IGNORE_COLOR_VALUE:
return self.transform(self.default_fore)
if self.parent.id != "TEXT":
return self.parent.value.foreground
return None
@property
def background(self):
if self.inherited:
return self.parent.value.background
if self.default_back:
return self.transform(self.default_back, 0 if self.default_fore else 0.15)
if self.parent.id != "TEXT":
return self.parent.value.background
return None
@property
def font_style(self):
return self.parent.value.font_style | self.default_font
@property
def effect_color(self):
if self.inherited:
return self.parent.value.effect_color
if self.default_effect_color:
return self.transform(self.default_effect_color)
if self.parent.id != "TEXT":
return self.parent.value.effect_color
return None
class Attribute:
def __init__(self, id, parent, scope=None, foreground=None, background=None, font_style=0, effect_type=None):
self.id = id
self.parent = parent
self.scope = scope
if id in default_attributes:
self.value = default_attributes[id]
if background == IGNORE_COLOR:
self.value.default_back = IGNORE_COLOR_VALUE
if foreground == IGNORE_COLOR:
self.value.default_fore = IGNORE_COLOR_VALUE
self.value.parent = parent
else:
self.value = DerivedAttributeValue(parent=parent)
if foreground:
self.value.default_fore = rgb256_to_hex(*foreground) if foreground != IGNORE_COLOR else IGNORE_COLOR_VALUE
if background:
self.value.default_back = rgb256_to_hex(*background) if background != IGNORE_COLOR else IGNORE_COLOR_VALUE
if font_style:
self.value.default_font = font_style
if effect_type:
self.value.effect_type = effect_type
all_attributes.append(self)
text = Attribute("TEXT", None)
def load_default_attributes(scheme_path):
scheme = ET.ElementTree(file=scheme_path)
attributes = scheme.findall('.//attributes/option')
for attr in attributes:
name = attr.attrib.get('name')
options = attr.findall('./value/option')
attr_value = DerivedAttributeValue()
for option in options:
option_name = option.attrib.get('name')
option_value = option.attrib.get('value')
if not option_value: continue
if option_name == 'FOREGROUND': attr_value.default_fore = option_value
if option_name == 'BACKGROUND': attr_value.default_back = option_value
if option_name == 'FONT_TYPE': attr_value.default_font = int(option_value)
if option_name == 'ERROR_STRIPE_COLOR': attr_value.error_stripe = option_value
if option_name == 'EFFECT_TYPE': attr_value.effect_type = int(option_value)
if option_name == 'EFFECT_COLOR': attr_value.default_effect_color = option_value
default_attributes[name] = attr_value
load_default_attributes('DefaultColorSchemesManager.xml')
for id in [
"SEARCH_RESULT_ATTRIBUTES", # EditorColors
"WRITE_SEARCH_RESULT_ATTRIBUTES",
"IDENTIFIER_UNDER_CARET_ATTRIBUTES",
"WRITE_IDENTIFIER_UNDER_CARET_ATTRIBUTES",
"TEXT_SEARCH_RESULT_ATTRIBUTES",
"INJECTED_LANGUAGE_FRAGMENT",
"ERRORS_ATTRIBUTES", # CodeInsightColors
"WARNING_ATTRIBUTES",
"GENERIC_SERVER_ERROR_OR_WARNING",
"DUPLICATE_FROM_SERVER",
"INFO_ATTRIBUTES",
"NOT_USED_ELEMENT_ATTRIBUTES",
"DEPRECATED_ATTRIBUTES",
"HYPERLINK_ATTRIBUTES",
"FOLLOWED_HYPERLINK_ATTRIBUTES",
"TODO_DEFAULT_ATTRIBUTES",
"CONSOLE_NORMAL_OUTPUT", # ConsoleViewContentType
"CONSOLE_ERROR_OUTPUT",
"CONSOLE_USER_INPUT",
"CONSOLE_RED_OUTPUT",
"CONSOLE_GREEN_OUTPUT",
"CONSOLE_YELLOW_OUTPUT",
"CONSOLE_BLUE_OUTPUT",
"CONSOLE_MAGENTA_OUTPUT",
"CONSOLE_CYAN_OUTPUT",
"CONSOLE_GRAY_OUTPUT",
"CONSOLE_SYSTEM_OUTPUT",
"CUSTOM_KEYWORD1_ATTRIBUTES", # CustomHighlighterColors
"CUSTOM_KEYWORD2_ATTRIBUTES",
"CUSTOM_KEYWORD3_ATTRIBUTES",
"CUSTOM_KEYWORD4_ATTRIBUTES",
"BREAKPOINT_ATTRIBUTES" # DebuggerColors
]:
Attribute(id, text)
# HighlighterColors
bad_character = Attribute("BAD_CHARACTER", text, scope='invalid')
matched_brace = Attribute("MATCHED_BRACE_ATTRIBUTES", text, background=(153, 204, 255))
unmatched_brace = Attribute("UNMATCHED_BRACE_ATTRIBUTES", text, background=(255, 220, 220))
# DefaultLanguageHighlighterColors (MUST HAVE!)
default_identifier=Attribute("DEFAULT_IDENTIFIER", text, scope='entity')
default_number=Attribute("DEFAULT_NUMBER", text, scope='constant.numeric')
default_keyword=Attribute("DEFAULT_KEYWORD", text, scope='keyword')
default_string=Attribute("DEFAULT_STRING", text, scope='string')
default_block_comment=Attribute("DEFAULT_BLOCK_COMMENT", text, scope='comment.block')
default_line_comment=Attribute("DEFAULT_LINE_COMMENT", text, scope='comment.line')
default_doc_comment=Attribute("DEFAULT_DOC_COMMENT", text, scope='comment.documentation')
default_operation_sign=Attribute("DEFAULT_OPERATION_SIGN", text, scope='keyword.operator')
default_braces=Attribute("DEFAULT_BRACES", text, scope='punctuation')
default_dot=Attribute("DEFAULT_DOT", text, scope='punctuation')
default_semicolon=Attribute("DEFAULT_SEMICOLON", text, scope='punctuation')
default_comma=Attribute("DEFAULT_COMMA", text, scope='punctuation')
default_parentheses=Attribute("DEFAULT_PARENTHS", text, scope='punctuation')
default_brackets=Attribute("DEFAULT_BRACKETS", text, scope='punctuation')
default_label=Attribute("DEFAULT_LABEL", default_identifier)
default_constant=Attribute("DEFAULT_CONSTANT", default_identifier, scope='constant')
default_local_variable=Attribute("DEFAULT_LOCAL_VARIABLE", default_identifier, scope='variable')
default_global_variable=Attribute("DEFAULT_GLOBAL_VARIABLE", default_local_variable, font_style=2)
default_function_declaration=Attribute("DEFAULT_FUNCTION_DECLARATION", default_identifier, scope='entity.name.function')
default_function_call=Attribute("DEFAULT_FUNCTION_CALL", default_identifier, scope='support.function')
default_parameter=Attribute("DEFAULT_PARAMETER", default_identifier, scope='variable.parameter')
default_class_name=Attribute("DEFAULT_CLASS_NAME", default_identifier, scope='entity.name')
default_interface_name=Attribute("DEFAULT_INTERFACE_NAME", default_class_name)
default_instance_method=Attribute("DEFAULT_INSTANCE_METHOD", default_function_declaration)
default_instance_field=Attribute("DEFAULT_INSTANCE_FIELD", default_local_variable)
default_static_method=Attribute("DEFAULT_STATIC_METHOD", default_function_declaration)
default_static_field=Attribute("DEFAULT_STATIC_FIELD", default_global_variable)
default_doc_comment_markup=Attribute("DEFAULT_DOC_MARKUP", default_doc_comment)
default_doc_comment_tag=Attribute("DEFAULT_DOC_COMMENT_TAG", default_doc_comment)
default_valid_string_escape=Attribute("DEFAULT_VALID_STRING_ESCAPE", text, scope='constant.character.escape')
default_invalid_string_escape=Attribute("DEFAULT_INVALID_STRING_ESCAPE", text, scope='invalid')
default_predefined_symbol=Attribute("DEFAULT_PREDEFINED_SYMBOL", default_identifier, scope='support.type')
default_metadata=Attribute("DEFAULT_METADATA", text, scope='meta.tag')
default_markup_tag=Attribute("DEFAULT_TAG", text, scope='punctuation.definition.tag')
default_markup_attribute=Attribute("DEFAULT_ATTRIBUTE", default_identifier, scope='entity.other.attribute-name')
default_markup_entity=Attribute("DEFAULT_ENTITY", default_identifier, scope='constant.character.entity')
default_template_language=Attribute("DEFAULT_TEMPLATE_LANGUAGE_COLOR", text, scope='text source')
# CodeInsightColors (Java)
java_local_variable = Attribute("LOCAL_VARIABLE_ATTRIBUTES", text)
java_implicit_anonymous_class_parameter = Attribute("IMPLICIT_ANONYMOUS_CLASS_PARAMETER_ATTRIBUTES", text)
java_instance_field = Attribute("INSTANCE_FIELD_ATTRIBUTES", text)
java_static_field = Attribute("STATIC_FIELD_ATTRIBUTES", text)
java_static_method = Attribute("STATIC_METHOD_ATTRIBUTES", text)
java_parameter = Attribute("PARAMETER_ATTRIBUTES", text)
java_class_name = Attribute("CLASS_NAME_ATTRIBUTES", text)
# SyntaxHighlighterColors (Java)
java_line_comment = Attribute("JAVA_LINE_COMMENT", text, scope='comment.line')
java_block_comment = Attribute("JAVA_BLOCK_COMMENT", java_line_comment, scope='comment.block')
java_doc_comment = Attribute("JAVA_DOC_COMMENT", java_line_comment, scope='comment.documentation')
java_keyword = Attribute("JAVA_KEYWORD", text, scope='keyword')
java_number = Attribute("JAVA_NUMBER", text, scope='constant.numeric')
java_string = Attribute("JAVA_STRING", text, scope='string')
java_opSign = Attribute("JAVA_OPERATION_SIGN", text, scope='keyword.operator')
java_parenths = Attribute("JAVA_PARENTH", text, scope='punctuation')
java_brackets = Attribute("JAVA_BRACKETS", text, scope='punctuation')
java_braces = Attribute("JAVA_BRACES", text, scope='punctuation')
java_comma = Attribute("JAVA_COMMA", text, scope='punctuation')
java_dot = Attribute("JAVA_DOT", text, scope='punctuation')
java_semicolon = Attribute("JAVA_SEMICOLON", text, scope='punctuation')
java_valid_string_escape = Attribute("JAVA_VALID_STRING_ESCAPE", text, scope='constant.character.escape')
java_invalid_string_escape = Attribute("JAVA_INVALID_STRING_ESCAPE", text, scope='invalid')
java_doc_comment_tag = Attribute("JAVA_DOC_TAG", text)
java_doc_comment_markup = Attribute("JAVA_DOC_MARKUP", text)
# XmlHighlighterColors
xml_prologue = Attribute("XML_PROLOGUE", text)
xml_tag = Attribute("XML_TAG", text, scope='punctuation.definition.tag', background=IGNORE_COLOR)
xml_attribute_name = Attribute("XML_ATTRIBUTE_NAME", text, scope='entity.other.attribute-name.localname.xml')
xml_tag_name = Attribute("XML_TAG_NAME", text, scope='entity.name.tag.xml')
xml_attribute_value = Attribute("XML_ATTRIBUTE_VALUE", text, scope='string.quoted.double')
xml_tag_data = Attribute("XML_TAG_DATA", text)
xml_entity_reference = Attribute("XML_ENTITY_REFERENCE", text, scope='constant.character.entity')
html_comment = Attribute("HTML_COMMENT", default_block_comment, scope='comment.block.html')
html_tag = Attribute("HTML_TAG", xml_tag, scope='punctuation.definition.tag', background=IGNORE_COLOR)
html_tag_name = Attribute("HTML_TAG_NAME", xml_tag_name, scope="entity.name.tag")
html_attribute_name = Attribute("HTML_ATTRIBUTE_NAME", xml_attribute_name, scope="entity.other.attribute-name.html")
html_attribute_value = Attribute("HTML_ATTRIBUTE_VALUE", xml_attribute_value)
html_entity_reference = Attribute("HTML_ENTITY_REFERENCE", xml_entity_reference)
# PyHighlighter
py_keyword = Attribute("PY.KEYWORD", default_keyword, scope="storage.type")
py_string = Attribute("PY.STRING", default_string, 'string.quoted')
py_number = Attribute("PY.NUMBER", default_number)
py_comment = Attribute("PY.LINE_COMMENT", default_line_comment)
py_opSign = Attribute("PY.OPERATION_SIGN", default_operation_sign)
py_parenths = Attribute("PY.PARENTHS", default_parentheses)
py_brackets = Attribute("PY.BRACKETS", default_brackets)
py_braces = Attribute("PY.BRACES", default_braces)
py_comma = Attribute("PY.COMMA", default_comma)
py_dot = Attribute("PY.DOT", default_dot)
py_doc_comment = Attribute("PY.DOC_COMMENT", default_doc_comment)
py_decorator = Attribute("PY.DECORATOR", text, scope='entity.name.function.decorator')
py_class_def = Attribute("PY.CLASS_DEFINITION", text, scope='entity.name.class')
py_func_def = Attribute("PY.FUNC_DEFINITION", text, scope='entity.name.function')
py_predef_def = Attribute("PY.PREDEFINED_DEFINITION", text) # scope???
py_predef_usage = Attribute("PY.PREDEFINED_USAGE", text, scope='support.function')
py_builtin_name = Attribute("PY.BUILTIN_NAME", text, scope='support.function')
py_valid_string_escape = Attribute("PY.VALID_STRING_ESCAPE", default_valid_string_escape)
py_invalid_string_escape = Attribute("PY.INVALID_STRING_ESCAPE", default_invalid_string_escape)
# DjangoTemplateHighlighter
dj_comment = Attribute("DJANGO_COMMENT", html_comment)
dj_tag_name = Attribute("DJANGO_TAG_NAME", xml_tag_name)
dj_id = Attribute("DJANGO_ID", xml_attribute_name)
dj_string_literal = Attribute("DJANGO_STRING_LITERAL", xml_attribute_value)
dj_keyword = Attribute("DJANGO_KEYWORD", default_keyword)
dj_number = Attribute("DJANGO_NUMBER", default_number)
dj_tag_start_end = Attribute("DJANGO_TAG_START_END", default_braces)
dj_filter = Attribute("DJANGO_FILTER", default_braces, scope='support.function')
# Gql
gql_string_literal = Attribute("GQL_STRING_LITERAL", default_string)
gql_keyword = Attribute("GQL_KEYWORD", default_keyword)
gql_int_literal = Attribute("GQL_INT_LITERAL", default_number)
gql_id =Attribute("GQL_ID", default_number)
# BuildoutCfgSyntaxHighlighter
bld_section_name = Attribute("BUILDOUT.SECTION_NAME", default_number)
bld_key = Attribute("BUILDOUT.KEY", default_keyword)
bld_value = Attribute("BUILDOUT.VALUE", default_string)
bld_comment = Attribute("BUILDOUT.LINE_COMMENT", default_line_comment)
bld_separator = Attribute("BUILDOUT.KEY_VALUE_SEPARATOR", default_operation_sign)
# REST
rest_line_comment = Attribute("REST.LINE_COMMENT", default_line_comment)
rest_section_header = Attribute("REST.SECTION.HEADER", default_number)
rest_bold = Attribute("REST.BOLD", text, font_style=1)
rest_italic = Attribute("REST.ITALIC", text, font_style=2)
rest_fixed = Attribute("REST.FIXED", text, background=(217, 217, 240))
rest_interpreted = Attribute("REST.INTERPRETED", text, background=(202, 218, 186))
rest_ref_name = Attribute("REST.REF.NAME", default_string)
rest_explicit = Attribute("REST.EXPLICIT", default_keyword)
rest_field = Attribute("REST.FIELD", default_keyword)
rest_inline = Attribute("REST.INLINE", text, background=(237, 252, 237))
# CSS
css_ident = Attribute("CSS.IDENT", html_tag_name, scope='entity.other.attribute-name.class.css')
css_comment = Attribute("CSS.COMMENT", html_comment, scope='comment.block.css')
css_property_name = Attribute("CSS.PROPERTY_NAME", html_attribute_name, scope='support.type.property-name')
css_property_value = Attribute("CSS.PROPERTY_VALUE", html_attribute_value, scope='meta.property-value.css')
css_tag_name = Attribute("CSS.TAG_NAME", html_tag_name, scope='entity.name.tag.css')
css_number = Attribute("CSS.NUMBER", default_number, scope='constant.numeric.css')
css_function = Attribute("CSS.FUNCTION", html_tag_name, scope='support.function.misc.css')
css_url = Attribute("CSS.URL", html_attribute_value, scope='variable.parameter.misc.css')
# LESS
less_variable = Attribute("LESS_VARIABLE", text, scope='variable.other.less')
less_code_injection_delim = Attribute("LESS_JS_CODE_DELIM", text, scope='source.css.less')
less_code_injection = Attribute("LESS_INJECTED_CODE", text, scope='source.js.embedded.less', foreground=IGNORE_COLOR)
# SASS
sass_identifier = Attribute("SASS_IDENTIFIER", css_ident, scope='entity.other.attribute-name.class.css')
sass_variable = Attribute("SASS_VARIABLE", text, scope='variable.parameter.sass')
sass_string = Attribute("SASS_STRING", default_string, scope='string.quoted.double.css')
sass_extend = Attribute("SASS_EXTEND", default_keyword, scope='keyword.control.at-rule.css')
sass_keyword = Attribute("SASS_KEYWORD", default_keyword, scope='keyword.control.at-rule.css')
sass_important = Attribute("SASS_IMPORTANT", default_keyword, scope='keyword.control.at-rule.css')
sass_default = Attribute("SASS_DEFAULT", default_keyword, scope='keyword.control.at-rule.css')
sass_property_name = Attribute("SASS_PROPERTY_NAME", css_property_name, scope='support.type.property-name.css')
sass_property_value = Attribute("SASS_PROPERTY_VALUE", css_property_value, scope='support.constant.property-value.css')
sass_tag_name = Attribute("SASS_TAG_NAME", css_tag_name, scope='meta.selector.css entity.name.tag')
sass_function = Attribute("SASS_FUNCTION", css_function, scope='support.constant.property-value.css')
sass_url = Attribute("SASS_URL", css_url, scope='support.constant.property-value.css')
sass_mixin = Attribute("SASS_MIXIN", default_keyword, scope='entity.other.attribute-name.tag')
sass_comment = Attribute("SASS_COMMENT", default_block_comment, scope='comment.block.css')
sass_number = Attribute("SASS_NUMBER", default_number, scope='constant.numeric.css')
# JS
js_regexp = Attribute("JS.REGEXP", default_string, scope='string.regexp')
js_local_var = Attribute("JS.LOCAL_VARIABLE", default_local_variable)
js_global_var = Attribute("JS.GLOBAL_VARIABLE", default_global_variable)
js_parameter = Attribute("JS.PARAMETER", default_parameter, effect_type=1, scope='variable.parameter')
js_instance_member_func = Attribute("JS.INSTANCE_MEMBER_FUNCTION", default_instance_method)
# YAML
yaml_comment = Attribute("YAML_COMMENT", default_line_comment, scope="comment.line.number-sign.yaml")
yaml_scalar_key = Attribute("YAML_SCALAR_KEY", default_keyword, scope="entity.name.tag.yaml")
yaml_scalar_value = Attribute("YAML_SCALAR_VALUE", text, scope="string.unquoted.block.yaml")
yaml_scalar_string = Attribute("YAML_SCALAR_STRING", text, scope="string.quoted.single.yaml")
yaml_scalar_dstring = Attribute("YAML_SCALAR_DSTRING", text, scope="string.quoted.double.yaml")
yaml_scalar_list = Attribute("YAML_SCALAR_LIST", text, scope="string.unquoted.block.yaml")
yaml_text = Attribute("YAML_TEXT", text, scope="string.unquoted.yaml")
yaml_sign = Attribute("YAML_SIGN", default_operation_sign)
# Puppet
puppet_comment = Attribute("PUPPET_BLOCK_COMMENT", default_line_comment, scope="comment.block.puppet")
puppet_regex = Attribute("PUPPET_REGEX", default_string, scope='string.regexp')
puppet_variable = Attribute("PUPPET_VARIABLE", default_local_variable, scope="punctuation.definition.variable.puppet")
puppet_variable_interpolation = Attribute("PUPPET_VARIABLE_INTERPOLATION", default_string, scope='string source')
puppet_escape_sequence = Attribute("PUPPET_ESCAPE_SEQUENCE", default_valid_string_escape)
puppet_resource_reference = Attribute("PUPPET_RESOURCE_REFERENCE", text)
puppet_keyword = Attribute("PUPPET_KEYWORD", default_keyword, scope="keyword.control.puppet")
puppet_digit = Attribute("PUPPET_NUMBER", default_number)
puppet_dq_string = Attribute("PUPPET_STRING", default_string, scope="string.quoted.double.puppet")
puppet_sq_string = Attribute("PUPPET_SQ_STRING", default_string, scope="string.quoted.single.puppet")
puppet_operation_sign = Attribute("PUPPET_OPERATION_SIGN", default_operation_sign, scope="keyword.operator.assignment.puppet")
puppet_parenths = Attribute("PUPPET_PARENTH", default_parentheses, scope="punctuation.section.scope.puppet")
puppet_brackets = Attribute("PUPPET_BRACKETS", default_brackets, scope="punctuation.definition.array.begin.puppet")
puppet_braces = Attribute("PUPPET_BRACES", default_braces, scope="punctuation.section.scope.puppet")
puppet_comma = Attribute("PUPPET_COMMA", default_comma)
puppet_dot = Attribute("PUPPET_DOT", default_dot)
puppet_semicolon = Attribute("PUPPET_SEMICOLON", default_semicolon)
puppet_bat_character = Attribute("PUPPET_BAD_CHARACTER", bad_character)
puppet_class = Attribute("PUPPET_CLASS", default_class_name, scope="entity.name.type.class.puppet")
# RubyHighlighter
rb_keyword = Attribute("RUBY_KEYWORD", default_keyword)
rb_comment = Attribute("RUBY_COMMENT", default_line_comment)
rb_heredoc_id = Attribute("RUBY_HEREDOC_ID", default_string, scope="punctuation.definition.string.begin.ruby")
rb_heredoc = Attribute("RUBY_HEREDOC_CONTENT", default_string, scope='string.unquoted.heredoc.ruby')
rb_number = Attribute("RUBY_NUMBER", default_number)
rb_string = Attribute("RUBY_STRING", default_string, scope="string.quoted.single.ruby")
rb_interpolated_string = Attribute("RUBY_INTERPOLATED_STRING", default_string, scope="string.quoted.double.ruby")
rb_words = Attribute("RUBY_WORDS", default_string, scope= "string.quoted.other.literal.upper.ruby")
rb_escape_sequence = Attribute("RUBY_ESCAPE_SEQUENCE", default_valid_string_escape)
rb_invalid_escape_sequence = Attribute("RUBY_INVALID_ESCAPE_SEQUENCE", default_invalid_string_escape)
rb_opSign = Attribute("RUBY_OPERATION_SIGN", default_operation_sign)
rb_brackets = Attribute("RUBY_BRACKETS", default_brackets)
rb_expr_in_string = Attribute("RUBY_EXPR_IN_STRING", default_string, scope='string source')
rb_bad_character = Attribute("RUBY_BAD_CHARACTER", text, scope='invalid')
rb_regexp = Attribute("RUBY_REGEXP", default_string, scope='string.regexp')
rb_identifier = Attribute("RUBY_IDENTIFIER", text, scope='variable')
rb_method_name = Attribute("RUBY_METHOD_NAME", rb_identifier, scope='entity.name.function')
rb_constant = Attribute("RUBY_CONSTANT", rb_identifier, scope='constant')
rb_constant_decl = Attribute("RUBY_CONSTANT_DECLARATION", rb_identifier, scope='entity.name.type.class.ruby')
rb_gvar = Attribute("RUBY_GVAR", rb_identifier, scope='variable.other.readwrite.global')
rb_cvar = Attribute("RUBY_CVAR", rb_identifier, scope='variable.other.readwrite.class')
rb_ivar = Attribute("RUBY_IVAR", rb_identifier, scope='variable.other.readwrite.instance')
rb_nth_ref = Attribute("RUBY_NTH_REF", text)
rb_comma = Attribute("RUBY_COMMA", default_comma, scope='punctuation.separator.object')
rb_dot = Attribute("RUBY_DOT", default_dot, scope='punctuation.separator.method')
rb_colon = Attribute("RUBY_COLON", default_semicolon)
rb_semicolon = Attribute("RUBY_SEMICOLON", default_semicolon, scope='punctuation.separator.statement')
rb_hash_assoc = Attribute("RUBY_HASH_ASSOC", default_operation_sign, scope='punctuation.separator.key-value')
rb_line_continuation = Attribute("RUBY_LINE_CONTINUATION", default_operation_sign)
rb_local_var = Attribute("RUBY_LOCAL_VAR_ID", rb_identifier)
rb_parameter = Attribute("RUBY_PARAMETER_ID", rb_identifier, scope='variable.parameter')
rb_symbol = Attribute("RUBY_SYMBOL", rb_identifier, scope='constant.other.symbol')
rb_specific_call = Attribute("RUBY_SPECIFIC_CALL", rb_identifier, scope='storage')
rb_paramdef = Attribute("RUBY_PARAMDEF_CALL", rb_identifier, scope='support.function')
# HAML
haml_text = Attribute("HAML_TEXT", text, scope='text.haml')
haml_class = Attribute("HAML_CLASS", haml_text, scope='entity.name.tag.class.haml')
haml_id = Attribute("HAML_ID", haml_text, scope='entity.name.tag.id.haml')
haml_tag = Attribute("HAML_TAG", haml_text, scope='punctuation.definition.tag.haml')
haml_tag_name = Attribute("HAML_TAG_NAME", haml_class, scope='meta.tag.haml')
haml_tag_attribute_name = Attribute("TAG_ATTR_KEY", haml_text, scope='entity.other.attribute-name.html')
haml_comment = Attribute("HAML_COMMENT", default_line_comment, scope='comment.line.slash.haml')
haml_xhtml = Attribute("HAML_XHTML", haml_text, scope='meta.prolog.haml')
haml_code_injection = Attribute("HAML_RUBY_CODE", haml_text, scope='source.ruby.embedded.haml', foreground=IGNORE_COLOR)
haml_ruby_evaluator = Attribute("HAML_RUBY_START", haml_text, scope='meta.line.ruby.haml')
haml_line_continuation = Attribute("HAML_LINE_CONTINUATION", haml_text)
haml_filter = Attribute("HAML_FILTER", haml_text)
haml_filter_content = Attribute("HAML_FILTER_CONTENT", haml_text)
haml_string = Attribute("HAML_STRING", default_string, scope="string.quoted.single.haml")
haml_string_interpolated = Attribute("HAML_STRING_INTERPOLATED", default_string, scope="string.quoted.double.haml")
haml_parenths = Attribute("HAML_PARENTHS", default_parentheses)
haml_ws_removal = Attribute("HAML_WS_REMOVAL", haml_text, scope='punctuation')
# SLIM
slim_text = Attribute("SLIM_STATIC_CONTENT", text, scope='text.slim')
slim_tag = Attribute("SLIM_TAG", slim_text, scope='entity.name.tag.slim')
slim_class = Attribute("SLIM_CLASS", slim_tag)
slim_id = Attribute("SLIM_ID", slim_tag)
slim_tag_start = Attribute("SLIM_TAG_START", slim_text, scope='punctuation.definition.tag.slim')
slim_tag_attribute_name = Attribute("SLIM_TAG_ATTR_KEY", haml_text, scope='entity.other.attribute-name.html')
slim_comment = Attribute("SLIM_COMMENT", default_line_comment, scope='comment.line.slash.slim')
slim_doctype = Attribute("SLIM_DOCTYPE_KWD", slim_tag, scope='meta.prolog.slim')
slim_code_injection = Attribute("SLIM_RUBY_CODE", haml_text, scope='source.ruby.embedded.slim', foreground=IGNORE_COLOR)
slim_call = Attribute("SLIM_CALL", slim_text, scope='meta.line.ruby.slim')
slim_interpolation = Attribute("SLIM_INTERPOLATION", rb_expr_in_string)
slim_bad_character = Attribute("SLIM_BAD_CHARACTER", slim_text, scope="invalid.illegal.bad-ampersand.html")
slim_parenths = Attribute("SLIM_PARENTHS", default_parentheses)
slim_filter = Attribute("SLIM_FILTER", slim_tag)
slim_filter_content = Attribute("SLIM_FILTER_CONTENT", slim_text)
slim_string_interpolated = Attribute("SLIM_STRING_INTERPOLATED", default_string, scope="string.quoted.double.html")
# Cucumber (Gherkin)
cucumber_text = Attribute("GHERKIN_TEXT", text, scope='text.gherkin.feature')
cucumber_comment = Attribute("GHERKIN_COMMENT", default_line_comment, scope='comment.line.number-sign')
cucumber_keyword = Attribute("GHERKIN_KEYWORD", default_keyword, scope='keyword.language.gherkin.feature')
cucumber_tag = Attribute("GHERKIN_TAG", cucumber_text, scope='storage.type.tag.cucumber')
cucumber_pystring = Attribute("GHERKIN_PYSTRING", default_string, scope='string.quoted.single')
cucumber_table_header = Attribute("GHERKIN_TABLE_HEADER_CELL", cucumber_text, scope='variable.other')
cucumber_table_cell = Attribute("GHERKIN_TABLE_CELL", cucumber_text)
cucumber_table_pipe = Attribute("GHERKIN_TABLE_PIPE", default_semicolon, scope='keyword.control.cucumber.table')
cucumber_outline_param_substitution = Attribute("GHERKIN_OUTLINE_PARAMETER_SUBSTITUTION", cucumber_text, scope='variable.other')
cucumber_scenario_regexp_param = Attribute("GHERKIN_REGEXP_PARAMETER", cucumber_text, scope='string.quoted.double')
#CoffeeScript
coffee_block_comment = Attribute("COFFEESCRIPT.BLOCK_COMMENT", default_block_comment, scope='comment.block.coffee')
coffee_line_comment = Attribute("COFFEESCRIPT.LINE_COMMENT", default_block_comment, scope='comment.line.coffee')
coffee_bad_char = Attribute("COFFEESCRIPT.BAD_CHARACTER", bad_character)
coffee_semicolon = Attribute("COFFEESCRIPT.SEMICOLON", default_semicolon, scope='punctuation.terminator.statement.coffee')
coffee_comma = Attribute("COFFEESCRIPT.COMMA", default_comma, scope='meta.delimiter.object.comma.coffee')
coffee_dot = Attribute("COFFEESCRIPT.DOT", default_dot, scope='meta.delimiter.method.period.coffee')
coffee_class = Attribute("COFFEESCRIPT.CLASS_NAME", text, scope='entity.name.function.coffee')
coffee_identifier = Attribute("COFFEESCRIPT.IDENTIFIER", text, scope='source.coffee', background=IGNORE_COLOR)
coffee_local_var = Attribute("COFFEESCRIPT.LOCAL_VARIABLE", coffee_identifier)
coffee_global_var = Attribute("COFFEESCRIPT.GLOBAL_VARIABLE", coffee_identifier, scope='variable.other.readwrite.global')
coffee_function_name = Attribute("COFFEESCRIPT.FUNCTION_NAME", text, scope='entity.name.function.coffee')
coffee_obj_key = Attribute("COFFEESCRIPT.OBJECT_KEY", text, scope='variable.assignment.coffee')
coffee_number = Attribute("COFFEESCRIPT.NUMBER", default_number, scope='constant.numeric.coffee')
coffee_bool = Attribute("COFFEESCRIPT.BOOLEAN", default_keyword, scope='constant.language.boolean')
coffee_str_bound = Attribute("COFFEESCRIPT.STRING_LITERAL", default_string, scope='punctuation.definition.string.begin.coffee')
coffee_str = Attribute("COFFEESCRIPT.STRING", default_string, scope='string.quoted.single.coffee')
coffee_heredoc_id = Attribute("COFFEESCRIPT.HEREDOC_ID", default_string, scope='punctuation.definition.string.begin.coffee')
coffee_heredoc_content = Attribute("COFFEESCRIPT.HEREDOC_CONTENT", default_string, scope='string.quoted.double.heredoc.coffee')
coffee_heregex_id = Attribute("COFFEESCRIPT.HEREGEX_ID", default_string, scope='string.regexp.coffee')
coffee_heregex_content = Attribute("COFFEESCRIPT.HEREGEX_CONTENT", default_string, scope='string.regexp.coffee')
coffee_js_id = Attribute("COFFEESCRIPT.JAVASCRIPT_ID", default_string, scope='punctuation.definition.string.begin.coffee')
coffee_expression_substitution = Attribute("COFFEESCRIPT.EXPRESSIONS_SUBSTITUTION_MARK", text, scope='punctuation.section.embedded.coffee')
coffee_parenths = Attribute("COFFEESCRIPT.PARENTHESIS", default_parentheses, scope='meta.brace.round.coffee')
coffee_brackets = Attribute("COFFEESCRIPT.BRACKET", default_brackets, scope='meta.brace.square.coffee')
coffee_braces = Attribute("COFFEESCRIPT.BRACE", default_braces, scope='meta.brace.curly.coffee')
coffee_operator = Attribute("COFFEESCRIPT.OPERATIONS", text, scope='keyword.operator.coffee')
coffee_operator_exists = Attribute("COFFEESCRIPT.EXISTENTIAL", text, scope='keyword.operator.coffee')
coffee_keyword = Attribute("COFFEESCRIPT.KEYWORD", default_keyword, scope='keyword.control.coffee')
coffee_range = Attribute("COFFEESCRIPT.RANGE", default_dot, scope='meta.delimiter.method.period.coffee')
coffee_splat = Attribute("COFFEESCRIPT.SPLAT", default_dot, scope='meta.delimiter.method.period.coffee')
coffee_this = Attribute("COFFEESCRIPT.THIS", default_keyword, scope='variable.language.coffee')
coffee_colon = Attribute("COFFEESCRIPT.COLON", default_semicolon, scope='keyword.operator.coffee')
coffee_prototype = Attribute("COFFEESCRIPT.PROTOTYPE", text, scope='entity.name.function.coffee')
coffee_fun_arrow = Attribute("COFFEESCRIPT.FUNCTION", default_number, scope='storage.type.function.coffee')
coffee_fun_binding_arrow = Attribute("COFFEESCRIPT.FUNCTION_BINDING", default_number, scope='storage.type.function.coffee')
coffee_regexp_id = Attribute("COFFEESCRIPT.REGULAR_EXPRESSION_ID", default_string, scope='string.regexp.coffee')
coffee_regexp = Attribute("COFFEESCRIPT.REGULAR_EXPRESSION_CONTENT", default_string, scope='string.regexp.coffee')
coffee_regexp_flag = Attribute("COFFEESCRIPT.REGULAR_EXPRESSION_FLAG", default_string, scope='string.regexp.coffee')
coffee_escaped_chars = Attribute("COFFEESCRIPT.ESCAPE_SEQUENCE", default_valid_string_escape, scope='constant.character.escape.coffe')
coffee_js_injection = Attribute("COFFEESCRIPT.JAVASCRIPT_CONTENT", default_string, scope='string.quoted.script.coffee', foreground=IGNORE_COLOR)
# ERB : "text.html.ruby"
erb_text = xml_tag
erb_block_start = Attribute("RHTML_SCRIPTLET_START_ID", erb_text, scope='punctuation.section.embedded.ruby')
erb_block_end = Attribute("RHTML_SCRIPTLET_END_ID", erb_text, scope='punctuation.section.embedded.ruby')
erb_block_expression_start = Attribute("RHTML_EXPRESSION_START_ID", erb_text, scope='punctuation.section.embedded.ruby')
erb_block_expression_end = Attribute("RHTML_EXPRESSION_END_ID", erb_text, scope='punctuation.section.embedded.ruby')
erb_comment = Attribute("RHTML_COMMENT_ID", default_line_comment, scope='comment.block.erb')
erb_omit_line_modifier = Attribute("RHTML_OMIT_NEW_LINE_ID", erb_text, scope='punctuation.section.embedded.ruby')
erb_ruby_injection_bg = Attribute("RHTML_SCRIPTING_BACKGROUND_ID", erb_text, scope='source.ruby.rails.embedded.html', foreground=IGNORE_COLOR)
# ClojureHighlighter
clj_comment = Attribute("Clojure Line comment", default_line_comment)
clj_atom = Attribute("Clojure Atom", default_keyword)
clj_keyword = Attribute("Clojure Keyword", rb_identifier)
clj_numbers = Attribute("Clojure Numbers", default_number)
clj_strings = Attribute("Clojure Strings", default_string)
clj_character = Attribute("Clojure Character", default_string)
clj_literal = Attribute("Clojure Literal", default_instance_field)
clj_first_in_list = Attribute("First symbol in list", rb_identifier, font_style=1)
# Objective-C Highlighter
oc_typedef = Attribute("TYPEDEF", text, 'storage.type')
oc_block_comment = Attribute("OC.BLOCK_COMMENT", default_block_comment)
oc_line_comment = Attribute("OC.LINE_COMMENT", default_line_comment)
oc_cpp_keyword = Attribute("OC.CPP_KEYWORD", default_keyword)
oc_conditionally_not_compiled = Attribute("CONDITIONALLY_NOT_COMPILED", default_block_comment)
oc_directive = Attribute("OC.DIRECTIVE", text, scope='keyword.other.directive')
oc_ivar = Attribute("IVAR", text, scope='variable.other.selector.objc')
oc_local_variable = Attribute("OC.LOCAL_VARIABLE", text, scope='variable.other.selector.objc')
oc_global_variable = Attribute("OC.GLOBAL_VARIABLE", oc_local_variable)
oc_extern_variable = Attribute("OC.EXTERN_VARIABLE", oc_local_variable)
oc_property = Attribute("OC.PROPERTY", oc_ivar)
oc_keyword = Attribute("OC.KEYWORD", default_keyword)
oc_label = Attribute("LABEL", oc_keyword)
oc_number = Attribute("OC.NUMBER", default_number)
oc_selfsuperthis = Attribute("OC.SELFSUPERTHIS", oc_keyword, scope='variable.language.objc')
oc_string = Attribute("OC.STRING", default_string)
oc_struct_field = Attribute("OC.STRUCT_FIELD", text, scope='constant.other.symbol')
oc_format_token = Attribute("OC_FORMAT_TOKEN", default_string, scope='string source')
oc_class_reference = Attribute("CLASS_REFERENCE", oc_typedef, scope='entity.name.class')
oc_protocol_reference = Attribute("PROTOCOL_REFERENCE", oc_class_reference, scope='meta.implementation.objc')
oc_message_argument = Attribute("OC.MESSAGE_ARGUMENT", default_function_call, scope='entity.name.function')
oc_method_declaration = Attribute("OC.METHOD_DECLARATION", default_function_declaration, scope='entity.name.function')
oc_parameter = Attribute("OC.PARAMETER", text, scope='variable.parameter.function.objc')
oc_badcharacter = Attribute("OC.BADCHARACTER", text, scope='invalid')
oc_dot = Attribute("OC.DOT", text)
oc_comma = Attribute("OC.COMMA", oc_dot)
oc_braces = Attribute("OC.BRACES", oc_dot)
oc_brackets = Attribute("OC.BRACKETS", oc_dot)
oc_semicolon = Attribute("OC.SEMICOLON", oc_dot)
oc_operation_sign = Attribute("OC.OPERATION_SIGN", oc_dot)
oc_parenths = Attribute("OC.PARENTHS", oc_dot)
oc_enum_const = Attribute("ENUM_CONST", text, scope='constant.other.symbol')
oc_macroname = Attribute("MACRONAME", oc_message_argument)
oc_macro_parameter = Attribute("MACRO_PARAMETER", text)
# PHP
php_var = Attribute("PHP_VAR", default_local_variable)
php_parameter = Attribute("PHP_PARAMETER", default_parameter)
# Go
go_block_comment = Attribute("GO_BLOCK_COMMENT", default_block_comment)
go_line_comment = Attribute("GO_LINE_COMMENT", default_line_comment)
go_builtin_constant = Attribute("GO_BUILTIN_CONSTANT", default_constant)
go_local_constant = Attribute("GO_LOCAL_CONSTANT", default_constant)
go_package_local_constant = Attribute("GO_PACKAGE_LOCAL_CONSTANT", default_constant)
go_package_exported_constant = Attribute("GO_PACKAGE_EXPORTED_CONSTANT", default_constant)
go_builtin_variable = Attribute("GO_BUILTIN_VARIABLE", default_global_variable)
go_method_receiver = Attribute("GO_METHOD_RECEIVER", default_local_variable)
go_exported_function = Attribute("GO_EXPORTED_FUNCTION", default_function_declaration)
go_local_function = Attribute("GO_LOCAL_FUNCTION", default_function_declaration)
go_builtin_function_call = Attribute("GO_BUILTIN_FUNCTION_CALL", default_function_call)
go_local_function_call = Attribute("GO_LOCAL_FUNCTION_CALL", default_function_call)
go_exported_function_call = Attribute("GO_EXPORTED_FUNCTION_CALL", default_function_call)
go_keyword = Attribute("GO_KEYWORD", default_keyword)
go_package = Attribute("GO_PACKAGE", default_identifier)
go_builtin_type_reference = Attribute("GO_BUILTIN_TYPE_REFERENCE", default_class_name)
go_type_reference = Attribute("GO_TYPE_REFERENCE", default_class_name)
# CustomHighlighter
custom_number = Attribute("CUSTOM_NUMBER_ATTRIBUTES", default_number)
custom_string = Attribute("CUSTOM_STRING_ATTRIBUTES", default_string)
custom_line_comment = Attribute("CUSTOM_LINE_COMMENT_ATTRIBUTES", default_line_comment)
custom_multi_line_comment = Attribute("CUSTOM_MULTI_LINE_COMMENT_ATTRIBUTES", default_doc_comment)
custom_valid_string_escape = Attribute("CUSTOM_VALID_STRING_ESCAPE_ATTRIBUTES", default_valid_string_escape)
custom_invalid_string_escape = Attribute("CUSTOM_INVALID_STRING_ESCAPE_ATTRIBUTES", default_invalid_string_escape)
# Jade
jade_statements = Attribute("JADE_STATEMENTS", default_keyword)
jade_file_path = Attribute("JADE_FILE_PATH", default_string)
jade_filter_name = Attribute("JADE_FILTER_NAME", default_label)
jade_js_block = Attribute("JADE_JS_BLOCK", default_identifier)
def color_from_textmate(color, alpha_blend_with=None):
rgba = color[1:]
if len(rgba) == 8 and alpha_blend_with:
r, g, b = hex_to_rgb(rgba[:6])
rb, gb, bb = hex_to_rgb(alpha_blend_with[1:])
alpha = int(rgba[6:8], 16) / 256
r = r * alpha + rb * (1-alpha)
g = g * alpha + gb * (1-alpha)
b = b * alpha + bb * (1-alpha)
return rgb_to_hex(r, g, b)
if len(rgba) == 3:
r = rgba[0]
g = rgba[1]
b = rgba[2]
return r + r + g + g + b + b
return rgba[:6]
def font_style_from_textmate(style):
result = 0
if 'bold' in style: result += 1
if 'italic' in style: result += 2
return result
def attr_from_textmate(settings, old_value, background):
result = AttributeValue()
if ('foreground' in settings) and ((old_value == None) or (old_value.default_fore != IGNORE_COLOR_VALUE)):
result.foreground = color_from_textmate(settings['foreground'])
if ('background' in settings) and ((old_value == None) or (old_value.default_back != IGNORE_COLOR_VALUE)):
result.background = color_from_textmate(settings['background'], background)
if 'fontStyle' in settings:
tm_font_style = settings['fontStyle']
result.font_style = font_style_from_textmate(tm_font_style)
if 'underline' in tm_font_style:
result.effect_type = 1
return result
def find_by_scope(settings, scope):
# compound scope
less_specific = None
less_specific_weight = 0
less_specific_selector_size = 0
# simple scope (without whitespaces and '-')
ss_less_specific = None
ss_less_specific_weight = 0
for setting in settings:
scope_of_setting = setting.get('scope', None)
if scope_of_setting is None:
if scope is None: return setting
else:
if not isinstance(scope_of_setting, list):
scopes_of_setting = scope_of_setting.split(",")
else:
scopes_of_setting = scope_of_setting
for aScope in scopes_of_setting:
aScope = aScope.strip()
# ignore excludes in scopes selectors,
# more accurate parsing/matching required!
chain_without_excludes = aScope.split(' -')[0]
aScope_selectors = chain_without_excludes.split(' ')
# We need:
# 1. "Match the element deepest down in the scope e.g. string wins over source.php when the scope is source.php string.quoted."
# it is very simple implementation of above rule
matchingScope = aScope_selectors[-1]
if matchingScope is None:
continue
# Consider scope size as scope size until first not excluded element
aScopeSelectorSize = 0
for i in range(0, len(aScope_selectors) - 1):
aScopeSelectorSize = len(aScope_selectors[i].strip())
isSimpleScope = (aScopeSelectorSize == 0)
if matchingScope == scope:
if isSimpleScope:
return setting
less_specific = setting
less_specific_weight = len(matchingScope)
less_specific_selector_size = aScopeSelectorSize
if scope is not None and scope.startswith(matchingScope):
# We need:
# 2. "Match most of the deepest element e.g. string.quoted wins over string."
# so let's consider matched symbols count as weight
new_match_weight = len(matchingScope)
weight = ss_less_specific_weight if isSimpleScope else less_specific_weight
if new_match_weight > weight:
if isSimpleScope:
ss_less_specific = setting
ss_less_specific_weight = new_match_weight
else:
less_specific = setting
less_specific_weight = new_match_weight
less_specific_selector_size = aScopeSelectorSize
else:
# if matched part is equal and scope isn't simple - let's choose the shortest scope
# in general case should work better, because some where particular complicated
# scope won't override similar but more general scope
if not isSimpleScope and (new_match_weight == weight):
if less_specific_selector_size > aScopeSelectorSize:
less_specific = setting
less_specific_weight = new_match_weight
less_specific_selector_size = aScopeSelectorSize
return ss_less_specific if (ss_less_specific is not None) else less_specific
def load_textmate_scheme(tmtheme):
themeDict = None
with open(tmtheme, 'rb') as f:
themeDict = plistlib.load(f)
all_settings = themeDict['settings']
used_scopes = set()
default_settings = find_by_scope(all_settings, None)
if not default_settings:
print("Cannot find default settings")
return
default_settings = default_settings['settings']
text.value = attr_from_textmate(default_settings, None, None)
background = None
selection_background = None
caret_row_color = None
if 'background' in default_settings:
background = default_settings['background']
all_colors["GUTTER_BACKGROUND"] = color_from_textmate(background)
if 'invisibles' in default_settings:
all_colors['INDENT_GUIDE'] = color_from_textmate(default_settings['invisibles'], background)
all_colors['SELECTED_INDENT_GUIDE'] = all_colors['INDENT_GUIDE']
all_colors['WHITESPACES'] = color_from_textmate(default_settings['invisibles'], background)
if 'selection' in default_settings:
selection_background = color_from_textmate(default_settings['selection'], background)
all_colors['SELECTION_BACKGROUND'] = selection_background
if 'lineHighlight' in default_settings:
caret_row_color = color_from_textmate(default_settings['lineHighlight'], background)
if 'caret' in default_settings:
all_colors['CARET_COLOR'] = color_from_textmate(default_settings['caret'])
if 'foreground' in default_settings:
all_colors["LINE_NUMBERS_COLOR"] = color_from_textmate(default_settings['foreground'])
if caret_row_color is not None and selection_background is not None and selection_background == caret_row_color:
y, i, q = hex_to_yiq(caret_row_color)
if y < 0.5:
y /= 2
else:
y += 0.2
caret_row_color = rgb_to_hex(*colorsys.yiq_to_rgb(y, i, q))
if caret_row_color is not None:
all_colors['CARET_ROW_COLOR'] = caret_row_color
all_colors['CONSOLE_BACKGROUND_KEY'] = text.value.background
if background is not None:
blend_spy_js_attributes(background)
for attr in all_attributes:
if attr.scope:
settings = find_by_scope(all_settings, attr.scope)
if settings:
the_scope = settings['scope']
if the_scope:
print("converting attribute " + attr.id + " from TextMate scope " + the_scope)
used_scopes.add(the_scope)
attr.value = attr_from_textmate(settings['settings'], attr.value, background)
else:
print("[!] scope not found: " + attr.scope)
return all_settings, used_scopes
def blend_spy_js_attributes(background):
Attribute("SPY-JS.FUNCTION_SCOPE", text, background=blend_with_as_rgb256(background, "#FFFFF0", "04"), effect_type=2)
Attribute("SPY-JS.PROGRAM_SCOPE", text, background=blend_with_as_rgb256(background, "#FFFFFF", "04"), effect_type=2)
Attribute("SPY-JS.EXCEPTION", text, background=blend_with_as_rgb256(background, "#FFCCCC", "04"), effect_type=2)
Attribute("SPY-JS.PATH_LEVEL_ONE", text, background=blend_with_as_rgb256(background, "#E2FFE2", "04"), effect_type=2)
Attribute("SPY-JS.PATH_LEVEL_TWO", text, effect_type=1)
Attribute("SPY-JS.VALUE_HINT", text, effect_type=0)
return
def blend_with_as_rgb256(base_hex_color, blend_with_hex_color, blend_hex_alpha):
result = hex_to_rgb(color_from_textmate(base_hex_color + blend_hex_alpha, blend_with_hex_color))
return int(result[0] * 256), int(result[1] * 256), int(result[2] * 256)
def underscore_to_camelcase(value):
def camelcase():
while True:
yield str.capitalize
c = camelcase()
return "".join(next(c)(x) if x else '_' for x in value.split("_"))
def isDark():
back = hex_to_rgb(text.value.background)
intensity = (back[0] + back[1] + back[2])/3
return intensity < 0.5
def removeNoneAttrib(elem):
"""Remove None attributes from XML tree"""
elem.attrib = {
k: elem.attrib[k]
for k in elem.attrib
if elem.attrib[k] is not None
}
for subelem in elem:
removeNoneAttrib(subelem)
def write_idea_scheme(filename):
name, ext = os.path.splitext(os.path.basename(filename))
baseName = "Darcula" if isDark() else "Default"
scheme = ET.Element("scheme", name=underscore_to_camelcase(name), version="1", parent_scheme=baseName)
colors = ET.SubElement(scheme, 'colors')
for name, value in all_colors.items():
ET.SubElement(colors, 'option', name=name, value=value)
attributes = ET.SubElement(scheme, 'attributes')
# let's sort attributes, then diffs between generated schemes will look nice
all_attributes.sort(key=lambda attr: attr.id)
for attr in all_attributes:
if attr.value.inherited:
print('inheriting ' + attr.id + ' from ' + attr.parent.id)
elif isinstance(attr.value, DerivedAttributeValue):
print('transforming IDEA default color for ' + attr.id)
fore = attr.value.foreground
back = attr.value.background
saveFg = fore and (fore != IGNORE_COLOR_VALUE)
saveBg = back and (back != IGNORE_COLOR_VALUE)
if saveFg or saveBg or attr.value.font_style or attr.value.effect_type or attr.value.error_stripe:
option = ET.SubElement(attributes, 'option', name=attr.id)
value = ET.SubElement(option, 'value')
if saveFg: ET.SubElement(value, 'option', name='FOREGROUND', value=fore)
if saveBg: ET.SubElement(value, 'option', name='BACKGROUND', value=back)
if attr.value.font_style:
ET.SubElement(value, 'option', name='FONT_TYPE', value=str(attr.value.font_style))
if attr.value.effect_type:
ET.SubElement(value, 'option', name='EFFECT_TYPE', value=str(attr.value.effect_type))
if attr.value.effect_color:
ET.SubElement(value, 'option', name='EFFECT_COLOR', value=attr.value.effect_color)
elif fore:
ET.SubElement(value, 'option', name='EFFECT_COLOR', value=fore)
else:
ET.SubElement(value, 'option', name='EFFECT_COLOR', value=text.value.foreground)
if attr.value.error_stripe:
ET.SubElement(value, 'option', name='ERROR_STRIPE_COLOR', value=attr.value.error_stripe)
else:
ET.SubElement(attributes, 'option', name=attr.id, baseAttributes=attr.parent.id)
indent(scheme)
capitalize_colors(scheme)
tree = ET.ElementTree(scheme)
removeNoneAttrib(tree.getroot())
tree.write(filename)
if len(sys.argv) != 3:
print('Usage: colorSchemeTool <TextMate scheme> <IDEA/PyCharm/RubyMine scheme>')
exit(1)
all_settings, used_scopes = load_textmate_scheme(sys.argv[1])
write_idea_scheme(sys.argv[2])
for setting in all_settings:
scope = setting.get('scope', None)
if scope and not scope in used_scopes:
print("Unused scope: " + scope)