diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..2dc868f --- /dev/null +++ b/.drone.yml @@ -0,0 +1,11 @@ +kind: pipeline +type: docker +name: default + +steps: +- name: 50ohm.de + image: ghcr.io/astral-sh/uv:python3.12-bookworm + environment: + commands: + - uv pip install --system --break-system-packages --requirements requirements.txt + - cd test && pytest --junitxml=./test-reports/junit.xml diff --git a/renderer/comment.py b/renderer/comment.py index cd4ff6f..52fff45 100644 --- a/renderer/comment.py +++ b/renderer/comment.py @@ -1,7 +1,17 @@ +import re + from mistletoe.block_token import BlockToken +from mistletoe.span_token import SpanToken -class Comment(BlockToken): +class SpanComment(SpanToken): + """ + Coment span token (% Eiersalat). + Identifies a comment in text. + """ + pattern = re.compile(r'(%.*\n?)') + +class BlockComment(BlockToken): @staticmethod def start(line): return line.startswith("%") diff --git a/renderer/dash.py b/renderer/dash.py new file mode 100644 index 0000000..10f80a2 --- /dev/null +++ b/renderer/dash.py @@ -0,0 +1,11 @@ +import re + +from mistletoe.span_token import SpanToken + + +class Dash(SpanToken): + """ + Dash span token ( - ). + Identifies a dash in a text. + """ + pattern = re.compile(r'(\s-\s)') diff --git a/renderer/fifty_ohm_html_renderer.py b/renderer/fifty_ohm_html_renderer.py index 24fd496..bec6559 100644 --- a/renderer/fifty_ohm_html_renderer.py +++ b/renderer/fifty_ohm_html_renderer.py @@ -2,11 +2,15 @@ import textwrap from mistletoe import HtmlRenderer -from .comment import Comment -from .quote import Quote -from .tag import Tag -from .underline import Underline -from .unit import Unit +from renderer.comment import BlockComment, SpanComment +from renderer.dash import Dash +from renderer.halfwidth_spaces import HalfwidthSpaces +from renderer.nonbreaking_spaces import NonbreakingSpaces, NonbreakingSpacesDots +from renderer.quote import Quote +from renderer.references import References +from renderer.tag import Tag +from renderer.underline import Underline +from renderer.unit import Unit units = { "A": "A", @@ -26,7 +30,6 @@ units = { "cm": "cm", "m": "m", "m²": "m²", - "Ohm": "Ω", "ppm": "ppm", "pps": "pps", "s": "s", @@ -43,12 +46,35 @@ no_space_units = ["°", "%"] class FiftyOhmHtmlRenderer(HtmlRenderer): margin_anchor_id = 0 margin_id = 0 + section_url = "section.html" + ref_id = 0 def __init__(self): - super().__init__(Comment, Unit, Quote, Underline, Tag) + super().__init__( + Dash, + BlockComment, + SpanComment, + Quote, + Unit, + Underline, + Tag, + HalfwidthSpaces, + NonbreakingSpaces, + NonbreakingSpacesDots, + HalfwidthSpaces, + NonbreakingSpaces, + NonbreakingSpacesDots, + References, + ) - def render_comment(): - return None + def render_dash(self, token): + return " – " + + def render_block_comment(self, token): + return "" + + def render_span_comment(self, token): + return "" def render_quote(self, token): return f"„{self.render_inner(token)}“" @@ -104,7 +130,7 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): if token.tagtype == "webmargin": type = "margin" - elif token.tagtype == "webtip": + elif token.tagtype == "webtipp": type = "tipp" elif token.tagtype == "webindepth": type = "indepth" @@ -114,3 +140,16 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): return self.render_tag_helper( type, self.render_inner(token), self.margin_id, self.margin_anchor_id ) + + def render_halfwidth_spaces(self, token): + return f"{token.first}. {token.second}." + + def render_nonbreaking_spaces(self, token): + return f"{token.first} {token.second}" + + def render_nonbreaking_spaces_dots(self, token): + lookup = {"": "", " ": " "} + return f"{lookup[token.first]}{token.second}{lookup[token.third]}" + + def render_references(self, token): + return f'{self.ref_id}' diff --git a/renderer/halfwidth_spaces.py b/renderer/halfwidth_spaces.py new file mode 100644 index 0000000..f9daf9b --- /dev/null +++ b/renderer/halfwidth_spaces.py @@ -0,0 +1,18 @@ +import re + +from mistletoe.span_token import SpanToken + + +class HalfwidthSpaces(SpanToken): + """ + Insert halfwidth space into span token (Z. B.) + Identifies "z.B.", "d.h." and "D.h." with and without space in between. + """ + pattern = re.compile(r"\b(z|d|D)\.(B|h)\.") + + def __init__(self, match_object): + self.first = match_object.group(1) + self.second = match_object.group(2) + + + diff --git a/renderer/nonbreaking_spaces.py b/renderer/nonbreaking_spaces.py new file mode 100644 index 0000000..932653f --- /dev/null +++ b/renderer/nonbreaking_spaces.py @@ -0,0 +1,30 @@ +import re + +from mistletoe.span_token import SpanToken + + +class NonbreakingSpaces(SpanToken): + """ + Insert unbreakable space into span token (§ 3) + Identifies "§$number", "Abs.$number", "Klasse [A,E,N]" w/ and w\ space between. + """ + pattern = re.compile(r"(§|Abs\.|Klasse)\s?(\d|[NEA])") + + def __init__(self, match_object): + self.first = match_object.group(1) + self.second = match_object.group(2) + +class NonbreakingSpacesDots(SpanToken): + """ + Insert unbreakable space before and after "..." if there is a space + Identifies "..." with leading and/or trailing space + """ + pattern = re.compile(r"(\s?)(\.\.\.)(\s?)") + + def __init__(self, match_object): + self.first = match_object.group(1) + self.second = match_object.group(2) + self.third = match_object.group(3) + + + diff --git a/renderer/references.py b/renderer/references.py new file mode 100644 index 0000000..e8b5f18 --- /dev/null +++ b/renderer/references.py @@ -0,0 +1,15 @@ +import re + +from mistletoe.span_token import SpanToken + + +class References(SpanToken): + """ + Resolve references for html + Identifies "[ref:$]" + """ + pattern = re.compile(r"\[ref\:(\S+)\]") + + def __init__(self, match_object): + self.first = match_object.group(1) + diff --git a/renderer/tag.py b/renderer/tag.py index 05d089b..6bdc187 100644 --- a/renderer/tag.py +++ b/renderer/tag.py @@ -2,12 +2,24 @@ import re from mistletoe.block_token import BlockToken, tokenize +captures = [ + "margin", + "indepth", + "webmargin", + "tipp", + "webtipp", + "webindepth", + "unit", + "danger", + "webonly", + "latexonly", +] class Tag(BlockToken): @staticmethod def start(line): - return re.match(r"^\s*<[^>]+>", line) + return re.match(r"^\s*<("+"|".join(captures)+r")+>", line) @classmethod def read(cls, lines): diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..fa39cef --- /dev/null +++ b/requirements.txt @@ -0,0 +1,7 @@ +coverage==7.6.9 +iniconfig==2.0.0 +mistletoe==1.4.0 +packaging==24.2 +pluggy==1.5.0 +pytest==8.3.4 +pytest-cov==6.0.0 diff --git a/test/test_comment.py b/test/test_comment.py new file mode 100644 index 0000000..9abf3ce --- /dev/null +++ b/test/test_comment.py @@ -0,0 +1,20 @@ +import mistletoe +import pytest +from mistletoe.ast_renderer import AstRenderer + +from renderer.comment import BlockComment, SpanComment +from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer +from test.util import paragraph + + +def test_comment_html(capsys) : + + assertions = { + "%Comment\nBar" : "
Bar
\n", + # TODO: This test is not working as expected. The comment should be removed + #"%Comment\n" : "a", + "Foo\n%Comment\nBar" : "Foo\nBar
\n", + } + + for assertion in assertions: + assert mistletoe.markdown(assertion, FiftyOhmHtmlRenderer) == assertions[assertion] diff --git a/test/test_dash.py b/test/test_dash.py new file mode 100644 index 0000000..2289b0c --- /dev/null +++ b/test/test_dash.py @@ -0,0 +1,14 @@ +import mistletoe + +from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer +from test.util import paragraph + + +def test_dash_html() : + + assertions = { + "Foo - Bar" : "Foo – Bar", + } + + for assertion in assertions: + assert mistletoe.markdown(assertion, FiftyOhmHtmlRenderer) == paragraph(assertions[assertion]) diff --git a/test/test_halfwidth_spaces.py b/test/test_halfwidth_spaces.py new file mode 100644 index 0000000..0438674 --- /dev/null +++ b/test/test_halfwidth_spaces.py @@ -0,0 +1,10 @@ +import mistletoe + +from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer +from test.util import paragraph + +def test_halfwidth_space_html(): + input = "Dies ist z.B. ein Test. D.h. hier sollten d.h. Spaces ersetzt worden sein." + target = "Dies ist z. B. ein Test. D. h. hier sollten d. h. Spaces ersetzt worden sein." + + assert mistletoe.markdown(input, FiftyOhmHtmlRenderer) == paragraph(target) diff --git a/test/test_nonbreaking_spaces.py b/test/test_nonbreaking_spaces.py new file mode 100644 index 0000000..88fb8cb --- /dev/null +++ b/test/test_nonbreaking_spaces.py @@ -0,0 +1,36 @@ +import mistletoe + +from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer +from test.util import paragraph + +def test_paragraph_html(): + input = "Der Test befindet sich unter §2 vielleicht aber auch § 3." + target = "Der Test befindet sich unter § 2 vielleicht aber auch § 3." + + assert mistletoe.markdown(input, FiftyOhmHtmlRenderer) == paragraph(target) + +def test_three_points_html(): + assertions = { + "Heute hatte ich ... zum Mittagessen." : "Heute hatte ich ... zum Mittagessen.", + "Niemals hätte ich gedacht, dass...ich ...nicht kann." : "Niemals hätte ich gedacht, dass...ich ...nicht kann.", + "Oh nein ...ein Pinguin." : "Oh nein ...ein Pinguin.", + "Haha .. . Hahaha" : "Haha .. . Hahaha" + } + + for key, value in assertions.items(): + assert mistletoe.markdown(key, FiftyOhmHtmlRenderer) == paragraph(value) + + +def test_absatz_html(): + input = "Der Test befindet sich unter Abs.2 vielleicht aber auch Abs. 3." + target = "Der Test befindet sich unter Abs. 2 vielleicht aber auch Abs. 3." + + assert mistletoe.markdown(input, FiftyOhmHtmlRenderer) == paragraph(target) + +def test_class_html(): + input = "Ich lerne für Klasse A, Klasse E und Klasse N." + target = "Ich lerne für Klasse A, Klasse E und Klasse N." + + assert mistletoe.markdown(input, FiftyOhmHtmlRenderer) == paragraph(target) + + diff --git a/test/test_references.py b/test/test_references.py new file mode 100644 index 0000000..80dff9d --- /dev/null +++ b/test/test_references.py @@ -0,0 +1,17 @@ +import mistletoe + +from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer +from test.util import paragraph + + +def test_references_html(): + # Right now this tests only the default values. + # The correct behavior can be tested when the information is added to the renderer class + assertions = { + "[ref:e_oszilloskop_bildschirmfoto_sinus]": '0', + "[ref:n_rst_r]": '0', + "[ref:Uuuuuh]": '0', # Test the default parameters + } + + for key, value in assertions.items(): + assert mistletoe.markdown(key, FiftyOhmHtmlRenderer) == paragraph(value) diff --git a/test/test_tag.py b/test/test_tag.py index ba6ab95..967e8f3 100644 --- a/test/test_tag.py +++ b/test/test_tag.py @@ -18,7 +18,7 @@ def test_tag_html() : "Foo
",1,0)+'\n', "Foo
",1,0)+'\n', "Foo
",1,0)+'\n', - "Foo
",1,0)+'\n', + "Foo
",1,0)+'\n', "Foo
",1,0)+'\n', "Foo
",1,0)+'\n', "Foo
",1,0)+'\n',