]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/samples/stxview/StructuredText/DocumentClass.py
   1 ############################################################################## 
   3 # Zope Public License (ZPL) Version 1.0 
   4 # ------------------------------------- 
   6 # Copyright (c) Digital Creations.  All rights reserved. 
   8 # This license has been certified as Open Source(tm). 
  10 # Redistribution and use in source and binary forms, with or without 
  11 # modification, are permitted provided that the following conditions are 
  14 # 1. Redistributions in source code must retain the above copyright 
  15 #    notice, this list of conditions, and the following disclaimer. 
  17 # 2. Redistributions in binary form must reproduce the above copyright 
  18 #    notice, this list of conditions, and the following disclaimer in 
  19 #    the documentation and/or other materials provided with the 
  22 # 3. Digital Creations requests that attribution be given to Zope 
  23 #    in any manner possible. Zope includes a "Powered by Zope" 
  24 #    button that is installed by default. While it is not a license 
  25 #    violation to remove this button, it is requested that the 
  26 #    attribution remain. A significant investment has been put 
  27 #    into Zope, and this effort will continue if the Zope community 
  28 #    continues to grow. This is one way to assure that growth. 
  30 # 4. All advertising materials and documentation mentioning 
  31 #    features derived from or use of this software must display 
  32 #    the following acknowledgement: 
  34 #       "This product includes software developed by Digital Creations 
  35 #       for use in the Z Object Publishing Environment 
  36 #       (http://www.zope.org/)." 
  38 #    In the event that the product being advertised includes an 
  39 #    intact Zope distribution (with copyright and license included) 
  40 #    then this clause is waived. 
  42 # 5. Names associated with Zope or Digital Creations must not be used to 
  43 #    endorse or promote products derived from this software without 
  44 #    prior written permission from Digital Creations. 
  46 # 6. Modified redistributions of any form whatsoever must retain 
  47 #    the following acknowledgment: 
  49 #       "This product includes software developed by Digital Creations 
  50 #       for use in the Z Object Publishing Environment 
  51 #       (http://www.zope.org/)." 
  53 #    Intact (re-)distributions of any official Zope release do not 
  54 #    require an external acknowledgement. 
  56 # 7. Modifications are encouraged but must be packaged separately as 
  57 #    patches to official Zope releases.  Distributions that do not 
  58 #    clearly separate the patches from the original work must be clearly 
  59 #    labeled as unofficial distributions.  Modifications which do not 
  60 #    carry the name Zope may be packaged in any form, as long as they 
  61 #    conform to all of the clauses above. 
  66 #    THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY 
  67 #    EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  68 #    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  69 #    PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS 
  70 #    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
  71 #    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
  72 #    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 
  73 #    USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
  74 #    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
  75 #    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
  76 #    OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
  80 # This software consists of contributions made by Digital Creations and 
  81 # many individuals on behalf of Digital Creations.  Specific 
  82 # attributions are listed in the accompanying credits file. 
  84 ############################################################################## 
  87 from string 
import split
, join
, replace
, expandtabs
, strip
, find
, rstrip
 
  88 from STletters 
import * 
  94 def flatten(obj
, append
): 
  95    if obj
.getNodeType()==STDOM
.TEXT_NODE
: 
  96       append(obj
.getNodeValue()) 
  98       for child 
