Exemple #1
0
def mixin_exists(namespace, name):
    expect_type(name, String)
    # TODO invasive, but there's no other way to ask for this at the moment
    for fname, arity in namespace._mixins.keys():
        if name.value == fname:
            return Boolean(True)
    return Boolean(False)
Exemple #2
0
def mixin_exists(namespace, name):
    expect_type(name, String)
    # TODO invasive, but there's no other way to ask for this at the moment
    for fname, arity in namespace._mixins.keys():
        if name.value == fname:
            return Boolean(True)
    return Boolean(False)
Exemple #3
0
def change_color(color, red=None, green=None, blue=None, hue=None, saturation=None, lightness=None, alpha=None):
    do_rgb = red or green or blue
    do_hsl = hue or saturation or lightness
    if do_rgb and do_hsl:
        raise ValueError("Can't change both RGB and HSL channels at the same time")

    if alpha is None:
        alpha = color.alpha
    else:
        alpha = alpha.value

    if do_rgb:
        channels = list(color.rgba[:3])
        if red:
            channels[0] = _interpret_percentage(red, relto=255)
        if green:
            channels[1] = _interpret_percentage(green, relto=255)
        if blue:
            channels[2] = _interpret_percentage(blue, relto=255)

        return Color.from_rgb(*channels, alpha=alpha)

    else:
        channels = list(color.hsl)
        if hue:
            expect_type(hue, Number, unit=None)
            channels[0] = (hue.value / 360) % 1
        # Ruby sass treats plain numbers for saturation and lightness as though
        # they were percentages, just without the %
        if saturation:
            channels[1] = _interpret_percentage(saturation, relto=100)
        if lightness:
            channels[2] = _interpret_percentage(lightness, relto=100)

        return Color.from_hsl(*channels, alpha=alpha)
Exemple #4
0
def change_color(color, red=None, green=None, blue=None, hue=None, saturation=None, lightness=None, alpha=None):
    do_rgb = red or green or blue
    do_hsl = hue or saturation or lightness
    if do_rgb and do_hsl:
        raise ValueError("Can't change both RGB and HSL channels at the same time")

    if alpha is None:
        alpha = color.alpha
    else:
        alpha = alpha.value

    if do_rgb:
        channels = list(color.rgba[:3])
        if red:
            channels[0] = _interpret_percentage(red, relto=255)
        if green:
            channels[1] = _interpret_percentage(green, relto=255)
        if blue:
            channels[2] = _interpret_percentage(blue, relto=255)

        return Color.from_rgb(*channels, alpha=alpha)

    else:
        channels = list(color.hsl)
        if hue:
            expect_type(hue, Number, unit=None)
            channels[0] = (hue.value / 360) % 1
        # Ruby sass treats plain numbers for saturation and lightness as though
        # they were percentages, just without the %
        if saturation:
            channels[1] = _interpret_percentage(saturation, relto=100)
        if lightness:
            channels[2] = _interpret_percentage(lightness, relto=100)

        return Color.from_hsl(*channels, alpha=alpha)
Exemple #5
0
def set_nth(list, n, value):
    expect_type(n, Number, unit=None)

    py_n = n.to_python_index(len(list))
    return List(
        tuple(list[:py_n]) + (value,) + tuple(list[py_n + 1:]),
        use_comma=list.use_comma)
Exemple #6
0
def join(lst1, lst2, separator=String.unquoted('auto')):
    expect_type(separator, String)

    ret = []
    ret.extend(List.from_maybe(lst1))
    ret.extend(List.from_maybe(lst2))

    if separator.value == 'comma':
        use_comma = True
    elif separator.value == 'space':
        use_comma = False
    elif separator.value == 'auto':
        # The Sass docs are slightly misleading here, but the algorithm is: use
        # the delimiter from the first list that has at least 2 items, or
        # default to spaces.
        if len(lst1) > 1:
            use_comma = lst1.use_comma
        elif len(lst2) > 1:
            use_comma = lst2.use_comma
        else:
            use_comma = False
    else:
        raise ValueError("separator for join() must be comma, space, or auto")

    return List(ret, use_comma=use_comma)
