This might not be the best possible name but it reflects an idea that came 
from Seth Jonson in another thread.

The idea is to clone all those nodes that are present in the outline 
outside copied tree. All nodes that are located only under the copied tree 
should not be cloned unless they have clones under the copied tree. In 
essence this is just what paste-node command does plus it keeps identity of 
all nodes that have clones elsewhere in the outline outside the copied tree.

Here is the code:

from xml.etree import ElementTree as ET
import leo.core.leoNodes as leoNodes

c.frame.log.clearTab('Log')
def paste_as_template(p):
    def newgnx():
        ni = g.app.nodeIndices
        t_s = ni.update()
        return f"{ni.userId}.{t_s}.{ni.lastIndex:d}"
    def skip_root(v):
        if v.gnx != root_gnx:
            yield v
            for ch in v.children:
                yield from skip_root(ch)
    def translate_gnx(gnx):
        if gnx in outside:
            return gnx
        return newgnx()
    gnx2v = c.fileCommands.gnxDict
    def getv(gnx):
        v = gnx2v.get(gnx)
        if v is None:
            return leoNodes.VNode(c, gnx), True
        return v, False
    def viter(pargnx, xv):
        chgnx = xv.attrib.get('t')
        b = bodies[chgnx]
        gnx = translation.get(chgnx)
        if gnx in seen:
            yield pargnx, gnx, heads[gnx], b
        else:
            seen.add(gnx)
            h = xv[0].text
            heads[gnx] = h
            yield pargnx, gnx, h, b
            for xch in xv[1:]:
                yield from viter(gnx, xch)
    def dumptree(): # just for debuging
        levs = {'':-1}
        for pgnx, gnx, h, b in viter('', xvnodes[0]):
            lev = levs[pgnx] + 1
            levs[gnx] = lev
            g.es(f'{"----" * lev}[{gnx}]{h}')
    def do_paste(vpar, index):
        vpargnx = vpar.gnx
        rows = viter(vpargnx, xvnodes[0])
        pgnx, gnx, h, b = next(rows)
        v, _ = getv(gnx)
        v.h = h
        v.b = b
        vpar.children.insert(index, v)
        v.parents.append(vpar)
        pasted = v
        for pgnx, gnx, h, b in rows:
            v, isNew = getv(gnx)
            if isNew:
                v.h = h
                v.b = b
            vpar = getv(pgnx)[0]
            vpar.children.append(v)
            v.parents.append(vpar)
        return pasted
    def undoHelper():
        v = vpar.children.pop(index)
        v.parents.remove(vpar)
        c.redraw(bunch.p)
    def redoHelper():
        vpar.children.insert(index, pasted)
        pasted.parents.append(vpar)
        c.redraw(newp)
    xroot = ET.fromstring(g.app.gui.getTextFromClipboard())
    #xroot = ET.fromstring(clipboard_text())
    xvnodes = xroot.find('vnodes')
    xtnodes = xroot.find('tnodes')
    bodies = {x.attrib['tx']:x.text for x in xtnodes}
    root_gnx = xvnodes[0].attrib.get('t')
    outside = {x.gnx:x for x in skip_root(c.hiddenRootNode)}
    translation = {x:translate_gnx(x) for x in bodies.keys()}
    seen = set()
    heads = {}
    dumptree()
    bunch = c.undoer.createCommonBunch(p)
    if p.isExpanded():
        vpar = p.v
        index = 0
        parStack = p.stack + [(p.v, p._childIndex)]
    else:
        parStack = p.stack
        vpar = p.stack[-1][0] if p.stack else c.hiddenRootNode
        index = p._childIndex + 1
    seen.clear()
    pasted = do_paste(vpar, index)
    newp = leoNodes.Position(pasted, index, parStack)
    bunch.undoHelper = undoHelper
    bunch.redoHelper = redoHelper
    bunch.undoType = 'paste-retaining-outside-clones'
    c.undoer.pushBead(bunch)
    c.redraw(newp)
paste_as_template(p)

The command is undoable.

Vitalije

-- 
You received this message because you are subscribed to the Google Groups 
"leo-editor" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/leo-editor/14528440-f602-4a39-8915-0ab140fd73fa%40googlegroups.com.

Reply via email to