.. @+leo-ver=5-thin
.. @+node:ekr.20100805165051.7158: * @file customizing.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.20050901101608.4: ** @rst html\customizing.html
################
Customizing Leo
################

This chapter discusses how to customize Leo using the plugins and other means.
See `Specifying settings`_ for a description of how to change Leo's settings.

.. contents::
    :depth: 3
.. @+node:ekr.20050901102055: *3* @rst-no-head links
.. _`Scripting Leo with Python`:    scripting.html
.. _`History of Leo`:               history.html
.. _`rst3 plugin`:                  glossary.html#rst3-plugin
.. _`Specifying settings`:          commands.html#specifying-settings
.. @+node:EKR.20040524104904.140: *3* Specifying settings
Leo stores options in **@settings trees**, outlines whose headline is
@settings. When opening a .leo file, Leo looks for @settings trees not only
in the outline being opened but also in various leoSettings.leo files.
This scheme allows for the following kinds of settings:

- Per-installation or per-machine settings.
- Per-user settings.
- Per-folder settings.
- Per-file settings.

There are four kinds of settings files:

1. **Default settings files**, named **leoSettings.leo**.
   Although they can be used in other ways, they typically contain default settings.

2. **Personal settings files**, named **myLeoSettings.leo**. They provide a way
   of ensuring that your customized settings are not altered when updating Leo
   from bzr or while installing a new version of Leo. The myLeoSettings.leo acts
   much like Python's site-customize.py file. myLeoSettings.leo will never be
   part of any Leo distribution, and it will never exist in Leo's cvs
   repository. This solution is *much* better than trying to update
   leoSettings.leo with scripts.

3. **Machine settings files**, named **LeoSettings.leo** (note the capital 'L'),
   and appearing in a unique directory.

4. **Command-line settings files**, specified using Leo's -c command-line
   option. Any .leo file may be used, provided it has an @settings tree. These
   files typically provide a common set of settings for files scattered in
   various places on the file system.

The following sections describe the kinds of nodes in @settings trees.
.. @+node:ekr.20090116130002.1: *4* Configuration directories
Settings files can be found in the following directories:

- **homeDir**, the HOME/.leo directory. HOME is given by Python's HOME
  environment variable, or by os.expanduser('~') if no HOME environment variable
  exists.

- **configDir**, Leo's configuration directory: leo/config.

- **machineDir**, the HOME/.leo/MACHINE directory. MACHINE is given by Python's
  HOSTNAME environment variable, or by Python's COMPUTERNAME environment
  variable if there is no HOSTNAME variable, or by the value returned by
  socket.gethostname() if neither environment variable exists.

- **localDir**, the directory containing the .leo file being loaded.

In addition, Leo's -c command-line option can specify any .leo file anywhere.
.. @+node:ekr.20090116094356.2: *4* Search order for settings files
When reading a .leo file, Leo looks for settings in default settings
files first, then settings in personal settings files, and finally
settings in local settings files.  The exact search order is:

1. Default settings files:

   a. configDir/leoSettings.leo
   b. homeDir/leoSettings.leo
   c. localDir/leoSettings.leo

2. Personal settings files:

   a. configDir/myLeoSettings.leo
   b. homeDir/myLeoSettings.leo
   c. homeDir/<machine-name>LeoSettings.leo (note capitalization)
   d. localDir/myLeoSettings.leo

3. Local settings files:

   a. The file specified by the -c command-line option.
   b. The file being loaded.

Settings that appear later in this list override settings that
appear earlier in this list.  This happens on a setting-by-setting
basis, *not* on a file-by-file basis.  In other words, each individual
setting overrides only the *corresponding* setting in previously-read
files.  Reading a setting file does *not* reset all previous settings.
Note that the same file might appear several times in the search list.
Leo detects such duplicate file names and only loads each settings file once.
Leo remembers all the settings in settings files and does not reread those
settings when reading another .leo file.

