From 6e3d8650dbaf84645da1b5d1e0836830fd96ea87 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Tue, 26 Apr 2016 18:21:27 +0300 Subject: [PATCH] patch: apply-somehow - rework dialog * make it more similar to the merge conflict resolve dialog * allow editing in diff viewer --- .../com/intellij/diff/DiffContentFactory.java | 6 + .../intellij/diff/DiffContentFactoryImpl.java | 14 + .../intellij/diff/merge/MergeModelBase.java | 2 +- .../intellij/diff/merge/TextMergeViewer.java | 40 +- .../tools/fragmented/UnifiedDiffChange.java | 39 +- .../diff/tools/holders/TextEditorHolder.java | 15 +- .../com/intellij/diff/util/DiffDrawUtil.java | 21 +- .../src/com/intellij/diff/util/DiffUtil.java | 113 ++- .../diff/util/TextDiffTypeFactory.java | 15 +- .../src/messages/DiffBundle.properties | 3 + .../patch/PatchDiffRequestFactory.java | 12 +- .../changes/patch/tool/ApplyPatchChange.java | 342 ++++++--- .../patch/tool/ApplyPatchDiffRequest.java | 29 +- .../patch/tool/ApplyPatchDiffTool.java | 10 +- .../patch/tool/ApplyPatchMergeRequest.java | 28 +- .../patch/tool/ApplyPatchMergeTool.java | 70 +- .../changes/patch/tool/ApplyPatchRequest.java | 44 ++ .../changes/patch/tool/ApplyPatchViewer.java | 698 ++++++++++++++---- .../patch/tool/PatchChangeBuilder.java | 70 +- 19 files changed, 1116 insertions(+), 455 deletions(-) create mode 100644 platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchRequest.java diff --git a/platform/diff-api/src/com/intellij/diff/DiffContentFactory.java b/platform/diff-api/src/com/intellij/diff/DiffContentFactory.java index 8dd004c11532..270150b7103c 100644 --- a/platform/diff-api/src/com/intellij/diff/DiffContentFactory.java +++ b/platform/diff-api/src/com/intellij/diff/DiffContentFactory.java @@ -53,6 +53,9 @@ public abstract class DiffContentFactory { @NotNull public abstract DocumentContent create(@NotNull String text, @Nullable VirtualFile highlightFile); + @NotNull + public abstract DocumentContent create(@NotNull String text, @Nullable DocumentContent referent); + @NotNull public abstract DocumentContent create(@Nullable Project project, @NotNull Document document); @@ -62,6 +65,9 @@ public abstract class DiffContentFactory { @NotNull public abstract DocumentContent create(@Nullable Project project, @NotNull Document document, @Nullable VirtualFile file); + @NotNull + public abstract DocumentContent create(@NotNull Document document, @Nullable DocumentContent referent); + @NotNull public abstract DiffContent create(@Nullable Project project, @NotNull VirtualFile file); diff --git a/platform/diff-impl/src/com/intellij/diff/DiffContentFactoryImpl.java b/platform/diff-impl/src/com/intellij/diff/DiffContentFactoryImpl.java index e86b6884f394..0b118daca842 100644 --- a/platform/diff-impl/src/com/intellij/diff/DiffContentFactoryImpl.java +++ b/platform/diff-impl/src/com/intellij/diff/DiffContentFactoryImpl.java @@ -81,6 +81,20 @@ public class DiffContentFactoryImpl extends DiffContentFactory { return createImpl(text, highlightFile != null ? highlightFile.getFileType() : null, highlightFile, null, true, true); } + @NotNull + @Override + public DocumentContent create(@NotNull String text, @Nullable DocumentContent referent) { + if (referent == null) return create(text); + return createImpl(text, referent.getContentType(), referent.getHighlightFile(), null, false, true); + } + + @NotNull + @Override + public DocumentContent create(@NotNull Document document, @Nullable DocumentContent referent) { + if (referent == null) return new DocumentContentImpl(document); + return new DocumentContentImpl(document, referent.getContentType(), referent.getHighlightFile(), null, null); + } + @Override @NotNull public DocumentContent create(@Nullable Project project, @NotNull Document document) { diff --git a/platform/diff-impl/src/com/intellij/diff/merge/MergeModelBase.java b/platform/diff-impl/src/com/intellij/diff/merge/MergeModelBase.java index ed5d9de8cdcd..16674ebeef4e 100644 --- a/platform/diff-impl/src/com/intellij/diff/merge/MergeModelBase.java +++ b/platform/diff-impl/src/com/intellij/diff/merge/MergeModelBase.java @@ -39,7 +39,7 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; -abstract class MergeModelBase implements Disposable { +public abstract class MergeModelBase implements Disposable { public static final Logger LOG = Logger.getInstance(MergeModelBase.class); @Nullable private final Project myProject; diff --git a/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java b/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java index 2f409aeb31f3..5b5e1d98b805 100644 --- a/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java @@ -40,9 +40,6 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.command.UndoConfirmationPolicy; -import com.intellij.openapi.command.undo.DocumentReference; -import com.intellij.openapi.command.undo.DocumentReferenceManager; -import com.intellij.openapi.command.undo.UndoManager; import com.intellij.openapi.diff.DiffBundle; import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.Document; @@ -54,12 +51,8 @@ import com.intellij.openapi.progress.util.ProgressWindow; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.ui.popup.Balloon; -import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.Disposer; -import com.intellij.ui.HyperlinkAdapter; import com.intellij.ui.awt.RelativePoint; import com.intellij.util.Alarm; import com.intellij.util.containers.ContainerUtil; @@ -68,8 +61,6 @@ import gnu.trove.TIntArrayList; import org.jetbrains.annotations.*; import javax.swing.*; -import javax.swing.event.HyperlinkEvent; -import javax.swing.event.HyperlinkListener; import java.awt.*; import java.awt.event.ActionEvent; import java.util.*; @@ -300,12 +291,7 @@ public class TextMergeViewer implements MergeTool.MergeViewer { DiffUtil.executeWriteCommand(outputDocument, getProject(), "Init merge content", () -> { outputDocument.setText(baseDocument.getCharsSequence()); - - UndoManager undoManager = getProject() != null ? UndoManager.getInstance(getProject()) : UndoManager.getGlobalInstance(); - if (undoManager != null) { - DocumentReference ref = DocumentReferenceManager.getInstance().create(outputDocument); - undoManager.nonundoableActionPerformed(ref, false); - } + DiffUtil.putNonundoableOperation(getProject(), outputDocument); }); } @@ -581,26 +567,16 @@ public class TextMergeViewer implements MergeTool.MergeViewer { LOG.assertTrue(getFirstUnresolvedChange(true, null) == null); ApplicationManager.getApplication().invokeLater(() -> { if (isDisposed()) return; - String message = "All changes have been processed.
Save changes and finish merging"; - HyperlinkListener listener = new HyperlinkAdapter() { - @Override - protected void hyperlinkActivated(HyperlinkEvent e) { - if (isDisposed()) return; - destroyChangedBlocks(); - myMergeContext.finishMerge(MergeResult.RESOLVED); - } - }; JComponent component = getEditor().getComponent(); - Point point = new Point(component.getWidth() / 2, JBUI.scale(5)); - Color bgColor = MessageType.INFO.getPopupBackground(); + RelativePoint point = new RelativePoint(component, new Point(component.getWidth() / 2, JBUI.scale(5))); - Balloon balloon = JBPopupFactory.getInstance() - .createHtmlTextBalloonBuilder(message, null, bgColor, listener) - .setAnimationCycle(200) - .createBalloon(); - balloon.show(new RelativePoint(component, point), Balloon.Position.below); - Disposer.register(this, balloon); + String message = DiffBundle.message("merge.all.changes.processed.message.text"); + DiffUtil.showSuccessPopup(message, point, this, () -> { + if (isDisposed()) return; + destroyChangedBlocks(); + myMergeContext.finishMerge(MergeResult.RESOLVED); + }); }); } } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffChange.java b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffChange.java index 7d38d7cab7e2..b5efd0397eb3 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffChange.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffChange.java @@ -15,7 +15,6 @@ */ package com.intellij.diff.tools.fragmented; -import com.intellij.diff.fragments.DiffFragment; import com.intellij.diff.fragments.LineFragment; import com.intellij.diff.util.*; import com.intellij.diff.util.DiffUtil.UpdatedLineRange; @@ -77,12 +76,7 @@ public class UnifiedDiffChange { private void installHighlighter(@NotNull LineRange deleted, @NotNull LineRange inserted) { assert myHighlighters.isEmpty(); - if (myLineFragment.getInnerFragments() != null) { - doInstallHighlighterWithInner(deleted, inserted); - } - else { - doInstallHighlighterSimple(deleted, inserted); - } + doInstallHighlighters(deleted, inserted); doInstallActionHighlighters(); } @@ -99,35 +93,8 @@ public class UnifiedDiffChange { } } - private void doInstallHighlighterSimple(@NotNull LineRange deleted, @NotNull LineRange inserted) { - createLineHighlighters(deleted, inserted, false); - } - - private void doInstallHighlighterWithInner(@NotNull LineRange deleted, @NotNull LineRange inserted) { - List innerFragments = myLineFragment.getInnerFragments(); - assert innerFragments != null; - - int deletedStartOffset = myEditor.getDocument().getLineStartOffset(deleted.start); - int insertedStartOffset = myEditor.getDocument().getLineStartOffset(inserted.start); - - createLineHighlighters(deleted, inserted, true); - - for (DiffFragment fragment : innerFragments) { - createInlineHighlighter(TextDiffType.DELETED, - deletedStartOffset + fragment.getStartOffset1(), - deletedStartOffset + fragment.getEndOffset1()); - createInlineHighlighter(TextDiffType.INSERTED, - insertedStartOffset + fragment.getStartOffset2(), - insertedStartOffset + fragment.getEndOffset2()); - } - } - - private void createLineHighlighters(@NotNull LineRange deleted, @NotNull LineRange inserted, boolean ignored) { - myHighlighters.addAll(DiffDrawUtil.createUnifiedChunkHighlighters(myEditor, deleted, inserted, ignored)); - } - - private void createInlineHighlighter(@NotNull TextDiffType type, int start, int end) { - myHighlighters.addAll(DiffDrawUtil.createInlineHighlighter(myEditor, start, end, type)); + private void doInstallHighlighters(@NotNull LineRange deleted, @NotNull LineRange inserted) { + myHighlighters.addAll(DiffDrawUtil.createUnifiedChunkHighlighters(myEditor, deleted, inserted, myLineFragment.getInnerFragments())); } public int getLine1() { diff --git a/platform/diff-impl/src/com/intellij/diff/tools/holders/TextEditorHolder.java b/platform/diff-impl/src/com/intellij/diff/tools/holders/TextEditorHolder.java index 50abbb250769..9971ef08d351 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/holders/TextEditorHolder.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/holders/TextEditorHolder.java @@ -66,19 +66,20 @@ public class TextEditorHolder extends EditorHolder { // Build // + @NotNull + public static TextEditorHolder create(@Nullable Project project, @NotNull DocumentContent content) { + EditorEx editor = DiffUtil.createEditor(content.getDocument(), project, false, true); + DiffUtil.configureEditor(editor, content, project); + return new TextEditorHolder(editor); + } + public static class TextEditorHolderFactory extends EditorHolderFactory { public static TextEditorHolderFactory INSTANCE = new TextEditorHolderFactory(); @Override @NotNull public TextEditorHolder create(@NotNull DiffContent content, @NotNull DiffContext context) { - if (!(content instanceof DocumentContent)) throw new IllegalArgumentException(content.toString()); - Project project = context.getProject(); - DocumentContent documentContent = (DocumentContent)content; - - EditorEx editor = DiffUtil.createEditor(documentContent.getDocument(), project, false, true); - DiffUtil.configureEditor(editor, documentContent, project); - return new TextEditorHolder(editor); + return TextEditorHolder.create(context.getProject(), (DocumentContent)content); } @Override diff --git a/platform/diff-impl/src/com/intellij/diff/util/DiffDrawUtil.java b/platform/diff-impl/src/com/intellij/diff/util/DiffDrawUtil.java index 4183e95d532b..61856165795c 100644 --- a/platform/diff-impl/src/com/intellij/diff/util/DiffDrawUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/util/DiffDrawUtil.java @@ -15,6 +15,7 @@ */ package com.intellij.diff.util; +import com.intellij.diff.fragments.DiffFragment; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.colors.EditorColors; @@ -242,7 +243,9 @@ public class DiffDrawUtil { public static List createUnifiedChunkHighlighters(@NotNull Editor editor, @NotNull LineRange deleted, @NotNull LineRange inserted, - boolean ignored) { + @Nullable List innerFragments) { + boolean ignored = innerFragments != null; + List list = new ArrayList<>(); if (!inserted.isEmpty() && !deleted.isEmpty()) { list.addAll(createLineMarker(editor, deleted.start, TextDiffType.DELETED, SeparatorPlacement.TOP)); @@ -260,6 +263,22 @@ public class DiffDrawUtil { list.addAll(createHighlighter(editor, deleted.start, deleted.end, TextDiffType.DELETED, ignored)); list.addAll(createLineMarker(editor, deleted.end - 1, TextDiffType.DELETED, SeparatorPlacement.BOTTOM)); } + + if (innerFragments != null) { + int deletedStartOffset = editor.getDocument().getLineStartOffset(deleted.start); + int insertedStartOffset = editor.getDocument().getLineStartOffset(inserted.start); + + for (DiffFragment fragment : innerFragments) { + int deletedWordStart = deletedStartOffset + fragment.getStartOffset1(); + int deletedWordEnd = deletedStartOffset + fragment.getEndOffset1(); + list.addAll(createInlineHighlighter(editor, deletedWordStart, deletedWordEnd, TextDiffType.DELETED)); + + int insertedWordStart = insertedStartOffset + fragment.getStartOffset2(); + int insertedWordEnd = insertedStartOffset + fragment.getEndOffset2(); + list.addAll(createInlineHighlighter(editor, insertedWordStart, insertedWordEnd, TextDiffType.INSERTED)); + } + } + return list; } diff --git a/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java b/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java index baf8b5338e5f..1683c7795172 100644 --- a/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java @@ -40,11 +40,15 @@ import com.intellij.diff.tools.util.base.TextDiffViewerUtil; import com.intellij.icons.AllIcons; import com.intellij.ide.DataManager; import com.intellij.lang.Language; +import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.impl.LaterInvocator; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.UndoConfirmationPolicy; +import com.intellij.openapi.command.undo.DocumentReference; +import com.intellij.openapi.command.undo.DocumentReferenceManager; +import com.intellij.openapi.command.undo.UndoManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diff.DiffBundle; import com.intellij.openapi.diff.impl.GenericDataProvider; @@ -60,13 +64,17 @@ import com.intellij.openapi.editor.highlighter.EditorHighlighter; import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.PlainTextFileType; import com.intellij.openapi.fileTypes.SyntaxHighlighter; import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.ui.DialogWrapperDialog; +import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.WindowWrapper; +import com.intellij.openapi.ui.popup.Balloon; +import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.*; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; @@ -75,11 +83,10 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.openapi.wm.impl.IdeFrameImpl; import com.intellij.testFramework.LightVirtualFile; -import com.intellij.ui.ColorUtil; -import com.intellij.ui.IdeBorderFactory; -import com.intellij.ui.JBColor; -import com.intellij.ui.ScreenUtil; +import com.intellij.ui.*; +import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.components.JBLabel; +import com.intellij.util.ArrayUtil; import com.intellij.util.DocumentUtil; import com.intellij.util.LineSeparator; import com.intellij.util.containers.ContainerUtil; @@ -90,11 +97,11 @@ import org.jetbrains.annotations.*; import javax.swing.*; import javax.swing.border.Border; +import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; import java.awt.*; import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.BitSet; -import java.util.Collections; +import java.util.*; import java.util.List; public class DiffUtil { @@ -129,7 +136,7 @@ public class DiffUtil { } @Nullable - public static EditorHighlighter createEditorHighlighter(@Nullable Project project, @NotNull DocumentContent content) { + private static EditorHighlighter createEditorHighlighter(@Nullable Project project, @NotNull DocumentContent content) { FileType type = content.getContentType(); VirtualFile file = content.getHighlightFile(); Language language = content.getUserData(DiffUserDataKeys.LANGUAGE); @@ -139,18 +146,19 @@ public class DiffUtil { SyntaxHighlighter syntaxHighlighter = SyntaxHighlighterFactory.getSyntaxHighlighter(language, project, file); return highlighterFactory.createEditorHighlighter(syntaxHighlighter, EditorColorsManager.getInstance().getGlobalScheme()); } - else if ((file != null && file.getFileType() == type) || file instanceof LightVirtualFile) { - return highlighterFactory.createEditorHighlighter(project, file); + if (file != null) { + if ((type == null || type == PlainTextFileType.INSTANCE) || file.getFileType() == type || file instanceof LightVirtualFile) { + return highlighterFactory.createEditorHighlighter(project, file); + } } if (type != null) { return highlighterFactory.createEditorHighlighter(project, type); } - return null; } @NotNull - public static EditorHighlighter createEmptyEditorHighlighter() { + private static EditorHighlighter createEmptyEditorHighlighter() { return new EmptyEditorHighlighter(EditorColorsManager.getInstance().getGlobalScheme().getAttributes(HighlighterColors.TEXT)); } @@ -366,6 +374,30 @@ public class DiffUtil { } } + public static void showSuccessPopup(@NotNull String message, + @NotNull RelativePoint point, + @NotNull Disposable disposable, + @Nullable Runnable hyperlinkHandler) { + HyperlinkListener listener = null; + if (hyperlinkHandler != null) { + listener = new HyperlinkAdapter() { + @Override + protected void hyperlinkActivated(HyperlinkEvent e) { + hyperlinkHandler.run(); + } + }; + } + + Color bgColor = MessageType.INFO.getPopupBackground(); + + Balloon balloon = JBPopupFactory.getInstance() + .createHtmlTextBalloonBuilder(message, null, bgColor, listener) + .setAnimationCycle(200) + .createBalloon(); + balloon.show(point, Balloon.Position.below); + Disposer.register(disposable, balloon); + } + // // Titles // @@ -441,7 +473,7 @@ public class DiffUtil { @NotNull public static JComponent createTitle(@NotNull String title) { - return createTitle(title, null, null, true); + return createTitle(title, null, null, false); } @NotNull @@ -622,6 +654,31 @@ public class DiffUtil { return ComparisonManager.getInstance().isEquals(chunk1, chunk2, comparisonPolicy); } + @NotNull + public static int[] getSortedIndexes(@NotNull List values, @NotNull Comparator comparator) { + final List indexes = new ArrayList<>(values.size()); + for (int i = 0; i < values.size(); i++) { + indexes.add(i); + } + + ContainerUtil.sort(indexes, (i1, i2) -> { + T val1 = values.get(indexes.get(i1)); + T val2 = values.get(indexes.get(i2)); + return comparator.compare(val1, val2); + }); + + return ArrayUtil.toIntArray(indexes); + } + + @NotNull + public static int[] invertIndexes(@NotNull int[] indexes) { + int[] inverted = new int[indexes.length]; + for (int i = 0; i < indexes.length; i++) { + inverted[indexes[i]] = i; + } + return inverted; + } + // // Document modification // @@ -814,12 +871,11 @@ public class DiffUtil { @NotNull public static UpdatedLineRange updateRangeOnModification(int start, int end, int changeStart, int changeEnd, int shift) { - return updateRangeOnModification(start, end, changeStart, changeEnd, shift, false, false); + return updateRangeOnModification(start, end, changeStart, changeEnd, shift, false); } @NotNull - public static UpdatedLineRange updateRangeOnModification(int start, int end, int changeStart, int changeEnd, int shift, - boolean greedy, boolean strict) { + public static UpdatedLineRange updateRangeOnModification(int start, int end, int changeStart, int changeEnd, int shift, boolean greedy) { if (end <= changeStart) { // change before return new UpdatedLineRange(start, end, false); } @@ -828,7 +884,7 @@ public class DiffUtil { } if (start <= changeStart && end >= changeEnd) { // change inside - return new UpdatedLineRange(start, end + shift, strict); + return new UpdatedLineRange(start, end + shift, false); } // range is damaged. We don't know new boundaries. @@ -869,28 +925,29 @@ public class DiffUtil { public static TextDiffType getLineDiffType(@NotNull LineFragment fragment) { boolean left = fragment.getStartLine1() != fragment.getEndLine1(); boolean right = fragment.getStartLine2() != fragment.getEndLine2(); - return getType(left, right); + return getDiffType(left, right); } @NotNull public static TextDiffType getDiffType(@NotNull DiffFragment fragment) { boolean left = fragment.getEndOffset1() != fragment.getStartOffset1(); boolean right = fragment.getEndOffset2() != fragment.getStartOffset2(); - return getType(left, right); + return getDiffType(left, right); } - private static TextDiffType getType(boolean left, boolean right) { - if (left && right) { + @NotNull + public static TextDiffType getDiffType(boolean hasDeleted, boolean hasInserted) { + if (hasDeleted && hasInserted) { return TextDiffType.MODIFIED; } - else if (left) { + else if (hasDeleted) { return TextDiffType.DELETED; } - else if (right) { + else if (hasInserted) { return TextDiffType.INSERTED; } else { - LOG.error("DiffFragment should not be empty"); + LOG.error("Diff fragment should not be empty"); return TextDiffType.MODIFIED; } } @@ -990,6 +1047,14 @@ public class DiffUtil { return !ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(file).hasReadonlyFiles(); } + public static void putNonundoableOperation(@Nullable Project project, @NotNull Document document) { + UndoManager undoManager = project != null ? UndoManager.getInstance(project) : UndoManager.getGlobalInstance(); + if (undoManager != null) { + DocumentReference ref = DocumentReferenceManager.getInstance().create(document); + undoManager.nonundoableActionPerformed(ref, false); + } + } + // // Windows // diff --git a/platform/diff-impl/src/com/intellij/diff/util/TextDiffTypeFactory.java b/platform/diff-impl/src/com/intellij/diff/util/TextDiffTypeFactory.java index 047f18b0c063..30084b5bda0a 100644 --- a/platform/diff-impl/src/com/intellij/diff/util/TextDiffTypeFactory.java +++ b/platform/diff-impl/src/com/intellij/diff/util/TextDiffTypeFactory.java @@ -22,6 +22,7 @@ import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.ui.ColorUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -106,12 +107,12 @@ public class TextDiffTypeFactory { if (editor instanceof EditorEx) { Color fg = attributes.getBackgroundColor(); Color bg = ((EditorEx)editor).getBackgroundColor(); - return getMiddleColor(fg, bg); + return ColorUtil.mix(fg, bg, MIDDLE_COLOR_FACTOR); } else { Color fg = attributes.getBackgroundColor(); Color bg = EditorColorsManager.getInstance().getGlobalScheme().getDefaultBackground(); - return getMiddleColor(fg, bg); + return ColorUtil.mix(fg, bg, MIDDLE_COLOR_FACTOR); } } @@ -136,14 +137,6 @@ public class TextDiffTypeFactory { @NotNull public static Color getMiddleColor(@NotNull Color fg, @NotNull Color bg) { - int red = avg(fg.getRed(), bg.getRed(), MIDDLE_COLOR_FACTOR); - int green = avg(fg.getGreen(), bg.getGreen(), MIDDLE_COLOR_FACTOR); - int blue = avg(fg.getBlue(), bg.getBlue(), MIDDLE_COLOR_FACTOR); - //noinspection UseJBColor - return new Color(red, green, blue); - } - - private static int avg(int fg, int bg, double factor) { - return (int)(fg + Math.round(factor * (bg - fg))); + return ColorUtil.mix(fg, bg, MIDDLE_COLOR_FACTOR); } } diff --git a/platform/platform-resources-en/src/messages/DiffBundle.properties b/platform/platform-resources-en/src/messages/DiffBundle.properties index e16b96a9fdeb..8132217df7e0 100644 --- a/platform/platform-resources-en/src/messages/DiffBundle.properties +++ b/platform/platform-resources-en/src/messages/DiffBundle.properties @@ -70,6 +70,7 @@ merge.dialog.all.conflicts.resolved.message.text=All conflicts resolved merge.statistics.message={0, choice, 0#No changes|1#One change|2#{0, number} changes}. {1, choice, 0#No conflicts|1#One conflict|2#{0, number} conflicts} merge.dialog.exit.without.applying.changes.confirmation.message=Are you sure you want to exit without applying changes? cancel.visual.merge.dialog.title=Cancel Visual Merge +apply.somehow.status.message.all.applied=All hunks resolved apply.somehow.status.message.already.applied={0, number} {0, choice, 1#hunk is|2#hunks are} already applied apply.somehow.status.message.cant.apply=Can''t apply {0, number} {0, choice, 1#hunk|2#hunks} apply.somehow.status.message.cant.apply.some=Can''t apply {0, number} of {1, number} hunks @@ -77,6 +78,8 @@ merge.dialog.apply.partially.resolved.changes.confirmation.message=There {0, cho apply.partially.resolved.merge.dialog.title=Apply Changes merge.dialog.resolve.side.with.discard.title=Accept Changes merge.dialog.resolve.side.with.discard.message=Are you sure you want to discard your changes and accept {0, choice, 0#left|1#right} side? +merge.all.changes.processed.message.text=All changes have been processed.
Save changes and finish merging +apply.patch.all.changes.processed.message.text=All hunks have been processed.
Save changes and finish resolve merge.all.changes.have.processed.save.and.finish.confirmation.text=All changes have been processed.\nWould you like to save changes and finish merging? all.changes.processed.dialog.title=All Changes Processed merge.save.and.finish.button=Save and &Finish diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/PatchDiffRequestFactory.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/PatchDiffRequestFactory.java index 92e626dadea5..06d84cbcd3a6 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/PatchDiffRequestFactory.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/PatchDiffRequestFactory.java @@ -93,7 +93,7 @@ public class PatchDiffRequestFactory { applier.execute(); final AppliedTextPatch appliedTextPatch = AppliedTextPatch.create(applier.getAppliedInfo()); - return createBadDiffRequest(file, localContent, appliedTextPatch, null, null, null, null); + return createBadDiffRequest(project, file, localContent, appliedTextPatch, null, null, null, null); } else { String localContent = texts.getLocal().toString(); @@ -133,7 +133,8 @@ public class PatchDiffRequestFactory { } @NotNull - public static DiffRequest createBadDiffRequest(@Nullable VirtualFile file, + public static DiffRequest createBadDiffRequest(@Nullable Project project, + @NotNull VirtualFile file, @NotNull String localContent, @NotNull AppliedTextPatch textPatch, @Nullable String windowTitle, @@ -145,7 +146,9 @@ public class PatchDiffRequestFactory { if (resultTitle == null) resultTitle = VcsBundle.message("patch.apply.conflict.patched.somehow.version"); if (patchTitle == null) patchTitle = VcsBundle.message("patch.apply.conflict.patch"); - return new ApplyPatchDiffRequest(textPatch, localContent, file, windowTitle, localTitle, resultTitle, patchTitle); + DocumentContent resultContent = DiffContentFactory.getInstance().createDocument(project, file); + if (resultContent == null) resultContent = DiffContentFactory.getInstance().create(localContent, file); + return new ApplyPatchDiffRequest(resultContent, textPatch, localContent, windowTitle, localTitle, resultTitle, patchTitle); } @NotNull @@ -219,7 +222,8 @@ public class PatchDiffRequestFactory { if (resultTitle == null) resultTitle = VcsBundle.message("patch.apply.conflict.patched.somehow.version"); if (patchTitle == null) patchTitle = VcsBundle.message("patch.apply.conflict.patch"); - return new ApplyPatchMergeRequest(project, document, textPatch, localContent, + DocumentContent resultContent = DiffContentFactory.getInstance().create(project, document, file); + return new ApplyPatchMergeRequest(project, resultContent, textPatch, localContent, windowTitle, localTitle, resultTitle, patchTitle, callback); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchChange.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchChange.java index b7921f7a6904..1efb72f45db1 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchChange.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchChange.java @@ -17,27 +17,34 @@ package com.intellij.openapi.vcs.changes.patch.tool; import com.intellij.diff.comparison.ByWord; import com.intellij.diff.comparison.ComparisonPolicy; +import com.intellij.diff.comparison.DiffTooBigException; import com.intellij.diff.fragments.DiffFragment; -import com.intellij.diff.tools.util.SyncScrollSupport; +import com.intellij.diff.merge.MergeModelBase; import com.intellij.diff.util.*; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.diff.DiffBundle; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.LogicalPosition; import com.intellij.openapi.editor.ex.DocumentEx; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.ex.MarkupModelEx; +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.progress.DumbProgressIndicator; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.vcs.changes.patch.AppliedTextPatch; +import com.intellij.openapi.vcs.changes.patch.AppliedTextPatch.HunkStatus; import com.intellij.openapi.vcs.ex.LineStatusMarkerRenderer; +import com.intellij.ui.ColorUtil; import com.intellij.ui.JBColor; import com.intellij.util.PairConsumer; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.*; import java.awt.*; import java.awt.event.MouseEvent; import java.util.ArrayList; @@ -45,42 +52,109 @@ import java.util.List; class ApplyPatchChange { @NotNull private final ApplyPatchViewer myViewer; + private final int myIndex; // index in myModelChanges @NotNull private final LineRange myPatchDeletionRange; @NotNull private final LineRange myPatchInsertionRange; - @NotNull private final AppliedTextPatch.HunkStatus myStatus; + @NotNull private final HunkStatus myStatus; + + @Nullable private final List myPatchInnerDifferences; + @NotNull private final List myOperations = new ArrayList<>(); @NotNull private final List myHighlighters = new ArrayList<>(); - @Nullable private LineRange myAppliedTo; - private boolean myIsValid = true; + private boolean myResolved; - public ApplyPatchChange(@NotNull ApplyPatchViewer viewer, @NotNull PatchChangeBuilder.Hunk hunk) { + public ApplyPatchChange(@NotNull PatchChangeBuilder.Hunk hunk, int index, @NotNull ApplyPatchViewer viewer) { + myIndex = index; myViewer = viewer; myPatchDeletionRange = hunk.getPatchDeletionRange(); myPatchInsertionRange = hunk.getPatchInsertionRange(); myStatus = hunk.getStatus(); - myAppliedTo = hunk.getAppliedToLines(); - installHighlighters(); - installPersistentHighlighters(); + myPatchInnerDifferences = calcPatchInnerDifferences(hunk, viewer); + } + + @Nullable + private static List calcPatchInnerDifferences(@NotNull PatchChangeBuilder.Hunk hunk, + @NotNull ApplyPatchViewer viewer) { + LineRange deletionRange = hunk.getPatchDeletionRange(); + LineRange insertionRange = hunk.getPatchInsertionRange(); + + if (deletionRange.isEmpty() || insertionRange.isEmpty()) return null; + + try { + DocumentEx patchDocument = viewer.getPatchEditor().getDocument(); + CharSequence deleted = DiffUtil.getLinesContent(patchDocument, deletionRange.start, deletionRange.end); + CharSequence inserted = DiffUtil.getLinesContent(patchDocument, insertionRange.start, insertionRange.end); + + return ByWord.compare(deleted, inserted, ComparisonPolicy.DEFAULT, DumbProgressIndicator.INSTANCE); + } + catch (DiffTooBigException ignore) { + return null; + } } public void reinstallHighlighters() { destroyHighlighters(); installHighlighters(); + + myViewer.repaintDivider(); } private void installHighlighters() { - createStatusHighlighter(myViewer.getPatchEditor(), myPatchDeletionRange.start, myPatchInsertionRange.end); + createResultHighlighters(); + createPatchHighlighters(); + createStatusHighlighter(); + createOperations(); + } - if (myAppliedTo != null) { - EditorEx resultEditor = myViewer.getResultEditor(); - createStatusHighlighter(resultEditor, myAppliedTo.start, myAppliedTo.end); + private void createPatchHighlighters() { + EditorEx patchEditor = myViewer.getPatchEditor(); + myHighlighters.addAll(DiffDrawUtil.createUnifiedChunkHighlighters(patchEditor, myPatchDeletionRange, myPatchInsertionRange, + myPatchInnerDifferences)); + } - myHighlighters.addAll(DiffDrawUtil.createLineMarker(resultEditor, myAppliedTo.start, myAppliedTo.end, - TextDiffType.MODIFIED, true)); + private void createResultHighlighters() { + LineRange resultRange = getResultRange(); + if (resultRange == null) return; + EditorEx editor = myViewer.getResultEditor(); + + int startLine = resultRange.start; + int endLine = resultRange.end; + + TextDiffType type = getDiffType(); + boolean resolved = isRangeApplied(); + + myHighlighters.addAll(DiffDrawUtil.createHighlighter(editor, startLine, endLine, type, false, resolved, false)); + myHighlighters.addAll(DiffDrawUtil.createLineMarker(editor, startLine, endLine, type, resolved)); + } + + private void createStatusHighlighter() { + int line1 = myPatchDeletionRange.start; + int line2 = myPatchInsertionRange.end; + + Color color = getStatusColor(); + if (isResolved()) { + color = ColorUtil.mix(color, myViewer.getPatchEditor().getGutterComponentEx().getBackground(), 0.6f); } + + String tooltip = getStatusText(); + + EditorEx patchEditor = myViewer.getPatchEditor(); + Document document = patchEditor.getDocument(); + MarkupModelEx markupModel = patchEditor.getMarkupModel(); + TextRange textRange = DiffUtil.getLinesRange(document, line1, line2); + + RangeHighlighter highlighter = markupModel.addRangeHighlighter(textRange.getStartOffset(), textRange.getEndOffset(), + HighlighterLayer.LAST, null, HighlighterTargetArea.LINES_IN_RANGE); + + PairConsumer clickHandler = getResultRange() != null ? + (e, event) -> myViewer.scrollToChange(this, Side.RIGHT, false) : + null; + highlighter.setLineMarkerRenderer(LineStatusMarkerRenderer.createRenderer(line1, line2, color, tooltip, clickHandler)); + + myHighlighters.add(highlighter); } private void destroyHighlighters() { @@ -88,42 +162,71 @@ class ApplyPatchChange { highlighter.dispose(); } myHighlighters.clear(); + + for (MyGutterOperation operation : myOperations) { + operation.dispose(); + } + myOperations.clear(); } - private void createStatusHighlighter(@NotNull EditorEx editor, int line1, int line2) { - Color color = getStatusColor(); - String tooltip = getStatusText(); + // + // Getters + // - Document document = editor.getDocument(); - MarkupModelEx markupModel = editor.getMarkupModel(); - TextRange textRange = DiffUtil.getLinesRange(document, line1, line2); - - RangeHighlighter highlighter = markupModel.addRangeHighlighter(textRange.getStartOffset(), textRange.getEndOffset(), - HighlighterLayer.LAST, null, HighlighterTargetArea.LINES_IN_RANGE); - - PairConsumer clickHandler = myAppliedTo != null ? (e, event) -> handleStatusClick(editor, event) : null; - highlighter.setLineMarkerRenderer(LineStatusMarkerRenderer.createRenderer(line1, line2, color, tooltip, clickHandler)); - - myHighlighters.add(highlighter); + public int getIndex() { + return myIndex; } - private void handleStatusClick(@NotNull EditorEx editor, @NotNull MouseEvent event) { - assert myAppliedTo != null; - EditorEx resultEditor = myViewer.getResultEditor(); - EditorEx patchEditor = myViewer.getPatchEditor(); + @NotNull + public HunkStatus getStatus() { + return myStatus; + } - Side clickSide = Side.fromLeft(editor == resultEditor); - int clickLine = clickSide.select(myAppliedTo.start, myPatchInsertionRange.start); - EditorEx clickEditor = clickSide.select(resultEditor, patchEditor); - int targetY = clickEditor.logicalPositionToXY(new LogicalPosition(clickLine, 0)).y; - int topShift = targetY - clickEditor.getScrollingModel().getVerticalScrollOffset(); + @NotNull + public LineRange getPatchRange() { + return new LineRange(myPatchDeletionRange.start, myPatchInsertionRange.end); + } - int[] offsets = SyncScrollSupport.getTargetOffsets(resultEditor, patchEditor, - myAppliedTo.start, myAppliedTo.end, - myPatchInsertionRange.start, myPatchInsertionRange.end, - topShift); - DiffUtil.scrollToPoint(resultEditor, new Point(0, offsets[0]), false); - DiffUtil.scrollToPoint(patchEditor, new Point(0, offsets[1]), false); + @NotNull + public LineRange getPatchAffectedRange() { + return isRangeApplied() ? myPatchInsertionRange : myPatchDeletionRange; + } + + @NotNull + public LineRange getPatchDeletionRange() { + return myPatchDeletionRange; + } + + @NotNull + public LineRange getPatchInsertionRange() { + return myPatchInsertionRange; + } + + @Nullable + public LineRange getResultRange() { + ApplyPatchViewer.MyModel model = myViewer.getModel(); + int lineStart = model.getLineStart(myIndex); + int lineEnd = model.getLineEnd(myIndex); + + if (lineStart != -1 || lineEnd != -1) return new LineRange(lineStart, lineEnd); + return null; + } + + public boolean isResolved() { + return myResolved; + } + + public void setResolved(boolean resolved) { + myResolved = resolved; + } + + @NotNull + public TextDiffType getDiffType() { + return DiffUtil.getDiffType(!myPatchDeletionRange.isEmpty(), !myPatchInsertionRange.isEmpty()); + } + + public boolean isRangeApplied() { + return myResolved || getStatus() == HunkStatus.ALREADY_APPLIED; } @NotNull @@ -154,76 +257,127 @@ class ApplyPatchChange { } } - private void installPersistentHighlighters() { - EditorEx patchEditor = myViewer.getPatchEditor(); - DocumentEx patchDocument = patchEditor.getDocument(); + // + // Operations + // - if (myPatchDeletionRange.isEmpty() || myPatchInsertionRange.isEmpty()) { - DiffDrawUtil.createUnifiedChunkHighlighters(patchEditor, myPatchDeletionRange, myPatchInsertionRange, false); + private void createOperations() { + if (myViewer.isReadOnly()) return; + if (isResolved()) return; + + if (myStatus == HunkStatus.EXACTLY_APPLIED) { + ContainerUtil.addIfNotNull(myOperations, createOperation(OperationType.APPLY)); } - else { - DiffDrawUtil.createUnifiedChunkHighlighters(patchEditor, myPatchDeletionRange, myPatchInsertionRange, true); + ContainerUtil.addIfNotNull(myOperations, createOperation(OperationType.IGNORE)); + } - CharSequence deleted = DiffUtil.getLinesContent(patchDocument, myPatchDeletionRange.start, myPatchDeletionRange.end); - CharSequence inserted = DiffUtil.getLinesContent(patchDocument, myPatchInsertionRange.start, myPatchInsertionRange.end); - List wordDiff = ByWord.compare(deleted, inserted, ComparisonPolicy.DEFAULT, DumbProgressIndicator.INSTANCE); + @Nullable + private MyGutterOperation createOperation(@NotNull OperationType type) { + if (isResolved()) return null; - int deletionStartShift = patchDocument.getLineStartOffset(myPatchDeletionRange.start); - int insertionStartShift = patchDocument.getLineStartOffset(myPatchInsertionRange.start); - for (DiffFragment fragment : wordDiff) { - int deletedWordStart = deletionStartShift + fragment.getStartOffset1(); - int deletedWordEnd = deletionStartShift + fragment.getEndOffset1(); - DiffDrawUtil.createInlineHighlighter(patchEditor, deletedWordStart, deletedWordEnd, TextDiffType.DELETED); + EditorEx editor = myViewer.getPatchEditor(); + Document document = editor.getDocument(); - int insertedWordStart = insertionStartShift + fragment.getStartOffset2(); - int insertedWordEndEnd = insertionStartShift + fragment.getEndOffset2(); - DiffDrawUtil.createInlineHighlighter(patchEditor, insertedWordStart, insertedWordEndEnd, TextDiffType.INSERTED); + int line = getPatchRange().start; + int offset = line == DiffUtil.getLineCount(document) ? document.getTextLength() : document.getLineStartOffset(line); + + RangeHighlighter highlighter = editor.getMarkupModel().addRangeHighlighter(offset, offset, + HighlighterLayer.ADDITIONAL_SYNTAX, + null, + HighlighterTargetArea.LINES_IN_RANGE); + return new MyGutterOperation(highlighter, type); + } + + private class MyGutterOperation { + @NotNull private final RangeHighlighter myHighlighter; + @NotNull private final OperationType myType; + + private MyGutterOperation(@NotNull RangeHighlighter highlighter, @NotNull OperationType type) { + myHighlighter = highlighter; + myType = type; + + myHighlighter.setGutterIconRenderer(createRenderer()); + } + + public void dispose() { + myHighlighter.dispose(); + } + + @Nullable + public GutterIconRenderer createRenderer() { + switch (myType) { + case APPLY: + return createApplyRenderer(); + case IGNORE: + return createIgnoreRenderer(); + default: + throw new IllegalArgumentException(myType.name()); } } } - // - // Getters - // - - @NotNull - public LineRange getPatchDeletionRange() { - return myPatchDeletionRange; - } - - @NotNull - public LineRange getPatchInsertionRange() { - return myPatchInsertionRange; - } - - @NotNull - public AppliedTextPatch.HunkStatus getStatus() { - return myStatus; + @Nullable + private GutterIconRenderer createApplyRenderer() { + return createIconRenderer(DiffBundle.message("merge.dialog.apply.change.action.name"), DiffUtil.getArrowIcon(Side.RIGHT), () -> { + myViewer.executeCommand("Accept change", () -> { + myViewer.replaceChange(this); + }); + }); } @Nullable - public LineRange getAppliedTo() { - return myAppliedTo; + private GutterIconRenderer createIgnoreRenderer() { + return createIconRenderer(DiffBundle.message("merge.dialog.ignore.change.action.name"), AllIcons.Diff.Remove, () -> { + myViewer.executeCommand("Ignore change", () -> { + myViewer.markChangeResolved(this); + }); + }); } - public boolean isValid() { - return myIsValid; + @Nullable + private static GutterIconRenderer createIconRenderer(@NotNull final String text, + @NotNull final Icon icon, + @NotNull final Runnable perform) { + final String tooltipText = DiffUtil.createTooltipText(text, null); + return new DiffGutterRenderer(icon, tooltipText) { + @Override + protected void performAction(AnActionEvent e) { + perform.run(); + } + }; + } + + private enum OperationType { + APPLY, IGNORE } // - // Shift + // State // - public boolean processChange(int oldLine1, int oldLine2, int shift) { - if (myAppliedTo == null) return false; - int line1 = myAppliedTo.start; - int line2 = myAppliedTo.end; + @NotNull + public State storeState() { + LineRange resultRange = getResultRange(); + return new State( + myIndex, + resultRange != null ? resultRange.start : -1, + resultRange != null ? resultRange.end : -1, + myResolved); + } - DiffUtil.UpdatedLineRange newRange = DiffUtil.updateRangeOnModification(line1, line2, oldLine1, oldLine2, shift, true, true); + public void restoreState(@NotNull State state) { + myResolved = state.myResolved; + } - myAppliedTo = new LineRange(newRange.startLine, newRange.endLine); - if (newRange.damaged) myIsValid = false; + public static class State extends MergeModelBase.State { + private final boolean myResolved; - return newRange.damaged || myAppliedTo.start != line1 || myAppliedTo.end != line2; + public State(int index, + int startLine, + int endLine, + boolean resolved) { + super(index, startLine, endLine); + myResolved = resolved; + } } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchDiffRequest.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchDiffRequest.java index a8c7f2f5af01..2f32d8a4632b 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchDiffRequest.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchDiffRequest.java @@ -15,48 +15,52 @@ */ package com.intellij.openapi.vcs.changes.patch.tool; +import com.intellij.diff.contents.DocumentContent; import com.intellij.diff.requests.DiffRequest; import com.intellij.openapi.vcs.changes.patch.AppliedTextPatch; -import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class ApplyPatchDiffRequest extends DiffRequest { +public class ApplyPatchDiffRequest extends DiffRequest implements ApplyPatchRequest { + @NotNull private final DocumentContent myResultContent; @NotNull private final AppliedTextPatch myAppliedPatch; + @NotNull private final String myLocalContent; - @Nullable private final VirtualFile myHighlightFile; @Nullable private final String myWindowTitle; @NotNull private final String myLocalTitle; @NotNull private final String myResultTitle; @NotNull private final String myPatchTitle; - public ApplyPatchDiffRequest(@NotNull AppliedTextPatch appliedPatch, + public ApplyPatchDiffRequest(@NotNull DocumentContent resultContent, + @NotNull AppliedTextPatch appliedPatch, @NotNull String localContent, - @Nullable VirtualFile highlightFile, @Nullable String windowTitle, @NotNull String localTitle, @NotNull String resultTitle, @NotNull String patchTitle) { + myResultContent = resultContent; myAppliedPatch = appliedPatch; myLocalContent = localContent; - myHighlightFile = highlightFile; myWindowTitle = windowTitle; myLocalTitle = localTitle; myResultTitle = resultTitle; myPatchTitle = patchTitle; } + @Override + @NotNull + public DocumentContent getResultContent() { + return myResultContent; + } + + @Override @NotNull public String getLocalContent() { return myLocalContent; } - @Nullable - public VirtualFile getHighlightFile() { - return myHighlightFile; - } - + @Override @NotNull public AppliedTextPatch getPatch() { return myAppliedPatch; @@ -68,16 +72,19 @@ public class ApplyPatchDiffRequest extends DiffRequest { return myWindowTitle; } + @Override @NotNull public String getLocalTitle() { return myLocalTitle; } + @Override @NotNull public String getResultTitle() { return myResultTitle; } + @Override @NotNull public String getPatchTitle() { return myPatchTitle; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchDiffTool.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchDiffTool.java index 72147f355d5f..214a264e096e 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchDiffTool.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchDiffTool.java @@ -40,13 +40,19 @@ public class ApplyPatchDiffTool implements FrameDiffTool { private static class MyApplyPatchViewer extends ApplyPatchViewer implements DiffViewer { public MyApplyPatchViewer(@NotNull DiffContext context, @NotNull ApplyPatchDiffRequest request) { - super(context, request, null); + super(context, request); } @NotNull @Override public ToolbarComponents init() { - return super.doInit(); + initPatchViewer(); + + ToolbarComponents components = new ToolbarComponents(); + components.statusPanel = getStatusPanel(); + components.toolbarActions = createToolbarActions(); + + return components; } } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchMergeRequest.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchMergeRequest.java index 9f342127c184..5ebc4a5f280c 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchMergeRequest.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchMergeRequest.java @@ -15,11 +15,11 @@ */ package com.intellij.openapi.vcs.changes.patch.tool; +import com.intellij.diff.contents.DocumentContent; import com.intellij.diff.merge.MergeRequest; import com.intellij.diff.merge.MergeResult; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; import com.intellij.openapi.vcs.changes.patch.AppliedTextPatch; @@ -27,13 +27,13 @@ import com.intellij.util.Consumer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class ApplyPatchMergeRequest extends MergeRequest { +public class ApplyPatchMergeRequest extends MergeRequest implements ApplyPatchRequest { @Nullable private final Project myProject; - @NotNull private final Document myDocument; - @NotNull private final CharSequence myOriginalContent; - + @NotNull private final DocumentContent myResultContent; @NotNull private final AppliedTextPatch myAppliedPatch; + + @NotNull private final CharSequence myOriginalContent; @NotNull private final String myLocalContent; @Nullable private final String myWindowTitle; @@ -44,7 +44,7 @@ public class ApplyPatchMergeRequest extends MergeRequest { @Nullable private final Consumer myCallback; public ApplyPatchMergeRequest(@Nullable Project project, - @NotNull Document document, + @NotNull DocumentContent resultContent, @NotNull AppliedTextPatch appliedPatch, @NotNull String localContent, @Nullable String windowTitle, @@ -53,13 +53,13 @@ public class ApplyPatchMergeRequest extends MergeRequest { @NotNull String patchTitle, @Nullable Consumer callback) { myProject = project; - myDocument = document; + myResultContent = resultContent; myAppliedPatch = appliedPatch; myOriginalContent = ApplicationManager.getApplication().runReadAction(new Computable() { @Override public CharSequence compute() { - return myDocument.getImmutableCharSequence(); + return myResultContent.getDocument().getImmutableCharSequence(); } }); myLocalContent = localContent; @@ -77,16 +77,19 @@ public class ApplyPatchMergeRequest extends MergeRequest { return myProject; } + @Override @NotNull - public Document getDocument() { - return myDocument; + public DocumentContent getResultContent() { + return myResultContent; } + @Override @NotNull public String getLocalContent() { return myLocalContent; } + @Override @NotNull public AppliedTextPatch getPatch() { return myAppliedPatch; @@ -98,16 +101,19 @@ public class ApplyPatchMergeRequest extends MergeRequest { return myWindowTitle; } + @Override @NotNull public String getLocalTitle() { return myLocalTitle; } + @Override @NotNull public String getResultTitle() { return myResultTitle; } + @Override @NotNull public String getPatchTitle() { return myPatchTitle; @@ -137,7 +143,7 @@ public class ApplyPatchMergeRequest extends MergeRequest { new WriteCommandAction.Simple(myProject) { @Override protected void run() throws Throwable { - myDocument.setText(applyContent); + myResultContent.getDocument().setText(applyContent); } }.execute(); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchMergeTool.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchMergeTool.java index c711a37bde55..828a361a0afe 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchMergeTool.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchMergeTool.java @@ -16,16 +16,20 @@ package com.intellij.openapi.vcs.changes.patch.tool; import com.intellij.diff.DiffContext; -import com.intellij.diff.FrameDiffTool; import com.intellij.diff.merge.*; -import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.util.BooleanGetter; -import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.diff.util.DiffUtil; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diff.DiffBundle; +import com.intellij.ui.awt.RelativePoint; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.JBUI; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.awt.event.ActionEvent; +import java.awt.*; + +import static com.intellij.diff.merge.MergeUtil.createSimpleResolveAction; public class ApplyPatchMergeTool implements MergeTool { @NotNull @@ -44,7 +48,7 @@ public class ApplyPatchMergeTool implements MergeTool { @NotNull private final ApplyPatchMergeRequest myMergeRequest; public MyApplyPatchViewer(@NotNull MergeContext context, @NotNull ApplyPatchMergeRequest request) { - super(createWrapperDiffContext(context), createWrapperDiffRequest(request), request.getDocument()); + super(createWrapperDiffContext(context), request); myMergeContext = context; myMergeRequest = request; } @@ -54,28 +58,16 @@ public class ApplyPatchMergeTool implements MergeTool { return new MergeUtil.ProxyDiffContext(mergeContext); } - @NotNull - private static ApplyPatchDiffRequest createWrapperDiffRequest(@NotNull ApplyPatchMergeRequest request) { - VirtualFile file = FileDocumentManager.getInstance().getFile(request.getDocument()); - return new ApplyPatchDiffRequest(request.getPatch(), request.getLocalContent(), file, request.getTitle(), - request.getLocalTitle(), request.getResultTitle(), request.getPatchTitle()); - } - @NotNull @Override public ToolbarComponents init() { + initPatchViewer(); + ToolbarComponents components = new ToolbarComponents(); + components.statusPanel = getStatusPanel(); + components.toolbarActions = createToolbarActions(); - FrameDiffTool.ToolbarComponents init = super.doInit(); - components.statusPanel = init.statusPanel; - components.toolbarActions = init.toolbarActions; - - components.closeHandler = new BooleanGetter() { - @Override - public boolean get() { - return MergeUtil.showExitWithoutApplyingChangesDialog(MyApplyPatchViewer.this, myMergeRequest, myMergeContext); - } - }; + components.closeHandler = () -> MergeUtil.showExitWithoutApplyingChangesDialog(this, myMergeRequest, myMergeContext); return components; } @@ -83,18 +75,28 @@ public class ApplyPatchMergeTool implements MergeTool { @Override public Action getResolveAction(@NotNull final MergeResult result) { if (result == MergeResult.LEFT || result == MergeResult.RIGHT) return null; + return createSimpleResolveAction(result, myMergeRequest, myMergeContext, this); + } - String caption = MergeUtil.getResolveActionTitle(result, myMergeRequest, myMergeContext); - return new AbstractAction(caption) { - @Override - public void actionPerformed(ActionEvent e) { - if (result == MergeResult.CANCEL && - !MergeUtil.showExitWithoutApplyingChangesDialog(MyApplyPatchViewer.this, myMergeRequest, myMergeContext)) { - return; - } - myMergeContext.finishMerge(result); - } - }; + @Override + protected void onChangeResolved() { + super.onChangeResolved(); + + if (!ContainerUtil.exists(getModelChanges(), (c) -> !c.isResolved())) { + ApplicationManager.getApplication().invokeLater(() -> { + if (isDisposed()) return; + + JComponent component = getComponent(); + int yOffset = new RelativePoint(getResultEditor().getComponent(), new Point(0, JBUI.scale(5))).getPoint(component).y; + RelativePoint point = new RelativePoint(component, new Point(component.getWidth() / 2, yOffset)); + + String message = DiffBundle.message("apply.patch.all.changes.processed.message.text"); + DiffUtil.showSuccessPopup(message, point, this, () -> { + if (isDisposed()) return; + myMergeContext.finishMerge(MergeResult.RESOLVED); + }); + }); + } } } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchRequest.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchRequest.java new file mode 100644 index 000000000000..17f7c425eacf --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchRequest.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.vcs.changes.patch.tool; + +import com.intellij.diff.contents.DocumentContent; +import com.intellij.openapi.vcs.changes.patch.AppliedTextPatch; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +interface ApplyPatchRequest { + @NotNull + DocumentContent getResultContent(); + + @NotNull + String getLocalContent(); + + @NotNull + AppliedTextPatch getPatch(); + + @Nullable + String getTitle(); + + @NotNull + String getLocalTitle(); + + @NotNull + String getResultTitle(); + + @NotNull + String getPatchTitle(); +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchViewer.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchViewer.java index 23f7339cba56..f8144e68c16b 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchViewer.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchViewer.java @@ -17,110 +17,200 @@ package com.intellij.openapi.vcs.changes.patch.tool; import com.intellij.diff.DiffContentFactory; import com.intellij.diff.DiffContext; -import com.intellij.diff.FrameDiffTool; +import com.intellij.diff.DiffDialogHints; +import com.intellij.diff.DiffManager; +import com.intellij.diff.actions.ProxyUndoRedoAction; +import com.intellij.diff.actions.impl.FocusOppositePaneAction; +import com.intellij.diff.actions.impl.SetEditorSettingsAction; import com.intellij.diff.contents.DocumentContent; -import com.intellij.diff.requests.DiffRequest; +import com.intellij.diff.merge.MergeModelBase; import com.intellij.diff.requests.SimpleDiffRequest; import com.intellij.diff.tools.fragmented.LineNumberConvertor; -import com.intellij.diff.tools.simple.SimpleDiffViewer; -import com.intellij.diff.tools.util.DiffSplitter; -import com.intellij.diff.tools.util.StatusPanel; +import com.intellij.diff.tools.holders.TextEditorHolder; +import com.intellij.diff.tools.util.*; +import com.intellij.diff.tools.util.base.TextDiffSettingsHolder; +import com.intellij.diff.tools.util.base.TextDiffViewerUtil; +import com.intellij.diff.tools.util.side.TwosideContentPanel; import com.intellij.diff.util.*; +import com.intellij.icons.AllIcons; import com.intellij.openapi.Disposable; -import com.intellij.openapi.command.undo.DocumentReference; -import com.intellij.openapi.command.undo.DocumentReferenceManager; -import com.intellij.openapi.command.undo.UndoManager; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.ex.ActionUtil; +import com.intellij.openapi.command.UndoConfirmationPolicy; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diff.DiffBundle; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.EditorFactory; -import com.intellij.openapi.editor.event.DocumentEvent; -import com.intellij.openapi.editor.event.DocumentListener; +import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.event.VisibleAreaListener; import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.editor.ex.EditorMarkupModel; import com.intellij.openapi.editor.impl.DocumentImpl; +import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.BooleanGetter; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.vcs.changes.patch.AppliedTextPatch; import com.intellij.util.containers.ContainerUtil; import gnu.trove.TIntArrayList; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.*; import javax.swing.*; import java.awt.*; import java.util.ArrayList; +import java.util.BitSet; import java.util.List; -class ApplyPatchViewer implements Disposable { - @NotNull private final ApplyPatchDiffRequest myPatchRequest; +class ApplyPatchViewer implements DataProvider, Disposable { + public static final Logger LOG = Logger.getInstance(ApplyPatchViewer.class); @Nullable private final Project myProject; - @NotNull private final Document myResultDocument; + @NotNull private final DiffContext myContext; + @NotNull private final ApplyPatchRequest myPatchRequest; - @NotNull private final MySimpleDiffViewer myViewer; - - @NotNull private final DiffSplitter myPatchSplitter; - @NotNull private final EditorEx myPatchEditor; + @NotNull private final TextEditorHolder myResultHolder; + @NotNull private final TextEditorHolder myPatchHolder; @NotNull private final EditorEx myResultEditor; + @NotNull private final EditorEx myPatchEditor; + @NotNull private final SimpleDiffPanel myPanel; + @NotNull private final TwosideContentPanel myContentPanel; + + @NotNull private final MyModel myModel; + + @NotNull private final FocusTrackerSupport myFocusTrackerSupport; + @NotNull private final MyPrevNextDifferenceIterable myPrevNextDifferenceIterable; @NotNull private final StatusPanel myStatusPanel; + @NotNull private final SetEditorSettingsAction myEditorSettingsAction; + + // Changes with known AppliedTo. Ordered as in result-editor + @NotNull private final List myResultChanges = new ArrayList<>(); + // All changes. Ordered as in patch-editor @NotNull private final List myPatchChanges = new ArrayList<>(); + // All changes. Ordered as in result-editor. Non-applied changes are at the very beginning with model ranges [-1. -1) + @NotNull private final List myModelChanges = new ArrayList<>(); - public ApplyPatchViewer(@NotNull DiffContext context, - @NotNull ApplyPatchDiffRequest patchRequest, - @Nullable Document resultDocument) { - myPatchRequest = patchRequest; + private boolean myDisposed; + public ApplyPatchViewer(@NotNull DiffContext context, @NotNull ApplyPatchRequest request) { myProject = context.getProject(); - myResultDocument = resultDocument != null ? resultDocument : new DocumentImpl(""); + myContext = context; + myPatchRequest = request; - VirtualFile file = patchRequest.getHighlightFile(); - DiffContentFactory contentFactory = DiffContentFactory.getInstance(); - DocumentContent localContent = contentFactory.create(myPatchRequest.getLocalContent(), file); - DocumentContent mergedContent = contentFactory.create(myProject, myResultDocument, file); - SimpleDiffRequest diffRequest = new SimpleDiffRequest(myPatchRequest.getTitle(), localContent, mergedContent, - myPatchRequest.getLocalTitle(), myPatchRequest.getResultTitle()); - if (resultDocument == null) diffRequest.putUserData(DiffUserDataKeys.FORCE_READ_ONLY, true); + DocumentContent resultContent = request.getResultContent(); + DocumentContent patchContent = DiffContentFactory.getInstance().create(new DocumentImpl("", true), resultContent); - myViewer = new MySimpleDiffViewer(context, diffRequest); - myResultEditor = myViewer.getEditor2(); + myResultHolder = TextEditorHolder.create(myProject, resultContent); + myPatchHolder = TextEditorHolder.create(myProject, patchContent); - myPatchEditor = DiffUtil.createEditor(new DocumentImpl("", true), myProject, true, true); - DiffUtil.setEditorHighlighter(myProject, myPatchEditor, mergedContent); + myResultEditor = myResultHolder.getEditor(); + myPatchEditor = myPatchHolder.getEditor(); + + if (isReadOnly()) myResultEditor.setViewer(true); + myPatchEditor.setViewer(true); + + DiffUtil.disableBlitting(myResultEditor); DiffUtil.disableBlitting(myPatchEditor); + + ((EditorMarkupModel)myResultEditor.getMarkupModel()).setErrorStripeVisible(false); + myResultEditor.setVerticalScrollbarOrientation(EditorEx.VERTICAL_SCROLLBAR_LEFT); + myPatchEditor.getGutterComponentEx().setForceShowRightFreePaintersArea(true); - - JPanel patchPanel = new JPanel(new BorderLayout(0, DiffUtil.TITLE_GAP)); - patchPanel.add(myPatchEditor.getComponent(), BorderLayout.CENTER); - patchPanel.add(myViewer.getPatchTitle(), BorderLayout.NORTH); + ((EditorMarkupModel)myPatchEditor.getMarkupModel()).setErrorStripeVisible(false); - myPatchSplitter = new DiffSplitter(); - myPatchSplitter.setProportion(2f / 3); - myPatchSplitter.setFirstComponent(myViewer.getComponent()); - myPatchSplitter.setSecondComponent(patchPanel); - myPatchSplitter.setHonorComponentsMinimumSize(false); + List holders = ContainerUtil.list(myResultHolder, myPatchHolder); + List editors = ContainerUtil.list(myResultEditor, myPatchEditor); + JComponent resultTitle = DiffUtil.createTitle(myPatchRequest.getResultTitle()); + JComponent patchTitle = DiffUtil.createTitle(myPatchRequest.getPatchTitle()); + List titleComponents = DiffUtil.createSyncHeightComponents(ContainerUtil.list(resultTitle, patchTitle)); + myContentPanel = new TwosideContentPanel(holders, titleComponents); + myPanel = new SimpleDiffPanel(myContentPanel, this, myContext); + + myModel = new MyModel(myProject, myResultEditor.getDocument()); + + myFocusTrackerSupport = new FocusTrackerSupport.Twoside(holders); + myFocusTrackerSupport.setCurrentSide(Side.LEFT); + myPrevNextDifferenceIterable = new MyPrevNextDifferenceIterable(); myStatusPanel = new MyStatusPanel(); + + + new MyFocusOppositePaneAction().install(myPanel); + new TextDiffViewerUtil.EditorActionsPopup(createEditorPopupActions()).install(editors); + + new TextDiffViewerUtil.EditorFontSizeSynchronizer(editors).install(this); + + TextDiffSettingsHolder.TextDiffSettings textSettings = TextDiffSettingsHolder.getInstance().getSettings("ApplyPatch"); + myEditorSettingsAction = new SetEditorSettingsAction(textSettings, editors); + myEditorSettingsAction.applyDefaults(); + + if (!isReadOnly()) { + DiffUtil.registerAction(new ApplySelectedChangesAction(true), myPanel); + DiffUtil.registerAction(new IgnoreSelectedChangesAction(true), myPanel); + } + + ProxyUndoRedoAction.register(myProject, myResultEditor, myContentPanel); } @NotNull - public JComponent getComponent() { - return myPatchSplitter; + protected List createToolbarActions() { + List group = new ArrayList<>(); + + if (!isReadOnly()) { + group.add(new ShowDiffWithLocalAction()); + group.add(new ApplyNonConflictsAction()); + group.add(myEditorSettingsAction); + } + + return group; } - @Nullable - public JComponent getPreferredFocusedComponent() { - return myViewer.getPreferredFocusedComponent(); + @NotNull + private List createEditorPopupActions() { + List group = new ArrayList<>(); + + if (!isReadOnly()) { + group.add(new ApplySelectedChangesAction(false)); + group.add(new IgnoreSelectedChangesAction(false)); + } + + group.add(Separator.getInstance()); + group.addAll(TextDiffViewerUtil.createEditorPopupActions()); + + return group; } @Override public void dispose() { - EditorFactory.getInstance().releaseEditor(myPatchEditor); - Disposer.dispose(myViewer); + if (myDisposed) return; + myDisposed = true; + + Disposer.dispose(myResultHolder); + Disposer.dispose(myPatchHolder); + } + + // + // Getters + // + + public boolean isReadOnly() { + return !DiffUtil.canMakeWritable(myResultEditor.getDocument()); + } + + @NotNull + public MyModel getModel() { + return myModel; + } + + @NotNull + public List getModelChanges() { + return myModelChanges; + } + + public boolean isDisposed() { + return myDisposed; } @NotNull @@ -129,8 +219,13 @@ class ApplyPatchViewer implements Disposable { } @NotNull - public MySimpleDiffViewer getViewer() { - return myViewer; + public JComponent getComponent() { + return myPanel; + } + + @Nullable + public JComponent getPreferredFocusedComponent() { + return myResultEditor.getContentComponent(); } @NotNull @@ -144,31 +239,44 @@ class ApplyPatchViewer implements Disposable { } @NotNull - public FrameDiffTool.ToolbarComponents doInit() { - Document patchDocument = myPatchEditor.getDocument(); + public Side getCurrentSide() { + return myFocusTrackerSupport.getCurrentSide(); + } + + @Nullable + @Override + public Object getData(@NonNls String dataId) { + if (CommonDataKeys.PROJECT.is(dataId)) { + return myProject; + } + else if (DiffDataKeys.PREV_NEXT_DIFFERENCE_ITERABLE.is(dataId)) { + return myPrevNextDifferenceIterable; + } + return null; + } + + // + // Impl + // + + protected void initPatchViewer() { + final Document outputDocument = myResultEditor.getDocument(); + DiffUtil.executeWriteCommand(outputDocument, myProject, "Init merge content", () -> { + outputDocument.setText(myPatchRequest.getLocalContent()); + if (!isReadOnly()) DiffUtil.putNonundoableOperation(myProject, outputDocument); + }); PatchChangeBuilder builder = new PatchChangeBuilder(); - builder.exec(myPatchRequest.getPatch().getHunks(), myPatchRequest.getLocalContent()); + builder.exec(myPatchRequest.getPatch().getHunks()); - DiffUtil.executeWriteCommand(myResultDocument, myProject, "Init merge content", () -> { - myResultDocument.setText(builder.getPatchApplyResult()); - - UndoManager undoManager = myProject != null ? UndoManager.getInstance(myProject) : UndoManager.getGlobalInstance(); - if (undoManager != null) { - DocumentReference ref = DocumentReferenceManager.getInstance().create(myResultDocument); - undoManager.nonundoableActionPerformed(ref, false); - } - }); - + Document patchDocument = myPatchEditor.getDocument(); patchDocument.setText(builder.getPatchContent()); - LineNumberConvertor convertor = builder.getLineConvertor(); myPatchEditor.getGutterComponentEx().setLineNumberConvertor(convertor.createConvertor1(), convertor.createConvertor2()); - TIntArrayList lines = builder.getSeparatorLines(); for (int i = 0; i < lines.size(); i++) { int offset = patchDocument.getLineStartOffset(lines.get(i)); @@ -176,52 +284,388 @@ class ApplyPatchViewer implements Disposable { } - for (PatchChangeBuilder.Hunk hunk : builder.getHunks()) { - myPatchChanges.add(new ApplyPatchChange(this, hunk)); + List hunks = builder.getHunks(); + + int[] modelToPatchIndexes = DiffUtil.getSortedIndexes(hunks, (h1, h2) -> { + LineRange lines1 = h1.getAppliedToLines(); + LineRange lines2 = h2.getAppliedToLines(); + if (lines1 == null && lines2 == null) return 0; + if (lines1 == null) return -1; + if (lines2 == null) return 1; + return lines1.start - lines2.start; + }); + int[] patchToModelIndexes = DiffUtil.invertIndexes(modelToPatchIndexes); + + List modelRanges = new ArrayList<>(); + for (int modelIndex = 0; modelIndex < hunks.size(); modelIndex++) { + int patchIndex = modelToPatchIndexes[modelIndex]; + PatchChangeBuilder.Hunk hunk = hunks.get(patchIndex); + LineRange resultRange = hunk.getAppliedToLines(); + + ApplyPatchChange change = new ApplyPatchChange(hunk, modelIndex, this); + + myModelChanges.add(change); + if (resultRange != null) myResultChanges.add(change); + + modelRanges.add(resultRange != null ? resultRange : new LineRange(-1, -1)); + } + myModel.setChanges(modelRanges); + + for (int index : patchToModelIndexes) { + myPatchChanges.add(myModelChanges.get(index)); + } + + + for (ApplyPatchChange change : myModelChanges) { + change.reinstallHighlighters(); } myStatusPanel.update(); - myPatchSplitter.setPainter(new MyDividerPainter()); + myContentPanel.setPainter(new MyDividerPainter()); - VisibleAreaListener areaListener = (e) -> myPatchSplitter.repaint(); + VisibleAreaListener areaListener = (e) -> myContentPanel.repaint(); myResultEditor.getScrollingModel().addVisibleAreaListener(areaListener); myPatchEditor.getScrollingModel().addVisibleAreaListener(areaListener); - myResultEditor.getDocument().addDocumentListener(new MyDocumentListener(), this); - - - FrameDiffTool.ToolbarComponents init = myViewer.init(); - init.statusPanel = getStatusPanel(); - return init; + myPatchEditor.getGutterComponentEx().revalidateMarkup(); } - private class MyDocumentListener implements DocumentListener { - private boolean myShouldRepaint; + public void scrollToChange(@NotNull ApplyPatchChange change, @NotNull Side masterSide, boolean forceScroll) { + if (change.getResultRange() == null) { + DiffUtil.moveCaret(myPatchEditor, change.getPatchRange().start); + myPatchEditor.getScrollingModel().scrollToCaret(forceScroll ? ScrollType.CENTER : ScrollType.MAKE_VISIBLE); + } + else { + LineRange resultRange = change.getResultRange(); + LineRange patchRange = change.getPatchAffectedRange(); - @Override - public void beforeDocumentChange(DocumentEvent e) { - myShouldRepaint = false; - if (myPatchChanges.isEmpty()) return; - - LineRange lineRange = DiffUtil.getAffectedLineRange(e); - int shift = DiffUtil.countLinesShift(e); - - for (ApplyPatchChange change : myPatchChanges) { - myShouldRepaint |= change.processChange(lineRange.start, lineRange.end, shift); + int topShift = -1; + if (!forceScroll) { + int masterLine = masterSide.select(resultRange.start, patchRange.start); + EditorEx masterEditor = masterSide.select(myResultEditor, myPatchEditor); + int targetY = masterEditor.logicalPositionToXY(new LogicalPosition(masterLine, 0)).y; + int scrollOffset = masterEditor.getScrollingModel().getVerticalScrollOffset(); + topShift = targetY - scrollOffset; } + + int[] offsets = SyncScrollSupport.getTargetOffsets(myResultEditor, myPatchEditor, + resultRange.start, resultRange.end, + patchRange.start, patchRange.end, + topShift); + + DiffUtil.moveCaret(myResultEditor, resultRange.start); + DiffUtil.moveCaret(myPatchEditor, patchRange.start); + + DiffUtil.scrollToPoint(myResultEditor, new Point(0, offsets[0]), false); + DiffUtil.scrollToPoint(myPatchEditor, new Point(0, offsets[1]), false); + } + } + + // + // Modification operations + // + + public void repaintDivider() { + myContentPanel.repaintDivider(); + } + + public void executeCommand(@Nullable String commandName, + @NotNull final Runnable task) { + myModel.executeMergeCommand(commandName, null, UndoConfirmationPolicy.DEFAULT, false, null, task); + } + + class MyModel extends MergeModelBase { + public MyModel(@Nullable Project project, @NotNull Document document) { + super(project, document); } @Override - public void documentChanged(DocumentEvent e) { - if (myShouldRepaint) { - myShouldRepaint = false; + protected void reinstallHighlighters(int index) { + ApplyPatchChange change = myModelChanges.get(index); + change.reinstallHighlighters(); + } - myPatchSplitter.repaintDivider(); - for (ApplyPatchChange change : myPatchChanges) { - change.reinstallHighlighters(); + @NotNull + @Override + protected ApplyPatchChange.State storeChangeState(int index) { + ApplyPatchChange change = myModelChanges.get(index); + return change.storeState(); + } + + @Override + protected void restoreChangeState(@NotNull ApplyPatchChange.State state) { + super.restoreChangeState(state); + ApplyPatchChange change = myModelChanges.get(state.myIndex); + + boolean wasResolved = change.isResolved(); + change.restoreState(state); + if (wasResolved != change.isResolved()) onChangeResolved(); + } + } + + protected void onChangeResolved() { + if (isDisposed()) return; + myStatusPanel.update(); + } + + public void markChangeResolved(@NotNull ApplyPatchChange change) { + if (change.isResolved()) return; + + change.setResolved(true); + myModel.invalidateHighlighters(change.getIndex()); + onChangeResolved(); + } + + public void replaceChange(@NotNull ApplyPatchChange change) { + LineRange resultRange = change.getResultRange(); + LineRange patchRange = change.getPatchInsertionRange(); + if (resultRange == null || change.isResolved()) return; + if (change.getStatus() != AppliedTextPatch.HunkStatus.EXACTLY_APPLIED) return; + + List newContent = DiffUtil.getLines(myPatchEditor.getDocument(), patchRange.start, patchRange.end); + myModel.replaceChange(change.getIndex(), newContent); + + markChangeResolved(change); + } + + private class ApplySelectedChangesAction extends ApplySelectedChangesActionBase { + private ApplySelectedChangesAction(boolean shortcut) { + super(shortcut); + getTemplatePresentation().setText("Accept"); + getTemplatePresentation().setIcon(AllIcons.Actions.Checked); + copyShortcutFrom(ActionManager.getInstance().getAction("Diff.ApplyRightSide")); + } + + @Override + protected boolean isEnabled(@NotNull ApplyPatchChange change) { + return !change.isResolved() && change.getStatus() == AppliedTextPatch.HunkStatus.EXACTLY_APPLIED; + } + + @Override + protected void apply(@NotNull List changes) { + for (int i = changes.size() - 1; i >= 0; i--) { + replaceChange(changes.get(i)); + } + } + } + + private class IgnoreSelectedChangesAction extends ApplySelectedChangesActionBase { + private IgnoreSelectedChangesAction(boolean shortcut) { + super(shortcut); + getTemplatePresentation().setText("Ignore"); + getTemplatePresentation().setIcon(AllIcons.Diff.Remove); + copyShortcutFrom(ActionManager.getInstance().getAction("Diff.IgnoreRightSide")); + } + + @Override + protected boolean isEnabled(@NotNull ApplyPatchChange change) { + return !change.isResolved(); + } + + @Override + protected void apply(@NotNull List changes) { + for (ApplyPatchChange change : changes) { + markChangeResolved(change); + } + } + } + + private abstract class ApplySelectedChangesActionBase extends DumbAwareAction { + private final boolean myShortcut; + + public ApplySelectedChangesActionBase(boolean shortcut) { + myShortcut = shortcut; + } + + @Override + public void update(@NotNull AnActionEvent e) { + if (myShortcut) { + // consume shortcut even if there are nothing to do - avoid calling some other action + e.getPresentation().setEnabledAndVisible(true); + return; + } + + Presentation presentation = e.getPresentation(); + Editor editor = e.getData(CommonDataKeys.EDITOR); + + Side side = Side.fromValue(ContainerUtil.list(myResultEditor, myPatchEditor), editor); + if (side == null) { + presentation.setEnabledAndVisible(false); + return; + } + + presentation.setVisible(true); + presentation.setEnabled(isSomeChangeSelected(side)); + } + + @Override + public void actionPerformed(@NotNull final AnActionEvent e) { + Editor editor = e.getData(CommonDataKeys.EDITOR); + final Side side = Side.fromValue(ContainerUtil.list(myResultEditor, myPatchEditor), editor); + if (editor == null || side == null) return; + + final List selectedChanges = getSelectedChanges(side); + if (selectedChanges.isEmpty()) return; + + String title = e.getPresentation().getText() + " in patch resolve"; + + executeCommand(title, () -> { + apply(selectedChanges); + }); + } + + private boolean isSomeChangeSelected(@NotNull Side side) { + EditorEx editor = side.select(myResultEditor, myPatchEditor); + List carets = editor.getCaretModel().getAllCarets(); + if (carets.size() != 1) return true; + Caret caret = carets.get(0); + if (caret.hasSelection()) return true; + + int line = editor.getDocument().getLineNumber(editor.getExpectedCaretOffset()); + + List changes = myModelChanges; + for (ApplyPatchChange change : changes) { + if (!isEnabled(change)) continue; + LineRange range = side.select(change.getResultRange(), change.getPatchRange()); + if (range == null) continue; + + if (DiffUtil.isSelectedByLine(line, range.start, range.end)) return true; + } + return false; + } + + @NotNull + @CalledInAwt + private List getSelectedChanges(@NotNull Side side) { + final BitSet lines = DiffUtil.getSelectedLines(side.select(myResultEditor, myPatchEditor)); + + List affectedChanges = new ArrayList<>(); + for (ApplyPatchChange change : myModelChanges) { + if (!isEnabled(change)) continue; + LineRange range = side.select(change.getResultRange(), change.getPatchRange()); + if (range == null) continue; + + if (DiffUtil.isSelectedByLine(lines, range.start, range.end)) { + affectedChanges.add(change); } } + return affectedChanges; + } + + protected abstract boolean isEnabled(@NotNull ApplyPatchChange change); + + @CalledWithWriteLock + protected abstract void apply(@NotNull List changes); + } + + private class ApplyNonConflictsAction extends DumbAwareAction { + public ApplyNonConflictsAction() { + ActionUtil.copyFrom(this, "Diff.ApplyNonConflicts"); + } + + @Override + public void update(AnActionEvent e) { + boolean enabled = ContainerUtil.exists(myModelChanges, c -> { + if (c.isResolved()) return false; + if (c.getStatus() == AppliedTextPatch.HunkStatus.NOT_APPLIED) return false; + return true; + }); + e.getPresentation().setEnabled(enabled); + } + + @Override + public void actionPerformed(AnActionEvent e) { + List changes = myModelChanges; + if (changes.isEmpty()) return; + + executeCommand("Apply Non Conflicted Changes", () -> { + for (int i = changes.size() - 1; i >= 0; i--) { + ApplyPatchChange change = changes.get(i); + switch (change.getStatus()) { + case ALREADY_APPLIED: + markChangeResolved(change); + break; + case EXACTLY_APPLIED: + replaceChange(change); + break; + case NOT_APPLIED: + break; + } + } + }); + } + } + + // + // Actions + // + + private class MyFocusOppositePaneAction extends FocusOppositePaneAction { + public MyFocusOppositePaneAction() { + super(false); + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + EditorEx targetEditor = getCurrentSide().other().select(myResultEditor, myPatchEditor); + DiffUtil.requestFocus(myProject, targetEditor.getContentComponent()); + } + } + + private class ShowDiffWithLocalAction extends DumbAwareAction { + public ShowDiffWithLocalAction() { + super("Compare with local content", null, AllIcons.Diff.Diff); + } + + @Override + public void actionPerformed(AnActionEvent e) { + DocumentContent resultContent = myPatchRequest.getResultContent(); + DocumentContent localContent = DiffContentFactory.getInstance().create(myPatchRequest.getLocalContent(), resultContent); + + SimpleDiffRequest request = new SimpleDiffRequest(myPatchRequest.getTitle(), + localContent, resultContent, + myPatchRequest.getLocalTitle(), myPatchRequest.getResultTitle()); + + LogicalPosition currentPosition = DiffUtil.getCaretPosition(myResultEditor); + request.putUserData(DiffUserDataKeys.SCROLL_TO_LINE, Pair.create(Side.RIGHT, currentPosition.line)); + + DiffManager.getInstance().showDiff(myProject, request, new DiffDialogHints(null, myPanel)); + } + } + + // + // Helpers + // + + private class MyPrevNextDifferenceIterable extends PrevNextDifferenceIterableBase { + @NotNull + @Override + protected List getChanges() { + return getCurrentSide().select(myResultChanges, myPatchChanges); + } + + @NotNull + @Override + protected EditorEx getEditor() { + return getCurrentSide().select(myResultEditor, myPatchEditor); + } + + @Override + protected int getStartLine(@NotNull ApplyPatchChange change) { + //noinspection ConstantConditions + return getCurrentSide().select(change.getResultRange(), change.getPatchAffectedRange()).start; + } + + @Override + protected int getEndLine(@NotNull ApplyPatchChange change) { + //noinspection ConstantConditions + return getCurrentSide().select(change.getResultRange(), change.getPatchAffectedRange()).end; + } + + @Override + protected void scrollToChange(@NotNull ApplyPatchChange change) { + ApplyPatchViewer.this.scrollToChange(change, getCurrentSide(), true); } } @@ -240,17 +684,15 @@ class ApplyPatchViewer implements Disposable { @Override public void process(@NotNull Handler handler) { - for (ApplyPatchChange change : myPatchChanges) { - LineRange appliedTo = change.getAppliedTo(); - if (appliedTo == null) continue; + for (ApplyPatchChange change : myResultChanges) { + LineRange resultRange = change.getResultRange(); + LineRange patchRange = change.getPatchRange(); + assert resultRange != null; - int patchLine1 = change.getPatchDeletionRange().start; - int patchLine2 = change.getPatchInsertionRange().end; + Color color = change.getDiffType().getColor(myPatchEditor); - Color color = TextDiffType.MODIFIED.getColor(myPatchEditor); - - // do not abort - ranges are ordered in patch order, but they can be not ordered in terms of appliedTo - handler.process(appliedTo.start, appliedTo.end, patchLine1, patchLine2, color); + // do not abort - ranges are ordered in patch order, but they can be not ordered in terms of resultRange + handler.process(resultRange.start, resultRange.end, patchRange.start, patchRange.end, color, change.isResolved()); } } } @@ -259,10 +701,13 @@ class ApplyPatchViewer implements Disposable { @Nullable @Override protected String getMessage() { - int total = myPatchChanges.size(); + int totalUnresolved = 0; int alreadyApplied = 0; int notApplied = 0; for (ApplyPatchChange change : myPatchChanges) { + if (change.isResolved()) continue; + + totalUnresolved++; switch (change.getStatus()) { case ALREADY_APPLIED: alreadyApplied++; @@ -275,42 +720,17 @@ class ApplyPatchViewer implements Disposable { } } - if (total == notApplied) { + if (totalUnresolved == 0) { + return DiffBundle.message("apply.somehow.status.message.all.applied", notApplied); + } + if (totalUnresolved == notApplied) { return DiffBundle.message("apply.somehow.status.message.cant.apply", notApplied); } else { - String message = DiffBundle.message("apply.somehow.status.message.cant.apply.some", notApplied, total); + String message = DiffBundle.message("apply.somehow.status.message.cant.apply.some", notApplied, totalUnresolved); if (alreadyApplied == 0) return message; return message + ". " + DiffBundle.message("apply.somehow.status.message.already.applied", alreadyApplied); } } } - - class MySimpleDiffViewer extends SimpleDiffViewer { - private JComponent myPatchTitleComponent; - - public MySimpleDiffViewer(@NotNull DiffContext context, @NotNull DiffRequest request) { - super(context, request); - } - - @NotNull - @Override - protected List createTitles() { - List requestTitles = DiffUtil.createTextTitles(myRequest, getEditors()); - JComponent patchTitleLabel = DiffUtil.createTitle(myPatchRequest.getPatchTitle(), null, null, false); - assert requestTitles.size() == 2; - - List titles = ContainerUtil.append(requestTitles, patchTitleLabel); - List syncTitles = DiffUtil.createSyncHeightComponents(titles); - - JComponent title1 = syncTitles.get(0); - JComponent title2 = syncTitles.get(1); - myPatchTitleComponent = syncTitles.get(2); - return ContainerUtil.list(title1, title2); - } - - public JComponent getPatchTitle() { - return myPatchTitleComponent; - } - } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/PatchChangeBuilder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/PatchChangeBuilder.java index 700a20a458e1..b80eb04fa0d6 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/PatchChangeBuilder.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/PatchChangeBuilder.java @@ -21,12 +21,14 @@ import com.intellij.diff.util.LineRange; import com.intellij.openapi.editor.impl.DocumentImpl; import com.intellij.openapi.vcs.changes.patch.AppliedTextPatch; import com.intellij.openapi.vcs.changes.patch.AppliedTextPatch.AppliedSplitPatchHunk; +import com.intellij.openapi.vcs.changes.patch.AppliedTextPatch.HunkStatus; import com.intellij.util.containers.ContainerUtil; import gnu.trove.TIntArrayList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; class PatchChangeBuilder { @@ -34,18 +36,30 @@ class PatchChangeBuilder { @NotNull private final List myHunks = new ArrayList<>(); @NotNull private final LineNumberConvertor.Builder myConvertor = new LineNumberConvertor.Builder(); @NotNull private final TIntArrayList myChangedLines = new TIntArrayList(); - private CharSequence myPatchedContent; private int totalLines = 0; @NotNull public static CharSequence getPatchedContent(@NotNull AppliedTextPatch patch, @NotNull String localContent) { PatchChangeBuilder builder = new PatchChangeBuilder(); - builder.exec(patch.getHunks(), localContent); - return builder.getPatchApplyResult(); + builder.exec(patch.getHunks()); + + DocumentImpl document = new DocumentImpl(localContent, true); + List appliedHunks = ContainerUtil.filter(builder.getHunks(), (h) -> h.getStatus() == HunkStatus.EXACTLY_APPLIED); + ContainerUtil.sort(appliedHunks, Comparator.comparingInt(h -> h.getAppliedToLines().start)); + + for (int i = appliedHunks.size() - 1; i >= 0; i--) { + Hunk hunk = appliedHunks.get(i); + LineRange appliedTo = hunk.getAppliedToLines(); + List inserted = hunk.getInsertedLines(); + + DiffUtil.applyModification(document, appliedTo.start, appliedTo.end, inserted); + } + + return document.getText(); } - public void exec(@NotNull List splitHunks, @NotNull CharSequence localContent) { + public void exec(@NotNull List splitHunks) { int lastBeforeLine = -1; for (AppliedSplitPatchHunk hunk : splitHunks) { List contextBefore = hunk.getContextBefore(); @@ -87,30 +101,6 @@ class PatchChangeBuilder { myHunks.add(new Hunk(hunk.getInsertedLines(), deletionRange, insertionRange, hunk.getAppliedTo(), hunk.getStatus())); } - - - DocumentImpl document = new DocumentImpl(localContent, true); - List appliedHunks = ContainerUtil.filter(myHunks, (h) -> h.getOriginalAppliedToLines() != null); - ContainerUtil.sort(appliedHunks, (h1, h2) -> Integer.compare(h1.getOriginalAppliedToLines().start, - h2.getOriginalAppliedToLines().start)); - - int shift = 0; - for (Hunk hunk : appliedHunks) { - LineRange appliedTo = hunk.getOriginalAppliedToLines(); - List inserted = hunk.getInsertedLines(); - - int insertedLines = inserted.size(); - int deletedLines = appliedTo.end - appliedTo.start; - - hunk.setAppliedToLines(new LineRange(appliedTo.start + shift, appliedTo.start + shift + insertedLines)); - - if (hunk.getStatus() == AppliedTextPatch.HunkStatus.EXACTLY_APPLIED) { - DiffUtil.applyModification(document, appliedTo.start + shift, appliedTo.end + shift, inserted); - shift += insertedLines - deletedLines; - } - } - - myPatchedContent = document.getText(); } private void addContext(@NotNull List context, int beforeLineNumber, int afterLineNumber) { @@ -156,11 +146,6 @@ class PatchChangeBuilder { return myChangedLines; } - @NotNull - public CharSequence getPatchApplyResult() { - return myPatchedContent; - } - static class Hunk { @NotNull private final List myInsertedLines; @@ -168,15 +153,13 @@ class PatchChangeBuilder { @NotNull private final LineRange myPatchInsertionRange; @Nullable private final LineRange myAppliedToLines; - @NotNull private final AppliedTextPatch.HunkStatus myStatus; - - @Nullable private LineRange myUpdatedAppliedToLines; + @NotNull private final HunkStatus myStatus; public Hunk(@NotNull List insertedLines, @NotNull LineRange patchDeletionRange, @NotNull LineRange patchInsertionRange, @Nullable LineRange appliedToLines, - @NotNull AppliedTextPatch.HunkStatus status) { + @NotNull HunkStatus status) { myInsertedLines = insertedLines; myPatchDeletionRange = patchDeletionRange; myPatchInsertionRange = patchInsertionRange; @@ -195,26 +178,17 @@ class PatchChangeBuilder { } @NotNull - public AppliedTextPatch.HunkStatus getStatus() { + public HunkStatus getStatus() { return myStatus; } - @Nullable public LineRange getAppliedToLines() { - return myUpdatedAppliedToLines; - } - - private void setAppliedToLines(@Nullable LineRange value) { - myUpdatedAppliedToLines = value; + return myAppliedToLines; } @NotNull private List getInsertedLines() { return myInsertedLines; } - - private LineRange getOriginalAppliedToLines() { - return myAppliedToLines; - } } }