<?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.511160714286">
	<global_window_position top="33" left="180" height="896" width="1045"/>
	<global_log_window_position top="0" left="0" height="0" width="0"/>
</globals>
<preferences/>
<find_panel_settings/>
<vnodes>
<v t="ekr.20051031040240" str_leo_pos="9"><vh>Startup</vh>
<v t="ekr.20080312060129.5"><vh>Buttons</vh>
<v t="ekr.20070628175250"><vh>@@button Add if g.unitTesting @key=f6</vh></v>
<v t="ekr.20071004062031"><vh>@@button print -----</vh></v>
<v t="ekr.20071001054335"><vh>@@button split-defs</vh></v>
<v t="ekr.20080121091513"><vh>@@button parse2tree</vh></v>
<v t="ekr.20080220082617"><vh>@@button print g.es stats</vh>
<v t="ekr.20080220082617.1"><vh>&lt;&lt; docstring &gt;&gt;</vh></v>
<v t="ekr.20080220082617.2"><vh>&lt;&lt; version history &gt;&gt;</vh></v>
<v t="ekr.20080220082617.3"><vh> ctor</vh></v>
<v t="ekr.20080220082617.4"><vh>error &amp; trace</vh></v>
<v t="ekr.20080220082617.5"><vh>main</vh></v>
<v t="ekr.20080221101728"><vh>munging...</vh>
<v t="ekr.20080221071308"><vh>mungeString</vh></v>
<v t="ekr.20080220093930"><vh>mungeHeadline</vh></v>
<v t="ekr.20080221073909"><vh>mungeStatements</vh></v>
<v t="ekr.20080221101728.1"><vh>stringize</vh></v>
</v>
<v t="ekr.20080220082617.6"><vh>scan &amp; helpers</vh>
<v t="ekr.20080220182141"><vh>scanIdChain</vh></v>
<v t="ekr.20080220082617.9"><vh>scanNode</vh>
<v t="ekr.20080221071734"><vh>&lt;&lt; insert statements highlighting the @thin node &gt;&gt;</vh></v>
<v t="ekr.20080221071734.1"><vh>&lt;&lt; Insert a comment containing the headline &gt;&gt;</vh></v>
</v>
<v t="ekr.20080220082617.8"><vh>scanParens</vh></v>
<v t="ekr.20080220183819"><vh>scanStringArg</vh></v>
</v>
<v t="ekr.20080220082617.10"><vh>setDecl</vh></v>
<v t="ekr.20080221110301"><vh>setToBeTranslated</vh></v>
</v>
<v t="ekr.20060910141935"><vh>ZODB plugin buttons</vh>
<v t="ekr.20060910141935.1"><vh>@@button zodb-read</vh></v>
<v t="ekr.20060910141935.2"><vh>@@button zodb-write</vh></v>
</v>
</v>
<v t="ekr.20080312060129.6"><vh>Commands</vh>
<v t="ekr.20060531093331"><vh>@@command clones-tab</vh>
<v t="ekr.20060531093331.1"><vh>class cloneNavigator</vh>
<v t="ekr.20060531093331.2"><vh>init</vh></v>
<v t="ekr.20060531093331.3"><vh>getAllClones</vh></v>
<v t="ekr.20060531093331.4"><vh>displayClones</vh>
<v t="ekr.20060531093331.5"><vh>&lt;&lt;Fill listbox with clone parent headlines&gt;&gt;</vh></v>
<v t="ekr.20060531093331.6"><vh>&lt;&lt;Goto selected position when listbox selection changes&gt;&gt;</vh></v>
</v>
</v>
</v>
<v t="ekr.20071024180738"><vh>@@command ext-unit-test @key=Alt+6</vh></v>
<v t="ekr.20071024171346"><vh>@@command unit-test @key=Alt+4</vh></v>
</v>
<v t="ekr.20070605104410"><vh>@chapters</vh></v>
<v t="ekr.20080121092503"><vh>Scripts</vh>
<v t="ekr.20080121090750"><vh>create-at-auto-nodes</vh></v>
</v>
</v>
<v t="EKR.20040430162943"><vh>Notes</vh>
<v t="ekr.20060217111834"><vh>@url http://docs.python.org/lib/re-syntax.html</vh></v>
<v t="ekr.20060908104329"><vh>@url file:c:/prog/tigris-cvs/leo/doc/leoDocs.leo#Users Guide</vh></v>
<v t="ekr.20031218072017.329"><vh>@thin ../doc/leoNotes.txt</vh></v>
</v>
<v t="EKR.20040519090151.3"><vh>Projects</vh>
<v t="EKR.20040429143933" annotate="7d71002855046e6f6465710155007102550262677103680255087072696f72697479710455043939393971055502666771066802550870726f677265737371076802550961726368657479706571086802752e"><vh>@thin leoProjects.txt</vh></v>
</v>
<v t="EKR.20040519090151.2"><vh>To do</vh>
<v t="ekr.20040117181936"><vh>@thin ../doc/leoToDo.txt</vh></v>
<v t="ekr.20060207133601"><vh>@thin ../doc/leoToDoLater.txt</vh></v>
</v>
<v t="ekr.20031218072017.2406" a="TV"><vh>Code</vh>
<v t="ekr.20040629121554.1"><vh>getSignOnLine (Contains hard-coded version info)</vh></v>
<v t="ekr.20031218072017.2604"><vh>Core classes...</vh>
<v t="ekr.20031218072017.2605"><vh>@thin leo.py </vh></v>
<v t="ekr.20031218072017.2608"><vh>@thin leoApp.py</vh></v>
<v t="ekr.20041005105605.1"><vh>@thin leoAtFile.py</vh></v>
<v t="ekr.20070227091955.1"><vh>@thin leoBridge.py</vh></v>
<v t="ekr.20070317085508.1"><vh>@thin leoChapters.py</vh></v>
<v t="ekr.20031218072017.2794"><vh>@thin leoColor.py</vh></v>
<v t="ekr.20031218072017.2810"><vh>@thin leoCommands.py</vh></v>
<v t="ekr.20041117062700"><vh>@thin leoConfig.py</vh></v>
<v t="ekr.20050710142719"><vh>@thin leoEditCommands.py</vh></v>
<v t="ekr.20031218072017.3018"><vh>@thin leoFileCommands.py</vh></v>
<v t="ekr.20031218072017.3093"><vh>@thin leoGlobals.py</vh></v>
<v t="ekr.20031218072017.3206"><vh>@thin leoImport.py</vh></v>
<v t="ekr.20031218072017.3320"><vh>@thin leoNodes.py</vh></v>
<v t="ekr.20031218072017.3439"><vh>@thin leoPlugins.py</vh></v>
<v t="ekr.20061024060248.1"><vh>@thin leoPymacs.py</vh></v>
<v t="ekr.20031218072017.3446"><vh>@thin leoTangle.py</vh></v>
<v t="ekr.20051104075904" annotate="285808000000616e6e6f7461746571007d71017471022e"><vh>@thin leoTest.py</vh></v>
<v t="ekr.20031218072017.3603"><vh>@thin leoUndo.py</vh></v>
</v>
<v t="ekr.20031218072017.3625"><vh>Gui Base classes</vh>
<v t="ekr.20050721093241"><vh>&lt;&lt; about gui classes and gui plugins &gt;&gt;</vh></v>
<v t="ekr.20031218072017.3630"><vh>@thin leoCompare.py</vh></v>
<v t="ekr.20060123151617"><vh>@thin leoFind.py</vh></v>
<v t="ekr.20031218072017.3655"
expanded="ekr.20070424053629,"><vh>@thin leoFrame.py</vh></v>
<v t="ekr.20031218072017.3719"><vh>@thin leoGui.py</vh></v>
<v t="ekr.20061031131434"><vh>@thin leoKeys.py</vh></v>
<v t="ekr.20031218072017.3749"><vh>@thin leoMenu.py</vh></v>
</v>
<v t="ekr.20031218072017.3821"><vh>Gui Tkinter classes</vh>
<v t="ekr.20031218072017.3838"><vh>@thin leoTkinterComparePanel.py</vh></v>
<v t="ekr.20031218072017.3858"><vh>@thin leoTkinterDialog.py</vh></v>
<v t="ekr.20031218072017.3897"><vh>@thin leoTkinterFind.py</vh></v>
<v t="ekr.20031218072017.3939"><vh>@thin leoTkinterFrame.py</vh></v>
<v t="ekr.20031218072017.4047"><vh>@thin leoTkinterGui.py</vh></v>
<v t="ekr.20031218072017.4099"><vh>@thin leoTkinterKeys.py</vh></v>
<v t="ekr.20031218072017.4100"><vh>@thin leoTkinterMenu.py</vh></v>
<v t="ekr.20040803072955"><vh>@thin leoTkinterTree.py</vh></v>
</v>
<v t="ekr.20080112145409"><vh>Gui gtk classes</vh>
<v t="ekr.20080112145409.1"><vh>@thin leoGtkDialog.py</vh></v>
<v t="ekr.20080112173119"><vh>@thin leoGtkFind.py</vh></v>
<v t="ekr.20080112145409.53"><vh>@thin leoGtkFrame.py</vh></v>
<v t="ekr.20080112145409.435"><vh>@thin leoGtkGui.py</vh></v>
<v t="ekr.20080112171650"><vh>@thin leoGtkKeys.py</vh></v>
<v t="ekr.20080112171213"><vh>@thin leoGtkMenu.py</vh></v>
<v t="ekr.20080112170946"><vh>@thin leoGtkTree.py</vh></v>
</v>
</v>
</vnodes>
<tnodes>
<t tx="EKR.20040430162943"></t>
<t tx="EKR.20040519090151.2"></t>
<t tx="EKR.20040519090151.3"></t>
<t tx="ekr.20031218072017.2406">@tabwidth -4
@pagewidth 80

@ This section contains all the source code of leo.py.

Leo's code uses the following conventions throughout:

c:  a commander
ch: a character
d:  a dialog or a dict.
g:  the leoGlobal module.
i, j, k: indices into a string
p:  a position.
s:  a string
t:  a tnode or a text widget.
u:  an undoer
v:  a vnode
z:  a local temp.</t>
<t tx="ekr.20031218072017.2604"></t>
<t tx="ekr.20031218072017.3625">&lt;&lt; about gui classes and gui plugins &gt;&gt;
</t>
<t tx="ekr.20031218072017.3821"></t>
<t tx="ekr.20040629121554.1">def getSignOnLine (self):
    c = self
    return "Leo 4.4.8 rc1, build %s, April 3, 2008" % c.getBuildNumber()
</t>
<t tx="ekr.20050721093241">@nocolor

The following are notes for anyone who is interested in writing alternate gui's for Leo.

Rule 1: Leo's core is (or should be) free of gui-specific code.

Core code calls 'gui wrapper methods' defined by gui-specific classes.  The base classes for these gui-specific classes are in the node Code--&gt;Gui Base classes.

Rule 2: Gui-specific code should be localized.  

The @file nodes contained in the node 'Code--&gt;Gui Tkinter classes' in leoPy.leo contain all of Leo's Tkinter-specific code.  Gui plugins would typically put all similar code in a single file.

