mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[recent files + diff] IJ-MR-209657 IJPL-242683 Remove diff and alike files from the data model instead of just hiding them from UI
Previously, diff virtual files were just filtered out from the files list displayed in UI, but the backing data model retained them until the file got closed or the project got closed depending on the settings state. Now we always check on both frontend and backend if a specific file is allowed to be shown and do not add it/remove it from the model, should it be disallowed to be there. That does not solve the core problem with diff files holding a lot of hard references in their userdata, but improves the problem on the recent files side. Changes on the diff virtual file side are still necessary (cherry picked from commit 4df2acdff046ef2ae0ce8f106d64669bb8bfa902) GitOrigin-RevId: a6d724a4c64dad8a29287327a40ffd5e6189d8de
This commit is contained in:
committed by
intellij-monorepo-bot
parent
336d6e18ee
commit
a3e9476e35
+6
-2
@@ -114,6 +114,7 @@ internal class BackendRecentFileEventsModel(private val project: Project, corout
|
||||
val metadata =
|
||||
metadataRequest.frontendRecentFiles
|
||||
.mapNotNull { frontendFileId -> frontendFileId.virtualFile() }
|
||||
.filter { isAllowedInRecentFilesModel(project, it) }
|
||||
.map { frontendFile ->
|
||||
readAction {
|
||||
createRecentFileViewModel(frontendFile, project)
|
||||
@@ -183,7 +184,7 @@ internal class BackendRecentFileEventsModel(private val project: Project, corout
|
||||
private suspend fun processOrderChangeEvent(event: OrderChangeEvent) {
|
||||
when (event.changeKind) {
|
||||
FileChangeKind.ADDED -> {
|
||||
val models = createRecentFilesViewModels(event.files)
|
||||
val models = createRecentFilesViewModels(event.files.filter { isAllowedInRecentFilesModel(project, it) })
|
||||
val fileEvent = BackendRecentFilesEvent.ItemsAdded(models)
|
||||
|
||||
for (fileKind in RecentFileKind.entries) {
|
||||
@@ -212,7 +213,9 @@ internal class BackendRecentFileEventsModel(private val project: Project, corout
|
||||
BackendRecentFilesModel.getInstance(project).getFilesByKind(fileKind).toSet()
|
||||
}
|
||||
|
||||
val filesToUpdate = files.filter { file -> knownFilesByKind.values.any { known -> known.contains(file) } }
|
||||
val filesToUpdate = files.filter { file ->
|
||||
isAllowedInRecentFilesModel(project, file) && knownFilesByKind.values.any { known -> known.contains(file) }
|
||||
}
|
||||
|
||||
val models = createRecentFilesViewModels(filesToUpdate)
|
||||
assert(models.size == filesToUpdate.size)
|
||||
@@ -266,6 +269,7 @@ internal class BackendRecentFileEventsModel(private val project: Project, corout
|
||||
getFilesToShow(project = project,
|
||||
recentFileKind = filter.filesKind,
|
||||
filesFromFrontendEditorSelectionHistory = filter.frontendEditorSelectionHistory.mapNotNull(VirtualFileId::virtualFile))
|
||||
.filter { isAllowedInRecentFilesModel(project, it) }
|
||||
.map {
|
||||
readAction {
|
||||
createRecentFileViewModel(it, project)
|
||||
|
||||
+7
-2
@@ -1,17 +1,22 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.recentFiles.backend
|
||||
|
||||
import com.intellij.openapi.fileEditor.impl.IdeDocumentHistoryImpl
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.platform.recentFiles.shared.RecentFileKind
|
||||
import com.intellij.platform.recentFiles.shared.RecentFilesMutableState
|
||||
|
||||
internal class BackendRecentFilesMutableState(project: Project) : RecentFilesMutableState<VirtualFile>(project) {
|
||||
override fun checkValidity(model: VirtualFile): Boolean {
|
||||
return model.isValid
|
||||
override fun isAllowedInModel(targetFilesKind: RecentFileKind, model: VirtualFile): Boolean {
|
||||
return isAllowedInRecentFilesModel(project, model)
|
||||
}
|
||||
|
||||
fun getFilesByKind(filesKind: RecentFileKind): List<VirtualFile> {
|
||||
return chooseStateToWriteTo(filesKind).value.entries
|
||||
}
|
||||
}
|
||||
|
||||
internal fun isAllowedInRecentFilesModel(project: Project, file: VirtualFile): Boolean {
|
||||
return file.isValid && (file !is IdeDocumentHistoryImpl.OptionallyIncluded || file.isIncludedInDocumentHistory(project))
|
||||
}
|
||||
+11
-1
@@ -4,6 +4,7 @@ package com.intellij.platform.recentFiles.frontend
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.platform.recentFiles.shared.RecentFileKind
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
@@ -16,4 +17,13 @@ interface RecentFilesExcluder {
|
||||
@JvmField
|
||||
val EP_NAME: ExtensionPointName<RecentFilesExcluder> = ExtensionPointName<RecentFilesExcluder>("com.intellij.recentFiles.excluder")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun isExcludedFromRecentFiles(project: Project, fileKind: RecentFileKind, file: VirtualFile): Boolean {
|
||||
return RecentFilesExcluder.EP_NAME.findFirstSafe { ext ->
|
||||
when (fileKind) {
|
||||
RecentFileKind.RECENTLY_EDITED -> ext.isExcludedFromRecentlyEdited(project, file)
|
||||
RecentFileKind.RECENTLY_OPENED, RecentFileKind.RECENTLY_OPENED_UNPINNED -> ext.isExcludedFromRecentlyOpened(project, file)
|
||||
}
|
||||
} != null
|
||||
}
|
||||
|
||||
+4
-1
@@ -25,8 +25,11 @@ private class RecentlySelectedEditorListener : FileEditorManagerListener {
|
||||
if (source.getEditors(file).isEmpty()) {
|
||||
thisLogger().trace { "Do remove closed frontend file from model: ${file.name}" }
|
||||
frontendRecentFilesModel.applyFrontendChanges(RecentFileKind.RECENTLY_OPENED_UNPINNED, listOf(file), FileChangeKind.REMOVED)
|
||||
if (isExcludedFromRecentFiles(source.project, RecentFileKind.RECENTLY_OPENED, file)) {
|
||||
frontendRecentFilesModel.applyFrontendChanges(RecentFileKind.RECENTLY_OPENED, listOf(file), FileChangeKind.REMOVED)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun selectionChanged(event: FileEditorManagerEvent) {
|
||||
val file = event.newFile ?: return
|
||||
|
||||
+29
-38
@@ -15,11 +15,11 @@ import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.platform.project.projectId
|
||||
import com.intellij.platform.recentFiles.frontend.RecentFilesExcluder
|
||||
import com.intellij.platform.recentFiles.frontend.SwitcherVirtualFile
|
||||
import com.intellij.platform.recentFiles.frontend.createFilesSearchRequestRequest
|
||||
import com.intellij.platform.recentFiles.frontend.createFilesUpdateRequest
|
||||
import com.intellij.platform.recentFiles.frontend.createHideFilesRequest
|
||||
import com.intellij.platform.recentFiles.frontend.isExcludedFromRecentFiles
|
||||
import com.intellij.platform.recentFiles.shared.FileChangeKind
|
||||
import com.intellij.platform.recentFiles.shared.FileSwitcherApi
|
||||
import com.intellij.platform.recentFiles.shared.RecentFileKind
|
||||
@@ -42,38 +42,13 @@ class FrontendRecentFilesModel(private val project: Project) {
|
||||
private val modelState = FrontendRecentFilesMutableState(project)
|
||||
fun getRecentFiles(fileKind: RecentFileKind): List<SwitcherVirtualFile> {
|
||||
val capturedModelState = modelState.chooseStateToReadFrom(fileKind).value.entries
|
||||
val filteredModel = filterOutExcludedFiles(capturedModelState, fileKind)
|
||||
|
||||
return when (fileKind) {
|
||||
RecentFileKind.RECENTLY_OPENED_UNPINNED -> considerOpenedEditorWindowsForFiles(filteredModel)
|
||||
else -> filteredModel
|
||||
RecentFileKind.RECENTLY_OPENED_UNPINNED -> considerOpenedEditorWindowsForFiles(capturedModelState)
|
||||
else -> capturedModelState
|
||||
}
|
||||
}
|
||||
|
||||
private fun filterOutExcludedFiles(
|
||||
capturedModelState: List<SwitcherVirtualFile>,
|
||||
fileKind: RecentFileKind,
|
||||
): List<SwitcherVirtualFile> {
|
||||
val filteredModel = capturedModelState.filter { fileModel ->
|
||||
val file = fileModel.virtualFile ?: return@filter true
|
||||
val excluder = RecentFilesExcluder.EP_NAME.findFirstSafe { ext ->
|
||||
when (fileKind) {
|
||||
RecentFileKind.RECENTLY_EDITED -> ext.isExcludedFromRecentlyEdited(project, file)
|
||||
RecentFileKind.RECENTLY_OPENED, RecentFileKind.RECENTLY_OPENED_UNPINNED -> ext.isExcludedFromRecentlyOpened(project, file)
|
||||
}
|
||||
}
|
||||
excluder == null
|
||||
}
|
||||
LOG.trace {
|
||||
val modelData = if (filteredModel.size != capturedModelState.size)
|
||||
"After filtering: ${filteredModel.joinToString { it.virtualFile?.name ?: "null" }}"
|
||||
else
|
||||
""
|
||||
"Return requested $fileKind list: ${capturedModelState.joinToString { it.virtualFile?.name ?: "null" }} $modelData"
|
||||
}
|
||||
return filteredModel
|
||||
}
|
||||
|
||||
private fun considerOpenedEditorWindowsForFiles(filteredModel: List<SwitcherVirtualFile>): List<SwitcherVirtualFile> {
|
||||
// With the tabs disabled, switching between editor windows doesn't work anyway,
|
||||
// so trying to associate the editors with the files just produces annoying duplicate entries.
|
||||
@@ -101,36 +76,52 @@ class FrontendRecentFilesModel(private val project: Project) {
|
||||
|
||||
fun applyFrontendChanges(filesKind: RecentFileKind, files: List<VirtualFile>, changeKind: FileChangeKind) {
|
||||
if (files.isEmpty()) return
|
||||
LOG.trace { "Applying frontend changes for kind: $filesKind, changeKind: $changeKind, files: ${files.joinToString { it.name }}" }
|
||||
val filesToApply = if (changeKind == FileChangeKind.REMOVED) files else files.filterNot { isExcludedFromRecentFiles(project, filesKind, it) }
|
||||
if (changeKind != FileChangeKind.REMOVED) {
|
||||
val filesToRemove = files - filesToApply.toSet()
|
||||
if (filesToRemove.isNotEmpty()) {
|
||||
when (filesKind) {
|
||||
RecentFileKind.RECENTLY_EDITED -> applyFrontendChanges(RecentFileKind.RECENTLY_EDITED, filesToRemove, FileChangeKind.REMOVED)
|
||||
RecentFileKind.RECENTLY_OPENED, RecentFileKind.RECENTLY_OPENED_UNPINNED -> {
|
||||
applyFrontendChanges(RecentFileKind.RECENTLY_OPENED, filesToRemove, FileChangeKind.REMOVED)
|
||||
applyFrontendChanges(RecentFileKind.RECENTLY_OPENED_UNPINNED, filesToRemove, FileChangeKind.REMOVED)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (filesToApply.isEmpty()) return
|
||||
|
||||
LOG.trace { "Applying frontend changes for kind: $filesKind, changeKind: $changeKind, files: ${filesToApply.joinToString { it.name }}" }
|
||||
modelUpdateScope.launch {
|
||||
val frontendStateToUpdate = modelState.chooseStateToWriteTo(filesKind)
|
||||
val fileModels = files.map { convertVirtualFileToViewModel(it, project) }
|
||||
val fileModels = filesToApply.map { convertVirtualFileToViewModel(it, project) }
|
||||
|
||||
frontendStateToUpdate.update { oldList ->
|
||||
when (changeKind) {
|
||||
val updatedEntries = when (changeKind) {
|
||||
FileChangeKind.ADDED -> {
|
||||
val maybeItemsWithRichMetadata = oldList.entries.associateBy { it }
|
||||
val effectiveModelsToInsert = fileModels.map { fileModel -> maybeItemsWithRichMetadata[fileModel] ?: fileModel }
|
||||
RecentFilesState(effectiveModelsToInsert + (oldList.entries - effectiveModelsToInsert.toSet()))
|
||||
effectiveModelsToInsert + (oldList.entries - effectiveModelsToInsert.toSet())
|
||||
}
|
||||
FileChangeKind.REMOVED -> {
|
||||
RecentFilesState(oldList.entries - fileModels.toSet())
|
||||
oldList.entries - fileModels.toSet()
|
||||
}
|
||||
FileChangeKind.UPDATED_AND_PUT_ON_TOP -> {
|
||||
RecentFilesState(fileModels + oldList.entries - fileModels.toSet())
|
||||
fileModels + oldList.entries - fileModels.toSet()
|
||||
}
|
||||
else -> {
|
||||
oldList
|
||||
oldList.entries
|
||||
}
|
||||
}
|
||||
RecentFilesState(updatedEntries.filter { modelState.isAllowedInModel(filesKind, it) })
|
||||
}
|
||||
|
||||
when (changeKind) {
|
||||
FileChangeKind.REMOVED -> {
|
||||
FileSwitcherApi.getInstance().updateRecentFilesBackendState(createHideFilesRequest(filesKind, files, project))
|
||||
FileSwitcherApi.getInstance().updateRecentFilesBackendState(createHideFilesRequest(filesKind, filesToApply, project))
|
||||
}
|
||||
else -> {
|
||||
FileSwitcherApi.getInstance().updateRecentFilesBackendState(createFilesUpdateRequest(filesKind, files, true, project))
|
||||
FileSwitcherApi.getInstance().updateRecentFilesBackendState(createFilesUpdateRequest(filesKind, filesToApply, true, project))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,4 +167,4 @@ class FrontendRecentFilesModel(private val project: Project) {
|
||||
return project.serviceAsync<FrontendRecentFilesModel>()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -7,6 +7,7 @@ import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.platform.recentFiles.frontend.SwitcherVirtualFile
|
||||
import com.intellij.platform.recentFiles.frontend.isExcludedFromRecentFiles
|
||||
import com.intellij.platform.recentFiles.shared.RecentFileKind
|
||||
import com.intellij.platform.recentFiles.shared.RecentFilesMutableState
|
||||
import com.intellij.platform.recentFiles.shared.RecentFilesState
|
||||
@@ -14,8 +15,9 @@ import com.intellij.util.IconUtil
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
internal class FrontendRecentFilesMutableState(project: Project) : RecentFilesMutableState<SwitcherVirtualFile>(project) {
|
||||
override fun checkValidity(model: SwitcherVirtualFile): Boolean {
|
||||
return model.virtualFile?.isValid != false
|
||||
override fun isAllowedInModel(targetFilesKind: RecentFileKind, model: SwitcherVirtualFile): Boolean {
|
||||
val file = model.virtualFile ?: return true
|
||||
return file.isValid && !isExcludedFromRecentFiles(project, targetFilesKind, file)
|
||||
}
|
||||
|
||||
fun chooseStateToReadFrom(filesKind: RecentFileKind): MutableStateFlow<RecentFilesState<SwitcherVirtualFile>> {
|
||||
|
||||
+5
-5
@@ -18,7 +18,7 @@ abstract class RecentFilesMutableState<T>(protected val project: Project) {
|
||||
protected val recentlyEditedFilesState: MutableStateFlow<RecentFilesState<T>> = MutableStateFlow(RecentFilesState())
|
||||
protected val recentlyOpenedPinnedFilesState: MutableStateFlow<RecentFilesState<T>> = MutableStateFlow(RecentFilesState())
|
||||
|
||||
abstract fun checkValidity(model: T): Boolean
|
||||
abstract fun isAllowedInModel(targetFilesKind: RecentFileKind, model: T): Boolean
|
||||
|
||||
fun chooseStateToWriteTo(targetFilesKind: RecentFileKind): MutableStateFlow<RecentFilesState<T>> {
|
||||
return when (targetFilesKind) {
|
||||
@@ -34,7 +34,7 @@ abstract class RecentFilesMutableState<T>(protected val project: Project) {
|
||||
LOG.debug("Adding ${batch.size} items to $targetFilesKind frontend model")
|
||||
targetModel.update { oldList ->
|
||||
val updatedState = toAdd + (oldList.entries - toAdd.toSet())
|
||||
RecentFilesState(updatedState.filter(::checkValidity))
|
||||
RecentFilesState(updatedState.filter { isAllowedInModel(targetFilesKind, it) })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,11 +49,11 @@ abstract class RecentFilesMutableState<T>(protected val project: Project) {
|
||||
val newValuesToPutIntoFirstPosition = oldList.entries.mapNotNull { oldItem -> itemsToMergeWithExisting[oldItem] }
|
||||
val restOfExistingValues = oldList.entries - newValuesToPutIntoFirstPosition.toSet()
|
||||
val updatedState = newValuesToPutIntoFirstPosition + restOfExistingValues
|
||||
RecentFilesState(updatedState.filter(::checkValidity))
|
||||
RecentFilesState(updatedState.filter { isAllowedInModel(targetFilesKind, it) })
|
||||
}
|
||||
else {
|
||||
val effectiveModelsToInsert = oldList.entries.map { oldItem -> itemsToMergeWithExisting[oldItem] ?: oldItem }
|
||||
RecentFilesState(effectiveModelsToInsert.filter(::checkValidity))
|
||||
RecentFilesState(effectiveModelsToInsert.filter { isAllowedInModel(targetFilesKind, it) })
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,7 @@ abstract class RecentFilesMutableState<T>(protected val project: Project) {
|
||||
LOG.debug("Removing ${batch.size} items from $targetFilesKind frontend model")
|
||||
targetModel.update { oldList ->
|
||||
val updatedState = oldList.entries - batch.toSet()
|
||||
RecentFilesState(updatedState.filter(::checkValidity))
|
||||
RecentFilesState(updatedState.filter { isAllowedInModel(targetFilesKind, it) })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user