• R/O
  • HTTP
  • SSH
  • HTTPS

标签
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

tidy tool for Template Toolkit


File Info

Rev. 9d9df820e560239e7c8f346c3484353712c572b4
大小 5,873 字节
时间 2015-08-18 19:39:43
作者 hylom
Log Message

add SWITCH directive support

Content

#!/usr/bin/python

'''
tttidy - tidy tool for template toolkit
'''

import sys
import re
import argparse

USAGE = '''  tttidy - tidy tool for template toolkit
  usage: tttidy <file>
'''

INDENT_LENGTH = 4
INDENT_CHAR = ' '
START_TAG = r'\[%-?'
END_TAG = r'-?%]'

class Indenter(object):
    '''Object for indenting template'''
    def __init__(self, debug=False):
        '''Initializer'''
        self.indent_length = INDENT_LENGTH
        self.indent_char = INDENT_CHAR
        self.start_tag = re.compile(START_TAG)
        self.end_tag = re.compile(END_TAG)
        self.reset()
        self.debug = debug

    def debug_print(self, s):
        if self.debug:
            sys.stderr.write(s + '\n')

    def reset(self):
        self._in_template = False
        self._indent_level = 0

    def indent(self, template):
        directives = self.extract_directives(template)
        ret = []
        lv = 0
        for ln in range(len(template)):
            (cur, nex) = self._calc_indent_level(directives[ln])
            ret.append(self.indent_char * self.indent_length * (lv + cur) + template[ln].strip())
            lv += nex + cur

        return ret

    def extract_directives(self, template):
        ret = []
        for line in template:
            ret.append(self._line_scan(line.strip()))
        # strip comments
        def _strip_comment(line):
            c = line.find('#')
            if c == -1:
                return line
            else:
                return line[0:c]
        ret = [_strip_comment(x).strip() for x in ret]
        return ret

    def _line_scan(self, line):
        if self._in_template:
            #cursor = line.find(self.end_tag)
            m = self.end_tag.search(line)
            if m == None:
                return line
            else:
                cursor = m.start()
                offset = m.end() - m.start()
                body = line[:cursor].rstrip() + ';'
                offset = 2
                rest = line[cursor + offset:]
                self._in_template = False
                return body + self._line_scan(rest)
        else:
            #cursor = line.find(self.start_tag)
            m = self.start_tag.search(line)
            if m == None:
                return ''
            else:
                cursor = m.start()
                offset = m.end() - m.start()
                rest = line[cursor + offset:]
                self._in_template = True
                return self._line_scan(rest)
    
    def _calc_indent_level(self, line):
        if len(line) == 0:
            return (0, 0)

        self.debug_print(line)

        count_if = len(re.findall(u'^(IF|FOREACH|SWITCH)\s', line))
        count_if += len(re.findall(u'\s(IF|FOREACH|SWITCH)\s', line))
        count_if += len(re.findall(u'^BLOCK(\s|;)', line))
        count_if += len(re.findall(u'\sBLOCK(\s|;)', line))
        count_end = len(re.findall(u'^END(\s|;)', line))
        count_end += len(re.findall(u'(\s|;)END(\s|;)', line))
        count_end += len(re.findall(u'^END$', line))
        count_end += len(re.findall(u'(\s|;)END$', line))
        count_elsif = len(re.findall(u'^ELSIF\s', line))
        count_elsif += len(re.findall(u'(\s|;)ELSIF\s', line))
        count_elsif += len(re.findall(u'^ELSE(\s|;)', line))
        count_elsif += len(re.findall(u'(\s|;)ELSE(\s|;)', line))
        count_elsif += len(re.findall(u'^ELSE$', line))
        count_elsif += len(re.findall(u'(|;)\sELSE$', line))

        # support for "PROCESS xxx IF" style
        if re.search(r'PROCESS\s+[^;]+\s+IF', line):
            count_if -= 1

        counter_current = 0
        counter_next = 0
        # case: IF - ELSIF - ELSE - END directives all exists in one line
        if count_if == count_end and count_if > 0 and count_elsif > 0:
            self.debug_print("if:{} end:{} elsif:{} cc:{} cn:{}".format(count_if, count_end, count_elsif, counter_current, counter_next))
            return (counter_current, counter_next)

        # else
        if count_if > count_end:
            count_if -= count_end
            count_end = 0
        else:
            count_end -= count_if
            count_if = 0

        if count_if > 0:
            counter_next += 1
        elif count_end > 0:
            counter_current -= 1
        elif count_elsif > 0 and count_if == 0:
            counter_current -= 1
            counter_next += 1

        self.debug_print("if:{} end:{} elsif:{} cc:{} cn:{}".format(count_if, count_end, count_elsif, counter_current, counter_next))
        return (counter_current, counter_next)


def _error_exit(msg=None):
    if msg != None:
        print >> sys.stderr, msg
    else:
        sys.stderr.write(USAGE)
    sys.exit(-1)

def indent(template, debug=False):
    '''add indent'''
    indenter = Indenter(debug)
    r = indenter.indent(template)
    return r

def unindent(template):
    '''unindet template'''
    buf = []
    for l in template:
        buf.append(l.strip())
    return buf

def main():
    '''tttidy main routine'''
    parser = argparse.ArgumentParser('tidy tool for template toolkit')
    parser.add_argument('file', type=file)
    parser.add_argument('--unindent', '-u', action='store_true')
    parser.add_argument('--directives', action='store_true')
    parser.add_argument('--debug', action='store_true')

    args = parser.parse_args()

    # when '--directives' is given, extract directives
    # this is for debug
    if args.directives:
        indenter = Indenter()
        r = indenter.extract_directives(args.file)
        print "\n".join(r)
        return

    # when '--unindent' is given, do unindent
    if args.unindent:
        ret = unindent(args.file)
        print "\n".join(ret)
        return

    # do indent
    ret = unindent(args.file)
    ret = indent(ret, args.debug)
    print "\n".join(ret)


if __name__ == '__main__':
    main()