Skip to content

started of a domain #92

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 147 additions & 6 deletions src/sphinx_tags/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
"""Sphinx extension to create tags for documentation pages.

"""
from collections import defaultdict
from collections.abc import Iterable
import os
import re
from fnmatch import fnmatch
from pathlib import Path
from typing import List
from typing import List, Any

from docutils import nodes
from docutils.nodes import Element
from docutils.parsers.rst import directives

from sphinx import addnodes
from sphinx.addnodes import desc_signature
from sphinx.directives import ObjectDescription
from sphinx.domains import Domain, Index, IndexEntry
from sphinx.roles import XRefRole

from sphinx.util.nodes import make_refnode
from sphinx.errors import ExtensionError
from sphinx.util.docutils import SphinxDirective
from sphinx.util.logging import getLogger
Expand All @@ -17,8 +29,15 @@

logger = getLogger("sphinx-tags")

"""
https://www.sphinx-doc.org/en/master/development/tutorials/recipe.html

page \\approx recipie
tag \\approx
"""


class TagLinks(SphinxDirective):
class TagLinks(ObjectDescription):
"""Custom directive for adding tags to Sphinx-generated files.

Loosely based on https://stackoverflow.com/questions/18146107/how-to-add-blog-style-tags-in-restructuredtext-with-sphinx
Expand All @@ -36,7 +55,21 @@ class TagLinks(SphinxDirective):
# Custom attributes
separator = ","

def run(self):
def get_signatures(self) -> list[str]:
# signature can be none, instead identify using doc name
return []

def handle_signature(self, sig: str, signode: desc_signature) -> Any:
print(f"sig:{sig} {signode}")

signode += addnodes.desc_name(text=self.env.docname)
return sig

def add_target_and_index(
self, name: Any, sig: str, signode: desc_signature
) -> None:
signode["ids"].append(f"tagpage-{sig}")

if not (self.arguments or self.content):
raise ExtensionError("No tags passed to 'tags' directive.")

Expand All @@ -58,6 +91,7 @@ def run(self):
current_doc_dir = Path(self.env.doc2path(self.env.docname)).parent
relative_tag_dir = Path(os.path.relpath(tag_dir, current_doc_dir))

# this probably gets moved to tag index
for tag in tags:
count += 1
# We want the link to be the path to the _tags folder, relative to
Expand All @@ -83,7 +117,8 @@ def run(self):
# register tags to global metadata for document
self.env.metadata[self.env.docname]["tags"] = tags

return [result]
td = self.env.get_domain("tag")
td.add_tagpage(self.env.docname, tags)

def _get_plaintext_node(
self, tag: str, file_basename: str, relative_tag_dir: Path
Expand Down Expand Up @@ -125,6 +160,111 @@ def _get_tag_color(self, tag: str) -> str:
return "primary"


class TagsIndex(Index):
"""A custom index that creates a tags matrix."""

name = "tag"
localname = "Tag Index"
shortname = "Tag"

def generate(
self, docnames: Iterable[str] | None = None
) -> tuple[list[tuple[str, list[IndexEntry]]], bool]:
content = defaultdict(list)

pages = {
name: (dispname, typ, docname, anchor)
for name, dispname, typ, docname, anchor, _ in self.domain.get_objects()
}
pages_tags = self.domain.data["tags"]

tags_pages = defaultdict(list)

# create tag->pages mapping
for page_name, tags in pages_tags.items():
for tag in tags:
tags_pages[tag].append(page_name)

# create specific output
for tag, page_names in tags_pages.items():
for page_name in page_names:
dispname, typ, docname, anchor = pages[page_name]
content[tag].append(dispname, 0, docname, anchor, docname, "", typ)

# convert the dict to the sorted list of tuples expected

return sorted(content.items()), True


class PagesIndex(Index):
"""A custom index that creates a pages matrix."""

name = "tagpage"
localname = "Page Index"
shortname = "TagPage"

def generate(
self, docnames: Iterable[str] | None = None
) -> tuple[list[tuple[str, list[IndexEntry]]], bool]:
content = defaultdict(list)

# sort the list of pages
pages = sorted(self.domain.get_objects(), key=lambda page: page[0])

# name, subtype, docname, anchor, extra, qualifier, description

for _name, dispname, typ, docname, anchor, _priority in pages:
content[dispname[0].lower()].append(
(dispname, 0, docname, anchor, docname, "", typ)
)

# convert the dict to the sorted list of tuples expected

return sorted(content.items()), True


class TagDomain(Domain):
name = "tag"
roles = {"ref": XRefRole()}
directives = {"tags": TagLinks}
initial_data = {
"pages": [], # pages list
"tags": {}, # name -> tags
}

def get_full_qualified_name(self, node: Element) -> str | None:
return f"tagpage.{node.arguments[0]}"

def get_objects(self) -> Iterable[tuple[str, str, str, str, str, int]]:
yield from self.data["pages"]

def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
match = [
(docname, anchor)
for name, sig, typ, docname, anchor, prio in self.get_objects()
if sig == target
]

if len(match) > 0:
todocname = match[0][0]
targ = match[0][1]
return make_refnode(builder, fromdocname, todocname, targ, contnode, targ)
else:
logger.info(f"Found nothing: {fromdocname}->{target}")
return None

def add_tagpage(self, docname, tags):
"""Add a new page of tags to domain"""
name = f"tagpage.{docname}"
anchor = f"tagpage-{docname}"

self.data["tags"][name] = tags
# name, dispname, type, docname, anchor, priority
self.data["pages"].append(
(name, docname, "TagPage", self.env.docname, anchor, 0)
)


class Tag:
"""A tag contains entries"""

Expand Down Expand Up @@ -375,8 +515,9 @@ def setup(app):
# TODO: tags should be updated after sphinx-gallery is generated, and the
# gallery is also connected to builder-inited. Are there situations when
# this will not work?
app.connect("builder-inited", update_tags)
app.add_directive("tags", TagLinks)
app.add_domain(TagDomain)
# app.connect("builder-inited", update_tags)
# app.add_directive("tags", TagLinks)

return {
"version": __version__,
Expand Down
3 changes: 2 additions & 1 deletion test/sources/test-ipynb/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ Test document

Test ref
--------
:ref:`sphx_tag_tag_1`
`tag_1`
.. :ref:`sphx_tag_tag_1`
2 changes: 1 addition & 1 deletion test/sources/test-ipynb/page_1.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"tags": []
},
"source": [
".. tags:: tag_1, tag2, tag 3, [{(tag 4)}]"
".. tag:tags:: tag_1, tag2, tag 3, [{(tag 4)}]"
]
}
],
Expand Down
2 changes: 1 addition & 1 deletion test/sources/test-ipynb/page_2.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"tags": []
},
"source": [
".. tags:: tag_1, tag_5, {{🧪test tag; please ignore🧪}}"
".. tag:tags:: tag_1, tag_5, {{🧪test tag; please ignore🧪}}"
]
}
],
Expand Down
4 changes: 2 additions & 2 deletions test/sources/test-ipynb/page_5.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
"cell_type": "raw",
"metadata": {
"raw_mimetype": "text/restructuredtext",
"tags":[]
"tags": []
},
"source": [
".. tags:: \n",
".. tag:tags:: \n",
"\n",
" tag_1, tag_5, \n",
" tag2, \n",
Expand Down
2 changes: 1 addition & 1 deletion test/sources/test-ipynb/subdir/page_3.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"tags": []
},
"source": [
".. tags:: tag 3"
".. tag:tags:: tag 3"
]
}
],
Expand Down
2 changes: 1 addition & 1 deletion test/sources/test-myst/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ _tags/tagsindex
```

## Test ref
{ref}`sphx_tag_tag_1`
`tag_1`
2 changes: 1 addition & 1 deletion test/sources/test-myst/page_1.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Page 1
```{tags} tag_1, tag2, tag 3, [{(tag 4)}]
```{tag:tags} tag_1, tag2, tag 3, [{(tag 4)}]
```
2 changes: 1 addition & 1 deletion test/sources/test-myst/page_2.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Page 2
```{tags} tag_1, tag_5, {{🧪test tag; please ignore🧪}}
```{tag:tags} tag_1, tag_5, {{🧪test tag; please ignore🧪}}
```
2 changes: 1 addition & 1 deletion test/sources/test-myst/page_5.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Page 5
```{tags}
```{tag:tags}
tag_1, tag_5,
tag2,
tag 3, [{(tag 4)}]
Expand Down
2 changes: 1 addition & 1 deletion test/sources/test-myst/subdir/page_3.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Page 3
```{tags} tag 3
```{tag:tags} tag 3
```
5 changes: 4 additions & 1 deletion test/sources/test-rst/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@ Test document
Test ref
--------

:ref:`sphx_tag_tag_1`
`tag_1`


.. :ref:`sphx_tag_tag_1`
2 changes: 1 addition & 1 deletion test/sources/test-rst/page_1.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Page 1
======
.. tags:: tag_1, tag2, tag 3, [{(tag 4)}]
.. tag:tags:: tag_1, tag2, tag 3, [{(tag 4)}]
2 changes: 1 addition & 1 deletion test/sources/test-rst/page_2.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Page 2
======
.. tags:: tag_1, tag_5, {{🧪test tag; please ignore🧪}}
.. tag:tags:: tag_1, tag_5, {{🧪test tag; please ignore🧪}}
2 changes: 1 addition & 1 deletion test/sources/test-rst/page_5.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Page 5
======
.. tags::
.. tag:tags::

tag_1, tag_5,
tag2,
Expand Down
2 changes: 1 addition & 1 deletion test/sources/test-rst/subdir/page_3.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Page 3
======
.. tags:: tag 3
.. tag:tags:: tag 3