Skip to content

Commit 8a49970

Browse files
committed
Allow extending or disabling global settings
1 parent ca4eeb3 commit 8a49970

19 files changed

+409
-138
lines changed

docs/source/autodoc.rst

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -293,19 +293,14 @@ Autodoc directive
293293
for all objects nested within the root. That is, object's members,
294294
their members, and so on.
295295
296-
If
297-
:rst:dir:`lua:autoobject:members`,
298-
:rst:dir:`lua:autoobject:globals`,
299-
:rst:dir:`lua:autoobject:undoc-members`,
300-
:rst:dir:`lua:autoobject:private-members`,
301-
:rst:dir:`lua:autoobject:special-members`,
302-
or :rst:dir:`lua:autoobject:inherited-members`
303-
are given as flags, they are propagated to all documented objects.
304-
305-
If they're given as list, they are not propagated.
306-
307-
Options from :py:data:`lua_ls_default_options` are applied to all recursively
308-
documented objects.
296+
Options like ``no-index`` or :rst:dir:`lua:autoobject:member-order` are always
297+
passed down to all members.
298+
299+
List options like :rst:dir:`lua:autoobject:members`
300+
or :rst:dir:`lua:autoobject:globals`
301+
are passed down if they're empty or start with ``+``
302+
(see :py:data:`lua_ls_default_options` for info on ``+``
303+
and overriding defaults).
309304
310305
.. rst:directive:option:: member-order
311306

docs/source/settings.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,25 @@ Settings
5656
# And so on...
5757
}
5858
59+
If using defaults for the ``:members:``, ``:exclude-members:``, and other
60+
list options, setting the option on a directive will override the default.
61+
Instead, to extend the default list with the per-directive option,
62+
the list may be prepended with a plus sign (``+``), as follows:
63+
64+
.. code-block:: rst
65+
66+
.. lua:autoobject:: Noodle
67+
:members: eat
68+
:private-members: +_spicy, _garlickly
69+
70+
Also, the defaults can be disabled per-directive with the negated form,
71+
``:no-option:`` as an option of the directive:
72+
73+
.. code-block:: rst
74+
75+
.. lua:autoobject:: foo
76+
:no-undoc-members:
77+
5978
.. py:data:: class_default_function_name
6079
:type: str
6180