Rule 3: Gui-specific code can call gui methods directly.

There are no restrictions about the code in the gui-specific classes.

Rule 4:  Gui-specific classes must implement the 'gui wrapper methods' specified in the gui base classes.

This is the way that gui-specific classes provide gui-specific services to Leo's core.

The alternative would be to implement all gui-specific commands directly in the gui-specific code.  But this would be much more work than needed.  For example, only a few gui-specific wrappers are needed to implement all commands that deal with body text.  Implementing each of these commands 'from scratch' would duplicate a lot of code unnecessarily.

Using the gui wrapper methods is a bit messy for two reasons:

1.  It requires defining enough wrappers (both in the base gui classes and subclasses) so that all gui-specific services needed by Leo's core are available.   Adding a wrapper to a gui base class involves adding it to all gui-specific subclasses.  It's easy to forget to add a wrapper.  The gui base class defines all wrappers as a function that just calls oops().  This prints a warning that the wrapper should be defined in a subclass.

2. The original wrappers assumed Tkinter-like indices.  Wrappers that were defined later assume Python indices (see Rule 5 below).   The newer style wrappers that use Python indices have 'Python' in their name.   Having two sets of wrappers is one of the ugliest features of the present code.  I find it hard to remember which wrappers exist and what exactly they do :-)

