added proper link resolution

This commit is contained in:
Amy G. Bowersox 2024-02-28 00:43:39 -07:00
parent 0fdbd3d221
commit f34f446bf9
3 changed files with 67 additions and 17 deletions

View File

@ -3,7 +3,7 @@
import argparse import argparse
import sys import sys
from pathlib import Path from pathlib import Path
from tree import SourceNode from tree import SourceNode, SourceIndex
from mparse import create_markdown_parser from mparse import create_markdown_parser
# The command line parser # The command line parser
@ -29,7 +29,9 @@ def main():
for node in nodes: for node in nodes:
node.load_metadata(source_dir) node.load_metadata(source_dir)
mdparse = create_markdown_parser() src_index = SourceIndex(nodes)
mdparse = create_markdown_parser(src_index)
for node in nodes: for node in nodes:
node.parse_markdown(source_dir, mdparse) node.parse_markdown(source_dir, mdparse)

View File

@ -23,10 +23,14 @@ class MetaStripper(Extension):
class ObsidianLinks(Extension): class ObsidianLinks(Extension):
def __init__(self, src_index, **kwargs):
super(ObsidianLinks, self).__init__(**kwargs)
self._src_index = src_index
class ObsidianLinksProc(InlineProcessor): class ObsidianLinksProc(InlineProcessor):
def __init__(self, pattern, md): def __init__(self, pattern, md, src_index):
super(ObsidianLinks.ObsidianLinksProc, self).__init__(pattern, md) super(ObsidianLinks.ObsidianLinksProc, self).__init__(pattern, md)
self._src_index = src_index
def parse_reference(self, contents): def parse_reference(self, contents):
text = None text = None
@ -34,31 +38,37 @@ class ObsidianLinks(Extension):
if len(t) > 1: if len(t) > 1:
text = t[1] text = t[1]
contents = t[0] contents = t[0]
node, linktype = self._src_index.lookup(contents)
if not text: if not text:
text = contents text = contents
return contents, text if node:
return node.link_target, text
return None, text
def handleMatch(self, m, data): def handleMatch(self, m, data):
link, text = self.parse_reference(m.group(0)[2:-2]) link, text = self.parse_reference(m.group(0)[2:-2])
el = etree.Element('a') if link is None:
el.set('href', link) el = etree.Element('span')
el.text = text 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) return el, m.start(0), m.end(0)
def extendMarkdown(self, md): def extendMarkdown(self, md):
OBSLINK_PATTERN = r'\[\[(.*?)\]\]' 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): def extendMarkdown(self, md):
md.inlinePatterns.register(SimpleTagInlineProcessor(r'()~~(.*?)~~', 'del'), 'strikeout', 0) md.inlinePatterns.register(SimpleTagInlineProcessor(r'()~~(.*?)~~', 'del'), 'strikeout', 0)
class Highlight(Extension):
def extendMarkdown(self, md):
md.inlinePatterns.register(SimpleTagInlineProcessor(r'()\=\=(.*?)\=\=', 'ins'), 'highlight', 0) md.inlinePatterns.register(SimpleTagInlineProcessor(r'()\=\=(.*?)\=\=', 'ins'), 'highlight', 0)
def create_markdown_parser(): def create_markdown_parser(src_index):
return markdown.Markdown(extensions=[MetaStripper(), ObsidianLinks(), Strikeout(), Highlight()]) return markdown.Markdown(extensions=[MetaStripper(), ObsidianLinks(src_index), ObsidianInlines()])

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
from urllib.parse import quote as urlquote
import yaml import yaml
# The paths that are always to be ignored. # The paths that are always to be ignored.
@ -21,6 +22,11 @@ class SourceNode:
def __str__(self): def __str__(self):
return f"SourceNode({self._path}, {self._is_dir}) [is_md={self._is_md}]" 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 @classmethod
def generate_list(cls, source_root): def generate_list(cls, source_root):
nodes = [] nodes = []
@ -43,10 +49,8 @@ class SourceNode:
def load_metadata(self, source_dir): def load_metadata(self, source_dir):
if self._is_md: if self._is_md:
with open(source_dir / self._path, "r", encoding="utf-8") as f: with open(source_dir / self._path, "r", encoding="utf-8") as f:
print(">>>opened")
l = f.readline() l = f.readline()
if l == '---\n': if l == '---\n':
print(">>>startmd")
metalines = [] metalines = []
l = f.readline() l = f.readline()
while l != '---\n': while l != '---\n':
@ -59,3 +63,37 @@ class SourceNode:
markdown_parser.reset() markdown_parser.reset()
with open(source_dir / self._path, "r", encoding="utf-8") as f: with open(source_dir / self._path, "r", encoding="utf-8") as f:
self.text = markdown_parser.convert(f.read()) 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