#!/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()