mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge pull request #6537 from tk0miya/refactor_domain
refactor: Add data accessors to CDomain, ChangesetDomain and JavaScriptDomain
This commit is contained in:
commit
cb7e2a9dea
@ -11,6 +11,7 @@
|
|||||||
import re
|
import re
|
||||||
import string
|
import string
|
||||||
from typing import Any, Dict, Iterator, List, Tuple
|
from typing import Any, Dict, Iterator, List, Tuple
|
||||||
|
from typing import cast
|
||||||
|
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
from docutils.nodes import Element
|
from docutils.nodes import Element
|
||||||
@ -22,12 +23,15 @@ from sphinx.builders import Builder
|
|||||||
from sphinx.directives import ObjectDescription
|
from sphinx.directives import ObjectDescription
|
||||||
from sphinx.domains import Domain, ObjType
|
from sphinx.domains import Domain, ObjType
|
||||||
from sphinx.environment import BuildEnvironment
|
from sphinx.environment import BuildEnvironment
|
||||||
from sphinx.locale import _
|
from sphinx.locale import _, __
|
||||||
from sphinx.roles import XRefRole
|
from sphinx.roles import XRefRole
|
||||||
|
from sphinx.util import logging
|
||||||
from sphinx.util.docfields import Field, TypedField
|
from sphinx.util.docfields import Field, TypedField
|
||||||
from sphinx.util.nodes import make_refnode
|
from sphinx.util.nodes import make_refnode
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# RE to split at word boundaries
|
# RE to split at word boundaries
|
||||||
wsplit_re = re.compile(r'(\W+)')
|
wsplit_re = re.compile(r'(\W+)')
|
||||||
|
|
||||||
@ -201,13 +205,9 @@ class CObject(ObjectDescription):
|
|||||||
signode['ids'].append(targetname)
|
signode['ids'].append(targetname)
|
||||||
signode['first'] = (not self.names)
|
signode['first'] = (not self.names)
|
||||||
self.state.document.note_explicit_target(signode)
|
self.state.document.note_explicit_target(signode)
|
||||||
inv = self.env.domaindata['c']['objects']
|
|
||||||
if name in inv:
|
domain = cast(CDomain, self.env.get_domain('c'))
|
||||||
self.state_machine.reporter.warning(
|
domain.note_object(name, self.objtype)
|
||||||
'duplicate C object description of %s, ' % name +
|
|
||||||
'other instance in ' + self.env.doc2path(inv[name][0]),
|
|
||||||
line=self.lineno)
|
|
||||||
inv[name] = (self.env.docname, self.objtype)
|
|
||||||
|
|
||||||
indextext = self.get_index_text(name)
|
indextext = self.get_index_text(name)
|
||||||
if indextext:
|
if indextext:
|
||||||
@ -271,10 +271,22 @@ class CDomain(Domain):
|
|||||||
'objects': {}, # fullname -> docname, objtype
|
'objects': {}, # fullname -> docname, objtype
|
||||||
} # type: Dict[str, Dict[str, Tuple[str, Any]]]
|
} # type: Dict[str, Dict[str, Tuple[str, Any]]]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def objects(self) -> Dict[str, Tuple[str, str]]:
|
||||||
|
return self.data.setdefault('objects', {}) # fullname -> docname, objtype
|
||||||
|
|
||||||
|
def note_object(self, name: str, objtype: str, location: Any = None) -> None:
|
||||||
|
if name in self.objects:
|
||||||
|
docname = self.objects[name][0]
|
||||||
|
logger.warning(__('duplicate C object description of %s, '
|
||||||
|
'other instance in %s, use :noindex: for one of them'),
|
||||||
|
name, docname, location=location)
|
||||||
|
self.objects[name] = (self.env.docname, objtype)
|
||||||
|
|
||||||
def clear_doc(self, docname: str) -> None:
|
def clear_doc(self, docname: str) -> None:
|
||||||
for fullname, (fn, _l) in list(self.data['objects'].items()):
|
for fullname, (fn, _l) in list(self.objects.items()):
|
||||||
if fn == docname:
|
if fn == docname:
|
||||||
del self.data['objects'][fullname]
|
del self.objects[fullname]
|
||||||
|
|
||||||
def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
|
def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
|
||||||
# XXX check duplicates
|
# XXX check duplicates
|
||||||
@ -290,9 +302,9 @@ class CDomain(Domain):
|
|||||||
# becase TypedField can generate xrefs
|
# becase TypedField can generate xrefs
|
||||||
if target in CObject.stopwords:
|
if target in CObject.stopwords:
|
||||||
return contnode
|
return contnode
|
||||||
if target not in self.data['objects']:
|
if target not in self.objects:
|
||||||
return None
|
return None
|
||||||
obj = self.data['objects'][target]
|
obj = self.objects[target]
|
||||||
return make_refnode(builder, fromdocname, obj[0], 'c.' + target,
|
return make_refnode(builder, fromdocname, obj[0], 'c.' + target,
|
||||||
contnode, target)
|
contnode, target)
|
||||||
|
|
||||||
@ -301,15 +313,15 @@ class CDomain(Domain):
|
|||||||
) -> List[Tuple[str, Element]]:
|
) -> List[Tuple[str, Element]]:
|
||||||
# strip pointer asterisk
|
# strip pointer asterisk
|
||||||
target = target.rstrip(' *')
|
target = target.rstrip(' *')
|
||||||
if target not in self.data['objects']:
|
if target not in self.objects:
|
||||||
return []
|
return []
|
||||||
obj = self.data['objects'][target]
|
obj = self.objects[target]
|
||||||
return [('c:' + self.role_for_objtype(obj[1]),
|
return [('c:' + self.role_for_objtype(obj[1]),
|
||||||
make_refnode(builder, fromdocname, obj[0], 'c.' + target,
|
make_refnode(builder, fromdocname, obj[0], 'c.' + target,
|
||||||
contnode, target))]
|
contnode, target))]
|
||||||
|
|
||||||
def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]:
|
def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]:
|
||||||
for refname, (docname, type) in list(self.data['objects'].items()):
|
for refname, (docname, type) in list(self.objects.items()):
|
||||||
yield (refname, refname, type, docname, 'c.' + refname, 1)
|
yield (refname, refname, type, docname, 'c.' + refname, 1)
|
||||||
|
|
||||||
|
|
||||||
|
@ -117,22 +117,9 @@ class ChangeSetDomain(Domain):
|
|||||||
'changes': {}, # version -> list of ChangeSet
|
'changes': {}, # version -> list of ChangeSet
|
||||||
} # type: Dict
|
} # type: Dict
|
||||||
|
|
||||||
def clear_doc(self, docname: str) -> None:
|
@property
|
||||||
for version, changes in self.data['changes'].items():
|
def changesets(self) -> Dict[str, List[ChangeSet]]:
|
||||||
for changeset in changes[:]:
|
return self.data.setdefault('changes', {}) # version -> list of ChangeSet
|
||||||
if changeset.docname == docname:
|
|
||||||
changes.remove(changeset)
|
|
||||||
|
|
||||||
def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
|
|
||||||
# XXX duplicates?
|
|
||||||
for version, otherchanges in otherdata['changes'].items():
|
|
||||||
changes = self.data['changes'].setdefault(version, [])
|
|
||||||
for changeset in otherchanges:
|
|
||||||
if changeset.docname in docnames:
|
|
||||||
changes.append(changeset)
|
|
||||||
|
|
||||||
def process_doc(self, env: "BuildEnvironment", docname: str, document: nodes.document) -> None: # NOQA
|
|
||||||
pass # nothing to do here. All changesets are registered on calling directive.
|
|
||||||
|
|
||||||
def note_changeset(self, node: addnodes.versionmodified) -> None:
|
def note_changeset(self, node: addnodes.versionmodified) -> None:
|
||||||
version = node['version']
|
version = node['version']
|
||||||
@ -140,10 +127,27 @@ class ChangeSetDomain(Domain):
|
|||||||
objname = self.env.temp_data.get('object')
|
objname = self.env.temp_data.get('object')
|
||||||
changeset = ChangeSet(node['type'], self.env.docname, node.line,
|
changeset = ChangeSet(node['type'], self.env.docname, node.line,
|
||||||
module, objname, node.astext())
|
module, objname, node.astext())
|
||||||
self.data['changes'].setdefault(version, []).append(changeset)
|
self.changesets.setdefault(version, []).append(changeset)
|
||||||
|
|
||||||
|
def clear_doc(self, docname: str) -> None:
|
||||||
|
for version, changes in self.changesets.items():
|
||||||
|
for changeset in changes[:]:
|
||||||
|
if changeset.docname == docname:
|
||||||
|
changes.remove(changeset)
|
||||||
|
|
||||||
|
def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
|
||||||
|
# XXX duplicates?
|
||||||
|
for version, otherchanges in otherdata['changes'].items():
|
||||||
|
changes = self.changesets.setdefault(version, [])
|
||||||
|
for changeset in otherchanges:
|
||||||
|
if changeset.docname in docnames:
|
||||||
|
changes.append(changeset)
|
||||||
|
|
||||||
|
def process_doc(self, env: "BuildEnvironment", docname: str, document: nodes.document) -> None: # NOQA
|
||||||
|
pass # nothing to do here. All changesets are registered on calling directive.
|
||||||
|
|
||||||
def get_changesets_for(self, version: str) -> List[ChangeSet]:
|
def get_changesets_for(self, version: str) -> List[ChangeSet]:
|
||||||
return self.data['changes'].get(version, [])
|
return self.changesets.get(version, [])
|
||||||
|
|
||||||
|
|
||||||
def setup(app: "Sphinx") -> Dict[str, Any]:
|
def setup(app: "Sphinx") -> Dict[str, Any]:
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Any, Dict, Iterator, List, Tuple
|
from typing import Any, Dict, Iterator, List, Tuple
|
||||||
|
from typing import cast
|
||||||
|
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
from docutils.nodes import Element, Node
|
from docutils.nodes import Element, Node
|
||||||
@ -22,13 +23,17 @@ from sphinx.directives import ObjectDescription
|
|||||||
from sphinx.domains import Domain, ObjType
|
from sphinx.domains import Domain, ObjType
|
||||||
from sphinx.domains.python import _pseudo_parse_arglist
|
from sphinx.domains.python import _pseudo_parse_arglist
|
||||||
from sphinx.environment import BuildEnvironment
|
from sphinx.environment import BuildEnvironment
|
||||||
from sphinx.locale import _
|
from sphinx.locale import _, __
|
||||||
from sphinx.roles import XRefRole
|
from sphinx.roles import XRefRole
|
||||||
|
from sphinx.util import logging
|
||||||
from sphinx.util.docfields import Field, GroupedField, TypedField
|
from sphinx.util.docfields import Field, GroupedField, TypedField
|
||||||
from sphinx.util.docutils import SphinxDirective
|
from sphinx.util.docutils import SphinxDirective
|
||||||
from sphinx.util.nodes import make_refnode
|
from sphinx.util.nodes import make_refnode
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class JSObject(ObjectDescription):
|
class JSObject(ObjectDescription):
|
||||||
"""
|
"""
|
||||||
Description of a JavaScript object.
|
Description of a JavaScript object.
|
||||||
@ -106,14 +111,10 @@ class JSObject(ObjectDescription):
|
|||||||
signode['ids'].append(fullname.replace('$', '_S_'))
|
signode['ids'].append(fullname.replace('$', '_S_'))
|
||||||
signode['first'] = not self.names
|
signode['first'] = not self.names
|
||||||
self.state.document.note_explicit_target(signode)
|
self.state.document.note_explicit_target(signode)
|
||||||
objects = self.env.domaindata['js']['objects']
|
|
||||||
if fullname in objects:
|
domain = cast(JavaScriptDomain, self.env.get_domain('js'))
|
||||||
self.state_machine.reporter.warning(
|
domain.note_object(fullname, self.objtype,
|
||||||
'duplicate object description of %s, ' % fullname +
|
location=(self.env.docname, self.lineno))
|
||||||
'other instance in ' +
|
|
||||||
self.env.doc2path(objects[fullname][0]),
|
|
||||||
line=self.lineno)
|
|
||||||
objects[fullname] = self.env.docname, self.objtype
|
|
||||||
|
|
||||||
indextext = self.get_index_text(mod_name, name_obj)
|
indextext = self.get_index_text(mod_name, name_obj)
|
||||||
if indextext:
|
if indextext:
|
||||||
@ -248,10 +249,13 @@ class JSModule(SphinxDirective):
|
|||||||
noindex = 'noindex' in self.options
|
noindex = 'noindex' in self.options
|
||||||
ret = [] # type: List[Node]
|
ret = [] # type: List[Node]
|
||||||
if not noindex:
|
if not noindex:
|
||||||
self.env.domaindata['js']['modules'][mod_name] = self.env.docname
|
domain = cast(JavaScriptDomain, self.env.get_domain('js'))
|
||||||
|
|
||||||
|
domain.note_module(mod_name)
|
||||||
# Make a duplicate entry in 'objects' to facilitate searching for
|
# Make a duplicate entry in 'objects' to facilitate searching for
|
||||||
# the module in JavaScriptDomain.find_obj()
|
# the module in JavaScriptDomain.find_obj()
|
||||||
self.env.domaindata['js']['objects'][mod_name] = (self.env.docname, 'module')
|
domain.note_object(mod_name, 'module', location=(self.env.docname, self.lineno))
|
||||||
|
|
||||||
targetnode = nodes.target('', '', ids=['module-' + mod_name],
|
targetnode = nodes.target('', '', ids=['module-' + mod_name],
|
||||||
ismod=True)
|
ismod=True)
|
||||||
self.state.document.note_explicit_target(targetnode)
|
self.state.document.note_explicit_target(targetnode)
|
||||||
@ -314,31 +318,48 @@ class JavaScriptDomain(Domain):
|
|||||||
}
|
}
|
||||||
initial_data = {
|
initial_data = {
|
||||||
'objects': {}, # fullname -> docname, objtype
|
'objects': {}, # fullname -> docname, objtype
|
||||||
'modules': {}, # mod_name -> docname
|
'modules': {}, # modname -> docname
|
||||||
} # type: Dict[str, Dict[str, Tuple[str, str]]]
|
} # type: Dict[str, Dict[str, Tuple[str, str]]]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def objects(self) -> Dict[str, Tuple[str, str]]:
|
||||||
|
return self.data.setdefault('objects', {}) # fullname -> docname, objtype
|
||||||
|
|
||||||
|
def note_object(self, fullname: str, objtype: str, location: Any = None) -> None:
|
||||||
|
if fullname in self.objects:
|
||||||
|
docname = self.objects[fullname][0]
|
||||||
|
logger.warning(__('duplicate object description of %s, other instance in %s'),
|
||||||
|
fullname, docname, location=location)
|
||||||
|
self.objects[fullname] = (self.env.docname, objtype)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def modules(self) -> Dict[str, str]:
|
||||||
|
return self.data.setdefault('modules', {}) # modname -> docname
|
||||||
|
|
||||||
|
def note_module(self, modname: str) -> None:
|
||||||
|
self.modules[modname] = self.env.docname
|
||||||
|
|
||||||
def clear_doc(self, docname: str) -> None:
|
def clear_doc(self, docname: str) -> None:
|
||||||
for fullname, (pkg_docname, _l) in list(self.data['objects'].items()):
|
for fullname, (pkg_docname, _l) in list(self.objects.items()):
|
||||||
if pkg_docname == docname:
|
if pkg_docname == docname:
|
||||||
del self.data['objects'][fullname]
|
del self.objects[fullname]
|
||||||
for mod_name, pkg_docname in list(self.data['modules'].items()):
|
for modname, pkg_docname in list(self.modules.items()):
|
||||||
if pkg_docname == docname:
|
if pkg_docname == docname:
|
||||||
del self.data['modules'][mod_name]
|
del self.modules[modname]
|
||||||
|
|
||||||
def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
|
def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
|
||||||
# XXX check duplicates
|
# XXX check duplicates
|
||||||
for fullname, (fn, objtype) in otherdata['objects'].items():
|
for fullname, (fn, objtype) in otherdata['objects'].items():
|
||||||
if fn in docnames:
|
if fn in docnames:
|
||||||
self.data['objects'][fullname] = (fn, objtype)
|
self.objects[fullname] = (fn, objtype)
|
||||||
for mod_name, pkg_docname in otherdata['modules'].items():
|
for mod_name, pkg_docname in otherdata['modules'].items():
|
||||||
if pkg_docname in docnames:
|
if pkg_docname in docnames:
|
||||||
self.data['modules'][mod_name] = pkg_docname
|
self.modules[mod_name] = pkg_docname
|
||||||
|
|
||||||
def find_obj(self, env: BuildEnvironment, mod_name: str, prefix: str, name: str,
|
def find_obj(self, env: BuildEnvironment, mod_name: str, prefix: str, name: str,
|
||||||
typ: str, searchorder: int = 0) -> Tuple[str, Tuple[str, str]]:
|
typ: str, searchorder: int = 0) -> Tuple[str, Tuple[str, str]]:
|
||||||
if name[-2:] == '()':
|
if name[-2:] == '()':
|
||||||
name = name[:-2]
|
name = name[:-2]
|
||||||
objects = self.data['objects']
|
|
||||||
|
|
||||||
searches = []
|
searches = []
|
||||||
if mod_name and prefix:
|
if mod_name and prefix:
|
||||||
@ -354,10 +375,10 @@ class JavaScriptDomain(Domain):
|
|||||||
|
|
||||||
newname = None
|
newname = None
|
||||||
for search_name in searches:
|
for search_name in searches:
|
||||||
if search_name in objects:
|
if search_name in self.objects:
|
||||||
newname = search_name
|
newname = search_name
|
||||||
|
|
||||||
return newname, objects.get(newname)
|
return newname, self.objects.get(newname)
|
||||||
|
|
||||||
def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
|
def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
|
||||||
typ: str, target: str, node: pending_xref, contnode: Element
|
typ: str, target: str, node: pending_xref, contnode: Element
|
||||||
@ -384,9 +405,8 @@ class JavaScriptDomain(Domain):
|
|||||||
name.replace('$', '_S_'), contnode, name))]
|
name.replace('$', '_S_'), contnode, name))]
|
||||||
|
|
||||||
def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]:
|
def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]:
|
||||||
for refname, (docname, type) in list(self.data['objects'].items()):
|
for refname, (docname, type) in list(self.objects.items()):
|
||||||
yield refname, refname, type, docname, \
|
yield refname, refname, type, docname, refname.replace('$', '_S_'), 1
|
||||||
refname.replace('$', '_S_'), 1
|
|
||||||
|
|
||||||
def get_full_qualified_name(self, node: Element) -> str:
|
def get_full_qualified_name(self, node: Element) -> str:
|
||||||
modname = node.get('js:module')
|
modname = node.get('js:module')
|
||||||
|
Loading…
Reference in New Issue
Block a user