Rule 5:  Leo's core should use Python indices, not gui-specific indices.

Leo's core mostly follows this rule: there may be a few exceptions.

A Python index is an int that runs from 0 (beginning of text) to len(s) (end of text s).  That is, there are exactly len(s) + 1 valid indices.  In contrast, Tkinter indices run from "1.0" to "x.y" where text s has x lines and where the length of the last line is y-1. 

Two (recently written) functions in leoGlobals.py support conversions from Python indices to the row/column indices used by Tkinter.

- g.convertPythonIndexToRowCol converts a Python index to a row/column index used by Tkinter.
- g.convertRowColToPythonIndex does the reverse.

Important:  the first Tkinter index is '1.0', not '0.0', but the row returned by g.convertPythonIndexToRowCol is zero based, so the code that actually creates Tkinter indices from row/col must add 1 to the row.  Similar remarks apply when going in the reverse direction.
</t>
<t tx="ekr.20051031040240"></t>
<t tx="ekr.20060217111834">@nocolor

.  any char
^  start line
$  end of line
\w alphanum: [a-zA-Z0-9_]
\W non-alphanum
\s whitespace
\S non-whitespace

These can be done with regexps:
    
copy-to-end-of-each-line:   (.)$        --&gt;  \1x
copy-to-start-of-each-line: ^([ \t]+)   --&gt;  \1x
remove-leading-ws:  ^[ \t]+             --&gt;  empty
remove-trailing-ws: [ \t]+$             --&gt;  empty
paste-at-column:    ^(.{4})             --&gt;  \1x
paste-after-lws:    ^([ \t]+)           --&gt;  \1x

(?=...)
    Matches if ... matches next, but doesnt consume any of the string. This is called a lookahead assertion. For example, Isaac (?=Asimov) will match 'Isaac ' only if it's followed by 'Asimov'.

(?!...)
    Matches if ... doesn't match next. This is a negative lookahead assertion. For example, Isaac (?!Asimov) will match 'Isaac ' only if it is not followed by 'Asimov'.

(?&lt;=...)
    Matches if the current position in the string is preceded by a match for ... that ends at the current position. This is called a positive lookbehind assertion. The contained pattern must only match strings of some fixed length, meaning that abc or a|b are allowed, but a* and a{3,4} are not</t>
<t tx="ekr.20060531093331">@
Ever have a clone that is difficult to understand outside the context of its
original parent? Here's some code to help. It displays the headline of the
current node plus the headlines of all the parents of all the clones of the
current node. Selecting a displayed parent headline moves the current node to
the corresponding clone in the outline.

The idea is to be able to quickly see the context of all the clones of the
current node and to be able to easily navigate from one clone instance to the
next.
@c

@others
c.cn = cloneNavigator(c)
c.cn.displayClones(c)
</t>
<t tx="ekr.20060531093331.1">class cloneNavigator:
    '''
       Displays the headline of the current node plus the headlines of
       all the parents of all the clones of the current node.  Selecting
       a displayed parent headline moves the current node to the
       corresponding clone in the outline.
       
       The idea is to be able to quickly see the context of all the clones
       of the current node and to be able to easily navigate from one clone
       instance to the next.
    '''
    @others</t>
<t tx="ekr.20060531093331.2">def __init__ (self,c):
    self.c = c
    import Tkinter as Tk
    if 0:
        f = Tk.Toplevel()
    else:
        log = c.frame.log
        log.selectTab('Clones')
        f = log.tabFrame
        for w in f.winfo_children():
            w.destroy()
    
    # Create and pack empty label and listbox
    self.title = Tk.Label(f)
    self.title.pack(anchor="nw")
    self.lb = Tk.Listbox(f)
    self.lb.pack(expand=1,fill="both")</t>
