From 31f7eae82272026571fd8e55292a1498e6b8f31f Mon Sep 17 00:00:00 2001 From: David Ham Date: Mon, 3 May 2021 21:50:22 +0100 Subject: [PATCH 1/9] Support containers in LaTeX output. Support containers in the LaTeX writer by outputting the start and end of a LaTeX group, wrapping the beginning and end of a LaTeX environment. The class name(s) are passed as an argument to the environment. --- sphinx/texinputs/sphinx.sty | 5 +++++ sphinx/texinputs/sphinxlatexcontainers.sty | 12 ++++++++++++ sphinx/writers/latex.py | 6 ++++-- 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 sphinx/texinputs/sphinxlatexcontainers.sty diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 108c18b644f..f6964e446b8 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -270,6 +270,11 @@ \input{sphinxlatexshadowbox.sty} +%% CONTAINERS +% +\input{sphinxlatexcontainers.sty} + + %% PYGMENTS % stylesheet for highlighting with pygments \RequirePackage{sphinxhighlight} diff --git a/sphinx/texinputs/sphinxlatexcontainers.sty b/sphinx/texinputs/sphinxlatexcontainers.sty new file mode 100644 index 00000000000..1372619916b --- /dev/null +++ b/sphinx/texinputs/sphinxlatexcontainers.sty @@ -0,0 +1,12 @@ +%% CONTAINER DIRECTIVES +% +% change this info string if making any custom modification +\ProvidesFile{sphinxlatexcontainers.sty}[2021/05/03 containers] + +% The purpose of this file is to provide a dummy environment sphinxcontainer +% which will be inserted for every container directive the container class +% name will be passed as the argument to the environment. User-defined +% formatting of directives can be achieved by renewing the definition of +% this environment, and branching on the value of the argument. + +\newenvironment{sphinxcontainer}[1]{}{} \ No newline at end of file diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 546db9e31be..4db75d1ef3d 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -1975,10 +1975,12 @@ def depart_compound(self, node: Element) -> None: pass def visit_container(self, node: Element) -> None: - pass + classes = node.get('classes', []) + self.body.append( + '\n\\bgroup\\begin{sphinxcontainer}{%s}' % ' '.join(classes)) def depart_container(self, node: Element) -> None: - pass + self.body.append('\n\\end{sphinxcontainer}\\egroup') def visit_decoration(self, node: Element) -> None: pass From 1b03748f689bb87b299ee6ed15081e76458d49be Mon Sep 17 00:00:00 2001 From: David Ham Date: Mon, 3 May 2021 22:29:11 +0100 Subject: [PATCH 2/9] Grammar. --- sphinx/texinputs/sphinxlatexcontainers.sty | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/texinputs/sphinxlatexcontainers.sty b/sphinx/texinputs/sphinxlatexcontainers.sty index 1372619916b..25b3d90b27b 100644 --- a/sphinx/texinputs/sphinxlatexcontainers.sty +++ b/sphinx/texinputs/sphinxlatexcontainers.sty @@ -4,7 +4,7 @@ \ProvidesFile{sphinxlatexcontainers.sty}[2021/05/03 containers] % The purpose of this file is to provide a dummy environment sphinxcontainer -% which will be inserted for every container directive the container class +% which will be inserted for every container directive. The container class % name will be passed as the argument to the environment. User-defined % formatting of directives can be achieved by renewing the definition of % this environment, and branching on the value of the argument. From 8ba93dd21fa82e745cae5caf3a57cd6442dafda9 Mon Sep 17 00:00:00 2001 From: David Ham Date: Tue, 4 May 2021 16:32:17 +0100 Subject: [PATCH 3/9] Refactor to one environment per class. Also rename sphinxcontainer to sphinxclass. --- sphinx/texinputs/sphinxlatexcontainers.sty | 10 +++++----- sphinx/writers/latex.py | 8 +++++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/sphinx/texinputs/sphinxlatexcontainers.sty b/sphinx/texinputs/sphinxlatexcontainers.sty index 25b3d90b27b..5a6047ec93e 100644 --- a/sphinx/texinputs/sphinxlatexcontainers.sty +++ b/sphinx/texinputs/sphinxlatexcontainers.sty @@ -3,10 +3,10 @@ % change this info string if making any custom modification \ProvidesFile{sphinxlatexcontainers.sty}[2021/05/03 containers] -% The purpose of this file is to provide a dummy environment sphinxcontainer -% which will be inserted for every container directive. The container class +% The purpose of this file is to provide a dummy environment sphinxclass +% which will be inserted for each class in each container directive. The class % name will be passed as the argument to the environment. User-defined -% formatting of directives can be achieved by renewing the definition of -% this environment, and branching on the value of the argument. +% formatting of directives can be achieved by renewing the definition of this +% environment, and branching on the value of the argument. -\newenvironment{sphinxcontainer}[1]{}{} \ No newline at end of file +\newenvironment{sphinxclass}[1]{}{} \ No newline at end of file diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 4db75d1ef3d..1d5bf20fc06 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -1976,11 +1976,13 @@ def depart_compound(self, node: Element) -> None: def visit_container(self, node: Element) -> None: classes = node.get('classes', []) - self.body.append( - '\n\\bgroup\\begin{sphinxcontainer}{%s}' % ' '.join(classes)) + for c in classes: + self.body.append('\n\\bgroup\\begin{sphinxclass}{%s}' % c) def depart_container(self, node: Element) -> None: - self.body.append('\n\\end{sphinxcontainer}\\egroup') + classes = node.get('classes', []) + for c in classes: + self.body.append('\n\\end{sphinxclass}\\egroup') def visit_decoration(self, node: Element) -> None: pass From 61765f3f4623bb4bd39acf6dd726cb40124862f0 Mon Sep 17 00:00:00 2001 From: David Ham Date: Wed, 12 May 2021 21:03:04 +0100 Subject: [PATCH 4/9] sphinxclass environment definition docutils style. --- sphinx/texinputs/sphinxlatexcontainers.sty | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sphinx/texinputs/sphinxlatexcontainers.sty b/sphinx/texinputs/sphinxlatexcontainers.sty index 5a6047ec93e..1036fde539a 100644 --- a/sphinx/texinputs/sphinxlatexcontainers.sty +++ b/sphinx/texinputs/sphinxlatexcontainers.sty @@ -9,4 +9,9 @@ % formatting of directives can be achieved by renewing the definition of this % environment, and branching on the value of the argument. -\newenvironment{sphinxclass}[1]{}{} \ No newline at end of file +\ifx\sphinxclass\undefined % poor man's "provideenvironment" + \newenvironment{sphinxclass}[1]{ + \def\sphinxClassFunctionName{sphinxCLASS#1}% + \csname \sphinxClassFunctionName \endcsname}% + {\csname end\sphinxClassFunctionName \endcsname}% +\fi \ No newline at end of file From ca47ac06546230b3db5666176a28b9b0d3199fa1 Mon Sep 17 00:00:00 2001 From: David Ham Date: Wed, 12 May 2021 21:05:53 +0100 Subject: [PATCH 5/9] Remove superfluous groupings. --- sphinx/writers/latex.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 1d5bf20fc06..9a9c63b8fb3 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -1977,12 +1977,12 @@ def depart_compound(self, node: Element) -> None: def visit_container(self, node: Element) -> None: classes = node.get('classes', []) for c in classes: - self.body.append('\n\\bgroup\\begin{sphinxclass}{%s}' % c) + self.body.append('\n\\begin{sphinxclass}{%s}' % c) def depart_container(self, node: Element) -> None: classes = node.get('classes', []) for c in classes: - self.body.append('\n\\end{sphinxclass}\\egroup') + self.body.append('\n\\end{sphinxclass}') def visit_decoration(self, node: Element) -> None: pass From 180c3c92a414534bd43b8470a9cc48e8e8c73d10 Mon Sep 17 00:00:00 2001 From: David Ham Date: Sat, 15 May 2021 21:53:36 +0100 Subject: [PATCH 6/9] Test for LaTeX container output. --- tests/roots/test-latex-container/conf.py | 0 tests/roots/test-latex-container/index.rst | 4 ++++ tests/test_build_latex.py | 8 ++++++++ 3 files changed, 12 insertions(+) create mode 100644 tests/roots/test-latex-container/conf.py create mode 100644 tests/roots/test-latex-container/index.rst diff --git a/tests/roots/test-latex-container/conf.py b/tests/roots/test-latex-container/conf.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/roots/test-latex-container/index.rst b/tests/roots/test-latex-container/index.rst new file mode 100644 index 00000000000..339a625221d --- /dev/null +++ b/tests/roots/test-latex-container/index.rst @@ -0,0 +1,4 @@ +.. container:: classname + + text + \ No newline at end of file diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index bb1904d2c2f..7bb747cb858 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -1599,3 +1599,11 @@ def test_latex_elements_extrapackages(app, status, warning): def test_latex_nested_tables(app, status, warning): app.builder.build_all() assert '' == warning.getvalue() + + +@pytest.mark.sphinx('latex', testroot='latex-container') +def test_latex_container(app, status, warning): + app.builder.build_all() + result = (app.outdir / 'python.tex').read_text() + assert r'\begin{sphinxclass}{classname}' in result + assert r'\end{sphinxclass}' in result From b1b512576189a19323122d03073c5801cc0b73df Mon Sep 17 00:00:00 2001 From: David Ham Date: Sun, 4 Jul 2021 20:05:33 +0100 Subject: [PATCH 7/9] Changes requested by review. --- sphinx/texinputs/sphinxlatexcontainers.sty | 27 +++++++++++++--------- sphinx/writers/latex.py | 4 ++-- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/sphinx/texinputs/sphinxlatexcontainers.sty b/sphinx/texinputs/sphinxlatexcontainers.sty index 1036fde539a..c15001c4945 100644 --- a/sphinx/texinputs/sphinxlatexcontainers.sty +++ b/sphinx/texinputs/sphinxlatexcontainers.sty @@ -3,15 +3,20 @@ % change this info string if making any custom modification \ProvidesFile{sphinxlatexcontainers.sty}[2021/05/03 containers] -% The purpose of this file is to provide a dummy environment sphinxclass -% which will be inserted for each class in each container directive. The class -% name will be passed as the argument to the environment. User-defined -% formatting of directives can be achieved by renewing the definition of this -% environment, and branching on the value of the argument. +% The purpose of this file is to provide a dummy environment sphinxclass which +% will be inserted for each class in each container directive. The class name +% will be passed as the argument to the environment. +% +% For a class foo, the user can define customised handling of that class by +% defining the sphinxclassfoo LaTeX environment. -\ifx\sphinxclass\undefined % poor man's "provideenvironment" - \newenvironment{sphinxclass}[1]{ - \def\sphinxClassFunctionName{sphinxCLASS#1}% - \csname \sphinxClassFunctionName \endcsname}% - {\csname end\sphinxClassFunctionName \endcsname}% -\fi \ No newline at end of file +\newenvironment{sphinxuseclass}[1]{% + \def\sphinxClassFunctionName{sphinxclass#1}% + \ltx@ifundefined{\sphinxClassFunctionName}% + {}% undefined so do nothing + {\expandafter\begin\expandafter{\sphinxClassFunctionName}}% +{% + \ltx@ifundefined{\sphinxClassFunctionName}% + {}% we did nothing so we keep doing nothing + {\expandafter\end\expandafter{\sphinxClassFunctionName}}% +}% diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 9a9c63b8fb3..a08d6568e80 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -1977,12 +1977,12 @@ def depart_compound(self, node: Element) -> None: def visit_container(self, node: Element) -> None: classes = node.get('classes', []) for c in classes: - self.body.append('\n\\begin{sphinxclass}{%s}' % c) + self.body.append('\n\\begin{sphinxuseclass}{%s}' % c) def depart_container(self, node: Element) -> None: classes = node.get('classes', []) for c in classes: - self.body.append('\n\\end{sphinxclass}') + self.body.append('\n\\end{sphinxuseclass}') def visit_decoration(self, node: Element) -> None: pass From 52aac401482015e9f38988f39679f5cfaa14cc56 Mon Sep 17 00:00:00 2001 From: David Ham Date: Sun, 4 Jul 2021 20:15:56 +0100 Subject: [PATCH 8/9] Update tests to match code changes. --- tests/roots/test-latex-container/index.rst | 2 +- tests/test_build_latex.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/roots/test-latex-container/index.rst b/tests/roots/test-latex-container/index.rst index 339a625221d..899788bd5f2 100644 --- a/tests/roots/test-latex-container/index.rst +++ b/tests/roots/test-latex-container/index.rst @@ -1,4 +1,4 @@ .. container:: classname - text + text \ No newline at end of file diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index 7bb747cb858..e0cfce953d7 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -1605,5 +1605,5 @@ def test_latex_nested_tables(app, status, warning): def test_latex_container(app, status, warning): app.builder.build_all() result = (app.outdir / 'python.tex').read_text() - assert r'\begin{sphinxclass}{classname}' in result - assert r'\end{sphinxclass}' in result + assert r'\begin{sphinxuseclass}{classname}' in result + assert r'\end{sphinxuseclass}' in result From 5b3bd3f43a3aa7bcff48d530233afc3bedbb1394 Mon Sep 17 00:00:00 2001 From: David Ham Date: Sun, 4 Jul 2021 21:10:52 +0100 Subject: [PATCH 9/9] Put the brackets in the right places. --- sphinx/texinputs/sphinxlatexcontainers.sty | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/texinputs/sphinxlatexcontainers.sty b/sphinx/texinputs/sphinxlatexcontainers.sty index c15001c4945..93b2c8c086a 100644 --- a/sphinx/texinputs/sphinxlatexcontainers.sty +++ b/sphinx/texinputs/sphinxlatexcontainers.sty @@ -15,7 +15,7 @@ \ltx@ifundefined{\sphinxClassFunctionName}% {}% undefined so do nothing {\expandafter\begin\expandafter{\sphinxClassFunctionName}}% -{% +}{% \ltx@ifundefined{\sphinxClassFunctionName}% {}% we did nothing so we keep doing nothing {\expandafter\end\expandafter{\sphinxClassFunctionName}}%