#!/usr/bin/env python3
import argparse
import sys
import os
import tempfile
import subprocess
import shutil
from pathlib import Path
# Import local files
from . util import import_md
from . katex import KatexClient
from . images import ImageProcessor , ImageProcessorNamespace
from . output_generator import OutputGenerator , FormatitkoRecursiveError
from . html_generator import HTMLGenerator , StandaloneHTMLGenerator
from . transform_processor import TransformProcessor
from . pandoc_processor import PandocProcessor
from . tex_generator import UCWTexGenerator
from . context import get_context_from_doc
from panflute import convert_text
def main ( ) :
# Initialize command line arguments
parser = argparse . ArgumentParser ( formatter_class = argparse . ArgumentDefaultsHelpFormatter )
parser . add_argument ( " -l " , " --img-lookup-dirs " , help = " Image lookup directories. When processing images, the program will try to find the image in them first. Always looks for images in the same folder as the markdown file. " , nargs = " + " , default = [ ] )
parser . add_argument ( " -p " , " --img-public-dir " , help = " Directory to put processed images into. The program will overwrite images, whose dependencies are newer. " , default = " public " )
parser . add_argument ( " -c " , " --img-cache-dir " , help = " Directory to cache processed images and intermediate products. The program will overwrite files, whose dependencies are newer. " , default = " cache " )
parser . add_argument ( " -i " , " --img-web-path " , help = " Path where the processed images are available on the website. " , default = " / " )
parser . add_argument ( " -w " , " --output-html " , help = " The HTML file (for Web) to write into. " )
parser . add_argument ( " -s " , " --output-standalone-html " , help = " The Standalone HTML file to write into. A full page is generated instead of just a fragment. " )
parser . add_argument ( " -t " , " --output-tex " , help = " The TEX file to write into. " )
parser . add_argument ( " -m " , " --output-md " , help = " The Markdown file to write into. (Uses pandoc to generate markdown) " )
parser . add_argument ( " -j " , " --output-json " , help = " The JSON file to dump the pandoc-compatible AST into. " )
parser . add_argument ( " -P " , " --output-pdf " , help = " The PDF file to save the PDF generated by TeX. " )
parser . add_argument ( " --katex-server " , action = ' store_true ' , help = " Starts a KaTeX server and prints the socket filename onto stdout. Useful for running formatitko many times without starting the KaTeX server each time. " )
parser . add_argument ( " -k " , " --katex-socket " , help = " The KaTeX server socket filename obtained by running with `--katex-server`. " )
parser . add_argument ( " input_filename " , help = " The markdown file to process. " , nargs = " ? " if " --katex-server " in sys . argv else None )
parser . add_argument ( " --debug " , action = ' store_true ' )
parser . add_argument ( " --traceback-limit " , help = " Traceback limit for when errors happen, defaults to 0, as it is only useful for internal debugging. " , default = 0 )
parser . add_argument ( " --deps " , help = " File to write list of dependencies to. May depend on output formats used. " )
args = parser . parse_args ( )
if args . katex_server :
with KatexClient ( connect = False ) as katexClient :
print ( katexClient . get_socket ( ) )
try :
while True :
pass
except KeyboardInterrupt :
print ( " Exiting... " )
return
# Use panflute to parse the input MD file
doc = import_md ( open ( args . input_filename , " r " ) . read ( ) )
if args . debug :
try :
OutputGenerator ( sys . stdout ) . generate ( doc )
except FormatitkoRecursiveError as e :
e . pretty_print ( tracebacklimit = args . traceback_limit )
try :
doc = TransformProcessor ( args . input_filename ) . transform ( doc )
except FormatitkoRecursiveError as e :
e . pretty_print ( tracebacklimit = args . traceback_limit )
# Initialize the image processor (this just keeps some basic state)
imageProcessor = ImageProcessor ( { " " : ImageProcessorNamespace ( args . img_public_dir , args . img_web_path , args . img_cache_dir , args . img_lookup_dirs , True ) } )
if args . output_html is not None :
# Initialize KaTeX client (this runs the node app and connects to a unix socket)
with KatexClient ( socket = args . katex_socket ) as katexClient :
with open ( args . output_html , " w " ) as file :
try :
HTMLGenerator ( file , katexClient , imageProcessor ) . generate ( doc )
except FormatitkoRecursiveError as e :
e . pretty_print ( tracebacklimit = args . traceback_limit )
if args . output_standalone_html is not None :
# Initialize KaTeX client (this runs the node app and connects to a unix socket)
with KatexClient ( socket = args . katex_socket ) as katexClient :
with open ( args . output_standalone_html , " w " ) as file :
try :
StandaloneHTMLGenerator ( file , katexClient , imageProcessor ) . generate ( doc )
except FormatitkoRecursiveError as e :
e . pretty_print ( tracebacklimit = args . traceback_limit )
if args . output_tex is not None :
with open ( args . output_tex , " w " ) as file :
try :
UCWTexGenerator ( file , imageProcessor ) . generate ( doc )
except FormatitkoRecursiveError as e :
e . pretty_print ( tracebacklimit = args . traceback_limit )
if args . output_md is not None :
with open ( args . output_md , " w " ) as file :
file . write ( convert_text ( PandocProcessor ( ) . transform ( doc ) , input_format = " panflute " , output_format = " markdown " ) )
if args . output_json is not None :
with open ( args . output_json , " w " ) as file :
file . write ( convert_text ( PandocProcessor ( ) . transform ( doc ) , input_format = " panflute " , output_format = " json " ) )
if args . output_pdf is not None :
if args . output_tex is None :
fd = tempfile . NamedTemporaryFile ( dir = " . " , suffix = " .tex " )
with open ( fd . name , " w " ) as file :
try :
UCWTexGenerator ( file , imageProcessor ) . generate ( doc )
except FormatitkoRecursiveError as e :
e . pretty_print ( tracebacklimit = args . traceback_limit )
filename = fd . name
else :
filename = args . output_tex
outdir = tempfile . TemporaryDirectory ( prefix = " formatitko " )
env = os . environ . copy ( )
d = Path ( " / " . join ( __file__ . split ( " / " ) [ : - 1 ] ) )
env [ " TEXINPUTS " ] = " .: " + str ( d / " tex " ) + " : " + env . get ( " TEXINPUTS " , " " )
subprocess . run ( [ " luatex " , " -halt-on-error " , " -output-directory= " + outdir . name , " -jobname=formatitko " , filename ] , check = True , env = env )
shutil . move ( outdir . name + " /formatitko.pdf " , args . output_pdf )
if args . deps is not None :
with open ( args . deps , " w " ) as file :
for dep in get_context_from_doc ( doc ) . get_deps ( ) :
file . write ( dep + " \n " )
if args . debug :
print ( " ----------------------------------- " )
try :
OutputGenerator ( sys . stdout ) . generate ( doc )
except FormatitkoRecursiveError as e :
e . pretty_print ( tracebacklimit = args . traceback_limit )
if __name__ == " __main__ " :
main ( )