@ -14,13 +14,14 @@ from typing import List
from mj_show import show
from mj_show import show
flags = [ " dog " ]
flags = [ " dog " ]
commands = [ ]
commands = { }
def executeCommand ( source : Code , element : Element ) - > List [ Element ] :
def executeCommand ( source : Code , element : Element ) - > List [ Element ] :
mode = ' empty '
mode = ' empty '
text = " "
text = " "
content = [ ]
content = [ ]
def print ( s : str ) :
def print ( s : str ) :
nonlocal mode , text
if mode == ' elements ' :
if mode == ' elements ' :
raise SyntaxError ( " Cannot use `print` and `appendChild` in one command at the same time. " )
raise SyntaxError ( " Cannot use `print` and `appendChild` in one command at the same time. " )
mode = ' text '
mode = ' text '
@ -30,11 +31,16 @@ def executeCommand(source: Code, element: Element) -> List[Element]:
print ( s + " \n " )
print ( s + " \n " )
def appendChild ( e : Element ) :
def appendChild ( e : Element ) :
nonlocal mode , content
if mode == ' text ' :
if mode == ' text ' :
raise SyntaxError ( " Cannot use `print` and `appendChild` in one command at the same time. " )
raise SyntaxError ( " Cannot use `print` and `appendChild` in one command at the same time. " )
mode = ' elements '
mode = ' elements '
content . append ( e )
content . append ( e )
def appendChildren ( l : List [ Element ] ) :
for e in l :
appendChild ( e )
exec ( source )
exec ( source )
if mode == ' text ' :
if mode == ' text ' :
@ -42,83 +48,74 @@ def executeCommand(source: Code, element: Element) -> List[Element]:
if mode == ' elements ' :
if mode == ' elements ' :
return content
return content
return [ ]
def transform ( e : Element , doc : Doc ) - > Element : # Returns next sibling element to transform
def transform ( e : Element ) - > Element : # Returns next sibling element to transform
""" Transform the AST, making format-agnostic changes. """
""" Transform the AST, making format-agnostic changes. """
if isinstance ( e , Whitespace ) and bavlna ( e ) :
if isinstance ( e , Whitespace ) and bavlna ( e ) :
e = replaceEl ( e , NBSP ( ) )
e = NBSP ( )
if hasattr ( e , " attributes " ) :
if hasattr ( e , " attributes " ) :
# `if` attribute. Only show this element if flag is set.
# `if` attribute. Only show this element if flag is set.
if " if " in e . attributes :
if " if " in e . attributes :
if not e . attributes [ " if " ] in flags :
if not e . attributes [ " if " ] in flags :
deleteEl ( e )
return Null ( )
return
# `ifn` attribute. Only show this element if flag is NOT set
# `ifn` attribute. Only show this element if flag is NOT set
if " ifn " in e . attributes :
if " ifn " in e . attributes :
if e . attributes [ " ifn " ] in flags :
if e . attributes [ " ifn " ] in flags :
deleteEl ( e )
return Null ( )
return
# `c` attribute. Execute a command with the name saved in this attribute.
# `c` attribute. Execute a command with the name saved in this attribute.
if ( isinstance ( e , Div ) or isinstance ( e , Span ) ) and " c " in e . attributes :
if ( isinstance ( e , Div ) or isinstance ( e , Span ) ) and " c " in e . attributes :
if isinstance ( e , Div ) :
if isinstance ( e , Div ) :
e = replaceEl ( e , MultilineCommand ( * e . content , identifier = e . identifier , classes = e . classes , attributes = e . attributes ) )
e = MultilineCommand ( * e . content , identifier = e . identifier , classes = e . classes , attributes = e . attributes )
else :
else :
e = replaceEl ( e , InlineCommand ( * e . content , identifier = e . identifier , classes = e . classes , attributes = e . attributes ) )
e = InlineCommand ( * e . content , identifier = e . identifier , classes = e . classes , attributes = e . attributes )
print ( f " Created inline command { e } " )
# Execute python code inside source code block
# Execute python code inside source code block
if isinstance ( e , CodeBlock ) and hasattr ( e , " classes " ) and " python " in e . classes and " run " in e . classes :
if isinstance ( e , CodeBlock ) and hasattr ( e , " classes " ) and " python " in e . classes and " run " in e . classes :
exec ( e . text )
exec ( e . text )
deleteEl ( e )
return Null ( )
return
# Define commands
if isinstance ( e , CodeBlock ) and hasattr ( e , " classes " ) and " python " in e . classes and hasattr ( e , attributes ) :
# TODO: def/longdef?
if isinstance ( e , CodeBlock ) and hasattr ( e , " classes " ) and " python " in e . classes and hasattr ( e , " attributes " ) :
if " define " in e . attributes :
if " define " in e . attributes :
if not e . attributes [ " define " ] in commands :
if not e . attributes [ " define " ] in commands :
commands [ e . attributes [ " define " ] ] = compile ( e . text , ' <string> ' , ' exec ' )
commands [ e . attributes [ " define " ] ] = compile ( e . text , ' <string> ' , ' exec ' )
return Null ( )
else :
else :
raise NameError ( f " Command already defined: ' { e . attributes [ ' define ' ] } ' " )
raise NameError ( f " Command already defined: ' { e . attributes [ ' define ' ] } ' " )
if " redefine " in e . attributes :
if " redefine " in e . attributes :
commands [ e . attributes [ " redefine " ] ] = compile ( e . text , ' <string> ' , ' exec ' )
commands [ e . attributes [ " redefine " ] ] = compile ( e . text , ' <string> ' , ' exec ' )
return Null ( )
# Handle special command shorthand [!commandname]{}
# Handle special command shorthand [!commandname]{}
if isinstance ( e , Span ) and len ( e . content ) == 1 and isinstance ( e . content [ 0 ] , Str ) and re . match ( r " ^![ \ w.]+$ " , e . content [ 0 ] . text ) :
if isinstance ( e , Span ) and len ( e . content ) == 1 and isinstance ( e . content [ 0 ] , Str ) and re . match ( r " ^![ \ w.]+$ " , e . content [ 0 ] . text ) :
e = replaceEl ( e , InlineCommand ( identifier = e . identifier , classes = e . classes , attributes = { * * e . attributes , " c " : e . content [ 0 ] . text [ 1 : ] } ) )
e = InlineCommand ( identifier = e . identifier , classes = e . classes , attributes = { * * e . attributes , " c " : e . content [ 0 ] . text [ 1 : ] } )
# The command is executed first and then its contents are transformed. TODO: Is this what we want?
# Execute commands
# Walk transforms the children first, then the root element,
# so the content of the element the command receives is
# already transformed.
# TODO: Transform content that comes out of commands.
if isinstance ( e , Command ) :
if isinstance ( e , Command ) :
if not e . attributes [ " c " ] in commands :
if not e . attributes [ " c " ] in commands :
raise NameError ( f " Command not defined ' { e . attributes [ ' c ' ] } ' . " )
raise NameError ( f " Command not defined ' { e . attributes [ ' c ' ] } ' . " )
e = e . replaceSelf ( executeCommand ( commands [ e . attributes [ " c " ] ] , e ) )
e = e . replaceSelf ( executeCommand ( commands [ e . attributes [ " c " ] ] , e ) )
# Transformation of other elements. This is not done using a for cycle,
return e
# because deletions of elements would mess with it.
children = ( ( child_name , getattr ( e , child_name ) ) for child_name in e . _children )
for child_name , child in children :
if hasattr ( e , " content " ) and len ( e . content ) > 0 :
next = transform ( e . content [ 0 ] )
while next != None :
next = transform ( next )
print ( next )
# Return nearest sibling to transform
return e . next
doc = convert_text ( open ( sys . argv [ 1 ] , " r " ) . read ( ) , standalone = True , extra_args = [ " -f " , " markdown+fenced_code_attributes " ] )
doc = convert_text ( open ( sys . argv [ 1 ] , " r " ) . read ( ) , standalone = True , extra_args = [ " -f " , " markdown+fenced_code_attributes " ] )
print ( show ( doc ) )
print ( show ( doc ) )
print ( doc . content . _children )
doc = doc . walk ( transform )
#transform(doc )
print ( " --------------------- " )
#print("---------------------" )
#print(show(doc))
#print(convert_text(doc, input_format="panflute", output_format="markdown") )
print ( convert_text ( doc , input_format = " panflute " , output_format = " markdown " ) )