From d874316382d3413ab4b78c2563754b4b225cc525 Mon Sep 17 00:00:00 2001 From: Brendan <2bndy5@gmail.com> Date: Tue, 19 Apr 2022 22:12:04 -0700 Subject: [PATCH] More extensions (#60) * patch literal blocks captions; add result directive * update docs for results directive * add task-list directive and keys role * add experimental button idea * add in new demo CSS * pleasing pylint * ran black on button.py * partial solution to content tabs in #56 * improve api doc signatures and code block captions * pleasing stylelint * pleasing pylint * polish & remove experimental button.py - CSS additions consolidated and revised - result directive (and corresponding CSS) - various improvements to the docs * pleasing stylelint * still pleasing stylelint * hopefully the last stylelint fix * [stylelint] WTH is with property ordering in scss * adjust custon keys' CSS for chrome * remove button testing CSS * use descrptive directive name * use snake casing for docutils node * move a margin reset to typeset.scss * review changes to kbd_keys.py * use plain text for keys role in latex * simplfy example CSS for custom task-list * move rst-result CSS to _highlight.scss * wrap each param in span & style said span * [no ci] move comment to proper location * condensed selectors = less deviation from upstream * set autocrlf to input * try overriding git global config for this repo * override config for all files (not by core config) --- .gitattributes | 10 + docs/_static/extra_css.css | 42 ++- docs/additional_samples.rst | 304 ++++++++++-------- docs/admonitions.rst | 155 ++++----- docs/conf.py | 33 +- docs/content_tabs.rst | 41 +-- docs/demo_api.rst | 152 +++++---- docs/index.rst | 8 +- docs/keys.rst | 158 +++++++++ docs/mermaid_diagrams.rst | 121 ++----- docs/requirements.txt | 1 + docs/specimen.rst | 25 +- docs/task_lists.rst | 161 ++++++++++ docs/test_py_module/test.py | 9 +- sphinx_immaterial/__init__.py | 2 + sphinx_immaterial/apidoc_formatting.py | 51 +++ sphinx_immaterial/content_tabs.py | 5 +- sphinx_immaterial/kbd_keys.py | 94 ++++++ sphinx_immaterial/object_toc.py | 2 +- sphinx_immaterial/task_lists.py | 95 ++++++ sphinx_immaterial/theme_result.py | 53 +++ src/assets/stylesheets/main/_api.scss | 8 +- src/assets/stylesheets/main/_typeset.scss | 8 + .../main/extensions/pymdownx/_highlight.scss | 19 +- 24 files changed, 1082 insertions(+), 475 deletions(-) create mode 100644 .gitattributes create mode 100644 docs/keys.rst create mode 100644 docs/task_lists.rst create mode 100644 sphinx_immaterial/kbd_keys.py create mode 100644 sphinx_immaterial/task_lists.py create mode 100644 sphinx_immaterial/theme_result.py diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..813e4309d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,10 @@ +# We need to make sure that the remote and workspace line endings all use LF due to +# linting and other reasons. + +# Set core.autocrlf to false in case people have this set differently. +# If this is set to 'true' or 'input', then it overrides the eol option. +* text autocrlf=false + +# This setting forces Git to normalize line endings to LF on checkin and +# prevents conversion to CRLF when the file is checked out. +* text eol=lf diff --git a/docs/_static/extra_css.css b/docs/_static/extra_css.css index bdce350a5..bfb5ad333 100644 --- a/docs/_static/extra_css.css +++ b/docs/_static/extra_css.css @@ -16,11 +16,51 @@ --md-icon__fa-gitlab: url('data:image/svg+xml;charset=utf-8,'); --md-icon__fa-gitkraken: url('data:image/svg+xml;charset=utf-8,'); --md-icon__fa-bitbucket: url('data:image/svg+xml;charset=utf-8,'); - --md-admonition-icon--pied-piper: url('data:image/svg+xml;charset=utf-8,') +} + +/* ************************* my-special-key style ************************************* */ + +.md-typeset kbd.key-my-special-key, +.md-typeset kbd.key-git { + color: var(--md-primary-fg-color); + background: var(--md-accent-bg-color); +} + +.md-typeset kbd.key-git::before { + content: "██"; + -webkit-mask-image: var(--md-icon__fa-git); + -webkit-mask-repeat: no-repeat; + mask-image: var(--md-icon__fa-git); + mask-repeat: no-repeat; +} + +.md-typeset kbd.key-my-special-key:hover, +.md-typeset kbd.key-git:hover { + color: var(--md-accent-fg-color); +} + +/* **************************** custom-task-list style rules *************************** */ + +/* style for the unchecked checkboxes */ +.custom-task-list-style > ul > li > label .task-list-indicator::before { + -webkit-mask-image: var(--md-admonition-icon--failure); + mask-image: var(--md-admonition-icon--failure); + background-color: hsl(0, 72%, 55%); +} + +/* style for the checked checkboxes */ +.custom-task-list-style>ul>.task-list-item>.task-list-control>[type="checkbox"]:checked+.task-list-indicator::before { + -webkit-mask-image: var(--md-admonition-icon--success); + mask-image: var(--md-admonition-icon--success); + background-color: hsl(122, 84%, 45%); } /* *************************** custom admonition style rules *************************** */ +:root { + --md-admonition-icon--pied-piper: url('data:image/svg+xml;charset=utf-8,') +} + .md-typeset .admonition.pied-piper { border-color: rgb(43, 155, 70); } diff --git a/docs/additional_samples.rst b/docs/additional_samples.rst index 329508d16..480104f2a 100644 --- a/docs/additional_samples.rst +++ b/docs/additional_samples.rst @@ -7,7 +7,6 @@ Various examples of styling applied to Sphinx constructs. You can view the `source <./_sources/examples.txt>`_ of this page to see the specific reStructuredText used to create these examples. - Headings ======== This is a first level heading (``h1``). @@ -23,79 +22,87 @@ This is a third level heading (``h3``). Code ==== -The theme uses pygments for ``inline code text`` and -:: - multiline - code text +.. rst-example:: + + The theme uses pygments for ``inline code text`` and + :: + + multiline + code text Here's an included example with line numbers. -.. literalinclude:: ../sphinx_immaterial/autodoc_property_type.py - :caption: source from this theme in *sphinx_immaterial/autodoc_property_type.py* - :linenos: +.. rst-example:: + + .. literalinclude:: ../sphinx_immaterial/autodoc_property_type.py + :caption: source from this theme in *sphinx_immaterial/autodoc_property_type.py* + :linenos: It also works with existing Sphinx highlighting: -.. code-block:: html +.. rst-example:: + + .. code-block:: html - - Hello World - + + Hello World + -.. code-block:: python + .. code-block:: python - def hello(): - """Greet.""" - return "Hello World" + def hello(): + """Greet.""" + return "Hello World" -.. code-block:: javascript + .. code-block:: javascript - /** - * Greet. - */ - function hello(): { - return "Hello World"; - } + /** + * Greet. + */ + function hello(): { + return "Hello World"; + } Footnotes ========= -I have footnoted a first item [#f1]_ and second item [#f2]_. -This also references the second item [#f2]_. -.. rubric:: Footnotes -.. [#f1] My first footnote. -.. [#f2] My second footnote. +.. rst-example:: -Icons -===== -The following template HTML: + I have footnoted a first item [#f1]_ and second item [#f2]_. + This also references the second item [#f2]_. -.. code-block:: html + .. rubric:: Footnotes + .. [#f1] My first footnote. + .. [#f2] My second footnote. - +Icons +===== -translates to a the site's icon: +.. rst-example:: The following raw HTML + :output-prefix: translates to the icon: -.. raw:: html + .. raw:: html - + The material icon font provides hundreds to choose from. You can use the ```` tag or the ```` tag. -.. raw:: html +.. rst-example:: - - - - - - - - - - + .. raw:: html + + + + + + + + + + + Tables @@ -109,30 +116,32 @@ using ``.. cssclass:: custom-class`` and then add it to your configuration's Grid ---- -A grid table: -+------------------------+------------+----------+----------+ -| Header1 | Header2 | Header3 | Header4 | -+========================+============+==========+==========+ -| row1, cell1 | cell2 | cell3 | cell4 | -+------------------------+------------+----------+----------+ -| row2 ... | ... | ... | | -+------------------------+------------+----------+----------+ -| ... | ... | ... | | -+------------------------+------------+----------+----------+ +.. rst-example:: A grid table: + + +------------------------+------------+----------+----------+ + | Header1 | Header2 | Header3 | Header4 | + +========================+============+==========+==========+ + | row1, cell1 | cell2 | cell3 | cell4 | + +------------------------+------------+----------+----------+ + | row2 ... | ... | ... | | + +------------------------+------------+----------+----------+ + | ... | ... | ... | | + +------------------------+------------+----------+----------+ Simple ------ -A simple table: -===== ===== ======= -H1 H2 H3 -===== ===== ======= -cell1 cell2 cell3 -... ... ... -... ... ... -===== ===== ======= +.. rst-example:: A simple table: + + ===== ===== ======= + H1 H2 H3 + ===== ===== ======= + cell1 cell2 cell3 + ... ... ... + ... ... ... + ===== ===== ======= User-styled Table ----------------- @@ -146,80 +155,90 @@ User-styled Table This is feature demonstration. There is no css for the plain class, and so this is completely unstyled. -.. cssclass:: plain -===== ====== ======= -User Styled Table -===== ====== ======= -cell1 cell2 cell3 -... ... ... -... ... ... -===== ====== ======= +.. rst-example:: + + .. cssclass:: plain + + ===== ====== ======= + User Styled Table + ===== ====== ======= + cell1 cell2 cell3 + ... ... ... + ... ... ... + ===== ====== ======= List Tables ----------- -.. list-table:: A List Table - :header-rows: 1 +.. rst-example:: + + .. list-table:: A List Table + :header-rows: 1 - * - Column 1 - - Column 2 - * - Item 1 - - Item 2 + * - Column 1 + - Column 2 + * - Item 1 + - Item 2 Alignment ~~~~~~~~~ -.. list-table:: Center Aligned - :header-rows: 1 - :align: center - - * - Column 1 - - Column 2 - * - Item 1 - - Item 2 - - -.. list-table:: Right Aligned - :widths: 15 10 30 - :header-rows: 1 - :align: right - - * - Treat - - Quantity - - Description - * - Albatross - - 2.99 - - On a stick! - * - Crunchy Frog - - 1.49 - - If we took the bones out - * - Gannet Ripple - - 1.99 - - On a stick! +.. rst-example:: + + .. list-table:: Center Aligned + :header-rows: 1 + :align: center + + * - Column 1 + - Column 2 + * - Item 1 + - Item 2 + + +.. rst-example:: + + .. list-table:: Right Aligned + :widths: 15 10 30 + :header-rows: 1 + :align: right + + * - Treat + - Quantity + - Description + * - Albatross + - 2.99 + - On a stick! + * - Crunchy Frog + - 1.49 + - If we took the bones out + * - Gannet Ripple + - 1.99 + - On a stick! Code Documentation ================== -An example Python function. -.. py:function:: format_exception(etype, value, tb[, limit=None]) +.. rst-example:: An example Python function. - Format the exception with a traceback. + .. py:function:: format_exception(etype, value, tb[, limit=None]) - :param etype: exception type - :param value: exception value - :param tb: traceback object - :param limit: maximum number of stack frames to show - :type limit: integer or None - :rtype: list of strings + Format the exception with a traceback. -An example JavaScript function. + :param etype: exception type + :param value: exception value + :param tb: traceback object + :param limit: maximum number of stack frames to show + :type limit: integer or None + :rtype: list of strings -.. js:class:: MyAnimal(name[, age]) +.. rst-example:: An example JavaScript function. - :param string name: The name of the animal - :param number age: an optional age for the animal + .. js:class:: MyAnimal(name[, age]) + + :param string name: The name of the animal + :param number age: an optional age for the animal Glossaries ========== @@ -239,37 +258,44 @@ Glossaries Math ==== -.. math:: +.. rst-example:: - (a + b)^2 = a^2 + 2ab + b^2 + .. math:: - (a - b)^2 = a^2 - 2ab + b^2 + (a + b)^2 = a^2 + 2ab + b^2 -.. math:: + (a - b)^2 = a^2 - 2ab + b^2 - (a + b)^2 &= (a + b)(a + b) \\ - &= a^2 + 2ab + b^2 +.. rst-example:: + .. math:: + + (a + b)^2 &= (a + b)(a + b) \\ + &= a^2 + 2ab + b^2 -.. math:: - :nowrap: +.. rst-example:: - \begin{eqnarray} - y & = & ax^2 + bx + c \\ - f(x) & = & x^2 + 2xy + y^2 - \end{eqnarray} + .. math:: + :nowrap: + + \begin{eqnarray} + y & = & ax^2 + bx + c \\ + f(x) & = & x^2 + 2xy + y^2 + \end{eqnarray} Production Lists ================ -.. productionlist:: - try_stmt: try1_stmt | try2_stmt - try1_stmt: "try" ":" `suite` - : ("except" [`expression` ["," `target`]] ":" `suite`)+ - : ["else" ":" `suite`] - : ["finally" ":" `suite`] - try2_stmt: "try" ":" `suite` - : "finally" ":" `suite` +.. rst-example:: + + .. productionlist:: + try_stmt: try1_stmt | try2_stmt + try1_stmt: "try" ":" `suite` + : ("except" [`expression` ["," `target`]] ":" `suite`)+ + : ["else" ":" `suite`] + : ["finally" ":" `suite`] + try2_stmt: "try" ":" `suite` + : "finally" ":" `suite` Sub-pages ========= diff --git a/docs/admonitions.rst b/docs/admonitions.rst index b96c24a9a..fe476f067 100644 --- a/docs/admonitions.rst +++ b/docs/admonitions.rst @@ -11,22 +11,26 @@ Most of the admonitions that the mkdocs-material theme supports were "borrowed" admonitions defined in the reStructuredText specifications. You may recognize them from usage in other sphinx-based themes. They are: -``note``, ``todo``, ``seealso`` +.. rst-example:: ``note``, ``todo``, ``seealso`` + .. seealso:: This admonition is specific to Sphinx directives and not defined in the rST specifications as you can `seealso`. ``note`` and ``todo`` are admonitions defined by the rST specifications. -``tip``, ``hint``, ``important`` +.. rst-example:: ``tip``, ``hint``, ``important`` + .. important:: It is **important** to correctly use admonitions. -``attention``, ``caution``, ``warning`` +.. rst-example:: ``attention``, ``caution``, ``warning`` + .. warning:: This is a **warning**. -``danger``, ``error`` +.. rst-example:: ``danger``, ``error`` + .. error:: You have made a grave **error**. @@ -38,87 +42,69 @@ These admonitions can still be used, but the syntax is a little different becaus on the generic admonition defined in the reStructuredText specifications. To use the following admonitions' styles from the mkdocs-material theme, the rST syntax is -shown inside the demonstrated admonition. +shown to demonstrate using the ``:class:`` option of generic admonitions. .. important:: The ``:class:`` options below (in the rST code blocks) must use lower case letters for the styling to work. Otherwise, the admonition will look like a `note` (as that is the default fallback style). -``todo``, ``info`` +.. rst-example:: ``todo``, ``info`` + .. admonition:: Info :class: info Thanks to the mkdocs-material theme, the ``todo`` class is also an alias of the - ``info`` class when not using the ``.. todo::`` directive. - - .. code-block:: rst + ``info`` class when not using the `.. todo:: ` directive. - .. admonition:: Info - :class: info +.. rst-example:: ``abstract``, ``summary``, ``tldr`` -``abstract``, ``summary``, ``tldr`` .. admonition:: TL;DR :class: tldr - .. code-block:: rst + The ``:class: tldr`` part is important. - .. admonition:: TL;DR - :class: tldr +.. rst-example:: ``success``, ``check``, ``done`` -``success``, ``check``, ``done`` - .. admonition:: Done + .. admonition:: Accomplished :class: done - .. code-block:: rst + This style is used for ``success``, ``check``, ``done`` CSS classes. - .. admonition:: Done - :class: done +.. rst-example:: ``question``, ``help``, ``faq`` -``question``, ``help``, ``faq`` .. admonition:: FAQ :class: faq - .. code-block:: rst + Helpful advice goes here. - .. admonition:: FAQ - :class: faq +.. rst-example:: ``failure``, ``fail``, ``missing`` -``failure``, ``fail``, ``missing`` - .. admonition:: Missing + .. admonition:: Something Missing :class: missing - .. code-block:: rst + We expected some loss of feature-coverage. - .. admonition:: Missing - :class: missing +.. rst-example:: ``bug`` -``bug`` - .. admonition:: Bug + .. admonition:: Known Bug :class: bug - .. code-block:: rst + Bug reported data/conclusion. - .. admonition:: Bug - :class: bug +.. rst-example:: ``example`` -``example`` - .. admonition:: Example + .. admonition:: Example Admonition :class: example - .. code-block:: rst + Example Body. - .. admonition:: Example - :class: example +.. rst-example:: ``cite``, ``quote`` -``cite``, ``quote`` - .. admonition:: Quote + .. admonition:: Unknown Quote :class: quote - .. code-block:: rst - - .. admonition:: Quote - :class: quote + Somebody somewhere said something catchy. Collapsible dropdown ********************* @@ -136,27 +122,23 @@ The `sphinxcontrib-details-directive extension`_ should be added to conf.py's ex extensions = ["sphinx_immaterial", "sphinxcontrib.details.directive"] - If the ``:class:`` option is not supplied to the ``details`` directive then the admonition style falls back to a `note` admonition style. -.. details:: Open by default - :class: example - :open: +.. rst-example:: - .. code-block:: rst + .. details:: Open by default + :class: example + :open: - .. details:: Open by default - :class: example - :open: + Use the ``:open:`` option as a flag to expand the admonition by default. -.. details:: Closed by default - :class: help +.. rst-example:: - .. code-block:: rst + .. details:: Closed by default + :class: help - .. details:: Closed by default - :class: help + Without the ``:open:`` flag, the admonition is collapsed by default. Removing the title ****************** @@ -168,25 +150,19 @@ The admonition's title can be removed if the ``md-admonition`` directive is not any arguments. Because the ``md-admonition`` directive is an adaptation of the generic ``admonition`` directive, the ``class`` option is still respected. -.. md-admonition:: - :class: error - - This example uses the styling of the ``error`` admonition +.. rst-example:: - .. code-block:: rst + .. md-admonition:: + :class: error - .. md-admonition:: - :class: error + This example uses the styling of the ``error`` admonition -.. md-admonition:: Using a title - :class: help +.. rst-example:: - This example uses the styling of the ``help`` admonition + .. md-admonition:: Using a title + :class: help - .. code-block:: rst - - .. md-admonition:: Using a title - :class: help + This example uses the styling of the ``help`` admonition .. hint:: You can use the ``md-admonition`` directive in other themes by adding the theme's module to your @@ -207,43 +183,26 @@ folder and add the new CSS to an additional style sheet. .. md-tab-item:: rST code - .. code-block:: rst + .. rst-example:: Pied Piper Example + :output-prefix: .. admonition:: Pied Piper - :class: pied-piper + :class: pied-piper - Don't tell him you use spaces instead of tabs... + Don't tell him you use spaces instead of tabs... .. md-tab-item:: CSS code - .. code-block:: css + .. literalinclude:: _static/extra_css.css + :language: css :caption: docs/_static/extra_css.css - - :root { - --md-admonition-icon--pied-piper: url('data:image/svg+xml;charset=utf-8,') - } - .md-typeset .admonition.pied-piper { - border-color: rgb(43, 155, 70); - } - .md-typeset .pied-piper > .admonition-title { - background-color: rgba(43, 155, 70, 0.1); - border-color: rgb(43, 155, 70); - } - .md-typeset .pied-piper > .admonition-title::before { - background-color: rgb(43, 155, 70); - -webkit-mask-image: var(--md-admonition-icon--pied-piper); - mask-image: var(--md-admonition-icon--pied-piper); - } + :start-at: /* *************************** custom admonition style rules + :end-before: /* ********** .. md-tab-item:: conf.py code .. code-block:: python + :caption: docs/conf.py html_static_path = ["_static"] html_css_files = ["extra_css.css"] - - -.. admonition:: Pied Piper - :class: pied-piper - - Don't tell him you use spaces instead of tabs... diff --git a/docs/conf.py b/docs/conf.py index 212e58cc9..80dea063f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -35,6 +35,8 @@ "sphinx.ext.mathjax", "sphinx.ext.viewcode", "sphinxcontrib.details.directive", + "sphinx_immaterial.theme_result", + "sphinx_immaterial.kbd_keys", ] intersphinx_mapping = { @@ -57,28 +59,27 @@ # This pattern also affects html_static_path and html_extra_path. exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. +# -- sphinx_immaterial.keys extension options # +# optional key_map for example purposes +keys_map = {"my-special-key": "Awesome Key", "git": ""} + +# -- Options for HTML output ------------------------------------------------- # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named 'default.css' will overwrite the builtin 'default.css'. html_static_path = ["_static"] -html_css_files = [ - "extra_css.css", - "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css", -] +html_css_files = ["extra_css.css"] +html_last_updated_fmt = "" +html_title = "Sphinx-Immaterial" +html_favicon = "_static/images/favicon.ico" # colored version of material/bookshelf.svg +html_logo = "_static/images/Ybin.gif" # from https://gifer.com/en/Ybin -# -- HTML theme settings ------------------------------------------------ +# -- HTML theme specific settings ------------------------------------------------ extensions.append("sphinx_immaterial") -html_title = "Sphinx-Immaterial" html_theme = "sphinx_immaterial" -html_favicon = "_static/images/favicon.ico" # colored version of material/bookshelf.svg -html_logo = "_static/images/Ybin.gif" # from https://gifer.com/en/Ybin # material theme options (see theme.conf for more information) html_theme_options = { @@ -131,21 +132,17 @@ { "version": "https://sphinx-immaterial.rtfd.io", "title": "ReadTheDocs", - "aliases": [] + "aliases": [], }, { "version": "https://jbms.github.io/sphinx-immaterial", "title": "Github Pages", - "aliases": [] + "aliases": [], }, ], "toc_title_is_page_title": True, } # end html_theme_options -html_last_updated_fmt = "" -html_use_index = False -html_domain_indices = False - # ---- Other documentation options ------------------------- todo_include_todos = True diff --git a/docs/content_tabs.rst b/docs/content_tabs.rst index 85a2cbd66..140b7e236 100644 --- a/docs/content_tabs.rst +++ b/docs/content_tabs.rst @@ -42,7 +42,7 @@ the sphinx-immaterial theme provides its own directives to make use of content t This directive supports ``:class:`` and ``:name:`` options to use custom CSS classes and reference links (respectively). - .. code-block:: rst + .. rst-example:: ``md-tab-set`` Example .. md-tab-set:: :class: custom-tab-set-style @@ -69,30 +69,6 @@ the sphinx-immaterial theme provides its own directives to make use of content t :start-at: /* ************************ custom-tab-set-style :end-before: /* *********************** custom-tab-item-style - .. md-tab-set:: - :class: custom-tab-set-style - :name: ref_this_tab_set - - .. md-tab-item:: Local Ref - - A reference to this tab set renders like so: - `tab set description `. - - This syntax can only be used on the same page as the tab set. - - .. md-tab-item:: Cross-page Ref - - To cross-reference this tab set from a different page, use - :ref:`tab set description ` - - Clearly, this also works on the same page as the tab set. - - .. md-tab-item:: Custom CSS - - .. literalinclude:: _static/extra_css.css - :language: css - :start-at: /* ************************ custom-tab-set-style - :end-before: /* *********************** custom-tab-item-style .. rst:directive:: md-tab-item @@ -108,7 +84,7 @@ the sphinx-immaterial theme provides its own directives to make use of content t Use the ``:class:`` option to optionally provide custom CSS classes to the tab's content (not the tab's label). - .. code-block:: rst + .. rst-example:: ``md-tab-item`` Example .. md-tab-set:: @@ -124,19 +100,6 @@ the sphinx-immaterial theme provides its own directives to make use of content t :start-at: /* *********************** custom-tab-item-style :end-before: /* ************************* inline icon stuff - .. md-tab-set:: - - .. md-tab-item:: Customized content - :class: custom-tab-item-style - - This content could be styled differently from other page content. - - .. md-tab-item:: Custom CSS - - .. literalinclude:: _static/extra_css.css - :language: css - :start-at: /* *********************** custom-tab-item-style - :end-before: /* ************************* inline icon stuff Typical examples are seen in this documentations' `Custom admonitions `_ and diff --git a/docs/demo_api.rst b/docs/demo_api.rst index 7b05937dd..6248d1875 100644 --- a/docs/demo_api.rst +++ b/docs/demo_api.rst @@ -7,56 +7,73 @@ sample API documentation and generated content :mod:`test_py_module` ===================== -.. automodule:: test_py_module.test - :members: - :private-members: - :special-members: +.. rst-example:: autodoc example + .. automodule:: test_py_module.test + :members: + :private-members: + :special-members: C++ API ======= -.. cpp:type:: MyType +.. rst-example:: - Some type + .. cpp:type:: MyType -.. cpp:function:: const MyType Foo(const MyType bar) + Some type - Some function type thing +.. rst-example:: -.. cpp:class:: template std::array + .. c:macro:: DEFAULT_LENGTH - Some cpp class + .. cpp:function:: const MyType Foo(const MyType bar, uint8_t* arr, unsigned int len = DEFAULT_LENGTH, bool baz= false) -.. cpp:member:: float Sphinx::version + Some function type thing - The description of Sphinx::version. +.. rst-example:: -.. cpp:var:: int version + .. cpp:class:: template std::array - The description of version. + Some cpp class -.. cpp:type:: std::vector List +.. rst-example:: - The description of List type. + .. cpp:member:: float Sphinx::version -.. cpp:enum:: MyEnum + The description of `Sphinx::version`. - An unscoped enum. +.. rst-example:: - .. cpp:enumerator:: A + .. cpp:var:: int version -.. cpp:enum-class:: MyScopedEnum + The description of version. - A scoped enum. +.. rst-example:: - .. cpp:enumerator:: B + .. cpp:type:: std::vector List -.. cpp:enum-struct:: protected MyScopedVisibilityEnum : std::underlying_type::type + The description of List type. - A scoped enum with non-default visibility, and with a specified underlying type. +.. rst-example:: - .. cpp:enumerator:: B + .. cpp:enum:: MyEnum + + An unscoped enum. + + .. cpp:enumerator:: A + + .. cpp:enum-class:: MyScopedEnum + + A scoped enum. + + .. cpp:enumerator:: B + + .. cpp:enum-struct:: protected MyScopedVisibilityEnum : std::underlying_type::type + + A scoped enum with non-default visibility, and with a specified underlying type. + + .. cpp:enumerator:: B JavaScript API @@ -66,74 +83,79 @@ JavaScript API .. js:module:: module_a.submodule -* Link to :js:class:`ModTopLevel` +.. rst-example:: -.. js:class:: ModTopLevel + * Link to :js:class:`ModTopLevel` - * Link to :js:meth:`mod_child_1` - * Link to :js:meth:`ModTopLevel.mod_child_1` +.. rst-example:: -.. js:method:: ModTopLevel.mod_child_1 + .. js:class:: ModTopLevel - * Link to :js:meth:`mod_child_2` + * Link to :js:meth:`mod_child_1` + * Link to :js:meth:`ModTopLevel.mod_child_1` -.. js:method:: ModTopLevel.mod_child_2 +.. rst-example:: - * Link to :js:meth:`module_a.submodule.ModTopLevel.mod_child_1` + .. js:method:: ModTopLevel.mod_child_1 -.. js:module:: module_b.submodule + * Link to :js:meth:`mod_child_2` -* Link to :js:class:`ModTopLevel` + .. js:method:: ModTopLevel.mod_child_2 -.. js:class:: ModNested + * Link to :js:meth:`module_a.submodule.ModTopLevel.mod_child_1` - .. js:method:: nested_child_1 +.. rst-example:: - * Link to :js:meth:`nested_child_2` - - .. js:method:: nested_child_2 - - * Link to :js:meth:`nested_child_1` + * Link to :js:class:`ModTopLevel` +.. js:module:: module_b.submodule -Generated Index -=============== +.. rst-example:: -Part of the sphinx build process in generate and index file: :ref:`genindex`. + .. js:class:: ModNested + .. js:method:: nested_child_1 -Optional parameter args -======================= + * Link to :js:meth:`nested_child_2` -At this point optional parameters `cannot be generated from code`_. -However, some projects will manually do it, like so: + .. js:method:: nested_child_2 -This example comes from `django-payments module docs`_. + * Link to :js:meth:`nested_child_1` -.. class:: payments.dotpay.DotpayProvider(seller_id, pin[, channel=0[, lock=False], lang='pl']) + .. js:method:: getJSON(href, callback, priority[, err_back, flags]) - This backend implements payments using a popular Polish gateway, `Dotpay.pl `_. + :param string href: An URI to the location of the resource. + :param callback: Gets called with the object. + :param err_back: + Gets called in case the request fails. And a lot of other + text so we need multiple lines. + :throws SomeError: For whatever reason in that case. + :returns: Something. - Due to API limitations there is no support for transferring purchased items. +Generated Index +=============== +.. rst-example:: - :param seller_id: Seller ID assigned by Dotpay - :param pin: PIN assigned by Dotpay - :param channel: Default payment channel (consult reference guide) - :param lang: UI language - :param lock: Whether to disable channels other than the default selected above + A generated index (:ref:`genindex`) is part of the Sphinx build process, unless + `html_use_index` is set to `False`. -.. _cannot be generated from code: https://groups.google.com/forum/#!topic/sphinx-users/_qfsVT5Vxpw -.. _django-payments module docs: http://django-payments.readthedocs.org/en/latest/modules.html#payments.authorizenet.AuthorizeNetProvide + Sphinx also allows indexing by domain (programming language), as seen in the + :ref:`modindex` for the demo Python module that is documented on this page. +.. note:: + This theme does not support a separate search page (usually referenced with + ``:ref:`search``), since the search is accessible in the site's navigation bar. Data ==== -.. data:: Data_item_1 - Data_item_2 - Data_item_3 +.. rst-example:: + + .. data:: Data_item_1 + Data_item_2 + Data_item_3 - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce congue elit eu hendrerit mattis. + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce congue elit eu hendrerit mattis. -Some data link :data:`Data_item_1`. + Some data link :data:`Data_item_1`. diff --git a/docs/index.rst b/docs/index.rst index 1230d213b..d58f68dd7 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -56,12 +56,12 @@ Update your ``conf.py`` with the required changes: There are a lot more ways to customize this theme. See :ref:`Customization` or ``theme.conf`` for more details. -.. admonition:: Settings used in this documentation +.. details:: Settings used in this documentation :class: example .. literalinclude:: ./conf.py - :start-at: # -- HTML theme settings ------------------------------------------------ - :end-before: # ---- Other documentation options ------------------------- + :start-at: # -- HTML theme specific settings + :end-before: # ---- Other documentation options .. toctree:: @@ -71,6 +71,8 @@ or ``theme.conf`` for more details. admonitions content_tabs mermaid_diagrams + task_lists + keys .. toctree:: :caption: Examples and Uses diff --git a/docs/keys.rst b/docs/keys.rst new file mode 100644 index 000000000..40fbaf713 --- /dev/null +++ b/docs/keys.rst @@ -0,0 +1,158 @@ +Keys extension +============== + +.. _pymdownx.keys: https://facelessuser.github.io/pymdown-extensions/extensions/keys/ + +This extension is meant to mimic the python markdown extension, `pymdownx.keys`_. + +It simply adds a role to invoke inline usage of keyboard keys with custom CSS provided by +the sphinx-immaterial theme. + +.. details:: CSS is not included with this extension + :class: success + + To add CSS to a theme that does not support this extension, try using: + + .. code-block:: CSS + + kbd[class^="key-"] { + background-color: var(--md-typeset-kbd-color); + border-radius: 0.1rem; + box-shadow: 0 0.1rem 0 0.05rem var(--md-typeset-kbd-border-color), 0 0.1rem 0 var(--md-typeset-kbd-border-color), 0 -0.1rem 0.2rem var(--md-typeset-kbd-accent-color) inset; + color: var(--md-default-fg-color); + display: inline-block; + font-size: 0.75em; + padding: 0 0.6666666667em; + vertical-align: text-top; + word-break: break-word; + font-feature-settings: "kern"; + font-family: var(--md-code-font-family); + } + + .keys span { + color: var(--md-default-fg-color--light); + padding: 0 0.2em; + } + +.. _pymdownx-keys-req: + +Markdown extension pre-requisite +-------------------------------- + +This pre-requisite does not mean Markdown support is enabled. However, this extension +does import the ``pymdownx.keymap_db`` module to use for the `keys_map` option's defaults. + +To use this extension, the pymdownx package needs to be installed. + +.. code-block:: shell + + python -m pip install pymdown-extensions + +And be sure to include the extension in your conf.py file. + +.. code-block:: python + + extensions = ["sphinx_immaterial.kbd_keys"] + +.. _keys_extension_role: + +Keys extension role +----------------------- + +.. rst:role:: keys + + The value of this role is interpreted as a keyboard key name. Each role invocation can + describe multiple keys pressed simultaneously using the `keys_separator`. + + .. rst-example:: + + :keys:`ctrl+alt+tab` + + :keys:`caps-lock`, :keys:`left-cmd+shift+a`, :keys:`backspace` + +Keys extension configuration +------------------------------------- + +These variables can be used to control the :rst:role:`keys` role behavior from the Sphinx +project's conf.py file. + +.. confval:: keys_strict + + The containing span element can strictly follow HTML5 specifications by using the + ``kbd`` tag instead of a ``span`` tag. + + The sphinx-immaterial theme does not adhere to the HTML5 strictness, therefore this + `bool` option is disabled (`False`) by default. + +.. confval:: keys_class + + The class attribute `str` value used in the containing span element. Defaults to ``"keys"``. + + Only change this if needed for your theme. The sphinx-immaterial theme is configured to use + the default value. + +.. confval:: keys_separator + + The `str` value used as the delimiter between keys. Defaults to ``"+"``. + + Changing this also requires changing the text provided to the :rst:role:`keys` role. + +.. confval:: keys_map + + An additional `dict` where ``key: value`` pairs consist of: + + .. csv-table:: + :header: key, value + + aliased key-\ **name** inputs (preferably a CSS friendly name), displayed output `str` + + By default the english mappings are included from the `pymdownx package `. + + .. seealso:: + The tables in + `pymdownx.keys`_ docs in `Extending/Modifying Key-Map Index + `_. + + .. md-tab-set:: + + .. md-tab-item:: conf.py + + Define the key name and give it a `str` value to display. + + In our case, "Awesome Key" will be shown for ``:keys:`my-special-key```. + + .. literalinclude:: conf.py + :language: python + :start-at: # -- sphinx_immaterial.keys extension options + :end-before: # -- + + .. md-tab-item:: CSS code + + Remember to prepend ``key-`` to whatever the `keys_map` key was. In our case, + ``my-special-key`` turns into ``key-my-special-key``. + + .. literalinclude:: _static/extra_css.css + :language: css + :start-at: /* ************************* my-special-key style + :end-before: /* **************************** custom-task-list style rules + + + .. md-tab-item:: rST code + + Specify the key using a known name in the `keys_map` index. + + In our case, ``my-special-key`` to fetch the display text from `keys_map`. + + .. rst-example:: + + :keys:`my-special-key` + :keys:`git` = :keys:`git+my-special-key` + + + Use of spaces in a key name will result in CSS class that has hyphens instead of + spaces in a lower case form of the given text. Therefore, entering + ``My Special Key`` ignores the `keys_map` but still uses the + ``key-my-special-key`` CSS class. + + .. rst-example:: + + :keys:`My Special Key` + :keys:`Git` = :keys:`Git+My Special Key` diff --git a/docs/mermaid_diagrams.rst b/docs/mermaid_diagrams.rst index 59328cf65..599244f70 100644 --- a/docs/mermaid_diagrams.rst +++ b/docs/mermaid_diagrams.rst @@ -4,7 +4,8 @@ Mermaid diagrams ================ .. note:: - Use of this feature has no affect or affiliation with sphinx's graphviz implementation. + Use of this feature has no affect or affiliation with sphinx's + :py:mod:`graphviz ` implementation. The mkdocs-material theme is equipped to make use of diagrams generated (during page load time) with `mermaid.js`_. Although, its implementation relies on a markdown extension that does not get @@ -15,15 +16,24 @@ directive that exposes the underlying implementation in mkdocs-material theme. .. rst:directive:option:: class :type: string - + A space delimited list of qualified names that get used as the HTML element's ``class`` attribute. + .. hint:: + You can use this option to specify ``text-align`` property via the following + CSS classes: + + - ``align-right`` sets the ``text-align`` property to ``right``. + - ``align-left`` sets the ``text-align`` property to ``left``. + - ``align-center`` sets the ``text-align`` property to ``center``. + + .. rst:directive:option:: name :type: string - + A qualified name that get used as the HTML element's ``id`` attribute. - + Use the `ref` role to reference the element by name. The `md-mermaid` directive's ``:class:`` and ``:name:`` options can be used @@ -34,16 +44,22 @@ directive that exposes the underlying implementation in mkdocs-material theme. .. md-admonition:: :class: missing - + While all `mermaid.js`_ features should work out-of-the-box, this theme will currently only - adjust the fonts and colors for `flowcharts`_, `sequence diagrams `, - `class diagrams `, `state diagrams `, and - `entity-relationship diagrams `. + adjust the fonts and colors for the following types of diagrams: + + .. rst-example:: References linking directly to a diagram's ``:name:`` + + - `flowcharts`_ + - `sequence diagrams ` + - `class diagrams ` + - `state diagrams ` + - `entity-relationship diagrams ` Using flowcharts ---------------- -.. code-block:: rst +.. rst-example:: .. md-mermaid:: :name: flowcharts @@ -55,20 +71,10 @@ Using flowcharts D --> B; B ---->|No| E[Yay!]; -.. md-mermaid:: - :name: flowcharts - - graph LR - A[Start] --> B{Error?}; - B -->|Yes| C[Hmm...]; - C --> D[Debug]; - D --> B; - B ---->|No| E[Yay!]; - Using sequence diagrams ----------------------- -.. code-block:: rst +.. rst-example:: .. md-mermaid:: :name: sequence-diagrams @@ -83,23 +89,10 @@ Using sequence diagrams John->>Bob: How about you? Bob-->>John: Jolly good! -.. md-mermaid:: - :name: sequence-diagrams - - sequenceDiagram - Alice->>John: Hello John, how are you? - loop Healthcheck - John->>John: Fight against hypochondria - end - Note right of John: Rational thoughts! - John-->>Alice: Great! - John->>Bob: How about you? - Bob-->>John: Jolly good! - Using state diagrams -------------------- -.. code-block:: rst +.. rst-example:: .. md-mermaid:: :name: state-diagrams @@ -116,26 +109,11 @@ Using state diagrams join_state --> State4 State4 --> [*] -.. md-mermaid:: - :name: state-diagrams - - stateDiagram-v2 - state fork_state <> - [*] --> fork_state - fork_state --> State2 - fork_state --> State3 - - state join_state <> - State2 --> join_state - State3 --> join_state - join_state --> State4 - State4 --> [*] Using class diagrams -------------------- - -.. code-block:: rst +.. rst-example:: .. md-mermaid:: :name: class-diagrams @@ -164,44 +142,13 @@ Using class diagrams +int postalCode +String country -validate() - +outputAsLabel() + +outputAsLabel() } -.. md-mermaid:: - :name: class-diagrams - - classDiagram - Person <|-- Student - Person <|-- Professor - Person : +String name - Person : +String phoneNumber - Person : +String emailAddress - Person: +purchaseParkingPass() - Address "1" <-- "0..1" Person:lives at - class Student{ - +int studentNumber - +int averageMark - +isEligibleToEnrol() - +getSeminarsTaken() - } - class Professor{ - +int salary - } - class Address{ - +String street - +String city - +String state - +int postalCode - +String country - -validate() - +outputAsLabel() - } - Using entity-relationship diagrams ---------------------------------- - -.. code-block:: rst +.. rst-example:: .. md-mermaid:: :name: entity-relationship-diagrams @@ -210,11 +157,3 @@ Using entity-relationship diagrams CUSTOMER ||--o{ ORDER : places ORDER ||--|{ LINE-ITEM : contains CUSTOMER }|..|{ DELIVERY-ADDRESS : uses - -.. md-mermaid:: - :name: entity-relationship-diagrams - - erDiagram - CUSTOMER ||--o{ ORDER : places - ORDER ||--|{ LINE-ITEM : contains - CUSTOMER }|..|{ DELIVERY-ADDRESS : uses diff --git a/docs/requirements.txt b/docs/requirements.txt index 4f1766b22..fa20fb5bf 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,4 @@ # The sphinx docs theme to use sphinx_immaterial sphinxcontrib-details-directive +pymdown-extensions diff --git a/docs/specimen.rst b/docs/specimen.rst index 4682d2cb0..d5515527e 100644 --- a/docs/specimen.rst +++ b/docs/specimen.rst @@ -373,23 +373,28 @@ Images Default Alignment ~~~~~~~~~~~~~~~~~ +.. rst-example:: -.. image:: desert-flower.jpg - :alt: Default image + .. image:: desert-flower.jpg + :alt: Default image Center Alignment ~~~~~~~~~~~~~~~~ -.. image:: desert-flower.jpg - :alt: Centered Image, 80% scale - :scale: 80% - :align: center +.. rst-example:: + + .. image:: desert-flower.jpg + :alt: Centered Image, 80% scale + :scale: 80% + :align: center Right Alignment ~~~~~~~~~~~~~~~ -.. image:: desert-flower.jpg - :alt: Right Image, 60% scale - :scale: 60% - :align: right +.. rst-example:: + + .. image:: desert-flower.jpg + :alt: Right Image, 60% scale + :scale: 60% + :align: right Math again ---------- diff --git a/docs/task_lists.rst b/docs/task_lists.rst new file mode 100644 index 000000000..6d7dcc144 --- /dev/null +++ b/docs/task_lists.rst @@ -0,0 +1,161 @@ +Task Lists +============== + +This Sphinx extension mimics the HTML output of the ``pymdownx.tasklist`` Markdown +extension, which allows for the definition of task lists. With this extension and the +mkdocs-material theme's CSS, you can make list items prefixed with ``[ ]`` to render an unchecked +checkbox or ``[x]`` to render a checked checkbox. + +This extension can be optionally be used in other sphinx theme's that support checkboxes. + +.. code-block:: python + :caption: This is already done in sphinx-immaterial theme: + + extensions = ["sphinx_immaterial.task_lists"] + +.. details:: CSS not included with extension + :class: check + + The CSS for checkboxes is not included with this extension. Rather, the CSS is served from the + sphinx-immaterial theme (which is inherited from mkdocs-material theme). + + To use this extension with a theme that has no CSS support, try adding your own CSS: + + .. code-block:: css + + :root { + --md-task-list-icon: url('data:image/svg+xml;charset=utf-8,'); + --md-task-list-icon--checked: url('data:image/svg+xml;charset=utf-8,'); + } + + /* style for the unchecked checkboxes */ + .task-list-indicator::before { + -webkit-mask-image: var(--md-task-list-icon); + mask-image: var(--md-task-list-icon); + background-color: hsla(232deg, 75%, 90%, 0.12); + + content: ""; + height: 1.25em; + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-size: contain; + mask-size: contain; + position: absolute; + top: .15em; + width: 1.25em; + } + + /* style for the checked checkboxes */ + .task-list-control > [type="checkbox"]:checked + .task-list-indicator::before { + -webkit-mask-image: var(--md-task-list-icon--checked); + mask-image: var(--md-task-list-icon--checked); + background-color: hsl(122deg, 84%, 45%); + } + +Config variables +---------------- + +.. confval:: custom_checkbox + + A global conf.py `bool` variable to enable custom CSS for all checkboxes shown. Default is `False`. + +.. confval:: clickable_checkbox + + A global conf.py `bool` variable to enable user interaction with the checkboxes shown. Default is `False`. + + .. note:: + If this option is used, then any user changes will not be saved. + +``task-list`` Directive +----------------------- + +.. rst:directive:: task-list + + This directive traverses the immediate list's items and adds a checkbox according to + GitHub Flavored MarkDown. + + + .. rst:directive:option:: class + :type: string + + A space delimited list of qualified names that get used as the HTMl element's + ``class`` attribute. + + The ``class`` option is only applied to the containing ``div`` element. + + .. md-tab-set:: + + .. md-tab-item:: rST code + + .. rst-example:: Custom icons scoped to immediate list only (not child lists) + + .. task-list:: + :class: custom-task-list-style + :custom: + + + [ ] Custom unchecked checkbox + + [x] Custom checked checkbox + + .. task-list:: + :custom: + + * [ ] A goal for a task. + * [x] A fulfilled goal. + + .. md-tab-item:: CSS Hint + + .. literalinclude:: _static/extra_css.css + :language: css + :start-at: /* **************************** custom-task-list style rules + :end-before: /* *************************** custom admonition style rules + + .. rst:directive:option:: name + :type: string + + A qualified name that get used as the HTML element's ``name`` attribute. + + The ``name`` option is only applied to the containing ``div`` element. + Use the `ref` role to reference the element by name. + + .. rst:directive:option:: custom + :type: flag + + Allow custom styled checkboxes. Default is `False` unless `custom_checkbox` is enabled. + + .. rst:directive:option:: clickable + :type: flag + + Allow user interaction with checkboxes. Default is `False` unless `clickable_checkbox` is enabled. + + .. note:: + If this option is used, then any user changes will not be saved. + +Task List Example +----------------- + +The following `task-list` example demonstrates nested `task-list`. +Notice that indentation is important with reStructuredText lists. + +.. rst-example:: A feature spanning ``task-list`` example + + .. task-list:: + :name: task_list_example + :custom: + + 1. [x] Task A + 2. [ ] Task B + + .. task-list:: + :clickable: + + * [x] Task B1 + * [x] Task B2 + * [] Task B3 + + A rogue paragraph with a reference to + the `parent task_list `. + + - A list item without a checkbox. + - [ ] Another bullet point. + + 3. [ ] Task C diff --git a/docs/test_py_module/test.py b/docs/test_py_module/test.py index f47b9840c..58ebd4ffb 100644 --- a/docs/test_py_module/test.py +++ b/docs/test_py_module/test.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- """Test Module for sphinx_rtd_theme.""" +from typing import Union class Foo: @@ -45,11 +46,11 @@ def __init__(self, qux, spam=False): """Start the Foo. :param qux: The first argument to initialize class. - :type qux: string + :type qux: str :param spam: Spam me yes or no... :type spam: bool - """ + #: Doc comment for instance attribute qux. self.qux = 3 @@ -111,3 +112,7 @@ def another_function(self, a, b, **kwargs): This is deprecated since 3.0 """ return sum(kwargs.values()) / len(kwargs), a + b + +def func(long: int, param: str, args: None, flags: bool, lists: Union[list, tuple]): + """A function with many parameters.""" + return None diff --git a/sphinx_immaterial/__init__.py b/sphinx_immaterial/__init__.py index 803f9926e..a36df7c7c 100644 --- a/sphinx_immaterial/__init__.py +++ b/sphinx_immaterial/__init__.py @@ -317,6 +317,8 @@ def setup(app): app.setup_extension("sphinx_immaterial.md_admonition") app.setup_extension("sphinx_immaterial.content_tabs") app.setup_extension("sphinx_immaterial.mermaid_diagrams") + app.setup_extension("sphinx_immaterial.task_lists") + # patch the details directive's run method monkey_patch_details_run() diff --git a/sphinx_immaterial/apidoc_formatting.py b/sphinx_immaterial/apidoc_formatting.py index 9747133ec..a169b2624 100644 --- a/sphinx_immaterial/apidoc_formatting.py +++ b/sphinx_immaterial/apidoc_formatting.py @@ -147,6 +147,8 @@ def depart_desc_type(self, node: sphinx.addnodes.desc_type) -> None: def visit_desc_signature(self, node: sphinx.addnodes.desc_signature) -> None: node_text = node.astext() + # add highlight to invoke syntax highlighting in CSS + node["classes"].append("highlight") if len(node_text) > SIGNATURE_WRAP_LENGTH: node["classes"].append("sig-wrap") super().visit_desc_signature(node) @@ -165,6 +167,14 @@ def depart_desc_parameterlist( _, close_paren = node.get("parens", ("(", ")")) self.body[-1] = self.body[-1].replace(")", close_paren) + def visit_desc_parameter(self, node: sphinx.addnodes.desc_parameter) -> None: + self.body.append('') + super().visit_desc_parameter(node) + + def depart_desc_parameter(self, node: sphinx.addnodes.desc_parameter) -> None: + super().depart_desc_parameter(node) + self.body.append("") + def depart_field_name(self, node: docutils.nodes.Element) -> None: self.add_permalink_ref(node, _("Permalink to this headline")) super().depart_field_name(node) @@ -174,6 +184,47 @@ def depart_term(self, node: docutils.nodes.Element) -> None: self.add_permalink_ref(node, _("Permalink to this definition")) super().depart_term(node) + def visit_caption(self, node: docutils.nodes.Element) -> None: + attributes = {"class": "caption-text"} + if isinstance(node.parent, docutils.nodes.container) and node.parent.get( + "literal_block" + ): + # add highlight class to caption's div container. + # This is needed to trigger mkdocs-material CSS rule `.highlight .filename` + self.body.append('
') + # append a CSS class to trigger mkdocs-material theme's caption CSS style + attributes["class"] += " filename" + else: + super().visit_caption(node) + self.add_fignumber(node.parent) + self.body.append(self.starttag(node, "span", **attributes)) + + def depart_caption(self, node: docutils.nodes.Element) -> None: + if not isinstance( + node.parent, docutils.nodes.container + ) and not node.parent.get("literal_block"): + # only append ending tag if parent is not a literal-block. + # Because all elements in the caption should be within a span element + self.body.append("") + + # append permalink if available + if isinstance(node.parent, docutils.nodes.container) and node.parent.get( + "literal_block" + ): + self.add_permalink_ref(node.parent, _("Permalink to this code")) + self.body.append("") # done; add closing tag + elif isinstance(node.parent, docutils.nodes.figure): + self.add_permalink_ref(node.parent, _("Permalink to this image")) + elif node.parent.get("toctree"): + self.add_permalink_ref(node.parent.parent, _("Permalink to this toctree")) + + if isinstance(node.parent, docutils.nodes.container) and node.parent.get( + "literal_block" + ): + self.body.append("
\n") + else: + super().depart_caption(node) + def _monkey_patch_python_get_signature_prefix( directive_cls: Type[sphinx.domains.python.PyObject], diff --git a/sphinx_immaterial/content_tabs.py b/sphinx_immaterial/content_tabs.py index 07b200b45..17e982aab 100644 --- a/sphinx_immaterial/content_tabs.py +++ b/sphinx_immaterial/content_tabs.py @@ -91,9 +91,7 @@ def run(self) -> List[nodes.Node]: # add tab label textnodes, _ = self.state.inline_text(self.arguments[0], self.lineno) - tab_label = nodes.rubric( - self.arguments[0], *textnodes, classes=["tabbed-label"] - ) + tab_label = nodes.rubric("", "", *textnodes, classes=["tabbed-label"]) self.add_name(tab_label) tab_item += tab_label @@ -152,6 +150,7 @@ def visit_tab_set(self: HTMLTranslator, node: content_tab_set): # create: label_node = content_tab_label( + "", "", *tab_label.children, input_id=tab_item_identity, diff --git a/sphinx_immaterial/kbd_keys.py b/sphinx_immaterial/kbd_keys.py new file mode 100644 index 000000000..6b35e0ca4 --- /dev/null +++ b/sphinx_immaterial/kbd_keys.py @@ -0,0 +1,94 @@ +from typing import List, Tuple +from docutils import nodes +from sphinx.application import Sphinx +from sphinx.config import Config +from sphinx.writers.html import HTMLTranslator +from sphinx.util.logging import getLogger + +LOGGER = getLogger(__name__) + +try: + import pymdownx.keymap_db as keys_db +except ImportError: + LOGGER.info( + "Could not import `keymap_db` module from `pymdownx` package.\n " + "Please ensure `pymdown-extensions` is installed.\n " + "The `:keys:` role has no default key map." + ) + keys_db = None + + +class kbd_node(nodes.TextElement): + pass + + +def map_filter(key: str, user_map: dict) -> Tuple[str, str]: + display = key.title() + cls = key.replace("_", "-").replace(" ", "-").lower() + if key in user_map.keys(): + display = user_map[key] + if keys_db is not None: + if key in keys_db.aliases: + display = keys_db.keymap[keys_db.aliases[key]] + cls = keys_db.aliases[key] + return (cls, display) + + +def visit_kbd(self: HTMLTranslator, node: kbd_node): + tag = "kbd" if self.builder.config["keys_strict"] else "span" + self.body.append(f'<{tag} class="' + f'{self.builder.config["keys_class"]}"') + keys = node.rawsource.split(self.builder.config["keys_separator"]) + + keys_out = ">" + for i, key in enumerate(keys): + cls, text = map_filter(key.strip().lower(), self.builder.config["keys_map"]) + keys_out += f'{text}' + if i + 1 != len(keys): + keys_out += f'{self.builder.config["keys_separator"]}' + self.body.append(keys_out) + + +def depart_kbd(self, node): + tag = "kbd" if self.builder.config["keys_strict"] else "span" + self.body.append(f"") + + +def visit_kbd_latex(self, node): + keys = node.rawsource.split(self.builder.config["keys_separator"]) + for i, key in enumerate(keys): + _, text = map_filter(key.strip().lower(), self.builder.config["keys_map"]) + self.body.append(text) + if i + 1 < len(keys): + self.body.append(f' {self.builder.config["keys_separator"]} ') + + +def depart_kbd_latex(self, node): + pass + + +def keys_role( + role, rawtext, text, lineno, inliner, options={}, content=[] +) -> Tuple[List[nodes.Node], List[str]]: + keys_div = kbd_node(text) + return [keys_div], [] + + +def _config_inited(app: Sphinx, config: Config) -> None: + """Merge default `keys_db.keymap` with user-specified `keys_map` role option.""" + if keys_db is not None and app.config["keys_map"].keys(): + keys_db.keymap.update(**app.config["keys_map"]) + app.config["keys_map"] = keys_db.keymap + + +def setup(app: Sphinx): + app.add_config_value("keys_class", "keys", rebuild=True, types=str) + app.add_config_value("keys_strict", False, rebuild=True, types=bool) + app.add_config_value("keys_separator", "+", rebuild=True, types=str) + app.add_config_value("keys_map", {}, rebuild=True, types=dict) + app.add_role("keys", keys_role) + app.connect("config-inited", _config_inited) + app.add_node( + kbd_node, + html=(visit_kbd, depart_kbd), + latex=(visit_kbd_latex, depart_kbd_latex), + ) diff --git a/sphinx_immaterial/object_toc.py b/sphinx_immaterial/object_toc.py index 936971f57..3de92dc63 100644 --- a/sphinx_immaterial/object_toc.py +++ b/sphinx_immaterial/object_toc.py @@ -15,7 +15,7 @@ def _monkey_patch_toc_tree_process_doc(app: sphinx.application.Sphinx): """ TocTreeCollector = sphinx.environment.collectors.toctree.TocTreeCollector - # Apply the monkey pach + # Apply the monkey patch orig_process_doc = TocTreeCollector.process_doc def _make_section_from_desc( diff --git a/sphinx_immaterial/task_lists.py b/sphinx_immaterial/task_lists.py new file mode 100644 index 000000000..409c25984 --- /dev/null +++ b/sphinx_immaterial/task_lists.py @@ -0,0 +1,95 @@ +"""A custom directive that allows using checkboxes for lists""" +from typing import List +from docutils import nodes +from docutils.parsers.rst import directives +from sphinx.util.docutils import SphinxDirective +from sphinx.application import Sphinx +from sphinx.writers.html import HTMLTranslator + + +def visit_checkbox_label(self: HTMLTranslator, node: nodes.Node): + attributes = {} + if node["custom"]: + attributes = {"class": "task-list-control"} + self.body.append(self.starttag(node, "label", **attributes)) + self.body.append('") + if node["custom"]: + self.body.append('') + + +def depart_checkbox_label(self: HTMLTranslator, node: nodes.Node): + self.body.append("") + + +class checkbox_label(nodes.container): + pass + + +class TaskListDirective(SphinxDirective): + """a special directive""" + + has_content = True + optional_arguments = 4 + option_spec = { + "name": directives.unchanged, + "class": directives.class_option, + "custom": directives.flag, + "clickable": directives.flag, + } + + def run(self) -> List[nodes.Node]: + """Run the directive.""" + self.assert_has_content() + task_list = nodes.container( + "", is_div=True, classes=self.options.get("class", []) + ) + if self.options.get("name", ""): + self.add_name(task_list) + clickable = "clickable" in self.options or self.config["clickable_checkbox"] + custom = "custom" in self.options or self.config["custom_checkbox"] + self.state.nested_parse(self.content, self.content_offset, task_list) + self.set_source_info(task_list) + + def first_matching(obj, cls_t): + return obj.first_child_matching_class(cls_t) + + for child in task_list.children: + if isinstance(child, nodes.list_item): + child["classes"] = ["task-list"] + + for li_ in child.children: + if isinstance(li_, nodes.list_item): + if li_.astext().startswith("["): + li_["classes"] = ["task-list-item"] + checked = li_.astext().lower().startswith("[x]") + first_para = first_matching(li_, nodes.paragraph) + if first_para is not None: + first_text = first_matching(li_[first_para], nodes.Text) + li_[first_para][first_text] = li_[first_para][ + first_text + ].lstrip("[x] ") + li_[first_para][first_text] = li_[first_para][ + first_text + ].lstrip("[ ] ") + checkbox = checkbox_label( + "", + custom=custom, + disabled=not clickable, + checked=checked, + ) + li_.insert(0, checkbox) + + return [task_list] + + +def setup(app: Sphinx): + """Setup the extension.""" + app.add_directive("task-list", TaskListDirective) + app.add_node(checkbox_label, html=(visit_checkbox_label, depart_checkbox_label)) + app.add_config_value("custom_checkbox", False, rebuild="html", types=bool) + app.add_config_value("clickable_checkbox", False, rebuild="html", types=bool) diff --git a/sphinx_immaterial/theme_result.py b/sphinx_immaterial/theme_result.py new file mode 100644 index 000000000..b1f41eb24 --- /dev/null +++ b/sphinx_immaterial/theme_result.py @@ -0,0 +1,53 @@ +"""A directive designed to reduce example snippets duplication.""" +from docutils.parsers.rst import directives +from docutils import nodes +from sphinx.util.docutils import SphinxDirective +from sphinx.directives.code import container_wrapper + + +class ResultsDirective(SphinxDirective): + """Takes content as a rst code snippet and renders it after outputting it as a + literal code-block.""" + + has_content = True + optional_arguments = 1 + final_argument_whitespace = True + option_spec = { + "class": directives.class_option, + "name": directives.unchanged, + "output-prefix": directives.unchanged, + } + + def run(self): + """Run the directive.""" + container_node = nodes.container( + "", classes=self.options.get("class", []) + ["results"] + ) + code = "\n".join(self.content) + literal_node = nodes.literal_block(code, code) + literal_node["language"] = "rst" + if self.arguments: + literal_node = container_wrapper(self, literal_node, self.arguments[0]) + container_node += literal_node + + if "output-prefix" in self.options: + out_prefix = nodes.container("", classes=["results-prefix"]) + prefix = self.options.get("output-prefix", "") + if not prefix: + prefix = "Which renders the following content:" + textnodes, _ = self.state.inline_text(prefix, self.lineno) + out_prefix += textnodes + container_node += out_prefix + + # the `result` CSS class is theme specific (as used by mkdocs-material theme) + results_div = nodes.container("", classes=["result"]) + self.state.nested_parse(self.content, self.content_offset, results_div) + container_node += results_div + + self.set_source_info(container_node) + self.add_name(container_node) + return [container_node] + + +def setup(app): + app.add_directive("rst-example", ResultsDirective) diff --git a/src/assets/stylesheets/main/_api.scss b/src/assets/stylesheets/main/_api.scss index 0d9fb8eed..03b027bed 100644 --- a/src/assets/stylesheets/main/_api.scss +++ b/src/assets/stylesheets/main/_api.scss @@ -45,7 +45,7 @@ $objinfo-icon-size: 16px; font-weight: 700; } - a.reference > .sig-name { + a.reference > span { color: var(--md-typeset-a-color); &:hover { @@ -65,9 +65,9 @@ $objinfo-icon-size: 16px; color: var(--md-accent-fg-color); } + // Ensure each parameter starts on a new line and is indented. &.sig-wrap { - .sig-param { - // Ensure each parameter starts on a new line and is indented. + .sig-param-decl { &::before { white-space: pre; // 5 spaces below result in 4 spaces of indent. @@ -76,7 +76,7 @@ $objinfo-icon-size: 16px; } } - .sig-param + .sig-paren { + .sig-paren:last-of-type { // Ensure the final paren starts on a new line &::before { white-space: pre; diff --git a/src/assets/stylesheets/main/_typeset.scss b/src/assets/stylesheets/main/_typeset.scss index 336985544..af5bdf822 100644 --- a/src/assets/stylesheets/main/_typeset.scss +++ b/src/assets/stylesheets/main/_typeset.scss @@ -256,6 +256,14 @@ kbd { } } + // sphinx-immaterial: reset margin for code-blocks with a caption + .code-block-caption + .notranslate { + pre, + .highlighttable { + margin-top: 0; + } + } + // Keyboard key kbd { display: inline-block; diff --git a/src/assets/stylesheets/main/extensions/pymdownx/_highlight.scss b/src/assets/stylesheets/main/extensions/pymdownx/_highlight.scss index de8ecf923..0ae683473 100644 --- a/src/assets/stylesheets/main/extensions/pymdownx/_highlight.scss +++ b/src/assets/stylesheets/main/extensions/pymdownx/_highlight.scss @@ -322,7 +322,10 @@ } // Code block result container - :is(.highlight, .highlighttable) + .result { + // sphinx-immaterial: altered to support + // 1. docutils classes (.literal-block-wrapper, div[class^="highlight-"]) + // 2. rst-result directive's output-prefix (.results-prefix) + :is(.highlight, .highlighttable, .literal-block-wrapper, div[class^="highlight-"], .results-prefix) + .result { margin-top: calc(-1em + #{px2em(-2px)}); padding: 0 px2em(16px); overflow: visible; @@ -338,6 +341,20 @@ content: ""; } } + + // sphinx-immaterial: reset margin for rst-result directive's output-prefix + .results .results-prefix + .result { + margin-top: 0; + } + + // sphinx-immaterial: use modified style from span.filename (see above) + .results .results-prefix { + margin-top: -1em; + padding: px2em(9px, 13.6px) px2em(16px, 13.6px); + font-weight: 700; + font-size: px2em(13.6px); + background-color: var(--md-code-bg-color); + } } // ----------------------------------------------------------------------------