Browse Source

Přidány InlineGroups, metadatum `language` přejmenováno na `lang`, unifikován handling jazyka. #21

citace
Jan Černohorský 1 year ago
parent
commit
0c2ce7d56c
  1. 13
      src/formatitko/context.py
  2. 2
      src/formatitko/elements.py
  3. 6
      src/formatitko/formatitko.py
  4. 12
      src/formatitko/html_generator.py
  5. 12
      src/formatitko/output_generator.py
  6. 4
      src/formatitko/tex.py
  7. 8
      src/formatitko/transform.py
  8. 43
      src/formatitko/transform_processor.py
  9. 4
      test/test-files/test-partial.md
  10. 7
      test/test.md

13
src/formatitko/context.py

@ -1,4 +1,4 @@
from panflute import Doc, Element, Div from panflute import Doc, Element, Div, Span
from typing import Union, Callable from typing import Union, Callable
from types import ModuleType from types import ModuleType
@ -79,8 +79,6 @@ class Context:
return None return None
def set_metadata(self, key: str, value): def set_metadata(self, key: str, value):
if key == "language":
warnings.warn("Setting language this way doesn't propagate to TeX. Either use the Front Matter or specify it additionally using the \\languagexx macro.", UserWarning)
meta = self.doc.metadata meta = self.doc.metadata
keys = key.split(".") keys = key.split(".")
for k in keys[:-1]: for k in keys[:-1]:
@ -99,9 +97,14 @@ class Context:
# and also causes KaTeX math blocks to be isolated in a similar way. # and also causes KaTeX math blocks to be isolated in a similar way.
# #
# Whenever a new context is created, its content should be eclosed in a group and vice-versa. # Whenever a new context is created, its content should be eclosed in a group and vice-versa.
class Group(Div): class Group(Element):
def __init__(self, *args, context:Context, metadata={}, **kwargs): def __init__(self, *args, context:Context, metadata={}, **kwargs):
self.metadata = metadata self.metadata = metadata # This is only here for backwards compatibility with old html.py, tex.py and transform.py. FIXME: Remove this when the time comes.
self.context = context self.context = context
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
class BlockGroup(Group, Div):
pass
class InlineGroup(Group, Span):
pass

2
src/formatitko/elements.py

@ -2,7 +2,7 @@ from panflute import Quoted
from .command import Command, InlineCommand, BlockCommand from .command import Command, InlineCommand, BlockCommand
from .context import Group from .context import Group, BlockGroup, InlineGroup
from .whitespace import Whitespace, NBSP from .whitespace import Whitespace, NBSP
# This is a small extension to the Quoted panflute elements which allows to # This is a small extension to the Quoted panflute elements which allows to

6
src/formatitko/formatitko.py

@ -6,7 +6,7 @@ import sys
# Import local files # Import local files
from .transform import transform from .transform import transform
from .util import import_md from .util import import_md
from .context import Context, Group from .context import Context, BlockGroup
from .katex import KatexClient from .katex import KatexClient
from .html import html from .html import html
from .tex import tex from .tex import tex
@ -41,7 +41,7 @@ def main():
# The language metadatum is important, so it's read before transformation and # The language metadatum is important, so it's read before transformation and
# then attached to a group inside the Doc # then attached to a group inside the Doc
language = doc1.get_metadata("language", None, True) language = doc1.get_metadata("lang", None, True)
context = Context(doc1, args.input_filename) context = Context(doc1, args.input_filename)
# Transform the document. This includes all the fancy formatting this software does. # Transform the document. This includes all the fancy formatting this software does.
@ -49,7 +49,7 @@ def main():
# Now wrap the document contents in a group, which is able to pop its language # Now wrap the document contents in a group, which is able to pop its language
# setting out to TeX # setting out to TeX
doc1.content = [Group(*doc1.content, context=context, metadata={"language":language})] doc1.content = [BlockGroup(*doc1.content, context=context, metadata={"lang":language})]
doc2 = TransformProcessor(args.input_filename).transform(doc2) doc2 = TransformProcessor(args.input_filename).transform(doc2)

12
src/formatitko/html_generator.py

