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
|
||||
(Obsidian standard metadata)
|
||||
List of alternative names that can be used to link to a
|
||||
particular page.
|
||||
List of alternative names that can be used to link to a particular page.
|
||||
|
||||
description
|
||||
(Obsidian Publish standard metadata)
|
||||
|
@ -13,6 +12,10 @@ publish
|
|||
(Obsidian Publish standard metadata)
|
||||
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
|
||||
The file name of the template to be used to render this page, overriding the default.
|
||||
|
||||
|
|
|
@ -17,6 +17,9 @@ dragonglass_version
|
|||
python_version
|
||||
The version number of Python that's running dragonglass.
|
||||
|
||||
tags:
|
||||
A list of all tags the page being rendered has, in sorted order.
|
||||
|
||||
text
|
||||
The text of the page being rendered.
|
||||
|
||||
|
|
|
@ -42,6 +42,8 @@ INLINE_FOOTNOTE_REF_PATTERN = INLINE_FOOTNOTE_REF_PREFIX + "{}" + ETX
|
|||
# Obsidian comment marker
|
||||
COMMENT_MARKER = '%%'
|
||||
|
||||
# Tags pattern
|
||||
OBSTAG_PATTERN = r'#([a-zA-Z0-9/_-]+)'
|
||||
|
||||
def is_proper_url(s: str) -> bool:
|
||||
"""
|
||||
|
@ -1033,6 +1035,49 @@ class ObsidianStyleBlockquotes(Extension):
|
|||
'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:
|
||||
"""
|
||||
Creates a Markdown parser with all our extensions loaded.
|
||||
|
@ -1063,5 +1108,6 @@ def create_markdown_parser(context: Context) -> markdown.Markdown:
|
|||
ObsidianImages(context),
|
||||
ObsidianLinks(context),
|
||||
ObsidianLists(),
|
||||
ObsidianInlines()],
|
||||
ObsidianInlines(),
|
||||
ObsidianTags(context)],
|
||||
extension_configs=extconfig)
|
||||
|
|
|
@ -36,6 +36,17 @@ blockquote {
|
|||
span.task-list-item-checked {
|
||||
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 {
|
||||
padding: 0.1em 0.25em;
|
||||
margin-top: 0.5em;
|
||||
|
|
|
@ -44,6 +44,7 @@ class SourceNode:
|
|||
self._path = path
|
||||
self._is_dir = is_dir
|
||||
self._is_md = path.match(MARKDOWN_PAT)
|
||||
self._tags: dict[str, str] = {}
|
||||
self.metadata: dict[str, Any] = {}
|
||||
self.text: str | None = None
|
||||
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(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:
|
||||
"""
|
||||
Loads the metadata for this particular node and saves it in the "metadata" attribute.
|
||||
|
@ -133,6 +145,9 @@ class SourceNode:
|
|||
metalines.append(cur_line)
|
||||
cur_line = f.readline()
|
||||
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:
|
||||
"""
|
||||
|
@ -156,7 +171,8 @@ class SourceNode:
|
|||
return {
|
||||
"text": self.text,
|
||||
"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