Writing the cffm and cfam commands was snap using c.cloneFindByPredicate, a powerful new addition to Leo. Here is the entire code for the new commands:
@cmd('clone-find-all-marked') @cmd('cfam') def cloneFindAllMarked(self, event=None): '''The clone-find-all-marked command.''' self.cloneFindMarkedHelper(flatten=False) @cmd('clone-find-all-flattened-marked') @cmd('cffm') def cloneFindAllFlattenedMarked(self, event=None): '''The clone-find-all-flattened-marked command.''' self.cloneFindMarkedHelper(flatten=True) def cloneFindMarkedHelper(self, flatten): '''Helper for clone-find-marked commands.''' def isMarked(p): return p.isMarked() self.cloneFindByPredicate( generator = self.all_unique_positions, predicate = isMarked, flatten = flatten, undoType = 'clone-find-marked', ) It's hard to imagine anything simpler. *Important*: the predicate could filter on an attribute or *combination *of attributes. For example, the predicate could return p has attributes A and B but *not* attribute C. Instantly we have full database query capabilities. If we then hoist the resulting node we see *all and only* those nodes satisfying the query. Here is c.findNodeByPredicate. *Important*: Rev c8a3581c9b corrects a serious blunder in c.cloneFindByPredicate. Don't use previous versions! def cloneFindByPredicate(self, generator, # The generator used to traverse the tree. predicate, # A function of one argument p, returning True # if p should be included in the results. flatten=False, # True: Put all matches at the top level. undoType=None, # The undo name, shown in the Edit:Undo menu. # The default is 'clone-find-predicate' ): ''' Traverse the tree given using the generator, cloning all positions for which predicate(p) is True. Undoably move all clones to a new node, created as the last top-level node. Arguments: generator, The generator used to traverse the tree. predicate, A function of one argument p returning true if p should be included. flatten=False, True: Move all node to be parents of the root node. undo_type=None, The undo/redo name shown in the Edit:Undo menu. The default is 'clone-find-predicate' ''' c = self u, undoType = c.undoer, undoType or 'clone-find-predicate' clones, seen = [], set(), for p in generator(): if predicate(p) and p.v not in seen: if flatten: seen.add(p.v) else: for p2 in p.self_and_subtree(): seen.add(p2.v) clones.append(p.copy()) if clones: undoData = u.beforeInsertNode(c.p) root = c.createCloneFindPredicateRoot(flatten, undoType) # This was botched in previous versions. # The result was low-level vnode failures. for p in clones: clone = p.clone() clone.moveToLastChildOf(root) u.afterInsertNode(root, undoType, undoData, dirtyVnodeList=[]) c.selectPosition(root) c.setChanged(True) c.redraw() else: g.es_print('not found:', undoType) Imo, this is the dawn of a new era in Leo's database capabilities. Edward -- 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 leo-editor+unsubscr...@googlegroups.com. To post to this group, send email to leo-editor@googlegroups.com. Visit this group at https://groups.google.com/group/leo-editor. For more options, visit https://groups.google.com/d/optout.