Skip to content

Instantly share code, notes, and snippets.

@evandrocoan
Created November 7, 2017 21:31
Show Gist options
  • Save evandrocoan/eba23f91b7afbc8f324b318ebddf9800 to your computer and use it in GitHub Desktop.
Save evandrocoan/eba23f91b7afbc8f324b318ebddf9800 to your computer and use it in GitHub Desktop.
Scheme Converter
"""
Convert Color Scheme.
Licensed under MIT.
Copyright (C) 2017 Isaac Muse <isaacmuse@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of
the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
from __future__ import absolute_import
import sublime
import sublime_plugin
import re
from os import path
from os import makedirs
from plistlib import readPlistFromBytes
import codecs
TEMP_FOLDER = "sublime_color_scheme_format"
TEMP_PATH = "Packages/User/%s" % TEMP_FOLDER
GLOBAL_OPTIONS = "globals"
# XML
XML_COMMENT_RE = re.compile(br"^[\r\n\s]*<!--[\s\S]*?-->[\s\r\n]*|<!--[\s\S]*?-->")
RE_CAMEL_CASE = re.compile('[A-Z]')
RE_SNAKE_CASE = re.compile('_(.)')
def packages_path(pth):
"""Get packages path."""
return path.join(path.dirname(sublime.packages_path()), path.normpath(pth))
def to_snake(m):
"""Convert to snake case."""
return '_' + m.group(0).lower()
def to_camel(m):
"""Convert to camel case."""
return m.group(1).Upper()
def get_tmtheme(scheme):
"""Get old tmtheme style."""
tmtheme = {
"settings": [
{
"settings": {}
}
]
}
for k, v in scheme.get("globals", {}).items():
tmtheme["settings"]["settings"][RE_SNAKE_CASE.sub(to_camel, k)] = v
for k, v in scheme.items():
if k in ('variables', 'rules', "globals"):
continue
tmtheme[k] = v
for rule in scheme["rules"]:
entry = {}
name = rule.get('name')
scope = rule.get('scope')
if name:
entry['name'] = name
if scope:
entry['scope'] = scope
entry['settings'] = {}
foreground = rule.get('foreground')
background = rule.get('background')
fontstyle = rule.get("font_style")
selection_foreground = rule.get('selection_foreground')
if foreground and isinstance(foreground, str):
entry['settings']['foreground'] = foreground
if selection_foreground:
entry['selectionForeground'] = selection_foreground
if background:
entry['settings']['background'] = background
if fontstyle:
entry['settings']['fontStyle'] = fontstyle
tmtheme['settings'].append(entry)
return tmtheme
def sublime_format_path(pth):
"""Format path for sublime internal use."""
m = re.match(r"^([A-Za-z]{1}):(?:/|\\)(.*)", pth)
if sublime.platform() == "windows" and m is not None:
pth = m.group(1) + "/" + m.group(2)
return pth.replace("\\", "/")
class ConvertSublimeColorSchemeFormat(object):
"""Determine color scheme colors and style for text in a Sublime view buffer."""
def __init__(self, scheme_file):
"""Initialize."""
self.color_scheme = path.normpath(scheme_file)
self.base_name = path.basename(self.color_scheme)
assert not scheme_file.endswith('.sublime-color-scheme'), "Scheme not the correct format!"
content = sublime.load_binary_resource(sublime_format_path(self.color_scheme))
self.legacy = True
self.convert_format(readPlistFromBytes(XML_COMMENT_RE.sub(b'', content)))
self.scheme_file = scheme_file
def convert_format(self, obj):
"""Convert tmTheme object to new format."""
self.scheme_obj = {
"variables": {},
"globals": {},
"rules": []
}
for k, v in obj.items():
if k == "settings":
continue
self.scheme_obj[k] = v
for item in obj["settings"]:
if item.get('scope', None) is None and item.get('name', None) is None:
for k, v in item["settings"].items():
self.scheme_obj["globals"][RE_CAMEL_CASE.sub(to_snake, k)] = v
if 'settings' in item and item.get('scope') is not None:
rule = {}
name = item.get('name')
if name is not None:
rule['name'] = name
scope = item.get('scope')
if scope is not None:
rule["scope"] = scope
fg = item['settings'].get('foreground')
if fg is not None:
rule['foreground'] = item['settings'].get('foreground')
bg = item['settings'].get('background')
if bg is not None:
rule['background'] = bg
selfg = item["settings"].get("selectionForeground")
if selfg is not None:
rule["selection_foreground"] = selfg
font_style = item["settings"].get('fontStyle')
if font_style is not None:
rule['font_style'] = font_style
self.scheme_obj['rules'].append(rule)
def get_scheme_obj(self):
"""Get the scheme file used during the process."""
return self.scheme_obj
def get_scheme_file(self):
"""Get the scheme file used during the process."""
return self.scheme_file
class ConvertSublimeColorSchemeCommand(sublime_plugin.TextCommand):
"""Convert tmTheme file from the active view to sublime-color-scheme format."""
def run(self, edit):
"""Run the command."""
temp = packages_path(TEMP_PATH)
if not path.exists(temp):
makedirs(temp)
scheme = self.view.settings().get("color_scheme")
if scheme is None:
pref_settings = sublime.load_settings('Preferences.sublime-settings')
scheme = pref_settings.get('color_scheme')
try:
converter = ConvertSublimeColorSchemeFormat(scheme)
except Exception:
return
name = packages_path(path.join(TEMP_PATH, path.splitext(converter.base_name)[0] + '.sublime-color-scheme'))
with codecs.open(name, "w", encoding='utf-8') as f:
f.write(sublime.encode_value(converter.get_scheme_obj(), pretty=True))
class ConvertAllSublimeColorSchemeCommand(sublime_plugin.ApplicationCommand):
"""Convert all tmTheme files to sublime-color-scheme format."""
def run(self):
"""Run the command."""
temp = packages_path(TEMP_PATH)
if not path.exists(temp):
makedirs(temp)
# Skip User folder
for scheme in sublime.find_resources('*.tmTheme'):
if scheme.startswith('Packages/User/'):
continue
try:
converter = ConvertSublimeColorSchemeFormat(scheme)
except Exception:
return
name = packages_path(path.join(TEMP_PATH, path.splitext(converter.base_name)[0] + '.sublime-color-scheme'))
with codecs.open(name, "w", encoding='utf-8') as f:
f.write(sublime.encode_value(converter.get_scheme_obj(), pretty=True))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment