Browse Source

První draft #13, obecná třída ze které podědí HTML_generator a TeX_generator.

pull/28/head
Jan Černohorský 10 months ago
parent
commit
1a56c0e03f
  1. 87
      src/formatitko/formatitko.py
  2. 2
      src/formatitko/katex.py
  3. 340
      src/formatitko/output_generator.py
  4. 2
      src/formatitko/transform.py

87
src/formatitko/formatitko.py

@ -1,6 +1,7 @@
#!/usr/bin/env python3
import argparse
import sys
# Import local files
from .transform import transform
@ -10,52 +11,54 @@ from .katex import KatexClient
from .html import html
from .tex import tex
from .images import ImageProcessor
from .output_generator import Output_generator
from .mj_show import show
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 not overwrite existing images.", default="public")
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.", default="output.html")
parser.add_argument("-t", "--output-tex", help="The TEX file to write into.", default="output.tex")
parser.add_argument("input_filename", help="The markdown file to process.")
parser.add_argument("--debug", action='store_true')
args = parser.parse_args()
# TODO: Accept path to unix socket for katexClient, then don't init our own,
# just connect to an existing one. For formátíking many files in a row.
# Use panflute to parse the input MD file
doc = import_md(open(args.input_filename, "r").read())
if args.debug:
print(show(doc))
# The language metadatum is important, so it's read before transformation and
# then attached to a group inside the Doc
language = doc.get_metadata("language", None, True)
context = Context(doc, args.input_filename)
# Transform the document. This includes all the fancy formatting this software does.
doc = doc.walk(transform, context)
# Now wrap the document contents in a group, which is able to pop its language
# setting out to TeX
doc.content = [Group(*doc.content, metadata={"language":language})]
# Initialize the image processor (this just keeps some basic state)
imageProcessor = ImageProcessor(args.img_public_dir, args.img_web_path, *args.img_lookup_dirs)
# Initialize KaTeX client (this runs the node app and connects to a unix socket)
with KatexClient() as katexClient:
# Generate HTML and TeX out of the transformed document
open(args.output_html, "w").write(html(doc, katexClient, imageProcessor))
open(args.output_tex, "w").write(tex(doc, imageProcessor))
if args.debug:
print(show(doc))
# 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 not overwrite existing images.", default="public")
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.", default="output.html")
parser.add_argument("-t", "--output-tex", help="The TEX file to write into.", default="output.tex")
parser.add_argument("input_filename", help="The markdown file to process.")
parser.add_argument("--debug", action='store_true')
args = parser.parse_args()
# TODO: Accept path to unix socket for katexClient, then don't init our own,
# just connect to an existing one. For formátíking many files in a row.
# Use panflute to parse the input MD file
doc = import_md(open(args.input_filename, "r").read())
if args.debug:
print(show(doc))
# The language metadatum is important, so it's read before transformation and
# then attached to a group inside the Doc
language = doc.get_metadata("language", None, True)
context = Context(doc, args.input_filename)
# Transform the document. This includes all the fancy formatting this software does.
doc = doc.walk(transform, context)
# Now wrap the document contents in a group, which is able to pop its language
# setting out to TeX
doc.content = [Group(*doc.content, metadata={"language":language})]
# Initialize the image processor (this just keeps some basic state)
imageProcessor = ImageProcessor(args.img_public_dir, args.img_web_path, *args.img_lookup_dirs)
# Initialize KaTeX client (this runs the node app and connects to a unix socket)
with KatexClient() as katexClient:
# Generate HTML and TeX out of the transformed document
#open(args.output_html, "w").write(html(doc, katexClient, imageProcessor))
#open(args.output_tex, "w").write(tex(doc, imageProcessor))
Output_generator(sys.stdout).generate(doc)
if args.debug:
print(show(doc))
if __name__ == "__main__":

2
src/formatitko/katex.py

@ -65,5 +65,5 @@ class KatexClient:
def __enter__(self):
return self
def __exit__(self):
def __exit__(self, type, value, tb):
self._server_process.terminate()

340
src/formatitko/output_generator.py

