|
1 # -*- coding: utf-8 -*- |
|
2 """ |
|
3 pygments.sphinxext |
|
4 ~~~~~~~~~~~~~~~~~~ |
|
5 |
|
6 Sphinx extension to generate automatic documentation of lexers, |
|
7 formatters and filters. |
|
8 |
|
9 :copyright: Copyright 2006-2014 by the Pygments team, see AUTHORS. |
|
10 :license: BSD, see LICENSE for details. |
|
11 """ |
|
12 |
|
13 from __future__ import print_function |
|
14 |
|
15 import sys |
|
16 |
|
17 from docutils import nodes |
|
18 from docutils.statemachine import ViewList |
|
19 from sphinx.util.compat import Directive |
|
20 from sphinx.util.nodes import nested_parse_with_titles |
|
21 |
|
22 |
|
23 MODULEDOC = ''' |
|
24 .. module:: %s |
|
25 |
|
26 %s |
|
27 %s |
|
28 ''' |
|
29 |
|
30 LEXERDOC = ''' |
|
31 .. class:: %s |
|
32 |
|
33 :Short names: %s |
|
34 :Filenames: %s |
|
35 :MIME types: %s |
|
36 |
|
37 %s |
|
38 |
|
39 ''' |
|
40 |
|
41 FMTERDOC = ''' |
|
42 .. class:: %s |
|
43 |
|
44 :Short names: %s |
|
45 :Filenames: %s |
|
46 |
|
47 %s |
|
48 |
|
49 ''' |
|
50 |
|
51 FILTERDOC = ''' |
|
52 .. class:: %s |
|
53 |
|
54 :Name: %s |
|
55 |
|
56 %s |
|
57 |
|
58 ''' |
|
59 |
|
60 class PygmentsDoc(Directive): |
|
61 """ |
|
62 A directive to collect all lexers/formatters/filters and generate |
|
63 autoclass directives for them. |
|
64 """ |
|
65 has_content = False |
|
66 required_arguments = 1 |
|
67 optional_arguments = 0 |
|
68 final_argument_whitespace = False |
|
69 option_spec = {} |
|
70 |
|
71 def run(self): |
|
72 self.filenames = set() |
|
73 if self.arguments[0] == 'lexers': |
|
74 out = self.document_lexers() |
|
75 elif self.arguments[0] == 'formatters': |
|
76 out = self.document_formatters() |
|
77 elif self.arguments[0] == 'filters': |
|
78 out = self.document_filters() |
|
79 else: |
|
80 raise Exception('invalid argument for "pygmentsdoc" directive') |
|
81 node = nodes.compound() |
|
82 vl = ViewList(out.split('\n'), source='') |
|
83 nested_parse_with_titles(self.state, vl, node) |
|
84 for fn in self.filenames: |
|
85 self.state.document.settings.record_dependencies.add(fn) |
|
86 return node.children |
|
87 |
|
88 def document_lexers(self): |
|
89 from pygments.lexers._mapping import LEXERS |
|
90 out = [] |
|
91 modules = {} |
|
92 moduledocstrings = {} |
|
93 for classname, data in sorted(LEXERS.items(), key=lambda x: x[0]): |
|
94 module = data[0] |
|
95 mod = __import__(module, None, None, [classname]) |
|
96 self.filenames.add(mod.__file__) |
|
97 cls = getattr(mod, classname) |
|
98 if not cls.__doc__: |
|
99 print("Warning: %s does not have a docstring." % classname) |
|
100 docstring = cls.__doc__ |
|
101 if isinstance(docstring, bytes): |
|
102 docstring = docstring.decode('utf8') |
|
103 modules.setdefault(module, []).append(( |
|
104 classname, |
|
105 ', '.join(data[2]) or 'None', |
|
106 ', '.join(data[3]).replace('*', '\\*').replace('_', '\\') or 'None', |
|
107 ', '.join(data[4]) or 'None', |
|
108 docstring)) |
|
109 if module not in moduledocstrings: |
|
110 moddoc = mod.__doc__ |
|
111 if isinstance(moddoc, bytes): |
|
112 moddoc = moddoc.decode('utf8') |
|
113 moduledocstrings[module] = moddoc |
|
114 |
|
115 for module, lexers in sorted(modules.items(), key=lambda x: x[0]): |
|
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 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[1]) or 'None', |
|
137 ', '.join(data[2]).replace('*', '\\*') or 'None', |
|
138 docstring)) |
|
139 return ''.join(out) |
|
140 |
|
141 def document_filters(self): |
|
142 from 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 |
|
154 def setup(app): |
|
155 app.add_directive('pygmentsdoc', PygmentsDoc) |