summaryrefslogtreecommitdiff
path: root/sphinx/directives/patches.py
blob: 00be5584d2d3f1c4a90d159de9221eeb48643b49 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# -*- coding: utf-8 -*-
"""
    sphinx.directives.patches
    ~~~~~~~~~~~~~~~~~~~~~~~~~

    :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
    :license: BSD, see LICENSE for details.
"""

from docutils import nodes
from docutils.parsers.rst import directives
from docutils.parsers.rst.directives import images, html, tables

from sphinx import addnodes
from sphinx.util.docutils import SphinxDirective
from sphinx.util.nodes import set_source_info

if False:
    # For type annotation
    from typing import Dict, List, Tuple  # NOQA
    from sphinx.application import Sphinx  # NOQA


class Figure(images.Figure):
    """The figure directive which applies `:name:` option to the figure node
    instead of the image node.
    """

    def run(self):
        # type: () -> List[nodes.Node]
        name = self.options.pop('name', None)
        result = images.Figure.run(self)
        if len(result) == 2 or isinstance(result[0], nodes.system_message):
            return result

        (figure_node,) = result
        if name:
            self.options['name'] = name
            self.add_name(figure_node)

        # fill lineno using image node
        if figure_node.line is None and len(figure_node) == 2:
            figure_node.line = figure_node[1].line

        return [figure_node]


class Meta(html.Meta, SphinxDirective):
    def run(self):
        # type: () -> List[nodes.Node]
        result = html.Meta.run(self)
        for node in result:
            if (isinstance(node, nodes.pending) and
               isinstance(node.details['nodes'][0], html.MetaBody.meta)):
                meta = node.details['nodes'][0]
                meta.source = self.env.doc2path(self.env.docname)
                meta.line = self.lineno
                meta.rawcontent = meta['content']

                # docutils' meta nodes aren't picklable because the class is nested
                meta.__class__ = addnodes.meta

        return result


class RSTTable(tables.RSTTable):
    """The table directive which sets source and line information to its caption.

    Only for docutils-0.13 or older version."""

    def make_title(self):
        # type: () -> Tuple[nodes.Node, unicode]
        title, message = tables.RSTTable.make_title(self)
        if title:
            set_source_info(self, title)

        return title, message


class CSVTable(tables.CSVTable):
    """The csv-table directive which sets source and line information to its caption.

    Only for docutils-0.13 or older version."""

    def make_title(self):
        # type: () -> Tuple[nodes.Node, unicode]
        title, message = tables.CSVTable.make_title(self)
        if title:
            set_source_info(self, title)

        return title, message


class ListTable(tables.ListTable):
    """The list-table directive which sets source and line information to its caption.

    Only for docutils-0.13 or older version."""

    def make_title(self):
        # type: () -> Tuple[nodes.Node, unicode]
        title, message = tables.ListTable.make_title(self)
        if title:
            set_source_info(self, title)

        return title, message


def setup(app):
    # type: (Sphinx) -> Dict
    directives.register_directive('figure', Figure)
    directives.register_directive('meta', Meta)
    directives.register_directive('table', RSTTable)
    directives.register_directive('csv-table', CSVTable)
    directives.register_directive('list-table', ListTable)

    return {
        'version': 'builtin',
        'parallel_read_safe': True,
        'parallel_write_safe': True,
    }