Search in sources :

Example 6 with Range

use of com.intellij.diff.util.Range in project intellij-community by JetBrains.

the class ComparisonManagerImpl method createInnerFragments.

@NotNull
private static List<LineFragment> createInnerFragments(@NotNull LineFragment fragment, @NotNull CharSequence text1, @NotNull CharSequence text2, @NotNull ComparisonPolicy policy, @NotNull ProgressIndicator indicator, boolean tryComputeDifferences) throws DiffTooBigException {
    CharSequence subSequence1 = text1.subSequence(fragment.getStartOffset1(), fragment.getEndOffset1());
    CharSequence subSequence2 = text2.subSequence(fragment.getStartOffset2(), fragment.getEndOffset2());
    if (fragment.getStartLine1() == fragment.getEndLine1() || fragment.getStartLine2() == fragment.getEndLine2()) {
        // Insertion / Deletion
        if (ComparisonUtil.isEquals(subSequence1, subSequence2, policy)) {
            return singletonList(new LineFragmentImpl(fragment, Collections.emptyList()));
        } else {
            return singletonList(fragment);
        }
    }
    if (!tryComputeDifferences)
        return singletonList(fragment);
    List<ByWord.LineBlock> lineBlocks = ByWord.compareAndSplit(subSequence1, subSequence2, policy, indicator);
    assert lineBlocks.size() != 0;
    int startOffset1 = fragment.getStartOffset1();
    int startOffset2 = fragment.getStartOffset2();
    int currentStartLine1 = fragment.getStartLine1();
    int currentStartLine2 = fragment.getStartLine2();
    List<LineFragment> chunks = new ArrayList<>();
    for (int i = 0; i < lineBlocks.size(); i++) {
        ByWord.LineBlock block = lineBlocks.get(i);
        Range offsets = block.offsets;
        // special case for last line to void problem with empty last line
        int currentEndLine1 = i != lineBlocks.size() - 1 ? currentStartLine1 + block.newlines1 : fragment.getEndLine1();
        int currentEndLine2 = i != lineBlocks.size() - 1 ? currentStartLine2 + block.newlines2 : fragment.getEndLine2();
        chunks.add(new LineFragmentImpl(currentStartLine1, currentEndLine1, currentStartLine2, currentEndLine2, offsets.start1 + startOffset1, offsets.end1 + startOffset1, offsets.start2 + startOffset2, offsets.end2 + startOffset2, block.fragments));
        currentStartLine1 = currentEndLine1;
        currentStartLine2 = currentEndLine2;
    }
    return chunks;
}
Also used : ArrayList(java.util.ArrayList) TextRange(com.intellij.openapi.util.TextRange) MergeRange(com.intellij.diff.util.MergeRange) Range(com.intellij.diff.util.Range) NotNull(org.jetbrains.annotations.NotNull)

Example 7 with Range

use of com.intellij.diff.util.Range in project intellij-community by JetBrains.

the class LineFragmentSplitter method mergeChunks.

@NotNull
private static PendingChunk mergeChunks(@NotNull PendingChunk chunk1, @NotNull PendingChunk chunk2) {
    WordBlock block1 = chunk1.block;
    WordBlock block2 = chunk2.block;
    WordBlock newBlock = new WordBlock(new Range(block1.words.start1, block2.words.end1, block1.words.start2, block2.words.end2), new Range(block1.offsets.start1, block2.offsets.end1, block1.offsets.start2, block2.offsets.end2));
    return new PendingChunk(newBlock, chunk1.hasEqualWords || chunk2.hasEqualWords, chunk1.hasWordsInside || chunk2.hasWordsInside, chunk1.isEqualIgnoreWhitespaces && chunk2.isEqualIgnoreWhitespaces);
}
Also used : Range(com.intellij.diff.util.Range) NotNull(org.jetbrains.annotations.NotNull)

Example 8 with Range

use of com.intellij.diff.util.Range in project intellij-community by JetBrains.

the class ChangeDiffIterableBase method unchanged.

@NotNull
@Override
public Iterator<Range> unchanged() {
    return new Iterator<Range>() {

        @NotNull
        private final ChangeIterable myIterable = createChangeIterable();

        int lastIndex1 = 0;

        int lastIndex2 = 0;

        {
            if (myIterable.valid()) {
                if (myIterable.getStart1() == 0 && myIterable.getStart2() == 0) {
                    lastIndex1 = myIterable.getEnd1();
                    lastIndex2 = myIterable.getEnd2();
                    myIterable.next();
                }
            }
        }

        @Override
        public boolean hasNext() {
            return myIterable.valid() || (lastIndex1 != myLength1 || lastIndex2 != myLength2);
        }

        @Override
        public Range next() {
            if (myIterable.valid()) {
                assert (myIterable.getStart1() - lastIndex1 != 0) || (myIterable.getStart2() - lastIndex2 != 0);
                Range chunk = new Range(lastIndex1, myIterable.getStart1(), lastIndex2, myIterable.getStart2());
                lastIndex1 = myIterable.getEnd1();
                lastIndex2 = myIterable.getEnd2();
                myIterable.next();
                return chunk;
            } else {
                assert (myLength1 - lastIndex1 != 0) || (myLength2 - lastIndex2 != 0);
                Range chunk = new Range(lastIndex1, myLength1, lastIndex2, myLength2);
                lastIndex1 = myLength1;
                lastIndex2 = myLength2;
                return chunk;
            }
        }
    };
}
Also used : Iterator(java.util.Iterator) Range(com.intellij.diff.util.Range) NotNull(org.jetbrains.annotations.NotNull)

