List<LineBlock> (@NotNull CharSequence text1, @NotNull CharSequence text2, @NotNull ComparisonPolicy policy, @NotNull CancellationChecker indicator) { indicator.checkCanceled(); // TODO: figure out, what do we exactly want from 'Split' logic // -- it is used for trimming of ignored blocks. So we want whitespace-only leading/trailing lines to be separate block. // -- old approach: split by matched '\n's // TODO: other approach could lead to better results: // * Compare words-only // * prefer big chunks // -- here we can try to minimize number of matched pairs 'pair[i]' and 'pair[i+1]' such that // containsNewline(pair[i].left .. pair[i+1].left) XOR containsNewline(pair[i].right .. pair[i+1].right) == true // ex: "A X C" - "A Y C \n M C" - do not match with last 'C' // ex: "A \n" - "A B \n \n" - do not match with last '\n' // Try some greedy approach ? // * split into blocks // -- squash blocks with too small unchanged words count (1 matched word out of 40 - is a bad reason to create new block) // * match adjustment punctuation // * match adjustment whitespaces ('\n' are matched here) List<InlineChunk> words1 = getInlineChunks(text1); List<InlineChunk> words2 = getInlineChunks(text2); FairDiffIterable wordChanges = diff(words1, words2, indicator); wordChanges = optimizeWordChunks(text1, text2, words1, words2, wordChanges, indicator); List<WordBlock> wordBlocks = new LineFragmentSplitter(text1, text2, words1, words2, wordChanges, indicator).run(); List<FairDiffIterable> subIterables = collectWordBlockSubIterables(wordChanges, wordBlocks); List<LineBlock> lineBlocks = new ArrayList<>(wordBlocks.size()); for (int i = 0; i < wordBlocks.size(); i++) { WordBlock block = wordBlocks.get(i); Range offsets = block.offsets; Range words = block.words; CharSequence subtext1 = text1.subSequence(offsets.start1, offsets.end1); CharSequence subtext2 = text2.subSequence(offsets.start2, offsets.end2); List<InlineChunk> subwords1 = words1.subList(words.start1, words.end1); List<InlineChunk> subwords2 = words2.subList(words.start2, words.end2); FairDiffIterable subiterable = subIterables.get(i); FairDiffIterable delimitersIterable = matchAdjustmentDelimiters(subtext1, subtext2, subwords1, subwords2, subiterable, offsets.start1, offsets.start2, indicator); DiffIterable iterable = matchAdjustmentWhitespaces(subtext1, subtext2, delimitersIterable, policy, indicator); List<DiffFragment> fragments = convertIntoDiffFragments(iterable); int newlines1 = countNewlines(subwords1); int newlines2 = countNewlines(subwords2); lineBlocks.add(new LineBlock(fragments, offsets, newlines1, newlines2)); } return lineBlocks; }