Sphinx-Immaterial Theme

repository·main·Indexed 42 days ago

https://github.com/jbms/sphinx-immaterial

A Sphinx documentation theme adapted from mkdocs-material that provides a modern Material Design look. It includes extended support for admonitions with collapsible blocks and custom styling, C++ API documentation generation via libclang, and compatibility with Sphinx-specific features like object descriptions and native search indices.

Tokens
89K
Snippets
361
Records
428
Agent score
54%

What's inside Sphinx-Immaterial

  1. Use MyST Markdown Typography

    main

    MyST is a strict superset of CommonMark designed for scientific and technical documentation. It provides enhanced support for headings, attributes, mathematical notation, and complex list structures.

    Key features include:

    • Attributes: Use the attrs_block or attrs_inline extensions to add CSS classes to elements.
    • Advanced Lists: Support for task lists, definition lists, and custom numbering styles.
    • Scientific Notation: Support for subscript (sub) and superscript (sup) roles.
    • Footnotes: Pandoc-style footnote referencing and definitions.
  2. Organize Python entities into groups using docstrings

    main

    You can organize module-level and class members into logical groups using the :group: field in docstrings. This allows you to create summaries of related functions or methods.

    If you are using sphinx.ext.napoleon, you can also use a Group: section in your docstring.

    If no group is specified, members are assigned to a default group based on the python_apigen_default_groups configuration.

    # Using standard rST field
    def foo(x: int) -> int:
        """Does something or other.
    
        :param x: The parameter.
        :group: My group
        """
        pass
    
    # Using Napoleon syntax
    def bar(x: int) -> int:
        """Does something or other.
    
        Args:
          x: The parameter.
    
        Group:
          My group
        """
        pass
  3. Key differences between sphinx-immaterial and mkdocs-material

    main

    While sphinx-immaterial is an adaptation of mkdocs-material, it includes specific adjustments for the Sphinx ecosystem:

    • Sphinx Object Styles: Includes dedicated styles for Sphinx object descriptions (e.g., class and function documentation) which are not present in the original MkDocs version.
    • Search Implementation: Unlike mkdocs-material which uses lunr.js, this theme uses a search implementation based on the custom Sphinx index format, while maintaining the mkdocs-material search UI components.
  4. Use cross-references in Graphviz via the `xref` attribute

    main

    The extension provides a special xref attribute that accepts reStructuredText. This allows you to embed Sphinx cross-references (like :py:obj:, :py:class:, etc.) directly into your graphs.

    When you use xref:

    1. The text content of the parsed fragment becomes the label.
    2. If the fragment contains a hyperlink, the extension automatically extracts the href, tooltip, and target and applies them to the node.

    Overriding Labels: Because the label generated from xref escapes HTML characters (e.g., < becomes &lt;), you may need to manually specify a label attribute after the xref attribute if you require unescaped HTML characters in your node labels.

    digraph {
      node [
        xref=":py:obj:`~module.object`"
        label="<f0> test_module.test | <f1> functions"
        shape = record
      ]
    }
  5. Hide the Table of Contents (ToC)

    main

    You can hide the local table of contents on the right side of a page using either the :hide-toc: metadata field or by setting the :tocdepth: to 0. Note that if the toc.integrate feature is enabled, :hide-toc: will have no effect.

    # Option 1: Using hide-toc
    :hide-toc:
    
    # Option 2: Using tocdepth
    :tocdepth: 0
  6. How C++ API documentation is organized

    main

    The extension generates a separate page for every documented entity. Documentation is organized using the following concepts:

    • Groups: Top-level entities are organized into groups using the :group: field in their docstrings. You can insert a summary of a group into an existing page using the .. cpp-apigen-group:: directive.
    • Related Entities:
      • Class members are automatically considered related to their parent class.
      • Hidden friends (friend functions defined within a class) are automatically considered related members.
      • Non-members can be explicitly linked to another entity using the :relates: field in their docstring.
    • Group Summaries: For a parent entity, related entities are organized into groups based on their :group: field or default assignment rules. These summaries appear on the parent's documentation page.
  7. How class member groups are rendered

    main

    When documenting a class, the extension organizes members into sections based on their :group: field.

    1. Existing Sections: If the class docstring already contains a section with a title matching the group name (or its normalized ID), the member summaries are appended to that existing section.
    2. New Sections: If no matching section exists, a new section is created at the end of the class documentation.
    3. Section Order: New sections are added in the order of the first occurrence of a group's members (determined by their :order: value).
    class Foo:
        """This is some class.
    
        Constructors
        ------------
    
        This class defines the following constructors.
        """
    
        def __init__(self):
            """
            :group: Constructors
            """
            pass
  8. Configure arbitrary list markers for code annotations

    main

    The markers used in the .. code-annotations:: directive (the enumerated list) are arbitrary and do not need to match the numbers used in the code comments. For example, you can start your list with 3. or use # as a marker. The key is that the number inside the code comment (n) must match the $n^{th}$ item in the list provided to the directive.

    Warning: Do not use the same identifying number for multiple comments in a single block. This will cause all but the last button to link to the final annotation.

    // What can I put in an annotation? (1)
    /* What about nested lists and emojis? (2) */
    .. code-annotations::
        3. This is the first item in the list, but it maps to (1) in the code.
        #. This is the second item, mapping to (2).
  9. Understand the version data structure

    main

    Whether using version_info or a JSON file, each version entry must follow a specific structure. Note that the aliases field is required (use an empty list [] if no aliases are needed).

    Required fields per entry:

    • version: A string representing a relative/absolute path or a URL.
    • title: A string used as the label in the dropdown menu.
    • aliases: A list of strings used to give a version a surname like "latest" or "stable". This allows a URL like <domain>/stable to redirect to the specified version path.

    Note: aliases do not apply when the version field contains an external URL.

    [
      {"version": "1.0", "title": "1.0", "aliases": []},
      {"version": "2.0", "title": "2.0", "aliases": ["stable"]},
      {"version": "3.0-rc1", "title": "Release Candidate 1", "aliases": ["beta", "latest"]}
    ]
  10. Control member order with the :order: field

    main

    To control the sequence in which members appear within a group, use the :order: field in the docstring. Members are listed in ascending order of their integer value. Ties are broken according to the python_apigen_order_tiebreaker configuration option.

    For class members, the order also determines the order of the per-group sections in the class documentation. If using sphinx.ext.napoleon, you can use an Order: section.

    # Using standard rST field
    def foo(x: int) -> int:
        """Does something or other.
    
        :group: My group
        :order: 1
        """
        pass
    
    # Using Napoleon syntax
    def bar(x: int) -> int:
        """Does something or other.
    
        Group:
          My group
    
        Order:
          1
        """
        pass
  11. Use explicit markup blocks and directives

    main

    Explicit markup is used for constructs requiring special handling, such as footnotes, comments, or directives.

    An explicit markup block begins with .. (two dots followed by a space) and is terminated by the next paragraph at the same indentation level. There must be a blank line between explicit markup and normal paragraphs.

    .. note::
        This is a note block.
    
    .. code-block:: python
    
        print("Hello")