Remove from view all nodes that don't contain the every word in the search string in their headline, body, or in those of their children. Words in the search string are comma separated.

For example, if your tree looks like this:

red figs
  foo bar fred
foo bar
  pumpkin pie
  foo bar baz
baz foo
  blue moon

And you search for "foo,baz", you get:

foo bar
  foo bar baz
baz foo

The script uses two buttons.

  1. Find by Elim:

    from qtGui import leoQtTree
    
    def should_display(self, p):
        c = self.c
    
        # If we aren't filtering any nodes, just show them all
        if not hasattr(c, "nodes_to_show") or c.nodes_to_show is None:
            return True
    
        if p in c.nodes_to_show:
            return True
    
        for child in p.children_iter():
            if self.should_display(child):
                return True
    
        return False
    leoQtTree.should_display = should_display
    
    def drawTree (self,p,parent_item=None):
        # Don't draw the tree if it's filtered out due to find by elimination
        should_display = self.should_display(p)
        if not should_display:
            return
    
        # Draw the (visible) parent node.
        item = self.drawNode(p,parent_item)
    
        # Draw all the visible children.
        self.drawChildren(p,parent_item=item)
    leoQtTree.drawTree = drawTree
    
    
    import leo.scripts.leoFindScript as leoFindScript
    
    def getInput(event=None):
        stateName = 'get-input'
        k = c.k
        state = k.getState(stateName)
    
        if state == 0:
            k.setLabelBlue('Words to find (space separated): ',protect=True)
            k.getArg(event,stateName,1,getInput)
        else:
            k.clearState()
            find_by_elimination(k.arg.split(','))
    getInput()
    
    def find_by_elimination(words_to_find):
        g.es("searching...")
    
        c.nodes_to_show = []
    
        def find_all_nodes(word, check_body):
            return [result[0] for result in
                    leoFindScript.findAll(c, word, bodyFlag=check_body)]
    
        # Build a list of matching nodes for each word
        matches_for_each_word = []
        for word in words_to_find:
            matches_for_curr_word = []
            for check_body in [True, False]:
                matches_for_curr_word += find_all_nodes(word, check_body)
            matches_for_each_word += [matches_for_curr_word]
    
        if len(matches_for_each_word) == 1:
            c.nodes_to_show = matches_for_each_word[0]
        elif len(matches_for_each_word) > 1:
            # If a node appears in every list, it should be displayed
            for node in matches_for_each_word[0]:
                in_all = True
                for node_list in matches_for_each_word[1:]:
                    if node not in node_list:
                        in_all = False
                        break
                if in_all:
                    c.nodes_to_show.append(node)
    
        # Expand all the nodes if there aren't a lot of matches
        if len(c.nodes_to_show) < 40:
            for p in c.nodes_to_show:
                p.expand()
                for parent in p.parents_iter():
                    parent.expand()
    
        g.es("done searching")
    
        c.redraw()
    
  2. Restore nodes:

    c.nodes_to_show = None
    c.redraw()