.. imprint: a program for creating documents from data and content templates

.. Copyright (C) 2019  Joseph R. Fox-Rabinovitz <jfoxrabinovitz at gmail dot com>

.. This program is free software: you can redistribute it and/or modify
.. it under the terms of the GNU Affero General Public License as
.. published by the Free Software Foundation, either version 3 of the
.. License, or (at your option) any later version.

.. This program is distributed in the hope that it will be useful,
.. but WITHOUT ANY WARRANTY; without even the implied warranty of
.. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
.. GNU Affero General Public License for more details.

.. Author: Joseph Fox-Rabinovitz <jfoxrabinovitz at gmail dot com>
.. Version: 13 Apr 2019: Initial Coding


.. _t_plugin:

===============
Writing Plugins
===============

Imprint is all about customization, and the :ref:`introduction-layers-plugins`
is the crux of that customization. But what exactly is a plugin, and how do you
write one? This tutorial aims to provide a step-by-step, hands-on, introduction
the types of plugins that are supported, and how to write them.

A :ref:`plugin <plugins>` is a :py:func:`callable` that creates the dynamic
content that makes gives Imprint its power. Each plugin fulfills a particular
interface, defined by the XML tag that it is bound to. There are three main
types of content that can be generated by default: :ref:`t_plugin-figures`,
:ref:`t_plugin-tables` and :ref:`t_plugin-strings`. Custom tags that support
plugins can be created as well. This advanced topic is covered in the
:doc:`content_tutorial`.

While different types of plugins are different from each other, there are a few
common features they all share. The first two arguments to each of the built-in
:ref:`plugins-handlers` are the dictionary of :ref:`keywords` and the
:ref:`plugins-data-configuration`. The remaining arguments depend on the
specific tag. Custom tags are not strictly required, but highly encouraged, to
follow this convention.


.. todo: Add sections for data logging


.. _t_plugin-toc:

.. contents:: Topics Covered:
   :depth: 2
   :local:


.. _t_plugin-figures:

-------
Figures
-------


.. _t_plugin-tables:

------
Tables
------

Tables are generally the most complex type of plugin for the builtin tags,
since they have to modify the document in-place as they generate their content.
This leads to interesting artifacts, like partially generated tables in case of
an error. Broken :ref:`t_plugin-figures` and :ref:`t_plugin-strings` are
entirely replaced by alt-text, but tables will generally be generated up to the
point where the error occurred.

It also means that the :ref:`xml-spec-tags-table` tag does not handle data
logging, instead leaving the task up to the discretion of individual plugins.
This is very different from the simpler plugin tags like
:ref:`xml-spec-tags-figure` and :ref:`xml-spec-tags-string`, which handle the
data logging in a uniform manner, without delegation to a plugin.


.. _t_plugin-strings:

-------
Strings
-------


.. _t_plugin-errors:

--------------
Error Handling
--------------


.. _t_plugin-using:

-----------------
Using Your Plugin
-----------------

You made a plugin. Now what? How do you use it in the template you just
created?

This is a two-step process. First you have to let Imprint and Python know where
your plugin lives. Second, you have to refer to the plugin in your template
somehow. Both steps are covered in detail in the next sections:


.. _t_plugin-using-registering:

-----------------------
Registering Your Plugin
-----------------------

To register a plugin, you must place it in the Python Path. This is normally
done with something like ::

    import sys
    sys.path.insert(0, 'path/to/plugin/module')

It is often convenient to put such a registration into a dedicated
:ref:`IIF File <configuration-iif>`.

.. todo:: This has been totally changed by the ??? keyword.

.. todo:: Add an example

.. note::

   Keep the import as ``import sys`` rather than ``from sys import path``,
   since the latter will add a :ref:`keyword <keywords>` to your namespace,
   while a module will be ignored after loading.


.. _t_plugin-using-referencing:

-----------------------
Referencing Your Plugin
-----------------------

Once a plugin is in your Python Path, you can reference it as you would any
other module in your tag's ``handler`` attribute.

.. todo:: Add an example