<t tx="ekr.20060531093331.3">def getAllClones(self,p):
    c = self.c
    def clonesOf(p,p1=p):
        return p.v.t == p1.v.t
    return filter(clonesOf, c.allNodes_iter(copy=True))</t>
<t tx="ekr.20060531093331.4">def displayClones(self,c):
    '''Displays the parent headline for all the clones of the current position'''
    cp = c.currentPosition()
    
    # "Title" is the headline of the current node
    self.title.configure(text=cp.headString())
    
    # Initialize listbox and clone list
    clones = self.getAllClones(cp)
    self.lb.delete(0,self.lb.size()-1)
    
    &lt;&lt;Fill listbox with clone parent headlines&gt;&gt;    
    &lt;&lt;Goto selected position when listbox selection changes&gt;&gt;
</t>
<t tx="ekr.20060531093331.5"># Add the headlines of all the clone parents to the listbox
for p in clones:
    if p.parent():
        text = p.parent().headString()
    else:
        text = "&lt;root&gt;"
    self.lb.insert(self.lb.size(),text)
    
    # Initial listbox selection corresponds to current position
    if p.v == cp.v:
        self.lb.selection_set(self.lb.size()-1)</t>
<t tx="ekr.20060531093331.6"># Callback for when a listbox entry is selected            
def gotoSelectedPosition(event,lb=self.lb,c=c,positions=clones):
    idx = int(lb.curselection()[0])
    p = positions[idx]
    c.frame.tree.expandAllAncestors(p)
    c.selectPosition(p)
    return
self.lb.bind(g.angleBrackets("ListboxSelect"), gotoSelectedPosition)</t>
<t tx="ekr.20060908104329"></t>
<t tx="ekr.20060910141935"></t>
<t tx="ekr.20060910141935.1"># c.k.simulateCommand('read-zodb-file')

path = r'c:\prog\tigris-cvs\leo\test\test2.leo'

if g.os_path_exists(path):
    c.zodbCommands.readFile()
else:
    g.es_print('not found: %s' % path)</t>
<t tx="ekr.20060910141935.2"># c.k.simulateCommand('write-zodb-file')

path = c.fileName()
# path = r'c:\prog\tigris-cvs\leo\test\test2.leo'

if g.os_path_exists(path):
    c.zodbCommands.writeFile()
else:
    g.es_print('not found: %s' % path)</t>
<t tx="ekr.20070605104410"></t>
<t tx="ekr.20070628175250">@color

u = c.undoer
b = u.beforeChangeNodeContents(p)
s = p.bodyString()

result = [' '*4 + line for line in g.splitLines(s)]
result.insert(0,'if g.unitTesting:\n')
s = ''.join(result)
c.setBodyString(p,s)

u.afterChangeNodeContents(p,'add-if-g-unitTesting',b)
</t>
<t tx="ekr.20071001054335"># script to split node containing multiple def's into child nodes

def createChild (parent,body,line):
    p = parent.insertAsLastChild()
    h = line [3:].strip()
    i = h.find('(')
    if i &gt; -1:
        func = h [: i].strip()
    h2 = g.choose(func,func,h)
    p.setHeadString(h2)
    p.setTnodeText(''.join(body))

s = p.bodyString()
if s.strip():
    b = c.undoer.beforeChangeTree(p)
    c.beginUpdate()
    try:
        lines = g.splitLines(s) ; body = [] ; changed = False ; lastDefLine = ''
        for line in lines:
            if g.match_word(line,0,'def'):
                if body and lastDefLine:
                    createChild(p,body,lastDefLine)
                    body = [] ; changed = True
                lastDefLine = line
            body.append(line)
        if body and lastDefLine:
            createChild(p,body,lastDefLine)
            changed = True
        if changed:
            c.setChanged(True) ; c.setBodyString(p,'')
    finally:
        c.undoer.afterChangeTree(p,'split-defs',b)
        c.endUpdate()</t>
