88from sphinx .errors import ExtensionError
99from sphinx .util .rst import textwidth
1010
11+ # from sphinx.addnodes import pending_xref
12+ from sphinx .builders import Builder
13+
1114from pathlib import Path
1215from docutils import nodes
1316import os
@@ -71,22 +74,18 @@ def run(self):
7174 for tag in "," .join (self .content ).split ("," )
7275 ]
7376 )
77+
7478 # Remove empty elements from page_tags
7579 # (can happen after _normalize_tag())
7680 page_tags = list (filter (None , page_tags ))
77-
78- # Leftover code from previous attempt:
79- #settings = frontend.get_default_settings(Parser)
80- #document = utils.new_document("tags", settings)
81- #tags = Parser().parse(tagline, document)
82- #print(f"Tags: {tags}")
83-
8481 global_tags = self .env .get_domain ("tags" )
8582 # Append this document to the list of documents containing this tag
8683 for tag in page_tags :
8784 global_tags .add_tag (tag , self .env .docname )
8885
8986 tag_dir = Path (self .env .app .srcdir ) / self .env .app .config .tags_output_dir
87+
88+ # sphinx.addnodes.pending_xref(rawsource="", *children, **attributes)
9089 result = nodes .paragraph ()
9190 result ["classes" ] = ["tags" ]
9291 result += nodes .inline (text = f"{ self .env .app .config .tags_intro_text } " )
@@ -126,6 +125,7 @@ def _get_plaintext_node(
126125 ) -> List [nodes .Node ]:
127126 """Get a plaintext reference link for the given tag"""
128127 link = relative_tag_dir / f"{ file_basename } .html"
128+ # return pending_xref(refuri=str(link), text=tag)
129129 return nodes .reference (refuri = str (link ), text = tag )
130130
131131 def _get_badge_node (
@@ -139,7 +139,7 @@ def _get_badge_node(
139139 text_nodes , messages = self .state .inline_text ("" , self .lineno )
140140
141141 # Ref paths always use forward slashes, even on Windows
142- tag_ref = f"{ tag } <{ relative_tag_dir .as_posix ()} /{ file_basename } >"
142+ tag_ref = f"{ tag } <{ relative_tag_dir .as_posix ()} /{ file_basename } .html >"
143143 tag_color = self ._get_tag_color (tag )
144144 tag_badge = XRefBadgeRole (tag_color )
145145 return tag_badge (
@@ -161,12 +161,14 @@ def _get_tag_color(self, tag: str) -> str:
161161 return "primary"
162162
163163
164- class PagesIndex (Index ):
165- """A custom index that creates a pages matrix."""
164+ class TagsIndex (Index ):
165+ """A custom index that creates a page with all tags and corresponding pages
166+ where they are defined.
167+ """
166168
167- name = "tagpage "
168- localname = "Page Index "
169- shortname = "TagPage "
169+ name = "index "
170+ localname = "All tags "
171+ shortname = "TagsIndex "
170172
171173 def generate (
172174 self , docnames : Iterable [str ] | None = None
@@ -177,14 +179,12 @@ def generate(
177179 pages = sorted (self .domain .get_objects (), key = lambda page : page [0 ])
178180
179181 # name, subtype, docname, anchor, extra, qualifier, description
180-
181182 for _name , dispname , typ , docname , anchor , _priority in pages :
182183 content [dispname [0 ].lower ()].append (
183184 (dispname , 0 , docname , anchor , docname , "" , typ )
184185 )
185186
186187 # convert the dict to the sorted list of tuples expected
187-
188188 return sorted (content .items ()), True
189189
190190
@@ -199,7 +199,7 @@ class TagsDomain(Domain):
199199 "tags" : TagLinks ,
200200 }
201201
202- indices = [PagesIndex ]
202+ indices = [TagsIndex ]
203203
204204 # The values defined in initial_data will be copied to
205205 # env.domaindata[domain_name] as the initial data of the domain, and domain
@@ -211,7 +211,7 @@ class TagsDomain(Domain):
211211 }
212212
213213 def get_full_qualified_name (self , node ):
214- print (f"Node: { node } " )
214+ # print(f"Node: {node}")
215215 return f"tags.{ node .arguments [0 ]} "
216216
217217 def get_objects (self ):
@@ -230,21 +230,35 @@ def add_tag(self, tagname, page):
230230 # Add this tag to the global list of tags
231231 # name, dispname, type, docname, anchor, priority
232232 self .data ["tags" ].append ((tagname , tagname , "Tag" , page , anchor , 0 ))
233+ # Create pages for each tag
234+ create_file (
235+ (tagname , self .data ["entries" ][tagname ]),
236+ # self.app.config.tags_extension,
237+ ".md" ,
238+ # Path(self.app.config.tags_output_dir),
239+ Path ("_tags" ),
240+ # self.app.srcdir,
241+ Path ("docs" ),
242+ # self.app.config.tags_page_title,
243+ "My tags" ,
244+ # self.app.config.tags_page_header,
245+ "With this tag" ,
246+ # self.app.config.tags_intro_text
247+ "Tags:" ,
248+ )
233249
234250 def add_tagpage (self , docname , tags ):
235251 """Add a new page of tags to domain"""
236- name = f"tagpage .{ docname } "
237- anchor = f"tagpage -{ docname } "
252+ name = f"index .{ docname } "
253+ anchor = f"index -{ docname } "
238254
239- print (f"{ self .data ['tags' ]= } " )
240255 # name, dispname, type, docname, anchor, priority
241256 self .data ["pages" ].append (
242- (name , docname , "TagPage " , self .env .docname , anchor , 0 )
257+ (name , docname , "TagsIndex " , self .env .docname , anchor , 0 )
243258 )
244259
245260
246261def create_file (
247- app ,
248262 tag : tuple ,
249263 extension : List [str ],
250264 tags_output_dir : Path ,
@@ -278,17 +292,11 @@ def create_file(
278292 the words after which the pages with the tag are listed (e.g. "With this tag: Hello World")
279293 tag_intro_text: str
280294 the words after which the tags of a given page are listed (e.g. "Tags: programming, python")
281-
282- self.tags = []
283- if tagblock:
284- self.tags = [_normalize_display_tag(tag) for tag in tagblock if tag]
285-
286295 """
287296
288- name = tag [0 ]
289- file_basename = _normalize_tag (tag [0 ], dashes = True )
290-
291297 # Get sorted file paths for tag pages, relative to /docs/_tags
298+ file_basename = _normalize_tag (tag [0 ], dashes = True )
299+ name = _normalize_display_tag (tag [0 ])
292300 tag_page_paths = sorted ([os .path .relpath (i , srcdir ) for i in tag [1 ]])
293301 ref_label = f"sphx_tag_{ file_basename } "
294302
@@ -355,10 +363,6 @@ def tagpage(tags, outdir, title, extension, tags_index_head):
355363 This page contains a list of all available tags.
356364
357365 """
358-
359- print (f"Tags: { tags = } " )
360- print (f"outdir: { outdir = } " )
361-
362366 if "md" in extension :
363367 content = []
364368 content .append ("(tagoverview)=" )
@@ -371,9 +375,7 @@ def tagpage(tags, outdir, title, extension, tags_index_head):
371375 content .append (f"caption: { tags_index_head } " )
372376 content .append ("maxdepth: 1" )
373377 content .append ("---" )
374- for name , pages in tags .items ():
375- file_basename = _normalize_tag (name , dashes = True )
376- content .append (f"{ name } ({ len (pages )} ) <{ file_basename } >" )
378+ content .append ("PLACEHOLDER" )
377379 content .append ("```" )
378380 content .append ("" )
379381 filename = os .path .join (outdir , "tagsindex.md" )
@@ -391,61 +393,77 @@ def tagpage(tags, outdir, title, extension, tags_index_head):
391393 content .append (f" :caption: { tags_index_head } " )
392394 content .append (" :maxdepth: 1" )
393395 content .append ("" )
394- for name , pages in tags .items ():
395- file_basename = _normalize_tag (name , dashes = True )
396- content .append (f" { name } ({ len (pages )} ) <{ file_basename } .rst>" )
396+ content .append ("" ) # placeholder
397397 content .append ("" )
398398 filename = os .path .join (outdir , "tagsindex.rst" )
399399
400400 with open (filename , "w" , encoding = "utf8" ) as f :
401401 f .write ("\n " .join (content ))
402402
403403
404- def update_tags (app ):
404+ def update_tags (app , env ):
405405 """Update tags according to pages found"""
406406 if app .config .tags_create_tags :
407407 tags_output_dir = Path (app .config .tags_output_dir )
408-
409- if not os .path .exists (os .path .join (app .srcdir , tags_output_dir )):
410- os .makedirs (os .path .join (app .srcdir , tags_output_dir ))
411-
412- for file in os .listdir (os .path .join (app .srcdir , tags_output_dir )):
413- if file .endswith ("md" ) or file .endswith ("rst" ):
414- os .remove (os .path .join (app .srcdir , tags_output_dir , file ))
415-
416408 # Create pages for each tag
417409 global_tags = app .env .get_domain ("tags" ).data ["entries" ]
418- logger .info (f"Global tags: { global_tags = } " , color = "green" )
419-
420- for tag in global_tags .items ():
421- create_file (
422- app ,
423- tag ,
424- app .config .tags_extension ,
425- tags_output_dir ,
426- app .srcdir ,
427- app .config .tags_page_title ,
428- app .config .tags_page_header ,
429- app .config .tags_intro_text ,
410+ # Inject these into found_docs
411+ for docname , tags in global_tags .items ():
412+ env .found_docs .add (docname )
413+ # Inject these into the tagsindex
414+ tags_output_dir = Path (app .config .tags_output_dir )
415+ outdir = os .path .join (app .srcdir , tags_output_dir )
416+ newcontent = []
417+ if "md" in app .config .tags_extension :
418+ filename = os .path .join (outdir , "tagsindex.md" )
419+ taglist = "{name} ({len}) <{file_basename}>"
420+ else :
421+ filename = os .path .join (outdir , "tagsindex.rst" )
422+ taglist = " {name} ({len}) <{file_basename}.rst>"
423+
424+ for name , pages in global_tags .items ():
425+ file_basename = _normalize_tag (name , dashes = True )
426+ newcontent .append (
427+ taglist .format (name = name , len = len (pages ), file_basename = file_basename )
430428 )
429+ with open (filename , "r" , encoding = "utf8" ) as f :
430+ content = f .read ()
431+ with open (filename , "w" , encoding = "utf8" ) as f :
432+ f .write (content .replace ("PLACEHOLDER" , "\n " .join (newcontent )))
433+ else :
434+ logger .info (
435+ "Tags were not created (tags_create_tags=False in conf.py)" , color = "white"
436+ )
437+ logger .info ("Tags updated" , color = "white" )
438+
439+ # Re-read files, create doctrees and add to env.found_docs and return
440+ # iterable of docnames to re-read for env-get-updated
441+ app .builder .read ()
442+ return env .found_docs
443+
444+
445+ def prepare_tags (app ):
446+ if app .config .tags_create_tags :
447+ tags_output_dir = Path (app .config .tags_output_dir )
448+
449+ if not os .path .exists (os .path .join (app .srcdir , tags_output_dir )):
450+ os .makedirs (os .path .join (app .srcdir , tags_output_dir ))
431451
432452 # Create tags overview page
433453 tagpage (
434- global_tags ,
454+ [] ,
435455 os .path .join (app .srcdir , tags_output_dir ),
436456 app .config .tags_overview_title ,
437457 app .config .tags_extension ,
438458 app .config .tags_index_head ,
439459 )
440- logger .info ("Tags updated" , color = "white" )
460+
461+ logger .info ("Tags output dir created" , color = "green" )
441462 else :
442463 logger .info (
443- "Tags were not created (tags_create_tags=False in conf.py)" , color = "white "
464+ "Tags were not created (tags_create_tags=False in conf.py)" , color = "red "
444465 )
445466
446- # Return iterable of docnames to re-read
447- return os .listdir (os .path .join (app .srcdir , tags_output_dir ))
448-
449467
450468def setup (app ):
451469 """Setup for Sphinx."""
@@ -473,10 +491,10 @@ def setup(app):
473491 "html" ,
474492 )
475493
476- # Update tags
477494 # Tags should be updated after sphinx-gallery is generated, on
478495 # builder-inited
479- app .connect ("builder-inited" , update_tags )
496+ app .connect ("builder-inited" , prepare_tags )
497+ app .connect ("env-get-updated" , update_tags )
480498 app .add_directive ("tags" , TagLinks )
481499 app .add_domain (TagsDomain )
482500
0 commit comments