**Caution**: This search order offers almost too much flexibility. This can be
confusing, even for power users. It's important to choose the "simplest
configuration scheme that could possibly work".  Something like:

- Use a single leoSettings.leo file for installation-wide defaults.
- Use a single myLeoSettings.leo files for personal defaults.
- Use local settings sparingly.

**Important**: it is good style to limit settings placed in 
myLeoSettings.leo to those settings that differ from default settings.
.. @+node:ekr.20090116094356.3: *4* Safe rules for local settings
You should use special care when placing default or personal settings files in
**local** directories, that is, directories other than homeDir, configDir or
machineDir. In particular, the value of localDir can change when Leo reads
additional files. This can result in Leo finding new default and personal
settings files. The values of these newly-read settings files will, as always,
override any previously-read settings.

Let us say that a setting is **volatile** if it is different from a default
setting. Let us say that settings file A.leo **covers** settings file if B.leo
if all volatile settings in B.leo occur in A.leo. With these definitions, the
**safe rule** for placing settings files in local directories is::

   Settings files in local directories should
   cover all other settings files.

Following this rule will ensure that the per-directory defaults specified in the
local settings file will take precedence over all previously-read default and
personal settings files. Ignore this principle at your peril.
.. @+node:ekr.20070317043727: *4* Organizer nodes
Organizer nodes have headlines that do no start with @.
Organizer nodes may be inserted freely without changing the meaning of an @setting tree.
.. @+node:ekr.20080411111008.1: *4* \@ignore and \@if nodes
Leo ignores any subtree of an @settings tree whose headline starts with @ignore.

You can use several other kinds of nodes to cause Leo to ignore parts of  an @settings tree:

- @if *expression*

  A node whose headline starts with @if *expression* acts like an organizer node if the expression evaluates to True,    
  otherwise acts like an @ignore node.
  If the expression is empty the body text should contain a script that will be evaluated (in an empty context).

- @ifplatform *platform-name*

  Same as @if sys.platform == "platform-name": except that it isn't necessary to import sys.

- @ifhostname *hostA,!hostB*

  Evaluates to True if and only if: h=g.computeMachineName(); h==hostA and h!=hostB.
  The "!" version allows matching to every machine name except the given one
  to allow differing settings on only a few machines.
.. @+node:ekr.20070317043727.2: *4* Simple settings nodes
Simple settings nodes have headlines of the form::

    @<type> name = val

set the value of name to val, with the indicated type.

<type> may be one of the following:

=============== =========================================================================================
<type>          Valid values
--------------- -----------------------------------------------------------------------------------------
\@bool           True, False, 0, 1
\@color          A Tk color name or value, such as 'red' or 'xf2fddff' (without the quotes)
\@directory      A path to a directory
\@float          A floating point number of the form nn.ff.
\@int            An integer
\@ints[list]     An integer (must be one of the ints in the list).
                 Example: @ints meaningOfLife[0,42,666]=42
\@keys[name]     Gives a name to a set of bindings for the Check Bindings script in leoSettings.leo.
\@path           A path to a directory or file
\@ratio          A floating point number between 0.0 and 1.0, inclusive.
\@string         A string
\@strings[list]  A string (must be one of the strings in the list).
                 Example: @strings tk_relief['flat','groove','raised']='groove'
=============== =========================================================================================

**Note**: For a list of Tk color specifiers see:

- http://www.tcl.tk/man/tcl8.4/TkCmd/colors.htm
- http://www.tcl.tk/man/tcl8.4/TkLib/GetColor.htm

**Important**: you can use the show-colors minibuffer command to guide you in making these settings.
.. @+node:ekr.20070317043727.3: *4* Complex settings nodes
Complex settings nodes have headlines of the form::

    @<type> description

The type may be one of the following:

=================== =====================================================================
<type>              Valid values 
------------------- ---------------------------------------------------------------------
\@buttons           Child @button nodes create global buttons
\@commands          Child @command nodes create global buttons
\@data              Body text contains a list of strings, one per line.
\@enabled-plugins   Body text contains a list of enabled plugins
\@font              Body text contains a font description
\@menus             Child @menu and @item nodes create menus and menu items.
\@menuat            Child @menu and @item nodes modify menu tree create by \@menus.
\@mode [name]       Body text contains a list of shortcut specifiers.
\@recentfiles       Body text contains a list of file paths.
\@shortcuts         Body text contains a list of shortcut specifies.
=================== =====================================================================

Complex nodes specify settings in their body text.
See the following sections for details.
.. @+node:ekr.20090116094356.5: *5* \@button
An @buttons tree in a settings file defines global buttons that
are created in the icon area of all .leo files.
All @button nodes in the @commands tree create global buttons.
All @button nodes outside the commands tree create buttons local to the settings file.
.. @+node:ekr.20090116094356.6: *5* \@commands
An \@commands tree in a settings file defines global commands.
All \@command nodes in the @commands tree create global commands.
All \@command nodes outside the commands tree create commands local to the settings file.
.. @+node:ekr.20090116094356.7: *5* \@data
The body text contains a list of strings, one per line.
Lines starting with '#' are ignored.
.. @+node:ekr.20090116094356.8: *5* \@enabled-plugins
The body text of the @enabled plugins node contains a list of enabled plugins,
one per line. Comment lines starting with '#' are ignored. Leo loads plugins in
the order they appear.
**Important**: Leo handles @enabled-plugins nodes a differently from other kinds
of settings. To avoid confusion, **please read the following carefully**.

As always, Leo looks for @enabled-plugins nodes in settings files in the order
specified by `Search order for settings files`_. Leo will enable all plugins
found in the @enabled-plugins node it finds *last* in the search order. Leo does
*not* enable plugins found in any other @enabled-plugins node. In particular,
**you can not specify a list of default plugins by placing that list in a
settings file that appears early in the search list**. Instead, the last
@enabled-plugins node found in the search list specifies all and *only* the plugins
that will be enabled.

Let us distinguish two different situations. First, what Leo does when loading a
file, say x.leo. Second, what Leo does when loading a second file, say y.leo,
*from x.leo*. When loading the first .leo file, Leo enables plugins from the
@enabled-plugins node it finds *last* in the search order. But after plugins
have *already* been loaded and enabled, there is no way to disable previously
loaded-and-enabled plugins. But local settings files can enable additional
plugins.

To avoid confusion, I highly recommend following another kind of safe rule.
We say that an @enabled-plugin node in file A.leo **covers** an @enabled-plugin
node in file B.leo if all plugins specified in B's @enabled-plugin node appear
A's @enabled-plugin node. The safe rule for plugins is::

  @enabled-plugin nodes in settings files in local directories
  should cover @enabled-plugins nodes in all other settings files.
.. @+node:ekr.20090116094356.11: *5* \@font
The body text contains a list of settings for a font.  For example::

    body_text_font_family = Courier New
    body_text_font_size = None
    body_text_font_slant = None
    body_text_font_weight = None

**Important**: you can use the show-fonts minibuffer command to guide you in making these settings.

.. @+node:ekr.20090116094356.10: *5* \@menuat
The form of this node is::

    @menuat *<path>* *<action>* *[clipboard]*

The @menuat setting has 2-3 parameters in its head text, its children are @menu and
@item nodes as for the @menu setting.  @menuat modifies the menu tree created by @menus.
It is intended to be used in myLeoSettings.leo to modify the menu tree created
in leoSettings.leo. This allows you to change the menus without having to
re-create the entire menu tree from leoSettings.leo, and ensures you don't miss
out when new things are added in the @menus in leoSettings.leo, as you would if
you replaced the @menus in leoSettings.leo with one in myLeoSettings.leo.
@menuat should occur in a @settings tree, but not as a descendant of a @menus
tree. There is an example of the use of the
@menuat setting in the file .../leo/core/test/menuAtTest.leo.

