added support for Obsidian style image references, including embedded dimensions
This commit is contained in:
parent
c0025f9513
commit
5e144d303d
|
@ -1,5 +1,6 @@
|
||||||
#/usr/bin/env python3
|
#/usr/bin/env python3
|
||||||
|
|
||||||
|
import re
|
||||||
import markdown
|
import markdown
|
||||||
import xml.etree.ElementTree as etree
|
import xml.etree.ElementTree as etree
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
@ -60,6 +61,98 @@ class MetaStripper(Extension):
|
||||||
md.preprocessors.register(MetaStripper.MetaStripperProc(md), 'metastripper', PRIO_BASE)
|
md.preprocessors.register(MetaStripper.MetaStripperProc(md), 'metastripper', PRIO_BASE)
|
||||||
|
|
||||||
|
|
||||||
|
class ObsidianImages(Extension):
|
||||||
|
"""An extension that supports image tags the way Obsidian handles them."""
|
||||||
|
DIMS = re.compile(r'(.*)\|(\d+)(?:x(\d+))?')
|
||||||
|
|
||||||
|
def __init__(self, context, **kwargs):
|
||||||
|
super(ObsidianImages, self).__init__(**kwargs)
|
||||||
|
self._context = context
|
||||||
|
|
||||||
|
@property
|
||||||
|
def invalid_reference_classname(self):
|
||||||
|
return 'invalid-reference'
|
||||||
|
|
||||||
|
def _parse_dimensions(self, s):
|
||||||
|
m = self.DIMS.match(s)
|
||||||
|
if m:
|
||||||
|
width = int(m.group(2))
|
||||||
|
height = int(m.group(3)) if m.group(3) else -1
|
||||||
|
return m.group(1), width, height
|
||||||
|
else:
|
||||||
|
return s, -1, -1
|
||||||
|
|
||||||
|
def _lookup_image_reference(self, name):
|
||||||
|
node, _ = self._context.src_index.lookup(name)
|
||||||
|
if node:
|
||||||
|
return node.link_target(self._context.url_prefix)
|
||||||
|
return None
|
||||||
|
|
||||||
|
class ObsidianImageProc(InlineProcessor):
|
||||||
|
def __init__(self, pattern, md, extref):
|
||||||
|
super(ObsidianImages.ObsidianImageProc, self).__init__(pattern, md)
|
||||||
|
self._extref = extref
|
||||||
|
|
||||||
|
def handleMatch(self, m, data):
|
||||||
|
name, width, height = self._extref._parse_dimensions(m.group(1))
|
||||||
|
link = self._extref._lookup_image_reference(name)
|
||||||
|
if link is None:
|
||||||
|
el = etree.Element('span')
|
||||||
|
el.set('class', self._extref.invalid_reference_classname)
|
||||||
|
el.text = name
|
||||||
|
else:
|
||||||
|
el = etree.Element('img')
|
||||||
|
el.set('src', link)
|
||||||
|
el.set('alt', name)
|
||||||
|
if width > 0:
|
||||||
|
el.set('width', str(width))
|
||||||
|
if height > 0:
|
||||||
|
el.set('height', str(height))
|
||||||
|
return el, m.start(0), m.end(0)
|
||||||
|
|
||||||
|
class GenericImageProc(InlineProcessor):
|
||||||
|
def __init__(self, pattern, md, extref):
|
||||||
|
super(ObsidianImages.GenericImageProc, self).__init__(pattern, md)
|
||||||
|
self._extref = extref
|
||||||
|
|
||||||
|
def handleMatch(self, m, data):
|
||||||
|
name, width, height = self._extref._parse_dimensions(m.group(1))
|
||||||
|
link = m.group(2)
|
||||||
|
if is_proper_url(link):
|
||||||
|
el = etree.Element('img')
|
||||||
|
el.set('src', link)
|
||||||
|
if len(name) > 0:
|
||||||
|
el.set('alt', name)
|
||||||
|
if width > 0:
|
||||||
|
el.set('width', str(width))
|
||||||
|
if height > 0:
|
||||||
|
el.set('height', str(height))
|
||||||
|
else:
|
||||||
|
newlink = self._extref._lookup_image_reference(link)
|
||||||
|
if newlink:
|
||||||
|
el = etree.Element('img')
|
||||||
|
el.set('src', newlink)
|
||||||
|
if len(name) > 0:
|
||||||
|
el.set('alt', name)
|
||||||
|
if width > 0:
|
||||||
|
el.set('width', str(width))
|
||||||
|
if height > 0:
|
||||||
|
el.set('height', str(height))
|
||||||
|
else:
|
||||||
|
el = etree.Element('span')
|
||||||
|
el.set('class', self._extref.invalid_reference_classname)
|
||||||
|
el.text = link
|
||||||
|
return el, m.start(0), m.end(0)
|
||||||
|
|
||||||
|
def extendMarkdown(self, md):
|
||||||
|
OBSIMAGE_PATTERN = r'!\[\[(.*?)\]\]'
|
||||||
|
GENERICIMAGE_PATTERN = r'!\[(.*?)\]\((.*?)\)'
|
||||||
|
md.inlinePatterns.register(ObsidianImages.ObsidianImageProc(OBSIMAGE_PATTERN, md, self),
|
||||||
|
'obsidian_images', PRIO_BASE + 1010)
|
||||||
|
md.inlinePatterns.register(ObsidianImages.GenericImageProc(GENERICIMAGE_PATTERN, md, self),
|
||||||
|
'obsidian_generic_images', PRIO_BASE + 1000)
|
||||||
|
|
||||||
|
|
||||||
class ObsidianLinks(Extension):
|
class ObsidianLinks(Extension):
|
||||||
"""
|
"""
|
||||||
An extension that processes Obsidian internal links in the [[page name]] format, as well as overrides the standard
|
An extension that processes Obsidian internal links in the [[page name]] format, as well as overrides the standard
|
||||||
|
@ -151,4 +244,4 @@ class ObsidianInlines(Extension):
|
||||||
|
|
||||||
|
|
||||||
def create_markdown_parser(context):
|
def create_markdown_parser(context):
|
||||||
return markdown.Markdown(extensions=[MetaStripper(), ObsidianLinks(context), ObsidianInlines()])
|
return markdown.Markdown(extensions=[MetaStripper(), ObsidianImages(context), ObsidianLinks(context), ObsidianInlines()])
|
||||||
|
|
Loading…
Reference in New Issue
Block a user