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 = """
+ {% 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
}