void (int[] offsets, @NotNull LighterAST tree, @NotNull BiConsumer<? super LighterASTTokenNode, ? super Integer> consumer) { if (offsets.length == 0) return; int[] sortedOffsets = offsets.clone(); Arrays.sort(sortedOffsets); new RecursiveLighterASTNodeWalkingVisitor(tree) { int nextIndex = 0; int nextOffset = sortedOffsets[0]; @Override public void visitNode(@NotNull LighterASTNode element) { if (containsNextOffset(element)) { super.visitNode(element); } } @Override public void visitTokenNode(@NotNull LighterASTTokenNode node) { if (containsNextOffset(node)) { consumer.accept(node, nextOffset); while (containsNextOffset(node)) { advanceOffset(); } } } private boolean containsNextOffset(@NotNull LighterASTNode element) { ProgressManager.checkCanceled(); return nextIndex < sortedOffsets.length && element.getStartOffset() <= nextOffset && nextOffset < element.getEndOffset(); } private void advanceOffset() { nextIndex++; if (nextIndex < sortedOffsets.length) { nextOffset = sortedOffsets[nextIndex]; } } }.visitNode(tree.getRoot()); }