Browse Source

Resolve #23.

pull/28/head
Jan Černohorský 11 months ago
parent
commit
7769b12cda
  1. 9
      src/formatitko/command.py
  2. 10
      src/formatitko/html_generator.py
  3. 12
      src/formatitko/images.py
  4. 4
      src/formatitko/katex.py
  5. 8
      src/formatitko/latex_generator.py
  6. 160
      src/formatitko/output_generator.py

9
src/formatitko/command.py

@ -1,5 +1,4 @@
from panflute import Div, Span, Para, Element
from typing import List
# Import local files
from .util import nullify, import_md
@ -11,7 +10,7 @@ class Command:
# This distinction is needed because while transforming the tree, inline
# elements cannot be replaced with block ones
class InlineCommand(Span, Command):
def replaceSelf(self, content: List[Element]) -> Span:
def replaceSelf(self, content: list[Element]) -> Span:
try:
return Span(*content)
except TypeError:
@ -22,7 +21,7 @@ class InlineCommand(Span, Command):
pass
class BlockCommand(Div, Command):
def replaceSelf(self, content: List[Element]) -> Div:
def replaceSelf(self, content: list[Element]) -> Div:
return Div(*content)
pass
@ -58,7 +57,7 @@ def handle_command_define(e: Element, c: Context):
#
# These two types, appending and printing, cannot be mixed.
def executeCommand(source, element: Element, ctx: Context) -> List[Element]:
def executeCommand(source, element: Element, ctx: Context) -> list[Element]:
mode = 'empty'
text = ""
content = []
@ -79,7 +78,7 @@ def executeCommand(source, element: Element, ctx: Context) -> List[Element]:
mode = 'elements'
content.append(e)
def appendChildren(l: List[Element]):
def appendChildren(l: list[Element]):
for e in l:
appendChild(e)

10
src/formatitko/html_generator.py

@ -2,7 +2,7 @@ from panflute import Cite, Emph, Image, LineBreak, Link, Math, Note, RawInline,
from panflute import BulletList, Citation, CodeBlock, Definition, DefinitionItem, DefinitionList, Header, HorizontalRule, LineBlock, LineItem, ListItem, Null, OrderedList, Para, Plain, RawBlock, TableBody, TableFoot, TableHead
from panflute import TableRow, TableCell, Caption, Doc
from panflute import ListContainer, Element
from typing import Union, Dict
from typing import Union
import os
import io
@ -40,16 +40,16 @@ class HTMLGenerator(OutputGenerator):
# text = text.replace(" ", " ") # Don't replace no-break spaces with HTML escapes, because we trust unicode?
return text
def start_tag(self, tag: str, attributes: Dict[str,str]={}) -> str:
def start_tag(self, tag: str, attributes: dict[str,str]={}) -> str:
words = [tag]
for key, value in attributes.items():
words.append(f"{key}=\"{self.escape_special_chars(value)}\"")
return "<" + " ".join(words) + ">"
def end_tag(self, tag: str, attributes: Dict[str,str]={}) -> str:
def end_tag(self, tag: str, attributes: dict[str,str]={}) -> str:
return "</" + tag + ">"
def single_tag(self, tag: str, attributes: Dict[str,str]={}) -> str:
def single_tag(self, tag: str, attributes: dict[str,str]={}) -> str:
return self.start_tag(tag, attributes)
def tagname(self, e) -> str:
@ -82,7 +82,7 @@ class HTMLGenerator(OutputGenerator):
except KeyError:
return type(e).__name__.lower()
def common_attributes(self, e) -> Dict[str,str]:
def common_attributes(self, e) -> dict[str,str]:
attributes = {}
if hasattr(e, "identifier") and e.identifier != "":
attributes["id"] = e.identifier

12
src/formatitko/images.py

