<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet ekr_test?>
<leo_file>
<leo_header file_format="2" tnodes="0" max_tnode_index="0" clone_windows="0"/>
<globals body_outline_ratio="0.5">
	<global_window_position top="48" left="3" height="692" width="1018"/>
	<global_log_window_position top="0" left="0" height="0" width="0"/>
</globals>
<preferences/>
<find_panel_settings/>
<vnodes>
<v t="ekr.20080129151228"><vh>Startup</vh>
<v t="ekr.20080129151123"><vh>@chapters</vh></v>
<v t="ekr.20070315073704"><vh>@settings</vh>
<v t="ekr.20070315073704.1"><vh>@enabled-plugins</vh></v>
<v t="ekr.20091104114053.3903"><vh>@bool warn_about_redefined_shortcuts = False</vh></v>
<v t="ekr.20070315073704.2"><vh>vim plugin</vh>
<v t="ekr.20070315073704.3"><vh>@string vim_cmd = c:\vim\vim63\gvim --servername LEO</vh></v>
<v t="ekr.20070315073704.4"><vh>@string vim_exe = c:\vim\vim63\gvim</vh></v>
</v>
</v>
<v t="ekr.20060901144246"><vh>buttons</vh>
<v t="ekr.20091110142807.2083"><vh>@button Remove newlines</vh></v>
<v t="ekr.20060901144331"><vh>@@button prev-show  @key=Alt-4</vh></v>
<v t="ekr.20060901144149.3"><vh>@@button next-show  @key=Alt-5</vh></v>
<v t="ekr.20060901144149.2"><vh>@@button prev-slide @key=Alt-6</vh></v>
<v t="ekr.20060901144359"><vh>@@button next-slide @key=Alt-7</vh></v>
<v t="ekr.20060902092242"><vh>@@button make-slide @key=Alt-0</vh></v>
</v>
<v t="ekr.20091110090536.1729"><vh>Dummy clones for slide show: do not delete!</vh>
<v t="ekr.20091110090536.1724"><vh> treeSelectHelper</vh></v>
<v t="ekr.20091110090536.1722"><vh>contractNode</vh></v>
<v t="ekr.20091110090536.1720"><vh>contractNodeOrGoToParent</vh></v>
<v t="ekr.20091110090536.1723"><vh>expandNode</vh></v>
<v t="ekr.20091110090536.1721"><vh>expandNodeAnd/OrGoToFirstChild</vh></v>
<v t="ekr.20091110090536.1719"><vh>goToParent</vh></v>
<v t="ekr.20091110090536.1725"><vh>p.moveToVisBack</vh>
<v t="ekr.20091110090536.1726"><vh>checkVisBackLimit</vh></v>
</v>
<v t="ekr.20091110090536.1727"><vh>p.moveToVisNext</vh>
<v t="ekr.20091110090536.1728"><vh>checkVisNextLimit</vh></v>
</v>
<v t="ekr.20091110090536.1718"><vh>selectVisBack</vh></v>
<v t="ekr.20091110090536.1717"><vh>selectVisNext</vh></v>
</v>
</v>
<v t="ekr.20091109103928.1545"><vh>Other</vh>
<v t="ekr.20060901144149.4"><vh>Sounds</vh>
<v t="ekr.20060901144149.5"><vh>@url http://mail.python.org/pipermail/python-list/2004-October/248738.html</vh></v>
<v t="ekr.20060901144149.6"><vh>@url c:\prog\Sounds\s1.wav</vh></v>
<v t="ekr.20060901144149.7"><vh>@url c:\prog\Sounds\s2.wav</vh></v>
</v>
<v t="ekr.20060902092259"><vh>Scripting with Leo (do not delete)</vh>
<v t="ekr.20060902092341.4"><vh>Leo's classes and objects</vh>
<v t="ekr.20091103090815.1427"><vh>c, g and p</vh></v>
<v t="ekr.20091103090815.1428"><vh>g.app</vh></v>
<v t="ekr.20091103090815.1429"><vh>commanders: c</vh></v>
<v t="ekr.20091103090815.1431"><vh>frames: c.frame, c.frame.body, etc.</vh></v>
<v t="ekr.20091103090815.1430"><vh>positions and iterators</vh></v>
<v t="ekr.20091103090815.1432"><vh>vnodes</vh></v>
</v>
<v t="ekr.20091103090815.1433"><vh>Useful methods</vh>
<v t="ekr.20060902092341.5"><vh>g.es writes to the log tab</vh></v>
<v t="ekr.20091103090815.1426"><vh>g.es can write to other tabs</vh></v>
<v t="ekr.20060902092341.6"><vh>app.windowList: the list of all open frames</vh></v>
<v t="ekr.20060902092341.7"><vh>Getting and setting headline and body text</vh></v>
<v t="ekr.20060902092341.9"><vh>Copying positions</vh></v>
<v t="ekr.20060902092341.8"><vh>Traversing outlines with generators.</vh>
<v t="ekr.20060902092341.10"><vh>c.all_positions</vh></v>
<v t="ekr.20060902092341.11"><vh>p.children_iter</vh></v>
<v t="ekr.20060902092341.12"><vh>p.parents_iter &amp; p.self_and_parents_iter</vh></v>
<v t="ekr.20060902092341.13"><vh>p.siblings_iter &amp; p.following_siblings_iter</vh></v>
<v t="ekr.20060902092341.14"><vh>p.subtree_iter &amp; p.self_and_subtree_iter</vh></v>
<v t="ekr.20060902092341.15"><vh>Testing whether a position is valid</vh></v>
</v>
<v t="ekr.20060902092341.16"><vh>Updating the screen</vh></v>
<v t="ekr.20060902092341.17"><vh>Invoking commands from scripts</vh></v>
<v t="ekr.20060902092341.18"><vh>Getting settings from @settings trees</vh></v>
<v t="ekr.20060902092341.19"><vh>Getting and setting preferences</vh></v>
<v t="ekr.20060902092341.20"><vh>Functions for finding and changing text from scripts</vh></v>
<v t="ekr.20060902092341.21"><vh>Running Leo in batch mode</vh></v>
<v t="ekr.20060902092341.22"><vh>Functions defined in leoGlobals.py</vh></v>
<v t="ekr.20060902092341.23"><vh>Redirecting output from scripts</vh></v>
<v t="ekr.20060902092341.24"><vh>Adding new Tabs to the log pane</vh></v>
<v t="ekr.20060902092341.25"><vh>Summary of the vnode and position classes</vh>
<v t="ekr.20060902092341.26"><vh>Iterators</vh></v>
<v t="ekr.20060902092341.27"><vh>Getters</vh></v>
<v t="ekr.20060902092341.28"><vh>Setters</vh></v>
</v>
<v t="ekr.20060902092341.29"><vh>Creating script buttons</vh></v>
<v t="ekr.20060902092341.30"><vh>\@test and @suite nodes</vh>
<v t="ekr.20060902095933"><vh>\@test nodes</vh></v>
<v t="ekr.20060902095933.1"><vh>\@suite nodes</vh></v>
</v>
<v t="ekr.20060902100250"><vh>conclusion</vh></v>
</v>
</v>
<v t="ekr.20060901153101"><vh>Introducing Leo (old)</vh>
<v t="ekr.20091107071654.1488"><vh>Leo looks like an ordinary outliner</vh></v>
<v t="ekr.20091107093823.6816"><vh>But no other program can do what Leo does</vh></v>
<v t="ekr.20091107071654.1501"><vh>Leo outlines shows you your data *your* way</vh>
<v t="ekr.20091107093823.6820"><vh>@url file:c:\leo.repo\trunk\leo\core\leoPy.leo --&gt; Projects</vh></v>
</v>
<v t="ekr.20091107071654.1502"><vh>Leo scripts create new ways to handle data</vh>
<v t="ekr.20091107071654.1503"><vh>Any node can contain a Python script</vh></v>
<v t="ekr.20091107071654.1506"><vh>Leo scripts have full access to outline data</vh>
<v t="ekr.20091107093823.1471"><vh>Some example scripts</vh>
<v t="ekr.20091107071654.1512"><vh>A first script</vh></v>
<v t="ekr.20091107071654.1513"><vh>It is easy to access nodes</vh></v>
<v t="ekr.20091107093823.1470"><vh>It is easy to traverse Leo outines</vh></v>
</v>
</v>
<v t="ekr.20091107071654.1507"><vh>The execute-script command *composes* scripts from outlines</vh>
<v t="ekr.20091107093823.6812"><vh>This script is formed from a tree</vh>
<v t="ekr.20091107093823.6813"><vh>class myClass</vh>
<v t="ekr.20091107093823.6814"><vh>printHi</vh></v>
</v>
</v>
</v>
<v t="ekr.20091107093823.6815"><vh>Leo can compose external files from outlines</vh>
<v t="ekr.20091107071654.1514"><vh>@thin ..\test\slide-show-file.py</vh></v>
<v t="ekr.20091107142231.6263"><vh>Execute slide-show-file.py</vh></v>
</v>
<v t="ekr.20091107093823.6808"><vh>You can apply scripts to data</vh></v>
<v t="ekr.20091107093823.1465"><vh>Nodes can be typed</vh>
<v t="ekr.20091107093823.1468"><vh>@html Leo's home page</vh></v>
</v>
</v>
<v t="ekr.20091107093823.6818"><vh>Leo changes how I work</vh>
<v t="ekr.20091107071654.1511"><vh>Some tasks disappear</vh></v>
<v t="ekr.20091107093823.1469"><vh>More interesting tasks arise</vh></v>
</v>
<v t="ekr.20091107093823.6819"><vh>Leo plays well with others</vh></v>
<v t="ekr.20091107071654.1493"><vh>Conclusions</vh></v>
</v>
<v t="ekr.20091110090536.1640"><vh>What people do with Leo</vh>
<v t="ekr.20091110090536.1641"><vh>Understand complex programs more easily</vh></v>
<v t="ekr.20091110090536.1642"><vh>Organize scripts</vh></v>
<v t="ekr.20091110090536.1643"><vh>Manage web sites</vh>
<v t="ekr.20091110090536.1644"><vh>@url http://webpages.charter.net/edreamleo/leo_toc.html</vh></v>
</v>
<v t="ekr.20091110090536.1645"><vh>Store scientific data</vh></v>
</v>
<v t="ekr.20091110090536.1731"><vh>Views *are* mathematical relations</vh></v>
<v t="ekr.20091117082920.12019"><vh>@image Lion image</vh></v>
<v t="ekr.20091117093857.2639"><vh>@image C:\leo.repo\trunk\leo\Icons\Lioness.jpg</vh></v>
<v t="ekr.20091117093857.2637"><vh>@html Lion image</vh></v>
<v t="ekr.20091110090536.1636"><vh>15-20 minutes: Introducing Leo (OLD)</vh>
<v t="ekr.20091116094116.2587"><vh>What people are saying about Leo</vh>
<v t="ekr.20091116094116.2588"><vh>Leo is revolutionary</vh></v>
<v t="ekr.20091116094116.2589"><vh>Leo is fun, even addicting</vh></v>
<v t="ekr.20091116094116.2590"><vh>Leo is a great outliner</vh></v>
<v t="ekr.20091116094116.2591"><vh>Leo is a great programming tool</vh></v>
<v t="ekr.20091116094116.2592"><vh>Leo is a great PIM</vh></v>
<v t="ekr.20091116094116.2593"><vh>Leo is a great documentation tool</vh></v>
<v t="ekr.20091116094116.2594"><vh>Leo clarifies complex systems</vh></v>
</v>
<v t="ekr.20091110090536.1604"><vh>Leo's screen</vh></v>
<v t="ekr.20091110090536.1695"><vh>What makes Leo special?</vh>
<v t="ekr.20091110090536.2171"><vh>1. Leo outlines</vh>
<v t="ekr.20091110090536.1696"><vh>Clones make Leo outlines special</vh>
<v t="ekr.20091110090536.1697"><vh>Clones are nodes appearing in several places in the outline</vh>
<v t="ekr.20091110090536.1698"><vh>A</vh>
<v t="ekr.20091110090536.1699"><vh>B</vh>
<v t="ekr.20091110090536.1700"><vh>C</vh></v>
<v t="ekr.20091110090536.1701"><vh>D</vh></v>
</v>
</v>
<v t="ekr.20091110090536.1698"></v>
</v>
<v t="ekr.20091110090536.1702"><vh>Clones create multiple views of data</vh>
<v t="ekr.20091110090536.1730"><vh>Here is an example of a view</vh>
<v t="ekr.20091110090536.1716"><vh>Fixed contractOrGoRight</vh>
<v t="ekr.20091110104908.2105"><vh>The bug</vh></v>
<v t="ekr.20091110104908.2106"><vh>What I did</vh></v>
<v t="ekr.20091110090536.1717"></v>
<v t="ekr.20091110090536.1718"></v>
<v t="ekr.20091110090536.1719"></v>
<v t="ekr.20091110090536.1720"></v>
<v t="ekr.20091110090536.1721"></v>
<v t="ekr.20091110090536.1722"></v>
<v t="ekr.20091110090536.1723"></v>
<v t="ekr.20091110090536.1724"></v>
<v t="ekr.20091110090536.1725"></v>
<v t="ekr.20091110090536.1727"></v>
</v>
</v>
<v t="ekr.20091110104908.2104"><vh>There is no such thing as *the* right view of data</vh></v>
</v>
</v>
<v t="ekr.20091110090536.1732"><vh>Outlines can represent external files</vh>
<v t="ekr.20091110090536.1951"><vh>@@thin leoNodes.py</vh>
<v t="ekr.20091110090536.1952"><vh>&lt;&lt; imports &gt;&gt;</vh></v>
<v t="ekr.20091110090536.1953"><vh>class vnode</vh>
<v t="ekr.20091110090536.1954"><vh>&lt;&lt; vnode constants &gt;&gt;</vh></v>
<v t="ekr.20091110090536.1955"><vh>v.Birth &amp; death</vh>
<v t="ekr.20091110090536.1956"><vh>v.__init</vh></v>
<v t="ekr.20091110090536.1957"><vh>v.__repr__ &amp; v.__str__</vh></v>
<v t="ekr.20091110090536.1958"><vh>v.dump</vh></v>
<v t="ekr.20091110090536.1959"><vh>v.__hash__ (only for zodb)</vh></v>
</v>
<v t="ekr.20091110090536.1960"><vh>v.Comparisons</vh>
<v t="ekr.20091110090536.1961"><vh>v.findAtFileName</vh></v>
<v t="ekr.20091110090536.1962"><vh>anyAtFileNodeName</vh></v>
<v t="ekr.20091110090536.1963"><vh>at...FileNodeName &amp; tests</vh>
<v t="ekr.20091110090536.1964"><vh>@test v.atAutoNodeName &amp; v.atAutoRstNodeName</vh></v>
</v>
<v t="ekr.20091110090536.1965"><vh>isAtAllNode</vh></v>
<v t="ekr.20091110090536.1966"><vh>isAnyAtFileNode</vh></v>
<v t="ekr.20091110090536.1967"><vh>isAt...FileNode (vnode)</vh></v>
<v t="ekr.20091110090536.1968"><vh>isAtIgnoreNode</vh></v>
<v t="ekr.20091110090536.1969"><vh>isAtOthersNode</vh></v>
<v t="ekr.20091110090536.1970"><vh>matchHeadline</vh></v>
</v>
<v t="ekr.20091110090536.1971"><vh>v.Getters</vh>
<v t="ekr.20091110090536.1972"><vh>v.bodyString</vh></v>
<v t="ekr.20091110090536.1973"><vh>v.Children</vh>
<v t="ekr.20091110090536.1974"><vh>v.firstChild</vh></v>
<v t="ekr.20091110090536.1975"><vh>v.hasChildren &amp; hasFirstChild</vh></v>
<v t="ekr.20091110090536.1976"><vh>v.lastChild</vh></v>
<v t="ekr.20091110090536.1977"><vh>v.nthChild</vh></v>
<v t="ekr.20091110090536.1978"><vh>v.numberOfChildren</vh></v>
</v>
<v t="ekr.20091110090536.1979"><vh>v.directParents</vh></v>
<v t="ekr.20091110090536.1980"><vh>v.hasBody</vh></v>
<v t="ekr.20091110090536.1981"><vh>v.headString &amp; v.cleanHeadString</vh></v>
<v t="ekr.20091110090536.1982"><vh>v.Status Bits</vh>
<v t="ekr.20091110090536.1983"><vh>v.isCloned</vh></v>
<v t="ekr.20091110090536.1984"><vh>v.isDirty</vh></v>
<v t="ekr.20091110090536.1985"><vh>v.isExpanded</vh></v>
<v t="ekr.20091110090536.1986"><vh>v.isMarked</vh></v>
<v t="ekr.20091110090536.1987"><vh>v.isOrphan</vh></v>
<v t="ekr.20091110090536.1988"><vh>v.isSelected</vh></v>
<v t="ekr.20091110090536.1989"><vh>v.isTopBitSet</vh></v>
<v t="ekr.20091110090536.1990"><vh>v.isVisited</vh></v>
<v t="ekr.20091110090536.1991"><vh>v.isWriteBit</vh></v>
<v t="ekr.20091110090536.1992"><vh>v.status</vh></v>
</v>
</v>
<v t="ekr.20091110090536.1993"><vh>v.Setters</vh>
<v t="ekr.20091110090536.1994"><vh> v.Dirty bits</vh>
<v t="ekr.20091110090536.1995"><vh>v.clearDirty</vh></v>
<v t="ekr.20091110090536.1996"><vh>v.findAllPotentiallyDirtyNodes</vh></v>
<v t="ekr.20091110090536.1997"><vh>v.setAllAncestorAtFileNodesDirty</vh></v>
<v t="ekr.20091110090536.1998"><vh>v.setDirty</vh></v>
</v>
<v t="ekr.20091110090536.1999"><vh> v.Status bits</vh>
<v t="ekr.20091110090536.2000"><vh>v.clearClonedBit</vh></v>
<v t="ekr.20091110090536.2001"><vh>v.clearMarked</vh></v>
<v t="ekr.20091110090536.2002"><vh>v.clearWriteBit</vh></v>
<v t="ekr.20091110090536.2003"><vh>v.clearOrphan</vh></v>
<v t="ekr.20091110090536.2004"><vh>v.clearVisited</vh></v>
<v t="ekr.20091110090536.2005"><vh>v.contract &amp; expand &amp; initExpandedBit</vh></v>
<v t="ekr.20091110090536.2006"><vh>v.initStatus</vh></v>
<v t="ekr.20091110090536.2007"><vh>v.setClonedBit &amp; initClonedBit</vh></v>
<v t="ekr.20091110090536.2008"><vh>v.setMarked &amp; initMarkedBit</vh></v>
<v t="ekr.20091110090536.2009"><vh>v.setOrphan</vh></v>
<v t="ekr.20091110090536.2010"><vh>v.setSelected</vh></v>
<v t="ekr.20091110090536.2011"><vh>v.setVisited</vh></v>
<v t="ekr.20091110090536.2012"><vh>v.setWriteBit</vh></v>
</v>
<v t="ekr.20091110090536.2013"><vh>v .setBodyString &amp; v.setHeadString</vh></v>
<v t="ekr.20091110090536.2014"><vh>v.setFileIndex</vh></v>
<v t="ekr.20091110090536.2015"><vh>v.computeIcon &amp; setIcon</vh></v>
<v t="ekr.20091110090536.2016"><vh>v.setSelection</vh></v>
</v>
<v t="ekr.20091110090536.2017"><vh>v.Low level methods</vh>
<v t="ekr.20091110090536.2018"><vh>v._addLink &amp; helper</vh>
<v t="ekr.20091110090536.2019"><vh>v._addParentLinks</vh></v>
</v>
<v t="ekr.20091110090536.2020"><vh>v._cutLink</vh>
<v t="ekr.20091110090536.2021"><vh>v._cutParentLinks</vh></v>
</v>
<v t="ekr.20091110090536.2022"><vh>v._linkAsNthChild (used by 4.x read logic)</vh></v>
<v t="ekr.20091110090536.2023"><vh>v.createOutlineFromCacheList &amp; helpers</vh>
<v t="ekr.20091110090536.2024"><vh>v.fastAddLastChild</vh></v>
</v>
</v>
<v t="ekr.20091110090536.2025"><vh>v.Properties</vh>
<v t="ekr.20091110090536.2026"><vh>v.b Property</vh></v>
<v t="ekr.20091110090536.2027"><vh>v.h property</vh></v>
<v t="ekr.20091110090536.2028"><vh>v.u Property</vh></v>
<v t="ekr.20091110090536.2029"><vh>v.gnx Property</vh></v>
</v>
</v>
<v t="ekr.20091110090536.2030"><vh>class nodeIndices</vh>
<v t="ekr.20091110090536.2031"><vh>nodeIndices.__init__</vh></v>
<v t="ekr.20091110090536.2032"><vh>areEqual (no longer used)</vh></v>
<v t="ekr.20091110090536.2033"><vh>get/setDefaultId</vh></v>
<v t="ekr.20091110090536.2034"><vh>getNewIndex</vh></v>
<v t="ekr.20091110090536.2035"><vh>isGnx (not used)</vh></v>
<v t="ekr.20091110090536.2036"><vh>scanGnx</vh></v>
<v t="ekr.20091110090536.2037"><vh>setTimeStamp</vh></v>
<v t="ekr.20091110090536.2038"><vh>toString</vh></v>
</v>
<v t="ekr.20091110090536.2039"><vh>class position</vh>
<v t="ekr.20091110090536.2040"><vh>&lt;&lt; about the position class &gt;&gt;</vh></v>
<v t="ekr.20091110090536.2041"><vh> p.ctor &amp; other special methods...</vh>
<v t="ekr.20091110090536.2042"><vh> p.__init__</vh></v>
<v t="ekr.20091110090536.2043"><vh>p.__eq__ &amp; __ne__</vh></v>
<v t="ekr.20091110090536.2044"><vh>p.__getattr__ (no longer used)</vh></v>
<v t="ekr.20091110090536.2045"><vh>p.__nonzero__ &amp; __bool__</vh></v>
<v t="ekr.20091110090536.2046"><vh>p.__str__ and p.__repr__</vh></v>
<v t="ekr.20091110090536.2047"><vh>p.archivedPosition</vh></v>
<v t="ekr.20091110090536.2048"><vh>p.copy</vh></v>
<v t="ekr.20091110090536.2049"><vh>p.dump</vh></v>
<v t="ekr.20091110090536.2050"><vh>p.key</vh></v>
</v>
<v t="ekr.20091110090536.2051"><vh>p.Properties</vh>
<v t="ekr.20091110090536.2052"><vh>p.b property</vh></v>
<v t="ekr.20091110090536.2053"><vh>p.h property</vh></v>
<v t="ekr.20091110090536.2054"><vh>p.gnx property</vh></v>
</v>
<v t="ekr.20091110090536.2055"><vh>p.Getters</vh>
<v t="ekr.20091110090536.2056"><vh>p.vnode proxies</vh>
<v t="ekr.20091110090536.2057"><vh>p.Comparisons</vh></v>
<v t="ekr.20091110090536.2058"><vh>p.Headline &amp; body strings</vh></v>
<v t="ekr.20091110090536.2059"><vh>p.Status bits</vh></v>
</v>
<v t="ekr.20091110090536.2060"><vh>p.children &amp; parents</vh>
<v t="ekr.20091110090536.2061"><vh>p.childIndex</vh></v>
<v t="ekr.20091110090536.2062"><vh>p.directParents</vh></v>
<v t="ekr.20091110090536.2063"><vh>p.hasChildren &amp; p.numberOfChildren</vh></v>
</v>
<v t="ekr.20091110090536.2064"><vh>p.getX &amp; vnode compatibility traversal routines</vh></v>
<v t="ekr.20091110090536.2065"><vh>p.hasX</vh>
<v t="ekr.20091110090536.2066"><vh>hasThreadNext (the only complex hasX method)</vh></v>
</v>
<v t="ekr.20091110090536.2067"><vh>p.findRootPosition</vh></v>
<v t="ekr.20091110090536.2068"><vh>p.isAncestorOf</vh></v>
<v t="ekr.20091110090536.2069"><vh>p.isCloned</vh></v>
<v t="ekr.20091110090536.2070"><vh>p.isRoot</vh></v>
<v t="ekr.20091110090536.2071"><vh>p.isVisible</vh></v>
<v t="ekr.20091110090536.2072"><vh>p.level &amp; simpleLevel</vh></v>
<v t="ekr.20091110090536.2073"><vh>p.textOffset</vh></v>
</v>
<v t="ekr.20091110090536.2074"><vh>p.Setters</vh>
<v t="ekr.20091110090536.2075"><vh>p.Vnode proxies</vh>
<v t="ekr.20091110090536.2076"><vh>p.Status bits</vh></v>
<v t="ekr.20091110090536.2077"><vh>p.computeIcon &amp; p.setIcon</vh></v>
<v t="ekr.20091110090536.2078"><vh>p.setSelection</vh></v>
</v>
<v t="ekr.20091110090536.2079"><vh>p.setBodyString &amp; setHeadString</vh></v>
<v t="ekr.20091110090536.2080"><vh>p.Visited bits</vh>
<v t="ekr.20091110090536.2081"><vh>p.clearVisitedInTree</vh></v>
<v t="ekr.20091110090536.2082"><vh>p.clearAllVisitedInTree</vh></v>
</v>
<v t="ekr.20091110090536.2083"><vh>p.Dirty bits</vh>
<v t="ekr.20091110090536.2084"><vh>p.clearDirty</vh></v>
<v t="ekr.20091110090536.2085"><vh>p.findAllPotentiallyDirtyNodes</vh></v>
<v t="ekr.20091110090536.2086"><vh>p.inAtIgnoreRange</vh></v>
<v t="ekr.20091110090536.2087"><vh>p.setAllAncestorAtFileNodesDirty</vh></v>
<v t="ekr.20091110090536.2088"><vh>p.setDirty</vh></v>
</v>
</v>
<v t="ekr.20091110090536.2089"><vh>p.File Conversion</vh>
<v t="ekr.20091110090536.2090"><vh>p.convertTreeToString</vh></v>
<v t="ekr.20091110090536.2091"><vh>p.moreHead</vh></v>
<v t="ekr.20091110090536.2092"><vh>p.moreBody</vh></v>
</v>
<v t="ekr.20091110090536.2093"><vh>p.generators</vh>
<v t="ekr.20091110090536.2094"><vh>p.children</vh></v>
<v t="ekr.20091110090536.2095"><vh>p.following_siblings</vh></v>
<v t="ekr.20091110090536.2096"><vh>p.nodes</vh></v>
<v t="ekr.20091110090536.2097"><vh>p.parents</vh></v>
<v t="ekr.20091110090536.2098"><vh>p.self_and_parents</vh></v>
<v t="ekr.20091110090536.2099"><vh>p.self_and_siblings</vh></v>
<v t="ekr.20091110090536.2100"><vh>p.self_and_subtree</vh></v>
<v t="ekr.20091110090536.2101"><vh>p.subtree</vh></v>
<v t="ekr.20091110090536.2102"><vh>p.unique_nodes</vh></v>
<v t="ekr.20091110090536.2103"><vh>p.unique_subtree</vh></v>
</v>
<v t="ekr.20091110090536.2104"><vh>p.Moving, Inserting, Deleting, Cloning, Sorting</vh>
<v t="ekr.20091110090536.2105"><vh>p.clone</vh></v>
<v t="ekr.20091110090536.2106"><vh>p.copyTreeAfter, copyTreeTo</vh></v>
<v t="ekr.20091110090536.2107"><vh>p.doDelete</vh></v>
<v t="ekr.20091110090536.2108"><vh>p.insertAfter</vh></v>
<v t="ekr.20091110090536.2109"><vh>p.insertAsLastChild</vh></v>
<v t="ekr.20091110090536.2110"><vh>p.insertAsNthChild</vh></v>
<v t="ekr.20091110090536.2111"><vh>p.invalidOutline</vh></v>
<v t="ekr.20091110090536.2112"><vh>p.moveAfter</vh></v>
<v t="ekr.20091110090536.2113"><vh>p.moveToFirst/LastChildOf</vh></v>
<v t="ekr.20091110090536.2114"><vh>p.moveToNthChildOf</vh></v>
<v t="ekr.20091110090536.2115"><vh>p.moveToRoot</vh></v>
<v t="ekr.20091110090536.2116"><vh>p.validateOutlineWithParent</vh>
<v t="ekr.20091110090536.2117"><vh>&lt;&lt; validate parent ivar &gt;&gt;</vh></v>
<v t="ekr.20091110090536.2118"><vh>&lt;&lt; validate childIndex ivar &gt;&gt;</vh></v>
<v t="ekr.20091110090536.2119"><vh>&lt;&lt; validate x ivar &gt;&gt;</vh></v>
</v>
</v>
<v t="ekr.20091110090536.2120"><vh>p.moveToX</vh>
<v t="ekr.20091110090536.2121"><vh>p.moveToBack</vh></v>
<v t="ekr.20091110090536.2122"><vh>p.moveToFirstChild</vh></v>
<v t="ekr.20091110090536.2123"><vh>p.moveToLastChild</vh></v>
<v t="ekr.20091110090536.2124"><vh>p.moveToLastNode</vh></v>
<v t="ekr.20091110090536.2125"><vh>p.moveToNext</vh></v>
<v t="ekr.20091110090536.2126"><vh>p.moveToNodeAfterTree</vh></v>
<v t="ekr.20091110090536.2127"><vh>p.moveToNthChild</vh></v>
<v t="ekr.20091110090536.2128"><vh>p.moveToParent</vh></v>
<v t="ekr.20091110090536.2129"><vh>p.moveToThreadBack</vh></v>
<v t="ekr.20091110090536.2130"><vh>p.moveToThreadNext</vh></v>
<v t="ekr.20091110090536.2131"><vh>p.moveToVisBack</vh>
<v t="ekr.20091110090536.2132"><vh>checkVisBackLimit</vh></v>
</v>
<v t="ekr.20091110090536.2133"><vh>p.moveToVisNext</vh>
<v t="ekr.20091110090536.2134"><vh>checkVisNextLimit</vh></v>
</v>
</v>
<v t="ekr.20091110090536.2135"><vh>p.Low level methods</vh>
<v t="ekr.20091110090536.2136"><vh>p._adjustPositionBeforeUnlink</vh>
<v t="ekr.20091110090536.2137"><vh>@test p.adjustPositionBeforeUnlink</vh>
<v t="ekr.20091110090536.2138"><vh>node 1</vh>
<v t="ekr.20091110090536.2139"><vh>node 1-1</vh>
<v t="ekr.20091110090536.2140"><vh>node 1-1-1</vh></v>
<v t="ekr.20091110090536.2141"><vh>node 1-1-2</vh></v>
</v>
<v t="ekr.20091110090536.2142"><vh>node 1-2</vh>
<v t="ekr.20091110090536.2143"><vh>node 1-2-1</vh></v>
<v t="ekr.20091110090536.2144"><vh>node 1-2-2</vh></v>
</v>
</v>
<v t="ekr.20091110090536.2145"><vh>node 2</vh>
<v t="ekr.20091110090536.2146"><vh>node 2-1</vh>
<v t="ekr.20091110090536.2147"><vh>node 2-1-1</vh></v>
<v t="ekr.20091110090536.2148"><vh>node 2-1-2</vh></v>
</v>
<v t="ekr.20091110090536.2149"><vh>node 2-2</vh>
<v t="ekr.20091110090536.2150"><vh>node 2-2-1</vh></v>
<v t="ekr.20091110090536.2151"><vh>node 2-2-2</vh></v>
</v>
</v>
<v t="ekr.20091110090536.2152"><vh>node 3</vh>
<v t="ekr.20091110090536.2153"><vh>node 3-1</vh>
<v t="ekr.20091110090536.2154"><vh>node 3-1-1</vh></v>
<v t="ekr.20091110090536.2155"><vh>node 3-1-2</vh></v>
</v>
<v t="ekr.20091110090536.2156"><vh>node 3-2</vh>
<v t="ekr.20091110090536.2157"><vh>node 3-2-1</vh></v>
<v t="ekr.20091110090536.2158"><vh>node 3-2-2</vh></v>
</v>
</v>
</v>
</v>
<v t="ekr.20091110090536.2159"><vh>p._linkAfter</vh></v>
<v t="ekr.20091110090536.2160"><vh>p._linkAsNthChild</vh></v>
<v t="ekr.20091110090536.2161"><vh>p._parentVnode</vh></v>
<v t="ekr.20091110090536.2162"><vh>p._linkAsRoot</vh></v>
<v t="ekr.20091110090536.2163"><vh>p._unlink</vh>
<v t="ekr.20091110090536.2164"><vh>p.badUnlink</vh></v>
</v>
<v t="ekr.20091110090536.2165"><vh>p.makeCacheList</vh></v>
</v>
</v>
<v t="ekr.20091110090536.2166"><vh>class poslist</vh>
<v t="ekr.20091110090536.2167"><vh>select_h</vh></v>
<v t="ekr.20091110090536.2168"><vh>select_b</vh></v>
</v>
</v>
</v>
</v>
<v t="ekr.20091110090536.2172"><vh>2. Leo scripts</vh>
<v t="ekr.20091110090536.2169"><vh>Scripts have full access to outlines</vh>
<v t="ekr.20091110090536.2173"><vh>An example script</vh></v>
</v>
<v t="ekr.20091110090536.2174"><vh>The @x convention: headlines are metadata</vh>
<v t="ekr.20091110090536.2189"><vh>Examples</vh>
<v t="ekr.20091110090536.2186"><vh>@html Leo's home page</vh></v>
<v t="ekr.20091110104908.2101"><vh>@url http://webpages.charter.net/edreamleo/front.html</vh></v>
<v t="ekr.20091110090536.2181"><vh>@test add-tab-to-lines</vh>
<v t="ekr.20091110090536.2182"><vh>work</vh></v>
<v t="ekr.20091110090536.2183"><vh>before sel=2.0,5.6</vh></v>
<v t="ekr.20091110090536.2184"><vh>after sel=2.0,5.10</vh></v>
</v>
<v t="ekr.20091110090536.2188"><vh>@button count-headline</vh></v>
</v>
</v>
</v>
</v>
<v t="ekr.20091110090536.1651"><vh>Conclusions</vh>
<v t="ekr.20091110104908.2102"><vh>@url http://webpages.charter.net/edreamleo/front.html</vh></v>
</v>
</v>
<v t="ekr.20091110090536.1635"><vh>Description</vh></v>
<v t="ekr.20091121184836.2583"><vh>Leo is really simple</vh>
<v t="ekr.20091122085016.2585"><vh>The elevator talk</vh></v>
<v t="ekr.20091122085016.2601"><vh>Leo's creation talk</vh></v>
<v t="ekr.20091122085016.2586"><vh>The essence of Leo existed before Leo did</vh></v>
<v t="ekr.20091122085016.2594"><vh>Example markup</vh>
<v t="ekr.20091116094116.2345"><vh>@@file mClass.py</vh>
<v t="ekr.20091122085016.2598"><vh>&lt;&lt; A longish docstring &gt;&gt;</vh></v>
<v t="ekr.20091116094116.2346"><vh>&lt;&lt; imports &gt;&gt;</vh></v>
<v t="ekr.20091122085016.2599"><vh>ctor</vh></v>
<v t="ekr.20091122085016.2600"><vh>doSomething</vh></v>
</v>
</v>
<v t="ekr.20091122085016.2595"><vh>Example script</vh>
<v t="ekr.20091116094116.2564"><vh>Scripts have full access to outlines</vh></v>
</v>
</v>
<v t="ekr.20091122085016.2587"><vh>2-5 Minutes: Communication</vh></v>
</v>
<v t="ekr.20091117082920.2628"><vh>Speakers Notes</vh>
<v t="ekr.20091117082920.8031"><vh>Who am I?</vh></v>
<v t="ekr.20091117082920.8032"><vh>Who are you?</vh></v>
<v t="ekr.20091124051255.2175"><vh>Intension: to give you the Leo Aha</vh></v>
<v t="ekr.20091117100212.2629"><vh>What people are saying about Leo</vh></v>
<v t="ekr.20091124051255.2177"><vh>The elements</vh></v>
<v t="ekr.20091124051255.2176"><vh>Leo is a new playground, and a new set of tools</vh></v>
<v t="ekr.20091124051255.2178"><vh>Surprising results</vh></v>
<v t="ekr.20091122085016.2592"><vh>Contact me</vh></v>
<v t="ekr.20091122085016.2588"><vh>References</vh></v>
</v>
<v t="ekr.20091109103928.1546"><vh>To do</vh>
<v t="ekr.20091108172508.15988"><vh>Bug double-click-icon-box is not selecting the proper node.</vh></v>
<v t="ekr.20091109103928.1544"><vh>Bug contracting a node should redraw the screen</vh></v>
<v t="ekr.20091122085016.2593"><vh>newHeadline</vh></v>
</v>
<v t="ekr.20060902101656" a="E"><vh>Slide shows</vh>
<v t="ekr.20091107142231.6264"><vh>5-10 minutes: Managing an Open Source Project</vh>
<v t="ekr.20091107142231.6265"><vh>Put your project first</vh></v>
<v t="ekr.20091107142231.6267"><vh>Encourage others</vh></v>
<v t="ekr.20091109103928.14983"><vh>Focus on simplicity</vh></v>
<v t="ekr.20091107142231.6268"><vh>Avoid politics</vh></v>
<v t="ekr.20091110090536.1654"><vh>Spend 1/2 of your time communicating about your project</vh>
<v t="ekr.20091110104908.2108"><vh>@url http://www.cs.virginia.edu/~robins/YouAndYourResearch.html</vh></v>
</v>
</v>
<v t="ekr.20091116094116.2312"><vh>@image 15-20 minutes: The Leo Aha</vh>
<v t="ekr.20091117093857.2640"><vh>Leo's users say...</vh>
<v t="ekr.20091116094116.2604"><vh>revolutionary</vh></v>
<v t="ekr.20091116094116.2605"><vh>fun, even addicting</vh></v>
<v t="ekr.20091116094116.2606"><vh>a great outliner</vh></v>
<v t="ekr.20091116094116.2607"><vh>a great editor and IDE</vh></v>
<v t="ekr.20091116094116.2608"><vh>a great PIM</vh></v>
<v t="ekr.20091117093857.2641"><vh>a great scripting tool</vh></v>
<v t="ekr.20091116094116.2609"><vh>a great documentation tool</vh></v>
<v t="ekr.20091116094116.2610"><vh>a great way to understand complex systems</vh></v>
</v>
<v t="ekr.20091116094116.2313"><vh>Leo's screen</vh></v>
<v t="ekr.20091124051255.2169"><vh>Elements</vh>
<v t="ekr.20091117100212.2632"><vh>Outlines</vh>
<v t="ekr.20091116094116.2317"><vh>Clones: The same node can appear in many places in an outline</vh>
<v t="ekr.20091116094116.2322"><vh>A</vh>
<v t="ekr.20091116094116.2323"><vh>B</vh>
<v t="ekr.20091116094116.2324"><vh>C</vh></v>
<v t="ekr.20091116094116.2325"><vh>D</vh></v>
</v>
</v>
</v>
<v t="ekr.20091124051255.2180"><vh>A little bit of markup</vh>
<v t="ekr.20091124084348.7193"><vh>@@thin leoNodes.py</vh>
<v t="ekr.20091124084348.7194"><vh>&lt;&lt; imports &gt;&gt;</vh></v>
<v t="ekr.20091124084348.7195"><vh>class vnode</vh>
<v t="ekr.20091124084348.7196"><vh>&lt;&lt; vnode constants &gt;&gt;</vh></v>
<v t="ekr.20091124084348.7197"><vh>v.Birth &amp; death</vh>
<v t="ekr.20091124084348.7198"><vh>v.__init</vh></v>
<v t="ekr.20091124084348.7199"><vh>v.__repr__ &amp; v.__str__</vh></v>
<v t="ekr.20091124084348.7200"><vh>v.dump</vh></v>
<v t="ekr.20091124084348.7201"><vh>v.__hash__ (only for zodb)</vh></v>
</v>
<v t="ekr.20091124084348.7202"><vh>v.Comparisons</vh>
<v t="ekr.20091124084348.7203"><vh>v.findAtFileName</vh></v>
<v t="ekr.20091124084348.7204"><vh>anyAtFileNodeName</vh></v>
<v t="ekr.20091124084348.7205"><vh>at...FileNodeName &amp; tests</vh>
<v t="ekr.20091124084348.7206"><vh>@test v.atAutoNodeName &amp; v.atAutoRstNodeName</vh></v>
</v>
<v t="ekr.20091124084348.7207"><vh>isAtAllNode</vh></v>
<v t="ekr.20091124084348.7208"><vh>isAnyAtFileNode</vh></v>
<v t="ekr.20091124084348.7209"><vh>isAt...FileNode (vnode)</vh></v>
<v t="ekr.20091124084348.7210"><vh>isAtIgnoreNode</vh></v>
<v t="ekr.20091124084348.7211"><vh>isAtOthersNode</vh></v>
<v t="ekr.20091124084348.7212"><vh>matchHeadline</vh></v>
</v>
<v t="ekr.20091124084348.7213"><vh>v.Getters</vh>
<v t="ekr.20091124084348.7214"><vh>v.bodyString</vh></v>
<v t="ekr.20091124084348.7215"><vh>v.Children</vh>
<v t="ekr.20091124084348.7216"><vh>v.firstChild</vh></v>
<v t="ekr.20091124084348.7217"><vh>v.hasChildren &amp; hasFirstChild</vh></v>
<v t="ekr.20091124084348.7218"><vh>v.lastChild</vh></v>
<v t="ekr.20091124084348.7219"><vh>v.nthChild</vh></v>
<v t="ekr.20091124084348.7220"><vh>v.numberOfChildren</vh></v>
</v>
<v t="ekr.20091124084348.7221"><vh>v.directParents</vh></v>
<v t="ekr.20091124084348.7222"><vh>v.hasBody</vh></v>
<v t="ekr.20091124084348.7223"><vh>v.headString &amp; v.cleanHeadString</vh></v>
<v t="ekr.20091124084348.7224"><vh>v.Status Bits</vh>
<v t="ekr.20091124084348.7225"><vh>v.isCloned</vh></v>
<v t="ekr.20091124084348.7226"><vh>v.isDirty</vh></v>
<v t="ekr.20091124084348.7227"><vh>v.isExpanded</vh></v>
<v t="ekr.20091124084348.7228"><vh>v.isMarked</vh></v>
<v t="ekr.20091124084348.7229"><vh>v.isOrphan</vh></v>
<v t="ekr.20091124084348.7230"><vh>v.isSelected</vh></v>
<v t="ekr.20091124084348.7231"><vh>v.isTopBitSet</vh></v>
<v t="ekr.20091124084348.7232"><vh>v.isVisited</vh></v>
<v t="ekr.20091124084348.7233"><vh>v.isWriteBit</vh></v>
<v t="ekr.20091124084348.7234"><vh>v.status</vh></v>
</v>
</v>
<v t="ekr.20091124084348.7235"><vh>v.Setters</vh>
<v t="ekr.20091124084348.7236"><vh> v.Dirty bits</vh>
<v t="ekr.20091124084348.7237"><vh>v.clearDirty</vh></v>
<v t="ekr.20091124084348.7238"><vh>v.findAllPotentiallyDirtyNodes</vh></v>
<v t="ekr.20091124084348.7239"><vh>v.setAllAncestorAtFileNodesDirty</vh></v>
<v t="ekr.20091124084348.7240"><vh>v.setDirty</vh></v>
</v>
<v t="ekr.20091124084348.7241"><vh> v.Status bits</vh>
<v t="ekr.20091124084348.7242"><vh>v.clearClonedBit</vh></v>
<v t="ekr.20091124084348.7243"><vh>v.clearMarked</vh></v>
<v t="ekr.20091124084348.7244"><vh>v.clearWriteBit</vh></v>
<v t="ekr.20091124084348.7245"><vh>v.clearOrphan</vh></v>
<v t="ekr.20091124084348.7246"><vh>v.clearVisited</vh></v>
<v t="ekr.20091124084348.7247"><vh>v.contract &amp; expand &amp; initExpandedBit</vh></v>
<v t="ekr.20091124084348.7248"><vh>v.initStatus</vh></v>
<v t="ekr.20091124084348.7249"><vh>v.setClonedBit &amp; initClonedBit</vh></v>
<v t="ekr.20091124084348.7250"><vh>v.setMarked &amp; initMarkedBit</vh></v>
<v t="ekr.20091124084348.7251"><vh>v.setOrphan</vh></v>
<v t="ekr.20091124084348.7252"><vh>v.setSelected</vh></v>
<v t="ekr.20091124084348.7253"><vh>v.setVisited</vh></v>
<v t="ekr.20091124084348.7254"><vh>v.setWriteBit</vh></v>
</v>
<v t="ekr.20091124084348.7255"><vh>v .setBodyString &amp; v.setHeadString</vh></v>
<v t="ekr.20091124084348.7256"><vh>v.setFileIndex</vh></v>
<v t="ekr.20091124084348.7257"><vh>v.computeIcon &amp; setIcon</vh></v>
<v t="ekr.20091124084348.7258"><vh>v.setSelection</vh></v>
</v>
<v t="ekr.20091124084348.7259"><vh>v.Low level methods</vh>
<v t="ekr.20091124084348.7260"><vh>v._addLink &amp; helper</vh>
<v t="ekr.20091124084348.7261"><vh>v._addParentLinks</vh></v>
</v>
<v t="ekr.20091124084348.7262"><vh>v._cutLink</vh>
<v t="ekr.20091124084348.7263"><vh>v._cutParentLinks</vh></v>
</v>
<v t="ekr.20091124084348.7264"><vh>v._linkAsNthChild (used by 4.x read logic)</vh></v>
<v t="ekr.20091124084348.7265"><vh>v.createOutlineFromCacheList &amp; helpers</vh>
<v t="ekr.20091124084348.7266"><vh>v.fastAddLastChild</vh></v>
</v>
</v>
<v t="ekr.20091124084348.7267"><vh>v.Properties</vh>
<v t="ekr.20091124084348.7268"><vh>v.b Property</vh></v>
<v t="ekr.20091124084348.7269"><vh>v.h property</vh></v>
<v t="ekr.20091124084348.7270"><vh>v.u Property</vh></v>
<v t="ekr.20091124084348.7271"><vh>v.gnx Property</vh></v>
</v>
</v>
<v t="ekr.20091124084348.7272"><vh>class nodeIndices</vh>
<v t="ekr.20091124084348.7273"><vh>nodeIndices.__init__</vh></v>
<v t="ekr.20091124084348.7274"><vh>areEqual (no longer used)</vh></v>
<v t="ekr.20091124084348.7275"><vh>get/setDefaultId</vh></v>
<v t="ekr.20091124084348.7276"><vh>getNewIndex</vh></v>
<v t="ekr.20091124084348.7277"><vh>isGnx (not used)</vh></v>
<v t="ekr.20091124084348.7278"><vh>scanGnx</vh></v>
<v t="ekr.20091124084348.7279"><vh>setTimeStamp</vh></v>
<v t="ekr.20091124084348.7280"><vh>toString</vh></v>
</v>
<v t="ekr.20091124084348.7281"><vh>class position</vh>
<v t="ekr.20091124084348.7282"><vh>&lt;&lt; about the position class &gt;&gt;</vh></v>
<v t="ekr.20091124084348.7283"><vh> p.ctor &amp; other special methods...</vh>
<v t="ekr.20091124084348.7284"><vh> p.__init__</vh></v>
<v t="ekr.20091124084348.7285"><vh>p.__eq__ &amp; __ne__</vh></v>
<v t="ekr.20091124084348.7286"><vh>p.__getattr__ (no longer used)</vh></v>
<v t="ekr.20091124084348.7287"><vh>p.__nonzero__ &amp; __bool__</vh></v>
<v t="ekr.20091124084348.7288"><vh>p.__str__ and p.__repr__</vh></v>
<v t="ekr.20091124084348.7289"><vh>p.archivedPosition</vh></v>
<v t="ekr.20091124084348.7290"><vh>p.copy</vh></v>
<v t="ekr.20091124084348.7291"><vh>p.dump</vh></v>
<v t="ekr.20091124084348.7292"><vh>p.key</vh></v>
</v>
<v t="ekr.20091124084348.7293"><vh>p.Properties</vh>
<v t="ekr.20091124084348.7294"><vh>p.b property</vh></v>
<v t="ekr.20091124084348.7295"><vh>p.h property</vh></v>
<v t="ekr.20091124084348.7296"><vh>p.gnx property</vh></v>
</v>
<v t="ekr.20091124084348.7297"><vh>p.Getters</vh>
<v t="ekr.20091124084348.7298"><vh>p.vnode proxies</vh>
<v t="ekr.20091124084348.7299"><vh>p.Comparisons</vh></v>
<v t="ekr.20091124084348.7300"><vh>p.Headline &amp; body strings</vh></v>
<v t="ekr.20091124084348.7301"><vh>p.Status bits</vh></v>
</v>
<v t="ekr.20091124084348.7302"><vh>p.children &amp; parents</vh>
<v t="ekr.20091124084348.7303"><vh>p.childIndex</vh></v>
<v t="ekr.20091124084348.7304"><vh>p.directParents</vh></v>
<v t="ekr.20091124084348.7305"><vh>p.hasChildren &amp; p.numberOfChildren</vh></v>
</v>
<v t="ekr.20091124084348.7306"><vh>p.getX &amp; vnode compatibility traversal routines</vh></v>
<v t="ekr.20091124084348.7307"><vh>p.hasX</vh>
<v t="ekr.20091124084348.7308"><vh>hasThreadNext (the only complex hasX method)</vh></v>
</v>
<v t="ekr.20091124084348.7309"><vh>p.findRootPosition</vh></v>
<v t="ekr.20091124084348.7310"><vh>p.isAncestorOf</vh></v>
<v t="ekr.20091124084348.7311"><vh>p.isCloned</vh></v>
<v t="ekr.20091124084348.7312"><vh>p.isRoot</vh></v>
<v t="ekr.20091124084348.7313"><vh>p.isVisible</vh></v>
<v t="ekr.20091124084348.7314"><vh>p.level &amp; simpleLevel</vh></v>
<v t="ekr.20091124084348.7315"><vh>p.textOffset</vh></v>
</v>
<v t="ekr.20091124084348.7316"><vh>p.Setters</vh>
<v t="ekr.20091124084348.7317"><vh>p.Vnode proxies</vh>
<v t="ekr.20091124084348.7318"><vh>p.Status bits</vh></v>
<v t="ekr.20091124084348.7319"><vh>p.computeIcon &amp; p.setIcon</vh></v>
<v t="ekr.20091124084348.7320"><vh>p.setSelection</vh></v>
</v>
<v t="ekr.20091124084348.7321"><vh>p.setBodyString &amp; setHeadString</vh></v>
<v t="ekr.20091124084348.7322"><vh>p.Visited bits</vh>
<v t="ekr.20091124084348.7323"><vh>p.clearVisitedInTree</vh></v>
<v t="ekr.20091124084348.7324"><vh>p.clearAllVisitedInTree</vh></v>
</v>
<v t="ekr.20091124084348.7325"><vh>p.Dirty bits</vh>
<v t="ekr.20091124084348.7326"><vh>p.clearDirty</vh></v>
<v t="ekr.20091124084348.7327"><vh>p.findAllPotentiallyDirtyNodes</vh></v>
<v t="ekr.20091124084348.7328"><vh>p.inAtIgnoreRange</vh></v>
<v t="ekr.20091124084348.7329"><vh>p.setAllAncestorAtFileNodesDirty</vh></v>
<v t="ekr.20091124084348.7330"><vh>p.setDirty</vh></v>
</v>
</v>
<v t="ekr.20091124084348.7331"><vh>p.File Conversion</vh>
<v t="ekr.20091124084348.7332"><vh>p.convertTreeToString</vh></v>
<v t="ekr.20091124084348.7333"><vh>p.moreHead</vh></v>
<v t="ekr.20091124084348.7334"><vh>p.moreBody</vh></v>
</v>
<v t="ekr.20091124084348.7335"><vh>p.generators</vh>
<v t="ekr.20091124084348.7336"><vh>p.children</vh></v>
<v t="ekr.20091124084348.7337"><vh>p.following_siblings</vh></v>
<v t="ekr.20091124084348.7338"><vh>p.nodes</vh></v>
<v t="ekr.20091124084348.7339"><vh>p.parents</vh></v>
<v t="ekr.20091124084348.7340"><vh>p.self_and_parents</vh></v>
<v t="ekr.20091124084348.7341"><vh>p.self_and_siblings</vh></v>
<v t="ekr.20091124084348.7342"><vh>p.self_and_subtree</vh></v>
<v t="ekr.20091124084348.7343"><vh>p.subtree</vh></v>
<v t="ekr.20091124084348.7344"><vh>p.unique_nodes</vh></v>
<v t="ekr.20091124084348.7345"><vh>p.unique_subtree</vh></v>
</v>
<v t="ekr.20091124084348.7346"><vh>p.Moving, Inserting, Deleting, Cloning, Sorting</vh>
<v t="ekr.20091124084348.7347"><vh>p.clone</vh></v>
<v t="ekr.20091124084348.7348"><vh>p.copyTreeAfter, copyTreeTo</vh></v>
<v t="ekr.20091124084348.7349"><vh>p.doDelete</vh></v>
<v t="ekr.20091124084348.7350"><vh>p.insertAfter</vh></v>
<v t="ekr.20091124084348.7351"><vh>p.insertAsLastChild</vh></v>
<v t="ekr.20091124084348.7352"><vh>p.insertAsNthChild</vh></v>
<v t="ekr.20091124084348.7353"><vh>p.invalidOutline</vh></v>
<v t="ekr.20091124084348.7354"><vh>p.moveAfter</vh></v>
<v t="ekr.20091124084348.7355"><vh>p.moveToFirst/LastChildOf</vh></v>
<v t="ekr.20091124084348.7356"><vh>p.moveToNthChildOf</vh></v>
<v t="ekr.20091124084348.7357"><vh>p.moveToRoot</vh></v>
<v t="ekr.20091124084348.7358"><vh>p.validateOutlineWithParent</vh>
<v t="ekr.20091124084348.7359"><vh>&lt;&lt; validate parent ivar &gt;&gt;</vh></v>
<v t="ekr.20091124084348.7360"><vh>&lt;&lt; validate childIndex ivar &gt;&gt;</vh></v>
<v t="ekr.20091124084348.7361"><vh>&lt;&lt; validate x ivar &gt;&gt;</vh></v>
</v>
</v>
<v t="ekr.20091124084348.7362"><vh>p.moveToX</vh>
<v t="ekr.20091124084348.7363"><vh>p.moveToBack</vh></v>
<v t="ekr.20091124084348.7364"><vh>p.moveToFirstChild</vh></v>
<v t="ekr.20091124084348.7365"><vh>p.moveToLastChild</vh></v>
<v t="ekr.20091124084348.7366"><vh>p.moveToLastNode</vh></v>
<v t="ekr.20091124084348.7367"><vh>p.moveToNext</vh></v>
<v t="ekr.20091124084348.7368"><vh>p.moveToNodeAfterTree</vh></v>
<v t="ekr.20091124084348.7369"><vh>p.moveToNthChild</vh></v>
<v t="ekr.20091124084348.7370"><vh>p.moveToParent</vh></v>
<v t="ekr.20091124084348.7371"><vh>p.moveToThreadBack</vh></v>
<v t="ekr.20091124084348.7372"><vh>p.moveToThreadNext</vh></v>
<v t="ekr.20091124084348.7373"><vh>p.moveToVisBack</vh>
<v t="ekr.20091124084348.7374"><vh>checkVisBackLimit</vh></v>
</v>
<v t="ekr.20091124084348.7375"><vh>p.moveToVisNext</vh>
<v t="ekr.20091124084348.7376"><vh>checkVisNextLimit</vh></v>
</v>
</v>
<v t="ekr.20091124084348.7377"><vh>p.Low level methods</vh>
<v t="ekr.20091124084348.7378"><vh>p._adjustPositionBeforeUnlink</vh>
<v t="ekr.20091124084348.7379"><vh>@test p.adjustPositionBeforeUnlink</vh>
<v t="ekr.20091124084348.7380"><vh>node 1</vh>
<v t="ekr.20091124084348.7381"><vh>node 1-1</vh>
<v t="ekr.20091124084348.7382"><vh>node 1-1-1</vh></v>
<v t="ekr.20091124084348.7383"><vh>node 1-1-2</vh></v>
</v>
<v t="ekr.20091124084348.7384"><vh>node 1-2</vh>
<v t="ekr.20091124084348.7385"><vh>node 1-2-1</vh></v>
<v t="ekr.20091124084348.7386"><vh>node 1-2-2</vh></v>
</v>
</v>
<v t="ekr.20091124084348.7387"><vh>node 2</vh>
<v t="ekr.20091124084348.7388"><vh>node 2-1</vh>
<v t="ekr.20091124084348.7389"><vh>node 2-1-1</vh></v>
<v t="ekr.20091124084348.7390"><vh>node 2-1-2</vh></v>
</v>
<v t="ekr.20091124084348.7391"><vh>node 2-2</vh>
<v t="ekr.20091124084348.7392"><vh>node 2-2-1</vh></v>
<v t="ekr.20091124084348.7393"><vh>node 2-2-2</vh></v>
</v>
</v>
<v t="ekr.20091124084348.7394"><vh>node 3</vh>
<v t="ekr.20091124084348.7395"><vh>node 3-1</vh>
<v t="ekr.20091124084348.7396"><vh>node 3-1-1</vh></v>
<v t="ekr.20091124084348.7397"><vh>node 3-1-2</vh></v>
</v>
<v t="ekr.20091124084348.7398"><vh>node 3-2</vh>
<v t="ekr.20091124084348.7399"><vh>node 3-2-1</vh></v>
<v t="ekr.20091124084348.7400"><vh>node 3-2-2</vh></v>
</v>
</v>
</v>
</v>
<v t="ekr.20091124084348.7401"><vh>p._linkAfter</vh></v>
<v t="ekr.20091124084348.7402"><vh>p._linkAsNthChild</vh></v>
<v t="ekr.20091124084348.7403"><vh>p._parentVnode</vh></v>
<v t="ekr.20091124084348.7404"><vh>p._linkAsRoot</vh></v>
<v t="ekr.20091124084348.7405"><vh>p._unlink</vh>
<v t="ekr.20091124084348.7406"><vh>p.badUnlink</vh></v>
</v>
<v t="ekr.20091124084348.7407"><vh>p.makeCacheList</vh></v>
</v>
</v>
<v t="ekr.20091124084348.7408"><vh>class poslist</vh>
<v t="ekr.20091124084348.7409"><vh>select_h</vh></v>
<v t="ekr.20091124084348.7410"><vh>select_b</vh></v>
</v>
</v>
</v>
</v>
<v t="ekr.20091117100212.2633"><vh>Scripts</vh>
<v t="ekr.20091124051255.2181"><vh>Python</vh></v>
<v t="ekr.20091124051255.2182"><vh>A real DOM</vh>
<v t="ekr.20091116094116.2564"></v>
</v>
</v>
<v t="ekr.20091124084348.7411"><vh>A brag</vh></v>
</v>
<v t="ekr.20091124051255.2179" a="E"><vh>Consequences</vh>
<v t="ekr.20091116094116.2343"><vh>There is no such thing as *the* right view of data</vh>
<v t="ekr.20091116094116.2328"><vh>Fixed contractOrGoRight</vh>
<v t="ekr.20091116094116.2329"><vh>The bug</vh></v>
<v t="ekr.20091116094116.2330"><vh>What I did</vh></v>
<v t="ekr.20091116094116.2331"><vh>selectVisNext</vh></v>
<v t="ekr.20091116094116.2332"><vh>selectVisBack</vh></v>
<v t="ekr.20091116094116.2333"><vh>goToParent</vh></v>
<v t="ekr.20091116094116.2334"><vh>contractNodeOrGoToParent</vh></v>
<v t="ekr.20091116094116.2335"><vh>expandNodeAnd/OrGoToFirstChild</vh></v>
<v t="ekr.20091116094116.2336"><vh>contractNode</vh></v>
<v t="ekr.20091116094116.2337"><vh>expandNode</vh></v>
<v t="ekr.20091116094116.2338"><vh> treeSelectHelper</vh></v>
<v t="ekr.20091116094116.2339"><vh>p.moveToVisBack</vh>
<v t="ekr.20091116094116.2340"><vh>checkVisBackLimit</vh></v>
</v>
<v t="ekr.20091116094116.2341"><vh>p.moveToVisNext</vh>
<v t="ekr.20091116094116.2342"><vh>checkVisNextLimit</vh></v>
</v>
</v>
</v>
<v t="ekr.20091116094116.2344"><vh>Outlines create external files</vh></v>
<v t="ekr.20091116094116.2566"><vh>The @x convention: headlines are metadata</vh>
<v t="ekr.20091116094116.2567"><vh>Examples</vh>
<v t="ekr.20091116094116.2568"><vh>@html Leo's home page</vh></v>
<v t="ekr.20091116094116.2569"><vh>@url http://webpages.charter.net/edreamleo/front.html</vh></v>
<v t="ekr.20091117100212.2635"><vh>@image Lion image</vh></v>
<v t="ekr.20091117100212.2636"><vh>@test fail</vh></v>
<v t="ekr.20091116094116.2570"><vh>@test add-tab-to-lines</vh>
<v t="ekr.20091116094116.2571"><vh>work</vh></v>
<v t="ekr.20091116094116.2572"><vh>before sel=2.0,5.6</vh></v>
<v t="ekr.20091116094116.2573"><vh>after sel=2.0,5.10</vh></v>
</v>
<v t="ekr.20091116094116.2574"><vh>@button count-headline</vh></v>
</v>
</v>
</v>
<v t="ekr.20091116094116.2575"><vh>Conclusions</vh></v>
<v t="ekr.20091117100212.2630"><vh>Contact</vh></v>
</v>
</v>
</vnodes>
<tnodes>
<t tx="ekr.20060901144149.2">c.k.simulateCommand('prev-slide-command')</t>
<t tx="ekr.20060901144149.3">c.k.simulateCommand('next-slide-show-command')</t>
<t tx="ekr.20060901144149.4">from PMIDI import * 
from time import sleep </t>
<t tx="ekr.20060901144149.5"></t>
<t tx="ekr.20060901144149.6"></t>
<t tx="ekr.20060901144149.7"></t>
<t tx="ekr.20060901144246">@color

@ A point that can cause confusion:
    
The slideshow.py plugin defines four commands whose names end in -command. It
would be possible to bind shortcuts for *these* commands in leoSettings.leo or
myLeoSettings.leo

The buttons below define commands whose names do *not* end in -command. These
button define shortcuts for these buttons using the @key syntax.</t>
<t tx="ekr.20060901144331">c.k.simulateCommand('prev-slide-show-command')</t>
<t tx="ekr.20060901144359">c.k.simulateCommand('next-slide-command')</t>
<t tx="ekr.20060901153101">@language rest
@
The @language **directive** shown above means that this slide show
is syntax-colored as reStructured text, a popular markup language.
@c

This is the first slide of a slideshow introducing Leo.

@
I'm not going to read everything on every slide.
So pay attention :-)


</t>
<t tx="ekr.20060902092242">c.beginUpdate()

try:
    p1 = p.copy()
    undoData = c.undoer.beforeChangeTree(p1)
    for p in c.currentPosition().self_and_subtree_iter():
        h = p.headString().strip()
        if not h.startswith('@slide'):
            p.setHeadString('@slide ' + h)
    c.undoer.afterChangeTree(p1,'make-slide',undoData)
finally:
    c.endUpdate()
</t>
<t tx="ekr.20060902092259">@language python

@nocolor-node

This slideshow describes the most useful functions, classes and methods in
leo.py. Keep in mind that *your scripts have complete access to all of Leo's
source code*, that is, all the code in LeoPy.leo. Your scripts can use Leo's
code in whatever ways are convenient. You are *not* limited by what you see in
this chapter.

**Important:** You can execute all the code in this slideshow. Just select the
code you want to execute and run the Execute Script command.

**Important**: Python is finicky about indentation, so you must be careful to
select the leading whitespace of the first line.</t>
<t tx="ekr.20060902092341.4" rst_http_attribute="5d71002855443c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d3122206e616d653d22687474702d6e6f64652d6d61726b65722d31223e710155043c2f613e71025d710328553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710455063c2f6469763e71055d71062855063c626f64793e710755073c2f626f64793e71085d71092855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e710a55073c2f68746d6c3e710b4e65656555243c64697620636c6173733d2273656374696f6e222069643d226f76657276696577223e0a710c55493c68313e3c6120636c6173733d22746f632d6261636b7265662220687265663d222369643122206e616d653d226f76657276696577223e4f766572766965773c2f613e3c2f68313e0a710d652e"># Note: Everything between '@' and '@c' is a comment.

@
Leo's source code is a collection of classes, and utility functions.
@c
</t>
<t tx="ekr.20060902092341.5" rst_http_attribute="5d71002855443c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d3522206e616d653d22687474702d6e6f64652d6d61726b65722d35223e710155043c2f613e71025d71032855403c64697620636c6173733d2273656374696f6e222069643d22672d746f702d7468652d636f6d6d616e6465722d6f662d7468652d746f702d77696e646f77223e710455063c2f6469763e71055d710628553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710755063c2f6469763e71085d71092855063c626f64793e710a55073c2f626f64793e710b5d710c2855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e710d55073c2f68746d6c3e710e4e6565656555073c2f6469763e0a710f55363c64697620636c6173733d2273656374696f6e222069643d22672d65732d77726974652d746f2d7468652d6c6f672d70616e65223e0a711055703c68313e3c6120636c6173733d22746f632d6261636b7265662220687265663d222369643322206e616d653d22672d65732d77726974652d746f2d7468652d6c6f672d70616e65223e672e657328293a20777269746520746f20746865206c6f672070616e653c2f613e3c2f68313e0a7111652e"># The g.es method prints its arguments to the Log tab of the log pane:
c.frame.log.clearTab('Log')
g.es("Hello world")

# g.es converts non-string arguments using repr:
g.es(c)

# g.es prints multiple arguments separated by commas:
g.es("Hello","world")
</t>
<t tx="ekr.20060902092341.6" rst_http_attribute="5d71002855443c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d3722206e616d653d22687474702d6e6f64652d6d61726b65722d37223e710155043c2f613e71025d71032855353c64697620636c6173733d2273656374696f6e222069643d22672d65732d77726974652d746f2d7468652d6c6f672d70616e65223e710455063c2f6469763e71055d710628553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710755063c2f6469763e71085d71092855063c626f64793e710a55073c2f626f64793e710b5d710c2855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e710d55073c2f68746d6c3e710e4e6565656555073c2f6469763e0a710f55463c64697620636c6173733d2273656374696f6e222069643d226170702d77696e646f776c6973742d7468652d6c6973742d6f662d616c6c2d6f70656e2d6672616d6573223e0a7110558e3c68313e3c6120636c6173733d22746f632d6261636b7265662220687265663d222369643422206e616d653d226170702d77696e646f776c6973742d7468652d6c6973742d6f662d616c6c2d6f70656e2d6672616d6573223e6170702e77696e646f774c6973743a20746865206c697374206f6620616c6c206f70656e206672616d65733c2f613e3c2f68313e0a7111652e"># g.app.windowlist is the list of the frames of all open windows.

aList = g.app.windowList # get the list of all open frames.
g.es("windows...")
for f in aList:
    print(f)
    print(f.c)
    print(f.shortFileName())
</t>
<t tx="ekr.20060902092341.7" rst_http_attribute="5d71002855443c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d3922206e616d653d22687474702d6e6f64652d6d61726b65722d39223e710155043c2f613e71025d71032855453c64697620636c6173733d2273656374696f6e222069643d226170702d77696e646f776c6973742d7468652d6c6973742d6f662d616c6c2d6f70656e2d6672616d6573223e710455063c2f6469763e71055d710628553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710755063c2f6469763e71085d71092855063c626f64793e710a55073c2f626f64793e710b5d710c2855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e710d55073c2f68746d6c3e710e4e6565656555073c2f6469763e0a710f55463c64697620636c6173733d2273656374696f6e222069643d2267657474696e672d616e642d73657474696e672d686561646c696e652d616e642d626f64792d74657874223e0a7110558d3c68313e3c6120636c6173733d22746f632d6261636b7265662220687265663d222369643522206e616d653d2267657474696e672d616e642d73657474696e672d686561646c696e652d616e642d626f64792d74657874223e47657474696e6720616e642073657474696e6720686561646c696e6520616e6420626f647920746578743c2f613e3c2f68313e0a7111652e"># For any position p, p.h is the headline and p.b is the body text.
print("head:",p.h)
print("body:",p.b)

p.setBodyString(p.b) # set p's body text.
p.setHeadString(p.h) # set p's headline text.</t>
<t tx="ekr.20060902092341.8" rst_http_attribute="5d71002855463c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d313122206e616d653d22687474702d6e6f64652d6d61726b65722d3131223e710155043c2f613e71025d71032855453c64697620636c6173733d2273656374696f6e222069643d2267657474696e672d616e642d73657474696e672d686561646c696e652d616e642d626f64792d74657874223e710455063c2f6469763e71055d710628553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710755063c2f6469763e71085d71092855063c626f64793e710a55073c2f626f64793e710b5d710c2855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e710d55073c2f68746d6c3e710e4e6565656555073c2f6469763e0a710f552f3c64697620636c6173733d2273656374696f6e222069643d2274726176657273696e672d6f75746c696e6573223e0a7110555f3c68313e3c6120636c6173733d22746f632d6261636b7265662220687265663d222369643622206e616d653d2274726176657273696e672d6f75746c696e6573223e54726176657273696e67206f75746c696e65733c2f613e3c2f68313e0a7111652e">@
The proper way to traverse an outline is with one of Leo's generators.</t>
<t tx="ekr.20060902092341.9"># Scripts and plugins should use p.copy() to 'capture' the value of a position:

p2 = p.copy()   # Correct: p2 will not change when p changes later.
p2 = p          # Wrong.  p2 will change after this assignment.

# For example, this creates a dictionary of positions, indexed by vnode.

d = {}
for p in c.all_positions():
    d[p.v] = p.copy()

print(d.get(c.rootPosition().v))

# **Warning** This dictionary will become invalid when the outline changes!
</t>
<t tx="ekr.20060902092341.10" rst_http_attribute="5d71002855463c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d313322206e616d653d22687474702d6e6f64652d6d61726b65722d3133223e710155043c2f613e71025d710328552e3c64697620636c6173733d2273656374696f6e222069643d2274726176657273696e672d6f75746c696e6573223e710455063c2f6469763e71055d710628553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710755063c2f6469763e71085d71092855063c626f64793e710a55073c2f626f64793e710b5d710c2855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e710d55073c2f68746d6c3e710e4e65656565552b3c64697620636c6173733d2273656374696f6e222069643d22632d616c6c6e6f6465732d69746572223e0a710f55573c68323e3c6120636c6173733d22746f632d6261636b7265662220687265663d222369643722206e616d653d22632d616c6c6e6f6465732d69746572223e632e616c6c4e6f6465735f697465723c2f613e3c2f68323e0a7110652e">@nocolor
The c.allNodes_iter iterator returns a list of all positions in the outline.
This script makes a list of all the nodes in an outline:
@color

    nodes = [p for p in c.allNodes_iter()]
    g.es("This outline contains %d nodes" % len(nodes))

@nocolor
Here is one way to count the nodes of an outline:
@color

    count = 0
    for p in c.allNodes_iter():
        count += 1
    g.es("This outline contains %d nodes" % count)

@nocolor
Here is a way to count the *distinct* vnodes of an outline:
@color

    positions = 0 ; tnodes = {}
    for p in c.allNodes_iter():
        positions += 1
        if not tnodes.get(p.v.t):
            tnodes[p.v.t] = p.v.t
    g.es("%8s positions" % positions)
    g.es("%8s vnodes" % len(tnodes.keys()))</t>
<t tx="ekr.20060902092341.11" rst_http_attribute="5d71002855463c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d313522206e616d653d22687474702d6e6f64652d6d61726b65722d3135223e710155043c2f613e71025d710328552a3c64697620636c6173733d2273656374696f6e222069643d22632d616c6c6e6f6465732d69746572223e710455063c2f6469763e71055d710628552e3c64697620636c6173733d2273656374696f6e222069643d2274726176657273696e672d6f75746c696e6573223e710755063c2f6469763e71085d710928553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710a55063c2f6469763e710b5d710c2855063c626f64793e710d55073c2f626f64793e710e5d710f2855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e711055073c2f68746d6c3e71114e656565656555073c2f6469763e0a7112552b3c64697620636c6173733d2273656374696f6e222069643d22702d6368696c6472656e2d69746572223e0a711355573c68323e3c6120636c6173733d22746f632d6261636b7265662220687265663d222369643822206e616d653d22702d6368696c6472656e2d69746572223e702e6368696c6472656e5f697465723c2f613e3c2f68323e0a7114652e">@nocolor
The p.children_iter iterator returns a list of all children of position p:
@color

    parent = p.parent()
    g.es("children of %s" % parent.headString(),color="purple")
    for p in parent.children_iter():
        g.es(p.headString())</t>
<t tx="ekr.20060902092341.12" rst_http_attribute="5d71002855463c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d313722206e616d653d22687474702d6e6f64652d6d61726b65722d3137223e710155043c2f613e71025d710328552a3c64697620636c6173733d2273656374696f6e222069643d22702d6368696c6472656e2d69746572223e710455063c2f6469763e71055d710628552e3c64697620636c6173733d2273656374696f6e222069643d2274726176657273696e672d6f75746c696e6573223e710755063c2f6469763e71085d710928553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710a55063c2f6469763e710b5d710c2855063c626f64793e710d55073c2f626f64793e710e5d710f2855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e711055073c2f68746d6c3e71114e656565656555073c2f6469763e0a711255463c64697620636c6173733d2273656374696f6e222069643d22702d706172656e74732d697465722d616e642d702d73656c662d616e642d706172656e74732d69746572223e0a7113558d3c68323e3c6120636c6173733d22746f632d6261636b7265662220687265663d222369643922206e616d653d22702d706172656e74732d697465722d616e642d702d73656c662d616e642d706172656e74732d69746572223e702e706172656e74735f6974657220616e6420702e73656c665f616e645f706172656e74735f697465723c2f613e3c2f68323e0a7114652e">@nocolor
The p.parents_iter iterator returns a list of all parents of position p, excluding p:
@color

    current = p.copy()
    g.es("inclusive parents of %s" % current.headString(),color="purple")
    for p in current.self_and_parents_iter():
        g.es(p.headString())

@nocolor
The p.self_and_parents_iter iterator returns a list of all parents of position p, including p:
@color

    current = p.copy()
    g.es("exclusive of %s" % current.headString(),color="purple")
    for p in current.parents_iter():
        g.es(p.headString())</t>
<t tx="ekr.20060902092341.13" rst_http_attribute="5d71002855463c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d313922206e616d653d22687474702d6e6f64652d6d61726b65722d3139223e710155043c2f613e71025d71032855453c64697620636c6173733d2273656374696f6e222069643d22702d706172656e74732d697465722d616e642d702d73656c662d616e642d706172656e74732d69746572223e710455063c2f6469763e71055d710628552e3c64697620636c6173733d2273656374696f6e222069643d2274726176657273696e672d6f75746c696e6573223e710755063c2f6469763e71085d710928553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710a55063c2f6469763e710b5d710c2855063c626f64793e710d55073c2f626f64793e710e5d710f2855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e711055073c2f68746d6c3e71114e656565656555073c2f6469763e0a711255493c64697620636c6173733d2273656374696f6e222069643d22702d7369626c696e67732d697465722d616e642d702d666f6c6c6f77696e672d7369626c696e67732d69746572223e0a711355943c68323e3c6120636c6173733d22746f632d6261636b7265662220687265663d22236964313022206e616d653d22702d7369626c696e67732d697465722d616e642d702d666f6c6c6f77696e672d7369626c696e67732d69746572223e702e7369626c696e67735f6974657220616e6420702e666f6c6c6f77696e675f7369626c696e67735f697465723c2f613e3c2f68323e0a7114652e">@nocolor
The p.siblings_iter iterator returns a list of all siblings of position p:
@color

    current = c.currentPosition()
    g.es("all siblings of %s" % current.headString(),color="purple")
    for p in current.self_and_siblings_iter():
        g.es(p.headString())

@nocolor
The p.following_siblings_iter iterator returns a list of all siblings that follow position p:
@color

    current = c.currentPosition()
    g.es("following siblings of %s" % current.headString(),color="purple")
    for p in current.following_siblings_iter():
        g.es(p.headString())</t>
<t tx="ekr.20060902092341.14" rst_http_attribute="5d71002855463c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d323122206e616d653d22687474702d6e6f64652d6d61726b65722d3231223e710155043c2f613e71025d71032855483c64697620636c6173733d2273656374696f6e222069643d22702d7369626c696e67732d697465722d616e642d702d666f6c6c6f77696e672d7369626c696e67732d69746572223e710455063c2f6469763e71055d710628552e3c64697620636c6173733d2273656374696f6e222069643d2274726176657273696e672d6f75746c696e6573223e710755063c2f6469763e71085d710928553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710a55063c2f6469763e710b5d710c2855063c626f64793e710d55073c2f626f64793e710e5d710f2855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e711055073c2f68746d6c3e71114e656565656555073c2f6469763e0a711255463c64697620636c6173733d2273656374696f6e222069643d22702d737562747265652d697465722d616e642d702d73656c662d616e642d737562747265652d69746572223e0a7113558e3c68323e3c6120636c6173733d22746f632d6261636b7265662220687265663d22236964313122206e616d653d22702d737562747265652d697465722d616e642d702d73656c662d616e642d737562747265652d69746572223e702e737562747265655f6974657220616e6420702e73656c665f616e645f737562747265655f697465723c2f613e3c2f68323e0a7114652e">@nocolor
The p.subtree_iter iterator returns a list of all positions in p's subtree, excluding p:
@color

    parent = p.parent()
    g.es("inclusive subtree of %s" % parent.headString(),color="purple")
    for p in parent.self_and_subtree_iter():
        g.es(p.headString())

@nocolor
The p.self_and_subtree_iter iterator returns a list of all positions in p's subtree, including p:
@color

    parent = p.parent()
    g.es("exclusive subtree of %s" % parent.headString(),color="purple")
    for p in parent.subtree_iter():
        g.es(p.headString())</t>
<t tx="ekr.20060902092341.15" rst_http_attribute="5d71002855463c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d323322206e616d653d22687474702d6e6f64652d6d61726b65722d3233223e710155043c2f613e71025d71032855453c64697620636c6173733d2273656374696f6e222069643d22702d737562747265652d697465722d616e642d702d73656c662d616e642d737562747265652d69746572223e710455063c2f6469763e71055d710628552e3c64697620636c6173733d2273656374696f6e222069643d2274726176657273696e672d6f75746c696e6573223e710755063c2f6469763e71085d710928553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710a55063c2f6469763e710b5d710c2855063c626f64793e710d55073c2f626f64793e710e5d710f2855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e711055073c2f68746d6c3e71114e656565656555073c2f6469763e0a7112553f3c64697620636c6173733d2273656374696f6e222069643d2274657374696e672d776865746865722d612d706f736974696f6e2d69732d76616c6964223e0a711355803c68323e3c6120636c6173733d22746f632d6261636b7265662220687265663d22236964313222206e616d653d2274657374696e672d776865746865722d612d706f736974696f6e2d69732d76616c6964223e54657374696e672077686574686572206120706f736974696f6e2069732076616c69643c2f613e3c2f68323e0a7114652e">@nocolor
The tests:
@color

    if p:       # Right
    if not p:   # Right

@nocolor
are the **only** correct ways to test whether a position p is valid.
In particular, the following **will not work**:
@color

    if p is None:       # Wrong
    if p is not None:   # Wrong</t>
<t tx="ekr.20060902092341.16" rst_http_attribute="5d71002855463c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d323522206e616d653d22687474702d6e6f64652d6d61726b65722d3235223e710155043c2f613e71025d710328553e3c64697620636c6173733d2273656374696f6e222069643d2274657374696e672d776865746865722d612d706f736974696f6e2d69732d76616c6964223e710455063c2f6469763e71055d710628552e3c64697620636c6173733d2273656374696f6e222069643d2274726176657273696e672d6f75746c696e6573223e710755063c2f6469763e71085d710928553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710a55063c2f6469763e710b5d710c2855063c626f64793e710d55073c2f626f64793e710e5d710f2855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e711055073c2f68746d6c3e71114e656565656555073c2f6469763e0a711255073c2f6469763e0a7113552f3c64697620636c6173733d2273656374696f6e222069643d227570646174696e672d7468652d73637265656e223e0a711455603c68313e3c6120636c6173733d22746f632d6261636b7265662220687265663d22236964313322206e616d653d227570646174696e672d7468652d73637265656e223e5570646174696e67207468652073637265656e3c2f613e3c2f68313e0a7115652e">@nocolor
You can use c.redraw_now to redraw the entire screen immediately:
@color

    c.redraw_now()

@nocolor
However, Leo's code redraws the screen using the following pattern:
@color
    
    c.beginUpdate()
    try:
        &lt;&lt; whatever &gt;&gt;
    finally:
        c.endUpdate()

@nocolor
This suppresses redraws inside &lt;&lt;whatever&gt;&gt; that would otherwise be caused by
c.endUpdate. c.endUpdate takes an optional argument:
@color

    c.endUpdate(flag)

@nocolor
redraws the screen only if flag is True. This is an important pattern. Leo uses
c.beginUpdate and c.endUpdate almost everywhere to redraw the screen, so
provided that &lt;&lt; whatever &gt;&gt; contains no calls to c.redraw_now this pattern
insures that at most one redraw occurs.</t>
<t tx="ekr.20060902092341.17" rst_http_attribute="5d71002855463c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d323722206e616d653d22687474702d6e6f64652d6d61726b65722d3237223e710155043c2f613e71025d710328552e3c64697620636c6173733d2273656374696f6e222069643d227570646174696e672d7468652d73637265656e223e710455063c2f6469763e71055d710628553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710755063c2f6469763e71085d71092855063c626f64793e710a55073c2f626f64793e710b5d710c2855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e710d55073c2f68746d6c3e710e4e6565656555073c2f6469763e0a710f553a3c64697620636c6173733d2273656374696f6e222069643d22696e766f6b696e672d636f6d6d616e64732d66726f6d2d73637269707473223e0a711055763c68313e3c6120636c6173733d22746f632d6261636b7265662220687265663d22236964313422206e616d653d22696e766f6b696e672d636f6d6d616e64732d66726f6d2d73637269707473223e496e766f6b696e6720636f6d6d616e64732066726f6d20736372697074733c2f613e3c2f68313e0a7111652e">@nocolor
Leo dispatches commands using c.doCommand,
which calls the "command1" and "command2" hook routines for the given label.
c.doCommand catches all exceptions thrown by the command:
@color

    c.doCommand(c.markHeadline,label="markheadline")

@nocolor
You can also call command handlers directly so that hooks will not be called:
@color

    c.markHeadline()

@nocolor
You can invoke minibuffer commands by name.  For example:
@color

    c.executeMinibufferCommand('open-outline')

@nocolor
c.keyHandler.funcReturn contains the value returned from the command.
In many cases, as above, this value is simply 'break'.</t>
<t tx="ekr.20060902092341.18">@nocolor
Any .leo file may contain an @settings tree, so settings may be different for each commander.
Plugins and other scripts can get the value of settings as follows:
@color

    format_headlines = c.config.getBool('rst3_format_headlines')
    g.es('format_headlines',format_headlines)

@nocolor
The c.config class has the following getters.
See the configSettings in leoCommands.py for details:

    getBool
    getColor
    getDirectory
    getFloat
    getInt
    getLanguage
    getRatio
    getShortcut
    getString

You can set any *existing* item in an @settings tree with c.config.set(p,setting,val).
For example:
@color

    for val in (False,True):
        c.config.set(p,'rst3_format_headlines',val)
        format_headlines = c.config.getBool('rst3_format_headlines')
        g.es('format_headlines',format_headlines)

@nocolor
c.config.set does not change the @settings tree; it simply changes the values returned by the getters.</t>
<t tx="ekr.20060902092341.19" rst_http_attribute="5d71002855463c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d323922206e616d653d22687474702d6e6f64652d6d61726b65722d3239223e710155043c2f613e71025d71032855393c64697620636c6173733d2273656374696f6e222069643d22696e766f6b696e672d636f6d6d616e64732d66726f6d2d73637269707473223e710455063c2f6469763e71055d710628553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710755063c2f6469763e71085d71092855063c626f64793e710a55073c2f626f64793e710b5d710c2855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e710d55073c2f68746d6c3e710e4e6565656555073c2f6469763e0a710f553b3c64697620636c6173733d2273656374696f6e222069643d2267657474696e672d616e642d73657474696e672d707265666572656e636573223e0a711055783c68313e3c6120636c6173733d22746f632d6261636b7265662220687265663d22236964313522206e616d653d2267657474696e672d616e642d73657474696e672d707265666572656e636573223e47657474696e6720616e642073657474696e6720707265666572656e6365733c2f613e3c2f68313e0a7111652e">@nocolor
Each commander maintains its own preferences.
Your scripts can get the following ivars:
@color

    ivars = (
        'output_doc_flag',
        'page_width',
        'page_width',
        'tab_width',
        'tangle_batch_flag',
        'tangle_directory',
        'target_language',
        'untangle_batch_flag',
        'use_header_flag',
    )
    
    g.es("Prefs ivars...\n",color="purple")
    for ivar in ivars:
        g.es(getattr(c,ivar))

@nocolor
If your script sets c.tab_width your script may call f.setTabWidth to redraw the screen:
@color

    c.tab_width = -4    # Change this and see what happens.
    c.frame.setTabWidth(c.tab_width)</t>
<t tx="ekr.20060902092341.20" rst_http_attribute="5d71002855463c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d333122206e616d653d22687474702d6e6f64652d6d61726b65722d3331223e710155043c2f613e71025d710328553a3c64697620636c6173733d2273656374696f6e222069643d2267657474696e672d616e642d73657474696e672d707265666572656e636573223e710455063c2f6469763e71055d710628553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710755063c2f6469763e71085d71092855063c626f64793e710a55073c2f626f64793e710b5d710c2855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e710d55073c2f68746d6c3e710e4e6565656555073c2f6469763e0a710f55503c64697620636c6173733d2273656374696f6e222069643d2266756e6374696f6e732d666f722d66696e64696e672d616e642d6368616e67696e672d746578742d66726f6d2d73637269707473223e0a711055a23c68313e3c6120636c6173733d22746f632d6261636b7265662220687265663d22236964313622206e616d653d2266756e6374696f6e732d666f722d66696e64696e672d616e642d6368616e67696e672d746578742d66726f6d2d73637269707473223e46756e6374696f6e7320666f722066696e64696e6720616e64206368616e67696e6720746578742066726f6d20736372697074733c2f613e3c2f68313e0a7111652e">@nocolor
The file leoFindScript.py contains functions for finding and changing text
from within scripts.  See leoFindScript.py in LeoPy.leo for full details.

The findall function returns a list of tuples (v,pos) describing matches in
c's entire tree:
@color

    import leoFindScript

    pattern="import leoGlobals as g"
    result = leoFindScript.findAll(c,pattern,bodyFlag=1)
    
    g.es("%-3d instances of: '%s'...\n" % (len(result),pattern),color="purple")
    
    for v,pos in result:
        body = v.bodyString()
        g.es('\n%-4d %s' % (pos,v.headString()))
        g.es(g.get_line_after(body,pos))

@nocolor
The reFindall function returns a list of tuples (v,mo,pos), where mo
is a MatchObject. The reFlags argument are flags to re.search:
@color

    import leoFindScript

    pattern="from .* import"
    result = leoFindScript.reFindAll(c,pattern,bodyFlag=1,reFlags=None)

    g.es("%-3d instances of: '%s'...\n" % (len(result),pattern),color="purple")
    for v,mo,pos in result:
        body = v.bodyString()
        g.es('\n%-4d %s' % (pos,v.headString()))
        g.es(g.get_line_after(body,pos))</t>
<t tx="ekr.20060902092341.21" rst_http_attribute="5d71002855463c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d333722206e616d653d22687474702d6e6f64652d6d61726b65722d3337223e710155043c2f613e71025d71032855263c64697620636c6173733d2273656374696f6e222069643d22672d726566696e64616c6c223e710455063c2f6469763e71055d710628554f3c64697620636c6173733d2273656374696f6e222069643d2266756e6374696f6e732d666f722d66696e64696e672d616e642d6368616e67696e672d746578742d66726f6d2d73637269707473223e710755063c2f6469763e71085d710928553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710a55063c2f6469763e710b5d710c2855063c626f64793e710d55073c2f626f64793e710e5d710f2855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e711055073c2f68746d6c3e71114e656565656555073c2f6469763e0a711255073c2f6469763e0a711355353c64697620636c6173733d2273656374696f6e222069643d2272756e6e696e672d6c656f2d696e2d62617463682d6d6f6465223e0a7114556c3c68313e3c6120636c6173733d22746f632d6261636b7265662220687265663d22236964313922206e616d653d2272756e6e696e672d6c656f2d696e2d62617463682d6d6f6465223e52756e6e696e67204c656f20696e206261746368206d6f64653c2f613e3c2f68313e0a7115652e">@nocolor
On startup, Leo looks for two arguments of the form:

    --script scriptFile

If found, Leo enters batch mode. In batch mode Leo does not show any windows.
Leo assumes the scriptFile contains a Python script and executes the contents of
that file using Leo's Execute Script command. By default, Leo sends all
output to the console window. Scripts in the scriptFile may disable or enable
this output by calling app.log.disable or app.log.enable

Scripts in the scriptFile may execute any of Leo's commands except the Edit Body
and Edit Headline commands. Those commands require interaction with the user.
For example, the following batch script reads a Leo file and prints all the
headlines in that file:
@color

    path = r"c:\prog\leoCVS\leo\test\test.leo"
   
    g.app.log.disable() # disable reading messages while opening the file
    flag,newFrame = g.openWithFileName(path,None)
    g.app.log.enable() # re-enable the log.
    
    for p in newFrame.c.allNodes_iter():
        g.es(g.toEncodedString(p.headString(),"utf-8"))</t>
<t tx="ekr.20060902092341.22" rst_http_attribute="5d71002855463c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d333922206e616d653d22687474702d6e6f64652d6d61726b65722d3339223e710155043c2f613e71025d71032855343c64697620636c6173733d2273656374696f6e222069643d2272756e6e696e672d6c656f2d696e2d62617463682d6d6f6465223e710455063c2f6469763e71055d710628553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710755063c2f6469763e71085d71092855063c626f64793e710a55073c2f626f64793e710b5d710c2855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e710d55073c2f68746d6c3e710e4e6565656555073c2f6469763e0a710f553e3c64697620636c6173733d2273656374696f6e222069643d2266756e6374696f6e732d646566696e65642d696e2d6c656f676c6f62616c732d7079223e0a7110557e3c68313e3c6120636c6173733d22746f632d6261636b7265662220687265663d22236964323022206e616d653d2266756e6374696f6e732d646566696e65642d696e2d6c656f676c6f62616c732d7079223e46756e6374696f6e7320646566696e656420696e206c656f476c6f62616c732e70793c2f613e3c2f68313e0a7111652e">@nocolor
leoGlobals.py contains many utility functions and constants.
The following script prints all the names defined in leoGlobals.py:
@color

    g.es("Names defined in leoGlobals.py",color="purple")
    names = g.__dict__.keys()
    names.sort()
    for name in names:
        g.es(name)</t>
<t tx="ekr.20060902092341.23" rst_http_attribute="5d71002855463c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d343122206e616d653d22687474702d6e6f64652d6d61726b65722d3431223e710155043c2f613e71025d710328553d3c64697620636c6173733d2273656374696f6e222069643d2266756e6374696f6e732d646566696e65642d696e2d6c656f676c6f62616c732d7079223e710455063c2f6469763e71055d710628553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710755063c2f6469763e71085d71092855063c626f64793e710a55073c2f626f64793e710b5d710c2855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e710d55073c2f68746d6c3e710e4e6565656555073c2f6469763e0a710f553b3c64697620636c6173733d2273656374696f6e222069643d227265646972656374696e672d6f75747075742d66726f6d2d73637269707473223e0a711055783c68313e3c6120636c6173733d22746f632d6261636b7265662220687265663d22236964323122206e616d653d227265646972656374696e672d6f75747075742d66726f6d2d73637269707473223e5265646972656374696e67206f75747075742066726f6d20736372697074733c2f613e3c2f68313e0a7111652e">@nocolor
leoGlobals.py defines 6 convenience methods for redirecting stdout and stderr:
@color

    g.redirectStderr() # Redirect stderr to the current log pane.
    g.redirectStdout() # Redirect stdout to the current log pane.
    g.restoreStderr()  # Restores stderr so it prints to the console window.
    g.restoreStdout()  # Restores stdout so it prints to the console window.
    g.stdErrIsRedirected() # Returns True if the stderr stream is redirected to the log pane.
    g.stdOutIsRedirected() # Returns True if the stdout stream is redirected to the log pane.

@nocolor
Calls need *not* be paired. Redundant calls are ignored and the last call made
controls where output for each stream goes.
**Note**: you must execute Leo in a console window to see non-redirected output from the print statement:
@color

    print "stdout isRedirected:", g.stdOutIsRedirected()
    print "stderr isRedirected:", g.stdErrIsRedirected()

    g.redirectStderr()
    print "stdout isRedirected:", g.stdOutIsRedirected()
    print "stderr isRedirected:", g.stdErrIsRedirected()

    g.redirectStdout()
    print "stdout isRedirected:", g.stdOutIsRedirected()
    print "stderr isRedirected:", g.stdErrIsRedirected()

    g.restoreStderr()
    print "stdout isRedirected:", g.stdOutIsRedirected()
    print "stderr isRedirected:", g.stdErrIsRedirected()

    g.restoreStdout()
    print "stdout isRedirected:", g.stdOutIsRedirected()
    print "stderr isRedirected:", g.stdErrIsRedirected()</t>
<t tx="ekr.20060902092341.24">@nocolor
**New in Leo 4.4a2**: Plugins and scripts can create new tabs in the log panel.
The following creates a tab named test or make it visible if it already exists:
@color
 
    c.frame.log.selectTab('Test')

@nocolor
When first created, a tab contains a text widget.
The c.frame.log class contains the following 'official' ivars:

- c.frame.log.tabName is the name of the active tab.
- c.frame.log.tabFrame is the Tk.Frame containing all the other widgets of the tab.
- c.frame.log.logCtrl is the initial Tk.Text widget.

The following line removes the initial text widget:
@color
    
    c.frame.log.logCtrl.pack_forget()

@nocolor
To make the text widget visible again:
@color

    c.frame.log.logCtrl.pack(side='top',expand=1,fill='both')

@nocolor
Plugins and scripts can pack any other widgets into c.frame.log.tabFrame.
For example, the following replaces the default text widget with a red box:
@color

    import Tkinter as Tk ; log = c.frame.log
    log.selectTab('Test')
    log.logCtrl.pack_forget()
    f = Tk.Frame(log.tabFrame,bg='red',height='1inch',width='2inch')
    f.pack(side='left',expand=0,fill='none')

@nocolor
Notes:

- g.es, g.enl, g.ecnl, g.ecnls write to the log tab specified by the optional
  tabName argument. The default for tabName is 'Log', so existing code works as
  before.

- The put and putnl methods of the tkinterLog class also take an optional
  tabName argument which defaults to 'Log'.</t>
<t tx="ekr.20060902092341.25" rst_http_attribute="5d71002855463c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d343322206e616d653d22687474702d6e6f64652d6d61726b65722d3433223e710155043c2f613e71025d710328553a3c64697620636c6173733d2273656374696f6e222069643d227265646972656374696e672d6f75747075742d66726f6d2d73637269707473223e710455063c2f6469763e71055d710628553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710755063c2f6469763e71085d71092855063c626f64793e710a55073c2f626f64793e710b5d710c2855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e710d55073c2f68746d6c3e710e4e6565656555073c2f6469763e0a710f55453c64697620636c6173733d2273656374696f6e222069643d2273756d6d6172792d6f662d7468652d766e6f64652d616e642d706f736974696f6e2d636c6173736573223e0a7110558c3c68313e3c6120636c6173733d22746f632d6261636b7265662220687265663d22236964323222206e616d653d2273756d6d6172792d6f662d7468652d766e6f64652d616e642d706f736974696f6e2d636c6173736573223e53756d6d617279206f662074686520766e6f646520616e6420706f736974696f6e20636c61737365733c2f613e3c2f68313e0a7111652e">Most scripts will use methods of the position class to access information in an
outline. The following sections summarizes the most useful methods that your
scripts can use. For a complete list, see the leoNodes.py in of LeoPy.leo.</t>
<t tx="ekr.20060902092341.26" rst_http_attribute="5d71002855463c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d343522206e616d653d22687474702d6e6f64652d6d61726b65722d3435223e710155043c2f613e71025d71032855443c64697620636c6173733d2273656374696f6e222069643d2273756d6d6172792d6f662d7468652d766e6f64652d616e642d706f736974696f6e2d636c6173736573223e710455063c2f6469763e71055d710628553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710755063c2f6469763e71085d71092855063c626f64793e710a55073c2f626f64793e710b5d710c2855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e710d55073c2f68746d6c3e710e4e6565656555253c64697620636c6173733d2273656374696f6e222069643d226974657261746f7273223e0a710f554c3c68323e3c6120636c6173733d22746f632d6261636b7265662220687265663d22236964323322206e616d653d226974657261746f7273223e4974657261746f72733c2f613e3c2f68323e0a7110652e">@nocolor
Iterators exist only in the position class:
@color

	c.allNodes_iter            # returns all positions in c's outline.
	p.children_iter            # returns all children of p.
	p.parents_iter             # returns all parents of p.
	p.self_and_parents_iter    # returns p and all parents of p.
	p.siblings_iter            # returns all siblings of p, including p.
	p.following_siblings_iter  # returns all siblings following p.
	p.subtree_iter             # returns all positions in p's subtree, excluding p.
	p.self_and_subtree_iter    # returns all positions in p's subtree, including p.</t>
<t tx="ekr.20060902092341.27" rst_http_attribute="5d71002855463c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d343722206e616d653d22687474702d6e6f64652d6d61726b65722d3437223e710155043c2f613e71025d71032855243c64697620636c6173733d2273656374696f6e222069643d226974657261746f7273223e710455063c2f6469763e71055d71062855443c64697620636c6173733d2273656374696f6e222069643d2273756d6d6172792d6f662d7468652d766e6f64652d616e642d706f736974696f6e2d636c6173736573223e710755063c2f6469763e71085d710928553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710a55063c2f6469763e710b5d710c2855063c626f64793e710d55073c2f626f64793e710e5d710f2855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e711055073c2f68746d6c3e71114e656565656555073c2f6469763e0a711255233c64697620636c6173733d2273656374696f6e222069643d2267657474657273223e0a711355483c68323e3c6120636c6173733d22746f632d6261636b7265662220687265663d22236964323422206e616d653d2267657474657273223e476574746572733c2f613e3c2f68323e0a7114652e">@nocolor
p.c is an 'official' ivar of the position class.  p.c is p's commander.

Here are the most useful getters of the vnode and position classes.
    
Returning strings:
@color

    p.bodyString() # the body string of p.
    p.headString() # the headline string of p.
    
@nocolor
Returning ints:
@color

    p.childIndex()
    p.numberOfChildren()
    p.level()
   
@nocolor 
Returning bools representing property bits:
@color

    p.hasChildren()
    p.isAncestorOf(v2) # True if v2 is a child, grandchild, etc. of p.
    p.isCloned()
    p.isDirty()
    p.isExpanded()
    p.isMarked()
    p.isVisible()
    p.isVisited()</t>
<t tx="ekr.20060902092341.28" rst_http_attribute="5d71002855463c6120636c6173733d22746172676574222069643d22687474702d6e6f64652d6d61726b65722d343922206e616d653d22687474702d6e6f64652d6d61726b65722d3439223e710155043c2f613e71025d71032855223c64697620636c6173733d2273656374696f6e222069643d2267657474657273223e710455063c2f6469763e71055d71062855443c64697620636c6173733d2273656374696f6e222069643d2273756d6d6172792d6f662d7468652d766e6f64652d616e642d706f736974696f6e2d636c6173736573223e710755063c2f6469763e71085d710928553f3c64697620636c6173733d22646f63756d656e74222069643d22636861707465722d372d736372697074696e672d6c656f2d776974682d707974686f6e223e710a55063c2f6469763e710b5d710c2855063c626f64793e710d55073c2f626f64793e710e5d710f2855433c68746d6c20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f313939392f7868746d6c2220786d6c3a6c616e673d22656e22206c616e673d22656e223e711055073c2f68746d6c3e71114e656565656555073c2f6469763e0a711255233c64697620636c6173733d2273656374696f6e222069643d2273657474657273223e0a711355483c68323e3c6120636c6173733d22746f632d6261636b7265662220687265663d22236964323522206e616d653d2273657474657273223e536574746572733c2f613e3c2f68323e0a7114652e">@nocolor
Here are the most useful setters of the Commands and position classes.
The following setters of the position class regardless of whether
p is the presently selected position:
@color

    p.setBodyString(s)  # Sets the body text of p.
    p.setHeadStringOrHeadline(s)  # Sets the headline text of p.

@nocolor
Moving nodes:
@color

    p.moveAfter(v2)           # move p after v2
    p.moveToNthChildOf(v2,n)  # move p to the n'th child of v2
    p.moveToRoot(oldRoot)     # make p the root position.
                              # oldRoot must be the old root position if it exists.
                              
@nocolor
The "visited" bit may be used by commands or scripts for any purpose.
Many commands use this bits for tree traversal, so these bits do not persist:
@color

    c.clearAllVisited() # Clears all visited bits in c's tree.
    p.clearVisited()
    p.setVisited()</t>
<t tx="ekr.20060902092341.29">@nocolor
Creating a script button should be your first thought whenever you want to
automate any task. The scripting plugin, mod_scripting.py, puts two buttons
in the icon menu, a pink Run Script button and a yellow Script Button
button. The Run Script button does the same thing as the Execute Script
command. The Script Button button is the interesting one. It creates a
button, confusingly called a **script button** in the icon area. A script button
executes a script when you push it.

Suppose node N is selected. When you press the Script Button button a new
(pink) script button is created. The name of the new button is N's headline
text. The script associated with the new button is N's body text. Now whenever
you press the new button, N's script is executed on the **presently** selected
node. Script buttons are extraordinarily useful. In effect, each script button
defines an instant command! For example, sometimes my fingers get tired of
saving a file. I simply put Save in a node's headline and c.save() in
the body text. I hit the Script Button button and I get a new button called
Save that will save the outline when I press it.

Here's a more interesting example. The following script searches the present node
and its ancestors looking for an @rst node. When such a node is found the
script calls the `rst3 plugin`_ to format it. I don't have to select the actual
@rst node; I can select any of its children:
@color

    import leoPlugins
    rst3 = leoPlugins.getPluginModule('rst3')
    if rst3: # already loaded.
        controller = rst3.controllers.get(c)
        if controller:
            for p in p.self_and_parents_iter():
                if p.headString().startswith('@rst '):
                    controller.processTree(p)
                    break
    else: # Just load the plugin.
        rst3 = leoPlugins.loadOnePlugin('rst3',verbose=True)
        if rst3:
            g.es('rst3 loaded')
            rst3.onCreate('tag',{'c':c})
        else:
            # Ask to be removed.
            g.app.scriptDict['removeMe'] = True

@nocolor
**Notes**:

-   The scripting plugin pre-defines the c, g and p symbols
    just as the Execute Script command does.

-   By default a script button executes the **present** body text of the node that original created the script button.
    This is very handy: you can modify a script button's script at any time without having to recreate the script button.

-   You can delete any script button by right-clicking on it.

-   On startup, the scripting plugin scans the entire .leo file and creates a script button
    for every node whose headline starts with @button scriptName.
    **Warning**: this is indeed a security risk of the kind discussed later.
    This feature can be disabled by setting atButtonNodes = True at the start of mod_scripting.py.</t>
<t tx="ekr.20060902092341.30">@test and @suite nodes are a major advance in unit testing. Such nodes
have headlines that start with @test or @suite. The file test.leo
contains many examples of @test and @suite nodes. @test and
@suite nodes are a direct outgrowth of script buttons. The unit test
script button in test.leo scans the selected outline, creating one unit test
for each test node and zero or more unit tests for each @suite node. The
unit test script then runs all the selected unit tests.</t>
<t tx="ekr.20060902095933">@nocolor
@test nodes create a single unit test from the script in its body
**without having to create a subclass of unittest.TestCase**.
For example, here is a complete unit test.  The headline is:
@color

    @test p.t == p.v.t

@nocolor
The body text is:
@color

    # NOTE: p.__getattr__ must be enabled for this test to work.
    root = c.rootPosition()
    for p in root.allNodes_iter():
        assert(p.t == p.v.t)
        
@nocolor
**That's all!** The headline marks the node as containing a unit test.
The body text contains the meat of the test.  No cruft at all!

**Notes**: The unit tests created from @test nodes define setUp and
tearDown methods. These methods ensure that the script being executed is
the presently selected node. The scripts in @test nodes can not override
the setUp and tearDown methods. In practice, this is not a problem
because the scripts in @test nodes are typically very simple. Such
scripts can use try/finally if they need to clean up after themselves.
Scripts in @test nodes often assume that descendant nodes hold test
data. Scripts in @test nodes can generally define and use sections, but
scripts may not use the @others directive if descendant nodes hold
data.
</t>
<t tx="ekr.20060902095933.1">@nocolor
@suite are an easy way to run legacy unit tests. The Unit Test
button assumes that the body text of an @suite node is a script that
creates a test suite and leaves the result in g.app.scriptDict['suite'].
test.leo several examples of @suite nodes.
Here is an @suite node that executes all doctests in Leo's sources.
The headline is:
@color

    @suite run all doctests

The body text is:
@color

    import unittest
    import leoTest
    import sys
    
    # DocTestSuite exists in Python 2.3 and above.
    if g.CheckVersion(sys.version, "2.3"):
        path = g.os_path_join(g.app.loadDir,"..","src")
        modules = leoTest.importAllModulesInPath(path)
        suite = leoTest.createUnitTestsFromDoctests(modules)                     
        if suite:
            g.app.scriptDict['suite'] = suite
    else:
        # Create an empty suite to suppress a warning.
        g.app.scriptDict['suite'] = unittest.TestSuite()
        print "Can't create unit tests from doctests"
        print "doctest.DocTestSuite requires Python 2.3 or above."

@nocolor
The real work of creating the test suites is done by
leoTest.createUnitTestsFromDoctests.

**Important**: if the suite was created successfully, the script must pass the suite
to script in the unit test script button by as follows:
@color

    g.app.scriptDict['suite'] = suite

@nocolor
@button unit test
The script in the Unit Test script button in test.leo is just:
@color

    import leoTest
    leoTest.doTests(all=False)

@nocolor
test.leo defines the leoTest module. The doTests function is the
code that supports @test and @suite nodes. **Important**: you could
customize how @test and @suite nodes work by using your own script
in the @button unit test node.</t>
<t tx="ekr.20060902100250">This is the end of the 'Scripting Leo' slide show.</t>
<t tx="ekr.20060902101656">@language rest</t>
<t tx="ekr.20070315073704"></t>
<t tx="ekr.20070315073704.1">plugins_menu.py
# plugin_manager.py
# attrib_edit.py
open_with.py
mod_scripting.py
rst3.py
slideshow.py
UNL.py
nav_buttons.py</t>
<t tx="ekr.20070315073704.2">For MacOS X (darwin) the following are typical defaults:

vim_cmd = /Applications/gvim.app/Contents/MacOS/gvim --servername LEO
vim_exe = /Applications/gvim.app/Contents/MacOS/gvim
</t>
<t tx="ekr.20070315073704.3"></t>
<t tx="ekr.20070315073704.4"></t>
<t tx="ekr.20080129151123"></t>
<t tx="ekr.20080129151228" str_leo_pos="4"></t>
<t tx="ekr.20091103090815.1426"># To create a tab named 'Test' or make it visible if it already exists:
log = c.frame.log
log.selectTab('Test')
log.clearTab('Test')

# When first created, a tab contains a Tk.Text widget.
# To write to this widget, add the tabName argument to g.es:
g.es('Test',color='blue',tabName='Test')
</t>
<t tx="ekr.20091103090815.1427">@
The Execute Script command predefines three variables, c, g and p.
    c is the commander (see below) of the outline containing the script.
    g is the leo.core.leoGlobals module, containing global functions.
    p is the position (see below) of the presently selected node in the outline.
@c

for z in (c,g,p):
    print(z)</t>
<t tx="ekr.20091103090815.1428">@
g.app is the **application object** representing the entire Leo application.
The ivars (instance variables) of g.app represent Leo's global variables.
@c

print(g.app)
</t>
<t tx="ekr.20091103090815.1429">@
A commander is a controller (in model/view/controller terminology).
Each open Leo window has its own commander.
Commanders contain data describing the window.

c.rootPosition() is the position (see below) of the outline's root node.
c.currentPosition() is the position of the outline's presently selected node.
@c

print(c.rootPosition())
print(c.currentPosition())</t>
<t tx="ekr.20091103090815.1430">@
A position represents the location of a particular node *in a tree traversal*.
Positions are the primary way to access data in Leo.

For any position p, p.v is p's outline node (vnode)
@c

print(p.v)

@
Iterators are the primary way of traversing the data in Leo outlines.
In effect, iterators return a list of positions.
@c

print('%d positions' % len(list(c.all_positions())))
print('%d unique nodes' % len(list(c.all_unique_nodes())))

</t>
<t tx="ekr.20091103090815.1431">@
Frames contains all the internal data needed to manage a Leo window.
c.frame is commander's frame.
@c

f = c.frame
print(f)

# "Official" components of c.frame:
print (f.c) # The frame's commander
print(f.log) # The log pane.
print(f.tree) # The outline pane.
print(f.body) # The body pane.
</t>
<t tx="ekr.20091103090815.1432">@
A vnode represents node in Leo's outline, including all clones of the node.
By convention, variables named v, v1 or v2 refer to vnodes.

For any position p, p.v is the vnode at that position,
p.h is the headline text and p.b is the body text.
@c

print (len(p.b),p.h)
</t>
<t tx="ekr.20091103090815.1433">@ The following slides list useful methods for scripting Leo.</t>
<t tx="ekr.20091104114053.3903"></t>
<t tx="ekr.20091107071654.1488">Leo's outlines are composed of **nodes**.

Nodes consist of **headlines* and **body text**.

The **outline pane** at the top left shows headlines.

Selecting a headline in the outline pane shows the body text in the **body
pane** at the bottom.

The **log window** is at the top right.

An emacs-like minibuffer is at the bottom.

You can do everything with keystrokes: no mouse is needed.</t>
<t tx="ekr.20091107071654.1493">Leo has gone far beyond my wildest hopes. I have Leo's users to thank for that.

I would never again willing program without Leo. All of Leo's sources,
documentation and scripts are contained in Leo outlines.

Leo's mission is to be the ultimate power tool for managing complex data like
computer programs, books and databases.  This task will never be finished.

Leo has a large community of users who push Leo in new directions.

Leo is a playground for exploring how to apply scripts to outlines.</t>
<t tx="ekr.20091107071654.1501">Leo outlines are more flexible than ordinary outlines.

**Clones** are nodes that appear in multiple places in the outline.

With clones, your data are *not* limited to a hierarchy:

- You can organize a *single* Leo outline in as many ways as you like.
- You don't have to choose a single "right" way to view your data.
- You can create a new view of (or relation on) your data at any time.

Views (relations) are normal parts of a Leo outline, not something tacked onto the outline.

In technical terms, a Leo outline is a DAG (Directed Acyclic Graph), not just a tree.
</t>
<t tx="ekr.20091107071654.1502">Leo's power comes from applying Python scripts to Leo's outlines.

That's *all*.

We'll see how this works in the next few slides.
</t>
<t tx="ekr.20091107071654.1503">Any node can contain a Python script.

You can use a Leo outline as filing cabinet for scripts. Because of clones,
this filing cabinet is more flexible than usual.

But this is a trivial way of combining outlines and scripts.

There are many more ways, some not at all obvious.</t>
<t tx="ekr.20091107071654.1506">We call any script in a Leo outline a **Leo script** because all such scripts have
*easy* access to *all* the data in the outline.

In fancy words, Leo has a DOM (Document Object Model).</t>
<t tx="ekr.20091107071654.1507">Leo's execute-script command **composes** scripts from an outline node and its
descendants.

The composition rules are simple, but they allow you to organize
scripts any way you like.</t>
<t tx="ekr.20091107071654.1511">Leo creates an environment in which some tasks become easier, and others
just *disappear*.  Some dogs that aren't barking:

- Leo remembers what you were doing the last time you worked on an outline.
  This is a small detail that makes a big difference.

- You almost never happen to open files in Leo. Leo loads @&lt;file&gt; nodes
  automatically when you load a Leo outline.
  
- Your views of data are permanent, until you decide you don't need them. You
  don't have to continually reinvent them.
  
- Views eliminate the need to search for text, and for bookmarks, etc.</t>
<t tx="ekr.20091107071654.1512">@
Everything from '@' to '@c' is a comment.

It is easy to use Leo's DOM: Leo's execute-script command predefines c and g and p:

- c is the "commander" of the outline, giving full access to all it's data.
- g is part of Leo's sources containing global utility classes and methods.
- p is the presently selected position.
@c

g.es('Hello','world',color='purple')
    # g.es prints its arguments to the log tab.

g.es(c)
g.es(g)
g.es(p)
</t>
<t tx="ekr.20091107071654.1513">@
For any position p, p.v is the node at that position,
p.v.b is the node's body text, and p.v.h is the node's headline.

As a convenience, p.b and p.b are synonyms for p.v.b and p.v.h.
@c

g.es('headline: ', p.h)
g.es('len(body):', len(p.b))</t>
<t tx="ekr.20091107093823.1465"></t>
<t tx="ekr.20091107093823.1468">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;!--@+leo-ver=4-thin--&gt;
&lt;!--@+node:ekr.20080301071818.1:@thin html/front.html--&gt;
&lt;!--@@first--&gt;

&lt;!--@@language html--&gt;
&lt;!--@@tabwidth -4--&gt;

&lt;!-- Last Modified: July 31, 2008 --&gt;
&lt;!-- Author: Edward K. Ream, edreamleo@gmail.com --&gt;

&lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"&gt;
&lt;head&gt;
&lt;!--@&lt;&lt;head&gt;&gt;--&gt;
&lt;!--@+node:ekr.20080301075734.1:&lt;&lt;head&gt;&gt;--&gt;
&lt;title&gt;Leo's Home Page&lt;/title&gt;

&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/&gt;

&lt;meta name="description" content="This page describes Leo, a programmer's outliner." /&gt;

&lt;meta name="keywords" content="LEO, LITERATE PROGRAMMING, OUTLINES, CWEB,
NOWEB, EDWARD K. REAM, DONALD E. KNUTH, SILVIO LEVY, OPEN SOFTWARE" /&gt;

&lt;!-- for GeoUrl --&gt;
&lt;meta name="ICBM" content="43.0713768, -89.4188004" /&gt;
&lt;meta name="DC.title" content="Leo's Home Page" /&gt;
&lt;!--@-node:ekr.20080301075734.1:&lt;&lt;head&gt;&gt;--&gt;
&lt;!--@nl--&gt;
&lt;/head&gt;

&lt;body bgcolor="#fffbdc"&gt;
&lt;!--@&lt;&lt; main table &gt;&gt;--&gt;
&lt;!--@+node:ekr.20080301075734.4:&lt;&lt; main table &gt;&gt;--&gt;

&lt;table border="0" bgcolor="#FFFBDC"&gt;
    &lt;tr&gt;
        &lt;td width="22%" height="21" align="center" bgcolor="#FFFBDC" valign="middle"&gt;
            &lt;b&gt;&lt;font size="4"&gt;Leo's Home&lt;/font&gt;&lt;/b&gt;
        &lt;/td&gt;

        &lt;td bgcolor="#F0E68C" width="78%" height="21" align="center"&gt;
            &lt;!--@            &lt;&lt; upper table &gt;&gt;--&gt;
            &lt;!--@+node:ekr.20080301080758:&lt;&lt; upper table&gt;&gt;--&gt;

            &lt;table border="0" width="100%"&gt;
                &lt;tr&gt;
                    &lt;td width="25%" align="center"&gt;
                        &lt;a href="http://www.python.org/"&gt;
                            &lt;img border="0" src="PythonPowered.gif" width="110" height="44" /&gt;&lt;/a&gt;
                    &lt;/td&gt;

                    &lt;td width="50%" align="center"&gt;
                        &lt;a href="http://groups.google.com/group/leo-editor"&gt;Leo at Google Groups&lt;/a&gt;

                    &lt;/td&gt;

                    &lt;td width="25%" align="center"&gt;
                        &lt;a href="http://www.mind-mapping.org/"&gt;mind-mapping.org&lt;/a&gt;
                    &lt;/td&gt;
                &lt;/tr&gt;
            &lt;/table&gt;
            &lt;!--@nonl--&gt;
            &lt;!--@-node:ekr.20080301080758:&lt;&lt; upper table&gt;&gt;--&gt;

            &lt;!--@nl--&gt;
        &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
        &lt;td bgcolor="#F0E68C" width="22%" height="143" valign="top"&gt;
            &lt;!--@            &lt;&lt; left table &gt;&gt;--&gt;
            &lt;!--@+node:ekr.20080301075734.6:&lt;&lt; left table &gt;&gt;--&gt;
            &lt;table border="0" width="100%"&gt;

                &lt;tr&gt;&lt;td width="50%" bgcolor="#DAA520"&gt;&lt;b&gt;Documentation&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;
                        &lt;!--
                        &lt;a href="http://sourceforge.net/project/screenshots.php?group_id=3458"&gt;Screen Shots&lt;/a&gt;
                        --&gt;
                        &lt;a href="http:screen-shots.html"&gt;Screen Shots&lt;/a&gt;
                &lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="intro.html"&gt;Beginners Guide&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="leo_toc.html"&gt;Users Guide&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;

                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="FAQ.html"&gt;FAQ&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;
                    &lt;a href="http://www.3dtree.com/ev/e/sbooks/leo/sbframetoc_ie.htm"&gt;Online tutorial&lt;/a&gt;
                &lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="testimonials.html"&gt;Quotes&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%" bgcolor="#DAA520"&gt;&lt;b&gt;Links&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;

                    &lt;!--@        &lt;&lt; download ref &gt;&gt;--&gt;
                    &lt;!--@+node:ekr.20080306071848:&lt;&lt; download ref &gt;&gt; (contains version number)--&gt;
                    &lt;a href="http://sourceforge.net/project/showfiles.php?group_id=3458&amp;amp;package_id=29106"&gt;
                        Download Leo[4.7 beta 1]&lt;/a&gt;
                    &lt;!--@nonl--&gt;
                    &lt;!--@-node:ekr.20080306071848:&lt;&lt; download ref &gt;&gt; (contains version number)--&gt;
                    &lt;!--@nl--&gt;
                &lt;/td&gt;&lt;/tr&gt;

                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="http://sourceforge.net/project/?group_id=3458"&gt; Leo at SourceForge&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="http://groups.google.com/group/leo-editor"&gt;Leo at Google Groups&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="http://launchpad.net/leo-editor"&gt;Leo at launchpad&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;!-- &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="http://leo.tigris.org/source/browse/leo/"&gt;Leo's cvs repository&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt; --&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;Leo's &lt;a href="http://leo.zwiki.org"&gt;Wiki&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;Leo's &lt;a href="http://www.greygreen.org/leo/"&gt;Daily snapshots&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;

                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="leoLinks.html"&gt;More links&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%" bgcolor="#DAA520"&gt;&lt;b&gt;Edward K. Ream&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="ekr.html"&gt;Home&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="mailto:edreamleo@gmail.com"&gt;Contact&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
            &lt;/table&gt;
            &lt;!--@-node:ekr.20080301075734.6:&lt;&lt; left table &gt;&gt;--&gt;
            &lt;!--@nl--&gt;

        &lt;/td&gt;

        &lt;td width="78%" height="143" bgcolor="#FFFBDC"&gt;
            &lt;!--@            &lt;&lt; center area &gt;&gt;--&gt;
            &lt;!--@+node:ekr.20080301082848:&lt;&lt; center area &gt;&gt;--&gt;
            &lt;h2&gt; Leo is...&lt;/h2&gt;

            &lt;ul&gt;
            &lt;!--@&lt;&lt; what is Leo list &gt;&gt;--&gt;

            &lt;!--@+node:ekr.20080301083325:&lt;&lt; what is Leo list &gt;&gt;--&gt;
            &lt;li&gt;
                A &lt;i&gt;versatile data management platform&lt;/i&gt;.&lt;br/&gt;
                Leo shows &lt;b&gt;user-created&lt;/b&gt; relationships among any kind of data:&lt;br /&gt;
                computer programs, web sites, etc.&lt;br /&gt;

                Leo shows multiple views of data within a single outline.&lt;/li&gt;
            &lt;li&gt;
                An &lt;i&gt;outlining editor for programmers&lt;/i&gt;.&lt;br /&gt;
                Leo supports &lt;i&gt;optional&lt;/i&gt; &lt;a HREF="http://www.eecs.harvard.edu/~nr/noweb/"&gt;noweb&lt;/a&gt;
                and &lt;a HREF="http://www-cs-faculty.stanford.edu/~knuth/cweb.html"&gt;CWEB&lt;/a&gt; markup.&lt;/li&gt;

            &lt;li&gt;A flexible &lt;i&gt;browser&lt;/i&gt; for projects, programs, classes or any other data.&lt;/li&gt;
            &lt;li&gt;A &lt;i&gt;project manager&lt;/i&gt;.&lt;/li&gt;
            &lt;li&gt;&lt;i&gt;Portable&lt;/i&gt;. Leo runs on Windows, Linux and MacOS X.&lt;/li&gt;
            &lt;li&gt;&lt;i&gt;100% pure&lt;/i&gt; &lt;a HREF="http://www.python.org/"&gt;&lt;i&gt;Python&lt;/i&gt;&lt;/a&gt;.&lt;/li&gt;

            &lt;li&gt;&lt;i&gt;Fully scriptable using &lt;/i&gt;&lt;a HREF="http://www.python.org/"&gt;&lt;i&gt;Python&lt;/i&gt;&lt;/a&gt;.&lt;/li&gt;
            &lt;li&gt;Leo's outline files are &lt;a HREF="http://www.w3.org/XML/"&gt;XML&lt;/a&gt; format.&lt;/li&gt;
            &lt;li&gt;
                &lt;a href="http://www.opensource.org/"&gt;&lt;i&gt;Open Software&lt;/i&gt;&lt;/a&gt;,
                distributed under the
                &lt;a href="http://www.opensource.org/licenses/mit-license.php/"&gt;

                MIT License
                &lt;/a&gt;.
            &lt;/li&gt;
            &lt;!--@nonl--&gt;
            &lt;!--@-node:ekr.20080301083325:&lt;&lt; what is Leo list &gt;&gt;--&gt;
            &lt;!--@nl--&gt;
            &lt;/ul&gt;

            &lt;p&gt;
            Please use &lt;a href="http://groups.google.com/group/leo-editor"&gt;leo-editor&lt;/a&gt;

            to ask questions and make suggestions.
            &lt;/p&gt;

            &lt;p&gt;
            Leo's author is &lt;a HREF="ekr.html"&gt;Edward K. Ream&lt;/a&gt;
            &lt;/p&gt;
            &lt;!--@nonl--&gt;
            &lt;!--@-node:ekr.20080301082848:&lt;&lt; center area &gt;&gt;--&gt;
            &lt;!--@nl--&gt;

        &lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;
&lt;!--@-node:ekr.20080301075734.4:&lt;&lt; main table &gt;&gt;--&gt;
&lt;!--@nl--&gt;
&lt;/body&gt;
&lt;/html&gt;

&lt;!--@-node:ekr.20080301071818.1:@thin html/front.html--&gt;
&lt;!--@-leo--&gt;
</t>
<t tx="ekr.20091107093823.1469">With Leo, I take considerable care to organize programs and data clearly.

Outline structure becomes a new domain for creativity. We say that Leo outlines
have **good style**.  Such a notion does not exist in any other tool.</t>
<t tx="ekr.20091107093823.1470">@
c.all_positions() is a generator returning each position of the outline.

Because of clones, a node may appear in more than one position.
@c

n = len(list(c.all_positions()))

g.es('This outline contains %s positions' % (n),color='blue')

for p in c.all_positions():
    sep = g.choose(p.hasChildren(),'+','-')
    indent = ' '*p.level()
    print ('%s%s %s' % (indent,sep,p.h))
</t>
<t tx="ekr.20091107093823.1471">@language python</t>
<t tx="ekr.20091107093823.6808"></t>
<t tx="ekr.20091107093823.6812">@language python

@others
    # The @others directive inserts all "unnamed" descendent
    # nodes into the external file.

myClass().printHi()</t>
<t tx="ekr.20091107093823.6813">class myClass:

    @others


</t>
<t tx="ekr.20091107093823.6814">def printHi(self):

    '''Print Hi on the log tab.'''

    g.es('Hi',color='blue')
</t>
<t tx="ekr.20091107093823.6815"></t>
<t tx="ekr.20091107093823.6816">You can do things in Leo you can't even *think* about in other programs.

Leo has two goals:

1. To show you your data better than any other program. The *only* way to do
   this is to let *you* choose how you want to see your data, not just in one
   way, but *in as many ways as you want*.

   Leo's outlines expand your *vision*. They are outlines "done right".
   
2. To allow you manipulate your data more simply and powerfully than in any
   other scripting environment. Leo aims to take scripting to another level.

   Leo's scripts expand your *power*.

That's all :-)

Leo is a power tool, but everything in Leo derives from just these two goals.</t>
<t tx="ekr.20091107093823.6818"></t>
<t tx="ekr.20091107093823.6819"></t>
<t tx="ekr.20091107093823.6820">Double clicking the icon box, or executing the double-click-icon-box command,
will open up Leo's sources, and select the "Projects" node.

The Projects nodes contains task-centric views of Leo's sources. Each view
typically contains notes in the top-level node, and clones of related sources in
child nodes.

Thus, each project node creates a full-fledged **relation** on the data.

So Leo outlines combine the best features of hierarchical databases, relational
databases and object-oriented databases.</t>
<t tx="ekr.20091107142231.6263">import os

os.system(r'python c:\leo.repo\trunk\leo\test\slide-show-file.py')</t>
<t tx="ekr.20091107142231.6264"></t>
<t tx="ekr.20091107142231.6265">Be an adult:

- Put yourself in the background.

- It's not about how smart you are.

- It's not about control.</t>
<t tx="ekr.20091107142231.6267">You want people to have *better* ideas than yours.

I didn't invent *any* of Leo's features.  I did expand some :-)

Every Leo feature came from somewhere (or someone) else.</t>
<t tx="ekr.20091107142231.6268"></t>
<t tx="ekr.20091108172508.15988"></t>
<t tx="ekr.20091109103928.1544"></t>
<t tx="ekr.20091109103928.1545"></t>
<t tx="ekr.20091109103928.1546">@nocolor

Summary on Leo's web site.
The main ways of using Leo for programming.

Fix bugs below.</t>
<t tx="ekr.20091109103928.14983">Others will, in their enthusiasm, likely want to add complexity via features.

"Ed, you continue to push the envelope. The amazing thing is that the footprint
isn't doubling every few months like it would be in another designer's hands."</t>
<t tx="ekr.20091110090536.1604">**Nodes** contain **headlines** and **body text**.</t>
<t tx="ekr.20091110090536.1635">@nocolor-node
    
Leo is a an unusual programmer's editor, a powerful scripting environment and a
data management environment. Leo is also a successful open-source project.
    
Edward Ream, the creator of Leo, will say a few words about Leo and invite
listeners to give Leo a closer look. For more information, google edreamleo.

Edward will also discuss what it takes to manage an open source project
successfully.</t>
<t tx="ekr.20091110090536.1636">

</t>
<t tx="ekr.20091110090536.1640">- Write computer programs.

- Manage web sites.

- Write documentation.</t>
<t tx="ekr.20091110090536.1641"></t>
<t tx="ekr.20091110090536.1642"></t>
<t tx="ekr.20091110090536.1643">- All of Leo's documentation is a Leo outline.</t>
<t tx="ekr.20091110090536.1644"></t>
<t tx="ekr.20091110090536.1645"></t>
<t tx="ekr.20091110090536.1651">You can do things with Leo that you can't even *imagine* doing in other programs.

Which is why some of the world's great programmers use Leo.

I'd like to answer your questions now.

For details, google edreamleo.

For more questions send me email or post to leo-editor google group.
</t>
<t tx="ekr.20091110090536.1654">Google: "you and your research" by Richard Hamming.</t>
<t tx="ekr.20091110090536.1695">This sections gives *hints* about how Leo works, and how the quotes given above
might be true. For details, see Leo's web site.


</t>
<t tx="ekr.20091110090536.1696"></t>
<t tx="ekr.20091110090536.1697"></t>
<t tx="ekr.20091110090536.1698"></t>
<t tx="ekr.20091110090536.1699"></t>
<t tx="ekr.20091110090536.1700"></t>
<t tx="ekr.20091110090536.1701"></t>
<t tx="ekr.20091110090536.1702"></t>
<t tx="ekr.20091110090536.1716"></t>
<t tx="ekr.20091110090536.1717">def selectVisNext (self,event=None):

    '''Select the visible node following the presently selected node.'''

    c = self ; p = c.p
    if not p: return
    if not c.canSelectVisNext(): return

    p.moveToVisNext(c)
    c.treeSelectHelper(p)
</t>
<t tx="ekr.20091110090536.1718"># This has an up arrow for a control key.

def selectVisBack (self,event=None):

    '''Select the visible node preceding the presently selected node.'''

    c = self ; p = c.p
    if not p: return
    if not c.canSelectVisBack(): return

    p.moveToVisBack(c)

    # g.trace(p.h)
    c.treeSelectHelper(p)
</t>
<t tx="ekr.20091110090536.1719">def goToParent (self,event=None):

    '''Select the parent of the selected node.'''

    c = self ; p = c.p

    # g.trace(p.parent())

    c.treeSelectHelper(p and p.parent())
</t>
<t tx="ekr.20091110090536.1720">def contractNodeOrGoToParent (self,event=None):

    """Simulate the left Arrow Key in folder of Windows Explorer."""

    trace = False and not g.unitTesting
    c = self ; p = c.p
    redraw = False ; fullRedraw = False
    if p.hasChildren() and p.isExpanded():
        if trace: g.trace('contract',p.h)
        c.contractNode()
        redraw = True # New in one-node world.
    elif p.hasParent() and p.parent().isVisible(c):
        redraw = False
        p.contract() # Make sure we know this node is contracted.
        # This "feature" is dubious.
        # To work properly, it requires a full redraw.
        if False: # self.sparse_goto_parent:
            for child in p.self_and_siblings():
                if child != p and child.isExpanded():
                    child.contract()
                    redraw = True ; fullRedraw = True
        if trace: g.trace('goto parent',p.h)
        c.goToParent()

    if redraw:
        if fullRedraw or p.isCloned():
            if trace: g.trace('full redraw',p.h)
            c.redraw()
        else:
            c.redraw_after_contract(p=p,setFocus=True)
</t>
<t tx="ekr.20091110090536.1721">def expandNodeAndGoToFirstChild (self,event=None):

    """If a node has children, expand it if needed and go to the first child."""

    trace = False and not g.unitTesting
    c = self ; p = c.p

    # New code.
    if p.hasChildren():
        if p.isExpanded():
            p.moveToFirstChild()
            if trace: g.trace('select',p.h)
            c.selectPosition(p)
        else:
            if trace: g.trace('expand',p.h)
            c.expandNode() # Calls redraw_after_expand.
    elif p.hasNext():
        c.goToNextSibling()
    else:
        while p.hasParent():
            p.moveToParent()
            if p.hasNext():
                p.moveToNext()
                break
        c.selectPosition(p)
    c.treeFocusHelper()

def expandNodeOrGoToFirstChild (self,event=None):

    """Simulate the Right Arrow Key in folder of Windows Explorer."""

    c = self ; p = c.p
    if p.hasChildren():
        if not p.isExpanded():
            c.expandNode() # Calls redraw_after_expand.
        else:
            c.redraw_after_expand(p.firstChild(),setFocus=True)
</t>
<t tx="ekr.20091110090536.1722">def contractNode (self,event=None):

    '''Contract the presently selected node.'''

    c = self ; p = c.p

    p.contract()

    if p.isCloned():
        c.redraw() # A full redraw is necessary to handle clones.
    else:
        c.redraw_after_contract(p=p,setFocus=True)
</t>
<t tx="ekr.20091110090536.1723">def expandNode (self,event=None):

    '''Expand the presently selected node.'''

    trace = False and not g.unitTesting
    c = self ; p = c.p

    p.expand()

    if p.isCloned():
        if trace: g.trace('***redraw')
        c.redraw() # Bug fix: 2009/10/03.
    else:
        c.redraw_after_expand(p,setFocus=True)

</t>
<t tx="ekr.20091110090536.1724">def treeSelectHelper (self,p):

    c = self

    if not p: p = c.p

    if p:
        # Do not call expandAllAncestors here.
        c.selectPosition(p)
        c.redraw_after_select(p)

    c.treeFocusHelper()
</t>
<t tx="ekr.20091110090536.1725">def moveToVisBack (self,c):

    """Move a position to the position of the previous visible node."""

    trace = False and not g.unitTesting
    verbose = True
    p = self ; limit,limitIsVisible = c.visLimit()
    if trace and verbose:
        g.trace(p,'limit',limit,'limitIsVisible',limitIsVisible)
    if trace: g.trace('***entry','parent',p.parent(),'p',p,g.callers(5))
    while p:
        # Short-circuit if possible.
        back = p.back()
        if trace: g.trace(
            'back',back,'hasChildren',bool(back and back.hasChildren()),
            'isExpanded',bool(back and back.isExpanded()))

        if back and back.hasChildren() and back.isExpanded():
            p.moveToThreadBack()
        elif back:
            p.moveToBack()
        else:
            p.moveToParent() # Same as p.moveToThreadBack()
        # if back and (not back.hasChildren() or not back.isExpanded()):
            # p.moveToBack()
        # else:
            # p.moveToThreadBack()
        if trace: g.trace(p.parent(),p)
        if p:
            if trace and verbose: g.trace('**p',p)
            done,val = self.checkVisBackLimit(limit,limitIsVisible,p)
            if done:
                if trace and verbose: g.trace('done',p)
                return val
            if p.isVisible(c):
                if trace and verbose: g.trace('isVisible',p)
                return p
    else:
        # assert not p.
        return p
</t>
<t tx="ekr.20091110090536.1726">def checkVisBackLimit (self,limit,limitIsVisible,p):

    '''Return done, return-val'''

    trace = True and not g.unitTesting
    c = p.v.context

    if limit:
        if limit == p:
            if trace: g.trace('at limit',p)
            if limitIsVisible and p.isVisible(c):
                return True,p
            else:
                return True,None
            #return True,g.choose(limitIsVisible and p.isVisible(c),p,None)
        elif limit.isAncestorOf(p):
            return False,None
        else:
            if trace: g.trace('outside limit tree',limit,p)
            return True,None
    else:
        return False,None
</t>
<t tx="ekr.20091110090536.1727">def moveToVisNext (self,c):

    """Move a position to the position of the next visible node."""

    trace = False and not g.unitTesting
    verbose = False
    p = self ; limit,limitIsVisible = c.visLimit()
    while p:
        if trace: g.trace('1',p.h)
        # if trace: g.trace('hasChildren %s, isExpanded %s %s' % (
            # p.hasChildren(),p.isExpanded(),p.h))
        # Short-circuit if possible.
        if p.hasNext() and p.hasChildren() and p.isExpanded():
            p.moveToFirstChild()
        elif p.hasNext():
            p.moveToNext()
        else:
            p.moveToThreadNext()
        # if p.hasNext() and (not p.hasChildren() or not p.isExpanded()):
            # p.moveToNext()
        # else:
            # p.moveToThreadNext()
        if trace: g.trace('2',p.h)
        if p:
            done,val = self.checkVisNextLimit(limit,p)
            if done: return val
            if p.isVisible(c):
                return p.copy()
    else:
        # assert not p.
        return p
</t>
<t tx="ekr.20091110090536.1728">def checkVisNextLimit (self,limit,p):

    '''Return done, return-val'''

    trace = False and not g.unitTesting

    if limit:
        # Unlike moveToVisBack, being at the limit does not terminate.
        if limit == p:
            return False, None
        elif limit.isAncestorOf(p):
            return False,None
        else:
            if trace: g.trace('outside limit tree')
            return True,None
    else:
        return False,None
</t>
<t tx="ekr.20091110090536.1729"></t>
<t tx="ekr.20091110090536.1730">@language python</t>
<t tx="ekr.20091110090536.1731">Proof:

- Relations are tuples, as are Leo views.
- Because of clones, a Leo view can contain any other node.

QED.</t>
<t tx="ekr.20091110090536.1732"></t>
<t tx="ekr.20091110090536.1951">@language python
@tabwidth -4
@pagewidth 80

use_zodb = False

&lt;&lt; imports &gt;&gt;

@others</t>
<t tx="ekr.20091110090536.1952">if use_zodb:
    # It may be important to import ZODB first.
    try:
        import ZODB
        import ZODB.FileStorage
    except ImportError:
        ZODB = None
else:
    ZODB = None

import leo.core.leoGlobals as g

if g.app and g.app.use_psyco:
    # g.pr("enabled psyco classes",__file__)
    try: from psyco.classes import *
    except ImportError: pass

import time
import re
import itertools</t>
<t tx="ekr.20091110090536.1953">if use_zodb and ZODB:
    class baseVnode (ZODB.Persistence.Persistent):
        pass
else:
    class baseVnode (object):
        pass

class vnode (baseVnode):
    &lt;&lt; vnode constants &gt;&gt;
    @others</t>
<t tx="ekr.20091110090536.1954"># Define the meaning of status bits in new vnodes.

# Archived...
clonedBit   = 0x01 # True: vnode has clone mark.
# unused      0x02
expandedBit = 0x04 # True: vnode is expanded.
markedBit   = 0x08 # True: vnode is marked
orphanBit   = 0x10 # True: vnode saved in .leo file, not derived file.
selectedBit = 0x20 # True: vnode is current vnode.
topBit      = 0x40 # True: vnode was top vnode when saved.

# Not archived...
richTextBit = 0x080 # Determines whether we use &lt;bt&gt; or &lt;btr&gt; tags.
visitedBit  = 0x100
dirtyBit    = 0x200
writeBit    = 0x400
</t>
<t tx="ekr.20091110090536.1955"></t>
<t tx="ekr.20091110090536.1956"># To support ZODB, the code must set v._p_changed = 1 whenever
# v.unknownAttributes or any mutable vnode object changes.

def __init__ (self,context):

    # The primary data: headline and body text.
    if g.isPython3:
        self._headString = 'newHeadline'
        self._bodyString = ''
    else:
        self._headString = unicode('newHeadline')
        self._bodyString = unicode('')

    # Structure data...
    self.children = [] # Ordered list of all children of this node.
    self.parents = [] # Unordered list of all parents of this node.

    # Other essential data...
    self.fileIndex = g.app.nodeIndices.getNewIndex()
        # The immutable file index for this vnode.
        # New in Leo 4.6 b2: allocate gnx (fileIndex) immediately.
    self.iconVal = 0 # The present value of the node's icon.
    self.statusBits = 0 # status bits

    # v.t no longer exists.  All code must now be aware of the one-node world.
    # self.t = self # For compatibility with scripts and plugins.

    # Information that is never written to any file...
    self.context = context # The context containing context.hiddenRootNode.
        # Required so we can compute top-level siblings.
        # It is named .context rather than .c to emphasize its limited usage.
    self.insertSpot = None # Location of previous insert point.
    self.scrollBarSpot = None # Previous value of scrollbar position.
    self.selectionLength = 0 # The length of the selected body text.
    self.selectionStart = 0 # The start of the selected body text.
</t>
<t tx="ekr.20091110090536.1957">def __repr__ (self):

    return "&lt;vnode %d:'%s'&gt;" % (id(self),self.cleanHeadString())

__str__ = __repr__
</t>
<t tx="ekr.20091110090536.1958">def dumpLink (self,link):
    return g.choose(link,link,"&lt;none&gt;")

def dump (self,label=""):

    v = self
    print('%s %s %s' % ('-'*10,label,v))
    print('len(parents) %s' % len(v.parents))
    print('len(children) %s' % len(v.children))
    print('parents %s' % g.listToString(v.parents))
    print('children%s' % g.listToString(v.children))
</t>
<t tx="ekr.20091110090536.1959">if use_zodb and ZODB:
    def __hash__(self):
        return self.__hash__()</t>
<t tx="ekr.20091110090536.1960"></t>
<t tx="ekr.20091110090536.1961">def findAtFileName (self,names,h=''):

    """Return the name following one of the names in nameList.
    Return an empty string."""

    # Allow h argument for unit testing.
    if not h: h = self.headString()

    if not g.match(h,0,'@'):
        return ""

    i = g.skip_id(h,1,'-')
    word = h[:i]
    if word in names and g.match_word(h,0,word):
        name = h[i:].strip()
        # g.trace(repr(word),repr(name))
        return name
    else:
        return ""
</t>
<t tx="ekr.20091110090536.1962">def anyAtFileNodeName (self):

    """Return the file name following an @file node or an empty string."""

    names = (
        "@auto",
        "@auto-rst",
        "@edit",
        "@file",
        "@thin",   "@file-thin",   "@thinfile",
        "@asis",   "@file-asis",   "@silentfile",
        "@noref",  "@file-noref",  "@rawfile",
        "@nosent", "@file-nosent", "@nosentinelsfile",
        "@shadow",)

    return self.findAtFileName(names)
</t>
<t tx="ekr.20091110090536.1963"># These return the filename following @xxx, in v.headString.
# Return the the empty string if v is not an @xxx node.

def atAutoNodeName (self,h=None):
    # # Prevent conflicts with autotrees plugin: don't allow @auto-whatever to match.
    # return g.match_word(h,0,tag) and not g.match(h,0,tag+'-') and h[len(tag):].strip()
    names = ("@auto","@auto-rst",)
    return self.findAtFileName(names,h=h)

def atAutoRstNodeName (self,h=None):
    names = ("@auto-rst",)
    return self.findAtFileName(names,h=h)

def atEditNodeName (self):
    names = ("@edit",)
    return self.findAtFileName(names)

def atFileNodeName (self):
    names = ("@file",)
    return self.findAtFileName(names)

def atNoSentinelsFileNodeName (self):
    names = ("@nosent", "@file-nosent", "@nosentinelsfile")
    return self.findAtFileName(names)

def atRawFileNodeName (self):
    names = ("@noref", "@file-noref", "@rawfile")
    return self.findAtFileName(names)

def atShadowFileNodeName (self):
    names = ("@shadow",)
    return self.findAtFileName(names)

def atSilentFileNodeName (self):
    names = ("@asis", "@file-asis", "@silentfile")
    return self.findAtFileName(names)

def atThinFileNodeName (self):
    names = ("@thin", "@file-thin", "@thinfile")
    return self.findAtFileName(names)

# New names, less confusing
atNoSentFileNodeName  = atNoSentinelsFileNodeName
atNorefFileNodeName   = atRawFileNodeName
atAsisFileNodeName    = atSilentFileNodeName
</t>
<t tx="ekr.20091110090536.1964">if g.unitTesting:

    c,p = g.getTestVars()

    table = (
        ('@auto-rst rst-file','rst-file','rst-file'),
        ('@auto x','x',''),
        ('xyz','',''),
    )

    for s,expected1,expected2 in table:
        result1 = p.v.atAutoNodeName(h=s)
        result2 = p.v.atAutoRstNodeName(h=s)
        assert result1 == expected1,'fail1: given %s expected %s got %s' % (
            repr(s),repr(expected1),repr(result1))
        assert result2 == expected2,'fail2: given %s expected %s got %s' % (
            repr(s),repr(expected2),repr(result2))
</t>
<t tx="ekr.20091110090536.1965">def isAtAllNode (self):

    """Returns True if the receiver contains @others in its body at the start of a line."""

    flag, i = g.is_special(self._bodyString,0,"@all")
    return flag
</t>
<t tx="ekr.20091110090536.1966">def isAnyAtFileNode (self):

    """Return True if v is any kind of @file or related node."""

    # This routine should be as fast as possible.
    # It is called once for every vnode when writing a file.

    h = self.headString()
    return h and h[0] == '@' and self.anyAtFileNodeName()
</t>
<t tx="ekr.20091110090536.1967">def isAtAutoNode (self):
    return g.choose(self.atAutoNodeName(),True,False)

def isAtAutoRstNode (self):
    return g.choose(self.atAutoRstNodeName(),True,False)

def isAtEditNode (self):
    return g.choose(self.atEditNodeName(),True,False)

def isAtFileNode (self):
    return g.choose(self.atFileNodeName(),True,False)

def isAtNoSentinelsFileNode (self):
    return g.choose(self.atNoSentinelsFileNodeName(),True,False)

def isAtRawFileNode (self): # @file-noref
    return g.choose(self.atRawFileNodeName(),True,False)

def isAtSilentFileNode (self): # @file-asis
    return g.choose(self.atSilentFileNodeName(),True,False)

def isAtShadowFileNode (self):
    return g.choose(self.atShadowFileNodeName(),True,False)

def isAtThinFileNode (self):
    return g.choose(self.atThinFileNodeName(),True,False)

# New names, less confusing:
isAtNoSentFileNode = isAtNoSentinelsFileNode
isAtNorefFileNode  = isAtRawFileNode
isAtAsisFileNode   = isAtSilentFileNode
</t>
<t tx="ekr.20091110090536.1968">def isAtIgnoreNode (self):

    """Returns True if the receiver contains @ignore in its body at the start of a line."""

    flag, i = g.is_special(self._bodyString, 0, "@ignore")
    return flag
</t>
<t tx="ekr.20091110090536.1969">def isAtOthersNode (self):

    """Returns True if the receiver contains @others in its body at the start of a line."""

    flag, i = g.is_special(self._bodyString,0,"@others")
    return flag
</t>
<t tx="ekr.20091110090536.1970">def matchHeadline (self,pattern):

    """Returns True if the headline matches the pattern ignoring whitespace and case.

    The headline may contain characters following the successfully matched pattern."""

    v = self

    h = g.toUnicode(v.headString(),'utf-8')
    h = h.lower().replace(' ','').replace('\t','')

    pattern = g.toUnicode(pattern,'utf-8')
    pattern = pattern.lower().replace(' ','').replace('\t','')

    return h.startswith(pattern)
</t>
<t tx="ekr.20091110090536.1971"></t>
<t tx="ekr.20091110090536.1972">def bodyString (self):

    # This message should never be printed and we want to avoid crashing here!
    if not g.isUnicode(self._bodyString):
        s = "v.bodyString: Leo internal error: not unicode:" + repr(self._bodyString)
        g.es_print('',s,color="red")

    # Make _sure_ we return a unicode string.
    return g.toUnicode(self._bodyString,g.app.tkEncoding)

getBody = bodyString</t>
<t tx="ekr.20091110090536.1973"></t>
<t tx="ekr.20091110090536.1974">def firstChild (self):

    v = self
    return v.children and v.children[0]
</t>
<t tx="ekr.20091110090536.1975">def hasChildren (self):

    v = self
    return len(v.children) &gt; 0

hasFirstChild = hasChildren
</t>
<t tx="ekr.20091110090536.1976">def lastChild (self):

    v = self
    return v.children and v.children[-1] or None
</t>
<t tx="ekr.20091110090536.1977"># childIndex and nthChild are zero-based.

def nthChild (self, n):

    v = self

    if 0 &lt;= n &lt; len(v.children):
        return v.children[n]
    else:
        return None
</t>
<t tx="ekr.20091110090536.1978">def numberOfChildren (self):

    v = self
    return len(v.children)
</t>
<t tx="ekr.20091110090536.1979">def directParents (self):

    """(New in 4.2) Return a list of all direct parent vnodes of a vnode.

    This is NOT the same as the list of ancestors of the vnode."""

    v = self
    return v.parents
</t>
<t tx="ekr.20091110090536.1980">def hasBody (self):

    '''Return True if this vnode contains body text.'''

    s = self._bodyString

    return s and len(s) &gt; 0
</t>
<t tx="ekr.20091110090536.1981">def headString (self):

    """Return the headline string."""

    # This message should never be printed and we want to avoid crashing here!
    if not g.isUnicode(self._headString):
        s = "Leo internal error: not unicode:" + repr(self._headString)
        g.es_print('',s,color="red")

    # Make _sure_ we return a unicode string.
    return g.toUnicode(self._headString,g.app.tkEncoding)

def cleanHeadString (self):

    s = self._headString
    return g.toEncodedString(s,"ascii") # Replaces non-ascii characters by '?'
</t>
<t tx="ekr.20091110090536.1982"></t>
<t tx="ekr.20091110090536.1983">def isCloned (self):

    return len(self.parents) &gt; 1
</t>
<t tx="ekr.20091110090536.1984">def isDirty (self):

    return (self.statusBits &amp; self.dirtyBit) != 0
</t>
<t tx="ekr.20091110090536.1985">def isExpanded (self):

    # g.trace( ( self.statusBits &amp; self.expandedBit ) != 0, g.callers())

    return ( self.statusBits &amp; self.expandedBit ) != 0
</t>
<t tx="ekr.20091110090536.1986">def isMarked (self):

    return ( self.statusBits &amp; vnode.markedBit ) != 0
</t>
<t tx="ekr.20091110090536.1987">def isOrphan (self):

    return ( self.statusBits &amp; vnode.orphanBit ) != 0
</t>
<t tx="ekr.20091110090536.1988">def isSelected (self):

    return ( self.statusBits &amp; vnode.selectedBit ) != 0
</t>
<t tx="ekr.20091110090536.1989">def isTopBitSet (self):

    return ( self.statusBits &amp; self.topBit ) != 0
</t>
<t tx="ekr.20091110090536.1990">def isVisited (self):

    return ( self.statusBits &amp; vnode.visitedBit ) != 0
</t>
<t tx="ekr.20091110090536.1991">def isWriteBit (self):

    v = self
    return (v.statusBits &amp; v.writeBit) != 0
</t>
<t tx="ekr.20091110090536.1992">def status (self):

    return self.statusBits
</t>
<t tx="ekr.20091110090536.1993"></t>
<t tx="ekr.20091110090536.1994"></t>
<t tx="ekr.20091110090536.1995">def clearDirty (self):
    v = self
    v.statusBits &amp;= ~ v.dirtyBit

</t>
<t tx="ekr.20091110090536.1996">def findAllPotentiallyDirtyNodes(self):

    trace = False and not g.unitTesting
    v = self ; c = v.context

    # Set the starting nodes.
    nodes = []
    newNodes = [v]

    # Add nodes until no more are added.
    while newNodes:
        addedNodes = []
        nodes.extend(newNodes)
        for v in newNodes:
            for v2 in v.parents:
                if v2 not in nodes and v2 not in addedNodes:
                    addedNodes.append(v2)
        newNodes = addedNodes[:]

    # Remove the hidden vnode.
    if c.hiddenRootNode in nodes:
        if trace: g.trace('removing hidden root',c.hiddenRootNode)
        nodes.remove(c.hiddenRootNode)

    if trace: g.trace(nodes)
    return nodes</t>
<t tx="ekr.20091110090536.1997"># Unlike p.setAllAncestorAtFileNodesDirty,
# there is no setDescendentsDirty arg.

def setAllAncestorAtFileNodesDirty (self):

    trace = False and not g.unitTesting
    verbose = False
    v = self
    dirtyVnodeList = []

    # Calculate all nodes that are joined to p or parents of such nodes.
    nodes = v.findAllPotentiallyDirtyNodes()

    if trace and verbose:
        for v in nodes:
            print v.isDirty(),v.isAnyAtFileNode(),v

    dirtyVnodeList = [v for v in nodes
        if not v.isDirty() and v.isAnyAtFileNode()]

    changed = len(dirtyVnodeList) &gt; 0

    for v in dirtyVnodeList:
        v.setDirty() # Do not call v.setDirty here!

    if trace: g.trace("vnode",dirtyVnodeList)

    return dirtyVnodeList
</t>
<t tx="ekr.20091110090536.1998">def setDirty (self):

    self.statusBits |= self.dirtyBit
</t>
<t tx="ekr.20091110090536.1999"></t>
<t tx="ekr.20091110090536.2000">def clearClonedBit (self):

    self.statusBits &amp;= ~ self.clonedBit
</t>
<t tx="ekr.20091110090536.2001">def clearMarked (self):

    self.statusBits &amp;= ~ self.markedBit
</t>
<t tx="ekr.20091110090536.2002">def clearWriteBit (self):
    self.statusBits &amp;= ~ self.writeBit
</t>
<t tx="ekr.20091110090536.2003">def clearOrphan (self):

    self.statusBits &amp;= ~ self.orphanBit
</t>
<t tx="ekr.20091110090536.2004">def clearVisited (self):

    self.statusBits &amp;= ~ self.visitedBit
</t>
<t tx="ekr.20091110090536.2005">def contract(self):

    # if self.context.p.v == self: g.trace(self,g.callers(4))

    self.statusBits &amp;= ~ self.expandedBit

def expand(self):

    # g.trace(self,g.callers(4))

    self.statusBits |= self.expandedBit

def initExpandedBit (self):

    # g.trace(self._headString)

    self.statusBits |= self.expandedBit
</t>
<t tx="ekr.20091110090536.2006">def initStatus (self, status):

    self.statusBits = status
</t>
<t tx="ekr.20091110090536.2007">def setClonedBit (self):

    self.statusBits |= self.clonedBit

def initClonedBit (self, val):

    if val:
        self.statusBits |= self.clonedBit
    else:
        self.statusBits &amp;= ~ self.clonedBit
</t>
<t tx="ekr.20091110090536.2008">def setMarked (self):

    self.statusBits |= self.markedBit

def initMarkedBit (self):

    self.statusBits |= self.markedBit
</t>
<t tx="ekr.20091110090536.2009">def setOrphan (self):

    self.statusBits |= self.orphanBit
</t>
<t tx="ekr.20091110090536.2010"># This only sets the selected bit.

def setSelected (self):

    self.statusBits |= self.selectedBit
</t>
<t tx="ekr.20091110090536.2011"># Compatibility routine for scripts

def setVisited (self):

    self.statusBits |= self.visitedBit
</t>
<t tx="ekr.20091110090536.2012">def setWriteBit (self):
    self.statusBits |= self.writeBit
</t>
<t tx="ekr.20091110090536.2013">def setBodyString (self,s,encoding="utf-8"):

    trace = False and not g.unitTesting
    v = self
    if trace and v._bodyString != s:
        g.trace('v %s %s -&gt; %s %s\nold: %s\nnew: %s' % (
            v.h, len(v._bodyString),len(s),g.callers(5),
            v._bodyString,s))
    v._bodyString = g.toUnicode(s,encoding,reportErrors=True)

def setHeadString (self,s,encoding="utf-8"):
    v = self
    v._headString = g.toUnicode(s,encoding,reportErrors=True)

initBodyString = setBodyString
initHeadString = setHeadString
setHeadText = setHeadString
setTnodeText = setBodyString
</t>
<t tx="ekr.20091110090536.2014">def setFileIndex (self, index):

    self.fileIndex = index
</t>
<t tx="ekr.20091110090536.2015">def computeIcon (self):

    val = 0 ; v = self
    if v.hasBody(): val += 1
    if v.isMarked(): val += 2
    if v.isCloned(): val += 4
    if v.isDirty(): val += 8
    return val

def setIcon (self):

    pass # Compatibility routine for old scripts
</t>
<t tx="ekr.20091110090536.2016">def setSelection (self, start, length):

    v = self
    v.selectionStart = start
    v.selectionLength = length
</t>
<t tx="ekr.20091110090536.2017"></t>
<t tx="ekr.20091110090536.2018">def _addLink (self,childIndex,parent_v,adjust=True):
    '''Adjust links after adding a link to v.'''

    trace = False and not g.unitTesting
    v = self

    # Update parent_v.children &amp; v.parents.
    parent_v.children.insert(childIndex,v)
    v.parents.append(parent_v)
    if trace: g.trace('*** added parent',parent_v,'to',v,
        'len(parents)',len(v.parents))

    # Set zodb changed flags.
    v._p_changed = 1
    parent_v._p_changed = 1

    # If v has only one parent, we adjust all
    # the parents links in the descendant tree.
    # This handles clones properly when undoing a delete.
    if adjust:
        if len(v.parents) == 1:
            for child in v.children:
                child._addParentLinks(parent=v)
</t>
<t tx="ekr.20091110090536.2019">def _addParentLinks(self,parent): 

    trace = False and not g.unitTesting
    v = self

    v.parents.append(parent)
    if trace: g.trace(
        '*** added parent',parent,'to',v,'len(parents)',len(v.parents))

    if len(v.parents) == 1:
        for child in v.children:
            child._addParentLinks(parent=v)</t>
<t tx="ekr.20091110090536.2020">def _cutLink (self,childIndex,parent_v):
    '''Adjust links after cutting a link to v.'''
    v = self

    assert parent_v.children[childIndex]==v
    del parent_v.children[childIndex]
    v.parents.remove(parent_v)
    v._p_changed = 1
    parent_v._p_changed = 1

    # If v has no more parents, we adjust all
    # the parent links in the descendant tree.
    # This handles clones properly when deleting a tree.
    if len(v.parents) == 0:
        for child in v.children:
            child._cutParentLinks(parent=v)</t>
<t tx="ekr.20091110090536.2021">def _cutParentLinks(self,parent):

    trace = False and not g.unitTesting
    v = self

    if trace: g.trace('parent',parent,'v',v)
    v.parents.remove(parent)

    if len(v.parents) == 0:
        for child in v.children:
            child._cutParentLinks(parent=v)
</t>
<t tx="ekr.20091110090536.2022">def _linkAsNthChild (self,parent_v,n):

    """Links self as the n'th child of vnode pv"""

    v = self # The child node.
    v._addLink(n,parent_v)
</t>
<t tx="ekr.20091110090536.2023">def createOutlineFromCacheList(self,c,aList):
    """ Create outline structure from recursive aList
    built by p.makeCacheList.

    Clones will be automatically created by gnx,
    but *not* for the top-level node.
    """

    parent_v = self

    #import pprint ; pprint.pprint(tree)
    parent_v = self
    h,b,gnx,children = aList
    if h is not None:
        v = parent_v
        v._headString = h    
        v._bodyString = b

    for z in children:
        h,b,gnx,grandChildren = z
        isClone,child_v = parent_v.fastAddLastChild(c,gnx)
        if isClone:
            if child_v.b != b: # or child_v.h
                # Bug fix: the last seen clone rules.
                child_v.h = h
                child_v.b = b
                # Bug fix: mark @&lt;file&gt; nodes dirty.
                child_v.setAllAncestorAtFileNodesDirty()
                child_v.setMarked()
                g.es("changed:",child_v.h,color="blue")
        else:
            child_v.createOutlineFromCacheList(c,z)
</t>
<t tx="ekr.20091110090536.2024"># Similar to createThinChild4
def fastAddLastChild(self,c,gnxString):
    '''Create new vnode as last child of the receiver.

    If the gnx exists already, create a clone instead of new vnode.
    '''

    trace = False and not g.unitTesting
    parent_v = self
    indices = g.app.nodeIndices
    gnxDict = c.fileCommands.gnxDict

    if gnxString is None: v = None
    else:                 v = gnxDict.get(gnxString)
    is_clone = v is not None

    if trace: g.trace(
        'clone','%-5s' % (is_clone),
        'parent_v',parent_v,'gnx',gnxString,'v',repr(v))

    if not is_clone:
        v = vnode(context=c)
        if gnxString:
            gnx = indices.scanGnx(gnxString,0)
            v.fileIndex = gnx
        gnxDict[gnxString] = v

    child_v = v
    child_v._linkAsNthChild(parent_v,parent_v.numberOfChildren())
    child_v.setVisited() # Supress warning/deletion of unvisited nodes.

    return is_clone,child_v
</t>
<t tx="ekr.20091110090536.2025"></t>
<t tx="ekr.20091110090536.2026">def __get_b(self):

    v = self
    return v.bodyString()

def __set_b(self,val):

    v = self
    v.setBodyString(val)

b = property(
    __get_b, __set_b,
    doc = "vnode body string property")
</t>
<t tx="ekr.20091110090536.2027">def __get_h(self):

    v = self
    return v.headString()

def __set_h(self,val):

    v = self
    v.setHeadString(val)

h = property(
    __get_h, __set_h,
    doc = "vnode headline string property")  
</t>
<t tx="ekr.20091110090536.2028">def __get_u(self):
    v = self
    if not hasattr(v,'unknownAttributes'):
        v.unknownAttributes = {}
    return v.unknownAttributes

def __set_u(self,val):
    v = self
    if val is None:
        if hasattr(v,'unknownAttributes'):
            delattr(v,'unknownAttributes')
    elif type(val) == type({}):
        v.unknownAttributes = val
    else:
        raise ValueError

u = property(
    __get_u, __set_u,
    doc = "vnode unknownAttribute property")
</t>
<t tx="ekr.20091110090536.2029">def __get_gnx(self):
    v = self
    return g.app.nodeIndices.toString(v.fileIndex)

gnx = property(
    __get_gnx, # __set_gnx,
    doc = "vnode gnx property")
</t>
<t tx="ekr.20091110090536.2030"># Indices are Python dicts containing 'id','loc','time' and 'n' keys.

class nodeIndices (object):

    """A class to implement global node indices (gnx's)."""

    @others
</t>
<t tx="ekr.20091110090536.2031">def __init__ (self,id):

    """ctor for nodeIndices class"""

    self.userId = id
    self.defaultId = id

    # A Major simplification: Only assign the timestamp once.
    self.setTimeStamp()
    self.lastIndex = 0
</t>
<t tx="ekr.20091110090536.2032">def areEqual (self,gnx1,gnx2):

    """Return True if all fields of gnx1 and gnx2 are equal"""

    # works whatever the format of gnx1 and gnx2.
    # This should never throw an exception.
    return gnx1 == gnx2
</t>
<t tx="ekr.20091110090536.2033"># These are used by the fileCommands read/write code.

def getDefaultId (self):

    """Return the id to be used by default in all gnx's"""
    return self.defaultId

def setDefaultId (self,theId):

    """Set the id to be used by default in all gnx's"""
    self.defaultId = theId
</t>
<t tx="ekr.20091110090536.2034">def getNewIndex (self):

    '''Create a new gnx.'''

    self.lastIndex += 1
    d = (self.userId,self.timeString,self.lastIndex)
    # g.trace(d)
    return d
</t>
<t tx="ekr.20091110090536.2035">def isGnx (self,gnx):
    try:
        theId,t,n = gnx
        return t != None
    except Exception:
        return False
</t>
<t tx="ekr.20091110090536.2036">def scanGnx (self,s,i):

    """Create a gnx from its string representation"""

    if not g.isString(s):
        g.es("scanGnx: unexpected index type:",type(s),'',s,color="red")
        return None,None,None

    s = s.strip()

    theId,t,n = None,None,None
    i,theId = g.skip_to_char(s,i,'.')
    if g.match(s,i,'.'):
        i,t = g.skip_to_char(s,i+1,'.')
        if g.match(s,i,'.'):
            i,n = g.skip_to_char(s,i+1,'.')
    # Use self.defaultId for missing id entries.
    if theId == None or len(theId) == 0:
        theId = self.defaultId
    # Convert n to int.
    if n:
        try: n = int(n)
        except Exception: pass

    return theId,t,n
</t>
<t tx="ekr.20091110090536.2037">def setTimestamp (self):

    """Set the timestamp string to be used by getNewIndex until further notice"""

    self.timeString = time.strftime(
        "%Y%m%d%H%M%S", # Help comparisons; avoid y2k problems.
        time.localtime())

    # g.trace(self.timeString,self.lastIndex,g.callers(4))

setTimeStamp = setTimestamp
</t>
<t tx="ekr.20091110090536.2038">def toString (self,index):

    """Convert a gnx (a tuple) to its string representation"""

    try:
        theId,t,n = index
        if n in (None,0,'',):
            return "%s.%s" % (theId,t)
        else:
            return "%s.%s.%d" % (theId,t,n)
    except Exception:
        if not g.app.unitTesting:
            g.trace('unusual gnx',repr(index),g.callers()) 
        try:
            theId,t,n = self.getNewIndex()
            if n in (None,0,'',):
                return "%s.%s" % (theId,t)
            else:
                return "%s.%s.%d" % (theId,t,n)
        except Exception:
            g.trace('double exception: returning original index')
            return repr(index)</t>
<t tx="ekr.20091110090536.2039">&lt;&lt; about the position class &gt;&gt;

# Positions should *never* be saved by the ZOBD.
class position (object):
    @others
</t>
<t tx="ekr.20091110090536.2040">@killcolor
@

A position marks the spot in a tree traversal. A position p consists of a vnode
p.v, a child index p._childIndex, and a stack of tuples (v,childIndex), one for
each ancestor **at the spot in tree traversal. Positions p has a unique set of
parents.

The p.moveToX methods may return a null (invalid) position p with p.v = None.

The tests "if p" or "if not p" are the _only_ correct way to test whether a
position p is valid. In particular, tests like "if p is None" or "if p is not
None" will not work properly.
</t>
<t tx="ekr.20091110090536.2041"></t>
<t tx="ekr.20091110090536.2042">def __init__ (self,v,childIndex=0,stack=None,trace=False):

    '''Create a new position with the given childIndex and parent stack.'''

    # To support ZODB the code must set v._p_changed = 1
    # whenever any mutable vnode object changes.

    self._childIndex = childIndex
    self.v = v

    # New in Leo 4.5: stack entries are tuples (v,childIndex).
    if stack:
        self.stack = stack[:] # Creating a copy here is safest and best.
    else:
        self.stack = []

    g.app.positions += 1

    # if g.app.tracePositions and trace: g.trace(g.callers())

    self.txtOffset = None # see self.textOffset()
</t>
<t tx="ekr.20091110090536.2043">def __eq__(self,p2):

    """Return True if two postions are equivalent."""

    p1 = self

    # Don't use g.trace: it might call p.__eq__ or p.__ne__.
    # print ('p.__eq__: %s %s' % (
        # p1 and p1.v and p1.h,p2 and p2.v and p2.h))

    if p2 is None or p2.v is None:
        return p1.v is None
    else:
        return ( p1.v == p2.v and
            p1._childIndex == p2._childIndex and
            p1.stack == p2.stack )

def __ne__(self,p2):

    """Return True if two postions are not equivalent."""

    return not self.__eq__(p2) # For possible use in Python 2.x.
</t>
<t tx="ekr.20091110090536.2044"># No longer used.  All code must now be aware of the one-node world.

# def __getattr__ (self,attr):

    # """Convert references to p.t into references to p.v."""

    # if attr=="t":
        # return self.v
    # else:
        # # New in 4.3: _silently_ raise the attribute error.
        # # This allows plugin code to use hasattr(p,attr) !
        # if 0:
            # print("unknown position attribute: %s" % attr)
            # import traceback ; traceback.print_stack()
        # raise AttributeError(attr)</t>
<t tx="ekr.20091110090536.2045">@
Tests such as 'if p' or 'if not p' are the _only_ correct ways to test whether a position p is valid.
In particular, tests like 'if p is None' or 'if p is not None' will not work properly.
@c

if g.isPython3:

    def __bool__ ( self):

        """Return True if a position is valid."""

        # Tracing this appears to cause unbounded prints.
        # print("__bool__",self.v and self.v.cleanHeadString())

        return self.v is not None

else:

    def __nonzero__ ( self):

        """Return True if a position is valid."""

        # if g.app.trace: "__nonzero__",self.v

        # g.trace(repr(self))

        return self.v is not None
</t>
<t tx="ekr.20091110090536.2046">def __str__ (self):

    p = self

    if p.v:
        return "&lt;pos %d childIndex: %d lvl: %d [%d] %s&gt;" % (
            id(p),p._childIndex,p.level(),len(p.stack),p.cleanHeadString())
    else:
        return "&lt;pos %d [%d] None&gt;" % (id(p),len(p.stack))

__repr__ = __str__
</t>
<t tx="ekr.20091110090536.2047">def archivedPosition (self,root_p=None):

    '''Return a representation of a position suitable for use in .leo files.'''

    p = self

    if root_p is None:
        aList = [z._childIndex for z in p.self_and_parents()]
    else:
        aList = []
        for z in p.self_and_parents():
            if z == root_p:
                aList.append(0)
                break
            else:
                aList.append(z._childIndex)
        # g.trace(aList)

    aList.reverse()
    return aList</t>
<t tx="ekr.20091110090536.2048"># Using this routine can generate huge numbers of temporary positions during a tree traversal.

def copy (self):

    """"Return an independent copy of a position."""

    # if g.app.tracePositions: g.trace(g.callers())

    return position(self.v,self._childIndex,self.stack,trace=False)
</t>
<t tx="ekr.20091110090536.2049">def dumpLink (self,link):

    return g.choose(link,link,"&lt;none&gt;")

def dump (self,label=""):

    p = self
    if p.v:
        p.v.dump() # Don't print a label
</t>
<t tx="ekr.20091110090536.2050">def key (self):

    p = self

    # For unified nodes we must include a complete key,
    # so we can distinguish between clones.
    result = []
    for z in p.stack:
        v,childIndex = z
        result.append('%s:%s' % (id(v),childIndex))

    result.append('%s:%s' % (id(p.v),p._childIndex))

    return '.'.join(result)
</t>
<t tx="ekr.20091110090536.2051"></t>
<t tx="ekr.20091110090536.2052">def __get_b(self):

    p = self
    return p.bodyString()

def __set_b(self,val):

    p = self ; c = p.v and p.v.context
    if c:
        c.setBodyString(p, val)
        # Don't redraw the screen: p.b must be fast.
        # c.redraw_after_icons_changed()

b = property(
    __get_b, __set_b,
    doc = "position body string property")
</t>
<t tx="ekr.20091110090536.2053">def __get_h(self):

    p = self
    return p.headString()

def __set_h(self,val):

    p = self ; c = p.v and p.v.context
    if c:
        c.setHeadString(p,val)
        # Don't redraw the screen: p.h must be fast.
        # c.redraw_after_head_changed()

h = property(
    __get_h, __set_h,
    doc = "position headline string property")  
</t>
<t tx="ekr.20091110090536.2054">def __get_gnx(self):
    p = self
    return g.app.nodeIndices.toString(p.v.fileIndex)

gnx = property(
    __get_gnx, # __set_gnx,
    doc = "position gnx property")
</t>
<t tx="ekr.20091110090536.2055"></t>
<t tx="ekr.20091110090536.2056"></t>
<t tx="ekr.20091110090536.2057">def anyAtFileNodeName         (self): return self.v.anyAtFileNodeName()
def atAutoNodeName            (self): return self.v.atAutoNodeName()
def atEditNodeName            (self): return self.v.atEditNodeName()
def atFileNodeName            (self): return self.v.atFileNodeName()
def atNoSentinelsFileNodeName (self): return self.v.atNoSentinelsFileNodeName()
def atRawFileNodeName         (self): return self.v.atRawFileNodeName()
def atShadowFileNodeName      (self): return self.v.atShadowFileNodeName()
def atSilentFileNodeName      (self): return self.v.atSilentFileNodeName()
def atThinFileNodeName        (self): return self.v.atThinFileNodeName()

# New names, less confusing
atNoSentFileNodeName  = atNoSentinelsFileNodeName
atNorefFileNodeName   = atRawFileNodeName
atAsisFileNodeName    = atSilentFileNodeName

def isAnyAtFileNode         (self): return self.v.isAnyAtFileNode()
def isAtAllNode             (self): return self.v.isAtAllNode()
def isAtAutoNode            (self): return self.v.isAtAutoNode()
def isAtAutoRstNode         (self): return self.v.isAtAutoRstNode()
def isAtEditNode            (self): return self.v.isAtEditNode()
def isAtFileNode            (self): return self.v.isAtFileNode()
def isAtIgnoreNode          (self): return self.v.isAtIgnoreNode()
def isAtNoSentinelsFileNode (self): return self.v.isAtNoSentinelsFileNode()
def isAtOthersNode          (self): return self.v.isAtOthersNode()
def isAtRawFileNode         (self): return self.v.isAtRawFileNode()
def isAtSilentFileNode      (self): return self.v.isAtSilentFileNode()
def isAtShadowFileNode      (self): return self.v.isAtShadowFileNode()
def isAtThinFileNode        (self): return self.v.isAtThinFileNode()

# New names, less confusing:
isAtNoSentFileNode = isAtNoSentinelsFileNode
isAtNorefFileNode  = isAtRawFileNode
isAtAsisFileNode   = isAtSilentFileNode

# Utilities.
def matchHeadline (self,pattern): return self.v.matchHeadline(pattern)
</t>
<t tx="ekr.20091110090536.2058">def bodyString (self):

    return self.v.bodyString()

def headString (self):

    return self.v.headString()

def cleanHeadString (self):

    return self.v.cleanHeadString()
</t>
<t tx="ekr.20091110090536.2059">def isDirty     (self): return self.v.isDirty()
def isExpanded  (self): return self.v.isExpanded()
def isMarked    (self): return self.v.isMarked()
def isOrphan    (self): return self.v.isOrphan()
def isSelected  (self): return self.v.isSelected()
def isTopBitSet (self): return self.v.isTopBitSet()
def isVisited   (self): return self.v.isVisited()
def status      (self): return self.v.status()
</t>
<t tx="ekr.20091110090536.2060"></t>
<t tx="ekr.20091110090536.2061"># This used to be time-critical code.

def childIndex(self):

    p = self
    return p._childIndex
</t>
<t tx="ekr.20091110090536.2062">def directParents (self):

    return self.v.directParents()
</t>
<t tx="ekr.20091110090536.2063">def hasChildren (self):

    p = self
    return len(p.v.children) &gt; 0

hasFirstChild = hasChildren

def numberOfChildren (self):

    p = self
    return len(p.v.children)
</t>
<t tx="ekr.20091110090536.2064"># These methods are useful abbreviations.
# Warning: they make copies of positions, so they should be used _sparingly_

def getBack          (self): return self.copy().moveToBack()
def getFirstChild    (self): return self.copy().moveToFirstChild()
def getLastChild     (self): return self.copy().moveToLastChild()
def getLastNode      (self): return self.copy().moveToLastNode()
def getLastVisible   (self): return self.copy().moveToLastVisible()
def getNext          (self): return self.copy().moveToNext()
def getNodeAfterTree (self): return self.copy().moveToNodeAfterTree()
def getNthChild    (self,n): return self.copy().moveToNthChild(n)
def getParent        (self): return self.copy().moveToParent()
def getThreadBack    (self): return self.copy().moveToThreadBack()
def getThreadNext    (self): return self.copy().moveToThreadNext()

# New in Leo 4.4.3 b2: add c args.
def getVisBack (self,c): return self.copy().moveToVisBack(c)
def getVisNext (self,c): return self.copy().moveToVisNext(c)

# These are efficient enough now that iterators are the normal way to traverse the tree!

back          = getBack
firstChild    = getFirstChild
lastChild     = getLastChild
lastNode      = getLastNode
lastVisible   = getLastVisible # New in 4.2 (was in tk tree code).
next          = getNext
nodeAfterTree = getNodeAfterTree
nthChild      = getNthChild
parent        = getParent
threadBack    = getThreadBack
threadNext    = getThreadNext
visBack       = getVisBack
visNext       = getVisNext

# New in Leo 4.4.3:
hasVisBack = visBack
hasVisNext = visNext</t>
<t tx="ekr.20091110090536.2065">def hasBack(self):
    p = self
    return p.v and p._childIndex &gt; 0

def hasNext(self):
    p = self
    try:
        parent_v = p._parentVnode()
            # Returns None if p.v is None.
        return p.v and parent_v and p._childIndex+1 &lt; len(parent_v.children)
    except Exception:
        g.trace('*** Unexpected exception')
        g.es_exception()
        return None

def hasParent(self):
    p = self
    return p.v and len(p.stack) &gt; 0

def hasThreadBack(self):
    p = self
    return p.hasParent() or p.hasBack() # Much cheaper than computing the actual value.
</t>
<t tx="ekr.20091110090536.2066">def hasThreadNext (self):

    p = self
    if not p.v: return False

    if p.hasChildren() or p.hasNext(): return True

    n = len(p.stack) -1
    while n &gt;= 0:
        v,childIndex = p.stack[n]
        # See how many children v's parent has.
        if n == 0:
            parent_v = v.context.hiddenRootNode
        else:
            parent_v,junk = p.stack[n-1]
        if len(parent_v.children) &gt; childIndex+1:
            # v has a next sibling.
            return True
        n -= 1
    return False
</t>
<t tx="ekr.20091110090536.2067">def findRootPosition (self):

    p = self.copy()
    while p.hasParent():
        p.moveToParent()
    while p.hasBack():
        p.moveToBack()
    return p</t>
<t tx="ekr.20091110090536.2068">def isAncestorOf (self, p2):

    p = self ; v = p.v

    for z in p2.stack:
        v2,junk = z
        if v2 == v:
            return True

    return False
</t>
<t tx="ekr.20091110090536.2069">def isCloned (self):

    p = self
    return p.v.isCloned()
</t>
<t tx="ekr.20091110090536.2070">def isRoot (self):

    p = self

    return not p.hasParent() and not p.hasBack()
</t>
<t tx="ekr.20091110090536.2071">def isVisible (self,c):

    p = self ; trace = False
    limit,limitIsVisible = c.visLimit()
    limit_v = limit and limit.v or None
    if p.v == limit_v:
        if trace: g.trace('*** at limit','limitIsVisible',limitIsVisible,p.h)
        return limitIsVisible

    # It's much easier with a full stack.
    n = len(p.stack)-1
    while n &gt;= 0:
        progress = n
        # v,n = p.vParentWithStack(v,p.stack,n)
        v,junk = p.stack[n]
        if v == limit_v:  # We are at a descendant of limit.
            if trace: g.trace('*** descendant of limit',
                'limitIsVisible',limitIsVisible,
                'limit.isExpanded()',limit.isExpanded(),'v',v)
            if limitIsVisible:
                return limit.isExpanded()
            else: # Ignore the expansion state of @chapter nodes.
                return True
        if not v.isExpanded():
            if trace: g.trace('*** non-limit parent is not expanded:',v._headString,p.h)
            return False
        n -= 1
        assert progress &gt; n

    return True
</t>
<t tx="ekr.20091110090536.2072">def level (self):

    '''Return the number of p's parents.'''

    p = self
    return p.v and len(p.stack) or 0

simpleLevel = level
</t>
<t tx="ekr.20091110090536.2073">def textOffset(self):
    '''
        See http://tinyurl.com/5nescw for details
    '''

    p = self

    # caching of p.textOffset, we need to calculate it only once
    if p.txtOffset is not None:
        return p.txtOffset

    p.txtOffset = 0
    # walk back from the current position
    for cursor in p.self_and_parents():
        # we also need the parent, the "text offset" is relative to it
        parent = cursor.parent()
        if parent == None: # root reached
            break
        parent_bodyString = parent.b
        if parent_bodyString == '': # organizer node
            continue
        parent_lines = parent_bodyString.split('\n')
        # check out if the cursor node is a section
        cursor_is_section = False
        cursor_headString = cursor.h
        if cursor_headString.startswith('&lt;&lt;'):
            cursor_is_section = True # section node
        for line in parent_lines:
            if cursor_is_section == True:
                # find out the section in the bodyString of the parent
                pos = line.find(cursor_headString)
            else:
                # otherwise find the "@others" directive in the bodyString of the parent
                pos = line.find('@others')
            if pos &gt; 0:
                # break the iteration over lines if something is found 
                break
        if pos &gt; 0:
            p.txtOffset += pos
        if parent.v.isAnyAtFileNode(): # do not scan upper
            break

    return p.txtOffset         
</t>
<t tx="ekr.20091110090536.2074"></t>
<t tx="ekr.20091110090536.2075"></t>
<t tx="ekr.20091110090536.2076"># Clone bits are no longer used.
# Dirty bits are handled carefully by the position class.

def clearMarked  (self): return self.v.clearMarked()
def clearOrphan  (self): return self.v.clearOrphan()
def clearVisited (self): return self.v.clearVisited()

def contract (self): return self.v.contract()
def expand   (self): return self.v.expand()

def initExpandedBit    (self): return self.v.initExpandedBit()
def initMarkedBit      (self): return self.v.initMarkedBit()
def initStatus (self, status): return self.v.initStatus(status)

def setMarked   (self): return self.v.setMarked()
def setOrphan   (self): return self.v.setOrphan()
def setSelected (self): return self.v.setSelected()
def setVisited  (self): return self.v.setVisited()
</t>
<t tx="ekr.20091110090536.2077">def computeIcon (self):

    return self.v.computeIcon()

def setIcon (self):

    pass # Compatibility routine for old scripts
</t>
<t tx="ekr.20091110090536.2078">def setSelection (self,start,length):

    return self.v.setSelection(start,length)
</t>
<t tx="ekr.20091110090536.2079">def setBodyString (self,s,encoding="utf-8"):

    p = self
    return p.v.setBodyString(s,encoding)

initBodyString = setBodyString
setTnodeText = setBodyString
scriptSetBodyString = setBodyString

def initHeadString (self,s,encoding="utf-8"):

    p = self
    p.v.initHeadString(s,encoding)

def setHeadString (self,s,encoding="utf-8"):

    p = self
    p.v.initHeadString(s,encoding)
    p.setDirty()
</t>
<t tx="ekr.20091110090536.2080"></t>
<t tx="ekr.20091110090536.2081"># Compatibility routine for scripts.

def clearVisitedInTree (self):

    for p in self.self_and_subtree():
        p.clearVisited()
</t>
<t tx="ekr.20091110090536.2082">def clearAllVisitedInTree (self):

    for p in self.self_and_subtree():
        p.v.clearVisited()
        p.v.clearWriteBit()
</t>
<t tx="ekr.20091110090536.2083"></t>
<t tx="ekr.20091110090536.2084">def clearDirty (self):

    p = self
    p.v.clearDirty()
</t>
<t tx="ekr.20091110090536.2085">def findAllPotentiallyDirtyNodes(self):

    p = self
    return p.v.findAllPotentiallyDirtyNodes()
</t>
<t tx="ekr.20091110090536.2086">def inAtIgnoreRange (self):

    """Returns True if position p or one of p's parents is an @ignore node."""

    p = self

    for p in p.self_and_parents():
        if p.isAtIgnoreNode():
            return True

    return False
</t>
<t tx="ekr.20091110090536.2087">def setAllAncestorAtFileNodesDirty (self,setDescendentsDirty=False):

    trace = False and not g.unitTesting
    verbose = False
    p = self
    dirtyVnodeList = []

    # Calculate all nodes that are joined to p or parents of such nodes.
    nodes = p.findAllPotentiallyDirtyNodes()

    if setDescendentsDirty:
        # N.B. Only mark _direct_ descendents of nodes.
        # Using the findAllPotentiallyDirtyNodes algorithm would mark way too many nodes.
        for p2 in p.subtree():
            # Only @thin nodes need to be marked.
            if p2.v not in nodes and p2.isAtThinFileNode():
                nodes.append(p2.v)

    if trace and verbose:
        for v in nodes:
            print (v.isDirty(),v.isAnyAtFileNode(),v)

    dirtyVnodeList = [v for v in nodes
        if not v.isDirty() and v.isAnyAtFileNode()]
    changed = len(dirtyVnodeList) &gt; 0

    for v in dirtyVnodeList:
        v.setDirty()

    if trace: g.trace("position",dirtyVnodeList,g.callers(5))

    return dirtyVnodeList
</t>
<t tx="ekr.20091110090536.2088">def setDirty (self,setDescendentsDirty=True):

    '''Mark a node and all ancestor @file nodes dirty.'''

    p = self ; dirtyVnodeList = []

    # g.trace(p.h,g.callers(4))

    if not p.v.isDirty():
        p.v.setDirty()
        dirtyVnodeList.append(p.v)

    # Important: this must be called even if p.v is already dirty.
    # Typing can change the @ignore state!
    dirtyVnodeList2 = p.setAllAncestorAtFileNodesDirty(setDescendentsDirty)
    dirtyVnodeList.extend(dirtyVnodeList2)

    return dirtyVnodeList
</t>
<t tx="ekr.20091110090536.2089">@
- convertTreeToString and moreHead can't be vnode methods because they uses level().
- moreBody could be anywhere: it may as well be a postion method.
</t>
<t tx="ekr.20091110090536.2090">def convertTreeToString (self):

    """Convert a positions  suboutline to a string in MORE format."""

    p = self ; level1 = p.level()

    array = []
    for p in p.self_and_subtree():
        array.append(p.moreHead(level1)+'\n')
        body = p.moreBody()
        if body:
            array.append(body +'\n')

    return ''.join(array)
</t>
<t tx="ekr.20091110090536.2091">def moreHead (self, firstLevel,useVerticalBar=False):

    """Return the headline string in MORE format."""

    # useVerticalBar is unused, but it would be useful in over-ridden methods.

    p = self
    level = self.level() - firstLevel
    plusMinus = g.choose(p.hasChildren(), "+", "-")

    return "%s%s %s" % ('\t'*level,plusMinus,p.h)
</t>
<t tx="ekr.20091110090536.2092">@ 
    + test line
    - test line
    \ test line
    test line +
    test line -
    test line \
    More lines...
@c

def moreBody (self):

    """Returns the body string in MORE format.  

    Inserts a backslash before any leading plus, minus or backslash."""

    p = self ; array = []
    lines = p.b.split('\n')
    for s in lines:
        i = g.skip_ws(s,0)
        if i &lt; len(s) and s[i] in ('+','-','\\'):
            s = s[:i] + '\\' + s[i:]
        array.append(s)
    return '\n'.join(array)
</t>
<t tx="ekr.20091110090536.2093"></t>
<t tx="ekr.20091110090536.2094">def children(self):

    '''Return all children of p.'''

    p = self
    p = p.firstChild()
    while p:
        yield p
        p.moveToNext()
    raise StopIteration

# Compatibility with old code.
children_iter = children
</t>
<t tx="ekr.20091110090536.2095">def following_siblings(self):
    '''
    Return all siblings that follow p, not including p.
    '''

    p = self
    p = p.copy() # Always include the original node.
    p = p.next()
    while p:
        yield p
        p.moveToNext()
    raise StopIteration

# Compatibility with old code.
following_siblings_iter = following_siblings
</t>
<t tx="ekr.20091110090536.2096">def nodes (self):

    p = self
    p = p.copy()
    while p:
        yield p.v
        p.moveToThreadNext()

# Compatibility with old code.
tnodes_iter = nodes
vnodes_iter = nodes
</t>
<t tx="ekr.20091110090536.2097">def parents(self):

    '''Return all parents of p.'''

    p = self
    p = p.parent()
    while p:
        yield p
        p.moveToParent()
    raise StopIteration

# Compatibility with old code.
parents_iter = parents
</t>
<t tx="ekr.20091110090536.2098">def self_and_parents(self):

    '''Return p and all parents of p.'''

    p = self
    p = p.copy()
    while p:
        yield p
        p.moveToParent()
    raise StopIteration

# Compatibility with old code.
self_and_parents_iter = self_and_parents
</t>
<t tx="ekr.20091110090536.2099">def self_and_siblings(self):
    '''Return all siblings of p including p.
    '''

    p = self
    p = p.copy()
    while p.hasBack():
        p.moveToBack()
    while p:
        yield p
        p.moveToNext()
    raise StopIteration

# Compatibility with old code.
self_and_siblings_iter = self_and_siblings</t>
<t tx="ekr.20091110090536.2100">def self_and_subtree(self):

    '''Return p's entire subtree, including p.'''

    p = self
    p = p.copy()
    after = p.nodeAfterTree()
    while p and p != after:
        yield p
        p.moveToThreadNext()
    raise StopIteration

# Compatibility with old code.
self_and_subtree_iter = self_and_subtree
</t>
<t tx="ekr.20091110090536.2101">def subtree(self):

    '''Return all descendants of p, not including p.'''

    p = self
    p = p.copy()
    after = p.nodeAfterTree()
    p.moveToThreadNext()
    while p and p != after:
        yield p
        p.moveToThreadNext()
    raise StopIteration

# Compatibility with old code.
subtree_iter = subtree
</t>
<t tx="ekr.20091110090536.2102">def unique_nodes (self):

    p = self
    p = p.copy()
    seen = set()
    while p:
        if p.v in seen:
            p.moveToNodeAfterTree()
        else:
            seen.add(p.v)
            yield p.v
            p.moveToThreadNext()

# Compatibility with old code.
unique_tnodes_iter = unique_nodes
unique_vnodes_iter = unique_nodes
</t>
<t tx="ekr.20091110090536.2103">def unique_subtree (self):
    '''Return unique positions in p's entire subtree, including p.'''

    p = self
    p = p.copy()
    after = p.nodeAfterTree()
    seen = set()
    while p and p != after:
        if p.v in seen:
            p.moveToNodeAfterTree()
        else:
            seen.add(p.v)
            yield p
            p.moveToThreadNext()
    raise StopIteration

# Compatibility with old code.
subtree_with_unique_tnodes_iter = unique_subtree
subtree_with_unique_vnodes_iter = unique_subtree
</t>
<t tx="ekr.20091110090536.2104"></t>
<t tx="ekr.20091110090536.2105">def clone (self):

    """Create a clone of back.

    Returns the newly created position."""

    p = self
    p2 = p.copy() # Do *not* copy the vnode!
    p2._linkAfter(p) # This should "just work"
    return p2
</t>
<t tx="ekr.20091110090536.2106"># These used by unit tests and by the group_operations plugin.

def copyTreeAfter(self):
    p = self
    p2 = p.insertAfter()
    p.copyTreeFromSelfTo(p2)
    return p2

def copyTreeFromSelfTo(self,p2):
    p = self
    p2.v._headString = p.h
    p2.v._bodyString = p.b

    # 2009/10/02: no need to copy arg to iter
    for child in p.children():
        child2 = p2.insertAsLastChild()
        child.copyTreeFromSelfTo(child2)
</t>
<t tx="ekr.20091110090536.2107">@ This is the main delete routine.
It deletes the receiver's entire tree from the screen.
Because of the undo command we never actually delete vnodes or tnodes.
@c

def doDelete (self,newNode=None):

    """Deletes position p from the outline."""

    p = self
    p.setDirty() # Mark @file nodes dirty!

    # Adjust newNode._childIndex if newNode is a following sibling of p.
    sib = p.copy()
    while sib.hasNext():
        sib.moveToNext()
        if sib == newNode:
            newNode._childIndex -= 1
            break

    p._unlink()
</t>
<t tx="ekr.20091110090536.2108">def insertAfter (self):

    """Inserts a new position after self.

    Returns the newly created position."""

    p = self ; context = p.v.context
    p2 = self.copy()

    p2.v = vnode(context=context)
    p2.v.iconVal = 0
    p2._linkAfter(p)

    return p2
</t>
<t tx="ekr.20091110090536.2109">def insertAsLastChild (self):

    """Inserts a new vnode as the last child of self.

    Returns the newly created position."""

    p = self
    n = p.numberOfChildren()

    return p.insertAsNthChild(n)
</t>
<t tx="ekr.20091110090536.2110">def insertAsNthChild (self,n):

    """Inserts a new node as the the nth child of self.
    self must have at least n-1 children.

    Returns the newly created position."""

    p = self ; context = p.v.context
    p2 = self.copy()

    p2.v = vnode(context=context)
    p2.v.iconVal = 0
    p2._linkAsNthChild(p,n)

    return p2
</t>
<t tx="ekr.20091110090536.2111">def invalidOutline (self, message):

    p = self

    if p.hasParent():
        node = p.parent()
    else:
        node = p

    g.alert("invalid outline: %s\n%s" % (message,node))
</t>
<t tx="ekr.20091110090536.2112">def moveAfter (self,a):

    """Move a position after position a."""

    p = self # Do NOT copy the position!

    # g.trace('before','p',p,p.stack,'\na',a,a.stack)

    a._adjustPositionBeforeUnlink(p)
    p._unlink()
    p._linkAfter(a)

    # g.trace('before','p',p,p.stack,'\na',a,a.stack)

    return p
</t>
<t tx="ekr.20091110090536.2113">def moveToFirstChildOf (self,parent):

    """Move a position to the first child of parent."""

    p = self # Do NOT copy the position!
    p._unlink()
    p._linkAsNthChild(parent,0)
    return p


def moveToLastChildOf (self,parent):

    """Move a position to the last child of parent."""

    p = self # Do NOT copy the position!
    p._unlink()
    n = parent.numberOfChildren()
    p._linkAsNthChild(parent,n)
    return p
</t>
<t tx="ekr.20091110090536.2114">def moveToNthChildOf (self,parent,n):

    """Move a position to the nth child of parent."""

    p = self # Do NOT copy the position!

    parent._adjustPositionBeforeUnlink(p)
    p._unlink()
    p._linkAsNthChild(parent,n)

    return p
</t>
<t tx="ekr.20091110090536.2115">def moveToRoot (self,oldRoot=None):

    '''Moves a position to the root position.

    Important: oldRoot must the previous root position if it exists.'''

    p = self # Do NOT copy the position!
    if oldRoot:
        oldRoot._adjustPositionBeforeUnlink(p)
    p._unlink()
    p._linkAsRoot(oldRoot)

    return p
</t>
<t tx="ekr.20091110090536.2116"># This routine checks the structure of the receiver's tree.

def validateOutlineWithParent (self,pv):

    p = self
    result = True # optimists get only unpleasant surprises.
    parent = p.getParent()
    childIndex = p._childIndex

    # g.trace(p,parent,pv)
    &lt;&lt; validate parent ivar &gt;&gt;
    &lt;&lt; validate childIndex ivar &gt;&gt;
    &lt;&lt; validate x ivar &gt;&gt;

    # Recursively validate all the children.
    for child in p.children():
        r = child.validateOutlineWithParent(p)
        if not r: result = False

    return result
</t>
<t tx="ekr.20091110090536.2117">if parent != pv:
    p.invalidOutline( "Invalid parent link: " + repr(parent))
</t>
<t tx="ekr.20091110090536.2118">if pv:
    if childIndex &lt; 0:
        p.invalidOutline ( "missing childIndex" + childIndex )
    elif childIndex &gt;= pv.numberOfChildren():
        p.invalidOutline ( "missing children entry for index: " + childIndex )
elif childIndex &lt; 0:
    p.invalidOutline ( "negative childIndex" + childIndex )
</t>
<t tx="ekr.20091110090536.2119">if not p.v and pv:
    self.invalidOutline ( "Empty t" )
</t>
<t tx="ekr.20091110090536.2120">@
These routines change self to a new position "in place".
That is, these methods must _never_ call p.copy().

When moving to a nonexistent position, these routines simply set p.v = None,
leaving the p.stack unchanged. This allows the caller to "undo" the effect of
the invalid move by simply restoring the previous value of p.v.

These routines all return self on exit so the following kind of code will work:
    after = p.copy().moveToNodeAfterTree()
</t>
<t tx="ekr.20091110090536.2121">def moveToBack (self):

    """Move self to its previous sibling."""

    p = self ; n = p._childIndex

    parent_v = p._parentVnode()
        # Returns None if p.v is None.

    # Do not assume n is in range: this is used by positionExists.
    if parent_v and p.v and 0 &lt; n &lt;= len(parent_v.children):
        p._childIndex -= 1
        p.v = parent_v.children[n-1]
    else:
        p.v = None

    return p
</t>
<t tx="ekr.20091110090536.2122">def moveToFirstChild (self):

    """Move a position to it's first child's position."""

    p = self

    if p.v and p.v.children:
        p.stack.append((p.v,p._childIndex),)
        p.v = p.v.children[0]
        p._childIndex = 0
    else:
        p.v = None

    return p</t>
<t tx="ekr.20091110090536.2123">def moveToLastChild (self):

    """Move a position to it's last child's position."""

    p = self

    if p.v and p.v.children:
        p.stack.append((p.v,p._childIndex),)
        n = len(p.v.children)
        p.v = p.v.children[n-1]
        p._childIndex = n-1
    else:
        p.v = None

    return p
</t>
<t tx="ekr.20091110090536.2124">def moveToLastNode (self):

    """Move a position to last node of its tree.

    N.B. Returns p if p has no children."""

    p = self

    # Huge improvement for 4.2.
    while p.hasChildren():
        p.moveToLastChild()

    return p
</t>
<t tx="ekr.20091110090536.2125">def moveToNext (self):

    """Move a position to its next sibling."""

    p = self ; n = p._childIndex

    parent_v = p._parentVnode()
        # Returns None if p.v is None.
    if not p.v: g.trace('parent_v',parent_v,'p.v',p.v)

    if p.v and parent_v and len(parent_v.children) &gt; n+1:
        p._childIndex = n+1
        p.v = parent_v.children[n+1]
    else:
        p.v = None

    return p
</t>
<t tx="ekr.20091110090536.2126">def moveToNodeAfterTree (self):

    """Move a position to the node after the position's tree."""

    p = self

    while p:
        if p.hasNext():
            p.moveToNext()
            break
        p.moveToParent()

    return p
</t>
<t tx="ekr.20091110090536.2127">def moveToNthChild (self,n):

    p = self

    if p.v and len(p.v.children) &gt; n:
        p.stack.append((p.v,p._childIndex),)
        p.v = p.v.children[n]
        p._childIndex = n
    else:
        p.v = None

    return p
</t>
<t tx="ekr.20091110090536.2128">def moveToParent (self):

    """Move a position to its parent position."""

    p = self

    if p.v and p.stack:
        p.v,p._childIndex = p.stack.pop()
    else:
        p.v = None

    return p
</t>
<t tx="ekr.20091110090536.2129">def moveToThreadBack (self):

    """Move a position to it's threadBack position."""

    p = self

    if p.hasBack():
        p.moveToBack()
        p.moveToLastNode()
    else:
        p.moveToParent()

    return p
</t>
<t tx="ekr.20091110090536.2130">def moveToThreadNext (self):

    """Move a position to threadNext position."""

    p = self

    if p.v:
        if p.v.children:
            p.moveToFirstChild()
        elif p.hasNext():
            p.moveToNext()
        else:
            p.moveToParent()
            while p:
                if p.hasNext():
                    p.moveToNext()
                    break #found
                p.moveToParent()
            # not found.

    return p
</t>
<t tx="ekr.20091110090536.2131">def moveToVisBack (self,c):

    """Move a position to the position of the previous visible node."""

    trace = False and not g.unitTesting
    verbose = True
    p = self ; limit,limitIsVisible = c.visLimit()
    if trace and verbose:
        g.trace(p,'limit',limit,'limitIsVisible',limitIsVisible)
    if trace: g.trace('***entry','parent',p.parent(),'p',p,g.callers(5))
    while p:
        # Short-circuit if possible.
        back = p.back()
        if trace: g.trace(
            'back',back,'hasChildren',bool(back and back.hasChildren()),
            'isExpanded',bool(back and back.isExpanded()))

        if back and back.hasChildren() and back.isExpanded():
            p.moveToThreadBack()
        elif back:
            p.moveToBack()
        else:
            p.moveToParent() # Same as p.moveToThreadBack()
        # if back and (not back.hasChildren() or not back.isExpanded()):
            # p.moveToBack()
        # else:
            # p.moveToThreadBack()
        if trace: g.trace(p.parent(),p)
        if p:
            if trace and verbose: g.trace('**p',p)
            done,val = self.checkVisBackLimit(limit,limitIsVisible,p)
            if done:
                if trace and verbose: g.trace('done',p)
                return val
            if p.isVisible(c):
                if trace and verbose: g.trace('isVisible',p)
                return p
    else:
        # assert not p.
        return p
</t>
<t tx="ekr.20091110090536.2132">def checkVisBackLimit (self,limit,limitIsVisible,p):

    '''Return done, return-val'''

    trace = True and not g.unitTesting
    c = p.v.context

    if limit:
        if limit == p:
            if trace: g.trace('at limit',p)
            if limitIsVisible and p.isVisible(c):
                return True,p
            else:
                return True,None
            #return True,g.choose(limitIsVisible and p.isVisible(c),p,None)
        elif limit.isAncestorOf(p):
            return False,None
        else:
            if trace: g.trace('outside limit tree',limit,p)
            return True,None
    else:
        return False,None
</t>
<t tx="ekr.20091110090536.2133">def moveToVisNext (self,c):

    """Move a position to the position of the next visible node."""

    trace = False and not g.unitTesting
    verbose = False
    p = self ; limit,limitIsVisible = c.visLimit()
    while p:
        if trace: g.trace('1',p.h)
        # if trace: g.trace('hasChildren %s, isExpanded %s %s' % (
            # p.hasChildren(),p.isExpanded(),p.h))
        # Short-circuit if possible.
        if p.hasNext() and p.hasChildren() and p.isExpanded():
            p.moveToFirstChild()
        elif p.hasNext():
            p.moveToNext()
        else:
            p.moveToThreadNext()
        # if p.hasNext() and (not p.hasChildren() or not p.isExpanded()):
            # p.moveToNext()
        # else:
            # p.moveToThreadNext()
        if trace: g.trace('2',p.h)
        if p:
            done,val = self.checkVisNextLimit(limit,p)
            if done: return val
            if p.isVisible(c):
                return p.copy()
    else:
        # assert not p.
        return p
</t>
<t tx="ekr.20091110090536.2134">def checkVisNextLimit (self,limit,p):

    '''Return done, return-val'''

    trace = False and not g.unitTesting

    if limit:
        # Unlike moveToVisBack, being at the limit does not terminate.
        if limit == p:
            return False, None
        elif limit.isAncestorOf(p):
            return False,None
        else:
            if trace: g.trace('outside limit tree')
            return True,None
    else:
        return False,None
</t>
<t tx="ekr.20091110090536.2135"># These methods are only for the use of low-level code
# in leoNodes.py, leoFileCommands.py and leoUndo.py.</t>
<t tx="ekr.20091110090536.2136">def _adjustPositionBeforeUnlink (self,p2):

    '''Adjust position p before unlinking p2.'''

    # p will change if p2 is a previous sibling of p or
    # p2 is a previous sibling of any ancestor of p.

    trace = False and not g.unitTesting
    p = self ; sib = p.copy()

    if trace: g.trace('entry',p.stack)

    # A special case for previous siblings.
    # Adjust p._childIndex, not the stack's childIndex.
    while sib.hasBack():
        sib.moveToBack()
        if sib == p2:
            p._childIndex -= 1
            if trace: g.trace('***new index: %s\n%s' % (
                p.h,p.stack))
            return

    # Adjust p's stack.
    stack = [] ; changed = False ; i = 0
    while i &lt; len(p.stack):
        v,childIndex = p.stack[i]
        p3 = position(v=v,childIndex=childIndex,stack=stack[:i])
        while p3:
            if p2.v == p3.v: # A match with the to-be-moved node?
                stack.append((v,childIndex-1),)
                changed = True
                break # terminate only the inner loop.
            p3.moveToBack()
        else:
            stack.append((v,childIndex),)
        i += 1

    if changed:
        if trace: g.trace('***new stack: %s\n%s' % (
            p.h,stack))
        p.stack = stack</t>
<t tx="ekr.20091110090536.2137">if g.unitTesting:

    c,p = g.getTestVars()

    table = (
        '1',
        '1-1','1-1-1','1-1-2',
        '1-2','1-2-1','1-2-2',
        '2',
        '2-1','2-1-1','2-1-2',
        '2-2','2-2-1','2-2-2',
        '3',
        '3-1','3-1-1','3-1-2',
        '3-2','3-2-1','3-2-2',
    )

    for suffix in table:
        h = 'node %s' % suffix
        p2 = g.findNodeInTree(c,p,h)
        assert p2,h

    table2 = (
        ('2-1-2','2-1-1','2-1-1'),
        ('3','2','2'),
    )  

    for h1,h2,h3 in table2:
        p1 = g.findNodeInTree(c,p,'node %s' % h1)
        p2 = g.findNodeInTree(c,p,'node %s' % h2)
        p3 = g.findNodeInTree(c,p,'node %s' % h3)
        p1._adjustPositionBeforeUnlink(p2)
        result = p1
        assert result.stack == p3.stack,'expected %s got %s' % (
            p3.h,result and result.h or '&lt;none&gt;')

    # Data.
    @others
</t>
<t tx="ekr.20091110090536.2138"># Node 1</t>
<t tx="ekr.20091110090536.2139"># node 1-1</t>
<t tx="ekr.20091110090536.2140"># node 1-1-1</t>
<t tx="ekr.20091110090536.2141"># node 1-1-2</t>
<t tx="ekr.20091110090536.2142"># node 1-2</t>
<t tx="ekr.20091110090536.2143"># node 1-2-1</t>
<t tx="ekr.20091110090536.2144"># node 1-2-2</t>
<t tx="ekr.20091110090536.2145"># node 2</t>
<t tx="ekr.20091110090536.2146"># node 2-1</t>
<t tx="ekr.20091110090536.2147"># node 2-1-1</t>
<t tx="ekr.20091110090536.2148"># node 2-1-2
</t>
<t tx="ekr.20091110090536.2149"># node 2-2</t>
<t tx="ekr.20091110090536.2150"># node 2-2-1</t>
<t tx="ekr.20091110090536.2151"># node 2-2-2
</t>
<t tx="ekr.20091110090536.2152"># node 3</t>
<t tx="ekr.20091110090536.2153"># node 3-1
</t>
<t tx="ekr.20091110090536.2154"># node 3-1-1</t>
<t tx="ekr.20091110090536.2155"># node 3-1-2
</t>
<t tx="ekr.20091110090536.2156"># node 3-2
</t>
<t tx="ekr.20091110090536.2157"># node 3-2-1</t>
<t tx="ekr.20091110090536.2158"># node 3-2-2
</t>
<t tx="ekr.20091110090536.2159">def _linkAfter (self,p_after,adjust=True):

    '''Link self after p_after.'''

    p = self
    parent_v = p_after._parentVnode()
        # Returns None if p.v is None

    # Init the ivars.
    p.stack = p_after.stack[:]
    p._childIndex = p_after._childIndex + 1

    # Set the links.
    child = p.v
    n = p_after._childIndex+1
    child._addLink(n,parent_v,adjust=adjust)</t>
<t tx="ekr.20091110090536.2160">def _linkAsNthChild (self,parent,n,adjust=True):

    p = self
    parent_v = parent.v

    # Init the ivars.
    p.stack = parent.stack[:]
    p.stack.append((parent_v,parent._childIndex),)
    p._childIndex = n

    child = p.v
    child._addLink(n,parent_v,adjust=adjust)

</t>
<t tx="ekr.20091110090536.2161">def _parentVnode (self):

    '''Return the parent vnode.
    Return the hiddenRootNode if there is no other parent.'''

    p = self

    if p.v:
        data = p.stack and p.stack[-1]
        if data:
            v, junk = data
            return v
        else:
            return p.v.context.hiddenRootNode
    else:
        return None
</t>
<t tx="ekr.20091110090536.2162">def _linkAsRoot (self,oldRoot):

    """Link self as the root node."""

    p = self
    assert(p.v)

    hiddenRootNode = p.v.context.hiddenRootNode

    if oldRoot: oldRootNode = oldRoot.v
    else:       oldRootNode = None

    # Init the ivars.
    p.stack = []
    p._childIndex = 0

    parent_v = hiddenRootNode
    child = p.v
    if not oldRoot: parent_v.children = []
    child._addLink(0,parent_v)

    return p
</t>
<t tx="ekr.20091110090536.2163">def _unlink (self):

    '''Unlink the receiver p from the tree.'''

    p = self ; n = p._childIndex
    parent_v = p._parentVnode()
        # returns None if p.v is None
    child = p.v
    assert(p.v)
    assert(parent_v)

    # Delete the child.
    if (0 &lt;= n &lt; len(parent_v.children) and
        parent_v.children[n] == child
    ):
        # This is the only call to v._cutlink.
        child._cutLink(n,parent_v)
    else:
        self.badUnlink(parent_v,n,child)</t>
<t tx="ekr.20091110090536.2164">def badUnlink (self,parent_v,n,child):

    if 0 &lt;= n &lt; len(parent_v.children):
        g.trace('**can not happen: children[%s] != p.v' % (n))
        g.trace('parent_v.children...\n',
            g.listToString(parent_v.children))
        g.trace('parent_v',parent_v)
        g.trace('parent_v.children[n]',parent_v.children[n])
        g.trace('child',child)
        g.trace('** callers:',g.callers())
        if g.app.unitTesting: assert False, 'children[%s] != p.v'
    else:   
        g.trace('**can not happen: bad child index: %s, len(children): %s' % (
            n,len(parent_v.children)))
        g.trace('parent_v.children...\n',
            g.listToString(parent_v.children))
        g.trace('parent_v',parent_v,'child',child)
        g.trace('** callers:',g.callers())
        if g.app.unitTesting: assert False, 'bad child index: %s' % (n)</t>
<t tx="ekr.20091110090536.2165">def makeCacheList(self):

    '''Create a recursive list describing a tree
    for use by v.createOutlineFromCacheList.
    '''

    p = self

    return [
        p.h,p.b,p.gnx,
        [p2.makeCacheList() for p2 in p.children()]]
</t>
<t tx="ekr.20091110090536.2166">class poslist(list):
    """ List of positions 

    This behaves like a normal list, with the distinction that it 
    has select_h and select_b methods that can be used 
    to search through immediate children of the nodes.

    """
    @others
</t>
<t tx="ekr.20091110090536.2167">def select_h(self, regex, flags = re.IGNORECASE):
    """ Find immediate child nodes of nodes in poslist with regex.

    You can chain find_h / find_b with select_h / select_b like this
    to refine an outline search::

        pl = c.find_h('@thin.*py').select_h('class.*').select_b('import (.*)')

    """
    pat = re.compile(regex, flags)
    res = poslist()
    for p in self:
        for child_p in p.children():            
            m = re.match(pat, child_p.h)
            if m:
                pc = child_p.copy()
                pc.mo = m
                res.append(pc)
    return res



</t>
<t tx="ekr.20091110090536.2168">def select_b(self, regex, flags = re.IGNORECASE ):
    """ Find all the nodes in poslist where body matches regex

    You can chain find_h / find_b with select_h / select_b like this
    to refine an outline search::

        pl = c.find_h('@thin.*py').select_h('class.*').select_b('import (.*)')
    """
    pat = re.compile(regex, flags)
    res = poslist()
    for p in self:
        m = re.finditer(pat, p.b)
        t1,t2 = itertools.tee(m,2)
        try:
            first = t1.next()
            # if does not raise StopIteration...
            pc = p.copy()
            pc.matchiter = t2
            res.append(pc)

        except StopIteration:
            pass

    return res



</t>
<t tx="ekr.20091110090536.2169">In Leo, **outline structure is real data that is available to scripts.**</t>
<t tx="ekr.20091110090536.2171"></t>
<t tx="ekr.20091110090536.2172">Leo is written entirely in Python.</t>
<t tx="ekr.20091110090536.2173">@language python

'''This script prints the number of nodes in the outline.'''

# Leo's execute-script command (ctrl-B) predefines c and g.

n = len(list(c.all_nodes())) # Count the number of nodes.
fn = c.shortFileName() # Get the name of Leo outline.
g.es('%s contains %s nodes' % (fn,n),color='red')</t>
<t tx="ekr.20091110090536.2174">Leo headlines naturally describe body text.

Headlines are *metadata*. Body text is data.

By *convention*, headlines that start with @x declare **node types**.

Leo's core supports many types. Scripts and plugins support others.</t>
<t tx="ekr.20091110090536.2181"># Scripts, including unit tests, can use outline structure, and types.

import leo.core.leoTest as leoTest
leoTest.runEditCommandTest(c,p)</t>
<t tx="ekr.20091110090536.2182">first line
    line 1
        line a
            line b
    line c
last line</t>
<t tx="ekr.20091110090536.2183">first line
line 1
    line a
        line b
line c
last line</t>
<t tx="ekr.20091110090536.2184">first line
    line 1
        line a
            line b
    line c
last line</t>
<t tx="ekr.20091110090536.2186">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;!--@+leo-ver=4-thin--&gt;
&lt;!--@+node:ekr.20080301071818.1:@thin html/front.html--&gt;
&lt;!--@@first--&gt;

&lt;!--@@language html--&gt;
&lt;!--@@tabwidth -4--&gt;

&lt;!-- Last Modified: July 31, 2008 --&gt;
&lt;!-- Author: Edward K. Ream, edreamleo@gmail.com --&gt;

&lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"&gt;
&lt;head&gt;
&lt;!--@&lt;&lt;head&gt;&gt;--&gt;
&lt;!--@+node:ekr.20080301075734.1:&lt;&lt;head&gt;&gt;--&gt;
&lt;title&gt;Leo's Home Page&lt;/title&gt;

&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/&gt;

&lt;meta name="description" content="This page describes Leo, a programmer's outliner." /&gt;

&lt;meta name="keywords" content="LEO, LITERATE PROGRAMMING, OUTLINES, CWEB,
NOWEB, EDWARD K. REAM, DONALD E. KNUTH, SILVIO LEVY, OPEN SOFTWARE" /&gt;

&lt;!-- for GeoUrl --&gt;
&lt;meta name="ICBM" content="43.0713768, -89.4188004" /&gt;
&lt;meta name="DC.title" content="Leo's Home Page" /&gt;
&lt;!--@-node:ekr.20080301075734.1:&lt;&lt;head&gt;&gt;--&gt;
&lt;!--@nl--&gt;
&lt;/head&gt;

&lt;body bgcolor="#fffbdc"&gt;
&lt;!--@&lt;&lt; main table &gt;&gt;--&gt;
&lt;!--@+node:ekr.20080301075734.4:&lt;&lt; main table &gt;&gt;--&gt;

&lt;table border="0" bgcolor="#FFFBDC"&gt;
    &lt;tr&gt;
        &lt;td width="22%" height="21" align="center" bgcolor="#FFFBDC" valign="middle"&gt;
            &lt;b&gt;&lt;font size="4"&gt;Leo's Home&lt;/font&gt;&lt;/b&gt;
        &lt;/td&gt;

        &lt;td bgcolor="#F0E68C" width="78%" height="21" align="center"&gt;
            &lt;!--@            &lt;&lt; upper table &gt;&gt;--&gt;
            &lt;!--@+node:ekr.20080301080758:&lt;&lt; upper table&gt;&gt;--&gt;

            &lt;table border="0" width="100%"&gt;
                &lt;tr&gt;
                    &lt;td width="25%" align="center"&gt;
                        &lt;a href="http://www.python.org/"&gt;
                            &lt;img border="0" src="PythonPowered.gif" width="110" height="44" /&gt;&lt;/a&gt;
                    &lt;/td&gt;

                    &lt;td width="50%" align="center"&gt;
                        &lt;a href="http://groups.google.com/group/leo-editor"&gt;Leo at Google Groups&lt;/a&gt;

                    &lt;/td&gt;

                    &lt;td width="25%" align="center"&gt;
                        &lt;a href="http://www.mind-mapping.org/"&gt;mind-mapping.org&lt;/a&gt;
                    &lt;/td&gt;
                &lt;/tr&gt;
            &lt;/table&gt;
            &lt;!--@nonl--&gt;
            &lt;!--@-node:ekr.20080301080758:&lt;&lt; upper table&gt;&gt;--&gt;

            &lt;!--@nl--&gt;
        &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
        &lt;td bgcolor="#F0E68C" width="22%" height="143" valign="top"&gt;
            &lt;!--@            &lt;&lt; left table &gt;&gt;--&gt;
            &lt;!--@+node:ekr.20080301075734.6:&lt;&lt; left table &gt;&gt;--&gt;
            &lt;table border="0" width="100%"&gt;

                &lt;tr&gt;&lt;td width="50%" bgcolor="#DAA520"&gt;&lt;b&gt;Documentation&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;
                        &lt;!--
                        &lt;a href="http://sourceforge.net/project/screenshots.php?group_id=3458"&gt;Screen Shots&lt;/a&gt;
                        --&gt;
                        &lt;a href="http:screen-shots.html"&gt;Screen Shots&lt;/a&gt;
                &lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="intro.html"&gt;Beginners Guide&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="leo_toc.html"&gt;Users Guide&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;

                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="FAQ.html"&gt;FAQ&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;
                    &lt;a href="http://www.3dtree.com/ev/e/sbooks/leo/sbframetoc_ie.htm"&gt;Online tutorial&lt;/a&gt;
                &lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="testimonials.html"&gt;Quotes&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%" bgcolor="#DAA520"&gt;&lt;b&gt;Links&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;

                    &lt;!--@        &lt;&lt; download ref &gt;&gt;--&gt;
                    &lt;!--@+node:ekr.20080306071848:&lt;&lt; download ref &gt;&gt; (contains version number)--&gt;
                    &lt;a href="http://sourceforge.net/project/showfiles.php?group_id=3458&amp;amp;package_id=29106"&gt;
                        Download Leo[4.7 beta 1]&lt;/a&gt;
                    &lt;!--@nonl--&gt;
                    &lt;!--@-node:ekr.20080306071848:&lt;&lt; download ref &gt;&gt; (contains version number)--&gt;
                    &lt;!--@nl--&gt;
                &lt;/td&gt;&lt;/tr&gt;

                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="http://sourceforge.net/project/?group_id=3458"&gt; Leo at SourceForge&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="http://groups.google.com/group/leo-editor"&gt;Leo at Google Groups&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="http://launchpad.net/leo-editor"&gt;Leo at launchpad&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;!-- &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="http://leo.tigris.org/source/browse/leo/"&gt;Leo's cvs repository&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt; --&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;Leo's &lt;a href="http://leo.zwiki.org"&gt;Wiki&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;Leo's &lt;a href="http://www.greygreen.org/leo/"&gt;Daily snapshots&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;

                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="leoLinks.html"&gt;More links&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%" bgcolor="#DAA520"&gt;&lt;b&gt;Edward K. Ream&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="ekr.html"&gt;Home&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="mailto:edreamleo@gmail.com"&gt;Contact&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
            &lt;/table&gt;
            &lt;!--@-node:ekr.20080301075734.6:&lt;&lt; left table &gt;&gt;--&gt;
            &lt;!--@nl--&gt;

        &lt;/td&gt;

        &lt;td width="78%" height="143" bgcolor="#FFFBDC"&gt;
            &lt;!--@            &lt;&lt; center area &gt;&gt;--&gt;
            &lt;!--@+node:ekr.20080301082848:&lt;&lt; center area &gt;&gt;--&gt;
            &lt;h2&gt; Leo is...&lt;/h2&gt;

            &lt;ul&gt;
            &lt;!--@&lt;&lt; what is Leo list &gt;&gt;--&gt;

            &lt;!--@+node:ekr.20080301083325:&lt;&lt; what is Leo list &gt;&gt;--&gt;
            &lt;li&gt;
                A &lt;i&gt;versatile data management platform&lt;/i&gt;.&lt;br/&gt;
                Leo shows &lt;b&gt;user-created&lt;/b&gt; relationships among any kind of data:&lt;br /&gt;
                computer programs, web sites, etc.&lt;br /&gt;

                Leo shows multiple views of data within a single outline.&lt;/li&gt;
            &lt;li&gt;
                An &lt;i&gt;outlining editor for programmers&lt;/i&gt;.&lt;br /&gt;
                Leo supports &lt;i&gt;optional&lt;/i&gt; &lt;a HREF="http://www.eecs.harvard.edu/~nr/noweb/"&gt;noweb&lt;/a&gt;
                and &lt;a HREF="http://www-cs-faculty.stanford.edu/~knuth/cweb.html"&gt;CWEB&lt;/a&gt; markup.&lt;/li&gt;

            &lt;li&gt;A flexible &lt;i&gt;browser&lt;/i&gt; for projects, programs, classes or any other data.&lt;/li&gt;
            &lt;li&gt;A &lt;i&gt;project manager&lt;/i&gt;.&lt;/li&gt;
            &lt;li&gt;&lt;i&gt;Portable&lt;/i&gt;. Leo runs on Windows, Linux and MacOS X.&lt;/li&gt;
            &lt;li&gt;&lt;i&gt;100% pure&lt;/i&gt; &lt;a HREF="http://www.python.org/"&gt;&lt;i&gt;Python&lt;/i&gt;&lt;/a&gt;.&lt;/li&gt;

            &lt;li&gt;&lt;i&gt;Fully scriptable using &lt;/i&gt;&lt;a HREF="http://www.python.org/"&gt;&lt;i&gt;Python&lt;/i&gt;&lt;/a&gt;.&lt;/li&gt;
            &lt;li&gt;Leo's outline files are &lt;a HREF="http://www.w3.org/XML/"&gt;XML&lt;/a&gt; format.&lt;/li&gt;
            &lt;li&gt;
                &lt;a href="http://www.opensource.org/"&gt;&lt;i&gt;Open Software&lt;/i&gt;&lt;/a&gt;,
                distributed under the
                &lt;a href="http://www.opensource.org/licenses/mit-license.php/"&gt;

                MIT License
                &lt;/a&gt;.
            &lt;/li&gt;
            &lt;!--@nonl--&gt;
            &lt;!--@-node:ekr.20080301083325:&lt;&lt; what is Leo list &gt;&gt;--&gt;
            &lt;!--@nl--&gt;
            &lt;/ul&gt;

            &lt;p&gt;
            Please use &lt;a href="http://groups.google.com/group/leo-editor"&gt;leo-editor&lt;/a&gt;

            to ask questions and make suggestions.
            &lt;/p&gt;

            &lt;p&gt;
            Leo's author is &lt;a HREF="ekr.html"&gt;Edward K. Ream&lt;/a&gt;
            &lt;/p&gt;
            &lt;!--@nonl--&gt;
            &lt;!--@-node:ekr.20080301082848:&lt;&lt; center area &gt;&gt;--&gt;
            &lt;!--@nl--&gt;

        &lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;
&lt;!--@-node:ekr.20080301075734.4:&lt;&lt; main table &gt;&gt;--&gt;
&lt;!--@nl--&gt;
&lt;/body&gt;
&lt;/html&gt;

&lt;!--@-node:ekr.20080301071818.1:@thin html/front.html--&gt;
&lt;!--@-leo--&gt;
</t>
<t tx="ekr.20091110090536.2188"># @button nodes create buttons in the icon bar.
# Pressing the button, applies the script to the selected node.

g.es('%s characters in headline' % (len(p.h)))</t>
<t tx="ekr.20091110090536.2189">@language python</t>
<t tx="ekr.20091110104908.2101"></t>
<t tx="ekr.20091110104908.2102"></t>
<t tx="ekr.20091110104908.2104"></t>
<t tx="ekr.20091110104908.2105">@nocolor-node

To exercise the bug, do the following in test.leo:

- Expand the "prototypes" node.
- Expand any child node.
- Move beyond the now-expanded child node.
- Hit Alt-Left.  This will select the prototype node.
  The expanded child node will be marked by Leo as being contracted,
  but it *wont* be contracted actually, which confuses moveToVisNext.</t>
<t tx="ekr.20091110104908.2106">@nocolor-node

The culprit was the sparse_goto_parent option.
It never worked properly, and it caused the expansion
state of nodes as seen by Leo to get out-of-synch
with the expansion state as seen by the qt tree code.
</t>
<t tx="ekr.20091110104908.2108"></t>
<t tx="ekr.20091110142807.2083">s = p.bodyString()

s = s.replace('\n\n','***2***')
s = s.replace('\n',' ')
s = s.replace('***2***','\n\n')
s = s.replace('\n  ','\n')
s = s.replace('\n ','\n')
s = s.replace('     ',' ')
s = s.replace('    ',' ')
s = s.replace('   ',' ')
s = s.replace('  ',' ')

p.setBodyString(s)</t>
<t tx="ekr.20091116094116.2312">/home/edreamleo/leo.repo/trunk/leo/Icons/Lioness.jpg</t>
<t tx="ekr.20091116094116.2313">*Nodes* contain *headlines* and *body text*.

Nodes and outlines are true Python objects.</t>
<t tx="ekr.20091116094116.2317"></t>
<t tx="ekr.20091116094116.2322"></t>
<t tx="ekr.20091116094116.2323"></t>
<t tx="ekr.20091116094116.2324"></t>
<t tx="ekr.20091116094116.2325"></t>
<t tx="ekr.20091116094116.2328">@language python</t>
<t tx="ekr.20091116094116.2329">@nocolor-node

To exercise the bug, do the following in test.leo:

- Expand the "prototypes" node.
- Expand any child node.
- Move beyond the now-expanded child node.
- Hit Alt-Left.  This will select the prototype node.
  The expanded child node will be marked by Leo as being contracted,
  but it *wont* be contracted actually, which confuses moveToVisNext.</t>
<t tx="ekr.20091116094116.2330">@nocolor-node

The culprit was the sparse_goto_parent option.
It never worked properly, and it caused the expansion
state of nodes as seen by Leo to get out-of-synch
with the expansion state as seen by the qt tree code.
</t>
<t tx="ekr.20091116094116.2331">def selectVisNext (self,event=None):

    '''Select the visible node following the presently selected node.'''

    c = self ; p = c.p
    if not p: return
    if not c.canSelectVisNext(): return

    p.moveToVisNext(c)
    c.treeSelectHelper(p)
</t>
<t tx="ekr.20091116094116.2332"># This has an up arrow for a control key.

def selectVisBack (self,event=None):

    '''Select the visible node preceding the presently selected node.'''

    c = self ; p = c.p
    if not p: return
    if not c.canSelectVisBack(): return

    p.moveToVisBack(c)

    # g.trace(p.h)
    c.treeSelectHelper(p)
</t>
<t tx="ekr.20091116094116.2333">def goToParent (self,event=None):

    '''Select the parent of the selected node.'''

    c = self ; p = c.p

    # g.trace(p.parent())

    c.treeSelectHelper(p and p.parent())
</t>
<t tx="ekr.20091116094116.2334">def contractNodeOrGoToParent (self,event=None):

    """Simulate the left Arrow Key in folder of Windows Explorer."""

    trace = False and not g.unitTesting
    c = self ; p = c.p
    redraw = False ; fullRedraw = False
    if p.hasChildren() and p.isExpanded():
        if trace: g.trace('contract',p.h)
        c.contractNode()
        redraw = True # New in one-node world.
    elif p.hasParent() and p.parent().isVisible(c):
        redraw = False
        p.contract() # Make sure we know this node is contracted.
        # This "feature" is dubious.
        # To work properly, it requires a full redraw.
        if False: # self.sparse_goto_parent:
            for child in p.self_and_siblings():
                if child != p and child.isExpanded():
                    child.contract()
                    redraw = True ; fullRedraw = True
        if trace: g.trace('goto parent',p.h)
        c.goToParent()

    if redraw:
        if fullRedraw or p.isCloned():
            if trace: g.trace('full redraw',p.h)
            c.redraw()
        else:
            c.redraw_after_contract(p=p,setFocus=True)
</t>
<t tx="ekr.20091116094116.2335">def expandNodeAndGoToFirstChild (self,event=None):

    """If a node has children, expand it if needed and go to the first child."""

    trace = False and not g.unitTesting
    c = self ; p = c.p

    # New code.
    if p.hasChildren():
        if p.isExpanded():
            p.moveToFirstChild()
            if trace: g.trace('select',p.h)
            c.selectPosition(p)
        else:
            if trace: g.trace('expand',p.h)
            c.expandNode() # Calls redraw_after_expand.
    elif p.hasNext():
        c.goToNextSibling()
    else:
        while p.hasParent():
            p.moveToParent()
            if p.hasNext():
                p.moveToNext()
                break
        c.selectPosition(p)
    c.treeFocusHelper()

def expandNodeOrGoToFirstChild (self,event=None):

    """Simulate the Right Arrow Key in folder of Windows Explorer."""

    c = self ; p = c.p
    if p.hasChildren():
        if not p.isExpanded():
            c.expandNode() # Calls redraw_after_expand.
        else:
            c.redraw_after_expand(p.firstChild(),setFocus=True)
</t>
<t tx="ekr.20091116094116.2336">def contractNode (self,event=None):

    '''Contract the presently selected node.'''

    c = self ; p = c.p

    p.contract()

    if p.isCloned():
        c.redraw() # A full redraw is necessary to handle clones.
    else:
        c.redraw_after_contract(p=p,setFocus=True)
</t>
<t tx="ekr.20091116094116.2337">def expandNode (self,event=None):

    '''Expand the presently selected node.'''

    trace = False and not g.unitTesting
    c = self ; p = c.p

    p.expand()

    if p.isCloned():
        if trace: g.trace('***redraw')
        c.redraw() # Bug fix: 2009/10/03.
    else:
        c.redraw_after_expand(p,setFocus=True)

</t>
<t tx="ekr.20091116094116.2338">def treeSelectHelper (self,p):

    c = self

    if not p: p = c.p

    if p:
        # Do not call expandAllAncestors here.
        c.selectPosition(p)
        c.redraw_after_select(p)

    c.treeFocusHelper()
</t>
<t tx="ekr.20091116094116.2339">def moveToVisBack (self,c):

    """Move a position to the position of the previous visible node."""

    trace = False and not g.unitTesting
    verbose = True
    p = self ; limit,limitIsVisible = c.visLimit()
    if trace and verbose:
        g.trace(p,'limit',limit,'limitIsVisible',limitIsVisible)
    if trace: g.trace('***entry','parent',p.parent(),'p',p,g.callers(5))
    while p:
        # Short-circuit if possible.
        back = p.back()
        if trace: g.trace(
            'back',back,'hasChildren',bool(back and back.hasChildren()),
            'isExpanded',bool(back and back.isExpanded()))

        if back and back.hasChildren() and back.isExpanded():
            p.moveToThreadBack()
        elif back:
            p.moveToBack()
        else:
            p.moveToParent() # Same as p.moveToThreadBack()
        # if back and (not back.hasChildren() or not back.isExpanded()):
            # p.moveToBack()
        # else:
            # p.moveToThreadBack()
        if trace: g.trace(p.parent(),p)
        if p:
            if trace and verbose: g.trace('**p',p)
            done,val = self.checkVisBackLimit(limit,limitIsVisible,p)
            if done:
                if trace and verbose: g.trace('done',p)
                return val
            if p.isVisible(c):
                if trace and verbose: g.trace('isVisible',p)
                return p
    else:
        # assert not p.
        return p
</t>
<t tx="ekr.20091116094116.2340">def checkVisBackLimit (self,limit,limitIsVisible,p):

    '''Return done, return-val'''

    trace = True and not g.unitTesting
    c = p.v.context

    if limit:
        if limit == p:
            if trace: g.trace('at limit',p)
            if limitIsVisible and p.isVisible(c):
                return True,p
            else:
                return True,None
            #return True,g.choose(limitIsVisible and p.isVisible(c),p,None)
        elif limit.isAncestorOf(p):
            return False,None
        else:
            if trace: g.trace('outside limit tree',limit,p)
            return True,None
    else:
        return False,None
</t>
<t tx="ekr.20091116094116.2341">def moveToVisNext (self,c):

    """Move a position to the position of the next visible node."""

    trace = False and not g.unitTesting
    verbose = False
    p = self ; limit,limitIsVisible = c.visLimit()
    while p:
        if trace: g.trace('1',p.h)
        # if trace: g.trace('hasChildren %s, isExpanded %s %s' % (
            # p.hasChildren(),p.isExpanded(),p.h))
        # Short-circuit if possible.
        if p.hasNext() and p.hasChildren() and p.isExpanded():
            p.moveToFirstChild()
        elif p.hasNext():
            p.moveToNext()
        else:
            p.moveToThreadNext()
        # if p.hasNext() and (not p.hasChildren() or not p.isExpanded()):
            # p.moveToNext()
        # else:
            # p.moveToThreadNext()
        if trace: g.trace('2',p.h)
        if p:
            done,val = self.checkVisNextLimit(limit,p)
            if done: return val
            if p.isVisible(c):
                return p.copy()
    else:
        # assert not p.
        return p
</t>
<t tx="ekr.20091116094116.2342">def checkVisNextLimit (self,limit,p):

    '''Return done, return-val'''

    trace = False and not g.unitTesting

    if limit:
        # Unlike moveToVisBack, being at the limit does not terminate.
        if limit == p:
            return False, None
        elif limit.isAncestorOf(p):
            return False,None
        else:
            if trace: g.trace('outside limit tree')
            return True,None
    else:
        return False,None
</t>
<t tx="ekr.20091116094116.2343"></t>
<t tx="ekr.20091116094116.2344"></t>
<t tx="ekr.20091116094116.2345">@language python
@tabwidth -4
@pagewidth 80

&lt;&lt; A longish docstring &gt;&gt;
&lt;&lt; imports &gt;&gt;

class myClass:
    '''An example class'''
    @others</t>
<t tx="ekr.20091116094116.2346">import os
import sys</t>
<t tx="ekr.20091116094116.2564">@language python # This is Leo markup. It applies to all descendant nodes.

# The execute-script command predefines g and c.

g.es('%s contains %s nodes' % (
    c.shortFileName(),
    len(list(c.all_nodes()))),
    color='red')</t>
<t tx="ekr.20091116094116.2566">By *convention*, headlines that start with @x declare **node types**.

Leo's core supports many types. Scripts and plugins support others.</t>
<t tx="ekr.20091116094116.2567">@language python</t>
<t tx="ekr.20091116094116.2568">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;!--@+leo-ver=4-thin--&gt;
&lt;!--@+node:ekr.20080301071818.1:@thin html/front.html--&gt;
&lt;!--@@first--&gt;

&lt;!--@@language html--&gt;
&lt;!--@@tabwidth -4--&gt;

&lt;!-- Last Modified: July 31, 2008 --&gt;
&lt;!-- Author: Edward K. Ream, edreamleo@gmail.com --&gt;

&lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"&gt;
&lt;head&gt;
&lt;!--@&lt;&lt;head&gt;&gt;--&gt;
&lt;!--@+node:ekr.20080301075734.1:&lt;&lt;head&gt;&gt;--&gt;
&lt;title&gt;Leo's Home Page&lt;/title&gt;

&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/&gt;

&lt;meta name="description" content="This page describes Leo, a programmer's outliner." /&gt;

&lt;meta name="keywords" content="LEO, LITERATE PROGRAMMING, OUTLINES, CWEB,
NOWEB, EDWARD K. REAM, DONALD E. KNUTH, SILVIO LEVY, OPEN SOFTWARE" /&gt;

&lt;!-- for GeoUrl --&gt;
&lt;meta name="ICBM" content="43.0713768, -89.4188004" /&gt;
&lt;meta name="DC.title" content="Leo's Home Page" /&gt;
&lt;!--@-node:ekr.20080301075734.1:&lt;&lt;head&gt;&gt;--&gt;
&lt;!--@nl--&gt;
&lt;/head&gt;

&lt;body bgcolor="#fffbdc"&gt;
&lt;!--@&lt;&lt; main table &gt;&gt;--&gt;
&lt;!--@+node:ekr.20080301075734.4:&lt;&lt; main table &gt;&gt;--&gt;

&lt;table border="0" bgcolor="#FFFBDC"&gt;
    &lt;tr&gt;
        &lt;td width="22%" height="21" align="center" bgcolor="#FFFBDC" valign="middle"&gt;
            &lt;b&gt;&lt;font size="4"&gt;Leo's Home&lt;/font&gt;&lt;/b&gt;
        &lt;/td&gt;

        &lt;td bgcolor="#F0E68C" width="78%" height="21" align="center"&gt;
            &lt;!--@            &lt;&lt; upper table &gt;&gt;--&gt;
            &lt;!--@+node:ekr.20080301080758:&lt;&lt; upper table&gt;&gt;--&gt;

            &lt;table border="0" width="100%"&gt;
                &lt;tr&gt;
                    &lt;td width="25%" align="center"&gt;
                        &lt;a href="http://www.python.org/"&gt;
                            &lt;img border="0" src="PythonPowered.gif" width="110" height="44" /&gt;&lt;/a&gt;
                    &lt;/td&gt;

                    &lt;td width="50%" align="center"&gt;
                        &lt;a href="http://groups.google.com/group/leo-editor"&gt;Leo at Google Groups&lt;/a&gt;

                    &lt;/td&gt;

                    &lt;td width="25%" align="center"&gt;
                        &lt;a href="http://www.mind-mapping.org/"&gt;mind-mapping.org&lt;/a&gt;
                    &lt;/td&gt;
                &lt;/tr&gt;
            &lt;/table&gt;
            &lt;!--@nonl--&gt;
            &lt;!--@-node:ekr.20080301080758:&lt;&lt; upper table&gt;&gt;--&gt;

            &lt;!--@nl--&gt;
        &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
        &lt;td bgcolor="#F0E68C" width="22%" height="143" valign="top"&gt;
            &lt;!--@            &lt;&lt; left table &gt;&gt;--&gt;
            &lt;!--@+node:ekr.20080301075734.6:&lt;&lt; left table &gt;&gt;--&gt;
            &lt;table border="0" width="100%"&gt;

                &lt;tr&gt;&lt;td width="50%" bgcolor="#DAA520"&gt;&lt;b&gt;Documentation&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;
                        &lt;!--
                        &lt;a href="http://sourceforge.net/project/screenshots.php?group_id=3458"&gt;Screen Shots&lt;/a&gt;
                        --&gt;
                        &lt;a href="http:screen-shots.html"&gt;Screen Shots&lt;/a&gt;
                &lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="intro.html"&gt;Beginners Guide&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="leo_toc.html"&gt;Users Guide&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;

                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="FAQ.html"&gt;FAQ&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;
                    &lt;a href="http://www.3dtree.com/ev/e/sbooks/leo/sbframetoc_ie.htm"&gt;Online tutorial&lt;/a&gt;
                &lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="testimonials.html"&gt;Quotes&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%" bgcolor="#DAA520"&gt;&lt;b&gt;Links&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;

                    &lt;!--@        &lt;&lt; download ref &gt;&gt;--&gt;
                    &lt;!--@+node:ekr.20080306071848:&lt;&lt; download ref &gt;&gt; (contains version number)--&gt;
                    &lt;a href="http://sourceforge.net/project/showfiles.php?group_id=3458&amp;amp;package_id=29106"&gt;
                        Download Leo[4.7 beta 1]&lt;/a&gt;
                    &lt;!--@nonl--&gt;
                    &lt;!--@-node:ekr.20080306071848:&lt;&lt; download ref &gt;&gt; (contains version number)--&gt;
                    &lt;!--@nl--&gt;
                &lt;/td&gt;&lt;/tr&gt;

                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="http://sourceforge.net/project/?group_id=3458"&gt; Leo at SourceForge&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="http://groups.google.com/group/leo-editor"&gt;Leo at Google Groups&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="http://launchpad.net/leo-editor"&gt;Leo at launchpad&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;!-- &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="http://leo.tigris.org/source/browse/leo/"&gt;Leo's cvs repository&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt; --&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;Leo's &lt;a href="http://leo.zwiki.org"&gt;Wiki&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;Leo's &lt;a href="http://www.greygreen.org/leo/"&gt;Daily snapshots&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;

                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="leoLinks.html"&gt;More links&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%" bgcolor="#DAA520"&gt;&lt;b&gt;Edward K. Ream&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="ekr.html"&gt;Home&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
                &lt;tr&gt;&lt;td width="50%"&gt;&lt;a href="mailto:edreamleo@gmail.com"&gt;Contact&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
            &lt;/table&gt;
            &lt;!--@-node:ekr.20080301075734.6:&lt;&lt; left table &gt;&gt;--&gt;
            &lt;!--@nl--&gt;

        &lt;/td&gt;

        &lt;td width="78%" height="143" bgcolor="#FFFBDC"&gt;
            &lt;!--@            &lt;&lt; center area &gt;&gt;--&gt;
            &lt;!--@+node:ekr.20080301082848:&lt;&lt; center area &gt;&gt;--&gt;
            &lt;h2&gt; Leo is...&lt;/h2&gt;

            &lt;ul&gt;
            &lt;!--@&lt;&lt; what is Leo list &gt;&gt;--&gt;

            &lt;!--@+node:ekr.20080301083325:&lt;&lt; what is Leo list &gt;&gt;--&gt;
            &lt;li&gt;
                A &lt;i&gt;versatile data management platform&lt;/i&gt;.&lt;br/&gt;
                Leo shows &lt;b&gt;user-created&lt;/b&gt; relationships among any kind of data:&lt;br /&gt;
                computer programs, web sites, etc.&lt;br /&gt;

                Leo shows multiple views of data within a single outline.&lt;/li&gt;
            &lt;li&gt;
                An &lt;i&gt;outlining editor for programmers&lt;/i&gt;.&lt;br /&gt;
                Leo supports &lt;i&gt;optional&lt;/i&gt; &lt;a HREF="http://www.eecs.harvard.edu/~nr/noweb/"&gt;noweb&lt;/a&gt;
                and &lt;a HREF="http://www-cs-faculty.stanford.edu/~knuth/cweb.html"&gt;CWEB&lt;/a&gt; markup.&lt;/li&gt;

            &lt;li&gt;A flexible &lt;i&gt;browser&lt;/i&gt; for projects, programs, classes or any other data.&lt;/li&gt;
            &lt;li&gt;A &lt;i&gt;project manager&lt;/i&gt;.&lt;/li&gt;
            &lt;li&gt;&lt;i&gt;Portable&lt;/i&gt;. Leo runs on Windows, Linux and MacOS X.&lt;/li&gt;
            &lt;li&gt;&lt;i&gt;100% pure&lt;/i&gt; &lt;a HREF="http://www.python.org/"&gt;&lt;i&gt;Python&lt;/i&gt;&lt;/a&gt;.&lt;/li&gt;

            &lt;li&gt;&lt;i&gt;Fully scriptable using &lt;/i&gt;&lt;a HREF="http://www.python.org/"&gt;&lt;i&gt;Python&lt;/i&gt;&lt;/a&gt;.&lt;/li&gt;
            &lt;li&gt;Leo's outline files are &lt;a HREF="http://www.w3.org/XML/"&gt;XML&lt;/a&gt; format.&lt;/li&gt;
            &lt;li&gt;
                &lt;a href="http://www.opensource.org/"&gt;&lt;i&gt;Open Software&lt;/i&gt;&lt;/a&gt;,
                distributed under the
                &lt;a href="http://www.opensource.org/licenses/mit-license.php/"&gt;

                MIT License
                &lt;/a&gt;.
            &lt;/li&gt;
            &lt;!--@nonl--&gt;
            &lt;!--@-node:ekr.20080301083325:&lt;&lt; what is Leo list &gt;&gt;--&gt;
            &lt;!--@nl--&gt;
            &lt;/ul&gt;

            &lt;p&gt;
            Please use &lt;a href="http://groups.google.com/group/leo-editor"&gt;leo-editor&lt;/a&gt;

            to ask questions and make suggestions.
            &lt;/p&gt;

            &lt;p&gt;
            Leo's author is &lt;a HREF="ekr.html"&gt;Edward K. Ream&lt;/a&gt;
            &lt;/p&gt;
            &lt;!--@nonl--&gt;
            &lt;!--@-node:ekr.20080301082848:&lt;&lt; center area &gt;&gt;--&gt;
            &lt;!--@nl--&gt;

        &lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;
&lt;!--@-node:ekr.20080301075734.4:&lt;&lt; main table &gt;&gt;--&gt;
&lt;!--@nl--&gt;
&lt;/body&gt;
&lt;/html&gt;

&lt;!--@-node:ekr.20080301071818.1:@thin html/front.html--&gt;
&lt;!--@-leo--&gt;
</t>
<t tx="ekr.20091116094116.2569"></t>
<t tx="ekr.20091116094116.2570">import leo.core.leoTest as leoTest
leoTest.runEditCommandTest(c,p)
</t>
<t tx="ekr.20091116094116.2571">first line
    line 1
        line a
            line b
    line c
last line</t>
<t tx="ekr.20091116094116.2572">first line
line 1
    line a
        line b
line c
last line</t>
<t tx="ekr.20091116094116.2573">first line
    line 1
        line a
            line b
    line c
last line</t>
<t tx="ekr.20091116094116.2574"># @button nodes create buttons in the icon bar.
# Pressing the button, applies the script to the selected node.

g.es('%s characters in headline' % (len(p.h)))</t>
<t tx="ekr.20091116094116.2575">You can do things with Leo that you can't even *imagine* doing in other programs.

Some of the world's great programmers use Leo.</t>
<t tx="ekr.20091116094116.2587">Peole get excited about Leo...</t>
<t tx="ekr.20091116094116.2588">"The most amazing software since the invention of the spreadsheet."

"A breakthrough tool and a whole new way of writing code."

"Utterly changed my view of programming (indeed of writing) forever."
</t>
<t tx="ekr.20091116094116.2589">"They'll have to pry Leo out of my cold, dead fingers!"

"I have been absolutely seduced by Leo over the past few days...I can not put it
down."

"There is almost an addictive withdrawal effect when I can complete an operation
in so much less time with Leo &amp; python than I had become used to."</t>
<t tx="ekr.20091116094116.2590">"Word outlines are very useful. But Leo makes Word look like a clunky toy."

"Leo is *exactly* the kind of outliner I was looking for."</t>
<t tx="ekr.20091116094116.2591">"Your current trajectory puts you on track to kick Emacs into the dustbin of
computing history."

Note: Many people use Leo *with* vim, emacs or ipython.

"People complain about the lack of a project manager for [Python]. Leo clearly
solves that problem and in a way that commercial tools can't touch."
</t>
<t tx="ekr.20091116094116.2592">"Leo is the best URL bookmark manager there is.

"I use Leo to organize my lists of pictures."
</t>
<t tx="ekr.20091116094116.2593">"I've already started converting the IT Procedures manual from Open Office to
Leo...the possibility of keeping system maintenance scripts in the IT manual is
mind boggling."

"Leo is the best outliner I have yet encountered for writing the early stages of
academic papers."
</t>
<t tx="ekr.20091116094116.2594">"Leo allows the designer to reveal and discipline structure at many
layers simultaneously: data structures, object structure, entity-relationship
structure, client-server structure, design pattern structure, temporal
structure, project management structure, and any other structure relevant to the
system."

"When I 'Leo-ise' other people's code, Leo makes the code's structure so
transparent that design faults become very quickly apparent."</t>
<t tx="ekr.20091116094116.2604">"A breakthrough tool and a whole new way of writing code."
    -- Joe Orr
</t>
<t tx="ekr.20091116094116.2605">"They'll have to pry Leo out of my cold, dead fingers!"
    -- Travers A. Hough</t>
<t tx="ekr.20091116094116.2606">"Leo makes Word [outlines] look like a clunky toy."
    -- Joe Orr</t>
<t tx="ekr.20091116094116.2607">"[Leo is] on track to kick Emacs into the dustbin of computing history."
    -- Dan Winkler</t>
<t tx="ekr.20091116094116.2608">"Leo is the best URL bookmark manager there is."
    -- Dan Winkler</t>
<t tx="ekr.20091116094116.2609">"Leo is the best outliner I have yet encountered for writing the
early stages of academic papers." -- Anon.
</t>
<t tx="ekr.20091116094116.2610">"Leo allows the designer to reveal..structure at many layers simultaneously..."
    -- Steven P. Schaefer

"When I 'Leo-ise' other people's code, Leo makes the code's structure so
transparent that design faults become very quickly apparent."
    -- David McNab</t>
<t tx="ekr.20091117082920.2628">@language rest
</t>
<t tx="ekr.20091117082920.8031">Thanks, David, for inviting me.

I'm excited to be here talking about the open-source project
that I've been leading for 15+ years.</t>
<t tx="ekr.20091117082920.8032">Programmers?

Use vim or emacs?

Any others?

TeX?  Knuth?  CWEB</t>
<t tx="ekr.20091117082920.12019">C:\leo.repo\trunk\leo\Icons\Lioness.jpg</t>
<t tx="ekr.20091117093857.2637">@language html

&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"&gt;
&lt;head&gt;&lt;/head&gt;

&lt;body bgcolor="#fffbdc"&gt;

    &lt;img src="C:\leo.repo\trunk\leo\Icons\Lioness.jpg"&gt;

&lt;!--
    &lt;img src="C:\leo.repo\trunk\leo\Icons\Lioness.jpg" width="864" height="560"&gt;
    &lt;img src="C:\leo.repo\trunk\leo\Icons\LIONA2.JPG" width="555" height="804"&gt;
    &lt;img src="C:\leo.repo\trunk\leo\Icons\VincennesZoo20020622_061.jpg" width="2048" height="1536"&gt;
--&gt;

&lt;/body&gt;
&lt;/html&gt;</t>
<t tx="ekr.20091117093857.2639"></t>
<t tx="ekr.20091117093857.2640">Leo creates a playground.</t>
<t tx="ekr.20091117093857.2641">"...keeping system maintenance scripts in the IT manual is mind boggling."
    -- David Nichols</t>
<t tx="ekr.20091117100212.2629">People get excited about Leo.

There is an Aha moment.</t>
<t tx="ekr.20091117100212.2630">Google edreamleo

Email:  edreamleo@gmail.com

Google Group: http://groups.google.com/group/leo-editor

</t>
<t tx="ekr.20091117100212.2632"></t>
<t tx="ekr.20091117100212.2633"></t>
<t tx="ekr.20091117100212.2635">C:\leo.repo\trunk\leo\Icons\Lioness.jpg</t>
<t tx="ekr.20091117100212.2636">assert 1 == 2
</t>
<t tx="ekr.20091121184836.2583">@language rest

- Programs (and data!) are outlines in disguise, but...

    viewing programs (or data) in an outline is not enough!
    
    - Programs must be *part of* outlines.

    - *Simple* markup connects outlines and programs.
        - @others allows you to see data at *any* level of detail.
        (Tail recursion isn't good enough: @others specifies indentation)
        - &lt;&lt; section &gt;&gt; encapsulates hard-to-encapsulate programs/data.
        
    - Outlines must be true objects.
        - Headlines are meta-data.

- There is no such thing a single "right" view of data.

    - Clones let you create as many views:
      you can put clones in as many views as you like.

</t>
<t tx="ekr.20091122085016.2585">Usually, outlines are just features of IDE's.

With Leo, outlines are an *integral* part of programming (and data).</t>
<t tx="ekr.20091122085016.2586">Leo is the combination of:

1. noweb markup.
2. @others, the *only* new essential markup in Leo.
3. MORE outlines with clones.
</t>
<t tx="ekr.20091122085016.2587">- Eliminate details without talking down to your audience.

- Spend *half* your time communicating your work.

- Tell stories.

* I've benefitted greatly from this talk.</t>
<t tx="ekr.20091122085016.2588">You and your research: Richard Hamming.

Ideas that stick.

The TeXBook.

MORE

Literate Programming.

Leo

Python</t>
<t tx="ekr.20091122085016.2592">I answer all my email: edreamleo@gmail.com

leo-editor:

Leo's users guide (being rewritten)</t>
<t tx="ekr.20091122085016.2593"></t>
<t tx="ekr.20091122085016.2594"># Passive integration
</t>
<t tx="ekr.20091122085016.2595"></t>
<t tx="ekr.20091122085016.2598">'''This is my class.'''</t>
<t tx="ekr.20091122085016.2599">def __init__ (self):
    pass</t>
<t tx="ekr.20091122085016.2600">def doSomething (self):
    
    pass</t>
<t tx="ekr.20091122085016.2601">Studied TeX.
Could not really understand it.
Wandering in the wilderness.
Aha 1: webs are outlines in disguise.
Aha 2: More as a prototype.
&lt;&lt; section &gt;&gt; came from cweb
I invented @others

Lucky: you won't invent sections or @others if you start with outlines.
You must start with markup first.
</t>
<t tx="ekr.20091124051255.2169"></t>
<t tx="ekr.20091124051255.2175">Before: so what?

After: wow!

I've gotten aha's from working on this talk.</t>
<t tx="ekr.20091124051255.2176"></t>
<t tx="ekr.20091124051255.2177">No other tool combines all 5 elements.

Most give only one.</t>
<t tx="ekr.20091124051255.2178">No one right view of data.

Headlines create natural meta-data.

Leo outlines combine hierarchical, relational and oo database features.

</t>
<t tx="ekr.20091124051255.2179"></t>
<t tx="ekr.20091124051255.2180"></t>
<t tx="ekr.20091124051255.2181"></t>
<t tx="ekr.20091124051255.2182"></t>
<t tx="ekr.20091124084348.7193">@language python
@tabwidth -4
@pagewidth 80

use_zodb = False

&lt;&lt; imports &gt;&gt;

@others</t>
<t tx="ekr.20091124084348.7194">if use_zodb:
    # It may be important to import ZODB first.
    try:
        import ZODB
        import ZODB.FileStorage
    except ImportError:
        ZODB = None
else:
    ZODB = None

import leo.core.leoGlobals as g

if g.app and g.app.use_psyco:
    # g.pr("enabled psyco classes",__file__)
    try: from psyco.classes import *
    except ImportError: pass

import time
import re
import itertools</t>
<t tx="ekr.20091124084348.7195">if use_zodb and ZODB:
    class baseVnode (ZODB.Persistence.Persistent):
        pass
else:
    class baseVnode (object):
        pass

class vnode (baseVnode):
    &lt;&lt; vnode constants &gt;&gt;
    @others</t>
<t tx="ekr.20091124084348.7196"># Define the meaning of status bits in new vnodes.

# Archived...
clonedBit   = 0x01 # True: vnode has clone mark.
# unused      0x02
expandedBit = 0x04 # True: vnode is expanded.
markedBit   = 0x08 # True: vnode is marked
orphanBit   = 0x10 # True: vnode saved in .leo file, not derived file.
selectedBit = 0x20 # True: vnode is current vnode.
topBit      = 0x40 # True: vnode was top vnode when saved.

# Not archived...
richTextBit = 0x080 # Determines whether we use &lt;bt&gt; or &lt;btr&gt; tags.
visitedBit  = 0x100
dirtyBit    = 0x200
writeBit    = 0x400
</t>
<t tx="ekr.20091124084348.7197"></t>
<t tx="ekr.20091124084348.7198"># To support ZODB, the code must set v._p_changed = 1 whenever
# v.unknownAttributes or any mutable vnode object changes.

def __init__ (self,context):

    # The primary data: headline and body text.
    if g.isPython3:
        self._headString = 'newHeadline'
        self._bodyString = ''
    else:
        self._headString = unicode('newHeadline')
        self._bodyString = unicode('')

    # Structure data...
    self.children = [] # Ordered list of all children of this node.
    self.parents = [] # Unordered list of all parents of this node.

    # Other essential data...
    self.fileIndex = g.app.nodeIndices.getNewIndex()
        # The immutable file index for this vnode.
        # New in Leo 4.6 b2: allocate gnx (fileIndex) immediately.
    self.iconVal = 0 # The present value of the node's icon.
    self.statusBits = 0 # status bits

    # v.t no longer exists.  All code must now be aware of the one-node world.
    # self.t = self # For compatibility with scripts and plugins.

    # Information that is never written to any file...
    self.context = context # The context containing context.hiddenRootNode.
        # Required so we can compute top-level siblings.
        # It is named .context rather than .c to emphasize its limited usage.
    self.insertSpot = None # Location of previous insert point.
    self.scrollBarSpot = None # Previous value of scrollbar position.
    self.selectionLength = 0 # The length of the selected body text.
    self.selectionStart = 0 # The start of the selected body text.
</t>
<t tx="ekr.20091124084348.7199">def __repr__ (self):

    return "&lt;vnode %d:'%s'&gt;" % (id(self),self.cleanHeadString())

__str__ = __repr__
</t>
<t tx="ekr.20091124084348.7200">def dumpLink (self,link):
    return g.choose(link,link,"&lt;none&gt;")

def dump (self,label=""):

    v = self
    print('%s %s %s' % ('-'*10,label,v))
    print('len(parents) %s' % len(v.parents))
    print('len(children) %s' % len(v.children))
    print('parents %s' % g.listToString(v.parents))
    print('children%s' % g.listToString(v.children))
</t>
<t tx="ekr.20091124084348.7201">if use_zodb and ZODB:
    def __hash__(self):
        return self.__hash__()</t>
<t tx="ekr.20091124084348.7202"></t>
<t tx="ekr.20091124084348.7203">def findAtFileName (self,names,h=''):

    """Return the name following one of the names in nameList.
    Return an empty string."""

    # Allow h argument for unit testing.
    if not h: h = self.headString()

    if not g.match(h,0,'@'):
        return ""

    i = g.skip_id(h,1,'-')
    word = h[:i]
    if word in names and g.match_word(h,0,word):
        name = h[i:].strip()
        # g.trace(repr(word),repr(name))
        return name
    else:
        return ""
</t>
<t tx="ekr.20091124084348.7204">def anyAtFileNodeName (self):

    """Return the file name following an @file node or an empty string."""

    names = (
        "@auto",
        "@auto-rst",
        "@edit",
        "@file",
        "@thin",   "@file-thin",   "@thinfile",
        "@asis",   "@file-asis",   "@silentfile",
        "@noref",  "@file-noref",  "@rawfile",
        "@nosent", "@file-nosent", "@nosentinelsfile",
        "@shadow",)

    return self.findAtFileName(names)
</t>
<t tx="ekr.20091124084348.7205"># These return the filename following @xxx, in v.headString.
# Return the the empty string if v is not an @xxx node.

def atAutoNodeName (self,h=None):
    # # Prevent conflicts with autotrees plugin: don't allow @auto-whatever to match.
    # return g.match_word(h,0,tag) and not g.match(h,0,tag+'-') and h[len(tag):].strip()
    names = ("@auto","@auto-rst",)
    return self.findAtFileName(names,h=h)

def atAutoRstNodeName (self,h=None):
    names = ("@auto-rst",)
    return self.findAtFileName(names,h=h)

def atEditNodeName (self):
    names = ("@edit",)
    return self.findAtFileName(names)

def atFileNodeName (self):
    names = ("@file",)
    return self.findAtFileName(names)

def atNoSentinelsFileNodeName (self):
    names = ("@nosent", "@file-nosent", "@nosentinelsfile")
    return self.findAtFileName(names)

def atRawFileNodeName (self):
    names = ("@noref", "@file-noref", "@rawfile")
    return self.findAtFileName(names)

def atShadowFileNodeName (self):
    names = ("@shadow",)
    return self.findAtFileName(names)

def atSilentFileNodeName (self):
    names = ("@asis", "@file-asis", "@silentfile")
    return self.findAtFileName(names)

def atThinFileNodeName (self):
    names = ("@thin", "@file-thin", "@thinfile")
    return self.findAtFileName(names)

# New names, less confusing
atNoSentFileNodeName  = atNoSentinelsFileNodeName
atNorefFileNodeName   = atRawFileNodeName
atAsisFileNodeName    = atSilentFileNodeName
</t>
<t tx="ekr.20091124084348.7206">if g.unitTesting:

    c,p = g.getTestVars()

    table = (
        ('@auto-rst rst-file','rst-file','rst-file'),
        ('@auto x','x',''),
        ('xyz','',''),
    )

    for s,expected1,expected2 in table:
        result1 = p.v.atAutoNodeName(h=s)
        result2 = p.v.atAutoRstNodeName(h=s)
        assert result1 == expected1,'fail1: given %s expected %s got %s' % (
            repr(s),repr(expected1),repr(result1))
        assert result2 == expected2,'fail2: given %s expected %s got %s' % (
            repr(s),repr(expected2),repr(result2))
</t>
<t tx="ekr.20091124084348.7207">def isAtAllNode (self):

    """Returns True if the receiver contains @others in its body at the start of a line."""

    flag, i = g.is_special(self._bodyString,0,"@all")
    return flag
</t>
<t tx="ekr.20091124084348.7208">def isAnyAtFileNode (self):

    """Return True if v is any kind of @file or related node."""

    # This routine should be as fast as possible.
    # It is called once for every vnode when writing a file.

    h = self.headString()
    return h and h[0] == '@' and self.anyAtFileNodeName()
</t>
<t tx="ekr.20091124084348.7209">def isAtAutoNode (self):
    return g.choose(self.atAutoNodeName(),True,False)

def isAtAutoRstNode (self):
    return g.choose(self.atAutoRstNodeName(),True,False)

def isAtEditNode (self):
    return g.choose(self.atEditNodeName(),True,False)

def isAtFileNode (self):
    return g.choose(self.atFileNodeName(),True,False)

def isAtNoSentinelsFileNode (self):
    return g.choose(self.atNoSentinelsFileNodeName(),True,False)

def isAtRawFileNode (self): # @file-noref
    return g.choose(self.atRawFileNodeName(),True,False)

def isAtSilentFileNode (self): # @file-asis
    return g.choose(self.atSilentFileNodeName(),True,False)

def isAtShadowFileNode (self):
    return g.choose(self.atShadowFileNodeName(),True,False)

def isAtThinFileNode (self):
    return g.choose(self.atThinFileNodeName(),True,False)

# New names, less confusing:
isAtNoSentFileNode = isAtNoSentinelsFileNode
isAtNorefFileNode  = isAtRawFileNode
isAtAsisFileNode   = isAtSilentFileNode
</t>
<t tx="ekr.20091124084348.7210">def isAtIgnoreNode (self):

    """Returns True if the receiver contains @ignore in its body at the start of a line."""

    flag, i = g.is_special(self._bodyString, 0, "@ignore")
    return flag
</t>
<t tx="ekr.20091124084348.7211">def isAtOthersNode (self):

    """Returns True if the receiver contains @others in its body at the start of a line."""

    flag, i = g.is_special(self._bodyString,0,"@others")
    return flag
</t>
<t tx="ekr.20091124084348.7212">def matchHeadline (self,pattern):

    """Returns True if the headline matches the pattern ignoring whitespace and case.

    The headline may contain characters following the successfully matched pattern."""

    v = self

    h = g.toUnicode(v.headString(),'utf-8')
    h = h.lower().replace(' ','').replace('\t','')

    pattern = g.toUnicode(pattern,'utf-8')
    pattern = pattern.lower().replace(' ','').replace('\t','')

    return h.startswith(pattern)
</t>
<t tx="ekr.20091124084348.7213"></t>
<t tx="ekr.20091124084348.7214">def bodyString (self):

    # This message should never be printed and we want to avoid crashing here!
    if not g.isUnicode(self._bodyString):
        s = "v.bodyString: Leo internal error: not unicode:" + repr(self._bodyString)
        g.es_print('',s,color="red")

    # Make _sure_ we return a unicode string.
    return g.toUnicode(self._bodyString,g.app.tkEncoding)

getBody = bodyString</t>
<t tx="ekr.20091124084348.7215"></t>
<t tx="ekr.20091124084348.7216">def firstChild (self):

    v = self
    return v.children and v.children[0]
</t>
<t tx="ekr.20091124084348.7217">def hasChildren (self):

    v = self
    return len(v.children) &gt; 0

hasFirstChild = hasChildren
</t>
<t tx="ekr.20091124084348.7218">def lastChild (self):

    v = self
    return v.children and v.children[-1] or None
</t>
<t tx="ekr.20091124084348.7219"># childIndex and nthChild are zero-based.

def nthChild (self, n):

    v = self

    if 0 &lt;= n &lt; len(v.children):
        return v.children[n]
    else:
        return None
</t>
<t tx="ekr.20091124084348.7220">def numberOfChildren (self):

    v = self
    return len(v.children)
</t>
<t tx="ekr.20091124084348.7221">def directParents (self):

    """(New in 4.2) Return a list of all direct parent vnodes of a vnode.

    This is NOT the same as the list of ancestors of the vnode."""

    v = self
    return v.parents
</t>
<t tx="ekr.20091124084348.7222">def hasBody (self):

    '''Return True if this vnode contains body text.'''

    s = self._bodyString

    return s and len(s) &gt; 0
</t>
<t tx="ekr.20091124084348.7223">def headString (self):

    """Return the headline string."""

    # This message should never be printed and we want to avoid crashing here!
    if not g.isUnicode(self._headString):
        s = "Leo internal error: not unicode:" + repr(self._headString)
        g.es_print('',s,color="red")

    # Make _sure_ we return a unicode string.
    return g.toUnicode(self._headString,g.app.tkEncoding)

def cleanHeadString (self):

    s = self._headString
    return g.toEncodedString(s,"ascii") # Replaces non-ascii characters by '?'
</t>
<t tx="ekr.20091124084348.7224"></t>
<t tx="ekr.20091124084348.7225">def isCloned (self):

    return len(self.parents) &gt; 1
</t>
<t tx="ekr.20091124084348.7226">def isDirty (self):

    return (self.statusBits &amp; self.dirtyBit) != 0
</t>
<t tx="ekr.20091124084348.7227">def isExpanded (self):

    # g.trace( ( self.statusBits &amp; self.expandedBit ) != 0, g.callers())

    return ( self.statusBits &amp; self.expandedBit ) != 0
</t>
<t tx="ekr.20091124084348.7228">def isMarked (self):

    return ( self.statusBits &amp; vnode.markedBit ) != 0
</t>
<t tx="ekr.20091124084348.7229">def isOrphan (self):

    return ( self.statusBits &amp; vnode.orphanBit ) != 0
</t>
<t tx="ekr.20091124084348.7230">def isSelected (self):

    return ( self.statusBits &amp; vnode.selectedBit ) != 0
</t>
<t tx="ekr.20091124084348.7231">def isTopBitSet (self):

    return ( self.statusBits &amp; self.topBit ) != 0
</t>
<t tx="ekr.20091124084348.7232">def isVisited (self):

    return ( self.statusBits &amp; vnode.visitedBit ) != 0
</t>
<t tx="ekr.20091124084348.7233">def isWriteBit (self):

    v = self
    return (v.statusBits &amp; v.writeBit) != 0
</t>
<t tx="ekr.20091124084348.7234">def status (self):

    return self.statusBits
</t>
<t tx="ekr.20091124084348.7235"></t>
<t tx="ekr.20091124084348.7236"></t>
<t tx="ekr.20091124084348.7237">def clearDirty (self):
    v = self
    v.statusBits &amp;= ~ v.dirtyBit

</t>
<t tx="ekr.20091124084348.7238">def findAllPotentiallyDirtyNodes(self):

    trace = False and not g.unitTesting
    v = self ; c = v.context

    # Set the starting nodes.
    nodes = []
    newNodes = [v]

    # Add nodes until no more are added.
    while newNodes:
        addedNodes = []
        nodes.extend(newNodes)
        for v in newNodes:
            for v2 in v.parents:
                if v2 not in nodes and v2 not in addedNodes:
                    addedNodes.append(v2)
        newNodes = addedNodes[:]

    # Remove the hidden vnode.
    if c.hiddenRootNode in nodes:
        if trace: g.trace('removing hidden root',c.hiddenRootNode)
        nodes.remove(c.hiddenRootNode)

    if trace: g.trace(nodes)
    return nodes</t>
<t tx="ekr.20091124084348.7239"># Unlike p.setAllAncestorAtFileNodesDirty,
# there is no setDescendentsDirty arg.

def setAllAncestorAtFileNodesDirty (self):

    trace = False and not g.unitTesting
    verbose = False
    v = self
    dirtyVnodeList = []

    # Calculate all nodes that are joined to p or parents of such nodes.
    nodes = v.findAllPotentiallyDirtyNodes()

    if trace and verbose:
        for v in nodes:
            print v.isDirty(),v.isAnyAtFileNode(),v

    dirtyVnodeList = [v for v in nodes
        if not v.isDirty() and v.isAnyAtFileNode()]

    changed = len(dirtyVnodeList) &gt; 0

    for v in dirtyVnodeList:
        v.setDirty() # Do not call v.setDirty here!

    if trace: g.trace("vnode",dirtyVnodeList)

    return dirtyVnodeList
</t>
<t tx="ekr.20091124084348.7240">def setDirty (self):

    self.statusBits |= self.dirtyBit
</t>
<t tx="ekr.20091124084348.7241"></t>
<t tx="ekr.20091124084348.7242">def clearClonedBit (self):

    self.statusBits &amp;= ~ self.clonedBit
</t>
<t tx="ekr.20091124084348.7243">def clearMarked (self):

    self.statusBits &amp;= ~ self.markedBit
</t>
<t tx="ekr.20091124084348.7244">def clearWriteBit (self):
    self.statusBits &amp;= ~ self.writeBit
</t>
<t tx="ekr.20091124084348.7245">def clearOrphan (self):

    self.statusBits &amp;= ~ self.orphanBit
</t>
<t tx="ekr.20091124084348.7246">def clearVisited (self):

    self.statusBits &amp;= ~ self.visitedBit
</t>
<t tx="ekr.20091124084348.7247">def contract(self):

    # if self.context.p.v == self: g.trace(self,g.callers(4))

    self.statusBits &amp;= ~ self.expandedBit

def expand(self):

    # g.trace(self,g.callers(4))

    self.statusBits |= self.expandedBit

def initExpandedBit (self):

    # g.trace(self._headString)

    self.statusBits |= self.expandedBit
</t>
<t tx="ekr.20091124084348.7248">def initStatus (self, status):

    self.statusBits = status
</t>
<t tx="ekr.20091124084348.7249">def setClonedBit (self):

    self.statusBits |= self.clonedBit

def initClonedBit (self, val):

    if val:
        self.statusBits |= self.clonedBit
    else:
        self.statusBits &amp;= ~ self.clonedBit
</t>
<t tx="ekr.20091124084348.7250">def setMarked (self):

    self.statusBits |= self.markedBit

def initMarkedBit (self):

    self.statusBits |= self.markedBit
</t>
<t tx="ekr.20091124084348.7251">def setOrphan (self):

    self.statusBits |= self.orphanBit
</t>
<t tx="ekr.20091124084348.7252"># This only sets the selected bit.

def setSelected (self):

    self.statusBits |= self.selectedBit
</t>
<t tx="ekr.20091124084348.7253"># Compatibility routine for scripts

def setVisited (self):

    self.statusBits |= self.visitedBit
</t>
<t tx="ekr.20091124084348.7254">def setWriteBit (self):
    self.statusBits |= self.writeBit
</t>
<t tx="ekr.20091124084348.7255">def setBodyString (self,s,encoding="utf-8"):

    trace = False and not g.unitTesting
    v = self
    if trace and v._bodyString != s:
        g.trace('v %s %s -&gt; %s %s\nold: %s\nnew: %s' % (
            v.h, len(v._bodyString),len(s),g.callers(5),
            v._bodyString,s))
    v._bodyString = g.toUnicode(s,encoding,reportErrors=True)

def setHeadString (self,s,encoding="utf-8"):
    v = self
    v._headString = g.toUnicode(s,encoding,reportErrors=True)

initBodyString = setBodyString
initHeadString = setHeadString
setHeadText = setHeadString
setTnodeText = setBodyString
</t>
<t tx="ekr.20091124084348.7256">def setFileIndex (self, index):

    self.fileIndex = index
</t>
<t tx="ekr.20091124084348.7257">def computeIcon (self):

    val = 0 ; v = self
    if v.hasBody(): val += 1
    if v.isMarked(): val += 2
    if v.isCloned(): val += 4
    if v.isDirty(): val += 8
    return val

def setIcon (self):

    pass # Compatibility routine for old scripts
</t>
<t tx="ekr.20091124084348.7258">def setSelection (self, start, length):

    v = self
    v.selectionStart = start
    v.selectionLength = length
</t>
<t tx="ekr.20091124084348.7259"></t>
<t tx="ekr.20091124084348.7260">def _addLink (self,childIndex,parent_v,adjust=True):
    '''Adjust links after adding a link to v.'''

    trace = False and not g.unitTesting
    v = self

    # Update parent_v.children &amp; v.parents.
    parent_v.children.insert(childIndex,v)
    v.parents.append(parent_v)
    if trace: g.trace('*** added parent',parent_v,'to',v,
        'len(parents)',len(v.parents))

    # Set zodb changed flags.
    v._p_changed = 1
    parent_v._p_changed = 1

    # If v has only one parent, we adjust all
    # the parents links in the descendant tree.
    # This handles clones properly when undoing a delete.
    if adjust:
        if len(v.parents) == 1:
            for child in v.children:
                child._addParentLinks(parent=v)
</t>
<t tx="ekr.20091124084348.7261">def _addParentLinks(self,parent): 

    trace = False and not g.unitTesting
    v = self

    v.parents.append(parent)
    if trace: g.trace(
        '*** added parent',parent,'to',v,'len(parents)',len(v.parents))

    if len(v.parents) == 1:
        for child in v.children:
            child._addParentLinks(parent=v)</t>
<t tx="ekr.20091124084348.7262">def _cutLink (self,childIndex,parent_v):
    '''Adjust links after cutting a link to v.'''
    v = self

    assert parent_v.children[childIndex]==v
    del parent_v.children[childIndex]
    v.parents.remove(parent_v)
    v._p_changed = 1
    parent_v._p_changed = 1

    # If v has no more parents, we adjust all
    # the parent links in the descendant tree.
    # This handles clones properly when deleting a tree.
    if len(v.parents) == 0:
        for child in v.children:
            child._cutParentLinks(parent=v)</t>
<t tx="ekr.20091124084348.7263">def _cutParentLinks(self,parent):

    trace = False and not g.unitTesting
    v = self

    if trace: g.trace('parent',parent,'v',v)
    v.parents.remove(parent)

    if len(v.parents) == 0:
        for child in v.children:
            child._cutParentLinks(parent=v)
</t>
<t tx="ekr.20091124084348.7264">def _linkAsNthChild (self,parent_v,n):

    """Links self as the n'th child of vnode pv"""

    v = self # The child node.
    v._addLink(n,parent_v)
</t>
<t tx="ekr.20091124084348.7265">def createOutlineFromCacheList(self,c,aList):
    """ Create outline structure from recursive aList
    built by p.makeCacheList.

    Clones will be automatically created by gnx,
    but *not* for the top-level node.
    """

    parent_v = self

    #import pprint ; pprint.pprint(tree)
    parent_v = self
    h,b,gnx,children = aList
    if h is not None:
        v = parent_v
        v._headString = h    
        v._bodyString = b

    for z in children:
        h,b,gnx,grandChildren = z
        isClone,child_v = parent_v.fastAddLastChild(c,gnx)
        if isClone:
            if child_v.b != b: # or child_v.h
                # Bug fix: the last seen clone rules.
                child_v.h = h
                child_v.b = b
                # Bug fix: mark @&lt;file&gt; nodes dirty.
                child_v.setAllAncestorAtFileNodesDirty()
                child_v.setMarked()
                g.es("changed:",child_v.h,color="blue")
        else:
            child_v.createOutlineFromCacheList(c,z)
</t>
<t tx="ekr.20091124084348.7266"># Similar to createThinChild4
def fastAddLastChild(self,c,gnxString):
    '''Create new vnode as last child of the receiver.

    If the gnx exists already, create a clone instead of new vnode.
    '''

    trace = False and not g.unitTesting
    parent_v = self
    indices = g.app.nodeIndices
    gnxDict = c.fileCommands.gnxDict

    if gnxString is None: v = None
    else:                 v = gnxDict.get(gnxString)
    is_clone = v is not None

    if trace: g.trace(
        'clone','%-5s' % (is_clone),
        'parent_v',parent_v,'gnx',gnxString,'v',repr(v))

    if not is_clone:
        v = vnode(context=c)
        if gnxString:
            gnx = indices.scanGnx(gnxString,0)
            v.fileIndex = gnx
        gnxDict[gnxString] = v

    child_v = v
    child_v._linkAsNthChild(parent_v,parent_v.numberOfChildren())
    child_v.setVisited() # Supress warning/deletion of unvisited nodes.

    return is_clone,child_v
</t>
<t tx="ekr.20091124084348.7267"></t>
<t tx="ekr.20091124084348.7268">def __get_b(self):

    v = self
    return v.bodyString()

def __set_b(self,val):

    v = self
    v.setBodyString(val)

b = property(
    __get_b, __set_b,
    doc = "vnode body string property")
</t>
<t tx="ekr.20091124084348.7269">def __get_h(self):

    v = self
    return v.headString()

def __set_h(self,val):

    v = self
    v.setHeadString(val)

h = property(
    __get_h, __set_h,
    doc = "vnode headline string property")  
</t>
<t tx="ekr.20091124084348.7270">def __get_u(self):
    v = self
    if not hasattr(v,'unknownAttributes'):
        v.unknownAttributes = {}
    return v.unknownAttributes

def __set_u(self,val):
    v = self
    if val is None:
        if hasattr(v,'unknownAttributes'):
            delattr(v,'unknownAttributes')
    elif type(val) == type({}):
        v.unknownAttributes = val
    else:
        raise ValueError

u = property(
    __get_u, __set_u,
    doc = "vnode unknownAttribute property")
</t>
<t tx="ekr.20091124084348.7271">def __get_gnx(self):
    v = self
    return g.app.nodeIndices.toString(v.fileIndex)

gnx = property(
    __get_gnx, # __set_gnx,
    doc = "vnode gnx property")
</t>
<t tx="ekr.20091124084348.7272"># Indices are Python dicts containing 'id','loc','time' and 'n' keys.

class nodeIndices (object):

    """A class to implement global node indices (gnx's)."""

    @others
</t>
<t tx="ekr.20091124084348.7273">def __init__ (self,id):

    """ctor for nodeIndices class"""

    self.userId = id
    self.defaultId = id

    # A Major simplification: Only assign the timestamp once.
    self.setTimeStamp()
    self.lastIndex = 0
</t>
<t tx="ekr.20091124084348.7274">def areEqual (self,gnx1,gnx2):

    """Return True if all fields of gnx1 and gnx2 are equal"""

    # works whatever the format of gnx1 and gnx2.
    # This should never throw an exception.
    return gnx1 == gnx2
</t>
<t tx="ekr.20091124084348.7275"># These are used by the fileCommands read/write code.

def getDefaultId (self):

    """Return the id to be used by default in all gnx's"""
    return self.defaultId

def setDefaultId (self,theId):

    """Set the id to be used by default in all gnx's"""
    self.defaultId = theId
</t>
<t tx="ekr.20091124084348.7276">def getNewIndex (self):

    '''Create a new gnx.'''

    self.lastIndex += 1
    d = (self.userId,self.timeString,self.lastIndex)
    # g.trace(d)
    return d
</t>
<t tx="ekr.20091124084348.7277">def isGnx (self,gnx):
    try:
        theId,t,n = gnx
        return t != None
    except Exception:
        return False
</t>
<t tx="ekr.20091124084348.7278">def scanGnx (self,s,i):

    """Create a gnx from its string representation"""

    if not g.isString(s):
        g.es("scanGnx: unexpected index type:",type(s),'',s,color="red")
        return None,None,None

    s = s.strip()

    theId,t,n = None,None,None
    i,theId = g.skip_to_char(s,i,'.')
    if g.match(s,i,'.'):
        i,t = g.skip_to_char(s,i+1,'.')
        if g.match(s,i,'.'):
            i,n = g.skip_to_char(s,i+1,'.')
    # Use self.defaultId for missing id entries.
    if theId == None or len(theId) == 0:
        theId = self.defaultId
    # Convert n to int.
    if n:
        try: n = int(n)
        except Exception: pass

    return theId,t,n
</t>
<t tx="ekr.20091124084348.7279">def setTimestamp (self):

    """Set the timestamp string to be used by getNewIndex until further notice"""

    self.timeString = time.strftime(
        "%Y%m%d%H%M%S", # Help comparisons; avoid y2k problems.
        time.localtime())

    # g.trace(self.timeString,self.lastIndex,g.callers(4))

setTimeStamp = setTimestamp
</t>
<t tx="ekr.20091124084348.7280">def toString (self,index):

    """Convert a gnx (a tuple) to its string representation"""

    try:
        theId,t,n = index
        if n in (None,0,'',):
            return "%s.%s" % (theId,t)
        else:
            return "%s.%s.%d" % (theId,t,n)
    except Exception:
        if not g.app.unitTesting:
            g.trace('unusual gnx',repr(index),g.callers()) 
        try:
            theId,t,n = self.getNewIndex()
            if n in (None,0,'',):
                return "%s.%s" % (theId,t)
            else:
                return "%s.%s.%d" % (theId,t,n)
        except Exception:
            g.trace('double exception: returning original index')
            return repr(index)</t>
<t tx="ekr.20091124084348.7281">&lt;&lt; about the position class &gt;&gt;

# Positions should *never* be saved by the ZOBD.
class position (object):
    @others
</t>
<t tx="ekr.20091124084348.7282">@killcolor
@

A position marks the spot in a tree traversal. A position p consists of a vnode
p.v, a child index p._childIndex, and a stack of tuples (v,childIndex), one for
each ancestor **at the spot in tree traversal. Positions p has a unique set of
parents.

The p.moveToX methods may return a null (invalid) position p with p.v = None.

The tests "if p" or "if not p" are the _only_ correct way to test whether a
position p is valid. In particular, tests like "if p is None" or "if p is not
None" will not work properly.
</t>
<t tx="ekr.20091124084348.7283"></t>
<t tx="ekr.20091124084348.7284">def __init__ (self,v,childIndex=0,stack=None,trace=False):

    '''Create a new position with the given childIndex and parent stack.'''

    # To support ZODB the code must set v._p_changed = 1
    # whenever any mutable vnode object changes.

    self._childIndex = childIndex
    self.v = v

    # New in Leo 4.5: stack entries are tuples (v,childIndex).
    if stack:
        self.stack = stack[:] # Creating a copy here is safest and best.
    else:
        self.stack = []

    g.app.positions += 1

    # if g.app.tracePositions and trace: g.trace(g.callers())

    self.txtOffset = None # see self.textOffset()
</t>
<t tx="ekr.20091124084348.7285">def __eq__(self,p2):

    """Return True if two postions are equivalent."""

    p1 = self

    # Don't use g.trace: it might call p.__eq__ or p.__ne__.
    # print ('p.__eq__: %s %s' % (
        # p1 and p1.v and p1.h,p2 and p2.v and p2.h))

    if p2 is None or p2.v is None:
        return p1.v is None
    else:
        return ( p1.v == p2.v and
            p1._childIndex == p2._childIndex and
            p1.stack == p2.stack )

def __ne__(self,p2):

    """Return True if two postions are not equivalent."""

    return not self.__eq__(p2) # For possible use in Python 2.x.
</t>
<t tx="ekr.20091124084348.7286"># No longer used.  All code must now be aware of the one-node world.

# def __getattr__ (self,attr):

    # """Convert references to p.t into references to p.v."""

    # if attr=="t":
        # return self.v
    # else:
        # # New in 4.3: _silently_ raise the attribute error.
        # # This allows plugin code to use hasattr(p,attr) !
        # if 0:
            # print("unknown position attribute: %s" % attr)
            # import traceback ; traceback.print_stack()
        # raise AttributeError(attr)</t>
<t tx="ekr.20091124084348.7287">@
Tests such as 'if p' or 'if not p' are the _only_ correct ways to test whether a position p is valid.
In particular, tests like 'if p is None' or 'if p is not None' will not work properly.
@c

if g.isPython3:

    def __bool__ ( self):

        """Return True if a position is valid."""

        # Tracing this appears to cause unbounded prints.
        # print("__bool__",self.v and self.v.cleanHeadString())

        return self.v is not None

else:

    def __nonzero__ ( self):

        """Return True if a position is valid."""

        # if g.app.trace: "__nonzero__",self.v

        # g.trace(repr(self))

        return self.v is not None
</t>
<t tx="ekr.20091124084348.7288">def __str__ (self):

    p = self

    if p.v:
        return "&lt;pos %d childIndex: %d lvl: %d [%d] %s&gt;" % (
            id(p),p._childIndex,p.level(),len(p.stack),p.cleanHeadString())
    else:
        return "&lt;pos %d [%d] None&gt;" % (id(p),len(p.stack))

__repr__ = __str__
</t>
<t tx="ekr.20091124084348.7289">def archivedPosition (self,root_p=None):

    '''Return a representation of a position suitable for use in .leo files.'''

    p = self

    if root_p is None:
        aList = [z._childIndex for z in p.self_and_parents()]
    else:
        aList = []
        for z in p.self_and_parents():
            if z == root_p:
                aList.append(0)
                break
            else:
                aList.append(z._childIndex)
        # g.trace(aList)

    aList.reverse()
    return aList</t>
<t tx="ekr.20091124084348.7290"># Using this routine can generate huge numbers of temporary positions during a tree traversal.

def copy (self):

    """"Return an independent copy of a position."""

    # if g.app.tracePositions: g.trace(g.callers())

    return position(self.v,self._childIndex,self.stack,trace=False)
</t>
<t tx="ekr.20091124084348.7291">def dumpLink (self,link):

    return g.choose(link,link,"&lt;none&gt;")

def dump (self,label=""):

    p = self
    if p.v:
        p.v.dump() # Don't print a label
</t>
<t tx="ekr.20091124084348.7292">def key (self):

    p = self

    # For unified nodes we must include a complete key,
    # so we can distinguish between clones.
    result = []
    for z in p.stack:
        v,childIndex = z
        result.append('%s:%s' % (id(v),childIndex))

    result.append('%s:%s' % (id(p.v),p._childIndex))

    return '.'.join(result)
</t>
<t tx="ekr.20091124084348.7293"></t>
<t tx="ekr.20091124084348.7294">def __get_b(self):

    p = self
    return p.bodyString()

def __set_b(self,val):

    p = self ; c = p.v and p.v.context
    if c:
        c.setBodyString(p, val)
        # Don't redraw the screen: p.b must be fast.
        # c.redraw_after_icons_changed()

b = property(
    __get_b, __set_b,
    doc = "position body string property")
</t>
<t tx="ekr.20091124084348.7295">def __get_h(self):

    p = self
    return p.headString()

def __set_h(self,val):

    p = self ; c = p.v and p.v.context
    if c:
        c.setHeadString(p,val)
        # Don't redraw the screen: p.h must be fast.
        # c.redraw_after_head_changed()

h = property(
    __get_h, __set_h,
    doc = "position headline string property")  
</t>
<t tx="ekr.20091124084348.7296">def __get_gnx(self):
    p = self
    return g.app.nodeIndices.toString(p.v.fileIndex)

gnx = property(
    __get_gnx, # __set_gnx,
    doc = "position gnx property")
</t>
<t tx="ekr.20091124084348.7297"></t>
<t tx="ekr.20091124084348.7298"></t>
<t tx="ekr.20091124084348.7299">def anyAtFileNodeName         (self): return self.v.anyAtFileNodeName()
def atAutoNodeName            (self): return self.v.atAutoNodeName()
def atEditNodeName            (self): return self.v.atEditNodeName()
def atFileNodeName            (self): return self.v.atFileNodeName()
def atNoSentinelsFileNodeName (self): return self.v.atNoSentinelsFileNodeName()
def atRawFileNodeName         (self): return self.v.atRawFileNodeName()
def atShadowFileNodeName      (self): return self.v.atShadowFileNodeName()
def atSilentFileNodeName      (self): return self.v.atSilentFileNodeName()
def atThinFileNodeName        (self): return self.v.atThinFileNodeName()

# New names, less confusing
atNoSentFileNodeName  = atNoSentinelsFileNodeName
atNorefFileNodeName   = atRawFileNodeName
atAsisFileNodeName    = atSilentFileNodeName

def isAnyAtFileNode         (self): return self.v.isAnyAtFileNode()
def isAtAllNode             (self): return self.v.isAtAllNode()
def isAtAutoNode            (self): return self.v.isAtAutoNode()
def isAtAutoRstNode         (self): return self.v.isAtAutoRstNode()
def isAtEditNode            (self): return self.v.isAtEditNode()
def isAtFileNode            (self): return self.v.isAtFileNode()
def isAtIgnoreNode          (self): return self.v.isAtIgnoreNode()
def isAtNoSentinelsFileNode (self): return self.v.isAtNoSentinelsFileNode()
def isAtOthersNode          (self): return self.v.isAtOthersNode()
def isAtRawFileNode         (self): return self.v.isAtRawFileNode()
def isAtSilentFileNode      (self): return self.v.isAtSilentFileNode()
def isAtShadowFileNode      (self): return self.v.isAtShadowFileNode()
def isAtThinFileNode        (self): return self.v.isAtThinFileNode()

# New names, less confusing:
isAtNoSentFileNode = isAtNoSentinelsFileNode
isAtNorefFileNode  = isAtRawFileNode
isAtAsisFileNode   = isAtSilentFileNode

# Utilities.
def matchHeadline (self,pattern): return self.v.matchHeadline(pattern)
</t>
<t tx="ekr.20091124084348.7300">def bodyString (self):

    return self.v.bodyString()

def headString (self):

    return self.v.headString()

def cleanHeadString (self):

    return self.v.cleanHeadString()
</t>
<t tx="ekr.20091124084348.7301">def isDirty     (self): return self.v.isDirty()
def isExpanded  (self): return self.v.isExpanded()
def isMarked    (self): return self.v.isMarked()
def isOrphan    (self): return self.v.isOrphan()
def isSelected  (self): return self.v.isSelected()
def isTopBitSet (self): return self.v.isTopBitSet()
def isVisited   (self): return self.v.isVisited()
def status      (self): return self.v.status()
</t>
<t tx="ekr.20091124084348.7302"></t>
<t tx="ekr.20091124084348.7303"># This used to be time-critical code.

def childIndex(self):

    p = self
    return p._childIndex
</t>
<t tx="ekr.20091124084348.7304">def directParents (self):

    return self.v.directParents()
</t>
<t tx="ekr.20091124084348.7305">def hasChildren (self):

    p = self
    return len(p.v.children) &gt; 0

hasFirstChild = hasChildren

def numberOfChildren (self):

    p = self
    return len(p.v.children)
</t>
<t tx="ekr.20091124084348.7306"># These methods are useful abbreviations.
# Warning: they make copies of positions, so they should be used _sparingly_

def getBack          (self): return self.copy().moveToBack()
def getFirstChild    (self): return self.copy().moveToFirstChild()
def getLastChild     (self): return self.copy().moveToLastChild()
def getLastNode      (self): return self.copy().moveToLastNode()
def getLastVisible   (self): return self.copy().moveToLastVisible()
def getNext          (self): return self.copy().moveToNext()
def getNodeAfterTree (self): return self.copy().moveToNodeAfterTree()
def getNthChild    (self,n): return self.copy().moveToNthChild(n)
def getParent        (self): return self.copy().moveToParent()
def getThreadBack    (self): return self.copy().moveToThreadBack()
def getThreadNext    (self): return self.copy().moveToThreadNext()

# New in Leo 4.4.3 b2: add c args.
def getVisBack (self,c): return self.copy().moveToVisBack(c)
def getVisNext (self,c): return self.copy().moveToVisNext(c)

# These are efficient enough now that iterators are the normal way to traverse the tree!

back          = getBack
firstChild    = getFirstChild
lastChild     = getLastChild
lastNode      = getLastNode
lastVisible   = getLastVisible # New in 4.2 (was in tk tree code).
next          = getNext
nodeAfterTree = getNodeAfterTree
nthChild      = getNthChild
parent        = getParent
threadBack    = getThreadBack
threadNext    = getThreadNext
visBack       = getVisBack
visNext       = getVisNext

# New in Leo 4.4.3:
hasVisBack = visBack
hasVisNext = visNext</t>
<t tx="ekr.20091124084348.7307">def hasBack(self):
    p = self
    return p.v and p._childIndex &gt; 0

def hasNext(self):
    p = self
    try:
        parent_v = p._parentVnode()
            # Returns None if p.v is None.
        return p.v and parent_v and p._childIndex+1 &lt; len(parent_v.children)
    except Exception:
        g.trace('*** Unexpected exception')
        g.es_exception()
        return None

def hasParent(self):
    p = self
    return p.v and len(p.stack) &gt; 0

def hasThreadBack(self):
    p = self
    return p.hasParent() or p.hasBack() # Much cheaper than computing the actual value.
</t>
<t tx="ekr.20091124084348.7308">def hasThreadNext (self):

    p = self
    if not p.v: return False

    if p.hasChildren() or p.hasNext(): return True

    n = len(p.stack) -1
    while n &gt;= 0:
        v,childIndex = p.stack[n]
        # See how many children v's parent has.
        if n == 0:
            parent_v = v.context.hiddenRootNode
        else:
            parent_v,junk = p.stack[n-1]
        if len(parent_v.children) &gt; childIndex+1:
            # v has a next sibling.
            return True
        n -= 1
    return False
</t>
<t tx="ekr.20091124084348.7309">def findRootPosition (self):

    p = self.copy()
    while p.hasParent():
        p.moveToParent()
    while p.hasBack():
        p.moveToBack()
    return p</t>
<t tx="ekr.20091124084348.7310">def isAncestorOf (self, p2):

    p = self ; v = p.v

    for z in p2.stack:
        v2,junk = z
        if v2 == v:
            return True

    return False
</t>
<t tx="ekr.20091124084348.7311">def isCloned (self):

    p = self
    return p.v.isCloned()
</t>
<t tx="ekr.20091124084348.7312">def isRoot (self):

    p = self

    return not p.hasParent() and not p.hasBack()
</t>
<t tx="ekr.20091124084348.7313">def isVisible (self,c):

    p = self ; trace = False
    limit,limitIsVisible = c.visLimit()
    limit_v = limit and limit.v or None
    if p.v == limit_v:
        if trace: g.trace('*** at limit','limitIsVisible',limitIsVisible,p.h)
        return limitIsVisible

    # It's much easier with a full stack.
    n = len(p.stack)-1
    while n &gt;= 0:
        progress = n
        # v,n = p.vParentWithStack(v,p.stack,n)
        v,junk = p.stack[n]
        if v == limit_v:  # We are at a descendant of limit.
            if trace: g.trace('*** descendant of limit',
                'limitIsVisible',limitIsVisible,
                'limit.isExpanded()',limit.isExpanded(),'v',v)
            if limitIsVisible:
                return limit.isExpanded()
            else: # Ignore the expansion state of @chapter nodes.
                return True
        if not v.isExpanded():
            if trace: g.trace('*** non-limit parent is not expanded:',v._headString,p.h)
            return False
        n -= 1
        assert progress &gt; n

    return True
</t>
<t tx="ekr.20091124084348.7314">def level (self):

    '''Return the number of p's parents.'''

    p = self
    return p.v and len(p.stack) or 0

simpleLevel = level
</t>
<t tx="ekr.20091124084348.7315">def textOffset(self):
    '''
        See http://tinyurl.com/5nescw for details
    '''

    p = self

    # caching of p.textOffset, we need to calculate it only once
    if p.txtOffset is not None:
        return p.txtOffset

    p.txtOffset = 0
    # walk back from the current position
    for cursor in p.self_and_parents():
        # we also need the parent, the "text offset" is relative to it
        parent = cursor.parent()
        if parent == None: # root reached
            break
        parent_bodyString = parent.b
        if parent_bodyString == '': # organizer node
            continue
        parent_lines = parent_bodyString.split('\n')
        # check out if the cursor node is a section
        cursor_is_section = False
        cursor_headString = cursor.h
        if cursor_headString.startswith('&lt;&lt;'):
            cursor_is_section = True # section node
        for line in parent_lines:
            if cursor_is_section == True:
                # find out the section in the bodyString of the parent
                pos = line.find(cursor_headString)
            else:
                # otherwise find the "@others" directive in the bodyString of the parent
                pos = line.find('@others')
            if pos &gt; 0:
                # break the iteration over lines if something is found 
                break
        if pos &gt; 0:
            p.txtOffset += pos
        if parent.v.isAnyAtFileNode(): # do not scan upper
            break

    return p.txtOffset         
</t>
<t tx="ekr.20091124084348.7316"></t>
<t tx="ekr.20091124084348.7317"></t>
<t tx="ekr.20091124084348.7318"># Clone bits are no longer used.
# Dirty bits are handled carefully by the position class.

def clearMarked  (self): return self.v.clearMarked()
def clearOrphan  (self): return self.v.clearOrphan()
def clearVisited (self): return self.v.clearVisited()

def contract (self): return self.v.contract()
def expand   (self): return self.v.expand()

def initExpandedBit    (self): return self.v.initExpandedBit()
def initMarkedBit      (self): return self.v.initMarkedBit()
def initStatus (self, status): return self.v.initStatus(status)

def setMarked   (self): return self.v.setMarked()
def setOrphan   (self): return self.v.setOrphan()
def setSelected (self): return self.v.setSelected()
def setVisited  (self): return self.v.setVisited()
</t>
<t tx="ekr.20091124084348.7319">def computeIcon (self):

    return self.v.computeIcon()

def setIcon (self):

    pass # Compatibility routine for old scripts
</t>
<t tx="ekr.20091124084348.7320">def setSelection (self,start,length):

    return self.v.setSelection(start,length)
</t>
<t tx="ekr.20091124084348.7321">def setBodyString (self,s,encoding="utf-8"):

    p = self
    return p.v.setBodyString(s,encoding)

initBodyString = setBodyString
setTnodeText = setBodyString
scriptSetBodyString = setBodyString

def initHeadString (self,s,encoding="utf-8"):

    p = self
    p.v.initHeadString(s,encoding)

def setHeadString (self,s,encoding="utf-8"):

    p = self
    p.v.initHeadString(s,encoding)
    p.setDirty()
</t>
<t tx="ekr.20091124084348.7322"></t>
<t tx="ekr.20091124084348.7323"># Compatibility routine for scripts.

def clearVisitedInTree (self):

    for p in self.self_and_subtree():
        p.clearVisited()
</t>
<t tx="ekr.20091124084348.7324">def clearAllVisitedInTree (self):

    for p in self.self_and_subtree():
        p.v.clearVisited()
        p.v.clearWriteBit()
</t>
<t tx="ekr.20091124084348.7325"></t>
<t tx="ekr.20091124084348.7326">def clearDirty (self):

    p = self
    p.v.clearDirty()
</t>
<t tx="ekr.20091124084348.7327">def findAllPotentiallyDirtyNodes(self):

    p = self
    return p.v.findAllPotentiallyDirtyNodes()
</t>
<t tx="ekr.20091124084348.7328">def inAtIgnoreRange (self):

    """Returns True if position p or one of p's parents is an @ignore node."""

    p = self

    for p in p.self_and_parents():
        if p.isAtIgnoreNode():
            return True

    return False
</t>
<t tx="ekr.20091124084348.7329">def setAllAncestorAtFileNodesDirty (self,setDescendentsDirty=False):

    trace = False and not g.unitTesting
    verbose = False
    p = self
    dirtyVnodeList = []

    # Calculate all nodes that are joined to p or parents of such nodes.
    nodes = p.findAllPotentiallyDirtyNodes()

    if setDescendentsDirty:
        # N.B. Only mark _direct_ descendents of nodes.
        # Using the findAllPotentiallyDirtyNodes algorithm would mark way too many nodes.
        for p2 in p.subtree():
            # Only @thin nodes need to be marked.
            if p2.v not in nodes and p2.isAtThinFileNode():
                nodes.append(p2.v)

    if trace and verbose:
        for v in nodes:
            print (v.isDirty(),v.isAnyAtFileNode(),v)

    dirtyVnodeList = [v for v in nodes
        if not v.isDirty() and v.isAnyAtFileNode()]
    changed = len(dirtyVnodeList) &gt; 0

    for v in dirtyVnodeList:
        v.setDirty()

    if trace: g.trace("position",dirtyVnodeList,g.callers(5))

    return dirtyVnodeList
</t>
<t tx="ekr.20091124084348.7330">def setDirty (self,setDescendentsDirty=True):

    '''Mark a node and all ancestor @file nodes dirty.'''

    p = self ; dirtyVnodeList = []

    # g.trace(p.h,g.callers(4))

    if not p.v.isDirty():
        p.v.setDirty()
        dirtyVnodeList.append(p.v)

    # Important: this must be called even if p.v is already dirty.
    # Typing can change the @ignore state!
    dirtyVnodeList2 = p.setAllAncestorAtFileNodesDirty(setDescendentsDirty)
    dirtyVnodeList.extend(dirtyVnodeList2)

    return dirtyVnodeList
</t>
<t tx="ekr.20091124084348.7331">@
- convertTreeToString and moreHead can't be vnode methods because they uses level().
- moreBody could be anywhere: it may as well be a postion method.
</t>
<t tx="ekr.20091124084348.7332">def convertTreeToString (self):

    """Convert a positions  suboutline to a string in MORE format."""

    p = self ; level1 = p.level()

    array = []
    for p in p.self_and_subtree():
        array.append(p.moreHead(level1)+'\n')
        body = p.moreBody()
        if body:
            array.append(body +'\n')

    return ''.join(array)
</t>
<t tx="ekr.20091124084348.7333">def moreHead (self, firstLevel,useVerticalBar=False):

    """Return the headline string in MORE format."""

    # useVerticalBar is unused, but it would be useful in over-ridden methods.

    p = self
    level = self.level() - firstLevel
    plusMinus = g.choose(p.hasChildren(), "+", "-")

    return "%s%s %s" % ('\t'*level,plusMinus,p.h)
</t>
<t tx="ekr.20091124084348.7334">@ 
    + test line
    - test line
    \ test line
    test line +
    test line -
    test line \
    More lines...
@c

def moreBody (self):

    """Returns the body string in MORE format.  

    Inserts a backslash before any leading plus, minus or backslash."""

    p = self ; array = []
    lines = p.b.split('\n')
    for s in lines:
        i = g.skip_ws(s,0)
        if i &lt; len(s) and s[i] in ('+','-','\\'):
            s = s[:i] + '\\' + s[i:]
        array.append(s)
    return '\n'.join(array)
</t>
<t tx="ekr.20091124084348.7335"></t>
<t tx="ekr.20091124084348.7336">def children(self):

    '''Return all children of p.'''

    p = self
    p = p.firstChild()
    while p:
        yield p
        p.moveToNext()
    raise StopIteration

# Compatibility with old code.
children_iter = children
</t>
<t tx="ekr.20091124084348.7337">def following_siblings(self):
    '''
    Return all siblings that follow p, not including p.
    '''

    p = self
    p = p.copy() # Always include the original node.
    p = p.next()
    while p:
        yield p
        p.moveToNext()
    raise StopIteration

# Compatibility with old code.
following_siblings_iter = following_siblings
</t>
<t tx="ekr.20091124084348.7338">def nodes (self):

    p = self
    p = p.copy()
    while p:
        yield p.v
        p.moveToThreadNext()

# Compatibility with old code.
tnodes_iter = nodes
vnodes_iter = nodes
</t>
<t tx="ekr.20091124084348.7339">def parents(self):

    '''Return all parents of p.'''

    p = self
    p = p.parent()
    while p:
        yield p
        p.moveToParent()
    raise StopIteration

# Compatibility with old code.
parents_iter = parents
</t>
<t tx="ekr.20091124084348.7340">def self_and_parents(self):

    '''Return p and all parents of p.'''

    p = self
    p = p.copy()
    while p:
        yield p
        p.moveToParent()
    raise StopIteration

# Compatibility with old code.
self_and_parents_iter = self_and_parents
</t>
<t tx="ekr.20091124084348.7341">def self_and_siblings(self):
    '''Return all siblings of p including p.
    '''

    p = self
    p = p.copy()
    while p.hasBack():
        p.moveToBack()
    while p:
        yield p
        p.moveToNext()
    raise StopIteration

# Compatibility with old code.
self_and_siblings_iter = self_and_siblings</t>
<t tx="ekr.20091124084348.7342">def self_and_subtree(self):

    '''Return p's entire subtree, including p.'''

    p = self
    p = p.copy()
    after = p.nodeAfterTree()
    while p and p != after:
        yield p
        p.moveToThreadNext()
    raise StopIteration

# Compatibility with old code.
self_and_subtree_iter = self_and_subtree
</t>
<t tx="ekr.20091124084348.7343">def subtree(self):

    '''Return all descendants of p, not including p.'''

    p = self
    p = p.copy()
    after = p.nodeAfterTree()
    p.moveToThreadNext()
    while p and p != after:
        yield p
        p.moveToThreadNext()
    raise StopIteration

# Compatibility with old code.
subtree_iter = subtree
</t>
<t tx="ekr.20091124084348.7344">def unique_nodes (self):

    p = self
    p = p.copy()
    seen = set()
    while p:
        if p.v in seen:
            p.moveToNodeAfterTree()
        else:
            seen.add(p.v)
            yield p.v
            p.moveToThreadNext()

# Compatibility with old code.
unique_tnodes_iter = unique_nodes
unique_vnodes_iter = unique_nodes
</t>
<t tx="ekr.20091124084348.7345">def unique_subtree (self):
    '''Return unique positions in p's entire subtree, including p.'''

    p = self
    p = p.copy()
    after = p.nodeAfterTree()
    seen = set()
    while p and p != after:
        if p.v in seen:
            p.moveToNodeAfterTree()
        else:
            seen.add(p.v)
            yield p
            p.moveToThreadNext()
    raise StopIteration

# Compatibility with old code.
subtree_with_unique_tnodes_iter = unique_subtree
subtree_with_unique_vnodes_iter = unique_subtree
</t>
<t tx="ekr.20091124084348.7346"></t>
<t tx="ekr.20091124084348.7347">def clone (self):

    """Create a clone of back.

    Returns the newly created position."""

    p = self
    p2 = p.copy() # Do *not* copy the vnode!
    p2._linkAfter(p) # This should "just work"
    return p2
</t>
<t tx="ekr.20091124084348.7348"># These used by unit tests and by the group_operations plugin.

def copyTreeAfter(self):
    p = self
    p2 = p.insertAfter()
    p.copyTreeFromSelfTo(p2)
    return p2

def copyTreeFromSelfTo(self,p2):
    p = self
    p2.v._headString = p.h
    p2.v._bodyString = p.b

    # 2009/10/02: no need to copy arg to iter
    for child in p.children():
        child2 = p2.insertAsLastChild()
        child.copyTreeFromSelfTo(child2)
</t>
<t tx="ekr.20091124084348.7349">@ This is the main delete routine.
It deletes the receiver's entire tree from the screen.
Because of the undo command we never actually delete vnodes or tnodes.
@c

def doDelete (self,newNode=None):

    """Deletes position p from the outline."""

    p = self
    p.setDirty() # Mark @file nodes dirty!

    # Adjust newNode._childIndex if newNode is a following sibling of p.
    sib = p.copy()
    while sib.hasNext():
        sib.moveToNext()
        if sib == newNode:
            newNode._childIndex -= 1
            break

    p._unlink()
</t>
<t tx="ekr.20091124084348.7350">def insertAfter (self):

    """Inserts a new position after self.

    Returns the newly created position."""

    p = self ; context = p.v.context
    p2 = self.copy()

    p2.v = vnode(context=context)
    p2.v.iconVal = 0
    p2._linkAfter(p)

    return p2
</t>
<t tx="ekr.20091124084348.7351">def insertAsLastChild (self):

    """Inserts a new vnode as the last child of self.

    Returns the newly created position."""

    p = self
    n = p.numberOfChildren()

    return p.insertAsNthChild(n)
</t>
<t tx="ekr.20091124084348.7352">def insertAsNthChild (self,n):

    """Inserts a new node as the the nth child of self.
    self must have at least n-1 children.

    Returns the newly created position."""

    p = self ; context = p.v.context
    p2 = self.copy()

    p2.v = vnode(context=context)
    p2.v.iconVal = 0
    p2._linkAsNthChild(p,n)

    return p2
</t>
<t tx="ekr.20091124084348.7353">def invalidOutline (self, message):

    p = self

    if p.hasParent():
        node = p.parent()
    else:
        node = p

    g.alert("invalid outline: %s\n%s" % (message,node))
</t>
<t tx="ekr.20091124084348.7354">def moveAfter (self,a):

    """Move a position after position a."""

    p = self # Do NOT copy the position!

    # g.trace('before','p',p,p.stack,'\na',a,a.stack)

    a._adjustPositionBeforeUnlink(p)
    p._unlink()
    p._linkAfter(a)

    # g.trace('before','p',p,p.stack,'\na',a,a.stack)

    return p
</t>
<t tx="ekr.20091124084348.7355">def moveToFirstChildOf (self,parent):

    """Move a position to the first child of parent."""

    p = self # Do NOT copy the position!
    p._unlink()
    p._linkAsNthChild(parent,0)
    return p


def moveToLastChildOf (self,parent):

    """Move a position to the last child of parent."""

    p = self # Do NOT copy the position!
    p._unlink()
    n = parent.numberOfChildren()
    p._linkAsNthChild(parent,n)
    return p
</t>
<t tx="ekr.20091124084348.7356">def moveToNthChildOf (self,parent,n):

    """Move a position to the nth child of parent."""

    p = self # Do NOT copy the position!

    parent._adjustPositionBeforeUnlink(p)
    p._unlink()
    p._linkAsNthChild(parent,n)

    return p
</t>
<t tx="ekr.20091124084348.7357">def moveToRoot (self,oldRoot=None):

    '''Moves a position to the root position.

    Important: oldRoot must the previous root position if it exists.'''

    p = self # Do NOT copy the position!
    if oldRoot:
        oldRoot._adjustPositionBeforeUnlink(p)
    p._unlink()
    p._linkAsRoot(oldRoot)

    return p
</t>
<t tx="ekr.20091124084348.7358"># This routine checks the structure of the receiver's tree.

def validateOutlineWithParent (self,pv):

    p = self
    result = True # optimists get only unpleasant surprises.
    parent = p.getParent()
    childIndex = p._childIndex

    # g.trace(p,parent,pv)
    &lt;&lt; validate parent ivar &gt;&gt;
    &lt;&lt; validate childIndex ivar &gt;&gt;
    &lt;&lt; validate x ivar &gt;&gt;

    # Recursively validate all the children.
    for child in p.children():
        r = child.validateOutlineWithParent(p)
        if not r: result = False

    return result
</t>
<t tx="ekr.20091124084348.7359">if parent != pv:
    p.invalidOutline( "Invalid parent link: " + repr(parent))
</t>
<t tx="ekr.20091124084348.7360">if pv:
    if childIndex &lt; 0:
        p.invalidOutline ( "missing childIndex" + childIndex )
    elif childIndex &gt;= pv.numberOfChildren():
        p.invalidOutline ( "missing children entry for index: " + childIndex )
elif childIndex &lt; 0:
    p.invalidOutline ( "negative childIndex" + childIndex )
</t>
<t tx="ekr.20091124084348.7361">if not p.v and pv:
    self.invalidOutline ( "Empty t" )
</t>
<t tx="ekr.20091124084348.7362">@
These routines change self to a new position "in place".
That is, these methods must _never_ call p.copy().

When moving to a nonexistent position, these routines simply set p.v = None,
leaving the p.stack unchanged. This allows the caller to "undo" the effect of
the invalid move by simply restoring the previous value of p.v.

These routines all return self on exit so the following kind of code will work:
    after = p.copy().moveToNodeAfterTree()
</t>
<t tx="ekr.20091124084348.7363">def moveToBack (self):

    """Move self to its previous sibling."""

    p = self ; n = p._childIndex

    parent_v = p._parentVnode()
        # Returns None if p.v is None.

    # Do not assume n is in range: this is used by positionExists.
    if parent_v and p.v and 0 &lt; n &lt;= len(parent_v.children):
        p._childIndex -= 1
        p.v = parent_v.children[n-1]
    else:
        p.v = None

    return p
</t>
<t tx="ekr.20091124084348.7364">def moveToFirstChild (self):

    """Move a position to it's first child's position."""

    p = self

    if p.v and p.v.children:
        p.stack.append((p.v,p._childIndex),)
        p.v = p.v.children[0]
        p._childIndex = 0
    else:
        p.v = None

    return p</t>
<t tx="ekr.20091124084348.7365">def moveToLastChild (self):

    """Move a position to it's last child's position."""

    p = self

    if p.v and p.v.children:
        p.stack.append((p.v,p._childIndex),)
        n = len(p.v.children)
        p.v = p.v.children[n-1]
        p._childIndex = n-1
    else:
        p.v = None

    return p
</t>
<t tx="ekr.20091124084348.7366">def moveToLastNode (self):

    """Move a position to last node of its tree.

    N.B. Returns p if p has no children."""

    p = self

    # Huge improvement for 4.2.
    while p.hasChildren():
        p.moveToLastChild()

    return p
</t>
<t tx="ekr.20091124084348.7367">def moveToNext (self):

    """Move a position to its next sibling."""

    p = self ; n = p._childIndex

    parent_v = p._parentVnode()
        # Returns None if p.v is None.
    if not p.v: g.trace('parent_v',parent_v,'p.v',p.v)

    if p.v and parent_v and len(parent_v.children) &gt; n+1:
        p._childIndex = n+1
        p.v = parent_v.children[n+1]
    else:
        p.v = None

    return p
</t>
<t tx="ekr.20091124084348.7368">def moveToNodeAfterTree (self):

    """Move a position to the node after the position's tree."""

    p = self

    while p:
        if p.hasNext():
            p.moveToNext()
            break
        p.moveToParent()

    return p
</t>
<t tx="ekr.20091124084348.7369">def moveToNthChild (self,n):

    p = self

    if p.v and len(p.v.children) &gt; n:
        p.stack.append((p.v,p._childIndex),)
        p.v = p.v.children[n]
        p._childIndex = n
    else:
        p.v = None

    return p
</t>
<t tx="ekr.20091124084348.7370">def moveToParent (self):

    """Move a position to its parent position."""

    p = self

    if p.v and p.stack:
        p.v,p._childIndex = p.stack.pop()
    else:
        p.v = None

    return p
</t>
<t tx="ekr.20091124084348.7371">def moveToThreadBack (self):

    """Move a position to it's threadBack position."""

    p = self

    if p.hasBack():
        p.moveToBack()
        p.moveToLastNode()
    else:
        p.moveToParent()

    return p
</t>
<t tx="ekr.20091124084348.7372">def moveToThreadNext (self):

    """Move a position to threadNext position."""

    p = self

    if p.v:
        if p.v.children:
            p.moveToFirstChild()
        elif p.hasNext():
            p.moveToNext()
        else:
            p.moveToParent()
            while p:
                if p.hasNext():
                    p.moveToNext()
                    break #found
                p.moveToParent()
            # not found.

    return p
</t>
<t tx="ekr.20091124084348.7373">def moveToVisBack (self,c):

    """Move a position to the position of the previous visible node."""

    trace = False and not g.unitTesting
    verbose = True
    p = self ; limit,limitIsVisible = c.visLimit()
    if trace and verbose:
        g.trace(p,'limit',limit,'limitIsVisible',limitIsVisible)
    if trace: g.trace('***entry','parent',p.parent(),'p',p,g.callers(5))
    while p:
        # Short-circuit if possible.
        back = p.back()
        if trace: g.trace(
            'back',back,'hasChildren',bool(back and back.hasChildren()),
            'isExpanded',bool(back and back.isExpanded()))

        if back and back.hasChildren() and back.isExpanded():
            p.moveToThreadBack()
        elif back:
            p.moveToBack()
        else:
            p.moveToParent() # Same as p.moveToThreadBack()
        # if back and (not back.hasChildren() or not back.isExpanded()):
            # p.moveToBack()
        # else:
            # p.moveToThreadBack()
        if trace: g.trace(p.parent(),p)
        if p:
            if trace and verbose: g.trace('**p',p)
            done,val = self.checkVisBackLimit(limit,limitIsVisible,p)
            if done:
                if trace and verbose: g.trace('done',p)
                return val
            if p.isVisible(c):
                if trace and verbose: g.trace('isVisible',p)
                return p
    else:
        # assert not p.
        return p
</t>
<t tx="ekr.20091124084348.7374">def checkVisBackLimit (self,limit,limitIsVisible,p):

    '''Return done, return-val'''

    trace = True and not g.unitTesting
    c = p.v.context

    if limit:
        if limit == p:
            if trace: g.trace('at limit',p)
            if limitIsVisible and p.isVisible(c):
                return True,p
            else:
                return True,None
            #return True,g.choose(limitIsVisible and p.isVisible(c),p,None)
        elif limit.isAncestorOf(p):
            return False,None
        else:
            if trace: g.trace('outside limit tree',limit,p)
            return True,None
    else:
        return False,None
</t>
<t tx="ekr.20091124084348.7375">def moveToVisNext (self,c):

    """Move a position to the position of the next visible node."""

    trace = False and not g.unitTesting
    verbose = False
    p = self ; limit,limitIsVisible = c.visLimit()
    while p:
        if trace: g.trace('1',p.h)
        # if trace: g.trace('hasChildren %s, isExpanded %s %s' % (
            # p.hasChildren(),p.isExpanded(),p.h))
        # Short-circuit if possible.
        if p.hasNext() and p.hasChildren() and p.isExpanded():
            p.moveToFirstChild()
        elif p.hasNext():
            p.moveToNext()
        else:
            p.moveToThreadNext()
        # if p.hasNext() and (not p.hasChildren() or not p.isExpanded()):
            # p.moveToNext()
        # else:
            # p.moveToThreadNext()
        if trace: g.trace('2',p.h)
        if p:
            done,val = self.checkVisNextLimit(limit,p)
            if done: return val
            if p.isVisible(c):
                return p.copy()
    else:
        # assert not p.
        return p
</t>
<t tx="ekr.20091124084348.7376">def checkVisNextLimit (self,limit,p):

    '''Return done, return-val'''

    trace = False and not g.unitTesting

    if limit:
        # Unlike moveToVisBack, being at the limit does not terminate.
        if limit == p:
            return False, None
        elif limit.isAncestorOf(p):
            return False,None
        else:
            if trace: g.trace('outside limit tree')
            return True,None
    else:
        return False,None
</t>
<t tx="ekr.20091124084348.7377"># These methods are only for the use of low-level code
# in leoNodes.py, leoFileCommands.py and leoUndo.py.</t>
<t tx="ekr.20091124084348.7378">def _adjustPositionBeforeUnlink (self,p2):

    '''Adjust position p before unlinking p2.'''

    # p will change if p2 is a previous sibling of p or
    # p2 is a previous sibling of any ancestor of p.

    trace = False and not g.unitTesting
    p = self ; sib = p.copy()

    if trace: g.trace('entry',p.stack)

    # A special case for previous siblings.
    # Adjust p._childIndex, not the stack's childIndex.
    while sib.hasBack():
        sib.moveToBack()
        if sib == p2:
            p._childIndex -= 1
            if trace: g.trace('***new index: %s\n%s' % (
                p.h,p.stack))
            return

    # Adjust p's stack.
    stack = [] ; changed = False ; i = 0
    while i &lt; len(p.stack):
        v,childIndex = p.stack[i]
        p3 = position(v=v,childIndex=childIndex,stack=stack[:i])
        while p3:
            if p2.v == p3.v: # A match with the to-be-moved node?
                stack.append((v,childIndex-1),)
                changed = True
                break # terminate only the inner loop.
            p3.moveToBack()
        else:
            stack.append((v,childIndex),)
        i += 1

    if changed:
        if trace: g.trace('***new stack: %s\n%s' % (
            p.h,stack))
        p.stack = stack</t>
<t tx="ekr.20091124084348.7379">if g.unitTesting:

    c,p = g.getTestVars()

    table = (
        '1',
        '1-1','1-1-1','1-1-2',
        '1-2','1-2-1','1-2-2',
        '2',
        '2-1','2-1-1','2-1-2',
        '2-2','2-2-1','2-2-2',
        '3',
        '3-1','3-1-1','3-1-2',
        '3-2','3-2-1','3-2-2',
    )

    for suffix in table:
        h = 'node %s' % suffix
        p2 = g.findNodeInTree(c,p,h)
        assert p2,h

    table2 = (
        ('2-1-2','2-1-1','2-1-1'),
        ('3','2','2'),
    )  

    for h1,h2,h3 in table2:
        p1 = g.findNodeInTree(c,p,'node %s' % h1)
        p2 = g.findNodeInTree(c,p,'node %s' % h2)
        p3 = g.findNodeInTree(c,p,'node %s' % h3)
        p1._adjustPositionBeforeUnlink(p2)
        result = p1
        assert result.stack == p3.stack,'expected %s got %s' % (
            p3.h,result and result.h or '&lt;none&gt;')

    # Data.
    @others
</t>
<t tx="ekr.20091124084348.7380"># Node 1</t>
<t tx="ekr.20091124084348.7381"># node 1-1</t>
<t tx="ekr.20091124084348.7382"># node 1-1-1</t>
<t tx="ekr.20091124084348.7383"># node 1-1-2</t>
<t tx="ekr.20091124084348.7384"># node 1-2</t>
<t tx="ekr.20091124084348.7385"># node 1-2-1</t>
<t tx="ekr.20091124084348.7386"># node 1-2-2</t>
<t tx="ekr.20091124084348.7387"># node 2</t>
<t tx="ekr.20091124084348.7388"># node 2-1</t>
<t tx="ekr.20091124084348.7389"># node 2-1-1</t>
<t tx="ekr.20091124084348.7390"># node 2-1-2
</t>
<t tx="ekr.20091124084348.7391"># node 2-2</t>
<t tx="ekr.20091124084348.7392"># node 2-2-1</t>
<t tx="ekr.20091124084348.7393"># node 2-2-2
</t>
<t tx="ekr.20091124084348.7394"># node 3</t>
<t tx="ekr.20091124084348.7395"># node 3-1
</t>
<t tx="ekr.20091124084348.7396"># node 3-1-1</t>
<t tx="ekr.20091124084348.7397"># node 3-1-2
</t>
<t tx="ekr.20091124084348.7398"># node 3-2
</t>
<t tx="ekr.20091124084348.7399"># node 3-2-1</t>
<t tx="ekr.20091124084348.7400"># node 3-2-2
</t>
<t tx="ekr.20091124084348.7401">def _linkAfter (self,p_after,adjust=True):

    '''Link self after p_after.'''

    p = self
    parent_v = p_after._parentVnode()
        # Returns None if p.v is None

    # Init the ivars.
    p.stack = p_after.stack[:]
    p._childIndex = p_after._childIndex + 1

    # Set the links.
    child = p.v
    n = p_after._childIndex+1
    child._addLink(n,parent_v,adjust=adjust)</t>
<t tx="ekr.20091124084348.7402">def _linkAsNthChild (self,parent,n,adjust=True):

    p = self
    parent_v = parent.v

    # Init the ivars.
    p.stack = parent.stack[:]
    p.stack.append((parent_v,parent._childIndex),)
    p._childIndex = n

    child = p.v
    child._addLink(n,parent_v,adjust=adjust)

</t>
<t tx="ekr.20091124084348.7403">def _parentVnode (self):

    '''Return the parent vnode.
    Return the hiddenRootNode if there is no other parent.'''

    p = self

    if p.v:
        data = p.stack and p.stack[-1]
        if data:
            v, junk = data
            return v
        else:
            return p.v.context.hiddenRootNode
    else:
        return None
</t>
<t tx="ekr.20091124084348.7404">def _linkAsRoot (self,oldRoot):

    """Link self as the root node."""

    p = self
    assert(p.v)

    hiddenRootNode = p.v.context.hiddenRootNode

    if oldRoot: oldRootNode = oldRoot.v
    else:       oldRootNode = None

    # Init the ivars.
    p.stack = []
    p._childIndex = 0

    parent_v = hiddenRootNode
    child = p.v
    if not oldRoot: parent_v.children = []
    child._addLink(0,parent_v)

    return p
</t>
<t tx="ekr.20091124084348.7405">def _unlink (self):

    '''Unlink the receiver p from the tree.'''

    p = self ; n = p._childIndex
    parent_v = p._parentVnode()
        # returns None if p.v is None
    child = p.v
    assert(p.v)
    assert(parent_v)

    # Delete the child.
    if (0 &lt;= n &lt; len(parent_v.children) and
        parent_v.children[n] == child
    ):
        # This is the only call to v._cutlink.
        child._cutLink(n,parent_v)
    else:
        self.badUnlink(parent_v,n,child)</t>
<t tx="ekr.20091124084348.7406">def badUnlink (self,parent_v,n,child):

    if 0 &lt;= n &lt; len(parent_v.children):
        g.trace('**can not happen: children[%s] != p.v' % (n))
        g.trace('parent_v.children...\n',
            g.listToString(parent_v.children))
        g.trace('parent_v',parent_v)
        g.trace('parent_v.children[n]',parent_v.children[n])
        g.trace('child',child)
        g.trace('** callers:',g.callers())
        if g.app.unitTesting: assert False, 'children[%s] != p.v'
    else:   
        g.trace('**can not happen: bad child index: %s, len(children): %s' % (
            n,len(parent_v.children)))
        g.trace('parent_v.children...\n',
            g.listToString(parent_v.children))
        g.trace('parent_v',parent_v,'child',child)
        g.trace('** callers:',g.callers())
        if g.app.unitTesting: assert False, 'bad child index: %s' % (n)</t>
<t tx="ekr.20091124084348.7407">def makeCacheList(self):

    '''Create a recursive list describing a tree
    for use by v.createOutlineFromCacheList.
    '''

    p = self

    return [
        p.h,p.b,p.gnx,
        [p2.makeCacheList() for p2 in p.children()]]
</t>
<t tx="ekr.20091124084348.7408">class poslist(list):
    """ List of positions 

    This behaves like a normal list, with the distinction that it 
    has select_h and select_b methods that can be used 
    to search through immediate children of the nodes.

    """
    @others
</t>
<t tx="ekr.20091124084348.7409">def select_h(self, regex, flags = re.IGNORECASE):
    """ Find immediate child nodes of nodes in poslist with regex.

    You can chain find_h / find_b with select_h / select_b like this
    to refine an outline search::

        pl = c.find_h('@thin.*py').select_h('class.*').select_b('import (.*)')

    """
    pat = re.compile(regex, flags)
    res = poslist()
    for p in self:
        for child_p in p.children():            
            m = re.match(pat, child_p.h)
            if m:
                pc = child_p.copy()
                pc.mo = m
                res.append(pc)
    return res



</t>
<t tx="ekr.20091124084348.7410">def select_b(self, regex, flags = re.IGNORECASE ):
    """ Find all the nodes in poslist where body matches regex

    You can chain find_h / find_b with select_h / select_b like this
    to refine an outline search::

        pl = c.find_h('@thin.*py').select_h('class.*').select_b('import (.*)')
    """
    pat = re.compile(regex, flags)
    res = poslist()
    for p in self:
        m = re.finditer(pat, p.b)
        t1,t2 = itertools.tee(m,2)
        try:
            first = t1.next()
            # if does not raise StopIteration...
            pc = p.copy()
            pc.matchiter = t2
            res.append(pc)

        except StopIteration:
            pass

    return res



</t>
<t tx="ekr.20091124084348.7411">“Ed, you continue to push the envelope. The amazing thing is that the footprint
isn’t doubling every few months like it would be in another designer’s hands.
Adding features by removing constraints, hot refactoring while adding unit
tests.”</t>
</tnodes>
</leo_file>
