h
yield parent_gnx, gnx, h, b
for xch in xv[1:]:
yield from viter(gnx, xch)
Variables heads, bodies and seen are defined in the parent scope. Heads and bodies are dicts, and seen is a set. (While I was writing this I'vre realized there was a bug in pasteAsTemplate. If outside clones have children, their children used to be duplicated. The fix was to initialize `seen` set to `outside` set.)
Generator yields tuples of four elements (parent_gnx, child_gnx, headline, body). Descendant nodes are iterated only once. This tuple allows us to create or use already existent nodes and link them. This is done in the `do_paste` function:
def do_paste(vpar, index):
'''
pastes a new node as a child of vpar at given index
'''
vpargnx = vpar.gnx
# the first node is inserted at the given index
# and the rest are just appended at parents children
# to achieve this we first create a generator object
The rest of code in the c.pasteAsTemplate is just for making this operation undoable.
While writing this explanations I've discovered a few bugs and fixed them. The latest version is 027e147eb.
Now I would like to point out some problems I encountered while writing this code and suggestions how to improve Leo. First of all I've realized that running experiments during development can demage the outline. I've learned to postpone all v-node manipulations as late as possilbe. Using this aproach has lead me to more testable code as well. For example: it would be natural to use FastRead to read clipboard, but it was almost imposible to reuse anything from this class, because it messes up with gnxDict. FastRead is too tied to the rest of Leo. Therefore I had to reimplement this functionallity from scratch. FastRead should at least have a method to turn xml into ElementTree.Element, and a generator to generate tuples (level, gnx, h, b, ua) or (parent_gnx, gnx, h, b, ua). If it had such methods, I would certainly use them in this command. Furthermore this methods would be easy to test and they would be completely decoupled from anything else in Leo. They would provide functionallity without messing any other part of Leo. This would make them easy to use without fear that they could change something behind your back. Let's just remember a bug with the empty outline due to the gnx collisions. Segundo Bob has written a great issue report, provided scripts to reproduce the bug and yet we couldn't find the bug for several years. Unable to find the bug I was very certain that this bug was caused by some low level OS thing outside Python. But the bug was just in messed up gnxDict which FastRead relies on.
When I looked at FastAtRead's code recently I was thouroughly disappointed with its current shape. For the testing purpose, some new kwargs are added which again makes this code harder to read, harder to understand, and also slower than it used to be.
I see here the fundamentaly wrong decesion to change inner code of methods in order to make some tests against it. This kind of tests are useless because they test not the production code but the different one. There are many places in Leo that have `if g.unitTesting` guard. At some places they just add some logging but there are places where this guard is not so benign, where it changes the actual meaning of the method. I remember how the experimental code I wrote before, whch was the inspiration for FastAtRead, used to be testable and decoupled from everything else inside Leo. It doesn't have to be this way.
For example viter generator function yields tuples of strings. It is very easy to test it, to debug, to print the results and it won't spoil anything inside Leo ivars. Its usage is harmless. I think both FastRead and FastAtRead should do the same. Instead of actually creating vnodes and manipulating them, they should generate necessary data for node creation and linkage. Top level methods like readWithElementTree should use this generator methods to actually create vnodes. FastAtRead.read_into_root should also use some generator of tuples consisting of simple data types (strings, ints, booleans) and just use those tuples to actually create and link vnodes. That way it won't be necessary to add any kwargs for testing. It would be trivial to test these generators and compare the values from those tuples with expected ones. And if the generators work correctly than we can be pretty sure that top level functions will work correctly too.
Again while writing this I've just realized that I forgot about unknown attributes in paste-as-template.
Vitalije