The clone find commands, cfa and cff, move clones of all nodes matching the search pattern under a single organizer node, created as the last top-level node. Flattened searches put all nodes as direct children of the organizer node:
cfaclone-find-allcffclone-find-all-flattened
The clone-marked commands move clones of all marked nodes under an organizer node. Especially useful for gathering nodes by hand:
See the docstring of these plugins for more details:
bookmarks.pyManagesURL's used as bookmarks.contextmenu.pyCreatescontextmenusforheadlines.demo.pyCreatesdemosandslides.mod_scripting.pySupports@buttonand@commandnodes.quicksearch.pyAddsNavtabforsearching.todo.pyTo-dolistsandsimpleprojectmanagement.viewrendered.pyCreatesarenderingpane.AutomaticallyloadedbyLeo's help commands.Supports@graphics-script,@image,@html,@movieand@svgnodes.viewrendered3.pyAnenhancedversionofviewrendered3.py.vim.py&xemacs.pyInterfacewithvimandxemacs.
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:
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.
c.configc's configuration objectc.framec's outer frame, a leoFrame instance.c.undoerc's undo handler.c.user_dictAtemporarydictforuseofscriptsandplugins.
SubCommanders:
# In leo/core...c.atFileCommandsc.chapterControllerc.fileCommandsc.findCommandsc.importCommandsc.keyHandler=c.kc.persistenceControllerc.printingControllerc.rstCommandsc.shadowControllerc.tangleCommandsc.testManagerc.vimCommands# In leo/commands...c.abbrevCommandsc.controlCommandsc.convertCommandsc.debugCommandsc.editCommandsc.editFileCommandsc.gotoCommandsc.helpCommandsc.keyHandlerCommandsc.killBufferCommandsc.rectangleCommandsc.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()
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.
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.
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:forpinto_be_changed_nodes:# Change p.dirtyVnodeList.append(p.v)u.afterChangeNodeContents(p,undoType,bunch)changed=Trueifchanged:u.afterChangeGroup(c.p,undoType,reportFlag=False,dirtyVnodeList=dirtyVnodeList)
v.b:v's body text.v.gnxv's gnx.v.h:v's headline text.v.u:v.unknownAttributes,apersistentPythondictionary.
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.
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:
For full details, see @file leoGlobals.py in LeoPyRef.leo.
g vars
g.appg.app.guig.app.windowlistg.unitTestingg.user_dict# a temporary dict for use of scripts and plugins.
g decorator
@g.command(command-name)
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)
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.
A widget is an actual Qt widget. Leo’s core seldom accesses widgets directly. Instead, a wrapper class defines a standard api that hides the details of the underlying gui text widgets.
Leo’s core uses the wrapper api almost exclusively. That is, Leo’s core code treats wrappers as if they were only text widgets there are!
A back door exists for special cases. All wrapper classes define an official widget ivar, so core or plugin code can gain access to the real Qt widget using wrapper.widget. Searching for wrapper.widget will find all gui-dependent snippets of code in Leo’s core.
uA’s (user Attributes) associate arbitrary data with any vnode. uA’s are dictionaries of dictionaries–an outer dictionary and zero or more inner dictionaries. The outer dictionary associates plugin names (or Leo’s core) with inner dictionaries. The inner dictionaries carry the actual data.
The v.u or p.v properties get and set uA’s. You can think of p.u as a synonym for p.v.unknownAttributes on both sides of an assignment. For example:
This is a typical usage of Leo’s generators. Generators visit each position (or node) quickly. Even if you aren’t going to program much, you should be aware of how easy it is to get and set the data in each node. In fact, now would be a great time to read Leo’s Scripting Tutorial again :-) This will allow you to “dream bigger” with Leo.
The following script creates a list of all positions having an icon, that is, an outer uA dict with a ‘icon’ key:
Important: If you don’t understand these lines, please study Python’s list comprehensions. They are incredibly useful. ‘n’.join(aList) is a great idiom to know. str.join is one of python’s most useful string methods. It converts between lists and strings.
The predicate could filter on an attribute or combination of attributes. For example, the predicate could return p has attributes A and B but not attribute C. This instantly gives Leo full database query capabilities. If we then hoist the resulting node we see all and only those nodes satisfying the query.
These following position methods make it easy to skip @ignore trees or @<file> trees containing @all:
Controller: The Commands class and its helpers in leoCommands.py and leoEditCommands.py.
Model: The VNode and Position classes in leoNodes.py.
View: The gui-independent base classes are in the node “Gui Base Classes”. The Qt-Specific subclasses are in the node “Qt gui”.
Important: The general organization of these classes have changed hardly at all in Leo’s 20+ year history. The reason is that what each class does is fairly obvious. How the gets the job done may have changed drastically, but that’s an internal implementation detail of the class itself. This is the crucial design principle that allows Leo’s code to remain stable. Classes do not know or meddle in the internal details of other classes. As a result, nobody, including EKR, needs to remember internal details.
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