summaryrefslogtreecommitdiffstats
path: root/doc/development/tutorials/helloworld.rst
diff options
context:
space:
mode:
Diffstat (limited to 'doc/development/tutorials/helloworld.rst')
-rw-r--r--doc/development/tutorials/helloworld.rst189
1 files changed, 189 insertions, 0 deletions
diff --git a/doc/development/tutorials/helloworld.rst b/doc/development/tutorials/helloworld.rst
new file mode 100644
index 0000000..8940e3d
--- /dev/null
+++ b/doc/development/tutorials/helloworld.rst
@@ -0,0 +1,189 @@
+Developing a "Hello world" extension
+====================================
+
+The objective of this tutorial is to create a very basic extension that adds a
+new directive. This directive will output a paragraph containing "hello world".
+
+Only basic information is provided in this tutorial. For more information, refer
+to the :doc:`other tutorials <index>` that go into more details.
+
+.. warning::
+
+ For this extension, you will need some basic understanding of docutils_
+ and Python.
+
+
+Overview
+--------
+
+We want the extension to add the following to Sphinx:
+
+* A ``helloworld`` directive, that will simply output the text "hello world".
+
+
+Prerequisites
+-------------
+
+We will not be distributing this plugin via `PyPI`_ and will instead include it
+as part of an existing project. This means you will need to use an existing
+project or create a new one using :program:`sphinx-quickstart`.
+
+We assume you are using separate source (:file:`source`) and build
+(:file:`build`) folders. Your extension file could be in any folder of your
+project. In our case, let's do the following:
+
+#. Create an :file:`_ext` folder in :file:`source`
+#. Create a new Python file in the :file:`_ext` folder called
+ :file:`helloworld.py`
+
+Here is an example of the folder structure you might obtain:
+
+.. code-block:: text
+
+ └── source
+    ├── _ext
+ │   └── helloworld.py
+    ├── _static
+    ├── conf.py
+    ├── somefolder
+    ├── index.rst
+    ├── somefile.rst
+    └── someotherfile.rst
+
+
+Writing the extension
+---------------------
+
+Open :file:`helloworld.py` and paste the following code in it:
+
+.. literalinclude:: examples/helloworld.py
+ :language: python
+ :linenos:
+
+Some essential things are happening in this example, and you will see them for
+all directives.
+
+.. rubric:: The directive class
+
+Our new directive is declared in the ``HelloWorld`` class.
+
+.. literalinclude:: examples/helloworld.py
+ :language: python
+ :linenos:
+ :lines: 5-9
+
+This class extends the docutils_' ``Directive`` class. All extensions that
+create directives should extend this class.
+
+.. seealso::
+
+ `The docutils documentation on creating directives <docutils directives_>`_
+
+This class contains a ``run`` method. This method is a requirement and it is
+part of every directive. It contains the main logic of the directive and it
+returns a list of docutils nodes to be processed by Sphinx. These nodes are
+docutils' way of representing the content of a document. There are many types of
+nodes available: text, paragraph, reference, table, etc.
+
+.. seealso::
+
+ `The docutils documentation on nodes <docutils nodes_>`_
+
+The ``nodes.paragraph`` class creates a new paragraph node. A paragraph
+node typically contains some text that we can set during instantiation using
+the ``text`` parameter.
+
+.. rubric:: The ``setup`` function
+
+.. currentmodule:: sphinx.application
+
+This function is a requirement. We use it to plug our new directive into
+Sphinx.
+
+.. literalinclude:: examples/helloworld.py
+ :language: python
+ :linenos:
+ :lines: 12-
+
+The simplest thing you can do is to call the :meth:`~Sphinx.add_directive` method,
+which is what we've done here. For this particular call, the first argument is
+the name of the directive itself as used in a reST file. In this case, we would
+use ``helloworld``. For example:
+
+.. code-block:: rst
+
+ Some intro text here...
+
+ .. helloworld::
+
+ Some more text here...
+
+We also return the :ref:`extension metadata <ext-metadata>` that indicates the
+version of our extension, along with the fact that it is safe to use the
+extension for both parallel reading and writing.
+
+
+Using the extension
+-------------------
+
+The extension has to be declared in your :file:`conf.py` file to make Sphinx
+aware of it. There are two steps necessary here:
+
+#. Add the :file:`_ext` directory to the `Python path`_ using
+ ``sys.path.append``. This should be placed at the top of the file.
+
+#. Update or create the :confval:`extensions` list and add the extension file
+ name to the list
+
+For example:
+
+.. code-block:: python
+
+ import os
+ import sys
+
+ sys.path.append(os.path.abspath("./_ext"))
+
+ extensions = ['helloworld']
+
+.. tip::
+
+ We're not distributing this extension as a `Python package`_, we need to
+ modify the `Python path`_ so Sphinx can find our extension. This is why we
+ need the call to ``sys.path.append``.
+
+You can now use the extension in a file. For example:
+
+.. code-block:: rst
+
+ Some intro text here...
+
+ .. helloworld::
+
+ Some more text here...
+
+The sample above would generate:
+
+.. code-block:: text
+
+ Some intro text here...
+
+ Hello World!
+
+ Some more text here...
+
+
+Further reading
+---------------
+
+This is the very basic principle of an extension that creates a new directive.
+
+For a more advanced example, refer to :doc:`todo`.
+
+
+.. _docutils: https://docutils.sourceforge.io/
+.. _docutils directives: https://docutils.sourceforge.io/docs/howto/rst-directives.html
+.. _docutils nodes: https://docutils.sourceforge.io/docs/ref/doctree.html
+.. _PyPI: https://pypi.org/
+.. _Python package: https://packaging.python.org/
+.. _Python path: https://docs.python.org/3/using/cmdline.html#envvar-PYTHONPATH