@ -0,0 +1,340 @@
from panflute import Element, ListContainer, Inline, Block
from panflute import Cite, Code, Emph, Image, LineBreak, Link, Math, Note, Quoted, RawInline, SmallCaps, SoftBreak, Space, Span, Str, Strikeout, Strong, Subscript, Superscript, Underline
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 typing import Union
from .whitespace import NBSP
from .transform import FQuoted
from .context import Group
class UnknownElementException(Exception):
"An unknown Element has been passed to the Output_generator, probably because panflute introduced a new one."
pass
class Output_generator:
def __init__(self, output_file, indent_str: str="\t", initial_indent_level: int=0):
self.output_file = output_file
self.indent_str = indent_str
self.indent_level = initial_indent_level
self._at_start_of_line = True
def indent(self) -> str:
return self.indent_str*self.indent_level
def iup(self):
self.indent_level += 1
def ido(self):
self.indent_level -= 1
def write(self, text: str):
if self._at_start_of_line:
self.output_file.write(self.indent())
self.output_file.write(text)
self._at_start_of_line = False
def writeln(self, text: str):
if not self._at_start_of_line:
self.output_file.write("\n")
self.output_file.write(self.indent())
self.output_file.write(text+"\n")
self._at_start_of_line = True
def writeraw(self, text: str):
if not self._at_start_of_line:
self.output_file.write("\n")
self.output_file.write(text+"\n")
self._at_start_of_line = True
def endln(self):
if not self._at_start_of_line:
self.output_file.write("\n")
self._at_start_of_line = True
def stag(self, tag: str) -> str:
return tag
def etag(self, tag: str) -> str:
return "/" + tag
def ntag(self, tag: str) -> str:
return "/" + tag + "/"
def generate(self, e: Union[Element, ListContainer]):
if isinstance(e, ListContainer):
self.generate_ListContainer(e)
elif isinstance(e, Inline):
self.generate_Inline(e)
elif isinstance(e, Block):
self.generate_Block(e)
else:
try:
{
TableRow: self.generate_TableRow,
TableCell: self.generate_TableCell,
Caption: self.generate_Caption,
Doc: self.generate_Doc,
LineItem: self.generate_LineItem,
ListItem: self.generate_ListItem
}[type(e)](e)
except KeyError:
raise UnknownElementException(type(e))
def generate_ListContainer(self, e: ListContainer):
for child in e:
self.generate(child)
def generate_Inline(self, e: Inline):
{
Cite: self.generate_Cite,
Code: self.generate_Code,
Emph: self.generate_Emph,
Image: self.generate_Image,
LineBreak: self.generate_LineBreak,
Link: self.generate_Link,
Math: self.generate_Math,
Note: self.generate_Note,
Quoted: self.generate_Quoted,
RawInline: self.generate_RawInline,
SmallCaps: self.generate_SmallCaps,
SoftBreak: self.generate_SoftBreak,
Space: self.generate_Space,
Span: self.generate_Span,
Str: self.generate_Str,
Strikeout: self.generate_Strikeout,
Strong: self.generate_Strong,
Subscript: self.generate_Subscript,
Superscript: self.generate_Superscript,
Underline: self.generate_Underline,
NBSP: self.generate_NBSP,
FQuoted: self.generate_FQuoted
}[type(e)](e)
def generate_Str(self, e):
self.write(e.text)
def generate_Space(self, e):
self.write(" ")
def generate_NBSP(self, e):
self.write("~")
def generate_SoftBreak(self, e):
self.endln()
def generate_Cite(self, e):
self.generate_simple_inline_tag(e, "Cite")
def generate_Emph(self, e):
self.generate_simple_inline_tag(e, "Emph")
def generate_Image(self, e):
self.generate_simple_inline_tag(e, "Image")
def generate_LineBreak(self, e):
self.generate_simple_inline_tag(e, "LineBreak")
def generate_Link(self, e):
self.generate_simple_inline_tag(e, "Link")
def generate_Note(self, e):
self.generate_simple_inline_tag(e, "Note")
def generate_Quoted(self, e):
self.generate_simple_inline_tag(e, "Quoted")
def generate_RawInline(self, e):
self.generate_simple_inline_tag(e, "RawInline")
def generate_SmallCaps(self, e):
self.generate_simple_inline_tag(e, "SmallCaps")
def generate_Span(self, e):
self.generate_simple_inline_tag(e, "Span")
def generate_Strikeout(self, e):
self.generate_simple_inline_tag(e, "Strikeout")
def generate_Strong(self, e):
self.generate_simple_inline_tag(e, "Strong")
def generate_Subscript(self, e):
self.generate_simple_inline_tag(e, "Subscript")
def generate_Superscript(self, e):
self.generate_simple_inline_tag(e, "Superscript")
def generate_Underline(self, e):
self.generate_simple_inline_tag(e, "Underline")
def generate_FQuoted(self, e):
self.generate_simple_inline_tag(e, "FQuoted")
def generate_simple_inline_tag(self, e, tag: str):
self.write(self.stag(tag)+" ")
self.generate(e.content)
self.write(" "+self.etag(tag))
def generate_Math(self, e):
self.generate_raw_inline_tag(e, "Math")
def generate_Code(self, e):
self.generate_raw_inline_tag(e, "Code")
def generate_RawInline(self, e):
self.generate_raw_inline_tag(e, "RawInline")
def generate_raw_inline_tag(self, e, tag: str):
self.write(self.stag(tag)+" ")
self.write(e.text)
self.write(" "+self.etag(tag))
def generate_Block(self, e: Block):
{
BlockQuote: self.generate_BlockQuote,
BulletList: self.generate_BulletList,
Citation: self.generate_Citation,
CodeBlock: self.generate_CodeBlock,
Definition: self.generate_Definition,
DefinitionItem: self.generate_DefinitionItem,
DefinitionList: self.generate_DefinitionList,
Div: self.generate_Div,
Figure: self.generate_Figure,
Header: self.generate_Header,
HorizontalRule: self.generate_HorizontalRule,
LineBlock: self.generate_LineBlock,
MetaBlocks: self.generate_MetaBlocks,
MetaBool: self.generate_MetaBool,
MetaInlines: self.generate_MetaInlines,
MetaList: self.generate_MetaList,
MetaMap: self.generate_MetaMap,
MetaString: self.generate_MetaString,
Null: self.generate_Null,
OrderedList: self.generate_OrderedList,
Para: self.generate_Para,
Plain: self.generate_Plain,
RawBlock: self.generate_RawBlock,
Table: self.generate_Table,
TableBody: self.generate_TableBody,
TableFoot: self.generate_TableFoot,
TableHead: self.generate_TableHead,
Group: self.generate_Group
}[type(e)](e)
def generate_BlockQuote(self, e):
self.generate_simple_block_tag(e, "BlockQuote")
def generate_BulletList(self, e):
self.generate_simple_block_tag(e, "BulletList")
def generate_Citation(self, e):
self.generate_simple_block_tag(e, "Citation")
def generate_Definition(self, e):
self.generate_simple_block_tag(e, "Definition")
def generate_DefinitionItem(self, e):
self.generate_simple_block_tag(e, "DefinitionItem")
def generate_DefinitionList(self, e):
self.generate_simple_block_tag(e, "DefinitionList")
def generate_Div(self, e):
self.generate_simple_block_tag(e, "Div")
def generate_Figure(self, e):
self.generate_simple_block_tag(e, "Figure")
def generate_Header(self, e):
self.generate_simple_block_tag(e, "Header")
def generate_LineBlock(self, e):
self.generate_simple_block_tag(e, "LineBlock")
def generate_LineItem(self, e):
self.generate_simple_block_tag(e, "LineItem")
def generate_ListItem(self, e):
self.generate_simple_block_tag(e, "ListItem")
def generate_MetaBlocks(self, e):
self.generate_simple_block_tag(e, "MetaBlocks")
def generate_MetaBool(self, e):
self.generate_simple_block_tag(e, "MetaBool")
def generate_MetaInlines(self, e):
self.generate_simple_block_tag(e, "MetaInlines")
def generate_MetaList(self, e):
self.generate_simple_block_tag(e, "MetaList")
def generate_MetaMap(self, e):
self.generate_simple_block_tag(e, "MetaMap")
def generate_MetaString(self, e):
self.generate_simple_block_tag(e, "MetaString")
def generate_OrderedList(self, e):
self.generate_simple_block_tag(e, "OrderedList")
def generate_Para(self, e):
self.generate_simple_block_tag(e, "Para")
def generate_Plain(self, e):
self.generate_simple_block_tag(e, "Plain")
def generate_Caption(self, e):
self.generate_simple_block_tag(e, "Caption")
def generate_Table(self, e):
self.generate_simple_block_tag(e, "Table")
def generate_TableBody(self, e):
self.generate_simple_block_tag(e, "TableBody")
def generate_TableCell(self, e):
self.generate_simple_block_tag(e, "TableCell")
def generate_TableFoot(self, e):
self.generate_simple_block_tag(e, "TableFoot")
def generate_TableHead(self, e):
self.generate_simple_block_tag(e, "TableHead")
def generate_TableRow(self, e):
self.generate_simple_block_tag(e, "TableRow")
def generate_Doc(self, e):
self.generate_simple_block_tag(e, "Doc")
def generate_Group(self, e):
self.generate_simple_block_tag(e, "Group")
def generate_simple_block_tag(self, e, tag: str):
self.writeln(self.stag(tag))
self.iup()
self.generate(e.content)
self.ido()
self.writeln(self.etag(tag))
def generate_Null(self, e):
self.generate_empty_block_tag(e, "Null")
def generate_HorizontalRule(self, e):
self.generate_empty_block_tag(e, "HorizontalRule")
def generate_empty_block_tag(self, e, tag: str):
self.writeln(self.ntag(tag))
def generate_CodeBlock(self, e):
self.generate_raw_block_tag(e, "CodeBlock")
def generate_RawBlock(self, e):
self.generate_raw_block_tag(e, "RawBlock")
def generate_raw_block_tag(self, e, tag: str):
self.writeln(self.stag(tag)+"\n")
self.writeraw(e.text)
self.writeln(self.etag(tag))

2
src/formatitko/transform.py

@ -1,4 +1,4 @@
from panflute import Element, Div, Span, Quoted, Image, CodeBlock, Str, MetaInlines, MetaStr, MetaBool
from panflute import Element, Div, Span, Quoted, Image, CodeBlock, Str, MetaInlines, MetaString, MetaBool
import re
# Import local files

Loading…
Cancel
Save