| /* |
| * 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); |
| } |
| } |