[find in files] IJPL-198653 fixup review

(cherry picked from commit fdd809002d51513bcca328e56e3130df01eaa473)


(cherry picked from commit 824a489fa938b08efec50963c3f96ad3f0161b77)

IJ-MR-173754

GitOrigin-RevId: ea9ba9550ed340caadd06d62f92a2fa0e8c9c562
This commit is contained in:
Vera Petrenkova
2025-08-19 11:03:36 +02:00
committed by intellij-monorepo-bot
parent ed9ecc80cd
commit d286a06b5f
6 changed files with 27 additions and 56 deletions

View File

@@ -1214,7 +1214,7 @@ a:com.intellij.openapi.fileTypes.LanguageFileType
- extractCharsetFromFileContent(com.intellij.openapi.project.Project,com.intellij.openapi.vfs.VirtualFile,java.lang.String):java.nio.charset.Charset
- getDisplayName():java.lang.String
- f:getLanguage():com.intellij.lang.Language
- isBinary():Z
- f:isBinary():Z
- isJVMDebuggingSupported():Z
- isSecondary():Z
e:com.intellij.openapi.fileTypes.OSFileIdeAssociation$ExtensionMode

View File

@@ -4,6 +4,7 @@ package com.intellij.openapi.fileTypes;
import com.intellij.lang.Language;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -49,7 +50,17 @@ public abstract class LanguageFileType implements FileType {
}
@Override
public boolean isBinary() {
public final boolean isBinary() {
return computeBinary();
}
/**
* Remote development only.
* Allows overriding {@code isBinary} when {@link LanguageFileType} is used
* as a placeholder for unsupported file types on the frontend.
*/
@ApiStatus.Internal
protected boolean computeBinary() {
return false;
}

View File

@@ -24,7 +24,6 @@ import com.intellij.platform.project.projectId
import com.intellij.platform.scopes.ScopeModelApi
import com.intellij.platform.util.coroutines.childScope
import com.intellij.usages.FindUsagesProcessPresentation
import com.intellij.usages.UsageChangedListener
import com.intellij.usages.UsageInfo2UsageAdapter
import com.intellij.usages.UsageInfoAdapter
import fleet.rpc.client.RpcTimeoutException
@@ -93,7 +92,7 @@ open class FindAndReplaceExecutorImpl(val coroutineScope: CoroutineScope) : Find
return@collect
}
throttledItems.items.forEach { item ->
val usage = UsageInfoModel.createUsageInfoModel(project, item, initScope)
val usage = UsageInfoModel.createUsageInfoModel(project, item, initScope, onUpdateModelCallback)
if (searchDisposable == null || !Disposer.tryRegister(searchDisposable, usage)) {
Disposer.dispose(usage)
return@collect
@@ -104,12 +103,6 @@ open class FindAndReplaceExecutorImpl(val coroutineScope: CoroutineScope) : Find
Disposer.dispose(searchDisposable)
return@collect
}
usage.addInitializationListener(object : UsageChangedListener {
override fun modelInitialized() {
onUpdateModelCallback.accept(usage)
}
}, searchDisposable)
}
}
onFinish()

View File

