Skip to content

Commit

Permalink
rst domain: Generate node_id for objects in the right way
Browse files Browse the repository at this point in the history
  • Loading branch information
tk0miya committed Feb 29, 2020
1 parent 093d24e commit c889580
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 41 deletions.
5 changes: 5 additions & 0 deletions CHANGES
Expand Up @@ -23,6 +23,11 @@ Incompatible changes
* Due to the scoping changes for :rst:dir:`productionlist` some uses of
:rst:role:`token` must be modified to include the scope which was previously
ignored.
* #6903: rst domain: Internal data structure has changed. Now objects have
for cross reference
* #7229: rst domain: Reference reStructuredText entries via hyperlink target
reference notation (ex. ``numref_``). Only cross reference notation are
available (ex. ``:rst:role:`numref```).

Deprecated
----------
Expand Down
73 changes: 36 additions & 37 deletions sphinx/domains/rst.py
Expand Up @@ -25,7 +25,7 @@
from sphinx.locale import _, __
from sphinx.roles import XRefRole
from sphinx.util import logging
from sphinx.util.nodes import make_refnode
from sphinx.util.nodes import make_id, make_refnode


logger = logging.getLogger(__name__)
Expand All @@ -39,19 +39,16 @@ class ReSTMarkup(ObjectDescription):
"""

def add_target_and_index(self, name: str, sig: str, signode: desc_signature) -> None:
targetname = self.objtype + '-' + name
if targetname not in self.state.document.ids:
signode['names'].append(targetname)
signode['ids'].append(targetname)
self.state.document.note_explicit_target(signode)
node_id = make_id(self.env, self.state.document, self.objtype, name)
signode['ids'].append(node_id)
self.state.document.note_explicit_target(signode)

domain = cast(ReSTDomain, self.env.get_domain('rst'))
domain.note_object(self.objtype, name, location=signode)
domain = cast(ReSTDomain, self.env.get_domain('rst'))
domain.note_object(self.objtype, name, node_id, location=signode)

indextext = self.get_index_text(self.objtype, name)
if indextext:
self.indexnode['entries'].append(('single', indextext,
targetname, '', None))
self.indexnode['entries'].append(('single', indextext, node_id, '', None))

def get_index_text(self, objectname: str, name: str) -> str:
return ''
Expand Down Expand Up @@ -127,26 +124,30 @@ def handle_signature(self, sig: str, signode: desc_signature) -> str:
return name

def add_target_and_index(self, name: str, sig: str, signode: desc_signature) -> None:
domain = cast(ReSTDomain, self.env.get_domain('rst'))

directive_name = self.current_directive
targetname = '-'.join([self.objtype, self.current_directive, name])
if targetname not in self.state.document.ids:
signode['names'].append(targetname)
signode['ids'].append(targetname)
self.state.document.note_explicit_target(signode)
if directive_name:
prefix = '-'.join([self.objtype, directive_name])
objname = ':'.join([directive_name, name])
else:
prefix = self.objtype
objname = name

objname = ':'.join(filter(None, [directive_name, name]))
domain = cast(ReSTDomain, self.env.get_domain('rst'))
domain.note_object(self.objtype, objname, location=signode)
node_id = make_id(self.env, self.state.document, prefix, name)
signode['ids'].append(node_id)
self.state.document.note_explicit_target(signode)
domain.note_object(self.objtype, objname, node_id, location=signode)

if directive_name:
key = name[0].upper()
pair = [_('%s (directive)') % directive_name,
_(':%s: (directive option)') % name]
self.indexnode['entries'].append(('pair', '; '.join(pair), targetname, '', key))
self.indexnode['entries'].append(('pair', '; '.join(pair), node_id, '', key))
else:
key = name[0].upper()
text = _(':%s: (directive option)') % name
self.indexnode['entries'].append(('single', text, targetname, '', key))
self.indexnode['entries'].append(('single', text, node_id, '', key))

@property
def current_directive(self) -> str:
Expand Down Expand Up @@ -193,37 +194,36 @@ class ReSTDomain(Domain):
} # type: Dict[str, Dict[Tuple[str, str], str]]

@property
def objects(self) -> Dict[Tuple[str, str], str]:
return self.data.setdefault('objects', {}) # (objtype, fullname) -> docname
def objects(self) -> Dict[Tuple[str, str], Tuple[str, str]]:
return self.data.setdefault('objects', {}) # (objtype, fullname) -> (docname, node_id)

def note_object(self, objtype: str, name: str, location: Any = None) -> None:
def note_object(self, objtype: str, name: str, node_id: str, location: Any = None) -> None:
if (objtype, name) in self.objects:
docname = self.objects[objtype, name]
docname, node_id = self.objects[objtype, name]
logger.warning(__('duplicate description of %s %s, other instance in %s') %
(objtype, name, docname), location=location)

self.objects[objtype, name] = self.env.docname
self.objects[objtype, name] = (self.env.docname, node_id)

def clear_doc(self, docname: str) -> None:
for (typ, name), doc in list(self.objects.items()):
for (typ, name), (doc, node_id) in list(self.objects.items()):
if doc == docname:
del self.objects[typ, name]

def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
# XXX check duplicates
for (typ, name), doc in otherdata['objects'].items():
for (typ, name), (doc, node_id) in otherdata['objects'].items():
if doc in docnames:
self.objects[typ, name] = doc
self.objects[typ, name] = (doc, node_id)

def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
typ: str, target: str, node: pending_xref, contnode: Element
) -> Element:
objtypes = self.objtypes_for_role(typ)
for objtype in objtypes:
todocname = self.objects.get((objtype, target))
todocname, node_id = self.objects.get((objtype, target), (None, None))
if todocname:
return make_refnode(builder, fromdocname, todocname,
objtype + '-' + target,
return make_refnode(builder, fromdocname, todocname, node_id,
contnode, target + ' ' + objtype)
return None

Expand All @@ -232,25 +232,24 @@ def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Bui
) -> List[Tuple[str, Element]]:
results = [] # type: List[Tuple[str, Element]]
for objtype in self.object_types:
todocname = self.objects.get((objtype, target))
todocname, node_id = self.objects.get((objtype, target), (None, None))
if todocname:
results.append(('rst:' + self.role_for_objtype(objtype),
make_refnode(builder, fromdocname, todocname,
objtype + '-' + target,
make_refnode(builder, fromdocname, todocname, node_id,
contnode, target + ' ' + objtype)))
return results

def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]:
for (typ, name), docname in self.data['objects'].items():
yield name, name, typ, docname, typ + '-' + name, 1
for (typ, name), (docname, node_id) in self.data['objects'].items():
yield name, name, typ, docname, node_id, 1


def setup(app: Sphinx) -> Dict[str, Any]:
app.add_domain(ReSTDomain)

return {
'version': 'builtin',
'env_version': 1,
'env_version': 2,
'parallel_read_safe': True,
'parallel_write_safe': True,
}
8 changes: 4 additions & 4 deletions tests/test_domain_rst.py
Expand Up @@ -76,7 +76,7 @@ def test_rst_directive_option(app):
[desc_content, ()])]))
assert_node(doctree[0],
entries=[("single", ":foo: (directive option)",
"directive:option--foo", "", "F")])
"directive-option-foo", "", "F")])
assert_node(doctree[1], addnodes.desc, desctype="directive:option",
domain="rst", objtype="directive:option", noindex=False)

Expand All @@ -90,7 +90,7 @@ def test_rst_directive_option_with_argument(app):
[desc_content, ()])]))
assert_node(doctree[0],
entries=[("single", ":foo: (directive option)",
"directive:option--foo", "", "F")])
"directive-option-foo", "", "F")])
assert_node(doctree[1], addnodes.desc, desctype="directive:option",
domain="rst", objtype="directive:option", noindex=False)

Expand All @@ -105,7 +105,7 @@ def test_rst_directive_option_type(app):
[desc_content, ()])]))
assert_node(doctree[0],
entries=[("single", ":foo: (directive option)",
"directive:option--foo", "", "F")])
"directive-option-foo", "", "F")])
assert_node(doctree[1], addnodes.desc, desctype="directive:option",
domain="rst", objtype="directive:option", noindex=False)

Expand All @@ -121,7 +121,7 @@ def test_rst_directive_and_directive_option(app):
desc)])]))
assert_node(doctree[1][1][0],
entries=[("pair", "foo (directive); :bar: (directive option)",
"directive:option-foo-bar", "", "B")])
"directive-option-foo-bar", "", "B")])
assert_node(doctree[1][1][1], ([desc_signature, desc_name, ":bar:"],
[desc_content, ()]))
assert_node(doctree[1][1][1], addnodes.desc, desctype="directive:option",
Expand Down

0 comments on commit c889580

Please sign in to comment.