#!/usr/bin/env python # $Id: Indenter.py,v 1.7 2006/01/08 01:09:30 tavis_rudd Exp $ """Indentation maker. @@TR: this code is unsupported and largely undocumented ... This version is based directly on code by Robert Kuzelj and uses his directive syntax. Some classes and attributes have been renamed. Indentation is output via $self._CHEETAH__indenter.indent() to prevent '_indenter' being looked up on the searchList and another one being found. The directive syntax will soon be changed somewhat. Meta-Data ================================================================================ Author: Mike Orr License: This software is released for unlimited distribution under the terms of the MIT license. See the LICENSE file. Version: $Revision: 1.7 $ Start Date: 2001/11/07 Last Revision Date: $Date: 2006/01/08 01:09:30 $ """ __author__ = "Mike Orr " __revision__ = "$Revision: 1.7 $"[11:-2] import re import sys def indentize(source): return IndentProcessor().process(source) class IndentProcessor: """Preprocess #indent tags.""" LINE_SEP = '\n' ARGS = "args" INDENT_DIR = re.compile(r'[ \t]*#indent[ \t]*(?P.*)') DIRECTIVE = re.compile(r"[ \t]*#") WS = "ws" WHITESPACES = re.compile(r"(?P[ \t]*)") INC = "++" DEC = "--" SET = "=" CHAR = "char" ON = "on" OFF = "off" PUSH = "push" POP = "pop" def process(self, _txt): result = [] for line in _txt.splitlines(): match = self.INDENT_DIR.match(line) if match: #is indention directive args = match.group(self.ARGS).strip() if args == self.ON: line = "#silent $self._CHEETAH__indenter.on()" elif args == self.OFF: line = "#silent $self._CHEETAH__indenter.off()" elif args == self.INC: line = "#silent $self._CHEETAH__indenter.inc()" elif args == self.DEC: line = "#silent $self._CHEETAH__indenter.dec()" elif args.startswith(self.SET): level = int(args[1:]) line = "#silent $self._CHEETAH__indenter.setLevel(%(level)d)" % {"level":level} elif args.startswith('chars'): self.indentChars = eval(args.split('=')[1]) line = "#silent $self._CHEETAH__indenter.setChars(%(level)d)" % {"level":level} elif args.startswith(self.PUSH): line = "#silent $self._CHEETAH__indenter.push()" elif args.startswith(self.POP): line = "#silent $self._CHEETAH__indenter.pop()" else: match = self.DIRECTIVE.match(line) if not match: #is not another directive match = self.WHITESPACES.match(line) if match: size = len(match.group("ws").expandtabs(4)) line = ("${self._CHEETAH__indenter.indent(%(size)d)}" % {"size":size}) + line.lstrip() else: line = "${self._CHEETAH__indenter.indent(0)}" + line result.append(line) return self.LINE_SEP.join(result) class Indenter: """A class that keeps track of the current indentation level. .indent() returns the appropriate amount of indentation. """ def __init__(self): self.On = 1 self.Level = 0 self.Chars = " "*4 self.LevelStack = [] def on(self): self.On = 1 def off(self): self.On = 0 def inc(self): self.Level += 1 def dec(self): """decrement can only be applied to values greater zero values below zero don't make any sense at all!""" if self.Level > 0: self.Level -= 1 def push(self): self.LevelStack.append(self.Level) def pop(self): """the levestack can not become -1. any attempt to do so sets the level to 0!""" if len(self.LevelStack) > 0: self.Level = self.LevelStack.pop() else: self.Level = 0 def setLevel(self, _level): """the leve can't be less than zero. any attempt to do so sets the level automatically to zero!""" if _level < 0: self.Level = 0 else: self.Level = _level def setChar(self, _chars): self.Chars = _chars def indent(self, _default=0): if self.On: return self.Chars * self.Level else: return " " * _default