.. @+leo-ver=5-thin
.. @+node:ekr.20100805165051.7163: * @file writingPlugins.txt
.. @@language rest
.. @@tabwidth -4

.. @+at @rst-options
..  call_docutils=False
..  code_mode=False
..  generate_rst=True
..  http_server_support = False
..  show_organizer_nodes=True
..  show_headlines=True
..  show_leo_directives=True
..  stylesheet_path=..\doc
..  write_intermediate_file = True
..  verbose=True
.. @@c

.. @+all
.. @+node:ekr.20060612103240: ** @rst html\writingPlugins.html
###############
Writing Plugins
###############

A **plugin** is a Python file that appears in Leo's plugin directory. Plugins
modify how Leo works. With plugins you can give Leo new commands, modify how
existing commands work, or change any other aspect of Leo's look and feel.
leoPlugins.leo contains all of Leo's official plugins. Studying this file is
a good way to learn how to write plugins.

You **enable** plugins using @enabled-plugins nodes in leoSettings.leo or
myLeoSettings.leo. For more details, see the @enabled-plugins node in
leoSettings.leo. Leo imports all enabled plugins at startup time. Plugins become
**active** if importing the plugin was successful.

Writing plugins is quite similar to writing any other Leo script.  See
`Scripting Leo with Python`_. In particular:

1. Plugins can use any of Leo's source code simply by importing any module
   defined in leoPy.leo.

2. Plugins can register event handlers just like any other Leo script. For full
   details, see the section called `event handlers`_ in Leo's scripting chapter.

The rest of this chapters discusses topics related specifically to plugins.


.. contents::
    :depth: 2
.. @+node:ekr.20060612103824: *3* @rst-no-head links
.. External links...
.. _docutils:             http://docutils.sourceforge.net
.. _LaTeX:                http://www.latex-project.org/
.. _reStructuredText:     http://docutils.sourceforge.net/rst.html
.. _SilverCity:           http://silvercity.sourceforge.net

.. Relative links...
.. _`Event handlers`:               scripting.html#event-handlers
.. _`Scripting Leo with Python`:    scripting.html
.. _`Customizing Leo`:              customizing.html
.. @+node:ville.20100807185755.4510: *3* enabled-plugins
@enabled-plugins node is as list of plugins to load. If you have @enabled-plugins
node in your myLeoSettings.leo, the plugins are loaded from there. If such a
node doesn't exist, the global leoSettings.leo is used instead.

The @enabled-plugins bundled in leoSettings.leo contains a list of default
(recommended) plugins. For your own @enabled-plugins in myLeoSettings.leo, you
should use the node in leoSettings.leo as a starting point unless you are
certain you want to disable a recommended plugin.

@enabled-plugins nodes contain the list of enabled plugins, one per line.

Comment lines starting with '#' are ignored.

Plugins are essentially normal python modules, and loading a plugin basically
means importing it and running the "init" function in the module's root level
namespace. A line in @enabled-plugins is a module name that leo should import.

Here's an example @enabled-plugins node::

    # Standard plugins enabled in official distributions....

    plugins_menu.py
    quicksearch.py

    # third party plugins

    # 'leoplugin' module inside python package 'foo'
    foo.leoplugin

    # top-level module
    barplugin

Note that some entries end with .py. This is done to retain backwards
compatibility - if an entry ends with .py, it means a plugin in Leo's 'plugins'
directory (package) and is translated to e.g. "leo.plugins.plugins_menu" before
importing.

Normally, a third party plugin should be a basic python module that is installed
globally for the python interpreter with "python setup.py install". Installing 
plugins to Leo's 'plugins' directory is not recommended, as such plugins 
can disappear when Leo is upgraded. 
.. @+node:EKR.20040524104904.240: *3* Support for unit testing
The plugins test suite creates a new convention: if a plugin has a function at
the outer (module) level called unitTest, Leo will call that function when
doing unit testing for plugins. So it would be good if writers of plugins would
create such a unitTest function. To indicate a failure the unitTest just
throws an exception. Leo's plugins test suite takes care of the rest.
.. @+node:EKR.20040524104904.224: *3* Important security warnings
Naively using plugins can expose you and your .leo files to malicious attacks.
The fundamental principles are::

    Scripts and plugins must never blindly execute code from untrusted sources.

and::

    .leo files obtained from other people may potentially contain hostile code.

Stephen Schaefer summarizes the danger this way::

    I foresee a future in which the majority of leo projects come from
    marginally trusted sources...a world of leo documents sent hither and yon -
    resumes, project proposals, textbooks, magazines, contracts - and as a race
    of Pandora's, we cannot resist wanting to see "What's in the box?" And are
    we going to fire up a text editor to make a detailed examination of the
    ASCII XML? Never! We're going to double click on the cute leo file icon, and
    leo will fire up in all its raging glory. Just like Word (and its macros) or
    Excel (and its macros).

In other words::

    When we share "our" .leo files we can NOT assume that
    we know what is in our "own" documents!

Not all environments are untrustworthy. Code in a commercial cvs repository is
probably trustworthy: employees might be terminated for posting malicious code.
Still, the potential for abuse exists anywhere.

In Python it is very easy to write a script that will blindly execute other scripts::

    # Warning: extremely dangerous code

    # Execute the body text of all nodes that start with `@script`.
    def onLoadFile():
        for p in c.all_positions():
            h = p.h.lower()
            if g.match_word(h,0,"@script"):
                s = p.b
                if s and len(s) > 0:
                    try: # SECURITY BREACH: s may be malicious!
                        exec(s + '\n')
                    except:
                        es_exception()

Executing this kind of code is typically an intolerable security risk.
**Important**: rexec provides *no protection whatever*.
Leo is a repository of source code, so any text operation is potentially malicious.
For example, consider the following script, which is valid in rexec mode::

    badNode = c.p
    for p in c.all_positions():
        << change `rexec` to `exec` in p's body >>
    << delete badNode >>
    << clear the undo stack >>

This script will introduce a security hole the .leo file without doing anything
prohibited by rexec, and without leaving any traces of the perpetrating script
behind. The damage will become permanent *outside* this script when the user
saves the .leo file.
.. @-all
.. @-leo
