1212
1313import typing as t
1414
15+ from jinja2 .runtime import Context
16+ from jinja2 .utils import pass_context
17+
1518from antsibull_core .logging import log
1619
20+ from ..semantic_helper import parse_option , parse_return_value
21+
22+ from .filters import extract_plugin_data
1723from .parser import Command , CommandSet , convert_text
1824
1925
@@ -35,9 +41,13 @@ def _create_error(text: str, error: str) -> str:
3541
3642
3743class _Context :
44+ j2_context : Context
3845 counts : t .Dict [str , int ]
46+ plugin_fqcn : t .Optional [str ]
47+ plugin_type : t .Optional [str ]
3948
40- def __init__ (self ):
49+ def __init__ (self , j2_context : Context ):
50+ self .j2_context = j2_context
4151 self .counts = {
4252 'italic' : 0 ,
4353 'bold' : 0 ,
@@ -53,6 +63,7 @@ def __init__(self):
5363 'return-value' : 0 ,
5464 'ruler' : 0 ,
5565 }
66+ self .plugin_fqcn , self .plugin_type = extract_plugin_data (j2_context )
5667
5768
5869# 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:
159170 return f"<code class='docutils literal notranslate'>{ html_escape (parameters [0 ])} </code>"
160171
161172
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+
162274class _HorizontalLine (Command ):
163275 command = 'HORIZONTALLINE'
164276 parameter_count = 0
@@ -178,16 +290,21 @@ def handle(self, parameters: t.List[str], context: t.Any) -> str:
178290 _Link (),
179291 _Ref (),
180292 _Const (),
293+ _OptionName (),
294+ _OptionValue (),
295+ _EnvVariable (),
296+ _RetValue (),
181297 _HorizontalLine (),
182298])
183299
184300
185- def html_ify (text : str ) -> str :
301+ @pass_context
302+ def html_ify (context : Context , text : str ) -> str :
186303 ''' convert symbols like I(this is in italics) to valid HTML '''
187304 flog = mlog .fields (func = 'html_ify' )
188305 flog .fields (text = text ).debug ('Enter' )
189306
190- our_context = _Context ()
307+ our_context = _Context (context )
191308
192309 try :
193310 text = convert_text (text , _COMMAND_SET , html_escape , our_context )
0 commit comments