[debugger] IJPL-158332 Sync new action with old hot swap actions

GitOrigin-RevId: 2e45ce6bf2e0bec1875e9048407f81c0c5eeb63a
This commit is contained in:
Maksim Zuev
2024-07-30 20:57:58 +00:00
committed by intellij-monorepo-bot
parent 20887d40f3
commit 68cade0689
6 changed files with 88 additions and 51 deletions
@@ -3,34 +3,68 @@ package com.intellij.debugger.impl.hotswap
import com.intellij.debugger.impl.DebuggerManagerListener
import com.intellij.debugger.impl.DebuggerSession
import com.intellij.debugger.ui.HotSwapStatusListener
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.HotSwapResultListener
import com.intellij.xdebugger.impl.hotswap.HotSwapSession
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>()
internal class HotSwapDebugSessionManager {
private val disposables = ConcurrentHashMap<DebuggerSession, Disposable>()
private val sessions = ConcurrentHashMap<DebuggerSession, HotSwapSession<*>>()
override fun sessionCreated(session: DebuggerSession?) {
if (session == null) return
fun createSessionListenerOrNull(session: DebuggerSession): HotSwapStatusListener? = sessions[session]
?.let { HotSwapStatusListenerAdapter(it.startHotSwapListening()) }
companion object {
@JvmStatic
fun getInstance(project: Project): HotSwapDebugSessionManager = project.service()
}
internal fun createSession(session: DebuggerSession) {
if (!Registry.`is`("debugger.hotswap.floating.toolbar")) return
val disposable = Disposer.newDisposable()
sessions[session] = disposable
HotSwapSessionManager.getInstance(session.project).createSession(JvmHotSwapProvider(session), disposable)
disposables[session] = disposable
val hotSwapSession = HotSwapSessionManager.getInstance(session.project).createSession(JvmHotSwapProvider(session), disposable)
sessions[session] = hotSwapSession
}
internal fun removeSession(session: DebuggerSession) {
disposables.remove(session)?.let { Disposer.dispose(it) }
sessions.remove(session)
}
}
internal class HotSwapDebugSessionListener : DebuggerManagerListener {
override fun sessionCreated(session: DebuggerSession?) {
if (session == null) return
HotSwapDebugSessionManager.getInstance(session.project).createSession(session)
}
override fun sessionRemoved(session: DebuggerSession?) {
if (session == null) return
sessions.remove(session)?.let { Disposer.dispose(it) }
HotSwapDebugSessionManager.getInstance(session.project).removeSession(session)
}
}
companion object {
@JvmStatic
fun getInstance(project: Project): HotSwapDebugSessionListener = project.service()
private class HotSwapStatusListenerAdapter(private val listener: HotSwapResultListener) : 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()
}
}
@@ -26,23 +26,7 @@ internal class JvmHotSwapProvider(private val debuggerSession: DebuggerSession)
override fun performHotSwap(context: DataContext, session: HotSwapSession<VirtualFile>) {
val project = context.getData(CommonDataKeys.PROJECT) ?: return
val listener = session.createStatusListener()
HotSwapUI.getInstance(project).compileAndReload(debuggerSession, HotSwapStatusListenerAdapter(listener),
*session.getChanges().toTypedArray())
}
}
private class HotSwapStatusListenerAdapter(private val listener: HotSwapResultListener) : 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()
HotSwapUI.getInstance(project).compileAndReload(debuggerSession, *session.getChanges().toTypedArray())
}
}
@@ -19,7 +19,6 @@ public abstract class HotSwapUI {
@Nullable HotSwapStatusListener callback);
public abstract void compileAndReload(@NotNull DebuggerSession session, VirtualFile @NotNull ... files);
public abstract void compileAndReload(@NotNull DebuggerSession session, @Nullable HotSwapStatusListener callback, VirtualFile @NotNull ... files);
public abstract void addListener(HotSwapVetoableListener listener);
@@ -7,6 +7,7 @@ import com.intellij.debugger.impl.DebuggerManagerListener;
import com.intellij.debugger.impl.DebuggerSession;
import com.intellij.debugger.impl.HotSwapFile;
import com.intellij.debugger.impl.HotSwapManager;
import com.intellij.debugger.impl.hotswap.HotSwapDebugSessionManager;
import com.intellij.debugger.settings.DebuggerSettings;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.application.ApplicationManager;
@@ -29,7 +30,6 @@ import com.intellij.ui.UIBundle;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.FileCollectionFactory;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.ui.MessageCategory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.util.JpsPathUtil;
@@ -276,8 +276,9 @@ public final class HotSwapUIImpl extends HotSwapUI {
boolean compileBeforeHotswap,
@Nullable HotSwapStatusListener callback) {
dontAskHotswapAfterThisCompilation();
Project project = session.getProject();
callback = mergeCallbacksIfNeeded(callback, HotSwapDebugSessionManager.getInstance(project).createSessionListenerOrNull(session));
if (compileBeforeHotswap) {
Project project = session.getProject();
ProjectTaskManagerImpl.putBuildOriginator(project, this.getClass());
ProjectTaskManager projectTaskManager = ProjectTaskManager.getInstance(project);
if (callback == null) {
@@ -300,15 +301,11 @@ public final class HotSwapUIImpl extends HotSwapUI {
@Override
public void compileAndReload(@NotNull DebuggerSession session, VirtualFile @NotNull ... files) {
compileAndReload(session, null, files);
}
@Override
public void compileAndReload(@NotNull DebuggerSession session, @Nullable HotSwapStatusListener callback, VirtualFile @NotNull ... files) {
dontAskHotswapAfterThisCompilation();
Project project = session.getProject();
ProjectTaskManagerImpl.putBuildOriginator(project, this.getClass());
HotSwapStatusListener callback = HotSwapDebugSessionManager.getInstance(project).createSessionListenerOrNull(session);
if (callback == null) {
ProjectTaskManager.getInstance(project).compile(files);
} else {
@@ -323,6 +320,30 @@ public final class HotSwapUIImpl extends HotSwapUI {
return new ProjectTaskContext(callback).withUserData(HOT_SWAP_CALLBACK_KEY, callback);
}
private static @Nullable HotSwapStatusListener mergeCallbacksIfNeeded(@Nullable HotSwapStatusListener callback1, @Nullable HotSwapStatusListener callback2) {
if (callback1 == null) return callback2;
if (callback2 == null) return callback1;
return new HotSwapStatusListener() {
@Override
public void onSuccess(@NotNull List<DebuggerSession> sessions) {
callback1.onSuccess(sessions);
callback2.onSuccess(sessions);
}
@Override
public void onCancel(List<DebuggerSession> sessions) {
callback1.onCancel(sessions);
callback2.onCancel(sessions);
}
@Override
public void onFailure(List<DebuggerSession> sessions) {
callback1.onFailure(sessions);
callback2.onFailure(sessions);
}
};
}
public void dontAskHotswapAfterThisCompilation() {
myAskBeforeHotswap = false;
}
@@ -29,7 +29,6 @@ private class HotSwapWithRebuildAction : AnAction(), CustomComponentAction {
override fun actionPerformed(e: AnActionEvent) {
val session = session ?: return
session.startHotSwap()
callWithTemplate(e.dataContext, session)
}
@@ -19,11 +19,12 @@ class HotSwapSessionManager(private val project: Project, private val parentScop
private val listeners = DisposableWrapperList<HotSwapChangesListener>()
private val sessions = DisposableWrapperList<HotSwapSession<*>>()
fun <T> createSession(provider: HotSwapProvider<T>, disposable: Disposable) {
fun <T> createSession(provider: HotSwapProvider<T>, disposable: Disposable): HotSwapSession<T> {
val hotSwapSession = HotSwapSession(project, provider, parentScope)
Disposer.register(disposable, hotSwapSession)
sessions.add(hotSwapSession, disposable)
hotSwapSession.init()
return hotSwapSession
}
internal fun addListener(listener: HotSwapChangesListener, disposable: Disposable) {
@@ -84,24 +85,23 @@ class HotSwapSession<T>(val project: Project, internal val provider: HotSwapProv
}
}
internal fun startHotSwap() {
currentStatus = HotSwapVisibleStatus.IN_PROGRESS
}
fun getChanges() = changesCollector.getChanges()
fun createStatusListener() = object : HotSwapResultListener {
override fun onCompleted() {
completeHotSwap()
HotSwapStatusNotificationManager.getInstance(project).showSuccessNotification(coroutineScope)
}
fun startHotSwapListening(): HotSwapResultListener {
currentStatus = HotSwapVisibleStatus.IN_PROGRESS
return object : HotSwapResultListener {
override fun onCompleted() {
completeHotSwap()
HotSwapStatusNotificationManager.getInstance(project).showSuccessNotification(coroutineScope)
}
override fun onFailed() {
completeHotSwap()
}
override fun onFailed() {
completeHotSwap()
}
override fun onCanceled() {
currentStatus = HotSwapVisibleStatus.CHANGES_READY
override fun onCanceled() {
currentStatus = HotSwapVisibleStatus.CHANGES_READY
}
}
}
}