/* * 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.DiffIterableUtil; import com.intellij.diff.comparison.iterables.FairDiffIterable; import com.intellij.diff.util.Range; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.DumbProgressIndicator; import com.intellij.openapi.util.Pair; 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 = Math.min(Math.max(0, start), source.length); myEnd = Math.min(Math.max(myStart, end), 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) { int start = -1; int end = -1; int shift = 0; try { FairDiffIterable iterable = ByLine.compare(Arrays.asList(prevContent), Arrays.asList(mySource), ComparisonPolicy.IGNORE_WHITESPACES, DumbProgressIndicator.INSTANCE); for (Pair<Range, Boolean> pair : DiffIterableUtil.iterateAll(iterable)) { Boolean equals = pair.second; Range range = pair.first; if (!equals) { if (Math.max(myStart, range.start2) < Math.min(myEnd, range.end2)) { // ranges intersect if (range.start2 <= myStart) start = range.start1; if (range.end2 > myEnd) end = range.end1; } if (range.start2 > myStart) { if (start == -1) start = myStart - shift; if (end == -1 && range.start2 >= myEnd) end = myEnd - shift; } shift += (range.end2 - range.start2) - (range.end1 - range.start1); } else { // intern strings, reducing memory usage 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]; } } } } if (start == -1) start = myStart - shift; if (end == -1) end = myEnd - shift; if (start < 0 || end > prevContent.length || end < start) { LOG.error("Invalid block range: [" + start + ", " + end + "); length - " + prevContent.length); } 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"); } } }