[vcs] IJPL-150202, IJPL-150203, IJPL-150360 Resolve Conflicts In Import Statements bugfix.

GitOrigin-RevId: 313578648cb6683ab1e163a0dffa565d79c0eb99
This commit is contained in:
Denis Zaichenko
2024-05-20 23:39:42 +02:00
committed by intellij-monorepo-bot
parent 3c51daa55b
commit 345ae2543a
10 changed files with 141 additions and 97 deletions

View File

@@ -7,6 +7,7 @@ import com.intellij.psi.PsiFile
import com.intellij.psi.PsiJavaFile
class JavaImportBlockRangeProvider : ImportBlockRangeProvider {
override fun isEnabledForFile(file: PsiFile): Boolean = file is PsiJavaFile
override fun getImportBlockRange(file: PsiFile): TextRange? {
if (file !is PsiJavaFile) return null

View File

@@ -7,7 +7,6 @@ import com.intellij.diff.tools.util.base.HighlightingLevel;
import com.intellij.diff.tools.util.base.TextDiffSettingsHolder.TextDiffSettings;
import com.intellij.diff.tools.util.breadcrumbs.BreadcrumbsPlacement;
import com.intellij.icons.AllIcons;
import com.intellij.idea.ActionsBundle;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.ActionUtil;
import com.intellij.openapi.diff.DiffBundle;
@@ -187,7 +186,6 @@ public class SetEditorSettingsActionGroup extends ActionGroup implements DumbAwa
actions.add(Separator.getInstance());
if (e != null && e.getData(DiffDataKeys.MERGE_VIEWER) != null) {
actions.add(new ResolveConflictsInImportsToggleAction());
actions.add(Separator.getInstance());
actions.add(ActionManager.getInstance().getAction(IdeActions.ACTION_CONTEXT_HELP));
}
@@ -346,25 +344,4 @@ public class SetEditorSettingsActionGroup extends ActionGroup implements DumbAwa
private interface EditorSettingAction {
void applyDefaults(@NotNull List<? extends Editor> editors);
}
private class ResolveConflictsInImportsToggleAction extends ToggleAction implements DumbAware {
private ResolveConflictsInImportsToggleAction() {
super(ActionsBundle.message("action.EditorToggleResolveConflictsInImports.text"));
}
@Override
public @NotNull ActionUpdateThread getActionUpdateThread() {
return ActionUpdateThread.EDT;
}
@Override
public boolean isSelected(@NotNull AnActionEvent e) {
return myTextSettings.isAutoResolveImportConflicts();
}
@Override
public void setSelected(@NotNull AnActionEvent e, boolean state) {
myTextSettings.setAutoResolveImportConflicts(state);
}
}
}

View File

@@ -7,11 +7,17 @@ import com.intellij.diff.comparison.ComparisonManager
import com.intellij.diff.comparison.ComparisonPolicy
import com.intellij.diff.comparison.DiffTooBigException
import com.intellij.diff.fragments.MergeLineFragment
import com.intellij.diff.tools.util.DiffDataKeys
import com.intellij.diff.tools.util.text.LineOffsetsUtil
import com.intellij.diff.util.LineRange
import com.intellij.diff.util.MergeRange
import com.intellij.diff.util.ThreeSide
import com.intellij.idea.ActionsBundle
import com.intellij.lang.imports.ImportBlockRangeProvider
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.ToggleAction
import com.intellij.openapi.editor.Document
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.RangeMarker
import com.intellij.openapi.fileEditor.FileDocumentManager
@@ -85,6 +91,13 @@ class MergeImportUtil {
return LineRange(document.getLineNumber(range.startOffset),
document.getLineNumber(range.endOffset) + 1)
}
fun isEnabledFor(project: Project?, document: Document): Boolean {
if (project == null) return false
val file = FileDocumentManager.getInstance().getFile(document) ?: return false
val psiFile = PsiManager.getInstance(project).findFile(file) ?: return false
return ImportBlockRangeProvider.isFileSupported(psiFile)
}
}
}
@@ -111,4 +124,36 @@ data class ProcessorData<T : TextBlockTransferableData>(val processor: CopyPaste
class MergeReferenceData(private val left: List<ProcessorData<*>>,
private val right: List<ProcessorData<*>>) {
fun getReferenceData(side: ThreeSide): List<ProcessorData<*>> = side.selectNotNull(left, emptyList(), right)
}
internal class ResolveConflictsInImportsToggleAction : ToggleAction() {
override fun getActionUpdateThread(): ActionUpdateThread {
return ActionUpdateThread.BGT
}
override fun update(e: AnActionEvent) {
super.update(e)
val viewer = getMergeViewer(e)
if (viewer == null) {
e.presentation.isEnabledAndVisible = false
return
}
e.presentation.isEnabledAndVisible = MergeImportUtil.isEnabledFor(viewer.project, viewer.editor.document)
}
override fun isSelected(e: AnActionEvent): Boolean {
return getMergeViewer(e)?.textSettings?.isAutoResolveImportConflicts ?: false
}
override fun setSelected(e: AnActionEvent, state: Boolean) {
getMergeViewer(e)?.textSettings?.isAutoResolveImportConflicts = state
}
private fun getMergeViewer(e: AnActionEvent): MergeThreesideViewer? {
val textMergeViewer = e.getData(DiffDataKeys.MERGE_VIEWER) as? TextMergeViewer
return textMergeViewer?.viewer
}
}

View File

@@ -920,24 +920,33 @@ public class MergeThreesideViewer extends ThreesideTextDiffViewerEx {
}
private @NotNull List<ProcessorData<?>> getReferenceData(@NotNull ThreeSide sourceSide, @NotNull List<MergeLineFragment> fragments) {
if (myProject == null) return Collections.emptyList();
if (!getTextSettings().isAutoResolveImportConflicts()) return Collections.emptyList();
Document sourceDocument = getContent(sourceSide).getDocument();
VirtualFile file = FileDocumentManager.getInstance().getFile(sourceDocument);
if (file == null) return Collections.emptyList();
PsiFile psiFile = PsiManager.getInstance(myProject).findFile(file);
if (psiFile == null) return Collections.emptyList();
try {
if (myProject == null) return Collections.emptyList();
if (!getTextSettings().isAutoResolveImportConflicts()) return Collections.emptyList();
Document sourceDocument = getContent(sourceSide).getDocument();
VirtualFile file = FileDocumentManager.getInstance().getFile(sourceDocument);
if (file == null) return Collections.emptyList();
PsiFile psiFile = PsiManager.getInstance(myProject).findFile(file);
if (psiFile == null) return Collections.emptyList();
int[] startOffsets = fragments.stream().mapToInt(fragment -> sourceDocument.getLineStartOffset(fragment.getStartLine(sourceSide)))
.toArray();
int[] endOffsets = fragments.stream().mapToInt(fragment -> sourceDocument.getLineEndOffset(fragment.getEndLine(sourceSide)))
.toArray();
int[] startOffsets = fragments.stream().mapToInt(fragment -> sourceDocument.getLineStartOffset(fragment.getStartLine(sourceSide)))
.toArray();
int[] endOffsets = fragments.stream().mapToInt(fragment -> sourceDocument.getLineEndOffset(fragment.getEndLine(sourceSide) - 1))
.toArray();
return ContainerUtil.mapNotNull(CopyPastePostProcessor.EP_NAME.getExtensionList(), processor -> {
return processor instanceof ReferenceCopyPasteProcessor
? createProcessorData(processor, sourceSide, psiFile, startOffsets, endOffsets)
: null;
});
return ContainerUtil.mapNotNull(CopyPastePostProcessor.EP_NAME.getExtensionList(), processor -> {
return processor instanceof ReferenceCopyPasteProcessor
? createProcessorData(processor, sourceSide, psiFile, startOffsets, endOffsets)
: null;
});
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Exception e) {
LOG.error(e);
return Collections.emptyList();
}
}
private @NotNull <T extends TextBlockTransferableData>

View File

@@ -14,6 +14,9 @@ import com.intellij.util.xmlb.annotations.Transient
import com.intellij.util.xmlb.annotations.XMap
import org.jetbrains.annotations.NonNls
import java.util.*
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KMutableProperty1
import kotlin.reflect.KProperty
@State(name = "TextDiffSettings", storages = [(Storage(value = DiffUtil.DIFF_CONFIG))], category = SettingsCategory.CODE)
class TextDiffSettingsHolder : PersistentStateComponent<TextDiffSettingsHolder.State> {
@@ -52,6 +55,9 @@ class TextDiffSettingsHolder : PersistentStateComponent<TextDiffSettingsHolder.S
// Fragments settings
var EXPAND_BY_DEFAULT: Boolean = true
) {
@Transient
var ENABLE_SYNC_SCROLL: Boolean = true
@Transient
val eventDispatcher: EventDispatcher<TextDiffSettings.Listener> = EventDispatcher.create(TextDiffSettings.Listener::class.java)
}
@@ -68,94 +74,90 @@ class TextDiffSettingsHolder : PersistentStateComponent<TextDiffSettingsHolder.S
// Presentation settings
var isEnableSyncScroll: Boolean = true
get() = field
set(value) { field = value
PLACE_SETTINGS.eventDispatcher.multicaster.scrollingChanged() }
var isEnableSyncScroll: Boolean by placeDelegate(PlaceSettings::ENABLE_SYNC_SCROLL) { scrollingChanged() }
var isEnableAligningChangesMode: Boolean
get() = SHARED_SETTINGS.ENABLE_ALIGNING_CHANGES_MODE
set(value) { SHARED_SETTINGS.ENABLE_ALIGNING_CHANGES_MODE = value
SHARED_SETTINGS.eventDispatcher.multicaster.alignModeChanged() }
var isEnableAligningChangesMode: Boolean by sharedDelegate(SharedSettings::ENABLE_ALIGNING_CHANGES_MODE) { alignModeChanged() }
// Diff settings
var highlightPolicy: HighlightPolicy = PLACE_SETTINGS.HIGHLIGHT_POLICY
set(value) {
field = value
if (value != HighlightPolicy.DO_NOT_HIGHLIGHT) { // do not persist confusing value as new default
PLACE_SETTINGS.HIGHLIGHT_POLICY = value
if (field != value) {
field = value
if (value != HighlightPolicy.DO_NOT_HIGHLIGHT) { // do not persist confusing value as new default
PLACE_SETTINGS.HIGHLIGHT_POLICY = value
}
PLACE_SETTINGS.eventDispatcher.multicaster.highlightPolicyChanged()
}
PLACE_SETTINGS.eventDispatcher.multicaster.highlightPolicyChanged()
}
var ignorePolicy: IgnorePolicy
get() = PLACE_SETTINGS.IGNORE_POLICY
set(value) { PLACE_SETTINGS.IGNORE_POLICY = value
PLACE_SETTINGS.eventDispatcher.multicaster.ignorePolicyChanged() }
var ignorePolicy: IgnorePolicy by placeDelegate(PlaceSettings::IGNORE_POLICY) { ignorePolicyChanged() }
//
// Merge
//
var isAutoApplyNonConflictedChanges: Boolean
get() = SHARED_SETTINGS.MERGE_AUTO_APPLY_NON_CONFLICTED_CHANGES
set(value) { SHARED_SETTINGS.MERGE_AUTO_APPLY_NON_CONFLICTED_CHANGES = value }
var isAutoApplyNonConflictedChanges: Boolean by sharedDelegate(SharedSettings::MERGE_AUTO_APPLY_NON_CONFLICTED_CHANGES)
var isAutoResolveImportConflicts: Boolean
get() = SHARED_SETTINGS.MERGE_AUTO_RESOLVE_IMPORT_CONFLICTS
set(value) { SHARED_SETTINGS.MERGE_AUTO_RESOLVE_IMPORT_CONFLICTS = value
SHARED_SETTINGS.eventDispatcher.multicaster.resolveConflictsInImportsChanged()}
var isAutoResolveImportConflicts: Boolean by sharedDelegate(SharedSettings::MERGE_AUTO_RESOLVE_IMPORT_CONFLICTS) { resolveConflictsInImportsChanged() }
var isEnableLstGutterMarkersInMerge: Boolean
get() = SHARED_SETTINGS.MERGE_LST_GUTTER_MARKERS
set(value) { SHARED_SETTINGS.MERGE_LST_GUTTER_MARKERS = value }
var isEnableLstGutterMarkersInMerge: Boolean by sharedDelegate(SharedSettings::MERGE_LST_GUTTER_MARKERS)
// Editor settings
var isShowLineNumbers: Boolean
get() = PLACE_SETTINGS.SHOW_LINE_NUMBERS
set(value) { PLACE_SETTINGS.SHOW_LINE_NUMBERS = value }
var isShowLineNumbers: Boolean by placeDelegate(PlaceSettings::SHOW_LINE_NUMBERS)
var isShowWhitespaces: Boolean
get() = PLACE_SETTINGS.SHOW_WHITESPACES
set(value) { PLACE_SETTINGS.SHOW_WHITESPACES = value }
var isShowWhitespaces: Boolean by placeDelegate(PlaceSettings::SHOW_WHITESPACES)
var isShowIndentLines: Boolean
get() = PLACE_SETTINGS.SHOW_INDENT_LINES
set(value) { PLACE_SETTINGS.SHOW_INDENT_LINES = value }
var isShowIndentLines: Boolean by placeDelegate(PlaceSettings::SHOW_INDENT_LINES)
var isUseSoftWraps: Boolean
get() = PLACE_SETTINGS.USE_SOFT_WRAPS
set(value) { PLACE_SETTINGS.USE_SOFT_WRAPS = value }
var isUseSoftWraps: Boolean by placeDelegate(PlaceSettings::USE_SOFT_WRAPS)
var highlightingLevel: HighlightingLevel
get() = PLACE_SETTINGS.HIGHLIGHTING_LEVEL
set(value) { PLACE_SETTINGS.HIGHLIGHTING_LEVEL = value }
var highlightingLevel: HighlightingLevel by placeDelegate(PlaceSettings::HIGHLIGHTING_LEVEL)
var contextRange: Int
get() = SHARED_SETTINGS.CONTEXT_RANGE
set(value) { SHARED_SETTINGS.CONTEXT_RANGE = value
PLACE_SETTINGS.eventDispatcher.multicaster.foldingChanged() }
var contextRange: Int by sharedDelegate(SharedSettings::CONTEXT_RANGE) { foldingChanged() }
var isExpandByDefault: Boolean
get() = PLACE_SETTINGS.EXPAND_BY_DEFAULT
set(value) { PLACE_SETTINGS.EXPAND_BY_DEFAULT = value
PLACE_SETTINGS.eventDispatcher.multicaster.foldingChanged() }
var isExpandByDefault: Boolean by placeDelegate(PlaceSettings::EXPAND_BY_DEFAULT) { foldingChanged() }
var isReadOnlyLock: Boolean
get() = PLACE_SETTINGS.READ_ONLY_LOCK
set(value) { PLACE_SETTINGS.READ_ONLY_LOCK = value }
var isReadOnlyLock: Boolean by placeDelegate(PlaceSettings::READ_ONLY_LOCK)
var breadcrumbsPlacement: BreadcrumbsPlacement
get() = PLACE_SETTINGS.BREADCRUMBS_PLACEMENT
set(value) { PLACE_SETTINGS.BREADCRUMBS_PLACEMENT = value
PLACE_SETTINGS.eventDispatcher.multicaster.breadcrumbsPlacementChanged() }
var breadcrumbsPlacement: BreadcrumbsPlacement by placeDelegate(PlaceSettings::BREADCRUMBS_PLACEMENT) { breadcrumbsPlacementChanged() }
//
// Impl
//
private fun <T> sharedDelegate(accessor: KMutableProperty1<SharedSettings, T>,
onChange: Listener.() -> Unit = {}): ReadWriteProperty<Any?, T> {
return object : ReadWriteProperty<Any?, T> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return accessor.get(SHARED_SETTINGS)
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
if (value == accessor.get(SHARED_SETTINGS)) return
accessor.set(SHARED_SETTINGS, value)
onChange(SHARED_SETTINGS.eventDispatcher.multicaster)
}
}
}
private fun <T> placeDelegate(accessor: KMutableProperty1<PlaceSettings, T>,
onChange: Listener.() -> Unit = {}): ReadWriteProperty<Any?, T> {
return object : ReadWriteProperty<Any?, T> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return accessor.get(PLACE_SETTINGS)
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
if (value == accessor.get(PLACE_SETTINGS)) return
accessor.set(PLACE_SETTINGS, value)
onChange(PLACE_SETTINGS.eventDispatcher.multicaster)
}
}
}
companion object {
@JvmField val KEY: Key<TextDiffSettings> = Key.create("TextDiffSettings")

View File

@@ -3333,9 +3333,11 @@ com.intellij.lang.imports.ImportBlockRangeProvider
- s:getEP_NAME():com.intellij.openapi.extensions.ExtensionPointName
- a:getImportBlockRange(com.intellij.psi.PsiFile):com.intellij.openapi.util.TextRange
- s:getRange(com.intellij.psi.PsiFile):com.intellij.openapi.util.TextRange
- a:isEnabledForFile(com.intellij.psi.PsiFile):Z
f:com.intellij.lang.imports.ImportBlockRangeProvider$Companion
- f:getEP_NAME():com.intellij.openapi.extensions.ExtensionPointName
- f:getRange(com.intellij.psi.PsiFile):com.intellij.openapi.util.TextRange
- f:isFileSupported(com.intellij.psi.PsiFile):Z
com.intellij.lang.injection.ConcatenationAwareInjector
- a:getLanguagesToInject(com.intellij.lang.injection.MultiHostRegistrar,com.intellij.psi.PsiElement[]):V
f:com.intellij.lang.injection.MultiHostRegistrarPlaceholderHelper

View File

@@ -11,9 +11,11 @@ interface ImportBlockRangeProvider {
val EP_NAME: ExtensionPointName<ImportBlockRangeProvider> = ExtensionPointName.create("com.intellij.importBlockRangeProvider")
@JvmStatic
fun getRange(file: PsiFile): TextRange? = EP_NAME.extensionList.firstNotNullOfOrNull { it.getImportBlockRange(file) }
fun getRange(file: PsiFile): TextRange? = EP_NAME.findFirstSafe { it.isEnabledForFile(file) }?.getImportBlockRange(file)
fun isFileSupported(file: PsiFile): Boolean = EP_NAME.findFirstSafe { it.isEnabledForFile(file) } != null
}
fun isEnabledForFile(file: PsiFile): Boolean
fun getImportBlockRange(file: PsiFile): TextRange?
}

