List<Block> (@NotNull List<? extends TemplateLanguageBlock> tlBlocks, @NotNull List<DataLanguageBlockWrapper> foreignBlocks) { ArrayList<Block> result = new ArrayList<>(tlBlocks.size() + foreignBlocks.size()); int vInd = 0; int fInd = 0; while (vInd < tlBlocks.size() && fInd < foreignBlocks.size()) { final TemplateLanguageBlock v = tlBlocks.get(vInd); final DataLanguageBlockWrapper f = foreignBlocks.get(fInd); final TextRange vRange = v.getTextRange(); final TextRange fRange = f.getTextRange(); if (vRange.getStartOffset() >= fRange.getEndOffset()) { // add leading foreign blocks result.add(f); fInd++; } else if (vRange.getEndOffset() <= fRange.getStartOffset()) { // add leading TL blocks result.add(v); vInd++; } else if (vRange.getStartOffset() < fRange.getStartOffset() || vRange.getStartOffset() == fRange.getStartOffset() && vRange.getEndOffset() >= fRange.getEndOffset()) { // add including TL blocks and split intersecting foreign blocks result.add(v); while (fInd < foreignBlocks.size() && vRange.contains(foreignBlocks.get(fInd).getTextRange())) { v.addForeignChild(foreignBlocks.get(fInd++)); } if (fInd < foreignBlocks.size()) { final DataLanguageBlockWrapper notContainedF = foreignBlocks.get(fInd); if (vRange.intersectsStrict(notContainedF.getTextRange())) { Pair<List<DataLanguageBlockWrapper>, List<DataLanguageBlockWrapper>> splitBlocks = splitBlocksByRightBound(notContainedF.getOriginal(), vRange); v.addForeignChildren(splitBlocks.getFirst()); foreignBlocks.remove(fInd); if (splitBlocks.getSecond().size() > 0) { foreignBlocks.addAll(fInd, splitBlocks.getSecond()); } } } vInd++; } else { // add including foreign blocks or split them if needed int lastContainedTlInd = vInd; while (lastContainedTlInd < tlBlocks.size() && fRange.intersectsStrict(tlBlocks.get(lastContainedTlInd).getTextRange())) { lastContainedTlInd++; } if (fRange.contains(tlBlocks.get(lastContainedTlInd - 1).getTextRange())) { result.add(f); fInd++; while (vInd < lastContainedTlInd) { f.addTlChild(tlBlocks.get(vInd++)); } } else { Block original = f.getOriginal(); if (!original.getSubBlocks().isEmpty()) { foreignBlocks.remove(fInd); foreignBlocks.addAll(fInd, buildChildWrappers(original)); } else { result.add(new ErrorLeafBlock(f.getTextRange().getStartOffset(), getEndOffset(tlBlocks, foreignBlocks))); return result; } } } } while (vInd < tlBlocks.size()) { result.add(tlBlocks.get(vInd++)); } while (fInd < foreignBlocks.size()) { result.add(foreignBlocks.get(fInd++)); } return result; }