[java] Support the auto-run floating toolbar in remdev

#IDEA-365843 Fixed

GitOrigin-RevId: 632b97cdb34f31ab99c802d08094c863c3119fcd
This commit is contained in:
Louis Vignier
2025-04-23 16:29:50 +02:00
committed by intellij-monorepo-bot
parent 20c2e2ef24
commit 4bfba9c80e
19 changed files with 491 additions and 185 deletions

3
.idea/modules.xml generated
View File

@@ -497,6 +497,9 @@
<module fileurl="file://$PROJECT_DIR$/plugins/dev/intellij.java.dev/intellij.java.dev.iml" filepath="$PROJECT_DIR$/plugins/dev/intellij.java.dev/intellij.java.dev.iml" />
<module fileurl="file://$PROJECT_DIR$/java/execution/openapi/intellij.java.execution.iml" filepath="$PROJECT_DIR$/java/execution/openapi/intellij.java.execution.iml" />
<module fileurl="file://$PROJECT_DIR$/java/execution/impl/intellij.java.execution.impl.iml" filepath="$PROJECT_DIR$/java/execution/impl/intellij.java.execution.impl.iml" />
<module fileurl="file://$PROJECT_DIR$/java/execution/backend/intellij.java.execution.impl.backend.iml" filepath="$PROJECT_DIR$/java/execution/backend/intellij.java.execution.impl.backend.iml" />
<module fileurl="file://$PROJECT_DIR$/java/execution/frontend/intellij.java.execution.impl.frontend.iml" filepath="$PROJECT_DIR$/java/execution/frontend/intellij.java.execution.impl.frontend.iml" />
<module fileurl="file://$PROJECT_DIR$/java/execution/shared/intellij.java.execution.impl.shared.iml" filepath="$PROJECT_DIR$/java/execution/shared/intellij.java.execution.impl.shared.iml" />
<module fileurl="file://$PROJECT_DIR$/java/java-features-trainer/intellij.java.featuresTrainer.iml" filepath="$PROJECT_DIR$/java/java-features-trainer/intellij.java.featuresTrainer.iml" />
<module fileurl="file://$PROJECT_DIR$/java/java-frontback-impl/intellij.java.frontback.impl.iml" filepath="$PROJECT_DIR$/java/java-frontback-impl/intellij.java.frontback.impl.iml" />
<module fileurl="file://$PROJECT_DIR$/java/java-frontback-psi-api/intellij.java.frontback.psi.iml" filepath="$PROJECT_DIR$/java/java-frontback-psi-api/intellij.java.frontback.psi.iml" />

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="5" platform="JVM 17" allPlatforms="JVM [17]" useProjectSettings="false">
<compilerSettings>
<option name="additionalArguments" value="-Xjvm-default=all" />
</compilerSettings>
<compilerArguments>
<stringArguments>
<stringArg name="jvmTarget" arg="17" />
<stringArg name="apiVersion" arg="2.1" />
<stringArg name="languageVersion" arg="2.1" />
</stringArguments>
<arrayArguments>
<arrayArg name="pluginClasspaths">
<args>
<arg>$KOTLIN_BUNDLED$/lib/kotlinx-serialization-compiler-plugin.jar</arg>
<arg>$MAVEN_REPOSITORY$/jetbrains/fleet/rhizomedb-compiler-plugin/2.1.20-0.3/rhizomedb-compiler-plugin-2.1.20-0.3.jar</arg>
<arg>$MAVEN_REPOSITORY$/com/jetbrains/fleet/rpc-compiler-plugin/2.1.20-0.3/rpc-compiler-plugin-2.1.20-0.3.jar</arg>
</args>
</arrayArg>
<arrayArg name="pluginOptions" />
</arrayArguments>
</compilerArguments>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="kotlinx-serialization-core" level="project" />
<orderEntry type="library" name="kotlinx-serialization-json" level="project" />
<orderEntry type="module" module-name="intellij.java.execution.impl.shared" />
<orderEntry type="module" module-name="intellij.java.execution.impl" />
<orderEntry type="module" module-name="intellij.platform.editor" />
<orderEntry type="module" module-name="intellij.platform.kernel.backend" />
<orderEntry type="module" module-name="intellij.platform.ide" />
<orderEntry type="module" module-name="intellij.platform.ide.rpc" />
<orderEntry type="module" module-name="intellij.platform.project" />
<orderEntry type="module" module-name="intellij.platform.lang.impl" />
<orderEntry type="module" module-name="intellij.platform.smRunner" />
<orderEntry type="module" module-name="intellij.platform.core.ui" />
</component>
</module>

