Merge pull request #2475 from jfbu/master

merge stable into master and update sphinx.sty and CHANGES for 1.5
This commit is contained in:
Jean-François B 2016-04-20 19:23:27 +02:00
commit 4959a75c6f
5 changed files with 189 additions and 65 deletions

View File

@ -11,6 +11,9 @@ python:
- "3.5" - "3.5"
- "pypy" - "pypy"
env: env:
global:
- TEST=-v
matrix:
- DOCUTILS=0.11 - DOCUTILS=0.11
- DOCUTILS=0.12 - DOCUTILS=0.12
install: install:

View File

@ -4,6 +4,8 @@ Release 1.5 (in development)
Incompatible changes Incompatible changes
-------------------- --------------------
* LaTeX package fancybox is not longer a dependency of sphinx.sty
Features added Features added
-------------- --------------
@ -24,6 +26,10 @@ Features added
-------------- --------------
* Now :confval:`suppress_warnings` accepts following configurations: ``app.add_node``, ``app.add_directive``, ``app.add_role`` and ``app.add_generic_role`` (ref: #2451) * Now :confval:`suppress_warnings` accepts following configurations: ``app.add_node``, ``app.add_directive``, ``app.add_role`` and ``app.add_generic_role`` (ref: #2451)
* LaTeX writer allows page breaks in topic contents; and their horizontal
extent now fits in the line width (shadow in margin). Warning-type
admonitions allow page breaks (if very long) and their vertical spacing
has been made more coherent with the one for Hint-type notices.
Bugs fixed Bugs fixed
---------- ----------
@ -34,6 +40,8 @@ Bugs fixed
* #2436: Sphinx does not check version by :confval:`needs_sphinx` if loading extensions failed * #2436: Sphinx does not check version by :confval:`needs_sphinx` if loading extensions failed
* #2397: Setup shorthandoff for turkish documents * #2397: Setup shorthandoff for turkish documents
* #2447: VerbatimBorderColor wrongly used also for captions of PDF * #2447: VerbatimBorderColor wrongly used also for captions of PDF
* #2456: C++, fix crash related to document merging (e.g., singlehtml and Latex builders).
* #2446: latex(pdf) sets local tables of contents (or more generally topic nodes) in unbreakable boxes, causes overflow at bottom
Release 1.4.1 (released Apr 12, 2016) Release 1.4.1 (released Apr 12, 2016)

View File

@ -572,7 +572,7 @@ class ASTIdentifier(ASTBase):
classname=None) classname=None)
key = symbol.get_lookup_key() key = symbol.get_lookup_key()
assert key assert key
pnode['cpp:parentKey'] = key pnode['cpp:parent_key'] = key
pnode += nodes.Text(self.identifier) pnode += nodes.Text(self.identifier)
signode += pnode signode += pnode
elif mode == 'lastIsName': elif mode == 'lastIsName':
@ -3768,10 +3768,10 @@ class CPPObject(ObjectDescription):
raise NotImplementedError() raise NotImplementedError()
def handle_signature(self, sig, signode): def handle_signature(self, sig, signode):
if 'cpp:parentSymbol' not in self.env.ref_context: if 'cpp:parent_symbol' not in self.env.ref_context:
root = self.env.domaindata['cpp']['rootSymbol'] root = self.env.domaindata['cpp']['root_symbol']
self.env.ref_context['cpp:parentSymbol'] = root self.env.ref_context['cpp:parent_symbol'] = root
parentSymbol = self.env.ref_context['cpp:parentSymbol'] parentSymbol = self.env.ref_context['cpp:parent_symbol']
parser = DefinitionParser(sig, self) parser = DefinitionParser(sig, self)
try: try:
@ -3783,16 +3783,16 @@ class CPPObject(ObjectDescription):
# the possibly inner declarations. # the possibly inner declarations.
name = _make_phony_error_name() name = _make_phony_error_name()
symbol = parentSymbol.add_name(name) symbol = parentSymbol.add_name(name)
self.env.ref_context['cpp:lastSymbol'] = symbol self.env.ref_context['cpp:last_symbol'] = symbol
raise ValueError raise ValueError
try: try:
symbol = parentSymbol.add_declaration(ast, docname=self.env.docname) symbol = parentSymbol.add_declaration(ast, docname=self.env.docname)
self.env.ref_context['cpp:lastSymbol'] = symbol self.env.ref_context['cpp:last_symbol'] = symbol
except _DuplicateSymbolError as e: except _DuplicateSymbolError as e:
# Assume we are actually in the old symbol, # Assume we are actually in the old symbol,
# instead of the newly created duplicate. # instead of the newly created duplicate.
self.env.ref_context['cpp:lastSymbol'] = e.symbol self.env.ref_context['cpp:last_symbol'] = e.symbol
if ast.objectType == 'enumerator': if ast.objectType == 'enumerator':
self._add_enumerator_to_parent(ast) self._add_enumerator_to_parent(ast)
@ -3839,13 +3839,13 @@ class CPPClassObject(CPPObject):
return _('%s (C++ class)') % name return _('%s (C++ class)') % name
def before_content(self): def before_content(self):
lastSymbol = self.env.ref_context['cpp:lastSymbol'] lastSymbol = self.env.ref_context['cpp:last_symbol']
assert lastSymbol assert lastSymbol
self.oldParentSymbol = self.env.ref_context['cpp:parentSymbol'] self.oldParentSymbol = self.env.ref_context['cpp:parent_symbol']
self.env.ref_context['cpp:parentSymbol'] = lastSymbol self.env.ref_context['cpp:parent_symbol'] = lastSymbol
def after_content(self): def after_content(self):
self.env.ref_context['cpp:parentSymbol'] = self.oldParentSymbol self.env.ref_context['cpp:parent_symbol'] = self.oldParentSymbol
def parse_definition(self, parser): def parse_definition(self, parser):
return parser.parse_declaration("class") return parser.parse_declaration("class")
@ -3859,13 +3859,13 @@ class CPPEnumObject(CPPObject):
return _('%s (C++ enum)') % name return _('%s (C++ enum)') % name
def before_content(self): def before_content(self):
lastSymbol = self.env.ref_context['cpp:lastSymbol'] lastSymbol = self.env.ref_context['cpp:last_symbol']
assert lastSymbol assert lastSymbol
self.oldParentSymbol = self.env.ref_context['cpp:parentSymbol'] self.oldParentSymbol = self.env.ref_context['cpp:parent_symbol']
self.env.ref_context['cpp:parentSymbol'] = lastSymbol self.env.ref_context['cpp:parent_symbol'] = lastSymbol
def after_content(self): def after_content(self):
self.env.ref_context['cpp:parentSymbol'] = self.oldParentSymbol self.env.ref_context['cpp:parent_symbol'] = self.oldParentSymbol
def parse_definition(self, parser): def parse_definition(self, parser):
ast = parser.parse_declaration("enum") ast = parser.parse_declaration("enum")
@ -3912,7 +3912,7 @@ class CPPNamespaceObject(Directive):
def run(self): def run(self):
env = self.state.document.settings.env env = self.state.document.settings.env
rootSymbol = env.domaindata['cpp']['rootSymbol'] rootSymbol = env.domaindata['cpp']['root_symbol']
if self.arguments[0].strip() in ('NULL', '0', 'nullptr'): if self.arguments[0].strip() in ('NULL', '0', 'nullptr'):
symbol = rootSymbol symbol = rootSymbol
stack = [] stack = []
@ -3927,8 +3927,8 @@ class CPPNamespaceObject(Directive):
ast = ASTNamespace(name, None) ast = ASTNamespace(name, None)
symbol = rootSymbol.add_name(ast.nestedName, ast.templatePrefix) symbol = rootSymbol.add_name(ast.nestedName, ast.templatePrefix)
stack = [symbol] stack = [symbol]
env.ref_context['cpp:parentSymbol'] = symbol env.ref_context['cpp:parent_symbol'] = symbol
env.temp_data['cpp:namespaceStack'] = stack env.temp_data['cpp:namespace_stack'] = stack
return [] return []
@ -3954,14 +3954,14 @@ class CPPNamespacePushObject(Directive):
self.warn(e.description) self.warn(e.description)
name = _make_phony_error_name() name = _make_phony_error_name()
ast = ASTNamespace(name, None) ast = ASTNamespace(name, None)
oldParent = env.ref_context.get('cpp:parentSymbol', None) oldParent = env.ref_context.get('cpp:parent_symbol', None)
if not oldParent: if not oldParent:
oldParent = env.domaindata['cpp']['rootSymbol'] oldParent = env.domaindata['cpp']['root_symbol']
symbol = oldParent.add_name(ast.nestedName, ast.templatePrefix) symbol = oldParent.add_name(ast.nestedName, ast.templatePrefix)
stack = env.temp_data.get('cpp:namespaceStack', []) stack = env.temp_data.get('cpp:namespace_stack', [])
stack.append(symbol) stack.append(symbol)
env.ref_context['cpp:parentSymbol'] = symbol env.ref_context['cpp:parent_symbol'] = symbol
env.temp_data['cpp:namespaceStack'] = stack env.temp_data['cpp:namespace_stack'] = stack
return [] return []
@ -3977,7 +3977,7 @@ class CPPNamespacePopObject(Directive):
def run(self): def run(self):
env = self.state.document.settings.env env = self.state.document.settings.env
stack = env.temp_data.get('cpp:namespaceStack', None) stack = env.temp_data.get('cpp:namespace_stack', None)
if not stack or len(stack) == 0: if not stack or len(stack) == 0:
self.warn("C++ namespace pop on empty stack. Defaulting to gobal scope.") self.warn("C++ namespace pop on empty stack. Defaulting to gobal scope.")
stack = [] stack = []
@ -3986,17 +3986,17 @@ class CPPNamespacePopObject(Directive):
if len(stack) > 0: if len(stack) > 0:
symbol = stack[-1] symbol = stack[-1]
else: else:
symbol = env.domaindata['cpp']['rootSymbol'] symbol = env.domaindata['cpp']['root_symbol']
env.ref_context['cpp:parentSymbol'] = symbol env.ref_context['cpp:parent_symbol'] = symbol
env.temp_data['cpp:namespaceStack'] = stack env.temp_data['cpp:namespace_stack'] = stack
return [] return []
class CPPXRefRole(XRefRole): class CPPXRefRole(XRefRole):
def process_link(self, env, refnode, has_explicit_title, title, target): def process_link(self, env, refnode, has_explicit_title, title, target):
parent = env.ref_context.get('cpp:parentSymbol', None) parent = env.ref_context.get('cpp:parent_symbol', None)
if parent: if parent:
refnode['cpp:parentKey'] = parent.get_lookup_key() refnode['cpp:parent_key'] = parent.get_lookup_key()
if refnode['reftype'] == 'any': if refnode['reftype'] == 'any':
# Assume the removal part of fix_parens for :any: refs. # Assume the removal part of fix_parens for :any: refs.
# The addition part is done with the reference is resolved. # The addition part is done with the reference is resolved.
@ -4055,12 +4055,12 @@ class CPPDomain(Domain):
'enumerator': CPPXRefRole() 'enumerator': CPPXRefRole()
} }
initial_data = { initial_data = {
'rootSymbol': Symbol(None, None, None, None, None, None), 'root_symbol': Symbol(None, None, None, None, None, None),
'names': {} # full name for indexing -> docname 'names': {} # full name for indexing -> docname
} }
def clear_doc(self, docname): def clear_doc(self, docname):
rootSymbol = self.data['rootSymbol'] rootSymbol = self.data['root_symbol']
rootSymbol.clear_doc(docname) rootSymbol.clear_doc(docname)
for name, nDocname in list(self.data['names'].items()): for name, nDocname in list(self.data['names'].items()):
if nDocname == docname: if nDocname == docname:
@ -4069,11 +4069,11 @@ class CPPDomain(Domain):
def process_doc(self, env, docname, document): def process_doc(self, env, docname, document):
# just for debugging # just for debugging
# print(docname) # print(docname)
# print(self.data['rootSymbol'].dump(0)) # print(self.data['root_symbol'].dump(0))
pass pass
def merge_domaindata(self, docnames, otherdata): def merge_domaindata(self, docnames, otherdata):
self.data['rootSymbol'].merge_with(otherdata['rootSymbol'], self.data['root_symbol'].merge_with(otherdata['root_symbol'],
docnames, self.env) docnames, self.env)
ourNames = self.data['names'] ourNames = self.data['names']
for name, docname in otherdata['names'].items(): for name, docname in otherdata['names'].items():
@ -4102,8 +4102,8 @@ class CPPDomain(Domain):
warner.warn('Unparseable C++ cross-reference: %r\n%s' warner.warn('Unparseable C++ cross-reference: %r\n%s'
% (target, str(e.description))) % (target, str(e.description)))
return None, None return None, None
parentKey = node.get("cpp:parentKey", None) parentKey = node.get("cpp:parent_key", None)
rootSymbol = self.data['rootSymbol'] rootSymbol = self.data['root_symbol']
if parentKey: if parentKey:
parentSymbol = rootSymbol.direct_lookup(parentKey) parentSymbol = rootSymbol.direct_lookup(parentKey)
if not parentSymbol: if not parentSymbol:
@ -4152,7 +4152,7 @@ class CPPDomain(Domain):
return [] return []
def get_objects(self): def get_objects(self):
rootSymbol = self.data['rootSymbol'] rootSymbol = self.data['root_symbol']
for symbol in rootSymbol.get_all_symbols(): for symbol in rootSymbol.get_all_symbols():
if symbol.declaration is None: if symbol.declaration is None:
continue continue

