VCS: diff for big files - throw exception if algorithm tries to allocate array bigger than 10000000 line status tracker and diff/merge shows notifications

This commit is contained in:
irengrig
2011-06-01 18:03:50 +04:00
parent c0533211ad
commit 848382aff2
50 changed files with 438 additions and 189 deletions
@@ -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() {
@@ -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
@@ -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));
}
@@ -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<FilePath, String>(myAfterFile, ourCannotLoadPreviousRevision));
return;
}
ArrayList<LineFragment> lineFragments = getLineFragments(myBeforeContent, myAfterContent);
ArrayList<LineFragment> lineFragments = getLineFragments(myAfterFile.getPath(), myBeforeContent, myAfterContent);
for (Iterator<LineFragment> 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<LineFragment> 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<LineFragment> 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)";
@@ -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;
}
@@ -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.
@@ -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;
@@ -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 "";
}
}
}
@@ -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<Revision> 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<Revision> 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<Revision> 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<Revision> 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<Revision> 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<Revision> rr = createRevisions("one", "two");
SelectionCalculator c = new SelectionCalculator(gw, rr, 0, 0);
@@ -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<T> 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;
@@ -26,4 +26,5 @@ public interface DiffPanel extends DiffViewer, Disposable {
void setContents(DiffContent content1, DiffContent content2);
void setRequestFocus(boolean requestFocus);
boolean hasDifferences();
void setTooBigFileErrorContents();
}
@@ -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<ActionUrl> 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;
@@ -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.*;
@@ -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<CanNotCalculateDiffPanel> PANEL_KEY = new Key<CanNotCalculateDiffPanel>("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.");
}
}
}
@@ -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<DiffMarkupType extends DiffMarkup> implements
}
private LineBlocks addMarkup(final ArrayList<LineFragment> lines) {
resetMarkup();
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
for (Iterator<LineFragment> iterator = lines.iterator(); iterator.hasNext();) {
@@ -80,9 +80,9 @@ public class SimpleDiffPanelState<DiffMarkupType extends DiffMarkup> 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;
}
@@ -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<Change> changes = result.buildChanges();
Collections.sort(changes, CHANGE_ORDER);
@@ -102,7 +103,7 @@ public class ChangeList {
return myDocuments[side.getIndex()];
}
private ArrayList<Change> buildChanges() {
private ArrayList<Change> buildChanges() throws FilesTooBigForDiffException {
Document base = getDocument(FragmentSide.SIDE1);
String[] baseLines = DiffUtil.convertToLines(base.getText());
Document version = getDocument(FragmentSide.SIDE2);
@@ -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<MergeBuilder.MergeFragment> fragmentList = processText(leftText, baseText, rightText, logger);
@@ -116,7 +116,7 @@ public class MergeList implements ChangeList.Parent, UserDataHolder {
private static List<MergeBuilder.MergeFragment> 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());
}
@@ -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());
@@ -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);
@@ -179,7 +179,7 @@ public class MergeRequestImpl extends MergeRequest {
});
}
if (getMergeContent() != null) {
if (getMergeContent() != null && mergePanel.getMergeList() != null) {
new AllResolvedListener(mergePanel, builder.getDialogWrapper());
}
}
@@ -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;
@@ -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<LineFragment> process(String text1, String text2) {
public ArrayList<LineFragment> 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<LineFragment> findSubFragments(String text1, String text2) {
private ArrayList<LineFragment> 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);
@@ -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];
@@ -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<TextDiffType> 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);
@@ -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" +
@@ -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);
@@ -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);
@@ -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"));
@@ -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");
@@ -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));
@@ -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"),
@@ -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<LineFragment> lineFragments = processor.process("f(a, b)\n", "f(a,\nb)\n");
assertTrue(lineFragments.size() == 1);
@@ -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[]{
@@ -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);
@@ -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<FragmentsCollector> {
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<Collector> {
void process(DiffFragment fragment, Collector collector);
void process(DiffFragment fragment, Collector collector) throws FilesTooBigForDiffException;
}
class BaseFragmentRunner<ActualRunner extends BaseFragmentRunner> {
@@ -144,7 +145,7 @@ public interface DiffCorrection {
public DiffFragment[] getFragments() { return myFragments; }
public void processAll(DiffFragment[] fragments, FragmentProcessor<ActualRunner> processor) {
public void processAll(DiffFragment[] fragments, FragmentProcessor<ActualRunner> 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<FragmentBuffer> processor) {
public void processAll(DiffFragment[] fragments, FragmentProcessor<FragmentBuffer> 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();
@@ -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));
}
@@ -39,6 +39,7 @@ public class Diff {
}
public static <T> 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;
@@ -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;
}
}
@@ -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++;
@@ -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;
@@ -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);
}
@@ -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();
@@ -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);
@@ -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<LineFragment> fragments = new DiffFragmentsProcessor().process(step1lineFragments);
if (fragments.size() > 1 || (fragments.size() == 1 && fragments.get(0).getType() != null && fragments.get(0).getType() != TextDiffTypeEnum.NONE)) {
@@ -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) {
@@ -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();
@@ -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<CanNotCalculateDiffPanel> PANEL_KEY = new Key<CanNotCalculateDiffPanel>("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<Range>();
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<Range> 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<Range> getNewChangedRanges() {
private List<Range> getNewChangedRanges() throws FilesTooBigForDiffException {
List<String> lines = new DocumentWrapper(myDocument).getLines(myFirstChangedLine, myLastChangedLine);
List<String> 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.");
}
}
}
@@ -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<Range> 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<String> current, List<String> upToDate, int shift, int uShift) {
public RangesBuilder(List<String> current, List<String> upToDate, int shift, int uShift) throws FilesTooBigForDiffException {
myRanges = new LinkedList<Range>();
Diff.Change ch = Diff.buildChanges(ArrayUtil.toStringArray(upToDate), ArrayUtil.toStringArray(current));
@@ -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<VcsFileRevision> filteredRevisions() {
private List<VcsFileRevision> filteredRevisions() throws FilesTooBigForDiffException {
ArrayList<VcsFileRevision> result = new ArrayList<VcsFileRevision>();
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);
@@ -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);