@ -1,16 +1,16 @@
#!/usr/bin/env python3
#!/usr/bin/env python3
# Import local files
from whitespace import *
from command import *
from util import *
import builtin_commands
from panflute import *
from panflute import *
import re
import re
import sys
import sys
from typing import List
from typing import List
# Import local files
from whitespace import *
from command import *
from util import *
from mj_show import show
from mj_show import show
flags = [ " dog " ]
flags = [ " dog " ]
@ -20,14 +20,14 @@ 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
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 '
text + = s
text + = s
def println ( s : str ) :
def println ( s : str = " " ) :
print ( s + " \n " )
print ( s + " \n " )
def appendChild ( e : Element ) :
def appendChild ( e : Element ) :
@ -53,6 +53,9 @@ def executeCommand(source: Code, element: Element) -> List[Element]:
def transform ( e : Element , doc : Doc ) - > Element : # Returns next sibling element to transform
def transform ( e : Element , doc : Doc ) - > Element : # Returns next sibling element to transform
""" Transform the AST, making format-agnostic changes. """
""" Transform the AST, making format-agnostic changes. """
global commands
global flags
if isinstance ( e , Whitespace ) and bavlna ( e ) :
if isinstance ( e , Whitespace ) and bavlna ( e ) :
e = NBSP ( )
e = NBSP ( )
@ -60,11 +63,11 @@ def transform(e: Element, doc: Doc) -> Element: # Returns next sibling element t
# `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 :
return Null ( )
return nullify ( e )
# `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 :
return Null ( )
return nullify ( e )
# `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 :
@ -72,32 +75,54 @@ def transform(e: Element, doc: Doc) -> Element: # Returns next sibling element t
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 = 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 )
return Null ( )
return nullify ( e )
# Define commands
## Define commands
# TODO: def/longdef?
# TODO: def/longdef?
if isinstance ( e , CodeBlock ) and hasattr ( e , " classes " ) and " python " in e . classes and hasattr ( e , " attributes " ) :
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 ( )
return nullify ( e )
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 ( )
return nullify ( e )
# Handle special command shorthand [!commandname]{}
if isinstance ( e , Span ) and len ( e . content ) == 1 and isinstance ( e . content [ 0 ] , Str ) :
if isinstance ( e , Span ) and len ( e . content ) == 1 and isinstance ( e . content [ 0 ] , Str ) and re . match ( r " ^![ \ w.]+$ " , e . content [ 0 ] . text ) :
print ( isinstance ( e , Span ) )
e = InlineCommand ( identifier = e . identifier , classes = e . classes , attributes = { * * e . attributes , " c " : e . content [ 0 ] . text [ 1 : ] } )
## Handle special command shorthand [!commandname]{}
if re . match ( r " ^![ \ w.]+$ " , e . content [ 0 ] . text ) :
# Execute commands
e = InlineCommand ( identifier = e . identifier , classes = e . classes , attributes = { * * e . attributes , " c " : e . content [ 0 ] . text [ 1 : ] } )
## Handle include [>path/file.md]{} TODO: implement properly as commands
# This is for including content from files with their own flags
# and commands without affecting the state of the current
# document.
elif re . match ( r " ^>.+$ " , e . content [ 0 ] . text ) :
includedDoc = convert_text ( open ( e . content [ 0 ] . text [ 1 : ] , " r " ) . read ( ) , standalone = True ) # TODO: Put into function
oCommands = commands . copy ( )
oFlags = flags [ : ]
includedDoc = includedDoc . walk ( transform )
commands = oCommands
flags = oFlags
#e = Div(*includedDoc.content)
## Handle import [#path/file.md]{} TODO: implement properly as commands
# This is the exact opposite of include. We take the commands
# and flags but drop the content.
elif re . match ( r " ^#.+$ " , e . content [ 0 ] . text ) :
importedDoc = convert_text ( open ( e . content [ 0 ] . text [ 1 : ] , " r " ) . read ( ) , standalone = True ) # TODO: Put into function
importedDoc . walk ( transform )
return nullify ( e )
## Execute commands
# Walk transforms the children first, then the root element,
# Walk transforms the children first, then the root element,
# so the content of the element the command receives is
# so the content of the element the command receives is
# already transformed.
# already transformed.
@ -110,7 +135,8 @@ def transform(e: Element, doc: Doc) -> Element: # Returns next sibling element t
return e
return e
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 ) # TODO: Put into function so we can specify extensions and parameters globally.
print ( show ( doc ) )
print ( show ( doc ) )
doc = doc . walk ( transform )
doc = doc . walk ( transform )