Exemple #7
0
def set_nth(list, n, value):
    expect_type(n, Number, unit=None)

    py_n = n.to_python_index(len(list))
    return List(
        tuple(list[:py_n]) + (value,) + tuple(list[py_n + 1:]),
        use_comma=list.use_comma)
Exemple #8
0
def join(lst1, lst2, separator=String.unquoted('auto')):
    expect_type(separator, String)

    ret = []
    ret.extend(List.from_maybe(lst1))
    ret.extend(List.from_maybe(lst2))

    if separator.value == 'comma':
        use_comma = True
    elif separator.value == 'space':
        use_comma = False
    elif separator.value == 'auto':
        # The Sass docs are slightly misleading here, but the algorithm is: use
        # the delimiter from the first list that has at least 2 items, or
        # default to spaces.
        if len(lst1) > 1:
            use_comma = lst1.use_comma
        elif len(lst2) > 1:
            use_comma = lst2.use_comma
        else:
            use_comma = False
    else:
        raise ValueError("separator for join() must be comma, space, or auto")

    return List(ret, use_comma=use_comma)
Exemple #9
0
def absolute_path(relative_path):
    """Return an absolute path for the given relative path, relative to the
    calling file.
    """
    expect_type(relative_path, String)
    # TODO i can't get the calling file until "rule" or something else helpful
    # is actually passed in!
    return String(os.path.abspath(relative_path.value))
Exemple #10
0
def variable_exists(namespace, name):
    expect_type(name, String)
    try:
        namespace.variable('$' + name.value)
    except KeyError:
        return Boolean(False)
    else:
        return Boolean(True)
def absolute_path(relative_path):
    """Return an absolute path for the given relative path, relative to the
    calling file.
    """
    expect_type(relative_path, String)
    # TODO i can't get the calling file until "rule" or something else helpful
    # is actually passed in!
    return String(os.path.abspath(relative_path.value))
Exemple #12
0
def variable_exists(namespace, name):
    expect_type(name, String)
    try:
        namespace.variable('$' + name.value)
    except KeyError:
        return Boolean(False)
    else:
        return Boolean(True)
Exemple #13
0
def invert(color):
    """Returns the inverse (negative) of a color.  The red, green, and blue
    values are inverted, while the opacity is left alone.
    """
    if isinstance(color, Number):
        # invert(n) and invert(n%) are CSS3 filters and should be left
        # intact
        return String.unquoted("invert(%s)" % (color.render(), ))

    expect_type(color, Color)
    r, g, b, a = color.rgba
    return Color.from_rgb(1 - r, 1 - g, 1 - b, alpha=a)
Exemple #14
0
def invert(color):
    """Returns the inverse (negative) of a color.  The red, green, and blue
    values are inverted, while the opacity is left alone.
    """
    if isinstance(color, Number):
        # invert(n) and invert(n%) are CSS3 filters and should be left
        # intact
        return String.unquoted("invert(%s)" % (color.render(),))

    expect_type(color, Color)
    r, g, b, a = color.rgba
    return Color.from_rgb(1 - r, 1 - g, 1 - b, alpha=a)
Exemple #15
0
def join_file_segments(*segments):
    """Join path parts into a single path, using the appropriate OS-specific
    delimiter.
    """
    parts = []
    for segment in segments:
        expect_type(segment, String)
        parts.append(segment.value)

    if parts:
        return String(os.path.join(*parts))
    else:
        return String('')
def join_file_segments(*segments):
    """Join path parts into a single path, using the appropriate OS-specific
    delimiter.
    """
    parts = []
    for segment in segments:
        expect_type(segment, String)
        parts.append(segment.value)

    if parts:
        return String(os.path.join(*parts))
    else:
        return String('')
Exemple #17
0
def global_variable_exists(namespace, name):
    expect_type(name, String)

    # TODO this is...  imperfect and invasive, but should be a good
    # approximation
    scope = namespace._variables
    while len(scope.maps) > 1:
        scope = scope.maps[-1]

    try:
        scope['$' + name.value]
    except KeyError:
        return Boolean(False)
    else:
        return Boolean(True)
