Skip to content

Commit a4de250

Browse files
authored
Add a new confval directive to document settings and configuration values (#12536)
1 parent 05d1d8a commit a4de250

File tree

5 files changed

+120
-6
lines changed

5 files changed

+120
-6
lines changed

CHANGES.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ Features added
5858
Patch by Bénédikt Tran and Adam Turner.
5959
* #12524: Add a ``class`` option to the :rst:dir:`toctree` directive.
6060
Patch by Tim Hoffmann.
61+
* #12536: Add the :rst:dir:`confval` directive.
62+
Patch by Adam Turner.
6163

6264
Bugs fixed
6365
----------

doc/conf.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -328,12 +328,6 @@ def setup(app: Sphinx) -> None:
328328
app.connect('autodoc-process-docstring', cut_lines(4, what=['module']))
329329
app.connect('source-read', linkify_issues_in_changelog)
330330
app.connect('build-finished', build_redirects)
331-
app.add_object_type(
332-
'confval',
333-
'confval',
334-
objname='configuration value',
335-
indextemplate='pair: %s; configuration value',
336-
)
337331
fdesc = GroupedField('parameter', label='Parameters', names=['param'], can_collapse=True)
338332
app.add_object_type(
339333
'event', 'event', 'pair: %s; event', parse_event, doc_field_types=[fdesc]

doc/usage/domains/standard.rst

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,44 @@ There is a set of directives allowing documenting command-line programs:
4242

4343
``cmdoption`` directive is a deprecated alias for the ``option`` directive.
4444

45+
.. rst:directive:: .. confval:: name
46+
47+
Describes a configuration value or setting that the documented
48+
code or program uses or defines.
49+
Referenceable by :rst:role:`confval`.
50+
51+
.. rst:directive:option:: type
52+
:type: text
53+
54+
Describes the type of the configuration value.
55+
This is optional, and if specified will be interpreted as reStructuredText.
56+
57+
.. rst:directive:option:: default
58+
:type: text
59+
60+
Describes the default value of the configuration value.
61+
This is optional, and if specified will be interpreted as reStructuredText.
62+
63+
Example:
64+
65+
.. code-block:: rst
66+
67+
.. confval:: the_answer
68+
:type: ``int`` (a *number*)
69+
:default: **42**
70+
71+
This is a setting that controls the value of the answer.
72+
73+
will be rendered as follows:
74+
75+
.. confval:: the_answer
76+
:no-contents-entry:
77+
:no-index-entry:
78+
:type: ``int`` (a *number*)
79+
:default: **42**
80+
81+
This is a setting that controls the value of the answer.
82+
4583
.. rst:directive:: .. envvar:: name
4684
4785
Describes an environment variable that the documented code or program uses

doc/usage/referencing.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,13 @@ Cross-referencing other items of interest
222222
The following roles do possibly create a cross-reference, but do not refer to
223223
objects:
224224

225+
.. rst:role:: confval
226+
227+
A configuration value or setting.
228+
Index entries are generated.
229+
Also generates a link to the matching :rst:dir:`confval` directive,
230+
if it exists.
231+
225232
.. rst:role:: envvar
226233
227234
An environment variable. Index entries are generated. Also generates a link

sphinx/domains/std/__init__.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,76 @@ def result_nodes(self, document: nodes.document, env: BuildEnvironment, node: El
102102
return [indexnode, targetnode, node], []
103103

104104

105+
class ConfigurationValue(ObjectDescription[str]):
106+
index_template: str = _('%s; configuration value')
107+
option_spec: ClassVar[OptionSpec] = {
108+
'no-index': directives.flag,
109+
'no-index-entry': directives.flag,
110+
'no-contents-entry': directives.flag,
111+
'no-typesetting': directives.flag,
112+
'type': directives.unchanged_required,
113+
'default': directives.unchanged_required,
114+
}
115+
116+
def handle_signature(self, sig: str, sig_node: desc_signature) -> str:
117+
sig_node.clear()
118+
sig_node += addnodes.desc_name(sig, sig)
119+
name = ws_re.sub(' ', sig)
120+
sig_node['fullname'] = name
121+
return name
122+
123+
def _object_hierarchy_parts(self, sig_node: desc_signature) -> tuple[str, ...]:
124+
return (sig_node['fullname'],)
125+
126+
def _toc_entry_name(self, sig_node: desc_signature) -> str:
127+
if not sig_node.get('_toc_parts'):
128+
return ''
129+
name, = sig_node['_toc_parts']
130+
return name
131+
132+
def add_target_and_index(self, name: str, sig: str, signode: desc_signature) -> None:
133+
node_id = make_id(self.env, self.state.document, self.objtype, name)
134+
signode['ids'].append(node_id)
135+
self.state.document.note_explicit_target(signode)
136+
index_entry = self.index_template % name
137+
self.indexnode['entries'].append(('pair', index_entry, node_id, '', None))
138+
self.env.domains['std'].note_object(self.objtype, name, node_id, location=signode)
139+
140+
def transform_content(self, content_node: addnodes.desc_content) -> None:
141+
"""Insert *type* and *default* as a field list."""
142+
field_list = nodes.field_list()
143+
if 'type' in self.options:
144+
field, msgs = self.format_type(self.options['type'])
145+
field_list.append(field)
146+
field_list += msgs
147+
if 'default' in self.options:
148+
field, msgs = self.format_default(self.options['default'])
149+
field_list.append(field)
150+
field_list += msgs
151+
if len(field_list.children) > 0:
152+
content_node.insert(0, field_list)
153+
154+
def format_type(self, type_: str) -> tuple[nodes.field, list[system_message]]:
155+
"""Formats the ``:type:`` option."""
156+
parsed, msgs = self.parse_inline(type_, lineno=self.lineno)
157+
field = nodes.field(
158+
'',
159+
nodes.field_name('', _('Type')),
160+
nodes.field_body('', *parsed),
161+
)
162+
return field, msgs
163+
164+
def format_default(self, default: str) -> tuple[nodes.field, list[system_message]]:
165+
"""Formats the ``:default:`` option."""
166+
parsed, msgs = self.parse_inline(default, lineno=self.lineno)
167+
field = nodes.field(
168+
'',
169+
nodes.field_name('', _('Default')),
170+
nodes.field_body('', *parsed),
171+
)
172+
return field, msgs
173+
174+
105175
class Target(SphinxDirective):
106176
"""
107177
Generic target for user-defined cross-reference types.
@@ -527,6 +597,7 @@ class StandardDomain(Domain):
527597
'token': ObjType(_('grammar token'), 'token', searchprio=-1),
528598
'label': ObjType(_('reference label'), 'ref', 'keyword',
529599
searchprio=-1),
600+
'confval': ObjType('configuration value', 'confval'),
530601
'envvar': ObjType(_('environment variable'), 'envvar'),
531602
'cmdoption': ObjType(_('program option'), 'option'),
532603
'doc': ObjType(_('document'), 'doc', searchprio=-1),
@@ -536,12 +607,14 @@ class StandardDomain(Domain):
536607
'program': Program,
537608
'cmdoption': Cmdoption, # old name for backwards compatibility
538609
'option': Cmdoption,
610+
'confval': ConfigurationValue,
539611
'envvar': EnvVar,
540612
'glossary': Glossary,
541613
'productionlist': ProductionList,
542614
}
543615
roles: dict[str, RoleFunction | XRefRole] = {
544616
'option': OptionXRefRole(warn_dangling=True),
617+
'confval': XRefRole(warn_dangling=True),
545618
'envvar': EnvVarXRefRole(),
546619
# links to tokens in grammar productions
547620
'token': TokenXRefRole(),

0 commit comments

Comments
 (0)