sphinx-lua-ls 0.0.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sphinx_lua_ls/__init__.py +166 -0
- sphinx_lua_ls/_version.py +21 -0
- sphinx_lua_ls/autodoc.py +632 -0
- sphinx_lua_ls/doctree.py +477 -0
- sphinx_lua_ls/domain.py +1156 -0
- sphinx_lua_ls/intersphinx.py +204 -0
- sphinx_lua_ls/lua_ls.py +694 -0
- sphinx_lua_ls/py.typed +0 -0
- sphinx_lua_ls-0.0.4.dist-info/LICENSE +21 -0
- sphinx_lua_ls-0.0.4.dist-info/METADATA +92 -0
- sphinx_lua_ls-0.0.4.dist-info/RECORD +13 -0
- sphinx_lua_ls-0.0.4.dist-info/WHEEL +5 -0
- sphinx_lua_ls-0.0.4.dist-info/top_level.txt +1 -0
sphinx_lua_ls/autodoc.py
ADDED
|
@@ -0,0 +1,632 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Autodoc directives for lua.
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import contextlib
|
|
9
|
+
import functools
|
|
10
|
+
import math
|
|
11
|
+
import re
|
|
12
|
+
import textwrap
|
|
13
|
+
from typing import Any, Callable, ClassVar, Type
|
|
14
|
+
|
|
15
|
+
import docutils.nodes
|
|
16
|
+
import docutils.statemachine
|
|
17
|
+
import sphinx.addnodes
|
|
18
|
+
import sphinx.util.docutils
|
|
19
|
+
import sphinx.util.nodes
|
|
20
|
+
from docutils.parsers.rst import directives
|
|
21
|
+
from sphinx.util.docutils import SphinxDirective
|
|
22
|
+
|
|
23
|
+
import sphinx_lua_ls.domain
|
|
24
|
+
from sphinx_lua_ls.doctree import Kind, Object, Visibility
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class AutodocUtilsMixin(SphinxDirective):
|
|
28
|
+
"""
|
|
29
|
+
Provides facilities for rendering automatically generated documentation.
|
|
30
|
+
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
# Override type of `option_spec` to make it compatible with `ObjectDescription`.
|
|
34
|
+
option_spec: ClassVar[dict[str, Callable[[str], Any]]] # type: ignore
|
|
35
|
+
|
|
36
|
+
def push_context(self, modname: str, classname: str):
|
|
37
|
+
classes = self.env.ref_context.setdefault("lua:classes", [])
|
|
38
|
+
classes.append(self.env.ref_context.get("lua:class"))
|
|
39
|
+
self.env.ref_context["lua:class"] = classname
|
|
40
|
+
|
|
41
|
+
modules = self.env.ref_context.setdefault("lua:modules", [])
|
|
42
|
+
modules.append(self.env.ref_context.get("lua:module"))
|
|
43
|
+
self.env.ref_context["lua:module"] = modname
|
|
44
|
+
|
|
45
|
+
def pop_context(self):
|
|
46
|
+
classes = self.env.ref_context.setdefault("lua:classes", [])
|
|
47
|
+
if classes:
|
|
48
|
+
self.env.ref_context["lua:class"] = classes.pop()
|
|
49
|
+
else:
|
|
50
|
+
self.env.ref_context.pop("lua:class")
|
|
51
|
+
|
|
52
|
+
modules = self.env.ref_context.setdefault("lua:modules", [])
|
|
53
|
+
if modules:
|
|
54
|
+
self.env.ref_context["lua:module"] = modules.pop()
|
|
55
|
+
else:
|
|
56
|
+
self.env.ref_context.pop("lua:module")
|
|
57
|
+
|
|
58
|
+
@contextlib.contextmanager
|
|
59
|
+
def save_context(self):
|
|
60
|
+
modname = self.env.ref_context.get("lua:module")
|
|
61
|
+
classname = self.env.ref_context.get("lua:classname")
|
|
62
|
+
try:
|
|
63
|
+
yield
|
|
64
|
+
finally:
|
|
65
|
+
self.env.ref_context["lua:module"] = modname
|
|
66
|
+
self.env.ref_context["lua:classname"] = classname
|
|
67
|
+
|
|
68
|
+
def render(self, root: Object, name: str, pass_through: bool = False):
|
|
69
|
+
if not self.env.ref_context.get("lua:class") and root.kind == Kind.Module:
|
|
70
|
+
# This is a module.
|
|
71
|
+
return self.render_module(root, name, pass_through)
|
|
72
|
+
elif root.kind == Kind.Module:
|
|
73
|
+
# This is a module inside of a class. We will render it as a class.
|
|
74
|
+
return self.render_class(root, name, pass_through)
|
|
75
|
+
elif root.kind == Kind.Data:
|
|
76
|
+
return self.render_data(root, name, pass_through)
|
|
77
|
+
elif root.kind == Kind.Function:
|
|
78
|
+
return self.render_function(root, name, pass_through)
|
|
79
|
+
elif root.kind == Kind.Class:
|
|
80
|
+
return self.render_class(root, name, pass_through)
|
|
81
|
+
elif root.kind == Kind.Alias:
|
|
82
|
+
return self.render_alias(root, name, pass_through)
|
|
83
|
+
else:
|
|
84
|
+
raise RuntimeError(f"unknown lua object kind {root.kind}")
|
|
85
|
+
|
|
86
|
+
def render_module(self, root: Object, name: str, pass_through: bool = False):
|
|
87
|
+
with self.save_context():
|
|
88
|
+
nodes = list(
|
|
89
|
+
self._create_directive(
|
|
90
|
+
name, sphinx_lua_ls.domain.LuaModule, "lua:module", pass_through
|
|
91
|
+
).run()
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
container = docutils.nodes.container()
|
|
95
|
+
nodes.append(container)
|
|
96
|
+
|
|
97
|
+
if root.docstring:
|
|
98
|
+
self.render_docs(
|
|
99
|
+
str(root.file or f"<docstring for {self.arguments[0]}>"),
|
|
100
|
+
root.line or 0,
|
|
101
|
+
root.docstring,
|
|
102
|
+
container,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
for name, child in self.get_children(root):
|
|
106
|
+
nodes.extend(self.render(child, name))
|
|
107
|
+
|
|
108
|
+
return nodes
|
|
109
|
+
|
|
110
|
+
def render_data(self, root: Object, name: str, pass_through: bool = False):
|
|
111
|
+
with self.save_context():
|
|
112
|
+
return self._create_directive(
|
|
113
|
+
name,
|
|
114
|
+
LuaData,
|
|
115
|
+
"lua:data",
|
|
116
|
+
pass_through,
|
|
117
|
+
root=root,
|
|
118
|
+
).run()
|
|
119
|
+
|
|
120
|
+
def render_function(self, root: Object, name: str, pass_through: bool = False):
|
|
121
|
+
with self.save_context():
|
|
122
|
+
return self._create_directive(
|
|
123
|
+
name,
|
|
124
|
+
LuaFunction,
|
|
125
|
+
"lua:function",
|
|
126
|
+
pass_through,
|
|
127
|
+
root=root,
|
|
128
|
+
).run()
|
|
129
|
+
|
|
130
|
+
def render_class(self, root: Object, name: str, pass_through: bool = False):
|
|
131
|
+
with self.save_context():
|
|
132
|
+
return self._create_directive(
|
|
133
|
+
name,
|
|
134
|
+
LuaClass,
|
|
135
|
+
"lua:class",
|
|
136
|
+
pass_through,
|
|
137
|
+
root=root,
|
|
138
|
+
).run()
|
|
139
|
+
|
|
140
|
+
def render_alias(self, root: Object, name: str, pass_through: bool = False):
|
|
141
|
+
with self.save_context():
|
|
142
|
+
return self._create_directive(
|
|
143
|
+
name,
|
|
144
|
+
LuaAlias,
|
|
145
|
+
"lua:alias",
|
|
146
|
+
pass_through,
|
|
147
|
+
root=root,
|
|
148
|
+
).run()
|
|
149
|
+
|
|
150
|
+
def render_docs(self, path: str, line: int, docs: str, node, titles=False):
|
|
151
|
+
docs = re.sub(r"^\@\*\w+\*.*$", "", docs, flags=re.MULTILINE)
|
|
152
|
+
docs = re.sub(r"^```lua\n.*?\n```", "", docs, flags=re.MULTILINE | re.DOTALL)
|
|
153
|
+
see_sections = list(re.finditer(r"^See:\n", docs, flags=re.MULTILINE))
|
|
154
|
+
if see_sections:
|
|
155
|
+
match = see_sections[-1]
|
|
156
|
+
see_section = docs[match.span()[1] :]
|
|
157
|
+
docs = docs[: match.span()[0]]
|
|
158
|
+
else:
|
|
159
|
+
see_section = ""
|
|
160
|
+
|
|
161
|
+
see_lines = []
|
|
162
|
+
rejected_see_lines = []
|
|
163
|
+
for see_line in see_section.splitlines():
|
|
164
|
+
if match := re.match(
|
|
165
|
+
r"""
|
|
166
|
+
^[ ][ ]\*[ ]
|
|
167
|
+
(?:
|
|
168
|
+
~(?P<rejected_type>.+?)~ (?P<rejected_doc>.*)
|
|
169
|
+
|
|
|
170
|
+
\[(?P<type>.+?)\]\(.*?\) (?P<doc>.*)
|
|
171
|
+
)
|
|
172
|
+
$
|
|
173
|
+
""",
|
|
174
|
+
see_line,
|
|
175
|
+
flags=re.VERBOSE,
|
|
176
|
+
):
|
|
177
|
+
typ = match.group("type") or match.group("rejected_type")
|
|
178
|
+
doc = match.group("doc") or match.group("rejected_doc") or ""
|
|
179
|
+
if doc:
|
|
180
|
+
doc = ": " + doc
|
|
181
|
+
see_lines.append(f":lua:obj:`{typ}`{doc}")
|
|
182
|
+
else:
|
|
183
|
+
rejected_see_lines.append(see_line)
|
|
184
|
+
|
|
185
|
+
if rejected_see_lines:
|
|
186
|
+
docs += "\n\nSee:\n" + "\n".join(rejected_see_lines)
|
|
187
|
+
|
|
188
|
+
docs = textwrap.dedent(docs)
|
|
189
|
+
|
|
190
|
+
if len(see_lines) > 1:
|
|
191
|
+
see_lines = ["", "See:", ""] + [
|
|
192
|
+
nl for l in see_lines for nl in (f"- {l}", "")
|
|
193
|
+
]
|
|
194
|
+
else:
|
|
195
|
+
see_lines = [""] + [f"See: {l}" for l in see_lines]
|
|
196
|
+
|
|
197
|
+
lines = docs.splitlines() + see_lines
|
|
198
|
+
|
|
199
|
+
items = [(path, line)] * len(lines)
|
|
200
|
+
|
|
201
|
+
content = docutils.statemachine.StringList(lines, items=items)
|
|
202
|
+
|
|
203
|
+
with sphinx.util.docutils.switch_source_input(self.state, content):
|
|
204
|
+
if titles:
|
|
205
|
+
sphinx.util.nodes.nested_parse_with_titles(self.state, content, node)
|
|
206
|
+
else:
|
|
207
|
+
self.state.nested_parse(content, 0, node)
|
|
208
|
+
|
|
209
|
+
def _create_directive(
|
|
210
|
+
self,
|
|
211
|
+
name: str,
|
|
212
|
+
cls: Type[SphinxDirective],
|
|
213
|
+
directive_name: str,
|
|
214
|
+
pass_through: bool = False,
|
|
215
|
+
**kwargs,
|
|
216
|
+
) -> SphinxDirective:
|
|
217
|
+
if pass_through:
|
|
218
|
+
options = self.options.copy()
|
|
219
|
+
options.pop("module", None)
|
|
220
|
+
else:
|
|
221
|
+
recursive = self.options.get("recursive", False)
|
|
222
|
+
members_map = lambda x: x if recursive and x is True else None
|
|
223
|
+
options = {
|
|
224
|
+
"members": members_map(self.options.get("members")),
|
|
225
|
+
"undoc-members": members_map(self.options.get("undoc-members")),
|
|
226
|
+
"private-members": members_map(self.options.get("private-members")),
|
|
227
|
+
"special-members": members_map(self.options.get("special-members")),
|
|
228
|
+
"inherited-members": members_map(self.options.get("inherited-members")),
|
|
229
|
+
"member-order": self.options.get("member-order", None),
|
|
230
|
+
"recursive": recursive,
|
|
231
|
+
}
|
|
232
|
+
if "no-index" in self.options:
|
|
233
|
+
# NB: `no-index` should not be present in `options` if it wasn't present
|
|
234
|
+
# in `self.options`.
|
|
235
|
+
options["no-index"] = self.options["no-index"]
|
|
236
|
+
|
|
237
|
+
return cls(
|
|
238
|
+
directive_name,
|
|
239
|
+
[name],
|
|
240
|
+
options,
|
|
241
|
+
self.content if pass_through else docutils.statemachine.StringList(),
|
|
242
|
+
self.lineno if pass_through else 0,
|
|
243
|
+
self.content_offset if pass_through else 0,
|
|
244
|
+
self.block_text if pass_through else "",
|
|
245
|
+
self.state,
|
|
246
|
+
self.state_machine,
|
|
247
|
+
**kwargs,
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
@property
|
|
251
|
+
def objtree(self) -> Object:
|
|
252
|
+
return getattr(self.env, "lua_ls_doc_root")
|
|
253
|
+
|
|
254
|
+
@functools.cached_property
|
|
255
|
+
def parent(self):
|
|
256
|
+
modname = self.env.ref_context.get("lua:module", None)
|
|
257
|
+
classname = self.env.ref_context.get("lua:class", None)
|
|
258
|
+
if classname:
|
|
259
|
+
basepath = ".".join(filter(None, [modname, classname]))
|
|
260
|
+
return self.objtree.find(basepath)
|
|
261
|
+
|
|
262
|
+
_GROUPS = {
|
|
263
|
+
Kind.Module: 0,
|
|
264
|
+
Kind.Data: 1,
|
|
265
|
+
Kind.Function: 2,
|
|
266
|
+
Kind.Class: 3,
|
|
267
|
+
Kind.Alias: 4,
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
def get_children(self, root: Object):
|
|
271
|
+
children = list(root.children.items())
|
|
272
|
+
|
|
273
|
+
order = self.options.get("member-order") or "bysource"
|
|
274
|
+
if order == "alphabetical":
|
|
275
|
+
children.sort(key=lambda ch: ch[0].lower())
|
|
276
|
+
elif order == "groupwise":
|
|
277
|
+
children.sort(key=lambda ch: (self._GROUPS[ch[1].kind], ch[0].lower()))
|
|
278
|
+
elif order == "bysource":
|
|
279
|
+
children.sort(
|
|
280
|
+
key=lambda ch: (
|
|
281
|
+
str(ch[1].file or "@"),
|
|
282
|
+
ch[1].line or math.inf,
|
|
283
|
+
ch[0].lower(),
|
|
284
|
+
)
|
|
285
|
+
)
|
|
286
|
+
else:
|
|
287
|
+
raise RuntimeError(f"unknown member order {order}")
|
|
288
|
+
|
|
289
|
+
inherited_names = set()
|
|
290
|
+
|
|
291
|
+
parent = self.parent
|
|
292
|
+
if (
|
|
293
|
+
parent
|
|
294
|
+
and parent.kind == Kind.Class
|
|
295
|
+
and isinstance(parent, sphinx_lua_ls.doctree.Class)
|
|
296
|
+
):
|
|
297
|
+
for basename in parent.bases:
|
|
298
|
+
base = self.objtree.find(basename)
|
|
299
|
+
if base:
|
|
300
|
+
inherited_names.update(base.children.keys())
|
|
301
|
+
|
|
302
|
+
include_normal = False
|
|
303
|
+
include_undoc = False
|
|
304
|
+
include_private = False
|
|
305
|
+
include_special = False
|
|
306
|
+
include_inherited = False
|
|
307
|
+
|
|
308
|
+
include = set()
|
|
309
|
+
exclude = self.options.get("exclude-members", set())
|
|
310
|
+
|
|
311
|
+
if exclude is True:
|
|
312
|
+
exclude = set()
|
|
313
|
+
|
|
314
|
+
if members := self.options.get("members"):
|
|
315
|
+
if members is True:
|
|
316
|
+
include_normal = True
|
|
317
|
+
else:
|
|
318
|
+
include.update(members)
|
|
319
|
+
if undoc := self.options.get("undoc-members"):
|
|
320
|
+
if undoc is True:
|
|
321
|
+
include_undoc = True
|
|
322
|
+
else:
|
|
323
|
+
include.update(undoc)
|
|
324
|
+
if private := self.options.get("private-members"):
|
|
325
|
+
if private is True:
|
|
326
|
+
include_private = True
|
|
327
|
+
else:
|
|
328
|
+
include.update(private)
|
|
329
|
+
if special := self.options.get("special-members"):
|
|
330
|
+
if special is True:
|
|
331
|
+
include_special = True
|
|
332
|
+
else:
|
|
333
|
+
include.update(special)
|
|
334
|
+
if inherited := self.options.get("inherited-members"):
|
|
335
|
+
if inherited is True:
|
|
336
|
+
include_inherited = True
|
|
337
|
+
else:
|
|
338
|
+
include.update(inherited)
|
|
339
|
+
|
|
340
|
+
for name, child in children:
|
|
341
|
+
if name in exclude:
|
|
342
|
+
continue
|
|
343
|
+
if name not in include:
|
|
344
|
+
is_undoc = not child.docstring
|
|
345
|
+
if is_undoc and not include_undoc:
|
|
346
|
+
continue
|
|
347
|
+
is_private = child.visibility != Visibility.Public
|
|
348
|
+
if is_private and not include_private:
|
|
349
|
+
continue
|
|
350
|
+
is_special = name.startswith("__")
|
|
351
|
+
if is_special and not include_special:
|
|
352
|
+
continue
|
|
353
|
+
is_inherited = name in inherited_names
|
|
354
|
+
if is_inherited and not include_inherited:
|
|
355
|
+
continue
|
|
356
|
+
if (
|
|
357
|
+
not is_undoc
|
|
358
|
+
and not is_private
|
|
359
|
+
and not is_special
|
|
360
|
+
and not is_inherited
|
|
361
|
+
and not include_normal
|
|
362
|
+
):
|
|
363
|
+
continue
|
|
364
|
+
yield name, child
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
class AutodocObjectMixin(sphinx_lua_ls.domain.LuaObject[Any], AutodocUtilsMixin):
|
|
368
|
+
def __init__(self, *args, root: Object):
|
|
369
|
+
super().__init__(*args)
|
|
370
|
+
self.root = root
|
|
371
|
+
|
|
372
|
+
if self.root.visibility == Visibility.Private:
|
|
373
|
+
self.options["private"] = True
|
|
374
|
+
elif self.root.visibility == Visibility.Protected:
|
|
375
|
+
self.options["protected"] = True
|
|
376
|
+
elif self.root.visibility == Visibility.Package:
|
|
377
|
+
self.options["package"] = True
|
|
378
|
+
if self.root.is_async:
|
|
379
|
+
self.options["async"] = True
|
|
380
|
+
if self.root.is_deprecated:
|
|
381
|
+
self.options["deprecated"] = True
|
|
382
|
+
|
|
383
|
+
def run(self) -> list[docutils.nodes.Node]:
|
|
384
|
+
if self.root.file:
|
|
385
|
+
self.state.document.settings.record_dependencies.add(str(self.root.file))
|
|
386
|
+
return super().run()
|
|
387
|
+
|
|
388
|
+
def transform_content(self, content_node: sphinx.addnodes.desc_content) -> None:
|
|
389
|
+
if self.root.docstring:
|
|
390
|
+
self.render_docs(
|
|
391
|
+
str(self.root.file or f"<docstring for {self.arguments[0]}>"),
|
|
392
|
+
self.root.line or 0,
|
|
393
|
+
self.root.docstring,
|
|
394
|
+
content_node,
|
|
395
|
+
)
|
|
396
|
+
if self.allow_nesting:
|
|
397
|
+
for name, child in self.get_children(self.root):
|
|
398
|
+
content_node += self.render(child, name)
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
class LuaFunction(sphinx_lua_ls.domain.LuaFunction, AutodocObjectMixin):
|
|
402
|
+
@functools.cached_property
|
|
403
|
+
def is_method(self):
|
|
404
|
+
assert isinstance(self.root, sphinx_lua_ls.doctree.Function)
|
|
405
|
+
|
|
406
|
+
return self.parent and self.parent.kind == Kind.Class
|
|
407
|
+
|
|
408
|
+
@functools.cached_property
|
|
409
|
+
def is_staticmethod(self):
|
|
410
|
+
assert isinstance(self.root, sphinx_lua_ls.doctree.Function)
|
|
411
|
+
|
|
412
|
+
return (
|
|
413
|
+
self.parent
|
|
414
|
+
and self.parent.kind == Kind.Class
|
|
415
|
+
and (not self.root.params or self.root.params[0].name != "self")
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
@property
|
|
419
|
+
def objtype(self):
|
|
420
|
+
if self.is_staticmethod:
|
|
421
|
+
return "staticmethod"
|
|
422
|
+
elif self.is_method:
|
|
423
|
+
return "method"
|
|
424
|
+
else:
|
|
425
|
+
return "function"
|
|
426
|
+
|
|
427
|
+
@objtype.setter
|
|
428
|
+
def objtype(self, value): # type: ignore
|
|
429
|
+
assert value == "function"
|
|
430
|
+
|
|
431
|
+
def parse_signature(self, sig):
|
|
432
|
+
assert isinstance(self.root, sphinx_lua_ls.doctree.Function)
|
|
433
|
+
return (
|
|
434
|
+
self.arguments[0],
|
|
435
|
+
(
|
|
436
|
+
[(p.name or "", p.type or "") for p in self.root.params],
|
|
437
|
+
[(p.name or "", p.type or "") for p in self.root.returns],
|
|
438
|
+
),
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
def transform_content(self, content_node: sphinx.addnodes.desc_content) -> None:
|
|
442
|
+
assert isinstance(self.root, sphinx_lua_ls.doctree.Function)
|
|
443
|
+
|
|
444
|
+
if self.root.docstring:
|
|
445
|
+
self.render_docs(
|
|
446
|
+
str(self.root.file or f"<docstring for {self.arguments[0]}>"),
|
|
447
|
+
self.root.line or 0,
|
|
448
|
+
self.root.docstring,
|
|
449
|
+
content_node,
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
for child in content_node:
|
|
453
|
+
if isinstance(child, docutils.nodes.field_list):
|
|
454
|
+
field_list = child
|
|
455
|
+
break
|
|
456
|
+
else:
|
|
457
|
+
field_list = docutils.nodes.field_list()
|
|
458
|
+
content_node += field_list
|
|
459
|
+
|
|
460
|
+
for i, param in enumerate(self.root.params):
|
|
461
|
+
if param.docstring and not (i == 0 and param.name == "self"):
|
|
462
|
+
# if param.type:
|
|
463
|
+
# objtree: Object = getattr(self.env, "lua_ls_doc_root")
|
|
464
|
+
# obj = objtree.find(param.type)
|
|
465
|
+
# if obj and obj.docstring == param.docstring:
|
|
466
|
+
# continue
|
|
467
|
+
|
|
468
|
+
field_body = docutils.nodes.field_body("")
|
|
469
|
+
self.render_docs(
|
|
470
|
+
str(
|
|
471
|
+
self.root.file
|
|
472
|
+
or f"<docstring for {self.arguments[0]}, param {param.name}>"
|
|
473
|
+
),
|
|
474
|
+
self.root.line or 0,
|
|
475
|
+
param.docstring,
|
|
476
|
+
field_body,
|
|
477
|
+
)
|
|
478
|
+
field_list += docutils.nodes.field(
|
|
479
|
+
"",
|
|
480
|
+
docutils.nodes.field_name("", "param " + (param.name or "_")),
|
|
481
|
+
field_body,
|
|
482
|
+
)
|
|
483
|
+
if param.type:
|
|
484
|
+
field_list += docutils.nodes.field(
|
|
485
|
+
"",
|
|
486
|
+
docutils.nodes.field_name(
|
|
487
|
+
"", "type " + (param.name or f"_{i + 1}")
|
|
488
|
+
),
|
|
489
|
+
docutils.nodes.field_body("", docutils.nodes.Text(param.type)),
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
for i, param in enumerate(self.root.returns):
|
|
493
|
+
if param.docstring:
|
|
494
|
+
# if param.type:
|
|
495
|
+
# objtree: Object = getattr(self.env, "lua_ls_doc_root")
|
|
496
|
+
# obj = objtree.find(param.type)
|
|
497
|
+
# if obj and obj.docstring == param.docstring:
|
|
498
|
+
# continue
|
|
499
|
+
|
|
500
|
+
field_body = docutils.nodes.field_body("")
|
|
501
|
+
self.render_docs(
|
|
502
|
+
str(
|
|
503
|
+
self.root.file
|
|
504
|
+
or f"<docstring for {self.arguments[0]}, param {param.name}>"
|
|
505
|
+
),
|
|
506
|
+
self.root.line or 0,
|
|
507
|
+
param.docstring,
|
|
508
|
+
field_body,
|
|
509
|
+
)
|
|
510
|
+
field_list += docutils.nodes.field(
|
|
511
|
+
"",
|
|
512
|
+
docutils.nodes.field_name(
|
|
513
|
+
"", "return " + (param.name or f"_{i + 1}")
|
|
514
|
+
),
|
|
515
|
+
field_body,
|
|
516
|
+
)
|
|
517
|
+
if param.type:
|
|
518
|
+
field_list += docutils.nodes.field(
|
|
519
|
+
"",
|
|
520
|
+
docutils.nodes.field_name(
|
|
521
|
+
"", "rtype " + (param.name or f"_{i + 1}")
|
|
522
|
+
),
|
|
523
|
+
docutils.nodes.field_body("", docutils.nodes.Text(param.type)),
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
if self.allow_nesting:
|
|
527
|
+
for name, child in self.get_children(self.root):
|
|
528
|
+
content_node += self.render(child, name)
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
class LuaData(sphinx_lua_ls.domain.LuaData, AutodocObjectMixin):
|
|
532
|
+
def parse_signature(self, sig):
|
|
533
|
+
assert isinstance(self.root, sphinx_lua_ls.doctree.Data)
|
|
534
|
+
return self.arguments[0], self.root.type
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
class LuaAlias(sphinx_lua_ls.domain.LuaAlias, AutodocObjectMixin):
|
|
538
|
+
def parse_signature(self, sig):
|
|
539
|
+
assert isinstance(self.root, sphinx_lua_ls.doctree.Alias)
|
|
540
|
+
return self.arguments[0], self.root.type
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
class LuaClass(sphinx_lua_ls.domain.LuaClass, AutodocObjectMixin):
|
|
544
|
+
def parse_signature(self, sig):
|
|
545
|
+
if self.root.kind == Kind.Class:
|
|
546
|
+
bases = (
|
|
547
|
+
self.root.bases
|
|
548
|
+
if isinstance(self.root, sphinx_lua_ls.doctree.Class)
|
|
549
|
+
else []
|
|
550
|
+
)
|
|
551
|
+
return self.arguments[0], bases
|
|
552
|
+
else:
|
|
553
|
+
return self.arguments[0], []
|
|
554
|
+
|
|
555
|
+
def get_signature_prefix(self, signature: str):
|
|
556
|
+
if self.root.kind == Kind.Class:
|
|
557
|
+
return super().get_signature_prefix(signature)
|
|
558
|
+
else:
|
|
559
|
+
return sphinx_lua_ls.domain.LuaObject.get_signature_prefix(self, signature)
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
def _parse_members(value: str):
|
|
563
|
+
if not value:
|
|
564
|
+
return True
|
|
565
|
+
elif "," in value:
|
|
566
|
+
return {s for m in value.split(",") if (s := m.strip())}
|
|
567
|
+
else:
|
|
568
|
+
return set(value.split())
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
class AutoObjectDirective(AutodocUtilsMixin):
|
|
572
|
+
required_arguments = 1
|
|
573
|
+
option_spec = {
|
|
574
|
+
"no-index": directives.flag,
|
|
575
|
+
"annotation": directives.unchanged,
|
|
576
|
+
"virtual": directives.flag,
|
|
577
|
+
"private": directives.flag,
|
|
578
|
+
"protected": directives.flag,
|
|
579
|
+
"package": directives.flag,
|
|
580
|
+
"abstract": directives.flag,
|
|
581
|
+
"async": directives.flag,
|
|
582
|
+
"global": directives.flag,
|
|
583
|
+
"deprecated": directives.flag,
|
|
584
|
+
"members": _parse_members,
|
|
585
|
+
"undoc-members": _parse_members,
|
|
586
|
+
"private-members": _parse_members,
|
|
587
|
+
"special-members": _parse_members,
|
|
588
|
+
"inherited-members": _parse_members,
|
|
589
|
+
"exclude-members": _parse_members,
|
|
590
|
+
"recursive": lambda x: directives.flag(x) or True,
|
|
591
|
+
"member-order": lambda x: directives.choice(
|
|
592
|
+
x, ("alphabetical", "groupwise", "bysource")
|
|
593
|
+
),
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
has_content = True
|
|
597
|
+
|
|
598
|
+
def run(self):
|
|
599
|
+
for name, option in self.env.config["lua_ls_default_options"].items():
|
|
600
|
+
if name not in self.options:
|
|
601
|
+
self.options[name] = option
|
|
602
|
+
|
|
603
|
+
name = self.arguments[0].strip()
|
|
604
|
+
|
|
605
|
+
if not name:
|
|
606
|
+
raise self.error(f"got an empty object name")
|
|
607
|
+
|
|
608
|
+
found = self.get_root(name, getattr(self.env, "lua_ls_doc_root"))
|
|
609
|
+
if not found:
|
|
610
|
+
raise self.error(f"unknown lua object {name}")
|
|
611
|
+
|
|
612
|
+
root, modname, classname, objname = found
|
|
613
|
+
|
|
614
|
+
self.push_context(modname, classname)
|
|
615
|
+
try:
|
|
616
|
+
return self.render(root, objname, pass_through=True)
|
|
617
|
+
finally:
|
|
618
|
+
self.pop_context()
|
|
619
|
+
|
|
620
|
+
def get_root(self, name: str, root: Object) -> tuple[Object, str, str, str] | None:
|
|
621
|
+
modname = self.options.get("module", self.env.ref_context.get("lua:module"))
|
|
622
|
+
classname = self.env.ref_context.get("lua:class", None)
|
|
623
|
+
|
|
624
|
+
candidates = [
|
|
625
|
+
".".join(filter(None, [modname, classname, name])),
|
|
626
|
+
".".join(filter(None, [modname, name])),
|
|
627
|
+
".".join(filter(None, [name])),
|
|
628
|
+
]
|
|
629
|
+
|
|
630
|
+
for candidate in candidates:
|
|
631
|
+
if found := root.find_path(candidate):
|
|
632
|
+
return found
|