[3] | 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 | |
---|