1818import com .laytonsmith .core .environments .RuntimeMode ;
1919import com .laytonsmith .core .environments .StaticRuntimeEnv ;
2020import com .laytonsmith .core .exceptions .StackTraceFrame ;
21+ import com .laytonsmith .core .constructs .CArray ;
2122import com .laytonsmith .core .natives .interfaces .Mixed ;
2223import com .laytonsmith .core .environments .Breakpoint ;
2324import org .eclipse .lsp4j .debug .Capabilities ;
@@ -111,6 +112,7 @@ public class MSDebugServer implements IDebugProtocolServer {
111112 public static final int DEFAULT_PORT = 6732 ;
112113
113114 private static final int LOCALS_REF = 1 ;
115+ private static final int COMPOUND_REF_START = 100 ;
114116
115117 /** Default bind address for the DAP TCP listener. */
116118 public static final String DEFAULT_BIND_ADDRESS = "127.0.0.1" ;
@@ -137,6 +139,8 @@ public class MSDebugServer implements IDebugProtocolServer {
137139 private DebugSecurity securityMode = DebugSecurity .KEYPAIR ;
138140 private DebugAuthenticator authenticator ;
139141 private SSLContext sslContext ;
142+ private final ConcurrentHashMap <Integer , Mixed > compoundVariableRefs = new ConcurrentHashMap <>();
143+ private int nextCompoundRef = COMPOUND_REF_START ;
140144
141145 /**
142146 * Starts a DAP TCP listener on the given port with an explicit threading mode.
@@ -593,7 +597,10 @@ public CompletableFuture<Void> configurationDone(ConfigurationDoneArguments args
593597 @ Override
594598 public CompletableFuture <Void > disconnect (DisconnectArguments args ) {
595599 if (debugCtx != null ) {
596- if (suspendOnStart && !scriptCompleted ) {
600+ if (managedExecution ) {
601+ // Embedded mode: the server stays alive for reconnection.
602+ // Don't mark as disconnected, just release any paused threads.
603+ } else if (suspendOnStart && !scriptCompleted ) {
597604 // Suspend mode: pause execution until a new debugger connects.
598605 // awaitReconnect() releases paused threads so they can block
599606 // in shouldPause() on the reconnect monitor.
@@ -866,27 +873,57 @@ public CompletableFuture<ScopesResponse> scopes(ScopesArguments args) {
866873 public CompletableFuture <VariablesResponse > variables (VariablesArguments args ) {
867874 VariablesResponse response = new VariablesResponse ();
868875 PausedState inspected = lastInspectedState ;
869- if (inspected == null || args .getVariablesReference () != LOCALS_REF ) {
876+ int ref = args .getVariablesReference ();
877+
878+ if (inspected == null ) {
870879 response .setVariables (new Variable [0 ]);
871880 return CompletableFuture .completedFuture (response );
872881 }
873882
874- Map <String , Mixed > vars = inspected .getVariables ();
875- List <Variable > result = new ArrayList <>();
876883 Environment stateEnv = inspected .getEnvironment ();
877- for (Map .Entry <String , Mixed > entry : vars .entrySet ()) {
878- Variable v = new Variable ();
879- v .setName (entry .getKey ());
880- v .setValue (entry .getValue ().val ());
881- v .setType (entry .getValue ().typeof (stateEnv ).val ());
882- v .setVariablesReference (0 );
883- result .add (v );
884+ List <Variable > result = new ArrayList <>();
885+
886+ if (ref == LOCALS_REF ) {
887+ compoundVariableRefs .clear ();
888+ nextCompoundRef = COMPOUND_REF_START ;
889+ Map <String , Mixed > vars = inspected .getVariables ();
890+ for (Map .Entry <String , Mixed > entry : vars .entrySet ()) {
891+ result .add (buildVariable (entry .getKey (), entry .getValue (), stateEnv ));
892+ }
893+ } else if (compoundVariableRefs .containsKey (ref )) {
894+ Mixed compound = compoundVariableRefs .get (ref );
895+ if (compound instanceof CArray arr ) {
896+ for (Mixed key : arr .keySet ()) {
897+ Mixed value = arr .get (key , Target .UNKNOWN );
898+ result .add (buildVariable (key .val (), value , stateEnv ));
899+ }
900+ }
884901 }
885902
886903 response .setVariables (result .toArray (new Variable [0 ]));
887904 return CompletableFuture .completedFuture (response );
888905 }
889906
907+ private Variable buildVariable (String name , Mixed value , Environment stateEnv ) {
908+ Variable v = new Variable ();
909+ v .setName (name );
910+ v .setType (value .typeof (stateEnv ).val ());
911+ if (value instanceof CArray arr ) {
912+ int refId = nextCompoundRef ++;
913+ compoundVariableRefs .put (refId , value );
914+ v .setVariablesReference (refId );
915+ if (arr .inAssociativeMode ()) {
916+ v .setValue ("array (associative, length: " + arr .size (stateEnv ) + ")" );
917+ } else {
918+ v .setValue ("array (length: " + arr .size (stateEnv ) + ")" );
919+ }
920+ } else {
921+ v .setVariablesReference (0 );
922+ v .setValue (value .val ());
923+ }
924+ return v ;
925+ }
926+
890927 @ Override
891928 public CompletableFuture <EvaluateResponse > evaluate (EvaluateArguments args ) {
892929 EvaluateResponse response = new EvaluateResponse ();
0 commit comments