blob: b38c827adf9f1a99f6c64a824f7d4907160f6526 [file] [log] [blame]
/*
* Copyright 2000-2013 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.openapi.diff.impl;
import com.intellij.CommonBundle;
import com.intellij.openapi.diff.impl.string.DiffString;
import com.intellij.openapi.diff.ex.DiffFragment;
import com.intellij.openapi.diff.impl.highlighting.FragmentSide;
import com.intellij.openapi.diff.impl.highlighting.Util;
import com.intellij.openapi.diff.impl.processing.DiffCorrection;
import com.intellij.openapi.diff.impl.processing.Formatting;
import com.intellij.openapi.diff.impl.processing.Word;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.TextRange;
import com.intellij.util.diff.Diff;
import com.intellij.util.diff.FilesTooBigForDiffException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
public abstract class ComparisonPolicy {
public static final ComparisonPolicy DEFAULT = new DefaultPolicy();
public static final ComparisonPolicy TRIM_SPACE = new TrimSpacePolicy();
public static final ComparisonPolicy IGNORE_SPACE = new IgnoreSpacePolicy();
public static final ComparisonPolicy[] COMPARISON_POLICIES = new ComparisonPolicy[]{DEFAULT, IGNORE_SPACE, TRIM_SPACE};
private final String myName;
protected ComparisonPolicy(final String name) {
myName = name;
}
public String getName() {
return myName;
}
@NotNull
public DiffFragment[] buildFragments(@NotNull DiffString[] strings1, @NotNull DiffString[] strings2) throws FilesTooBigForDiffException {
DiffFragmentBuilder builder = new DiffFragmentBuilder(strings1, strings2);
Object[] wrappers1 = getWrappers(strings1);
Object[] wrappers2 = getWrappers(strings2);
Diff.Change change = Diff.buildChanges(wrappers1, wrappers2);
return builder.buildFragments(Util.concatEquals(change, wrappers1, wrappers2));
}
@NotNull
public DiffFragment[] buildDiffFragmentsFromLines(@NotNull DiffString[] lines1, @NotNull DiffString[] lines2)
throws FilesTooBigForDiffException {
DiffFragmentBuilder builder = new DiffFragmentBuilder(lines1, lines2);
Object[] wrappers1 = getLineWrappers(lines1);
Object[] wrappers2 = getLineWrappers(lines2);
Diff.Change change = Diff.buildChanges(wrappers1, wrappers2);
return builder.buildFragments(change);
}
@NotNull
public DiffFragment createFragment(@Nullable DiffString text1, @Nullable DiffString text2) {
text1 = toNull(text1);
text2 = toNull(text2);
if (text1 == null && text2 == null) return new DiffFragment(DiffString.EMPTY, DiffString.EMPTY);
DiffFragment result = new DiffFragment(text1, text2);
if (text1 != null && text2 != null) {
result.setModified(!getWrapper(text1).equals(getWrapper(text2)));
}
return result;
}
@NotNull
public abstract DiffFragment createFragment(@NotNull Word word1, @NotNull Word word2);
@NotNull
protected abstract Object[] getWrappers(@NotNull DiffString[] strings);
@NotNull
protected abstract Object[] getLineWrappers(@NotNull DiffString[] lines);
@NotNull
private Object getWrapper(@NotNull DiffString text) {
return getWrappers(new DiffString[]{text})[0];
}
private static class DefaultPolicy extends ComparisonPolicy {
public DefaultPolicy() {
super(CommonBundle.message("comparison.policy.default.name"));
}
@NotNull
@Override
protected Object[] getWrappers(@NotNull DiffString[] strings) {
return strings;
}
@NotNull
@Override
protected Object[] getLineWrappers(@NotNull DiffString[] lines) {
return lines;
}
@NotNull
@Override
public DiffFragment createFragment(@NotNull Word word1, @NotNull Word word2) {
return createFragment(word1.getText(), word2.getText());
}
@SuppressWarnings({"HardCodedStringLiteral"})
public String toString() {
return "DEFAULT";
}
}
private static class TrimSpacePolicy extends ComparisonPolicy {
public TrimSpacePolicy() {
super(CommonBundle.message("comparison.policy.trim.space.name"));
}
@NotNull
@Override
protected Object[] getLineWrappers(@NotNull DiffString[] lines) {
return trimStrings(lines);
}
@NotNull
@Override
public DiffFragment createFragment(@NotNull Word word1, @NotNull Word word2) {
DiffString text1 = word1.getText();
DiffString text2 = word2.getText();
if (word1.isWhitespace() && word2.isWhitespace() &&
word1.atEndOfLine() && word2.atEndOfLine()) {
return DiffFragment.unchanged(text1, text2);
}
return createFragment(text1, text2);
}
@NotNull
@Override
protected Object[] getWrappers(@NotNull DiffString[] strings) {
Object[] result = new Object[strings.length];
boolean atBeginning = true;
for (int i = 0; i < strings.length; i++) {
DiffString string = strings[i];
DiffString wrapper = atBeginning ? string.trimLeading() : string;
if (wrapper.endsWith('\n')) {
atBeginning = true;
wrapper = wrapper.trimTrailing();
}
else {
atBeginning = false;
}
result[i] = wrapper;
}
return result;
}
@SuppressWarnings({"HardCodedStringLiteral"})
public String toString() {
return "TRIM";
}
}
private static class IgnoreSpacePolicy extends ComparisonPolicy
implements DiffCorrection.FragmentProcessor<DiffCorrection.FragmentsCollector> {
public IgnoreSpacePolicy() {
super(CommonBundle.message("comparison.policy.ignore.spaces.name"));
}
@NotNull
@Override
protected Object[] getLineWrappers(@NotNull DiffString[] lines) {
Object[] result = new Object[lines.length];
for (int i = 0; i < lines.length; i++) {
DiffString line = lines[i];
result[i] = getWrapper(line);
}
return result;
}
@NotNull
@Override
public DiffFragment[] buildFragments(@NotNull DiffString[] strings1, @NotNull DiffString[] strings2)
throws FilesTooBigForDiffException {
DiffFragment[] fragments = super.buildFragments(strings1, strings2);
DiffCorrection.FragmentsCollector collector = new DiffCorrection.FragmentsCollector();
collector.processAll(fragments, this);
return collector.toArray();
}
@NotNull
private static Object getWrapper(@NotNull DiffString line) {
return line.skipSpaces();
}
@NotNull
@Override
public DiffFragment createFragment(@NotNull Word word1, @NotNull Word word2) {
DiffString text1 = word1.getText();
DiffString text2 = word2.getText();
return word1.isWhitespace() && word2.isWhitespace() ? DiffFragment.unchanged(text1, text2) : createFragment(text1, text2);
}
@NotNull
@Override
public DiffFragment createFragment(DiffString text1, DiffString text2) {
DiffString toCompare1 = toNotNull(text1);
DiffString toCompare2 = toNotNull(text2);
if (getWrapper(toCompare1).equals(getWrapper(toCompare2))) {
return DiffFragment.unchanged(toCompare1, toCompare2);
}
return new DiffFragment(text1, text2);
}
@NotNull
@Override
protected Object[] getWrappers(@NotNull DiffString[] strings) {
return trimStrings(strings);
}
@SuppressWarnings({"HardCodedStringLiteral"})
public String toString() {
return "IGNORE";
}
@Override
public void process(@NotNull DiffFragment fragment, @NotNull DiffCorrection.FragmentsCollector collector) {
if (fragment.isEqual()) {
collector.add(fragment);
return;
}
if (fragment.isOneSide()) {
FragmentSide side = FragmentSide.chooseSide(fragment);
DiffString text = side.getText(fragment);
DiffString trimed = text.trim();
if (trimed.isEmpty()) {
collector.add(side.createFragment(text, DiffString.EMPTY, false));
return;
}
}
collector.add(fragment);
}
}
@Nullable
private static DiffString toNull(@Nullable DiffString text1) {
return text1 == null || text1.isEmpty() ? null : text1;
}
@NotNull
private static DiffString toNotNull(@Nullable DiffString text) {
return text == null ? DiffString.EMPTY : text;
}
@NotNull
protected Object[] trimStrings(@NotNull DiffString[] strings) {
Object[] result = new Object[strings.length];
for (int i = 0; i < strings.length; i++) {
DiffString string = strings[i];
result[i] = string.trim();
}
return result;
}
public boolean isEqual(@NotNull DiffFragment fragment) {
if (fragment.isOneSide()) return false;
Object[] wrappers = getLineWrappers(new DiffString[]{fragment.getText1(), fragment.getText2()});
return Comparing.equal(wrappers[0], wrappers[1]);
}
@NotNull
public Word createFormatting(@NotNull DiffString text, @NotNull TextRange textRange) {
return new Formatting(text, textRange);
}
public static ComparisonPolicy[] getAllInstances() {
return COMPARISON_POLICIES;
}
@NotNull
@TestOnly
protected Object[] getWrappers(@NotNull String[] lines) {
DiffString[] unsafeStrings = new DiffString[lines.length];
for (int i = 0; i < lines.length; i++) {
unsafeStrings[i] = DiffString.createNullable(lines[i]);
}
return getWrappers(unsafeStrings);
}
@NotNull
@TestOnly
protected Object[] getLineWrappers(@NotNull String[] lines) {
DiffString[] unsafeStrings = new DiffString[lines.length];
for (int i = 0; i < lines.length; i++) {
unsafeStrings[i] = DiffString.createNullable(lines[i]);
}
return getLineWrappers(unsafeStrings);
}
}