#@+leo-ver=4-thin #@+node:EKR.20040502195524:@thin ../scripts/leoScripts.txt #@+others #@+node:EKR.20040502195524.1:Fnd/change scripts # Note: the initScriptFind script makes setting up Find/Change scripts very easy. #@nonl #@+node:EKR.20040502195524.2:Routines that execute script-find and script-change #@+node:EKR.20040502195524.3:doFind...Script def doFindScript (self): g.app.searchDict["type"] = "find" self.runFindScript() def doFindAllScript (self): """The user has just pressed the Find All button with script-find radio button checked. N.B. Only this code is executed.""" g.app.searchDict["type"] = "findAll" while 1: self.runFindScript() if not g.app.searchDict.get("continue"): break def runFindScript (self): c = self.c try: exec c.find_text in {} # Use {} to get a pristine environment. except: g.es("exception executing find script") g.es_exception(full=False) g.app.searchDict["continue"] = False # 2/1/04 #@-node:EKR.20040502195524.3:doFind...Script #@+node:EKR.20040502195524.4:doChange...Script def doChangeScript (self): g.app.searchDict["type"] = "change" self.runChangeScript() def doChangeAllScript (self): """The user has just pressed the Change All button with script-change box checked. N.B. Only this code is executed.""" g.app.searchDict["type"] = "changeAll" while 1: self.runChangeScript() if not g.app.searchDict.get("continue"): break def runChangeScript (self): c = self.c try: assert(c.script_change_flag) # 2/1/04 exec c.change_text in {} # Use {} to get a pristine environment. except: g.es("exception executing change script") g.es_exception(full=False) g.app.searchDict["continue"] = False # 2/1/04 #@nonl #@-node:EKR.20040502195524.4:doChange...Script #@-node:EKR.20040502195524.2:Routines that execute script-find and script-change #@+node:EKR.20040502195524.5:Find script to check for dubious leading whitespace # Initialize Leo's find panel using the named children of this node. import leoGlobals as g g.app.searchDict = {} # Clear dict.get("v") logic. g.initScriptFind("Find script") c = g.top() c.selectVnode(c.rootPosition()) c.redraw() #@nonl #@+node:EKR.20040502195524.6:Find script import leoGlobals as g c = g.top() ; v = c.currentVnode() last_v = g.app.searchDict.get("v") if last_v and v == last_v: v = v.threadNext() found = False while v: lines = v.bodyString().split('\n') for s in lines: i = g.skip_ws(s,0) leading = s[0:i] if leading: blanks, tabs = 0,0 for ch in leading: if ch == ' ': blanks += 1 if ch == '\t': tabs += 1 ; break if blanks > 0 and tabs > 0: # g.trace(leading) g.es("blanks precede leading tab: " + v.headString()) found = True ; break if found: break v = v.threadNext() if found: g.app.searchDict["v"] = v c.selectVnode(v) c.redraw() else: g.es("done",color="blue") g.app.searchDict["v"] = None g.app.searchDict["continue"] = False #@nonl #@-node:EKR.20040502195524.6:Find script #@+node:EKR.20040502195524.7:test if 1: dubious line #@nonl #@-node:EKR.20040502195524.7:test #@-node:EKR.20040502195524.5:Find script to check for dubious leading whitespace #@+node:EKR.20040502195524.8:Find script to clean whitespace # Initialize Leo's find panel using the named children of this node. import leoGlobals as g g.app.searchDict = {} # Clear dict.get("v") logic. g.initScriptFind("Find script","Change script") c = g.top() c.selectVnode(c.rootPosition()) c.redraw() #@nonl #@+node:EKR.20040502195524.9:Find script import leoGlobals as g c = g.top() ; v = c.currentVnode() ; d = g.app.searchDict findAll = d.get("type") == "findAll" if findAll and c.suboutline_only_flag: after = v.nodeAfterTree() else: after = None found = False ; count = 0 while v and v != after and not found: s = v.bodyString() lines = s.split('\n') for line in lines: if line and not line.strip(): if findAll: g.es(v.headString()) ; count += 1 else: c.frame.tree.expandAllAncestors(v) c.selectVnode(v) c.redraw() # Necessary to make the new node visible. if not findAll: g.es("found node with whitespace to clean") found = True break v = v.threadNext() if not found: if findAll: g.es("found %d nodes" % (count), color="blue") else: g.es("not found") #@-node:EKR.20040502195524.9:Find script #@+node:EKR.20040502195524.10:Change script import leoGlobals as g c = g.top() ; d = g.app.searchDict changeAll = d.get("type") == "changeAll" count = d.get("count",0) if changeAll: v = d.get("v") if v: v = v.threadNext() after = d.get("after") if v == after: v = None else: v = c.currentVnode() d["count"] = 0 after = g.choose(c.suboutline_only_flag,v.nodeAfterTree(),None) d["after"] = after d["v"] = v ; d["continue"] = v != None else: v = c.currentVnode() if v: s = oldText = v.bodyString() lines = s.split('\n') lines = [line.rstrip() for line in lines] s = '\n'.join(lines) if s != oldText: v.setBodyStringOrPane(s,encoding=g.app.tkEncoding) if changeAll: g.es(v.headString()) ; d["count"] = count + 1 else: c.frame.body.onBodyChanged(v,"Change",oldText=oldText) # Handles undo. c.frame.body.setInsertPointToStartOfLine(0) else: if changeAll: g.es("found %d nodes" % (count), color="blue") else: g.es("done") #@nonl #@-node:EKR.20040502195524.10:Change script #@-node:EKR.20040502195524.8:Find script to clean whitespace #@+node:EKR.20040502195524.11:Find scripts to convert @doc comments to doc strings # Initialize Leo's find panel using the named children of this node. import leoGlobals as g g.app.searchDict = {} # Clear dict.get("v") logic. g.initScriptFind("Find script","Change script") # Start searching at the top. c = g.top() c.selectVnode(c.rootPosition()) #@nonl #@+node:EKR.20040502195524.12:Find script import leoGlobals as g import re docPart = re.compile("""^(@$|@ |@doc)(.*)$ ^@c[ \t]*(.*?)$ ^(def[ \t]*.*?:.*?)$ (.*)""", re.MULTILINE | re.DOTALL) c = g.top() ; d = g.app.searchDict v = c.currentVnode() # Move past previously matched node. last_v = d.get("v") if last_v: if v == last_v: v = last_v.threadNext() d["v"] = None d["m"] = None ; d["c"] = c while v: m = docPart.match(v.bodyString()) if m: d["m"] = m ; d["v"] = v c.frame.tree.expandAllAncestors(v) c.selectVnode(v) c.redraw() # Necessary to make the new node visible. break v = v.threadNext() if not d.get("v"): g.es("no @doc part found",color="blue") #@nonl #@-node:EKR.20040502195524.12:Find script #@+node:EKR.20040502195524.13:Change script import leoGlobals as g def replaceDocPart(m,body): # Warning: m.group(0) is the _whole_ match. directive = m.group(1) doc = m.group(2) blanks = m.group(3).strip() if blanks: blanks += "\n\n" else: blanks = "" defLine = m.group(4) rest = m.group(5) docList = doc.split('\n') doc = string.join(docList,"\n\t") if body.hasTextSelection(): # If text is selected only that text becomes the doc part. sel = body.getSelectedText() i = doc.find(sel) if i > -1: doc = doc[:i] + doc[i + len(sel):] # Remove selected text. return directive + doc.rstrip() + "\n@c\n\n" + defLine + '\n\n\t"""' + sel + '"""\n' + rest else: g.es("selection should be in @doc part") return None # This disables any replacement. else: return blanks + defLine + '\n\n\t"""' + doc.strip() + '"""\n' + rest d = g.app.searchDict ; c = d.get("c") ; v = d.get("v") ; m = d.get("m") if c and v and m: body = c.frame.body oldText = v.bodyString() s = replaceDocPart(m,body) if s: # Don't make a replacement if there was an error. v.setBodyStringOrPane(s,encoding=g.app.tkEncoding) body.onBodyChanged(v,"Change",oldText=oldText) # Handles undo. #@nonl #@-node:EKR.20040502195524.13:Change script #@+node:EKR.20040502195524.14:re tests import leoGlobals as g import re s = """@doc line 0 line 1d line 2 #@@c # a comment def abc(self): xx after 1 after 2""" pat = re.compile("""^(@$|@ |@doc)(.*?)$ ^@c[ \t]*(.*?)$ ^(def[ \t]*.*?:.*?)$ (.*)""", re.MULTILINE | re.DOTALL) m = pat.match(s) print "---" if m: print "doc: ", m.group(2).strip() print "blanks:", m.group(3).strip() print "def: ", m.group(4).strip() print "rest: ", m.group(5).strip() else: print "no match" #@-node:EKR.20040502195524.14:re tests #@+node:EKR.20040502195524.15:early find script # This script was a breakthrough. # Executing this script initializes the Find text from the given script string. # To do: get the script from a named child of this node. import leoGlobals as g script = """ import leoGlobals as g c = g.top() ; v = c.currentVnode() print v v = v.threadNext() c.selectVnode(v)""" g.app.searchDict = {} # Communication between search & change scripts c = g.top() c.script_search_flag = True c.find_text = script g.app.findFrame.init(c) c.frame.OnFindPanel() #@nonl #@-node:EKR.20040502195524.15:early find script #@-node:EKR.20040502195524.11:Find scripts to convert @doc comments to doc strings #@+node:EKR.20040502195118:Other find scripts # This file contains functions for non-interactive searching. # You might find these useful while running other scripts. import leo, string, re #@+others #@+node:EKR.20040502195118.1:changeAll def changeAll ( commander, findPat, changePat, bodyFlag = 1 ): """ changeAll make changes in an entire Leo outline. commander Commands object for a Leo outline window. findPat the search string. changePat the replacement string. bodyFlag True: change body text. False: change headline text. """ n = len(changePat) v = commander.rootVnode() pos = 0 while v != None: v, pos = changeNext(v, pos, findPat, changePat, bodyFlag) pos = pos + n #@nonl #@-node:EKR.20040502195118.1:changeAll #@+node:EKR.20040502195118.2:changeNext def changeNext ( v, pos, findPat, changePat, bodyFlag = 1 ): """ changeNext: use string.find() to change text in a Leo outline. v the vnode to start the search. pos the position within the body text of v to start the search. findPat the search string. changePat the replacement string. bodyFlag True: change body text. False: change headline text. returns a tuple (v,pos) showing where the change occured. returns (None,0) if no further match in the outline was found. Note: if (v,pos) is a tuple returned previously from changeNext, changeNext(v,pos+len(findPat),findPat,changePat) changes the next matching string. """ n = len(findPat) v, pos = findNext(v, pos, findPat, bodyFlag) if v == None: return None, 0 if bodyFlag: s = v.bodyString() # s[pos:pos+n] = changePat s = s[:pos] + changePat + s[pos+n:] v.setBodyStringOrPane(s) else: s = v.headString() # s[pos:pos+n] = changePat s = s[:pos] + changePat + s[pos+n:] v.setHeadStringOrHeadline(s) print "setting head string: ", result return v, pos #@nonl #@-node:EKR.20040502195118.2:changeNext #@+node:EKR.20040502195118.3:changePrev def changePrev ( v, pos, findPat, changePat, bodyFlag = 1 ): """ changePrev: use string.rfind() to change text in a Leo outline. v the vnode to start the search. pos the position within the body text of v to start the search. findPat the search string. changePat the replacement string. bodyFlag True: change body text. False: change headline text. returns a tuple (v,pos) showing where the change occured. returns (None,0) if no further match in the outline was found. Note: if (v,pos) is a tuple returned previously from changePrev, changePrev(v,pos-len(findPat),findPat,changePat) changes the next matching string. """ n = len(findPat) v, pos = findPrev(v, pos, findPat, bodyFlag) if v == None: return None, 0 if bodyFlag: s = v.bodyString() # s[pos:pos+n] = changePat s = s[:pos] + changePat + s[pos+n:] v.setBodyStringOrPane(s) else: s = v.headString() #s[pos:pos+n] = changePat s = s[:pos] + changePat + s[pos+n:] v.setHeadStringOrHeadline(s) return v, pos #@nonl #@-node:EKR.20040502195118.3:changePrev #@+node:EKR.20040502195118.4:findAll def findAll(c,pattern,bodyFlag=1): """ findAll search an entire Leo outline for a pattern. c commander for a Leo outline window. pattern the search string. bodyFlag True: search body text. False: search headline text. returns a list of tuples (v,pos) showing where matches occured. returns [] if no match were found. """ v = c.rootVnode() n = len(pattern) result = [] ; pos = 0 while v != None: v, pos = findNext(v,pos,pattern,bodyFlag) if v: result.append ((v, pos),) pos = pos + n return result #@nonl #@-node:EKR.20040502195118.4:findAll #@+node:EKR.20040502195118.5:findNext def findNext ( v, pos, pattern, bodyFlag = 1 ): """ findNext: use string.find() to find a pattern in a Leo outline. v the vnode to start the search. pos the position within the body text of v to start the search. pattern the search string. bodyFlag True: search body text. False: search headline text. returns a tuple (v,pos) showing where the match occured. returns (None,0) if no further match in the outline was found. Note: if (v,pos) is a tuple returned previously from findNext, findNext(v,pos+len(pattern),pattern) finds the next match. """ while v != None: if bodyFlag: s = v.bodyString() else: s = v.headString() pos = s.find(pattern,pos ) if pos != -1: return v, pos v = v.threadNext() pos = 0 return None, 0 #@nonl #@-node:EKR.20040502195118.5:findNext #@+node:EKR.20040502195118.6:findPrev def findPrev ( v, pos, pattern, bodyFlag = 1 ): """ findPrev: use string.rfind() to find a pattern in a Leo outline. v the vnode to start the search. pos the position within the body text of v to start the search. pattern the search string bodyFlag True: search body text. False: search headline text. returns a tuple (v,pos) showing where the match occured. returns (None,0) if no further match in the outline was found. Note: if (v,pos) is a tuple returned previously from findPrev, findPrev(v,pos-len(pattern),pattern) finds the next match. """ while v != None: if bodyFlag: s = v.bodyString() else: s = v.headString() pos = s.rfind(pattern,0,pos) if pos != -1: return v, pos v = v.threadBack() pos = -1 return None, 0 #@nonl #@-node:EKR.20040502195118.6:findPrev #@+node:EKR.20040502195118.7:reChangeAll def reChangeAll ( commander, findPat, changePat, bodyFlag, reFlags = None ): """ reChangeAll: make changes in an entire Leo outline using re module. commander Commands object for a Leo outline window. findPat the search string. changePat the replacement string. bodyFlag True: change body text. False: change headline text. reFlags flags argument to re.search(). """ n = len(changePat) v = commander.rootVnode() pos = 0 while v != None: v, mo, pos = reChangeNext( v, pos, findPat, changePat, bodyFlag, reFlags) pos = pos + n #@nonl #@-node:EKR.20040502195118.7:reChangeAll #@+node:EKR.20040502195118.8:reChangeNext def reChangeNext ( v, pos, findPat, changePat, bodyFlag, reFlags = None ): """ reChangeNext: use re.search() to change text in a Leo outline. v the vnode to start the search. pos the position within the body text of v to start the search. findPat the search string. changePat the replacement string. bodyFlag True: change body text. False: change headline text. reFlags flags argument to re.search(). returns a tuple (v,pos) showing where the change occured. returns (None,0) if no further match in the outline was found. Note: if (v,pos) is a tuple returned previously from reChangeNext, reChangeNext(v,pos+len(findPat),findPat,changePat,bodyFlag) changes the next matching string. """ n = len(findPat) v, mo, pos = reFindNext(v, pos, findPat, bodyFlag, reFlags) if v == None: return None, None, 0 if bodyFlag: s = v.bodyString() print s, findPat, changePat # s[pos:pos+n] = changePat s = s[:pos] + changePat + s[pos+n:] v.setBodyStringOrPane(s) else: s = v.headString() # s[pos:pos+n] = changePat s = s[:pos] + changePat + s[pos+n:] v.setHeadStringOrHeadline(s) return v, mo, pos #@nonl #@-node:EKR.20040502195118.8:reChangeNext #@+node:EKR.20040502195118.9:reChangePrev def reChangePrev ( v, pos, findPat, changePat, bodyFlag, reFlags = None ): """ reChangePrev: use re.search() to change text in a Leo outline. v the vnode to start the search. pos the position within the body text of v to start the search. findPat the search string. changePat the replacement string. bodyFlag True: change body text. False: change headline text. reFlags flags argument to re.search(). returns a tuple (v,pos) showing where the change occured. returns (None,0) if no further match in the outline was found. Note: if (v,pos) is a tuple returned previously from reChangePrev, reChangePrev(v,pos-len(findPat),findPat,changePat,bodyFlag) changes the next matching string. """ n = len(findPat) v, mo, pos = reFindPrev(v, pos, findPat, bodyFlag, reFlags) if v == None: return None, None, 0 if bodyFlag: s = v.bodyString() # s[pos:pos+n] = changePat s = s[:pos] + changePat + s[pos+n:] v.setBodyStringOrPane(s) else: s = v.headString() # s[pos:pos+n] = changePat s = s[:pos] + changePat + s[pos+n:] v.setHeadStringOrHeadline(s) return v, mo, pos #@nonl #@-node:EKR.20040502195118.9:reChangePrev #@+node:EKR.20040502195118.10:reFindAll def reFindAll(c,findPat,bodyFlag,reFlags=None): """ reFindAll search an entire Leo outline using re module. c commander for a Leo outline window. pattern the search string. bodyFlag True: search body text. False: search headline text. reFlags flags argument to re.search(). returns a list of tuples (v,pos) showing where matches occured. returns [] if no match were found. """ v = c.rootVnode() n = len(findPat) result = [] ; pos = 0 while v != None: v, mo, pos = reFindNext(v,pos,findPat,bodyFlag,reFlags) if v != None: result.append ( (v,mo,pos) ) pos = pos + n return result #@nonl #@-node:EKR.20040502195118.10:reFindAll #@+node:EKR.20040502195118.11:reFindNext def reFindNext ( v, pos, pattern, bodyFlag, reFlags = None ): """ reFindNext: use re.search() to find pattern in a Leo outline. v the vnode to start the search. pos the position within the body text of v to start the search. pattern the search string bodyFlag True: search body text. False: search headline text. reFlags the flags argument to re.search() returns a tuple (v,mo,pos) showing where the match occured. returns (None,None,0) if no further match in the outline was found. mo is a "match object" Note: if (v,pos) is a tuple returned previously from reFindNext, reFindNext(v,pos+len(pattern),pattern) finds the next match. """ while v != None: if bodyFlag: s = v.bodyString() else: s = v.headString() if reFlags == None: mo = re.search ( pattern, s[pos:] ) else: mo = re.search ( pattern, s[pos:], reFlags ) if mo != None: return v, mo, pos + mo.start() v = v.threadNext() pos = 0 return None, None, 0 #@nonl #@-node:EKR.20040502195118.11:reFindNext #@+node:EKR.20040502195118.12:reFindPrev def reFindPrev ( v, pos, pattern, bodyFlag, reFlags = None ): """ reFindPrev: use re.search() to find pattern in a Leo outline. v the vnode to start the search. pos the position within the body text of v to start the search. pattern the search string bodyFlag True: search body text. False: search headline text. reFlags the flags argument to re.search() returns a tuple (v,mo,pos) showing where the match occured. returns (None,None,0) if no further match in the outline was found. Note 1: Searches vnodes in reverse (v.threadBack) direction. Searches text of vnodes in _forward_ direction. Note 2: if (v,pos) is a tuple returned previously from reFindPrev, reFindPrev(v,pos-len(pattern),pattern) finds the next match. """ while v != None: if bodyFlag: s = v.bodyString() else: s = v.headString() # Forward search through text... if reFlags == None: mo = re.search ( pattern, s[pos:] ) else: mo = re.search ( pattern, s[pos:], reFlags ) if mo != None: return v, mo, pos+mo.start() # Reverse search through vnode. v = v.threadBack() pos = 0 return None, None, 0 #@nonl #@-node:EKR.20040502195118.12:reFindPrev #@+node:EKR.20040502195118.13:lineAtPos def lineAtPos ( s, pos ): """ lineAtPos: return the line of a string containing the given index. s a string pos an index into s """ # find the start of the line containing the match if len(s) < 1: return "" if pos > len(s): pos = len(s)-1 while pos > 0: if s[pos] == '\n': pos = pos + 1 break else: pos = pos - 1 # return the line containing the match s = s[pos:] list = s.split("\n") return list[0] #@nonl #@-node:EKR.20040502195118.13:lineAtPos #@+node:EKR.20040502195118.14:printFindList def printFindList( findList, bodyFlag = 1 ): """ printFindList: Print matching lines from the list. findList: a list of (v,pos) tuples returned from findAll(). Only the line containing the match is printed. Lines are printed once for each match found on the line. """ for v,pos in findList: if v != None: if bodyFlag: s = v.bodyString() else: s = v.headString() print lineAtPos(s, pos) #@nonl #@-node:EKR.20040502195118.14:printFindList #@-others #@nonl #@-node:EKR.20040502195118:Other find scripts #@-node:EKR.20040502195524.1:Fnd/change scripts #@+node:EKR.20040502195524.16:Other scripts #@+node:EKR.20040517142700:c2py Convert C code to Python syntax #@@first #@@language python #@@tabwidth -4 import leoGlobals as g import string #@+at #@nonl # When using c2py as a script to translate entire files, use # convertCFileToPython(). When using c2py within Leo, use # convertCurrentTree(). # # Please set user data in the << specifying user types >> section. #@-at #@@c #@<< what c2py does >> #@+node:EKR.20040517142700.2:<< what c2py does >> #@+at #@nonl # c2py converts C or C++ text into python text. The conversion is not # complete. Nevertheless, c2py eliminates much of the tedious text # manipulation that would otherwise be required. # # The following is a list of the translations performed by c2py. These # transformations are controlled by convertCodeList(). # # I. Prepass # # These translations before removing all curly braces. # # Suppose we are translating: # # aTypeSpec aClass::aMethod(t1 v1,...,tn vn) # { # body # } # # 1. Translates the function prototype, i.e., translates: # # aTypeSpec aClass::aMethod(t1 v1,...,tn vn) # to: # def aMethod(v1,...vn): # # As a special case, c2py translates: # # aTypeSpec aClass::aClass(t1 v1,...,tn vn) # to: # aClass.__init__(t1 v1,...,tn vn) # # Yes, I know, aClass.__init__ isn't proper Python, but retaining the class # name is useful. # # 2. Let t denote any member of typeList or classList. # # a) Removes all casts of the form (t) or (t*) or (t**), etc. # b) Converts t x, t *x, t **x, etc. to x. # c) Converts x = new t(...) to x = t(...) # d) For all i in ivarsDict[aClass] converts this -> i to self.i # e) For all i in ivarsDict[aClass] converts i to self.i # # 3. Converts < < x > > = to @c. This Leo-specific translation is not done # when translating files. # # II. Main Pass # # This pass does the following simple translations everywhere except in # comments and strings. # # Changes all -> to . # Changes all this.self to self (This corrects problems during the prepass.) # Removes all curly braces # Changes all #if to if # Changes all else if to elif # Changes all #else to else: # Changes all else to else: # Removes all #endif # Changes all && to and # Changes all || to or # Changes all TRUE to True # Changes all FALSE to False # Changes all NULL to None # Changes all this to self # Changes all @code to @c. This Leo-specific translation is not done when # translating files. # # III. Complex Pass # # This pass attempts more complex translations. # # Converts if ( x ) to if x: # Converts elif ( x ) to elif x: # Converts while ( x ) to while x: # Converts for ( x ; y ; z ) to for x SEMI y SEMI z: # # remove all semicolons. # # IV. Final Pass # # This pass completes the translation. # # Removes all semicolons. # Removes @c if it starts the text. This Leo-specific translation is not done # when translating files. # Removes all blank lines. # Removes excess whitespace from all lines, leaving leading whitespace # unchanged. # Replaces C/C++ comments by Python comments. # Removes trailing whitespace from all lines. #@-at #@-node:EKR.20040517142700.2:<< what c2py does >> #@nl #@<< theory of operation >> #@+node:EKR.20040517142700.3:<< theory of operation >> #@+at #@nonl # Strategy and Performance # # c2py is straightforward. The speed of c2py is unimportant. We don't care # about the memory used because we translate only small pieces of text at a # time. # # We can do body[i:j] = x, regardless of len(x). We can also do del body[i:j] # to delete characters. # # We scan repeatedly through the text. Using many passes greatly simplifies # the code and does not slow down c2py significantly. # # No scans are done within strings or comments. The idiom to handle such # scans is the following: # # def someScan(body): # i = 0 # while i < body(len): # if isStringOrComment(body,i): # i = skipStringOrComment(body,i) # elif << found what we are looking for ? >> : # << convert what we are looking for, setting i >> # else: i += 1 # # That's about all there is to it. The code was remarkably easy to write and # seems clear to me. #@-at #@-node:EKR.20040517142700.3:<< theory of operation >> #@nl #@<< specify user types >> #@+node:EKR.20040517142700.4:<< specify user types >> #@+at #@nonl # Please change the following lists so they contain the types and classes used # by your program. # # c2py removes all type definitions correctly; it converts # new aType(...) # to # aType(...) #@-at #@@c classList = [ "vnode", "tnode", "Commands", "wxString", "wxTreeCtrl", "wxTextCtrl", "wxSplitterWindow" ] typeList = ["char", "void", "short", "long", "int", "double", "float"] #@+at #@nonl # Please change ivarsDict so it represents the instance variables (ivars) used # by your program's classes. # # ivarsDict is a dictionary used to translate ivar i of class c to self.i. It # also translates this->i to self.i. #@-at #@@c ivarsDict = { "atFile": [ "mCommands", "mErrors", "mStructureErrors", "mTargetFileName", "mOutputFileName", "mOutputStream", "mStartSentinelComment", "mEndSentinelComment", "mRoot"], "vnode": ["mCommands", "mJoinList", "mIconVal", "mTreeID", "mT", "mStatusBits"], "tnode": ["mBodyString", "mBodyRTF", "mJoinHead", "mStatusBits", "mFileIndex", "mSelectionStart", "mSelectionLength", "mCloneIndex"], "LeoFrame": ["mNextFrame", "mPrevFrame", "mCommands"], "Commands": [ # public "mCurrentVnode", "mLeoFrame", "mInhibitOnTreeChanged", "mMaxTnodeIndex", "mTreeCtrl", "mBodyCtrl", "mFirstWindowAndNeverSaved", #private "mTabWidth", "mChanged", "mOutlineExpansionLevel", "mUsingClipboard", "mFileName", "mMemoryInputStream", "mMemoryOutputStream", "mFileInputStream", "mInputFile", "mFileOutputStream", "mFileSize", "mTopVnode", "mTagList", "mMaxVnodeTag", "mUndoType", "mUndoVnode", "mUndoParent", "mUndoBack", "mUndoN", "mUndoDVnodes", "mUndoLastChild", "mUndoablyDeletedVnode" ]} #@nonl #@-node:EKR.20040517142700.4:<< specify user types >> #@nl tabWidth = 4 # how many blanks in a tab. printFlag = False doLeoTranslations = True ; dontDoLeoTranslations = False #@<< define testData >> #@+node:EKR.20040517142700.5:<< define testData >> testData = [ "\n@doc\n\ This is a doc part: format, whilest, {};->.\n\ <<\ section def>>=\n\ LeoFrame::LeoFrame(vnode *v, char *s, int i)\n\ {\n\ // test ; {} /* */.\n\ #if 0 //comment\n\ if(gLeoFrameList)gLeoFrameList -> mPrevFrame = this ;\n\ else\n\ this -> mNextFrame = gLeoFrameList ;\n\ #else\n\ \n\ vnode *v = new vnode(a,b);\n\ Commands *commander = (Commands) NULL ; // after cast\n\ this -> mPrevFrame = NULL ;\n\ #endif\n\ if (a==b)\n\ a = 2;\n\ else if (a ==c)\n\ a = 3;\n\ else return; \n\ /* Block comment test:\n\ if(2):while(1): end.*/\n\ for(int i = 1; i < limit; ++i){\n\ mVisible = FALSE ;\n\ mOnTop = TRUE ;\n\ }\n\ // trailing ws. \n\ mCommands = new Commands(this, mTreeCtrl, mTextCtrl) ;\n\ gActiveFrame = this ;\n\ }\n\ ", "<<" + "vnode methods >>=\n\ \n\ void vnode::OnCopyNode(wxCommandEvent& WXUNUSED(event))\n\ {\n\ mCommands -> copyOutline();\n\ }\n\ \n@doc\n\ another doc part if, then, else, -> \n<<" + "vnode methods >>=\n\ void vnode::OnPasteNode(wxCommandEvent& WXUNUSED(event))\n\ {\n\ mCommands -> pasteOutline();\n\ }\n" ] #@nonl #@-node:EKR.20040517142700.5:<< define testData >> #@nl #@+others #@+node:EKR.20040517142700.1:Documentation #@-node:EKR.20040517142700.1:Documentation #@+node:EKR.20040517142700.6:speedTest def speedTest(passes): import time file = r"c:\prog\LeoPy\LeoPy.leo" f=open(file) if not f: print "not found: ", file return s=f.read() f.close() print "file:", file, " size:", len(s), " passes:", passes print "speedTest start" time1 = time.clock() p = passes while p > 0: n = len(s) ; i = 0 ; lines = 0 while -1 < i < n: if s[i] == '\n': lines += 1 ; i += 1 else: i = s.find('\n',i) # _much_ faster than list-based-find. continue # match is about 9 times slower than simple test. if s[i]=='\n': # match(s,i,'\n'): # i += 1 else: i += 1 p -= 1 time2 = time.clock() print "lines:", lines print "speedTest done:" print "elapsed time:", time2-time1 print "time/pass:", (time2-time1)/passes #@nonl #@-node:EKR.20040517142700.6:speedTest #@+node:EKR.20040517142700.7:leo1to2 #@+node:EKR.20040517142700.8:leo1to2 def leo1to2(): import leo import leoGlobals c=leoGlobals.top() v=c.currentVnode() convertLeo1to2(v,c) #@-node:EKR.20040517142700.8:leo1to2 #@+node:EKR.20040517142700.9:convertLeo1to2 def convertLeo1to2(v,c): after=v.nodeAfterTree() while v and v != after: s=v.bodyString() print "converting:", v.headString() s=convertStringLeo1to2(s) v.setBodyStringOrPane(s) v=v.threadNext() c.Repaint() # for backward compatibility print "end of leo1to2" #@nonl #@-node:EKR.20040517142700.9:convertLeo1to2 #@+node:EKR.20040517142700.10:convertStringLeo1to2 def convertStringLeo1to2 (s): # print "convertStringLeo1to2:start\n", s codeList = stringToList(s) ; outputList = [] i = 0 while i < len(codeList): j = skipCodePart(codeList,i) if j > i: code = codeList[i:j] convertCodeList1to2(code) i = j #print "-----code:", listToString(code) for item in code: outputList.append(item) j = skipDocPart(codeList,i) if j > i: doc = codeList[i:j] convertDocList(doc) # same as in c2py #print "-----doc:", listToString(doc) i = j for item in doc: outputList.append(item) result = listToString(outputList) global printFlag if printFlag: print "-----:\n", result return result #@nonl #@-node:EKR.20040517142700.10:convertStringLeo1to2 #@+node:EKR.20040517142700.11:convertCodeList1to2 #@+at #@nonl # We do _not_ replace @root by @file or insert @others as needed. Inserting # @others can be done easily enough by hand, and may take more global # knowledge than we can reasonably expect to have. #@-at #@@c def convertCodeList1to2(list): if 0: # There isn't much reason to do this. removeAtRoot(list) safeReplace(list, "@code", "@c") replaceSectionDefs(list) removeLeadingAtCode(list) #@-node:EKR.20040517142700.11:convertCodeList1to2 #@-node:EKR.20040517142700.7:leo1to2 #@+node:EKR.20040517142700.12:c2py entry points #@+at #@nonl # We separate the processing into two parts, 1) a leo-aware driver that # iterates over @file trees and 2) a text-based part that processes one or # more files or strings. #@-at #@+node:EKR.20040517142700.13:convertCurrentTree def convertCurrentTree(): import c2py import leo import leoGlobals c=leoGlobals.top() v = c.currentVnode() c2py.convertLeoTree(v,c) #@nonl #@-node:EKR.20040517142700.13:convertCurrentTree #@+node:EKR.20040517142700.14:convertLeoTree def convertLeoTree(v,c): after=v.nodeAfterTree() while v and v != after: s=v.bodyString() print "converting:", v.headString() s=convertCStringToPython(s, doLeoTranslations ) v.setBodyStringOrPane(s) v=v.threadNext() c.Repaint() # for backward compatibility. print "end of c2py" #@nonl #@-node:EKR.20040517142700.14:convertLeoTree #@+node:EKR.20040517142700.15:convertCFileToPython def convertCFileToPython(file): f=open(file, 'r') if not f: return s = f.read() f.close(); f=open(file + ".py", 'w') if not f: return s = convertCStringToPython(s, dontDoLeoTranslations ) f.write(s) f.close() #@nonl #@-node:EKR.20040517142700.15:convertCFileToPython #@-node:EKR.20040517142700.12:c2py entry points #@+node:EKR.20040517142700.16:c2py Top Level #@+node:EKR.20040517142700.17:convertCStringToPython def convertCStringToPython(s, leoFlag): # print "convertCStringToPython:start\n", s firstPart = True codeList = stringToList(s) if not leoFlag: convertCodeList(codeList, firstPart, dontDoLeoTranslations) return listToString(codeList) outputList = [] i = 0 while i < len(codeList): j = skipCodePart(codeList,i) if j > i: code = codeList[i:j] convertCodeList(code, firstPart, doLeoTranslations) i = j #print "-----code:", listToString(code) for item in code: outputList.append(item) firstPart = False # don't remove @c from here on. j = skipDocPart(codeList,i) if j > i: doc = codeList[i:j] convertDocList(doc) #print "-----doc:", listToString(doc) i = j for item in doc: outputList.append(item) result = listToString(outputList) global printFlag if printFlag: print "-----:\n", result return result #@nonl #@-node:EKR.20040517142700.17:convertCStringToPython #@+node:EKR.20040517142700.18:convertCodeList def convertCodeList(list, firstPart, leoFlag): #first replace(list, "\r", None) convertLeadingBlanks(list) if leoFlag: replaceSectionDefs(list) mungeAllFunctions(list) #next safeReplace(list, " -> ", '.') safeReplace(list, "->", '.') safeReplace(list, " . ", '.') safeReplace(list, "this.self", "self") safeReplace(list, "{", None) safeReplace(list, "}", None) safeReplace(list, "#if", "if") safeReplace(list, "#else", "else") safeReplace(list, "#endif", None) safeReplace(list, "else if", "elif") safeReplace(list, "else", "else:") safeReplace(list, "&&", "and") safeReplace(list, "||", "or") safeReplace(list, "TRUE", "True") safeReplace(list, "FALSE", "False") safeReplace(list, "NULL", "None") safeReplace(list, "this", "self") safeReplace(list, "try", "try:") safeReplace(list, "catch", "except:") if leoFlag: safeReplace(list, "@code", "@c") #next handleAllKeywords(list) # after processing for keywords removeSemicolonsAtEndOfLines(list) #last if firstPart and leoFlag: removeLeadingAtCode(list) removeBlankLines(list) removeExcessWs(list) # your taste may vary: in Python I don't like extra whitespace safeReplace(list, " :", ":") safeReplace(list, ", ", ",") safeReplace(list, " ,", ",") safeReplace(list, " (", "(") safeReplace(list, "( ", "(") safeReplace(list, " )", ")") safeReplace(list, ") ", ")") replaceComments(list) # should follow all calls to safeReplace removeTrailingWs(list) safeReplace(list, "\t ", "\t") # happens when deleting declarations. #@nonl #@-node:EKR.20040517142700.18:convertCodeList #@+node:EKR.20040517142700.19:convertDocList def convertDocList(docList): # print "convertDocList:", docList if matchWord(docList, 0, "@doc"): i = skipWs(docList, 4) if match(docList, i, "\n"): i += 1 docList[0:i] = list("@ ") #@nonl #@-node:EKR.20040517142700.19:convertDocList #@+node:EKR.20040517142700.20:skipDocPart def skipDocPart(list, i): # print "skipDocPart", i while i < len(list): if matchWord(list, i, "@code") or matchWord(list, i, "@c"): break elif isSectionDef(list,i): break else: i = skipPastLine(list, i) return i #@nonl #@-node:EKR.20040517142700.20:skipDocPart #@+node:EKR.20040517142700.21:skipCodePart def skipCodePart(codeList, i): # print "skipCodePart", i if matchWord(codeList, i, "@doc") or matchWord(codeList, i, "@"): return i while i < len(codeList): if match(codeList, i, "//"): i = skipPastLine(codeList,i) elif match(codeList, i, "/*"): i = skipCBlockComment(codeList,i) elif match(codeList, i, '"') or match(codeList, i, "'"): i = skipString(codeList,i) elif match(codeList, i, "\n"): i += 1 if matchWord(codeList, i, "@doc") or matchWord(codeList, i, "@"): break else: i += 1 return i #@nonl #@-node:EKR.20040517142700.21:skipCodePart #@-node:EKR.20040517142700.16:c2py Top Level #@+node:EKR.20040517142700.22:removeSentinels #@-node:EKR.20040517142700.22:removeSentinels #@+node:EKR.20040517142700.23:Scanning & Replacing #@+node:EKR.20040517142700.24:convertLeadingBlanks def convertLeadingBlanks(list): global tabWidth if tabWidth < 2: return i = 0 while i < len(list): n = 0 while i < len(list) and list[i] == ' ': n += 1 ; i += 1 if n == tabWidth: list[i-tabWidth:i] = ['\t'] i = i - tabWidth + 1 n = 0 i = skipPastLine(list, i) #@nonl #@-node:EKR.20040517142700.24:convertLeadingBlanks #@+node:EKR.20040517142700.25:findInList def findInList(list, i, findStringOrList): findList = stringToList(findStringOrList) while i < len(list): if match(list, i, findList): return i else: i += 1 return -1 #@nonl #@-node:EKR.20040517142700.25:findInList #@+node:EKR.20040517142700.26:findInCode def findInCode(codeList, i, findStringOrList): findList = stringToList(findStringOrList) while i < len(codeList): if isStringOrComment(codeList,i): i = skipStringOrComment(codeList,i) elif match(codeList, i, findList): return i else: i += 1 return -1 #@nonl #@-node:EKR.20040517142700.26:findInCode #@+node:EKR.20040517142700.27:mungeAllFunctions # We scan for a '{' at the top level that is preceeded by ')' # @code and < < x > > = have been replaced by @c def mungeAllFunctions(codeList): prevSemi = 0 # Previous semicolon: header contains all previous text i = 0 firstOpen = None while i < len(codeList): if isStringOrComment(codeList,i): i = skipStringOrComment(codeList,i) prevSemi = i elif match(codeList, i, '('): if not firstOpen: firstOpen = i i += 1 elif match(codeList, i, '#'): i = skipPastLine(codeList, i) prevSemi = i elif match(codeList, i, ';'): i += 1 prevSemi = i elif matchWord(codeList, i, "@code"): i += 5 prevSemi = i # restart the scan elif matchWord(codeList, i, "@c"): i += 2 ; prevSemi = i # restart the scan elif match(codeList, i, "{"): i = handlePossibleFunctionHeader(codeList,i,prevSemi,firstOpen) prevSemi = i ; firstOpen = None # restart the scan else: i += 1 #@nonl #@+node:EKR.20040517142700.28:handlePossibleFunctionHeader # converts function header lines from c++ format to python format. # That is, converts # x1..nn w::y ( t1 z1,..tn zn) { # to # def y (z1,..zn): { def handlePossibleFunctionHeader(codeList, i, prevSemi, firstOpen): assert(match(codeList,i,"{")) prevSemi = skipWsAndNl(codeList, prevSemi) close = prevNonWsOrNlChar(codeList, i) if close < 0 or codeList[close] != ')': return 1 + skipToMatchingBracket(codeList, i) if not firstOpen: return 1 + skipToMatchingBracket(codeList, i) close2 = skipToMatchingBracket(codeList, firstOpen) if close2 != close: return 1 + skipToMatchingBracket(codeList, i) open = firstOpen assert(codeList[open]=='(') head = codeList[prevSemi:open] # do nothing if the head starts with "if", "for" or "while" k = skipWs(head,0) if k >= len(head) or not head[k] in string.letters: return 1 + skipToMatchingBracket(codeList, i) kk = skipPastWord(head,k) if kk > k: headString = listToString(head[k:kk]) # C keywords that might be followed by '{' # print "headString:", headString if headString in [ "class", "do", "for", "if", "struct", "switch", "while"]: return 1 + skipToMatchingBracket(codeList, i) args = codeList[open:close+1] k = 1 + skipToMatchingBracket(codeList,i) body = codeList[i:k] #print "head:", listToString(head) #print "args:", listToString(args) #print "body:", listToString(body) #print "tot: ", listToString(codeList[prevSemi:k]) head = massageFunctionHead(head) args = massageFunctionArgs(args) body = massageFunctionBody(body) #print "head2:", listToString(head) #print "args2:", listToString(args) #print "body2:", listToString(body) #print "tot2: ", listToString(codeList[prevSemi:k]) result = [] for item in head: result.append(item) for item in args: result.append(item) for item in body: result.append(item) codeList[prevSemi:k] = result return k #@nonl #@-node:EKR.20040517142700.28:handlePossibleFunctionHeader #@+node:EKR.20040517142700.29:massageFunctionArgs def massageFunctionArgs(args): global gClassName assert(args[0]=='(') assert(args[-1]==')') result = ['('] ; lastWord = [] if gClassName: for item in list("self,"): result.append(item) #can put extra comma i = 1 while i < len(args): i = skipWsAndNl(args, i) c = args[i] if c in string.letters: j = skipPastWord(args,i) lastWord = args[i:j] i = j elif c == ',' or c == ')': for item in lastWord: result.append(item) if lastWord != [] and c == ',': result.append(',') lastWord = [] i += 1 else: i += 1 if result[-1] == ',': del result[-1] result.append(')') result.append(':') # print "new args:", listToString(result) return result #@nonl #@-node:EKR.20040517142700.29:massageFunctionArgs #@+node:EKR.20040517142700.30:massageFunctionHead (sets gClassName) def massageFunctionHead(head): # print "head:", listToString(head) result = [] prevWord = [] global gClassName ; gClassName = [] i = 0 while i < len(head): i = skipWsAndNl(head, i) if i < len(head) and head[i] in string.letters: result = [] j = skipPastWord(head,i) prevWord = head[i:j] i = j # look for ::word2 i = skipWs(head,i) if match(head,i,"::"): # Set the global to the class name. gClassName = listToString(prevWord) # print "class name:", gClassName i = skipWs(head, i+2) if i < len(head) and (head[i]=='~' or head[i] in string.letters): j = skipPastWord(head,i) if head[i:j] == prevWord: for item in list("__init__"): result.append(item) elif head[i]=='~' and head[i+1:j] == prevWord: for item in list("__del__"): result.append(item) else: # for item in "::": result.append(item) for item in head[i:j]: result.append(item) i = j else: for item in prevWord:result.append(item) else: i += 1 finalResult = list("def ") for item in result: finalResult.append(item) # print "new head:", listToString(finalResult) return finalResult #@nonl #@-node:EKR.20040517142700.30:massageFunctionHead (sets gClassName) #@+node:EKR.20040517142700.31:massageFunctionBody def massageFunctionBody(body): body = massageIvars(body) body = removeCasts(body) body = removeTypeNames(body) return body #@nonl #@+node:EKR.20040517142700.32:massageIvars def massageIvars(body): if gClassName and ivarsDict.has_key(gClassName): ivars = ivarsDict [ gClassName ] else: ivars = [] # print "key:ivars=", gClassName, ':', `ivars` i = 0 while i < len(body): if isStringOrComment(body,i): i = skipStringOrComment(body,i) elif body[i] in string.letters: j = skipPastWord(body,i) word = listToString(body[i:j]) # print "looking up:", word if word in ivars: # replace word by self.word # print "replacing", word, " by self.", word word = "self." + word word = list(word) body[i:j] = word delta = len(word)-(j-i) i = j + delta else: i = j else: i += 1 return body #@nonl #@-node:EKR.20040517142700.32:massageIvars #@+node:EKR.20040517142700.33:removeCasts def removeCasts(body): i = 0 while i < len(body): if isStringOrComment(body,i): i = skipStringOrComment(body,i) elif match(body, i, '('): start = i i = skipWs(body, i+1) if body[i] in string.letters: j = skipPastWord(body,i) word = listToString(body[i:j]) i = j if word in classList or word in typeList: i = skipWs(body, i) while match(body,i,'*'): i += 1 i = skipWs(body, i) if match(body,i,')'): i += 1 # print "removing cast:", listToString(body[start:i]) del body[start:i] i = start else: i += 1 return body #@nonl #@-node:EKR.20040517142700.33:removeCasts #@+node:EKR.20040517142700.34:removeTypeNames # Do _not_ remove type names when preceeded by new. def removeTypeNames(body): i = 0 while i < len(body): if isStringOrComment(body,i): i = skipStringOrComment(body,i) elif matchWord(body, i, "new"): i = skipPastWord(body,i) i = skipWs(body,i) # don't remove what follows new. if body[i] in string.letters: i = skipPastWord(body,i) elif body[i] in string.letters: j = skipPastWord(body,i) word = listToString(body[i:j]) if word in classList or word in typeList: k = skipWs(body, j) while match(body,k,'*'): k += 1 ; j = k # print "Deleting type name:", listToString(body[i:j]) del body[i:j] else: i = j else: i += 1 return body #@nonl #@-node:EKR.20040517142700.34:removeTypeNames #@-node:EKR.20040517142700.31:massageFunctionBody #@-node:EKR.20040517142700.27:mungeAllFunctions #@+node:EKR.20040517142700.35:handleAllKeywords # converts if ( x ) to if x: # converts while ( x ) to while x: def handleAllKeywords(codeList): # print "handAllKeywords:", listToString(codeList) i = 0 while i < len(codeList): if isStringOrComment(codeList,i): i = skipStringOrComment(codeList,i) elif ( matchWord(codeList,i,"if") or matchWord(codeList,i,"while") or matchWord(codeList,i,"for") or matchWord(codeList,i,"elif") ): i = handleKeyword(codeList,i) else: i += 1 # print "handAllKeywords2:", listToString(codeList) #@nonl #@+node:EKR.20040517142700.36:handleKeyword def handleKeyword(codeList,i): isFor = False if (matchWord(codeList,i,"if")): i += 2 elif (matchWord(codeList,i,"elif")): i += 4 elif (matchWord(codeList,i,"while")): i += 5 elif (matchWord(codeList,i,"for")): i += 3 isFor = True else: assert(0) # Make sure one space follows the keyword k = i i = skipWs(codeList,i) if k == i: c = codeList[i] codeList[i:i+1] = [ ' ', c ] i += 1 # Remove '(' and matching ')' and add a ':' if codeList[i] == "(": j = removeMatchingBrackets(codeList,i) if j > i and j < len(codeList): c = codeList[j] codeList[j:j+1] = [":", " ", c] j = j + 2 return j return i #@nonl #@-node:EKR.20040517142700.36:handleKeyword #@-node:EKR.20040517142700.35:handleAllKeywords #@+node:EKR.20040517142700.37:isWs and isWOrNl def isWs(c): return c == ' ' or c == '\t' def isWsOrNl(c): return c == ' ' or c == '\t' or c == '\n' #@nonl #@-node:EKR.20040517142700.37:isWs and isWOrNl #@+node:EKR.20040517142700.38:isSectionDef # returns the ending index if i points to < < x > > = def isSectionDef(list, i): i = skipWs(list,i) if not match(list,i,"<<"): return False while i < len(list) and list[i] != '\n': if match(list,i,">>="): return i+3 else: i += 1 return False #@nonl #@-node:EKR.20040517142700.38:isSectionDef #@+node:EKR.20040517142700.39:isStringOrComment def isStringOrComment(list, i): return match(list,i,"'") or match(list,i,'"') or match(list,i,"//") or match(list,i,"/*") #@nonl #@-node:EKR.20040517142700.39:isStringOrComment #@+node:EKR.20040517142700.40:match # returns True if findList matches starting at codeList[i] def match (codeList, i, findStringOrList): findList = stringToList(findStringOrList) n = len(findList) j = 0 while i+j < len(codeList) and j < len(findList): if codeList[i+j] != findList[j]: return False else: j += 1 if j == n: return i+j return False #@nonl #@-node:EKR.20040517142700.40:match #@+node:EKR.20040517142700.41:matchWord def matchWord (codeList, i, findStringOrList): j = match(codeList,i,findStringOrList) if not j: return False elif j >= len(codeList): return True else: c = codeList[j] return not (c in string.letters or c in string.digits or c == '_') #@nonl #@-node:EKR.20040517142700.41:matchWord #@+node:EKR.20040517142700.42:prevNonWsChar and prevNonWsOrNlChar def prevNonWsChar(list, i): i -= 1 while i >= 0 and isWs(list[i]): i -= 1 return i def prevNonWsOrNlChar(list, i): i -= 1 while i >= 0 and isWsOrNl(list[i]): i -= 1 return i #@nonl #@-node:EKR.20040517142700.42:prevNonWsChar and prevNonWsOrNlChar #@+node:EKR.20040517142700.43:removeAllCComments def removeAllCComments(list, delim): i = 0 while i < len(list): if match(list,i,"'") or match(list,i,'"'): i = skipString(list,i) elif match(list,i,"//"): j = skipPastLine(list,i) print "deleting single line comment:", listToString(list[i:j]) del list[i:j] elif match(list,i,"/*"): j = skipCBlockComment(list,i) print "deleting block comment:", listToString(list[i:j]) del list[i:j] else: i += 1 #@nonl #@-node:EKR.20040517142700.43:removeAllCComments #@+node:EKR.20040517142700.44:removeAllCSentinels def removeAllCSentinels(list, delim): i = 0 while i < len(list): if match(list,i,"'") or match(list,i,'"'): # string starts a line. i = skipString(list,i) i = skipPastLine(list,i) elif match(list,i,"/*"): # block comment starts a line i = skipCBlockComment(list,i) i = skipPastLine(line,i) elif match(list,i,"//@"): j = skipPastLine(list,i) print "deleting sentinel:", listToString(list[i:j]) del list[i:j] else: i = skipPastLine(list,i) #@nonl #@-node:EKR.20040517142700.44:removeAllCSentinels #@+node:EKR.20040517142700.45:removeAllPythonComments def removeAllPythonComments(list, delim): i = 0 while i < len(list): if match(list,i,"'") or match(list,i,'"'): i = skipString(list,i) elif match(list,i,"#"): j = skipPastLine(list,i) print "deleting comment:", listToString(list[i:j]) del list[i:j] else: i += 1 #@nonl #@-node:EKR.20040517142700.45:removeAllPythonComments #@+node:EKR.20040517142700.46:removeAllPythonSentinels def removeAllPythonSentinels(list, delim): i = 0 while i < len(list): if match(list,i,"'") or match(list,i,'"'): # string starts a line. i = skipString(list,i) i = skipPastLine(list,i) elif match(list,i,"#@"): j = skipPastLine(list,i) print "deleting sentinel:", listToString(list[i:j]) del list[i:j] else: i = skipPastLine(list,i) #@nonl #@-node:EKR.20040517142700.46:removeAllPythonSentinels #@+node:EKR.20040517142700.47:removeAtRoot def removeAtRoot (codeList): i = skipWs(codeList, 0) if matchWord(codeList,i,"@root"): j = skipPastLine(codeList,i) del codeList[i:j] while i < len(codeList): if isStringOrComment(codeList,i): i = skipStringOrComment(codeList,i) elif match(codeList,i,"\n"): i = skipWs(codeList, i+1) if matchWord (codeList,i,"@root"): j = skipPastLine(codeList,i) del codeList[i:j] else: i += 1 #@-node:EKR.20040517142700.47:removeAtRoot #@+node:EKR.20040517142700.48:removeBlankLines def removeBlankLines(codeList): i = 0 while i < len(codeList): j = i while j < len(codeList) and (codeList[j]==" " or codeList[j]=="\t"): j += 1 if j== len(codeList) or codeList[j] == '\n': del codeList[i:j+1] else: oldi = i i = skipPastLine(codeList,i) #@nonl #@-node:EKR.20040517142700.48:removeBlankLines #@+node:EKR.20040517142700.49:removeExcessWs def removeExcessWs(codeList): i = 0 i = removeExcessWsFromLine(codeList,i) while i < len(codeList): if isStringOrComment(codeList,i): i = skipStringOrComment(codeList,i) elif match(codeList,i,'\n'): i += 1 i = removeExcessWsFromLine(codeList,i) else: i += 1 #@nonl #@+node:EKR.20040517142700.50:removeExessWsFromLine def removeExcessWsFromLine(codeList,i): assert(i==0 or codeList[i-1] == '\n') i = skipWs(codeList,i) while i < len(codeList): if isStringOrComment(codeList,i): break # safe elif match(codeList, i, '\n'): break elif match(codeList, i, ' ') or match(codeList, i, '\t'): # Replace all whitespace by one blank. k = i i = skipWs(codeList,i) codeList[k:i] = [' '] i = k + 1 # make sure we don't go past a newline! else: i += 1 return i #@nonl #@-node:EKR.20040517142700.50:removeExessWsFromLine #@-node:EKR.20040517142700.49:removeExcessWs #@+node:EKR.20040517142700.51:removeLeadingAtCode def removeLeadingAtCode(codeList): i = skipWsAndNl(codeList,0) if matchWord(codeList,i,"@code"): i = skipWsAndNl(codeList,5) del codeList[0:i] elif matchWord(codeList,i,"@c"): i = skipWsAndNl(codeList,2) del codeList[0:i] #@nonl #@-node:EKR.20040517142700.51:removeLeadingAtCode #@+node:EKR.20040517142700.52:removeMatchingBrackets def removeMatchingBrackets(codeList, i): j = skipToMatchingBracket(codeList, i) if j > i and j < len(codeList): # print "del brackets:", listToString(codeList[i:j+1]) c = codeList[j] if c == ')' or c == ']' or c == '}': del codeList[j:j+1] del codeList[i:i+1] # print "returning:", listToString(codeList[i:j]) return j - 1 else: return j + 1 else: return j #@nonl #@-node:EKR.20040517142700.52:removeMatchingBrackets #@+node:EKR.20040517142700.53:removeSemicolonsAtEndOfLines def removeSemicolonsAtEndOfLines(list): i = 0 while i < len(list): if isStringOrComment(list,i): i = skipStringOrComment(list,i) elif list[i] == ';': j = skipWs(list,i+1) if j >= len(list) or match(list,j,'\n') or match(list,j,'#') or match(list,j,"//"): del list[i] else: i += 1 else: i += 1 #@nonl #@-node:EKR.20040517142700.53:removeSemicolonsAtEndOfLines #@+node:EKR.20040517142700.54:removeTrailingWs def removeTrailingWs(list): i = 0 while i < len(list): if isWs(list[i]): j = i i = skipWs(list,i) assert(j < i) if i >= len(list) or list[i] == '\n': # print "removing trailing ws:", `i-j` del list[j:i] i = j else: i += 1 #@nonl #@-node:EKR.20040517142700.54:removeTrailingWs #@+node:EKR.20040517142700.55:replace # Replaces all occurances of findString by changeString. # Deletes all occurances if change is None def replace(codeList, findString, changeString): if len(findString)==0: return findList = stringToList(findString) changeList = stringToList(changeString) i = 0 while i < len(codeList): if match(codeList, i, findList): codeList[i:i+len(findList)] = changeList i += len(changeList) else: i += 1 #@nonl #@-node:EKR.20040517142700.55:replace #@+node:EKR.20040517142700.56:replaceComments # For Leo we expect few block comments; doc parts are much more common. def replaceComments(codeList): i = 0 if match(codeList, i, "//"): codeList[0:2] = ['#'] while i < len(codeList): if match(codeList, i, "//"): codeList[i:i+2] = ['#'] i = skipPastLine(codeList,i) elif match(codeList, i, "/*"): j = skipCBlockComment(codeList,i) del codeList[j-2:j] codeList[i:i+2] = ['#'] j -= 2 ; k = i ; delta = -1 while k < j + delta : if codeList[k]=='\n': codeList[k:k+1] = ['\n', '#', ' '] delta += 2 ; k += 3 # progress! else: k += 1 i = j + delta elif match(codeList, i, '"') or match(codeList, i, "'"): i = skipString(codeList,i) else: i += 1 #@nonl #@-node:EKR.20040517142700.56:replaceComments #@+node:EKR.20040517142700.57:replaceSectionDefs # Replaces < < x > > = by @c (at the start of lines). def replaceSectionDefs(codeList): i = 0 j = isSectionDef(codeList,i) if j > 0: codeList[i:j] = list("@c ") while i < len(codeList): if isStringOrComment(codeList,i): i = skipStringOrComment(codeList,i) elif match(codeList,i,"\n"): i += 1 j = isSectionDef(codeList,i) if j > i: codeList[i:j] = list("@c ") else: i += 1 #@nonl #@-node:EKR.20040517142700.57:replaceSectionDefs #@+node:EKR.20040517142700.58:safeReplace # Replaces occurances of findString by changeString outside of C comments and strings. # Deletes all occurances if change is None. def safeReplace(codeList, findString, changeString): if len(findString)==0: return findList = stringToList(findString) changeList = stringToList(changeString) i = 0 if findList[0] in string.letters: #use matchWord while i < len(codeList): if isStringOrComment(codeList,i): i = skipStringOrComment(codeList,i) elif matchWord(codeList, i, findList): codeList[i:i+len(findList)] = changeList i += len(changeList) else: i += 1 else: #use match while i < len(codeList): if match(codeList, i, findList): codeList[i:i+len(findList)] = changeList i += len(changeList) else: i += 1 #@nonl #@-node:EKR.20040517142700.58:safeReplace #@+node:EKR.20040517142700.59:skipCBlockComment def skipCBlockComment(codeList, i): assert(match(codeList, i, "/*")) i += 2 while i < len(codeList): if match(codeList, i, "*/"): return i + 2 else: i += 1 return i #@nonl #@-node:EKR.20040517142700.59:skipCBlockComment #@+node:EKR.20040517142700.60:skipPastLine def skipPastLine(codeList, i): while i < len(codeList) and codeList[i] != '\n': i += 1 if i < len(codeList) and codeList[i] == '\n': i += 1 return i #@nonl #@-node:EKR.20040517142700.60:skipPastLine #@+node:EKR.20040517142700.61:skipPastWord def skipPastWord(list, i): assert(list[i] in string.letters or list[i]=='~') # Kludge: this helps recognize dtors. if list[i]=='~': i += 1 while i < len(list) and ( list[i] in string.letters or list[i] in string.digits or list[i]=='_'): i += 1 return i #@nonl #@-node:EKR.20040517142700.61:skipPastWord #@+node:EKR.20040517142700.62:skipString def skipString(codeList, i): delim = codeList[i] # handle either single or double-quoted strings assert(delim == '"' or delim == "'") i += 1 while i < len(codeList): if codeList[i] == delim: return i + 1 elif codeList[i] == '\\': i += 2 else: i += 1 return i #@nonl #@-node:EKR.20040517142700.62:skipString #@+node:EKR.20040517142700.63:skipStringOrComment def skipStringOrComment(list,i): if match(list,i,"'") or match(list,i,'"'): return skipString(list,i) if match(list, i, "//"): return skipPastLine(list,i) elif match(list, i, "/*"): return skipCBlockComment(list,i) else: assert(0) #@nonl #@-node:EKR.20040517142700.63:skipStringOrComment #@+node:EKR.20040517142700.64:skipToMatchingBracket def skipToMatchingBracket(codeList, i): c = codeList[i] if c == '(': delim = ')' elif c == '{': delim = '}' elif c == '[': delim = ']' else: assert(0) i += 1 while i < len(codeList): c = codeList[i] if isStringOrComment(codeList,i): i = skipStringOrComment(codeList,i) elif c == delim: return i elif c == '(' or c == '[' or c == '{': i = skipToMatchingBracket(codeList,i) i += 1 # skip the closing bracket. else: i += 1 return i #@nonl #@-node:EKR.20040517142700.64:skipToMatchingBracket #@+node:EKR.20040517142700.65:skipWs and skipWsAndNl def skipWs(list, i): while i < len(list): c = list[i] if c == ' ' or c == '\t': i += 1 else: break return i def skipWsAndNl(list, i): while i < len(list): c = list[i] if c == ' ' or c == '\t' or c == '\n': i += 1 else: break return i #@nonl #@-node:EKR.20040517142700.65:skipWs and skipWsAndNl #@+node:EKR.20040517142700.66:stringToList # converts a string to a list containing one item per character of the list. # converts None to the empty string and leaves other types alone. # list(string) does not work on none. def stringToList(string): if string: return list(string) else: return [] #@nonl #@-node:EKR.20040517142700.66:stringToList #@+node:EKR.20040517142700.67:listToString def listToString(list): return string.join(list,"") #@nonl #@-node:EKR.20040517142700.67:listToString #@-node:EKR.20040517142700.23:Scanning & Replacing #@-others gClassName = "" # The class name for the present function. Used to modify ivars. gIvars = [] # List of ivars to be converted to self.ivar def test(): global printFlag ; printFlag = True for s in testData: convertCStringToPython(s, doLeoTranslations) def go(): test() if __name__ == "__main__": speedTest(2) #@nonl #@-node:EKR.20040517142700:c2py Convert C code to Python syntax #@+node:EKR.20040502195524.24:Clear all timestamps # About the only time you should run this script is when: # - changing the format of timestamps in nodeIndices.setTimestamp or # - when making a retroactive change to leoID.txt. import leoGlobals as g if 0: # This is usually a very bad idea. c = g.top() ; v = c.rootVnode() while v: v.t.fileIndex = None v = v.threadNext() g.es("all timestamps cleared") #@nonl #@-node:EKR.20040502195524.24:Clear all timestamps #@+node:EKR.20040502195524.30:Count pages import leoGlobals as g import leoTest u = leoTest.testUtils() nodes = 0 ; lines = 0 c = g.top() c.clearAllVisited() if 0: v = u.findNodeAnywhere(c,"Code") else: root = u.findRootNode (c.currentVnode()) v = u.findNodeInTree(root,"Code") after = v.nodeAfterTree() # g.trace(v,after) while v and v != after: if not v.t.isVisited(): v.t.setVisited() nodes += 1 lines += len(g.splitLines(v.bodyString())) v = v.threadNext() pages = ((nodes * 10) + lines) / 60 print "nodes,lines,pages",nodes,lines,pages g.es("nodes,lines,pages",nodes,lines,pages) #@nonl #@-node:EKR.20040502195524.30:Count pages #@+node:EKR.20040502195524.31:Count separate nodes (tnodes) import leoGlobals as g c = g.top() p = g.findTopLevelNode("Code") tnodes = {} ; count = 0 for p in p.self_and_subtree_iter(): tnodes[p.v.t]=p.v.t count += 1 s = "%4s: %d vnodes, %d distinct" % ("Code",count,len(tnodes.keys())) print s ; g.es(s) tnodes = {} ; count = 0 for p in c.allNodes_iter(): tnodes[p.v.t]=p.v.t count += 1 s = "%4s: %d vnodes, %d distinct" % ("All",count,len(tnodes.keys())) print s ; g.es(s) #@nonl #@-node:EKR.20040502195524.31:Count separate nodes (tnodes) #@+node:EKR.20040502195524.32:Count total, visible nodes import leoGlobals as g c = g.top() total,visible = 0,0 if 0: # old way: v = c.rootVnode() while v: total += 1 v = v.threadNext() v = c.rootVnode() while v: visible += 1 v = v.visNext() else: for p in c.allNodes_iter(): total += 1 p = c.rootPosition() while p: visible += 1 p.moveToVisNext() print "total,visible",total,visible #@nonl #@-node:EKR.20040502195524.32:Count total, visible nodes #@+node:EKR.20040518104556:Create diagrams using Graphviz and pydot #@+node:EKR.20040518104556.1:pydot notes by EKR #@@nocolor - I have found it easiest to create pydot objects rather than creating Graphviz strings. It's the natural way, IMO. - The pydot documentation is poor. When you cut through the blah-blah-blah all that is really going on is that you use ctors to create pydot objects. Typically you specify attributes in the ctors, but there are also getters and setters (various silly redundant flavors) to do this. - It took me awhile to get the difference between names and labels. Names are essentially object identifiers, and they are restricted to what are basically C identifiers. Labels are what are shown in nodes. The default label is the node's name. It's a bit strange to use strings instead of Python object references, but it's no big deal. - The documentation for Graphviz is weak. Very few examples. It took me a long time to realize that by default Graphviz lays out nodes and edges independently of the order in which they were created. The ordering="out" argument to the Dot ctor overrides some parts of the layout algorithm so that nodes are laid out in roughly the definition order. If you want to place nodes yourself, you can specify their exact position. This would be feasible to do in a script and I haven't done that yet. In short, Graphviz and pydot are very impressive tools. The documentation could be improved, but once one gets the hang of things it is fairly easy to get real work done. #@nonl #@-node:EKR.20040518104556.1:pydot notes by EKR #@+node:EKR.20040518104556.2:pydot docs #@@nocolor #@nonl #@+node:EKR.20040518104556.3:General note about attributes The original documentation repeats endlessly the same info about attributes. Attributes can be set in several ways: set("attributeName") set_[attribute name], i.e. set_color, set_fontname object.attributeName = val Similarly, you can get attribute values with corresponding getters. #@nonl #@-node:EKR.20040518104556.3:General note about attributes #@+node:EKR.20040518104556.4:Cluster(Graph) class Cluster(Graph) Methods: __init__(self, graph_name='subG', suppress_disconnected=False, **attrs) graph_name: the cluster's name (the string 'cluster' will be always prepended) suppress_disconnected: False: remove from the cluster any disconnected nodes. Attributes: attributes = ['pencolor', 'bgcolor', 'labeljust', 'labelloc', 'URL', 'fontcolor', 'fontsize', 'label', 'fontname', 'lp', 'style', 'target', 'color', 'peripheries', 'fillcolor'] #@nonl #@-node:EKR.20040518104556.4:Cluster(Graph) #@+node:EKR.20040518104556.5:Common class Common Common information to several classes. Should not be directly used, several classes are derived from this one. char_range(self, a, b) Generate a list containing a range of characters. is_ID(self, s) Checks whether a string is an dot language ID. Data: chars_ID = None parent_graph = None #@-node:EKR.20040518104556.5:Common #@+node:EKR.20040518104556.6:Dot(Graph) class Dot(Graph) A container for handling a dot language file. This class implements methods to write and process a dot language file. Methods defined here: __init__(self, **args) Attributes: formats = ['ps', 'ps2', 'hpgl', 'pcl', 'mif', 'pic', 'gd', 'gd2', 'gif', 'jpg', 'jpeg', 'png', 'wbmp', 'ismap', 'imap', 'cmap', 'vrml', 'vtx', 'mp', 'fig', ...] progs = None #@nonl #@+node:EKR.20040518104556.7:create and create_xxx create(self, prog='dot', format='ps') Creates and returns a Postscript representation of the graph. create will write the graph to a temporary dot file and process it with the program given by 'prog' (which defaults to 'twopi'), reading the Postscript output and returning it as a string is the operation is successful. On failure None is returned. There's also the preferred possibility of using: create_'format'(prog='program') which are automatically defined for all the supported formats. [create_ps(), create_gif(), create_dia(), ...] #@nonl #@-node:EKR.20040518104556.7:create and create_xxx #@+node:EKR.20040518104556.8:write and write_xxx write(self, path, prog='dot', format='raw') Writes a graph to a file. Given a filename 'path' it will open/create and truncate such file and write on it a representation of the graph defined by the dot object and in the format specified by 'format'. The format 'raw' is used to dump the string representation of the Dot object, without further processing. The output can be processed by any of graphviz tools, defined in 'prog', which defaults to 'dot' Returns True or False according to the success of the write operation. There's also the preferred possibility of using: write_'format'(path, prog='program') which are automatically defined for all the supported formats. [write_ps(), write_gif(), write_dia(), ...] #@nonl #@-node:EKR.20040518104556.8:write and write_xxx #@-node:EKR.20040518104556.6:Dot(Graph) #@+node:EKR.20040518104556.9:Edge class Edge(__builtin__.object, Common) A graph edge. This class represents a graph's edge with all its attributes. edge(src, dst, attribute=value, ...) src: source node's name dst: destination node's name -------------------------------------------------------------------------------- Methods defined here: __eq__(self, edge) Compare two edges. If the parent graph is directed, arcs linking node A to B are considered equal and A->B != B->A If the parent graph is undirected, any edge connecting two nodes is equal to any other edge connecting the same nodes, A->B == B->A __init__(self, src, dst, **attrs) get_destination(self) Get the edge's destination node name. get_source(self) Get the edges source node name. parse_node_ref(self, node_str) set(self, name, value) Set an attribute value by name. Given an attribute 'name' it will set its value to 'value'. There's always the possibility of using the methods: set_'name'(value) which are defined for all the existing attributes. to_string(self) Returns a string representation of the edge in dot language. -------------------------------------------------------------------------------- Data and other attributes defined here: __dict__ = dictionary for instance variables (if defined) __weakref__ = list of weak references to the object (if defined) attributes = ['style', 'target', 'pos', 'layer', 'tooltip', 'color', 'showboxes', 'URL', 'fontcolor', 'fontsize', 'label', 'fontname', 'comment', 'lp', 'arrowhead', 'arrowsize', 'arrowtail', 'constraint', 'decorate', 'dir', ...] #@nonl #@-node:EKR.20040518104556.9:Edge #@+node:EKR.20040518104556.10:Error class Error(exceptions.Exception) General error handling class. Methods defined here: __init__(self, value) __str__(self) #@nonl #@-node:EKR.20040518104556.10:Error #@+node:EKR.20040518104556.11:Graph(Common) class Graph(__builtin__.object, Common) Class representing a graph in Graphviz's dot language. This class implements the methods to work on a representation of a graph in Graphviz's dot language. Data and other attributes: __dict__ = dictionary for instance variables (if defined) __weakref__ = list of weak references to the object (if defined) attributes = ['Damping', 'bb', 'center', 'clusterrank', 'compound', 'concentrate', 'defaultdist', 'dim', 'fontpath', 'epsilon', 'layers', 'layersep', 'margin', 'maxiter', 'mclimit', 'mindist', 'pack', 'packmode', 'model', 'page', ...] #@nonl #@+node:EKR.20040518104556.12:Graph.__init__ __init__(self, graph_name='G', type='digraph', strict=False, suppress_disconnected=False, simplify=False, **attrs) graph_name: the graph's name type: 'graph' or 'digraph' suppress_disconnected: defaults to False, which will remove from the graph any disconnected nodes. simplify: if True it will avoid displaying equal edges, i.e. only one edge between two nodes. removing the duplicated ones. All the attributes defined in the Graphviz dot language should be supported. Attributes can be set through the dynamically generated methods: set_[attribute name], i.e. set_size, set_fontname or using the instance's attributes: Graph.[attribute name], i.e. graph_instance.label, graph_instance.fontname #@nonl #@-node:EKR.20040518104556.12:Graph.__init__ #@+node:EKR.20040518104556.13:add_edge add_edge(self, graph_edge) Adds an edge object to the graph. #@nonl #@-node:EKR.20040518104556.13:add_edge #@+node:EKR.20040518104556.14:add_node add_node(self, graph_node) Adds a node object to the graph. #@nonl #@-node:EKR.20040518104556.14:add_node #@+node:EKR.20040518104556.15:add_subgraph add_subgraph(self, sgraph) Adds an edge object to the graph. #@-node:EKR.20040518104556.15:add_subgraph #@+node:EKR.20040518104556.16:getters... get(self, name) Get an attribute value by name. get_'name'() is defined for all attributes. get_edge(self, src, dst) Retrieved an edge from the graph. Returns a list, a single Edge, or None get_edge_list(self) Returns the list of Edge instances composing the graph. get_name(self) Get the graph's name. get_node(self, name) Given a node's name the corresponding Node instance will be returned. Returns a list, a single Node or None. get_node_list(self) Returns the list of Node instances composing the graph. get_simplify(self) Get whether to simplify or not. get_strict(self, val) Get graph's 'strict' mode (True, False). This option is only valid for top level graphs. get_subgraph(self, name) Given a subgraph's name the corresponding Subgraph instance will be returned. Returns a list of Subgraphs, a single Subgraph or None. get_subgraph_list(self) Returns the list of Subgraph instances in the graph. get_suppress_disconnected(val) Get if suppress disconnected is set. get_type(self) Get the graph's type, 'graph' or 'digraph'. #@nonl #@-node:EKR.20040518104556.16:getters... #@+node:EKR.20040518104556.17:setters... set(self, name, value) Set an attribute value by name. set_'name'(value) are defined for all the existing attributes. set_graph_parent(self, parent) Sets a graph and its elements to point the the parent. Any subgraph added to a parent graph receives a reference to the parent to access some common data. set_name(self, graph_name) Set the graph's name. set_simplify(self, simplify) Set whether to simplify or not. If True it will avoid displaying equal edges. set_strict(self, val) Set graph to 'strict' mode. This option is only valid for top level graphs. set_suppress_disconnected(val) Suppress disconnected nodes in the output graph. set_type(self, graph_type) Set the graph's type, 'graph' or 'digraph'. #@-node:EKR.20040518104556.17:setters... #@+node:EKR.20040518104556.18:toString to_string(self, indent='') Returns a string representation of the graph in dot language. #@nonl #@-node:EKR.20040518104556.18:toString #@-node:EKR.20040518104556.11:Graph(Common) #@+node:EKR.20040518104556.19:Node(Common) class Node(__builtin__.object, Common) A graph node. This class represents a graph's node with all its attributes. Data and attributes: __dict__ = dictionary for instance variables (if defined) __weakref__ = list of weak references to the object (if defined) attributes = ['showboxes', 'URL', 'fontcolor', 'fontsize', 'label', 'fontname', 'comment', 'root', 'toplabel', 'vertices', 'width', 'z', 'bottomlabel', 'distortion', 'fixedsize', 'group', 'height', 'orientation', 'pin', 'rects', ...] #@nonl #@+node:EKR.20040518104556.20:Node.__init__ node(name, attribute=value, ...) name: node's name All the attributes defined in the Graphviz dot language should be supported. __init__(self, name, **attrs) #@-node:EKR.20040518104556.20:Node.__init__ #@+node:EKR.20040518104556.21:get_name get_name(self) Get the node's name. #@nonl #@-node:EKR.20040518104556.21:get_name #@+node:EKR.20040518104556.22:set, set_x and set_name set(self, name, value) Set an attribute value by name. Given an attribute 'name' it will set its value to 'value'. set_'name'(value) is defined for all the existing attributes. set_name(self, node_name) Set the node's name. #@nonl #@-node:EKR.20040518104556.22:set, set_x and set_name #@+node:EKR.20040518104556.23:toString to_string(self) Returns a string representation of the node in dot language. #@nonl #@-node:EKR.20040518104556.23:toString #@-node:EKR.20040518104556.19:Node(Common) #@+node:EKR.20040518104556.24:Subgraph(Graph) class Subgraph(Graph) Methods: __init__(self, graph_name='subG', suppress_disconnected=False, **attrs) graph_name: the subgraph's name suppress_disconnected: False: removes from the subgraph any disconnected nodes. Attributes: attributes = ['Damping', 'bb', 'center', 'clusterrank', 'compound', 'concentrate', 'defaultdist', 'dim', 'fontpath', 'epsilon', 'layers', 'layersep', 'margin', 'maxiter', 'mclimit', 'mindist', 'pack', 'packmode', 'model', 'page', ...] #@nonl #@-node:EKR.20040518104556.24:Subgraph(Graph) #@+node:EKR.20040518104556.25:Functions #@+node:EKR.20040518104556.26:find_graphviz find_graphviz() Locate Graphviz's executables in the system. Attempts to locate graphviz's executables in a Unix system. It will look for 'dot', 'twopi' and 'neato' in all the directories specified in the PATH environment variable. It will return a dictionary containing the program names as keys and their paths as values. #@nonl #@-node:EKR.20040518104556.26:find_graphviz #@+node:EKR.20040518104556.27:graph_from_adjacency_matrix graph_from_adjacency_matrix(matrix, node_prefix='', directed=False) Creates a basic graph out of an adjacency matrix. The matrix has to be a list of rows of values representing an adjacency matrix. The values can be anything: bool, int, float, as long as they can evaluate to True or False. #@nonl #@-node:EKR.20040518104556.27:graph_from_adjacency_matrix #@+node:EKR.20040518104556.28:graph_from_edges graph_from_edges(edge_list, node_prefix='', directed=False) Creates a basic graph out of an edge list. The edge list has to be a list of tuples representing the nodes connected by the edge. The values can be anything: bool, int, float, str. If the graph is undirected by default, it is only calculated from one of the symmetric halves of the matrix. #@-node:EKR.20040518104556.28:graph_from_edges #@+node:EKR.20040518104556.29:graph_from_incidence_matrix graph_from_incidence_matrix(matrix, node_prefix='', directed=False) Creates a basic graph out of an incidence matrix. The matrix has to be a list of rows of values representing an incidence matrix. The values can be anything: bool, int, float, as long as they can evaluate to True or False. #@nonl #@-node:EKR.20040518104556.29:graph_from_incidence_matrix #@-node:EKR.20040518104556.25:Functions #@-node:EKR.20040518104556.2:pydot docs #@+node:EKR.20040518104556.30:@url http://www.research.att.com/sw/tools/graphviz/refs.html #@-node:EKR.20040518104556.30:@url http://www.research.att.com/sw/tools/graphviz/refs.html #@+node:EKR.20040518104556.31:@url http://dkbza.org/pydot/pydot.html #@-node:EKR.20040518104556.31:@url http://dkbza.org/pydot/pydot.html #@+node:EKR.20040518104556.33:Write an outline using Graphviz import leoGlobals as g import string try: import pydot except: s = "pydot must be installed" print s ; es(s,color="red") pydot = None #@<< code >> #@+node:EKR.20040518104556.34:<< code >> #@+others #@+node:EKR.20040518104556.35:addLeoNodesToGraph def addLeoNodesToGraph(p,graph,top=False): # Create p's vnode. thisNode = pydot.Node(name=vnodeRepr(p.v),label=vnodeLabel(p.v)) graph.add_node(thisNode) if p.hasChildren(): child = p.firstChild() childNode = addLeoNodesToGraph(child,graph) graph.add_node(childNode) edge2 = pydot.Edge(tnodeRepr(p.v.t),vnodeRepr(child.v)) graph.add_edge(edge2) while child.hasNext(): next = child.next() edge = pydot.Edge(vnodeRepr(child.v),vnodeRepr(next.v),dir="both") nextNode = addLeoNodesToGraph(next,graph) graph.add_node(nextNode) graph.add_edge(edge) child = next tnode = pydot.Node(name=tnodeRepr(p.v.t),shape="box",label=tnodeLabel(p.v.t)) edge1 = pydot.Edge(vnodeRepr(p.v),tnodeRepr(p.v.t),arrowhead="none") graph.add_edge(edge1) graph.add_node(tnode) if 0: # Confusing. if not top and p.v._parent: edge = pydot.Edge(vnodeRepr(p.v),vnodeRepr(p.v._parent), style="dotted",arrowhead="onormal") graph.add_edge(edge) if 0: # Marginally useful. for v in p.v.t.vnodeList: edge = pydot.Edge(tnodeRepr(p.v.t),vnodeRepr(v), style="dotted",arrowhead="onormal") graph.add_edge(edge) return thisNode #@nonl #@-node:EKR.20040518104556.35:addLeoNodesToGraph #@+node:EKR.20040518104556.36:tnode/vnodeLabel def tnodeLabel(t): return "t %d [%d]" % (id(t),len(t.vnodeList)) def vnodeLabel(v): return "v %d %s" % (id(v),v.t.headString) #@-node:EKR.20040518104556.36:tnode/vnodeLabel #@+node:EKR.20040518104556.37:tnode/vnodeRepr def dotId(s): """Convert s to a C id""" s2 = [ch for ch in s if ch in (string.letters + string.digits + '_')] return string.join(s2,'') def tnodeRepr(t): return "t_%d" % id(t) def vnodeRepr(v): return "v_%d_%s" % (id(v),dotId(v.headString())) #@nonl #@-node:EKR.20040518104556.37:tnode/vnodeRepr #@-others #@nonl #@-node:EKR.20040518104556.34:<< code >> #@nl if pydot: c = g.top() ; p = c.currentPosition() graph = pydot.Dot(simplify=True,ordering="out") root = g.findNodeInTree(p,"Root") addLeoNodesToGraph(root,graph,top=True) graph.write_jpeg(r'c:\prog\test\pydotOut.jpg',prog='dot') #@nonl #@+node:EKR.20040518104556.38:Root #@+node:EKR.20040518104556.39:clone #@+node:EKR.20040518104556.40:Child1 #@+node:EKR.20040518104556.41:GrandChild #@-node:EKR.20040518104556.41:GrandChild #@-node:EKR.20040518104556.40:Child1 #@+node:EKR.20040518104556.42:Child2 #@-node:EKR.20040518104556.42:Child2 #@-node:EKR.20040518104556.39:clone #@-node:EKR.20040518104556.38:Root #@-node:EKR.20040518104556.33:Write an outline using Graphviz #@-node:EKR.20040518104556:Create diagrams using Graphviz and pydot #@+node:EKR.20040502195524.33:Find script to change OnX to x in body (didn't quite work :-) # Script to change OnXXX to xxx in all body text. if 0: import leoGlobals as g c = g.top() ; v = c.currentVnode() v = v.threadNext() after = v.nodeAfterTree() count = 0 while v and v != after: while 1: s = v.bodyString() if not s: break i = s.find("c.On") if i == -1: break c = s[i+4].lower() s = s[:i] + 'c.' + c + s[i+5:] v.setBodyStringOrPane(s) count += 1 v = v.threadNext() print count #@nonl #@-node:EKR.20040502195524.33:Find script to change OnX to x in body (didn't quite work :-) #@+node:EKR.20040502195524.34:Find scripts to change OnX to x in headline if 0: # Script to change OnXxx to xxx in all headlines import leoGlobals as g c = g.top() ; v = c.currentVnode() after = v.nodeAfterTree() while v and v != after: h = v.headString() if g.match(h,0,"On") and len(h) > 2: h = h[2].lower() + h[3:] print h v.setHeadString(h) v = v.threadNext() # Script to change OnXXX to xxx in all body text. if 0: import leoGlobals as g c = g.top() ; v = c.currentVnode() after = v.nodeAfterTree() while v and v != after: s = v.bodyString() if s: i = s.find("def ") if i > -1: c = s[i+6].lower() s = s[:i] + "def " + c + s[i+7:] print v.headString() v.setBodyStringOrPane(s) v = v.threadNext() #@nonl #@-node:EKR.20040502195524.34:Find scripts to change OnX to x in headline #@+node:EKR.20040502195213.7:findDosFile import leoGlobals as g import fnmatch, os def findDosFile(pattern, dirname): """Check for crlf in files""" files = os.listdir(dirname) names = fnmatch.filter(files, pattern) for name in names: path = g.os_path_join(dirname, name) if g.os_path_isfile(path): bytes = open(path, 'rb').read() count = bytes.count('\r\n') if '\0' not in bytes and count: print "%4d %s" % (count,path) dir = "c:\prog\leoCvs\leo" print ; findDosFile("*",dir) #@nonl #@-node:EKR.20040502195213.7:findDosFile #@+node:EKR.20040502195213:Get statistics using dis module # routines to gather static statistics about opcodes based on dis module. import leoGlobals as g import compiler import dis import os import string import sys import types #@+others #@+node:EKR.20040502195213.1:go def go(): dir = "c:/prog/leoCVS/leo/" modules = getModules(dir) stats = [0] * 256 try: # Importing these might start leo itself and hang idle. modules.remove("leo") modules.remove("openLeo") modules.remove("openEkr") modules.remove("setup") except: pass # print modules for m in modules: try: print "module:", m exec("import " + m) a = eval(m) any(a,stats) except: import traceback ; traceback.print_exc() print "----- no matching class in", m g.print_stats(stats) #@nonl #@-node:EKR.20040502195213.1:go #@+node:EKR.20040502195213.2:getFiles def getFiles (dir): # Generate the list of modules. allFiles = os.listdir(dir) files = [] for f in allFiles: head,tail = g.os_path_split(f) root,ext = g.os_path_splitext(tail) if ext==".py": files.append(g.os_path_join(dir,f)) return files #@nonl #@-node:EKR.20040502195213.2:getFiles #@+node:EKR.20040502195213.3:getModules def getModules (dir): """Return the list of Python files in dir.""" files = [] try: allFiles = os.listdir(dir) for f in allFiles: head,tail = g.os_path_split(f) fn,ext = g.os_path_splitext(tail) if ext==".py": files.append(fn) except: pass return files #@nonl #@-node:EKR.20040502195213.3:getModules #@+node:EKR.20040502195213.4:any def any(x,stats,printName = 0): # based on dis.dis() """Gathers statistics for classes, methods, functions, or code.""" if not x: return if type(x) is types.InstanceType: x = x.__class__ if hasattr(x, 'im_func'): x = x.im_func if hasattr(x, 'func_code'): x = x.func_code if hasattr(x, '__dict__'): items = x.__dict__.items() items.sort() for name, x1 in items: if type(x1) in (types.MethodType, types.FunctionType, types.CodeType): if printName: print name try: any(x1,stats) except TypeError, msg: print "Sorry:", msg elif hasattr(x, 'co_code'): code(x,stats) else: raise TypeError, \ "don't know how to disassemble %s objects" % \ type(x).__name__ #@nonl #@-node:EKR.20040502195213.4:any #@+node:EKR.20040502195213.5:code def code (co, stats): """Gather static count statistics for a code object.""" codeList = co.co_code # Count the number of occurances of each opcode. i = 0 ; n = len(codeList) while i < n: c = codeList[i] op = ord(c) stats[op] += 1 i = i+1 if op >= dis.HAVE_ARGUMENT: i = i+2 #@nonl #@-node:EKR.20040502195213.5:code #@+node:EKR.20040502195213.6:print_stats def print_stats (stats): stats2 = [] ; total = 0 for i in xrange(0,256): if stats[i] > 0: stats2.append((stats[i],i)) total += stats[i] stats2.sort() stats2.reverse() for stat,i in stats2: print string.rjust(repr(stat),6), dis.opname[i] print "total", total #@nonl #@-node:EKR.20040502195213.6:print_stats #@-others #@nonl #@-node:EKR.20040502195213:Get statistics using dis module #@+node:EKR.20040517143706:Linux install script #@@first """ A simple script to install Leo on Linux. Contributed by David McNab """ import commands,os,sys # commands module is for Unix only. # We must be root to use this script. if os.getuid() != 0: print "You need to run this install script as root" sys.exit(1) # Create /usr/lib/leo and copy all files there. print "***** Installing Leo to /usr/lib/leo..." commands.getoutput("mkdir -p /usr/lib/leo") commands.getoutput("cp -rp * /usr/lib/leo") # Create user's 'leo' command script into /usr/bin/leo print "***** Creating Leo startup script -> /usr/bin/leo" fd = open("/usr/bin/leo", "w") fd.write("""#!/usr/bin/python import commands,sys files = " ".join(sys.argv[1:]) print commands.getoutput("python /usr/lib/leo/leo.py %s" % files) """) fd.close() commands.getoutput("chmod 755 /usr/bin/leo") print "***** Leo installed successfully - type 'leo filename.leo' to use it." #@-node:EKR.20040517143706:Linux install script #@+node:EKR.20040502195524.17:Script to find and replace all functions in leoGlobals.py import leoGlobals as g import string c = g.top() #@+others #@+node:EKR.20040502195524.19:findFunctionsInTree def findFunctionsInTree(p): nameList = [] for p in p.self_and_subtree_iter(): names = findDefs(p.bodyString()) if names: for name in names: if name not in nameList: nameList.append(name) return nameList #@nonl #@-node:EKR.20040502195524.19:findFunctionsInTree #@+node:EKR.20040502195524.20:findDefs def findDefs(body): lines = body.split('\n') names = [] for s in lines: i = g.skip_ws(s,0) if g.match(s,i,"class"): return [] # The classes are defined in a single node. if g.match(s,i,"def"): i = g.skip_ws(s,i+3) j = g.skip_c_id(s,i) if j > i: name = s[i:j] if g.match(name,0,"__init__"): return [] # Disallow other class methods. names.append(name) return names #@nonl #@-node:EKR.20040502195524.20:findDefs #@+node:EKR.20040502195524.21:prependNamesInTree def prependNamesInTree(p,nameList,prefix,replace=False): c = p.c assert(len(prefix) > 0) ch1 = string.letters + '_' ch2 = string.letters + string.digits + '_' def_s = "def " ; def_n = len(def_s) prefix_n = len(prefix) total = 0 c.beginUpdate() for p in p.self_and_subtree_iter(): count = 0 ; s = p.bodyString() printFlag = False if s: for name in nameList: i = 0 ; n = len(name) while 1: #@ << look for name followed by '(' >> #@+node:EKR.20040502195524.22:<< look for name followed by '(' >> i = s.find(name,i) if i == -1: break elif g.match(s,i-1,'.'): i += n # Already an attribute. elif g.match(s,i-prefix_n,prefix): i += n # Already preceded by the prefix. elif g.match(s,i-def_n,def_s): i += n # preceded by "def" elif i > 0 and s[i-1] in ch1: i += n # Not a word match. elif i+n < len(s) and s[i+n] in ch2: i += n # Not a word match. else: j = i + n j = g.skip_ws(s,j) if j >= len(s) or s[j] != '(': i += n else: # Replace name by prefix+name s = s[:i] + prefix + name + s[i+n:] i += n ; count += 1 # g.es('.',newline=False) if 1: if not printFlag: printFlag = True # print p.headString() print g.get_line(s,i-n) #@nonl #@-node:EKR.20040502195524.22:<< look for name followed by '(' >> #@nl if count and replace: if 0: #@ << print before and after >> #@+node:EKR.20040502195524.23:<< print before and after >> print "-"*10,count,p.headString() print "before..." print p.bodyString() print "-"*10,"after..." print s #@nonl #@-node:EKR.20040502195524.23:<< print before and after >> #@nl p.setBodyStringOrPane(s) p.setDirty() g.es("%3d %s" % (count,p.headString())) total += count c.endUpdate() return total #@nonl #@-node:EKR.20040502195524.21:prependNamesInTree #@-others if 1: #@ << set nameList to the list of functions in leoGlobals.py >> #@+node:EKR.20040502195524.18:<< set nameList to the list of functions in leoGlobals.py >> nameList = ( 'alert', 'angleBrackets', 'appendToList', 'callerName', 'CheckVersion', 'choose', 'clearAllIvars', 'clear_stats', 'collectGarbage', 'computeLeadingWhitespace', 'computeWidth', 'computeWindowTitle', 'createTopologyList', 'create_temp_name', 'disableIdleTimeHook', 'doHook', 'dump', 'ecnl', 'ecnls', 'enableIdleTimeHook', 'enl', 'ensure_extension', 'es', 'esDiffTime', 'es_error', 'es_event_exception', 'es_exception', 'escaped', 'executeScript', 'file_date', 'findNodeAnywhere', 'findTopLevelNode', 'findNodeInTree', 'findReference', 'find_line_start', 'find_on_line', 'flattenList', 'funcToMethod', 'getBaseDirectory', 'getOutputNewline', 'getTime', 'get_Sherlock_args', 'get_directives_dict', 'get_leading_ws', 'get_line', 'get_line_after', 'getpreferredencoding', 'idleTimeHookHandler', 'importFromPath', 'initScriptFind', 'init_sherlock', 'init_trace', 'isUnicode', 'isValidEncoding', 'is_c_id', 'is_nl', 'is_special', 'is_ws', 'is_ws_or_nl', 'joinLines', 'listToString', 'makeAllNonExistentDirectories', 'makeDict', 'match', 'match_c_word', 'match_ignoring_case', 'match_word', 'module_date', 'openWithFileName', 'optimizeLeadingWhitespace', 'os_path_abspath', 'os_path_basename', 'os_path_dirname', 'os_path_exists', 'os_path_getmtime', 'os_path_isabs', 'os_path_isdir', 'os_path_isfile', 'os_path_join', 'os_path_norm', 'os_path_normcase', 'os_path_normpath', 'os_path_split', 'os_path_splitext', 'pause', 'plugin_date', 'plugin_signon', 'printDiffTime', 'printGc', 'printGcRefs', 'printGlobals', 'printLeoModules', 'print_bindings', 'print_stats', 'readlineForceUnixNewline', 'redirectStderr', 'redirectStdout', 'removeLeadingWhitespace', 'removeTrailingWs', 'reportBadChars', 'restoreStderr', 'restoreStdout', 'sanitize_filename', 'scanAtEncodingDirective', 'scanAtFileOptions', 'scanAtLineendingDirective', 'scanAtPagewidthDirective', 'scanAtRootOptions', 'scanAtTabwidthDirective', 'scanDirectives', 'scanError', 'scanf', 'set_delims_from_language', 'set_delims_from_string', 'set_language', 'shortFileName', 'skip_blank_lines', 'skip_block_comment', 'skip_braces', 'skip_c_id', 'skip_heredoc_string', 'skip_leading_ws', 'skip_leading_ws_with_indent', 'skip_line', 'skip_long', 'skip_matching_delims', 'skip_nl', 'skip_non_ws', 'skip_parens', 'skip_pascal_begin_end', 'skip_pascal_block_comment', 'skip_pascal_braces', 'skip_pascal_string', 'skip_php_braces', 'skip_pp_directive', 'skip_pp_if', 'skip_pp_part', 'skip_python_string', 'skip_string', 'skip_to_char', 'skip_to_end_of_line', 'skip_to_semicolon', 'skip_typedef', 'skip_ws', 'skip_ws_and_nl', 'splitLines', 'stat', 'stdErrIsRedirected', 'stdOutIsRedirected', 'toEncodedString', 'toUnicode', 'toUnicodeFileEncoding', 'top', 'trace', 'trace_tag', 'update_file_if_changed', 'utils_rename', 'windows', 'wrap_lines') #@nonl #@-node:EKR.20040502195524.18:<< set nameList to the list of functions in leoGlobals.py >> #@nl else: p = g.findNodeAnywhere("@file leoGlobals.py") nameList = findFunctionsInTree(p) nameList.sort() ; g.enl() for name in nameList: g.es("'%s'," % name) s = "%d functions in leoGlobals.py" % len(nameList) print s ; g.es(s) if 0: p = g.findTopLevelNode(c,"Code") g.enl() ; g.enl() count = prependNamesInTree(p,nameList,"g.",replace=True) # Just prints if replace==False. s = "%d --- done --- " % count print s ; g.es(s) #@nonl #@-node:EKR.20040502195524.17:Script to find and replace all functions in leoGlobals.py #@-node:EKR.20040502195524.16:Other scripts #@+node:EKR.20040502195524.35:Recursive import script # An example of running this script: import leoGlobals as g #@+others #@+node:EKR.20040502195524.36:importFiles def importFiles (dir,type=None,kind="@file",recursive=False): c = g.top() ; v = c.currentVnode() # Check the params. if kind != "@file" and kind != "@root": g.es("kind must be @file or @root: " + kind) return if not g.os_path_exists(dir): g.es("directory does not exist: " + dir) return c.beginUpdate() root = createLastChildOf(v,"imported files") try: importDir (dir,type,kind,recursive,root) root.contract() except: g.es_exception() c.endUpdate() #@-node:EKR.20040502195524.36:importFiles #@+node:EKR.20040502195524.37:importDir def importDir (dir,types,kind,recursive,root): c = g.top() # Get the commander. g.es("dir: " + dir,color="blue") try: files = os.listdir(dir) files2 = [] ; dirs =[] for f in files: path = g.os_path_join(dir,f) if g.os_path_isfile(path): name, ext = g.os_path_splitext(f) if not types or ext in types: files2.append(path) elif recursive: dirs.append(path) if len(files2) > 0 or len(dirs) > 0: child = createLastChildOf(root,dir) c.selectVnode(child) if len(files2) > 0: c.importCommands.importFilesCommand(files2,kind) if len(dirs) > 0: dirs.sort() for dir in dirs: importDir(dir,types,kind,recursive,child) except: g.es("exception in importFiles script") g.es_exception() #@-node:EKR.20040502195524.37:importDir #@+node:EKR.20040502195524.38:createLastChildOf def createLastChildOf (v,headline): child = v.insertAsLastChild() child.initHeadString(headline) return child #@-node:EKR.20040502195524.38:createLastChildOf #@-others types = (".py",) #,".c",".html",".txt") dir = "c:/Zope-2.6.2-src/lib/python" dir = "c:/Zope-2.6.2-src/lib/Components" importFiles(dir,types,recursive=True) g.es("done",color="blue") #@-node:EKR.20040502195524.35:Recursive import script #@+node:EKR.20040502195524.39:Testing scripts #@+node:EKR.20040502195524.40:Script to clean unused tnodeLists import leoGlobals as g c = g.top() v = c.rootVnode() while v: # 12/13/03: Empty tnodeLists are not errors because they never get written to the .leo file. # New in 4.2: tnode list is in tnode. if hasattr(v.t,"tnodeList") and len(v.t.tnodeList) > 0 and not v.isAnyAtFileNode(): g.es("deleting tnodeList for ",v,color="blue") delattr(v.t,"tnodeList") c.setChanged(True) v = v.threadNext() g.es("tnodeList script complete") #@-node:EKR.20040502195524.40:Script to clean unused tnodeLists #@+node:EKR.20040502195524.41:Script to check topology of all clones import leoGlobals as g g.checkTopologyOfAllClones() #@-node:EKR.20040502195524.41:Script to check topology of all clones #@+node:EKR.20040502195524.42:Scripts for checking clones if 0: checkForMismatchedJoinedNodes() print g.createTopologyList(c=g.top(),root=g.top().currentVnode().parent(),useHeadlines=False) checkTopologiesOfLinkedNodes() checkForPossiblyBrokenLinks() #@nonl #@+node:EKR.20040502195524.43:checkForMismatchedJoinedNodes def checkForMismatchedJoinedNodes (c=None): """Checks outline for possible broken join lists""" if not c: c = g.top() d = {} # Keys are tnodes, values are headlines. v = c.rootVnode() while v: aTuple = d.get(v.t) if aTuple: head,body = aTuple if v.headString()!= head: g.es("headline mismatch in joined nodes",v) if v.bodyString()!= body: g.es("body mismatch in joined nodes",v) else: d[v.t] = (v.headString(),v.bodyString()) v = v.threadNext() g.es("end of checkForMismatchedJoinedNodes") #@-node:EKR.20040502195524.43:checkForMismatchedJoinedNodes #@+node:EKR.20040502195524.44:checkForPossiblyBrokenLinks def checkForPossiblyBrokenLinks (c=None): """Checks outline for possible broken join lists""" if not c: c = g.top() d = {} # Keys are headlines, values are (tnodes,parent) tuples v = c.rootVnode() while v: h = v.headString() parent = v.parent() aTuple = d.get(h) if aTuple: t,p = aTuple if (t != v.t and p and parent and p.t != parent.t and p.headString() == parent.headString() and len(h) > 1 and h != "NewHeadline"): g.es("different tnodes with same headline and parent headlines: " + v.headString()) else: d[h] = (v.t,parent) v = v.threadNext() #@-node:EKR.20040502195524.44:checkForPossiblyBrokenLinks #@+node:EKR.20040502195524.45:checkTopologiesOfLinkedNodes def checkTopologiesOfLinkedNodes(c=None): if not c: c = g.top() d = {} # Keys are tnodes, values are topology lists. v = c.rootVnode() count = 0 while v: top1 = g.createTopologyList(c=c,root=v) top2 = d.get(v.t) if top2: count += 1 if top1 != top1: g.es("mismatched topologies for two vnodes with the same tnode!",v) else: d[v.t] = top1 v = v.threadNext() g.es("end of checkTopologiesOfLinkedNodes. Checked %d nodes: " % count) #@nonl #@-node:EKR.20040502195524.45:checkTopologiesOfLinkedNodes #@+node:EKR.20040502195524.46:checkLinksOfNodesWithSameTopologies (to do) #@+at #@nonl # Nodes with the same topologies should be joined PROVIDED: # - Topologies are non-trivial. # - Topologies include tnodes somehow. # - Topologies include headlines somehow. #@-at #@-node:EKR.20040502195524.46:checkLinksOfNodesWithSameTopologies (to do) #@-node:EKR.20040502195524.42:Scripts for checking clones #@-node:EKR.20040502195524.39:Testing scripts #@-others #@nonl #@-node:EKR.20040502195524:@thin ../scripts/leoScripts.txt #@-leo