The **path** argument specifies a target location in the menu tree as defined by
@menus and modified by earlier @menuat settings. The path takes the form
/entry1/entry2/entry3 where each entry is the name of a menu or item with all
text except a-z and 0-9 removed. Upper case letters are converted to lower case.
So for example to use the `Outline->Move->Move Down` menu item as a target, you
would specify a path as `/outline/move/movedown`.

The **action** argument specifies what the menu item does.
There are 5 available actions:

- **before**: The supplied items and sub menus will be inserted immediately
  before the target menu or item.

- **after**: The supplied items and sub menus will be inserted immediately after
  the target menu or item.

- **append**: The supplied items and sub menus will be appended at the end of
  the menu containing the target menu or item.

- **cut**: The target menu or item will be removed from the menu tree and saved
  to an internal clipboard. This can be used for deleting menus or items.
  Descendants of the @menuat setting are ignored.

- **copy**: The target menu or item will be copied and saved to
  an internal clipboard.  Descendants of the @menuat setting are ignored.

The optional **clipboard** argument modifies the action of the before, after,
and append actions. By default these actions insert the menus and items supplied
as descendants of the @menuat setting. If you specify "clipboard" (without the
quotes) as the source, the contents of the clipboard from a previous cut or copy
action will be used instead. This parameter is optional and can be left blank.
.. @+node:ekr.20090116094356.9: *5* \@menus
Leo creates its menus from the @menu, @item and @popup nodes in the @menus tree.
Within @menus trees, @menu nodes create menus and @item nodes create menu items. 

The menu name always follows @menu. If the menu name is 'Plugins', Leo will
create the Plugins menu and populate the menu by calling the
'create-optional-menus' hook. This creates the Plugins menu as usual. Nested
@menu nodes define submenus.

The command name follows @item. If the body text of an @item node exists, this
body text is the menu name. Otherwise, the menu name is the command name.
However, if the command name starts with a '*', hyphens are removed from the
menu name. Menu names and command names may contain a single ampersand (&). If
present, the following character is underlined in the name. If the command
name in an @item node is just a hyphen (-), the item represents a menu
separator.

@popup *<widget-name>* creates a popup menu for use by the rClick plugin.
The children of this node should be @menu and @item nodes, used as with
@menus.
.. @+node:ekr.20090116094356.14: *5* \@mode
The form of this node is::

    @mode *<mode name>*

The body text contains a list of shortcut specifiers. @mode nodes work just
like @shortcuts nodes, but in addition they have the side effect of creating
the enter-<mode name>-mode command.
.. @+node:ekr.20090116094356.13: *5* \@recentfiles
The body text contains a list of paths of recently opened files, one path per
line. Leo writes the list of recent files to .leoRecentFiles.txt in Leo's
config directory, again one file per line.
.. @+node:ekr.20090116094356.12: *5* \@shortcuts
The body text contains a list of shortcut specifiers.
.. @+node:ekr.20060105214753: *3* Input modes
Leo now allows you to specify input modes. You enter mode x with the
enter-x-mode command. The purpose of a mode is to create different bindings
for keys within a mode. Often plain keys are useful in input modes.

You can specify modes with @mode nodes in leoSettings.leo. @mode nodes work
just like @shortcuts nodes, but in addition they have the side effect of
creating the enter-<mode name>-mode command.

Notes:

- You can exit any mode using the keyboard-quit (Control-g) command. This is the
  **only** binding that is automatically created in each mode. All other bindings
  must be specified in the @mode node. In particular, the bindings specified in
  @shortcuts nodes are **not** in effect in mode (again, except for the
  keyboard-quit binding).

