Skip to content

Commit

Permalink
Feature/sublime color scheme (#42)
Browse files Browse the repository at this point in the history
* Some intial work to add .sublime-color-scheme support

* Lint fixes

* Handle font style proper

* Fix bold, italic, select and code highlight for 3150

* Fix selection related issues

* Update changelog

* JSON doesn't use single quote strings

* More changes

Fix differences in checking if pygments setting or default style has
changed.

Deprecate get_css

* Template cleanup

Change name from Scheme2CSS to SchemeTemplate. Also remove get_css and move initialization of ColorSchemeMatcher to legacy setup function.

* Upgrade color scheme matcher

* Use sublime's builtin serializer

* Lint
  • Loading branch information
facelessuser authored Oct 19, 2017
1 parent e2553f3 commit 2dc38d8
Show file tree
Hide file tree
Showing 11 changed files with 592 additions and 300 deletions.
7 changes: 4 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ language: python
python:
- "3.3"
install:
- pip install "flake8<3"
- pip install flake8
- pip install flake8-docstrings
- pip install flake8-putty
- pip install flake8-mutable
- pip install flake8-builtins
- pip install pep8-naming
- pip install pytest
- pip install mkdocs
- pip install mkdocs-material
- pip install pymdown-extensions
- pip install pygments
- pip install pytest
addons:
apt:
packages:
Expand Down
7 changes: 7 additions & 0 deletions docs/src/markdown/changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## 3.0.0

> Oct x, 2017
- **NEW**: Support for `.sublime-color-schemes` (which are subject to change).
- **NEW**: Update `rgba` library.

## 2.2.0

> Oct 11, 2017
Expand Down
3 changes: 1 addition & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
[flake8]
ignore=D202,D203,D401
ignore=D202,D203,D401,N802
max-line-length=120
exclude=st3/mdpopups/png.py,site/*.py
putty-ignore=st3/mdpopups/mdx/*.py : +N802
29 changes: 21 additions & 8 deletions st3/mdpopups/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from . import version as ver
from . import colorbox
from collections import OrderedDict
from .st_scheme_template import Scheme2CSS, POPUP, PHANTOM
from .st_scheme_template import SchemeTemplate, POPUP, PHANTOM, NEW_SCHEMES
from .st_clean_css import clean_css
from .st_pygments_highlight import syntax_hl as pyg_syntax_hl
from .st_code_highlight import SublimeHighlight
Expand Down Expand Up @@ -102,6 +102,7 @@ def _can_show(view, location=-1):

return can_show


##############################
# Theme/Scheme cache management
##############################
Expand Down Expand Up @@ -175,15 +176,15 @@ def _get_scheme(view):
# Check if cache expired or user changed pygments setting.
if (
_is_cache_expired(t) or
obj.variables.get('use_pygments', False) != (not settings.get(HL_SETTING, True)) or
obj.variables.get('default_style', True) != settings.get(STYLE_SETTING, True)
obj.use_pygments != (not settings.get(HL_SETTING, True)) or
obj.default_style != settings.get(STYLE_SETTING, True)
):
obj = None
user_css = ''
default_css = ''
if obj is None:
try:
obj = Scheme2CSS(scheme)
obj = SchemeTemplate(scheme)
_prune_cache()
user_css = _get_user_css()
default_css = _get_default_css()
Expand Down Expand Up @@ -277,6 +278,7 @@ def _get_theme(view, css=None, css_type=POPUP, template_vars=None):
obj, user_css, default_css = _get_scheme(view)
try:
return obj.apply_template(
view,
default_css + '\n' +
((clean_css(css) + '\n') if css else '') +
user_css,
Expand Down Expand Up @@ -541,10 +543,20 @@ def scope2style(view, scope, selected=False, explicit_background=False):
'style': ''
}
obj = _get_scheme(view)[0]
style_obj = obj.guess_style(scope, selected, explicit_background)
style['color'] = style_obj.fg_simulated
style['background'] = style_obj.bg_simulated
style['style'] = style_obj.style
style_obj = obj.guess_style(view, scope, selected, explicit_background)
if NEW_SCHEMES:
style['color'] = style_obj['foreground']
style['background'] = style_obj['background']
font = []
if style_obj['bold']:
font.append('bold')
if style_obj['italic']:
font.append('italic')
style['style'] = ' '.join(font)
else:
style['color'] = style_obj.fg_simulated
style['background'] = style_obj.bg_simulated
style['style'] = style_obj.style
return style


Expand Down Expand Up @@ -769,6 +781,7 @@ def update(self, new_phantoms):

self.phantoms = new_phantoms


if frontmatter:
def format_frontmatter(values):
"""Format values as frontmatter."""
Expand Down
6 changes: 3 additions & 3 deletions st3/mdpopups/colorbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,16 @@ def checkered_color(color, background):
return checkered.get_rgb()


def get_border_size(dir, border_map):
def get_border_size(direction, border_map):
"""Get size of border map."""

size = 0
if dir == X:
if direction == X:
if border_map & LEFT:
size += 1
if border_map & RIGHT:
size += 1
elif dir == Y:
elif direction == Y:
if border_map & TOP:
size += 1
if border_map & BOTTOM:
Expand Down
56 changes: 43 additions & 13 deletions st3/mdpopups/rgba.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,33 @@

RGB_CHANNEL_SCALE = 1.0 / 255.0
HUE_SCALE = 1.0 / 360.0
PERCENT_TO_CHANNEL = 255.0 / 100.0
CHANNEL_TO_PERCENT = 100.0 / 255.0
SCALE_PERCENT = 1 / 100.0
SCALE_HALF_PERCENT = 1 / 50.0


def mix_channel(cf, af, cb, ab):
"""
Mix the color channel.
cf: Channel foreground
af: Alpha foreground
cb: Channel background
ab: Alpha background
The foreground is overlayed on the secondary color it is to be mixed with.
The alpha channels are applied and the colors mix.
"""

return clamp(
round_int(
abs(
cf * (af * RGB_CHANNEL_SCALE) + cb * (ab * RGB_CHANNEL_SCALE) * (1 - (af * RGB_CHANNEL_SCALE))
)
),
0, 255
)


def clamp(value, mn, mx):
Expand All @@ -21,7 +48,7 @@ def clamp(value, mn, mx):
def round_int(dec):
"""Round float to nearest int using expected rounding."""

return int(decimal.Decimal(dec).quantize(decimal.Decimal('0'), decimal.ROUND_HALF_UP))
return int(decimal.Decimal(dec).quantize(decimal.Decimal('0'), decimal.ROUND_HALF_DOWN))


class RGBA(object):
Expand Down Expand Up @@ -72,21 +99,12 @@ def apply_alpha(self, background="#000000FF"):
the transparent color against the given background.
"""

def tx_alpha(cf, af, cb, ab):
"""Translate the color channel with the alpha channel and background channel color."""

return round_int(
abs(
cf * (af * RGB_CHANNEL_SCALE) + cb * (ab * RGB_CHANNEL_SCALE) * (1 - (af * RGB_CHANNEL_SCALE))
)
) & 0xFF

if self.a < 0xFF:
r, g, b, a = self._split_channels(background)

self.r = tx_alpha(self.r, self.a, r, a)
self.g = tx_alpha(self.g, self.a, g, a)
self.b = tx_alpha(self.b, self.a, b, a)
self.r = mix_channel(self.r, self.a, r, a)
self.g = mix_channel(self.g, self.a, g, a)
self.b = mix_channel(self.b, self.a, b, a)

return self.get_rgb()

Expand Down Expand Up @@ -121,6 +139,18 @@ def blue(self, factor):

self.b = round_int(clamp(self.b + (255.0 * factor) - 255.0, 0.0, 255.0))

def blend(self, color, percent, alpha=False):
"""Blend color."""

factor = clamp(round_int(clamp(float(percent), 0.0, 100.0) * PERCENT_TO_CHANNEL), 0, 255)
r, g, b, a = self._split_channels(color)

self.r = mix_channel(self.r, factor, r, 255)
self.g = mix_channel(self.g, factor, g, 255)
self.b = mix_channel(self.b, factor, b, 255)
if alpha:
self.a = mix_channel(self.a, factor, a, 255)

def luminance(self, factor):
"""Get true luminance."""

Expand Down
57 changes: 42 additions & 15 deletions st3/mdpopups/st_code_highlight.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
from .st_color_scheme_matcher import ColorSchemeMatcher
from .st_mapping import lang_map

NEW_SCHEMES = int(sublime.version()) >= 3150

INLINE_BODY_START = '<code class="inline-highlight">'
BODY_START = '<div class="highlight"><pre>'
LINE = '%(code)s<br>'
Expand All @@ -45,10 +47,12 @@ def __init__(self, scheme):
"""Initialization."""

self.view = None
self.csm = ColorSchemeMatcher(scheme)

self.fground = self.csm.get_special_color('foreground', simulate_transparency=True)
self.bground = self.csm.get_special_color('background', simulate_transparency=True)
if not NEW_SCHEMES:
self.csm = ColorSchemeMatcher(scheme)

self.fground = self.csm.get_special_color('foreground', simulate_transparency=True)
self.bground = self.csm.get_special_color('background', simulate_transparency=True)

def setup(self, **kwargs):
"""Get get general document preferences from sublime preferences."""
Expand All @@ -58,7 +62,7 @@ def setup(self, **kwargs):
self.pt = 0
self.end = 0
self.curr_row = 0
self.ebground = self.bground
# self.ebground = self.bground

def setup_print_block(self, curr_sel, multi=False):
"""Determine start and end points and whether to parse whole file or selection."""
Expand Down Expand Up @@ -113,9 +117,9 @@ def format_text(self, line, text, color, bgcolor, style, empty, annotate=False):
text = '&nbsp;'

css_style = ''
if style and style == 'bold':
if style and 'bold' in style:
css_style += ' font-weight: bold;'
if style and style == 'italic':
if style and 'italic' in style:
css_style += ' font-style: italic;'

if bgcolor is None:
Expand All @@ -140,10 +144,25 @@ def convert_line_to_html(self, empty):
scope_name = self.view.scope_name(self.pt)
while self.view.scope_name(self.end) == scope_name and self.end < self.size:
self.end += 1
color_match = self.csm.guess_color(scope_name, selected=do_highlight, explicit_background=True)
color = color_match.fg_simulated
bgcolor = color_match.bg_simulated
style = color_match.style
if NEW_SCHEMES:
color_match = self.view.style_for_scope(scope_name)
color = color_match.get('foreground', self.fground)
bgcolor = color_match.get('background')
style = []
if color_match['bold']:
style.append('bold')
if color_match['italic']:
style.append('italic')
if do_highlight:
sfg = color_match.get('selection_forground', self.defaults.get('selection_forground'))
if sfg:
color = sfg
bgcolor = color_match.get('selection', '#0000FF')
else:
color_match = self.csm.guess_color(scope_name, selected=do_highlight, explicit_background=True)
color = color_match.fg_simulated
bgcolor = color_match.bg_simulated
style = color_match.style.split(' ')

region = sublime.Region(self.pt, self.end)
# Normal text formatting
Expand All @@ -154,11 +173,15 @@ def convert_line_to_html(self, empty):
self.pt = self.end
self.end = self.pt + 1

# Get the color for the space at the end of a line
if self.end < self.view.size():
end_key = self.view.scope_name(self.pt)
color_match = self.csm.guess_color(end_key, explicit_background=True)
self.ebground = color_match.bg_simulated
# # Get the color for the space at the end of a line
# if self.end < self.view.size():
# end_key = self.view.scope_name(self.pt)
# if NEW_SCHEMES:
# color_match = self.view.style_for_scope(end_key)
# self.ebground = color_match.get('background')
# else:
# color_match = self.csm.guess_color(end_key, explicit_background=True)
# self.ebground = color_match.bg_simulated

# Join line segments
return ''.join(line)
Expand Down Expand Up @@ -231,6 +254,10 @@ def syntax_highlight(self, src, lang, hl_lines=[], inline=False, no_wrap=False,
"""Syntax Highlight."""

self.set_view(src, 'text' if not lang else lang)
if NEW_SCHEMES:
self.defaults = self.view.style()
self.fground = self.defaults.get('foreground', '#000000')
self.bground = self.defaults.get('background', '#FFFFFF')
self.inline = inline
self.hl_lines = hl_lines
self.no_wrap = no_wrap
Expand Down
Loading

0 comments on commit 2dc38d8

Please sign in to comment.