Exemple #18
0
def global_variable_exists(namespace, name):
    expect_type(name, String)

    # TODO this is...  imperfect and invasive, but should be a good
    # approximation
    scope = namespace._variables
    while len(scope.maps) > 1:
        scope = scope.maps[-1]

    try:
        scope['$' + name.value]
    except KeyError:
        return Boolean(False)
    else:
        return Boolean(True)
Exemple #19
0
def _interpret_percentage(n, relto=1., clamp=True):
    expect_type(n, Number, unit='%')

    if n.is_unitless:
        ret = n.value / relto
    else:
        ret = n.value / 100

    if clamp:
        if ret < 0:
            return 0
        elif ret > 1:
            return 1

    return ret
Exemple #20
0
def _interpret_percentage(n, relto=1., clamp=True):
    expect_type(n, Number, unit='%')

    if n.is_unitless:
        ret = n.value / relto
    else:
        ret = n.value / 100

    if clamp:
        if ret < 0:
            return 0
        elif ret > 1:
            return 1

    return ret
Exemple #21
0
def nth(lst, n):
    """Return the nth item in the list."""
    expect_type(n, (String, Number), unit=None)

    if isinstance(n, String):
        if n.value.lower() == 'first':
            i = 0
        elif n.value.lower() == 'last':
            i = -1
        else:
            raise ValueError("Invalid index %r" % (n,))
    else:
        # DEVIATION: nth treats lists as circular lists
        i = n.to_python_index(len(lst), circular=True)

    return lst[i]
Exemple #22
0
def _scale_channel(channel, scaleby):
    if scaleby is None:
        return channel

    expect_type(scaleby, Number)
    if not scaleby.is_simple_unit('%'):
        raise ValueError("Expected percentage, got %r" % (scaleby,))

    factor = scaleby.value / 100
    if factor > 0:
        # Add x% of the remaining range, up to 1
        return channel + (1 - channel) * factor
    else:
        # Subtract x% of the existing channel.  We add here because the factor
        # is already negative
        return channel * (1 + factor)
Exemple #23
0
def _scale_channel(channel, scaleby):
    if scaleby is None:
        return channel

    expect_type(scaleby, Number)
    if not scaleby.is_simple_unit('%'):
        raise ValueError("Expected percentage, got %r" % (scaleby,))

    factor = scaleby.value / 100
    if factor > 0:
        # Add x% of the remaining range, up to 1
        return channel + (1 - channel) * factor
    else:
        # Subtract x% of the existing channel.  We add here because the factor
        # is already negative
        return channel * (1 + factor)
Exemple #24
0
def nth(lst, n):
    """Return the nth item in the list."""
    expect_type(n, (String, Number), unit=None)

    if isinstance(n, String):
        if n.value.lower() == 'first':
            i = 0
        elif n.value.lower() == 'last':
            i = -1
        else:
            raise ValueError("Invalid index %r" % (n,))
    else:
        # DEVIATION: nth treats lists as circular lists
        i = n.to_python_index(len(lst), circular=True)

    return lst[i]
Exemple #25
0
def nth(lst, n):
    """
    Return the Nth item in the string
    """
    expect_type(n, (String, Number), unit=None)

    if isinstance(n, String):
        if n.value.lower() == "first":
            i = 0
        elif n.value.lower() == "last":
            i = -1
        else:
            raise ValueError("Invalid index %r" % (n,))
    else:
        i = (int(n.value) - 1) % len(lst)

    return lst[i]
Exemple #26
0
def append(lst, val, separator=String.unquoted('auto')):
    expect_type(separator, String)

    ret = []
    ret.extend(List.from_maybe(lst))
    ret.append(val)

    separator = separator.value
    if separator == 'comma':
        use_comma = True
    elif separator == 'space':
        use_comma = False
    elif separator == 'auto':
        if len(lst) < 2:
            use_comma = False
        else:
            use_comma = lst.use_comma
    else:
        raise ValueError('Separator must be auto, comma, or space')

    return List(ret, use_comma=use_comma)