- Leo supports something akin to tab completion within modes: if you type a key
  that isn't bound in a mode a 'Mode' tab will appear in the log pane. This tab
  shows all the keys that you can type and the commands to which they are bound.
  The mode-help command does the same thing.

- @shortcuts nodes specify the bindings for what might be called the 'top-level'
  mode. These are the bindings in effect when no internal state is present, for
  example, just after executing the keyboard-quit command.

- The top_level_unbound_key_action setting determines what happens to
  unbound keys in the top-level mode. Leo ignores unbound keys in all other modes.
  The possibilities are 'insert', 'replace' and 'ignore'.

- The set-insert-mode, set-overwrite-mode and set-ignore-mode
  commands alter what happens to unbound keys in the top-level mode.

With all these options it should be possible to emulate the keyboard behavior of any other editor.
.. @+node:ekr.20050306090601: *3* Adding extensible attributes to nodes and .leo files
Leo's .leo file format is extensible.
The basis for extending .leo files are the v.unknownAttributes ivars of vnodes,
uA's for short.
Leo translates between uA's and xml attributes in the corresponding
<v> elements in .leo files.
Plugins may also use v.tempAttributes ivars to hold temporary information
that will *not* be written to the .leo file.
These two ivars are called **attribute ivars**.

Attribute ivars must be Python dictionaries, whose keys are names of plugins and
whose values are *other* dictionaries, called **inner dictionaries**, for
exclusive use of each plugin.

The v.u Python property allows plugins to get and set v.unknownAttributes easily::

    d = v.u # gets uA (the outer dict) for v
    v.u = d # sets uA (the outer dict) for v

For example:

    plugin_name = 'xyzzy'
    d = v.u # Get the outer dict.
    inner_d = d.get(plugin_name,{}) # Get the inner dict.
    inner_d ['duration']= 5
    inner_d ['notes'] "This is a note."
    d [plugin_name] = inner_d
    v.u = d

No corresponding Python properties exist for v.tempAttributes,
so the corresponding example would be::

    plugin_name = 'xyzzy'
    # Get the outer dict.
    if hasattr(p.v,'tempAttributes'): d = p.v.tempAttributes
    else: d = {}
    inner_d = d.get(plugin_name,{}) # Get the inner dict.
    inner_d ['duration'] = 5
    inner_d ['notes'] = "This is a note."
    d [plugin_name] = inner_d
    p.v.tempAttributes = d

**Important**: All members of inner dictionaries should be picklable: Leo
uses Python's Pickle module to encode all values in these dictionaries. Leo will
discard any attributes that can not be pickled. This should not be a major
problem to plugins. For example, instead of putting a tnode into these
dictionaries, a plugin could put the tnode's gnx (a string) in the dictionary.

**Note**: Leo does *not* pickle members of inner dictionaries whose name (key) starts with str\_.
The values of such members should be a Python string.
This convention allows strings to appear in .leo files in a more readable format.

Here is how Leo associates uA's with <v> elements in .leo files:

- **Native xml attributes** are the attributes of <v> elements that are
  known (treated specially) by Leo's read/write code. The native attributes of
  <v> elements are a, t, vtag, tnodeList, marks,
  expanded and descendentTnodeUnknownAttributes. All other attributes of
  <v> and <t> elements are **foreign xml attributes**.

- When reading a .leo file, Leo will create v.unknownAttributes ivars for
  any vnode whose corresponding <v> or <t> element contains a
  foreign xml attribute.

- When writing a file, Leo will write foreign xml attributes in <v> elements
  if the corresponding vnode contains an unknownAttributes ivar.

- Leo performs the usual xml escapes on these strings when reading or writing
  the unknownAttributes ivars.
.. @+node:ekr.20050620150517: *3* Specifying Tk options using .leo_xresources
Leo looks for a file called .leo_xresources in the users home directory. If
found, Leo will pass that file to Tk's option_readfile method for the top
widget. This allows users to set Tk options.
.. @+node:ekr.20080310093038.4: *3* Translating Leo's menus and messages
.. _gettext: http://docs.python.org/lib/module-gettext.html

