tidy tool for Template Toolkit
Rev. | 9d9df820e560239e7c8f346c3484353712c572b4 |
---|---|
大小 | 5,873 字节 |
时间 | 2015-08-18 19:39:43 |
作者 | hylom |
Log Message | add SWITCH directive support
|
#!/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()