Exemple #27
0
def append(lst, val, separator=String.unquoted('auto')):
    expect_type(separator, String)

    ret = []
    ret.extend(List.from_maybe(lst))
    ret.append(val)

    separator = separator.value
    if separator == 'comma':
        use_comma = True
    elif separator == 'space':
        use_comma = False
    elif separator == 'auto':
        if len(lst) < 2:
            use_comma = False
        else:
            use_comma = lst.use_comma
    else:
        raise ValueError('Separator must be auto, comma, or space')

    return List(ret, use_comma=use_comma)
Exemple #28
0
def str_insert(string, insert, index):
    expect_type(string, String)
    expect_type(insert, String)
    expect_type(index, Number, unit=None)

    py_index = index.to_python_index(len(string.value), check_bounds=False)
    return String(string.value[:py_index] + insert.value + string.value[py_index:], quotes=string.quotes)
Exemple #29
0
def str_insert(string, insert, index):
    expect_type(string, String)
    expect_type(insert, String)
    expect_type(index, Number, unit=None)

    py_index = index.to_python_index(len(string.value), check_bounds=False)
    return String(
        string.value[:py_index] + insert.value + string.value[py_index:],
        quotes=string.quotes)
Exemple #30
0
def str_slice(string, start_at, end_at=None):
    expect_type(string, String)
    expect_type(start_at, Number, unit=None)
    py_start_at = start_at.to_python_index(len(string.value))

    if end_at is None:
        py_end_at = None
    else:
        expect_type(end_at, Number, unit=None)
        # Endpoint is inclusive, unlike Python
        py_end_at = end_at.to_python_index(len(string.value)) + 1

    return String(string.value[py_start_at:py_end_at], quotes=string.quotes)
Exemple #31
0
def str_slice(string, start_at, end_at=None):
    expect_type(string, String)
    expect_type(start_at, Number, unit=None)
    py_start_at = start_at.to_python_index(len(string.value))

    if end_at is None:
        py_end_at = None
    else:
        expect_type(end_at, Number, unit=None)
        # Endpoint is inclusive, unlike Python
        py_end_at = end_at.to_python_index(len(string.value)) + 1

    return String(
        string.value[py_start_at:py_end_at],
        quotes=string.quotes)
Exemple #32
0
def str_length(string):
    expect_type(string, String)

    # nb: can't use `len(string)`, because that gives the Sass list length,
    # which is 1
    return Number(len(string.value))
Exemple #33
0
def keywords(value):
    """Extract named arguments, as a map, from an argument list."""
    expect_type(value, Arglist)
    return value.extract_keywords()
Exemple #34
0
def split_filename(path):
    expect_type(path, String)
    dir_, file_ = os.path.split(path.value)
    base, ext = os.path.splitext(file_)
    return List([String(dir_), String(base), String(ext)], use_comma=False)
def split_filename(path):
    expect_type(path, String)
    dir_, file_ = os.path.split(path.value)
    base, ext = os.path.splitext(file_)
    return List([String(dir_), String(base), String(ext)], use_comma=False)
Exemple #36
0
def str_index(string, substring):
    expect_type(string, String)
    expect_type(substring, String)

    # 1-based indexing, with 0 for failure
    return Number(string.value.find(substring.value) + 1)
Exemple #37
0
def percentage(value):
    expect_type(value, Number, unit=None)
    return value * Number(100, unit='%')
Exemple #38
0
def to_lower_case(string):
    expect_type(string, String)

    return String(string.value.lower(), quotes=string.quotes)
Exemple #39
0
def str_index(string, substring):
    expect_type(string, String)
    expect_type(substring, String)

    # 1-based indexing, with 0 for failure
    return Number(string.value.find(substring.value) + 1)
Exemple #40
0
def str_length(string):
    expect_type(string, String)

    # nb: can't use `len(string)`, because that gives the Sass list length,
    # which is 1
    return Number(len(string.value))
Exemple #41
0
def to_lower_case(string):
    expect_type(string, String)

    return String(string.value.lower(), quotes=string.quotes)
Exemple #42
0
def percentage(value):
    expect_type(value, Number, unit=None)
    return value * Number(100, unit='%')
Exemple #43
0
def keywords(value):
    """Extract named arguments, as a map, from an argument list."""
    expect_type(value, Arglist)
    return value.extract_keywords()