Example 9 with Range

use of com.intellij.diff.util.Range in project intellij-community by JetBrains.

the class ByWord method compareAndSplit.

@NotNull
public static List<LineBlock> compareAndSplit(@NotNull CharSequence text1, @NotNull CharSequence text2, @NotNull ComparisonPolicy policy, @NotNull ProgressIndicator 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<LineBlock> lineBlocks = new ArrayList<>(wordBlocks.size());
    for (WordBlock block : wordBlocks) {
        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 = fair(subiterable(wordChanges, words.start1, words.end1, words.start2, words.end2));
        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;
}
Also used : WordBlock(com.intellij.diff.comparison.LineFragmentSplitter.WordBlock) ArrayList(java.util.ArrayList) MergingCharSequence(com.intellij.util.text.MergingCharSequence) FairDiffIterable(com.intellij.diff.comparison.iterables.FairDiffIterable) MergeRange(com.intellij.diff.util.MergeRange) Range(com.intellij.diff.util.Range) FairDiffIterable(com.intellij.diff.comparison.iterables.FairDiffIterable) DiffIterable(com.intellij.diff.comparison.iterables.DiffIterable) DiffFragment(com.intellij.diff.fragments.DiffFragment) NotNull(org.jetbrains.annotations.NotNull)

Example 10 with Range

use of com.intellij.diff.util.Range in project intellij-community by JetBrains.

the class Block method createPreviousBlock.

@NotNull
public Block createPreviousBlock(@NotNull String[] prevContent) {
    try {
        FairDiffIterable iterable = ByLine.compare(Arrays.asList(prevContent), Arrays.asList(mySource), ComparisonPolicy.IGNORE_WHITESPACES, DumbProgressIndicator.INSTANCE);
        // empty range should not be transferred to the non-empty range
        boolean greedy = myStart != myEnd;
        int start = myStart;
        int end = myEnd;
        int shift = 0;
        for (Range range : iterable.iterateChanges()) {
            int changeStart = range.start2 + shift;
            int changeEnd = range.end2 + shift;
            int changeShift = (range.end1 - range.start1) - (range.end2 - range.start2);
            DiffUtil.UpdatedLineRange updatedRange = DiffUtil.updateRangeOnModification(start, end, changeStart, changeEnd, changeShift, greedy);
            start = updatedRange.startLine;
            end = updatedRange.endLine;
            shift += changeShift;
        }
        if (start < 0 || end > prevContent.length || end < start) {
            LOG.error("Invalid block range: [" + start + ", " + end + "); length - " + prevContent.length);
        }
        // intern strings, reducing memory usage
        for (Range range : iterable.iterateUnchanged()) {
            int count = range.end1 - range.start1;
            for (int i = 0; i < count; i++) {
                int prevIndex = range.start1 + i;
                int sourceIndex = range.start2 + i;
                if (prevContent[prevIndex].equals(mySource[sourceIndex])) {
                    prevContent[prevIndex] = mySource[sourceIndex];
                }
            }
        }
        return new Block(prevContent, start, end);
    } catch (DiffTooBigException e) {
        return new Block(prevContent, 0, 0);
    }
}
Also used : DiffUtil(com.intellij.diff.util.DiffUtil) DiffTooBigException(com.intellij.diff.comparison.DiffTooBigException) FairDiffIterable(com.intellij.diff.comparison.iterables.FairDiffIterable) Range(com.intellij.diff.util.Range) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

Range (com.intellij.diff.util.Range)26 NotNull (org.jetbrains.annotations.NotNull)21 MergeRange (com.intellij.diff.util.MergeRange)8 ArrayList (java.util.ArrayList)7 TextRange (com.intellij.openapi.util.TextRange)5 FairDiffIterable (com.intellij.diff.comparison.iterables.FairDiffIterable)3 Iterator (java.util.Iterator)3 DiffTooBigException (com.intellij.diff.comparison.DiffTooBigException)2 DiffIterable (com.intellij.diff.comparison.iterables.DiffIterable)2 DiffIterableUtil (com.intellij.diff.comparison.iterables.DiffIterableUtil)2 DiffUtil (com.intellij.diff.util.DiffUtil)2 IntPair (com.intellij.diff.util.IntPair)2 TIntArrayList (gnu.trove.TIntArrayList)2 Nullable (org.jetbrains.annotations.Nullable)2 WordBlock (com.intellij.diff.comparison.LineFragmentSplitter.WordBlock)1 DiffIterableUtil.fair (com.intellij.diff.comparison.iterables.DiffIterableUtil.fair)1 com.intellij.diff.fragments (com.intellij.diff.fragments)1 DiffFragment (com.intellij.diff.fragments.DiffFragment)1 Side (com.intellij.diff.util.Side)1 Logger (com.intellij.openapi.diagnostic.Logger)1