From 6ed4d37503a068bfde25c61fbfd320001765feac Mon Sep 17 00:00:00 2001 From: sethg Date: Sat, 1 Feb 2020 23:10:00 +0100 Subject: [PATCH 01/10] Add name option for index links --- sphinx/domains/index.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sphinx/domains/index.py b/sphinx/domains/index.py index d0bdbcfe0..ee24d2522 100644 --- a/sphinx/domains/index.py +++ b/sphinx/domains/index.py @@ -12,6 +12,7 @@ from typing import Any, Dict, Iterable, List, Tuple from docutils import nodes from docutils.nodes import Node, system_message +from docutils.parsers.rst import directives from sphinx import addnodes from sphinx.domains import Domain @@ -68,11 +69,16 @@ class IndexDirective(SphinxDirective): required_arguments = 1 optional_arguments = 0 final_argument_whitespace = True - option_spec = {} # type: Dict + option_spec = { + 'name': directives.unchanged, + } # type: Dict def run(self) -> List[Node]: arguments = self.arguments[0].split('\n') - targetid = 'index-%s' % self.env.new_serialno('index') + if 'name' in self.options: + targetid = 'index-%s' % self.options['name'] + else: + targetid = 'index-%s' % self.env.new_serialno('index') targetnode = nodes.target('', '', ids=[targetid]) self.state.document.note_explicit_target(targetnode) indexnode = addnodes.index() From 28ad37034311d510dc436cc899839b213914e294 Mon Sep 17 00:00:00 2001 From: sethg Date: Sun, 16 Feb 2020 21:37:41 +0100 Subject: [PATCH 02/10] Add option to docs --- doc/usage/restructuredtext/directives.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/usage/restructuredtext/directives.rst b/doc/usage/restructuredtext/directives.rst index 291a6ddc0..933d213c9 100644 --- a/doc/usage/restructuredtext/directives.rst +++ b/doc/usage/restructuredtext/directives.rst @@ -874,6 +874,19 @@ mainly contained in information units, such as the language reference. .. versionchanged:: 1.1 Added ``see`` and ``seealso`` types, as well as marking main entries. + .. rubric:: options + + .. rst:directive:option:: name: a label for hyperlink + :type: text + + Define implicit target name that can be referenced by using + :rst:role:`ref`. For example:: + + .. index:: Python + :name: py-index + + .. versionadded:: 2.5 + .. rst:role:: index While the :rst:dir:`index` directive is a block-level markup and links to the From d89d348db1575d70ffb4dfc9e736bd966afee1f6 Mon Sep 17 00:00:00 2001 From: sethg Date: Sun, 16 Feb 2020 21:38:47 +0100 Subject: [PATCH 03/10] Append to tagetnode names list --- sphinx/domains/index.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sphinx/domains/index.py b/sphinx/domains/index.py index ee24d2522..44431eed5 100644 --- a/sphinx/domains/index.py +++ b/sphinx/domains/index.py @@ -75,11 +75,13 @@ class IndexDirective(SphinxDirective): def run(self) -> List[Node]: arguments = self.arguments[0].split('\n') - if 'name' in self.options: - targetid = 'index-%s' % self.options['name'] - else: - targetid = 'index-%s' % self.env.new_serialno('index') + targetid = 'index-%s' % self.env.new_serialno('index') targetnode = nodes.target('', '', ids=[targetid]) + + if 'name' in self.options: + targetname = self.options['name'] + targetnode['names'].append(targetname) + self.state.document.note_explicit_target(targetnode) indexnode = addnodes.index() indexnode['entries'] = [] From b20d74f8a018e29b2141d1553306a35e53115720 Mon Sep 17 00:00:00 2001 From: sethg Date: Sat, 22 Feb 2020 13:31:18 +0100 Subject: [PATCH 04/10] Review updates --- doc/usage/restructuredtext/directives.rst | 2 +- sphinx/domains/index.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/usage/restructuredtext/directives.rst b/doc/usage/restructuredtext/directives.rst index 933d213c9..b5b0a2980 100644 --- a/doc/usage/restructuredtext/directives.rst +++ b/doc/usage/restructuredtext/directives.rst @@ -885,7 +885,7 @@ mainly contained in information units, such as the language reference. .. index:: Python :name: py-index - .. versionadded:: 2.5 + .. versionadded:: 3.0 .. rst:role:: index diff --git a/sphinx/domains/index.py b/sphinx/domains/index.py index 44431eed5..7aa1018f5 100644 --- a/sphinx/domains/index.py +++ b/sphinx/domains/index.py @@ -71,7 +71,7 @@ class IndexDirective(SphinxDirective): final_argument_whitespace = True option_spec = { 'name': directives.unchanged, - } # type: Dict + } def run(self) -> List[Node]: arguments = self.arguments[0].split('\n') From 8a5a00d06c74d73bfb9d991129f1f7de25daba4b Mon Sep 17 00:00:00 2001 From: sethg Date: Sat, 22 Feb 2020 14:12:27 +0100 Subject: [PATCH 05/10] Add basic syntax test for index :name: --- tests/test_environment_indexentries.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test_environment_indexentries.py b/tests/test_environment_indexentries.py index ad7559ff2..0ace124d0 100644 --- a/tests/test_environment_indexentries.py +++ b/tests/test_environment_indexentries.py @@ -126,3 +126,14 @@ def test_create_index_by_key(app): assert index[0] == ('D', [('docutils', [[('main', '#term-docutils')], [], None])]) assert index[1] == ('P', [('Python', [[('main', '#term-python')], [], None])]) assert index[2] == ('ス', [('スフィンクス', [[('main', '#term-0')], [], 'ス'])]) + + +@pytest.mark.sphinx('dummy', freshenv=True) +def test_create_index_with_name(app): + text = (".. index:: single: docutils\n :name: ref1\n" + ".. index:: see: Python; interpreter\n :name: ref2\n") + restructuredtext.parse(app, text) + index = IndexEntries(app.env).create_index(app.builder) + assert len(index) == 2 + assert index[0] == ('D', [('docutils', [[('', '#index-0')], [], None])]) + assert index[1] == ('P', [('Python', [[], [('see interpreter', [])], None])]) From 86f79af79953e84524ceedd6a53264cc74d7ed3d Mon Sep 17 00:00:00 2001 From: sethg Date: Sat, 22 Feb 2020 14:25:14 +0100 Subject: [PATCH 06/10] Add checks for references --- tests/test_environment_indexentries.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_environment_indexentries.py b/tests/test_environment_indexentries.py index 0ace124d0..449e0458f 100644 --- a/tests/test_environment_indexentries.py +++ b/tests/test_environment_indexentries.py @@ -134,6 +134,13 @@ def test_create_index_with_name(app): ".. index:: see: Python; interpreter\n :name: ref2\n") restructuredtext.parse(app, text) index = IndexEntries(app.env).create_index(app.builder) + + # check index is created correctly assert len(index) == 2 assert index[0] == ('D', [('docutils', [[('', '#index-0')], [], None])]) assert index[1] == ('P', [('Python', [[], [('see interpreter', [])], None])]) + + # check the reference labels are created correctly + labels = app.env.domaindata['std']['anonlabels'] + assert labels['ref1'] == ('index', 'index-0') + assert labels['ref2'] == ('index', 'index-1') From d761c81d60282e403481ed01d857cc2c718597f3 Mon Sep 17 00:00:00 2001 From: sethg Date: Sat, 22 Feb 2020 16:02:55 +0100 Subject: [PATCH 07/10] Implement review changes --- tests/test_environment_indexentries.py | 38 ++++++++++++++------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/tests/test_environment_indexentries.py b/tests/test_environment_indexentries.py index 449e0458f..41a269d24 100644 --- a/tests/test_environment_indexentries.py +++ b/tests/test_environment_indexentries.py @@ -112,6 +112,26 @@ def test_create_seealso_index(app): assert index[2] == ('S', [('Sphinx', [[], [('see also documentation tool', [])], None])]) +@pytest.mark.sphinx('dummy', freshenv=True) +def test_create_index_with_name(app): + text = (".. index:: single: docutils\n" + " :name: ref1\n" + ".. index:: see: Python; interpreter\n" + " :name: ref2\n") + restructuredtext.parse(app, text) + index = IndexEntries(app.env).create_index(app.builder) + + # check index is created correctly + assert len(index) == 2 + assert index[0] == ('D', [('docutils', [[('', '#index-0')], [], None])]) + assert index[1] == ('P', [('Python', [[], [('see interpreter', [])], None])]) + + # check the reference labels are created correctly + std = app.env.get_domain('std') + assert std.anonlabels['ref1'] == ('index', 'index-0') + assert std.anonlabels['ref2'] == ('index', 'index-1') + + @pytest.mark.sphinx('dummy', freshenv=True) def test_create_index_by_key(app): # At present, only glossary directive is able to create index key @@ -126,21 +146,3 @@ def test_create_index_by_key(app): assert index[0] == ('D', [('docutils', [[('main', '#term-docutils')], [], None])]) assert index[1] == ('P', [('Python', [[('main', '#term-python')], [], None])]) assert index[2] == ('ス', [('スフィンクス', [[('main', '#term-0')], [], 'ス'])]) - - -@pytest.mark.sphinx('dummy', freshenv=True) -def test_create_index_with_name(app): - text = (".. index:: single: docutils\n :name: ref1\n" - ".. index:: see: Python; interpreter\n :name: ref2\n") - restructuredtext.parse(app, text) - index = IndexEntries(app.env).create_index(app.builder) - - # check index is created correctly - assert len(index) == 2 - assert index[0] == ('D', [('docutils', [[('', '#index-0')], [], None])]) - assert index[1] == ('P', [('Python', [[], [('see interpreter', [])], None])]) - - # check the reference labels are created correctly - labels = app.env.domaindata['std']['anonlabels'] - assert labels['ref1'] == ('index', 'index-0') - assert labels['ref2'] == ('index', 'index-1') From b469cc104e6a237bdca05687b88aead3f9c287e5 Mon Sep 17 00:00:00 2001 From: sethg Date: Sat, 22 Feb 2020 16:23:05 +0100 Subject: [PATCH 08/10] Review updates --- sphinx/domains/index.py | 9 +++++---- tests/test_environment_indexentries.py | 16 +++++++++------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/sphinx/domains/index.py b/sphinx/domains/index.py index 7aa1018f5..adc28fedf 100644 --- a/sphinx/domains/index.py +++ b/sphinx/domains/index.py @@ -75,12 +75,13 @@ class IndexDirective(SphinxDirective): def run(self) -> List[Node]: arguments = self.arguments[0].split('\n') - targetid = 'index-%s' % self.env.new_serialno('index') - targetnode = nodes.target('', '', ids=[targetid]) if 'name' in self.options: - targetname = self.options['name'] - targetnode['names'].append(targetname) + targetid = self.options['name'] + targetnode = nodes.target('', '', names=[targetid]) + else: + targetid = 'index-%s' % self.env.new_serialno('index') + targetnode = nodes.target('', '', ids=[targetid]) self.state.document.note_explicit_target(targetnode) indexnode = addnodes.index() diff --git a/tests/test_environment_indexentries.py b/tests/test_environment_indexentries.py index 41a269d24..685b36599 100644 --- a/tests/test_environment_indexentries.py +++ b/tests/test_environment_indexentries.py @@ -116,20 +116,22 @@ def test_create_seealso_index(app): def test_create_index_with_name(app): text = (".. index:: single: docutils\n" " :name: ref1\n" - ".. index:: see: Python; interpreter\n" - " :name: ref2\n") + ".. index:: single: Python\n" + " :name: ref2\n" + ".. index:: Sphinx\n") restructuredtext.parse(app, text) index = IndexEntries(app.env).create_index(app.builder) # check index is created correctly - assert len(index) == 2 - assert index[0] == ('D', [('docutils', [[('', '#index-0')], [], None])]) - assert index[1] == ('P', [('Python', [[], [('see interpreter', [])], None])]) + assert len(index) == 3 + assert index[0] == ('D', [('docutils', [[('', '#ref1')], [], None])]) + assert index[1] == ('P', [('Python', [[('', '#ref2')], [], None])]) + assert index[2] == ('S', [('Sphinx', [[('', '#index-0')], [], None])]) # check the reference labels are created correctly std = app.env.get_domain('std') - assert std.anonlabels['ref1'] == ('index', 'index-0') - assert std.anonlabels['ref2'] == ('index', 'index-1') + assert std.anonlabels['ref1'] == ('index', 'ref1') + assert std.anonlabels['ref2'] == ('index', 'ref2') @pytest.mark.sphinx('dummy', freshenv=True) From 14ee165d76824f70af3fb0f19cbb3b1164022a1a Mon Sep 17 00:00:00 2001 From: sethg Date: Sat, 22 Feb 2020 18:46:18 +0100 Subject: [PATCH 09/10] Use targetnode['ids'] --- sphinx/domains/index.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sphinx/domains/index.py b/sphinx/domains/index.py index adc28fedf..33ec9f465 100644 --- a/sphinx/domains/index.py +++ b/sphinx/domains/index.py @@ -77,8 +77,8 @@ class IndexDirective(SphinxDirective): arguments = self.arguments[0].split('\n') if 'name' in self.options: - targetid = self.options['name'] - targetnode = nodes.target('', '', names=[targetid]) + targetname = self.options['name'] + targetnode = nodes.target('', '', names=[targetname]) else: targetid = 'index-%s' % self.env.new_serialno('index') targetnode = nodes.target('', '', ids=[targetid]) @@ -89,7 +89,7 @@ class IndexDirective(SphinxDirective): indexnode['inline'] = False self.set_source_info(indexnode) for entry in arguments: - indexnode['entries'].extend(process_index_entry(entry, targetid)) + indexnode['entries'].extend(process_index_entry(entry, targetnode['ids'][0])) return [indexnode, targetnode] From 2d2833486237f855a99e0868b33c3198470ffde4 Mon Sep 17 00:00:00 2001 From: sethg Date: Sat, 22 Feb 2020 19:49:26 +0100 Subject: [PATCH 10/10] Fix whitespace --- sphinx/domains/index.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/domains/index.py b/sphinx/domains/index.py index 33ec9f465..18a256bac 100644 --- a/sphinx/domains/index.py +++ b/sphinx/domains/index.py @@ -77,7 +77,7 @@ class IndexDirective(SphinxDirective): arguments = self.arguments[0].split('\n') if 'name' in self.options: - targetname = self.options['name'] + targetname = self.options['name'] targetnode = nodes.target('', '', names=[targetname]) else: targetid = 'index-%s' % self.env.new_serialno('index')