<t tx="ekr.20071004062031">print '-'*60
</t>
<t tx="ekr.20071024171346"># You can run unit tests by selecting an outline containing unit tests.

import leoTest

leoTest.doTests(c,all=False)
c.selectPosition(p,updateBeadList=False)</t>
<t tx="ekr.20071024180738"># You can run unit tests by selecting an outline containing unit tests.

import leoTest

leoTest.runTestsExternally(c,all=False)

</t>
<t tx="ekr.20080112145409"></t>
<t tx="ekr.20080121090750"># A script to create @auto nodes from all .py files in a directory.

import glob,os

reallyCreate = True

baseDir = r'c:\Python25\Lib\site-packages\pubsub'
baseDir = r'C:\Program Files\Komodo Edit 4.3\lib\mozilla\python\komodo\codeintel2'
dirs = ('',) #'Extensions','UserConfig',)
print '-----'

c.beginUpdate()
try:
    for theDir in dirs:
        pattern = g.os_path_join(baseDir,theDir,'*.py')
        files = glob.glob(pattern)
        print pattern
        # print g.listToString(files)
        for name in files:
            h = '@auto %s' % (name[len(baseDir) + 1:].strip())
            print 'creating',h
            if reallyCreate:
                child = p.insertAsLastChild()
                child.initHeadString(h)
finally:
    c.endUpdate()
</t>
<t tx="ekr.20080121091513">c.importCommands.createOutline(
    fileName=None,
    parent=p,
    atAuto=True,
    s=p.bodyString(),ext='.py')


</t>
<t tx="ekr.20080121092503"></t>
<t tx="ekr.20080220082617">@first # -*- coding: utf-8 -*-

# To do: put list of to-be-translated strings in a doc part.

&lt;&lt; docstring &gt;&gt;
&lt;&lt; version history &gt;&gt;

class controllerClass:
    @others

x = controllerClass(c,p)
x.main()
</t>
<t tx="ekr.20080220082617.1">'''Here is a cute Leo script. It discovers all g.es statements and the unbound
variables in those statements in a single pass over the selected outline. It
then puts the decls followed by the statements in the body text of the @scan_g.es_results node.

Thus, after this script, you can **execute** the body text of the @scan_g.es_results node.
In particular, assuming that g.translateString converts all translated text to upper case,
it is easy to tell which strings have been translated.
'''</t>
<t tx="ekr.20080220082617.2">@nocolor
@

2008/2/19 EKR: Initial 2-pass version.
2008/2/20 EKR:
- Convert to single-pass using decls and statements arrays.
- Add 'tabName' to list of keyword arguments.
- Fixed various bugs.
2008/2/20 EKR 2:
- Generate g.es statements to inicate beginnings of files.
  This allows us to execute all generated statements at once.
- Convert between '.' and '__' as needed to avoid using real ivars.
2008/2/21 EKR:
- Added mungeString.
- Rewrote mungeStatements, scanParens and scanIdChain.
These changes now properly handle all arguments.
2008/2/21 EKR 2:
- Added stringize and related logic.
- Added setToBeTranslated to put list of to-be-translated strings into leading docstring.</t>
<t tx="ekr.20080220082617.3">def __init__ (self,c,p):

    self.c = c
    self.p = p

    self.decls = {}
    self.keywordArgs = ('color','commas','newline','spaces','tabName',)
    self.nodeName = '@scan_g.es_results'
    self.statements = []
    self.printStatements = ('g.es','g.es_print',)
    self.suppressTranslation = False # True: keyword arg to g.es seen.
    self.toBeTranslated = []
    self.traceFlag = False

    self.root = g.findNodeAnywhere(c,self.nodeName)
</t>
<t tx="ekr.20080220082617.4">def error (self,s):

    self.statements.append('***error: %s' % s)

def trace(self,s):

    if self.traceFlag:
        self.statements.append(s)