View File

@@ -0,0 +1,13 @@
<!--suppress PluginXmlValidity -->
<idea-plugin>
<dependencies>
<module name="intellij.platform.kernel.backend"/>
<module name="intellij.java.execution.impl.shared"/>
<plugin id="com.intellij.platform.experimental.backend"/>
</dependencies>
<extensions defaultExtensionNs="com.intellij">
<postStartupActivity implementation="com.intellij.execution.backend.JavaAutoRunTrackerActivity"/>
<platform.rpc.backend.remoteApiProvider implementation="com.intellij.execution.backend.JavaTestDiscoveryRemoteApiProvider"/>
</extensions>
</idea-plugin>

View File

@@ -0,0 +1,26 @@
// 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.execution.backend
import com.intellij.execution.shared.JavaAutoRunFloatingToolbarApi
import com.intellij.execution.shared.JavaAutoRunFloatingToolbarStatus
import com.intellij.openapi.components.service
import com.intellij.platform.project.ProjectId
import com.intellij.platform.project.findProjectOrNull
import kotlinx.coroutines.flow.Flow
class BackendJavaAutoRunFloatingToolbarApi : JavaAutoRunFloatingToolbarApi {
override suspend fun setToolbarEnabled(projectId: ProjectId, enabled: Boolean) {
val project = projectId.findProjectOrNull() ?: return
project.service<JavaAutoRunTrackerService>().setFloatingToolbarEnabled(enabled)
}
override suspend fun disableAllAutoTests(projectId: ProjectId) {
val project = projectId.findProjectOrNull() ?: return
project.service<JavaAutoRunTrackerService>().disableAutoTests()
}
override suspend fun toolbarStatus(projectId: ProjectId): Flow<JavaAutoRunFloatingToolbarStatus>? {
val project = projectId.findProjectOrNull() ?: return null
return project.service<JavaAutoRunTrackerService>().flow
}
}

View File

@@ -0,0 +1,117 @@
// 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.execution.backend
import com.intellij.build.BuildView
import com.intellij.execution.ExecutionListener
import com.intellij.execution.ExecutionManager
import com.intellij.execution.process.ProcessHandler
import com.intellij.execution.runners.ExecutionEnvironment
import com.intellij.execution.shared.JavaAutoRunFloatingToolbarStatus
import com.intellij.execution.testDiscovery.JavaAutoRunManager
import com.intellij.execution.testframework.TestConsoleProperties
import com.intellij.execution.testframework.autotest.AutoTestListener
import com.intellij.execution.testframework.sm.runner.ui.SMTRunnerConsoleView
import com.intellij.execution.ui.ConsoleViewWithDelegate
import com.intellij.execution.ui.ExecutionConsole
import com.intellij.execution.ui.RunContentDescriptor
import com.intellij.execution.ui.RunContentManager
import com.intellij.execution.ui.RunContentManager.getInstanceIfCreated
import com.intellij.openapi.application.EDT
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.observable.util.whenDisposed
import com.intellij.openapi.project.Project
import com.intellij.openapi.startup.ProjectActivity
import com.intellij.util.application
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
/**
* Keeps track of the current auto-run test descriptor.
*/
@Service(Service.Level.PROJECT)
class JavaAutoRunTrackerService(val project: Project, val scope: CoroutineScope) {
private var autoRunConfiguration: RunContentDescriptor? = null
val flow: MutableStateFlow<JavaAutoRunFloatingToolbarStatus> = MutableStateFlow(JavaAutoRunFloatingToolbarStatus(false, false))
fun registerListeners() {
val autoRunManager = JavaAutoRunManager.getInstance(project)
project.messageBus.connect(scope).subscribe(AutoTestListener.TOPIC, object : AutoTestListener {
override fun autoTestStatusChanged() {
updateCurrentConfiguration(project, autoRunManager)
}
})
project.messageBus.connect(scope).subscribe(ExecutionManager.EXECUTION_TOPIC, object : ExecutionListener {
override fun processStarted(executorId: String, env: ExecutionEnvironment, handler: ProcessHandler) {
updateCurrentConfiguration(project, autoRunManager)
}
})
}
fun setFloatingToolbarEnabled(enabled: Boolean) {
val properties = getConsoleProperties(project) ?: return
TestConsoleProperties.SHOW_AUTO_TEST_TOOLBAR.set(properties, enabled)
autoTestStatusChanged()
}
fun disableAutoTests() {
scope.launch(Dispatchers.EDT) {
JavaAutoRunManager.getInstance(project).disableAllAutoTests()
}
}
fun updateCurrentConfiguration(project: Project, autoRunManager: JavaAutoRunManager) {
scope.launch(Dispatchers.EDT) {
val content = RunContentManager.getInstance(project).getAllDescriptors().firstOrNull { autoRunManager.isAutoTestEnabled(it) }
if (content == autoRunConfiguration) return@launch
autoRunConfiguration = content
autoTestStatusChanged()
if (content == null) return@launch
content.whenDisposed {
application.invokeLater {
autoTestStatusChanged()
}
}
getConsoleProperties(project)?.addListener(TestConsoleProperties.SHOW_AUTO_TEST_TOOLBAR) {
autoTestStatusChanged()
}
}
}
private fun autoTestStatusChanged() {
val floatingToolbarEnabled = when(autoRunConfiguration) {
null -> false
else -> getConsoleProperties(project)?.let { TestConsoleProperties.SHOW_AUTO_TEST_TOOLBAR.get(it) } ?: false
}
flow.value = JavaAutoRunFloatingToolbarStatus(autoRunConfiguration != null, floatingToolbarEnabled)
}
private fun getConsoleProperties(project: Project): TestConsoleProperties? {
val content = getInstanceIfCreated(project)?.selectedContent ?: return null
val console = getSMTRunnerConsoleView(content.executionConsole) ?: return null
return console.properties
}
private fun getSMTRunnerConsoleView(console: ExecutionConsole): SMTRunnerConsoleView? {
return when (console) {
is SMTRunnerConsoleView -> console
is ConsoleViewWithDelegate -> getSMTRunnerConsoleView(console.delegate)
is BuildView -> console.consoleView?.let { getSMTRunnerConsoleView(it) }
else -> null
}
}
}
private class JavaAutoRunTrackerActivity() : ProjectActivity {
override suspend fun execute(project: Project) {
project.service<JavaAutoRunTrackerService>().registerListeners()
}
}

View File

@@ -0,0 +1,14 @@
// 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.execution.backend
import com.intellij.execution.shared.JavaAutoRunFloatingToolbarApi
import com.intellij.platform.rpc.backend.RemoteApiProvider
import fleet.rpc.remoteApiDescriptor
class JavaTestDiscoveryRemoteApiProvider: RemoteApiProvider {
override fun RemoteApiProvider.Sink.remoteApis() {
remoteApi(remoteApiDescriptor<JavaAutoRunFloatingToolbarApi>()) {
BackendJavaAutoRunFloatingToolbarApi()
}
}
}

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="5" platform="JVM 17" allPlatforms="JVM [17]" useProjectSettings="false">
<compilerSettings>
<option name="additionalArguments" value="-Xjvm-default=all" />
</compilerSettings>
<compilerArguments>
<stringArguments>
<stringArg name="jvmTarget" arg="17" />
<stringArg name="apiVersion" arg="2.1" />
<stringArg name="languageVersion" arg="2.1" />
</stringArguments>
<arrayArguments>
<arrayArg name="pluginClasspaths">
<args>
<arg>$KOTLIN_BUNDLED$/lib/kotlinx-serialization-compiler-plugin.jar</arg>
<arg>$MAVEN_REPOSITORY$/jetbrains/fleet/rhizomedb-compiler-plugin/2.1.20-0.3/rhizomedb-compiler-plugin-2.1.20-0.3.jar</arg>
<arg>$MAVEN_REPOSITORY$/com/jetbrains/fleet/rpc-compiler-plugin/2.1.20-0.3/rpc-compiler-plugin-2.1.20-0.3.jar</arg>
</args>
</arrayArg>
<arrayArg name="pluginOptions" />
</arrayArguments>
</compilerArguments>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="kotlinx-serialization-core" level="project" />
<orderEntry type="library" name="kotlinx-serialization-json" level="project" />
<orderEntry type="module" module-name="intellij.java.execution.impl.shared" />
<orderEntry type="module" module-name="intellij.platform.core.ui" />
<orderEntry type="module" module-name="intellij.platform.ide.rpc" />
<orderEntry type="module" module-name="intellij.platform.ide.impl" />
<orderEntry type="module" module-name="intellij.platform.kernel" />
<orderEntry type="module" module-name="intellij.platform.project" />
<orderEntry type="module" module-name="intellij.platform.testRunner" />
<orderEntry type="module" module-name="intellij.java.frontback.impl" />
</component>
</module>