@ -1,4 +1,4 @@
from typing import List, Union, Tuple
from typing import Union
import os
import shutil
import subprocess
@ -14,7 +14,7 @@ class ImageMagickError(Exception):
pass
class ImageProcessor:
def __init__(self, public_dir: str, web_path: str, cache_dir: str, *lookup_dirs: List[str]):
def __init__(self, public_dir: str, web_path: str, cache_dir: str, *lookup_dirs: list[str]):
self.public_dir = public_dir
self.cache_dir = cache_dir
self.lookup_dirs = lookup_dirs
@ -24,7 +24,7 @@ class ImageProcessor:
if not os.path.exists(self.cache_dir):
os.mkdir(self.cache_dir)
def process_image(self, input_filename: str, format: str, source_dir: str, width: int=None, height:int=None, quality: int=None, dpi: int=None, fit: bool=True, deps: List[str]=[]) -> str:
def process_image(self, input_filename: str, format: str, source_dir: str, width: int=None, height:int=None, quality: int=None, dpi: int=None, fit: bool=True, deps: list[str]=[]) -> str:
name = os.path.basename(input_filename)
base, ext = os.path.splitext(name)
ext = ext[1:]
@ -85,7 +85,7 @@ class ImageProcessor:
return target_name
def is_outdated(self, target: str, deps: List[str]):
def is_outdated(self, target: str, deps: list[str]):
target_timestamp = os.path.getmtime(target)
for dep in deps:
dep_timestamp = os.path.getmtime(dep)
@ -113,7 +113,7 @@ class ImageProcessor:
raise e
return target_name if relative else target_path
def get_image_size(self, input_filename: str, additional_dirs: List[str]=[]) -> Tuple[int, int]:
def get_image_size(self, input_filename: str, additional_dirs: list[str]=[]) -> tuple[int, int]:
full_path = self.find_image(input_filename, additional_dirs)
if full_path is None:
raise FileNotFoundError(f'Image {input_filename} not found.')
@ -121,7 +121,7 @@ class ImageProcessor:
return Image.open(full_path).size
def find_image(self, input_filename: str, additional_dirs: List[str]=[]) -> Union[str, None]:
def find_image(self, input_filename: str, additional_dirs: list[str]=[]) -> Union[str, None]:
for dir in [*self.lookup_dirs, *additional_dirs]:
if os.path.isfile(dir + "/" + input_filename):
return dir + "/" + input_filename

4
src/formatitko/katex.py

@ -3,8 +3,6 @@ import subprocess
import tempfile
import json
import os
from typing import Dict
class KatexError(Exception):
pass
@ -45,7 +43,7 @@ class KatexClient:
self._client.connect(self._socket_file)
def render(self, tex: str, options: Dict={}):
def render(self, tex: str, options: dict={}):
# Send formulas to translate
self._client.sendall((json.dumps({"formulas":[{"tex":tex}], "options":options})+"\n").encode("utf-8"))

8
src/formatitko/latex_generator.py

@ -2,7 +2,7 @@ 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, Dict
from typing import Union
from .whitespace import NBSP
from .transform import FQuoted
@ -34,13 +34,13 @@ class LaTeXGenerator(OutputGenerator):
text = text.replace(" ", "~") # We use unicode no-break spaces to force nbsp in output
return text
def start_tag(self, tag: str, attributes: Dict[str,str]={}) -> str:
def start_tag(self, tag: str, attributes: dict[str,str]={}) -> str:
return "\\" + tag + "{"
def end_tag(self, tag: str, attributes: Dict[str,str]={}) -> str:
def end_tag(self, tag: str, attributes: dict[str,str]={}) -> str:
return "}"
def single_tag(self, tag: str, attributes: Dict[str,str]={}) -> str:
def single_tag(self, tag: str, attributes: dict[str,str]={}) -> str:
return "\\" + tag + "{}"

160
src/formatitko/output_generator.py

