Code Annotations

A special directive was created to make use of the mkdocs-material theme’s Code Annotations feature.

.. code-annotations::

This directive shall hold an enumerated list of annotations that can be used in a code-block immediately prior to this directive. The given list will not be rendered in the generated output, unless there is no immediately prior code-block to annotate or there are no annotated comments in the immediately prior code-block. Additionally, all annotations will be excluded when using the “copy to clipboard” button for an annotated code-block; the annotated comments’ text will still be copied (if not Hiding the annotated comment).

An error will be shown in the build log if the given list is not recognized as an enumerated list.

Note

When using this directive, the "content.code.annotate" does not need to be specified in the features list.

Using annotations

Each annotation in the code snippet should be a comment containing the identifying number in parentheses ((1)) that corresponds to the sequential order of annotations specified in the list of code-annotations.

Note

Remember to specify the language syntax for pygments to highlight the code-block. Without this information, pygments may incorrectly identify comments in a code-block which is required for the detection of annotations.

Hint

All annotations are hyperlinked. This means you can right click the annotation’s button and open it as a link in a new tab (or copy the link to share it).

Example of code annotations
.. code-block:: python

    html_theme_options = {
        "features" : [
            "content.code.annotate"  # (1)
        ],
    }

.. code-annotations::
    1. .. admonition:: Obsolete
           :class: failure

           This has no special effect because the :rst:dir:`code-annotations` directive
           automatically enables the feature.
html_theme_options = {
    "features" : [
        "content.code.annotate"  # (1)
    ],
}
  1. Obsolete

    This has no special effect because the code-annotations directive automatically enables the feature.

Arbitrary list markers

The enumerated lists’ markers are arbitrary and do not directly correspond to the identifying numbers used in the annotated comment. Because of this arbitrariness, the identifying numbers in the annotated comments must always start counting from 1 (for each code-block). Remember, the # character can be used instead of numbers/letters in the enumerated lists’ markers.

The below example demonstrates this arbitrariness as the annotated comment (1) corresponds to the first annotated list item (beginning with the marker 3.).

.. code-block:: cpp

    // What can I put in an annotation? (1)
    /* What about nested lists and emojis? (2) */

.. code-annotations::
    3. These annotations can have anything that Sphinx supports (including extensions).

       .. graphviz::

           digraph { A -> B }
       .. image:: desert-flower.jpg
           :width: 75%
    #. Indentation for lists' items that span multiple lines can be tricky in
       reStructuredText.

       0. First item in a nested list that starts with ``0``.
       #. Checkout the `sphinxemoji <https://sphinxemojicodes.rtfd.io>`_ extension to
          put emojis here.
// What can I put in an annotation? (1)
/* What about nested lists and emojis? (2) */
  1. These annotations can have anything that Sphinx supports (including extensions).

    %3 A A B B A->B _images/desert-flower.jpg
  2. Indentation for lists’ items that span multiple lines can be tricky in reStructuredText.

    1. First item in a nested list that starts with 0.

    2. Checkout the sphinxemoji extension to put emojis here.

Warning

Using the same identifying number to annotate multiple comments will essentially turn all but the last button into hyperlinks that target to the last button.

.. code-block:: lua

    -- (1) some text, and (1)

    local var_name = 0
    -- (1)

.. code-annotations::
    #. Should've used :duref:`footnotes <footnotes>` instead.
-- (1) some text, and (1)

local var_name = 0
-- (1)
  1. Should’ve used footnotes instead.

Hiding the annotated comment

The annotated comment can be hidden in the code-block if the annotation’s identifying number ends with a exclamation mark (!) after the closing parenthesis.

.. code-block:: cmake
    :caption: Erroneous example!
    :linenos:

    # (1)! remove me

    # (2)! (3) remove me

    # (4) some text   (5)! remove me

.. code-annotations::
    1. I'm the first annotation.
    2. I'm the second annotation.
    3. Nothing to see here because it won't be rendered.
    4. I'm the forth annotation.
    5. I'm the fifth annotation.
Erroneous example!
1
2
3
4
5
# (1)! remove me

# (2)! (3) remove me

# (4) some text   (5)! remove me
  1. I’m the first annotation.

  2. I’m the second annotation.

  3. Nothing to see here because it won’t be rendered.

  4. I’m the forth annotation.

  5. I’m the fifth annotation.

Limitations

For technical reasons, this hiding mechanism will only work with 1 annotation per code comment. In the above example, you should notice that, on line 3, the third annotation is removed because the second annotation has the ! appended in the comment. And all text is removed from the third comment, on line 5, because the fifth annotation has the ! appended to it.

Custom tooltip width

For annotations with an excess of content,it might be desirable to change the width of the annotations’ tooltip using by changing the following CSS variable:

:root {
  --md-tooltip-width: 600px;
}

With the above CSS changes, a tooltip would be rendered like so:

.. code-block:: yaml

    # (1)!

.. code-annotations::
    1. Muuuuuuuuuuuuuuuuuuuuuuuuuuuuch more space!
# (1)!
  1. Muuuuuuuuuuuuuuuuuuuuuuuuuuuuch more space!

Annotation buttons with numbers

The mkdocs-material legacy behavior was to use the annotated comment’s identifying number in the button that was rendered. However, this behavior was removed because annotated comment’s identifying number is arbitrary to the annotated list item’s numeric marker – see example snippet in Arbitrary list markers.

To enable this legacy behavior, use the following custom CSS rules:

.md-typeset .md-annotation__index > ::before {
  content: attr(data-md-annotation-id);
}
.md-typeset :focus-within > .md-annotation__index > ::before {
  transform: none;
}

Using the above CSS would render annotations like so:

.. code-block:: python

    def my_func(param)  # (1)!
        """A doc string."""
        return param + 1  # (2)!

.. code-annotations::
    1. Data goes in here.
    2. Data comes out here.
def my_func(param)  # (1)!
    """A doc string."""
    return param + 1  # (2)!
  1. Data goes in here.

  2. Data comes out here.


Last update: Feb 17, 2024