sphinx_lua_ls/autodoc.py

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -201,14 +201,14 @@ class AutodocUtilsMixin(sphinx_lua_ls.domain.LuaContextManagerMixin):
201201
"""
202202

203203
option_spec: ClassVar[dict[str, Callable[[str], Any]]] = { # type: ignore
204-
"members": utils.parse_list_option,
205-
"undoc-members": utils.parse_list_option,
206-
"private-members": utils.parse_list_option,
207-
"protected-members": utils.parse_list_option,
208-
"package-members": utils.parse_list_option,
209-
"special-members": utils.parse_list_option,
210-
"inherited-members": utils.parse_list_option,
211-
"exclude-members": utils.parse_list_option,
204+
"members": utils.parse_list_option_or_true,
205+
"undoc-members": utils.parse_list_option_or_true,
206+
"private-members": utils.parse_list_option_or_true,
207+
"protected-members": utils.parse_list_option_or_true,
208+
"package-members": utils.parse_list_option_or_true,
209+
"special-members": utils.parse_list_option_or_true,
210+
"inherited-members": utils.parse_list_option_or_true,
211+
"exclude-members": utils.parse_list_option_or_true,
212212
"title": directives.unchanged,
213213
"index-title": directives.unchanged,
214214
"recursive": directives.flag,
@@ -220,7 +220,7 @@ class AutodocUtilsMixin(sphinx_lua_ls.domain.LuaContextManagerMixin):
220220
"module-member-order": lambda x: directives.choice(
221221
x, ("alphabetical", "groupwise", "bysource")
222222
),
223-
"globals": utils.parse_list_option,
223+
"globals": utils.parse_list_option_or_true,
224224
"class-doc-from": lambda x: directives.choice(
225225
x, ("class", "both", "ctor", "separate", "none")
226226
),
@@ -232,8 +232,14 @@ class AutodocUtilsMixin(sphinx_lua_ls.domain.LuaContextManagerMixin):
232232
),
233233
"require-function-name": directives.unchanged,
234234
"require-separator": directives.unchanged,
235-
**sphinx_lua_ls.domain.LuaObject.option_spec,
236235
}
236+
option_spec.update(
237+
{
238+
f"no-{key}": directives.flag
239+
for key in sphinx_lua_ls.domain.GLOBAL_OPTIONS & set(option_spec)
240+
}
241+
)
242+
option_spec.update(sphinx_lua_ls.domain.LuaObject.option_spec)
237243

238244
def render(self, root: Object, name: str, top_level: bool = False):
239245
if root.kind is None:
@@ -383,25 +389,39 @@ def _create_directive(
383389
top_level: bool = False,
384390
) -> SphinxDirective:
385391
if top_level:
386-
options = self.options.copy()
392+
options = self.orig_options.copy()
387393
options.pop("module", None)
388394
else:
389395
options = {}
390396
for key in [
391397
"member-order",
398+
"no-member-order",
392399
"module-member-order",
400+
"no-module-member-order",
393401
"recursive",
402+
"no-recursive",
394403
"no-index",
404+
"no-no-index",
405+
"no-index-entry",
406+
"no-no-index-entry",
407+
"no-contents-entry",
408+
"no-no-contents-entry",
395409
"inherited-members-table",
410+
"no-inherited-members-table",
396411
"class-doc-from",
412+
"no-class-doc-from",
397413
"class-signature",
414+
"no-class-signature",
398415
"annotate-require",
416+
"no-annotate-require",
399417
"require-function-name",
418+
"no-require-function-name",
400419
"require-separator",
420+
"no-require-separator",
401421
]:
402-
if key in self.options:
403-
options[key] = self.options[key]
404-
if "recursive" in self.options:
422+
if key in self.orig_options:
423+
options[key] = self.orig_options[key]
424+
if "recursive" in self.orig_options:
405425
for key in [
406426
"members",
407427
"globals",
@@ -411,9 +431,17 @@ def _create_directive(
411431
"package-members",
412432
"special-members",
413433
"inherited-members",
434+
"using",
414435
]:
415-
if key in self.options and self.options[key] is True:
416-
options[key] = self.options[key]
436+
if key in self.orig_options:
437+
if self.orig_options[key] is True:
438+
options[key] = self.orig_options[key]
439+
elif (
440+
self.orig_options[key] and self.orig_options[key][0] == "+"
441+
):
442+
options[key] = self.orig_options[key]
443+
if f"no-{key}" in self.orig_options:
444+
options[f"no-{key}"] = self.orig_options[f"no-{key}"]
417445

418446
match root.visibility:
419447
case Visibility.Private:
@@ -939,9 +967,7 @@ class AutoObjectDirective(AutodocUtilsMixin):
939967
has_content = True
940968

941969
def run(self):
942-
for name, option in self.lua_domain.config.default_options.items():
943-
if name not in self.options:
944-
self.options[name] = option
970+
self.prepare_options()
945971

946972
name = self.arguments[0].strip()
947973

sphinx_lua_ls/config.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,11 @@ def _options(name: str, value) -> dict[str, _t.Any]:
8787
for key, option in value.items():
8888
parser = sphinx_lua_ls.autodoc.AutoObjectDirective.option_spec.get(key, None)
8989
if parser is None:
90-
raise ConfigError(f"unknown option in {name}: {key}")
90+
raise ConfigError(f"unknown option in {name}: :{key}:")
91+
if key not in sphinx_lua_ls.domain.GLOBAL_OPTIONS:
92+
raise ConfigError(
93+
f"incorrect option in {name}: :{key}: can't be set from config"
94+
)
9195
_type(f"{name}[{key!r}]", option, str)
9296
try:
9397
new_value[key] = parser(option)

sphinx_lua_ls/domain.py

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,54 @@ def pop_context(self):
261261
else:
262262
self.env.ref_context.pop("lua:using", None)
263263

264+
def prepare_options(self):
265+
self.orig_options = self.options.copy()
266+
for name, option in self.lua_domain.config.default_options.items():
267+
if f"no-{name}" in self.options:
268+
continue
269+
if name not in self.options:
270+
self.options[name] = option
271+
else:
272+
given_option = self.options[name]
273+
if (
274+
isinstance(given_option, list)
275+
and given_option
276+
and given_option[0] == "+"
277+
):
278+
if isinstance(option, list):
279+
self.options[name] = option + given_option[1:]
280+
else:
281+
self.options[name] = given_option[1:]
282+
283+
284+
GLOBAL_OPTIONS = {
285+
"no-index",
286+
"no-index-entry",
287+
"no-contents-entry",
288+
"using",
289+
"members",
290+
"undoc-members",
291+
"private-members",
292+
"protected-members",
293+
"package-members",
294+
"special-members",
295+
"inherited-members",
296+
"exclude-members",
297+
"title",
298+
"index-title",
299+
"recursive",
300+
"index-table",
301+
"inherited-members-table",
302+
"member-order",
303+
"module-member-order",
304+
"globals",
305+
"class-doc-from",
306+
"class-signature",
307+
"annotate-require",
308+
"require-function-name",
309+
"require-separator",
310+
}
311+
264312

265313
class LuaObject(
266314
ObjectDescription[tuple[str, str, str, str]], LuaContextManagerMixin, Generic[T]
@@ -295,6 +343,9 @@ class LuaObject(
295343
"using": utils.parse_list_option,
296344
**ObjectDescription.option_spec,
297345
}
346+
option_spec.update(
347+
{f"no-{key}": directives.flag for key in GLOBAL_OPTIONS & set(option_spec)}
348+
)
298349

299350
doc_field_types = [
300351
LuaTypedField(
@@ -327,9 +378,7 @@ class LuaObject(
327378
collected_bases: list[str] | None = None
328379

329380
def run(self) -> list[nodes.Node]:
330-
for name, option in self.lua_domain.config.default_options.items():
331-
if name not in self.options:
332-
self.options[name] = option
381+
self.prepare_options()
333382
return super().run()
334383

335384
def parse_signature(self, sig: str) -> tuple[str, T]:
@@ -955,9 +1004,7 @@ class LuaModule(LuaContextManagerMixin):
9551004
}
9561005

9571006
def run(self) -> list[nodes.Node]:
958-
for name, option in self.lua_domain.config.default_options.items():
959-
if name not in self.options:
960-
self.options[name] = option
1007+
self.prepare_options()
9611008

9621009
if self.env.ref_context.get("lua:class", None):
9631010
raise self.severe("lua:module only available on top level")

sphinx_lua_ls/utils.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,22 @@ def parse_list_option(value: str):
387387
if not value:
388388
return True
389389
else:
390-
return separate_sig(value)
390+
value = value.strip()
391+
if value.startswith("+"):
392+
return ["+", *separate_sig(value.lstrip("+, "))]
393+
else:
394+
return separate_sig(value)
395+
396+
397+
def parse_list_option_or_true(value: str):
398+
if not value:
399+
return True
400+
else:
401+
value = value.strip()
402+
if value.startswith("+"):
403+
return ["+", *separate_sig(value.lstrip("+, "))]
404+
else:
405+
return separate_sig(value)
391406

392407

393408
_VCS_MARKERS = [".git", ".hg", ".svn"]
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Minimal makefile for Sphinx documentation
2+
#
3+
4+
# You can set these variables from the command line, and also
5+
# from the environment for the first two.
6+
SPHINXOPTS ?=
7+
SPHINXBUILD ?= sphinx-build
8+
SOURCEDIR = .
9+
BUILDDIR = build
10+
11+
# Put it first so that "make" without argument is like "make help".
12+
help:
13+
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14+
15+
.PHONY: help Makefile
16+
17+
# Catch-all target: route all unknown targets to Sphinx using the new
18+
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19+
%: Makefile
20+
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
project = "Test"
2+
copyright = "test"
3+
author = "test"
4+
5+
extensions = ["sphinx_lua_ls"]
6+
lua_ls_backend = "emmylua"
7+
lua_ls_project_root = "lua"
8+
lua_ls_default_options = {
9+
"members": "",
10+
"exclude-members": "bar",
11+
"undoc-members": "",
12+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Test autodoc
2+
============
3+
4+
.. container:: regression
5+
6+
.. lua:autoobject:: autodoc
7+
8+
.. lua:autoobject:: autodoc
9+
:exclude-members: +foo
10+
:no-undoc-members:
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--- @namespace autodoc
2+
3+
--- Description
4+
local autodoc = {}
5+
6+
--- Description.
7+
function autodoc.foo() end
8+
9+
--- Description.
10+
function autodoc.bar() end
11+
12+
--- Description.
13+
function autodoc.baz() end
14+
15+
function autodoc.undoc() end
16+
17+
return autodoc

0 commit comments

Comments
 (0)