mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Add glossary directive and :term: role for crossreferencing into the glossary.
This commit is contained in:
parent
a826246980
commit
12cfdea91f
1
TODO
1
TODO
@ -9,4 +9,3 @@ Global TODO
|
||||
- look at the old tools/ scripts, what functionality should be rewritten
|
||||
- add search via Xapian?
|
||||
- optionally have a contents tree view in the sidebar (AJAX based)?
|
||||
- .. caveat?
|
@ -53,9 +53,13 @@ class highlightlang(nodes.Element): pass
|
||||
# like emphasis, but doesn't apply further text processors, e.g. smartypants
|
||||
class literal_emphasis(nodes.emphasis): pass
|
||||
|
||||
# glossary
|
||||
class glossary(nodes.Element): pass
|
||||
|
||||
# make them known to docutils. this is needed, because the HTMl writer
|
||||
# will choke at some point if these are not added
|
||||
nodes._add_node_class_names("""index desc desc_content desc_signature
|
||||
desc_classname desc_name desc_parameterlist desc_parameter desc_optional
|
||||
centered versionmodified seealso productionlist production toctree
|
||||
pending_xref compact_paragraph highlightlang""".split())
|
||||
pending_xref compact_paragraph highlightlang literal_emphasis
|
||||
glossary""".split())
|
||||
|
@ -579,3 +579,35 @@ def literalinclude_directive(name, arguments, options, content, lineno,
|
||||
literalinclude_directive.content = 0
|
||||
literalinclude_directive.arguments = (1, 0, 0)
|
||||
directives.register_directive('literalinclude', literalinclude_directive)
|
||||
|
||||
|
||||
# ------ glossary directive ---------------------------------------------------------
|
||||
|
||||
def glossary_directive(name, arguments, options, content, lineno,
|
||||
content_offset, block_text, state, state_machine):
|
||||
"""Glossary with cross-reference targets for :dfn: roles."""
|
||||
env = state.document.settings.env
|
||||
node = addnodes.glossary()
|
||||
state.nested_parse(content, content_offset, node)
|
||||
|
||||
# the content should be definition lists
|
||||
dls = [child for child in node if isinstance(child, nodes.definition_list)]
|
||||
# now, extract definition terms to enable cross-reference creation
|
||||
for dl in dls:
|
||||
dl['classes'].append('glossary')
|
||||
for li in dl.children:
|
||||
if not li.children or not isinstance(li[0], nodes.term):
|
||||
continue
|
||||
termtext = li.children[0].astext()
|
||||
new_id = 'term-' + nodes.make_id(termtext)
|
||||
if new_id in env.gloss_entries:
|
||||
new_id = 'term-' + str(len(env.gloss_entries))
|
||||
env.gloss_entries.add(new_id)
|
||||
li[0]['names'].append(new_id)
|
||||
li[0]['ids'].append(new_id)
|
||||
state.document.settings.env.note_glossaryterm(termtext, new_id)
|
||||
return [node]
|
||||
|
||||
glossary_directive.content = 1
|
||||
glossary_directive.arguments = (0, 0, 0)
|
||||
directives.register_directive('glossary', glossary_directive)
|
||||
|
@ -52,7 +52,7 @@ default_settings = {
|
||||
|
||||
# This is increased every time a new environment attribute is added
|
||||
# to properly invalidate pickle files.
|
||||
ENV_VERSION = 10
|
||||
ENV_VERSION = 11
|
||||
|
||||
|
||||
def walk_depth(node, depth, maxdepth):
|
||||
@ -206,6 +206,7 @@ class BuildEnvironment:
|
||||
self.modules = {} # modname -> filename, synopsis, platform, deprecated
|
||||
self.tokens = {} # tokenname -> filename
|
||||
self.labels = {} # labelname -> filename, labelid
|
||||
self.glossary = {} # term -> filename, labelid
|
||||
|
||||
# Other inventories
|
||||
self.indexentries = {} # filename -> list of
|
||||
@ -219,6 +220,7 @@ class BuildEnvironment:
|
||||
self.currclass = None # current class name
|
||||
self.currdesc = None # current descref name
|
||||
self.index_num = 0 # autonumber for index targets
|
||||
self.gloss_entries = set() # existing definition labels
|
||||
|
||||
def set_warning_stream(self, stream):
|
||||
self.warning_stream = stream
|
||||
@ -247,6 +249,9 @@ class BuildEnvironment:
|
||||
for labelname, (fn, _, _) in self.labels.items():
|
||||
if fn == filename:
|
||||
del self.labels[labelname]
|
||||
for term, (fn, _) in self.glossary.items():
|
||||
if fn == filename:
|
||||
del self.glossary[term]
|
||||
self.indexentries.pop(filename, None)
|
||||
for version, changes in self.versionchanges.items():
|
||||
new = [change for change in changes if change[1] != filename]
|
||||
@ -351,6 +356,8 @@ class BuildEnvironment:
|
||||
self.filename = None
|
||||
self.currmodule = None
|
||||
self.currclass = None
|
||||
self.indexnum = 0
|
||||
self.gloss_entries = set()
|
||||
|
||||
if save_parsed:
|
||||
# save the parsed doctree
|
||||
@ -497,7 +504,6 @@ class BuildEnvironment:
|
||||
def note_token(self, tokenname):
|
||||
self.tokens[tokenname] = self.filename
|
||||
|
||||
|
||||
def note_index_entry(self, type, string, targetid, aliasname):
|
||||
self.indexentries.setdefault(self.filename, []).append(
|
||||
(type, string, targetid, aliasname))
|
||||
@ -505,6 +511,9 @@ class BuildEnvironment:
|
||||
def note_versionchange(self, type, version, node):
|
||||
self.versionchanges.setdefault(version, []).append(
|
||||
(type, self.filename, self.currmodule, self.currdesc, node.deepcopy()))
|
||||
|
||||
def note_glossaryterm(self, text, labelname):
|
||||
self.glossary[text] = (self.filename, labelname)
|
||||
# -------
|
||||
|
||||
# --------- RESOLVING REFERENCES AND TOCTREES ------------------------------
|
||||
@ -592,6 +601,20 @@ class BuildEnvironment:
|
||||
newnode['refuri'] = builder.get_relative_uri(
|
||||
docfilename, filename) + '#' + labelid
|
||||
newnode.append(nodes.emphasis(sectname, sectname))
|
||||
elif typ == 'term':
|
||||
filename, labelid = self.glossary.get(target, ('', ''))
|
||||
if not filename:
|
||||
print >>self.warning_stream, \
|
||||
'%s: term not in glossary: %s' % (docfilename, target)
|
||||
newnode = contnode
|
||||
else:
|
||||
newnode = nodes.reference('', '')
|
||||
if filename == docfilename:
|
||||
newnode['refid'] = labelid
|
||||
else:
|
||||
newnode['refuri'] = builder.get_relative_uri(
|
||||
docfilename, filename) + '#' + labelid
|
||||
newnode.append(contnode)
|
||||
elif typ == 'token':
|
||||
filename = self.tokens.get(target, '')
|
||||
if not filename:
|
||||
|
@ -20,7 +20,7 @@ ws_re = re.compile(r'\s+')
|
||||
|
||||
generic_docroles = {
|
||||
'command' : nodes.strong,
|
||||
'dfn' : addnodes.literal_emphasis,
|
||||
'dfn' : addnodes.emphasis,
|
||||
'guilabel' : nodes.strong,
|
||||
'kbd' : nodes.literal,
|
||||
'keyword' : nodes.literal,
|
||||
@ -89,6 +89,7 @@ roles.register_local_role('rfc', indexmarkup_role)
|
||||
# default is `literal`
|
||||
innernodetypes = {
|
||||
'ref': nodes.emphasis,
|
||||
'term': nodes.emphasis,
|
||||
'token': nodes.strong,
|
||||
}
|
||||
|
||||
@ -106,7 +107,7 @@ def xfileref_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
typ in ('data', 'exc', 'func', 'class', 'const', 'attr', 'meth'):
|
||||
text = text[1:]
|
||||
pnode['refspecific'] = True
|
||||
pnode['reftarget'] = ws_re.sub('', text)
|
||||
pnode['reftarget'] = ws_re.sub((' ' if typ == 'term' else ''), text)
|
||||
pnode['modname'] = env.currmodule
|
||||
pnode['classname'] = env.currclass
|
||||
pnode += innernodetypes.get(typ, nodes.literal)(rawtext, text, classes=['xref'])
|
||||
@ -153,6 +154,7 @@ specific_docroles = {
|
||||
|
||||
'ref': xfileref_role,
|
||||
'token' : xfileref_role,
|
||||
'term': xfileref_role,
|
||||
|
||||
'menuselection' : menusel_role,
|
||||
'file' : emph_literal_role,
|
||||
|
@ -691,6 +691,11 @@ dt:target,
|
||||
background-color: #fbe54e;
|
||||
}
|
||||
|
||||
dl.glossary dt {
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
padding-right: 5px;
|
||||
|
@ -591,6 +591,11 @@ dd {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
dl.glossary dt {
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.refcount {
|
||||
color: #060;
|
||||
}
|
||||
|
@ -44,6 +44,8 @@
|
||||
<span class="linkdescr">quick access to all modules</span></p>
|
||||
<p class="biglink"><a class="biglink" href="{{ pathto("genindex.rst") }}">General Index</a><br>
|
||||
<span class="linkdescr">all functions, classes, terms</span></p>
|
||||
<p class="biglink"><a class="biglink" href="{{ pathto("glossary.rst") }}">Glossary</a><br>
|
||||
<span class="linkdescr">the most important terms explained</span></p>
|
||||
</td><td width="50%">
|
||||
<p class="biglink"><a class="biglink" href="{{ pathto("search.rst") }}">Search page</a><br>
|
||||
<span class="linkdescr">search this documentation</span></p>
|
||||
|
@ -211,6 +211,11 @@ class HTMLTranslator(BaseTranslator):
|
||||
def visit_index(self, node):
|
||||
raise nodes.SkipNode
|
||||
|
||||
def visit_glossary(self, node):
|
||||
pass
|
||||
def depart_glossary(self, node):
|
||||
pass
|
||||
|
||||
# these are only handled specially in the SmartyPantsHTMLTranslator
|
||||
def visit_literal_emphasis(self, node):
|
||||
return self.visit_emphasis(node)
|
||||
|
Loading…
Reference in New Issue
Block a user