12
12
13
13
import typing as t
14
14
15
+ from jinja2 .runtime import Context
16
+ from jinja2 .utils import pass_context
17
+
15
18
from antsibull_core .logging import log
16
19
20
+ from ..semantic_helper import parse_option , parse_return_value
21
+
22
+ from .filters import extract_plugin_data
17
23
from .parser import Command , CommandSet , convert_text
18
24
19
25
@@ -35,9 +41,13 @@ def _create_error(text: str, error: str) -> str:
35
41
36
42
37
43
class _Context :
44
+ j2_context : Context
38
45
counts : t .Dict [str , int ]
46
+ plugin_fqcn : t .Optional [str ]
47
+ plugin_type : t .Optional [str ]
39
48
40
- def __init__ (self ):
49
+ def __init__ (self , j2_context : Context ):
50
+ self .j2_context = j2_context
41
51
self .counts = {
42
52
'italic' : 0 ,
43
53
'bold' : 0 ,
@@ -53,6 +63,7 @@ def __init__(self):
53
63
'return-value' : 0 ,
54
64
'ruler' : 0 ,
55
65
}
66
+ self .plugin_fqcn , self .plugin_type = extract_plugin_data (j2_context )
56
67
57
68
58
69
# In the following, we make heavy use of escaped whitespace ("\ ") being removed from the output.
@@ -159,6 +170,107 @@ def handle(self, parameters: t.List[str], context: t.Any) -> str:
159
170
return f"<code class='docutils literal notranslate'>{ html_escape (parameters [0 ])} </code>"
160
171
161
172
173
+ class _OptionName (Command ):
174
+ command = 'O'
175
+ parameter_count = 1
176
+ escaped_content = True
177
+
178
+ def handle (self , parameters : t .List [str ], context : t .Any ) -> str :
179
+ context .counts ['option-name' ] += 1
180
+ if context .plugin_fqcn is None or context .plugin_type is None :
181
+ raise Exception ('The markup O(...) cannot be used outside a plugin or role' )
182
+ text = parameters [0 ]
183
+ try :
184
+ plugin_fqcn , plugin_type , option_link , option , value = parse_option (
185
+ text , context .plugin_fqcn , context .plugin_type , require_plugin = False )
186
+ except ValueError as exc :
187
+ return _create_error (f'O({ text } )' , str (exc ))
188
+ if value is None :
189
+ cls = 'ansible-option'
190
+ text = f'{ option } '
191
+ strong_start = '<strong>'
192
+ strong_end = '</strong>'
193
+ else :
194
+ cls = 'ansible-option-value'
195
+ text = f'{ option } ={ value } '
196
+ strong_start = ''
197
+ strong_end = ''
198
+ if plugin_fqcn and plugin_type and plugin_fqcn .count ('.' ) >= 2 :
199
+ # TODO: handle role arguments (entrypoint!)
200
+ namespace , name , plugin = plugin_fqcn .split ('.' , 2 )
201
+ url = f'../../{ namespace } /{ name } /{ plugin } _{ plugin_type } .html'
202
+ fragment = f'parameter-{ quote (option_link .replace ("." , "/" ))} '
203
+ link_start = (
204
+ f'<a class="reference internal" href="{ url } #{ fragment } ">'
205
+ '<span class="std std-ref"><span class="pre">'
206
+ )
207
+ link_end = '</span></span></a>'
208
+ else :
209
+ link_start = ''
210
+ link_end = ''
211
+ return (
212
+ f'<code class="{ cls } literal notranslate">'
213
+ f'{ strong_start } { link_start } { text } { link_end } { strong_end } </code>'
214
+ )
215
+
216
+
217
+ class _OptionValue (Command ):
218
+ command = 'V'
219
+ parameter_count = 1
220
+ escaped_content = True
221
+
222
+ def handle (self , parameters : t .List [str ], context : t .Any ) -> str :
223
+ context .counts ['option-value' ] += 1
224
+ text = parameters [0 ]
225
+ return f'<code class="ansible-value literal notranslate">{ html_escape (text )} </code>'
226
+
227
+
228
+ class _EnvVariable (Command ):
229
+ command = 'E'
230
+ parameter_count = 1
231
+ escaped_content = True
232
+
233
+ def handle (self , parameters : t .List [str ], context : t .Any ) -> str :
234
+ context .counts ['environment-var' ] += 1
235
+ text = parameters [0 ]
236
+ return f'<code class="xref std std-envvar literal notranslate">{ html_escape (text )} </code>'
237
+
238
+
239
+ class _RetValue (Command ):
240
+ command = 'RV'
241
+ parameter_count = 1
242
+ escaped_content = True
243
+
244
+ def handle (self , parameters : t .List [str ], context : t .Any ) -> str :
245
+ context .counts ['return-value' ] += 1
246
+ if context .plugin_fqcn is None or context .plugin_type is None :
247
+ raise Exception ('The markup RV(...) cannot be used outside a plugin or role' )
248
+ text = parameters [0 ]
249
+ try :
250
+ plugin_fqcn , plugin_type , rv_link , rv , value = parse_return_value (
251
+ text , context .plugin_fqcn , context .plugin_type , require_plugin = False )
252
+ except ValueError as exc :
253
+ return _create_error (f'RV({ text } )' , str (exc ))
254
+ cls = 'ansible-return-value'
255
+ if value is None :
256
+ text = f'{ rv } '
257
+ else :
258
+ text = f'{ rv } ={ value } '
259
+ if plugin_fqcn and plugin_type and plugin_fqcn .count ('.' ) >= 2 :
260
+ namespace , name , plugin = plugin_fqcn .split ('.' , 2 )
261
+ url = f'../../{ namespace } /{ name } /{ plugin } _{ plugin_type } .html'
262
+ fragment = f'return-{ quote (rv_link .replace ("." , "/" ))} '
263
+ link_start = (
264
+ f'<a class="reference internal" href="{ url } #{ fragment } ">'
265
+ '<span class="std std-ref"><span class="pre">'
266
+ )
267
+ link_end = '</span></span></a>'
268
+ else :
269
+ link_start = ''
270
+ link_end = ''
271
+ return f'<code class="{ cls } literal notranslate">{ link_start } { text } { link_end } </code>'
272
+
273
+
162
274
class _HorizontalLine (Command ):
163
275
command = 'HORIZONTALLINE'
164
276
parameter_count = 0
@@ -178,16 +290,21 @@ def handle(self, parameters: t.List[str], context: t.Any) -> str:
178
290
_Link (),
179
291
_Ref (),
180
292
_Const (),
293
+ _OptionName (),
294
+ _OptionValue (),
295
+ _EnvVariable (),
296
+ _RetValue (),
181
297
_HorizontalLine (),
182
298
])
183
299
184
300
185
- def html_ify (text : str ) -> str :
301
+ @pass_context
302
+ def html_ify (context : Context , text : str ) -> str :
186
303
''' convert symbols like I(this is in italics) to valid HTML '''
187
304
flog = mlog .fields (func = 'html_ify' )
188
305
flog .fields (text = text ).debug ('Enter' )
189
306
190
- our_context = _Context ()
307
+ our_context = _Context (context )
191
308
192
309
try :
193
310
text = convert_text (text , _COMMAND_SET , html_escape , our_context )
0 commit comments