#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ----------------------------------------------------------------
# cssqc/indentation.py
# 
# Do not allow descendant selectors.
# (e.g. div > a {} is ok, but div a {} is not)
# ----------------------------------------------------------------
# copyright (c) 2014 - <NAME>
# Distributed under The MIT License, see LICENSE
# ----------------------------------------------------------------

from cssqc.qualityWarning import QualityWarning
from cssqc.helpers import inspectWhitespaces, isLast
from cssyacc import Whitespace, Statement

def getHelp():
    return """Ensure proper indentation. OPT can be integer number of spaces or 'tab'.
Allows right align for properties with same suffix."""

class indentation:
    def __init__(self, data):
        if data == 'tab':
            self.indent = '\t'
        else:
            self.indent = ' '*int(data)

    def afterParse(self, result):
        warnings = []
        
        # parse everything not in rulesets
        for el in result:
            ln = inspectWhitespaces(el, \
                    lambda ws: (not '\n' in ws.value) or ws.value.endswith('\n'))
            if ln != -1:
                warnings.append(QualityWarning('indentation', ln+1, \
                    'Incorrect indentation outside of block.'))

        return warnings

    def on_Ruleset(self, rs):
        warnings = []
        
        # parse selector indent
        for s in rs.selectors:
            ln = inspectWhitespaces(s, lambda ws: (not '\n' in ws.value) or ws.value.endswith('\n'+self.indent*rs.depth))
            if ln != -1:
                warnings.append(QualityWarning('indentation', ln+1, \
                    'Incorrect indentation in selector.'))
        
        # vars for align enable
        carry = 0
        last_length = 0
        last_suffix = ''
        
        # parse block elements
        for i in range(len(rs.block.elements)):
            el = rs.block.elements[i]

            # last whitespace is for closing brace
            if isLast(i, rs.block.elements) \
                and type(el) is Whitespace:
                if not (('\n' not in el.value) or el.value.endswith('\n'+self.indent*rs.depth)):
                    warnings.append(QualityWarning('indentation', el.lineno+1, \
                        'Incorect indentation of closing braces.'))
                    
            # whitespace can have additional spaces for alignment
            elif type(el) is Whitespace:
                if not (('\n' not in el.value) or el.value.endswith('\n'+self.indent*(rs.depth+1))):
                    nextElement = None
                    if not isLast(i, rs.block.elements):
                        nextElement = rs.block.elements[i+1]
                    
                    if type(nextElement) is Statement \
                        and type(nextElement.text[0]) is tuple \
                        and nextElement.text[0][0].endswith(last_suffix) \
                        and el.value.endswith('\n'+self.indent*(rs.depth+1)+' '*(last_length - len(nextElement.text[0][0]))):
                        carry = (last_length - len(nextElement.text[0][0]))
                    else:
                        warnings.append(QualityWarning('indentation', el.lineno+1, \
                            'Incorect indentation in block.'))
            
            # store first tuple length and suffix for alignment
            elif type(el) is Statement:
                if type(el.text[0]) is tuple:
                    last_length = carry + len(el.text[0][0])
                    last_suffix = el.text[0][0][-5:]
                    carry = 0

                ln = inspectWhitespaces(el, \
                    lambda ws: (not '\n' in ws.value) or ws.value.endswith('\n'+self.indent*(rs.depth+1)))
                if ln != -1:
                    warnings.append(QualityWarning('indentation', ln+1, \
                        'Incorect indentation in block.'))
            
            # parse everything else
            else:
                ln = inspectWhitespaces(el, \
                    lambda ws: (not '\n' in ws.value) or ws.value.endswith('\n'+self.indent*(rs.depth+1)))
                if ln != -1:
                    warnings.append(QualityWarning('indentation', ln+1, \
                        'Incorect indentation in block.'))
            
        return warnings

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ----------------------------------------------------------------
# cssqc/indentation.py
# 
# Do not allow descendant selectors.
# (e.g. div > a {} is ok, but div a {} is not)
# ----------------------------------------------------------------
# copyright (c) 2014 - <NAME>
# Distributed under The MIT License, see LICENSE
# ----------------------------------------------------------------

