void (@NotNull ASTNode injectionHost, @NotNull List<Block> result, @NotNull List<Block> withInjections, @NotNull List<Block> regularBlocks) { int i = 0; int j = 0; int injectionHostOffset = injectionHost.getStartOffset(); // Since there are possible injections without formatter blocks (i.e. whitespace only block), // we need to detect such scenarios and correctly split as if there was an injection. List<TextRange> injectedRanges = new ArrayList<>(withInjections.size()); Int2ObjectMap<Block> injectedBlocksMap = new Int2ObjectOpenHashMap<>(); boolean lastInjected = true; int lastOffset = 0; for (Block block : withInjections) { TextRange range = block.getTextRange(); if (block instanceof AnotherLanguageBlockWrapper) { injectedRanges.add(range); injectedBlocksMap.put(range.getStartOffset(), block); lastInjected = true; } else { if (!lastInjected) { // add range for empty injection int offset = range.getStartOffset(); injectedRanges.add(new TextRange(lastOffset, offset)); } lastOffset = range.getEndOffset(); lastInjected = false; } } // Perform actual splitting int injectedRangesCount = injectedRanges.size(); while (i < regularBlocks.size()) { Block reg = regularBlocks.get(i); if (j < injectedRangesCount) { TextRange injRange = injectedRanges.get(j); TextRange regRange = reg.getTextRange(); if (regRange.getEndOffset() <= injRange.getStartOffset()) { // Regular block does not intersect with injected - add result.add(reg); i++; } else if (injRange.getStartOffset() <= regRange.getStartOffset() && regRange.getEndOffset() <= injRange.getEndOffset()) { // Regular block completely within injected - skip i++; } else { if (regRange.getStartOffset() < injRange.getStartOffset()) { // Regular block ends within or after an injected - split ASTNode node = notNull(injectionHost.findLeafElementAt(injRange.getStartOffset() - 1 - injectionHostOffset), injectionHost); result.add(createSimpleChild(node, reg.getIndent(), reg.getWrap(), reg.getAlignment(), new TextRange( regRange.getStartOffset(), injRange.getStartOffset()))); if (regRange.getEndOffset() <= injRange.getEndOffset()) { // Block ends within injected - move to the next block i++; continue; } // Case of a regular block spanning over multiple injected ones } // Add injected block to the result addIfNotNull(result, injectedBlocksMap.get(injRange.getStartOffset())); j++; if (regRange.getStartOffset() < injRange.getEndOffset()) { // we have a regular block starting within or before last added injected block - split int lastInjection = injRange.getEndOffset(); while (j < injectedRangesCount) { // check if single block does not span over next injected block TextRange nextRange = injectedRanges.get(j); if (nextRange.getStartOffset() < regRange.getEndOffset()) { // out regular block ends within or after the next injected block - add a split if it's not empty if (lastInjection < nextRange.getStartOffset()) { ASTNode node = notNull(injectionHost.findLeafElementAt(lastInjection - injectionHostOffset), injectionHost); result.add(createSimpleChild(node, reg.getIndent(), null, reg.getAlignment(), new TextRange(lastInjection, nextRange.getStartOffset()))); } lastInjection = nextRange.getEndOffset(); if (lastInjection <= regRange.getEndOffset()) { // Add current injected block and repeat if regular block ends after it addIfNotNull(result, injectedBlocksMap.get(nextRange.getStartOffset())); j++; continue; } } break; } // We might have some leftover of regular block after last added injected one, // which does not end within or after the next injected block - add a split if (lastInjection < regRange.getEndOffset()) { ASTNode node = notNull(injectionHost.findLeafElementAt(lastInjection - injectionHostOffset), injectionHost); result.add(createSimpleChild(node, reg.getIndent(), null, reg.getAlignment(), new TextRange(lastInjection, regRange.getEndOffset()))); } i++; } } } else { // No more injected blocks to process, just add the regular ones result.add(reg); i++; } } // Add any leftover injected blocks while (j < injectedRangesCount) { addIfNotNull(result, injectedBlocksMap.get(injectedRanges.get(j++).getStartOffset())); } }