Implement index entries, production lists and the glossary.

This commit is contained in:
Georg Brandl
2007-12-16 12:20:41 +00:00
parent ef49fadf8c
commit d6deb877df
5 changed files with 107 additions and 44 deletions

View File

@@ -143,14 +143,14 @@ class Builder(object):
"""Load necessary templates and perform initialization."""
raise NotImplementedError
def get_target_uri(self, source_filename):
def get_target_uri(self, source_filename, typ=None):
"""Return the target URI for a source filename."""
raise NotImplementedError
def get_relative_uri(self, from_, to):
def get_relative_uri(self, from_, to, typ=None):
"""Return a relative URI between two source filenames."""
return relative_uri(self.get_target_uri(from_),
self.get_target_uri(to))
self.get_target_uri(to, typ))
def get_outdated_files(self):
"""Return a list of output files that are outdated."""
@@ -195,10 +195,11 @@ class Builder(object):
self.load_env()
to_build = list(self.get_outdated_files())
if not to_build:
self.msg('no files are out of date, exiting.')
self.msg('no target files are out of date, exiting.')
return
self.build(to_build,
summary='%d source files that are out of date' % len(to_build))
summary='targets for %d source files that are '
'out of date' % len(to_build))
def build(self, filenames, summary=None):
if summary:
@@ -482,7 +483,7 @@ class StandaloneHTMLBuilder(Builder):
# --------- these are overwritten by the Web builder
def get_target_uri(self, source_filename):
def get_target_uri(self, source_filename, typ=None):
return source_filename[:-4] + '.html'
def get_outdated_files(self):
@@ -561,7 +562,7 @@ class WebHTMLBuilder(StandaloneHTMLBuilder):
os_path(filename))) > targetmtime:
yield filename
def get_target_uri(self, source_filename):
def get_target_uri(self, source_filename, typ=None):
if source_filename == 'index.rst':
return ''
if source_filename.endswith(SEP+'index.rst'):
@@ -650,10 +651,14 @@ class LaTeXBuilder(Builder):
self.filenames = []
def get_outdated_files(self):
# always rebuild everything for now
# XXX always rebuild everything for now
return self.env.all_files
def get_target_uri(self, source_filename):
def get_target_uri(self, source_filename, typ=None):
if typ == 'token':
# token references are always inside production lists and must be
# replaced by \token{} in LaTeX
return '@token'
if source_filename not in self.filenames:
raise NoUri
else:
@@ -661,7 +666,7 @@ class LaTeXBuilder(Builder):
def get_document_data(self):
for toplevel in ["c-api", "distutils", "documenting", "extending",
"install", "reference", "tutorial", "using", "library"]:
"install", "reference", "tutorial", "using", "library"]:
yield (toplevel + SEP + 'index.rst', toplevel+'.tex', 'manual')
yield ('whatsnew' + SEP + self.config['version'] + '.rst',
'whatsnew.tex', 'howto')
@@ -722,6 +727,7 @@ class LaTeXBuilder(Builder):
largetree.extend(specials)
print
print "resolving references..."
# XXX problem here: :ref:s to distant PDF
self.env.resolve_references(largetree, indexfile, self)
return largetree

View File

