1 | """ |
---|
2 | Indentation maker. |
---|
3 | @@TR: this code is unsupported and largely undocumented ... |
---|
4 | |
---|
5 | This version is based directly on code by Robert Kuzelj |
---|
6 | <robert_kuzelj@yahoo.com> and uses his directive syntax. Some classes and |
---|
7 | attributes have been renamed. Indentation is output via |
---|
8 | $self._CHEETAH__indenter.indent() to prevent '_indenter' being looked up on the |
---|
9 | searchList and another one being found. The directive syntax will |
---|
10 | soon be changed somewhat. |
---|
11 | """ |
---|
12 | |
---|
13 | import re |
---|
14 | import sys |
---|
15 | |
---|
16 | def indentize(source): |
---|
17 | return IndentProcessor().process(source) |
---|
18 | |
---|
19 | class IndentProcessor(object): |
---|
20 | """Preprocess #indent tags.""" |
---|
21 | LINE_SEP = '\n' |
---|
22 | ARGS = "args" |
---|
23 | INDENT_DIR = re.compile(r'[ \t]*#indent[ \t]*(?P<args>.*)') |
---|
24 | DIRECTIVE = re.compile(r"[ \t]*#") |
---|
25 | WS = "ws" |
---|
26 | WHITESPACES = re.compile(r"(?P<ws>[ \t]*)") |
---|
27 | |
---|
28 | INC = "++" |
---|
29 | DEC = "--" |
---|
30 | |
---|
31 | SET = "=" |
---|
32 | CHAR = "char" |
---|
33 | |
---|
34 | ON = "on" |
---|
35 | OFF = "off" |
---|
36 | |
---|
37 | PUSH = "push" |
---|
38 | POP = "pop" |
---|
39 | |
---|
40 | def process(self, _txt): |
---|
41 | result = [] |
---|
42 | |
---|
43 | for line in _txt.splitlines(): |
---|
44 | match = self.INDENT_DIR.match(line) |
---|
45 | if match: |
---|
46 | #is indention directive |
---|
47 | args = match.group(self.ARGS).strip() |
---|
48 | if args == self.ON: |
---|
49 | line = "#silent $self._CHEETAH__indenter.on()" |
---|
50 | elif args == self.OFF: |
---|
51 | line = "#silent $self._CHEETAH__indenter.off()" |
---|
52 | elif args == self.INC: |
---|
53 | line = "#silent $self._CHEETAH__indenter.inc()" |
---|
54 | elif args == self.DEC: |
---|
55 | line = "#silent $self._CHEETAH__indenter.dec()" |
---|
56 | elif args.startswith(self.SET): |
---|
57 | level = int(args[1:]) |
---|
58 | line = "#silent $self._CHEETAH__indenter.setLevel(%(level)d)" % {"level":level} |
---|
59 | elif args.startswith('chars'): |
---|
60 | self.indentChars = eval(args.split('=')[1]) |
---|
61 | line = "#silent $self._CHEETAH__indenter.setChars(%(level)d)" % {"level":level} |
---|
62 | elif args.startswith(self.PUSH): |
---|
63 | line = "#silent $self._CHEETAH__indenter.push()" |
---|
64 | elif args.startswith(self.POP): |
---|
65 | line = "#silent $self._CHEETAH__indenter.pop()" |
---|
66 | else: |
---|
67 | match = self.DIRECTIVE.match(line) |
---|
68 | if not match: |
---|
69 | #is not another directive |
---|
70 | match = self.WHITESPACES.match(line) |
---|
71 | if match: |
---|
72 | size = len(match.group("ws").expandtabs(4)) |
---|
73 | line = ("${self._CHEETAH__indenter.indent(%(size)d)}" % {"size":size}) + line.lstrip() |
---|
74 | else: |
---|
75 | line = "${self._CHEETAH__indenter.indent(0)}" + line |
---|
76 | result.append(line) |
---|
77 | |
---|
78 | return self.LINE_SEP.join(result) |
---|
79 | |
---|
80 | class Indenter(object): |
---|
81 | """ |
---|
82 | A class that keeps track of the current indentation level. |
---|
83 | .indent() returns the appropriate amount of indentation. |
---|
84 | """ |
---|
85 | On = 1 |
---|
86 | Level = 0 |
---|
87 | Chars = ' ' |
---|
88 | LevelStack = [] |
---|
89 | |
---|
90 | def on(self): |
---|
91 | self.On = 1 |
---|
92 | def off(self): |
---|
93 | self.On = 0 |
---|
94 | def inc(self): |
---|
95 | self.Level += 1 |
---|
96 | def dec(self): |
---|
97 | """decrement can only be applied to values greater zero |
---|
98 | values below zero don't make any sense at all!""" |
---|
99 | if self.Level > 0: |
---|
100 | self.Level -= 1 |
---|
101 | def push(self): |
---|
102 | self.LevelStack.append(self.Level) |
---|
103 | def pop(self): |
---|
104 | """the levestack can not become -1. any attempt to do so |
---|
105 | sets the level to 0!""" |
---|
106 | if len(self.LevelStack) > 0: |
---|
107 | self.Level = self.LevelStack.pop() |
---|
108 | else: |
---|
109 | self.Level = 0 |
---|
110 | def setLevel(self, _level): |
---|
111 | """the leve can't be less than zero. any attempt to do so |
---|
112 | sets the level automatically to zero!""" |
---|
113 | if _level < 0: |
---|
114 | self.Level = 0 |
---|
115 | else: |
---|
116 | self.Level = _level |
---|
117 | def setChar(self, _chars): |
---|
118 | self.Chars = _chars |
---|
119 | def indent(self, _default=0): |
---|
120 | if self.On: |
---|
121 | return self.Chars * self.Level |
---|
122 | return " " * _default |
---|
123 | |
---|