6

考虑一个带有这个骨架的 reStructuredText 文档:

Main Title
==========

text text text text text

Subsection
----------

text text text text text

.. my-import-from:: file1
.. my-import-from:: file2

my-import-from指令由特定于文档的 Sphinx 扩展提供,它应该读取作为其参数提供的文件,解析其中嵌入的 reST,并将结果作为当前输入文件中的一个部分注入。(与 autodoc 类似,但文件格式不同。)我现在拥有的代码如下所示:

class MyImportFromDirective(Directive):
    required_arguments = 1
    def run(self):
        src, srcline = self.state_machine.get_source_and_line()
        doc_file = os.path.normpath(os.path.join(os.path.dirname(src),
                                                 self.arguments[0]))
        self.state.document.settings.record_dependencies.add(doc_file)
        doc_text  = ViewList()

        try:
            doc_text = extract_doc_from_file(doc_file)
        except EnvironmentError as e:
            raise self.error(e.filename + ": " + e.strerror) from e

        doc_section = nodes.section()
        doc_section.document = self.state.document

        # report line numbers within the nested parse correctly
        old_reporter = self.state.memo.reporter
        self.state.memo.reporter = AutodocReporter(doc_text,
                                                   self.state.memo.reporter)
        nested_parse_with_titles(self.state, doc_text, doc_section)
        self.state.memo.reporter = old_reporter

        if len(doc_section) == 1 and isinstance(doc_section[0], nodes.section):
            doc_section = doc_section[0]

        # If there was no title, synthesize one from the name of the file.
        if len(doc_section) == 0 or not isinstance(doc_section[0], nodes.title):
            doc_title = nodes.title()
            doc_title.append(make_title_text(doc_file))
            doc_section.insert(0, doc_title)

        return [doc_section]

这是可行的,除了新部分是作为当前部分的部分注入的,而不是兄弟部分。换句话说,上面的示例文档生成了一个如下所示的 TOC 树:

  • 主题
    • 小节
      • 文件 1
      • 文件2

而不是想要的

  • 主题
    • 小节
    • 文件 1
    • 文件2

我该如何解决?Docutils 文档......不足,特别是在控制部分深度方面。我尝试过的一件显而易见的事情是返回doc_section.children而不是[doc_section]; 完全从 TOC 树中删除File1和删除File2(但确实使文档正文中的节标题看起来是正确的嵌套级别)。

4

2 回答 2

4

我认为不可能通过从指令中返回该部分来做到这一点(不按照弗洛里安的建议做一些事情),因为它将被附加到“当前”部分。但是,您可以通过self.state.section以下方式添加该部分(为简洁起见,处理已删除的选项)

class FauxHeading(object):
    """
    A heading level that is not defined by a string. We need this to work with
    the mechanics of
    :py:meth:`docutils.parsers.rst.states.RSTState.check_subsection`.

    The important thing is that the length can vary, but it must be equal to
    any other instance of FauxHeading.
    """

    def __init__(self, length):
        self.length = length

    def __len__(self):
        return self.length

    def __eq__(self, other):
        return isinstance(other, FauxHeading)


class ParmDirective(Directive):

    required_arguments = 1
    optional_arguments = 0
    has_content = True
    option_spec = {
        'type':          directives.unchanged,
        'precision':     directives.nonnegative_int,
        'scale':         directives.nonnegative_int,
        'length':        directives.nonnegative_int}

    def run(self):
        variableName = self.arguments[0]
        lineno = self.state_machine.abs_line_number()
        secBody = None
        block_length = 0

        # added for some space
        lineBlock = nodes.line('', '', nodes.line_block())

        # parse the body of the directive
        if self.has_content and len(self.content):
            secBody = nodes.container()
            block_length += nested_parse_with_titles(
                self.state, self.content, secBody)

        # keeping track of the level seems to be required if we want to allow
        # nested content. Not sure why, but fits with the pattern in
        # :py:meth:`docutils.parsers.rst.states.RSTState.new_subsection`
        myLevel = self.state.memo.section_level
        self.state.section(
            variableName,
            '',
            FauxHeading(2 + len(self.options) + block_length),
            lineno,
            [lineBlock] if secBody is None else [lineBlock, secBody])
        self.state.memo.section_level = myLevel

        return []
于 2015-04-22T10:39:13.163 回答
1

我不知道如何直接在您的自定义指令中执行此操作。但是,您可以在解析后使用自定义转换来提升树中的File1File2节点。例如,查看docutils.transforms.frontmatter模块中的转换。

在您的 Sphinx 扩展中,使用该Sphinx.add_transform方法注册自定义转换。

更新:您还可以通过docutils.nodes.pending在节点列表中返回该类的一个或多个实例来直接在指令中注册转换。确保note_pending在这种情况下调用文档的方法(在您的指令中,您可以通过 获取文档self.state_machine.document)。

于 2014-04-10T11:49:04.237 回答