added support for tags, both in metadata and inline in the text
This commit is contained in:
parent
8c4ab0c4d5
commit
91919dd324
|
@ -2,8 +2,7 @@ METADATA VALUES USED BY DRAGONGLASS
|
||||||
|
|
||||||
aliases
|
aliases
|
||||||
(Obsidian standard metadata)
|
(Obsidian standard metadata)
|
||||||
List of alternative names that can be used to link to a
|
List of alternative names that can be used to link to a particular page.
|
||||||
particular page.
|
|
||||||
|
|
||||||
description
|
description
|
||||||
(Obsidian Publish standard metadata)
|
(Obsidian Publish standard metadata)
|
||||||
|
@ -13,6 +12,10 @@ publish
|
||||||
(Obsidian Publish standard metadata)
|
(Obsidian Publish standard metadata)
|
||||||
If this boolean value is False, the page will not be published.
|
If this boolean value is False, the page will not be published.
|
||||||
|
|
||||||
|
tags
|
||||||
|
(Obsidian standard metadata)
|
||||||
|
List of tags for this page. Tags may be defined here or inline in the text.
|
||||||
|
|
||||||
template
|
template
|
||||||
The file name of the template to be used to render this page, overriding the default.
|
The file name of the template to be used to render this page, overriding the default.
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,9 @@ dragonglass_version
|
||||||
python_version
|
python_version
|
||||||
The version number of Python that's running dragonglass.
|
The version number of Python that's running dragonglass.
|
||||||
|
|
||||||
|
tags:
|
||||||
|
A list of all tags the page being rendered has, in sorted order.
|
||||||
|
|
||||||
text
|
text
|
||||||
The text of the page being rendered.
|
The text of the page being rendered.
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,8 @@ INLINE_FOOTNOTE_REF_PATTERN = INLINE_FOOTNOTE_REF_PREFIX + "{}" + ETX
|
||||||
# Obsidian comment marker
|
# Obsidian comment marker
|
||||||
COMMENT_MARKER = '%%'
|
COMMENT_MARKER = '%%'
|
||||||
|
|
||||||
|
# Tags pattern
|
||||||
|
OBSTAG_PATTERN = r'#([a-zA-Z0-9/_-]+)'
|
||||||
|
|
||||||
def is_proper_url(s: str) -> bool:
|
def is_proper_url(s: str) -> bool:
|
||||||
"""
|
"""
|
||||||
|
@ -1033,6 +1035,49 @@ class ObsidianStyleBlockquotes(Extension):
|
||||||
'callout-text', 11)
|
'callout-text', 11)
|
||||||
|
|
||||||
|
|
||||||
|
class ObsidianTags(Extension):
|
||||||
|
def __init__(self, context: Context, **kwargs: dict[str, Any]) -> None:
|
||||||
|
"""
|
||||||
|
Initialize the ObsidianStyleBlockquotes extension.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
context (Context): Context object that contains configuration information.
|
||||||
|
**kwargs (dict[str, Any]: Additional configuration information.
|
||||||
|
"""
|
||||||
|
super(ObsidianTags, self).__init__(**kwargs)
|
||||||
|
self._context = context
|
||||||
|
|
||||||
|
def stash_tag(self, tagname: str) -> None:
|
||||||
|
self._context.current_node.stash_tag(tagname)
|
||||||
|
|
||||||
|
class ObsidianTagsProcessor(InlineProcessor):
|
||||||
|
def __init__(self, pattern: str, md: markdown.Markdown, extref: Any) -> None:
|
||||||
|
"""
|
||||||
|
Initialize the GenericLinksProc.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
pattern (str): Regular expression pattern to be matched by this processor.
|
||||||
|
md (markdown.Markdown): Reference to the Markdown parser.
|
||||||
|
extref (ObsidianLinks): Backreference to the outer object.
|
||||||
|
"""
|
||||||
|
super(ObsidianTags.ObsidianTagsProcessor, self).__init__(pattern, md)
|
||||||
|
self._extref = extref
|
||||||
|
|
||||||
|
def handleMatch(self, m: re.Match[str], data: str) -> tuple[etree.Element | None, int | None, int | None]: # noqa: N802
|
||||||
|
tagname = m.group(1)
|
||||||
|
if not re.search(r'[^0-9]', tagname):
|
||||||
|
return None, None, None
|
||||||
|
self._extref.stash_tag(tagname)
|
||||||
|
tag = etree.Element('span')
|
||||||
|
tag.attrib['class'] = "tag"
|
||||||
|
tag.text = f"#{tagname}"
|
||||||
|
return tag, m.start(0), m.end(0)
|
||||||
|
|
||||||
|
def extendMarkdown(self, md) -> None:
|
||||||
|
md.inlinePatterns.register(ObsidianTags.ObsidianTagsProcessor(OBSTAG_PATTERN, md, self),
|
||||||
|
'obsidian-tags', PRIO_BASE + 40)
|
||||||
|
|
||||||
|
|
||||||
def create_markdown_parser(context: Context) -> markdown.Markdown:
|
def create_markdown_parser(context: Context) -> markdown.Markdown:
|
||||||
"""
|
"""
|
||||||
Creates a Markdown parser with all our extensions loaded.
|
Creates a Markdown parser with all our extensions loaded.
|
||||||
|
@ -1063,5 +1108,6 @@ def create_markdown_parser(context: Context) -> markdown.Markdown:
|
||||||
ObsidianImages(context),
|
ObsidianImages(context),
|
||||||
ObsidianLinks(context),
|
ObsidianLinks(context),
|
||||||
ObsidianLists(),
|
ObsidianLists(),
|
||||||
ObsidianInlines()],
|
ObsidianInlines(),
|
||||||
|
ObsidianTags(context)],
|
||||||
extension_configs=extconfig)
|
extension_configs=extconfig)
|
||||||
|
|
|
@ -36,6 +36,17 @@ blockquote {
|
||||||
span.task-list-item-checked {
|
span.task-list-item-checked {
|
||||||
text-decoration-line: line-through;
|
text-decoration-line: line-through;
|
||||||
}
|
}
|
||||||
|
span.tag {
|
||||||
|
background-color: hsla(258, 88%, 66%, 0.1);
|
||||||
|
border: 0px solid hsla(258, 88%, 66%, 0.15);
|
||||||
|
border-radius: 2em;
|
||||||
|
color: hsl(258, 88%, 66%);
|
||||||
|
font-size: 0.875em;
|
||||||
|
font-weight: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 0.25em 0.65em;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
div.codehilite {
|
div.codehilite {
|
||||||
padding: 0.1em 0.25em;
|
padding: 0.1em 0.25em;
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
|
|
|
@ -44,6 +44,7 @@ class SourceNode:
|
||||||
self._path = path
|
self._path = path
|
||||||
self._is_dir = is_dir
|
self._is_dir = is_dir
|
||||||
self._is_md = path.match(MARKDOWN_PAT)
|
self._is_md = path.match(MARKDOWN_PAT)
|
||||||
|
self._tags: dict[str, str] = {}
|
||||||
self.metadata: dict[str, Any] = {}
|
self.metadata: dict[str, Any] = {}
|
||||||
self.text: str | None = None
|
self.text: str | None = None
|
||||||
self.backlinks: set[Any] = set()
|
self.backlinks: set[Any] = set()
|
||||||
|
@ -117,6 +118,17 @@ class SourceNode:
|
||||||
return urlquote(xpath.relative_to(rel_path.parent, walk_up=True).as_posix())
|
return urlquote(xpath.relative_to(rel_path.parent, walk_up=True).as_posix())
|
||||||
return urlquote(prefix + xpath.as_posix())
|
return urlquote(prefix + xpath.as_posix())
|
||||||
|
|
||||||
|
def stash_tag(self, tagname: str) -> None:
|
||||||
|
"""
|
||||||
|
Add a tag to the set of tags in this node.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tagname (str): The tag name to be added.
|
||||||
|
"""
|
||||||
|
rtag = tagname.lower()
|
||||||
|
if rtag not in self._tags:
|
||||||
|
self._tags[rtag] = tagname
|
||||||
|
|
||||||
def load_metadata(self) -> None:
|
def load_metadata(self) -> None:
|
||||||
"""
|
"""
|
||||||
Loads the metadata for this particular node and saves it in the "metadata" attribute.
|
Loads the metadata for this particular node and saves it in the "metadata" attribute.
|
||||||
|
@ -133,6 +145,9 @@ class SourceNode:
|
||||||
metalines.append(cur_line)
|
metalines.append(cur_line)
|
||||||
cur_line = f.readline()
|
cur_line = f.readline()
|
||||||
self.metadata = yaml.full_load(''.join(metalines))
|
self.metadata = yaml.full_load(''.join(metalines))
|
||||||
|
# Load up the initial tags.
|
||||||
|
for tag in self.metadata.get("tags", []):
|
||||||
|
self.stash_tag(tag)
|
||||||
|
|
||||||
def parse_markdown(self, markdown_parser: markdown.Markdown) -> None:
|
def parse_markdown(self, markdown_parser: markdown.Markdown) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -156,7 +171,8 @@ class SourceNode:
|
||||||
return {
|
return {
|
||||||
"text": self.text,
|
"text": self.text,
|
||||||
"title": self.page_title,
|
"title": self.page_title,
|
||||||
"description": self.metadata.get("description", "")
|
"description": self.metadata.get("description", ""),
|
||||||
|
"tags": [self._tags[n] for n in sorted(self._tags.keys())]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user