diff --git a/README.md b/README.md index 075c9a79..496ebd2e 100644 --- a/README.md +++ b/README.md @@ -1 +1,5 @@ -[![Build Status](https://ci.consulo.io/job/consulo-javascript/badge/icon)](https://ci.consulo.io/job/consulo-javascript) \ No newline at end of file +[![Build Status](https://ci.consulo.io/job/consulo-javascript/badge/icon)](https://ci.consulo.io/job/consulo-javascript) + + +# Browser Debugging + * For `Chrome Like` browsers visit [https://github.com/consulo/chrome-consulo-debugger-extension](link) diff --git a/debugger/browser-debugger-impl/pom.xml b/debugger/browser-debugger-impl/pom.xml index 32040926..5ebf640d 100644 --- a/debugger/browser-debugger-impl/pom.xml +++ b/debugger/browser-debugger-impl/pom.xml @@ -55,21 +55,15 @@ ${project.groupId} - com.intellij.xml + consulo.javascript-cdt.debugger.impl ${project.version} - provided - com.github.kklisura.cdt - cdt-java-client - 2.1.0 - - - org.javassist - javassist - - + ${project.groupId} + com.intellij.xml + ${project.version} + provided diff --git a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/BrowserCDTDebugProcess.java b/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/BrowserCDTDebugProcess.java new file mode 100644 index 00000000..e0865745 --- /dev/null +++ b/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/BrowserCDTDebugProcess.java @@ -0,0 +1,22 @@ +package consulo.javascript.debugger.browser; + +import consulo.execution.ExecutionResult; +import consulo.execution.debug.XDebugSession; +import consulo.javascript.debugger.cdt.CDTProcessBase; +import consulo.javascript.debugger.cdt.ChromeDevToolsFactory; +import consulo.process.ExecutionException; +import jakarta.annotation.Nonnull; + +/** + * @author VISTALL + * @since 2026-02-15 + */ +public class BrowserCDTDebugProcess extends CDTProcessBase { + public BrowserCDTDebugProcess(@Nonnull XDebugSession session, ExecutionResult result) throws ExecutionException { + super(session, result); + } + + public void init(SessionHolder.BrowserSession session) { + initTools(ChromeDevToolsFactory.create(new ProxyWebSocketService(session))); + } +} diff --git a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/BrowserDebuggerProcess.java b/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/BrowserDebuggerProcess.java index 6ac3c935..9e7e8048 100644 --- a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/BrowserDebuggerProcess.java +++ b/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/BrowserDebuggerProcess.java @@ -2,7 +2,6 @@ import consulo.builtinWebServer.webSocket.WebSocketConnection; import consulo.execution.debug.DefaultDebugProcessHandler; -import consulo.javascript.debugger.browser.process.CDTProcess; import consulo.javascript.debugger.browser.transport.DetachDebuggerRequest; import consulo.javascript.debugger.browser.transport.ExtensionWebSocketAccepter; import jakarta.annotation.Nonnull; @@ -18,7 +17,7 @@ public BrowserDebuggerProcess(@Nonnull SessionHolder.BrowserSession browserSessi myBrowserSession = browserSession; } - public void setDebugProcess(CDTProcess cdtProcess) { + public void setDebugProcess(BrowserCDTDebugProcess cdtProcess) { myBrowserSession.setDebugProcess(cdtProcess); } diff --git a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/JavaScriptBrowserDebugRunner.java b/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/JavaScriptBrowserDebugRunner.java index 360c0886..bcc582f0 100644 --- a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/JavaScriptBrowserDebugRunner.java +++ b/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/JavaScriptBrowserDebugRunner.java @@ -9,7 +9,7 @@ import consulo.execution.runner.DefaultProgramRunner; import consulo.execution.runner.ExecutionEnvironment; import consulo.execution.ui.RunContentDescriptor; -import consulo.javascript.debugger.browser.process.CDTProcess; +import consulo.javascript.debugger.cdt.CDTProcessBase; import consulo.process.ExecutionException; import jakarta.annotation.Nonnull; @@ -34,7 +34,7 @@ protected RunContentDescriptor doExecute(@Nonnull RunProfileState state, @Nonnul BrowserDebuggerProcess processHandler = (BrowserDebuggerProcess) result.getProcessHandler(); - CDTProcess process = new CDTProcess(xDebugSession, result); + BrowserCDTDebugProcess process = new BrowserCDTDebugProcess(xDebugSession, result); processHandler.setDebugProcess(process); diff --git a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/SessionHolder.java b/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/SessionHolder.java index 3a5950df..186e9f37 100644 --- a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/SessionHolder.java +++ b/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/SessionHolder.java @@ -4,7 +4,6 @@ import consulo.annotation.component.ServiceAPI; import consulo.annotation.component.ServiceImpl; import consulo.builtinWebServer.webSocket.WebSocketConnection; -import consulo.javascript.debugger.browser.process.CDTProcess; import consulo.util.collection.Lists; import consulo.util.collection.SmartList; import jakarta.inject.Singleton; @@ -28,7 +27,7 @@ public class BrowserSession { private WebSocketConnection myWebSocketConnection; - private CDTProcess myDebugProcess; + private BrowserCDTDebugProcess myDebugProcess; private List> myHandlers = new SmartList<>(); @@ -54,7 +53,7 @@ public void close() { myBrowserSessions.remove(this); } - public void setDebugProcess(CDTProcess debugProcess) { + public void setDebugProcess(BrowserCDTDebugProcess debugProcess) { myDebugProcess = debugProcess; } @@ -62,7 +61,7 @@ public WebSocketConnection getWebSocketConnection() { return myWebSocketConnection; } - public CDTProcess getDebugProcess() { + public BrowserCDTDebugProcess getDebugProcess() { return myDebugProcess; } } diff --git a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTScopeValue.java b/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTScopeValue.java deleted file mode 100644 index 23ca18b6..00000000 --- a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTScopeValue.java +++ /dev/null @@ -1,26 +0,0 @@ -package consulo.javascript.debugger.browser.process; - -import com.github.kklisura.cdt.protocol.types.debugger.Scope; -import com.github.kklisura.cdt.protocol.types.runtime.RemoteObject; -import consulo.platform.base.icon.PlatformIconGroup; -import consulo.ui.image.Image; -import consulo.util.lang.StringUtil; -import jakarta.annotation.Nonnull; - -import java.util.Locale; - -/** - * @author VISTALL - * @since 2026-02-15 - */ -public class CDTScopeValue extends CDTRemoteObjectValue { - public CDTScopeValue(@Nonnull Scope scope, @Nonnull RemoteObject remoteObject, CDTProcess process) { - super(StringUtil.capitalize(scope.getType().name().toLowerCase(Locale.ROOT)), remoteObject, process); - } - - @Nonnull - @Override - protected Image getObjectIcon() { - return PlatformIconGroup.nodesFolder(); - } -} diff --git a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTScript.java b/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTScript.java deleted file mode 100644 index 631285fa..00000000 --- a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTScript.java +++ /dev/null @@ -1,27 +0,0 @@ -package consulo.javascript.debugger.browser.process; - -import com.github.kklisura.cdt.protocol.events.debugger.ScriptParsed; -import consulo.virtualFileSystem.VirtualFile; -import consulo.virtualFileSystem.VirtualFileManager; - -/** - * @author VISTALL - * @since 2026-02-15 - */ -public class CDTScript { - private final String myId; - private final String myUrl; - - public CDTScript(ScriptParsed scriptParsed) { - myId = scriptParsed.getScriptId(); - myUrl = scriptParsed.getUrl(); - } - - public String getId() { - return myId; - } - - public VirtualFile toVirtualFile() { - return VirtualFileManager.getInstance().findFileByUrl(myUrl); - } -} diff --git a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/transport/ExtensionWebSocketAccepter.java b/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/transport/ExtensionWebSocketAccepter.java index 7d768870..98a87253 100644 --- a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/transport/ExtensionWebSocketAccepter.java +++ b/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/transport/ExtensionWebSocketAccepter.java @@ -2,13 +2,13 @@ import com.google.gson.Gson; import consulo.annotation.component.ExtensionImpl; -import consulo.application.ReadAction; import consulo.builtinWebServer.webSocket.WebSocketAccepter; import consulo.builtinWebServer.webSocket.WebSocketConnection; import consulo.execution.debug.XDebugSession; import consulo.execution.ui.console.ConsoleViewContentType; +import consulo.javascript.debugger.browser.BrowserCDTDebugProcess; import consulo.javascript.debugger.browser.SessionHolder; -import consulo.javascript.debugger.browser.process.CDTProcess; +import consulo.javascript.debugger.cdt.CDTProcessBase; import jakarta.annotation.Nonnull; import jakarta.inject.Inject; @@ -64,7 +64,7 @@ public void accept(@Nonnull WebSocketConnection conn, @Nonnull String text) { session = mySessionHolder.find(tabId); if (session != null) { - CDTProcess debugProcess = session.getDebugProcess(); + CDTProcessBase debugProcess = session.getDebugProcess(); XDebugSession xDebugSession = debugProcess.getSession(); @@ -94,15 +94,13 @@ public void accept(@Nonnull WebSocketConnection conn, @Nonnull String text) { session = mySessionHolder.find(tabId); if (session != null) { - CDTProcess debugProcess = session.getDebugProcess(); + BrowserCDTDebugProcess debugProcess = session.getDebugProcess(); XDebugSession xDebugSession = debugProcess.getSession(); debugProcess.init(session); xDebugSession.getConsoleView().print("Browser connected\n", ConsoleViewContentType.LOG_INFO_OUTPUT); - - ReadAction.nonBlocking(xDebugSession::initBreakpoints).submitDefault(); } break; diff --git a/debugger/browser-debugger-impl/src/main/java/module-info.java b/debugger/browser-debugger-impl/src/main/java/module-info.java index e402d2f2..2aed0f0e 100644 --- a/debugger/browser-debugger-impl/src/main/java/module-info.java +++ b/debugger/browser-debugger-impl/src/main/java/module-info.java @@ -8,9 +8,8 @@ requires com.google.gson; requires cdt.java.client; - - exports consulo.javascript.debugger.browser; - exports consulo.javascript.debugger.browser.process; - exports consulo.javascript.debugger.browser.transport; - + + requires consulo.javascript.cdt.debugger.impl; + + opens consulo.javascript.debugger.browser to consulo.util.xml.serializer; } \ No newline at end of file diff --git a/debugger/cdt-debugger-impl/pom.xml b/debugger/cdt-debugger-impl/pom.xml new file mode 100644 index 00000000..56c8ba66 --- /dev/null +++ b/debugger/cdt-debugger-impl/pom.xml @@ -0,0 +1,81 @@ + + + + 4.0.0 + + consulo + arch.ide-api-provided + 3-SNAPSHOT + + + + consulo.plugin + consulo.javascript-cdt.debugger.impl + 3-SNAPSHOT + jar + + + + consulo + https://maven.consulo.dev/repository/snapshots/ + + true + interval:60 + + + + + + + ${project.groupId} + consulo.javascript-base.impl + ${project.version} + + + + ${project.groupId} + consulo.javascript-debugger.impl + ${project.version} + + + + ${project.groupId} + com.intellij.xml + ${project.version} + provided + + + + consulo.internal.com.github.kklisura.cdt + cdt-java-client + 4.0.2 + + + org.javassist + javassist + + + + + + com.google.code.gson + gson + provided + + + \ No newline at end of file diff --git a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTBreakpointInfo.java b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTBreakpointInfo.java similarity index 93% rename from debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTBreakpointInfo.java rename to debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTBreakpointInfo.java index 00622390..99759ad1 100644 --- a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTBreakpointInfo.java +++ b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTBreakpointInfo.java @@ -1,4 +1,4 @@ -package consulo.javascript.debugger.browser.process; +package consulo.javascript.debugger.cdt; import com.github.kklisura.cdt.protocol.types.debugger.Location; import consulo.execution.debug.breakpoint.XBreakpoint; diff --git a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTExecutionStack.java b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTExecutionStack.java similarity index 90% rename from debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTExecutionStack.java rename to debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTExecutionStack.java index 72c12aed..1be641d2 100644 --- a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTExecutionStack.java +++ b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTExecutionStack.java @@ -1,4 +1,4 @@ -package consulo.javascript.debugger.browser.process; +package consulo.javascript.debugger.cdt; import com.github.kklisura.cdt.protocol.types.debugger.CallFrame; import consulo.execution.debug.frame.XExecutionStack; @@ -17,7 +17,7 @@ public class CDTExecutionStack extends XExecutionStack { public CDTExecutionStack(String displayName, List callFrames, - CDTProcess process) { + CDTProcessBase process) { super(displayName); myFrames = new ArrayList<>(callFrames.size()); diff --git a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTProcess.java b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTProcessBase.java similarity index 77% rename from debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTProcess.java rename to debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTProcessBase.java index c9760d8b..2c3dbf61 100644 --- a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTProcess.java +++ b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTProcessBase.java @@ -1,10 +1,12 @@ -package consulo.javascript.debugger.browser.process; +package consulo.javascript.debugger.cdt; import com.github.kklisura.cdt.protocol.ChromeDevTools; import com.github.kklisura.cdt.protocol.commands.Debugger; +import com.github.kklisura.cdt.protocol.events.debugger.Paused; import com.github.kklisura.cdt.protocol.types.debugger.Location; import com.github.kklisura.cdt.protocol.types.debugger.SetBreakpointByUrl; import consulo.application.Application; +import consulo.application.ReadAction; import consulo.application.concurrent.ApplicationConcurrency; import consulo.execution.ExecutionResult; import consulo.execution.debug.*; @@ -19,8 +21,6 @@ import consulo.javascript.debugger.JavaScriptEditorsProvider; import consulo.javascript.debugger.JavaScriptLineBreakpointType; import consulo.javascript.debugger.JavaScriptListPanel; -import consulo.javascript.debugger.browser.ChromeDevToolsFactory; -import consulo.javascript.debugger.browser.SessionHolder; import consulo.javascript.icon.JavaScriptIconGroup; import consulo.localize.LocalizeValue; import consulo.process.ExecutionException; @@ -28,22 +28,22 @@ import consulo.ui.ex.content.Content; import consulo.util.io.Url; import consulo.util.io.Urls; -import consulo.virtualFileSystem.VirtualFile; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; +import java.net.SocketException; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; import java.util.function.Consumer; /** * @author VISTALL * @since 2026-02-15 */ -public class CDTProcess extends XDebugProcess { +public abstract class CDTProcessBase extends XDebugProcess { private final ExecutionResult myResult; private CDTScriptHolder myScripts = new CDTScriptHolder(); @@ -54,19 +54,14 @@ public class CDTProcess extends XDebugProcess { private ChromeDevTools myChromeDevTools; - private Executor myExecutor; + private ExecutorService myExecutor; private Map myBreakpoints = new HashMap<>(); - public CDTProcess(@Nonnull XDebugSession session, ExecutionResult result) throws ExecutionException { + public CDTProcessBase(@Nonnull XDebugSession session, ExecutionResult result) throws ExecutionException { super(session); - myScriptListPanel = new JavaScriptListPanel<>(session.getProject()) { - @Nullable - @Override - public VirtualFile toVirtualFile(@Nonnull CDTScript value, boolean toOpen) { - return value.toVirtualFile(); - } - }; + myScriptListPanel = new JavaScriptListPanel<>(); + myExecutor = Application.get().getInstance(ApplicationConcurrency.class).createBoundedScheduledExecutorService("CDTProcess", 1); myResult = result; @@ -74,39 +69,33 @@ public VirtualFile toVirtualFile(@Nonnull CDTScript value, boolean toOpen) { getSession().setPauseActionSupported(true); } - public void init(SessionHolder.BrowserSession session) { - myChromeDevTools = ChromeDevToolsFactory.create(session); + public void initTools(ChromeDevTools devTools) { + myChromeDevTools = devTools; Debugger debugger = myChromeDevTools.getDebugger(); debugger.onScriptParsed(event -> { - CDTScript cdtScript = new CDTScript(event); + CDTScript cdtScript = new CDTScript(getSession().getProject(), event); myScripts.add(cdtScript); getSession().getProject().getUIAccess().execute(() -> myScriptListPanel.add(cdtScript)); }); - debugger.onPaused(event -> { - XBreakpoint breakpoint = null; - List hitBreakpoints = event.getHitBreakpoints(); - if (hitBreakpoints != null) { - for (String hitBreakpoint : hitBreakpoints) { - CDTBreakpointInfo info = myBreakpoints.get(hitBreakpoint); - if (info != null) { - breakpoint = info.getBreakpoint(); - break; - } - } - } + debugger.onPaused(this::onPause); - XDebugSession debugSession = getSession(); - if (breakpoint != null) { - debugSession.breakpointReached(breakpoint, null, new CDTSuspendContext(event, this)); - } - else { - debugSession.positionReached(new CDTSuspendContext(event, this)); - } + devTools.getRuntime().onExecutionContextDestroyed(executionContextDestroyed -> { + getProcessHandler().destroyProcess(); + }); + + initOthers(); + } + + protected void initOthers() { + invoke(devTools -> { + ReadAction.run(() -> getSession().initBreakpoints()); + + devTools.getRuntime().runIfWaitingForDebugger(); }); } @@ -119,7 +108,36 @@ public void invoke(Consumer runnable) { return; } - myExecutor.execute(() -> runnable.accept(myChromeDevTools)); + myExecutor.execute(() -> { + try { + runnable.accept(myChromeDevTools); + } + catch (Exception e) { + e.printStackTrace(); + } + }); + } + + protected void onPause(Paused event) { + XBreakpoint breakpoint = null; + List hitBreakpoints = event.getHitBreakpoints(); + if (hitBreakpoints != null) { + for (String hitBreakpoint : hitBreakpoints) { + CDTBreakpointInfo info = myBreakpoints.get(hitBreakpoint); + if (info != null) { + breakpoint = info.getBreakpoint(); + break; + } + } + } + + XDebugSession debugSession = getSession(); + if (breakpoint != null) { + debugSession.breakpointReached(breakpoint, null, new CDTSuspendContext(event, this)); + } + else { + debugSession.positionReached(new CDTSuspendContext(event, this)); + } } @Nullable @@ -154,10 +172,9 @@ public boolean checkCanInitBreakpoints() { @Override public XBreakpointHandler[] getBreakpointHandlers() { return new XBreakpointHandler[]{ - new XBreakpointHandler>(JavaScriptLineBreakpointType.class) { + new XBreakpointHandler<>(JavaScriptLineBreakpointType.class) { @Override public void registerBreakpoint(@Nonnull final XLineBreakpoint lineBreakpoint) { - String presentableFilePath = lineBreakpoint.getFileUrl(); int line = lineBreakpoint.getLine(); XExpression conditionExpression = lineBreakpoint.getConditionExpression(); String expression = conditionExpression == null ? null : conditionExpression.getExpression(); @@ -216,7 +233,16 @@ public void startStepOut(@Nullable XSuspendContext context) { @Override public void stop() { - // TODO !myVm.detach(); + if (myChromeDevTools instanceof AutoCloseable closeable) { + try { + closeable.close(); + } + catch (Exception ignored) { + } + } + + myExecutor.shutdown(); + myBreakpoints.clear(); Application.get().runReadAction(new Runnable() { diff --git a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTRemoteObjectValue.java b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTRemoteObjectValue.java similarity index 77% rename from debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTRemoteObjectValue.java rename to debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTRemoteObjectValue.java index 4ae49cba..e3256c6a 100644 --- a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTRemoteObjectValue.java +++ b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTRemoteObjectValue.java @@ -1,4 +1,4 @@ -package consulo.javascript.debugger.browser.process; +package consulo.javascript.debugger.cdt; import com.github.kklisura.cdt.protocol.types.runtime.Properties; import com.github.kklisura.cdt.protocol.types.runtime.PropertyDescriptor; @@ -9,6 +9,7 @@ import consulo.execution.debug.icon.ExecutionDebugIconGroup; import consulo.ui.image.Image; import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; import java.util.List; @@ -17,12 +18,12 @@ * @since 2026-02-15 */ public class CDTRemoteObjectValue extends XNamedValue { - @Nonnull + @Nullable private final RemoteObject myRemoteObject; - private final CDTProcess myProcess; + private final CDTProcessBase myProcess; - public CDTRemoteObjectValue(@Nonnull String name, @Nonnull RemoteObject remoteObject, CDTProcess process) { + public CDTRemoteObjectValue(@Nonnull String name, @Nullable RemoteObject remoteObject, CDTProcessBase process) { super(name); myRemoteObject = remoteObject; myProcess = process; @@ -30,13 +31,21 @@ public CDTRemoteObjectValue(@Nonnull String name, @Nonnull RemoteObject remoteOb @Override public void computeChildren(@Nonnull XCompositeNode node) { - if (myRemoteObject.getType() != RemoteObjectType.OBJECT) { + fill(myRemoteObject, node, myProcess); + } + + public static void fill(RemoteObject remoteObject, XCompositeNode node, CDTProcessBase process) { + if (remoteObject == null) { + return; + } + + if (remoteObject.getType() != RemoteObjectType.OBJECT) { node.addChildren(XValueChildrenList.EMPTY, true); return; } - myProcess.invoke(devTools -> { - String objectId = myRemoteObject.getObjectId(); + process.invoke(devTools -> { + String objectId = remoteObject.getObjectId(); Properties properties = devTools.getRuntime().getProperties(objectId); @@ -47,7 +56,7 @@ public void computeChildren(@Nonnull XCompositeNode node) { for (PropertyDescriptor propertyDescriptor : result) { RemoteObject value = propertyDescriptor.getValue(); - list.add(new CDTRemoteObjectValue(propertyDescriptor.getName(), value, myProcess)); + list.add(new CDTRemoteObjectValue(propertyDescriptor.getName(), value, process)); } node.addChildren(list, true); @@ -61,6 +70,11 @@ protected Image getObjectIcon() { @Override public void computePresentation(@Nonnull XValueNode node, @Nonnull XValuePlace place) { + if (myRemoteObject == null) { + node.setPresentation(getObjectIcon(), null, "null", false); + return; + } + if (myRemoteObject.getType() == RemoteObjectType.OBJECT) { node.setPresentation(getObjectIcon(), "", "", true); } diff --git a/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTScopeValue.java b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTScopeValue.java new file mode 100644 index 00000000..788f0658 --- /dev/null +++ b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTScopeValue.java @@ -0,0 +1,42 @@ +package consulo.javascript.debugger.cdt; + +import com.github.kklisura.cdt.protocol.types.debugger.Scope; +import com.github.kklisura.cdt.protocol.types.debugger.ScopeType; +import com.github.kklisura.cdt.protocol.types.runtime.RemoteObject; +import consulo.execution.debug.frame.XCompositeNode; +import consulo.execution.debug.frame.XValueGroup; +import consulo.util.lang.StringUtil; +import jakarta.annotation.Nonnull; + +import java.util.Locale; + +/** + * @author VISTALL + * @since 2026-02-15 + */ +public class CDTScopeValue extends XValueGroup { + @Nonnull + private final Scope myScope; + @Nonnull + private final RemoteObject myRemoteObject; + private final CDTProcessBase myProcess; + + public CDTScopeValue(@Nonnull Scope scope, + @Nonnull RemoteObject remoteObject, + CDTProcessBase process) { + super(StringUtil.capitalize(scope.getType().name().toLowerCase(Locale.ROOT))); + myScope = scope; + myRemoteObject = remoteObject; + myProcess = process; + } + + @Override + public void computeChildren(@Nonnull XCompositeNode node) { + CDTRemoteObjectValue.fill(myRemoteObject, node, myProcess); + } + + @Override + public boolean isAutoExpand() { + return myScope.getType() == ScopeType.LOCAL; + } +} diff --git a/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTScript.java b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTScript.java new file mode 100644 index 00000000..c4c0510e --- /dev/null +++ b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTScript.java @@ -0,0 +1,77 @@ +package consulo.javascript.debugger.cdt; + +import com.github.kklisura.cdt.protocol.events.debugger.ScriptParsed; +import com.github.kklisura.cdt.protocol.types.debugger.ScriptLanguage; +import consulo.javascript.debugger.JavaScriptFileInfo; +import consulo.javascript.icon.JavaScriptIconGroup; +import consulo.language.editor.FileColorManager; +import consulo.navigation.OpenFileDescriptorFactory; +import consulo.project.Project; +import consulo.ui.color.ColorValue; +import consulo.ui.image.Image; +import consulo.virtualFileSystem.VirtualFile; +import consulo.virtualFileSystem.VirtualFileManager; +import consulo.virtualFileSystem.util.VirtualFileUtil; +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; + +/** + * @author VISTALL + * @since 2026-02-15 + */ +public class CDTScript implements JavaScriptFileInfo { + private final String myId; + private final String myUrl; + private final Project myProject; + private final ScriptLanguage myScriptLanguage; + + public CDTScript(Project project, ScriptParsed scriptParsed) { + myProject = project; + myId = scriptParsed.getScriptId(); + myUrl = scriptParsed.getUrl(); + myScriptLanguage = scriptParsed.getScriptLanguage(); + } + + public String getId() { + return myId; + } + + public VirtualFile toVirtualFile() { + return VirtualFileManager.getInstance().findFileByUrl(myUrl); + } + + @Nonnull + @Override + public String getPath() { + return/* myId + ":" +*/ VirtualFileUtil.urlToPath(myUrl); + } + + @Nonnull + @Override + public Image getIcon() { + return switch (myScriptLanguage) { + case JAVA_SCRIPT -> JavaScriptIconGroup.javascript(); + case WEB_ASSEMBLY -> + // TODO web assembly icon + JavaScriptIconGroup.javascript(); + }; + } + + @Nullable + @Override + public ColorValue getFileStatusColor() { + VirtualFile virtualFile = toVirtualFile(); + if (virtualFile != null) { + return FileColorManager.getInstance(myProject).getFileColorValue(virtualFile); + } + return null; + } + + @Override + public void navigate(boolean focus) { + VirtualFile file = toVirtualFile(); + if (file != null) { + OpenFileDescriptorFactory.getInstance(myProject).newBuilder(file).build().navigate(focus); + } + } +} diff --git a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTScriptHolder.java b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTScriptHolder.java similarity index 91% rename from debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTScriptHolder.java rename to debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTScriptHolder.java index db20c752..2dbe5154 100644 --- a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTScriptHolder.java +++ b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTScriptHolder.java @@ -1,4 +1,4 @@ -package consulo.javascript.debugger.browser.process; +package consulo.javascript.debugger.cdt; import consulo.util.collection.Lists; diff --git a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTStackFrame.java b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTStackFrame.java similarity index 55% rename from debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTStackFrame.java rename to debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTStackFrame.java index 23f9a67d..fef896b3 100644 --- a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTStackFrame.java +++ b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTStackFrame.java @@ -1,4 +1,4 @@ -package consulo.javascript.debugger.browser.process; +package consulo.javascript.debugger.cdt; import com.github.kklisura.cdt.protocol.types.debugger.CallFrame; import com.github.kklisura.cdt.protocol.types.debugger.Location; @@ -11,6 +11,8 @@ import consulo.execution.debug.frame.XCompositeNode; import consulo.execution.debug.frame.XStackFrame; import consulo.execution.debug.frame.XValueChildrenList; +import consulo.ui.ex.ColoredTextContainer; +import consulo.ui.ex.SimpleTextAttributes; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -22,28 +24,36 @@ */ public class CDTStackFrame extends XStackFrame { private final CallFrame myCallFrame; - private final CDTProcess myProcess; + private final CDTProcessBase myProcess; private XSourcePosition mySourcePosition; - public CDTStackFrame(CallFrame callFrame, CDTProcess process) { + private final Location myLocation; + private final CDTScript myScript; + private final String myScriptId; + + public CDTStackFrame(CallFrame callFrame, CDTProcessBase process) { myCallFrame = callFrame; myProcess = process; - Location location = callFrame.getLocation(); + myLocation = callFrame.getLocation(); - if (location != null) { - String scriptId = location.getScriptId(); + if (myLocation != null) { + myScriptId = myLocation.getScriptId(); + myScript = process.getScripts().find(myScriptId); - CDTScript script = process.getScripts().find(scriptId); - if (script != null) { + if (myScript != null) { mySourcePosition = Application.get().getInstance(XSourcePositionFactory.class).createPosition( - script.toVirtualFile(), - location.getLineNumber(), - location.getColumnNumber() + myScript.toVirtualFile(), + myLocation.getLineNumber(), + myLocation.getColumnNumber() ); } } + else { + myScript = null; + myScriptId = null; + } } @Nullable @@ -58,6 +68,22 @@ public Object getEqualityObject() { return myCallFrame.getCallFrameId(); } + @Override + public void customizePresentation(ColoredTextContainer component) { + XSourcePosition position = getSourcePosition(); + if (position != null) { + component.append(position.getFile().getName(), SimpleTextAttributes.REGULAR_ATTRIBUTES); + component.append(":" + (position.getLine() + 1), SimpleTextAttributes.REGULAR_ATTRIBUTES); + } + else if (myScript != null) { + component.append(myScript.getPath(), SimpleTextAttributes.REGULAR_ATTRIBUTES); + component.append(":" + (myLocation.getLineNumber() + 1), SimpleTextAttributes.REGULAR_ATTRIBUTES); + } + else { + component.append(myScriptId, SimpleTextAttributes.REGULAR_ATTRIBUTES); + } + } + @Override public void computeChildren(@Nonnull XCompositeNode node) { myProcess.invoke(devTools -> { @@ -74,7 +100,7 @@ public void computeChildren(@Nonnull XCompositeNode node) { continue; } - list.add(new CDTScopeValue(scope, object, myProcess)); + list.addTopGroup(new CDTScopeValue(scope, object, myProcess)); } node.addChildren(list, true); diff --git a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTSuspendContext.java b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTSuspendContext.java similarity index 85% rename from debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTSuspendContext.java rename to debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTSuspendContext.java index b1d2b475..e5068a90 100644 --- a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/process/CDTSuspendContext.java +++ b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/CDTSuspendContext.java @@ -1,4 +1,4 @@ -package consulo.javascript.debugger.browser.process; +package consulo.javascript.debugger.cdt; import com.github.kklisura.cdt.protocol.events.debugger.Paused; import consulo.execution.debug.frame.XExecutionStack; @@ -12,7 +12,7 @@ public class CDTSuspendContext extends XSuspendContext { private CDTExecutionStack myStack; - public CDTSuspendContext(Paused event, CDTProcess process) { + public CDTSuspendContext(Paused event, CDTProcessBase process) { myStack = new CDTExecutionStack("", event.getCallFrames(), process); } diff --git a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/ChromeDevToolsFactory.java b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/ChromeDevToolsFactory.java similarity index 73% rename from debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/ChromeDevToolsFactory.java rename to debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/ChromeDevToolsFactory.java index 687efbfb..3a21046a 100644 --- a/debugger/browser-debugger-impl/src/main/java/consulo/javascript/debugger/browser/ChromeDevToolsFactory.java +++ b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/ChromeDevToolsFactory.java @@ -1,7 +1,8 @@ -package consulo.javascript.debugger.browser; +package consulo.javascript.debugger.cdt; import com.github.kklisura.cdt.services.WebSocketService; import com.github.kklisura.cdt.services.config.ChromeDevToolsServiceConfiguration; +import com.github.kklisura.cdt.services.executors.EventExecutorService; import com.github.kklisura.cdt.services.impl.ChromeDevToolsServiceImpl; import com.github.kklisura.cdt.services.invocation.CommandInvocationHandler; import com.github.kklisura.cdt.services.utils.ProxyUtils; @@ -16,10 +17,23 @@ * @since 2026-02-15 */ public class ChromeDevToolsFactory { - public static ChromeDevToolsServiceImpl create(SessionHolder.BrowserSession browserSession) { + public static ChromeDevToolsServiceImpl create(WebSocketService webSocketService) { ChromeDevToolsServiceConfiguration conf = new ChromeDevToolsServiceConfiguration(); + conf.setEventExecutorService(new EventExecutorService() { + @Override + public void execute(Runnable runnable) { + runnable.run(); + } - WebSocketService webSocketService = new ProxyWebSocketService(browserSession); + @Override + public void shutdown() { + + } + }); + + if (Boolean.FALSE) { + webSocketService = new LoggingWebSocketService(webSocketService); + } // Create invocation handler CommandInvocationHandler commandInvocationHandler = new CommandInvocationHandler(); diff --git a/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/LoggingWebSocketService.java b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/LoggingWebSocketService.java new file mode 100644 index 00000000..c6786585 --- /dev/null +++ b/debugger/cdt-debugger-impl/src/main/java/consulo/javascript/debugger/cdt/LoggingWebSocketService.java @@ -0,0 +1,48 @@ +package consulo.javascript.debugger.cdt; + +import com.github.kklisura.cdt.services.WebSocketService; +import com.github.kklisura.cdt.services.exceptions.WebSocketServiceException; + +import java.net.URI; +import java.util.function.Consumer; + +/** + * @author VISTALL + * @since 2026-02-16 + */ +public class LoggingWebSocketService implements WebSocketService { + private final WebSocketService myDelegate; + + public LoggingWebSocketService(WebSocketService delegate) { + myDelegate = delegate; + } + + @Override + public void connect(URI uri) throws WebSocketServiceException { + myDelegate.connect(uri); + } + + @Override + public void send(String s) throws WebSocketServiceException { + System.out.println("send " + s); + myDelegate.send(s); + } + + @Override + public void addMessageHandler(Consumer consumer) throws WebSocketServiceException { + myDelegate.addMessageHandler(s -> { + System.out.println("rec: " + s); + consumer.accept(s); + }); + } + + @Override + public void close() { + myDelegate.close(); + } + + @Override + public boolean closed() { + return myDelegate.closed(); + } +} diff --git a/debugger/cdt-debugger-impl/src/main/java/module-info.java b/debugger/cdt-debugger-impl/src/main/java/module-info.java new file mode 100644 index 00000000..bcb862d6 --- /dev/null +++ b/debugger/cdt-debugger-impl/src/main/java/module-info.java @@ -0,0 +1,13 @@ +/** + * @author VISTALL + * @since 2026-02-15 + */ +module consulo.javascript.cdt.debugger.impl { + requires consulo.javascript.debugger.impl; + + requires com.google.gson; + + requires cdt.java.client; + + exports consulo.javascript.debugger.cdt; +} \ No newline at end of file diff --git a/debugger/debugger-impl/src/main/java/consulo/javascript/debugger/JavaScriptFileInfo.java b/debugger/debugger-impl/src/main/java/consulo/javascript/debugger/JavaScriptFileInfo.java new file mode 100644 index 00000000..beb65238 --- /dev/null +++ b/debugger/debugger-impl/src/main/java/consulo/javascript/debugger/JavaScriptFileInfo.java @@ -0,0 +1,22 @@ +package consulo.javascript.debugger; + +import consulo.navigation.Navigatable; +import consulo.ui.color.ColorValue; +import consulo.ui.image.Image; +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; + +/** + * @author VISTALL + * @since 2026-02-16 + */ +public interface JavaScriptFileInfo extends Navigatable { + @Nonnull + String getPath(); + + @Nonnull + Image getIcon(); + + @Nullable + ColorValue getFileStatusColor(); +} diff --git a/debugger/debugger-impl/src/main/java/consulo/javascript/debugger/JavaScriptListPanel.java b/debugger/debugger-impl/src/main/java/consulo/javascript/debugger/JavaScriptListPanel.java index b838e732..7ce337f2 100644 --- a/debugger/debugger-impl/src/main/java/consulo/javascript/debugger/JavaScriptListPanel.java +++ b/debugger/debugger-impl/src/main/java/consulo/javascript/debugger/JavaScriptListPanel.java @@ -16,17 +16,15 @@ package consulo.javascript.debugger; -import consulo.language.editor.FileColorManager; -import consulo.navigation.OpenFileDescriptorFactory; -import consulo.project.Project; +import consulo.ui.annotation.RequiredUIAccess; +import consulo.ui.color.ColorValue; import consulo.ui.ex.awt.ColoredListCellRenderer; import consulo.ui.ex.awt.JBList; import consulo.ui.ex.awt.JBScrollPane; import consulo.ui.ex.awt.SortedListModel; +import consulo.ui.ex.awtUnsafe.TargetAWT; import consulo.util.io.FileUtil; -import consulo.virtualFileSystem.VirtualFile; import jakarta.annotation.Nonnull; -import jakarta.annotation.Nullable; import javax.swing.*; import java.awt.*; @@ -38,67 +36,52 @@ * @author VISTALL * @since 21.03.14 */ -public abstract class JavaScriptListPanel extends JPanel { - @Nonnull - private final Project myProject; - private SortedListModel myModel = SortedListModel.create(new Comparator() { - @Override - public int compare(T o1, T o2) { - VirtualFile v1 = toVirtualFile(o1, false); - VirtualFile v2 = toVirtualFile(o2, false); - if (v1 == null || v2 == null) { - return -1; - } - return FileUtil.comparePaths(v1.getPath(), v2.getPath()); - } - }); +public class JavaScriptListPanel extends JPanel { + private SortedListModel myModel = SortedListModel.create((Comparator) (o1, o2) -> FileUtil.comparePaths(o1.getPath(), o2.getPath())); - public JavaScriptListPanel(@Nonnull Project project) { + public JavaScriptListPanel() { super(new BorderLayout()); init(); - myProject = project; } private void init() { - final JBList jbList = new JBList<>(myModel); - jbList.setCellRenderer(new ColoredListCellRenderer() { + final JBList list = new JBList<>(myModel); + list.setCellRenderer(new ColoredListCellRenderer() { @Override - protected void customizeCellRenderer(@Nonnull JList jList, T t, int i, boolean b, boolean b1) { - VirtualFile virtualFile = toVirtualFile(t, false); - if (virtualFile == null) { - append(""); - } - else { - setBackground(FileColorManager.getInstance(myProject).getFileColor(virtualFile)); - append(virtualFile.getPath()); - setIcon(virtualFile.getFileType().getIcon()); + protected void customizeCellRenderer(@Nonnull JList list, T value, int index, boolean selected, boolean hasFocus) { + append(value.getPath()); + + setIcon(value.getIcon()); + + if (!selected) { + ColorValue fileStatusColor = value.getFileStatusColor(); + if (fileStatusColor != null) { + setBackground(TargetAWT.to(fileStatusColor)); + } } } }); - jbList.addMouseListener(new MouseAdapter() { + + list.addMouseListener(new MouseAdapter() { @Override + @RequiredUIAccess public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1) { - T selectedValue = jbList.getSelectedValue(); + T selectedValue = list.getSelectedValue(); if (selectedValue == null) { return; } - VirtualFile virtualFile = toVirtualFile(selectedValue, true); - - if (virtualFile != null) { - OpenFileDescriptorFactory.getInstance(myProject).builder(virtualFile).build().navigate(true); + if (selectedValue.canNavigate()) { + selectedValue.navigate(true); } } } }); - add(new JBScrollPane(jbList), BorderLayout.CENTER); + add(new JBScrollPane(list), BorderLayout.CENTER); } - @Nullable - public abstract VirtualFile toVirtualFile(@Nonnull T value, boolean toOpen); - public void add(T value) { myModel.add(value); } diff --git a/plugin/pom.xml b/plugin/pom.xml index 6fbd31e2..74fc1fb3 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -142,12 +142,6 @@ ${project.version} - - com.googlecode.json-simple - json-simple - 1.1.1 - - ${project.groupId} consulo.javascript-debugger.impl @@ -156,26 +150,26 @@ ${project.groupId} - consulo.javascript-v8.debugger.impl + consulo.javascript-regexp.impl ${project.version} ${project.groupId} - consulo.javascript-regexp.impl + consulo.javascript-browser.debugger.impl ${project.version} ${project.groupId} - consulo.javascript-browser.debugger.impl + consulo.javascript-cdt.debugger.impl ${project.version} - com.github.kklisura.cdt + consulo.internal.com.github.kklisura.cdt cdt-java-client - 2.1.0 + 4.0.2 org.javassist diff --git a/pom.xml b/pom.xml index 73d0ef45..bf86e0aa 100644 --- a/pom.xml +++ b/pom.xml @@ -49,8 +49,8 @@ web-browser-impl debugger/debugger-impl - debugger/v8-debugger-impl debugger/browser-debugger-impl + debugger/cdt-debugger-impl lang-version-impl/javascript16-impl lang-version-impl/javascript17-impl lang-version-impl/javascript18-impl