in obj
.getChildNodes(): 
  99          flatten(child
, append
) 
 102 class StructuredTextExample(ST
.StructuredTextParagraph
): 
 103     """Represents a section of document with literal text, as for examples""" 
 105     def __init__(self
, subs
, **kw
): 
 110         apply(ST
.StructuredTextParagraph
.__init
__, 
 111               (self
, join(t
,'\n\n'), ()), 
 114     def getColorizableTexts(self
): return () 
 115     def setColorizableTexts(self
, src
): pass # never color examples 
 117 class StructuredTextBullet(ST
.StructuredTextParagraph
): 
 118     """Represents a section of a document with a title and a body""" 
 120 class StructuredTextNumbered(ST
.StructuredTextParagraph
): 
 121     """Represents a section of a document with a title and a body""" 
 123 class StructuredTextDescriptionTitle(ST
.StructuredTextParagraph
): 
 124     """Represents a section of a document with a title and a body""" 
 126 class StructuredTextDescriptionBody(ST
.StructuredTextParagraph
): 
 127     """Represents a section of a document with a title and a body""" 
 129 class StructuredTextDescription(ST
.StructuredTextParagraph
): 
 130     """Represents a section of a document with a title and a body""" 
 132     def __init__(self
, title
, src
, subs
, **kw
): 
 133        apply(ST
.StructuredTextParagraph
.__init
__, (self
, src
, subs
), kw
) 
 136     def getColorizableTexts(self
): return self
._title
, self
._src
 
 137     def setColorizableTexts(self
, src
): self
._title
, self
._src 
= src
 
 139     def getChildren(self
): 
 140        return (StructuredTextDescriptionTitle(self
._title
), 
 141                StructuredTextDescriptionBody(self
._src
, self
._subs
)) 
 143 class StructuredTextSectionTitle(ST
.StructuredTextParagraph
): 
 144     """Represents a section of a document with a title and a body""" 
 146 class StructuredTextSection(ST
.StructuredTextParagraph
): 
 147     """Represents a section of a document with a title and a body""" 
 148     def __init__(self
, src
, subs
=None, **kw
): 
 149        apply(ST
.StructuredTextParagraph
.__init
__, 
 150              (self
, StructuredTextSectionTitle(src
), subs
), 
 153     def getColorizableTexts(self
): 
 154         return self
._src
.getColorizableTexts() 
 156     def setColorizableTexts(self
,src
): 
 157         self
._src
.setColorizableTexts(src
) 
 159 # a StructuredTextTable holds StructuredTextRows 
 160 class StructuredTextTable(ST
.StructuredTextParagraph
): 
 162     rows is a list of lists containing tuples, which 
 163     represent the columns/cells in each rows. 
 165     rows = [[('row 1:column1',1)],[('row2:column1',1)]] 
 168     def __init__(self
, rows
, src
, subs
, **kw
): 
 169         apply(ST
.StructuredTextParagraph
.__init
__,(self
,subs
),kw
) 
 173                 self
._rows
.append(StructuredTextRow(row
,kw
)) 
 179         return self
.getRows() 
 181     def getColumns(self
): 
 183         for row 
in self
._rows
: 
 184             result
.append(row
.getColumns()) 
 187     def _getColumns(self
): 
 188         return self
.getColumns() 
 190     def setColumns(self
,columns
): 
 191         for index 
in range(len(self
._rows
)): 
 192             self
._rows
[index
].setColumns(columns
[index
]) 
 194     def _setColumns(self
,columns
): 
 195         return self
.setColumns(columns
) 
 197     def getColorizableTexts(self
): 
 199         return a tuple where each item is a column/cell's 
 200         contents. The tuple, result, will be of this format. 
 201         ("r1 col1", "r1=col2", "r2 col1", "r2 col2") 
 205         for row 
in self
._rows
: 
 206             for column 
in row
.getColumns()[0]: 
 207                 result
.append(column
.getColorizableTexts()[0]) 
 210     def setColorizableTexts(self
,texts
): 
 212         texts is going to a tuple where each item is the 
 213         result of being mapped to the colortext function. 
 214         Need to insert the results appropriately into the 
 215         individual columns/cells 
 217         for row_index 
in range(len(self
._rows
)): 
 218             for column_index 
in range(len(self
._rows
[row_index
]._columns
)): 
 219                 self
._rows
[row_index
]._columns
[column_index
].setColorizableTexts((texts
[0],)) 
 222     def _getColorizableTexts(self
): 
 223         return self
.getColorizableTexts() 
 225     def _setColorizableTexts(self
): 
 226         return self
.setColorizableTexts() 
 228 # StructuredTextRow holds StructuredTextColumns 
 229 class StructuredTextRow(ST
.StructuredTextParagraph
): 
 231     def __init__(self
,row
,kw
): 
 233         row is a list of tuples, where each tuple is 
 234         the raw text for a cell/column and the span 
 237         [('this is column one',1), ('this is column two',1)] 
 240         apply(ST
.StructuredTextParagraph
.__init
__,(self
,[]),kw
) 
 244             self
._columns
.append(StructuredTextColumn(column
[0], 
 251     def getColumns(self
): 
 252         return [self
._columns
] 
 254     def _getColumns(self
): 
 255         return [self
._columns
] 
 257     def setColumns(self
,columns
): 
 258         self
._columns 
= columns
 
 260     def _setColumns(self
,columns
): 
 261         return self
.setColumns(columns
) 
 263 # this holds the text of a table cell 
 264 class StructuredTextColumn(ST
.StructuredTextParagraph
): 
 266     StructuredTextColumn is a cell/column in a table. 
 267     A cell can hold multiple paragraphs. The cell 
 268     is either classified as a StructuredTextTableHeader 
 269     or StructuredTextTableData. 
 272     def __init__(self
,text
,span
,align
,valign
,typ
,kw
): 
 273         apply(ST
.StructuredTextParagraph
.__init
__,(self
,text
,[]),kw
) 
 276         self
._valign 
= valign
 
 289         return self
.getAlign() 
 294     def _getValign(self
): 
 295         return self
.getValign() 
 301         return self
.getType() 
 303 class StructuredTextTableHeader(ST
.StructuredTextParagraph
): pass 
 305 class StructuredTextTableData(ST
.StructuredTextParagraph
): pass 
 307 class StructuredTextMarkup(STDOM
.Element
): 
 309     def __init__(self
, v
, **kw
): 
 311        self
._attributes
=kw
.keys() 
 312        for k
, v 
in kw
.items(): setattr(self
, k
, v
) 
 314     def getChildren(self
, type=type, lt
=type([])): 
 316        if type(v
) is not lt
: v
=[v
] 
 319     def getColorizableTexts(self
): return self
._value
, 
 320     def setColorizableTexts(self
, v
): self
._value
=v
[0] 
 323        return '%s(%s)' % (self
.__class
__.__name
__, `self
._value`
) 
 325 class StructuredTextLiteral(StructuredTextMarkup
): 
 326     def getColorizableTexts(self
): return () 
 327     def setColorizableTexts(self
, v
): pass 
 329 class StructuredTextEmphasis(StructuredTextMarkup
): pass 
 331 class StructuredTextStrong(StructuredTextMarkup
): pass 
 333 class StructuredTextInnerLink(StructuredTextMarkup
): pass 
 335 class StructuredTextNamedLink(StructuredTextMarkup
): pass 
 337 class StructuredTextUnderline(StructuredTextMarkup
): pass 
 339 class StructuredTextSGML(StructuredTextMarkup
): pass 
 341 class StructuredTextLink(StructuredTextMarkup
): pass 
 343 class StructuredTextXref(StructuredTextMarkup
): pass 
 347     Class instance calls [ex.=> x()] require a structured text 
 348     structure. Doc will then parse each paragraph in the structure 
 349     and will find the special structures within each paragraph. 
 350     Each special structure will be stored as an instance. Special 
 351     structures within another special structure are stored within 
 353     EX : '-underline this-' => would be turned into an underline 
 354     instance. '-underline **this**' would be stored as an underline 
 355     instance with a strong instance stored in its string 
 379     def __call__(self
, doc
): 
 380         if type(doc
) is type(''): 
 381            doc
=ST
.StructuredText(doc
) 
 382            doc
.setSubparagraphs(self
.color_paragraphs( 
 383               doc
.getSubparagraphs())) 
 385            doc
=ST
.StructuredTextDocument(self
.color_paragraphs( 
 386               doc
.getSubparagraphs())) 
 389     def parse(self
, raw_string
, text_type
, 
 390               type=type, st
=type(''), lt
=type([])): 
 393        Parse accepts a raw_string, an expr to test the raw_string, 
 394        and the raw_string's subparagraphs. 
 396        Parse will continue to search through raw_string until  
 397        all instances of expr in raw_string are found.  
 399        If no instances of expr are found, raw_string is returned. 
 400        Otherwise a list of substrings and instances is returned 
 403        tmp 
= []    # the list to be returned if raw_string is split 
 406        if type(text_type
) is st
: text_type
=getattr(self
, text_type
) 
 409           t 
= text_type(raw_string
) 
 411           #an instance of expr was found 
 414           if start
: append(raw_string
[0:start
]) 
 418              # if we get a string back, add it to text to be parsed 
 419              raw_string 
= t
+raw_string
[end
:len(raw_string
)] 
 422                 # is we get a list, append it's elements 
 425                 # normal case, an object 
 427              raw_string 
= raw_string
[end
:len(raw_string
)] 
 429        if not tmp
: return raw_string 
# nothing found 
 431        if raw_string
: append(raw_string
) 
 432        elif len(tmp
)==1: return tmp
[0] 
 437     def color_text(self
, str, types
=None): 
 438        """Search the paragraph for each special structure 
 440        if types 
is None: types
=self
.text_types
 
 442        for text_type 
in types
: 
 444           if type(str) is StringType
: 
 445              str = self
.parse(str, text_type
) 
 446           elif type(str) is ListType
: 
 449                 if type(s
) is StringType
: 
 450                     s
=self
.parse(s
, text_type
) 
 451                     if type(s
) is ListType
: r
[len(r
):]=s
 
 454                     s
.setColorizableTexts( 
 456                            s
.getColorizableTexts() 
 461              r
=[]; a
=r
.append
; color
=self
.color_text
 
 462              for s 
in str.getColorizableTexts(): 
 463                 color(s
, (text_type
,)) 
 466              str.setColorizableTexts(r
) 
 470     def color_paragraphs(self
, raw_paragraphs
, 
 471                            type=type, sequence_types
=(type([]), type(())), 
 474        for paragraph 
in raw_paragraphs
: 
 475           if paragraph
.getNodeName() != 'StructuredTextParagraph': 
 476              result
.append(paragraph
) 
 479           for pt 
in self
.paragraph_types
: 
 481                 # grab the corresponding function 
 483              # evaluate the paragraph 
 486                 if type(r
) not in sequence_types
: 
 489                 for paragraph 
in new_paragraphs
: 
 490                     paragraph
.setSubparagraphs(self
.color_paragraphs(paragraph
.getSubparagraphs())) 
 493              new_paragraphs
=ST
.StructuredTextParagraph(paragraph
.getColorizableTexts()[0], 
 494                                                        self
.color_paragraphs(paragraph
.getSubparagraphs()), 
 495                                                        indent
=paragraph
.indent
), 
 497           # color the inline StructuredText types 
 498           # for each StructuredTextParagraph 
 499           for paragraph 
in new_paragraphs
: 
 501              if paragraph
.getNodeName() is "StructuredTextTable": 
 502                 cells 
= paragraph
.getColumns() 
 503                 text 
= paragraph
.getColorizableTexts() 
 504                 text 
= map(ST
.StructuredText
,text
) 
 505                 text 
= map(self
.__call
__,text
) 
 506                 for t 
in range(len(text
)): 
 507                     text
[t
] = text
[t
].getSubparagraphs() 
 508                 paragraph
.setColorizableTexts(text
) 
 510              paragraph
.setColorizableTexts( 
 512                     paragraph
.getColorizableTexts() 
 514              result
.append(paragraph
) 
 518     def doc_table(self
, paragraph
, expr 
= re
.compile(r
'\s*\|[-]+\|').match
): 
 519         text    
= paragraph
.getColorizableTexts()[0] 
 522         subs 
= paragraph
.getSubparagraphs() 
 534         TDdivider   
= re
.compile("[\-]+").match
 
 535         THdivider   
= re
.compile("[\=]+").match
 
 536         col         
= re
.compile('\|').search
 
 537         innertable  
= re
.compile('\|([-]+|[=]+)\|').search
 
 540         rows 
= split(text
,'\n') 
 543         for row 
in range(len(rows
)): 
 544             rows
[row
] = strip(rows
[row
]) 
 546         # have indexes store if a row is a divider 
 548         for index 
in range(len(rows
)): 
 549             tmpstr 
= rows
[index
][1:len(rows
[index
])-1] 
 550             if TDdivider(tmpstr
): 
 551                 indexes
.append("TDdivider") 
 552             elif THdivider(tmpstr
): 
 553                 indexes
.append("THdivider") 
 555                 indexes
.append("cell") 
 557         for index 
in range(len(indexes
)): 
 558             if indexes
[index
] is "TDdivider" or indexes
[index
] is THdivider
: 
 559                 ignore 
= [] # reset ignore 
 560                 #continue    # skip dividers 
 562             tmp     
= strip(rows
[index
])    # clean the row up 
 563             tmp     
= tmp
[1:len(tmp
)-1]     # remove leading + trailing | 
 566             # find the start and end of inner 
 567             # tables. ignore everything between 
 570                 while innertable(tmpstr
): 
 571                     start
,end   
= innertable(tmpstr
).span() 
 572                     if not (start
,end
-1) in ignore
: 
 573                         ignore
.append(start
,end
-1) 
 574                     tmpstr 
= " " + tmpstr
[end
:] 
 576             # find the location of column dividers 
 577             # NOTE: |'s in inner tables do not count 
 581                     bar         
= 1   # true if start is not in ignore 
 582                     start
,end   
= col(tmp
).span() 
 584                     if not start
+offset 
in spans
: 
 586                             if start
+offset 
>= s 
or start
+offset 
<= e
: 
 589                         if bar
:   # start is clean 
 590                             spans
.append(start
+offset
) 
 592                         foo 
= foo 
+ tmp
[:end
] 
 594                         offset 
= offset 
+ end
 
 596                         COLS
.append((foo 
+ tmp
[0:start
],start
+offset
)) 
 598                         tmp 
= " " + tmp
[end
:] 
 599                         offset 
= offset 
+ start
 
 600             if not offset
+len(tmp
) in spans
: 
 601                 spans
.append(offset
+len(tmp
)) 
 602             COLS
.append((foo 
+ tmp
,offset
+len(tmp
))) 
 608         ROWS 
= ROWS
[1:len(ROWS
)] 
 610         # find each column span 
 633         for index 
in range(len(C
)): 
 634             for i 
in range(len(C
[index
])): 
 635                 ROWS
[index
][i
] = (ROWS
[index
][i
][0],C
[index
][i
]) 
 638         # label things as either TableData or 
 643         for index 
in range(len(indexes
)): 
 644             if indexes
[index
] is "TDdivider": 
 647             if indexes
[index
] is "THdivider": 
 654         #print "all => ", all, "\n" 
 658                 index 
= all
.index(div
) 
 659                 for rowindex 
in range(all
[index
-1],all
[index
]):                     
 660                     for i 
in range(len(rows
[rowindex
])): 
 661                         rows
[rowindex
][i
] = (rows
[rowindex
][i
][0], 
 662                                              rows
[rowindex
][i
][1], 
 665                 index 
= all
.index(div
) 
 666                 for rowindex 
in range(all
[index
-1],all
[index
]): 
 667                     for i 
in range(len(rows
[rowindex
])): 
 668                         rows
[rowindex
][i
] = (rows
[rowindex
][i
][0], 
 669                                              rows
[rowindex
][i
][1], 
 672         # now munge the multi-line cells together 
 677             for index 
in range(len(row
)): 
 679                     COLS 
= range(len(row
)) 
 680                     for i 
in range(len(COLS
)): 
 682                 if TDdivider(row
[index
][0]) or THdivider(row
[index
][0]): 
 686                     COLS
[index
][0] = COLS
[index
][0] + (row
[index
][0]) + "\n" 
 687                     COLS
[index
][1] = row
[index
][1] 
 688                     COLS
[index
][2] = row
[index
][2] 
 690         # now that each cell has been munged together, 
 691         # determine the cell's alignment. 
 692         # Default is to center. Also determine the cell's 
 693         # vertical alignment, top, middle, bottom. Default is 
 698             for index 
in range(len(row
)): 
 706                 text            
= split(text
,'\n') 
 707                 text            
= text
[:len(text
)-1] 
 713                         topindent 
= topindent 
+ 1 
 720                         bottomindent 
= bottomindent 
+ 1 
 724                 tmp   
= join(text
[topindent
:len(text
)-bottomindent
],"\n") 
 725                 pars  
= re
.compile("\n\s*\n").split(tmp
) 
 729                     par 
= split(par
, ' ') 
 732                             leftindent 
= leftindent
+1 
 735                     left
.append(leftindent
) 
 740                             rightindent 
= rightindent 
+ 1 
 743                     right
.append(rightindent
) 
 748                 if topindent 
== bottomindent
: 
 752                 elif bottomindent 
< 1: 
 761                 elif left
[0] > 1 and right
[0] > 1: 
 766                 cols
.append(row
[index
][0],row
[index
][1],align
,valign
,row
[index
][2]) 
 769         return StructuredTextTable(rows
,text
,subs
,indent
=paragraph
.indent
) 
 771     def doc_bullet(self
, paragraph
, expr 
= re
.compile(r
'\s*[-*o]\s+').match
): 
 772         top
=paragraph
.getColorizableTexts()[0] 
 778         subs
=paragraph
.getSubparagraphs() 
 780            subs
=[StructuredTextExample(subs
)] 
 782         return StructuredTextBullet(top
[m
.span()[1]:], subs
, 
 783                                      indent
=paragraph
.indent
, 
 784                                      bullet
=top
[:m
.span()[1]] 
 789         expr 
= re
.compile(r
'(\s*[%s]+\.)|(\s*[0-9]+\.)|(\s*[0-9]+\s+)' % letters
).match
): 
 791         # This is the old expression. It had a nasty habit 
 792         # of grabbing paragraphs that began with a single 
 793         # letter word even if there was no following period. 
 795         #expr = re.compile('\s*' 
 796         #                   '(([a-zA-Z]|[0-9]+|[ivxlcdmIVXLCDM]+)\.)*' 
 797         #                   '([a-zA-Z]|[0-9]+|[ivxlcdmIVXLCDM]+)\.?' 
 800         top
=paragraph
.getColorizableTexts()[0] 
 802         if not m
: return None 
 803         subs
=paragraph
.getSubparagraphs() 
 805            subs
=[StructuredTextExample(subs
)] 
 807         return StructuredTextNumbered(top
[m
.span()[1]:], subs
, 
 808                                         indent
=paragraph
.indent
, 
 809                                         number
=top
[:m
.span()[1]]) 
 813         delim 
= re
.compile(r
'\s+--\s+').search
, 
 814         nb
=re
.compile(r
'[^\000- ]').search
, 
 817         top
=paragraph
.getColorizableTexts()[0] 
 819         if not d
: return None 
 820         start
, end 
= d
.span() 
 822         if find(title
, '\n') >= 0: return None 
 823         if not nb(title
): return None 
 827         subs
=paragraph
.getSubparagraphs() 
 829            subs
=[StructuredTextExample(subs
)] 
 832         return StructuredTextDescription( 
 834            indent
=paragraph
.indent
, 
 837     def doc_header(self
, paragraph
, 
 838                     expr    
= re
.compile(r
'[ %s0-9.:/,-_*<>\?\'\"]+' % letters).match 
 840         subs=paragraph.getSubparagraphs() 
 841         if not subs: return None 
 842         top=paragraph.getColorizableTexts()[0] 
 843         if not strip(top): return None 
 845            subs=StructuredTextExample(subs) 
 846            if strip(top)=='::': return subs 
 847            return ST.StructuredTextParagraph( 
 848               top[:-1], [subs], indent=paragraph.indent) 
 850         if find(top,'\n') >= 0: return None 
 851         return StructuredTextSection(top, subs, indent=paragraph.indent) 
 857           r"([^ 
\t\n\r\f\v']|[^ \t\n\r\f\v'][^
\n']*[^ \t\n\r\f\v'])" # contents 
 858           r"'(?:\s|[,.;:!?]|$)"                                        # close 
 863            start, end = r.span(1) 
 864            return (StructuredTextLiteral(s[start:end]), start-1, end+1) 
 870         expr = re.compile(r'\s
*\
*([ \n%s0-9]+)\
*(?
!\
*|
-)' % lettpunc).search 
 875            start, end = r.span(1) 
 876            return (StructuredTextEmphasis(s[start:end]), start-1, end+1) 
 880     def doc_inner_link(self, 
 882                        expr1 = re.compile(r"\.\.\s*").search, 
 883                        expr2 = re.compile(r"\[[%s0-9]+\]" % letters ).search): 
 885         # make sure we dont grab a named link 
 886         if expr2(s) and expr1(s): 
 887             start1,end1 = expr1(s).span() 
 888             start2,end2 = expr2(s).span() 
 890                 # uh-oh, looks like a named link 
 893                 # the .. is somewhere else, ignore it 
 894                 return (StructuredTextInnerLink(s[start2+1,end2-1],start2,end2)) 
 896         elif expr2(s) and not expr1(s): 
 897             start,end = expr2(s).span() 
 898             return (StructuredTextInnerLink(s[start+1:end-1]),start,end) 
 901     def doc_named_link(self, 
 903                        expr=re.compile(r"(\.\.\s)(\[[%s0-9]+\])" % letters).search): 
 907             start,end   = result.span(2) 
 909             str = strip(s[a:b]) + s[start:end] 
 910             st,en       = result.span() 
 911             return (StructuredTextNamedLink(str),st,en) 
 912             #return (StructuredTextNamedLink(s[st:en]),st,en) 
 915     def doc_underline(self, 
 917                       expr=re.compile(r"\s+\_([%s0-9\s]+)\_" % lettpunc).search): 
 921             start,end = result.span(1) 
 923             return (StructuredTextUnderline(s[start:end]),st,e) 
 929         expr = re.compile(r'\s
*\
*\
*([ \n%s0-9]+)\
*\
*' % lettpunc).search 
 934            start, end = r.span(1) 
 935            return (StructuredTextStrong(s[start:end]), start-2, end+2) 
 939     ## Some constants to make the doc_href() regex easier to read. 
 940     _DQUOTEDTEXT = r'("[%s0-9\n\-\.\,\;\(\)\/\:\/\*\']+")'  % letters ## double quoted text 
 941     _URL_AND_PUNC = r'([%s0-9\
@\
.\
,\?\
!\
/\
:\
;\
-\
#\~]+)' % letters  
 944     def doc_href(self
, s
, 
 945                  expr1 
= re
.compile(_DQUOTEDTEXT 
+ "(:)" + _URL_AND_PUNC 
+ _SPACES
).search
, 
 946                  expr2 
= re
.compile(_DQUOTEDTEXT 
+ r
'(\,\s+)' + _URL_AND_PUNC 
+ _SPACES
).search
): 
 948         punctuation 
= re
.compile(r
"[\,\.\?\!\;]+").match
 
 949         r
=expr1(s
) or expr2(s
) 
 952             # need to grab the href part and the 
 957             name    
= replace(name
,'"','',2) 
 960             if punctuation(s
[end
-1:end
]): 
 965             # name is the href title, link is the target 
 967             return (StructuredTextLink(name
, href
=link
), 
 970             #return (StructuredTextLink(s[start:end], href=s[start:end]), 
 975     def doc_sgml(self
,s
,expr
=re
.compile(r
"\<[%s0-9\.\=\'\"\
:\
/\
-\
#\+\s\*]+\>" % letters).search): 
 977         SGML text is ignored and outputed as-is 
 983             return (StructuredTextSGML(text
),start
,end
) 
 986     def doc_xref(self
, s
, 
 987         expr 
= re
.compile('\[([%s0-9\-.:/;,\n\~]+)\]' % letters
).search
 
 991             start
, end 
= r
.span(1) 
 992             return (StructuredTextXref(s
[start
:end
]), start
-1, end
+1)