It is easy to translate Leo's menu strings: simply create an @menus tree in
leoSettings.leo or myLeoSettings.leo that contains the translated menu names.

**New in Leo 4.4.8**:
Leo now contains support for translating messages sent to Leo's log:

- Rather than using an '_' function to denote strings to be translated, Leo's
  g.es and g.es_print functions translate "odd" (first, third, fifth) arguments,
  leaving "even" arguments untranslated. Keyword arguments, color, newline, etc.
  are never translated.

- All calls to g.es and g.es_print in Leo's core follow this convention.

- g.translateString does the actual translation using Python's `gettext`_ module.

- You can use the script in the node "@button print g.es stats" in scripts.leo
  to create catalogs of all scripts that need to be translated. Such catalogs
  are used by Python's gettext module. (This script was also used to check that
  the proper arguments to g.es and g.es_print were translated.)
.. @+node:ekr.20100122073254.11655: *3* Writing new importers
This section describes the process of creating an importer for a new language.
There are a set of "importers" in leoImport.py, all based on the
baseScannerClass class. You can define your own importer by creating a subclass.
This shouldn't be too difficult: baseScannerClass is supposed to do almost all
the work. With luck, your subclass might be very simple, as with class cScanner.

**Important** As I write this, I realize that I remember very little about the
code, but I do remember its general organization and the process of creating a
new importer. The following should be all you need to write any importer.

This base class has three main parts:

1. The "parser" that recognizes where nodes begin and end.

2. The "code generator" the actually creates the imported nodes.

3. Checking code that ensures that the imported code is equivalent
   to the original code.

You should never have to change the code generators or the checking code.
Confine your attention to the parser.

The parser thinks it is looking for classes, and within classes,
method definitions.  Your job is to tell the parser how to do this.
Let's look at part of the ctor for baseScannerClass for clues::

   # May be overridden in subclasses.
   self.anonymousClasses = [] # For Delphi Pascal interfaces.
   self.blockCommentDelim1 = None
   self.blockCommentDelim2 = None
   self.blockCommentDelim1_2 = None
   self.blockCommentDelim2_2 = None
   self.blockDelim1 = '{'
   self.blockDelim2 = '}'
   self.blockDelim2Cruft = [] # Stuff that can follow .blockDelim2.
   self.classTags = ['class',] # tags that start a tag.
   self.functionTags = []
   self.hasClasses = True
   self.hasFunctions = True
   self.lineCommentDelim = None
   self.lineCommentDelim2 = None
   self.outerBlockDelim1 = None
   self.outerBlockDelim2 = None
   self.outerBlockEndsDecls = True
   self.sigHeadExtraTokens = [] # Extra tokens valid in head of signature.
   self.sigFailTokens = []
       # A list of strings that abort a signature when seen in a tail.
       # For example, ';' and '=' in C.
   self.strict = False # True if leading whitespace is very significant.

Naturally, this looks like gibberish at first. I do *not* remember what all
these things do in detail, although obviously the names mean something. What I
*do* remember is that these ivars control the operation of the startsFunction
and startsClass methods and their helpers (especially startsHelper) and
the methods that call them, scan and scanHelper. Most of these methods have a
trace var that will enable tracing during importing.

So the strategy is simple: study startsHelper in detail, set the ivars above to
make startsHelper do what you want, and trace until things work as you want.

There is one more detail. Sometimes the ivars above are not sufficient to get
the job done. In that case, subclasses will override various methods of the
parser, but *not* the code generator. If indentation is important, you will want
to look at the Python importer. Notice that it overrides skipCodeBlock, called
by startsHelper.

That's about it. It would be pointless to give you more details, because those
details would lead you *away* from the process you need to follow. Having said
that, feel free to ask further questions. I'll be glad to answer them.
.. @-all
.. @-leo
