The following script ensures that every non-empty body text ends with exactly one newline. There are severl subtlties in the script:

This script may possibly form the basis for automatic regularization of whitespace. However, it remains to be seen whether this is really needed to keep cvs happy:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet ekr_stylesheet?>
<leo_header file_format="1" tnodes="3" max_tnode_index="3"/>
<v t="ekr.20060808103945" a="V"><vh>Set trailing ws script</vh>
<v t="ekr.20060808103945.1"><vh>pass1</vh></v>
<v t="ekr.20060808103945.2"><vh>pass2</vh></v>
<t tx="ekr.20060808103945">'''This script quickly ends all nodes in the selected tree with exactly one
newline and marks all @thin/@file nodes dirty if any of their descendents have
been changed.'''


    p = c.currentPosition()
    pass1(p) # Make the changes and do p.v.t.setDirty for all changed nodes p.
    pass2() # Quickly set all @thin/@file nodes dirty if any of their descendents are dirty.
<t tx="ekr.20060808103945.1">def pass1(root):

    '''Remove trailing newlines from all nodes.'''

    count = 0 ; seen = {}
    for p in root.self_and_subtree_iter():
        if seen.get(p.v.t): continue
        s = p.bodyString()
        if s:
            s2 = s.rstrip() + '\n'
            if s2 != s:
                s2 = g.toUnicode(s2,,reportErrors=True)
                p.v.t.bodyString = s2
                seen [p.v.t] = True
                p.v.t.setDirty() # Just set the bit: do **not** redraw!
                count += 1

    g.es_print("pass 1: %d nodes converted" % count)
<t tx="ekr.20060808103945.2">def pass2():

    '''Quickly mark all changed @file nodes dirty.'''

    count = 0

    # Important: we must look at **all** nodes because of clones.
    for p in c.allNodes_iter():
        if p.isAnyAtFileNode():
            root = p.copy()
            for p2 in root.self_and_subtree_iter():
                if p2.v.t.isDirty():
                    count += 1

    g.es_print("pass 2: %d @file/@thin nodes set dirty" % count)