From 75d4f86f62c77e7c3efa1108d15261e53de4a71e Mon Sep 17 00:00:00 2001 From: Denis Zaichenko Date: Tue, 9 Jul 2024 12:15:49 +0200 Subject: [PATCH] [vcs] IJPL-157627 Added ability to load inner fragments when 'Highlight lines' mode is enabled. GitOrigin-RevId: 992ae38f51a3cf97157605dc63d1529cd5821644 --- platform/diff-impl/resources/api-dump.txt | 6 ++ .../diff/merge/ChangeReferenceProcessor.kt | 80 +++++++++++++------ .../diff/merge/MergeThreesideViewer.java | 15 ++-- 3 files changed, 69 insertions(+), 32 deletions(-) diff --git a/platform/diff-impl/resources/api-dump.txt b/platform/diff-impl/resources/api-dump.txt index f93edeffa54c..5536fd328113 100644 --- a/platform/diff-impl/resources/api-dump.txt +++ b/platform/diff-impl/resources/api-dump.txt @@ -640,6 +640,12 @@ a:com.intellij.diff.lang.LangDiffIgnoredRangeProvider - pa:accepts(com.intellij.openapi.project.Project,com.intellij.lang.Language):Z - pa:computeIgnoredRanges(com.intellij.openapi.project.Project,java.lang.CharSequence,com.intellij.lang.Language):java.util.List - getIgnoredRanges(com.intellij.openapi.project.Project,java.lang.CharSequence,com.intellij.diff.contents.DiffContent):java.util.List +f:com.intellij.diff.merge.ChangeReferenceProcessor +- sf:Companion:com.intellij.diff.merge.ChangeReferenceProcessor$Companion +- (com.intellij.openapi.project.Project,com.intellij.openapi.editor.Editor,java.util.List,java.util.List):V +- f:process(com.intellij.diff.util.ThreeSide,java.util.List,java.util.List):V +f:com.intellij.diff.merge.ChangeReferenceProcessor$Companion +- f:getLOG():com.intellij.openapi.diagnostic.Logger a:com.intellij.diff.merge.MergeContextEx - com.intellij.diff.merge.MergeContext - ():V diff --git a/platform/diff-impl/src/com/intellij/diff/merge/ChangeReferenceProcessor.kt b/platform/diff-impl/src/com/intellij/diff/merge/ChangeReferenceProcessor.kt index 0112d1f809d0..4523b8656708 100644 --- a/platform/diff-impl/src/com/intellij/diff/merge/ChangeReferenceProcessor.kt +++ b/platform/diff-impl/src/com/intellij/diff/merge/ChangeReferenceProcessor.kt @@ -4,18 +4,26 @@ package com.intellij.diff.merge import com.intellij.codeInsight.editorActions.CopyPastePostProcessor import com.intellij.codeInsight.editorActions.ReferenceCopyPasteProcessor import com.intellij.codeInsight.editorActions.TextBlockTransferableData +import com.intellij.diff.comparison.ComparisonPolicy +import com.intellij.diff.tools.util.text.MergeInnerDifferences +import com.intellij.diff.util.DiffUtil import com.intellij.diff.util.Side import com.intellij.diff.util.ThreeSide import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.editor.Document import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.RangeMarker +import com.intellij.openapi.progress.DumbProgressIndicator import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.project.Project import com.intellij.openapi.util.Ref import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiFile +import java.util.concurrent.ConcurrentHashMap -class ChangeReferenceProcessor(val project: Project, private val editor: Editor, val files: List) { +class ChangeReferenceProcessor(private val project: Project, private val editor: Editor, private val files: List, private val documents: List) { + + private val innerDifferencesCache: MutableMap = ConcurrentHashMap() fun process( side: ThreeSide, @@ -51,39 +59,59 @@ class ChangeReferenceProcessor(val project: Project, private val editor: Editor, processInnerFragments: Boolean, ) { val sourceThreeSide = sourceSide.select(ThreeSide.LEFT, ThreeSide.RIGHT) ?: return + val sourceDocument = sourceThreeSide.select(documents) ?: return val psiFile = sourceSide.select(files[0], files[2]) ?: return - val sourceDocument = psiFile.fileDocument - val startOffset = sourceDocument.getLineStartOffset(change.getStartLine(sourceThreeSide)) - val endOffset = sourceDocument.getLineEndOffset(change.getEndLine(sourceThreeSide) - 1) + val sourceRange = DiffUtil.getLinesRange(sourceDocument, change.getStartLine(sourceThreeSide), change.getEndLine(sourceThreeSide)) - if (!processInnerFragments) { - val data = createReferenceData(psiFile, startOffset, endOffset) + if (change.getStartLine(sourceThreeSide) == change.getEndLine(sourceThreeSide)) return + + if (processInnerFragments) { + val innerDifferences = change.innerFragments ?: compareInner(change) ?: return + + innerDifferences.get(sourceThreeSide)?.forEach { + if (it.isEmpty) return@forEach + + val text = editor.document.getText(rangeMarker.textRange) + val fragmentStartOffset = sourceRange.startOffset + it.startOffset + val rangeInDocument = TextRange(fragmentStartOffset, fragmentStartOffset + it.length) + val fragmentText = sourceDocument.getText(rangeInDocument) + + if (fragmentText.isBlank()) return@forEach + + val offset = text.indexOf(fragmentText) + if (offset == -1) return@forEach + + val data = createReferenceData(psiFile, rangeInDocument.startOffset, rangeInDocument.endOffset) + val marker = sourceDocument.createRangeMarker( + rangeMarker.startOffset + offset, + rangeMarker.startOffset + offset + fragmentText.length + ) + data.forEach { processorData -> + processorData.process(project, editor, marker, 0, Ref(false)) + } + } + } + else { + val data = createReferenceData(psiFile, sourceRange.startOffset, sourceRange.endOffset) data.forEach { processorData -> processorData.process(project, editor, rangeMarker, 0, Ref(false)) } - return } + } - val innerFragments = change.innerFragments - innerFragments?.get(sourceThreeSide)?.forEach { - if (it.isEmpty) return@forEach + private fun getSequences(change: TextMergeChange): List { + return ThreeSide.map { + if (!change.isChange(it)) return@map null + val startLine = change.getStartLine(it) + val endLine = change.getEndLine(it) + if (startLine == endLine) return@map null + return@map DiffUtil.getLinesContent(it.select(documents), startLine, endLine) + } + } - val text = editor.document.getText(rangeMarker.textRange) - val fragmentStartOffset = startOffset + it.startOffset - val rangeInDocument = TextRange(fragmentStartOffset, fragmentStartOffset + it.length) - val fragmentText = sourceDocument.getText(rangeInDocument) - val offset = text.indexOf(fragmentText) - - if (offset == -1) return@forEach - - val data = createReferenceData(psiFile, rangeInDocument.startOffset, rangeInDocument.endOffset) - val marker = sourceDocument.createRangeMarker( - rangeMarker.startOffset + offset, - rangeInDocument.startOffset + offset + it.length - ) - data.forEach { processorData -> - processorData.process(project, editor, marker, 0, Ref(false)) - } + private fun compareInner(change: TextMergeChange): MergeInnerDifferences? { + return innerDifferencesCache.computeIfAbsent(change) { + return@computeIfAbsent DiffUtil.compareThreesideInner(getSequences(change), ComparisonPolicy.DEFAULT, DumbProgressIndicator.INSTANCE) } } diff --git a/platform/diff-impl/src/com/intellij/diff/merge/MergeThreesideViewer.java b/platform/diff-impl/src/com/intellij/diff/merge/MergeThreesideViewer.java index 3fde8d88cea4..132f6b336b3b 100644 --- a/platform/diff-impl/src/com/intellij/diff/merge/MergeThreesideViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/merge/MergeThreesideViewer.java @@ -1,9 +1,6 @@ // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.diff.merge; -import com.intellij.codeInsight.editorActions.CopyPastePostProcessor; -import com.intellij.codeInsight.editorActions.ReferenceCopyPasteProcessor; -import com.intellij.codeInsight.editorActions.TextBlockTransferableData; import com.intellij.diff.DiffContext; import com.intellij.diff.DiffDialogHints; import com.intellij.diff.DiffManager; @@ -59,7 +56,10 @@ import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageDialogBuilder; import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.NlsSafe; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.LineTokenizer; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.ex.Range; @@ -409,7 +409,6 @@ public class MergeThreesideViewer extends ThreesideTextDiffViewerEx { sequences.addAll(ContainerUtil.map(contents, content -> content.getDocument().getImmutableCharSequence())); if (getTextSettings().isAutoResolveImportConflicts()) { initPsiFiles(); - myChangeReferenceProcessor = new ChangeReferenceProcessor(myProject, getEditor(), myPsiFiles); return MergeImportUtil.getImportMergeRange(myProject, myPsiFiles); } return null; @@ -535,6 +534,9 @@ public class MergeThreesideViewer extends ThreesideTextDiffViewerEx { ); if (myResolveImportConflicts) { + myChangeReferenceProcessor = + new ChangeReferenceProcessor(myProject, getEditor(), myPsiFiles, + ContainerUtil.map(myMergeRequest.getContents(), content -> content.getDocument())); List importChanges = ContainerUtil.filter(getChanges(), change -> change.isImportChange()); if (importChanges.size() != fragmentsWithMetadata.getFragments().size()) { for (TextMergeChange importChange : importChanges) { @@ -1104,8 +1106,9 @@ public class MergeThreesideViewer extends ThreesideTextDiffViewerEx { if (myResolveImportConflicts && myPsiFiles.size() == 3) { Document document = getContent(ThreeSide.BASE).getDocument(); List markers = ContainerUtil.map(newRanges, range -> - document.createRangeMarker(document.getLineStartOffset(range.start), document.getLineEndOffset(range.end))); + document.createRangeMarker(DiffUtil.getLinesRange(document, range.start, range.end))); myChangeReferenceProcessor.process(side, changes, markers); + markers.forEach(RangeMarker::dispose); } }