1. Brian Mearns
  2. tome

Source

tome / src / tome / writeText.py

#!/usr/bin/python
"""
Copyright 2013 Brian Mearns

This file is part of Tome.

Tome is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Tome 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 Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with Tome.  If not, see <http://www.gnu.org/licenses/>.
"""
import Tome
import TextOutput
import sys
import AbstractWriter
import cStringIO

class TextWriter(AbstractWriter.AbstractWriter):
    __TEXT_OBJECT_MAP = {
        "ellips": "...",
        "md": "---",
        "nd": "--",
    }

    __FORMAT_MAP = {
        "b": "*",
        "i": "/",
        "em": "**",
        "u": "_",
    }

    def __init__(self, ostream=sys.stdout, linewidth=78):
        super(TextWriter, self).__init__()

        self.__linewidth = linewidth
        self.__writer = TextOutput.TextOutput(ostream, linewidth, initialLines=0)

        self.__chapterNotes = []
        self.__noteNumber = 1


    def _closePar(self, par):
        self.__writer.blankline()

    def _writeAccent(self, tag, char, segment):
        self.__writer.write(char)

    def _writeTextObject(self, tag, segment):
        if tag == "lnbrk":
            self.__writer.newline()
        elif tag == "sp":
            self.__writer.space()
        elif tag in TextWriter.__TEXT_OBJECT_MAP:
            self.__writer.write(TextWriter.__TEXT_OBJECT_MAP[tag])
        else:
            raise Exception("Unsupported text object '%s'." % tag)

    def _writeOut(self, string):
        self.__writer.write(string)

    def _formatSuffix(self, tag, segment):
        if tag in TextWriter.__FORMAT_MAP:
            return TextWriter.__FORMAT_MAP[tag]
        else:
            raise Exception("Unsupported format tag '%s'." % tag)
        
    def _formatPrefix(self, tag, segment):
        if tag in TextWriter.__FORMAT_MAP:
            return TextWriter.__FORMAT_MAP[tag]
        else:
            raise Exception("Unsupported format tag '%s'." % tag)

    def _finishBlockSegment(self, tag, segment):
        if tag == "q":
            self.__writer.write('"')
        elif tag == "sq":
            self.__writer.write("'")
        elif tag == "bq":
            self.__writer.write('"')
            self.__writer.blankline()
            self.__writer.outdent()
            self.__writer.rightOutdent()
        
    def _prepareBlockSegment(self, tag, segment):
        if tag == "q":
            self.__writer.write('"')
        elif tag == "sq":
            self.__writer.write("'")
        elif tag == "bq":
            self.__writer.blankline()
            self.__writer.indent()
            self.__writer.rightIndent()
            self.__writer.write('"')
        
    def _prepareScene(self, scene, firstScene):
        if not firstScene:
            self.__writer.justifyCenter()
            self.__writer.write("***")
            self.__writer.blankline()
            self.__writer.popJustify()

    def _finishParagraph(self, par, lastPar):
        self.__writer.blankline()

    def _preparePreformatted(self, par, firstPar):
        if not firstPar:
            self.__writer.blankline()
        self.__writer.preformatted = True
        self.__writer.indent()

    def _finishPreformatted(self, par, lastPar):
        self.__writer.outdent()
        self.__writer.preformatted = False

    def _writePartTitle(self, part):
        if part.title() is None:
            return

        self.__writer.flush()
        self.__writer.justifyCenter()
        for i in xrange(4):
            self.__writer.blankline()
        self.__writer.hr(fill=0.6, c='=')
        for i in xrange(3):
            self.__writer.blankline()

        string = "PART %d" % (
            self.getNumber(AbstractWriter.LEVEL_PART),
        )
        self.__writer.write(string)

        titles = part.allTitles()
        titleCount = len(titles)
        if titleCount > 0:
            self.__writer.blankline()
            for i in xrange(titleCount):
                self.__writer.write(titles[i])
                self.__writer.newline()

        self.__writer.blankline()
        self.__writer.flush()
        self.__writer.popJustify()

    def _writeBookTitle(self, book):

        self.__writer.flush()
        self.__writer.justifyCenter()

        hasPart = self.part.title() is not None
        hasBook = book.title() is not None
        firstBook = (self.getNumber(AbstractWriter.LEVEL_BOOK) == 1) and hasPart

        if hasBook:

            if firstBook:
                self.__writer.blankline()
                self.__writer.blankline()
                self.__writer.write("-----")
                self.__writer.blankline()
                self.__writer.blankline()
                self.__writer.write("Book %d" % (
                    self.getNumber(AbstractWriter.LEVEL_BOOK)
                ))

            else:
                self.__writer.blankline()
                self.__writer.blankline()
                self.__writer.hr(fill=0.4)
                self.__writer.blankline()
                self.__writer.blankline()
                self.__writer.blankline()

                if hasPart:
                    self.__writer.write("Part %d, " % self.getNumber(AbstractWriter.LEVEL_PART))
                self.__writer.write("Book %d" % self.getNumber(AbstractWriter.LEVEL_BOOK))

            titles = book.allTitles()
            titleCount = len(titles)
            if titleCount > 0:
                self.__writer.blankline()
                tcount = 0
                for i in xrange(titleCount):
                    title = titles[i]
                    if len(title.strip()) > 0:
                        self.__writer.write(titles[i])
                        self.__writer.newline()
                        tcount += 1
                if tcount > 0:
                    self.__writer.blankline()
            self.__writer.blankline()
            self.__writer.blankline()

        if firstBook and hasPart:
            self.__writer.hr(fill=0.6, c='=')
        elif hasBook:
            self.__writer.hr(fill=0.4)

        self.__writer.popJustify()

        

    def _writeChapterTitle(self, chapter):
        self.__writer.flush()
        self.__writer.blankline()
        self.__writer.blankline()
        self.__writer.blankline()
        self.__writer.justifyCenter()

        string = "Chapter %d" % self.getNumber(AbstractWriter.LEVEL_CHAPTER)
        self.__writer.write(string)

        titles = chapter.allTitles()
        titleCount = len(titles)
        if titleCount > 0:
            for i in xrange(titleCount):
                self.__writer.newline()
                self.__writer.write(titles[i])
            self.__writer.hr(maxlength=8)

        self.__writer.blankline()
        self.__writer.blankline()
        self.__writer.popJustify()

    def _writeNote(self, segment):
        note = super(TextWriter, self)._writeNote(segment)
        self.__writer.write("[%d]" % note[0])

    def _processNote(self, segment):
        number = self.getNumber(AbstractWriter.LEVEL_NOTE, 0)

        #Replace the writer with a temporary clone that writes to 
        # a buffer, then use it to write the note segment to the buffer,
        # so we can save it for later.
        old = self.__writer
        stream = cStringIO.StringIO()
        self.__writer = self.__writer.clone(stream)
        self._writeBlockSegment("p", segment)
        self.__writer.flush()
        self.__writer = old
        return number, stream.getvalue(), (self.listNumbers(AbstractWriter.LEVEL_CHAPTER))

    def _finishChapter(self, chapter):
        super(TextWriter, self)._finishChapter(chapter)

        notes = sorted(self.getNotes(AbstractWriter.LEVEL_CHAPTER),
            key=lambda note : note[0])
        if len(notes) > 0:
            self.__writer.flush()
            self.__writer.indent()
            self.__writer.rightIndent()
            self.__writer.hr(maxlength=10)
            self.__writer.blankline()
            self.__writer.write("Notes for Chapter %d" % self.getNumber(AbstractWriter.LEVEL_CHAPTER))
            self.__writer.blankline()
            for note in notes:
                number, note = note[:2]
                self.__writer.indent()
                self.__writer.write("[%d] " % number)
                self.__writer.write(note)
                self.__writer.blankline()
                self.__writer.outdent()
            self.__writer.flush()
            self.__writer.rightOutdent()
            self.__writer.outdent()

    def _frontMatter(self, tome):
        super(TextWriter, self)._frontMatter(tome)

        titles = tome.allTitles()
        titleCount = len(titles)
        authors = tome.authors()
        authorCount = len(authors)
        if titleCount > 0 or authorCount > 0:
            self.__writer.blankline()
            self.__writer.blankline()
            self.__writer.blankline()
            self.__writer.justifyCenter()
            indent = self.__writer.setIndent(3)
            rindent = self.__writer.setRightIndent(3)

            for i in xrange(titleCount):
                self.__writer.write(titles[i])
                self.__writer.newline()
                if (i+1) < titleCount:
                    self.__writer.write("---")
                    self.__writer.newline()

            if titleCount > 0 and authorCount > 0:
                self.__writer.write("---")
                self.__writer.blankline()

            for author in authors:
                self.__writer.write(author)
                self.__writer.newline()

            self.__writer.setRightIndent(rindent)
            self.__writer.setIndent(indent)
            self.__writer.popJustify()


    def _endMatter(self, tome):
        super(TextWriter, self)._endMatter(tome)


        #All Chapter Notes
        self.__writer.flush()
        self.__writer.indent()
        self.__writer.rightIndent()

        lastPart = lastBook = lastChapter = 0
        hasPart = hasBook = False
        thePart = theBook = theChapter = None
        for note in self.getNotes(AbstractWriter.LEVEL_TOME):
            number, content, location = note[:3]
            part, book, chapter = location[:3]
            if part != lastPart:
                if lastPart == 0:
                    #First note.
                    self.__writer.blankline()
                    self.__writer.blankline()
                    self.__writer.hr(fill=0.8)
                    self.__writer.write("All Notes")
                    self.__writer.blankline()
                    self.__writer.flush()

                thePart = tome[part-1]
                hasPart = thePart.title() is not None

            if part!= lastPart or book != lastBook:
                theBook = thePart[book-1]
                hasBook = theBook.title() is not None

            if part!= lastPart or book != lastBook or chapter != lastChapter:
                theChapter = theBook[chapter-1]

                prefix = ""
                if hasPart:
                    prefix += "%d." % part
                if hasBook:
                    prefix += "%d." % book
                self.__writer.write("Notes for Chapter %s%d" % (prefix, chapter))
                self.__writer.blankline()

            self.__writer.indent()
            self.__writer.write("[%d] " % number)
            self.__writer.write(content)
            self.__writer.blankline()
            self.__writer.outdent()

            lastPart = part
            lastBook = book
            lastChapter = chapter

        self.__writer.outdent()
        self.__writer.rightOutdent()
        

if __name__ == "__main__":
    parser = Tome.TomeOtlParser(sys.stdin, filename="<stdin>", debug=True)
    tome = parser.tome()
    writer = TextWriter(linewidth=78)
    writer.write(tome)