diff --git a/src/dragonglass/mparse.py b/src/dragonglass/mparse.py index 23c3592..e9a09d8 100644 --- a/src/dragonglass/mparse.py +++ b/src/dragonglass/mparse.py @@ -325,6 +325,8 @@ class ObsidianLinks(Extension): if not text: text = contents if node: + # record a backlink from the current node to the found one + node.backlinks.add(self._context.current_node) return node.link_target(self._context.url_prefix, self._context.current_node if self._context.relative_links else None), text return None, text diff --git a/src/dragonglass/template.py b/src/dragonglass/template.py index 0e1fb23..309d79e 100644 --- a/src/dragonglass/template.py +++ b/src/dragonglass/template.py @@ -12,8 +12,7 @@ from .tree import SourceNode """The default template used to render Markdown data.""" -DEFAULT_TEMPLATE = """ - +DEFAULT_TEMPLATE = """ {{ title }} @@ -21,6 +20,19 @@ DEFAULT_TEMPLATE = """

{{ title }}

{{ text }} + {% if backlinks|length > 0 %} +
+
+ Links to this page +
+ + {% endif %} """ @@ -68,6 +80,13 @@ def template_vars(node: SourceNode, ctxt: Context) -> dict[str, Any]: """ tvars = node.make_vars() + # Compute backlinks for this node. + backlinks = sorted(node.backlinks, key=lambda n: n.page_title) + tvars['backlinks'] = [{'title': n.page_title, + 'link': n.link_target(ctxt.url_prefix, node if ctxt.relative_links else None)} + for n in backlinks] + + # Add reference to the default stylesheet. if ctxt.relative_links: stylesheet_path = ctxt.source_dir / STYLESHEET_NAME rel_path = ctxt.source_dir / node.path diff --git a/src/dragonglass/tree.py b/src/dragonglass/tree.py index 8e0d6ba..8d0d745 100644 --- a/src/dragonglass/tree.py +++ b/src/dragonglass/tree.py @@ -29,6 +29,7 @@ class SourceNode: Attributes: metadata (dict[str, Any]): The metadata from the current node. text (str): The parsed HTML text of the current node. + backlinks (set[SourceNode]): Set of nodes that link to this one. """ def __init__(self, root: Path, path: Path, is_dir: bool) -> None: """ @@ -45,6 +46,7 @@ class SourceNode: self._is_md = path.match(MARKDOWN_PAT) self.metadata: dict[str, Any] = {} self.text: str | None = None + self.backlinks: set[Any] = set() def __str__(self) -> str: """Returns the string representation of the nmode.""" @@ -70,6 +72,11 @@ class SourceNode: """Returns the root path this node is under.""" return self._root + @property + def page_title(self) -> str: + """Returns the standard page title for this node.""" + return self._path.stem + def target_file(self, dest_dir: Path) -> Path: """ Computes the path of the target file as it will be written to the destination directory. @@ -143,7 +150,7 @@ class SourceNode: """ return { "text": self.text, - "title": self._path.stem + "title": self.page_title }