[Lldb-commits] [lldb] [lldb-dap ext] truncate lldb-dap server restart dialog (PR #181441)

Tom Yang via lldb-commits lldb-commits at lists.llvm.org
Thu Apr 30 12:59:40 PDT 2026


https://github.com/zhyty updated https://github.com/llvm/llvm-project/pull/181441

>From a13fa1f5c673e9a6bbd45e93638df13ea819c160 Mon Sep 17 00:00:00 2001
From: Tom Yang <toyang at fb.com>
Date: Wed, 11 Feb 2026 11:35:03 -0800
Subject: [PATCH 1/3] [lldb-dap ext] truncate lldb-dap spawn info display

Summary:

Test Plan:

Reviewers:

Subscribers:

Tasks:

Tags:
---
 .../lldb-dap/extension/src/lldb-dap-server.ts | 124 +++++++++++++++---
 1 file changed, 103 insertions(+), 21 deletions(-)

diff --git a/lldb/tools/lldb-dap/extension/src/lldb-dap-server.ts b/lldb/tools/lldb-dap/extension/src/lldb-dap-server.ts
index deacdea145a41..05f3b43e808c4 100644
--- a/lldb/tools/lldb-dap/extension/src/lldb-dap-server.ts
+++ b/lldb/tools/lldb-dap/extension/src/lldb-dap-server.ts
@@ -3,6 +3,77 @@ import * as child_process from "node:child_process";
 import { isDeepStrictEqual } from "util";
 import * as vscode from "vscode";
 
+/**
+ * The information needed to spawn a lldb-dap process: e.g. arguments, binary
+ * path, etc.
+ */
+class ServerSpawnInfo {
+  constructor(
+    readonly path: string,
+    readonly args: string[],
+    readonly env: { [key: string]: string },
+  ) {}
+
+  static create(
+    path: string,
+    args: string[],
+    env: NodeJS.ProcessEnv | { [key: string]: string } | undefined,
+  ): ServerSpawnInfo {
+    // Convert env to a plain object for later comparison. We filter out
+    // `LLDBDAP_LOG` because we ignore it when considering reusing lldb-dap
+    // server.
+    const normalizedEnv: { [key: string]: string } = {};
+    for (const [key, value] of Object.entries(env ?? {})) {
+      if (key !== "LLDBDAP_LOG") {
+        normalizedEnv[key] = String(value);
+      }
+    }
+    return new ServerSpawnInfo(path, args, normalizedEnv);
+  }
+
+  /**
+   * Compares this spawn info with another for equality.
+   */
+  equals(other: ServerSpawnInfo): boolean {
+    return isDeepStrictEqual(
+      [this.path, this.args, this.env],
+      [other.path, other.args, other.env],
+    );
+  }
+
+  /**
+   * Returns a human-readable string representation of this spawn info.
+   */
+  toDisplay(): string {
+    const cmd = [this.path, ...this.args];
+
+    const env = Object.entries(this.env)
+      .map(([k, v]) => `${k}=${v}`)
+      // Sort to make it easier to compare. Sorting isn't necessary for the
+      // `isDeepStrictEqual` check.
+      .sort()
+      .join("\n");
+
+    let display = cmd.join(" ");
+    if (env) {
+      display += `\n${env}`;
+    }
+
+    return display;
+  }
+
+  /**
+   * Returns a truncated representation of `toDisplay`.
+   */
+  toDisplayTruncated(maxLength: number = 300): string {
+    const full = this.toDisplay();
+    if (full.length <= maxLength) {
+      return full;
+    }
+    return full.substring(0, maxLength) + "...";
+  }
+}
+
 /**
  * Represents a running lldb-dap process that is accepting connections (i.e. in "server mode").
  *
@@ -12,7 +83,7 @@ import * as vscode from "vscode";
 export class LLDBDapServer implements vscode.Disposable {
   private serverProcess?: child_process.ChildProcessWithoutNullStreams;
   private serverInfo?: Promise<{ host: string; port: number }>;
-  private serverSpawnInfo?: string[];
+  private serverSpawnInfo?: ServerSpawnInfo;
   // Detects changes to the lldb-dap executable file since the server's startup.
   private serverFileWatcher?: FSWatcher;
   // Indicates whether the lldb-dap executable file has changed since the server's startup.
@@ -87,7 +158,7 @@ export class LLDBDapServer implements vscode.Disposable {
         }
       });
       this.serverProcess = process;
-      this.serverSpawnInfo = this.getSpawnInfo(dapPath, dapArgs, options?.env);
+      this.serverSpawnInfo = ServerSpawnInfo.create(dapPath, dapArgs, options?.env);
       this.serverFileChanged = false;
       this.serverFileWatcher = chokidarWatch(dapPath);
       this.serverFileWatcher
@@ -127,17 +198,17 @@ export class LLDBDapServer implements vscode.Disposable {
       changeTLDR.push("an old binary");
     }
 
-    const newSpawnInfo = this.getSpawnInfo(dapPath, args, env);
-    if (!isDeepStrictEqual(this.serverSpawnInfo, newSpawnInfo)) {
+    const newSpawnInfo = ServerSpawnInfo.create(dapPath, args, env);
+    if (!this.serverSpawnInfo.equals(newSpawnInfo)) {
       changeTLDR.push("different arguments");
       changeDetails.push(`
 The previous lldb-dap server was started with:
 
-${this.serverSpawnInfo.join(" ")}
+${this.serverSpawnInfo.toDisplayTruncated()}
 
 The new lldb-dap server will be started with:
 
-${newSpawnInfo.join(" ")}
+${newSpawnInfo.toDisplayTruncated()}
 `);
     }
 
@@ -157,6 +228,7 @@ Restarting the server will interrupt any existing debug sessions and start a new
       },
       "Restart",
       "Use Existing",
+      "Show Full Details",
     );
     switch (userInput) {
       case "Restart":
@@ -164,6 +236,9 @@ Restarting the server will interrupt any existing debug sessions and start a new
         return true;
       case "Use Existing":
         return true;
+      case "Show Full Details":
+        await this.showFullSpawnInfoComparison(this.serverSpawnInfo, newSpawnInfo);
+        return false;
       case undefined:
         return false;
     }
@@ -191,20 +266,27 @@ Restarting the server will interrupt any existing debug sessions and start a new
     }
   }
 
-  getSpawnInfo(
-    path: string,
-    args: string[],
-    env: NodeJS.ProcessEnv | { [key: string]: string } | undefined,
-  ): string[] {
-    return [
-      path,
-      ...args,
-      ...Object.entries(env ?? {})
-        // Filter and sort to avoid restarting the server just because the
-        // order of env changed or the log path changed.
-        .filter((entry) => String(entry[0]) !== "LLDBDAP_LOG")
-        .sort()
-        .map((entry) => String(entry[0]) + "=" + String(entry[1])),
-    ];
+  private async showFullSpawnInfoComparison(
+    oldSpawnInfo: ServerSpawnInfo,
+    newSpawnInfo: ServerSpawnInfo,
+  ): Promise<void> {
+    const content = `Comparing lldb-dap env and args
+===============================
+Each section contains the binary and args on the first line, and then env on the
+following lines.
+
+Existing
+--------
+${oldSpawnInfo.toDisplay()}
+
+New
+--------
+${newSpawnInfo.toDisplay()}
+`;
+    const doc = await vscode.workspace.openTextDocument({
+      content,
+      language: "text",
+    });
+    await vscode.window.showTextDocument(doc, { preview: true });
   }
 }

>From 6a3bf1eda6656021d8e7b57e3dfd7da6820f30cc Mon Sep 17 00:00:00 2001
From: Tom Yang <toyang at fb.com>
Date: Fri, 13 Feb 2026 15:59:43 -0800
Subject: [PATCH 2/3] join env with space character instead of newline

---
 lldb/tools/lldb-dap/extension/src/lldb-dap-server.ts | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/lldb/tools/lldb-dap/extension/src/lldb-dap-server.ts b/lldb/tools/lldb-dap/extension/src/lldb-dap-server.ts
index 05f3b43e808c4..b7a59e93e5d9e 100644
--- a/lldb/tools/lldb-dap/extension/src/lldb-dap-server.ts
+++ b/lldb/tools/lldb-dap/extension/src/lldb-dap-server.ts
@@ -52,7 +52,9 @@ class ServerSpawnInfo {
       // Sort to make it easier to compare. Sorting isn't necessary for the
       // `isDeepStrictEqual` check.
       .sort()
-      .join("\n");
+      // Joining with newlines makes it difficult to truncate by string length,
+      // so we opt for space.
+      .join(" ");
 
     let display = cmd.join(" ");
     if (env) {

>From 99b9d9d3d289be4b2877f0ebba36f9d1b859705a Mon Sep 17 00:00:00 2001
From: Tom Yang <toyang at meta.com>
Date: Thu, 30 Apr 2026 12:49:28 -0700
Subject: [PATCH 3/3] Remove preview in dialog completely, point users to "Show
 Full Details" button

---
 .../lldb-dap/extension/src/lldb-dap-server.ts | 28 ++++---------------
 1 file changed, 5 insertions(+), 23 deletions(-)

diff --git a/lldb/tools/lldb-dap/extension/src/lldb-dap-server.ts b/lldb/tools/lldb-dap/extension/src/lldb-dap-server.ts
index b7a59e93e5d9e..14bf0dc07f6cb 100644
--- a/lldb/tools/lldb-dap/extension/src/lldb-dap-server.ts
+++ b/lldb/tools/lldb-dap/extension/src/lldb-dap-server.ts
@@ -64,16 +64,6 @@ class ServerSpawnInfo {
     return display;
   }
 
-  /**
-   * Returns a truncated representation of `toDisplay`.
-   */
-  toDisplayTruncated(maxLength: number = 300): string {
-    const full = this.toDisplay();
-    if (full.length <= maxLength) {
-      return full;
-    }
-    return full.substring(0, maxLength) + "...";
-  }
 }
 
 /**
@@ -194,7 +184,6 @@ export class LLDBDapServer implements vscode.Disposable {
     }
 
     const changeTLDR = [];
-    const changeDetails = [];
 
     if (this.serverFileChanged) {
       changeTLDR.push("an old binary");
@@ -202,16 +191,7 @@ export class LLDBDapServer implements vscode.Disposable {
 
     const newSpawnInfo = ServerSpawnInfo.create(dapPath, args, env);
     if (!this.serverSpawnInfo.equals(newSpawnInfo)) {
-      changeTLDR.push("different arguments");
-      changeDetails.push(`
-The previous lldb-dap server was started with:
-
-${this.serverSpawnInfo.toDisplayTruncated()}
-
-The new lldb-dap server will be started with:
-
-${newSpawnInfo.toDisplayTruncated()}
-`);
+      changeTLDR.push("different configuration (args, env)");
     }
 
     // If the server hasn't changed, continue startup without killing it.
@@ -225,8 +205,10 @@ ${newSpawnInfo.toDisplayTruncated()}
       {
         modal: true,
         detail: `An existing lldb-dap server (${this.serverProcess.pid}) is running with ${changeTLDR.map((s) => `*${s}*`).join(" and ")}.
-${changeDetails.join("\n")}
-Restarting the server will interrupt any existing debug sessions and start a new server.`,
+
+Restarting the server will interrupt any existing debug sessions and start a new server.
+
+Click "Show Full Details" to see the differences between the existing and new server configuration.`,
       },
       "Restart",
       "Use Existing",



More information about the lldb-commits mailing list