@ -14,7 +14,7 @@ from pygments.formatters import HtmlFormatter
from pygments.util import ClassNotFound from pygments.util import ClassNotFound
from .whitespace import NBSP from .whitespace import NBSP
from .context import Group from .context import Group, BlockGroup, InlineGroup
from .output_generator import OutputGenerator from .output_generator import OutputGenerator
from .katex import KatexClient from .katex import KatexClient
from .images import ImageProcessor from .images import ImageProcessor
@ -78,6 +78,8 @@ class HTMLGenerator(OutputGenerator):
TableFoot: "tfoot", TableFoot: "tfoot",
TableRow: "tr", TableRow: "tr",
TableCell: "td", TableCell: "td",
InlineGroup: "span",
BlockGroup: "div"
}[type(e)] }[type(e)]
except KeyError: except KeyError:
return type(e).__name__.lower() return type(e).__name__.lower()
@ -193,9 +195,15 @@ class HTMLGenerator(OutputGenerator):
self.generate(link) self.generate(link)
def generate_InlineGroup(self, e: InlineGroup):
self.generate_Group(e)
def generate_BlockGroup(self, e: BlockGroup):
self.generate_Group(e)
def generate_Group(self, e: Group): def generate_Group(self, e: Group):
self.katexClient.begingroup() self.katexClient.begingroup()
self.generate(e.content) self.generate_simple_tag(e, attributes=self.common_attributes(e) | {"lang":self.context.get_metadata("lang")})
self.katexClient.endgroup() self.katexClient.endgroup()
def generate_Plain(self, e: Plain): def generate_Plain(self, e: Plain):

12
src/formatitko/output_generator.py

@ -6,7 +6,7 @@ from typing import Union
from .whitespace import NBSP from .whitespace import NBSP
from .elements import FQuoted from .elements import FQuoted
from .context import Group from .context import Group, InlineGroup, BlockGroup
import re import re
@ -59,7 +59,7 @@ class OutputGenerator:
TableBody: self.generate_TableBody, TableBody: self.generate_TableBody,
TableFoot: self.generate_TableFoot, TableFoot: self.generate_TableFoot,
TableHead: self.generate_TableHead, TableHead: self.generate_TableHead,
Group: self.generate_Group BlockGroup: self.generate_BlockGroup
} }
self.TYPE_DICT_INLINE = { self.TYPE_DICT_INLINE = {
@ -84,7 +84,8 @@ class OutputGenerator:
Superscript: self.generate_Superscript, Superscript: self.generate_Superscript,
Underline: self.generate_Underline, Underline: self.generate_Underline,
NBSP: self.generate_NBSP, NBSP: self.generate_NBSP,
FQuoted: self.generate_FQuoted FQuoted: self.generate_FQuoted,
InlineGroup: self.generate_InlineGroup
} }
def generate(self, e: Union[Element, ListContainer, list[Union[Element, ListContainer]]]): def generate(self, e: Union[Element, ListContainer, list[Union[Element, ListContainer]]]):
@ -408,7 +409,10 @@ class OutputGenerator:
def generate_Doc(self, e: Doc): def generate_Doc(self, e: Doc):
self.generate_simple_tag(e) self.generate_simple_tag(e)
def generate_Group(self, e: Group): def generate_BlockGroup(self, e: BlockGroup):
self.generate_simple_tag(e)
def generate_InlineGroup(self, e: InlineGroup):
self.generate_simple_tag(e) self.generate_simple_tag(e)
# Special elements with more contents # Special elements with more contents

4
src/formatitko/tex.py

@ -247,8 +247,8 @@ def tex(e: Union[Element, ListContainer], i: ImageProcessor, indent_level: int=0
elif isinstance(e, Group): elif isinstance(e, Group):
tag = "begingroup" tag = "begingroup"
open = "" open = ""
if "language" in e.metadata and e.metadata["language"] is not None: if "lang" in e.metadata and e.metadata["lang"] is not None:
open = "\\language"+e.metadata["language"] open = "\\language"+e.metadata["lang"]
close = "\\endgroup" close = "\\endgroup"
# The default which all non-overriding elements get generated by. This # The default which all non-overriding elements get generated by. This

8
src/formatitko/transform.py

@ -5,7 +5,7 @@ import os
# Import local files # Import local files
from .whitespace import Whitespace, NBSP, bavlna from .whitespace import Whitespace, NBSP, bavlna
from .util import nullify, import_md from .util import nullify, import_md
from .context import Context, Group from .context import Context, BlockGroup
from .command import Command, BlockCommand, InlineCommand from .command import Command, BlockCommand, InlineCommand
from .command_util import handle_command_define, parse_command from .command_util import handle_command_define, parse_command
from .elements import FQuoted from .elements import FQuoted
@ -70,9 +70,9 @@ def transform(e: Element, c: Context) -> Element:
if not c.trusted: if not c.trusted:
trusted = False trusted = False
nContext = Context(includedDoc, path, c, trusted=trusted) nContext = Context(includedDoc, path, c, trusted=trusted)
language = includedDoc.get_metadata("language") language = includedDoc.get_metadata("lang")
includedDoc = includedDoc.walk(transform, nContext) includedDoc = includedDoc.walk(transform, nContext)
e = Group(*includedDoc.content, context=nContext, metadata={"language": language}) e = BlockGroup(*includedDoc.content, context=nContext, metadata={"lang": language})
# Transform panflute's Quoted to custom FQuoted, see above. # Transform panflute's Quoted to custom FQuoted, see above.
if isinstance(e, Quoted): if isinstance(e, Quoted):
@ -82,7 +82,7 @@ def transform(e: Element, c: Context) -> Element:
"sk": "cs", "sk": "cs",
None: None None: None
} }
e = FQuoted(*e.content, quote_type=e.quote_type, style=quote_styles[c.get_metadata("language")]) e = FQuoted(*e.content, quote_type=e.quote_type, style=quote_styles[c.get_metadata("lang")])
if isinstance(e, Image): if isinstance(e, Image):
# Pass down the directory of the current source file for finding image # Pass down the directory of the current source file for finding image