View File

@@ -186,7 +186,7 @@ action.EditorToggleShowGutterIcons.text=Show Gutter Ic_ons
action.EditorToggleShowGutterIcons.description=Toggle display gutter icons in current editor
action.EditorToggleUseSoftWraps.text=Soft-Wrap
action.EditorToggleUseSoftWraps.description=Toggle using soft wraps in current editor
action.EditorToggleResolveConflictsInImports.text=Resolve Conflicts in Import Statements
action.Vcs.Diff.ResolveConflictsInImports.text=Resolve Conflicts in Import Statements
action.EditorToggleUseSoftWrapsInPreview.text=Soft-Wrap Preview Editor
action.EditorToggleUseSoftWrapsInPreview.description=Toggle using soft wraps in preview editors
action.EditorToggleVisualFormattingLayer.text=Toggle Visual Formatting Layer

View File

@@ -456,6 +456,9 @@
<add-to-group group-id="Diff.EditorGutterPopupMenu.EditorSettings"/>
<override-text place="popup@DiffToolbar"/>
</action>
<action id="Vcs.Diff.ResolveConflictsInImports" class="com.intellij.diff.merge.ResolveConflictsInImportsToggleAction">
<add-to-group group-id="Diff.EditorGutterPopupMenu.EditorSettings"/>
</action>
<action id="Vcs.Diff.ShowDiffInEditorTab" class="com.intellij.openapi.vcs.changes.actions.diff.MoveDiffPreviewToEditorAction">
<add-to-group group-id="Diff.EditorGutterPopupMenu.EditorSettings" anchor="last"/>
<add-to-group group-id="Diff.Binary.Settings" anchor="last"/>

View File

@@ -7,6 +7,9 @@ import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.psi.KtFile
class KotlinImportBlockRangeProvider : ImportBlockRangeProvider {
override fun isEnabledForFile(file: PsiFile): Boolean = file is KtFile
override fun getImportBlockRange(file: PsiFile): TextRange? {
if (file !is KtFile) return null
return file.importList?.textRange