From f34f446bf97cb0db119e1c8c478b111bad738537 Mon Sep 17 00:00:00 2001 From: Amy Gale Ruth Bowersox Date: Wed, 28 Feb 2024 00:43:39 -0700 Subject: [PATCH] added proper link resolution --- src/dragonglass/dragonglass.py | 6 +++-- src/dragonglass/mparse.py | 36 ++++++++++++++++++----------- src/dragonglass/tree.py | 42 ++++++++++++++++++++++++++++++++-- 3 files changed, 67 insertions(+), 17 deletions(-) diff --git a/src/dragonglass/dragonglass.py b/src/dragonglass/dragonglass.py index e056829..4b113bc 100644 --- a/src/dragonglass/dragonglass.py +++ b/src/dragonglass/dragonglass.py @@ -3,7 +3,7 @@ import argparse import sys from pathlib import Path -from tree import SourceNode +from tree import SourceNode, SourceIndex from mparse import create_markdown_parser # The command line parser @@ -29,7 +29,9 @@ def main(): for node in nodes: node.load_metadata(source_dir) - mdparse = create_markdown_parser() + src_index = SourceIndex(nodes) + + mdparse = create_markdown_parser(src_index) for node in nodes: node.parse_markdown(source_dir, mdparse) diff --git a/src/dragonglass/mparse.py b/src/dragonglass/mparse.py index b9974fa..8660be9 100644 --- a/src/dragonglass/mparse.py +++ b/src/dragonglass/mparse.py @@ -23,10 +23,14 @@ class MetaStripper(Extension): class ObsidianLinks(Extension): + def __init__(self, src_index, **kwargs): + super(ObsidianLinks, self).__init__(**kwargs) + self._src_index = src_index class ObsidianLinksProc(InlineProcessor): - def __init__(self, pattern, md): + def __init__(self, pattern, md, src_index): super(ObsidianLinks.ObsidianLinksProc, self).__init__(pattern, md) + self._src_index = src_index def parse_reference(self, contents): text = None @@ -34,31 +38,37 @@ class ObsidianLinks(Extension): if len(t) > 1: text = t[1] contents = t[0] + + node, linktype = self._src_index.lookup(contents) if not text: text = contents - return contents, text + if node: + return node.link_target, text + return None, text def handleMatch(self, m, data): link, text = self.parse_reference(m.group(0)[2:-2]) - el = etree.Element('a') - el.set('href', link) - el.text = text + if link is None: + el = etree.Element('span') + el.set('class', 'invalid-reference') + el.text = text + else: + el = etree.Element('a') + el.set('href', link) + el.text = text return el, m.start(0), m.end(0) def extendMarkdown(self, md): OBSLINK_PATTERN = r'\[\[(.*?)\]\]' - md.inlinePatterns.register(ObsidianLinks.ObsidianLinksProc(OBSLINK_PATTERN, md), 'obsidian_links', 0) + md.inlinePatterns.register(ObsidianLinks.ObsidianLinksProc(OBSLINK_PATTERN, md, self._src_index), + 'obsidian_links', 0) -class Strikeout(Extension): +class ObsidianInlines(Extension): def extendMarkdown(self, md): md.inlinePatterns.register(SimpleTagInlineProcessor(r'()~~(.*?)~~', 'del'), 'strikeout', 0) - - -class Highlight(Extension): - def extendMarkdown(self, md): md.inlinePatterns.register(SimpleTagInlineProcessor(r'()\=\=(.*?)\=\=', 'ins'), 'highlight', 0) -def create_markdown_parser(): - return markdown.Markdown(extensions=[MetaStripper(), ObsidianLinks(), Strikeout(), Highlight()]) +def create_markdown_parser(src_index): + return markdown.Markdown(extensions=[MetaStripper(), ObsidianLinks(src_index), ObsidianInlines()]) diff --git a/src/dragonglass/tree.py b/src/dragonglass/tree.py index cb5dc36..a97dcf3 100644 --- a/src/dragonglass/tree.py +++ b/src/dragonglass/tree.py @@ -1,5 +1,6 @@ #!/usr/bin/env python +from urllib.parse import quote as urlquote import yaml # The paths that are always to be ignored. @@ -21,6 +22,11 @@ class SourceNode: def __str__(self): return f"SourceNode({self._path}, {self._is_dir}) [is_md={self._is_md}]" + @property + def link_target(self): + xpath = self._path.with_suffix('.html') if self._is_md else self._path + return urlquote(xpath.as_posix()) + @classmethod def generate_list(cls, source_root): nodes = [] @@ -43,10 +49,8 @@ class SourceNode: def load_metadata(self, source_dir): if self._is_md: with open(source_dir / self._path, "r", encoding="utf-8") as f: - print(">>>opened") l = f.readline() if l == '---\n': - print(">>>startmd") metalines = [] l = f.readline() while l != '---\n': @@ -59,3 +63,37 @@ class SourceNode: markdown_parser.reset() with open(source_dir / self._path, "r", encoding="utf-8") as f: self.text = markdown_parser.convert(f.read()) + + +class SourceIndex: + def __init__(self, nodelist): + self._byname = {} + self._byalias = {} + for node in nodelist: + if node._is_dir: + continue + if node._is_md: + tmp = node._path.with_suffix('') + key = tmp.name + if key not in self._byname: + self._byname[key] = node + self._byname[tmp.as_posix()] = node + if node.metadata: + aliases = node.metadata.get('aliases', []) + if isinstance(aliases, list): + for alias in aliases: + if alias not in self._byalias: + self._byalias[alias] = node + else: + key = self._path.name + if key not in self._byname: + self._byname[key] = node + self._byname[self._path.as_posix()] = node + + def lookup(self, reference): + if reference in self._byname: + return self._byname[reference], 'NAME' + elif reference in self._byalias: + return self._byalias[reference], 'ALIAS' + else: + return None, None