From 848382aff296895a9dad1895da0b16dfce007ccd Mon Sep 17 00:00:00 2001 From: irengrig Date: Wed, 1 Jun 2011 18:03:50 +0400 Subject: [PATCH] VCS: diff for big files - throw exception if algorithm tries to allocate array bigger than 10000000 line status tracker and diff/merge shows notifications --- .../options/colors/ColorAndFontOptions.java | 35 +++++---- .../ide/util/gotoByName/ChooseByNameBase.java | 9 ++- .../diff/impl/settings/DiffPreviewPanel.java | 3 +- .../vcs/checkin/TodoCheckinHandlerWorker.java | 17 +++-- .../integration/revertion/Reverter.java | 3 +- .../revertion/SelectionReverter.java | 3 +- .../ui/models/SelectionCalculator.java | 9 ++- .../ui/models/SelectionDifferenceModel.java | 22 +++++- .../ui/models/SelectionCalculatorTest.java | 21 +++-- .../com/intellij/ide/diff/DiffElement.java | 3 +- .../com/intellij/openapi/diff/DiffPanel.java | 1 + .../ui/customization/CustomizationUtil.java | 9 ++- .../openapi/diff/ex/DiffPanelOptions.java | 6 +- .../openapi/diff/impl/DiffPanelImpl.java | 27 ++++++- .../highlighting/SimpleDiffPanelState.java | 6 +- .../impl/incrementalMerge/ChangeList.java | 5 +- .../diff/impl/incrementalMerge/MergeList.java | 14 ++-- .../incrementalMerge/MergeSearchHelper.java | 1 + .../impl/incrementalMerge/ui/MergePanel2.java | 45 +++++++---- .../diff/impl/mergeTool/MergeRequestImpl.java | 2 +- .../openapi/diff/impl/processing/ByWord.java | 15 ++-- .../impl/processing/TextCompareProcessor.java | 5 +- .../diff/impl/processing/UniteSameType.java | 3 +- .../impl/util/DiffPanelOutterComponent.java | 18 ++++- .../impl/PersistentRangeHighlighterImpl.java | 36 ++++++--- .../editor/impl/event/DocumentEventImpl.java | 7 +- .../diff/impl/highlighting/UtilTest.java | 5 +- .../diff/impl/processing/ByWordTest.java | 23 +++--- .../diff/impl/processing/CorrectionTest.java | 11 +-- .../processing/LineBlocksDiffPolicyTest.java | 5 +- .../impl/processing/NormalizationTest.java | 5 +- .../processing/TextCompareProcessorTest.java | 3 +- .../impl/processing/UniteSameTypeTest.java | 5 +- .../openapi/diff/impl/ComparisonPolicy.java | 7 +- .../diff/impl/processing/DiffCorrection.java | 27 +++---- .../diff/impl/processing/DiffPolicy.java | 7 +- .../util/src/com/intellij/util/diff/Diff.java | 5 ++ .../diff/FilesTooBigForDiffException.java | 19 +++++ .../src/com/intellij/util/diff/IntLCS.java | 4 +- .../intellij/util/diff/LinkedDiffPaths.java | 11 ++- .../com/intellij/util/diff/DiffTest.java | 2 +- .../com/intellij/util/diff/IntLCSTest.java | 18 ++--- .../util/diff/LinkedDiffPathsTest.java | 10 +-- .../diff/impl/patch/TextPatchBuilder.java | 12 ++- .../src/com/intellij/diff/FindBlock.java | 3 +- .../openapi/diff/impl/dir/DirDiffPanel.java | 11 ++- .../openapi/vcs/ex/LineStatusTracker.java | 76 ++++++++++++++++--- .../openapi/vcs/ex/RangesBuilder.java | 5 +- .../vcs/history/impl/VcsHistoryDialog.java | 26 +++++-- .../vcs/impl/LineStatusTrackerManager.java | 2 +- 50 files changed, 438 insertions(+), 189 deletions(-) create mode 100644 platform/util/src/com/intellij/util/diff/FilesTooBigForDiffException.java diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java b/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java index c65a3d9a45fd..ae323a649d72 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java @@ -23,6 +23,7 @@ import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationBundle; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diff.impl.settings.DiffOptionsPanel; import com.intellij.openapi.diff.impl.settings.DiffPreviewPanel; import com.intellij.openapi.editor.EditorFactory; @@ -59,6 +60,7 @@ import com.intellij.psi.search.scope.packageSet.NamedScopesHolder; import com.intellij.psi.search.scope.packageSet.PackageSet; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.HashMap; +import com.intellij.util.diff.FilesTooBigForDiffException; import gnu.trove.THashSet; import gnu.trove.TObjectHashingStrategy; import org.jetbrains.annotations.Nls; @@ -90,6 +92,7 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract private boolean myApplyCompleted = false; private boolean myDisposeCompleted = false; private final Disposable myDisposable = Disposer.newDisposable(); + private static final Logger LOG = Logger.getInstance("#com.intellij.application.options.colors.ColorAndFontOptions"); public static ColorAndFontOptions getColorAndFontsInstance() { ColorAndFontOptions colorAndFontOptions = null; @@ -371,22 +374,28 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract private class DiffColorsPageFactory implements ColorAndFontPanelFactory { public NewColorAndFontPanel createPanel(ColorAndFontOptions options) { - final DiffPreviewPanel diffPreviewPanel = new DiffPreviewPanel(myDisposable); - diffPreviewPanel.setMergeRequest(null); final DiffOptionsPanel optionsPanel = new DiffOptionsPanel(options); - SchemesPanel schemesPanel = new SchemesPanel(options); + PreviewPanel previewPanel; + try { + final DiffPreviewPanel diffPreviewPanel = new DiffPreviewPanel(myDisposable); + diffPreviewPanel.setMergeRequest(null); + schemesPanel.addListener(new ColorAndFontSettingsListener.Abstract(){ + @Override + public void schemeChanged(final Object source) { + diffPreviewPanel.setColorScheme(getSelectedScheme()); + optionsPanel.updateOptionsList(); + diffPreviewPanel.updateView(); + } + } ); + previewPanel = diffPreviewPanel; + } + catch (FilesTooBigForDiffException e) { + LOG.info(e); + previewPanel = new PreviewPanel.Empty(); + } - schemesPanel.addListener(new ColorAndFontSettingsListener.Abstract(){ - @Override - public void schemeChanged(final Object source) { - diffPreviewPanel.setColorScheme(getSelectedScheme()); - optionsPanel.updateOptionsList(); - diffPreviewPanel.updateView(); - } - } ); - - return new NewColorAndFontPanel(schemesPanel, optionsPanel, diffPreviewPanel, DIFF_GROUP, null, null); + return new NewColorAndFontPanel(schemesPanel, optionsPanel, previewPanel, DIFF_GROUP, null, null); } public String getPanelDisplayName() { diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java index 0768862a294c..95b52281eb79 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java @@ -59,6 +59,7 @@ import com.intellij.util.Function; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.diff.Diff; +import com.intellij.util.diff.FilesTooBigForDiffException; import com.intellij.util.text.Matcher; import com.intellij.util.text.MatcherHolder; import com.intellij.util.ui.UIUtil; @@ -850,7 +851,13 @@ public abstract class ChooseByNameBase { Object[] oldElements = myListModel.toArray(); Object[] newElements = elements.toArray(); - Diff.Change change = Diff.buildChanges(oldElements, newElements); + Diff.Change change = null; + try { + change = Diff.buildChanges(oldElements, newElements); + } + catch (FilesTooBigForDiffException e) { + // should not occur + } if (change == null) return; // Nothing changed diff --git a/platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffPreviewPanel.java b/platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffPreviewPanel.java index 868c6ab07f93..9ac0b0f849fa 100644 --- a/platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffPreviewPanel.java +++ b/platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffPreviewPanel.java @@ -33,6 +33,7 @@ import com.intellij.openapi.editor.event.*; import com.intellij.openapi.editor.ex.util.EditorUtil; import com.intellij.openapi.project.Project; import com.intellij.util.EventDispatcher; +import com.intellij.util.diff.FilesTooBigForDiffException; import javax.swing.*; import java.awt.*; @@ -89,7 +90,7 @@ public class DiffPreviewPanel implements PreviewPanel { } - public void setMergeRequest(Project project) { + public void setMergeRequest(Project project) throws FilesTooBigForDiffException { getMergePanel().setDiffRequest(new SampleMerge(project)); } diff --git a/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandlerWorker.java b/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandlerWorker.java index e823573ef26e..bd2a2d6ceab9 100644 --- a/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandlerWorker.java +++ b/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandlerWorker.java @@ -48,6 +48,7 @@ import com.intellij.psi.search.searches.IndexPatternSearch; import com.intellij.util.PairConsumer; import com.intellij.util.SmartList; import com.intellij.util.containers.Convertor; +import com.intellij.util.diff.FilesTooBigForDiffException; import java.util.*; @@ -186,7 +187,7 @@ public class TodoCheckinHandlerWorker { myAcceptor.skipped(new Pair(myAfterFile, ourCannotLoadPreviousRevision)); return; } - ArrayList lineFragments = getLineFragments(myBeforeContent, myAfterContent); + ArrayList lineFragments = getLineFragments(myAfterFile.getPath(), myBeforeContent, myAfterContent); for (Iterator iterator = lineFragments.iterator(); iterator.hasNext(); ) { ProgressManager.checkCanceled(); final LineFragment next = iterator.next(); @@ -287,11 +288,15 @@ public class TodoCheckinHandlerWorker { return StringUtil.join(fragment.split("\\s"), " "); } - private static ArrayList getLineFragments(String beforeContent, String afterContent) { - DiffFragment[] woFormattingBlocks = DiffPolicy.LINES_WO_FORMATTING.buildFragments(beforeContent, afterContent); - DiffFragment[] step1lineFragments = - new DiffCorrection.TrueLineBlocks(ComparisonPolicy.IGNORE_SPACE).correctAndNormalize(woFormattingBlocks); - return new DiffFragmentsProcessor().process(step1lineFragments); + private static ArrayList getLineFragments(final String fileName, String beforeContent, String afterContent) throws VcsException { + try { + DiffFragment[] woFormattingBlocks = DiffPolicy.LINES_WO_FORMATTING.buildFragments(beforeContent, afterContent); + DiffFragment[] step1lineFragments = + new DiffCorrection.TrueLineBlocks(ComparisonPolicy.IGNORE_SPACE).correctAndNormalize(woFormattingBlocks); + return new DiffFragmentsProcessor().process(step1lineFragments); + } catch (FilesTooBigForDiffException e) { + throw new VcsException("File " + fileName + " is too big and there are too many changes to build a diff", e); + } } private final static String ourInvalidFile = "Invalid file (s)"; diff --git a/platform/lvcs-impl/src/com/intellij/history/integration/revertion/Reverter.java b/platform/lvcs-impl/src/com/intellij/history/integration/revertion/Reverter.java index 74fb7a4f43d5..eae2937a7c96 100644 --- a/platform/lvcs-impl/src/com/intellij/history/integration/revertion/Reverter.java +++ b/platform/lvcs-impl/src/com/intellij/history/integration/revertion/Reverter.java @@ -26,6 +26,7 @@ import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.diff.FilesTooBigForDiffException; import com.intellij.util.text.DateFormatUtil; import java.io.IOException; @@ -108,5 +109,5 @@ public abstract class Reverter { protected abstract Revision getTargetRevision(); - protected abstract void doRevert() throws IOException; + protected abstract void doRevert() throws IOException, FilesTooBigForDiffException; } diff --git a/platform/lvcs-impl/src/com/intellij/history/integration/revertion/SelectionReverter.java b/platform/lvcs-impl/src/com/intellij/history/integration/revertion/SelectionReverter.java index 6881c57c8089..c7ee3789273e 100644 --- a/platform/lvcs-impl/src/com/intellij/history/integration/revertion/SelectionReverter.java +++ b/platform/lvcs-impl/src/com/intellij/history/integration/revertion/SelectionReverter.java @@ -26,6 +26,7 @@ import com.intellij.history.integration.ui.models.SelectionCalculator; import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.diff.FilesTooBigForDiffException; import java.io.IOException; import java.util.Collections; @@ -65,7 +66,7 @@ public class SelectionReverter extends Reverter { return Collections.singletonList(file); } - protected void doRevert() throws IOException { + protected void doRevert() throws IOException, FilesTooBigForDiffException { Block b = myCalculator.getSelectionFor(myLeftRevision, new Progress() { public void processed(int percentage) { // should be already processed. diff --git a/platform/lvcs-impl/src/com/intellij/history/integration/ui/models/SelectionCalculator.java b/platform/lvcs-impl/src/com/intellij/history/integration/ui/models/SelectionCalculator.java index 3a8e6964dfab..b50ad2dbd3f4 100644 --- a/platform/lvcs-impl/src/com/intellij/history/integration/ui/models/SelectionCalculator.java +++ b/platform/lvcs-impl/src/com/intellij/history/integration/ui/models/SelectionCalculator.java @@ -22,6 +22,7 @@ import com.intellij.history.core.Content; import com.intellij.history.core.revisions.Revision; import com.intellij.history.core.tree.Entry; import com.intellij.history.integration.IdeaGateway; +import com.intellij.util.diff.FilesTooBigForDiffException; import org.jetbrains.annotations.Nullable; import java.util.HashMap; @@ -44,7 +45,7 @@ public class SelectionCalculator { myToLine = toLine; } - public boolean canCalculateFor(Revision r, Progress p) { + public boolean canCalculateFor(Revision r, Progress p) throws FilesTooBigForDiffException { try { doGetSelectionFor(r, p); } @@ -54,16 +55,16 @@ public class SelectionCalculator { return true; } - public Block getSelectionFor(Revision r, Progress p) { + public Block getSelectionFor(Revision r, Progress p) throws FilesTooBigForDiffException { return doGetSelectionFor(r, p); } - private Block doGetSelectionFor(Revision r, Progress p) { + private Block doGetSelectionFor(Revision r, Progress p) throws FilesTooBigForDiffException { int target = myRevisions.indexOf(r); return getSelectionFor(target, target + 1, p); } - private Block getSelectionFor(int revisionIndex, int totalRevisions, Progress p) { + private Block getSelectionFor(int revisionIndex, int totalRevisions, Progress p) throws FilesTooBigForDiffException { Block cached = myCache.get(revisionIndex); if (cached != null) return cached; diff --git a/platform/lvcs-impl/src/com/intellij/history/integration/ui/models/SelectionDifferenceModel.java b/platform/lvcs-impl/src/com/intellij/history/integration/ui/models/SelectionDifferenceModel.java index 0ef4cae9b73e..608807a8c7be 100644 --- a/platform/lvcs-impl/src/com/intellij/history/integration/ui/models/SelectionDifferenceModel.java +++ b/platform/lvcs-impl/src/com/intellij/history/integration/ui/models/SelectionDifferenceModel.java @@ -24,6 +24,7 @@ import com.intellij.openapi.diff.FragmentContent; import com.intellij.openapi.diff.SimpleContent; import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; +import com.intellij.util.diff.FilesTooBigForDiffException; public class SelectionDifferenceModel extends FileDifferenceModel { private final SelectionCalculator myCalculator; @@ -60,12 +61,22 @@ public class SelectionDifferenceModel extends FileDifferenceModel { @Override protected boolean isLeftContentAvailable(RevisionProcessingProgress p) { - return myCalculator.canCalculateFor(myLeftRevision, p); + try { + return myCalculator.canCalculateFor(myLeftRevision, p); + } + catch (FilesTooBigForDiffException e) { + return false; + } } @Override protected boolean isRightContentAvailable(RevisionProcessingProgress p) { - return myCalculator.canCalculateFor(myRightRevision, p); + try { + return myCalculator.canCalculateFor(myRightRevision, p); + } + catch (FilesTooBigForDiffException e) { + return false; + } } @Override @@ -93,6 +104,11 @@ public class SelectionDifferenceModel extends FileDifferenceModel { } private String getContentOf(Revision r, RevisionProcessingProgress p) { - return myCalculator.getSelectionFor(r, p).getBlockContent(); + try { + return myCalculator.getSelectionFor(r, p).getBlockContent(); + } + catch (FilesTooBigForDiffException e) { + return ""; + } } } diff --git a/platform/lvcs-impl/testSrc/com/intellij/history/integration/ui/models/SelectionCalculatorTest.java b/platform/lvcs-impl/testSrc/com/intellij/history/integration/ui/models/SelectionCalculatorTest.java index d21952293d9e..b87a187f54c4 100644 --- a/platform/lvcs-impl/testSrc/com/intellij/history/integration/ui/models/SelectionCalculatorTest.java +++ b/platform/lvcs-impl/testSrc/com/intellij/history/integration/ui/models/SelectionCalculatorTest.java @@ -20,25 +20,22 @@ import com.intellij.diff.Block; import com.intellij.history.core.InMemoryLocalHistoryFacade; import com.intellij.history.core.LocalHistoryFacade; import com.intellij.history.core.LocalHistoryTestCase; -import com.intellij.history.core.revisions.CurrentRevision; import com.intellij.history.core.revisions.Revision; import com.intellij.history.core.tree.RootEntry; import com.intellij.history.integration.IdeaGateway; - -import static org.easymock.classextension.EasyMock.*; - -import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.diff.FilesTooBigForDiffException; import org.junit.Test; -import java.util.Arrays; import java.util.List; +import static org.easymock.classextension.EasyMock.*; + public class SelectionCalculatorTest extends LocalHistoryTestCase { IdeaGateway gw = new MyIdeaGateway(); LocalHistoryFacade vcs = new InMemoryLocalHistoryFacade(); @Test - public void testSelectionWasNotChanged() { + public void testSelectionWasNotChanged() throws FilesTooBigForDiffException { List rr = createRevisions("abc\ndef\nghi", "abc1\ndef1\nghi1"); SelectionCalculator c = new SelectionCalculator(gw, rr, 0, 2); @@ -50,7 +47,7 @@ public class SelectionCalculatorTest extends LocalHistoryTestCase { } @Test - public void testSelectionWasMoved() { + public void testSelectionWasMoved() throws FilesTooBigForDiffException { List rr = createRevisions("abc\ndef\nghi", "def\nghi"); SelectionCalculator c = new SelectionCalculator(gw, rr, 0, 1); @@ -62,7 +59,7 @@ public class SelectionCalculatorTest extends LocalHistoryTestCase { } @Test - public void testSelectionForVeryOldRevisionTakenBackward() { + public void testSelectionForVeryOldRevisionTakenBackward() throws FilesTooBigForDiffException { List rr = createRevisions("ghi\nabc\ndef", "abc\nghi\ndef", "abc\ndef\nghi"); SelectionCalculator c = new SelectionCalculator(gw, rr, 0, 1); @@ -76,7 +73,7 @@ public class SelectionCalculatorTest extends LocalHistoryTestCase { } @Test - public void testNormalizingLineEnds() { + public void testNormalizingLineEnds() throws FilesTooBigForDiffException { List rr = createRevisions("abc\ndef\nghi", "abc\r\ndef\r\nghi"); SelectionCalculator c = new SelectionCalculator(gw, rr, 0, 1); @@ -88,7 +85,7 @@ public class SelectionCalculatorTest extends LocalHistoryTestCase { } @Test - public void testProgressOnGetSelection() { + public void testProgressOnGetSelection() throws FilesTooBigForDiffException { List rr = createRevisions("one", "two", "three", "four"); SelectionCalculator c = new SelectionCalculator(gw, rr, 0, 0); @@ -105,7 +102,7 @@ public class SelectionCalculatorTest extends LocalHistoryTestCase { } @Test - public void testProgressOnCanCalculate() { + public void testProgressOnCanCalculate() throws FilesTooBigForDiffException { List rr = createRevisions("one", "two"); SelectionCalculator c = new SelectionCalculator(gw, rr, 0, 0); diff --git a/platform/platform-api/src/com/intellij/ide/diff/DiffElement.java b/platform/platform-api/src/com/intellij/ide/diff/DiffElement.java index cca53d2dd08f..86670dcf3ea6 100644 --- a/platform/platform-api/src/com/intellij/ide/diff/DiffElement.java +++ b/platform/platform-api/src/com/intellij/ide/diff/DiffElement.java @@ -30,6 +30,7 @@ import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.encoding.EncodingManager; +import com.intellij.util.diff.FilesTooBigForDiffException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -115,7 +116,7 @@ public abstract class DiffElement implements Disposable { } @Nullable - public JComponent getDiffComponent(DiffElement element, Project project, Window parentWindow) { + public JComponent getDiffComponent(DiffElement element, Project project, Window parentWindow) throws FilesTooBigForDiffException { disposeDiffComponent(); DiffRequest request; diff --git a/platform/platform-api/src/com/intellij/openapi/diff/DiffPanel.java b/platform/platform-api/src/com/intellij/openapi/diff/DiffPanel.java index 1c9734df8911..497b6926c739 100644 --- a/platform/platform-api/src/com/intellij/openapi/diff/DiffPanel.java +++ b/platform/platform-api/src/com/intellij/openapi/diff/DiffPanel.java @@ -26,4 +26,5 @@ public interface DiffPanel extends DiffViewer, Disposable { void setContents(DiffContent content1, DiffContent content2); void setRequestFocus(boolean requestFocus); boolean hasDifferences(); + void setTooBigFileErrorContents(); } diff --git a/platform/platform-impl/src/com/intellij/ide/ui/customization/CustomizationUtil.java b/platform/platform-impl/src/com/intellij/ide/ui/customization/CustomizationUtil.java index 9ff9bde1e078..50719f754723 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/customization/CustomizationUtil.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/customization/CustomizationUtil.java @@ -24,6 +24,7 @@ import com.intellij.ui.PopupHandler; import com.intellij.ui.treeStructure.Tree; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.diff.Diff; +import com.intellij.util.diff.FilesTooBigForDiffException; import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -196,7 +197,13 @@ public class CustomizationUtil { private static void computeDiff(final ActionUrl[] defaultUserObjects, final ActionUrl[] currentUserObjects, final ArrayList actions) { - Diff.Change change = Diff.buildChanges(defaultUserObjects, currentUserObjects); + Diff.Change change = null; + try { + change = Diff.buildChanges(defaultUserObjects, currentUserObjects); + } + catch (FilesTooBigForDiffException e) { + LOG.info(e); + } while (change != null) { for (int i = 0; i < change.deleted; i++) { final int idx = change.line0 + i; diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/ex/DiffPanelOptions.java b/platform/platform-impl/src/com/intellij/openapi/diff/ex/DiffPanelOptions.java index ba46d2d96611..879a5d87028b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/ex/DiffPanelOptions.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/ex/DiffPanelOptions.java @@ -16,12 +16,12 @@ package com.intellij.openapi.diff.ex; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.diff.impl.DiffSideView; import com.intellij.openapi.diff.impl.DiffPanelImpl; -import com.intellij.openapi.fileEditor.OpenFileDescriptor; +import com.intellij.openapi.diff.impl.DiffSideView; import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.ui.DialogWrapperDialog; +import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.DialogWrapperDialog; import java.awt.*; diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java index b70fcb64082f..117e95602838 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java @@ -46,13 +46,16 @@ import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.ui.EditorNotificationPanel; import com.intellij.ui.PopupHandler; import com.intellij.util.containers.CacheOneStepIterator; +import com.intellij.util.diff.FilesTooBigForDiffException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -92,6 +95,8 @@ public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSid private boolean myDisposed = false; private final GenericDataProvider myDataProvider; private Project myProject; + private static final Key PANEL_KEY = new Key("DiffPanelImpl.CanNotCalculateDiffPanel"); + private CanNotCalculateDiffPanel myNotCalculateDiffPanel; public DiffPanelImpl(final Window owner, Project project, boolean enableToolbar) { myProject = project; @@ -159,7 +164,21 @@ public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSid } void rediff() { - setLineBlocks(myData.updateEditors()); + try { + if (myNotCalculateDiffPanel != null) { + myPanel.removeTopComponent(myNotCalculateDiffPanel); + } + setLineBlocks(myData.updateEditors()); + } + catch (FilesTooBigForDiffException e) { + setTooBigFileErrorContents(); + } + } + + public void setTooBigFileErrorContents() { + setLineBlocks(LineBlocks.EMPTY); + myNotCalculateDiffPanel = new CanNotCalculateDiffPanel(); + myPanel.insertTopComponent(myNotCalculateDiffPanel); } public void setTitle1(String title) { @@ -588,4 +607,10 @@ public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSid return super.getData(dataId); } } + + public static class CanNotCalculateDiffPanel extends EditorNotificationPanel { + public CanNotCalculateDiffPanel() { + myLabel.setText("Can not calculate diff. File is too big and there are too many changes."); + } + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/SimpleDiffPanelState.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/SimpleDiffPanelState.java index e57161f990fe..377b57c2cbca 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/SimpleDiffPanelState.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/SimpleDiffPanelState.java @@ -25,6 +25,7 @@ import com.intellij.openapi.diff.impl.fragments.LineFragment; import com.intellij.openapi.diff.impl.processing.TextCompareProcessor; import com.intellij.openapi.diff.impl.splitter.LineBlocks; import com.intellij.openapi.project.Project; +import com.intellij.util.diff.FilesTooBigForDiffException; import java.util.ArrayList; import java.util.Iterator; @@ -56,7 +57,6 @@ public class SimpleDiffPanelState implements } private LineBlocks addMarkup(final ArrayList lines) { - resetMarkup(); ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { for (Iterator iterator = lines.iterator(); iterator.hasNext();) { @@ -80,9 +80,9 @@ public class SimpleDiffPanelState implements ApplicationManager.getApplication().runWriteAction(new ResetMarkupRunnable(this)); } - public LineBlocks updateEditors() { + public LineBlocks updateEditors() throws FilesTooBigForDiffException { + resetMarkup(); if (myAppender1.getEditor() == null || myAppender2.getEditor() == null) { - resetMarkup(); return LineBlocks.EMPTY; } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ChangeList.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ChangeList.java index fc2bd543765c..b44c2225c2f6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ChangeList.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ChangeList.java @@ -27,6 +27,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.containers.HashSet; +import com.intellij.util.diff.FilesTooBigForDiffException; import java.util.*; @@ -77,7 +78,7 @@ public class ChangeList { return Collections.unmodifiableList(myChanges); } - public static ChangeList build(Document base, Document version, Parent parent) { + public static ChangeList build(Document base, Document version, Parent parent) throws FilesTooBigForDiffException { ChangeList result = new ChangeList(base, version, parent); ArrayList changes = result.buildChanges(); Collections.sort(changes, CHANGE_ORDER); @@ -102,7 +103,7 @@ public class ChangeList { return myDocuments[side.getIndex()]; } - private ArrayList buildChanges() { + private ArrayList buildChanges() throws FilesTooBigForDiffException { Document base = getDocument(FragmentSide.SIDE1); String[] baseLines = DiffUtil.convertToLines(base.getText()); Document version = getDocument(FragmentSide.SIDE2); diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/MergeList.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/MergeList.java index eae0f578e829..ecc4683eb587 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/MergeList.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/MergeList.java @@ -35,6 +35,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.*; import com.intellij.util.containers.FilteringIterator; import com.intellij.util.containers.SequenceIterator; +import com.intellij.util.diff.FilesTooBigForDiffException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -60,16 +61,15 @@ public class MergeList implements ChangeList.Parent, UserDataHolder { myChanges[1] = new ChangeList(base, right, this); } - public static MergeList create(Project project, Document left, Document base, Document right) { + public static MergeList create(Project project, Document left, Document base, Document right) throws FilesTooBigForDiffException { MergeList mergeList = new MergeList(project, left, base, right); String leftText = left.getText(); String baseText = base.getText(); String rightText = right.getText(); - // todo do not copy @NonNls final Object[] data = { - "Left\n" + leftText, - "\nBase\n" + baseText, - "\nRight\n" + rightText + "Left\n", leftText, + "\nBase\n", baseText, + "\nRight\n", rightText }; ContextLogger logger = new ContextLogger(LOG, new ContextLogger.SimpleContext(data)); List fragmentList = processText(leftText, baseText, rightText, logger); @@ -116,7 +116,7 @@ public class MergeList implements ChangeList.Parent, UserDataHolder { private static List processText(String leftText, String baseText, String rightText, - ContextLogger logger) { + ContextLogger logger) throws FilesTooBigForDiffException { DiffFragment[] leftFragments = DiffPolicy.DEFAULT_LINES.buildFragments(baseText, leftText); DiffFragment[] rightFragments = DiffPolicy.DEFAULT_LINES.buildFragments(baseText, rightText); int[] leftOffsets = {0, 0}; @@ -160,7 +160,7 @@ public class MergeList implements ChangeList.Parent, UserDataHolder { return text1 != null ? text1.length() : 0; } - public static MergeList create(DiffRequest data) { + public static MergeList create(DiffRequest data) throws FilesTooBigForDiffException { DiffContent[] contents = data.getContents(); return create(data.getProject(), contents[0].getDocument(), contents[1].getDocument(), contents[2].getDocument()); } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/MergeSearchHelper.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/MergeSearchHelper.java index 5d57adf66c20..9bdfed2d372f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/MergeSearchHelper.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/MergeSearchHelper.java @@ -50,6 +50,7 @@ public class MergeSearchHelper { } public static Change findChangeAt(EditorMouseEvent e, MergePanel2 mergePanel, int index) { + if (mergePanel.getMergeList() == null) return null; Editor editor = e.getEditor(); LOG.assertTrue(editor == mergePanel.getEditor(index)); LogicalPosition logicalPosition = editor.xyToLogicalPosition(e.getMouseEvent().getPoint()); diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergePanel2.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergePanel2.java index 0f3acad79a9b..bf1228f933af 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergePanel2.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergePanel2.java @@ -50,8 +50,10 @@ import com.intellij.openapi.ui.DialogBuilder; import com.intellij.openapi.ui.LabeledComponent; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.IconLoader; +import com.intellij.ui.EditorNotificationPanel; import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; +import com.intellij.util.diff.FilesTooBigForDiffException; import gnu.trove.TIntHashSet; import org.jetbrains.annotations.NotNull; @@ -200,20 +202,29 @@ public class MergePanel2 implements DiffViewer { private void tryInitView() { if (!hasAllEditors()) return; if (myMergeList != null) return; - myMergeList = MergeList.create(myData); - myMergeList.addListener(myDividersRepainter); - myStatusUpdater = StatusUpdater.install(myMergeList, myPanel); - Editor left = getEditor(0); - Editor base = getEditor(1); - Editor right = getEditor(2); - myMergeList.setMarkups(left, base, right); - EditingSides[] sides = {new MyEditingSides(FragmentSide.SIDE1), new MyEditingSides(FragmentSide.SIDE2)}; - myScrollSupport.install(sides); - for (int i = 0; i < myDividers.length; i++) { - myDividers[i].listenEditors(sides[i]); + try { + myMergeList = MergeList.create(myData); + myMergeList.addListener(myDividersRepainter); + myStatusUpdater = StatusUpdater.install(myMergeList, myPanel); + Editor left = getEditor(0); + Editor base = getEditor(1); + Editor right = getEditor(2); + myMergeList.setMarkups(left, base, right); + EditingSides[] sides = {new MyEditingSides(FragmentSide.SIDE1), new MyEditingSides(FragmentSide.SIDE2)}; + myScrollSupport.install(sides); + for (int i = 0; i < myDividers.length; i++) { + myDividers[i].listenEditors(sides[i]); + } + if (myScrollToFirstDiff) { + myPanel.requestScrollEditors(); + } } - if (myScrollToFirstDiff) { - myPanel.requestScrollEditors(); + catch (final FilesTooBigForDiffException e) { + myPanel.insertTopComponent(new EditorNotificationPanel() { + { + myLabel.setText(e.getMessage()); + } + }); } } @@ -452,9 +463,11 @@ public class MergePanel2 implements DiffViewer { public int[] getFragmentStartingLines() { TIntHashSet beginnings = new TIntHashSet(); - for (int i = 0; i < 2; i++) { - FragmentSide branchSide = FragmentSide.fromIndex(i); - beginnings.addAll(myMergeList.getChanges(branchSide).getLineBlocks().getBegginings(MergeList.BASE_SIDE)); + if (myMergeList != null) { + for (int i = 0; i < 2; i++) { + FragmentSide branchSide = FragmentSide.fromIndex(i); + beginnings.addAll(myMergeList.getChanges(branchSide).getLineBlocks().getBegginings(MergeList.BASE_SIDE)); + } } int[] result = beginnings.toArray(); Arrays.sort(result); diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeRequestImpl.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeRequestImpl.java index 6e3d25730a9d..cfa59cab88e9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeRequestImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeRequestImpl.java @@ -179,7 +179,7 @@ public class MergeRequestImpl extends MergeRequest { }); } - if (getMergeContent() != null) { + if (getMergeContent() != null && mergePanel.getMergeList() != null) { new AllResolvedListener(mergePanel, builder.getDialogWrapper()); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/ByWord.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/ByWord.java index 4cff8397fec6..b69334a905bc 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/ByWord.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/ByWord.java @@ -23,6 +23,7 @@ import com.intellij.openapi.diff.impl.highlighting.FragmentSide; import com.intellij.openapi.diff.impl.highlighting.Util; import com.intellij.openapi.util.TextRange; import com.intellij.util.diff.Diff; +import com.intellij.util.diff.FilesTooBigForDiffException; import java.util.ArrayList; @@ -34,7 +35,7 @@ class ByWord implements DiffPolicy{ myComparisonPolicy = comparisonPolicy; } - public DiffFragment[] buildFragments(String text1, String text2) { + public DiffFragment[] buildFragments(String text1, String text2) throws FilesTooBigForDiffException { Word[] words1 = buildWords(text1, myComparisonPolicy); Word[] words2 = buildWords(text2, myComparisonPolicy); Diff.Change change = Diff.buildChanges(words1, words2); @@ -115,7 +116,7 @@ class ByWord implements DiffPolicy{ version.addOneSide(prefix, wordCount); } - private void processEquals(int changed1, int changed2, FragmentBuilder result) { + private void processEquals(int changed1, int changed2, FragmentBuilder result) throws FilesTooBigForDiffException { while (result.getVersion1().getCurrentWordIndex() < changed1) { result.processEqual(); } @@ -206,11 +207,11 @@ class ByWord implements DiffPolicy{ myFragments.add(fragment); } - private void addEqual(Word word1, Word word2) { + private void addEqual(Word word1, Word word2) throws FilesTooBigForDiffException { addAll(CORRECTION.correct(new DiffFragment[]{myComparisonPolicy.createFragment(word1, word2)})); } - public void processEqual() { + public void processEqual() throws FilesTooBigForDiffException { Word word1 = myVersion1.getCurrentWord(); Word word2 = myVersion2.getCurrentWord(); addAll(fragmentsByChar(myVersion1.getCurrentWordPrefix(), myVersion2.getCurrentWordPrefix())); @@ -220,7 +221,7 @@ class ByWord implements DiffPolicy{ myVersion2.incCurrentWord(); } - private DiffFragment[] fragmentsByChar(String text1, String text2) { + private DiffFragment[] fragmentsByChar(String text1, String text2) throws FilesTooBigForDiffException { if (text1.length() == 0 && text2.length() == 0) { return DiffFragment.EMPTY_ARRAY; } @@ -230,7 +231,7 @@ class ByWord implements DiffPolicy{ return Util.cutFirst(fragments); } - private void addPostfixes() { + private void addPostfixes() throws FilesTooBigForDiffException { String postfix1 = myVersion1.getCurrentWordPostfixAndOneMore(); String postfix2 = myVersion2.getCurrentWordPostfixAndOneMore(); int length1 = postfix1.length(); @@ -268,7 +269,7 @@ class ByWord implements DiffPolicy{ myVersion2.incCurrentWord(wordCount2); } - public void addTails() { + public void addTails() throws FilesTooBigForDiffException { String tail1 = myVersion1.getNotProcessedTail(); String tail2 = myVersion2.getNotProcessedTail(); if (tail1.length() == 0 && tail2.length() == 0) return; diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/TextCompareProcessor.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/TextCompareProcessor.java index b59f188b3ed6..97b059fd93df 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/TextCompareProcessor.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/TextCompareProcessor.java @@ -23,6 +23,7 @@ import com.intellij.openapi.diff.impl.fragments.LineFragment; import com.intellij.openapi.diff.impl.highlighting.FragmentSide; import com.intellij.openapi.diff.impl.highlighting.LineBlockDivider; import com.intellij.openapi.diff.impl.highlighting.Util; +import com.intellij.util.diff.FilesTooBigForDiffException; import java.util.ArrayList; @@ -34,7 +35,7 @@ public class TextCompareProcessor { myComparisonPolicy = comparisonPolicy; } - public ArrayList process(String text1, String text2) { + public ArrayList process(String text1, String text2) throws FilesTooBigForDiffException { DiffFragment[] woFormattingBlocks = DiffPolicy.LINES_WO_FORMATTING.buildFragments(text1, text2); DiffFragment[] step1lineFragments = new DiffCorrection.TrueLineBlocks(myComparisonPolicy). correctAndNormalize(woFormattingBlocks); @@ -49,7 +50,7 @@ public class TextCompareProcessor { return lineBlocks; } - private ArrayList findSubFragments(String text1, String text2) { + private ArrayList findSubFragments(String text1, String text2) throws FilesTooBigForDiffException { DiffFragment[] fragments = new ByWord(myComparisonPolicy).buildFragments(text1, text2); fragments = DiffCorrection.ConnectSingleSideToChange.INSTANCE.correct(fragments); fragments = UniteSameType.INSTANCE.correct(fragments); diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/UniteSameType.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/UniteSameType.java index 97f117c51ccf..e79997a6fe17 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/UniteSameType.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/processing/UniteSameType.java @@ -19,6 +19,7 @@ import com.intellij.openapi.diagnostic.Logger; 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.util.diff.FilesTooBigForDiffException; class UniteSameType implements DiffCorrection { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.processing.UniteSameType"); @@ -70,7 +71,7 @@ class UniteSameType implements DiffCorrection { return collector.toArray(); } - public static DiffFragment uniteAll(DiffFragment[] fragments) { + public static DiffFragment uniteAll(DiffFragment[] fragments) throws FilesTooBigForDiffException { fragments = INSTANCE.correct(fragments); LOG.assertTrue(fragments.length == 1); return fragments[0]; diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/util/DiffPanelOutterComponent.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/util/DiffPanelOutterComponent.java index 4fa5a8cb78ed..1814f5f26ae3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/util/DiffPanelOutterComponent.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/util/DiffPanelOutterComponent.java @@ -37,6 +37,7 @@ public class DiffPanelOutterComponent extends JPanel implements DataProvider { private ScrollingPanel myScrollingPanel = null; private final JPanel myBottomContainer; private JComponent myBottomComponent; + private JPanel myWrapper; public DiffPanelOutterComponent(List diffTypes, DiffRequest.ToolbarAddons defaultActions) { super(new BorderLayout()); @@ -47,6 +48,8 @@ public class DiffPanelOutterComponent extends JPanel implements DataProvider { myDefaultActions = defaultActions; myToolbar = new DiffToolbarComponent(this); disableToolbar(false); + myWrapper = new JPanel(new BorderLayout()); + add(myWrapper, BorderLayout.CENTER); } public DiffToolbar resetToolbar() { @@ -54,11 +57,20 @@ public class DiffPanelOutterComponent extends JPanel implements DataProvider { return myToolbar.getToolbar(); } + public void resetDiffComponent(JComponent component, ScrollingPanel scrollingPanel) { + myWrapper.removeAll(); + insertDiffComponent(component, scrollingPanel); + } + public void insertDiffComponent(JComponent component, ScrollingPanel scrollingPanel) { - add(component, BorderLayout.CENTER); + myWrapper.add(component, BorderLayout.CENTER); setScrollingPanel(scrollingPanel); } + public void insertTopComponent(JComponent component) { + myWrapper.add(component, BorderLayout.NORTH); + } + public JComponent getBottomComponent() { return myBottomComponent; } @@ -152,6 +164,10 @@ public class DiffPanelOutterComponent extends JPanel implements DataProvider { myScrollState = NO_SCROLL_NEEDED; } + public void removeTopComponent(final JComponent jComponent) { + myWrapper.remove(jComponent); + } + private interface DeferScrollToFirstDiff { DeferScrollToFirstDiff scrollNow(ScrollingPanel panel, JComponent component); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/PersistentRangeHighlighterImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/PersistentRangeHighlighterImpl.java index c74afce3ccff..ca6f63f572c9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/PersistentRangeHighlighterImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/PersistentRangeHighlighterImpl.java @@ -22,6 +22,7 @@ import com.intellij.openapi.editor.impl.event.DocumentEventImpl; import com.intellij.openapi.editor.markup.HighlighterTargetArea; import com.intellij.openapi.editor.markup.MarkupModel; import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.util.diff.FilesTooBigForDiffException; import org.jetbrains.annotations.NotNull; /** @@ -41,19 +42,14 @@ class PersistentRangeHighlighterImpl extends RangeHighlighterImpl implements Ran @Override protected void changedUpdateImpl(DocumentEvent e) { + // todo Denis Zhdanov DocumentEventImpl event = (DocumentEventImpl)e; - if (PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, this)) { - setLine(event.translateLineViaDiff(getLine())); - if (getLine() < 0 || getLine() >= getDocument().getLineCount()) { - invalidate(e); - } - else { - DocumentEx document = getDocument(); - setIntervalStart(document.getLineStartOffset(getLine())); - setIntervalEnd(document.getLineEndOffset(getLine())); - } + final boolean shouldTranslateViaDiff = PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, this); + boolean wasTranslatedViaDiff = shouldTranslateViaDiff; + if (shouldTranslateViaDiff) { + wasTranslatedViaDiff = translatedViaDiff(e, event); } - else { + if (! wasTranslatedViaDiff) { super.changedUpdateImpl(e); if (isValid()) { setLine(getDocument().getLineNumber(getStartOffset())); @@ -65,6 +61,24 @@ class PersistentRangeHighlighterImpl extends RangeHighlighterImpl implements Ran } } + private boolean translatedViaDiff(DocumentEvent e, DocumentEventImpl event) { + try { + setLine(event.translateLineViaDiff(getLine())); + } + catch (FilesTooBigForDiffException e1) { + return false; + } + if (getLine() < 0 || getLine() >= getDocument().getLineCount()) { + invalidate(e); + } + else { + DocumentEx document = getDocument(); + setIntervalStart(document.getLineStartOffset(getLine())); + setIntervalEnd(document.getLineEndOffset(getLine())); + } + return true; + } + @Override public String toString() { return "PersistentRangeHighlighter" + diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/event/DocumentEventImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/event/DocumentEventImpl.java index 42117378489a..13b36d84f9a3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/event/DocumentEventImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/event/DocumentEventImpl.java @@ -19,6 +19,7 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.diff.Diff; +import com.intellij.util.diff.FilesTooBigForDiffException; import org.jetbrains.annotations.NotNull; public class DocumentEventImpl extends DocumentEvent { @@ -139,7 +140,7 @@ public class DocumentEventImpl extends DocumentEvent { return myIsWholeDocReplaced; } - public int translateLineViaDiff(int line) { + public int translateLineViaDiff(int line) throws FilesTooBigForDiffException { if (myChange == null) buildDiff(); if (myChange == null) return line; @@ -163,14 +164,14 @@ public class DocumentEventImpl extends DocumentEvent { return newLine; } - public int translateLineViaDiffStrict(int line) { + public int translateLineViaDiffStrict(int line) throws FilesTooBigForDiffException { if (myChange == null) buildDiff(); Diff.Change change = myChange; if (change == null) return line; return Diff.translateLine(change, line); } - private void buildDiff() { + private void buildDiff() throws FilesTooBigForDiffException { //Diff diff = new Diff(strings1, strings2); //myChange = diff.diff_2(false); myChange = Diff.buildChanges(myOldString, myNewString); diff --git a/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/highlighting/UtilTest.java b/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/highlighting/UtilTest.java index 7a95bcb3ec26..2ade31268418 100644 --- a/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/highlighting/UtilTest.java +++ b/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/highlighting/UtilTest.java @@ -4,6 +4,7 @@ import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.MultiCheck; import com.intellij.util.Assertion; import com.intellij.util.diff.Diff; +import com.intellij.util.diff.FilesTooBigForDiffException; import junit.framework.TestCase; public class UtilTest extends TestCase { @@ -80,7 +81,7 @@ public class UtilTest extends TestCase { assertTrue(line[0].isEqual()); } - public void testConcatEquals() { + public void testConcatEquals() throws FilesTooBigForDiffException { Object[] left = new String[]{"a", "x", "a", "b"}; Object[] right = new String[]{"a", "b"}; Diff.Change change = Diff.buildChanges(left, right); @@ -133,7 +134,7 @@ public class UtilTest extends TestCase { multiCheck.flush(); } - public void testConcatEqualsConcatenatesChanged() { + public void testConcatEqualsConcatenatesChanged() throws FilesTooBigForDiffException { String[] left = new String[]{"i1", "a", "i2", "a", "b"}; String[] right = new String[]{"a", "b"}; Diff.Change change = Diff.buildChanges(left, right); diff --git a/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/ByWordTest.java b/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/ByWordTest.java index 0110e4ff7d76..a5386bc0e591 100644 --- a/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/ByWordTest.java +++ b/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/ByWordTest.java @@ -7,6 +7,7 @@ import com.intellij.openapi.diff.impl.highlighting.FragmentStringConvertion; import com.intellij.openapi.util.TextRange; import com.intellij.util.Assertion; import com.intellij.util.StringConvertion; +import com.intellij.util.diff.FilesTooBigForDiffException; import gnu.trove.Equality; import junit.framework.AssertionFailedError; import junit.framework.TestCase; @@ -20,7 +21,7 @@ public class ByWordTest extends TestCase { CHECK.setEquality(new FragmentEquality()); } - public void test1() { + public void test1() throws FilesTooBigForDiffException { DiffPolicy byWord = new ByWord(ComparisonPolicy.DEFAULT); DiffFragment[] fragments = byWord.buildFragments("abc def, 123", "ab def, 12"); CHECK.compareAll(new DiffFragment[]{new DiffFragment("abc", "ab"), @@ -28,7 +29,7 @@ public class ByWordTest extends TestCase { new DiffFragment("123", "12")}, fragments); } - public void test2() { + public void test2() throws FilesTooBigForDiffException { DiffPolicy byWord = new ByWord(ComparisonPolicy.DEFAULT); DiffFragment[] fragments = byWord.buildFragments(" a[xy]+1", ",a[]+1"); CHECK.compareAll(new DiffFragment[]{new DiffFragment(" ", null), @@ -38,13 +39,13 @@ public class ByWordTest extends TestCase { new DiffFragment("]+1", "]+1")}, fragments); } - public void test3() { + public void test3() throws FilesTooBigForDiffException { DiffPolicy byWord = new ByWord(ComparisonPolicy.DEFAULT); DiffFragment[] fragments = byWord.buildFragments("0987\n a.g();\n", "yyyy\n"); CHECK.compareAll(new DiffFragment[]{new DiffFragment("0987\n a.g();\n", "yyyy\n")}, fragments); } - public void test4() { + public void test4() throws FilesTooBigForDiffException { DiffPolicy byWord = new ByWord(ComparisonPolicy.DEFAULT); DiffFragment[] fragments = byWord.buildFragments(" abc\n2222\n", " x = abc\nzzzz\n"); CHECK.compareAll(new DiffFragment[]{ @@ -55,7 +56,7 @@ public class ByWordTest extends TestCase { new DiffFragment("\n", "\n")}, fragments); } - public void testIdea58505() { + public void testIdea58505() throws FilesTooBigForDiffException { DiffPolicy byWord = new ByWord(ComparisonPolicy.DEFAULT); DiffFragment[] fragments = byWord.buildFragments(" if (eventMerger!=null && !dataSelection.getValueIsAdjusting()) {", " if (eventMerger!=null && (dataSelection==null || !dataSelection.getValueIsAdjusting())) {"); @@ -71,7 +72,7 @@ public class ByWordTest extends TestCase { }, fragments); } - public void testIdea58505Trim() { + public void testIdea58505Trim() throws FilesTooBigForDiffException { DiffPolicy byWord = new ByWord(ComparisonPolicy.TRIM_SPACE); DiffFragment[] fragments = byWord.buildFragments(" if (eventMerger!=null && !dataSelection.getValueIsAdjusting()) {", " if (eventMerger!=null && (dataSelection==null || !dataSelection.getValueIsAdjusting())) {"); @@ -87,7 +88,7 @@ public class ByWordTest extends TestCase { }, fragments); } - public void testIdea56428() { + public void testIdea56428() throws FilesTooBigForDiffException { DiffPolicy byWord = new ByWord(ComparisonPolicy.DEFAULT); DiffFragment[] fragments = byWord.buildFragments("messageInsertStatement = connection.prepareStatement(\"INSERT INTO AUDIT (AUDIT_TYPE_ID, STATUS, SERVER_ID, INSTANCE_ID, REQUEST_ID) VALUES (?, ?, ?, ?, ?)\");\n", "messageInsertStatement = connection.prepareStatement(\"INSERT INTO AUDIT (AUDIT_TYPE_ID, CREATION_TIMESTAMP, STATUS, SERVER_ID, INSTANCE_ID, REQUEST_ID) VALUES (?, ?, ?, ?, ?, ?)\");\n"); @@ -130,7 +131,7 @@ public class ByWordTest extends TestCase { new Word(text, new TextRange(3, 4))}, words); } - public void testLeadingFormatting() { + public void testLeadingFormatting() throws FilesTooBigForDiffException { DiffPolicy byWord = new ByWord(ComparisonPolicy.DEFAULT); DiffFragment[] fragments = byWord.buildFragments(" abc\n 123", " 123"); CHECK.compareAll(new DiffFragment[]{new DiffFragment(" abc\n", null), @@ -138,7 +139,7 @@ public class ByWordTest extends TestCase { UniteSameType.INSTANCE.correct(fragments)); } - public void testRestyleNewLines() { + public void testRestyleNewLines() throws FilesTooBigForDiffException { DiffPolicy byWord = new ByWord(ComparisonPolicy.DEFAULT); DiffFragment[] fragments = byWord.buildFragments("f(a, b);", "f(a,\n b);"); CHECK.compareAll(new DiffFragment[]{new DiffFragment("f(a,", "f(a,"), @@ -147,7 +148,7 @@ public class ByWordTest extends TestCase { UniteSameType.INSTANCE.correct(fragments)); } - public void testIgnoreSpaces() { + public void testIgnoreSpaces() throws FilesTooBigForDiffException { ByWord byWord = new ByWord(ComparisonPolicy.IGNORE_SPACE); DiffFragment[] fragments = byWord.buildFragments(" o.f(a)", "o. f( b)"); CHECK.compareAll(new DiffFragment[]{DiffFragment.unchanged(" o.f(", "o. f( "), @@ -156,7 +157,7 @@ public class ByWordTest extends TestCase { UniteSameType.INSTANCE.correct(fragments)); } - public void testIgnoreLeadingAndTrailing() { + public void testIgnoreLeadingAndTrailing() throws FilesTooBigForDiffException { ByWord byWord = new ByWord(ComparisonPolicy.TRIM_SPACE); checkEqual(byWord.buildFragments(" text", "text")); checkEqual(byWord.buildFragments("text ", "text")); diff --git a/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/CorrectionTest.java b/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/CorrectionTest.java index eeb97166da56..bcc2c3ef47c7 100644 --- a/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/CorrectionTest.java +++ b/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/CorrectionTest.java @@ -5,6 +5,7 @@ import com.intellij.openapi.diff.impl.ComparisonPolicy; import com.intellij.openapi.diff.impl.highlighting.FragmentEquality; import com.intellij.openapi.diff.impl.highlighting.FragmentStringConvertion; import com.intellij.util.Assertion; +import com.intellij.util.diff.FilesTooBigForDiffException; import junit.framework.TestCase; public class CorrectionTest extends TestCase { @@ -16,7 +17,7 @@ public class CorrectionTest extends TestCase { CHECK.setEquality(new FragmentEquality()); } - public void testTrueLineBlock() { + public void testTrueLineBlock() throws FilesTooBigForDiffException { DiffCorrection.TrueLineBlocks correction = new DiffCorrection.TrueLineBlocks(ComparisonPolicy.DEFAULT); DiffFragment[] fragments = correction.correctAndNormalize(new DiffFragment[]{ DiffFragment.unchanged(" 1\n ab\n x\n", " 2\n ab\n x\n"), @@ -30,7 +31,7 @@ public class CorrectionTest extends TestCase { fragments); } - public void testTrueLineBlocksWithSameLines() { + public void testTrueLineBlocksWithSameLines() throws FilesTooBigForDiffException { DiffCorrection.TrueLineBlocks correction = new DiffCorrection.TrueLineBlocks(ComparisonPolicy.DEFAULT); DiffFragment[] fragments = correction.correctAndNormalize(new DiffFragment[]{ DiffFragment.unchanged(" X\n X\n X", " X\n X\n X")}); @@ -39,7 +40,7 @@ public class CorrectionTest extends TestCase { fragments); } - public void testChangedSpaceCorrection() { + public void testChangedSpaceCorrection() throws FilesTooBigForDiffException { DiffCorrection correction = new DiffCorrection.ChangedSpace(ComparisonPolicy.DEFAULT); DiffFragment[] fragments = correction.correct(new DiffFragment[]{ new DiffFragment("x", "y"), @@ -63,7 +64,7 @@ public class CorrectionTest extends TestCase { CHECK.compareAll(new DiffFragment[]{new DiffFragment("\n", "\n"), new DiffFragment(null, "\n")}, fragments); } - public void testConcatinateSingleSide() { + public void testConcatinateSingleSide() throws FilesTooBigForDiffException { DiffCorrection correction = new DiffCorrection.ConcatenateSingleSide(); DiffFragment[] corrected = correction.correct( new DiffFragment[]{new DiffFragment(null, "a"), @@ -81,7 +82,7 @@ public class CorrectionTest extends TestCase { corrected); } - public void testConnectSingleSideToChange() { + public void testConnectSingleSideToChange() throws FilesTooBigForDiffException { DiffFragment first = DiffFragment.unchanged("a", "A"); DiffFragment oneSide = new DiffFragment(null, "b"); DiffFragment equal = new DiffFragment("c", "c"); diff --git a/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/LineBlocksDiffPolicyTest.java b/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/LineBlocksDiffPolicyTest.java index ecf19a14d998..badcc338a445 100644 --- a/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/LineBlocksDiffPolicyTest.java +++ b/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/LineBlocksDiffPolicyTest.java @@ -4,18 +4,19 @@ import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.ComparisonPolicy; import com.intellij.openapi.diff.impl.highlighting.FragmentSide; import com.intellij.openapi.diff.impl.highlighting.Util; +import com.intellij.util.diff.FilesTooBigForDiffException; import junit.framework.Assert; import junit.framework.TestCase; public class LineBlocksDiffPolicyTest extends TestCase{ - public void test() { + public void test() throws FilesTooBigForDiffException { DiffPolicy.LineBlocks diffPolicy = new DiffPolicy.LineBlocks(ComparisonPolicy.DEFAULT); checkPolicy(diffPolicy, "abc\n123\n", "ABC\nXYZ\n"); checkPolicy(diffPolicy, "abc\n123", "ABC\nXYZ"); checkPolicy(diffPolicy, "abc\n123\n", "ABC\nXYZ"); } - private void checkPolicy(DiffPolicy.LineBlocks diffPolicy, String text1, String text2) { + private void checkPolicy(DiffPolicy.LineBlocks diffPolicy, String text1, String text2) throws FilesTooBigForDiffException { DiffFragment[] fragments = diffPolicy.buildFragments(text1, text2); Assert.assertEquals(text1, Util.getText(fragments, FragmentSide.SIDE1)); assertEquals(text2, Util.getText(fragments, FragmentSide.SIDE2)); diff --git a/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/NormalizationTest.java b/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/NormalizationTest.java index 9bc447ce6fac..0e1f22e7e917 100644 --- a/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/NormalizationTest.java +++ b/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/NormalizationTest.java @@ -4,6 +4,7 @@ import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.highlighting.FragmentEquality; import com.intellij.openapi.diff.impl.highlighting.FragmentStringConvertion; import com.intellij.util.Assertion; +import com.intellij.util.diff.FilesTooBigForDiffException; import junit.framework.TestCase; public class NormalizationTest extends TestCase { @@ -15,7 +16,7 @@ public class NormalizationTest extends TestCase { CHECK.setEquality(new FragmentEquality()); } - public void testSingleSide() { + public void testSingleSide() throws FilesTooBigForDiffException { DiffCorrection correction = DiffCorrection.Normalize.INSTANCE; DiffFragment[] corrected = correction.correct( new DiffFragment[]{new DiffFragment(null, "a"), @@ -33,7 +34,7 @@ public class NormalizationTest extends TestCase { corrected); } - public void testUnitesEquals() { + public void testUnitesEquals() throws FilesTooBigForDiffException { DiffCorrection correction = DiffCorrection.Normalize.INSTANCE; DiffFragment[] fragments = correction.correct(new DiffFragment[]{new DiffFragment(null, "a"), new DiffFragment("x", "x"), diff --git a/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/TextCompareProcessorTest.java b/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/TextCompareProcessorTest.java index 2c74a0b82872..4d4ed9b9937f 100644 --- a/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/TextCompareProcessorTest.java +++ b/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/TextCompareProcessorTest.java @@ -2,12 +2,13 @@ package com.intellij.openapi.diff.impl.processing; import com.intellij.openapi.diff.impl.ComparisonPolicy; import com.intellij.openapi.diff.impl.fragments.LineFragment; +import com.intellij.util.diff.FilesTooBigForDiffException; import junit.framework.TestCase; import java.util.ArrayList; public class TextCompareProcessorTest extends TestCase { - public void testIgnoreWrappingEqualText() { + public void testIgnoreWrappingEqualText() throws FilesTooBigForDiffException { TextCompareProcessor processor = new TextCompareProcessor(ComparisonPolicy.IGNORE_SPACE); ArrayList lineFragments = processor.process("f(a, b)\n", "f(a,\nb)\n"); assertTrue(lineFragments.size() == 1); diff --git a/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/UniteSameTypeTest.java b/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/UniteSameTypeTest.java index 787bc2a54111..019124eb9a62 100644 --- a/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/UniteSameTypeTest.java +++ b/platform/platform-impl/testSrc/com/intellij/openapi/diff/impl/processing/UniteSameTypeTest.java @@ -4,6 +4,7 @@ import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.highlighting.FragmentEquality; import com.intellij.openapi.diff.impl.highlighting.FragmentStringConvertion; import com.intellij.util.Assertion; +import com.intellij.util.diff.FilesTooBigForDiffException; import junit.framework.TestCase; public class UniteSameTypeTest extends TestCase { @@ -15,7 +16,7 @@ public class UniteSameTypeTest extends TestCase { CHECK.setEquality(new FragmentEquality()); } - public void testUnitDifferentOnesides() { + public void testUnitDifferentOnesides() throws FilesTooBigForDiffException { DiffFragment[] fragments = UniteSameType.INSTANCE.correct(new DiffFragment[]{new DiffFragment("a", "b"), new DiffFragment(null, " "), new DiffFragment("\n ", null), @@ -23,7 +24,7 @@ public class UniteSameTypeTest extends TestCase { CHECK.compareAll(new DiffFragment[]{new DiffFragment("a\n ", "b "), new DiffFragment("x", "x")}, fragments); } - public void testUniteEqualsUnitesFormattingOnly() { + public void testUniteEqualsUnitesFormattingOnly() throws FilesTooBigForDiffException { DiffFragment changed = new DiffFragment("abc", "123"); DiffFragment equal = new DiffFragment("qqq", "qqq"); DiffFragment[] fragments = DiffCorrection.UnitEquals.INSTANCE.correct(new DiffFragment[]{ diff --git a/platform/util/src/com/intellij/openapi/diff/impl/ComparisonPolicy.java b/platform/util/src/com/intellij/openapi/diff/impl/ComparisonPolicy.java index 537264aa3510..308b3ec65bec 100644 --- a/platform/util/src/com/intellij/openapi/diff/impl/ComparisonPolicy.java +++ b/platform/util/src/com/intellij/openapi/diff/impl/ComparisonPolicy.java @@ -26,6 +26,7 @@ import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.diff.Diff; +import com.intellij.util.diff.FilesTooBigForDiffException; public abstract class ComparisonPolicy { private final String myName; @@ -34,7 +35,7 @@ public abstract class ComparisonPolicy { myName = name; } - public DiffFragment[] buildFragments(String[] strings1, String[] strings2) { + public DiffFragment[] buildFragments(String[] strings1, String[] strings2) throws FilesTooBigForDiffException { DiffFragmentBuilder builder = new DiffFragmentBuilder(strings1, strings2); Object[] wrappers1 = getWrappers(strings1); Object[] wrappers2 = getWrappers(strings2); @@ -42,7 +43,7 @@ public abstract class ComparisonPolicy { return builder.buildFragments(Util.concatEquals(change, wrappers1, wrappers2)); } - public DiffFragment[] buildDiffFragmentsFromLines(String[] lines1, String[] lines2) { + public DiffFragment[] buildDiffFragmentsFromLines(String[] lines1, String[] lines2) throws FilesTooBigForDiffException { DiffFragmentBuilder builder = new DiffFragmentBuilder(lines1, lines2); Object[] wrappers1 = getLineWrappers(lines1); Object[] wrappers2 = getLineWrappers(lines2); @@ -194,7 +195,7 @@ public abstract class ComparisonPolicy { return result; } - public DiffFragment[] buildFragments(String[] strings1, String[] strings2) { + public DiffFragment[] buildFragments(String[] strings1, String[] strings2) throws FilesTooBigForDiffException { DiffFragment[] fragments = super.buildFragments(strings1, strings2); DiffCorrection.FragmentsCollector collector = new DiffCorrection.FragmentsCollector(); collector.processAll(fragments, this); diff --git a/platform/util/src/com/intellij/openapi/diff/impl/processing/DiffCorrection.java b/platform/util/src/com/intellij/openapi/diff/impl/processing/DiffCorrection.java index 3f7d4da9d8cb..0b6854a277d2 100644 --- a/platform/util/src/com/intellij/openapi/diff/impl/processing/DiffCorrection.java +++ b/platform/util/src/com/intellij/openapi/diff/impl/processing/DiffCorrection.java @@ -22,11 +22,12 @@ import com.intellij.openapi.diff.impl.ComparisonPolicy; import com.intellij.openapi.diff.impl.highlighting.FragmentSide; import com.intellij.openapi.diff.impl.highlighting.Util; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.diff.FilesTooBigForDiffException; import java.util.ArrayList; public interface DiffCorrection { - DiffFragment[] correct(DiffFragment[] fragments); + DiffFragment[] correct(DiffFragment[] fragments) throws FilesTooBigForDiffException; class TrueLineBlocks implements DiffCorrection, FragmentProcessor { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.processing.DiffCorrection.TrueLineBlocks"); @@ -38,13 +39,13 @@ public interface DiffCorrection { myComparisonPolicy = comparisonPolicy; } - public DiffFragment[] correct(DiffFragment[] fragments) { + public DiffFragment[] correct(DiffFragment[] fragments) throws FilesTooBigForDiffException { FragmentsCollector collector = new FragmentsCollector(); collector.processAll(fragments, this); return collector.toArray(); } - public void process(DiffFragment fragment, FragmentsCollector collector) { + public void process(DiffFragment fragment, FragmentsCollector collector) throws FilesTooBigForDiffException { if (!fragment.isEqual()) { if (myComparisonPolicy.isEqual(fragment)) fragment = myComparisonPolicy.createFragment(fragment.getText1(), fragment.getText2()); @@ -58,7 +59,7 @@ public interface DiffCorrection { } } - public DiffFragment[] correctAndNormalize(DiffFragment[] fragments) { + public DiffFragment[] correctAndNormalize(DiffFragment[] fragments) throws FilesTooBigForDiffException { return Normalize.INSTANCE.correct(correct(fragments)); } } @@ -72,7 +73,7 @@ public interface DiffCorrection { myDiffPolicy = new DiffPolicy.ByChar(myComparisonPolicy); } - public void process(DiffFragment fragment, FragmentsCollector collector) { + public void process(DiffFragment fragment, FragmentsCollector collector) throws FilesTooBigForDiffException { if (!fragment.isChange()) { collector.add(fragment); return; @@ -111,7 +112,7 @@ public interface DiffCorrection { return text.substring(0, i); } - public DiffFragment[] correct(DiffFragment[] fragments) { + public DiffFragment[] correct(DiffFragment[] fragments) throws FilesTooBigForDiffException { FragmentsCollector collector = new FragmentsCollector(); collector.processAll(fragments, this); return collector.toArray(); @@ -119,7 +120,7 @@ public interface DiffCorrection { } interface FragmentProcessor { - void process(DiffFragment fragment, Collector collector); + void process(DiffFragment fragment, Collector collector) throws FilesTooBigForDiffException; } class BaseFragmentRunner { @@ -144,7 +145,7 @@ public interface DiffCorrection { public DiffFragment[] getFragments() { return myFragments; } - public void processAll(DiffFragment[] fragments, FragmentProcessor processor) { + public void processAll(DiffFragment[] fragments, FragmentProcessor processor) throws FilesTooBigForDiffException { myFragments = fragments; for (;myIndex < myFragments.length; myIndex++) { DiffFragment fragment = myFragments[myIndex]; @@ -198,7 +199,7 @@ public interface DiffCorrection { } } - public void processAll(DiffFragment[] fragments, FragmentProcessor processor) { + public void processAll(DiffFragment[] fragments, FragmentProcessor processor) throws FilesTooBigForDiffException { super.processAll(fragments, processor); flushMarked(); } @@ -208,7 +209,7 @@ public interface DiffCorrection { public static final DiffCorrection INSTANCE = new ConcatenateSingleSide(); private static final int DEFAULT_MODE = 1; - public DiffFragment[] correct(DiffFragment[] fragments) { + public DiffFragment[] correct(DiffFragment[] fragments) throws FilesTooBigForDiffException { FragmentBuffer buffer = new FragmentBuffer(); buffer.processAll(fragments, this); return buffer.toArray(); @@ -225,7 +226,7 @@ public interface DiffCorrection { private static final int EQUAL_MODE = 1; private static final int FORMATTING_MODE = 2; - public DiffFragment[] correct(DiffFragment[] fragments) { + public DiffFragment[] correct(DiffFragment[] fragments) throws FilesTooBigForDiffException { FragmentBuffer buffer = new FragmentBuffer(); buffer.processAll(fragments, this); return buffer.toArray(); @@ -243,7 +244,7 @@ public interface DiffCorrection { private Normalize() {} - public DiffFragment[] correct(DiffFragment[] fragments) { + public DiffFragment[] correct(DiffFragment[] fragments) throws FilesTooBigForDiffException { return UnitEquals.INSTANCE.correct(ConcatenateSingleSide.INSTANCE.correct(fragments)); } } @@ -252,7 +253,7 @@ public interface DiffCorrection { public static final ConnectSingleSideToChange INSTANCE = new ConnectSingleSideToChange(); private static final int CHANGE = 1; - public DiffFragment[] correct(DiffFragment[] fragments) { + public DiffFragment[] correct(DiffFragment[] fragments) throws FilesTooBigForDiffException { FragmentBuffer buffer = new FragmentBuffer(); buffer.processAll(fragments, this); return buffer.toArray(); diff --git a/platform/util/src/com/intellij/openapi/diff/impl/processing/DiffPolicy.java b/platform/util/src/com/intellij/openapi/diff/impl/processing/DiffPolicy.java index 2a932eb1c8d4..2b46ad96c6d6 100644 --- a/platform/util/src/com/intellij/openapi/diff/impl/processing/DiffPolicy.java +++ b/platform/util/src/com/intellij/openapi/diff/impl/processing/DiffPolicy.java @@ -18,9 +18,10 @@ package com.intellij.openapi.diff.impl.processing; import com.intellij.openapi.diff.LineTokenizer; import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.ComparisonPolicy; +import com.intellij.util.diff.FilesTooBigForDiffException; public interface DiffPolicy { - DiffFragment[] buildFragments(String text1, String text2); + DiffFragment[] buildFragments(String text1, String text2) throws FilesTooBigForDiffException; DiffPolicy LINES_WO_FORMATTING = new LineBlocks(ComparisonPolicy.IGNORE_SPACE); DiffPolicy DEFAULT_LINES = new LineBlocks(ComparisonPolicy.DEFAULT); @@ -32,7 +33,7 @@ public interface DiffPolicy { myComparisonPolicy = comparisonPolicy; } - public DiffFragment[] buildFragments(String text1, String text2) { + public DiffFragment[] buildFragments(String text1, String text2) throws FilesTooBigForDiffException { String[] strings1 = new LineTokenizer(text1).execute(); String[] strings2 = new LineTokenizer(text2).execute(); return myComparisonPolicy.buildDiffFragmentsFromLines(strings1, strings2); @@ -47,7 +48,7 @@ public interface DiffPolicy { myComparisonPolicy = comparisonPolicy; } - public DiffFragment[] buildFragments(String text1, String text2) { + public DiffFragment[] buildFragments(String text1, String text2) throws FilesTooBigForDiffException { return myComparisonPolicy.buildFragments(splitByChar(text1), splitByChar(text2)); } diff --git a/platform/util/src/com/intellij/util/diff/Diff.java b/platform/util/src/com/intellij/util/diff/Diff.java index b3f85da2c673..2424b60c811e 100644 --- a/platform/util/src/com/intellij/util/diff/Diff.java +++ b/platform/util/src/com/intellij/util/diff/Diff.java @@ -39,6 +39,7 @@ public class Diff { } public static Change buildChanges(T[] objects1, T[] objects2) throws FilesTooBigForDiffException { + // Old variant of enumerator worked incorrectly with null values. // This check is to ensure that the corrected version does not introduce bugs. for (T anObjects1 : objects1) LOG.assertTrue(anObjects1 != null); @@ -175,6 +176,10 @@ public class Diff { private Change myFirstChange; private Change myLastChange; + public ChangeBuilder(final int startShift) { + skip(startShift, startShift); + } + public void addChange(int first, int second) { Change change = new Change(myIndex1, myIndex2, first, second, null); if (myLastChange != null) myLastChange.link = change; diff --git a/platform/util/src/com/intellij/util/diff/FilesTooBigForDiffException.java b/platform/util/src/com/intellij/util/diff/FilesTooBigForDiffException.java new file mode 100644 index 000000000000..71acb1c38afa --- /dev/null +++ b/platform/util/src/com/intellij/util/diff/FilesTooBigForDiffException.java @@ -0,0 +1,19 @@ +package com.intellij.util.diff; + +/** + * @author irengrig + * Date: 5/28/11 + * Time: 10:30 PM + */ +public class FilesTooBigForDiffException extends Exception { + private final int myNumLines; + + public FilesTooBigForDiffException(int numLines) { + super("Can not calculate diff. File is too big and there are too many changes."); + myNumLines = numLines; + } + + public int getNumLines() { + return myNumLines; + } +} diff --git a/platform/util/src/com/intellij/util/diff/IntLCS.java b/platform/util/src/com/intellij/util/diff/IntLCS.java index fd58b649845c..1a6529483442 100644 --- a/platform/util/src/com/intellij/util/diff/IntLCS.java +++ b/platform/util/src/com/intellij/util/diff/IntLCS.java @@ -44,7 +44,7 @@ class IntLCS { myCurrentEnds = new int[myMaxX + myMaxY + 1]; } - public int execute() { + public int execute() throws FilesTooBigForDiffException { for (int d =0; d <= myMaxX + myMaxY; d++) { int minDiag = -calcBound(myMaxY, d); int maxDiag = calcBound(myMaxX, d); @@ -103,7 +103,7 @@ class IntLCS { return skipEquals(x, y); } - private int encodeStep(int prevEnd, int diagLength, int tDiagonal, boolean afterVertical) { + private int encodeStep(int prevEnd, int diagLength, int tDiagonal, boolean afterVertical) throws FilesTooBigForDiffException { int end = prevEnd + diagLength; int prevDiagonal = tDiagonal + myMaxY; if (!afterVertical) end++; diff --git a/platform/util/src/com/intellij/util/diff/LinkedDiffPaths.java b/platform/util/src/com/intellij/util/diff/LinkedDiffPaths.java index 078e9d0d9607..dd3bdfa27968 100644 --- a/platform/util/src/com/intellij/util/diff/LinkedDiffPaths.java +++ b/platform/util/src/com/intellij/util/diff/LinkedDiffPaths.java @@ -19,6 +19,8 @@ package com.intellij.util.diff; * @author dyoma */ final class LinkedDiffPaths { + private static final int MAX_LEN = 10000000; + private int[] mySteps = new int[10]; private int[] myPrevSteps = new int[10]; private int myPosition = 0; @@ -53,7 +55,7 @@ final class LinkedDiffPaths { return myMaxY + 1; } - public int encodeStep(int x, int y, int diagLength, boolean afterVertical, int prevIndex) { + public int encodeStep(int x, int y, int diagLength, boolean afterVertical, int prevIndex) throws FilesTooBigForDiffException { int encodedPath = diagLength; if (afterVertical) encodedPath |= VERTICAL_DIRECTION_FLAG; int position = incPosition(); @@ -64,7 +66,7 @@ final class LinkedDiffPaths { return position; } - private int incPosition() { + private int incPosition() throws FilesTooBigForDiffException { int length = myPrevSteps.length; if (myPosition == length - 1) { myPrevSteps = copy(length, myPrevSteps); @@ -74,7 +76,10 @@ final class LinkedDiffPaths { return myPosition; } - private int[] copy(int length, int[] prevArray) { + private int[] copy(int length, int[] prevArray) throws FilesTooBigForDiffException { + if (length * 2 >= MAX_LEN) { + throw new FilesTooBigForDiffException(MAX_LEN); + } int[] array = new int[length * 2]; System.arraycopy(prevArray, 0, array, 0, length); return array; diff --git a/platform/util/testSrc/com/intellij/util/diff/DiffTest.java b/platform/util/testSrc/com/intellij/util/diff/DiffTest.java index f633e8fa334b..1c55f9603f81 100644 --- a/platform/util/testSrc/com/intellij/util/diff/DiffTest.java +++ b/platform/util/testSrc/com/intellij/util/diff/DiffTest.java @@ -56,7 +56,7 @@ public class DiffTest extends TestCase { IntLCSTest.checkLastChange(change, 5, 5, 3, 0); // inserted: AB2 } - public void testEqualUpToOneEnd() throws FilesTooBigFirDiffException { + public void testEqualUpToOneEnd() throws FilesTooBigForDiffException { Diff.Change change = Diff.buildChanges(DATA_AB, new Object[]{"a", "b", "1"}); IntLCSTest.checkLastChange(change, 2, 2, 1, 0); } diff --git a/platform/util/testSrc/com/intellij/util/diff/IntLCSTest.java b/platform/util/testSrc/com/intellij/util/diff/IntLCSTest.java index 57a028ed115f..c2a350dab1c2 100644 --- a/platform/util/testSrc/com/intellij/util/diff/IntLCSTest.java +++ b/platform/util/testSrc/com/intellij/util/diff/IntLCSTest.java @@ -22,47 +22,47 @@ import junit.framework.TestCase; * @author dyoma */ public class IntLCSTest extends TestCase { - public void testDiag() { + public void testDiag() throws FilesTooBigForDiffException { Diff.Change change = buildChange(new int[]{1, 2, 3}, new int[]{1, 2, 3}, 0); assertNull(change); } - public void testOneAtBegging() { + public void testOneAtBegging() throws FilesTooBigForDiffException { Diff.Change change = buildChange(new int[]{1, 2}, new int[]{1, 3}, 2); checkLastChange(change, 1, 1, 1, 1); } - public void testOneAntEnd() { + public void testOneAntEnd() throws FilesTooBigForDiffException { Diff.Change change = buildChange(new int[]{1, 3}, new int[]{2, 3}, 2); checkLastChange(change, 0, 0, 1, 1); } - public void testOneOverAtEnd() { + public void testOneOverAtEnd() throws FilesTooBigForDiffException { Diff.Change change = buildChange(new int[]{1, 2}, new int[]{1, 2, 3}, 1); checkLastChange(change, 2, 2, 1, 0); } - public void testOneOverAtBegging() { + public void testOneOverAtBegging() throws FilesTooBigForDiffException { Diff.Change change = buildChange(new int[]{1, 2, 3}, new int[]{2, 3}, 1); checkLastChange(change, 0, 0, 0, 1); } - public void testOneTail() { + public void testOneTail() throws FilesTooBigForDiffException { assertEquals(1, new IntLCS(new int[]{1, 2}, new int[]{1, 2, 3}).execute()); } - public void testSingleMiddle() { + public void testSingleMiddle() throws FilesTooBigForDiffException { Diff.Change change = buildChange(new int[]{1, 2, 3}, new int[]{4, 2, 5}, 4); checkChange(change, 0, 0, 1, 1); checkLastChange(change.link, 2, 2, 1, 1); } - public void testAbsolutelyDifferent() { + public void testAbsolutelyDifferent() throws FilesTooBigForDiffException { assertEquals(4, new IntLCS(new int[]{1, 2}, new int[]{3, 4}).execute()); assertEquals(6, new IntLCS(new int[]{1, 2, 3}, new int[]{4, 5, 6}).execute()); } - private Diff.Change buildChange(int[] first, int[] second, int expectedNonDiags) { + private Diff.Change buildChange(int[] first, int[] second, int expectedNonDiags) throws FilesTooBigForDiffException { IntLCS intLCS = new IntLCS(first, second); assertEquals(expectedNonDiags, intLCS.execute()); Reindexer reindexer = new Reindexer(); diff --git a/platform/util/testSrc/com/intellij/util/diff/LinkedDiffPathsTest.java b/platform/util/testSrc/com/intellij/util/diff/LinkedDiffPathsTest.java index f9b2b23632eb..befb38a60b8d 100644 --- a/platform/util/testSrc/com/intellij/util/diff/LinkedDiffPathsTest.java +++ b/platform/util/testSrc/com/intellij/util/diff/LinkedDiffPathsTest.java @@ -26,7 +26,7 @@ public class LinkedDiffPathsTest extends TestCase { return new LinkedDiffPaths(maxX, maxY); } - public void testOneDeleteAtferEnd() { + public void testOneDeleteAtferEnd() throws FilesTooBigForDiffException { LinkedDiffPaths paths = createPaths(2, 3); int key = paths.encodeStep(1, 1, 2, false, -1); paths.encodeStep(1, 2, 0, true, key); @@ -34,14 +34,14 @@ public class LinkedDiffPathsTest extends TestCase { IntLCSTest.checkLastChange(change, 2, 2, 1, 0); } - public void testOneInsertedAtBegging() { + public void testOneInsertedAtBegging() throws FilesTooBigForDiffException { LinkedDiffPaths paths = createPaths(3, 2); paths.encodeStep(2, 1, 2, false, -1); Diff.Change change = decode(paths); IntLCSTest.checkLastChange(change, 0, 0, 0, 1); } - public void testSingleMiddleChange() { + public void testSingleMiddleChange() throws FilesTooBigForDiffException { LinkedDiffPaths paths = createPaths(3, 3); int key = paths.encodeStep(0, 0, 1, true, -1); key = paths.encodeStep(1, 0, 0, false, key); @@ -49,7 +49,7 @@ public class LinkedDiffPathsTest extends TestCase { IntLCSTest.checkLastChange(decode(paths), 1, 1, 1, 1); } - public void testSingleChangeAtEnd() { + public void testSingleChangeAtEnd() throws FilesTooBigForDiffException { LinkedDiffPaths paths = createPaths(2, 2); int key = paths.encodeStep(0, 0, 1, false, -1); key = paths.encodeStep(0, 1, 0, true, key); @@ -57,7 +57,7 @@ public class LinkedDiffPathsTest extends TestCase { IntLCSTest.checkLastChange(decode(paths), 1, 1, 1, 1); } - public void testNotSquareChangeAtEnd() { + public void testNotSquareChangeAtEnd() throws FilesTooBigForDiffException { LinkedDiffPaths paths = createPaths(2, 3); int key = paths.encodeStep(0, 0, 1, false, -1); key = paths.encodeStep(0, 1, 0, true, key); diff --git a/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/TextPatchBuilder.java b/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/TextPatchBuilder.java index 37607fdbbef5..f73dfc3d10d1 100644 --- a/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/TextPatchBuilder.java +++ b/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/TextPatchBuilder.java @@ -26,6 +26,7 @@ import com.intellij.openapi.diff.impl.util.TextDiffTypeEnum; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.util.BeforeAfter; +import com.intellij.util.diff.FilesTooBigForDiffException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -116,8 +117,15 @@ public class TextPatchBuilder { String[] beforeLines = new LineTokenizer(beforeContent).execute(); String[] afterLines = new LineTokenizer(afterContent).execute(); - DiffFragment[] woFormattingBlocks = DiffPolicy.LINES_WO_FORMATTING.buildFragments(beforeContent, afterContent); - DiffFragment[] step1lineFragments = new DiffCorrection.TrueLineBlocks(ComparisonPolicy.DEFAULT).correctAndNormalize(woFormattingBlocks); + DiffFragment[] woFormattingBlocks; + DiffFragment[] step1lineFragments; + try { + woFormattingBlocks = DiffPolicy.LINES_WO_FORMATTING.buildFragments(beforeContent, afterContent); + step1lineFragments = new DiffCorrection.TrueLineBlocks(ComparisonPolicy.DEFAULT).correctAndNormalize(woFormattingBlocks); + } + catch (FilesTooBigForDiffException e) { + throw new VcsException("File '" + myBasePath + "' is too big and there are too many changes to build diff", e); + } ArrayList fragments = new DiffFragmentsProcessor().process(step1lineFragments); if (fragments.size() > 1 || (fragments.size() == 1 && fragments.get(0).getType() != null && fragments.get(0).getType() != TextDiffTypeEnum.NONE)) { diff --git a/platform/vcs-impl/src/com/intellij/diff/FindBlock.java b/platform/vcs-impl/src/com/intellij/diff/FindBlock.java index dbd53a21b40a..af874165b453 100644 --- a/platform/vcs-impl/src/com/intellij/diff/FindBlock.java +++ b/platform/vcs-impl/src/com/intellij/diff/FindBlock.java @@ -17,6 +17,7 @@ package com.intellij.diff; import com.intellij.openapi.util.text.LineTokenizer; import com.intellij.util.diff.Diff; +import com.intellij.util.diff.FilesTooBigForDiffException; /** * author: lesya @@ -36,7 +37,7 @@ public class FindBlock { } - public Block getBlockInThePrevVersion() { + public Block getBlockInThePrevVersion() throws FilesTooBigForDiffException { Diff.Change change = Diff.buildChanges(myResult.getSource(), myCurrentVersion.getSource()); while (change != null) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffPanel.java b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffPanel.java index 6e5c52d614bb..d802973ddda4 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffPanel.java +++ b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffPanel.java @@ -33,7 +33,7 @@ import com.intellij.ui.TableSpeedSearch; import com.intellij.ui.components.JBLabel; import com.intellij.ui.components.JBLoadingPanel; import com.intellij.ui.table.JBTable; -import com.intellij.util.containers.Convertor; +import com.intellij.util.diff.FilesTooBigForDiffException; import com.intellij.util.ui.UIUtil; import javax.swing.*; @@ -271,7 +271,14 @@ public class DirDiffPanel implements Disposable { } clearDiffPanel(); if (element.getType() == DType.CHANGED) { - myDiffPanelComponent = element.getSource().getDiffComponent(element.getTarget(), project, myDiffWindow.getWindow()); + try { + myDiffPanelComponent = element.getSource().getDiffComponent(element.getTarget(), project, myDiffWindow.getWindow()); + } + catch (FilesTooBigForDiffException e) { + // todo KB: check + myDiffPanelComponent = null; + myErrorLabel = new JLabel("Can not build diff for file " + element.getTarget().getPath() + ". File is too big and there are too many changes."); + } if (myDiffPanelComponent != null) { myDiffPanel.add(myDiffPanelComponent, BorderLayout.CENTER); myCurrentElement = element.getSource(); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java index d9b6c8ad647b..a51da92a46e8 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java @@ -24,14 +24,18 @@ import com.intellij.openapi.editor.event.DocumentAdapter; import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.editor.impl.DocumentImpl; import com.intellij.openapi.editor.markup.*; -import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsBundle; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.EditorNotificationPanel; +import com.intellij.util.diff.FilesTooBigForDiffException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -46,6 +50,8 @@ import java.util.ListIterator; */ public class LineStatusTracker { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.ex.LineStatusTracker"); + private static final Key PANEL_KEY = new Key("LineStatusTracker.CanNotCalculateDiffPanel"); + private final Object myLock = new Object(); // true -> have contents private BaseLoadState myBaseLoaded; @@ -64,8 +70,12 @@ public class LineStatusTracker { @Nullable private RevisionPack myBaseRevisionNumber; private String myPreviousBaseRevision; + private boolean myAnathemaThrown; + private FileEditorManager myFileEditorManager; + private final VirtualFile myVirtualFile; - private LineStatusTracker(final Document document, final Document upToDateDocument, final Project project) { + private LineStatusTracker(final Document document, final Document upToDateDocument, final Project project, final VirtualFile virtualFile) { + myVirtualFile = virtualFile; myApplication = ApplicationManager.getApplication(); myDocument = document; myUpToDateDocument = upToDateDocument; @@ -73,6 +83,8 @@ public class LineStatusTracker { myProject = project; myBaseLoaded = BaseLoadState.LOADING; myRanges = new ArrayList(); + myAnathemaThrown = false; + myFileEditorManager = FileEditorManager.getInstance(myProject); } public void initialize(@NotNull final String upToDateContent, @NotNull RevisionPack baseRevisionNumber) { @@ -119,14 +131,34 @@ public class LineStatusTracker { myApplication.assertReadAccessAllowed(); synchronized (myLock) { + removeAnathema(); removeHighlightersFromMarkupModel(); - myRanges = new RangesBuilder(myDocument, myUpToDateDocument).getRanges(); + try { + myRanges = new RangesBuilder(myDocument, myUpToDateDocument).getRanges(); + } + catch (FilesTooBigForDiffException e) { + installAnathema(); + return; + } for (final Range range : myRanges) { range.setHighlighter(createHighlighter(range)); } } } + private void removeAnathema() { + if (! myAnathemaThrown) return; + myAnathemaThrown = false; + final FileEditor[] editors = myFileEditorManager.getEditors(myVirtualFile); + for (FileEditor editor : editors) { + final CanNotCalculateDiffPanel panel = editor.getUserData(PANEL_KEY); + if (panel != null) { + myFileEditorManager.removeTopComponent(editor, panel); + editor.putUserData(PANEL_KEY, null); + } + } + } + @SuppressWarnings({"AutoBoxing"}) private RangeHighlighter createHighlighter(final Range range) { int first = @@ -163,6 +195,7 @@ public class LineStatusTracker { if (myDocumentListener != null) { myDocument.removeDocumentListener(myDocumentListener); } + removeAnathema(); removeHighlightersFromMarkupModel(); myRanges.clear(); } @@ -173,7 +206,7 @@ public class LineStatusTracker { } public VirtualFile getVirtualFile() { - return FileDocumentManager.getInstance().getFile(getDocument()); + return myVirtualFile; } public List getRanges() { @@ -192,6 +225,7 @@ public class LineStatusTracker { public void startBulkUpdate() { synchronized (myLock) { myBulkUpdate = true; + removeAnathema(); removeHighlightersFromMarkupModel(); myRanges.clear(); } @@ -228,6 +262,7 @@ public class LineStatusTracker { myUpToDateDocument.setReadOnly(false); myUpToDateDocument.setText(""); myUpToDateDocument.setReadOnly(true); + removeAnathema(); removeHighlightersFromMarkupModel(); myRanges.clear(); myBaseLoaded = BaseLoadState.LOADING; @@ -246,7 +281,7 @@ public class LineStatusTracker { myApplication.assertWriteAccessAllowed(); synchronized (myLock) { - if (myBulkUpdate || (BaseLoadState.LOADED != myBaseLoaded)) return; + if (myBulkUpdate || myAnathemaThrown || (BaseLoadState.LOADED != myBaseLoaded)) return; try { myFirstChangedLine = myDocument.getLineNumber(e.getOffset()); myLastChangedLine = myDocument.getLineNumber(e.getOffset() + e.getOldLength()); @@ -298,7 +333,7 @@ public class LineStatusTracker { myApplication.assertWriteAccessAllowed(); synchronized (myLock) { - if (myBulkUpdate || (BaseLoadState.LOADED != myBaseLoaded)) return; + if (myBulkUpdate || myAnathemaThrown || (BaseLoadState.LOADED != myBaseLoaded)) return; try { int line = myDocument.getLineNumber(e.getOffset() + e.getNewLength()); @@ -340,11 +375,15 @@ public class LineStatusTracker { } } } catch (ProcessCanceledException ignore) { + } catch (FilesTooBigForDiffException e1) { + installAnathema(); + removeHighlightersFromMarkupModel(); + myRanges.clear(); } } } - private List getNewChangedRanges() { + private List getNewChangedRanges() throws FilesTooBigForDiffException { List lines = new DocumentWrapper(myDocument).getLines(myFirstChangedLine, myLastChangedLine); List uLines = new DocumentWrapper(myUpToDateDocument) .getLines(myUpToDateFirstLine, myUpToDateLastLine); @@ -567,9 +606,9 @@ public class LineStatusTracker { } } - public static LineStatusTracker createOn(final Document doc, final Project project) { + public static LineStatusTracker createOn(@Nullable VirtualFile virtualFile, final Document doc, final Project project) { final Document document = new DocumentImpl(true); - return new LineStatusTracker(doc, document, project); + return new LineStatusTracker(doc, document, project, virtualFile); } public void baseRevisionLoadFailed() { @@ -621,4 +660,23 @@ public class LineStatusTracker { return myRevision.hashCode(); } } + + private void installAnathema() { + myAnathemaThrown = true; + final FileEditor[] editors = myFileEditorManager.getAllEditors(myVirtualFile); + for (FileEditor editor : editors) { + CanNotCalculateDiffPanel panel = editor.getUserData(PANEL_KEY); + if (panel == null) { + final CanNotCalculateDiffPanel newPanel = new CanNotCalculateDiffPanel(); + editor.putUserData(PANEL_KEY, newPanel); + myFileEditorManager.addTopComponent(editor, newPanel); + } + } + } + + public static class CanNotCalculateDiffPanel extends EditorNotificationPanel { + public CanNotCalculateDiffPanel() { + myLabel.setText("Can not highlight changed lines. File is too big and there are too many changes."); + } + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java index a344c2b7bb04..e17f868ffad4 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java @@ -18,6 +18,7 @@ package com.intellij.openapi.vcs.ex; import com.intellij.openapi.editor.Document; import com.intellij.util.ArrayUtil; import com.intellij.util.diff.Diff; +import com.intellij.util.diff.FilesTooBigForDiffException; import java.util.LinkedList; import java.util.List; @@ -29,11 +30,11 @@ import java.util.List; public class RangesBuilder { private List myRanges; - public RangesBuilder(Document current, Document upToDate) { + public RangesBuilder(Document current, Document upToDate) throws FilesTooBigForDiffException { this(new DocumentWrapper(current).getLines(), new DocumentWrapper(upToDate).getLines(), 0, 0); } - public RangesBuilder(List current, List upToDate, int shift, int uShift) { + public RangesBuilder(List current, List upToDate, int shift, int uShift) throws FilesTooBigForDiffException { myRanges = new LinkedList(); Diff.Change ch = Diff.buildChanges(ArrayUtil.toStringArray(upToDate), ArrayUtil.toStringArray(current)); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/impl/VcsHistoryDialog.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/impl/VcsHistoryDialog.java index 05c73d7f02f6..0695282ba701 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/impl/VcsHistoryDialog.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/impl/VcsHistoryDialog.java @@ -38,6 +38,7 @@ import com.intellij.openapi.vcs.history.*; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.table.TableView; +import com.intellij.util.diff.FilesTooBigForDiffException; import com.intellij.util.text.DateFormatUtil; import com.intellij.util.ui.ColumnInfo; import com.intellij.util.ui.ListTableModel; @@ -240,7 +241,15 @@ public class VcsHistoryDialog extends DialogWrapper implements DataProvider { if (myIsInLoading) return; if (myChangesOnlyCheckBox.isSelected()) { loadContentsFor(myRevisions.toArray(new VcsFileRevision[myRevisions.size()])); - ((ListTableModel)myList.getModel()).setItems(filteredRevisions()); + try { + ((ListTableModel)myList.getModel()).setItems(filteredRevisions()); + } + catch (FilesTooBigForDiffException e) { + myChangesOnlyCheckBox.setEnabled(false); + myChangesOnlyCheckBox.setSelected(false); + setErrorText(e.getMessage()); + ((ListTableModel)myList.getModel()).setItems(myRevisions); + } ((ListTableModel)myList.getModel()).fireTableDataChanged(); updateDiff(0, 0); @@ -252,7 +261,7 @@ public class VcsHistoryDialog extends DialogWrapper implements DataProvider { } - private List filteredRevisions() { + private List filteredRevisions() throws FilesTooBigForDiffException { ArrayList result = new ArrayList(); VcsFileRevision nextRevision = myRevisions.get(myRevisions.size() - 1); result.add(nextRevision); @@ -292,8 +301,13 @@ public class VcsHistoryDialog extends DialogWrapper implements DataProvider { } if (myIsDisposed) return; - myDiffPanel.setContents(new SimpleContent(getContentToShow(firstRev), myContentFileType), - new SimpleContent(getContentToShow(secondRev), myContentFileType)); + try { + myDiffPanel.setContents(new SimpleContent(getContentToShow(firstRev), myContentFileType), + new SimpleContent(getContentToShow(secondRev), myContentFileType)); + } + catch (FilesTooBigForDiffException e) { + myDiffPanel.setTooBigFileErrorContents(); + } myDiffPanel.setTitle1(VcsBundle.message("diff.content.title.revision.number", firstRev.getRevisionNumber())); myDiffPanel.setTitle2(VcsBundle.message("diff.content.title.revision.number", secondRev.getRevisionNumber())); @@ -395,14 +409,14 @@ public class VcsHistoryDialog extends DialogWrapper implements DataProvider { return null; } - protected String getContentToShow(VcsFileRevision revision) { + protected String getContentToShow(VcsFileRevision revision) throws FilesTooBigForDiffException { final Block block = getBlock(revision); if (block == null) return ""; return block.getBlockContent(); } @Nullable - private Block getBlock(VcsFileRevision revision){ + private Block getBlock(VcsFileRevision revision) throws FilesTooBigForDiffException { if (myRevisionToContentMap.containsKey(revision)) return myRevisionToContentMap.get(revision); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.java index 96dc1ff15c6f..37e2a0df0656 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.java @@ -263,7 +263,7 @@ public class LineStatusTrackerManager implements ProjectComponent, LineStatusTra if (myLineStatusTrackers.containsKey(document)) return; assert ! myPartner.containsKey(document); - final LineStatusTracker tracker = LineStatusTracker.createOn(document, myProject); + final LineStatusTracker tracker = LineStatusTracker.createOn(virtualFile, document, myProject); myLineStatusTrackers.put(document, tracker); startAlarm(document, virtualFile);