diff --git a/.gitignore b/.gitignore
index 82f9275..134cd7a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -160,3 +160,7 @@ cython_debug/
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
+
+test/acceptanceTest.html
+.DS_Store
+.envrc
diff --git a/renderer/__init__.py b/renderer/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/renderer/__main__.py b/renderer/__main__.py
deleted file mode 100644
index b8a5ddf..0000000
--- a/renderer/__main__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-import sys
-
-import mistletoe
-from fifty_ohm_html_renderer import FiftyOhmHtmlRenderer
-
-if __name__ == "__main__":
- with open(sys.argv[1]) as fin, open(sys.argv[2], "w") as fout:
- fout.write(mistletoe.markdown(fin, FiftyOhmHtmlRenderer))
diff --git a/renderer/fifty_ohm_html_renderer.py b/renderer/fifty_ohm_html_renderer.py
index de7bbe2..5af5929 100644
--- a/renderer/fifty_ohm_html_renderer.py
+++ b/renderer/fifty_ohm_html_renderer.py
@@ -5,19 +5,36 @@ from mistletoe import HtmlRenderer
from renderer.comment import BlockComment, SpanComment
from renderer.dash import Dash
from renderer.halfwidth_spaces import HalfwidthSpaces
+from renderer.morse import Morse
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
class FiftyOhmHtmlRenderer(HtmlRenderer):
-
margin_anchor_id = 0
margin_id = 0
+ section_url = "section.html"
+ ref_id = 0
def __init__(self):
- super().__init__(Dash, BlockComment, SpanComment, Quote, Underline, Tag, HalfwidthSpaces, NonbreakingSpaces, NonbreakingSpacesDots)
+ super().__init__(
+ Dash,
+ BlockComment,
+ SpanComment,
+ Quote,
+ Unit,
+ Underline,
+ Morse,
+ Tag,
+ HalfwidthSpaces,
+ NonbreakingSpaces,
+ NonbreakingSpacesDots,
+ References,
+ )
def render_dash(self, token):
return " – "
@@ -34,15 +51,63 @@ class FiftyOhmHtmlRenderer(HtmlRenderer):
def render_underline(self, token):
return f"{self.render_inner(token)}"
+ @classmethod
+ def render_unit(cls, token: Unit):
+ unit = token.prefix + cls.convert_unit_helper(token.unit)
+ if token.unit in ["°", "%"]:
+ # Special cases with no space between value and unit.
+ return f"{token.value}{unit}"
+ else:
+ # Default case is rendered with a narrow no-break space.
+ return f"{token.value} {unit}"
+
+ units = {
+ "Ohm": "Ω",
+ }
+
+ @classmethod
+ def convert_unit_helper(cls, unit: str) -> str:
+ """Converts human-typable units to their preferred representation.
+
+ :param str unit: The unit to convert
+ """
+ if unit in cls.units.keys():
+ return cls.units[unit]
+ else:
+ return unit
+
def render_thematic_break(self, token):
self.margin_anchor_id += 1
return f''
+ @staticmethod
+ def render_morse_helper(morse_code):
+ result = ''
+ for char in morse_code:
+ result += '\n'
+ for symbol in char:
+ result += '\n'
+ if symbol == 1:
+ result += "▄"
+ elif symbol == 2:
+ result += "▄▄▄"
+ elif symbol == 3:
+ result += " "
+ result += "\n"
+ result += "\n"
+ result += ""
+
+ return result
+
+ def render_morse(self, token):
+ morse_code = Morse.convert_to_morse_code(token.content)
+ return self.render_morse_helper(morse_code)
+
@staticmethod
def render_tag_helper(type, content, margin_id, margin_anchor_id):
- """ This function is used to render the different types of tags. It is
- used in the HtmlRenderer class and also in the test class """
- return textwrap.dedent(f'''\
+ """This function is used to render the different types of tags. It is
+ used in the HtmlRenderer class and also in the test class"""
+ return textwrap.dedent(f"""\
{content}
@@ -62,33 +127,29 @@ class FiftyOhmHtmlRenderer(HtmlRenderer):
moveFunc();
}})();
- ''')
+ """)
def render_tag(self, token):
- if(token.tagtype == "latexonly"):
+ if token.tagtype == "latexonly":
return ""
- elif(token.tagtype == "webonly"):
+ elif token.tagtype == "webonly":
return self.render_inner(token)
self.margin_id += 1
- if(token.tagtype == "webmargin"):
+ if token.tagtype == "webmargin":
type = "margin"
- elif(token.tagtype == "webtip"):
+ elif token.tagtype == "webtip":
type = "tip"
- elif(token.tagtype == "webindepth"):
+ elif token.tagtype == "webindepth":
type = "indepth"
- else :
+ else:
type = token.tagtype
return self.render_tag_helper(
- type,
- self.render_inner(token),
- self.margin_id,
- self.margin_anchor_id
+ type, self.render_inner(token), self.margin_id, self.margin_anchor_id
)
-
-
+
def render_halfwidth_spaces(self, token):
return f"{token.first}. {token.second}."
@@ -96,8 +157,8 @@ class FiftyOhmHtmlRenderer(HtmlRenderer):
return f"{token.first} {token.second}"
def render_nonbreaking_spaces_dots(self, token):
- lookup = {
- "" : "",
- " " : " "
- }
- return f"{lookup[token.first]}{token.second}{lookup[token.third]}"
\ No newline at end of file
+ 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
index f9daf9b..dfdd374 100644
--- a/renderer/halfwidth_spaces.py
+++ b/renderer/halfwidth_spaces.py
@@ -8,7 +8,7 @@ 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)\.")
+ pattern = re.compile(r"\b(z|Z|d|D)\.\s?(B|h)\.")
def __init__(self, match_object):
self.first = match_object.group(1)
diff --git a/renderer/morse.py b/renderer/morse.py
new file mode 100644
index 0000000..93ffd73
--- /dev/null
+++ b/renderer/morse.py
@@ -0,0 +1,89 @@
+import re
+
+from mistletoe.span_token import SpanToken
+
+
+class Morse(SpanToken):
+ """
+ Morse code span token ("[morse:moe]").
+ Generates morse code from a text.
+ """
+ @staticmethod
+ def convert_to_morse_code(text):
+ dit = 1
+ dah = 2
+ space = 3
+
+ morse_code = {
+ "a": [dit, dah],
+ "b": [dah, dit, dit, dit],
+ "c": [dah, dit, dah, dit],
+ "d": [dah, dit, dit],
+ "e": [dit],
+ "f": [dit, dit, dah, dit],
+ "g": [dah, dah, dit],
+ "h": [dit, dit, dit, dit],
+ "i": [dit, dit],
+ "j": [dit, dah, dah, dah],
+ "k": [dah, dit, dah],
+ "l": [dit, dah, dit, dit],
+ "m": [dah, dah],
+ "n": [dah, dit],
+ "o": [dah, dah, dah],
+ "p": [dit, dah, dah, dit],
+ "q": [dah, dah, dit, dah],
+ "r": [dit, dah, dit],
+ "s": [dit, dit, dit],
+ "t": [dah],
+ "u": [dit, dit, dah],
+ "v": [dit, dit, dit, dah],
+ "w": [dit, dah, dah],
+ "x": [dah, dit, dit, dah],
+ "y": [dah, dit, dah, dah],
+ "z": [dah, dah, dit, dit],
+ "ä": [dit, dah, dit, dah],
+ "ö": [dah, dah, dah, dit],
+ "ü": [dit, dit, dah, dah],
+ "ß": [dit, dit, dit, dah, dah, dit, dit],
+ "0": [dah, dah, dah, dah, dah],
+ "1": [dit, dah, dah, dah, dah],
+ "2": [dit, dit, dah, dah, dah],
+ "3": [dit, dit, dit, dah, dah],
+ "4": [dit, dit, dit, dit, dah],
+ "5": [dit, dit, dit, dit, dit],
+ "6": [dah, dit, dit, dit, dit],
+ "7": [dah, dah, dit, dit, dit],
+ "8": [dah, dah, dah, dit, dit],
+ "9": [dah, dah, dah, dah, dit],
+ ".": [dit, dah, dit, dah, dit, dah],
+ ",": [dah, dah, dit, dit, dah, dah],
+ ":": [dah, dah, dah, dit, dit, dit],
+ ";": [dah, dit, dah, dit, dah, dit],
+ "?": [dit, dit, dah, dah, dit, dit],
+ "!": [dah, dit, dah, dit, dah, dah],
+ "-": [dah, dit, dit, dit, dit, dah],
+ "_": [dit, dit, dah, dah, dit, dah],
+ "(": [dah, dit, dah, dah, dit],
+ ")": [dah, dit, dah, dah, dit, dah],
+ "'": [dit, dah, dah, dah, dah, dit],
+ "=": [dah, dit, dit, dit, dah],
+ "+": [dit, dah, dit, dah, dit],
+ "/": [dah, dit, dit, dah, dit],
+ "@": [dit, dah, dah, dit, dah, dit],
+ "ar": [dit, dah, dit, dah, dit],
+ "bk": [dah, dit, dit, dit, dah, dit, dah],
+ "sk": [dit, dit, dit, dah, dit, dah],
+ "correction": [dit, dit, dit, dit, dit, dit, dit, dit],
+ " ": [space]
+ }
+
+ result = []
+
+ for char in text:
+ if char.lower() in morse_code:
+ result.append(morse_code[char.lower()])
+
+ return result
+
+ parse_inner = False
+ pattern = re.compile(r'"\[morse:\s*(.+)\]"')
\ No newline at end of file
diff --git a/renderer/nonbreaking_spaces.py b/renderer/nonbreaking_spaces.py
index 932653f..08ac99d 100644
--- a/renderer/nonbreaking_spaces.py
+++ b/renderer/nonbreaking_spaces.py
@@ -6,7 +6,7 @@ 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.
+ Identifies "§$number", "Abs.$number", "Klasse [A,E,N]" w/ and without space between.
"""
pattern = re.compile(r"(§|Abs\.|Klasse)\s?(\d|[NEA])")
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 9092266..749a1bb 100644
--- a/renderer/tag.py
+++ b/renderer/tag.py
@@ -18,11 +18,11 @@ captures = [
"latexonly",
]
-class Tag(BlockToken):
+class Tag(BlockToken):
@staticmethod
def start(line):
- return re.match(r"^\s*<("+"|".join(captures)+r")+>", line)
+ return re.match(r"^\s*<(" + "|".join(captures) + r")+>", line)
@classmethod
def read(cls, lines):
@@ -34,9 +34,9 @@ class Tag(BlockToken):
for line in lines:
if line.startswith(f"{tagtype}>"):
break
- else :
+ else:
child_lines.append(line)
return tagtype, tokenize(child_lines)
def __init__(self, match):
- self.tagtype, self.children = match
\ No newline at end of file
+ self.tagtype, self.children = match
diff --git a/renderer/unit.py b/renderer/unit.py
new file mode 100644
index 0000000..4a6b9f0
--- /dev/null
+++ b/renderer/unit.py
@@ -0,0 +1,55 @@
+import re
+
+from mistletoe.span_token import SpanToken
+
+
+class Unit(SpanToken):
+ units = [
+ "A",
+ "Ah",
+ "A/mm²",
+ "baud",
+ "Bit",
+ "Bit/s",
+ "dB",
+ "dBi",
+ "dBm",
+ "dBW",
+ "F",
+ "J",
+ "Hz",
+ "H",
+ "cm",
+ "m",
+ "m²",
+ "Ohm",
+ "ppm",
+ "pps",
+ "s",
+ "V",
+ "W",
+ "Wh",
+ "°",
+ "%",
+ ]
+ prefixes = ["p", "n", "μ", "m", "k", "M", "G"]
+
+ pattern = re.compile(
+ r"(?P[0-9,]+) ?(?P"
+ # Group all prefixes together in a capture group
+ # Empty string at end of list is required so the group always exists in the resulting match
+ + "|".join(prefixes + [""])
+ + ")(?P"
+ # Group all units together in a capture group.
+ + "|".join(units)
+ + r")(?!\w)"
+ )
+
+ value: str
+ prefix: str
+ unit: str
+
+ def __init__(self, match: re.Match):
+ self.value = match.group("value")
+ self.prefix = match.group("prefix") or ""
+ self.unit = match.group("unit")
diff --git a/test/acceptanceTest.md b/test/acceptanceTest.md
index 715c69a..5148735 100644
--- a/test/acceptanceTest.md
+++ b/test/acceptanceTest.md
@@ -94,6 +94,8 @@ CQ CQ hier ist DL1PZ mit einem allgemeinen Anruf, hier ist DL1PZ und hört.
[table:n_morsetelegrafie_morsecode_buchstaben:Morsecode (Buchstaben)]
+Das ist ein A in Morsecode: [morse:a], das finde ich ganz toll!
+
...
diff --git a/test/test_halfwidth_spaces.py b/test/test_halfwidth_spaces.py
index 1dd1cbe..56a0d46 100644
--- a/test/test_halfwidth_spaces.py
+++ b/test/test_halfwidth_spaces.py
@@ -11,6 +11,7 @@ def test_halfwidth_space_html():
assert mistletoe.markdown(input, FiftyOhmHtmlRenderer) == paragraph(target)
+
def test_halfwidth_space_latex():
input = "Dies ist z.B. ein Test. D.h. hier sollten d.h. Spaces ersetzt worden sein."
target = "\nDies ist z.\,B. ein Test. D.\,h. hier sollten d.\,h. Spaces ersetzt worden sein.\n"
diff --git a/test/test_html.py b/test/test_html.py
new file mode 100644
index 0000000..8c2dc42
--- /dev/null
+++ b/test/test_html.py
@@ -0,0 +1,14 @@
+
+import mistletoe
+
+from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer
+
+
+def test_html(capsys) :
+
+ with capsys.disabled():
+ with open("test/acceptanceTest.md") as file:
+ content = file.read()
+ output = mistletoe.markdown(content, FiftyOhmHtmlRenderer)
+ with open("test/acceptanceTest.html", "w") as output_file:
+ output_file.write(output)
\ No newline at end of file
diff --git a/test/test_morse.py b/test/test_morse.py
new file mode 100644
index 0000000..d7ece1a
--- /dev/null
+++ b/test/test_morse.py
@@ -0,0 +1,17 @@
+import mistletoe
+
+from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer
+
+
+def test_morse_html() :
+
+ assertions = {
+ '"[morse:a]"' : ""+FiftyOhmHtmlRenderer.render_morse_helper([[1,2]])+"
\n",
+ '"[morse: a]"' : ""+FiftyOhmHtmlRenderer.render_morse_helper([[1,2]])+"
\n",
+ '"[morse: aaa]"' : ""+FiftyOhmHtmlRenderer.render_morse_helper([[1,2],[1,2],[1,2]])+"
\n",
+ '"[morse: a a]"' : ""+FiftyOhmHtmlRenderer.render_morse_helper([[1,2],[3],[1,2]])+"
\n",
+ '"[morse: db0]"' : ""+FiftyOhmHtmlRenderer.render_morse_helper([[2,1,1],[2,1,1,1],[2,2,2,2,2]])+"
\n",
+ }
+
+ for assertion in assertions:
+ assert mistletoe.markdown(assertion, FiftyOhmHtmlRenderer) == assertions[assertion]
\ No newline at end of file
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 09e6193..ca7eb26 100644
--- a/test/test_tag.py
+++ b/test/test_tag.py
@@ -4,6 +4,7 @@ from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer
from renderer.fifty_ohm_latex_renderer import FiftyOhmLaTeXRenderer
+
def test_thematic_break_html() :
assertions = {
"---" : '\n',
diff --git a/test/test_unit.py b/test/test_unit.py
new file mode 100644
index 0000000..eb736cd
--- /dev/null
+++ b/test/test_unit.py
@@ -0,0 +1,45 @@
+import mistletoe
+import pytest
+
+from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer
+
+from .util import paragraph
+
+
+@pytest.mark.html
+def test_basic_units_html():
+ """Test basic units: Insert non-breaking, smaller space."""
+ assertions = {
+ "1 V": "1 V",
+ "0,12 V": "0,12 V",
+ "0,75 kW": "0,75 kW",
+ "33 A": "33 A",
+ "1 Ah": "1 Ah", # Ah can be a tricky case if the RegEx is wrong, as A might match before Ah, thus rendering the output with an "A" unit
+ }
+
+ for input, output in assertions.items():
+ assert mistletoe.markdown(input, FiftyOhmHtmlRenderer) == paragraph(output)
+
+
+@pytest.mark.html
+def test_translated_units_html():
+ """Test translated units: Replace Ohm with Ω."""
+ assertions = {
+ "50 Ohm": "50 Ω",
+ "100 mOhm": "100 mΩ",
+ }
+
+ for input, output in assertions.items():
+ assert mistletoe.markdown(input, FiftyOhmHtmlRenderer) == paragraph(output)
+
+
+@pytest.mark.html
+def test_special_units_html():
+ """Test special units: Don't put space before ° and %."""
+ assertions = {
+ "100%": "100%",
+ "42,24°": "42,24°",
+ }
+
+ for input, output in assertions.items():
+ assert mistletoe.markdown(input, FiftyOhmHtmlRenderer) == paragraph(output)
diff --git a/test/util.py b/test/util.py
index f30aa79..a86b9eb 100644
--- a/test/util.py
+++ b/test/util.py
@@ -1,2 +1,2 @@
-def paragraph(text) :
- return f'{text}
\n'
\ No newline at end of file
+def paragraph(text):
+ return f"{text}
\n"