@@ -8,10 +8,10 @@ import com.intellij.ide.ui.icons.icon
import com.intellij.ide.ui.textChunk
import com.intellij.ide.vfs.virtualFile
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.readAction
import com.intellij.openapi.application.runReadAction
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.diagnostic.runAndLogException
import com.intellij.openapi.editor.Document
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.ex.DocumentEx
@@ -19,7 +19,6 @@ import com.intellij.openapi.editor.ex.DocumentFullUpdateListener
import com.intellij.openapi.fileEditor.*
import com.intellij.openapi.fileTypes.FileTypeManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.NlsContexts
import com.intellij.openapi.util.Segment
import com.intellij.openapi.util.TextRange
@@ -28,21 +27,23 @@ import com.intellij.openapi.vfs.findDocument
import com.intellij.psi.*
import com.intellij.usageView.UsageInfo
import com.intellij.usages.TextChunk
import com.intellij.usages.UsageChangedListener
import com.intellij.usages.UsageInfoAdapter
import com.intellij.usages.UsagePresentation
import com.intellij.usages.rules.MergeableUsage
import com.intellij.usages.rules.UsageDocumentProcessor
import com.intellij.usages.rules.UsageInFile
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
import com.intellij.util.containers.ContainerUtil
import kotlinx.coroutines.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import java.util.concurrent.CompletableFuture
import java.util.function.Consumer
import javax.swing.Icon
private val LOG = logger<UsageInfoModel>()
internal class UsageInfoModel private constructor(val project: Project, val model: FindInFilesResult, val coroutineScope: CoroutineScope) : UsageInfoAdapter, UsageInFile, UsageDocumentProcessor, Disposable {
internal class UsageInfoModel private constructor(val project: Project, val model: FindInFilesResult, val coroutineScope: CoroutineScope, private val initializationListener: Consumer<UsageInfoAdapter>) : UsageInfoAdapter, UsageInFile, UsageDocumentProcessor, Disposable {
private val virtualFile: VirtualFile? = run {
val virtualFile = model.usageInfos.firstOrNull()?.file?.virtualFile ?: model.fileId.virtualFile()
if (virtualFile == null) LOG.error("Cannot find virtualFile for ${model.presentablePath}")
@@ -64,11 +65,10 @@ internal class UsageInfoModel private constructor(val project: Project, val mode
set(value) {
field = value
if (value) {
initializationListeners.forEach { it.modelInitialized() }
initializationListener.accept(this)
}
}
private var initializationJob: Job? = null
private val initializationListeners: MutableList<UsageChangedListener> = ContainerUtil.createLockFreeCopyOnWriteList()
private val defaultRange: TextRange = TextRange(model.navigationOffset, model.navigationOffset + model.length)
private val defaultMergedRanges: List<TextRange> = model.mergedOffsets.map {
@@ -85,14 +85,13 @@ internal class UsageInfoModel private constructor(val project: Project, val mode
override fun dispose() {
(document as? DocumentEx)?.removeFullUpdateListener(fullUpdateListener)
initializationListeners.clear()
}
init {
initialize()
}
private fun initialize(onDocumentUpdated: ((usageInfos: List<UsageInfo>) -> Unit?)? = null) {
private fun initialize() {
//local IDE case
if (model.usageInfos.isNotEmpty()) {
cachedUsageInfos = model.usageInfos
@@ -149,30 +148,17 @@ internal class UsageInfoModel private constructor(val project: Project, val mode
}
finally {
//if we get some model without ranges or proper ranges were loaded - full model loaded
val loaded = defaultMergedRanges.isEmpty() || cachedUsageInfos.isNotEmpty()
isLoaded = loaded
if (loaded) {
withContext(Dispatchers.EDT) {
onDocumentUpdated?.invoke(cachedUsageInfos)
}
}
isLoaded = defaultMergedRanges.isEmpty() || cachedUsageInfos.isNotEmpty()
}
}
}
}
override fun addInitializationListener(listener: UsageChangedListener, disposable: Disposable) {
initializationListeners.add(listener)
Disposer.tryRegister(disposable) {
initializationListeners.remove(listener)
}
}
companion object {
@JvmStatic
@RequiresBackgroundThread
fun createUsageInfoModel(project: Project, model: FindInFilesResult, coroutineScope: CoroutineScope): UsageInfoModel {
return UsageInfoModel(project, model, coroutineScope)
fun createUsageInfoModel(project: Project, model: FindInFilesResult, coroutineScope: CoroutineScope, initializationListener: Consumer<UsageInfoAdapter>): UsageInfoModel {
return UsageInfoModel(project, model, coroutineScope, initializationListener)
}
}
@@ -292,7 +278,7 @@ internal class UsageInfoModel private constructor(val project: Project, val mode
override fun getDocument(): Document? {
document?.let { return it }
return try {
return LOG.runAndLogException {
runReadAction {
val psiDoc = cachedPsiFile?.let { psiFile -> PsiDocumentManager.getInstance(project).getDocument(psiFile) }
if (psiDoc == null) {
@@ -306,10 +292,6 @@ internal class UsageInfoModel private constructor(val project: Project, val mode
doc
}
}
catch (t: Throwable) {
LOG.warn("Failed to get document for ${model.presentablePath}", t)
null
}
}
private class UsageInfoModelPresentation(val model: FindInFilesResult) : UsagePresentation {

View File

@@ -1,9 +0,0 @@
// 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.usages
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
interface UsageChangedListener {
fun modelInitialized()
}

View File

@@ -1,10 +1,8 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.usages;
import com.intellij.openapi.Disposable;
import com.intellij.usageView.UsageInfo;
import com.intellij.usages.rules.MergeableUsage;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.CompletableFuture;
@@ -18,8 +16,4 @@ public interface UsageInfoAdapter extends Usage, MergeableUsage {
@NotNull UsageInfo @NotNull [] getMergedInfos();
@NotNull
CompletableFuture<UsageInfo[]> getMergedInfosAsync();
@ApiStatus.Internal
default void addInitializationListener(UsageChangedListener listener, Disposable parentDisposable) {
}
}