View File

@ -8,17 +8,23 @@
\NeedsTeXFormat{LaTeX2e}[1995/12/01] \NeedsTeXFormat{LaTeX2e}[1995/12/01]
\ProvidesPackage{sphinx}[2010/01/15 LaTeX package (Sphinx markup)] \ProvidesPackage{sphinx}[2010/01/15 LaTeX package (Sphinx markup)]
\ifx\directlua\undefined\else
% if compiling with lualatex 0.85 or later load compatibility patch issued by
% the LaTeX team for older packages relying on \pdf<name> named primitives.
\IfFileExists{luatex85.sty}{\RequirePackage{luatex85}}{}
\fi
\@ifclassloaded{memoir}{}{\RequirePackage{fancyhdr}} \@ifclassloaded{memoir}{}{\RequirePackage{fancyhdr}}
\RequirePackage{textcomp} \RequirePackage{textcomp}
\RequirePackage{fancybox}
\RequirePackage{titlesec} \RequirePackage{titlesec}
\RequirePackage{tabulary} \RequirePackage{tabulary}
\RequirePackage{makeidx} \RequirePackage{makeidx}
% For framing code-blocks and warning type notices, and shadowing topics
\RequirePackage{framed} \RequirePackage{framed}
\newif\ifSphinx@inframed % flag set if we are in a framed environment
\RequirePackage{ifthen} \RequirePackage{ifthen}
%The xcolor package draws better fcolorboxes % The xcolor package draws better fcolorboxes around verbatim code
%around verbatim code
\IfFileExists{xcolor.sty}{ \IfFileExists{xcolor.sty}{
\RequirePackage{xcolor} \RequirePackage{xcolor}
}{ }{
@ -242,17 +248,101 @@
\setlength\partopsep{0pt}% \setlength\partopsep{0pt}%
\setlength\leftmargin{0pt}% \setlength\leftmargin{0pt}%
}% }%
\item\MakeFramed {\FrameRestore}% \item
% use a minipage if we are already inside a framed environment
\relax\ifSphinx@inframed\noindent\begin{\minipage}{\linewidth}\fi
\MakeFramed {\FrameRestore}%
\small \small
\OriginalVerbatim[#1]% \OriginalVerbatim[#1]%
} }
\renewcommand{\endVerbatim}{% \renewcommand{\endVerbatim}{%
\endOriginalVerbatim \endOriginalVerbatim
\endMakeFramed \endMakeFramed
\ifSphinx@inframed\end{minipage}\fi
\endlist \endlist
% LaTeX environments always revert local changes on exit, here e.g. \parskip % LaTeX environments always revert local changes on exit, here e.g. \parskip
} }
% define macro to frame contents and add shadow on right and bottom
\def\Sphinx@shadowsep {5\p@} % \p@ means "pt "
\def\Sphinx@shadowsize {4\p@}
\def\Sphinx@shadowrule {\fboxrule}
\long\def\Sphinx@ShadowFBox#1{%
\leavevmode\begingroup
% first we frame the box #1
\setbox\@tempboxa
\hbox{\vrule\@width\Sphinx@shadowrule
\vbox{\hrule\@height\Sphinx@shadowrule
\kern\Sphinx@shadowsep
\hbox{\kern\Sphinx@shadowsep #1\kern\Sphinx@shadowsep}%
\kern\Sphinx@shadowsep
\hrule\@height\Sphinx@shadowrule}%
\vrule\@width\Sphinx@shadowrule}%
% Now we add the shadow, like \shadowbox from fancybox.sty would do
\dimen@\dimexpr.5\Sphinx@shadowrule+\Sphinx@shadowsize\relax
\hbox{\vbox{\offinterlineskip
\hbox{\copy\@tempboxa\kern-.5\Sphinx@shadowrule
% add shadow on right side
\lower\Sphinx@shadowsize
\hbox{\vrule\@height\ht\@tempboxa \@width\dimen@}%
}%
\kern-\dimen@ % shift back vertically to bottom of frame
% and add shadow at bottom
\moveright\Sphinx@shadowsize
\vbox{\hrule\@width\wd\@tempboxa \@height\dimen@}%
}%
% move left by the size of right shadow so shadow adds no width
\kern-\Sphinx@shadowsize
}%
\endgroup
}
% use framed.sty to allow page breaks in frame+shadow
% works well inside Lists and Quote-like environments
% produced by ``topic'' directive (or local contents)
% could nest if LaTeX writer authorized it
\newenvironment{SphinxShadowBox}
{\def\FrameCommand {\Sphinx@ShadowFBox }%
% configure framed.sty not to add extra vertical spacing
\OuterFrameSep \z@skip
% the \trivlist will add the vertical spacing on top and bottom which is
% typical of center environment as used in Sphinx <= 1.4.1
% the \noindent has the effet of an extra blank line on top, to
% imitate closely the layout from Sphinx <= 1.4.1; the \FrameHeightAdjust
% will put top part of frame on this baseline.
\def\FrameHeightAdjust {\baselineskip}%
\trivlist\item\noindent
% use a minipage if we are already inside a framed environment
\ifSphinx@inframed\begin{minipage}{\linewidth}\fi
\MakeFramed {\Sphinx@inframedtrue
% framed.sty puts into "\width" the added width (=2shadowsep+2shadowrule)
% adjust \hsize to what the contents must use
\advance\hsize-\width
% adjust LaTeX parameters to behave properly in indented/quoted contexts
\FrameRestore
% typeset the contents as in a minipage (Sphinx <= 1.4.1 used a minipage and
% itemize/enumerate are therein typeset more tightly, we want to keep
% that). We copy-paste from LaTeX source code but don't do a real minipage.
\@pboxswfalse
% for footnotes, but Sphinx inactivates footnotes in topics
\def\@mpfn{mpfootnote}\def\thempfn{\thempfootnote}\c@mpfootnote\z@
\let\@footnotetext\@mpfootnotetext
\let\@listdepth\@mplistdepth \@mplistdepth\z@
\@minipagerestore
\@setminipage
}%
}%
{% insert the "endminipage" code
\par\unskip
% handle (currently non existing) minipage style footnotes
\ifvoid\@mpfootins\else
\vskip\skip\@mpfootins\normalcolor\footnoterule\unvbox\@mpfootins
\fi
\@minipagefalse
\endMakeFramed
\ifSphinx@inframed\end{minipage}\fi
\endtrivlist
}
% \moduleauthor{name}{email} % \moduleauthor{name}{email}
\newcommand{\moduleauthor}[2]{} \newcommand{\moduleauthor}[2]{}
@ -316,23 +406,49 @@
% Notices / Admonitions % Notices / Admonitions
% %
\newlength{\py@noticelength}
\newcommand{\py@heavybox}{ % Code adapted from framed.sty's "snugshade" environment.
\setlength{\fboxrule}{1pt} % Nesting works (inner frames do not allow page breaks).
\setlength{\fboxsep}{6pt} \newcommand{\py@heavybox}{\par
\setlength{\py@noticelength}{\linewidth} \setlength{\FrameRule}{\p@}% 1pt
\addtolength{\py@noticelength}{-2\fboxsep} \setlength{\FrameSep}{\dimexpr.6\baselineskip-\FrameRule\relax}
\addtolength{\py@noticelength}{-2\fboxrule} % configure framed.sty's parameters to obtain same vertical spacing
%\setlength{\shadowsize}{3pt} % as for "light" boxes. We need for this to manually insert parskip glue and
\noindent\Sbox % revert a skip done by framed before the frame.
\minipage{\py@noticelength} \setlength{\OuterFrameSep}{0pt}
} \vspace{\FrameHeightAdjust}
\newcommand{\py@endheavybox}{ % copied/adapted from framed.sty's snugshade
\endminipage \def\FrameCommand##1{\hskip\@totalleftmargin
\endSbox \fboxsep\FrameSep \fboxrule\FrameRule\fbox{##1}%
\fbox{\TheSbox} \hskip-\linewidth \hskip-\@totalleftmargin \hskip\columnwidth}%
} % use a minipage if we are already inside a framed environment
\ifSphinx@inframed
\noindent\begin{minipage}{\linewidth}
\else
\vspace{\parskip}
\fi
\MakeFramed {\Sphinx@inframedtrue
\advance\hsize-\width \@totalleftmargin\z@ \linewidth\hsize
% minipage initialization copied from LaTeX source code.
\@pboxswfalse
% for footnotes
\def\@mpfn{mpfootnote}\def\thempfn{\thempfootnote}\c@mpfootnote\z@
\let\@footnotetext\@mpfootnotetext
\let\@listdepth\@mplistdepth \@mplistdepth\z@
\@minipagerestore
\@setminipage }%
}
\newcommand{\py@endheavybox}{%
\par\unskip
% handles footnotes
\ifvoid\@mpfootins\else
\vskip\skip\@mpfootins\normalcolor\footnoterule\unvbox\@mpfootins
\fi
\@minipagefalse\endMakeFramed
\ifSphinx@inframed\end{minipage}\fi
% arrange for similar spacing below frame as for "light" boxes.
\vskip .4\baselineskip
}
\newcommand{\py@lightbox}{% \newcommand{\py@lightbox}{%
\par\allowbreak \par\allowbreak

View File

@ -706,14 +706,11 @@ class LaTeXTranslator(nodes.NodeVisitor):
def visit_topic(self, node): def visit_topic(self, node):
self.in_minipage = 1 self.in_minipage = 1
self.body.append('\\setbox0\\vbox{\n' self.body.append('\n\\begin{SphinxShadowBox}\n')
'\\begin{minipage}{0.95\\linewidth}\n')
def depart_topic(self, node): def depart_topic(self, node):
self.in_minipage = 0 self.in_minipage = 0
self.body.append('\\end{minipage}}\n' self.body.append('\\end{SphinxShadowBox}\n')
'\\begin{center}\\setlength{\\fboxsep}{5pt}'
'\\shadowbox{\\box0}\\end{center}\n')
visit_sidebar = visit_topic visit_sidebar = visit_topic
depart_sidebar = depart_topic depart_sidebar = depart_topic