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