1919logger = logging .getLogger (__name__ )
2020
2121
22- class ExerciseDirective (SphinxDirective ):
23- """ A custom Sphinx Directive """
22+ class CustomDirective (SphinxDirective ):
23+ """ A custom Sphinx directive """
2424
25- name = "exercise"
26- has_content = True
27- required_arguments = 0
28- optional_arguments = 1
29- final_argument_whitespace = True
30- option_spec = {
31- "label" : directives .unchanged_required ,
32- "class" : directives .class_option ,
33- "nonumber" : directives .flag ,
34- }
25+ name = ""
3526
3627 def run (self ) -> List [Node ]:
28+ if self .name == "solution" and self .env .app .config .hide_solutions :
29+ return []
30+
3731 serial_no = self .env .new_serialno ()
3832
3933 if not hasattr (self .env , "exercise_list" ):
4034 self .env .exercise_list = {}
4135
42- # Take care of class option
4336 classes , class_name = [self .name ], self .options .get ("class" , "" )
4437 if class_name :
4538 classes .extend (class_name )
4639
47- title_text , _ = "" , ""
48- if "nonumber" in self .options :
49- title_text = f"{ self .name .title ()} "
40+ title_text , title = "" , ""
41+ if self .name == "exercise" :
42+ if "nonumber" in self .options :
43+ title_text = f"{ self .name .title ()} "
5044
51- if self .arguments != []:
52- title_text += f"({ self .arguments [0 ]} )"
53- _ += self .arguments [0 ]
45+ if self .arguments != []:
46+ title_text += f"({ self .arguments [0 ]} )"
47+ title += self .arguments [0 ]
48+ else :
49+ title_text = f"{ self .name .title ()} to "
50+ target_label = self .arguments [0 ]
5451
5552 textnodes , messages = self .state .inline_text (title_text , self .lineno )
5653
5754 section = nodes .section (ids = [f"{ self .name } -content" ])
5855 self .state .nested_parse (self .content , self .content_offset , section )
5956
60- if "nonumber" in self .options :
61- node = unenumerable_node ()
57+ if self .name == "exercise" :
58+ if "nonumber" in self .options :
59+ node = unenumerable_node ()
60+ else :
61+ node = enumerable_node ()
6262 else :
63- node = enumerable_node ()
63+ node = linked_node ()
6464
6565 node += nodes .title (title_text , "" , * textnodes )
6666 node += section
@@ -88,21 +88,46 @@ def run(self) -> List[Node]:
8888 node ["ids" ].append (label )
8989 node ["label" ] = label
9090 node ["docname" ] = self .env .docname
91+ node ["hidden" ] = True if "hidden" in self .options else False
9192 node .document = self .state .document
9293
94+ if self .name == "solution" :
95+ node ["target_label" ] = target_label
96+
9397 self .add_name (node )
9498
9599 self .env .exercise_list [label ] = {
96100 "type" : self .name ,
97101 "docname" : self .env .docname ,
98102 "node" : node ,
99- "title" : _ ,
103+ "title" : title ,
104+ "hidden" : node .get ("hidden" , bool ),
100105 }
106+
107+ if node .get ("hidden" , bool ):
108+ return []
109+
101110 return [node ]
102111
103112
104- class SolutionDirective (SphinxDirective ):
105- """ A custom Sphinx Directive """
113+ class ExerciseDirective (CustomDirective ):
114+ """ A custom exercise directive """
115+
116+ name = "exercise"
117+ has_content = True
118+ required_arguments = 0
119+ optional_arguments = 1
120+ final_argument_whitespace = True
121+ option_spec = {
122+ "label" : directives .unchanged_required ,
123+ "class" : directives .class_option ,
124+ "nonumber" : directives .flag ,
125+ "hidden" : directives .flag ,
126+ }
127+
128+
129+ class SolutionDirective (CustomDirective ):
130+ """ A custom solution directive """
106131
107132 name = "solution"
108133 has_content = True
@@ -112,65 +137,5 @@ class SolutionDirective(SphinxDirective):
112137 option_spec = {
113138 "label" : directives .unchanged_required ,
114139 "class" : directives .class_option ,
140+ "hidden" : directives .flag ,
115141 }
116- title_text = f"{ name .title ()} to "
117-
118- def run (self ):
119- serial_no = self .env .new_serialno ()
120-
121- if not hasattr (self .env , "exercise_list" ):
122- self .env .exercise_list = {}
123-
124- # Take care of class option
125- classes , class_name = [self .name ], self .options .get ("class" , [])
126- if class_name :
127- classes .extend (class_name )
128-
129- target_label = self .arguments [0 ]
130-
131- textnodes , messages = self .state .inline_text (self .title_text , self .lineno )
132-
133- section = nodes .section (ids = [f"{ self .name } -content" ])
134- self .state .nested_parse (self .content , self .content_offset , section )
135-
136- node = linked_node ()
137- node .document = self .state .document
138- node += nodes .title (self .title_text , "" , * textnodes )
139- node += section
140-
141- label = self .options .get ("label" , "" )
142- if label :
143- self .options ["noindex" ] = False
144- else :
145- self .options ["noindex" ] = True
146- label = f"{ self .env .docname } -{ self .name } -{ serial_no } "
147-
148- # Duplicate label warning
149- if not label == "" and label in self .env .exercise_list .keys ():
150- docpath = self .env .doc2path (self .env .docname )
151- path = docpath [: docpath .rfind ("." )]
152- other_path = self .env .doc2path (self .env .exercise_list [label ]["docname" ])
153- msg = f"duplicate label: { label } ; other instance in { other_path } "
154- logger .warning (msg , location = path , color = "red" )
155- return []
156-
157- self .options ["name" ] = label
158-
159- # Set node attributes
160- node ["classes" ].extend (classes )
161- node ["ids" ].append (label )
162- node ["label" ] = label
163- node ["docname" ] = self .env .docname
164- node ["target_label" ] = target_label
165- node .document = self .state .document
166-
167- self .add_name (node )
168-
169- self .env .exercise_list [label ] = {
170- "type" : self .name ,
171- "docname" : self .env .docname ,
172- "node" : node ,
173- "title" : "" ,
174- }
175-
176- return [node ]
0 commit comments