43
src/formatitko/transform_processor.py

@ -6,10 +6,11 @@ from typing import Union, Callable
import os import os
import re import re
import warnings
from .whitespace import NBSP from .whitespace import NBSP
from .elements import FQuoted from .elements import FQuoted
from .context import Group from .context import Group, InlineGroup, BlockGroup
from .util import nullify, import_md from .util import nullify, import_md
from .context import Context from .context import Context
from .whitespace import Whitespace, bavlna from .whitespace import Whitespace, bavlna
@ -69,6 +70,8 @@ class TransformProcessor:
TableFoot: self.transform_TableFoot, TableFoot: self.transform_TableFoot,
TableHead: self.transform_TableHead, TableHead: self.transform_TableHead,
Group: self.transform_Group, Group: self.transform_Group,
InlineGroup: self.transform_InlineGroup,
BlockGroup: self.transform_BlockGroup,
Cite: self.transform_Cite, Cite: self.transform_Cite,
Code: self.transform_Code, Code: self.transform_Code,
@ -253,6 +256,14 @@ class TransformProcessor:
e.content = self.transform(e.content) e.content = self.transform(e.content)
return e return e
def transform_InlineGroup(self, e: InlineGroup) -> InlineGroup:
e.content = self.transform(e.content)
return e
def transform_BlockGroup(self, e: BlockGroup) -> BlockGroup:
e.content = self.transform(e.content)
return e
def transform_Cite(self, e: Cite) -> Cite: def transform_Cite(self, e: Cite) -> Cite:
e.content = self.transform(e.content) e.content = self.transform(e.content)
return e return e
@ -314,7 +325,7 @@ class TransformProcessor:
raise DoubleDocError() raise DoubleDocError()
self.context = Context(e, self.root_file_path) self.context = Context(e, self.root_file_path)
e.content = self.transform(e.content) e.content = self.transform(e.content)
e.content = [Group(*e.content, context=self.context)] e.content = [BlockGroup(*e.content, context=self.context)]
return e return e
@ -326,7 +337,7 @@ class TransformProcessor:
"sk": "cs", "sk": "cs",
None: None None: None
} }
return FQuoted(*e.content, quote_type=e.quote_type, style=quote_styles[self.context.get_metadata("language")]) return FQuoted(*e.content, quote_type=e.quote_type, style=quote_styles[self.context.get_metadata("lang")])
def transform_Image(self, e: Image) -> Image: def transform_Image(self, e: Image) -> Image:
e.content = self.transform(e.content) e.content = self.transform(e.content)
@ -340,12 +351,15 @@ class TransformProcessor:
e.attributes["no-srcset"] = self.context.get_metadata("no-srcset") if self.context.get_metadata("no-srcset") is not None else False e.attributes["no-srcset"] = self.context.get_metadata("no-srcset") if self.context.get_metadata("no-srcset") is not None else False
return e return e
def create_Group(self, *content, new_context: Context) -> Group: def create_Group(self, *content, new_context: Context, inline: bool=False) -> Group:
old_context = self.context old_context = self.context
self.context = new_context self.context = new_context
content = self.transform([*content]) content = self.transform([*content])
self.context = old_context self.context = old_context
return Group(*content, context=new_context) if inline:
return InlineGroup(*content, context=new_context)
else:
return BlockGroup(*content, context=new_context)
def transform_Div(self, e: Div) -> Union[Div, Group, Null]: def transform_Div(self, e: Div) -> Union[Div, Group, Null]:
e.content = self.transform(e.content) e.content = self.transform(e.content)
@ -355,7 +369,7 @@ class TransformProcessor:
# Content of Div is enclosed in a separate context, all attributes are passed as metadata # Content of Div is enclosed in a separate context, all attributes are passed as metadata
new_context = Context(Doc(), self.context.path, self.context, trusted=self.context.trusted) new_context = Context(Doc(), self.context.path, self.context, trusted=self.context.trusted)
for attribute, value in e.attributes.items(): for attribute, value in e.attributes.items():
new_context.set_metadata(attribute, value) # FIXME: This raises a warning when done with `language`. Since context is available to OG, we should trash the warning and rework the OG to use the Context. new_context.set_metadata(attribute, value)
return self.create_Group(*e.content, new_context=new_context) return self.create_Group(*e.content, new_context=new_context)
if "c" in e.attributes: if "c" in e.attributes:
@ -383,19 +397,22 @@ class TransformProcessor:
trusted = False trusted = False
return self.create_Group(*includedDoc.content, new_context=Context(includedDoc, path, self.context, trusted=trusted)) return self.create_Group(*includedDoc.content, new_context=Context(includedDoc, path, self.context, trusted=trusted))
if "lang" in e.attributes:
warnings.warn("To set language in a way formátítko will understand, this Div has to have the `.group` class and be a Group.", UserWarning)
return e return e
def transform_Span(self, e: Span) -> Span: def transform_Span(self, e: Span) -> Span:
e.content = self.transform(e.content) e.content = self.transform(e.content)
# TODO: This sadly doesn't work. We would need to create a separate class InlineGroup, that would be Inline. # TODO: This sadly doesn't work. We would need to create a separate class InlineGroup, that would be Inline.
#if "group" in e.classes: if "group" in e.classes:
# # `.group` class for Spans # `.group` class for Spans
# # Content of Span is enclosed in a separate context, all attributes are passed as metadata # Content of Span is enclosed in a separate context, all attributes are passed as metadata
# new_context = Context(Doc(), self.context.path, self.context, trusted=self.context.trusted) new_context = Context(Doc(), self.context.path, self.context, trusted=self.context.trusted)
# for attribute, value in e.attributes.items(): for attribute, value in e.attributes.items():
# new_context.set_metadata(attribute, value) new_context.set_metadata(attribute, value)
# return self.create_Group(*e.content, new_context=new_context) return self.create_Group(*e.content, new_context=new_context, inline=True)
if "c" in e.attributes: if "c" in e.attributes:
# Commands can be called multiple ways, this handles the following syntax: # Commands can be called multiple ways, this handles the following syntax:

4
test/test-files/test-partial.md

@ -30,14 +30,14 @@ return [
```markdown {.group} ```markdown {.group}
--- ---
language: "cs" lang: "cs"
--- ---
Tak toto je "v prádelně" pánové! Tak toto je "v prádelně" pánové!
``` ```
```markdown {.group} ```markdown {.group}
--- ---
language: "en" lang: "en"
--- ---
This is "in a laundry room" gentlemen! This is "in a laundry room" gentlemen!
``` ```

7
test/test.md

@ -2,7 +2,6 @@
title: 'Wooooo a title' title: 'Wooooo a title'
subtitle: 'A subtitle' subtitle: 'A subtitle'
are_we_there_yet: False are_we_there_yet: False
language: "en"
lang: "en" lang: "en"
--- ---
[#test-files/test-import.md]{} [#test-files/test-import.md]{}
@ -56,7 +55,7 @@ This should only be shown to cats the second time
```markdown {.group} ```markdown {.group}
--- ---
language: cs lang: cs
--- ---
V​ pravém jízdním bruhu. V​ pravém jízdním bruhu.
V pravém jízdním bruhu. V pravém jízdním bruhu.
@ -115,10 +114,10 @@ $$
--- ---
In this text, there might be some phrases [v češtině]{.group language=cs} and <!-- Tohle nefunguje :( --> In this text, there might be some phrases [v češtině]{.group lang=cs} and
maybe even maybe even
:::{.group language=cs} :::{.group lang=cs}
celé pasáže textu v češtině. celé pasáže textu v češtině.
Růžový bagr bez zeleného bagru se žlutým bagrem. Růžový bagr bez zeleného bagru se žlutým bagrem.

Loading…
Cancel
Save