@ -2,7 +2,7 @@ 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, Dict, List
from typing import Union
from .whitespace import NBSP
from .transform import FQuoted
@ -20,9 +20,74 @@ class OutputGenerator:
self.indent_str = indent_str
self.indent_level = initial_indent_level
self._at_start_of_line = True
def generate(self, e: Union[Element, ListContainer, List[Union[Element, ListContainer]]]):
if isinstance(e, List):
self.TYPE_DICT_MISC = {
TableRow: self.generate_TableRow,
TableCell: self.generate_TableCell,
Caption: self.generate_Caption,
Doc: self.generate_Doc,
LineItem: self.generate_LineItem,
ListItem: self.generate_ListItem
}
self.TYPE_DICT_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
}
self.TYPE_DICT_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
}
def generate(self, e: Union[Element, ListContainer, list[Union[Element, ListContainer]]]):
if isinstance(e, list):
for el in e:
self.generate(el)
elif isinstance(e, ListContainer):
@ -33,14 +98,7 @@ class OutputGenerator:
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)
self.TYPE_DICT_MISC[type(e)](e)
except KeyError:
raise UnknownElementError(type(e))
@ -80,22 +138,22 @@ class OutputGenerator:
self.output_file.write("\n")
self._at_start_of_line = True
def start_tag(self, tag: str, attributes: Dict[str,str]={}) -> str:
def start_tag(self, tag: str, attributes: dict[str,str]={}) -> str:
return tag
def end_tag(self, tag: str, attributes: Dict[str,str]={}) -> str:
def end_tag(self, tag: str, attributes: dict[str,str]={}) -> str:
return "/" + tag
def single_tag(self, tag: str, attributes: Dict[str,str]={}) -> str:
def single_tag(self, tag: str, attributes: dict[str,str]={}) -> str:
return "/" + tag + "/"
def tagname(self, e) -> str:
return type(e).__name__
def common_attributes(self, e: Element) -> Dict[str,str]:
def common_attributes(self, e: Element) -> dict[str,str]:
return {}
def generate_simple_tag(self, e: Union[Element, None]=None, tag: str="", attributes: Union[Dict[str,str],None]=None, content: Union[ListContainer, Element, List[Union[Element, ListContainer]], str, None]=None, inline: Union[bool, None]=None):
def generate_simple_tag(self, e: Union[Element, None]=None, tag: str="", attributes: Union[dict[str,str],None]=None, content: Union[ListContainer, Element, list[Union[Element, ListContainer]], str, None]=None, inline: Union[bool, None]=None):
if not tag and e:
tag = self.tagname(e)
if attributes is None and e:
@ -124,29 +182,29 @@ class OutputGenerator:
else:
self.generate_simple_block_tag(tag, content, attributes)
def generate_simple_inline_tag(self, tag: str, content: Union[ListContainer, Element, List[Union[Element, ListContainer]]], attributes: Dict[str,str]={}):
def generate_simple_inline_tag(self, tag: str, content: Union[ListContainer, Element, list[Union[Element, ListContainer]]], attributes: dict[str,str]={}):
self.write(self.start_tag(tag, attributes))
self.generate(content)
self.write(self.end_tag(tag))
def generate_simple_block_tag(self, tag: str, content: Union[ListContainer, Element, List[Union[Element, ListContainer]]], attributes: Dict[str,str]={}):
def generate_simple_block_tag(self, tag: str, content: Union[ListContainer, Element, list[Union[Element, ListContainer]]], attributes: dict[str,str]={}):
self.writeln(self.start_tag(tag, attributes))
self.indent_more()
self.generate(content)
self.indent_less()
self.writeln(self.end_tag(tag))
def generate_raw_inline_tag(self, tag: str, text: str, attributes: Dict[str,str]={}):
def generate_raw_inline_tag(self, tag: str, text: str, attributes: dict[str,str]={}):
self.write(self.start_tag(tag, attributes))
self.write(text)
self.write(self.end_tag(tag))
def generate_raw_block_tag(self, tag: str, text: str, attributes: Dict[str,str]={}):
def generate_raw_block_tag(self, tag: str, text: str, attributes: dict[str,str]={}):
self.writeln(self.start_tag(tag, attributes))
self.writeraw(text)
self.writeln(self.end_tag(tag))
def generate_empty_block_tag(self, tag: str, attributes: Dict[str,str]={}):
def generate_empty_block_tag(self, tag: str, attributes: dict[str,str]={}):
self.writeln(self.single_tag(tag, attributes))
def generate_ListContainer(self, e: ListContainer):
@ -154,30 +212,7 @@ class OutputGenerator:
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)
self.TYPE_DICT_INLINE[type(e)](e)
def generate_Str(self, e: Str):
self.write(self.escape_special_chars(e.text))
@ -278,36 +313,7 @@ class OutputGenerator:
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)
self.TYPE_DICT_BLOCK[type(e)](e)
# Block elements
@ -420,7 +426,7 @@ class OutputGenerator:
self.generate_simple_tag(e)
# Maybe move this to ImageProcessor?
def get_image_processor_args(self, attributes:Dict[str,str]) -> Dict:
def get_image_processor_args(self, attributes:dict[str,str]) -> dict:
# Attributes → image processor args
additional_args = {}
if "file-width" in attributes:

Loading…
Cancel
Save