/* * Copyright 2000-2009 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.diff; import com.intellij.diff.comparison.ByLine; import com.intellij.diff.comparison.ComparisonPolicy; import com.intellij.diff.comparison.DiffTooBigException; import com.intellij.diff.comparison.iterables.FairDiffIterable; import com.intellij.diff.util.DiffUtil; import com.intellij.diff.util.Range; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.DumbProgressIndicator; import com.intellij.openapi.util.text.LineTokenizer; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import java.util.Arrays; import java.util.List; /** * author: lesya */ public class Block { private static final Logger LOG = Logger.getInstance(Block.class); @NotNull private final String[] mySource; private final int myStart; private final int myEnd; public Block(@NotNull String source, int start, int end) { this(tokenize(source), start, end); } public Block(@NotNull String[] source, int start, int end) { mySource = source; myStart = DiffUtil.bound(start, 0, source.length); myEnd = DiffUtil.bound(end, myStart, source.length); } @NotNull public static String[] tokenize(@NotNull String text) { return LineTokenizer.tokenize(text, false, false); } @NotNull public Block createPreviousBlock(@NotNull String prevContent) { return createPreviousBlock(tokenize(prevContent)); } @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); } } @NotNull public String getBlockContent() { return StringUtil.join(getLines(), "\n"); } @NotNull public List<String> getLines() { return Arrays.asList(mySource).subList(myStart, myEnd); } public int hashCode() { return Arrays.hashCode(mySource) ^ myStart ^ myEnd; } public boolean equals(Object object) { if (!(object instanceof Block)) return false; Block other = (Block)object; return Arrays.equals(mySource, other.mySource) && myStart == other.myStart && myEnd == other.myEnd; } public int getStart() { return myStart; } public int getEnd() { return myEnd; } public String toString() { StringBuilder result = new StringBuilder(); appendLines(result, 0, myStart); result.append("<-----------------------------\n"); appendLines(result, myStart, myEnd); result.append("----------------------------->\n"); appendLines(result, myEnd, mySource.length); return result.toString(); } private void appendLines(@NotNull StringBuilder result, int from, int to) { for (int i = from; i < to; i++) { result.append(mySource[i]); result.append("\n"); } } }