summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshimizukawa <shimizukawa@gmail.com>2016-02-13 22:30:06 +0900
committershimizukawa <shimizukawa@gmail.com>2016-02-14 19:28:58 +0900
commite6a5a3a92e938fcd75866b4227db9e0524d58f7c (patch)
tree193a7211fd4ce3a042e087f8c9b836de040f5bbe
parent358a13ee72a538eed1c1d8b5001cf68760934e22 (diff)
downloadsphinx-git-e6a5a3a92e938fcd75866b4227db9e0524d58f7c.tar.gz
classifier of glossary terms can be used for index entries grouping key. The classifier also be used for translation. See also :ref:`glossary-directive`.
-rw-r--r--CHANGES2
-rw-r--r--doc/markup/para.rst20
-rw-r--r--sphinx/builders/epub.py2
-rw-r--r--sphinx/builders/gettext.py2
-rw-r--r--sphinx/builders/html.py2
-rw-r--r--sphinx/builders/htmlhelp.py2
-rw-r--r--sphinx/builders/qthelp.py2
-rw-r--r--sphinx/domains/c.py2
-rw-r--r--sphinx/domains/cpp.py2
-rw-r--r--sphinx/domains/javascript.py2
-rw-r--r--sphinx/domains/python.py4
-rw-r--r--sphinx/domains/rst.py2
-rw-r--r--sphinx/domains/std.py53
-rw-r--r--sphinx/environment.py49
-rw-r--r--sphinx/roles.py7
-rw-r--r--sphinx/themes/basic/genindex.html2
-rw-r--r--sphinx/transforms.py13
-rw-r--r--sphinx/util/nodes.py6
-rw-r--r--sphinx/writers/latex.py2
-rw-r--r--sphinx/writers/texinfo.py2
20 files changed, 112 insertions, 66 deletions
diff --git a/CHANGES b/CHANGES
index 9310b45a2..d93935e32 100644
--- a/CHANGES
+++ b/CHANGES
@@ -73,6 +73,8 @@ Features added
sections using its title. Thanks to Tadhg O'Higgins.
* #1854: Allow to choose Janome for Japanese splitter.
* #1853: support custom text splitter on html search with `language='ja'`.
+* #2320: classifier of glossary terms can be used for index entries grouping key.
+ The classifier also be used for translation. See also :ref:`glossary-directive`.
Bugs fixed
----------
diff --git a/doc/markup/para.rst b/doc/markup/para.rst
index cc03a9f13..ba2cc52f5 100644
--- a/doc/markup/para.rst
+++ b/doc/markup/para.rst
@@ -183,6 +183,24 @@ Glossary
(When the glossary is sorted, the first term determines the sort order.)
+ If you want to specify "grouping key" for general index entries, you can put a "key"
+ as "term : key". For example::
+
+ .. glossary::
+
+ term 1 : A
+ term 2 : B
+ Definition of both terms.
+
+ Note that "key" is used for grouping key as is.
+ The "key" isn't normalized; key "A" and "a" become different groups.
+ The whole characters in "key" is used instead of a first character; it is used for
+ "Combining Character Sequence" and "Surrogate Pairs" grouping key.
+
+ In i18n situation, you can specify "localized term : key" even if original text only
+ have "term" part. In this case, translated "localized term" will be categorized in
+ "key" group.
+
.. versionadded:: 0.6
You can now give the glossary directive a ``:sorted:`` flag that will
automatically sort the entries alphabetically.
@@ -190,6 +208,8 @@ Glossary
.. versionchanged:: 1.1
Now supports multiple terms and inline markup in terms.
+ .. versionchanged:: 1.4
+ Index key for glossary term should be considered *experimental*.
Grammar production displays
---------------------------
diff --git a/sphinx/builders/epub.py b/sphinx/builders/epub.py
index fde2cbc12..8c0109264 100644
--- a/sphinx/builders/epub.py
+++ b/sphinx/builders/epub.py
@@ -400,7 +400,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
# XXX: modifies tree inline
# Logic modeled from themes/basic/genindex.html
for key, columns in tree:
- for entryname, (links, subitems) in columns:
+ for entryname, (links, subitems, key_) in columns:
for (i, (ismain, link)) in enumerate(links):
m = self.refuri_re.match(link)
if m:
diff --git a/sphinx/builders/gettext.py b/sphinx/builders/gettext.py
index 21c692f3f..fce6c8cc1 100644
--- a/sphinx/builders/gettext.py
+++ b/sphinx/builders/gettext.py
@@ -117,7 +117,7 @@ class I18nBuilder(Builder):
if 'index' in self.env.config.gettext_additional_targets:
# Extract translatable messages from index entries.
for node, entries in traverse_translatable_index(doctree):
- for typ, msg, tid, main in entries:
+ for typ, msg, tid, main, key_ in entries:
for m in split_index_msg(typ, msg):
if typ == 'pair' and m in pairindextypes.values():
# avoid built-in translated message was incorporated
diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py
index 03199f3b9..899c17d98 100644
--- a/sphinx/builders/html.py
+++ b/sphinx/builders/html.py
@@ -512,7 +512,7 @@ class StandaloneHTMLBuilder(Builder):
indexcounts = []
for _k, entries in genindex:
indexcounts.append(sum(1 + len(subitems)
- for _, (_, subitems) in entries))
+ for _, (_, subitems, _) in entries))
genindexcontext = dict(
genindexentries = genindex,
diff --git a/sphinx/builders/htmlhelp.py b/sphinx/builders/htmlhelp.py
index 2f06cb0e1..f4003c4c9 100644
--- a/sphinx/builders/htmlhelp.py
+++ b/sphinx/builders/htmlhelp.py
@@ -299,7 +299,7 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
write_index(subitem[0], subitem[1], [])
f.write('</UL>')
for (key, group) in index:
- for title, (refs, subitems) in group:
+ for title, (refs, subitems, key_) in group:
write_index(title, refs, subitems)
f.write('</UL>\n')
finally:
diff --git a/sphinx/builders/qthelp.py b/sphinx/builders/qthelp.py
index f6cfa84c5..0a7e85c92 100644
--- a/sphinx/builders/qthelp.py
+++ b/sphinx/builders/qthelp.py
@@ -148,7 +148,7 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
keywords = []
index = self.env.create_index(self, group_entries=False)
for (key, group) in index:
- for title, (refs, subitems) in group:
+ for title, (refs, subitems, key_) in group:
keywords.extend(self.build_keywords(title, refs, subitems))
keywords = u'\n'.join(keywords)
diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py
index 23ed04d05..c7fd0681e 100644
--- a/sphinx/domains/c.py
+++ b/sphinx/domains/c.py
@@ -206,7 +206,7 @@ class CObject(ObjectDescription):
indextext = self.get_index_text(name)
if indextext:
self.indexnode['entries'].append(('single', indextext,
- targetname, ''))
+ targetname, '', None))
def before_content(self):
self.typename_set = False
diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py
index 10602931d..a932227a6 100644
--- a/sphinx/domains/cpp.py
+++ b/sphinx/domains/cpp.py
@@ -3677,7 +3677,7 @@ class CPPObject(ObjectDescription):
name = text_type(ast.symbol.get_full_nested_name()).lstrip(':')
indexText = self.get_index_text(name)
- self.indexnode['entries'].append(('single', indexText, newestId, ''))
+ self.indexnode['entries'].append(('single', indexText, newestId, '', None))
if newestId not in self.state.document.ids:
# if the name is not unique, the first one will win
diff --git a/sphinx/domains/javascript.py b/sphinx/domains/javascript.py
index f7e2703e4..b5f64022a 100644
--- a/sphinx/domains/javascript.py
+++ b/sphinx/domains/javascript.py
@@ -97,7 +97,7 @@ class JSObject(ObjectDescription):
if indextext:
self.indexnode['entries'].append(('single', indextext,
fullname.replace('$', '_S_'),
- ''))
+ '', None))
def get_index_text(self, objectname, name_obj):
name, obj = name_obj
diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py
index ba5998084..1639d8288 100644
--- a/sphinx/domains/python.py
+++ b/sphinx/domains/python.py
@@ -257,7 +257,7 @@ class PyObject(ObjectDescription):
indextext = self.get_index_text(modname, name_cls)
if indextext:
self.indexnode['entries'].append(('single', indextext,
- fullname, ''))
+ fullname, '', None))
def before_content(self):
# needed for automatic qualification of members (reset in subclasses)
@@ -462,7 +462,7 @@ class PyModule(Directive):
ret.append(targetnode)
indextext = _('%s (module)') % modname
inode = addnodes.index(entries=[('single', indextext,
- 'module-' + modname, '')])
+ 'module-' + modname, '', None)])
ret.append(inode)
return ret
diff --git a/sphinx/domains/rst.py b/sphinx/domains/rst.py
index f0ad66ddc..b11c9450b 100644
--- a/sphinx/domains/rst.py
+++ b/sphinx/domains/rst.py
@@ -48,7 +48,7 @@ class ReSTMarkup(ObjectDescription):
indextext = self.get_index_text(self.objtype, name)
if indextext:
self.indexnode['entries'].append(('single', indextext,
- targetname, ''))
+ targetname, '', None))
def get_index_text(self, objectname, name):
if self.objtype == 'directive':
diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py
index 974f428aa..501d6ea30 100644
--- a/sphinx/domains/std.py
+++ b/sphinx/domains/std.py
@@ -64,7 +64,7 @@ class GenericObject(ObjectDescription):
indextype = 'single'
indexentry = self.indextemplate % (name,)
self.indexnode['entries'].append((indextype, indexentry,
- targetname, ''))
+ targetname, '', None))
self.env.domaindata['std']['objects'][self.objtype, name] = \
self.env.docname, targetname
@@ -85,8 +85,8 @@ class EnvVarXRefRole(XRefRole):
tgtid = 'index-%s' % env.new_serialno('index')
indexnode = addnodes.index()
indexnode['entries'] = [
- ('single', varname, tgtid, ''),
- ('single', _('environment variable; %s') % varname, tgtid, '')
+ ('single', varname, tgtid, '', None),
+ ('single', _('environment variable; %s') % varname, tgtid, '', None)
]
targetnode = nodes.target('', '', ids=[tgtid])
document.note_explicit_target(targetnode)
@@ -184,7 +184,7 @@ class Cmdoption(ObjectDescription):
self.indexnode['entries'].append(
('pair', _('%scommand line option; %s') %
((currprogram and currprogram + ' ' or ''), sig),
- targetname, ''))
+ targetname, '', None))
class Program(Directive):
@@ -214,11 +214,23 @@ class OptionXRefRole(XRefRole):
return title, target
-def register_term_to_glossary(env, node, new_id=None):
+def split_term_classifiers(line):
+ # split line into a term and classifiers. if no classifier, None is used..
+ parts = re.split(' +: +', line) + [None]
+ return parts
+
+
+def make_glossary_term(env, textnodes, index_key, source, lineno, new_id=None):
+ # get a text-only representation of the term and register it
+ # as a cross-reference target
+ term = nodes.term('', '', *textnodes)
+ term.source = source
+ term.line = lineno
+
gloss_entries = env.temp_data.setdefault('gloss_entries', set())
objects = env.domaindata['std']['objects']
- termtext = node.astext()
+ termtext = term.astext()
if new_id is None:
new_id = nodes.make_id('term-' + termtext)
if new_id in gloss_entries:
@@ -228,11 +240,13 @@ def register_term_to_glossary(env, node, new_id=None):
# add an index entry too
indexnode = addnodes.index()
- indexnode['entries'] = [('single', termtext, new_id, 'main')]
- indexnode.source, indexnode.line = node.source, node.line
- node.append(indexnode)
- node['ids'].append(new_id)
- node['names'].append(new_id)
+ indexnode['entries'] = [('single', termtext, new_id, 'main', index_key)]
+ indexnode.source, indexnode.line = term.source, term.line
+ term.append(indexnode)
+ term['ids'].append(new_id)
+ term['names'].append(new_id)
+
+ return term
class Glossary(Directive):
@@ -316,16 +330,15 @@ class Glossary(Directive):
termnodes = []
system_messages = []
for line, source, lineno in terms:
+ parts = split_term_classifiers(line)
# parse the term with inline markup
- res = self.state.inline_text(line, lineno)
- system_messages.extend(res[1])
-
- # get a text-only representation of the term and register it
- # as a cross-reference target
- term = nodes.term('', '', *res[0])
- term.source = source
- term.line = lineno
- register_term_to_glossary(env, term)
+ # classifiers (parts[1:]) will not be shown on doctree
+ textnodes, sysmsg = self.state.inline_text(parts[0], lineno)
+
+ # use first classifier as a index key
+ term = make_glossary_term(env, textnodes, parts[1], source, lineno)
+ term.rawsource = line
+ system_messages.extend(sysmsg)
termtexts.append(term.astext())
termnodes.append(term)
diff --git a/sphinx/environment.py b/sphinx/environment.py
index 2d653289c..53d54ba7b 100644
--- a/sphinx/environment.py
+++ b/sphinx/environment.py
@@ -1049,7 +1049,7 @@ class BuildEnvironment:
entries = self.indexentries[docname] = []
for node in document.traverse(addnodes.index):
try:
- for type, value, tid, main in node['entries']:
+ for type, value, tid, main, index_key in node['entries']:
split_index_msg(type, value)
except ValueError as exc:
self.warn_node(exc, node)
@@ -1771,16 +1771,16 @@ class BuildEnvironment:
"""Create the real index from the collected index entries."""
new = {}
- def add_entry(word, subword, link=True, dic=new):
+ def add_entry(word, subword, link=True, dic=new, key=None):
# Force the word to be unicode if it's a ASCII bytestring.
# This will solve problems with unicode normalization later.
# For instance the RFC role will add bytestrings at the moment
word = text_type(word)
entry = dic.get(word)
if not entry:
- dic[word] = entry = [[], {}]
+ dic[word] = entry = [[], {}, key]
if subword:
- add_entry(subword, '', link=link, dic=entry[1])
+ add_entry(subword, '', link=link, dic=entry[1], key=key)
elif link:
try:
uri = builder.get_relative_uri('genindex', fn) + '#' + tid
@@ -1792,7 +1792,7 @@ class BuildEnvironment:
for fn, entries in iteritems(self.indexentries):
# new entry types must be listed in directives/other.py!
- for type, value, tid, main in entries:
+ for type, value, tid, main, index_key in entries:
try:
if type == 'single':
try:
@@ -1800,22 +1800,24 @@ class BuildEnvironment:
except ValueError:
entry, = split_into(1, 'single', value)
subentry = ''
- add_entry(entry, subentry)
+ add_entry(entry, subentry, key=index_key)
elif type == 'pair':
first, second = split_into(2, 'pair', value)
- add_entry(first, second)
- add_entry(second, first)
+ add_entry(first, second, key=index_key)
+ add_entry(second, first, key=index_key)
elif type == 'triple':
first, second, third = split_into(3, 'triple', value)
- add_entry(first, second+' '+third)
- add_entry(second, third+', '+first)
- add_entry(third, first+' '+second)
+ add_entry(first, second+' '+third, key=index_key)
+ add_entry(second, third+', '+first, key=index_key)
+ add_entry(third, first+' '+second, key=index_key)
elif type == 'see':
first, second = split_into(2, 'see', value)
- add_entry(first, _('see %s') % second, link=False)
+ add_entry(first, _('see %s') % second, link=False,
+ key=index_key)
elif type == 'seealso':
first, second = split_into(2, 'see', value)
- add_entry(first, _('see also %s') % second, link=False)
+ add_entry(first, _('see also %s') % second, link=False,
+ key=index_key)
else:
self.warn(fn, 'unknown index entry type %r' % type)
except ValueError as err:
@@ -1844,7 +1846,7 @@ class BuildEnvironment:
oldsubitems = None
i = 0
while i < len(newlist):
- key, (targets, subitems) = newlist[i]
+ key, (targets, subitems, _key) = newlist[i]
# cannot move if it has subitems; structure gets too complex
if not subitems:
m = _fixre.match(key)
@@ -1852,7 +1854,7 @@ class BuildEnvironment:
if oldkey == m.group(1):
# prefixes match: add entry as subitem of the
# previous entry
- oldsubitems.setdefault(m.group(2), [[], {}])[0].\
+ oldsubitems.setdefault(m.group(2), [[], {}, _key])[0].\
extend(targets)
del newlist[i]
continue
@@ -1866,14 +1868,17 @@ class BuildEnvironment:
def keyfunc2(item, letters=string.ascii_uppercase + '_'):
# hack: mutating the subitems dicts to a list in the keyfunc
k, v = item
- v[1] = sorted((si, se) for (si, (se, void)) in iteritems(v[1]))
- # now calculate the key
- letter = unicodedata.normalize('NFD', k[0])[0].upper()
- if letter in letters:
- return letter
+ v[1] = sorted((si, se) for (si, (se, void, void)) in iteritems(v[1]))
+ if v[2] is None:
+ # now calculate the key
+ letter = unicodedata.normalize('NFD', k[0])[0].upper()
+ if letter in letters:
+ return letter
+ else:
+ # get all other symbols under one heading
+ return _('Symbols')
else:
- # get all other symbols under one heading
- return _('Symbols')
+ return v[2]
return [(key_, list(group))
for (key_, group) in groupby(newlist, keyfunc2)]
diff --git a/sphinx/roles.py b/sphinx/roles.py
index 59d69a1f1..a6583a6ea 100644
--- a/sphinx/roles.py
+++ b/sphinx/roles.py
@@ -191,7 +191,7 @@ def indexmarkup_role(typ, rawtext, text, lineno, inliner,
if typ == 'pep':
indexnode['entries'] = [
('single', _('Python Enhancement Proposals; PEP %s') % target,
- targetid, '')]
+ targetid, '', None)]
anchor = ''
anchorindex = target.find('#')
if anchorindex > 0:
@@ -212,7 +212,8 @@ def indexmarkup_role(typ, rawtext, text, lineno, inliner,
rn += sn
return [indexnode, targetnode, rn], []
elif typ == 'rfc':
- indexnode['entries'] = [('single', 'RFC; RFC %s' % target, targetid, '')]
+ indexnode['entries'] = [
+ ('single', 'RFC; RFC %s' % target, targetid, '', None)]
anchor = ''
anchorindex = target.find('#')
if anchorindex > 0:
@@ -317,7 +318,7 @@ def index_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
target = target[1:]
title = title[1:]
main = 'main'
- entries = [('single', target, targetid, main)]
+ entries = [('single', target, targetid, main, None)]
indexnode = addnodes.index()
indexnode['entries'] = entries
set_role_source_info(inliner, lineno, indexnode)
diff --git a/sphinx/themes/basic/genindex.html b/sphinx/themes/basic/genindex.html
index 69c4ec564..fac7f1899 100644
--- a/sphinx/themes/basic/genindex.html
+++ b/sphinx/themes/basic/genindex.html
@@ -46,7 +46,7 @@
<table style="width: 100%" class="indextable genindextable"><tr>
{%- for column in entries|slice(2) if column %}
<td style="width: 33%" valign="top"><dl>
- {%- for entryname, (links, subitems) in column %}
+ {%- for entryname, (links, subitems, _) in column %}
{{ indexentries(entryname, links) }}
{%- if subitems %}
<dd><dl>
diff --git a/sphinx/transforms.py b/sphinx/transforms.py
index 0d22020af..a5d44d73f 100644
--- a/sphinx/transforms.py
+++ b/sphinx/transforms.py
@@ -27,7 +27,7 @@ from sphinx.util.nodes import (
from sphinx.util.osutil import ustrftime
from sphinx.util.i18n import find_catalog
from sphinx.util.pycompat import indent
-from sphinx.domains.std import register_term_to_glossary
+from sphinx.domains.std import make_glossary_term, split_term_classifiers
default_substitutions = set([
@@ -340,7 +340,12 @@ class Locale(Transform):
for _id in node['names']:
if _id in gloss_entries:
gloss_entries.remove(_id)
- register_term_to_glossary(env, patch, _id)
+
+ parts = split_term_classifiers(msgstr)
+ patch = publish_msgstr(
+ env.app, parts[0], source, node.line, env.config, settings)
+ patch = make_glossary_term(
+ env, patch, parts[1], source, node.line, _id)
node['ids'] = patch['ids']
node['names'] = patch['names']
processed = True
@@ -521,7 +526,7 @@ class Locale(Transform):
# Extract and translate messages for index entries.
for node, entries in traverse_translatable_index(self.document):
new_entries = []
- for type, msg, tid, main in entries:
+ for type, msg, tid, main, key_ in entries:
msg_parts = split_index_msg(type, msg)
msgstr_parts = []
for part in msg_parts:
@@ -530,7 +535,7 @@ class Locale(Transform):
msgstr = part
msgstr_parts.append(msgstr)
- new_entries.append((type, ';'.join(msgstr_parts), tid, main))
+ new_entries.append((type, ';'.join(msgstr_parts), tid, main, None))
node['raw_entries'] = entries
node['entries'] = new_entries
diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py
index ccea95777..98f84f2bf 100644
--- a/sphinx/util/nodes.py
+++ b/sphinx/util/nodes.py
@@ -213,7 +213,7 @@ def process_index_entry(entry, targetid):
if entry.startswith(type+':'):
value = entry[len(type)+1:].strip()
value = pairindextypes[type] + '; ' + value
- indexentries.append(('pair', value, targetid, main))
+ indexentries.append(('pair', value, targetid, main, None))
break
else:
for type in indextypes:
@@ -221,7 +221,7 @@ def process_index_entry(entry, targetid):
value = entry[len(type)+1:].strip()
if type == 'double':
type = 'pair'
- indexentries.append((type, value, targetid, main))
+ indexentries.append((type, value, targetid, main, None))
break
# shorthand notation for single entries
else:
@@ -233,7 +233,7 @@ def process_index_entry(entry, targetid):
value = value[1:].lstrip()
if not value:
continue
- indexentries.append(('single', value, targetid, main))
+ indexentries.append(('single', value, targetid, main, None))
return indexentries
diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py
index 6eb287ce9..151db3854 100644
--- a/sphinx/writers/latex.py
+++ b/sphinx/writers/latex.py
@@ -1531,7 +1531,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
if not node.get('inline', True):
self.body.append('\n')
entries = node['entries']
- for type, string, tid, ismain in entries:
+ for type, string, tid, ismain, key_ in entries:
m = ''
if ismain:
m = '|textbf'
diff --git a/sphinx/writers/texinfo.py b/sphinx/writers/texinfo.py
index c29b9dda0..360b7d56d 100644
--- a/sphinx/writers/texinfo.py
+++ b/sphinx/writers/texinfo.py
@@ -1302,7 +1302,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
else:
self.body.append('\n')
for entry in node['entries']:
- typ, text, tid, text2 = entry
+ typ, text, tid, text2, key_ = entry
text = self.escape_menu(text)
self.body.append('@geindex %s\n' % text)