Skip to content

Commit

Permalink
Process events (#126)
Browse files Browse the repository at this point in the history
  • Loading branch information
coloursofnoise committed Aug 9, 2023
1 parent 3d85d6f commit 18de60a
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 0 deletions.
32 changes: 32 additions & 0 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,38 @@ Programs
__ https://github.com/sphinx-doc/sphinx/issues/880


Docstring processing
--------------------

*sphinx-click* provides the following additional events:

.. py:function:: sphinx-click-process-description(app, ctx, lines)
.. py:function:: sphinx-click-process-usage(app, ctx, lines)
.. py:function:: sphinx-click-process-options(app, ctx, lines)
.. py:function:: sphinx-click-process-arguments(app, ctx, lines)
.. py:function:: sphinx-click-process-envvars(app, ctx, lines)
.. py:function:: sphinx-click-process-epilog(app, ctx, lines)
:param app: the Sphinx application object
:param ctx: the ``click.Context`` object used to generate the description
:param lines: the lines of the documentation, see below

Events are emitted when sphinx-click has read and processed part of a
command's documentation. *lines* is a list of strings -- the lines of the
documentation that was processed -- that the event handler can
modify **in place** to change what Sphinx puts into the output.

.. code-block:: python
def process_description(app, ctx, lines):
"""Append some text to the "example" command description."""
if ctx.command.name == "example":
lines.extend(["Hello, World!", ""])
def setup(app):
app.connect("sphinx-click-process-description", process_description)
Example
-------

Expand Down
32 changes: 32 additions & 0 deletions sphinx_click/ext.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import inspect
import functools
import re
import traceback
import typing as ty
Expand All @@ -24,6 +25,23 @@

ANSI_ESC_SEQ_RE = re.compile(r'\x1B\[\d+(;\d+){0,2}m', flags=re.MULTILINE)

_T_Formatter = ty.Callable[[click.Context], ty.Generator[str, None, None]]


def _process_lines(event_name: str) -> ty.Callable[[_T_Formatter], _T_Formatter]:
def decorator(func: _T_Formatter) -> _T_Formatter:
@functools.wraps(func)
def process_lines(ctx: click.Context) -> ty.Generator[str, None, None]:
lines = list(func(ctx))
if "sphinx-click-env" in ctx.meta:
ctx.meta["sphinx-click-env"].app.events.emit(event_name, ctx, lines)
for line in lines:
yield line

return process_lines

return decorator


def _indent(text: str, level: int = 1) -> str:
prefix = ' ' * (4 * level)
Expand Down Expand Up @@ -123,6 +141,7 @@ def _format_help(help_string: str) -> ty.Generator[str, None, None]:
yield ''


@_process_lines("sphinx-click-process-description")
def _format_description(ctx: click.Context) -> ty.Generator[str, None, None]:
"""Format the description for a given `click.Command`.
Expand All @@ -134,6 +153,7 @@ def _format_description(ctx: click.Context) -> ty.Generator[str, None, None]:
yield from _format_help(help_string)


@_process_lines("sphinx-click-process-usage")
def _format_usage(ctx: click.Context) -> ty.Generator[str, None, None]:
"""Format the usage for a `click.Command`."""
yield '.. code-block:: shell'
Expand Down Expand Up @@ -163,6 +183,7 @@ def _format_option(opt: click.Option) -> ty.Generator[str, None, None]:
yield _indent(line)


@_process_lines("sphinx-click-process-options")
def _format_options(ctx: click.Context) -> ty.Generator[str, None, None]:
"""Format all `click.Option` for a `click.Command`."""
# the hidden attribute is part of click 7.x only hence use of getattr
Expand All @@ -189,6 +210,7 @@ def _format_argument(arg: click.Argument) -> ty.Generator[str, None, None]:
)


@_process_lines("sphinx-click-process-arguments")
def _format_arguments(ctx: click.Context) -> ty.Generator[str, None, None]:
"""Format all `click.Argument` for a `click.Command`."""
params = [x for x in ctx.command.params if isinstance(x, click.Argument)]
Expand Down Expand Up @@ -216,6 +238,7 @@ def _format_envvar(
yield _indent('Provide a default for :option:`{}`'.format(param_ref))


@_process_lines("sphinx-click-process-envars")
def _format_envvars(ctx: click.Context) -> ty.Generator[str, None, None]:
"""Format all envvars for a `click.Command`."""

Expand Down Expand Up @@ -255,6 +278,7 @@ def _format_subcommand(command: click.Command) -> ty.Generator[str, None, None]:
yield _indent(line)


@_process_lines("sphinx-click-process-epilog")
def _format_epilog(ctx: click.Context) -> ty.Generator[str, None, None]:
"""Format the epilog for a given `click.Command`.
Expand Down Expand Up @@ -466,6 +490,7 @@ def _generate_nodes(
source_name = ctx.command_path
result = statemachine.ViewList()

ctx.meta["sphinx-click-env"] = self.env
if semantic_group:
lines = _format_description(ctx)
else:
Expand Down Expand Up @@ -539,6 +564,13 @@ def run(self) -> ty.Iterable[nodes.section]:
def setup(app: application.Sphinx) -> ty.Dict[str, ty.Any]:
app.add_directive('click', ClickDirective)

app.add_event("sphinx-click-process-description")
app.add_event("sphinx-click-process-usage")
app.add_event("sphinx-click-process-options")
app.add_event("sphinx-click-process-arguments")
app.add_event("sphinx-click-process-envvars")
app.add_event("sphinx-click-process-epilog")

return {
'parallel_read_safe': True,
'parallel_write_safe': True,
Expand Down

0 comments on commit 18de60a

Please sign in to comment.