#============================================================================ # This library is free software; you can redistribute it and/or # modify it under the terms of version 2.1 of the GNU Lesser General Public # License as published by the Free Software Foundation. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #============================================================================ # Copyright (C) 2004, 2005 Mike Wray # Copyright (C) 2005 XenSource Ltd #============================================================================ """General pretty-printer, including support for SXP. """ import sys import types import StringIO #from xen.xend import sxp import cloud_sxp as sxp class PrettyItem: def __init__(self, width): self.width = width def insert(self, block): block.addtoline(self) def get_width(self): return self.width def output(self, _): print '***PrettyItem>output>', self pass def prettyprint(self, _): print '***PrettyItem>prettyprint>', self return self.width class PrettyString(PrettyItem): def __init__(self, x): PrettyItem.__init__(self, len(x)) self.value = x def output(self, out): out.write(self.value) def prettyprint(self, line): line.output(self) def show(self, out): print >> out, ("(string (width %d) '%s')" % (self.width, self.value)) class PrettySpace(PrettyItem): def output(self, out): out.write(' ' * self.width) def prettyprint(self, line): line.output(self) def show(self, out): print >> out, ("(space (width %d))" % self.width) class PrettyBreak(PrettyItem): def __init__(self, width, indent): PrettyItem.__init__(self, width) self.indent = indent self.space = 0 self.active = 0 def output(self, out): out.write(' ' * self.width) def prettyprint(self, line): if line.breaks(self.space): self.active = 1 line.newline(self.indent) else: line.output(self) def show(self, out): print >> out, ("(break (width %d) (indent %d) (space %d) (active %d))" % (self.width, self.indent, self.space, self.active)) class PrettyNewline(PrettySpace): def insert(self, block): block.newline() block.addtoline(self) def prettyprint(self, line): line.newline(0) line.output(self) def show(self, out): print >> out, ("(nl (width %d))" % self.width) class PrettyLine(PrettyItem): def __init__(self): PrettyItem.__init__(self, 0) self.content = [] def write(self, x): self.content.append(x) def end(self): width = 0 lastwidth = 0 lastbreak = None for x in self.content: if isinstance(x, PrettyBreak): if lastbreak: lastbreak.space = (width - lastwidth) lastbreak = x lastwidth = width width += x.get_width() if lastbreak: lastbreak.space = (width - lastwidth) self.width = width def prettyprint(self, line): for x in self.content: x.prettyprint(line) def show(self, out): print >> out, '(LINE (width %d)' % self.width for x in self.content: x.show(out) print >> out, ')' class PrettyBlock(PrettyItem): def __init__(self, all=0, parent=None): PrettyItem.__init__(self, 0) self.lines = [] self.parent = parent self.indent = 0 self.all = all self.broken = 0 self.newline() def add(self, item): item.insert(self) def end(self): self.width = 0 for l in self.lines: l.end() if self.width < l.width: self.width = l.width def breaks(self, _): return self.all and self.broken def newline(self): self.lines.append(PrettyLine()) def addtoline(self, x): self.lines[-1].write(x) def prettyprint(self, line): self.indent = line.used line.block = self if not line.fits(self.width): self.broken = 1 for l in self.lines: l.prettyprint(line) line.block = self.parent def show(self, out): print >> out, ('(BLOCK (width %d) (indent %d) (all %d) (broken %d)' % (self.width, self.indent, self.all, self.broken)) for l in self.lines: l.show(out) print >> out, ')' class Line: def __init__(self, out, width): self.block = None self.out = out self.width = width self.used = 0 self.space = self.width def newline(self, indent): indent += self.block.indent self.out.write('\n') self.out.write(' ' * indent) self.used = indent self.space = self.width - self.used def fits(self, n): return self.space - n >= 0 def breaks(self, n): return self.block.breaks(n) or not self.fits(n) def output(self, x): n = x.get_width() self.space -= n self.used += n if self.space < 0: self.space = 0 x.output(self.out) class PrettyPrinter: """A prettyprinter based on what I remember of Derek Oppen's prettyprint algorithm from TOPLAS way back. """ def __init__(self, width=40): self.width = width self.block = None self.top = None def write(self, x): self.block.add(PrettyString(x)) def add(self, item): self.block.add(item) def addbreak(self, width=1, indent=4): self.add(PrettyBreak(width, indent)) def addspace(self, width=1): self.add(PrettySpace(width)) def addnl(self, indent=0): self.add(PrettyNewline(indent)) def begin(self, all=0): block = PrettyBlock(all=all, parent=self.block) self.block = block def end(self): self.block.end() if self.block.parent: self.block.parent.add(self.block) else: self.top = self.block self.block = self.block.parent def prettyprint(self, out=sys.stdout): self.top.prettyprint(Line(out, self.width)) class SXPPrettyPrinter(PrettyPrinter): """An SXP prettyprinter. """ def pstring(self, x): io = StringIO.StringIO() sxp.show(x, out=io) io.seek(0) val = io.getvalue() io.close() return val def pprint(self, l): if isinstance(l, types.ListType): self.begin(all=1) self.write('(') i = 0 for x in l: if(i): self.addbreak() self.pprint(x) i += 1 self.addbreak(width=0, indent=0) self.write(')') self.end() else: self.write(self.pstring(l)) def prettyprint(sxpr, out=sys.stdout, width=80): """Prettyprint an SXP form. sxpr s-expression out destination width maximum output width """ if isinstance(sxpr, types.ListType): pp = SXPPrettyPrinter(width=width) pp.pprint(sxpr) pp.prettyprint(out=out) else: sxp.show(sxpr, out=out) print >> out def prettyprintstring(sxpr, width=80): """Prettyprint an SXP form to a string. sxpr s-expression width maximum output width """ io = StringIO.StringIO() prettyprint(sxpr, out=io, width=width) io.seek(0) val = io.getvalue() io.close() return val def main(): pin = sxp.Parser() while 1: buf = sys.stdin.read(100) pin.input(buf) if buf == '': break l = pin.get_val() prettyprint(l, width=80) if __name__ == "__main__": main()