This Cheat Sheet contains a summary of many of Leo’s important features.
Important: The easiest way to find documentation is to search LeoDocs.leo.
Alt-X puts focus in the minibuffer. Ctrl-G escapes from the minibuffer.
Once there, you can use tab completion to reduce typing. For example, <Alt-X>open<tab>
shows all commands that start with open.
Hit <Enter>
to run a complete command.
Ctrl-P
(repeat-complex-command
) repeats the last command entered from the minibuffer.
Leo maintains a command history list of all minibuffer commands you have entered.
When focus is in the minibuffer, UpArrow
shows the previous minibuffer command, and DnArrow
show the commands before that.
The body text of an @data history-list
setting node preloads commands into the command history list, ignoring lines starting with #
. For example:
run-pylint
beautify-tree
cff
sort-lines
# show-data
check-clones
expand-log-pane
contract-log-pane
@<file> nodes create external files:
@asis <filename> write only, no sentinels, exact line endings
@auto <filename> recommended
@clean <filename> recommended
@edit <filename> @edit node contains entire file
@file <filename> recommended
@nosent <filename> write only, no sentinels
This table summarizes the differences between @<file> nodes:
Sections & File data in
@<file> kind Sentinels? @others? .leo file? Notes
------------ ---------- ----------- ------------ -----
@asis no no yes
@auto no yes no 1, 2
@auto-xx no yes no 1, 2
@clean no yes yes
@edit no no no
@file yes yes no
@nosent no yes yes
@auto nodes read files using language-specific importers.
By default, the file’s extension determines the importer:
Extensions Importer
---------- --------
.c, .cc, .c++, .cpp,.cxx C
.cs', .c#' C Sharp
.el Elisp
.h, .h++ C
.html, .htm HTML
.ini Config file
.ipynb Jupyter notebook
.java Java
.js JavaScript
.md Markdown
.org Org Mode
.otl Vim outline
.pas Pascal
.php PHP
.py, .pyi, .pyw Python
.rest, .rst reStructuredText
.ts TypeScript
.xml XML
You can also specify importers explicitly as follows:
@auto-xxx Importer
--------- --------
@auto-ctext ctext
@auto-markdown markdown
@auto-md markdown
@auto-org org-mode
@auto-org-mode org-mode
@auto-otl vimoutline
@auto-vim-outline vimoutline
@auto-rst reStructuredText
Important: The importers/exporters for markdown, org-mode, reStructuredText and vimoutline files automatically generate section headings corresponding to Leo’s outline level. Body text of the top-level @auto node is ignored.
See the Directives reference for full details.
This section lists the ivars (instance variables), properties, functions and methods most commonly used in Leo scripts.
Very important: use Alt-1 (toggle-autocompleter) and Alt-2 (toggle-calltips) to recreate these lists as you type.
execute-script predefines:
c: The commander of the present outline.
g: The leo.core.leoGlobals module.
p: The presently selected position, c.p.
Ivars:
g.app A LeoApp instance.
g.app.gui A LeoGui instance.
g.app.pluginsController A LeoPluginsController instance.
g.app.* Leo's global variables.
Ivars:
c.config c's configuration object
c.frame c's outer frame, a leoFrame instance.
c.undoer c's undo handler.
c.user_dict A temporary dict for use of scripts and plugins.
SubCommanders:
# In leo/core...
c.atFileCommands
c.chapterController
c.fileCommands
c.findCommands
c.importCommands
c.keyHandler = c.k
c.persistenceController
c.printingController
c.rstCommands
c.shadowController
c.tangleCommands
c.testManager
c.vimCommands
# In leo/commands...
c.abbrevCommands
c.controlCommands
c.convertCommands
c.debugCommands
c.editCommands
c.editFileCommands
c.gotoCommands
c.helpCommands
c.keyHandlerCommands
c.killBufferCommands
c.rectangleCommands
c.spellCommands
Generators (New in Leo 5.5: All generators yield distinct positions):
c.all_positions()
c.all_unique_positions()
Most useful methods:
c.isChanged()
c.deletePositionsInList(aList, callback=None)
# safely deletes all the positions in aList.
c.positionExists(p)
c.redraw(p=None) # Redraw the screen. Select p if given.
c.save() # Save the present outline.
c.selectPosition()
Using Command names
When learning Leo’s codebase, it may be easier to refer to a command by its ‘command name’. You can therefore use c.doCommandByName(‘command-name’) instead of calling the proper method on the commander. This will return the same value as that method.
Leo Script Return Values
Commands created with @command and @button nodes can return values as well. Since top-level return statements aren’t allowed in scripts executed with exec, you can define a global variable named result, and Leo will return its value:
global result
result = 42
Official ivars of any leoFrame f:
f.c is the frame’s commander.
f.body is a leoBody instance.
f.body.bodyCtl is a leoQTextEditWidget instance.
f.body.bodyCtrl.widget is a LeoQTextBrowser(QTextBrowser) instance.
f.log is a leoLog instance.
f.tree is a leoQtTree instance.
f.tree.treeWidget is a LeoQTreeWidget (a QTreeWidget) instance.
Use autocompletion to explore these objects!
If you want to make a command undoable, you must create “before” and “after” snapshots of the parts of the outline that may change. Here are some examples. Leo’s source code contains many other examples.
To undo a single change to body text:
command = 'my-command-name'
b = c.undoer.beforeChangeNodeContents(p, oldYScroll=ypos)
# Change p's body text.
c.undoer.afterChangeNodeContents(p,
command=command, bunch=b, dirtyVnodeList=[])
If your command changes multiple nodes, the pattern is:
u, undoType = c.undoer, 'command-name'
u.beforeChangeGroup(c.p, undoType)
dirtyVnodeList = []
changed = False
# For each change, do something like the following:
for p in to_be_changed_nodes:
# Change p.
dirtyVnodeList.append(p.v)
u.afterChangeNodeContents(p, undoType, bunch)
changed = True
if changed:
u.afterChangeGroup(c.p, undoType,
reportFlag=False,
dirtyVnodeList=dirtyVnodeList)
Ivars:
v.b: v's body text.
v.gnx v's gnx.
v.h: v's headline text.
v.u: v.unknownAttributes, a persistent Python dictionary.
v.u (uA’s or unknownAttributes or userAttributes) allow plugins or scripts
to associate persistent data with vnodes. For details see the section about
userAttributes in the Customizing Leo chapter.
Important: Generally speaking, vnode properties are fast, while the
corresponding position properties are much slower. Nevertheless, scripts
should usually use position properties rather than vnode properties
because the position properties handle recoloring and other details.
Scripts should use vnode properties only when making batch changes to
vnodes.
Properties
p.b: same as p.v.b. *Warning*: p.b = s is expensive.
p.h: same as p.v.h. *Warning*: p.h = s is expensive.
p.u: same as p.v.u.
Generators (New in Leo 5.5: All generators yield distinct positions)
p.children()
p.parents()
p.self_and_parents()
p.self_and_siblings()
p.following_siblings()
p.subtree()
p.self_and_subtree()
Getters These return new positions
p.back()
p.children()
p.copy()
p.firstChild()
p.hasBack()
p.hasChildren()
p.hasNext()
p.hasParent()
p.hasThreadBack()
p.hasThreadNext()
p.isAncestorOf(p2)
p.isAnyAtFileNode()
p.isAt...Node()
p.isCloned()
p.isDirty()
p.isExpanded()
p.isMarked()
p.isRoot()
p.isVisible()
p.lastChild()
p.level()
p.next()
p.nodeAfterTree()
p.nthChild()
p.numberOfChildren()
p.parent()
p.parents()
p.threadBack()
p.threadNext()
p.visBack()
p.visNext()
Setters
p.setDirty() *Warning*: p.setDirty() is expensive.
p.setMarked()
Operations on nodes
p.clone()
p.contract()
p.doDelete(new_position)
p.expand()
p.insertAfter()
p.insertAsNthChild(n)
p.insertBefore()
p.moveAfter(p2)
p.moveToFirstChildOf(parent,n)
p.moveToLastChildOf(parent,n)
p.moveToNthChildOf(parent,n)
p.moveToRoot(oldRoot=None)
# oldRoot **must** be the old root position if it exists.
Moving positions
The following move positions themselves: they change the node to which a
position refers. They do not change outline structure in any way! Use
these when generators are not flexible enough:
p.moveToBack()
p.moveToFirstChild()
p.moveToLastChild()
p.moveToLastNode()
p.moveToNext()
p.moveToNodeAfterTree(p2)
p.moveToNthChild(n)
p.moveToParent()
p.moveToThreadBack()
p.moveToThreadNext()
p.moveToVisBack(c)
p.moveToVisNext(c)
For full details, see @file leoGlobals.py in LeoPyRef.leo.
g vars
g.app
g.app.gui
g.app.windowlist
g.unitTesting
g.user_dict # a temporary dict for use of scripts and plugins.
g decorator
g functions (the most interesting: there are many more in leoGlobals.py)
g.angleBrackets()
g.app.commanders()
g.app.gui.guiName()
g.es(*args,**keys)
g.es_print(*args,**keys)
g.es_exception()
g.getScript(c,p,
useSelectedText=True,
forcePythonSentinels=True,
useSentinels=True)
g.openWithFileName(fileName,old_c=None,gui=None)
g.os_path_... # Wrappers for os.path methods.
g.pdb(message='')
g.toEncodedString(s,encoding='utf-8',reportErrors=False)
g.toUnicode(s, encoding='utf-8',reportErrors=False)
g.trace(*args,**keys)
g.warning(*args,**keys)
@g.command('i1')
def i1_command(event):
c = event.get('c')
if not c: return
def callback(args, c, event):
g.trace(args)
c.bodyWantsFocus()
c.interactive(callback, event, prompts=['Prompt: '])
@g.command('i2')
def i2_command(event):
c = event.get('c')
if not c: return
def callback(args, c, event):
g.trace(args)
c.bodyWantsFocus()
c.interactive(callback, event,
prompts=['Find: ', ' Replace: '])
@g.command('i3')
def i3_command(event):
c = event.get('c')
if not c: return
def callback(args, c, event):
g.trace(args)
c.bodyWantsFocus()
c.interactive(callback, event,
prompts=['One: ', ' Two: ', ' Three: '])
LeoPyRef.leo
contains all of Leo’s core source code.
Leo’s code uses the following conventions throughout:
c: a commander.
ch: a character.
d: a dialog or a dict.
f: an open file.
fn: a file name.
g: the leoGlobals module.
i, j, k: indices into a string.
p: a Position.
s: a string.
t: a text widget.
u: an undoer.
w: a gui widget.
v: a Vnode
z: a local temp.
In more limited contexts, the following conventions apply:
si: a g.ShortcutInfo object.
ks: a g.KeyStroke object
stroke: a KeyStroke object.
btw: leoFrame.BaseTextWrapper
stw: leoFrame.StringTextWrapper
bqtw: qt_text.BaseQTextWrapper
lqtb: qt_text.LeoQTextBrowser
qhlw: qt_text.QHeadlineWrapper
qmbw: qt_text.QMinibufferWrapper
qlew: qt_text.QLineEditWrapper
qsciw: qt_text.QScintiallaWrapper
qtew: qt_text.QTextEditWrapper
Names defined in Leo’s core are unlikely to change, especially names used outside their defining module. This includes virtually everything in leoGlobals.py
, and many names in leoCommands.py
and other files.
The following ‘official’ ivars (instance vars) will always exist:
c.frame The frame containing the log,body,tree, etc.
c.frame.body The body pane.
c.frame.body.widget The gui widget for the body pane.
c.frame.body.wrapper The high level interface for the body widget.
c.frame.iconBar The icon bar.
c.frame.log The log pane.
c.frame.log.widget The gui widget for the log pane.
c.frame.log.wrapper The high-level interface for the log pane.
c.frame.tree The tree pane.
The following were official ivars that no longer exist:
c.frame.body.bodyCtrl Use c.frame.body.wrapper instead.
c.frame.log.logCtrl Use c.frame.log.wrapper instead.
Leo syntax colors clickable links in the body pane. For example:
Leo’s home page: https://leo-editor.github.io/leo-editor/
The status area shows the UNL (Universal Node Locator) for each node.
Control-clicking a UNL will take you to its target node, even if the target is in another Leo file!
gnx-based UNLs won’t break even if you move or rename the target node.
Try these examples!
The “Key bindings” node in this file:
unl:gnx://CheatSheet.leo#ekr.20131019184243.16685
The “6.7.5 release notes” node in LeoDocs.leo.
unl:gnx://LeoDocs.leo#ekr.20230703101804.1