import sys from enum import Enum, auto from idlelib.configdialog import is_int from pathlib import Path from pprint import pprint from typing import Optional class Block: def __init__(self, *parts): self.tag = type(self).__name__ self.data = list(parts) def extend(self, *parts): self.data.extend(parts) def __repr__(self): return f'{self.tag}:: {''.join(self.data)!r}' class Break(Block): pass class ATXHeading(Block): pass class SetextHeading(Block): pass class IndentedChunk(Block): pass class Fence(Block): def __init__(self, meta, *data): super().__init__(*data) self.meta = meta self.complete = False def __repr__(self): return f'{self.tag}:{self.meta}:: {''.join(self.data)!r}' class HTML(Block): pass class Definition(Block): pass class Paragraph(Block): pass class Blank(Block): pass def convert(md: str): blocks: list[Block] = [] cur_fence: Optional[Fence] = None def get(idx): try: return blocks[idx] except IndexError: return None for line in md.splitlines(keepends=True): if cur_fence: if line.lstrip(' ').startswith('```'): blocks.append(cur_fence) cur_fence = None else: cur_fence.extend(line) else: if line.isspace(): if len(blocks) >= 1 and isinstance(blocks[-1], Blank): blocks[-1].extend(line) else: blocks.append(Blank(line)) elif line.startswith(' ') or line.startswith('\t'): if len(blocks) >= 1 and isinstance(blocks[-1], IndentedChunk): blocks[-1].extend(line) elif len(blocks) >= 2 and isinstance(blocks[-1], Blank) and isinstance(blocks[-2], IndentedChunk): blocks[-2].extend(*blocks[-1].data, line) blocks.pop(-1) else: blocks.append(IndentedChunk(line)) elif line.lstrip(' ').startswith('```'): meta = line.strip().removeprefix('```') cur_fence = Fence(meta) else: if len(blocks) >= 1 and isinstance(blocks[-1], Paragraph): blocks[-1].extend(line) else: blocks.append(Paragraph(line)) pprint(blocks) def main(): for arg in sys.argv[1:]: md = Path(arg).read_text() html = convert(md) print('=' * 80) print(html) print('=' * 80) if __name__ == '__main__': main()