View File

@@ -0,0 +1,11 @@
<!--suppress PluginXmlValidity -->
<idea-plugin>
<dependencies>
<module name="intellij.java.execution.impl.shared"/>
<plugin id="com.intellij.platform.experimental.frontend"/>
</dependencies>
<extensions defaultExtensionNs="com.intellij">
<editorFloatingToolbarProvider implementation="com.intellij.execution.frontend.JavaAutoRunFloatingToolbarProvider"/>
</extensions>
</idea-plugin>

View File

@@ -0,0 +1,117 @@
// 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.execution.frontend
import com.intellij.execution.shared.JavaAutoRunFloatingToolbarApi
import com.intellij.icons.AllIcons
import com.intellij.ide.IdeBundle
import com.intellij.java.frontback.impl.JavaFrontbackBundle
import com.intellij.openapi.Disposable
import com.intellij.openapi.actionSystem.*
import com.intellij.openapi.actionSystem.ex.CustomComponentAction
import com.intellij.openapi.actionSystem.impl.ActionButton
import com.intellij.openapi.application.runInEdt
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.editor.EditorKind
import com.intellij.openapi.editor.toolbar.floating.FloatingToolbarComponent
import com.intellij.openapi.editor.toolbar.floating.FloatingToolbarProvider
import com.intellij.openapi.editor.toolbar.floating.isInsideMainEditor
import com.intellij.openapi.project.DumbAware
import com.intellij.platform.project.projectId
import com.intellij.ui.components.JBLabel
import com.intellij.util.ui.GridBag
import com.intellij.util.ui.JBUI
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import org.jetbrains.annotations.ApiStatus
import java.awt.GridBagLayout
import javax.swing.JComponent
import javax.swing.JPanel
/**
* Shows a floating toolbar when tests run automatically.
*/
@ApiStatus.Internal
class JavaAutoRunFloatingToolbarProvider : FloatingToolbarProvider {
override val backgroundAlpha: Float = JBUI.CurrentTheme.FloatingToolbar.TRANSLUCENT_BACKGROUND_ALPHA
override val autoHideable: Boolean = false
override val actionGroup: ActionGroup
get() = DefaultActionGroup(DisableAutoTestAction()).apply {
add(HideAction())
}
override fun isApplicable(dataContext: DataContext): Boolean {
return isInsideMainEditor(dataContext)
&& dataContext.getData(CommonDataKeys.EDITOR)?.editorKind == EditorKind.MAIN_EDITOR
}
override fun register(dataContext: DataContext, component: FloatingToolbarComponent, parentDisposable: Disposable) {
val project = dataContext.getData(CommonDataKeys.PROJECT) ?: return
updateFloatingToolbarVisibility(component, false)
project.service<AutoRunFloatingToolbarService>().scope.launch {
JavaAutoRunFloatingToolbarApi.getInstance().toolbarStatus(project.projectId())?.collect {
state -> runInEdt {
updateFloatingToolbarVisibility(component, state.autoTestEnabled && state.toolbarEnabled)
}
}
}
}
private fun updateFloatingToolbarVisibility(component: FloatingToolbarComponent, visible: Boolean) {
if (visible) {
component.autoHideable = true
} else {
component.autoHideable = false
component.hideImmediately()
}
}
}
private class DisableAutoTestAction : AnAction(), CustomComponentAction, DumbAware {
override fun actionPerformed(e: AnActionEvent) {}
override fun createCustomComponent(presentation: Presentation, place: String): JComponent {
val panel = JPanel(GridBagLayout())
val constraints = GridBag()
panel.add(JBLabel(JavaFrontbackBundle.message("auto.run.floating.toolbar.text")), constraints.next().insets(0, 8, 0, 8))
val disableButton = ActionButton(DisableAction(), null, ActionPlaces.EDITOR_FLOATING_TOOLBAR, ActionToolbar.DEFAULT_MINIMUM_BUTTON_SIZE)
disableButton.putClientProperty(Toggleable.SELECTED_KEY, true)
panel.add(disableButton, constraints.next())
panel.isOpaque = false
return panel
}
}
private class DisableAction : AnAction(IdeBundle.message("button.disable"), JavaFrontbackBundle.message("auto.run.floating.toolbar.disable.action"), AllIcons.Actions.RerunAutomatically) {
override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: return
project.service<AutoRunFloatingToolbarService>().scope.launch {
JavaAutoRunFloatingToolbarApi.getInstance().disableAllAutoTests(project.projectId())
}
}
}
private class HideAction : AnAction() {
override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: return
project.service<AutoRunFloatingToolbarService>().scope.launch {
JavaAutoRunFloatingToolbarApi.getInstance().setToolbarEnabled(project.projectId(), false)
}
}
override fun getActionUpdateThread() = ActionUpdateThread.EDT
override fun update(e: AnActionEvent) {
e.presentation.icon = AllIcons.Actions.Close
e.presentation.text = IdeBundle.message("tooltip.hide")
}
}
@Service(Service.Level.PROJECT)
private class AutoRunFloatingToolbarService(val scope: CoroutineScope)

