################################################## # SPYCE - Python-based HTML Scripting # Copyright (c) 2002 Rimon Barr. # # Refer to spyce.py # CVS: $Id: toc.py 31144 2012-07-15 15:38:56Z buzz $ ################################################## from spyceModule import spyceModule import tree __doc__ = '''Table-of-Contents module helps in creating indexed documents NB: The TOC module may force two passes of a file, if the first pass TOC emitted was not accurate. The second pass occurs via a redirect, so all modules are reinitialized. Unfortunately, this breaks things like include.context...''' ROOT_NAME = 'root' class toc(spyceModule): def start(self): if not self._api.getModule('pool').has_key('toc'): self._api.getModule('pool')['toc'] = {} try: self.oldtree, self.oldtags = self._api.getModule('pool')['toc'][self._api.getFilename()] except (KeyError, TypeError): self.oldtree = tree.tree( (ROOT_NAME, [], None) ) self.oldtags = {ROOT_NAME: self.oldtree} # tree data: (tag, numbering, data) self.tree = tree.tree((ROOT_NAME, [], None)) self.tags = {ROOT_NAME: self.tree} self.node = self.tree self.numbering = [] self.autotag = 0 self.tocShown = 0 self.fDOC_PUSH = None self.fDOC_POP = None self.fDOC_START = None self.fDOC_END = None self.fTOC_PUSH = None self.fTOC_POP = None self.fTOC_ENTRY = None def finish(self, theError): if not theError: self.tree.computePreChain() regenerate = not (self.oldtree == self.tree) file = self._api.getFilename() self._api.getModule('pool')['toc'][file] = self.tree, self.tags self.oldtree.delete() self.oldtree = None self.oldtags = None if self.tocShown and regenerate: self._api.getModule('redirect').internal(file) # set callbacks def setDOC_PUSH(self, f): self.fDOC_PUSH = f def setDOC_POP(self, f): self.fDOC_POP = f def setDOC_START(self, f): self.fDOC_START = f def setDOC_END(self, f): self.fDOC_END = f def setTOC_PUSH(self, f): self.fTOC_PUSH = f def setTOC_POP(self, f): self.fTOC_POP = f def setTOC_ENTRY(self, f): self.fTOC_ENTRY = f # sectioning def begin(self, data, tag=None, number=1): self._emit(self.node, self.fDOC_PUSH) self.numbering = _in(self.numbering) if number: self.numbering = _inc(self.numbering) self.node = self.node.append( (tag, self.numbering, data) ) else: self.node = self.node.append( (tag, None, data) ) if not tag: tag = self._genTag() self.tags[tag] = self.node self._emit(self.node, self.fDOC_START) def end(self): self._emit(self.node, self.fDOC_END) self.numbering = _out(self.numbering) self.node = self.node.parent self._emit(self.node, self.fDOC_POP) def next(self, data, tag=None, number=1): self._emit(self.node, self.fDOC_END) self.node = self.node.parent if number: self.numbering = _inc(self.numbering) self.node = self.node.append( (tag, self.numbering, data) ) else: self.node = self.node.append( (tag, None, data) ) if not tag: tag = self._genTag() self.tags[tag] = self.node self._emit(self.node, self.fDOC_START) def anchor(self, data, tag=ROOT_NAME): self.tree.data = tag, [], data self.tags[tag] = self.tree # shortcuts b=begin e=end n=next # sectioning by depth def level(self, depth, data, tag=None): curdepth = self.getDepth() if curdepth > depth: # indent while curdepth > depth: self.end() curdepth = self.getDepth() self.next(data, tag) elif curdepth < depth: # outdent while curdepth < depth - 1: self.begin(None) curdepth = self.getDepth() self.begin(data, tag) else: # next self.next(data, tag) def l1(self, data, tag=None): self.level(1, data, tag) def l2(self, data, tag=None): self.level(2, data, tag) def l3(self, data, tag=None): self.level(3, data, tag) def l4(self, data, tag=None): self.level(4, data, tag) def l5(self, data, tag=None): self.level(5, data, tag) def l6(self, data, tag=None): self.level(6, data, tag) def l7(self, data, tag=None): self.level(7, data, tag) def l8(self, data, tag=None): self.level(8, data, tag) def l9(self, data, tag=None): self.level(9, data, tag) # show toc def showTOC(self): self.tocShown = 1 self._tocHelper(self.oldtree) def _tocHelper(self, node): self._emit(node, self.fTOC_ENTRY) if node.children: self._emit(node, self.fTOC_PUSH) for c in node.children: self._tocHelper(c) self._emit(node, self.fTOC_POP) # current state def getTag(self, node=None): self.tocShown = 1 if not node: node = self.node tag, numbering, data = node.data return tag def getNumbering(self, tag=None): self.tocShown = 1 try: node = self.node if tag: node = self.oldtags[tag] tag, numbering, data = node.data return numbering except KeyError: return None def getData(self, tag=None): self.tocShown = 1 try: node = self.node if tag: node = self.oldtags[tag] tag, numbering, data = node.data return data except KeyError: return None def getDepth(self, tag=None): self.tocShown = 1 try: node = self.node if tag: node = self.tags[tag] return node.depth except KeyError: return None def getNextTag(self, tag=None): self.tocShown = 1 try: if not tag: tag = self.getTag() tag = self.oldtags[tag].next if tag==None: return None return self.getTag(tag) except KeyError: return None def getPrevTag(self, tag=None): self.tocShown = 1 try: if not tag: tag = self.getTag() node = self.oldtags[tag].prev if node==None: return None return self.getTag(node) except KeyError: return None def getParentTag(self, tag=None): self.tocShown = 1 try: if not tag: tag = self.getTag() node = self.oldtags[tag].parent if node==None: return None return self.getTag(node) except KeyError: return None def getChildrenTags(self, tag=None): self.tocShown = 1 try: if not tag: tag = self.getTag() nodes = self.oldtags[tag].children return map(self.getTag, nodes) except KeyError: return None # internal helpers def _genTag(self): tag = 'auto_'+str(self.autotag) self.autotag = self.autotag + 1 return tag def _emit(self, node, f): tag, numbering, data = node.data if f: s = f(node.depth, tag, numbering, data) # hierarchical counting def _inc(numbering, inc=1): return numbering[:-1]+[numbering[-1]+inc] def _in(numbering, start=0): return numbering+[start] def _out(numbering): return numbering[:-1] def defaultOutput(tag, numbering, data): return reduce(lambda s, i: '%s%d.' % (s, i), numbering, '') + ' ' + str(data)