Search code examples
latexpython-sphinx

Assign arguments to a Sphinx container


I'm declaring a custom environment in the preamble of conf.py which takes 6 arguments

% REQUIREMENT STYLE/FORMAT
\newenvironment{sphinxclasscustomizedrequirement}[6]{
    \rule{15cm}{1pt}\\ 
    \fontfamily{qcr}\selectfont
    \color{red}
    ARG1 = #1\\[1ex]
    \color{black}
    ARG2 = #2\\[1ex]
    ARG3 = #3\\[1ex]
    ARG4 = #4\\[1ex]
    ARG5 = #5\\[1ex]
    \rule{15cm}{1pt}\\
}{}

I wrap some blocks into this environment using a container directive

.. container:: customizedrequirement
    
    HELLO WORLD THIS IS A TEST

However, I cannot figure out how to specify the 6 arguments of this environment.

I want to generate this LaTeX code

\begin{sphinxuseclass}{customizedrequirement}{123456}{LOREM}{IPSUM}{DOLOR}{SIT}
\sphinxAtStartPar
HELLO WORLD THIS IS A TEST
\end{sphinxuseclass}

But I can't figure out how to do that in rst.

If I specify the arguments like in code-block

.. container:: customizedrequirement
    :a: A
    :b: B
    :c: C
    :d: DEBUG
    
    HELLO WORLD THIS IS A TEST

Then it generates this

\begin{sphinxuseclass}{customizedrequirement}
\begin{sphinxuseclass}{a}
\begin{sphinxuseclass}{a}
\begin{sphinxuseclass}{b}
\begin{sphinxuseclass}{b}
\begin{sphinxuseclass}{c}
\begin{sphinxuseclass}{c}
\begin{sphinxuseclass}{d}
\begin{sphinxuseclass}{debug}
\sphinxAtStartPar
HELLO WORLD THIS IS A TEST

\end{sphinxuseclass}
\end{sphinxuseclass}
\end{sphinxuseclass}
\end{sphinxuseclass}
\end{sphinxuseclass}
\end{sphinxuseclass}
\end{sphinxuseclass}
\end{sphinxuseclass}
\end{sphinxuseclass}

How do I generate a call to my environment with the specified arguments ?


Solution

  • What I ended up doing is writing a custom extension, because I could not get it to work out of the box, without an extension.

    class Requirement(Directive):
    
        has_content = True
    
        option_spec = {
            'id': directives.unchanged_required,
            'source': directives.unchanged,
            'allocation': directives.unchanged_required,
            'safety': directives.unchanged_required,
        }
    
    
        def run(self):
            paragraph_node = nodes.paragraph()
            self.state.nested_parse(self.content, self.content_offset, paragraph_node)
    
            req_id = self.options.get('id', 'undefined')
            source = self.options.get('source', 'None (derived requirement)')
            allocation = self.options.get('allocation', 'undefined')
            safety = self.options.get('safety', 'undefined')       
            arguments = f'{{{req_id}}}{{{source}}}{{{allocation}}}{{{safety}}}'.replace('_','\_')
            
            latex_prefix = nodes.raw('', '\\begin{customizedrequirement}' + arguments, format='latex')
            latex_suffix = nodes.raw('', '\end{customizedrequirement}', format='latex')
            return [latex_prefix, paragraph_node, latex_suffix]
    
    def setup(app):
        app.add_directive("requirement", Requirement)
    
        return {
            'version': '0.1',
            'parallel_read_safe': True,
            'parallel_write_safe': True,
        }
    

    This is the way I call the extension in .rst

    .. requirement::
        :id: ABCDE
        :source: req_1
        :allocation: team1
        :safety: high
    
        This is the textual content
    

    Finally, it generates the LaTeX I want :

    \begin{customizedrequirement}{ABCDE}{req_1}{team1}{high}
    \sphinxAtStartPar
    \sphinxAtStartPar
    This is the textual content
    
    
    \end{customizedrequirement}
    

    Don't forget to declare the style customizedrequirement to your preamble :

    latex_elements = {
      'preamble': r'''
    % REQUIREMENT STYLE/FORMAT
    \newenvironment{customizedrequirement}[5]{
        \rule{15cm}{1pt}\\ 
        \small
        \color{red}
        #1\\[1ex]
        \color{black}
        SOURCE=#2\\[1ex]
        ALLOCATION=#3\\[1ex]
        SAFETY=#4\\[1ex]
    }{
    \rule{15cm}{1pt}\\
    }
    '''
    }