Skip to content

Commit

Permalink
Merge pull request #5583 from jfbu/5579_style_index_entries
Browse files Browse the repository at this point in the history
LaTeX: add styling to general index, similar to domain indices
  • Loading branch information
jfbu committed Nov 6, 2018
2 parents 63daf8c + 00a75b2 commit c9999b1
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 25 deletions.
3 changes: 3 additions & 0 deletions sphinx/texinputs/python.ist
Expand Up @@ -4,6 +4,9 @@ heading_prefix " \\bigletter "

preamble "\\begin{sphinxtheindex}
\\let\\bigletter\\sphinxstyleindexlettergroup
\\let\\spxpagem \\sphinxstyleindexpagemain
\\let\\spxentry \\sphinxstyleindexentry
\\let\\spxextra \\sphinxstyleindexextra

"

Expand Down
5 changes: 4 additions & 1 deletion sphinx/texinputs/sphinx.sty
Expand Up @@ -1623,8 +1623,11 @@
% additional customizable styling
\def\sphinxstyleindexentry #1{\texttt{#1}}
\def\sphinxstyleindexextra #1{ \emph{(#1)}}
\def\sphinxstyleindexextra #1{ (\emph{#1})}
\def\sphinxstyleindexpageref #1{, \pageref{#1}}
\def\sphinxstyleindexpagemain#1{\textbf{#1}}
\protected\def\spxentry#1{#1}% will get \let to \sphinxstyleindexentry in index
\protected\def\spxextra#1{#1}% will get \let to \sphinxstyleindexextra in index
\def\sphinxstyleindexlettergroup #1%
{{\Large\sffamily#1}\nopagebreak\vspace{1mm}}
\def\sphinxstyleindexlettergroupDefault #1%
Expand Down
8 changes: 6 additions & 2 deletions sphinx/texinputs/sphinx.xdy
Expand Up @@ -3,11 +3,12 @@
;; Unfortunately xindy is out-of-the-box hyperref-incompatible. This
;; configuration is a workaround, which requires to pass option
;; hyperindex=false to hyperref.
;; textit and emph not currently used by Sphinx LaTeX writer.
(define-attributes (("textbf" "textit" "emph" "default")))
;; textit and emph not currently used, spxpagem replaces former textbf
(define-attributes (("textbf" "textit" "emph" "spxpagem" "default")))
(markup-locref :open "\textbf{\hyperpage{" :close "}}" :attr "textbf")
(markup-locref :open "\textit{\hyperpage{" :close "}}" :attr "textit")
(markup-locref :open "\emph{\hyperpage{" :close "}}" :attr "emph")
(markup-locref :open "\spxpagem{\hyperpage{" :close "}}" :attr "spxpagem")
(markup-locref :open "\hyperpage{" :close "}" :attr "default")

(require "numeric-sort.xdy")
Expand Down Expand Up @@ -193,6 +194,9 @@
(markup-index :open "\begin{sphinxtheindex}
\let\lettergroup\sphinxstyleindexlettergroup
\let\lettergroupDefault\sphinxstyleindexlettergroupDefault
\let\spxpagem\sphinxstyleindexpagemain
\let\spxentry\sphinxstyleindexentry
\let\spxextra\sphinxstyleindexextra
"
:close "
Expand Down
50 changes: 38 additions & 12 deletions sphinx/writers/latex.py
Expand Up @@ -169,6 +169,8 @@
},
} # type: Dict[unicode, Dict[unicode, unicode]]

EXTRA_RE = re.compile(r'^(.*\S)\s+\(([^()]*)\)\s*$')


class collected_footnote(nodes.footnote):
"""Footnotes that are collected are assigned this class."""
Expand Down Expand Up @@ -1884,8 +1886,8 @@ def depart_attribution(self, node):
# type: (nodes.Node) -> None
self.body.append('\n\\end{flushright}\n')

def visit_index(self, node, scre=re.compile(r';\s*')):
# type: (nodes.Node, Pattern) -> None
def visit_index(self, node, scre = None):
# type: (nodes.Node, None) -> None
def escape(value):
value = self.encode(value)
value = value.replace(r'\{', r'\sphinxleftcurlybrace{}')
Expand All @@ -1895,33 +1897,57 @@ def escape(value):
value = value.replace('!', '"!')
return value

def style(string):
match = EXTRA_RE.match(string)
if match:
return match.expand(r'\\spxentry{\1}\\spxextra{\2}')
else:
return '\\spxentry{%s}' % string

if scre:
warnings.warn(('LaTeXTranslator.visit_index() optional argument '
'"scre" is deprecated. It is ignored.'),
RemovedInSphinx30Warning, stacklevel=2)
if not node.get('inline', True):
self.body.append('\n')
entries = node['entries']
for type, string, tid, ismain, key_ in entries:
m = ''
if ismain:
m = '|textbf'
m = '|spxpagem'
try:
if type == 'single':
p = scre.sub('!', escape(string))
self.body.append(r'\index{%s%s}' % (p, m))
try:
p1, p2 = [escape(x) for x in split_into(2, 'single', string)]
P1, P2 = style(p1), style(p2)
self.body.append(r'\index{%s@%s!%s@%s%s}' % (p1, P1, p2, P2, m))
except ValueError:
p = escape(split_into(1, 'single', string)[0])
P = style(p)
self.body.append(r'\index{%s@%s%s}' % (p, P, m))
elif type == 'pair':
p1, p2 = [escape(x) for x in split_into(2, 'pair', string)]
self.body.append(r'\index{%s!%s%s}\index{%s!%s%s}' %
(p1, p2, m, p2, p1, m))
P1, P2 = style(p1), style(p2)
self.body.append(r'\index{%s@%s!%s@%s%s}\index{%s@%s!%s@%s%s}' %
(p1, P1, p2, P2, m, p2, P2, p1, P1, m))
elif type == 'triple':
p1, p2, p3 = [escape(x) for x in split_into(3, 'triple', string)]
P1, P2, P3 = style(p1), style(p2), style(p3)
self.body.append(
r'\index{%s!%s %s%s}\index{%s!%s, %s%s}'
r'\index{%s!%s %s%s}' %
(p1, p2, p3, m, p2, p3, p1, m, p3, p1, p2, m))
r'\index{%s@%s!%s %s@%s %s%s}'
r'\index{%s@%s!%s, %s@%s, %s%s}'
r'\index{%s@%s!%s %s@%s %s%s}' %
(p1, P1, p2, p3, P2, P3, m,
p2, P2, p3, p1, P3, P1, m,
p3, P3, p1, p2, P1, P2, m))
elif type == 'see':
p1, p2 = [escape(x) for x in split_into(2, 'see', string)]
self.body.append(r'\index{%s|see{%s}}' % (p1, p2))
P1 = style(p1)
self.body.append(r'\index{%s@%s|see{%s}}' % (p1, P1, p2))
elif type == 'seealso':
p1, p2 = [escape(x) for x in split_into(2, 'seealso', string)]
self.body.append(r'\index{%s|see{%s}}' % (p1, p2))
P1 = style(p1)
self.body.append(r'\index{%s@%s|see{%s}}' % (p1, P1, p2))
else:
logger.warning(__('unknown index entry type %s found'), type)
except ValueError as err:
Expand Down
26 changes: 16 additions & 10 deletions tests/test_build_latex.py
Expand Up @@ -1199,9 +1199,13 @@ def test_latex_index(app, status, warning):
app.builder.build_all()

