@ -3,18 +3,31 @@ from panflute import Cite, Code, Emph, Image, LineBreak, Link, Math, Note, Quote
from panflute import BlockQuote , BulletList , Citation , CodeBlock , Definition , DefinitionItem , DefinitionList , Div , Figure , Header , HorizontalRule , LineBlock , LineItem , ListItem , MetaBlocks , MetaBool , MetaInlines , MetaList , MetaMap , MetaString , Null , OrderedList , Para , Plain , RawBlock , Table , TableBody , TableFoot , TableHead
from panflute import TableRow , TableCell , Caption , Doc
from panflute import MetaValue
from panflute import stringify
from typing import Union , Callable
from . whitespace import NBSP
from . elements import FQuoted
from . context import Group , InlineGroup , BlockGroup , Context
import re
import re , sys
class UnknownElementError ( Exception ) :
" An unknown Element has been passed to the OutputGenerator, probably because panflute introduced a new one. "
pass
class OutputGeneratorError ( Exception ) :
" A generic exception which wraps other exceptions and adds element-based traceback "
elements : list [ Union [ Element , ListContainer , list [ Union [ Element , ListContainer ] ] ] ]
def __init__ ( self , e : Union [ Element , ListContainer , list [ Union [ Element , ListContainer ] ] ] , * args ) :
self . elements = [ e ]
super ( ) . __init__ ( args )
def add_element ( self , e : Union [ Element , ListContainer , list [ Union [ Element , ListContainer ] ] ] ) :
self . elements . append ( e )
class OutputGenerator :
_empty_lines : int
context : Union [ Context , None ]
@ -101,6 +114,25 @@ class OutputGenerator:
}
def generate ( self , e : Union [ Element , ListContainer , list [ Union [ Element , ListContainer ] ] ] ) :
try :
self . _generate ( e )
except OutputGeneratorError as err :
def eprint ( * args , * * kwargs ) :
print ( * args , file = sys . stderr , * * kwargs )
eprint ( " Error occured in " , end = " " )
for i in range ( len ( err . elements ) - 1 , 0 , - 1 ) :
if hasattr ( err . elements [ i ] , " content " ) and isinstance ( err . elements [ i ] . content [ 0 ] , Inline ) :
eprint ( )
eprint ( ' on line: " ' + stringify ( err . elements [ i ] ) + ' " ' , end = " " )
break
eprint ( type ( err . elements [ i ] ) . __name__ + " [ " + str ( err . elements [ i - 1 ] . index ) + " ] " , end = " : " )
eprint ( )
eprint ( " in element: " + str ( err . elements [ 0 ] ) )
sys . tracebacklimit = 0
raise err . __cause__ from None
def _generate ( self , e : Union [ Element , ListContainer , list [ Union [ Element , ListContainer ] ] ] ) :
try :
if isinstance ( e , Group ) :
old_context = self . context
self . context = e . context
@ -119,10 +151,16 @@ class OutputGenerator:
else :
try :
self . TYPE_DICT_MISC [ type ( e ) ] ( e )
except KeyError :
raise UnknownElementError ( type ( e ) )
except KeyError as er r :
raise UnknownElementError ( type ( e ) ) from err
if isinstance ( e , Group ) :
self . context = old_context
except OutputGeneratorError as err :
if not isinstance ( e , ListContainer ) :
err . add_element ( e )
raise err
except Exception as err :
raise OutputGeneratorError ( e ) from err
def escape_special_chars ( self , text : str ) - > str :
return text
@ -210,13 +248,13 @@ class OutputGenerator:
def generate_simple_inline_tag ( self , tag : str , content : Union [ ListContainer , Element , list [ Union [ Element , ListContainer ] ] ] , attributes : dict [ str , str ] = { } ) :
self . write ( self . start_tag ( tag , attributes ) )
self . generate ( content )
self . _ generate( content )
self . write ( self . end_tag ( tag ) )
def generate_simple_block_tag ( self , tag : str , content : Union [ ListContainer , Element , list [ Union [ Element , ListContainer ] ] ] , attributes : dict [ str , str ] = { } ) :
self . writeln ( self . start_tag ( tag , attributes ) )
self . indent_more ( )
self . generate ( content )
self . _ generate( content )
self . indent_less ( )
self . writeln ( self . end_tag ( tag ) )
@ -235,27 +273,27 @@ class OutputGenerator:
def generate_ListContainer ( self , e : ListContainer ) :
for child in e :
self . generate ( child )
self . _ generate( child )
def generate_list ( self , e : list ) :
for el in e :
self . generate ( el )
self . _ generate( el )
def generate_MetaList ( self , e : MetaList ) :
for child in e :
self . generate ( child )
self . _ generate( child )
def generate_MetaValue ( self , e : MetaValue ) :
try :
self . TYPE_DICT_META [ type ( e ) ] ( e )
except KeyError :
self . generate ( e . content )
self . _ generate( e . content )
def generate_MetaBlocks ( self , e : MetaBlocks ) :
self . generate ( e . content )
self . _ generate( e . content )
def generate_MetaInlines ( self , e : MetaInlines ) :
self . generate ( e . content )
self . _ generate( e . content )
def generate_MetaBool ( self , e : MetaBool ) :
self . generate_simple_tag ( e )
@ -285,33 +323,33 @@ class OutputGenerator:
if e . style == " cs " :
if e . quote_type == " SingleQuote " :
self . write ( " ‚ " )
self . generate ( e . content )
self . _ generate( e . content )
self . write ( " ‘ " )
elif e . quote_type == " DoubleQuote " :
self . write ( " „ " )
self . generate ( e . content )
self . _ generate( e . content )
self . write ( " “ " )
elif e . style == " en " :
if e . quote_type == " SingleQuote " :
self . write ( " ‘ " )
self . generate ( e . content )
self . _ generate( e . content )
self . write ( " ’ " )
elif e . quote_type == " DoubleQuote " :
self . write ( " “ " )
self . generate ( e . content )
self . _ generate( e . content )
self . write ( " ” " )
else :
if e . quote_type == " SingleQuote " :
self . write ( " ' " )
self . generate ( e . content )
self . _ generate( e . content )
self . write ( " ' " )
elif e . quote_type == " DoubleQuote " :
self . write ( " \" " )
self . generate ( e . content )
self . _ generate( e . content )
self . write ( " \" " )
else :
self . write ( " \" " )
self . generate ( e . content )
self . _ generate( e . content )
self . write ( " \" " )
@ -434,10 +472,10 @@ class OutputGenerator:
def generate_Doc ( self , e : Doc ) :
if " header_content " in e . metadata :
self . generate ( e . metadata [ " header_content " ] )
self . _ generate( e . metadata [ " header_content " ] )
self . generate_simple_tag ( e )
if " footer_content " in e . metadata :
self . generate ( e . metadata [ " footer_content " ] )
self . _ generate( e . metadata [ " footer_content " ] )
def generate_BlockGroup ( self , e : BlockGroup ) :
self . generate_simple_tag ( e )