Conditional toctree in Sphinx

后端 未结 4 1264
故里飘歌
故里飘歌 2020-12-30 12:31

I want to do multiple versions of a documentation, which differ in the sections that are included. To achieve this I would usually use either the only directive or the ifcon

4条回答
  •  -上瘾入骨i
    2020-12-30 12:58

    My previous answer fails if you have hierarchies of table of contents so I wrote a simple toctree-filt directive that is able to filter entries based on a prefix to the entry. For example, given a toctree-filt directive like

    .. toctree-filt::
       :maxdepth: 1
    
       user-manual
       :internal:supervisor-api
       :draft:new-feature
       :erik:erik-maths
       api
    

    and setting the exclusion list to ['draft','erik'] will result in an effective toctree that looks like

    .. toctree-filt::
       :maxdepth: 1
    
       user-manual
       supervisor-api
       api
    

    Add the following lines to your conf.py:

    sys.path.append(os.path.abspath('../sphinx-ext/'))
    extensions = ['toctree_filter']
    toc_filter_exclude = ['draft','erik']
    

    Put the following code in /sphinx_ext next to your /source directory:

    import re
    from sphinx.directives.other import TocTree
    
    
    def setup(app):
        app.add_config_value('toc_filter_exclude', [], 'html')
        app.add_directive('toctree-filt', TocTreeFilt)
        return {'version': '1.0.0'}
    
    class TocTreeFilt(TocTree):
        """
        Directive to notify Sphinx about the hierarchical structure of the docs,
        and to include a table-of-contents like tree in the current document. This
        version filters the entries based on a list of prefixes. We simply filter
        the content of the directive and call the super's version of run. The
        list of exclusions is stored in the **toc_filter_exclusion** list. Any
        table of content entry prefixed by one of these strings will be excluded.
        If `toc_filter_exclusion=['secret','draft']` then all toc entries of the
        form `:secret:ultra-api` or `:draft:new-features` will be excuded from
        the final table of contents. Entries without a prefix are always included.
        """
        hasPat = re.compile('^\s*:(.+):(.+)$')
    
        # Remove any entries in the content that we dont want and strip
        # out any filter prefixes that we want but obviously don't want the
        # prefix to mess up the file name.
        def filter_entries(self, entries):
            excl = self.state.document.settings.env.config.toc_filter_exclude
            filtered = []
            for e in entries:
                m = self.hasPat.match(e)
                if m != None:
                    if not m.groups()[0] in excl:
                        filtered.append(m.groups()[1])
                else:
                    filtered.append(e)
            return filtered
    
        def run(self):
            # Remove all TOC entries that should not be on display
            self.content = self.filter_entries(self.content)
            return super().run()
    

    Now just change your existing toctree directives to toctree-filt and you are good to roll. Note that Sphinx will post errors because it will find files that are not included in the document. Not sure how to fix that.

提交回复
热议问题