From 33806f068e152c8bf3860215a2a58a61051a6dc4 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sun, 4 Mar 2018 01:24:07 +0300 Subject: [PATCH] lst: track changelist for not-yet-initialized trackers Fix issue, when file from non-active changelist would briefly jump to active changelist and back when it's opened in Editor. PartialTracker is immediately registered in CLM and is used to determine file's changelist. But until its base content is loaded, it has no changed blocks and "affected changelists" defaults to active changelist. --- .../openapi/vcs/ex/LineStatusTrackerBase.kt | 5 ++-- .../openapi/vcs/changes/ChangeListWorker.java | 13 ++++---- .../vcs/ex/PartialLocalLineStatusTracker.kt | 18 +++++++++-- .../vcs/impl/LineStatusTrackerManager.kt | 30 +++++++------------ .../vcs/BaseLineStatusTrackerTestCase.kt | 2 +- 5 files changed, 38 insertions(+), 30 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerBase.kt b/platform/diff-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerBase.kt index 73c6806238f2..46e55eeb107f 100644 --- a/platform/diff-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerBase.kt +++ b/platform/diff-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerBase.kt @@ -51,7 +51,8 @@ abstract class LineStatusTrackerBase { var isReleased: Boolean = false private set - private var isInitialized: Boolean = false + protected var isInitialized: Boolean = false + private set protected val blocks: List get() = documentTracker.blocks internal val LOCK: DocumentTracker.Lock get() = documentTracker.LOCK @@ -93,7 +94,7 @@ abstract class LineStatusTrackerBase { } @CalledInAwt - fun setBaseRevision(vcsContent: CharSequence) { + open fun setBaseRevision(vcsContent: CharSequence) { setBaseRevision(vcsContent, null) } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListWorker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListWorker.java index ff796332193c..fea4481834c6 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListWorker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListWorker.java @@ -160,13 +160,14 @@ public class ChangeListWorker { myPartialChangeTrackers.put(filePath, tracker); - tracker.initChangeTracking(myDefault.id, ContainerUtil.map(myLists, list -> list.id)); - + ListData oldList = null; Change change = getChangeForAfterPath(filePath); if (change != null) { - removeChangeMapping(change); + oldList = removeChangeMapping(change); } + tracker.initChangeTracking(myDefault.id, ContainerUtil.map(myLists, list -> list.id), oldList != null ? oldList.id : null); + if (LOG.isDebugEnabled()) { LOG.debug(String.format("[registerChangeTracker] path: %s", filePath)); } @@ -769,7 +770,7 @@ public class ChangeListWorker { ListData partialList = getDataById(listId); if (myMainWorker && partialList == null) { LOG.error(String.format("Unknown changelist %s", listId)); - tracker.initChangeTracking(myDefault.id, ContainerUtil.map(myLists, list -> list.id)); + tracker.initChangeTracking(myDefault.id, ContainerUtil.map(myLists, list -> list.id), null); } data.add(partialList != null ? partialList : myDefault); } @@ -1187,7 +1188,7 @@ public class ChangeListWorker { } @Override - public void initChangeTracking(@NotNull String defaultId, @NotNull List changelistsIds) { + public void initChangeTracking(@NotNull String defaultId, @NotNull List changelistsId, @Nullable String fileChangelistIds) { throw new UnsupportedOperationException(); } @@ -1220,7 +1221,7 @@ public class ChangeListWorker { @NotNull List getAffectedChangeListsIds(); - void initChangeTracking(@NotNull String defaultId, @NotNull List changelistsIds); + void initChangeTracking(@NotNull String defaultId, @NotNull List changelistsIds, @Nullable String fileChangelistId); void defaultListChanged(@NotNull String oldListId, @NotNull String newListId); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/PartialLocalLineStatusTracker.kt b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/PartialLocalLineStatusTracker.kt index d17ba9320f75..eb6d77dd83df 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/PartialLocalLineStatusTracker.kt +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/PartialLocalLineStatusTracker.kt @@ -73,6 +73,7 @@ class PartialLocalLineStatusTracker(project: Project, private var defaultMarker: ChangeListMarker private var currentMarker: ChangeListMarker? = null + private var initialChangeListId: String? = null private val affectedChangeLists = HashSet() private val batchChangeTaskCounter: AtomicInteger = AtomicInteger() @@ -116,6 +117,8 @@ class PartialLocalLineStatusTracker(project: Project, newIds.add(block.marker.changelistId) } + if (!isInitialized) initialChangeListId?.let { newIds.add(it) } + if (newIds.isEmpty()) { if (affectedChangeLists.size == 1) { newIds.add(affectedChangeLists.single()) @@ -143,7 +146,10 @@ class PartialLocalLineStatusTracker(project: Project, } @CalledInAwt - fun setBaseRevision(vcsContent: CharSequence, changelistId: String?) { + override fun setBaseRevision(vcsContent: CharSequence) { + val changelistId = if (!isInitialized) initialChangeListId else null + initialChangeListId = null + setBaseRevision(vcsContent) { if (changelistId != null) { changeListManager.executeUnderDataLock { @@ -173,10 +179,12 @@ class PartialLocalLineStatusTracker(project: Project, } - override fun initChangeTracking(defaultId: String, changelistsIds: List) { + override fun initChangeTracking(defaultId: String, changelistsIds: List, fileChangelistId: String?) { documentTracker.writeLock { defaultMarker = ChangeListMarker(defaultId) + if (!isInitialized) initialChangeListId = fileChangelistId + val idsSet = changelistsIds.toSet() moveMarkers({ !idsSet.contains(it.marker.changelistId) }, defaultMarker) @@ -195,6 +203,8 @@ class PartialLocalLineStatusTracker(project: Project, documentTracker.writeLock { if (!affectedChangeLists.contains(listId)) return@writeLock + if (!isInitialized && initialChangeListId == listId) initialChangeListId = null + moveMarkers({ it.marker.changelistId == listId }, defaultMarker) if (affectedChangeLists.size == 1 && affectedChangeLists.contains(listId)) { @@ -210,6 +220,8 @@ class PartialLocalLineStatusTracker(project: Project, documentTracker.writeLock { if (!affectedChangeLists.contains(fromListId)) return@writeLock + if (!isInitialized && initialChangeListId == fromListId) initialChangeListId = toListId + moveMarkers({ it.marker.changelistId == fromListId }, ChangeListMarker(toListId)) updateAffectedChangeLists(false) @@ -218,6 +230,8 @@ class PartialLocalLineStatusTracker(project: Project, override fun moveChangesTo(toListId: String) { documentTracker.writeLock { + if (!isInitialized) initialChangeListId = toListId + moveMarkers({ true }, ChangeListMarker(toListId)) updateAffectedChangeLists(false) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.kt b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.kt index fe5f8f61654b..ef41a55bc639 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.kt +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.kt @@ -391,18 +391,14 @@ class LineStatusTrackerManager( @CalledInAwt - private fun installTracker(virtualFile: VirtualFile, - document: Document) { + private fun installTracker(virtualFile: VirtualFile, document: Document) { if (!canGetBaseRevisionFor(virtualFile)) return - val changelistId = changeListManager.getChangeList(virtualFile)?.id - installTracker(virtualFile, document, changelistId) + doInstallTracker(virtualFile, document) } @CalledInAwt - private fun installTracker(virtualFile: VirtualFile, - document: Document, - oldChangesChangelistId: String?): LineStatusTracker<*>? { + private fun doInstallTracker(virtualFile: VirtualFile, document: Document): LineStatusTracker<*>? { synchronized(LOCK) { if (isDisposed) return null if (trackers[document] != null) return null @@ -418,7 +414,7 @@ class LineStatusTrackerManager( trackers.put(document, data) registerTrackerInCLM(data) - refreshTracker(tracker, changelistId = oldChangesChangelistId) + refreshTracker(tracker) eventDispatcher.multicaster.onTrackerAdded(tracker) log("Tracker installed", virtualFile) @@ -471,10 +467,10 @@ class LineStatusTrackerManager( } @CalledInAwt - private fun refreshTracker(tracker: LineStatusTracker<*>, changelistId: String? = null) { + private fun refreshTracker(tracker: LineStatusTracker<*>) { synchronized(LOCK) { if (isDisposed) return - loader.scheduleRefresh(RefreshRequest(tracker.document, changelistId)) + loader.scheduleRefresh(RefreshRequest(tracker.document)) log("Refresh queued", tracker.virtualFile) } @@ -583,20 +579,16 @@ class LineStatusTrackerManager( } val tracker = getLineStatusTracker(document)!! - if (tracker is PartialLocalLineStatusTracker) { - val changelist = request.changelistId ?: changeListManager.getChangeList(virtualFile)?.id - tracker.setBaseRevision(refreshData.text, changelist) + tracker.setBaseRevision(refreshData.text) + log("Loading finished: success", virtualFile) + if (tracker is PartialLocalLineStatusTracker) { val state = fileStatesAwaitingRefresh.remove(tracker.virtualFile) if (state != null) { tracker.restoreState(state) log("Loading finished: state restored", virtualFile) } } - else { - tracker.setBaseRevision(refreshData.text) - } - log("Loading finished: success", virtualFile) } } } @@ -688,7 +680,7 @@ class LineStatusTrackerManager( if (changeList != null && !changeList.isDefault) { log("Tracker install from DocumentListener: ", virtualFile) - val tracker = installTracker(virtualFile, document, changeList.id) + val tracker = doInstallTracker(virtualFile, document) if (tracker is PartialLocalLineStatusTracker) { tracker.replayChangesFromDocumentEvents(listOf(event)) } @@ -779,7 +771,7 @@ class LineStatusTrackerManager( private class ContentInfo(val revision: VcsRevisionNumber, val charset: Charset) - private class RefreshRequest(val document: Document, val changelistId: String? = null) { + private class RefreshRequest(val document: Document) { override fun equals(other: Any?): Boolean = other is RefreshRequest && document == other.document override fun hashCode(): Int = document.hashCode() } diff --git a/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/BaseLineStatusTrackerTestCase.kt b/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/BaseLineStatusTrackerTestCase.kt index 64f3c1aabea8..72c82fff985a 100644 --- a/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/BaseLineStatusTrackerTestCase.kt +++ b/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/BaseLineStatusTrackerTestCase.kt @@ -378,7 +378,7 @@ abstract class BaseLineStatusTrackerTestCase : LightPlatformTestCase() { init { resetChangelists() - partialTracker.initChangeTracking(defaultChangeListIds(), changeListIds()) + partialTracker.initChangeTracking(defaultChangeListIds(), changeListIds(), null) } override fun destroy() {