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.
Leo stores options in @settings trees, that is, 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. The key design goal of @settings trees was that Leo's user options must be infinitely flexible. That goal has been accomplished. Indeed, users can create arbitrarily complex user options with @settings trees. Leo settings outlines are, in fact, much more flexible and powerful than any scheme based on flat text.
The myLeoSettings.leo file is a way of ensuring that your customized settings are not altered when updating Leo from cvs or while installing a new version of Leo. The myLeoSettings.leo acts much like Python's site-customize.py file. The myLeoSettings.leo file 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.
The Settings command opens the file leoSettings.leo.
Leo stores options in @settings trees, that is, parts of Leo outlines whose root node has the headline @settings. When opening a .leo file, Leo looks for @settings trees in the following places:
Settings that appear later in the above list override settings found earlier. For example, any setting specified in an @settings tree in the file being loaded overrides any setting seen in any leoSettings.leo file.
The following sections describe the kinds of nodes in @settings trees.
Organizer nodes have headlines that do no start with @. Organizer nodes may be inserted freely without changing the meaning of an @setting tree.
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 iff: h=g.computeMachineName(); h==hostA and h!=hostB. The "!" version allows matching to every machineName except the given one to allow differing settings on only a few machines.
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:
Important: you can use the show-colors minibuffer command to guide you in making these settings.
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 |
| @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. |
The actual settings are specified in the body text. At present, there are nine kinds of complex settings nodes:
@buttons
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.
@commands
New in Leo 4.4.8: 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.
@data
The body text contains a list of strings, one per line. Lines starting with '#' are ignored.
@enabled-plugins
The body text of the @enabled plugins node contains a list of enabled plugins, one per line. The first mention of a plugin controls whether the plugin is enabled or disabled. If the line starts with '#' the plugin is disabled. Otherwise the plugin is enabled.
Notes:
- Leo attempts to load all plugins every time an @enabled-plugins node is seen. If the plugin has already been loaded, Leo silently ignores the request to re-enable the plugin. Leo never attempts to disable a plugin while processing enabled plugin strings. Thus, plugins enabled in an @enabled-plugins node in leoSettings.leo will be enabled regardless of the contents of any other @enabled-plugins node.
- g.app.gui.getEnabledPlugins contains the last value last processed @enabled-plugins node.
- Leo no longer uses the pluginsManager.txt file.
@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.
@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.
The children of this node should be @menu and @item nodes, used as with @menus.
@menuat <path> <action> [<source>]
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.
path
This 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.
action
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.
source
By default the before, after, and append 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.
@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.
@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.
@shortcuts
The body text contains a list of shortcut specifiers.
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:
With all these options it should be possible to emulate the keyboard behavior of any other editor.
Leo's .leo file format is extensible. The basis for extending .leo files are the t.unknownAttributes and v.unknownAttributes ivars of tnodes and vnodes, or uA's for short. Leo translates between uA's and xml attributes in the corresponding <v> and <t> elements in .leo files. Plugins may also use v.tempAttributes or t.tempAttributes ivars to hold temporary information that will not be written to the .leo file.
Collectively, these four kinds of 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. For example, a plugin named 'xyzzy' would set t.unknownAttributes as follows:
# Create the uA if necessary.
if not hasattr(p.v.t,'unknownAttributes'):
p.v.t.unknownAttributes = {}
# Get the inner dictionary for the 'xyzzy' plugin, creating it if necessary.
d = p.v.t.unknownAttributes.get('xyzzy',{})
# Set some values. These values must be picklable.
d ['duration'] = 5
d ['notes'] = "This is a note."
# Update the uA.
p.v.t.unknownAttributes ['xyzzy'] = d
if hasattr(p.v.t,"unknownAttributes"):
d = p.v.t.unknownAttributes.get("xyzzy",{})
g.es(d['duration'])
g.es(d['notes'])
Plugins would use similar code to create v.unknownAttributes, t.tempAttributes, and v.tempAttributes ivars.
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.
Important: Plugins must not use v.unknownAttributes inside @thin trees. Indeed Leo uses hidden machinery to write t.unknownAttributes. Leo does not write t.unknownAttributes to thin derived files. Instead Leo writes a representation of all t.unknownAttributes contained in the @thin tree to a special xml attribute called descendentTnodeUnknownAttributes in the <v> element corresponding to the @thin node. Yes, this is complicated, but it works. Leo can not write v.unknownAttributes in @thin trees because only tnodes have gnx's in thin derived files. In effect, vnodes are anonymous.
Plugins that must associate attributes with vnodes should support only @file trees. A completely different alternative would be for the plugin to extend how Leo reads and writes <v> elements in .leo files, but that would be much more complicated than using t.unknownAttributes
Here are the details about how Leo associates uA's with <v> and <t> elements in .leo files:
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.
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: