mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:19:59 +07:00
AT-3543 split FindUsagesInToolWindowCommand into two commands, one that can be run in split mode, and another that waits on backend
(cherry picked from commit e8bd6241bb7216d2631ee6e2c0c73392bea013a9) IJ-CR-182408 GitOrigin-RevId: 2475891b4e21b3efde2c3d71b95d6f4201b53762
This commit is contained in:
committed by
intellij-monorepo-bot
parent
a28190efe3
commit
fbb509b0ac
@@ -173,6 +173,7 @@ fun <T : CommandChain> T.findUsages(expectedElementName: String = "", scope: Str
|
||||
|
||||
fun <T : CommandChain> T.findUsagesInToolWindow(expectedElementName: String = "", scope: String = "Project Files", warmup: Boolean = false): T = apply {
|
||||
navigateAndFindUsages(expectedElementName, "", scope, warmup = warmup, runInToolWindow = true)
|
||||
addCommand("${CMD_PREFIX}findUsagesInToolWindowWait")
|
||||
}
|
||||
|
||||
fun <T : CommandChain> T.navigateAndFindUsages(
|
||||
@@ -785,6 +786,10 @@ fun <T : CommandChain> T.setRegistry(registry: String, value: Boolean): T = appl
|
||||
addCommand("${CMD_PREFIX}set $registry=$value")
|
||||
}
|
||||
|
||||
fun <T : CommandChain> T.setRegistry(registry: String, value: Int): T = apply {
|
||||
addCommand("${CMD_PREFIX}set $registry=$value")
|
||||
}
|
||||
|
||||
fun <T : CommandChain> T.setRegistry(registry: String, value: String): T = apply {
|
||||
addCommand("${CMD_PREFIX}set $registry=$value")
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ public final class BaseCommandProvider implements CommandProvider {
|
||||
Map.entry(FindUsagesCommand.PREFIX, FindUsagesCommand::new),
|
||||
Map.entry(FindUsagesInBackgroundCommand.PREFIX, FindUsagesInBackgroundCommand::new),
|
||||
Map.entry(FindUsagesInToolWindowCommand.PREFIX, FindUsagesInToolWindowCommand::new),
|
||||
Map.entry(FindUsagesInToolWindowWaitCommand.PREFIX, FindUsagesInToolWindowWaitCommand::new),
|
||||
Map.entry(IdeEditorKeyCommand.PREFIX, IdeEditorKeyCommand::new),
|
||||
Map.entry(ShowAltEnter.PREFIX, ShowAltEnter::new),
|
||||
Map.entry(SelectCommand.PREFIX, SelectCommand::new),
|
||||
|
||||
@@ -1,34 +1,27 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.performancePlugin.commands
|
||||
|
||||
import com.intellij.find.FindManager
|
||||
import com.intellij.find.actions.findUsages
|
||||
import com.intellij.find.findUsages.FindUsagesOptions
|
||||
import com.intellij.find.usages.impl.searchTargets
|
||||
import com.intellij.ide.DataManager
|
||||
import com.intellij.openapi.actionSystem.ActionManager
|
||||
import com.intellij.openapi.actionSystem.ActionPlaces
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.actionSystem.IdeActions
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.application.readAction
|
||||
import com.intellij.openapi.components.serviceAsync
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.ui.playback.PlaybackContext
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
import com.intellij.usages.Usage
|
||||
import com.intellij.usages.UsageView
|
||||
import com.intellij.usages.UsageViewManager
|
||||
import com.intellij.usages.impl.UsageViewElementsListener
|
||||
import com.jetbrains.performancePlugin.PerformanceTestSpan
|
||||
import com.jetbrains.performancePlugin.commands.FindUsagesCommand.Companion.getElement
|
||||
import com.jetbrains.performancePlugin.commands.FindUsagesCommand.Companion.goToElement
|
||||
import com.sampullara.cli.Args
|
||||
import io.opentelemetry.api.trace.Span
|
||||
import com.intellij.openapi.wm.IdeFocusManager
|
||||
import io.opentelemetry.context.Context
|
||||
import kotlinx.coroutines.*
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
/**
|
||||
* Command to execute finds usages in the tool window (not in the popup), and to wait for the search to complete.
|
||||
* Command to execute find usages in the tool window (not in the popup). This command does not take any arguments, it is assumed that the
|
||||
* caret has been moved to the appropriate location in the editor beforehand. Additionally, the command does not wait for find usages to
|
||||
* complete; that job is left to [FindUsagesInToolWindowWaitCommand].
|
||||
*
|
||||
* N.B., it is required to set `ide.find.result.count.warning.limit` if your test finds more than 1000 usages; the property should be set on
|
||||
* the test context as it requires a restart, and shouldn't be set dynamically inside this command.
|
||||
*/
|
||||
class FindUsagesInToolWindowCommand(text: String, line: Int) : PerformanceCommandCoroutineAdapter(text, line) {
|
||||
companion object {
|
||||
@@ -41,93 +34,17 @@ class FindUsagesInToolWindowCommand(text: String, line: Int) : PerformanceComman
|
||||
}
|
||||
|
||||
override suspend fun doExecute(context: PlaybackContext) {
|
||||
val options = FindUsagesArguments()
|
||||
Args.parse(options, extractCommandArgument(PREFIX).split("|").flatMap { it.split(" ", limit = 2) }.toTypedArray(), false)
|
||||
|
||||
val project = context.project
|
||||
val elementName = options.expectedName
|
||||
goToElement(options.position, elementName, context)
|
||||
|
||||
var span: Span? = null
|
||||
var firstUsageSpan: Span? = null
|
||||
var toolWindowSpan: Span? = null
|
||||
|
||||
val currentOTContext = Context.current()
|
||||
withContext(Dispatchers.EDT) {
|
||||
currentOTContext.makeCurrent().use {
|
||||
val editor = project.serviceAsync<FileEditorManager>().selectedTextEditor
|
||||
if (editor == null) {
|
||||
throw Exception("No editor is opened")
|
||||
}
|
||||
val focusedComponent = IdeFocusManager.findInstance().focusOwner
|
||||
val dataContext = DataManager.getInstance().getDataContext(focusedComponent)
|
||||
val findUsagesAction = ApplicationManager.getApplication().serviceAsync<ActionManager>().getAction(IdeActions.ACTION_FIND_USAGES)
|
||||
val findUsagesActionEvent = AnActionEvent.createFromAnAction(findUsagesAction, null, ActionPlaces.KEYBOARD_SHORTCUT, dataContext)
|
||||
|
||||
val scope = readAction {
|
||||
FindUsagesOptions.findScopeByName(project, null, options.scope)
|
||||
}
|
||||
|
||||
val rangeMarker = readAction {
|
||||
editor.document.createRangeMarker(editor.caretModel.offset, editor.caretModel.offset)
|
||||
}
|
||||
|
||||
val searchTargets = readAction {
|
||||
PsiDocumentManager.getInstance(project).getPsiFile(editor.document)?.let { searchTargets(it, rangeMarker.startOffset) }
|
||||
}
|
||||
|
||||
val element = getElement(project, editor, rangeMarker)
|
||||
|
||||
if (!elementName.isNullOrEmpty()) {
|
||||
val foundElementName = readAction { (element as PsiNamedElement).name }
|
||||
check(foundElementName != null && foundElementName == elementName) { "Found element name $foundElementName does not correspond to expected $elementName" }
|
||||
}
|
||||
|
||||
Registry.get("ide.find.result.count.warning.limit").setValue(Integer.MAX_VALUE)
|
||||
|
||||
UsageViewElementsListener.EP_NAME.point.registerExtension(object : UsageViewElementsListener {
|
||||
override fun beforeUsageAdded(view: UsageView, usage: Usage) {
|
||||
UsageViewElementsListener.EP_NAME.point.unregisterExtension(this)
|
||||
|
||||
firstUsageSpan?.end()
|
||||
}
|
||||
})
|
||||
|
||||
val tracer = PerformanceTestSpan.getTracer(isWarmupMode)
|
||||
val parent = PerformanceTestSpan.getContext()
|
||||
|
||||
span = tracer.spanBuilder(SPAN_NAME).setParent(parent).startSpan()
|
||||
firstUsageSpan = tracer.spanBuilder(FIRST_USAGE_SPAN_NAME).setParent(parent).startSpan()
|
||||
toolWindowSpan = tracer.spanBuilder(TOOL_WINDOW_SPAN_NAME).setParent(parent).startSpan()
|
||||
|
||||
if (!searchTargets.isNullOrEmpty()) {
|
||||
findUsages(false, project, scope, searchTargets.first())
|
||||
}
|
||||
else {
|
||||
FindManager.getInstance(project).findUsages(element!!)
|
||||
}
|
||||
findUsagesAction.actionPerformed(findUsagesActionEvent)
|
||||
}
|
||||
}
|
||||
|
||||
var usageView: UsageView? = null
|
||||
|
||||
try {
|
||||
withTimeout(10.seconds) {
|
||||
usageView = UsageViewManager.getInstance(project).selectedUsageView
|
||||
while (usageView == null) {
|
||||
delay(50.milliseconds)
|
||||
usageView = UsageViewManager.getInstance(project).selectedUsageView
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (_: TimeoutCancellationException) {
|
||||
throw Exception("Timeout while waiting for the usage view to open")
|
||||
}
|
||||
|
||||
toolWindowSpan!!.end()
|
||||
|
||||
while (usageView!!.isSearchInProgress) {
|
||||
delay(50.milliseconds)
|
||||
}
|
||||
|
||||
span!!.setAttribute("number", usageView.usages.size.toLong())
|
||||
span.end()
|
||||
}
|
||||
|
||||
override fun getName(): String = PREFIX
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.performancePlugin.commands
|
||||
|
||||
import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.ui.playback.PlaybackContext
|
||||
import com.intellij.usages.UsageView
|
||||
import com.intellij.usages.UsageViewManager
|
||||
import com.jetbrains.performancePlugin.PerformanceTestSpan
|
||||
import com.jetbrains.performancePlugin.commands.FindUsagesInToolWindowCommand.Companion.FIRST_USAGE_SPAN_NAME
|
||||
import com.jetbrains.performancePlugin.commands.FindUsagesInToolWindowCommand.Companion.SPAN_NAME
|
||||
import com.jetbrains.performancePlugin.commands.FindUsagesInToolWindowCommand.Companion.TOOL_WINDOW_SPAN_NAME
|
||||
import kotlinx.coroutines.*
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
/**
|
||||
* Command to wait for find usages in the tool window (not in the popup) to complete. See [FindUsagesInToolWindowCommand].
|
||||
*/
|
||||
class FindUsagesInToolWindowWaitCommand(text: String, line: Int) : PerformanceCommandCoroutineAdapter(text, line) {
|
||||
companion object {
|
||||
const val NAME: String = "findUsagesInToolWindowWait"
|
||||
const val PREFIX: String = CMD_PREFIX + NAME
|
||||
}
|
||||
|
||||
override suspend fun doExecute(context: PlaybackContext) {
|
||||
val project = context.project
|
||||
|
||||
val tracer = PerformanceTestSpan.getTracer(isWarmupMode)
|
||||
val parent = PerformanceTestSpan.getContext()
|
||||
|
||||
val span = tracer.spanBuilder(SPAN_NAME).setParent(parent).startSpan()
|
||||
val firstUsageSpan = tracer.spanBuilder(FIRST_USAGE_SPAN_NAME).setParent(parent).startSpan()
|
||||
val toolWindowSpan = tracer.spanBuilder(TOOL_WINDOW_SPAN_NAME).setParent(parent).startSpan()
|
||||
|
||||
var usageView: UsageView? = null
|
||||
|
||||
try {
|
||||
withTimeout(10.seconds) {
|
||||
usageView = withContext(Dispatchers.EDT) {
|
||||
UsageViewManager.getInstance(project).selectedUsageView
|
||||
}
|
||||
while (usageView == null) {
|
||||
delay(50.milliseconds)
|
||||
usageView = withContext(Dispatchers.EDT) {
|
||||
UsageViewManager.getInstance(project).selectedUsageView
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (_: TimeoutCancellationException) {
|
||||
throw Exception("Timeout while waiting for the usage view to open")
|
||||
}
|
||||
|
||||
toolWindowSpan!!.end()
|
||||
firstUsageSpan?.end()
|
||||
|
||||
while (usageView!!.isSearchInProgress) {
|
||||
delay(50.milliseconds)
|
||||
}
|
||||
|
||||
span!!.setAttribute("number", usageView.usages.size.toLong())
|
||||
span.end()
|
||||
|
||||
FindUsagesDumper.storeMetricsDumpFoundUsages(usageView.usages.toMutableList(), project)
|
||||
}
|
||||
|
||||
override fun getName(): String = PREFIX
|
||||
}
|
||||
Reference in New Issue
Block a user