</t>
<t tx="ekr.20080220082617.5">def main (self):

    '''The main line.'''

    c = self.c
    self.scan()
    self.mungeStatements()
    keys = self.decls.keys()
    keys.sort()
    # This is such a great hack :-)
    decls = ["%s = '%s'" % (self.mungeString(z),self.stringize(z,delim="'")) for z in keys]

    # Put to-be-translated.
    results = ['@ To be translated...',]
    self.toBeTranslated.sort()
    results.extend(self.toBeTranslated)
    results.extend(['@c',])
    # Put decls.
    results.extend(['# Decls...',])
    results.extend(["color='red'","newline=True","tabName='Log'"])
    results.extend(decls)
    # Put statements
    results.extend(["g.app.translateToUpperCase=True",])
    results.extend(self.statements)
    results.extend(["g.app.translateToUpperCase=False",])

    results = '\n'.join(results)

    # Put the results in the root node, or print them.
    if self.root:
        c.setBodyString(self.root,results)
        c.beginUpdate()
        try:
            c.selectPosition(self.root)
        finally:
            c.endUpdate()
    else:
        print 'node not found',self.rootName
        print results

    g.es('done')
</t>
<t tx="ekr.20080220082617.6">def scan(self):


    for p in self.p.self_and_subtree_iter():

        self.scanNode(p)</t>
<t tx="ekr.20080220082617.8">def scanParens(self,s,i,outer):

    '''Scan a parenthesized list of args.'''

    assert g.match(s,i,'(')
    j = g.skip_matching_python_parens(s,i)
    if j == -1:
        self.error('**incomplete paren at: %s' % s[i:])
        return i+1 # Just skip the paren

    assert g.match(s,j,')')
    n = 1
    while i &lt; j:
        progress = i ; ch = s[i]

        if ch in ("'",'"',):
            i = self.scanStringArg(s,i,n,outer)
            n += 1

        elif g.is_c_id(ch):
            i = self.scanIdChain(s,i,outer)
            n += 1

        i = max(i,progress+1)

    return j + 1 # return the character after the paren.
</t>
<t tx="ekr.20080220082617.9">def scanNode(self,p):

    tags = ('g.es','g.es_print',)
    s,h = p.bodyString(), p.headString()
    print_h = True

    if h.startswith('@thin'):
        &lt;&lt; insert statements highlighting the @thin node &gt;&gt;

    i = 0
    while i &lt; len(s):
        progress = i
        for tag in tags:
            if g.match_word(s,i,tag):
                start = i ; i += len(tag)
                self.suppressTranslation = False
                i = g.skip_ws(s,i)
                if g.match(s,i,'('):
                    &lt;&lt; Insert a comment containing the headline &gt;&gt;
                    i = self.scanParens(s,i,outer=True)
                    statement = s[start:i]
                    if statement.find('*arg') == -1 and statement.find('**key') == -1:
                        self.statements.append(statement)
                break
        i = max(i,progress+1)
</t>
<t tx="ekr.20080220082617.10">def setDecl (self,s):

    s = s.strip()

    if s in ('c','g','p','len','str','repr','and','or','not','is',):
        return # Don't need a binding for these.

    if s in ('color','newline','tabName',):
        return # Special binding will be used for these.

    if s.isdigit():
        return # Don't bind integers.

    self.decls[s] = True
</t>
<t tx="ekr.20080220093930">def mungeHeadline (self,s):

    s = s.strip()
    s = s.replace('&lt;&lt;','&lt; &lt;')
    s = s.replace('&gt;&gt;','&gt; &gt;')
    return s
</t>
<t tx="ekr.20080220182141">def scanIdChain (self,s,i,outer):

    assert g.is_c_id(s[i])
    start = i 

    while i &lt; len(s):
        progress = i
        # Skip a.b.c...
        if not g.is_c_id(s[i]): break
        i = g.skip_id(s,i,chars='.')
        i = g.skip_ws(s,i)
        word = s[start:i].strip()
        if outer and g.match(s,i,'=') and word in (self.keywordArgs):
            # g.trace('***','=',word)
            self.suppressTranslation = True
        # Only a paren is valid now.
        if not g.match(s,i,'('): break
        # We shall munge the entire paren expression.
        i = g.skip_matching_python_parens(s,i)
        if g.match(s,i,')'): i += 1
        # Only a dot is valid now.
        if not g.match(s,i,'.'): break
        i += 1
        assert i &gt; progress

    self.setDecl(s[start:i])
    return i