View File

@@ -1,180 +0,0 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.execution.testDiscovery
import com.intellij.build.BuildView
import com.intellij.execution.ExecutionListener
import com.intellij.execution.ExecutionManager
import com.intellij.execution.process.ProcessHandler
import com.intellij.execution.runners.ExecutionEnvironment
import com.intellij.execution.testframework.TestConsoleProperties
import com.intellij.execution.testframework.autotest.AutoTestListener
import com.intellij.execution.testframework.sm.runner.ui.SMTRunnerConsoleView
import com.intellij.execution.ui.ConsoleViewWithDelegate
import com.intellij.execution.ui.ExecutionConsole
import com.intellij.execution.ui.RunContentDescriptor
import com.intellij.execution.ui.RunContentManager
import com.intellij.execution.ui.RunContentManager.getInstanceIfCreated
import com.intellij.icons.AllIcons
import com.intellij.ide.IdeBundle
import com.intellij.java.JavaBundle
import com.intellij.openapi.Disposable
import com.intellij.openapi.actionSystem.*
import com.intellij.openapi.actionSystem.ex.CustomComponentAction
import com.intellij.openapi.actionSystem.impl.ActionButton
import com.intellij.openapi.editor.EditorKind
import com.intellij.openapi.editor.toolbar.floating.FloatingToolbarComponent
import com.intellij.openapi.editor.toolbar.floating.FloatingToolbarProvider
import com.intellij.openapi.editor.toolbar.floating.isInsideMainEditor
import com.intellij.openapi.observable.util.whenDisposed
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.project.Project
import com.intellij.ui.components.JBLabel
import com.intellij.util.application
import com.intellij.util.ui.GridBag
import com.intellij.util.ui.JBUI
import org.jetbrains.annotations.ApiStatus
import java.awt.GridBagLayout
import javax.swing.JComponent
import javax.swing.JPanel
/**
* Shows a floating toolbar when tests run automatically.
*/
@ApiStatus.Internal
class JavaAutoRunFloatingToolbarProvider : FloatingToolbarProvider {
private var configuration: RunContentDescriptor? = null
override val backgroundAlpha: Float = JBUI.CurrentTheme.FloatingToolbar.TRANSLUCENT_BACKGROUND_ALPHA
override val autoHideable: Boolean = false
override val actionGroup: ActionGroup
get() = DefaultActionGroup(DisableAutoTestAction()).apply {
add(HideAction())
}
override fun isApplicable(dataContext: DataContext): Boolean {
return isInsideMainEditor(dataContext)
&& dataContext.getData(CommonDataKeys.EDITOR)?.editorKind == EditorKind.MAIN_EDITOR
}
override fun register(dataContext: DataContext, component: FloatingToolbarComponent, parentDisposable: Disposable) {
val project = dataContext.getData(CommonDataKeys.PROJECT) ?: return
val autoRunManager = JavaAutoRunManager.getInstance(project)
application.invokeLater {
updateFloatingToolbarVisibility(project, component, autoRunManager)
}
project.messageBus.connect(parentDisposable).subscribe(AutoTestListener.TOPIC, object: AutoTestListener {
override fun autoTestStatusChanged() {
updateFloatingToolbarVisibility(project, component, autoRunManager)
// Picks up the current descriptor when auto-test is enabled (auto-test is always disabled on project opening)
updateCurrentConfiguration(project, autoRunManager, component)
}
})
// The descriptor is disposed and created again after each run.
project.messageBus.connect(parentDisposable).subscribe(ExecutionManager.EXECUTION_TOPIC, object : ExecutionListener {
override fun processStarted(executorId: String, env: ExecutionEnvironment, handler: ProcessHandler) {
updateCurrentConfiguration(project, autoRunManager, component)
}
})
}
/**
* Keeps track of the current auto-run test descriptor.
*/
private fun updateCurrentConfiguration(project: Project, autoRunManager: JavaAutoRunManager, component: FloatingToolbarComponent) {
val content = RunContentManager.getInstance(project).getAllDescriptors().firstOrNull { autoRunManager.isAutoTestEnabled(it) }
if (content != configuration) { configuration = content; } else { return }
if (content == null) {
updateFloatingToolbarVisibility(project, component, autoRunManager)
return
}
content.whenDisposed {
application.invokeLater {
updateFloatingToolbarVisibility(project, component, autoRunManager)
}
}
getConsoleProperties(project)?.addListener(TestConsoleProperties.SHOW_AUTO_TEST_TOOLBAR) {
application.invokeLater {
updateFloatingToolbarVisibility(project, component, autoRunManager)
}
}
}
private fun updateFloatingToolbarVisibility(project: Project, component: FloatingToolbarComponent, autoRunManager: JavaAutoRunManager) {
val isToolbarEnabled = isAutoTestToolbarEnabled(project)
val hasEnabledAutoTests = autoRunManager.hasEnabledAutoTests()
if (isToolbarEnabled && hasEnabledAutoTests) {
component.autoHideable = true
} else {
component.autoHideable = false
component.hideImmediately()
}
}
}
private class DisableAutoTestAction : AnAction(), CustomComponentAction, DumbAware {
override fun actionPerformed(e: AnActionEvent) {}
override fun createCustomComponent(presentation: Presentation, place: String): JComponent {
val panel = JPanel(GridBagLayout())
val constraints = GridBag()
panel.add(JBLabel(JavaBundle.message("auto.test.on")), constraints.next().insets(0, 8, 0, 8))
val disableButton = ActionButton(DisableAction(), null, ActionPlaces.EDITOR_FLOATING_TOOLBAR, ActionToolbar.DEFAULT_MINIMUM_BUTTON_SIZE)
disableButton.putClientProperty(Toggleable.SELECTED_KEY, true)
panel.add(disableButton, constraints.next())
panel.isOpaque = false
return panel
}
}
private class DisableAction : AnAction(IdeBundle.message("button.disable"), JavaBundle.message("disable.auto.test"), AllIcons.Actions.RerunAutomatically) {
override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: return
val manager = JavaAutoRunManager.getInstance(project)
manager.disableAllAutoTests()
}
}
private class HideAction : AnAction() {
override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: return
val properties = getConsoleProperties(project) ?: return
TestConsoleProperties.SHOW_AUTO_TEST_TOOLBAR.set(properties, false)
}
override fun getActionUpdateThread() = ActionUpdateThread.EDT
override fun update(e: AnActionEvent) {
e.presentation.icon = AllIcons.Actions.Close
e.presentation.text = IdeBundle.message("tooltip.hide")
}
}
private fun getConsoleProperties(project: Project): TestConsoleProperties? {
val content = getInstanceIfCreated(project)?.selectedContent ?: return null
val console = getSMTRunnerConsoleView(content.executionConsole) ?: return null
return console.properties
}
private fun isAutoTestToolbarEnabled(project: Project): Boolean {
val properties = getConsoleProperties(project) ?: return false
return TestConsoleProperties.SHOW_AUTO_TEST_TOOLBAR.get(properties)
}
private fun getSMTRunnerConsoleView(console: ExecutionConsole): SMTRunnerConsoleView? {
return when (console) {
is SMTRunnerConsoleView -> console
is ConsoleViewWithDelegate -> getSMTRunnerConsoleView(console.delegate)
is BuildView -> console.consoleView?.let { getSMTRunnerConsoleView(it) }
else -> null
}
}

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="5" platform="JVM 17" allPlatforms="JVM [17]" useProjectSettings="false">
<compilerSettings>
<option name="additionalArguments" value="-Xjvm-default=all" />
</compilerSettings>
<compilerArguments>
<stringArguments>
<stringArg name="jvmTarget" arg="17" />
<stringArg name="apiVersion" arg="2.1" />
<stringArg name="languageVersion" arg="2.1" />
</stringArguments>
<arrayArguments>
<arrayArg name="pluginClasspaths">
<args>
<arg>$KOTLIN_BUNDLED$/lib/kotlinx-serialization-compiler-plugin.jar</arg>
<arg>$MAVEN_REPOSITORY$/jetbrains/fleet/rhizomedb-compiler-plugin/2.1.20-0.3/rhizomedb-compiler-plugin-2.1.20-0.3.jar</arg>
<arg>$MAVEN_REPOSITORY$/com/jetbrains/fleet/rpc-compiler-plugin/2.1.20-0.3/rpc-compiler-plugin-2.1.20-0.3.jar</arg>
</args>
</arrayArg>
<arrayArg name="pluginOptions" />
</arrayArguments>
</compilerArguments>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="kotlinx-serialization-core" level="project" />
<orderEntry type="library" name="kotlinx-serialization-json" level="project" />
<orderEntry type="module" module-name="intellij.platform.core" />
<orderEntry type="module" module-name="intellij.platform.core.ui" />
<orderEntry type="module" module-name="intellij.platform.editor" />
<orderEntry type="module" module-name="intellij.platform.ide" />
<orderEntry type="module" module-name="intellij.platform.ide.rpc" />
<orderEntry type="module" module-name="intellij.platform.ide.impl" />
<orderEntry type="module" module-name="intellij.platform.kernel" />
<orderEntry type="module" module-name="intellij.platform.project" />
</component>
</module>

