diff --git a/docs/conf.rst b/docs/conf.rst new file mode 100644 index 0000000..e873371 --- /dev/null +++ b/docs/conf.rst @@ -0,0 +1,12 @@ +============= +Configuration +============= + +The extension provides the following configuration: + +.. autoconfval:: project_example_style + + Controls the default value of the :rst:dir:`example` directive's + ``:style:`` option. + + Supported values are ``grid`` and ``tab``. The default is ``grid``. diff --git a/docs/index.rst b/docs/index.rst index 9503e0f..bddcc5c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -75,6 +75,7 @@ Contents .. toctree:: :caption: Contents + conf sphinxnotes_any changelog diff --git a/docs/sphinxnotes_any.rst b/docs/sphinxnotes_any.rst index ceaa691..3d47b7d 100644 --- a/docs/sphinxnotes_any.rst +++ b/docs/sphinxnotes_any.rst @@ -13,3 +13,7 @@ The ``example`` Object ====================== .. autoobj:: any:example + + The default value of the ``:style:`` option can be controlled by the + :confval:`project_example_style` config, which accepts ``grid`` and ``tab`` + and defaults to ``grid``. diff --git a/src/sphinxnotes/project/__init__.py b/src/sphinxnotes/project/__init__.py index 6b53ab9..c1f542c 100644 --- a/src/sphinxnotes/project/__init__.py +++ b/src/sphinxnotes/project/__init__.py @@ -21,6 +21,7 @@ def setup(app: Sphinx): meta.pre_setup(app) from . import sphinxnotes_any, sphinxnotes_render_ext + sphinxnotes_any.setup(app) sphinxnotes_render_ext.setup(app) diff --git a/src/sphinxnotes/project/sphinxnotes_any.py b/src/sphinxnotes/project/sphinxnotes_any.py index 7e9974e..f90bf87 100644 --- a/src/sphinxnotes/project/sphinxnotes_any.py +++ b/src/sphinxnotes/project/sphinxnotes_any.py @@ -14,6 +14,9 @@ from typing import TYPE_CHECKING from os import path +from sphinx.config import ENUM +from sphinx.errors import ConfigError + if TYPE_CHECKING: from sphinx.application import Sphinx from sphinx.config import Config @@ -37,6 +40,14 @@ def _read_template_file(name: str) -> str: return open(_get_template_file(name), 'r').read() +def _validate_project_example_style(style: str) -> str: + if style not in {'tab', 'grid'}: + raise ConfigError( + 'The "project_example_style" config value must be "tab" or "grid".' + ) + return style + + ANY_OBJECT_TYPES = { 'version': { 'schema': { @@ -61,11 +72,15 @@ def _read_template_file(name: str) -> str: 'templates': { 'obj': _read_template_file('example'), }, - } + }, } def _config_inited(app: Sphinx, config: Config) -> None: + config.project_example_style = _validate_project_example_style( + config.project_example_style + ) + if v := config.any_object_types: v.update(ANY_OBJECT_TYPES) else: @@ -75,5 +90,11 @@ def _config_inited(app: Sphinx, config: Config) -> None: def setup(app: Sphinx): app.setup_extension('sphinxnotes.any') + app.add_config_value( + 'project_example_style', + 'grid', + 'env', + types=ENUM('tab', 'grid'), + ) # Should have priority over sphinxnotes.any's "config-inited" callback. app.connect('config-inited', _config_inited, priority=400) diff --git a/src/sphinxnotes/project/sphinxnotes_render_ext.py b/src/sphinxnotes/project/sphinxnotes_render_ext.py index 8d3ba20..5ab8565 100644 --- a/src/sphinxnotes/project/sphinxnotes_render_ext.py +++ b/src/sphinxnotes/project/sphinxnotes_render_ext.py @@ -9,14 +9,35 @@ :copyright: Copyright 2025 Shengyu Zhang :license: BSD, see LICENSE for details. """ + from __future__ import annotations from typing import TYPE_CHECKING +from sphinx.config import ENUM +from sphinxnotes.render import filter + from .sphinxnotes_any import _read_template_file if TYPE_CHECKING: + from collections.abc import Iterable from sphinx.application import Sphinx from sphinx.config import Config + from sphinx.environment import BuildEnvironment + + +def _format_autoconfval_types(valid_types) -> list[str]: + if isinstance(valid_types, ENUM): + return [f'``{c!r}``' for c in sorted(valid_types._candidates)] # pyright: ignore[reportPrivateUsage] + return [f':py:`{t.__name__}`' for t in valid_types] + + +@filter('autoconfval_types') +def autoconfval_types(_: BuildEnvironment): + def _filter(valid_types) -> Iterable[str]: + return _format_autoconfval_types(valid_types) + + return _filter + DATA_DEFINE_DIRECTIVES = { 'autoconfval': { @@ -47,6 +68,7 @@ }, } + def _config_inited(app: Sphinx, config: Config) -> None: if v := config.render_ext_data_define_directives: v.update(DATA_DEFINE_DIRECTIVES) diff --git a/src/sphinxnotes/project/templates/autoconfval.rst b/src/sphinxnotes/project/templates/autoconfval.rst index 8832ded..b6efdfa 100644 --- a/src/sphinxnotes/project/templates/autoconfval.rst +++ b/src/sphinxnotes/project/templates/autoconfval.rst @@ -3,15 +3,8 @@ .. role:: py(code) :language: Python -{% set types = [] %} -{% for t in opt.valid_types %} - {# "" → "str" #} - {% set t = t | string %} - {% do types.append(t[8:-2]) %} -{% endfor %} - .. confval:: {{ name }} - :type: {{ types | roles('py') | join(',') }} + :type: {{ opt.valid_types | autoconfval_types | join(', ') }} :default: :py:`{{ opt.default | pprint }}` {%- for line in opt.description.split('\n') %} diff --git a/src/sphinxnotes/project/templates/example.rst b/src/sphinxnotes/project/templates/example.rst index be16592..ef1186a 100644 --- a/src/sphinxnotes/project/templates/example.rst +++ b/src/sphinxnotes/project/templates/example.rst @@ -1,4 +1,5 @@ -{% if not style or style == 'tab' %} +{% set effective_style = style or load_extra('env').config.project_example_style %} +{% if effective_style == 'tab' %} .. tab-set:: .. tab-item:: Result @@ -14,7 +15,7 @@ {% for line in content.split('\n') -%} {{ line }} {% endfor %} -{% elif style == 'grid' %} +{% elif effective_style == 'grid' %} .. grid:: 1 1 2 2 :gutter: 1 :margin: 0