1919from sphinx .util import logging
2020from sphinx .util .fileutil import copy_asset
2121from .directive import ExerciseDirective , SolutionDirective
22- import docutils
2322from .local_nodes import (
2423 enumerable_node ,
2524 unenumerable_node ,
@@ -97,31 +96,12 @@ def doctree_read(app: Sphinx, document: Node) -> None:
9796
9897 # If solution node
9998 if is_linked_node (node ):
100- target_labelid = node .get ("target_label" , "" )
101- target_attr = app .env .exercise_list .get (target_labelid , {})
102- target_node = target_attr .get ("node" , Node )
103- target_title = target_attr .get ("title" , "" )
10499 sectname = "Solution to "
105-
106- # If target node is unenumerable, fix title
107- if is_unenumerable_node (target_node ):
108- # If title exists, append to sectname
109- # note that math role has already been
110- # introduced
111- if target_title :
112- sectname += target_title
113- else :
114- # If node doesn't have a title,
115- # append "Exercise"
116- sectname += "Exercise"
117- # # If node is enumerable, target node number hasn't been assigned
118- # yet so the replacing of the sectname of enumerable_targets
119- # should take place during doctree-resolve.
120100 else :
121101 # If other node, simply add :math: to title
122102 # to allow for easy parsing in ref_node
123103 for item in node [0 ]:
124- if item . __class__ == docutils . nodes .math :
104+ if isinstance ( item , nodes .math ) :
125105 sectname += f":math:`{ item .astext ()} ` "
126106 continue
127107 sectname += f"{ item .astext ()} "
@@ -186,7 +166,7 @@ def _update_linked_node_title(self, node):
186166 # Remove parans
187167 title = target_node [0 ]
188168
189- if len (title ) == 1 and self . _is_node_type (title [0 ], nodes .Text ):
169+ if len (title ) == 1 and isinstance (title [0 ], nodes .Text ):
190170 _ = (
191171 title [0 ]
192172 .replace ("Exercise" , "" )
@@ -224,17 +204,17 @@ def _update_linked_node_title(self, node):
224204 def _update_title (self , title ):
225205 inline = nodes .inline ()
226206
227- if len (title ) == 1 and self . _is_node_type (title [0 ], nodes .Text ):
207+ if len (title ) == 1 and isinstance (title [0 ], nodes .Text ):
228208 _ = title [0 ][0 ].replace ("(" , "" ).replace (")" , "" )
229209 inline += nodes .Text (_ , _ )
230210 else :
231211 for ii in range (len (title )):
232212 item = title [ii ]
233213
234- if ii == 0 and self . _is_node_type (item , nodes .Text ):
214+ if ii == 0 and isinstance (item , nodes .Text ):
235215 _ = item .replace ("Exercise" , "" ).replace ("(" , "" ).lstrip ()
236216 title .replace (title [ii ], nodes .Text (_ , _ ))
237- elif ii == len (title ) - 1 and self . _is_node_type (item , nodes .Text ):
217+ elif ii == len (title ) - 1 and isinstance (item , nodes .Text ):
238218 _ = item .replace (")" , "" ).rstrip ()
239219 if _ :
240220 title .replace (title [ii ], nodes .Text (_ , _ ))
@@ -244,6 +224,12 @@ def _update_title(self, title):
244224
245225 return inline
246226
227+ def _has_math_child (self , node ):
228+ for item in node :
229+ if isinstance (item , nodes .math ):
230+ return True
231+ return False
232+
247233 def _update_ref (self , node : Node , labelid : str ) -> None :
248234 source_attr = self .env .exercise_list [labelid ]
249235 source_node = source_attr .get ("node" , Node )
@@ -254,28 +240,28 @@ def _update_ref(self, node: Node, labelid: str) -> None:
254240 target_attr = self .env .exercise_list [target_labelid ]
255241 target_node = target_attr .get ("node" , Node )
256242
257- # TODO: fix node.astext()
258243 if is_enumerable_node (target_node ) and node .astext () == default_title :
259244 node .replace (node [0 ], source_node [0 ][0 ][0 ])
260245 return
261246
262- # TODO: fix ":math:"
263- if (
264- is_unenumerable_node (target_node )
265- and target_attr
266- and ":math:" in node .astext ()
267- ):
268- title = self ._update_title (target_node [0 ])
269- title .insert (0 , nodes .Text (default_title , default_title ))
270- node .replace (node [0 ], title )
247+ if is_unenumerable_node (target_node ) and node .astext () == default_title :
248+ if target_attr .get ("title" ):
249+ if self ._has_math_child (target_node [0 ]):
250+ title = self ._update_title (target_node [0 ])
251+ title .insert (0 , nodes .Text (default_title , default_title ))
252+ node .replace (node [0 ], title )
253+ else :
254+ text = target_attr .get ("title" , "" )
255+ node [0 ].insert (len (node [0 ]), nodes .Text (text , text ))
256+ else :
257+ node [0 ].insert (len (node [0 ]), nodes .Text ("Exercise" , "Exercise" ))
271258 else :
272259 # If no node.astext() simply add "Exercise"
273260 if is_enumerable_node (source_node ) and not node .astext ():
274261 text = nodes .Text ("Exercise" , "Exercise" )
275262 node [0 ].insert (0 , text )
276263 return
277264
278- # TODO: fix ":math:"
279265 if ":math:" in node .astext ():
280266 title = self ._update_title (source_node [0 ])
281267 node .replace (node [0 ], title )
@@ -285,11 +271,38 @@ def _update_numref(self, node, labelid):
285271 source_node = source_attr .get ("node" , Node )
286272 node_title = node .get ("title" , "" )
287273
288- if node_title and ":math:" in node .astext () and "{name}" in node_title :
289- title = self ._update_title (source_node [0 ])
290- _ = node_title [: node_title .find ("{name}" )]
291- title .insert (0 , nodes .Text (_ , _ ))
292- node .replace (node [0 ], title )
274+ if "{name}" in node_title and self ._has_math_child (source_node [0 ]):
275+
276+ newtitle = nodes .inline ()
277+ for item in node_title .split ():
278+ if item == "{name}" :
279+ for _ in self ._update_title (source_node [0 ]):
280+ newtitle += _
281+ elif item == "{number}" or item == "%s" :
282+ source_docname = source_attr .get ("docname" , "" )
283+ source_type = self .domain .get_enumerable_node_type (source_node )
284+ source_number = self .domain .get_fignumber (
285+ self .env , self .builder , source_type , source_docname , source_node
286+ )
287+ source_num = "." .join (map (str , source_number ))
288+ newtitle += nodes .Text (source_num , source_num )
289+ else :
290+ newtitle += nodes .Text (item , item )
291+ newtitle += nodes .Text (" " , " " )
292+
293+ if newtitle [len (newtitle ) - 1 ].astext () == " " :
294+ newtitle .pop ()
295+ node .replace (node [0 ], newtitle )
296+
297+ def _get_refuri (self , node ):
298+ id_ = ""
299+ if node .get ("refuri" , "" ):
300+ id_ = node .get ("refuri" , "" )
301+
302+ if node .get ("refid" , "" ):
303+ id_ = node .get ("refid" , "" )
304+
305+ return id_ .split ("#" )[- 1 ]
293306
294307 def process (self , doctree : nodes .document , docname : str ) -> None :
295308
@@ -301,18 +314,17 @@ def process(self, doctree: nodes.document, docname: str) -> None:
301314 for node in doctree .traverse ():
302315
303316 # If node type is ref
304- if self . _is_node_type (node , nodes .reference ):
305- labelid = node . get ( "refuri" , "" ). split ( "#" )[ - 1 ]
317+ if isinstance (node , nodes .reference ):
318+ labelid = self . _get_refuri ( node )
306319
307320 # If extension directive referenced
308321 if labelid in self .env .exercise_list :
309-
310322 # Update displayed href text
311323 self ._update_ref (node , labelid )
312324
313325 # If node type is numref
314- if self . _is_node_type (node , number_reference ):
315- labelid = node . get ( "refuri" , "" ). split ( "#" )[ - 1 ]
326+ if isinstance (node , number_reference ):
327+ labelid = self . _get_refuri ( node )
316328
317329 # If extension directive referenced
318330 if labelid in self .env .exercise_list :
0 commit comments