View File

@@ -0,0 +1,2 @@
<idea-plugin>
</idea-plugin>

View File

@@ -0,0 +1,30 @@
// 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.execution.shared
import com.intellij.platform.project.ProjectId
import com.intellij.platform.rpc.RemoteApiProviderService
import fleet.rpc.RemoteApi
import fleet.rpc.Rpc
import fleet.rpc.remoteApiDescriptor
import kotlinx.coroutines.flow.Flow
import kotlinx.serialization.Serializable
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
@Rpc
interface JavaAutoRunFloatingToolbarApi : RemoteApi<Unit> {
suspend fun setToolbarEnabled(projectId: ProjectId, enabled: Boolean)
suspend fun disableAllAutoTests(projectId: ProjectId)
suspend fun toolbarStatus(projectId: ProjectId): Flow<JavaAutoRunFloatingToolbarStatus>?
companion object {
suspend fun getInstance(): JavaAutoRunFloatingToolbarApi {
return RemoteApiProviderService.resolve(remoteApiDescriptor<JavaAutoRunFloatingToolbarApi>())
}
}
}
@ApiStatus.Internal
@Serializable
data class JavaAutoRunFloatingToolbarStatus(val autoTestEnabled: Boolean, val toolbarEnabled: Boolean)

View File

@@ -73,6 +73,9 @@ annotations.new.line.record.component=New line for annotations
align.types.in.multi.catch=Align types in multi-catch
wrapping.switch.statement.or.expression='switch' statement/expression
auto.run.floating.toolbar.text=Auto test on
auto.run.floating.toolbar.disable.action=Disable auto-test
title.javadoc=JavaDoc
group.javadoc.other=Other
group.javadoc.alignment=Alignment