from cssqc.qualityWarning import QualityWarning
from cssqc.helpers import inspectWhitespaces, isLast
from cssyacc import Whitespace, Statement

def getHelp():
    return """Ensure proper indentation. OPT can be integer number of spaces or 'tab'.
Allows right align for properties with same suffix."""

class indentation:
    def __init__(self, data):
        if data == 'tab':
            self.indent = '\t'
        else:
            self.indent = ' '*int(data)

    def afterParse(self, result):
        warnings = []
        
        # parse everything not in rulesets
        for el in result:
            ln = inspectWhitespaces(el, \
                    lambda ws: (not '\n' in ws.value) or ws.value.endswith('\n'))
            if ln != -1:
                warnings.append(QualityWarning('indentation', ln+1, \
                    'Incorrect indentation outside of block.'))

        return warnings

    def on_Ruleset(self, rs):
        warnings = []
        
        # parse selector indent
        for s in rs.selectors:
            ln = inspectWhitespaces(s, lambda ws: (not '\n' in ws.value) or ws.value.endswith('\n'+self.indent*rs.depth))
            if ln != -1:
                warnings.append(QualityWarning('indentation', ln+1, \
                    'Incorrect indentation in selector.'))
        
        # vars for align enable
        carry = 0
        last_length = 0
        last_suffix = ''
        
        # parse block elements
        for i in range(len(rs.block.elements)):
            el = rs.block.elements[i]

            # last whitespace is for closing brace
            if isLast(i, rs.block.elements) \
                and type(el) is Whitespace:
                if not (('\n' not in el.value) or el.value.endswith('\n'+self.indent*rs.depth)):
                    warnings.append(QualityWarning('indentation', el.lineno+1, \
                        'Incorect indentation of closing braces.'))
                    
            # whitespace can have additional spaces for alignment
            elif type(el) is Whitespace:
                if not (('\n' not in el.value) or el.value.endswith('\n'+self.indent*(rs.depth+1))):
                    nextElement = None
                    if not isLast(i, rs.block.elements):
                        nextElement = rs.block.elements[i+1]
                    
                    if type(nextElement) is Statement \
                        and type(nextElement.text[0]) is tuple \
                        and nextElement.text[0][0].endswith(last_suffix) \
                        and el.value.endswith('\n'+self.indent*(rs.depth+1)+' '*(last_length - len(nextElement.text[0][0]))):
                        carry = (last_length - len(nextElement.text[0][0]))
                    else:
                        warnings.append(QualityWarning('indentation', el.lineno+1, \
                            'Incorect indentation in block.'))
            
            # store first tuple length and suffix for alignment
            elif type(el) is Statement:
                if type(el.text[0]) is tuple:
                    last_length = carry + len(el.text[0][0])
                    last_suffix = el.text[0][0][-5:]
                    carry = 0

                ln = inspectWhitespaces(el, \
                    lambda ws: (not '\n' in ws.value) or ws.value.endswith('\n'+self.indent*(rs.depth+1)))
                if ln != -1:
                    warnings.append(QualityWarning('indentation', ln+1, \
                        'Incorect indentation in block.'))
            
            # parse everything else
            else:
                ln = inspectWhitespaces(el, \
                    lambda ws: (not '\n' in ws.value) or ws.value.endswith('\n'+self.indent*(rs.depth+1)))
                if ln != -1:
                    warnings.append(QualityWarning('indentation', ln+1, \
                        'Incorect indentation in block.'))
            
        return warnings

#!/usr/bin/env python3 # -*- coding: utf-8 -*- # ---------------------------------------------------------------- # cssqc/indentation.py # # Do not allow descendant selectors. # (e.g. div > a {} is ok, but div a {} is not) # ---------------------------------------------------------------- # copyright (c) 2014 - <NAME> # Distributed under The MIT License, see LICENSE # ---------------------------------------------------------------- Ensure proper indentation. OPT can be integer number of spaces or 'tab'. Allows right align for properties with same suffix. # parse everything not in rulesets # parse selector indent # vars for align enable # parse block elements # last whitespace is for closing brace # whitespace can have additional spaces for alignment # store first tuple length and suffix for alignment # parse everything else