diff --git a/md2mu.py b/md2mu.py index 00e4ff8..ab98ce9 100644 --- a/md2mu.py +++ b/md2mu.py @@ -1,49 +1,146 @@ import mistune +from mistune import Markdown +from mistune.core import BlockState +from mistune.util import strip_end +from mistune.renderers._list import render_list +from mistune.renderers.markdown import MarkdownRenderer +from typing import Dict, Any +from textwrap import indent import argparse +import re -class Markdown2Micron(mistune.HTMLRenderer): - def text(self, text) -> str: - return text - def emphasis(self, text: str) -> str: - return '`*' + text + '`*' - def strong(self, text: str) -> str: - return '`!' + text + '`!' - def codespan(self, text: str) -> str: - return '`=' + text + '`=' - def heading(self, text, level, **attrs) -> str: +UNDERLINED = r'\b_{1,3}(?=[^\s_])' +UNDERLINED_END_RE = { + '_': re.compile(r'(?:(? int: + print(state) + pos = m.end() + marker = m.group(0) + mlen = len(marker) + _end_re = UNDERLINED_END_RE[marker] + m1 = _end_re.search(state.src, pos) + if not m1: + state.append_token({'type': 'text', 'raw': marker}) + return pos + end_pos = m1.end() + text = state.src[pos:end_pos-mlen] + prec_pos = self.precedence_scan(m, state, end_pos) + if prec_pos: + return prec_pos + new_state = state.copy() + new_state.src = text + new_state.in_underlined = True + state.append_token({ + 'type': 'underlined', + 'children': self.render(new_state), + }) + return end_pos + +def render_underlined(self, token, state) -> str: + return '`_' + self.render_children(token, state) + '`_' + +class Markdown2Micron(MarkdownRenderer): + NAME = 'micron' + + def __call__(self, tokens, state: BlockState): + out = self.render_tokens(tokens, state) + # special handle for line breaks + out += '\n\n'.join(self.render_referrences(state)) + '\n' + return strip_end(out) + + def render_children(self, token, state: BlockState): + children = token['children'] + return self.render_tokens(children, state) + + def text(self, token: Dict[str, Any], state: BlockState) -> str: + return token['raw'] + + def emphasis(self, token: Dict[str, Any], state: BlockState) -> str: + return '`*' + self.render_children(token, state) + '`*' + + def strong(self, token: Dict[str, Any], state: BlockState) -> str: + return '`!' + self.render_children(token, state) + '`!' + + def link(self, token: Dict[str, Any], state: BlockState) -> str: + label = token.get('label') + text = self.render_children(token, state) + out = '`[' + text + '`' + if label: + return out + '`[' + label + '`' + attrs = token['attrs'] + url = attrs['url'] + if text == url: + return '`[' + text + '`' + elif 'mailto:' + text == url: + return '`[' + text + '`' + out += url + return out + ']' + + def image(self, token: Dict[str, Any], state: BlockState) -> str: + return self.link(token, state) + + def codespan(self, token: Dict[str, Any], state: BlockState) -> str: + return '`=' + token['raw'] + '`=' + + def linebreak(self, token: Dict[str, Any], state: BlockState) -> str: + return ' \n' + + def softbreak(self, token: Dict[str, Any], state: BlockState) -> str: + return '\n' + + def blank_line(self, token: Dict[str, Any], state: BlockState) -> str: + return '' + + def inline_html(self, token: Dict[str, Any], state: BlockState) -> str: + return '' + + def paragraph(self, token: Dict[str, Any], state: BlockState) -> str: + text = self.render_children(token, state) + return text + '\n\n' + + def heading(self, token: Dict[str, Any], state: BlockState) -> str: + level = token['attrs']['level'] if level > 3: level = 3 - return '>' * level + text + '\n' - def link(self, text: str, url: str, title=None) -> str: - s = self.safe_url(url) - if text: - s = text + '`' + s - return f'`[{s}]' - def image(self, text: str, url: str, title=None) -> str: - s = self.safe_url(url) - if title: - s = title + '`' + s - return f'`[{s}]' - def blank_line(self) -> str: - return '' + '\n' - def linebreak(self) -> str: - return '\n' - def softbreak(self) -> str: - return '\n' - def inline_html(self, html: str) -> str: - return '`=\n' + html + '`=\n' - def thematic_break(self): - return '-' + '\n' - def paragraph(self, text): - return text + '\n' - def block_quote(self, text: str) -> str: - return '>>>>' + text - def list(self, text: str, ordered: bool, **attrs) -> str: - return text + '\n' - def list_item(self, text: str) -> str: - return '+ ' + text + '\n' - def block_code(self, code: str, info=None) -> str: - return '`=\n' + code + '`=\n' + marker = '>' * level + text = self.render_children(token, state) + return marker + ' ' + text + '\n\n' + def thematic_break(self, token: Dict[str, Any], state: BlockState) -> str: + return '-\n\n' + + def block_text(self, token: Dict[str, Any], state: BlockState) -> str: + return self.render_children(token, state) + '\n' + + def block_code(self, token: Dict[str, Any], state: BlockState) -> str: + code = token['raw'] + if code and code[-1] != '\n': + code += '\n' + marker = '`=' + return marker + '\n' + code + marker + '\n\n' + + def block_quote(self, token: Dict[str, Any], state: BlockState) -> str: + text = indent(self.render_children(token, state), '>>>>') + return text + '\n\n' + + def block_html(self, token: Dict[str, Any], state: BlockState) -> str: + return '' + + def block_error(self, token: Dict[str, Any], state: BlockState) -> str: + return '' + + def list(self, token: Dict[str, Any], state: BlockState) -> str: + return render_list(self, token, state) def main(): @@ -55,11 +152,13 @@ def main(): with open(args.md_file, 'r') as mdf: md_str = mdf.read() - m2μ = Markdown2Micron() - md2micron = mistune.create_markdown(renderer=m2μ) + m2μr = Markdown2Micron() + m2μ = Markdown(renderer=m2μr) + m2μ.inline.register('underlined', UNDERLINED, parse_underlined, before='emphasis') + m2μ.renderer.register('underlined', render_underlined) with open(args.mu_file, 'w') as muf: - md_str = muf.write(md2micron(md_str)) + md_str = muf.write(m2μ(md_str)) if __name__ == "__main__": main() \ No newline at end of file diff --git a/micron.mu b/micron.mu index d1aca50..ee29a91 100644 --- a/micron.mu +++ b/micron.mu @@ -1,11 +1,16 @@ ->h1 Heading 8-) ->>h2 Heading ->>>h3 Heading ->>>h4 Heading ->>>h5 Heading ->>>h6 Heading +> h1 Heading 8-) ->>Horizontal Rules +>> h2 Heading + +>>> h3 Heading + +>>> h4 Heading + +>>> h5 Heading + +>>> h6 Heading + +>> Horizontal Rules - @@ -13,43 +18,51 @@ - ->>Emphasis +>> Emphasis `!This is bold text`! -`!This is bold text`! -`*This is italic text`* +`_This is bold text`_ `*This is italic text`* +`_This is italic text`_ ~~Strikethrough~~ ->>Blockquotes +>> Blockquotes >>>>Blockquotes can also be nested... ->>>>by using additional greater-than signs right next to each other... ->>>>or with spaces between arrows. ->>Lists +>>>>>>>>by using additional greater-than signs right next to each other... ->>>Unordered +>>>>>>>>>>>>or with spaces between arrows. + + + + + + + +>> Lists + +>>> Unordered + Create a list by starting a line with `=+`=, `=-`=, or `=*`= -+ Marker character change forces new list start: +- Marker character change forces new list start: -+ Ac tristique libero volutpat at +* Ac tristique libero volutpat at + Facilisis in pretium nisl aliquet -+ Nulla volutpat aliquam velit +- Nulla volutpat aliquam velit + Very easy ->>>Ordered +>>> Ordered -+ Lorem ipsum dolor sit amet -+ Consectetur adipiscing elit -+ Integer molestie lorem at massa +1. Lorem ipsum dolor sit amet +2. Consectetur adipiscing elit +3. Integer molestie lorem at massa ->>Code +>> Code Inline `=code`= @@ -59,7 +72,9 @@ Indented code // Some comments line 1 of code line 2 of code -line 3 of code`= +line 3 of code +`= + Block code "fences" `= @@ -76,13 +91,13 @@ var foo = function (bar) { console.log(foo(5)); `= ->>Links +>> Links `[link text`http://dev.nodeca.com] `[link with title`http://nodeca.github.io/pica/demo/] ->>Images +>> Images -`[https://octodex.github.com/images/minion.png] -`[The Stormtroopocat`https://octodex.github.com/images/stormtroopocat.jpg] +`[Minion`https://octodex.github.com/images/minion.png] +`[Stormtroopocat`https://octodex.github.com/images/stormtroopocat.jpg]