View File

@@ -885,8 +885,6 @@
<runConfigurationExtension implementation="com.intellij.execution.testDiscovery.TestDiscoveryExtension"/>
<runConfigurationExtension implementation="com.intellij.execution.impl.JavaDebuggerAutoAttach"/>
<editorFloatingToolbarProvider implementation="com.intellij.execution.testDiscovery.JavaAutoRunFloatingToolbarProvider"/>
<completion.contributor language="JAVA" id="methodsChainsCompletionContributor" order="first"
implementationClass="com.intellij.compiler.chainsSearch.completion.MethodChainCompletionContributor"/>
<weigher order="after mostUsed" key="completion" id="methodChains"

View File

@@ -1896,9 +1896,6 @@ java.test.use.wall.time=Use Wall Time
java.test.overall.time=Overall time: {0}
java.test.sum.time=Sum time: {0}
auto.test.on=Auto-test on
disable.auto.test=Disable auto-test
error.no.annotation.class.found=No annotation class found
preview.api.usage={0} is a preview API and may be removed in a future release
preview.api.usage.reflective={0} is a reflective preview API and may be removed in a future release

View File

@@ -15,6 +15,9 @@
<orderEntry type="module" module-name="intellij.xml.dom.impl" scope="RUNTIME" />
<orderEntry type="module" module-name="intellij.java.debugger.memory.agent" scope="RUNTIME" />
<orderEntry type="module" module-name="intellij.java.execution.impl" scope="RUNTIME" />
<orderEntry type="module" module-name="intellij.java.execution.impl.shared" scope="RUNTIME" />
<orderEntry type="module" module-name="intellij.java.execution.impl.backend" scope="RUNTIME" />
<orderEntry type="module" module-name="intellij.java.execution.impl.frontend" scope="RUNTIME" />
<orderEntry type="module" module-name="intellij.platform.externalSystem.impl" scope="RUNTIME" />
<orderEntry type="module" module-name="intellij.java.ui" scope="RUNTIME" />
<orderEntry type="module" module-name="intellij.java.manifest" scope="RUNTIME" />