result = (app.outdir / 'Python.tex').text(encoding='utf8')
assert 'A \\index{famous}famous \\index{equation}equation:\n' in result
assert '\n\\index{Einstein}\\index{relativity}\\ignorespaces \nand' in result
assert '\n\\index{main \\sphinxleftcurlybrace{}}\\ignorespaces ' in result
assert ('A \\index{famous@\\spxentry{famous}}famous '
'\\index{equation@\\spxentry{equation}}equation:\n' in result)
assert ('\n\\index{Einstein@\\spxentry{Einstein}}'
'\\index{relativity@\\spxentry{relativity}}'
'\\ignorespaces \nand') in result
assert ('\n\\index{main \\sphinxleftcurlybrace{}@\\spxentry{'
'main \\sphinxleftcurlybrace{}}}\\ignorespaces ' in result)


@pytest.mark.sphinx('latex', testroot='latex-equations')
Expand Down Expand Up @@ -1269,20 +1273,22 @@ def test_latex_glossary(app, status, warning):
app.builder.build_all()

result = (app.outdir / 'test.tex').text(encoding='utf8')
assert (u'\\item[{änhlich\\index{änhlich|textbf}\\phantomsection'
assert (u'\\item[{änhlich\\index{änhlich@\\spxentry{änhlich}|spxpagem}'
r'\phantomsection'
r'\label{\detokenize{index:term-anhlich}}}] \leavevmode' in result)
assert (r'\item[{boson\index{boson|textbf}\phantomsection'
assert (r'\item[{boson\index{boson@\spxentry{boson}|spxpagem}\phantomsection'
r'\label{\detokenize{index:term-boson}}}] \leavevmode' in result)
assert (r'\item[{\sphinxstyleemphasis{fermion}\index{fermion|textbf}'
assert (r'\item[{\sphinxstyleemphasis{fermion}'
r'\index{fermion@\spxentry{fermion}|spxpagem}'
r'\phantomsection'
r'\label{\detokenize{index:term-fermion}}}] \leavevmode' in result)
assert (r'\item[{tauon\index{tauon|textbf}\phantomsection'
assert (r'\item[{tauon\index{tauon@\spxentry{tauon}|spxpagem}\phantomsection'
r'\label{\detokenize{index:term-tauon}}}] \leavevmode'
r'\item[{myon\index{myon|textbf}\phantomsection'
r'\item[{myon\index{myon@\spxentry{myon}|spxpagem}\phantomsection'
r'\label{\detokenize{index:term-myon}}}] \leavevmode'
r'\item[{electron\index{electron|textbf}\phantomsection'
r'\item[{electron\index{electron@\spxentry{electron}|spxpagem}\phantomsection'
r'\label{\detokenize{index:term-electron}}}] \leavevmode' in result)
assert (u'\\item[{über\\index{über|textbf}\\phantomsection'
assert (u'\\item[{über\\index{über@\\spxentry{über}|spxpagem}\\phantomsection'
r'\label{\detokenize{index:term-uber}}}] \leavevmode' in result)


Expand Down

0 comments on commit c9999b1

Please sign in to comment.