@@ -37,18 +37,20 @@ def index_directive(name, arguments, options, content, lineno,
targetnode = nodes.target('', '', ids=[targetid])
state.document.note_explicit_target(targetnode)
indexnode = addnodes.index()
indexnode['entries'] = arguments
indexnode['entries'] = ne = []
for entry in arguments:
entry = entry.strip()
for type in entrytypes:
if entry.startswith(type+':'):
value = entry[len(type)+1:].strip()
env.note_index_entry(type, value, targetid, value)
ne.append((type, value, targetid, value))
break
# shorthand notation for single entries
else:
for value in entry.split(','):
env.note_index_entry('single', value.strip(), targetid, value.strip())
ne.append(('single', value.strip(), targetid, value.strip()))
return [indexnode, targetnode]
index_directive.arguments = (1, 0, 1)

View File

@@ -52,7 +52,7 @@ default_settings = {
# This is increased every time a new environment attribute is added
# to properly invalidate pickle files.
ENV_VERSION = 12
ENV_VERSION = 13
def walk_depth(node, depth, maxdepth):
@@ -620,7 +620,7 @@ class BuildEnvironment:
newnode['refid'] = labelid
else:
newnode['refuri'] = builder.get_relative_uri(
docfilename, filename) + '#' + labelid
docfilename, filename, typ) + '#' + labelid
newnode.append(contnode)
elif typ == 'mod':
filename, synopsis, platform, deprecated = \

View File

@@ -97,7 +97,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
'papersize': 'a4paper', # XXX
'pointsize': '12pt',
'filename': document.settings.filename,
'title': None, # comes later
'title': None, # is determined later
'release': config['release'],
'date': time.strftime(config.get('today_fmt', '%B %d, %Y')),
}
@@ -109,6 +109,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
# flags
self.verbatim = None
self.in_title = 0
self.in_production_list = 0
self.first_document = 1
self.this_is_the_title = 1
self.literal_whitespace = 0
@@ -156,10 +157,24 @@ class LaTeXTranslator(nodes.NodeVisitor):
raise nodes.SkipNode # XXX
def visit_glossary(self, node):
raise nodes.SkipNode # XXX
pass
def depart_glossary(self, node):
pass
def visit_productionlist(self, node):
raise nodes.SkipNode # XXX
self.body.append('\n\n\\begin{productionlist}\n')
self.in_production_list = 1
def depart_productionlist(self, node):
self.body.append('\\end{productionlist}\n\n')
self.in_production_list = 0
def visit_production(self, node):
if node['tokenname']:
self.body.append('\\production{%s}{' % self.encode(node['tokenname']))
else:
self.body.append('\\productioncont{')
def depart_production(self, node):
self.body.append('}\n')
def visit_transition(self, node):
self.body.append('\n\n\\bigskip\\hrule{}\\bigskip\n\n')
@@ -410,9 +425,10 @@ class LaTeXTranslator(nodes.NodeVisitor):
pass
def visit_term(self, node):
if node.has_key('ids') and node['ids']:
self.body.append('\\hypertarget{%s}{}' % node['ids'][0])
self.body.append('\\item[')
def depart_term(self, node):
# definition list term.
self.body.append(']\n')
def visit_classifier(self, node):
@@ -461,27 +477,60 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append(self.context.pop())
def visit_target(self, node):
# XXX: no "index-" targets
def add_target(id):
# indexing uses standard LaTeX index markup, so the targets
# will be generated differently
if not id.startswith('index-'):
self.body.append(r'\hypertarget{%s}{' % id)
return '}'
return ''
# XXX specialcase 'module-' targets: add \declaremodule
# XXX where to put \makemodindex
if not (node.has_key('refuri') or node.has_key('refid')
or node.has_key('refname')):
ctx = ''
for id in node['ids']:
if id not in self.written_ids:
self.body.append(r'\hypertarget{%s}{' % id)
self.written_ids.add(id)
ctx += '}'
ctx += add_target(id)
self.context.append(ctx)
elif node.has_key('refid') and node['refid'] not in self.written_ids:
self.body.append(r'\hypertarget{%s}{' % node['refid'])
self.context.append(add_target(node['refid']))
self.written_ids.add(node['refid'])
self.context.append('}')
else:
self.context.append('')
def depart_target(self, node):
self.body.append(self.context.pop())
def visit_index(self, node):
raise nodes.SkipNode # XXX
indextype_map = {
'module': 'refmodindex', # XXX: key?
'keyword': 'kwindex',
'operator': 'opindex',
'object': 'obindex',
'exception': 'exindex',
'statement': 'stindex',
'builtin': 'bifuncindex',
}
def visit_index(self, node, scre=re.compile(r';\s*')):
entries = node['entries']
for type, string, tid, _ in entries:
if type == 'single':
self.body.append(r'\index{%s}' % scre.sub('!', self.encode(string)))
elif type == 'pair':
parts = tuple(self.encode(x.strip()) for x in string.split(';', 1))
self.body.append(r'\indexii{%s}{%s}' % parts)
elif type == 'triple':
parts = tuple(self.encode(x.strip()) for x in string.split(';', 2))
self.body.append(r'\indexiii{%s}{%s}{%s}' % parts)
elif type in self.indextype_map:
self.body.append(r'\%s{%s}' % (self.indextype_map[type],
self.encode(string)))
else:
raise RuntimeError('XXX unknown index entry type')
raise nodes.SkipNode
def visit_reference(self, node):
uri = node.get('refuri', '')
@@ -493,6 +542,12 @@ class LaTeXTranslator(nodes.NodeVisitor):
elif uri.startswith('#'):
self.body.append('\\hyperlink{%s}{' % uri[1:])
self.context.append('}')
elif uri.startswith('@token'):
if self.in_production_list:
self.body.append('\\token{')
else:
self.body.append('\\grammartoken{')
self.context.append('}')
else:
raise RuntimeError('XXX malformed reference target %s' % uri)
def depart_reference(self, node):

View File

@@ -855,26 +855,26 @@
% Use this def/redef approach for \url{} since hyperref defined this already,
% but only if we actually used hyperref:
\ifpdf
\newcommand{\url}[1]{{%
\py@pdfstartlink%
attr{ /Border [0 0 0] }%
user{%
/Subtype/Link%
/A<<%
/Type/Action%
/S/URI%
/URI(#1)%
>>%
}%
\py@LinkColor% color of the link text
\py@smallsize\sf #1%
\py@NormalColor% Turn it back off; these are declarative
\pdfendlink}% and don't appear bound to the current
}% formatting "box".
\else
\newcommand{\url}[1]{\mbox{\py@smallsize\textsf{#1}}}
\fi
%\ifpdf
% \newcommand{\url}[1]{{%
% \py@pdfstartlink%
% attr{ /Border [0 0 0] }%
% user{%
% /Subtype/Link%
% /A<<%
% /Type/Action%
% /S/URI%
% /URI(#1)%
% >>%
% }%
% \py@LinkColor% color of the link text
% \py@smallsize\sf #1%
% \py@NormalColor% Turn it back off; these are declarative
% \pdfendlink}% and don't appear bound to the current
% }% formatting "box".
%\else
% \newcommand{\url}[1]{\mbox{\py@smallsize\textsf{#1}}}
%\fi
\newcommand{\email}[1]{{\py@smallsize\textsf{#1}}}
\newcommand{\newsgroup}[1]{{\py@smallsize\textsf{#1}}}