View File

@@ -43,10 +43,13 @@
<module name="intellij.jvm.analysis.impl"/>
<module name="intellij.java.debugger.impl.frontend"/>
<module name="intellij.java.debugger.impl.backend"/>
<module name="intellij.java.execution.impl.frontend"/>
<module name="intellij.java.execution.impl.backend"/>
<module name="intellij.java.frontback.psi" loading="embedded"/>
<module name="intellij.java.frontback.psi.impl" loading="embedded"/>
<module name="intellij.java.frontback.impl" loading="embedded"/>
<module name="intellij.java.debugger.impl.shared" loading="embedded"/>
<module name="intellij.java.execution.impl.shared" loading="embedded"/>
<module name="intellij.java.syntax" loading="embedded"/>
<module name="intellij.java.psi.impl" loading="embedded"/>
<module name="intellij.java.psi" loading="embedded"/>

View File

@@ -38,6 +38,7 @@ object JavaPluginLayout {
"intellij.java.compiler",
"intellij.java.debugger",
"intellij.java.execution",
"intellij.java.execution.impl.shared",
"intellij.java.remoteServers",
"intellij.java.analysis",
"intellij.jvm.analysis",
@@ -57,6 +58,8 @@ object JavaPluginLayout {
"intellij.java.terminal",
"intellij.java.debugger.memory.agent",
"intellij.java.execution.impl",
"intellij.java.execution.impl.backend",
"intellij.java.execution.impl.frontend",
"intellij.java.ui",
"intellij.java.structureView",
"intellij.java.manifest",