77# For the full list of built-in configuration values, see the documentation: https://www.sphinx-doc.org/en/master/usage/configuration.html
88
99import os
10- import re
1110import subprocess
11+
1212from docutils import nodes
13+ from sphinx import addnodes
14+ from sphinx .util import logging
15+
1316
1417def get_version ():
1518 props_path = os .path .join (os .path .dirname (__file__ ), '..' , 'zip-content' , 'module.prop' )
@@ -21,6 +24,7 @@ def get_version():
2124 return line .replace ('version=' , '' ).lstrip ('v' ).strip ()
2225 return '0.0.0-unknown'
2326
27+
2428def get_revision ():
2529 # Try Read the Docs env vars first
2630 git_rev = os .environ .get ('READTHEDOCS_GIT_COMMIT_HASH' )
@@ -37,23 +41,52 @@ def get_revision():
3741 except Exception :
3842 return None
3943
40- def transform_doc_links (app , docname , source ):
41- """Phase 1: Convert local .rst links (no anchor) to :doc: roles."""
42- source [0 ] = re .sub (r'`([^`<]+)\s*<((?!http|mailto)[^>]+)\.rst>`_' , r':doc:`\1 <\2>`' , source [0 ])
4344
44- def fix_anchors_in_tree (app , doctree , docname ):
45- """Phase 2: Fix local .rst#anchor links in the resolved tree."""
46- ext = '.pdf' if app .builder .name == 'latex' else '.html'
47- for node in doctree .traverse (nodes .reference ):
48- uri = node .get ('refuri' )
49- if uri and '.rst#' in uri and not uri .startswith (('http' , 'mailto' )):
50- node ['refuri' ] = uri .replace ('.rst#' , f'{ ext } #' )
45+ def transform_rst_links (app , doctree ):
46+ """
47+ Automatically converts internal .rst file links to Sphinx cross-references
48+ (:doc: or :ref:), enabling validation and proper path resolution.
49+ """
50+
51+ docname = app .env .docname
52+ # Traverse only reference nodes that have a 'refuri' attribute
53+ for node in doctree .findall (nodes .reference ):
54+ uri = node .get ('refuri' , '' )
55+ if '.rst' not in uri or uri .startswith (('http' , 'mailto:' , '//' )):
56+ continue
57+
58+ parts = uri .split ('#' , 1 )
59+ has_anchor = len (parts ) > 1
60+ reftype = 'ref' if has_anchor else 'doc'
61+ reftarget = parts [1 ] if has_anchor else parts [0 ].removesuffix ('.rst' )
62+ logger .info (f"[DEBUG] Converting { uri } -> :{ reftype } :`{ reftarget } `" )
63+
64+ # Create pending_xref node which Sphinx resolves during build phase
65+ new_node = addnodes .pending_xref (
66+ '' ,
67+ reftype = reftype ,
68+ refdomain = 'std' ,
69+ reftarget = reftarget ,
70+ refdoc = docname ,
71+ refwarn = True ,
72+ refexplicit = True
73+ )
74+ # Transfer children (the link text) and replace the original node
75+ new_node .extend (node .children )
76+ node .replace_self (new_node )
77+
5178
5279def setup (app ):
53- # Process text before parsing
54- app .connect ('source-read' , transform_doc_links )
55- # Process nodes after tree is built
56- app .connect ('doctree-resolved' , fix_anchors_in_tree )
80+ # Hook to modify the document structure before rendering
81+ app .connect ('doctree-read' , transform_rst_links )
82+ return {
83+ 'version' : '0.1' ,
84+ 'parallel_read_safe' : True ,
85+ 'parallel_write_safe' : True
86+ }
87+
88+
89+ logger = logging .getLogger (__name__ )
5790
5891# Project information
5992project = 'Google sync add-on'
@@ -95,3 +128,11 @@ def setup(app):
95128 'github_version' : 'main' ,
96129 'conf_py_path' : '/docs/'
97130}
131+
132+ # Options for LaTeX output (e.g., PDF)
133+ if 'latex_elements' not in locals ():
134+ latex_elements = {}
135+
136+ # The 'openany' option allows chapters to begin on the next available page;
137+ # this prevents unwanted blank pages by allowing starts on even or odd pages
138+ latex_elements ['extraclassoptions' ] = (latex_elements .get ('extraclassoptions' , '' ) + ',openany' ).strip (',' )
0 commit comments