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;
}
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);
}
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;
}
}
};
}
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;
}
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);
}
}
Aggregations