</t>
<t tx="ekr.20080220183819">def scanStringArg(self,s,i,n,outer):

    '''Skip a string, and possible %'''

    j = g.skip_python_string(s,i)
    if j &lt;= i: return i

    # g.trace(n,s[i:j])

    if outer:
        self.setToBeTranslated(s[i:j],n)

    i = g.skip_ws(s,j)
    if not g.match(s,i,'%'):
        return i

    # Handle what follows the '%'
    i = g.skip_ws(s,i+1)

    if g.match(s,i,'('):
        i = self.scanParens(s,i,outer=False)
    elif i &lt; len(s) and g.is_c_id(s[i]):
        i = self.scanIdChain(s,i,outer)

    return i
</t>
<t tx="ekr.20080221071308">def mungeString (self,s):

    '''Convert string s so that it is a valid Python name.'''

    s = s.strip()
    # s = s.replace('@','_AT_')
    # s = s.replace('&lt;','_LT_')
    # s = s.replace('&gt;','_GT_')
    s = s.replace(',','_COMMA_')
    s = s.replace('.','_DOT_')
    s = s.replace('()','_PARENS_')
    s = s.replace('(','_LP_')
    s = s.replace(')','_RP_')
    s = s.replace('"','_DQ_')
    s = s.replace("'",'_SQ_')
    s = ''.join([g.choose(z == '_' or z.isalnum(),z,'_') for z in s])
    return s
</t>
<t tx="ekr.20080221071734">self.statements.append('# ---- %s' % (h))
self.statements.append("g.es_print('','%s %s',color='red')" % ('-'*20,h))</t>
<t tx="ekr.20080221071734.1">if print_h:
    print_h = False
    if not h.startswith('@thin'):
        self.statements.append('# -- node %s' % (self.mungeHeadline(h)))</t>
<t tx="ekr.20080221073909">def mungeStatements (self):

    '''Convert a references to an known id chain by the corresponding decl.'''

    keys = self.decls.keys()
    for tag in self.printStatements:
        if tag in keys: keys.remove(tag)

    results = []
    for s in self.statements:
        i = 0 ; inner_result = []
        while i &lt; len(s):
            progress = i
            for key in keys:
                if g.match_word(s,i,key):
                    inner_result.append(self.mungeString(key))
                    i += len(key)
                    break
            else:
                inner_result.append(s[i])
            i = max(i,progress+1)
        new_statement = ''.join(inner_result)
        if new_statement != s:
            # Add the original lines as comments.
            for z in g.splitLines(s):
                results.append ('# %s' % (z.rstrip()))
        results.append(new_statement) # Add the munged line.

    self.statements = results

</t>
<t tx="ekr.20080221101728"></t>
<t tx="ekr.20080221101728.1">def stringize (self,s,delim):

    s = s.strip()
    s = s.replace(delim,'\\%s' % (delim))
    return s
</t>
<t tx="ekr.20080221110301">def setToBeTranslated (self,s,n):


    s = s.strip()

    if s.startswith('"') or s.startswith("'"):
        s = s[1:]
    if s.endswith('"') or s.endswith("'"):
        s = s[:-1]

    s = s.strip()

    # Suppress translation when a keyword is seen, regardless of position.
    if s in self.keywordArgs:
        self.suppressTranslation = True

    if self.suppressTranslation:
        # g.trace('not added',s)
        return

    if (n % 2) == 1 and s not in self.toBeTranslated:
        self.toBeTranslated.append(s)
</t>
<t tx="ekr.20080312060129.5"></t>
<t tx="ekr.20080312060129.6"></t>
</tnodes>
</leo_file>
