Merge branch 'master' into subfolders-8.3
[pyTivo.git] / Cheetah / Utils / Indenter.py
blobabdb0dde686b1a42f06f2a903233acf566a1c0c1
1 #!/usr/bin/env python
2 # $Id: Indenter.py,v 1.7 2006/01/08 01:09:30 tavis_rudd Exp $
3 """Indentation maker.
4 @@TR: this code is unsupported and largely undocumented ...
6 This version is based directly on code by Robert Kuzelj
7 <robert_kuzelj@yahoo.com> and uses his directive syntax. Some classes and
8 attributes have been renamed. Indentation is output via
9 $self._CHEETAH__indenter.indent() to prevent '_indenter' being looked up on the
10 searchList and another one being found. The directive syntax will
11 soon be changed somewhat.
13 Meta-Data
14 ================================================================================
15 Author: Mike Orr <iron@mso.oz.net>
16 License: This software is released for unlimited distribution under the
17 terms of the MIT license. See the LICENSE file.
18 Version: $Revision: 1.7 $
19 Start Date: 2001/11/07
20 Last Revision Date: $Date: 2006/01/08 01:09:30 $
21 """
22 __author__ = "Mike Orr <iron@mso.oz.net>"
23 __revision__ = "$Revision: 1.7 $"[11:-2]
25 import re
26 import sys
28 def indentize(source):
29 return IndentProcessor().process(source)
31 class IndentProcessor:
32 """Preprocess #indent tags."""
33 LINE_SEP = '\n'
34 ARGS = "args"
35 INDENT_DIR = re.compile(r'[ \t]*#indent[ \t]*(?P<args>.*)')
36 DIRECTIVE = re.compile(r"[ \t]*#")
37 WS = "ws"
38 WHITESPACES = re.compile(r"(?P<ws>[ \t]*)")
40 INC = "++"
41 DEC = "--"
43 SET = "="
44 CHAR = "char"
46 ON = "on"
47 OFF = "off"
49 PUSH = "push"
50 POP = "pop"
52 def process(self, _txt):
53 result = []
55 for line in _txt.splitlines():
56 match = self.INDENT_DIR.match(line)
57 if match:
58 #is indention directive
59 args = match.group(self.ARGS).strip()
60 if args == self.ON:
61 line = "#silent $self._CHEETAH__indenter.on()"
62 elif args == self.OFF:
63 line = "#silent $self._CHEETAH__indenter.off()"
64 elif args == self.INC:
65 line = "#silent $self._CHEETAH__indenter.inc()"
66 elif args == self.DEC:
67 line = "#silent $self._CHEETAH__indenter.dec()"
68 elif args.startswith(self.SET):
69 level = int(args[1:])
70 line = "#silent $self._CHEETAH__indenter.setLevel(%(level)d)" % {"level":level}
71 elif args.startswith('chars'):
72 self.indentChars = eval(args.split('=')[1])
73 line = "#silent $self._CHEETAH__indenter.setChars(%(level)d)" % {"level":level}
74 elif args.startswith(self.PUSH):
75 line = "#silent $self._CHEETAH__indenter.push()"
76 elif args.startswith(self.POP):
77 line = "#silent $self._CHEETAH__indenter.pop()"
78 else:
79 match = self.DIRECTIVE.match(line)
80 if not match:
81 #is not another directive
82 match = self.WHITESPACES.match(line)
83 if match:
84 size = len(match.group("ws").expandtabs(4))
85 line = ("${self._CHEETAH__indenter.indent(%(size)d)}" % {"size":size}) + line.lstrip()
86 else:
87 line = "${self._CHEETAH__indenter.indent(0)}" + line
88 result.append(line)
90 return self.LINE_SEP.join(result)
92 class Indenter:
93 """A class that keeps track of the current indentation level.
94 .indent() returns the appropriate amount of indentation.
95 """
96 def __init__(self):
97 self.On = 1
98 self.Level = 0
99 self.Chars = " "*4
100 self.LevelStack = []
101 def on(self):
102 self.On = 1
103 def off(self):
104 self.On = 0
105 def inc(self):
106 self.Level += 1
107 def dec(self):
108 """decrement can only be applied to values greater zero
109 values below zero don't make any sense at all!"""
110 if self.Level > 0:
111 self.Level -= 1
112 def push(self):
113 self.LevelStack.append(self.Level)
114 def pop(self):
115 """the levestack can not become -1. any attempt to do so
116 sets the level to 0!"""
117 if len(self.LevelStack) > 0:
118 self.Level = self.LevelStack.pop()
119 else:
120 self.Level = 0
121 def setLevel(self, _level):
122 """the leve can't be less than zero. any attempt to do so
123 sets the level automatically to zero!"""
124 if _level < 0:
125 self.Level = 0
126 else:
127 self.Level = _level
128 def setChar(self, _chars):
129 self.Chars = _chars
130 def indent(self, _default=0):
131 if self.On:
132 return self.Chars * self.Level
133 else:
134 return " " * _default