[debugger] IJPL-158332 Hot swap button in a floating toolbar when source changes are detected

GitOrigin-RevId: f9ac6cbaa0ebdb0d7893e3c644b650d4317aef86
This commit is contained in:
Maksim Zuev
2024-07-26 12:18:16 +02:00
committed by intellij-monorepo-bot
parent 8fd9bd1bce
commit bb43d09386
10 changed files with 406 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
// 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.debugger.impl.hotswap
import com.intellij.debugger.impl.DebuggerManagerListener
import com.intellij.debugger.impl.DebuggerSession
import com.intellij.openapi.Disposable
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.registry.Registry
import com.intellij.xdebugger.impl.hotswap.HotSwapSessionManager
import java.util.concurrent.ConcurrentHashMap
@Service(Service.Level.PROJECT)
internal class HotSwapDebugSessionListener : DebuggerManagerListener {
private val sessions = ConcurrentHashMap<DebuggerSession, Disposable>()
override fun sessionCreated(session: DebuggerSession?) {
if (session == null) return
if (!Registry.`is`("debugger.hotswap.floating.toolbar")) return
val disposable = Disposer.newDisposable()
sessions[session] = disposable
HotSwapSessionManager.getInstance(session.project).createSession(JvmHotSwapProvider(session), disposable)
}
override fun sessionRemoved(session: DebuggerSession?) {
if (session == null) return
sessions.remove(session)?.let { Disposer.dispose(it) }
}
companion object {
@JvmStatic
fun getInstance(project: Project): HotSwapDebugSessionListener = project.service()
}
}

View File

@@ -0,0 +1,49 @@
// 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.debugger.impl.hotswap
import com.intellij.debugger.impl.DebuggerSession
import com.intellij.debugger.ui.HotSwapStatusListener
import com.intellij.debugger.ui.HotSwapUI
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.application.readAction
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectFileIndex
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.xdebugger.impl.hotswap.*
import kotlinx.coroutines.CoroutineScope
internal class JvmHotSwapProvider(private val debuggerSession: DebuggerSession) : HotSwapProvider<VirtualFile> {
override fun createChangesCollector(
session: HotSwapSession<VirtualFile>,
coroutineScope: CoroutineScope,
listener: SourceFileChangesListener<VirtualFile>,
) = SourceFileChangesCollectorImpl(
coroutineScope, listener,
InProjectFilter(session.project),
SearchScopeFilter(debuggerSession.searchScope),
)
override fun performHotSwap(context: DataContext, session: HotSwapSession<VirtualFile>) {
val project = context.getData(CommonDataKeys.PROJECT) ?: return
val listener = session.createStatusListener()
HotSwapUI.getInstance(project).reloadChangedClasses(debuggerSession, true, object : HotSwapStatusListener {
override fun onSuccess(sessions: MutableList<DebuggerSession>?) {
listener.onCompleted()
}
override fun onFailure(sessions: MutableList<DebuggerSession>?) {
listener.onFailed()
}
override fun onCancel(sessions: MutableList<DebuggerSession>?) {
listener.onCanceled()
}
})
}
}
private class InProjectFilter(private val project: Project) : SourceFileChangeFilter<VirtualFile> {
override suspend fun isApplicable(change: VirtualFile): Boolean =
readAction { ProjectFileIndex.getInstance(project).isInSource(change) }
}

View File

@@ -49,6 +49,8 @@
topic="com.intellij.debugger.impl.DebuggerManagerListener"/>
<listener class="com.intellij.debugger.ui.HotSwapUIImpl$HotSwapDebuggerManagerListener"
topic="com.intellij.debugger.impl.DebuggerManagerListener"/>
<listener class="com.intellij.debugger.impl.hotswap.HotSwapDebugSessionListener"
topic="com.intellij.debugger.impl.DebuggerManagerListener"/>
<listener class="com.intellij.packaging.impl.artifacts.ArtifactVirtualFileListener"
topic="com.intellij.openapi.vfs.newvfs.BulkFileListener"/>
<listener class="com.intellij.compiler.server.impl.BuildProcessPreloadedStateClearer"