+++ /dev/null
-##############################################################################
-#
-# Zope Public License (ZPL) Version 1.0
-# -------------------------------------
-#
-# Copyright (c) Digital Creations. All rights reserved.
-#
-# This license has been certified as Open Source(tm).
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# 1. Redistributions in source code must retain the above copyright
-# notice, this list of conditions, and the following disclaimer.
-#
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions, and the following disclaimer in
-# the documentation and/or other materials provided with the
-# distribution.
-#
-# 3. Digital Creations requests that attribution be given to Zope
-# in any manner possible. Zope includes a "Powered by Zope"
-# button that is installed by default. While it is not a license
-# violation to remove this button, it is requested that the
-# attribution remain. A significant investment has been put
-# into Zope, and this effort will continue if the Zope community
-# continues to grow. This is one way to assure that growth.
-#
-# 4. All advertising materials and documentation mentioning
-# features derived from or use of this software must display
-# the following acknowledgement:
-#
-# "This product includes software developed by Digital Creations
-# for use in the Z Object Publishing Environment
-# (http://www.zope.org/)."
-#
-# In the event that the product being advertised includes an
-# intact Zope distribution (with copyright and license included)
-# then this clause is waived.
-#
-# 5. Names associated with Zope or Digital Creations must not be used to
-# endorse or promote products derived from this software without
-# prior written permission from Digital Creations.
-#
-# 6. Modified redistributions of any form whatsoever must retain
-# the following acknowledgment:
-#
-# "This product includes software developed by Digital Creations
-# for use in the Z Object Publishing Environment
-# (http://www.zope.org/)."
-#
-# Intact (re-)distributions of any official Zope release do not
-# require an external acknowledgement.
-#
-# 7. Modifications are encouraged but must be packaged separately as
-# patches to official Zope releases. Distributions that do not
-# clearly separate the patches from the original work must be clearly
-# labeled as unofficial distributions. Modifications which do not
-# carry the name Zope may be packaged in any form, as long as they
-# conform to all of the clauses above.
-#
-#
-# Disclaimer
-#
-# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
-# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
-# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# SUCH DAMAGE.
-#
-#
-# This software consists of contributions made by Digital Creations and
-# many individuals on behalf of Digital Creations. Specific
-# attributions are listed in the accompanying credits file.
-#
-##############################################################################
-
-import re, ST, STDOM
-from string import split, join, replace, expandtabs, strip, find
-from STletters import letters,lettpunc,punctuations
-
-StringType=type('')
-ListType=type([])
-
-class StructuredTextExample(ST.StructuredTextParagraph):
- """Represents a section of document with literal text, as for examples"""
-
- def __init__(self, subs, **kw):
- t=[]; a=t.append
- for s in subs: a(s.getNodeValue())
- apply(ST.StructuredTextParagraph.__init__,
- (self, join(t,'\n\n'), ()),
- kw)
-
- def getColorizableTexts(self): return ()
- def setColorizableTexts(self, src): pass # never color examples
-
-class StructuredTextBullet(ST.StructuredTextParagraph):
- """Represents a section of a document with a title and a body"""
-
-class StructuredTextNumbered(ST.StructuredTextParagraph):
- """Represents a section of a document with a title and a body"""
-
-class StructuredTextDescriptionTitle(ST.StructuredTextParagraph):
- """Represents a section of a document with a title and a body"""
-
-class StructuredTextDescriptionBody(ST.StructuredTextParagraph):
- """Represents a section of a document with a title and a body"""
-
-class StructuredTextDescription(ST.StructuredTextParagraph):
- """Represents a section of a document with a title and a body"""
-
- def __init__(self, title, src, subs, **kw):
- apply(ST.StructuredTextParagraph.__init__, (self, src, subs), kw)
- self._title=title
-
- def getColorizableTexts(self): return self._title, self._src
- def setColorizableTexts(self, src): self._title, self._src = src
-
- def getChildren(self):
- return (StructuredTextDescriptionTitle(self._title),
- StructuredTextDescriptionBody(self._src, self._subs))
-
-class StructuredTextSectionTitle(ST.StructuredTextParagraph):
- """Represents a section of a document with a title and a body"""
-
-class StructuredTextSection(ST.StructuredTextParagraph):
- """Represents a section of a document with a title and a body"""
- def __init__(self, src, subs=None, **kw):
- apply(ST.StructuredTextParagraph.__init__,
- (self, StructuredTextSectionTitle(src), subs),
- kw)
-
- def getColorizableTexts(self):
- return self._src.getColorizableTexts()
-
- def setColorizableTexts(self,src):
- self._src.setColorizableTexts(src)
-
-# a StructuredTextTable holds StructuredTextRows
-class StructuredTextTable(ST.StructuredTextDocument):
- """
- rows is a list of lists containing tuples, which
- represent the columns/cells in each rows.
- EX
- rows = [[('row 1:column1',1)],[('row2:column1',1)]]
- """
-
- def __init__(self, rows, src, subs, **kw):
- apply(ST.StructuredTextDocument.__init__,(self,subs),kw)
- self._rows = []
- for row in rows:
- if row:
- self._rows.append(StructuredTextRow(row,kw))
-
- def getRows(self):
- return [self._rows]
-
- def _getRows(self):
- return self.getRows()
-
- def getColorizableTexts(self):
- """
- return a tuple where each item is a column/cell's
- contents. The tuple, result, will be of this format.
- ("r1 col1", "r1=col2", "r2 col1", "r2 col2")
- """
-
- #result = ()
- result = []
- for row in self._rows:
- for column in row.getColumns()[0]:
- #result = result[:] + (column.getColorizableTexts(),)
- result.append(column.getColorizableTexts()[0])
- return result
-
- def setColorizableTexts(self,texts):
- """
- texts is going to a tuple where each item is the
- result of being mapped to the colortext function.
- Need to insert the results appropriately into the
- individual columns/cells
- """
- for row_index in range(len(self._rows)):
- for column_index in range(len(self._rows[row_index]._columns)):
- self._rows[row_index]._columns[column_index].setColorizableTexts((texts[0],))
- texts = texts[1:]
-
- def _getColorizableTexts(self):
- return self.getColorizableTexts()
-
- def _setColorizableTexts(self):
- return self.setColorizableTexts()
-
-# StructuredTextRow holds StructuredTextColumns
-class StructuredTextRow(ST.StructuredTextDocument):
-
- def __init__(self,row,kw):
- """
- row is a list of tuples, where each tuple is
- the raw text for a cell/column and the span
- of that cell/column".
- EX
- [('this is column one',1), ('this is column two',1)]
- """
-
- apply(ST.StructuredTextDocument.__init__,(self,[]),kw)
- self._columns = []
- for column in row:
- self._columns.append(StructuredTextColumn(column[0],column[1],kw))
- def getColumns(self):
- return [self._columns]
-
- def _getColumns(self):
- return [self._columns]
-
-# this holds the raw text of a table cell
-class StructuredTextColumn(ST.StructuredTextParagraph):
- """
- StructuredTextColumn is a cell/column in a table.
- This contains the actual text of a column and is
- thus a StructuredTextParagraph. A StructuredTextColumn
- also holds the span of its column
- """
-
- def __init__(self,text,span,kw):
- apply(ST.StructuredTextParagraph.__init__,(self,text,[]),kw)
- self._span = span
-
- def getSpan(self):
- return self._span
-
- def _getSpan(self):
- return self._span
-
-class StructuredTextMarkup(STDOM.Element):
-
- def __init__(self, v, **kw):
- self._value=v
- self._attributes=kw.keys()
- for k, v in kw.items(): setattr(self, k, v)
-
- def getChildren(self, type=type, lt=type([])):
- v=self._value
- if type(v) is not lt: v=[v]
- return v
-
- def getColorizableTexts(self): return self._value,
- def setColorizableTexts(self, v): self._value=v[0]
-
- def __repr__(self):
- return '%s(%s)' % (self.__class__.__name__, `self._value`)
-
-class StructuredTextLiteral(StructuredTextMarkup):
- def getColorizableTexts(self): return ()
- def setColorizableTexts(self, v): pass
-
-class StructuredTextEmphasis(StructuredTextMarkup): pass
-
-class StructuredTextStrong(StructuredTextMarkup): pass
-
-class StructuredTextInnerLink(StructuredTextMarkup): pass
-
-class StructuredTextNamedLink(StructuredTextMarkup): pass
-
-class StructuredTextUnderline(StructuredTextMarkup): pass
-
-class StructuredTextLink(StructuredTextMarkup):
- "A simple hyperlink"
-
-class DocumentClass:
- """
- Class instance calls [ex.=> x()] require a structured text
- structure. Doc will then parse each paragraph in the structure
- and will find the special structures within each paragraph.
- Each special structure will be stored as an instance. Special
- structures within another special structure are stored within
- the 'top' structure
- EX : '-underline this-' => would be turned into an underline
- instance. '-underline **this**' would be stored as an underline
- instance with a strong instance stored in its string
- """
-
- paragraph_types = [
- 'doc_bullet',
- 'doc_numbered',
- 'doc_description',
- 'doc_header',
- 'doc_table',
- ]
-
- text_types = [
- 'doc_href',
- 'doc_strong',
- 'doc_emphasize',
- 'doc_literal',
- 'doc_inner_link',
- 'doc_named_link',
- 'doc_underline',
- ]
-
- def __call__(self, doc):
- if type(doc) is type(''):
- doc=ST.StructuredText(doc)
- doc.setSubparagraphs(self.color_paragraphs(
- doc.getSubparagraphs()))
- else:
- doc=ST.StructuredTextDocument(self.color_paragraphs(
- doc.getSubparagraphs()))
- return doc
-
- def parse(self, raw_string, text_type,
- type=type, st=type(''), lt=type([])):
-
- """
- Parse accepts a raw_string, an expr to test the raw_string,
- and the raw_string's subparagraphs.
-
- Parse will continue to search through raw_string until
- all instances of expr in raw_string are found.
-
- If no instances of expr are found, raw_string is returned.
- Otherwise a list of substrings and instances is returned
- """
-
- tmp = [] # the list to be returned if raw_string is split
- append=tmp.append
-
- if type(text_type) is st: text_type=getattr(self, text_type)
-
- while 1:
- t = text_type(raw_string)
- if not t: break
- #an instance of expr was found
- t, start, end = t
-
- if start: append(raw_string[0:start])
-
- tt=type(t)
- if tt is st:
- # if we get a string back, add it to text to be parsed
- raw_string = t+raw_string[end:len(raw_string)]
- else:
- if tt is lt:
- # is we get a list, append it's elements
- tmp[len(tmp):]=t
- else:
- # normal case, an object
- append(t)
- raw_string = raw_string[end:len(raw_string)]
-
- if not tmp: return raw_string # nothing found
-
- if raw_string: append(raw_string)
- elif len(tmp)==1: return tmp[0]
-
- return tmp
-
-
- def color_text(self, str, types=None):
- """Search the paragraph for each special structure
- """
- if types is None: types=self.text_types
-
- for text_type in types:
-
- if type(str) is StringType:
- str = self.parse(str, text_type)
- elif type(str) is ListType:
- r=[]; a=r.append
- for s in str:
- if type(s) is StringType:
- s=self.parse(s, text_type)
- if type(s) is ListType: r[len(r):]=s
- else: a(s)
- else:
- s.setColorizableTexts(
- map(self.color_text,
- s.getColorizableTexts()
- ))
- a(s)
- str=r
- else:
- r=[]; a=r.append; color=self.color_text
- for s in str.getColorizableTexts():
- color(s, (text_type,))
- a(s)
-
- str.setColorizableTexts(r)
-
- return str
-
- def color_paragraphs(self, raw_paragraphs,
- type=type, sequence_types=(type([]), type(())),
- st=type('')):
- result=[]
- for paragraph in raw_paragraphs:
-
- if paragraph.getNodeName() != 'StructuredTextParagraph':
- result.append(paragraph)
- continue
-
- for pt in self.paragraph_types:
- if type(pt) is st:
- # grab the corresponding function
- pt=getattr(self, pt)
- # evaluate the paragraph
- r=pt(paragraph)
- if r:
- if type(r) not in sequence_types:
- r=r,
- new_paragraphs=r
- for paragraph in new_paragraphs:
- paragraph.setSubparagraphs(self.color_paragraphs(paragraph.getSubparagraphs()))
- break
- else:
- new_paragraphs=ST.StructuredTextParagraph(paragraph.getColorizableTexts()[0],
- self.color_paragraphs(paragraph.getSubparagraphs()),
- indent=paragraph.indent),
- # color the inline StructuredText types
- # for each StructuredTextParagraph
- for paragraph in new_paragraphs:
- paragraph.setColorizableTexts(
- map(self.color_text,
- paragraph.getColorizableTexts()
- ))
- result.append(paragraph)
-
- return result
-
- def doc_table(self,paragraph, expr = re.compile('(\s*)([||]+)').match):
- #print "paragraph=>", type(paragraph), paragraph, paragraph._src
- text = paragraph.getColorizableTexts()[0]
- m = expr(text)
-
- if not (m):
- return None
- rows = []
-
- # initial split
- for row in split(text,"\n"):
- rows.append(row)
-
- # clean up the rows
- for index in range(len(rows)):
- tmp = []
- rows[index] = strip(rows[index])
- l = len(rows[index])-2
- result = split(rows[index][:l],"||")
- for text in result:
- if text:
- tmp.append(text)
- tmp.append('')
- else:
- tmp.append(text)
- rows[index] = tmp
- # remove trailing '''s
- for index in range(len(rows)):
- l = len(rows[index])-1
- rows[index] = rows[index][:l]
-
- result = []
- for row in rows:
- cspan = 0
- tmp = []
- for item in row:
- if item:
- tmp.append((item,cspan))
- cspan = 0
- else:
- cspan = cspan + 1
- result.append(tmp)
-
- subs = paragraph.getSubparagraphs()
- indent=paragraph.indent
- return StructuredTextTable(result,text,subs,indent=paragraph.indent)
-
- def doc_bullet(self, paragraph, expr = re.compile('\s*[-*o]\s+').match):
- top=paragraph.getColorizableTexts()[0]
- m=expr(top)
-
- if not m:
- return None
-
- subs=paragraph.getSubparagraphs()
- if top[-2:]=='::':
- subs=[StructuredTextExample(subs)]
- top=top[:-1]
- return StructuredTextBullet(top[m.span()[1]:], subs,
- indent=paragraph.indent,
- bullet=top[:m.span()[1]]
- )
-
- def doc_numbered(
- self, paragraph,
- expr = re.compile('(\s*[%s]+\.)|(\s*[0-9]+\.)|(\s*[0-9]+\s+)' % letters).match):
-
- # This is the old expression. It had a nasty habit
- # of grabbing paragraphs that began with a single
- # letter word even if there was no following period.
-
- #expr = re.compile('\s*'
- # '(([a-zA-Z]|[0-9]+|[ivxlcdmIVXLCDM]+)\.)*'
- # '([a-zA-Z]|[0-9]+|[ivxlcdmIVXLCDM]+)\.?'
- # '\s+').match):
-
- top=paragraph.getColorizableTexts()[0]
- m=expr(top)
- if not m: return None
- subs=paragraph.getSubparagraphs()
- if top[-2:]=='::':
- subs=[StructuredTextExample(subs)]
- top=top[:-1]
- return StructuredTextNumbered(top[m.span()[1]:], subs,
- indent=paragraph.indent,
- number=top[:m.span()[1]])
-
- def doc_description(
- self, paragraph,
- delim = re.compile('\s+--\s+').search,
- nb=re.compile(r'[^\000- ]').search,
- ):
-
- top=paragraph.getColorizableTexts()[0]
- d=delim(top)
- if not d: return None
- start, end = d.span()
- title=top[:start]
- if find(title, '\n') >= 0: return None
- if not nb(title): return None
- d=top[start:end]
- top=top[end:]
-
- subs=paragraph.getSubparagraphs()
- if top[-2:]=='::':
- subs=[StructuredTextExample(subs)]
- top=top[:-1]
-
- return StructuredTextDescription(
- title, top, subs,
- indent=paragraph.indent,
- delim=d)
-
- def doc_header(self, paragraph,
- expr = re.compile('[ %s0-9.:/,-_*<>\?\'\"]+' % letters).match
- ):
- subs=paragraph.getSubparagraphs()
- if not subs: return None
- top=paragraph.getColorizableTexts()[0]
- if not strip(top): return None
- if top[-2:]=='::':
- subs=StructuredTextExample(subs)
- if strip(top)=='::': return subs
- return ST.StructuredTextParagraph(top[:-1],
- [subs],
- indent=paragraph.indent,
- level=paragraph.level)
-
- if find(top,'\n') >= 0: return None
- return StructuredTextSection(top, subs, indent=paragraph.indent, level=paragraph.level)
-
- def doc_literal(
- self, s,
- expr=re.compile(
- "(?:\s|^)'" # open
- "([^ \t\n\r\f\v']|[^ \t\n\r\f\v'][^\n']*[^ \t\n\r\f\v'])" # contents
- "'(?:\s|[,.;:!?]|$)" # close
- ).search):
-
- r=expr(s)
- if r:
- start, end = r.span(1)
- return (StructuredTextLiteral(s[start:end]), start-1, end+1)
- else:
- return None
-
- def doc_emphasize(
- self, s,
- expr = re.compile('\s*\*([ \n%s0-9]+)\*(?!\*|-)' % lettpunc).search
- ):
-
- r=expr(s)
- if r:
- start, end = r.span(1)
- return (StructuredTextEmphasis(s[start:end]), start-1, end+1)
- else:
- return None
-
- def doc_inner_link(self,
- s,
- expr1 = re.compile("\.\.\s*").search,
- expr2 = re.compile("\[[%s0-9]+\]" % letters).search):
-
- # make sure we dont grab a named link
- if expr2(s) and expr1(s):
- start1,end1 = expr1(s).span()
- start2,end2 = expr2(s).span()
- if end1 == start2:
- # uh-oh, looks like a named link
- return None
- else:
- # the .. is somewhere else, ignore it
- return (StructuredTextInnerLink(s[start2+1:end2-1]),start2,end2)
- return None
- elif expr2(s) and not expr1(s):
- start,end = expr2(s).span()
- return (StructuredTextInnerLink(s[start+1:end-1]),start,end)
- return None
-
- def doc_named_link(self,
- s,
- expr=re.compile("(\.\.\s)(\[[%s0-9]+\])" % letters).search):
-
- result = expr(s)
- if result:
- start,end = result.span(2)
- a,b = result.span(1)
- str = strip(s[a:b]) + s[start:end]
- str = s[start+1:end-1]
- st,en = result.span()
- return (StructuredTextNamedLink(str),st,en)
- #return (StructuredTextNamedLink(s[st:en]),st,en)
- return None
-
- def doc_underline(self,
- s,
- expr=re.compile("\s+\_([0-9%s ]+)\_" % lettpunc).search):
-
- result = expr(s)
- if result:
- start,end = result.span(1)
- st,e = result.span()
- return (StructuredTextUnderline(s[start:end]),st,e)
- else:
- return None
-
- def doc_strong(self,
- s,
- expr = re.compile('\s*\*\*([ \n%s0-9]+)\*\*' % lettpunc).search
- ):
-
- r=expr(s)
- if r:
- start, end = r.span(1)
- return (StructuredTextStrong(s[start:end]), start-2, end+2)
- else:
- return None
-
- def doc_href(
-
- self, s,
- expr1 = re.compile("(\"[ %s0-9\n\-\.\,\;\(\)\/\:\/\*\']+\")(:)([a-zA-Z0-9\@\.\,\?\!\/\:\;\-\#\~]+)([,]*\s*)" % letters).search,
- expr2 = re.compile('(\"[ %s0-9\n\-\.\:\;\(\)\/\*\']+\")([,]+\s+)([a-zA-Z0-9\@\.\,\?\!\/\:\;\-\#\~]+)(\s*)' % letters).search):
-
- r=expr1(s) or expr2(s)
-
- if r:
- # need to grab the href part and the
- # beginning part
-
- start,e = r.span(1)
- name = s[start:e]
- name = replace(name,'"','',2)
- st,end = r.span(3)
-
- if s[end-1:end] in punctuations: end-=1
- link = s[st:end]
-
- # name is the href title, link is the target
- # of the href
- return (StructuredTextLink(name, href=link),
- start, end)
-
-
- else:
- return None