mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
diff: refactor - extract model for UnifiedDiffViewer
GitOrigin-RevId: 810ba63bba58a945491f881ac461c7baf96bafd0
This commit is contained in:
committed by
intellij-monorepo-bot
parent
55b8eada71
commit
b81005465b
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.diff.tools.fragmented;
|
||||
|
||||
import com.intellij.diff.fragments.LineFragment;
|
||||
import com.intellij.diff.util.LineRange;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
class ChangedBlock {
|
||||
@NotNull private final LineRange myRange1;
|
||||
@NotNull private final LineRange myRange2;
|
||||
|
||||
@NotNull private final LineFragment myLineFragment;
|
||||
|
||||
ChangedBlock(@NotNull LineRange range1,
|
||||
@NotNull LineRange range2,
|
||||
@NotNull LineFragment lineFragment) {
|
||||
myRange1 = range1;
|
||||
myRange2 = range2;
|
||||
myLineFragment = lineFragment;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public LineRange getRange1() {
|
||||
return myRange1;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public LineRange getRange2() {
|
||||
return myRange2;
|
||||
}
|
||||
|
||||
public int getLine1() {
|
||||
return myRange1.start;
|
||||
}
|
||||
|
||||
public int getLine2() {
|
||||
return myRange2.end;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public LineFragment getLineFragment() {
|
||||
return myLineFragment;
|
||||
}
|
||||
}
|
||||
@@ -16,84 +16,29 @@
|
||||
package com.intellij.diff.tools.fragmented;
|
||||
|
||||
import com.intellij.diff.fragments.LineFragment;
|
||||
import com.intellij.diff.util.*;
|
||||
import com.intellij.diff.util.DiffUtil;
|
||||
import com.intellij.diff.util.DiffUtil.UpdatedLineRange;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.editor.markup.GutterIconRenderer;
|
||||
import com.intellij.openapi.editor.markup.HighlighterLayer;
|
||||
import com.intellij.openapi.editor.markup.HighlighterTargetArea;
|
||||
import com.intellij.openapi.editor.markup.RangeHighlighter;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.diff.util.LineRange;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class UnifiedDiffChange {
|
||||
@NotNull private final UnifiedDiffViewer myViewer;
|
||||
@NotNull private final EditorEx myEditor;
|
||||
|
||||
// Boundaries of this change in myEditor. If current state is out-of-date - approximate value.
|
||||
private int myLine1;
|
||||
private int myLine2;
|
||||
|
||||
@NotNull private final LineRange myDeletedRange;
|
||||
@NotNull private final LineRange myInsertedRange;
|
||||
@NotNull private final LineFragment myLineFragment;
|
||||
|
||||
@NotNull private final List<RangeHighlighter> myHighlighters = new ArrayList<>();
|
||||
@NotNull private final List<MyGutterOperation> myOperations = new ArrayList<>();
|
||||
|
||||
public UnifiedDiffChange(@NotNull UnifiedDiffViewer viewer, @NotNull ChangedBlock block) {
|
||||
myViewer = viewer;
|
||||
myEditor = viewer.getEditor();
|
||||
|
||||
myLine1 = block.getLine1();
|
||||
myLine2 = block.getLine2();
|
||||
myLineFragment = block.getLineFragment();
|
||||
|
||||
LineRange deleted = block.getRange1();
|
||||
LineRange inserted = block.getRange2();
|
||||
|
||||
installHighlighter(deleted, inserted);
|
||||
}
|
||||
|
||||
public void destroyHighlighter() {
|
||||
for (RangeHighlighter highlighter : myHighlighters) {
|
||||
highlighter.dispose();
|
||||
}
|
||||
myHighlighters.clear();
|
||||
|
||||
for (MyGutterOperation operation : myOperations) {
|
||||
operation.dispose();
|
||||
}
|
||||
myOperations.clear();
|
||||
}
|
||||
|
||||
private void installHighlighter(@NotNull LineRange deleted, @NotNull LineRange inserted) {
|
||||
assert myHighlighters.isEmpty();
|
||||
|
||||
doInstallHighlighters(deleted, inserted);
|
||||
doInstallActionHighlighters();
|
||||
}
|
||||
|
||||
private void doInstallActionHighlighters() {
|
||||
boolean leftEditable = myViewer.isEditable(Side.LEFT, false);
|
||||
boolean rightEditable = myViewer.isEditable(Side.RIGHT, false);
|
||||
|
||||
if (leftEditable && rightEditable) {
|
||||
myOperations.add(createOperation(Side.LEFT));
|
||||
myOperations.add(createOperation(Side.RIGHT));
|
||||
}
|
||||
else if (rightEditable) {
|
||||
myOperations.add(createOperation(Side.LEFT));
|
||||
}
|
||||
}
|
||||
|
||||
private void doInstallHighlighters(@NotNull LineRange deleted, @NotNull LineRange inserted) {
|
||||
myHighlighters.addAll(DiffDrawUtil.createUnifiedChunkHighlighters(myEditor, deleted, inserted, myLineFragment.getInnerFragments()));
|
||||
public UnifiedDiffChange(int blockStart,
|
||||
int insertedStart,
|
||||
int blockEnd,
|
||||
@NotNull LineFragment lineFragment) {
|
||||
myLine1 = blockStart;
|
||||
myLine2 = blockEnd;
|
||||
myDeletedRange = new LineRange(blockStart, insertedStart);
|
||||
myInsertedRange = new LineRange(insertedStart, blockEnd);
|
||||
myLineFragment = lineFragment;
|
||||
}
|
||||
|
||||
public int getLine1() {
|
||||
@@ -112,86 +57,19 @@ public class UnifiedDiffChange {
|
||||
return myLineFragment;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public LineRange getDeletedRange() {
|
||||
return myDeletedRange;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public LineRange getInsertedRange() {
|
||||
return myInsertedRange;
|
||||
}
|
||||
|
||||
public void processChange(int oldLine1, int oldLine2, int shift) {
|
||||
UpdatedLineRange newRange = DiffUtil.updateRangeOnModification(myLine1, myLine2, oldLine1, oldLine2, shift);
|
||||
myLine1 = newRange.startLine;
|
||||
myLine2 = newRange.endLine;
|
||||
}
|
||||
|
||||
//
|
||||
// Gutter
|
||||
//
|
||||
|
||||
public void updateGutterActions() {
|
||||
for (MyGutterOperation operation : myOperations) {
|
||||
operation.update();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private MyGutterOperation createOperation(@NotNull Side sourceSide) {
|
||||
int offset = myEditor.getDocument().getLineStartOffset(myLine1);
|
||||
RangeHighlighter highlighter = myEditor.getMarkupModel().addRangeHighlighter(offset, offset,
|
||||
HighlighterLayer.ADDITIONAL_SYNTAX,
|
||||
null,
|
||||
HighlighterTargetArea.LINES_IN_RANGE);
|
||||
return new MyGutterOperation(sourceSide, highlighter);
|
||||
}
|
||||
|
||||
private class MyGutterOperation {
|
||||
@NotNull private final Side mySide;
|
||||
@NotNull private final RangeHighlighter myHighlighter;
|
||||
|
||||
private MyGutterOperation(@NotNull Side sourceSide, @NotNull RangeHighlighter highlighter) {
|
||||
mySide = sourceSide;
|
||||
myHighlighter = highlighter;
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
myHighlighter.dispose();
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (myHighlighter.isValid()) myHighlighter.setGutterIconRenderer(createRenderer());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public GutterIconRenderer createRenderer() {
|
||||
if (myViewer.isStateIsOutOfDate()) return null;
|
||||
if (!myViewer.isEditable(mySide.other(), true)) return null;
|
||||
|
||||
if (mySide.isLeft()) {
|
||||
return createIconRenderer(mySide, "Revert", AllIcons.Diff.Remove);
|
||||
}
|
||||
else {
|
||||
return createIconRenderer(mySide, "Accept", AllIcons.Actions.Checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private GutterIconRenderer createIconRenderer(@NotNull final Side sourceSide,
|
||||
@NotNull final String tooltipText,
|
||||
@NotNull final Icon icon) {
|
||||
return new DiffGutterRenderer(icon, tooltipText) {
|
||||
@Override
|
||||
protected void handleMouseClick() {
|
||||
if (myViewer.isStateIsOutOfDate()) return;
|
||||
if (!myViewer.isEditable(sourceSide.other(), true)) return;
|
||||
|
||||
final Project project = myViewer.getProject();
|
||||
final Document document = myViewer.getDocument(sourceSide.other());
|
||||
|
||||
DiffUtil.executeWriteCommand(document, project, "Replace change", () -> {
|
||||
myViewer.replaceChange(UnifiedDiffChange.this, sourceSide);
|
||||
myViewer.scheduleRediff();
|
||||
});
|
||||
// applyChange() will schedule rediff, but we want to try to do it in sync
|
||||
// and we can't do it inside write action
|
||||
myViewer.rediff();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.diff.tools.fragmented;
|
||||
|
||||
import com.intellij.diff.util.DiffDrawUtil;
|
||||
import com.intellij.diff.util.DiffGutterRenderer;
|
||||
import com.intellij.diff.util.DiffUtil;
|
||||
import com.intellij.diff.util.Side;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.editor.markup.GutterIconRenderer;
|
||||
import com.intellij.openapi.editor.markup.HighlighterLayer;
|
||||
import com.intellij.openapi.editor.markup.HighlighterTargetArea;
|
||||
import com.intellij.openapi.editor.markup.RangeHighlighter;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class UnifiedDiffChangeUi {
|
||||
@NotNull private final UnifiedDiffViewer myViewer;
|
||||
@NotNull private final EditorEx myEditor;
|
||||
@NotNull private final UnifiedDiffChange myChange;
|
||||
|
||||
@NotNull private final List<RangeHighlighter> myHighlighters = new ArrayList<>();
|
||||
@NotNull private final List<MyGutterOperation> myOperations = new ArrayList<>();
|
||||
|
||||
public UnifiedDiffChangeUi(@NotNull UnifiedDiffViewer viewer, @NotNull UnifiedDiffChange change) {
|
||||
myViewer = viewer;
|
||||
myEditor = viewer.getEditor();
|
||||
myChange = change;
|
||||
}
|
||||
|
||||
public void destroyHighlighter() {
|
||||
for (RangeHighlighter highlighter : myHighlighters) {
|
||||
highlighter.dispose();
|
||||
}
|
||||
myHighlighters.clear();
|
||||
|
||||
for (MyGutterOperation operation : myOperations) {
|
||||
operation.dispose();
|
||||
}
|
||||
myOperations.clear();
|
||||
}
|
||||
|
||||
public void installHighlighter() {
|
||||
assert myHighlighters.isEmpty() && myOperations.isEmpty();
|
||||
|
||||
doInstallHighlighters();
|
||||
doInstallActionHighlighters();
|
||||
}
|
||||
|
||||
private void doInstallActionHighlighters() {
|
||||
boolean leftEditable = myViewer.isEditable(Side.LEFT, false);
|
||||
boolean rightEditable = myViewer.isEditable(Side.RIGHT, false);
|
||||
|
||||
if (leftEditable && rightEditable) {
|
||||
myOperations.add(createOperation(Side.LEFT));
|
||||
myOperations.add(createOperation(Side.RIGHT));
|
||||
}
|
||||
else if (rightEditable) {
|
||||
myOperations.add(createOperation(Side.LEFT));
|
||||
}
|
||||
}
|
||||
|
||||
private void doInstallHighlighters() {
|
||||
myHighlighters.addAll(DiffDrawUtil.createUnifiedChunkHighlighters(myEditor,
|
||||
myChange.getDeletedRange(),
|
||||
myChange.getInsertedRange(),
|
||||
myChange.getLineFragment().getInnerFragments()));
|
||||
}
|
||||
|
||||
//
|
||||
// Gutter
|
||||
//
|
||||
|
||||
public void updateGutterActions() {
|
||||
for (MyGutterOperation operation : myOperations) {
|
||||
operation.update();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private MyGutterOperation createOperation(@NotNull Side sourceSide) {
|
||||
int offset = myEditor.getDocument().getLineStartOffset(myChange.getLine1());
|
||||
RangeHighlighter highlighter = myEditor.getMarkupModel().addRangeHighlighter(offset, offset,
|
||||
HighlighterLayer.ADDITIONAL_SYNTAX,
|
||||
null,
|
||||
HighlighterTargetArea.LINES_IN_RANGE);
|
||||
return new MyGutterOperation(sourceSide, highlighter);
|
||||
}
|
||||
|
||||
private class MyGutterOperation {
|
||||
@NotNull private final Side mySide;
|
||||
@NotNull private final RangeHighlighter myHighlighter;
|
||||
|
||||
private MyGutterOperation(@NotNull Side sourceSide, @NotNull RangeHighlighter highlighter) {
|
||||
mySide = sourceSide;
|
||||
myHighlighter = highlighter;
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
myHighlighter.dispose();
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (myHighlighter.isValid()) myHighlighter.setGutterIconRenderer(createRenderer());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public GutterIconRenderer createRenderer() {
|
||||
if (myViewer.isStateIsOutOfDate()) return null;
|
||||
if (!myViewer.isEditable(mySide.other(), true)) return null;
|
||||
|
||||
if (mySide.isLeft()) {
|
||||
return createIconRenderer(mySide, "Revert", AllIcons.Diff.Remove);
|
||||
}
|
||||
else {
|
||||
return createIconRenderer(mySide, "Accept", AllIcons.Actions.Checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private GutterIconRenderer createIconRenderer(@NotNull final Side sourceSide,
|
||||
@NotNull final String tooltipText,
|
||||
@NotNull final Icon icon) {
|
||||
return new DiffGutterRenderer(icon, tooltipText) {
|
||||
@Override
|
||||
protected void handleMouseClick() {
|
||||
if (myViewer.isStateIsOutOfDate()) return;
|
||||
if (!myViewer.isEditable(sourceSide.other(), true)) return;
|
||||
|
||||
final Project project = myViewer.getProject();
|
||||
final Document document = myViewer.getDocument(sourceSide.other());
|
||||
|
||||
DiffUtil.executeWriteCommand(document, project, "Replace change", () -> {
|
||||
myViewer.replaceChange(myChange, sourceSide);
|
||||
myViewer.scheduleRediff();
|
||||
});
|
||||
// applyChange() will schedule rediff, but we want to try to do it in sync
|
||||
// and we can't do it inside write action
|
||||
myViewer.rediff();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.diff.tools.fragmented;
|
||||
|
||||
import com.intellij.diff.util.Side;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.editor.ex.DocumentEx;
|
||||
import com.intellij.util.ThreeState;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class UnifiedDiffModel {
|
||||
@NotNull private final UnifiedDiffViewer myViewer;
|
||||
|
||||
@Nullable private ChangedBlockData myData = null;
|
||||
@NotNull private ThreeState myIsContentsEqual = ThreeState.UNSURE;
|
||||
|
||||
@NotNull private final List<UnifiedDiffChangeUi> myPresentations = new ArrayList<>();
|
||||
@NotNull private final List<RangeMarker> myGuardedRangeBlocks = new ArrayList<>();
|
||||
|
||||
public UnifiedDiffModel(@NotNull UnifiedDiffViewer viewer) {
|
||||
myViewer = viewer;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return myData != null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ThreeState isContentsEqual() {
|
||||
return myIsContentsEqual;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ChangedBlockData getData() {
|
||||
return myData;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<UnifiedDiffChange> getDiffChanges() {
|
||||
return myData != null ? myData.getDiffChanges() : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public LineNumberConvertor getLineNumberConvertor(@NotNull Side side) {
|
||||
return myData != null ? myData.getLineNumberConvertor(side) : null;
|
||||
}
|
||||
|
||||
public void setChanges(@NotNull List<UnifiedDiffChange> changes,
|
||||
boolean isContentsEqual,
|
||||
@NotNull List<RangeMarker> guardedBlocks,
|
||||
@NotNull LineNumberConvertor convertor1,
|
||||
@NotNull LineNumberConvertor convertor2) {
|
||||
assert myPresentations.isEmpty() && myGuardedRangeBlocks.isEmpty() && myData == null;
|
||||
|
||||
for (UnifiedDiffChange change : changes) {
|
||||
UnifiedDiffChangeUi changeUi = myViewer.createUi(change);
|
||||
changeUi.installHighlighter();
|
||||
myPresentations.add(changeUi);
|
||||
}
|
||||
|
||||
myGuardedRangeBlocks.addAll(guardedBlocks);
|
||||
|
||||
myData = new ChangedBlockData(changes, convertor1, convertor2);
|
||||
myIsContentsEqual = ThreeState.fromBoolean(isContentsEqual);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
for (UnifiedDiffChangeUi changeUi : myPresentations) {
|
||||
changeUi.destroyHighlighter();
|
||||
}
|
||||
myPresentations.clear();
|
||||
|
||||
DocumentEx document = myViewer.getEditor().getDocument();
|
||||
for (RangeMarker block : myGuardedRangeBlocks) {
|
||||
document.removeGuardedBlock(block);
|
||||
}
|
||||
myGuardedRangeBlocks.clear();
|
||||
|
||||
myData = null;
|
||||
myIsContentsEqual = ThreeState.UNSURE;
|
||||
}
|
||||
|
||||
public void updateGutterActions() {
|
||||
for (UnifiedDiffChangeUi changeUi : myPresentations) {
|
||||
changeUi.updateGutterActions();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ChangedBlockData {
|
||||
@NotNull private final List<UnifiedDiffChange> myDiffChanges;
|
||||
@NotNull private final LineNumberConvertor myLineNumberConvertor1;
|
||||
@NotNull private final LineNumberConvertor myLineNumberConvertor2;
|
||||
|
||||
ChangedBlockData(@NotNull List<UnifiedDiffChange> diffChanges,
|
||||
@NotNull LineNumberConvertor lineNumberConvertor1,
|
||||
@NotNull LineNumberConvertor lineNumberConvertor2) {
|
||||
myDiffChanges = diffChanges;
|
||||
myLineNumberConvertor1 = lineNumberConvertor1;
|
||||
myLineNumberConvertor2 = lineNumberConvertor2;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<UnifiedDiffChange> getDiffChanges() {
|
||||
return myDiffChanges;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public LineNumberConvertor getLineNumberConvertor(@NotNull Side side) {
|
||||
return side.select(myLineNumberConvertor1, myLineNumberConvertor2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import com.intellij.diff.contents.DocumentContent;
|
||||
import com.intellij.diff.fragments.LineFragment;
|
||||
import com.intellij.diff.requests.ContentDiffRequest;
|
||||
import com.intellij.diff.requests.DiffRequest;
|
||||
import com.intellij.diff.tools.fragmented.UnifiedDiffModel.ChangedBlockData;
|
||||
import com.intellij.diff.tools.util.*;
|
||||
import com.intellij.diff.tools.util.base.InitialScrollPositionSupport;
|
||||
import com.intellij.diff.tools.util.base.ListenerDiffViewerBase;
|
||||
@@ -44,6 +45,7 @@ import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.pom.Navigatable;
|
||||
import com.intellij.util.ThreeState;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import gnu.trove.TIntFunction;
|
||||
import org.jetbrains.annotations.*;
|
||||
@@ -69,7 +71,7 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
|
||||
@NotNull protected Side myMasterSide = Side.RIGHT;
|
||||
|
||||
@Nullable private ChangedBlockData myChangedBlockData;
|
||||
@NotNull private final UnifiedDiffModel myModel = new UnifiedDiffModel(this);
|
||||
|
||||
private final boolean[] myForceReadOnlyFlags;
|
||||
private boolean myReadOnlyLockSet = false;
|
||||
@@ -130,6 +132,7 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
@Override
|
||||
@CalledInAwt
|
||||
protected void onDispose() {
|
||||
myModel.clear();
|
||||
myFoldingModel.destroy();
|
||||
super.onDispose();
|
||||
EditorFactory.getInstance().releaseEditor(myEditor);
|
||||
@@ -217,6 +220,11 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
new TextDiffViewerUtil.EditorActionsPopup(createEditorPopupActions()).install(getEditors());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected UnifiedDiffChangeUi createUi(@NotNull UnifiedDiffChange change) {
|
||||
return new UnifiedDiffChangeUi(this, change);
|
||||
}
|
||||
|
||||
//
|
||||
// Diff
|
||||
//
|
||||
@@ -276,7 +284,7 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
getDocument(masterSide), masterSide.select(convertor1, convertor2),
|
||||
StringUtil.countNewLines(builder.getText()) + 1);
|
||||
|
||||
return apply(editorData, builder.getBlocks(), convertor1, convertor2, foldingState, isContentsEqual);
|
||||
return apply(editorData, builder.getChanges(), convertor1, convertor2, foldingState, isContentsEqual);
|
||||
}
|
||||
catch (DiffTooBigException e) {
|
||||
return () -> {
|
||||
@@ -316,11 +324,7 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
protected void markStateIsOutOfDate() {
|
||||
myStateIsOutOfDate = true;
|
||||
myFoldingModel.disposeLineConvertor();
|
||||
if (myChangedBlockData != null) {
|
||||
for (UnifiedDiffChange diffChange : myChangedBlockData.getDiffChanges()) {
|
||||
diffChange.updateGutterActions();
|
||||
}
|
||||
}
|
||||
myModel.updateGutterActions();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -343,7 +347,7 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
|
||||
@NotNull
|
||||
private Runnable apply(@NotNull final CombinedEditorData data,
|
||||
@NotNull final List<? extends ChangedBlock> blocks,
|
||||
@NotNull final List<UnifiedDiffChange> diffChanges,
|
||||
@NotNull final LineNumberConvertor convertor1,
|
||||
@NotNull final LineNumberConvertor convertor2,
|
||||
@Nullable final FoldingModelSupport.Data foldingState,
|
||||
@@ -386,16 +390,10 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
|
||||
if (data.getRangeHighlighter() != null) data.getRangeHighlighter().apply(myProject, myDocument);
|
||||
|
||||
|
||||
ArrayList<UnifiedDiffChange> diffChanges = new ArrayList<>(blocks.size());
|
||||
for (ChangedBlock block : blocks) {
|
||||
diffChanges.add(new UnifiedDiffChange(this, block));
|
||||
}
|
||||
|
||||
List<RangeMarker> guarderRangeBlocks = new ArrayList<>();
|
||||
if (!myEditor.isViewer()) {
|
||||
for (ChangedBlock block : blocks) {
|
||||
LineRange range = myMasterSide.select(block.getRange2(), block.getRange1());
|
||||
for (UnifiedDiffChange change : diffChanges) {
|
||||
LineRange range = myMasterSide.select(change.getInsertedRange(), change.getDeletedRange());
|
||||
if (range.isEmpty()) continue;
|
||||
TextRange textRange = DiffUtil.getLinesRange(myDocument, range.start, range.end);
|
||||
guarderRangeBlocks.add(createGuardedBlock(textRange.getStartOffset(), textRange.getEndOffset()));
|
||||
@@ -404,9 +402,7 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
guarderRangeBlocks.add(createGuardedBlock(textLength, textLength));
|
||||
}
|
||||
|
||||
|
||||
myChangedBlockData = new ChangedBlockData(diffChanges, guarderRangeBlocks, convertor1, convertor2, isContentsEqual);
|
||||
|
||||
myModel.setChanges(diffChanges, isContentsEqual, guarderRangeBlocks, convertor1, convertor2);
|
||||
|
||||
int newCaretLine = transferLineToOneside(oldCaretLineTwoside.second,
|
||||
oldCaretLineTwoside.second.select(oldCaretLineTwoside.first));
|
||||
@@ -442,8 +438,8 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
*/
|
||||
@CalledInAwt
|
||||
public int transferLineToOnesideStrict(@NotNull Side side, int line) {
|
||||
if (myChangedBlockData == null) return -1;
|
||||
return myChangedBlockData.getLineNumberConvertor(side).convertInv(line);
|
||||
LineNumberConvertor convertor = myModel.getLineNumberConvertor(side);
|
||||
return convertor != null ? convertor.convertInv(line) : -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -451,8 +447,8 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
*/
|
||||
@CalledInAwt
|
||||
public int transferLineFromOnesideStrict(@NotNull Side side, int line) {
|
||||
if (myChangedBlockData == null) return -1;
|
||||
return myChangedBlockData.getLineNumberConvertor(side).convert(line);
|
||||
LineNumberConvertor convertor = myModel.getLineNumberConvertor(side);
|
||||
return convertor != null ? convertor.convert(line) : -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -460,8 +456,8 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
*/
|
||||
@CalledInAwt
|
||||
public int transferLineToOneside(@NotNull Side side, int line) {
|
||||
if (myChangedBlockData == null) return line;
|
||||
return myChangedBlockData.getLineNumberConvertor(side).convertApproximateInv(line);
|
||||
LineNumberConvertor convertor = myModel.getLineNumberConvertor(side);
|
||||
return convertor != null ? convertor.convertApproximateInv(line) : line;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -472,14 +468,15 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
public Pair<int[], Side> transferLineFromOneside(int line) {
|
||||
int[] lines = new int[2];
|
||||
|
||||
if (myChangedBlockData == null) {
|
||||
ChangedBlockData blockData = myModel.getData();
|
||||
if (blockData == null) {
|
||||
lines[0] = line;
|
||||
lines[1] = line;
|
||||
return Pair.create(lines, myMasterSide);
|
||||
}
|
||||
|
||||
LineNumberConvertor lineConvertor1 = myChangedBlockData.getLineNumberConvertor(Side.LEFT);
|
||||
LineNumberConvertor lineConvertor2 = myChangedBlockData.getLineNumberConvertor(Side.RIGHT);
|
||||
LineNumberConvertor lineConvertor1 = blockData.getLineNumberConvertor(Side.LEFT);
|
||||
LineNumberConvertor lineConvertor2 = blockData.getLineNumberConvertor(Side.RIGHT);
|
||||
|
||||
Side side = myMasterSide;
|
||||
lines[0] = lineConvertor1.convert(line);
|
||||
@@ -503,15 +500,7 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
|
||||
@CalledInAwt
|
||||
private void destroyChangedBlockData() {
|
||||
if (myChangedBlockData == null) return;
|
||||
|
||||
for (UnifiedDiffChange change : myChangedBlockData.getDiffChanges()) {
|
||||
change.destroyHighlighter();
|
||||
}
|
||||
for (RangeMarker block : myChangedBlockData.getGuardedRangeBlocks()) {
|
||||
myDocument.removeGuardedBlock(block);
|
||||
}
|
||||
myChangedBlockData = null;
|
||||
myModel.clear();
|
||||
|
||||
UnifiedEditorRangeHighlighter.erase(myProject, myDocument);
|
||||
|
||||
@@ -528,8 +517,9 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
@Override
|
||||
public void beforeDocumentChange(@NotNull DocumentEvent e) {
|
||||
if (myDuringOnesideDocumentModification) return;
|
||||
if (myChangedBlockData == null) {
|
||||
LOG.warn("oneside beforeDocumentChange - myChangedBlockData == null");
|
||||
ChangedBlockData blockData = myModel.getData();
|
||||
if (blockData == null) {
|
||||
LOG.warn("oneside beforeDocumentChange - model is invalid");
|
||||
return;
|
||||
}
|
||||
// TODO: modify Document guard range logic - we can handle case, when whole read-only block is modified (ex: my replacing selection).
|
||||
@@ -559,12 +549,12 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
int twosideEndOffset = twosideDocument.getLineStartOffset(twosideEndLine) + onesideEndPosition.column;
|
||||
twosideDocument.replaceString(twosideStartOffset, twosideEndOffset, e.getNewFragment());
|
||||
|
||||
for (UnifiedDiffChange change : myChangedBlockData.getDiffChanges()) {
|
||||
for (UnifiedDiffChange change : blockData.getDiffChanges()) {
|
||||
change.processChange(line1, line2, shift);
|
||||
}
|
||||
|
||||
LineNumberConvertor masterConvertor = myChangedBlockData.getLineNumberConvertor(myMasterSide);
|
||||
LineNumberConvertor slaveConvertor = myChangedBlockData.getLineNumberConvertor(myMasterSide.other());
|
||||
LineNumberConvertor masterConvertor = blockData.getLineNumberConvertor(myMasterSide);
|
||||
LineNumberConvertor slaveConvertor = blockData.getLineNumberConvertor(myMasterSide.other());
|
||||
masterConvertor.handleMasterChange(line1, line2, shift, true);
|
||||
slaveConvertor.handleMasterChange(line1, line2, shift, false);
|
||||
}
|
||||
@@ -670,9 +660,8 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
}
|
||||
|
||||
protected boolean isSomeChangeSelected() {
|
||||
if (myChangedBlockData == null) return false;
|
||||
List<UnifiedDiffChange> changes = myChangedBlockData.getDiffChanges();
|
||||
if (changes.isEmpty()) return false;
|
||||
List<UnifiedDiffChange> changes = myModel.getDiffChanges();
|
||||
if (changes == null || changes.isEmpty()) return false;
|
||||
|
||||
return DiffUtil.isSomeRangeSelected(getEditor(), lines -> ContainerUtil.exists(changes, change -> isChangeSelected(change, lines)));
|
||||
}
|
||||
@@ -680,9 +669,8 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
@NotNull
|
||||
@CalledInAwt
|
||||
private List<UnifiedDiffChange> getSelectedChanges() {
|
||||
if (myChangedBlockData == null) return Collections.emptyList();
|
||||
final BitSet lines = DiffUtil.getSelectedLines(myEditor);
|
||||
List<UnifiedDiffChange> changes = myChangedBlockData.getDiffChanges();
|
||||
List<UnifiedDiffChange> changes = ContainerUtil.notNullize(myModel.getDiffChanges());
|
||||
return ContainerUtil.filter(changes, change -> isChangeSelected(change, lines));
|
||||
}
|
||||
|
||||
@@ -821,7 +809,7 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
@CalledInAwt
|
||||
@Nullable
|
||||
protected List<UnifiedDiffChange> getDiffChanges() {
|
||||
return myChangedBlockData == null ? null : myChangedBlockData.getDiffChanges();
|
||||
return myModel.getDiffChanges();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -872,10 +860,12 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
@CalledInAwt
|
||||
@Nullable
|
||||
protected UnifiedDiffChange getCurrentChange() {
|
||||
if (myChangedBlockData == null) return null;
|
||||
List<UnifiedDiffChange> changes = myModel.getDiffChanges();
|
||||
if (changes == null) return null;
|
||||
|
||||
int caretLine = myEditor.getCaretModel().getLogicalPosition().line;
|
||||
|
||||
for (UnifiedDiffChange change : myChangedBlockData.getDiffChanges()) {
|
||||
for (UnifiedDiffChange change : changes) {
|
||||
if (DiffUtil.isSelectedByLine(caretLine, change.getLine1(), change.getLine2())) return change;
|
||||
}
|
||||
return null;
|
||||
@@ -896,7 +886,7 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
}
|
||||
|
||||
public boolean isContentGood() {
|
||||
return myPanel.isGoodContent() && myChangedBlockData != null;
|
||||
return myPanel.isGoodContent() && myModel.isValid();
|
||||
}
|
||||
|
||||
public static boolean canShowRequest(@NotNull DiffContext context, @NotNull DiffRequest request) {
|
||||
@@ -960,11 +950,7 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
@Override
|
||||
protected void doApply(boolean readOnly) {
|
||||
myReadOnlyLockSet = readOnly;
|
||||
if (myChangedBlockData != null) {
|
||||
for (UnifiedDiffChange unifiedDiffChange : myChangedBlockData.getDiffChanges()) {
|
||||
unifiedDiffChange.updateGutterActions();
|
||||
}
|
||||
}
|
||||
myModel.updateGutterActions();
|
||||
updateEditorCanBeTyped();
|
||||
putEditorHint(myEditor, readOnly && isEditable(myMasterSide, false));
|
||||
}
|
||||
@@ -1043,9 +1029,11 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
@Nullable
|
||||
@Override
|
||||
protected String getMessage() {
|
||||
if (myChangedBlockData == null) return null;
|
||||
int changesCount = myChangedBlockData.getDiffChanges().size();
|
||||
if (changesCount == 0 && !myChangedBlockData.isContentsEqual()) {
|
||||
ChangedBlockData blockData = myModel.getData();
|
||||
|
||||
if (blockData == null) return null;
|
||||
int changesCount = blockData.getDiffChanges().size();
|
||||
if (changesCount == 0 && myModel.isContentsEqual() == ThreeState.NO) {
|
||||
return DiffBundle.message("diff.all.differences.ignored.text");
|
||||
}
|
||||
return DiffBundle.message("diff.count.differences.status.text", changesCount);
|
||||
@@ -1081,45 +1069,6 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
}
|
||||
}
|
||||
|
||||
private static class ChangedBlockData {
|
||||
@NotNull private final List<UnifiedDiffChange> myDiffChanges;
|
||||
@NotNull private final List<RangeMarker> myGuardedRangeBlocks;
|
||||
@NotNull private final LineNumberConvertor myLineNumberConvertor1;
|
||||
@NotNull private final LineNumberConvertor myLineNumberConvertor2;
|
||||
private final boolean myIsContentsEqual;
|
||||
|
||||
ChangedBlockData(@NotNull List<UnifiedDiffChange> diffChanges,
|
||||
@NotNull List<RangeMarker> guarderRangeBlocks,
|
||||
@NotNull LineNumberConvertor lineNumberConvertor1,
|
||||
@NotNull LineNumberConvertor lineNumberConvertor2,
|
||||
boolean isContentsEqual) {
|
||||
myDiffChanges = diffChanges;
|
||||
myGuardedRangeBlocks = guarderRangeBlocks;
|
||||
myLineNumberConvertor1 = lineNumberConvertor1;
|
||||
myLineNumberConvertor2 = lineNumberConvertor2;
|
||||
myIsContentsEqual = isContentsEqual;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<UnifiedDiffChange> getDiffChanges() {
|
||||
return myDiffChanges;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<RangeMarker> getGuardedRangeBlocks() {
|
||||
return myGuardedRangeBlocks;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public LineNumberConvertor getLineNumberConvertor(@NotNull Side side) {
|
||||
return side.select(myLineNumberConvertor1, myLineNumberConvertor2);
|
||||
}
|
||||
|
||||
public boolean isContentsEqual() {
|
||||
return myIsContentsEqual;
|
||||
}
|
||||
}
|
||||
|
||||
private static class CombinedEditorData {
|
||||
@NotNull private final CharSequence myText;
|
||||
@Nullable private final EditorHighlighter myHighlighter;
|
||||
@@ -1230,8 +1179,8 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
}
|
||||
|
||||
private boolean doScrollToChange(@NotNull ScrollToPolicy scrollToChangePolicy) {
|
||||
if (myChangedBlockData == null) return false;
|
||||
List<UnifiedDiffChange> changes = myChangedBlockData.getDiffChanges();
|
||||
List<UnifiedDiffChange> changes = myModel.getDiffChanges();
|
||||
if (changes == null) return false;
|
||||
|
||||
UnifiedDiffChange targetChange = scrollToChangePolicy.select(changes);
|
||||
if (targetChange == null) return false;
|
||||
@@ -1254,9 +1203,11 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase {
|
||||
@Override
|
||||
protected boolean doScrollToContext() {
|
||||
if (myNavigationContext == null) return false;
|
||||
if (myChangedBlockData == null) return false;
|
||||
|
||||
ChangedLinesIterator changedLinesIterator = new ChangedLinesIterator(myChangedBlockData.getDiffChanges());
|
||||
List<UnifiedDiffChange> changes = myModel.getDiffChanges();
|
||||
if (changes == null) return false;
|
||||
|
||||
ChangedLinesIterator changedLinesIterator = new ChangedLinesIterator(changes);
|
||||
int line = myNavigationContext.contextMatchCheck(changedLinesIterator);
|
||||
if (line == -1) {
|
||||
// this will work for the case, when spaces changes are ignored, and corresponding fragments are not reported as changed
|
||||
|
||||
+4
-11
@@ -32,7 +32,7 @@ class UnifiedFragmentBuilder {
|
||||
@NotNull private final Side myMasterSide;
|
||||
|
||||
@NotNull private final StringBuilder myBuilder = new StringBuilder();
|
||||
@NotNull private final List<ChangedBlock> myBlocks = new ArrayList<>();
|
||||
@NotNull private final List<UnifiedDiffChange> myChanges = new ArrayList<>();
|
||||
@NotNull private final List<HighlightRange> myRanges = new ArrayList<>();
|
||||
@NotNull private final LineNumberConvertor.Builder myConvertor1 = new LineNumberConvertor.Builder();
|
||||
@NotNull private final LineNumberConvertor.Builder myConvertor2 = new LineNumberConvertor.Builder();
|
||||
@@ -109,14 +109,7 @@ class UnifiedFragmentBuilder {
|
||||
|
||||
linesAfter = totalLines;
|
||||
|
||||
int blockStartLine1 = linesBefore;
|
||||
int blockEndLine1 = linesBetween;
|
||||
int blockStartLine2 = linesBetween;
|
||||
int blockEndLine2 = linesAfter;
|
||||
|
||||
myBlocks.add(new ChangedBlock(new LineRange(blockStartLine1, blockEndLine1),
|
||||
new LineRange(blockStartLine2, blockEndLine2),
|
||||
fragment));
|
||||
myChanges.add(new UnifiedDiffChange(linesBefore, linesBetween, linesAfter, fragment));
|
||||
|
||||
lastProcessedLine1 = endLine1;
|
||||
lastProcessedLine2 = endLine2;
|
||||
@@ -190,8 +183,8 @@ class UnifiedFragmentBuilder {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<ChangedBlock> getBlocks() {
|
||||
return myBlocks;
|
||||
public List<UnifiedDiffChange> getChanges() {
|
||||
return myChanges;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+5
-5
@@ -61,7 +61,7 @@ class UnifiedFragmentBuilderAutoTest : DiffTestCase() {
|
||||
|
||||
val ignoreWhitespaces = policy !== ComparisonPolicy.DEFAULT
|
||||
val text = builder.text
|
||||
val blocks = builder.blocks
|
||||
val changes = builder.changes
|
||||
val convertor1 = builder.convertor1
|
||||
val convertor2 = builder.convertor2
|
||||
val changedLines = builder.changedLines
|
||||
@@ -93,16 +93,16 @@ class UnifiedFragmentBuilderAutoTest : DiffTestCase() {
|
||||
}
|
||||
|
||||
// changed fragments and changed blocks should have same content
|
||||
assertEquals(blocks.size, fragments.size)
|
||||
assertEquals(changes.size, fragments.size)
|
||||
for (i in fragments.indices) {
|
||||
val fragment = fragments[i]
|
||||
val block = blocks[i]
|
||||
val block = changes[i]
|
||||
|
||||
val fragment1 = sequence1.subSequence(fragment.startOffset1, fragment.endOffset1)
|
||||
val fragment2 = sequence2.subSequence(fragment.startOffset2, fragment.endOffset2)
|
||||
|
||||
val block1 = DiffUtil.getLinesContent(document, block.range1.start, block.range1.end)
|
||||
val block2 = DiffUtil.getLinesContent(document, block.range2.start, block.range2.end)
|
||||
val block1 = DiffUtil.getLinesContent(document, block.deletedRange.start, block.deletedRange.end)
|
||||
val block2 = DiffUtil.getLinesContent(document, block.insertedRange.start, block.insertedRange.end)
|
||||
|
||||
assertEqualsCharSequences(fragment1, block1, ignoreWhitespaces, true)
|
||||
assertEqualsCharSequences(fragment2, block2, ignoreWhitespaces, true)
|
||||
|
||||
+4
-4
@@ -246,7 +246,7 @@ class UnifiedFragmentBuilderTest : DiffTestCase() {
|
||||
val actualText = processActualText(builder)
|
||||
|
||||
val expectedMapping = processExpectedLineMapping(lineMapping)
|
||||
val actualMapping = processActualLineMapping(builder.blocks, resultLineCount)
|
||||
val actualMapping = processActualLineMapping(builder.changes, resultLineCount)
|
||||
|
||||
val expectedChangedLines = processExpectedChangedLines(lineMapping)
|
||||
val actualChangedLines = processActualChangedLines(builder.changedLines)
|
||||
@@ -304,14 +304,14 @@ class UnifiedFragmentBuilderTest : DiffTestCase() {
|
||||
return LineMapping(leftSet, rightSet, unchangedSet)
|
||||
}
|
||||
|
||||
private fun processActualLineMapping(blocks: List<ChangedBlock>, lineCount: Int): LineMapping {
|
||||
private fun processActualLineMapping(blocks: List<UnifiedDiffChange>, lineCount: Int): LineMapping {
|
||||
val leftSet = BitSet()
|
||||
val rightSet = BitSet()
|
||||
val unchangedSet = BitSet()
|
||||
|
||||
blocks.forEach {
|
||||
leftSet.set(it.range1.start, it.range1.end)
|
||||
rightSet.set(it.range2.start, it.range2.end)
|
||||
leftSet.set(it.deletedRange.start, it.deletedRange.end)
|
||||
rightSet.set(it.insertedRange.start, it.insertedRange.end)
|
||||
}
|
||||
|
||||
unchangedSet.set(0, lineCount)
|
||||
|
||||
Reference in New Issue
Block a user