blob: 2412dee0ac339b503eebb1f2bb579b8571437777 [file] [log] [blame]
Yi Kong878f9942023-12-13 12:55:04 +09001"""
2 pygments.sphinxext
3 ~~~~~~~~~~~~~~~~~~
4
5 Sphinx extension to generate automatic documentation of lexers,
6 formatters and filters.
7
8 :copyright: Copyright 2006-2021 by the Pygments team, see AUTHORS.
9 :license: BSD, see LICENSE for details.
10"""
11
12import sys
13
14from docutils import nodes
15from docutils.statemachine import ViewList
16from docutils.parsers.rst import Directive
17from sphinx.util.nodes import nested_parse_with_titles
18
19
20MODULEDOC = '''
21.. module:: %s
22
23%s
24%s
25'''
26
27LEXERDOC = '''
28.. class:: %s
29
30 :Short names: %s
31 :Filenames: %s
32 :MIME types: %s
33
34 %s
35
36'''
37
38FMTERDOC = '''
39.. class:: %s
40
41 :Short names: %s
42 :Filenames: %s
43
44 %s
45
46'''
47
48FILTERDOC = '''
49.. class:: %s
50
51 :Name: %s
52
53 %s
54
55'''
56
57
58class PygmentsDoc(Directive):
59 """
60 A directive to collect all lexers/formatters/filters and generate
61 autoclass directives for them.
62 """
63 has_content = False
64 required_arguments = 1
65 optional_arguments = 0
66 final_argument_whitespace = False
67 option_spec = {}
68
69 def run(self):
70 self.filenames = set()
71 if self.arguments[0] == 'lexers':
72 out = self.document_lexers()
73 elif self.arguments[0] == 'formatters':
74 out = self.document_formatters()
75 elif self.arguments[0] == 'filters':
76 out = self.document_filters()
77 else:
78 raise Exception('invalid argument for "pygmentsdoc" directive')
79 node = nodes.compound()
80 vl = ViewList(out.split('\n'), source='')
81 nested_parse_with_titles(self.state, vl, node)
82 for fn in self.filenames:
83 self.state.document.settings.record_dependencies.add(fn)
84 return node.children
85
86 def document_lexers(self):
87 from pip._vendor.pygments.lexers._mapping import LEXERS
88 out = []
89 modules = {}
90 moduledocstrings = {}
91 for classname, data in sorted(LEXERS.items(), key=lambda x: x[0]):
92 module = data[0]
93 mod = __import__(module, None, None, [classname])
94 self.filenames.add(mod.__file__)
95 cls = getattr(mod, classname)
96 if not cls.__doc__:
97 print("Warning: %s does not have a docstring." % classname)
98 docstring = cls.__doc__
99 if isinstance(docstring, bytes):
100 docstring = docstring.decode('utf8')
101 modules.setdefault(module, []).append((
102 classname,
103 ', '.join(data[2]) or 'None',
104 ', '.join(data[3]).replace('*', '\\*').replace('_', '\\') or 'None',
105 ', '.join(data[4]) or 'None',
106 docstring))
107 if module not in moduledocstrings:
108 moddoc = mod.__doc__
109 if isinstance(moddoc, bytes):
110 moddoc = moddoc.decode('utf8')
111 moduledocstrings[module] = moddoc
112
113 for module, lexers in sorted(modules.items(), key=lambda x: x[0]):
114 if moduledocstrings[module] is None:
115 raise Exception("Missing docstring for %s" % (module,))
116 heading = moduledocstrings[module].splitlines()[4].strip().rstrip('.')
117 out.append(MODULEDOC % (module, heading, '-'*len(heading)))
118 for data in lexers:
119 out.append(LEXERDOC % data)
120
121 return ''.join(out)
122
123 def document_formatters(self):
124 from pip._vendor.pygments.formatters import FORMATTERS
125
126 out = []
127 for classname, data in sorted(FORMATTERS.items(), key=lambda x: x[0]):
128 module = data[0]
129 mod = __import__(module, None, None, [classname])
130 self.filenames.add(mod.__file__)
131 cls = getattr(mod, classname)
132 docstring = cls.__doc__
133 if isinstance(docstring, bytes):
134 docstring = docstring.decode('utf8')
135 heading = cls.__name__
136 out.append(FMTERDOC % (heading, ', '.join(data[2]) or 'None',
137 ', '.join(data[3]).replace('*', '\\*') or 'None',
138 docstring))
139 return ''.join(out)
140
141 def document_filters(self):
142 from pip._vendor.pygments.filters import FILTERS
143
144 out = []
145 for name, cls in FILTERS.items():
146 self.filenames.add(sys.modules[cls.__module__].__file__)
147 docstring = cls.__doc__
148 if isinstance(docstring, bytes):
149 docstring = docstring.decode('utf8')
150 out.append(FILTERDOC % (cls.__name__, name, docstring))
151 return ''.join(out)
152
153
154def setup(app):
155 app.add_directive('pygmentsdoc', PygmentsDoc)