diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index dbbcea05..d6d873ad 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -300,6 +300,7 @@ jobs: if: startsWith(runner.os, 'macOS') run: | brew install mupdf-tools imagemagick graphviz cairo libffi + brew link cairo echo "DYLD_FALLBACK_LIBRARY_PATH=/opt/homebrew/lib:${DYLD_FALLBACK_LIBRARY_PATH}" >> $GITHUB_ENV - name: Install tools required by the regression tests (Windows) if: startsWith(runner.os, 'Windows') diff --git a/src/rinoh/frontend/sphinx/nodes.py b/src/rinoh/frontend/sphinx/nodes.py index 803bcd4e..b3584a64 100644 --- a/src/rinoh/frontend/sphinx/nodes.py +++ b/src/rinoh/frontend/sphinx/nodes.py @@ -23,7 +23,7 @@ from ...flowable import DummyFlowable, LabeledFlowable, StaticGroupedFlowables from ...glossary import GlossaryTerm from ...image import Image -from ...index import IndexTerm, IndexTarget, InlineIndexTarget +from ...index import IndexTerm, IndexSee, IndexSeeAlso, IndexTarget, InlineIndexTarget from ...paragraph import Paragraph from ...reference import Reference from ...structure import Admonition, AdmonitionFlowables, DefinitionList, List @@ -97,6 +97,12 @@ def _index_terms(self): yield IndexTerm(one, two + ' ' + three) yield IndexTerm(two, three + ', ' + one) yield IndexTerm(three, one + ' ' + two) + elif type == 'see': + term, reference = (n.strip() for n in entry_name.split(';')) + yield IndexSee(term, reference) + elif type == 'seealso': + term, reference = (n.strip() for n in entry_name.split(';')) + yield IndexSeeAlso(term, reference) else: raise NotImplementedError diff --git a/src/rinoh/index.py b/src/rinoh/index.py index fdffac9a..9603e3e2 100644 --- a/src/rinoh/index.py +++ b/src/rinoh/index.py @@ -18,7 +18,7 @@ __all__ = ['IndexSection', 'Index', 'IndexStyle', 'IndexLabel', 'IndexTerm', - 'InlineIndexTarget', 'IndexTarget'] + 'IndexSee', 'IndexSeeAlso', 'InlineIndexTarget', 'IndexTarget'] class IndexSection(Section): @@ -49,7 +49,8 @@ def flowables(self, container): initials = self.get_style('initials', container) def hande_level(index_entries, level=1): top_level = level == 1 - entries = sorted((name for name in index_entries if name), + entries = sorted((name for name in index_entries + if name and not name.startswith('_index_see')), key=lambda s: (s.lower(), s)) last_section = None for entry in entries: @@ -61,7 +62,12 @@ def hande_level(index_entries, level=1): last_section = section target_ids = [target.get_id(document) for term, target in subentries.get(None, ())] - yield IndexEntry(term, level, target_ids) + see_references = [('index_see', reference) for reference + in subentries.get('_index_see', ())] + seealso_references = [('index_seealso', reference) for reference + in subentries.get('_index_seealso', ())] + yield IndexEntry(term, level, target_ids, + see_references + seealso_references) for paragraph in hande_level(subentries, level=level + 1): yield paragraph @@ -76,7 +82,7 @@ class IndexLabel(Paragraph): class IndexEntry(Paragraph): - def __init__(self, content, level, target_ids=None, + def __init__(self, content, level, target_ids=None, see_references=(), id=None, style=None, parent=None): if target_ids: refs = intersperse((Reference(id, 'page') @@ -84,6 +90,12 @@ def __init__(self, content, level, target_ids=None, entry_text = content + ', ' + MixedStyledText(refs) else: entry_text = content + if see_references: + refs = intersperse((MixedStyledText((StringField(see_label), ' ', + reference)) + for see_label, reference in see_references), + '; ') + entry_text = entry_text + ', ' + MixedStyledText(refs) super().__init__(entry_text, id=id, style=style, parent=parent) self.index_level = level @@ -96,6 +108,22 @@ def __repr__(self): return type(self).__name__ + super().__repr__() +class IndexSee(tuple): + def __new__(cls, term, reference): + return super().__new__(cls, (term, reference)) + + def __repr__(self): + return type(self).__name__ + super().__repr__() + + +class IndexSeeAlso(tuple): + def __new__(cls, term, reference): + return super().__new__(cls, (term, reference)) + + def __repr__(self): + return type(self).__name__ + super().__repr__() + + class IndexTargetBase(Styled): def __init__(self, index_terms, *args, **kwargs): super().__init__(*args, **kwargs) @@ -105,6 +133,16 @@ def prepare(self, flowable_target): super().prepare(flowable_target) index_entries = flowable_target.document.index_entries for index_term in self.index_terms: + if isinstance(index_term, IndexSee): + term, reference = index_term + _, subentries = index_entries.setdefault(term, (term, {})) + subentries.setdefault('_index_see', []).append(reference) + continue + if isinstance(index_term, IndexSeeAlso): + term, reference = index_term + _, subentries = index_entries.setdefault(term, (term, {})) + subentries.setdefault('_index_seealso', []).append(reference) + continue level_entries = index_entries for term in index_term: term_str = (term.to_string(flowable_target) diff --git a/src/rinoh/language/cls.py b/src/rinoh/language/cls.py index 77dc4b75..b011c6b2 100644 --- a/src/rinoh/language/cls.py +++ b/src/rinoh/language/cls.py @@ -43,6 +43,8 @@ class Language(AttributeType): warning: title for warning admonitions seealso: title for see-also admonitions + index_see: title for see label index entries + index_seealso: title for see-also label index entries """ languages = {} #: Dictionary mapping codes to :class:`Language`\ s diff --git a/src/rinoh/language/cs.py b/src/rinoh/language/cs.py index 5cc97a6b..39df67c8 100644 --- a/src/rinoh/language/cs.py +++ b/src/rinoh/language/cs.py @@ -9,7 +9,7 @@ from .cls import Language -CS = Language('cs', 'Česky', +CS = Language('cs', 'čeština', figure='Obrázek', table='Tabulka', contents='Obsah', @@ -19,8 +19,8 @@ index='Rejstřík', # admonitions - attention='Pozor!', - caution='Pozor!', + attention='Opatrnost!', + caution='Pozornost!', danger='!NEBEZPEČÍ!', error='Chyba', hint='Poznámka', @@ -29,8 +29,11 @@ tip='Tip', warning='Varování', seealso='Viz také', -) + # indexes + index_see='viz', + index_seealso='viz také', +) CS.no_break_after = ("do od u z ze za k ke o na v ve nad pod za po s se " "a i že až či").split() diff --git a/src/rinoh/language/de.py b/src/rinoh/language/de.py index 8fae41de..0e048ef8 100644 --- a/src/rinoh/language/de.py +++ b/src/rinoh/language/de.py @@ -29,4 +29,8 @@ tip='Tipp', warning='Warnung', seealso='Siehe auch', + + # indexes + index_see='siehe', + index_seealso='siehe auch', ) diff --git a/src/rinoh/language/en.py b/src/rinoh/language/en.py index 03d05079..eab3e643 100644 --- a/src/rinoh/language/en.py +++ b/src/rinoh/language/en.py @@ -33,6 +33,10 @@ tip='Tip', warning='Warning', seealso='See also', + + # indexes + index_see='see', + index_seealso='see also', ) EN.no_break_after = "a an the".split() diff --git a/src/rinoh/language/es.py b/src/rinoh/language/es.py index 6f76497b..ab0f041c 100644 --- a/src/rinoh/language/es.py +++ b/src/rinoh/language/es.py @@ -9,7 +9,7 @@ from .cls import Language -ES = Language('es', 'Spanish', +ES = Language('es', 'español', figure='Figura', table='Tabla', contents='Contenidos', @@ -28,5 +28,9 @@ note='Nota', tip='Consejo', warning='Precaución', - seealso='Vea también', + seealso='Véase también', + + # indexes + index_see='véase', + index_seealso='véase también', ) diff --git a/src/rinoh/language/fr.py b/src/rinoh/language/fr.py index 4ebad5c9..f7653143 100644 --- a/src/rinoh/language/fr.py +++ b/src/rinoh/language/fr.py @@ -9,19 +9,19 @@ from .cls import Language -FR = Language('fr', 'Français', +FR = Language('fr', 'français', figure='Figure', table='Tableau', - contents='Table des Matières', - list_of_figures='Liste des Figures', - list_of_tables='Liste des Tableaux', + contents='Table des matières', + list_of_figures='Liste des figures', + list_of_tables='Liste des tableaux', chapter='Chapitre', index='Index', # admonitions - attention='Attention!', - caution='Prudence!', - danger='!DANGER!', + attention='Attention !', + caution='Prudence !', + danger='! DANGER !', error='Erreur', hint='Conseil', important='Important', @@ -29,4 +29,10 @@ tip='Astuce', warning='Avertissement', seealso='Voir aussi', + + # indexes + index_see='voir', + index_seealso='voir aussi', ) + +FR.no_break_after = "-".split() diff --git a/src/rinoh/language/hu.py b/src/rinoh/language/hu.py index ce273dc1..12cc2b21 100644 --- a/src/rinoh/language/hu.py +++ b/src/rinoh/language/hu.py @@ -9,10 +9,10 @@ from .cls import Language -HU = Language('hu', 'Hungarian', +HU = Language('hu', 'magyar', contents='Tartalomjegyzék', - list_of_figures='Ábrák Listája', - list_of_tables='Asztalok Listája', + list_of_figures='Ábrák listája', + list_of_tables='Táblázatok listája', chapter='Fejezet', index='Index', @@ -27,4 +27,8 @@ tip='Tipp', warning='Figyelmeztetés', seealso='Lásd még', + + # indexes + index_see='lásd', + index_seealso='lásd még', ) \ No newline at end of file diff --git a/src/rinoh/language/it.py b/src/rinoh/language/it.py index 1a803efd..538364d0 100644 --- a/src/rinoh/language/it.py +++ b/src/rinoh/language/it.py @@ -9,12 +9,12 @@ from .cls import Language -IT = Language('it', 'Italiano', +IT = Language('it', 'italiano', figure='Figura', - table='Tabelle', + table='Tabella', contents='Contenuti', - list_of_figures='Elenco delle Figure', - list_of_tables='Elenco delle Tabelle', + list_of_figures='Elenco delle figure', + list_of_tables='Elenco delle tabelle', chapter='Capitolo', index='Indice', @@ -29,4 +29,8 @@ tip='Suggerimento', warning='Avvertimento', seealso='Vedi anche', + + # indexes + index_see='vedi', + index_seealso='vedi anche', ) diff --git a/src/rinoh/language/nl.py b/src/rinoh/language/nl.py index dfaf82ff..517681b6 100644 --- a/src/rinoh/language/nl.py +++ b/src/rinoh/language/nl.py @@ -32,4 +32,8 @@ tip='Tip', warning='Waarschuwing', seealso='Zie ook', + + # indexes + index_see='zie', + index_seealso='zie ook', ) diff --git a/src/rinoh/language/pl.py b/src/rinoh/language/pl.py index 528ba5b0..cd498d7e 100644 --- a/src/rinoh/language/pl.py +++ b/src/rinoh/language/pl.py @@ -9,12 +9,12 @@ from .cls import Language -PL = Language('pl', 'Polski', +PL = Language('pl', 'polski', figure='Ilustracja', table='Tabela', - contents='Spis Treści', - list_of_figures='Spis Ilustracji', - list_of_tables='Spis Tabel', + contents='Spis treści', + list_of_figures='Spis ilustracji', + list_of_tables='Spis tabel', chapter='Rozdział', index='Skorowidz', @@ -29,4 +29,8 @@ tip='Porada', warning='Ostrzeżenie', seealso='Zobacz również', + + # indexes + index_see='zobacz', + index_seealso='zobacz również', ) diff --git a/tests/test_index.py b/tests/test_index.py new file mode 100644 index 00000000..f3b3fa24 --- /dev/null +++ b/tests/test_index.py @@ -0,0 +1,79 @@ +from rinoh.index import IndexSee, IndexSeeAlso, IndexTarget, IndexTerm + + +class DummyDocument(object): + def __init__(self): + self.ids_by_element = {} + self.index_entries = {} + + def register_element(self, _element): + return None + +class DummyFlowableTarget(object): + def __init__(self, document): + self.document = document + + +def test_index_see_construction(): + assert tuple(IndexSee('term', 'reference')) == ('term', 'reference') + assert tuple(IndexSeeAlso('term', 'reference')) == ('term', 'reference') + +def test_target_index_entries(): + document = DummyDocument() + flowable_target = DummyFlowableTarget(document) + index_target = IndexTarget([ + IndexTerm('single_term1', 'single_term2', 'single_term3'), + IndexTerm('single_term4'), + IndexTerm('pair_term1', 'pair_term2'), + IndexTerm('pair_term2', 'pair_term1'), + IndexTerm('module', 'search' + ' ' + 'path'), + IndexTerm('search', 'path' + ', ' + 'module'), + IndexTerm('path', 'module' + ' ' + 'search'), + IndexSee('term', 'synonym_term'), + IndexSeeAlso('term2', 'synonym_term2'), + ]) + index_target.id = 'index-target' + + index_target.prepare(flowable_target) + + assert document.index_entries == { + 'single_term1': ('single_term1', { + 'single_term2': ('single_term2', { + 'single_term3': ('single_term3', { + None: [(IndexTerm('single_term1', 'single_term2', + 'single_term3'), index_target)] + }) + }) + }), + 'single_term4': ('single_term4', {None: [(IndexTerm('single_term4'), index_target)]}), + 'pair_term1': ('pair_term1', { + 'pair_term2': ('pair_term2', { + None: [(IndexTerm('pair_term1', 'pair_term2'), index_target)] + }) + }), + 'pair_term2': ('pair_term2', { + 'pair_term1': ('pair_term1', { + None: [(IndexTerm('pair_term2', 'pair_term1'), index_target)] + }) + }), + 'module': ('module', { + 'search path': ('search path', { + None: [(IndexTerm('module', 'search' + ' ' + 'path'), + index_target)] + }) + }), + 'search': ('search', { + 'path, module': ('path, module', { + None: [(IndexTerm('search', 'path' + ', ' + 'module'), + index_target)] + }) + }), + 'path': ('path', { + 'module search': ('module search', { + None: [(IndexTerm('path', 'module' + ' ' + 'search'), + index_target)] + }) + }), + 'term': ('term', {'_index_see': ['synonym_term']}), + 'term2': ('term2', {'_index_seealso': ['synonym_term2']}), + } diff --git a/tests_regression/sphinx/index.pdf b/tests_regression/sphinx/index.pdf new file mode 100644 index 00000000..a5f3d9d3 Binary files /dev/null and b/tests_regression/sphinx/index.pdf differ diff --git a/tests_regression/sphinx/index.stylelog b/tests_regression/sphinx/index.stylelog new file mode 100644 index 00000000..8c0644bc --- /dev/null +++ b/tests_regression/sphinx/index.stylelog @@ -0,0 +1,547 @@ +---------------------------------- page 1 ---------------------------------- +#### FlowablesContainer('background') + StaticGroupedFlowables() +#### DownExpandingContainer('title') + StaticGroupedFlowables() + Paragraph('Index', style='title page title') + > (0,0,1,0,2) title page title [Sphinx] > DEFAULT + (0,0,0,0,2) body [Sphinx] > default + SingleStyledText('Index') + Paragraph('Release ', style='title page subtitle') + > (0,0,1,0,2) title page subtitle [Sphinx] > title page title + (0,0,0,0,2) body [Sphinx] > default + SingleStyledText('Release ') + Paragraph('Author', style='title page author') + > (0,0,1,0,2) title page author [Sphinx] > DEFAULT + (0,0,0,0,2) body [Sphinx] > default + SingleStyledText('Author') +---------------------------------- page i ---------------------------------- +#### FlowablesContainer('background') + StaticGroupedFlowables() +#### FootnoteContainer('footnotes') + StaticGroupedFlowables() +#### FlowablesContainer('chapter title') + Paragraph('Table of Contents', style='front matter section title') + > (0,0,1,0,2) front matter section title [Sphinx] > DEFAULT + (0,0,0,0,2) body [Sphinx] > default + Field('Table of Contents') + StringField('Table of Contents') + SingleStyledText('Table of Contents') +#### ChainedContainer('column1') + StaticGroupedFlowables() + TableOfContentsSection(style='table of contents') + > (0,0,1,0,1) table of contents section [Sphinx] > DEFAULT + (0,0,0,1,1) chapter [Sphinx] > DEFAULT + TableOfContents() table of contents + > (0,0,0,0,2) table of contents [Sphinx] > default + TableOfContentsEntry(' Index 3') + > (0,0,0,1,2) toc level 1 [Sphinx] > table of contents + ReferenceField('') + > (0,0,0,1,4) toc entry number reference field [Sphinx] > linked reference + (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('') + Tab(' ') + ReferenceField('Index') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + StringField('Index') + SingleStyledText('Index') + Tab(' ') + ReferenceField('3') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('3') +#### DownExpandingContainer('footer') + StaticGroupedFlowables() + Footer(' i') + > (0,0,0,0,2) footer [Sphinx] > header_footer + MixedStyledText(' i') + MixedStyledText(' i') + Tab(' ') + Tab(' ') + Field('i') + SingleStyledText('i') +---------------------------------- page 1 ---------------------------------- +#### FlowablesContainer('background') + StaticGroupedFlowables() +#### FootnoteContainer('footnotes') + StaticGroupedFlowables() +#### ChainedContainer('column1') + StaticGroupedFlowables() + DocumentTree() index.rst + Paragraph('This page defines index entries ...', id='index-0') index.rst:9 + > (0,0,0,0,2) body [Sphinx] > default + MixedStyledText('This page defines index entries ...') + MixedStyledText('This page defines index entries ...') + SingleStyledText('This page defines index entries ...') + Paragraph('Target term details.', id='index-1') index.rst:13 + > (0,0,0,0,2) body [Sphinx] > default + MixedStyledText('Target term details.') + MixedStyledText('Target term details.') + SingleStyledText('Target term details.') + Paragraph('Related term details.', id='index-2') index.rst:17 + > (0,0,0,0,2) body [Sphinx] > default + MixedStyledText('Related term details.') + MixedStyledText('Related term details.') + SingleStyledText('Related term details.') + Paragraph('Python is a programming language...', id='index-3') index.rst:25 + > (0,0,0,0,2) body [Sphinx] > default + MixedStyledText('Python is a programming language...') + MixedStyledText('Python is a programming language...') + SingleStyledText('Python is a programming language...') + Paragraph('Learn about open source licensin...', id='index-4') index.rst:32 + > (0,0,0,0,2) body [Sphinx] > default + MixedStyledText('Learn about open source licensin...') + MixedStyledText('Learn about open source licensin...') + SingleStyledText('Learn about open source licensin...') + Paragraph('Database querying examples.', id='index-6') index.rst:43 + > (0,0,0,0,2) body [Sphinx] > default + MixedStyledText('Database querying examples.') + MixedStyledText('Database querying examples.') + SingleStyledText('Database querying examples.') + Paragraph('Testing best practices.', id='index-7') index.rst:50 + > (0,0,0,0,2) body [Sphinx] > default + MixedStyledText('Testing best practices.') + MixedStyledText('Testing best practices.') + SingleStyledText('Testing best practices.') + Paragraph('Main entry definition.', id='index-8') index.rst:55 + > (0,0,0,0,2) body [Sphinx] > default + MixedStyledText('Main entry definition.') + MixedStyledText('Main entry definition.') + SingleStyledText('Main entry definition.') + Paragraph('Deprecated functionality notice.', id='index-9') index.rst:61 + > (0,0,0,0,2) body [Sphinx] > default + MixedStyledText('Deprecated functionality notice.') + MixedStyledText('Deprecated functionality notice.') + SingleStyledText('Deprecated functionality notice.') +#### DownExpandingContainer('footer') + StaticGroupedFlowables() + Footer(' 1') + > (0,0,0,0,2) footer [Sphinx] > header_footer + MixedStyledText(' 1') + MixedStyledText(' 1') + Tab(' ') + Tab(' ') + Field('1') + SingleStyledText('1') +---------------------------------- page 3 ---------------------------------- +#### FlowablesContainer('background') + StaticGroupedFlowables() +#### FootnoteContainer('footnotes') + StaticGroupedFlowables() +#### FlowablesContainer('chapter title') + Paragraph('Index', style='front matter section title') + > (0,0,1,0,2) front matter section title [Sphinx] > DEFAULT + (0,0,0,0,2) body [Sphinx] > default + Field('Index') + StringField('Index') + SingleStyledText('Index') +#### ChainedContainer('column1') + StaticGroupedFlowables() + StaticGroupedFlowables() + IndexSection() + > (0,0,0,1,1) chapter [Sphinx] > DEFAULT + Index() index + > (0,0,0,0,2) index [Sphinx] > DEFAULT + IndexLabel('C') + > (0,0,0,0,2) index section label [Sphinx] > DEFAULT + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('C') + IndexEntry('C') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('C') + IndexEntry('language, 1') + > (0,0,0,1,2) level 2 index entry [Sphinx] > level 1 index entry + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('language, 1') + MixedStyledText('language, 1') + SingleStyledText('language, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') + IndexLabel('D') + > (0,0,0,0,2) index section label [Sphinx] > DEFAULT + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('D') + IndexEntry('data') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('data') + IndexEntry('retrieval, 1') + > (0,0,0,1,2) level 2 index entry [Sphinx] > level 1 index entry + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('retrieval, 1') + MixedStyledText('retrieval, 1') + SingleStyledText('retrieval, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') + IndexEntry('database') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('database') + IndexEntry('querying, 1') + > (0,0,0,1,2) level 2 index entry [Sphinx] > level 1 index entry + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('querying, 1') + MixedStyledText('querying, 1') + SingleStyledText('querying, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') + IndexEntry('debugging, see also debugger too...') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('debugging, see also debugger too...') + MixedStyledText('debugging, see also debugger too...') + SingleStyledText('debugging, ') + MixedStyledText('see also debugger tools') + MixedStyledText('see also debugger tools') + StringField('see also') + SingleStyledText('see also') + SingleStyledText(' ') + SingleStyledText('debugger tools') + IndexEntry('deprecated') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('deprecated') + IndexEntry('old method, 1') + > (0,0,0,1,2) level 2 index entry [Sphinx] > level 1 index entry + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('old method, 1') + MixedStyledText('old method, 1') + SingleStyledText('old method, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') + IndexLabel('E') + > (0,0,0,0,2) index section label [Sphinx] > DEFAULT + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('E') + IndexEntry('entry') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('entry') + IndexEntry('example, index, 1') + > (0,0,0,1,2) level 2 index entry [Sphinx] > level 1 index entry + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('example, index, 1') + MixedStyledText('example, index, 1') + SingleStyledText('example, index, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') + IndexEntry('example') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('example') + IndexEntry('index entry, 1') + > (0,0,0,1,2) level 2 index entry [Sphinx] > level 1 index entry + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('index entry, 1') + MixedStyledText('index entry, 1') + SingleStyledText('index entry, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') + IndexLabel('F') + > (0,0,0,0,2) index section label [Sphinx] > DEFAULT + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('F') + IndexEntry('function') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('function') + IndexEntry('example, 1') + > (0,0,0,1,2) level 2 index entry [Sphinx] > level 1 index entry + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('example, 1') + MixedStyledText('example, 1') + SingleStyledText('example, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') + IndexLabel('G') + > (0,0,0,0,2) index section label [Sphinx] > DEFAULT + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('G') + IndexEntry('GNU') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('GNU') + IndexEntry('GPL, 1') + > (0,0,0,1,2) level 2 index entry [Sphinx] > level 1 index entry + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('GPL, 1') + MixedStyledText('GPL, 1') + SingleStyledText('GPL, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') + IndexEntry('GNU General Public License, 1') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('GNU General Public License, 1') + MixedStyledText('GNU General Public License, 1') + SingleStyledText('GNU General Public License, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') + IndexEntry('GPL, see GNU General Public Lice...') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('GPL, see GNU General Public Lice...') + MixedStyledText('GPL, see GNU General Public Lice...') + SingleStyledText('GPL, ') + MixedStyledText('see GNU General Public License') + MixedStyledText('see GNU General Public License') + StringField('see') + SingleStyledText('see') + SingleStyledText(' ') + SingleStyledText('GNU General Public License') + IndexLabel('I') + > (0,0,0,0,2) index section label [Sphinx] > DEFAULT + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('I') + IndexEntry('index') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('index') + IndexEntry('entry example, 1') + > (0,0,0,1,2) level 2 index entry [Sphinx] > level 1 index entry + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('entry example, 1') + MixedStyledText('entry example, 1') + SingleStyledText('entry example, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') + IndexLabel('L') + > (0,0,0,0,2) index section label [Sphinx] > DEFAULT + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('L') + IndexEntry('language') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('language') + IndexEntry('C, 1') + > (0,0,0,1,2) level 2 index entry [Sphinx] > level 1 index entry + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('C, 1') + MixedStyledText('C, 1') + SingleStyledText('C, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') + IndexLabel('M') + > (0,0,0,0,2) index section label [Sphinx] > DEFAULT + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('M') + IndexEntry('main entry') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('main entry') + IndexEntry('important, 1') + > (0,0,0,1,2) level 2 index entry [Sphinx] > level 1 index entry + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('important, 1') + MixedStyledText('important, 1') + SingleStyledText('important, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') +#### ChainedContainer('column2') + (continued) StaticGroupedFlowables() + (continued) IndexSection() + > (0,0,0,1,1) chapter [Sphinx] > DEFAULT + (continued) Index() index + > (0,0,0,0,2) index [Sphinx] > DEFAULT + IndexEntry('mymodule, 1') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('mymodule, 1') + MixedStyledText('mymodule, 1') + SingleStyledText('mymodule, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') + IndexLabel('P') + > (0,0,0,0,2) index section label [Sphinx] > DEFAULT + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('P') + IndexEntry('Python') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('Python') + IndexEntry('interpreter, 1') + > (0,0,0,1,2) level 2 index entry [Sphinx] > level 1 index entry + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('interpreter, 1') + MixedStyledText('interpreter, 1') + SingleStyledText('interpreter, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') + IndexEntry('language, 1') + > (0,0,0,1,2) level 2 index entry [Sphinx] > level 1 index entry + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('language, 1') + MixedStyledText('language, 1') + SingleStyledText('language, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') + IndexLabel('R') + > (0,0,0,0,2) index section label [Sphinx] > DEFAULT + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('R') + IndexEntry('regular term, 1') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('regular term, 1') + MixedStyledText('regular term, 1') + SingleStyledText('regular term, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') + IndexEntry('related term, 1') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('related term, 1') + MixedStyledText('related term, 1') + SingleStyledText('related term, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') + IndexEntry('replacement, see also new method') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('replacement, see also new method') + MixedStyledText('replacement, see also new method') + SingleStyledText('replacement, ') + MixedStyledText('see also new method') + MixedStyledText('see also new method') + StringField('see also') + SingleStyledText('see also') + SingleStyledText(' ') + SingleStyledText('new method') + IndexEntry('retrieval') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('retrieval') + IndexEntry('data, 1') + > (0,0,0,1,2) level 2 index entry [Sphinx] > level 1 index entry + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('data, 1') + MixedStyledText('data, 1') + SingleStyledText('data, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') + IndexLabel('S') + > (0,0,0,0,2) index section label [Sphinx] > DEFAULT + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('S') + IndexEntry('see term, see target term') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('see term, see target term') + MixedStyledText('see term, see target term') + SingleStyledText('see term, ') + MixedStyledText('see target term') + MixedStyledText('see target term') + StringField('see') + SingleStyledText('see') + SingleStyledText(' ') + SingleStyledText('target term') + IndexEntry('seealso term, see also related t...') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('seealso term, see also related t...') + MixedStyledText('seealso term, see also related t...') + SingleStyledText('seealso term, ') + MixedStyledText('see also related term') + MixedStyledText('see also related term') + StringField('see also') + SingleStyledText('see also') + SingleStyledText(' ') + SingleStyledText('related term') + IndexEntry('SQL') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('SQL') + IndexEntry('SELECT, 1') + > (0,0,0,1,2) level 2 index entry [Sphinx] > level 1 index entry + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('SELECT, 1') + MixedStyledText('SELECT, 1') + SingleStyledText('SELECT, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') + IndexLabel('T') + > (0,0,0,0,2) index section label [Sphinx] > DEFAULT + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('T') + IndexEntry('target term, 1') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('target term, 1') + MixedStyledText('target term, 1') + SingleStyledText('target term, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') + IndexEntry('testing') + > (0,0,0,1,2) level 1 index entry [Sphinx] > default + (0,0,0,0,1) body [Sphinx] > default + SingleStyledText('testing') + IndexEntry('integration tests, 1') + > (0,0,0,1,2) level 2 index entry [Sphinx] > level 1 index entry + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('integration tests, 1') + MixedStyledText('integration tests, 1') + SingleStyledText('integration tests, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') + IndexEntry('unit tests, 1') + > (0,0,0,1,2) level 2 index entry [Sphinx] > level 1 index entry + (0,0,0,0,1) body [Sphinx] > default + MixedStyledText('unit tests, 1') + MixedStyledText('unit tests, 1') + SingleStyledText('unit tests, ') + MixedStyledText('1') + Reference('1') + > (0,0,0,0,1) linked reference [Sphinx] > DEFAULT + SingleStyledText('1') +#### DownExpandingContainer('footer') + StaticGroupedFlowables() + Footer(' 3') + > (0,0,0,0,2) footer [Sphinx] > header_footer + MixedStyledText(' 3') + MixedStyledText(' 3') + Tab(' ') + Tab(' ') + Field('3') + SingleStyledText('3') diff --git a/tests_regression/sphinx/test-index/conf.py b/tests_regression/sphinx/test-index/conf.py new file mode 100644 index 00000000..e92899a0 --- /dev/null +++ b/tests_regression/sphinx/test-index/conf.py @@ -0,0 +1,78 @@ + +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/stable/config + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + + +# -- Project information ----------------------------------------------------- + +project = 'Index' +author = 'Author' +copyright = '2026, Author' + +# The short X.Y version +version = '' +# The full version, including alpha/beta/rc tags +release = '' + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +#language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path . +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + + +# -- Options for rinohtype PDF output ---------------------------------------- + +rinoh_documents = [{ + 'doc': master_doc, + 'target': 'index', + 'title': project, + 'author': author, + 'template': 'template.rtt' +}] diff --git a/tests_regression/sphinx/test-index/index.rst b/tests_regression/sphinx/test-index/index.rst new file mode 100644 index 00000000..c71635f5 --- /dev/null +++ b/tests_regression/sphinx/test-index/index.rst @@ -0,0 +1,61 @@ +Index +===== + +.. index:: + single: regular term + see: see term; target term + seealso: seealso term; related term + +This page defines index entries including see and see also references. + +.. index:: single: target term + +Target term details. + +.. index:: single: related term + +Related term details. + +.. index:: + single: Python; interpreter + single: Python; language + pair: C; language + triple: index; entry; example + +Python is a programming language. + +.. index:: + single: GNU; GPL + see: GPL; GNU General Public License + single: GNU General Public License + +Learn about open source licensing. + +.. index:: + single: mymodule + single: function; example + +.. index:: + single: database; querying + single: SQL; SELECT + pair: data; retrieval + +Database querying examples. + +.. index:: + single: testing; unit tests + single: testing; integration tests + seealso: debugging; debugger tools + +Testing best practices. + +.. index:: + single: main entry; important + +Main entry definition. + +.. index:: + single: deprecated; old method + seealso: replacement; new method + +Deprecated functionality notice. diff --git a/tests_regression/sphinx/test-index/stylesheet.rts b/tests_regression/sphinx/test-index/stylesheet.rts new file mode 100644 index 00000000..14d5c542 --- /dev/null +++ b/tests_regression/sphinx/test-index/stylesheet.rts @@ -0,0 +1,6 @@ +[STYLESHEET] +name = Sphinx index +base = sphinx_base14 + +[title page date : Paragraph('title page date')] +hide = true diff --git a/tests_regression/sphinx/test-index/template.rtt b/tests_regression/sphinx/test-index/template.rtt new file mode 100644 index 00000000..66af265a --- /dev/null +++ b/tests_regression/sphinx/test-index/template.rtt @@ -0,0 +1,4 @@ +[TEMPLATE_CONFIGURATION] +name=index +template=book +stylesheet=stylesheet.rts