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
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.
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. |
@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 seven 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. This body text is treated exactly as the contents of the pluginsManager.txt file. 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.
- Leo will read the pluginsManager.txt file only if no @enabled-plugins node is found. The pluginsManager.txt file will no longer be part of the Leo distribution. Instead, the default plugins will be enabled in an @enabled-plugins node in leoSettings.leo.
- g.app.gui.getEnabledPlugins contains the last value last processed @enabled-plugins node, or the contents of the first pluginsManager.txt file encountered.
@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 and @item 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.
@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.