77"""
88
99from __future__ import annotations
10+ from logging import warning
1011from typing import Any , cast
1112from textwrap import dedent
1213
@@ -59,10 +60,13 @@ class DataNode(nodes.Node):
5960 template : Template
6061 schema : Schema
6162
62- class pending_data_node (DataNode , nodes .Invisible , nodes .Element ):
63+ class pending_data_node (DataNode , nodes .Invisible , nodes .meta ):
6364 need_external_data : bool = False
6465
6566 def render (self , caller : SphinxDirective | SphinxTransform , replace : bool = False ) -> rendered_data_node :
67+ if self .need_external_data :
68+ self ._complete_external_data ()
69+
6670 try :
6771 parsed = self .schema .parse (self .data )
6872 except ValueError as e :
@@ -91,6 +95,17 @@ def render(self, caller: SphinxDirective | SphinxTransform, replace: bool = Fals
9195
9296 return rendered
9397
98+ def _complete_external_data (self ):
99+ if not self .data .name :
100+ if title := find_titular_node_upward (self .parent ):
101+ self .data .name = title .astext ()
102+
103+ if not self .data .content :
104+ contnodes = []
105+ for i , child in enumerate (self .parent ):
106+ if child == self :
107+ contnodes = self .parent [i :]
108+ self .data .content = '\n \n ' .join ([n .astext () for n in contnodes ])
94109
95110
96111class rendered_data_node (DataNode , nodes .container ): ...
@@ -168,7 +183,7 @@ class DefineDirective(SphinxDirective):
168183 optional_arguments = 1
169184 has_content = True
170185
171- def extract_data (self ) -> Data :
186+ def _extract_data (self ) -> Data :
172187 return Data (
173188 self .arguments [0 ] if self .arguments else None ,
174189 self .options .copy (),
@@ -183,63 +198,55 @@ def current_schema(self) -> Schema:
183198 schema = self .env .current_document .get (SCHEMA_KEY , DEFAULT_SCHEMA )
184199 return cast (Schema , schema )
185200
186- def run (self ) -> list [ nodes . Node ] :
187- data = self .extract_data ()
201+ def new_pending_node (self ) -> pending_data_node :
202+ data = self ._extract_data ()
188203 tmpl = self .current_template ()
189204 schema = self .current_schema ()
190205
191206 n = pending_data_node ()
192207 self .set_source_info (n )
193208 n .data , n .template , n .schema = data , tmpl , schema
194209
195- if tmpl .phase != Phase .Parsing :
210+ return n
211+
212+ def run (self ) -> list [nodes .Node ]:
213+ n = self .new_pending_node ()
214+ if n .template .phase != Phase .Parsing :
196215 return [n ]
197216
198217 return [n .render (self )]
199218
200- class FreeDefineDirective (DefineDirective , FreeStyleDirective ): ...
201-
202- def complete_data (pending : pending_data_node ):
203- data = pending .data
204219
205- if data .content_missing :
206- contnodes = []
207- for i , child in enumerate (pending .parent ):
208- if child == pending :
209- contnodes = pending .parent [i :]
210- data .content = '\n \n ' .join ([n .astext () for n in contnodes ])
211- data .content_missing = False
220+ class FreeDefineDirective (DefineDirective , FreeStyleDirective ): ...
212221
213222
223+ class AutoDefineDirective (DefineDirective , FreeStyleDirective ):
224+ def new_pending_node (self ) -> pending_data_node :
225+ n = super ().new_pending_node ()
226+ n .need_external_data = True
227+ return n
214228
215229class ParsedHook (SphinxDirective ):
216230 def run (self ) -> list [nodes .Node ]:
217-
218231 # Save origin system_message method.
219232 orig_sysmsg = self .state_machine .reporter .system_message
220233
221234 for pending in self .state .document .findall (pending_data_node ):
235+ if pending .template .phase != Phase .Parsed :
236+ continue
237+
222238 # Hook system_message method to let it report the
223239 # correct line number.
224240 def sysmsg_fixed_lineno (level , message , * children , ** kwargs ):
225241 kwargs ['line' ] = pending .line
226242 return orig_sysmsg (level , message , * children , ** kwargs )
227243 self .state_machine .reporter .system_message = sysmsg_fixed_lineno
228244
229- data = pending .data
230-
231- if data .content_missing :
232- contnodes = []
233- for i , child in enumerate (pending .parent ):
234- if child == pending :
235- contnodes = pending .parent [i :]
236- data .content = '\n \n ' .join ([n .astext () for n in contnodes ])
237- data .content_missing = False
238-
239245 pending .render (self , replace = True )
240246
241247 # Restore system_message method.
242248 self .state_machine .reporter .system_message = orig_sysmsg
249+
243250 return [] # nothing to return
244251
245252def on_source_read (app , docname , content ):
@@ -255,6 +262,9 @@ class ResolvingHook(SphinxTransform):
255262
256263 def apply (self , ** kwargs ):
257264 for pending in self .document .findall (pending_data_node ):
265+ if pending .template .phase != Phase .Resolving :
266+ continue
267+
258268 pending .render (self , replace = True )
259269
260270
@@ -264,6 +274,7 @@ def setup(app: Sphinx):
264274 app .add_directive ('data:tmpl' , TemplateDirective , False )
265275 app .add_directive ('data:schema' , DataSchemaDirective , False )
266276 app .add_directive ('data:def' , FreeDefineDirective , False )
277+ app .add_directive ('data:autodef' , AutoDefineDirective , False )
267278 app .add_directive ('data:parsed-hook' , ParsedHook , False )
268279
269280 app .connect ('source-read' , on_source_read )
0 commit comments