summaryrefslogtreecommitdiff
path: root/sphinx/domains/std.py
diff options
context:
space:
mode:
Diffstat (limited to 'sphinx/domains/std.py')
-rw-r--r--sphinx/domains/std.py224
1 files changed, 99 insertions, 125 deletions
diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py
index e73c660e6..6574c9b76 100644
--- a/sphinx/domains/std.py
+++ b/sphinx/domains/std.py
@@ -18,6 +18,7 @@ from docutils.parsers.rst import directives
from docutils.statemachine import StringList
from sphinx import addnodes
+from sphinx.deprecation import RemovedInSphinx40Warning
from sphinx.directives import ObjectDescription
from sphinx.domains import Domain, ObjType
from sphinx.errors import NoUri
@@ -255,6 +256,9 @@ def make_glossary_term(env, textnodes, index_key, source, lineno, new_id=None):
termtext = term.astext()
if new_id is None:
new_id = nodes.make_id('term-' + termtext)
+ if new_id == 'term':
+ # the term is not good for node_id. Generate it by sequence number instead.
+ new_id = 'term-' + str(len(gloss_entries))
if new_id in gloss_entries:
new_id = 'term-' + str(len(gloss_entries))
gloss_entries.add(new_id)
@@ -300,6 +304,7 @@ class Glossary(SphinxDirective):
# first, collect single entries
entries = [] # type: List[Tuple[List[Tuple[str, str, int]], StringList]]
in_definition = True
+ in_comment = False
was_empty = True
messages = [] # type: List[nodes.Node]
for line, (source, lineno) in zip(self.content, self.content.items):
@@ -313,27 +318,33 @@ class Glossary(SphinxDirective):
if line and not line[0].isspace():
# enable comments
if line.startswith('.. '):
+ in_comment = True
continue
+ else:
+ in_comment = False
+
# first term of definition
if in_definition:
if not was_empty:
- messages.append(self.state.reporter.system_message(
- 2, 'glossary term must be preceded by empty line',
+ messages.append(self.state.reporter.warning(
+ _('glossary term must be preceded by empty line'),
source=source, line=lineno))
entries.append(([(line, source, lineno)], StringList()))
in_definition = False
# second term and following
else:
if was_empty:
- messages.append(self.state.reporter.system_message(
- 2, 'glossary terms must not be separated by empty '
- 'lines', source=source, line=lineno))
+ messages.append(self.state.reporter.warning(
+ _('glossary terms must not be separated by empty lines'),
+ source=source, line=lineno))
if entries:
entries[-1][0].append((line, source, lineno))
else:
- messages.append(self.state.reporter.system_message(
- 2, 'glossary seems to be misformatted, check '
- 'indentation', source=source, line=lineno))
+ messages.append(self.state.reporter.warning(
+ _('glossary seems to be misformatted, check indentation'),
+ source=source, line=lineno))
+ elif in_comment:
+ pass
else:
if not in_definition:
# first line of definition, determines indentation
@@ -342,9 +353,9 @@ class Glossary(SphinxDirective):
if entries:
entries[-1][1].append(line[indent_len:], source, lineno)
else:
- messages.append(self.state.reporter.system_message(
- 2, 'glossary seems to be misformatted, check '
- 'indentation', source=source, line=lineno))
+ messages.append(self.state.reporter.warning(
+ _('glossary seems to be misformatted, check indentation'),
+ source=source, line=lineno))
was_empty = False
# now, parse all the entries into a big definition list
@@ -494,8 +505,6 @@ class StandardDomain(Domain):
initial_data = {
'progoptions': {}, # (program, name) -> docname, labelid
'objects': {}, # (type, name) -> docname, labelid
- 'citations': {}, # citation_name -> docname, labelid, lineno
- 'citation_refs': {}, # citation_name -> list of docnames
'labels': { # labelname -> docname, labelid, sectionname
'genindex': ('genindex', '', _('Index')),
'modindex': ('py-modindex', '', _('Module Index')),
@@ -516,7 +525,6 @@ class StandardDomain(Domain):
'keyword': 'unknown keyword: %(target)s',
'doc': 'unknown document: %(target)s',
'option': 'unknown option: %(target)s',
- 'citation': 'citation not found: %(target)s',
}
enumerable_nodes = { # node_class -> (figtype, title_getter)
@@ -534,81 +542,60 @@ class StandardDomain(Domain):
for node, settings in env.app.registry.enumerable_nodes.items():
self.enumerable_nodes[node] = settings
+ @property
+ def objects(self):
+ # type: () -> Dict[Tuple[str, str], Tuple[str, str]]
+ return self.data.setdefault('objects', {}) # (objtype, name) -> docname, labelid
+
+ @property
+ def progoptions(self):
+ # type: () -> Dict[Tuple[str, str], Tuple[str, str]]
+ return self.data.setdefault('progoptions', {}) # (program, name) -> docname, labelid
+
+ @property
+ def labels(self):
+ # type: () -> Dict[str, Tuple[str, str, str]]
+ return self.data.setdefault('labels', {}) # labelname -> docname, labelid, sectionname
+
+ @property
+ def anonlabels(self):
+ # type: () -> Dict[str, Tuple[str, str]]
+ return self.data.setdefault('anonlabels', {}) # labelname -> docname, labelid
+
def clear_doc(self, docname):
# type: (str) -> None
- for key, (fn, _l) in list(self.data['progoptions'].items()):
- if fn == docname:
- del self.data['progoptions'][key]
- for key, (fn, _l) in list(self.data['objects'].items()):
+ key = None # type: Any
+ for key, (fn, _l) in list(self.progoptions.items()):
if fn == docname:
- del self.data['objects'][key]
- for key, (fn, _l, lineno) in list(self.data['citations'].items()):
+ del self.progoptions[key]
+ for key, (fn, _l) in list(self.objects.items()):
if fn == docname:
- del self.data['citations'][key]
- for key, docnames in list(self.data['citation_refs'].items()):
- if docnames == [docname]:
- del self.data['citation_refs'][key]
- elif docname in docnames:
- docnames.remove(docname)
- for key, (fn, _l, _l) in list(self.data['labels'].items()):
+ del self.objects[key]
+ for key, (fn, _l, _l) in list(self.labels.items()):
if fn == docname:
- del self.data['labels'][key]
- for key, (fn, _l) in list(self.data['anonlabels'].items()):
+ del self.labels[key]
+ for key, (fn, _l) in list(self.anonlabels.items()):
if fn == docname:
- del self.data['anonlabels'][key]
+ del self.anonlabels[key]
def merge_domaindata(self, docnames, otherdata):
# type: (List[str], Dict) -> None
# XXX duplicates?
for key, data in otherdata['progoptions'].items():
if data[0] in docnames:
- self.data['progoptions'][key] = data
+ self.progoptions[key] = data
for key, data in otherdata['objects'].items():
if data[0] in docnames:
- self.data['objects'][key] = data
- for key, data in otherdata['citations'].items():
- if data[0] in docnames:
- self.data['citations'][key] = data
- for key, data in otherdata['citation_refs'].items():
- citation_refs = self.data['citation_refs'].setdefault(key, [])
- for docname in data:
- if docname in docnames:
- citation_refs.append(docname)
+ self.objects[key] = data
for key, data in otherdata['labels'].items():
if data[0] in docnames:
- self.data['labels'][key] = data
+ self.labels[key] = data
for key, data in otherdata['anonlabels'].items():
if data[0] in docnames:
- self.data['anonlabels'][key] = data
+ self.anonlabels[key] = data
def process_doc(self, env, docname, document):
# type: (BuildEnvironment, str, nodes.document) -> None
- self.note_citations(env, docname, document)
- self.note_citation_refs(env, docname, document)
- self.note_labels(env, docname, document)
-
- def note_citations(self, env, docname, document):
- # type: (BuildEnvironment, str, nodes.document) -> None
- for node in document.traverse(nodes.citation):
- node['docname'] = docname
- label = cast(nodes.label, node[0]).astext()
- if label in self.data['citations']:
- path = env.doc2path(self.data['citations'][label][0])
- logger.warning(__('duplicate citation %s, other instance in %s'), label, path,
- location=node, type='ref', subtype='citation')
- self.data['citations'][label] = (docname, node['ids'][0], node.line)
-
- def note_citation_refs(self, env, docname, document):
- # type: (BuildEnvironment, str, nodes.document) -> None
- for node in document.traverse(addnodes.pending_xref):
- if node['refdomain'] == 'std' and node['reftype'] == 'citation':
- label = node['reftarget']
- citation_refs = self.data['citation_refs'].setdefault(label, [])
- citation_refs.append(docname)
-
- def note_labels(self, env, docname, document):
- # type: (BuildEnvironment, str, nodes.document) -> None
- labels, anonlabels = self.data['labels'], self.data['anonlabels']
for name, explicit in document.nametypes.items():
if not explicit:
continue
@@ -626,11 +613,11 @@ class StandardDomain(Domain):
# ignore footnote labels, labels automatically generated from a
# link and object descriptions
continue
- if name in labels:
+ if name in self.labels:
logger.warning(__('duplicate label %s, other instance in %s'),
- name, env.doc2path(labels[name][0]),
+ name, env.doc2path(self.labels[name][0]),
location=node)
- anonlabels[name] = docname, labelid
+ self.anonlabels[name] = docname, labelid
if node.tagname in ('section', 'rubric'):
title = cast(nodes.title, node[0])
sectname = clean_astext(title)
@@ -647,23 +634,15 @@ class StandardDomain(Domain):
else:
# anonymous-only labels
continue
- labels[name] = docname, labelid, sectname
+ self.labels[name] = docname, labelid, sectname
def add_object(self, objtype, name, docname, labelid):
# type: (str, str, str, str) -> None
- self.data['objects'][objtype, name] = (docname, labelid)
+ self.objects[objtype, name] = (docname, labelid)
def add_program_option(self, program, name, docname, labelid):
# type: (str, str, str, str) -> None
- self.data['progoptions'][program, name] = (docname, labelid)
-
- def check_consistency(self):
- # type: () -> None
- for name, (docname, labelid, lineno) in self.data['citations'].items():
- if name not in self.data['citation_refs']:
- logger.warning(__('Citation [%s] is not referenced.'), name,
- type='ref', subtype='citation',
- location=(docname, lineno))
+ self.progoptions[program, name] = (docname, labelid)
def build_reference_node(self, fromdocname, builder, docname, labelid,
sectname, rolename, **options):
@@ -703,7 +682,10 @@ class StandardDomain(Domain):
elif typ == 'option':
resolver = self._resolve_option_xref
elif typ == 'citation':
- resolver = self._resolve_citation_xref
+ warnings.warn('pending_xref(domain=std, type=citation) is deprecated: %r' % node,
+ RemovedInSphinx40Warning)
+ domain = env.get_domain('citation')
+ return domain.resolve_xref(env, fromdocname, builder, typ, target, node, contnode)
else:
resolver = self._resolve_obj_xref
@@ -714,13 +696,12 @@ class StandardDomain(Domain):
if node['refexplicit']:
# reference to anonymous label; the reference uses
# the supplied link caption
- docname, labelid = self.data['anonlabels'].get(target, ('', ''))
+ docname, labelid = self.anonlabels.get(target, ('', ''))
sectname = node.astext()
else:
# reference to named label; the final node will
# contain the section name after the label
- docname, labelid, sectname = self.data['labels'].get(target,
- ('', '', ''))
+ docname, labelid, sectname = self.labels.get(target, ('', '', ''))
if not docname:
return None
@@ -729,10 +710,10 @@ class StandardDomain(Domain):
def _resolve_numref_xref(self, env, fromdocname, builder, typ, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA
- if target in self.data['labels']:
- docname, labelid, figname = self.data['labels'].get(target, ('', '', ''))
+ if target in self.labels:
+ docname, labelid, figname = self.labels.get(target, ('', '', ''))
else:
- docname, labelid = self.data['anonlabels'].get(target, ('', ''))
+ docname, labelid = self.anonlabels.get(target, ('', ''))
figname = None
if not docname:
@@ -791,7 +772,7 @@ class StandardDomain(Domain):
def _resolve_keyword_xref(self, env, fromdocname, builder, typ, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA
# keywords are oddballs: they are referenced by named labels
- docname, labelid, _ = self.data['labels'].get(target, ('', '', ''))
+ docname, labelid, _ = self.labels.get(target, ('', '', ''))
if not docname:
return None
return make_refnode(builder, fromdocname, docname,
@@ -817,7 +798,7 @@ class StandardDomain(Domain):
# type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA
progname = node.get('std:program')
target = target.strip()
- docname, labelid = self.data['progoptions'].get((progname, target), ('', ''))
+ docname, labelid = self.progoptions.get((progname, target), ('', ''))
if not docname:
commands = []
while ws_re.search(target):
@@ -825,8 +806,7 @@ class StandardDomain(Domain):
commands.append(subcommand)
progname = "-".join(commands)
- docname, labelid = self.data['progoptions'].get((progname, target),
- ('', ''))
+ docname, labelid = self.progoptions.get((progname, target), ('', ''))
if docname:
break
else:
@@ -835,33 +815,12 @@ class StandardDomain(Domain):
return make_refnode(builder, fromdocname, docname,
labelid, contnode)
- def _resolve_citation_xref(self, env, fromdocname, builder, typ, target, node, contnode):
- # type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA
- docname, labelid, lineno = self.data['citations'].get(target, ('', '', 0))
- if not docname:
- if 'ids' in node:
- # remove ids attribute that annotated at
- # transforms.CitationReference.apply.
- del node['ids'][:]
- return None
-
- try:
- return make_refnode(builder, fromdocname, docname,
- labelid, contnode)
- except NoUri:
- # remove the ids we added in the CitationReferences
- # transform since they can't be transfered to
- # the contnode (if it's a Text node)
- if not isinstance(contnode, nodes.Element):
- del node['ids'][:]
- raise
-
def _resolve_obj_xref(self, env, fromdocname, builder, typ, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA
objtypes = self.objtypes_for_role(typ) or []
for objtype in objtypes:
- if (objtype, target) in self.data['objects']:
- docname, labelid = self.data['objects'][objtype, target]
+ if (objtype, target) in self.objects:
+ docname, labelid = self.objects[objtype, target]
break
else:
docname, labelid = '', ''
@@ -885,8 +844,8 @@ class StandardDomain(Domain):
key = (objtype, target)
if objtype == 'term':
key = (objtype, ltarget)
- if key in self.data['objects']:
- docname, labelid = self.data['objects'][key]
+ if key in self.objects:
+ docname, labelid = self.objects[key]
results.append(('std:' + self.role_for_objtype(objtype),
make_refnode(builder, fromdocname, docname,
labelid, contnode)))
@@ -897,22 +856,22 @@ class StandardDomain(Domain):
# handle the special 'doc' reference here
for doc in self.env.all_docs:
yield (doc, clean_astext(self.env.titles[doc]), 'doc', doc, '', -1)
- for (prog, option), info in self.data['progoptions'].items():
+ for (prog, option), info in self.progoptions.items():
if prog:
fullname = ".".join([prog, option])
yield (fullname, fullname, 'cmdoption', info[0], info[1], 1)
else:
yield (option, option, 'cmdoption', info[0], info[1], 1)
- for (type, name), info in self.data['objects'].items():
+ for (type, name), info in self.objects.items():
yield (name, name, type, info[0], info[1],
self.object_types[type].attrs['searchprio'])
- for name, info in self.data['labels'].items():
- yield (name, info[2], 'label', info[0], info[1], -1)
+ for name, (docname, labelid, sectionname) in self.labels.items():
+ yield (name, sectionname, 'label', docname, labelid, -1)
# add anonymous-only labels as well
- non_anon_labels = set(self.data['labels'])
- for name, info in self.data['anonlabels'].items():
+ non_anon_labels = set(self.labels)
+ for name, (docname, labelid) in self.anonlabels.items():
if name not in non_anon_labels:
- yield (name, name, 'label', info[0], info[1], -1)
+ yield (name, name, 'label', docname, labelid, -1)
def get_type_name(self, type, primary=False):
# type: (ObjType, bool) -> str
@@ -993,6 +952,21 @@ class StandardDomain(Domain):
else:
return None
+ def note_citations(self, env, docname, document):
+ # type: (BuildEnvironment, str, nodes.document) -> None
+ warnings.warn('StandardDomain.note_citations() is deprecated.',
+ RemovedInSphinx40Warning)
+
+ def note_citation_refs(self, env, docname, document):
+ # type: (BuildEnvironment, str, nodes.document) -> None
+ warnings.warn('StandardDomain.note_citation_refs() is deprecated.',
+ RemovedInSphinx40Warning)
+
+ def note_labels(self, env, docname, document):
+ # type: (BuildEnvironment, str, nodes.document) -> None
+ warnings.warn('StandardDomain.note_labels() is deprecated.',
+ RemovedInSphinx40Warning)
+
def setup(app):
# type: (Sphinx) -> Dict[str, Any]