def completion_logic(input, options = {})
      o = {}
      options = options.dup

      o[k = :enabled_as] = options.delete(k)

      raise ArgumentError, "Unknown option(s): #{options.inspect}" if not options.empty?
      raise ArgumentError, "options[:enabled_as] must be given" if not o[:enabled_as]

      # Check if this input is related to us.
      if not mat = input.match(/\A#{o[:enabled_as]}\.((?:[^.].*)|)\z/)
        return nil
      end

      lookup = mat[1]

      # Parse lookup string into node name and prefix.
      global_name, prefix = if mat = lookup.match(/\A(?:([^.]*)|(.+)\.(.*?))\z/)
        if mat[1]
          # "something".
          ["", mat[1]]
        else
          # "something.other", "something.other.other.".
          [mat[2], mat[3]]
        end
      else
        # Handle no match just in case.
        ["", ""]
      end

      base = if global_name == ""
        # Base is root.
        nil
      else
        # Find a named base node. If not found, return no candidates right away.
        find_node(global_name) or return []
      end
      
      # Select sub-nodes.
      candidates = children_of(base).select do |node|
        # Select those matching `prefix`.
        node.name.to_s.index(prefix) == 0
      end.map do |node|
        # Provide 1+ candidates per item.
        case node
        when Node::Group
          # A neat trick to prevent IRB from appending a " " after group name.
          [node.name, "#{node.name}."]
        else
          [node.name]
        end.map(&:to_s)
      end.flatten(1).map do |s|
        # Convert to final names.
        [
          "#{o[:enabled_as]}.",
          ("#{global_name}." if global_name != ""),
          s,
        ].compact.join
      end

      candidates
    end
def completion_logic(input, options = {})
      o = {}
      options = options.dup

      o[k = :enabled_as] = options.delete(k)

      raise ArgumentError, "Unknown option(s): #{options.inspect}" if not options.empty?
      raise ArgumentError, "options[:enabled_as] must be given" if not o[:enabled_as]

      # Check if this input is related to us.
      if not mat = input.match(/\A#{o[:enabled_as]}\.((?:[^.].*)|)\z/)
        return nil
      end

      lookup = mat[1]

      # Parse lookup string into node name and prefix.
      global_name, prefix = if mat = lookup.match(/\A(?:([^.]*)|(.+)\.(.*?))\z/)
        if mat[1]
          # "something".
          ["", mat[1]]
        else
          # "something.other", "something.other.other.".
          [mat[2], mat[3]]
        end
      else
        # Handle no match just in case.
        ["", ""]
      end

      base = if global_name == ""
        # Base is root.
        nil
      else
        # Find a named base node. If not found, return no candidates right away.
        find_node(global_name) or return []
      end
      
      # Select sub-nodes.
      candidates = children_of(base).select do |node|
        # Select those matching `prefix`.
        node.name.to_s.index(prefix) == 0
      end.map do |node|
        # Provide 1+ candidates per item.
        case node
        when Node::Group
          # A neat trick to prevent IRB from appending a " " after group name.
          [node.name, "#{node.name}."]
        else
          [node.name]
        end.map(&:to_s)
      end.flatten(1).map do |s|
        # Convert to final names.
        [
          "#{o[:enabled_as]}.",
          ("#{global_name}." if global_name != ""),
          s,
        ].compact.join
      end

      candidates
    end
Perform logic needed to do IRB completion. Returns Array if completion is handled successfully, <tt>nil</tt>
 if input is not related to HackTree.

   completion_logic("c.he", :enabled_as => :c)    # => ["c.hello"]