From 128d38648cc262beb877899df6b452b581b871ae Mon Sep 17 00:00:00 2001
From: Adam Fowler <adamfowler71@gmail.com>
Date: Thu, 16 Mar 2023 17:23:16 +0000
Subject: [PATCH 1/4] Remove hard dependency with CodeLLDB

---
 package.json            |  5 +----
 src/WorkspaceContext.ts | 18 +++++++++++++++-
 src/debugger/lldb.ts    | 48 +++++++++++++++++++++++++++++++++++++++++
 src/extension.ts        |  2 +-
 4 files changed, 67 insertions(+), 6 deletions(-)

diff --git a/package.json b/package.json
index 8369697a0..589b8e6bc 100644
--- a/package.json
+++ b/package.json
@@ -567,9 +567,6 @@
       ]
     }
   },
-  "extensionDependencies": [
-    "vadimcn.vscode-lldb"
-  ],
   "scripts": {
     "vscode:prepublish": "npm run esbuild-base -- --minify",
     "esbuild-base": "esbuild ./src/extension.ts --bundle --outfile=dist/extension.js --external:vscode --format=cjs --platform=node --target=node16",
@@ -608,4 +605,4 @@
     "@types/lcov-parse": "1.0.0",
     "lcov-parse": "1.0.0"
   }
-}
\ No newline at end of file
+}
diff --git a/src/WorkspaceContext.ts b/src/WorkspaceContext.ts
index 6ab270309..6c5599dc0 100644
--- a/src/WorkspaceContext.ts
+++ b/src/WorkspaceContext.ts
@@ -23,7 +23,7 @@ import {
     swiftLibraryPathKey,
     getErrorDescription,
 } from "./utilities/utilities";
-import { getLLDBLibPath } from "./debugger/lldb";
+import { checkLLDBInstalled, getLLDBLibPath } from "./debugger/lldb";
 import { LanguageClientManager } from "./sourcekit-lsp/LanguageClientManager";
 import { TemporaryFolder } from "./utilities/tempFolder";
 import { SwiftToolchain } from "./toolchain/toolchain";
@@ -350,6 +350,22 @@ export class WorkspaceContext implements vscode.Disposable {
         return { dispose: () => this.observers.delete(fn) };
     }
 
+    async setupLLDB() {
+        await checkLLDBInstalled().then(
+            async result => {
+                if (result) {
+                    this.setLLDBVersion();
+                }
+            },
+            error => {
+                const errorMessage = `Error: ${getErrorDescription(error)}`;
+                vscode.window.showErrorMessage(
+                    `Failed to setup CodeLLDB for debugging of Swift code. Debugging may produce unexpected results. ${errorMessage}`
+                );
+            }
+        );
+    }
+
     /** find LLDB version and setup path in CodeLLDB */
     async setLLDBVersion() {
         const libPathResult = await getLLDBLibPath(this.toolchain);
diff --git a/src/debugger/lldb.ts b/src/debugger/lldb.ts
index 78ac826db..29629ad0a 100644
--- a/src/debugger/lldb.ts
+++ b/src/debugger/lldb.ts
@@ -15,12 +15,60 @@
 // Based on code taken from CodeLLDB https://github.com/vadimcn/vscode-lldb/
 // LICENSED with MIT License
 
+import * as vscode from "vscode";
 import * as path from "path";
 import * as fs from "fs/promises";
 import { execFile } from "../utilities/utilities";
 import { Result } from "../utilities/result";
 import { SwiftToolchain } from "../toolchain/toolchain";
 
+/**
+ * Check if CodeLLDB extension is installed and offer to install it if it is not.
+ * @returns Whether extension was installed
+ */
+export async function checkLLDBInstalled(): Promise<boolean> {
+    const lldbExtension = vscode.extensions.getExtension("vadimcn.vscode-lldb");
+    // if extension is in list return true
+    if (lldbExtension) {
+        return true;
+    }
+
+    // otherwise display menu asking if user wants to install it
+    return new Promise<boolean>((resolve, reject) => {
+        vscode.window
+            .showWarningMessage(
+                "The Swift extension requires the CodeLLDB extension to enable debugging. Do you want to install it?",
+                "Yes",
+                "No"
+            )
+            .then(async result => {
+                switch (result) {
+                    case "Yes":
+                        try {
+                            await installCodeLLDB();
+                            return resolve(true);
+                        } catch (error) {
+                            return reject(error);
+                        }
+                        break;
+                    case "No":
+                        break;
+                }
+                return resolve(false);
+            });
+    });
+}
+
+/**
+ * Install CodeLLDB extension
+ */
+async function installCodeLLDB() {
+    await vscode.commands.executeCommand(
+        "workbench.extensions.installExtension",
+        "vadimcn.vscode-lldb"
+    );
+}
+
 /**
  * Get LLDB library for given LLDB executable
  * @param executable LLDB executable
diff --git a/src/extension.ts b/src/extension.ts
index 54832cf45..d7352df9a 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -46,7 +46,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<Api> {
         context.subscriptions.push(workspaceContext);
 
         // setup swift version of LLDB. Don't await on this as it can run in the background
-        workspaceContext.setLLDBVersion();
+        workspaceContext.setupLLDB();
 
         // listen for workspace folder changes and active text editor changes
         workspaceContext.setupEventListeners();

From 1c9297a00242d5a310e0b01b01f35998ade0730e Mon Sep 17 00:00:00 2001
From: Adam Fowler <adamfowler71@gmail.com>
Date: Thu, 16 Mar 2023 18:17:18 +0000
Subject: [PATCH 2/4] Add state to never ask about LLDB again

---
 src/WorkspaceContext.ts |  4 ++--
 src/debugger/lldb.ts    | 22 +++++++++++++++++-----
 src/extension.ts        |  2 +-
 3 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/src/WorkspaceContext.ts b/src/WorkspaceContext.ts
index 6c5599dc0..3ba16a6e9 100644
--- a/src/WorkspaceContext.ts
+++ b/src/WorkspaceContext.ts
@@ -350,8 +350,8 @@ export class WorkspaceContext implements vscode.Disposable {
         return { dispose: () => this.observers.delete(fn) };
     }
 
-    async setupLLDB() {
-        await checkLLDBInstalled().then(
+    async setupLLDB(extContext: vscode.ExtensionContext) {
+        await checkLLDBInstalled(extContext.globalState).then(
             async result => {
                 if (result) {
                     this.setLLDBVersion();
diff --git a/src/debugger/lldb.ts b/src/debugger/lldb.ts
index 29629ad0a..2e14f8b05 100644
--- a/src/debugger/lldb.ts
+++ b/src/debugger/lldb.ts
@@ -26,20 +26,29 @@ import { SwiftToolchain } from "../toolchain/toolchain";
  * Check if CodeLLDB extension is installed and offer to install it if it is not.
  * @returns Whether extension was installed
  */
-export async function checkLLDBInstalled(): Promise<boolean> {
+export async function checkLLDBInstalled(workspaceState: vscode.Memento): Promise<boolean> {
     const lldbExtension = vscode.extensions.getExtension("vadimcn.vscode-lldb");
     // if extension is in list return true
     if (lldbExtension) {
+        // reset skip check flag
+        workspaceState.update("skip-check-lldb", false);
         return true;
     }
-
+    // if workspace is set to ignore LLDB check then return
+    if (workspaceState.get("skip-check-lldb") === true) {
+        return false;
+    }
     // otherwise display menu asking if user wants to install it
     return new Promise<boolean>((resolve, reject) => {
         vscode.window
             .showWarningMessage(
-                "The Swift extension requires the CodeLLDB extension to enable debugging. Do you want to install it?",
+                "Do you want to install the CodeLLDB extension?",
+                {
+                    modal: true,
+                    detail: "The Swift extension requires it to enable debugging.",
+                },
                 "Yes",
-                "No"
+                "Never"
             )
             .then(async result => {
                 switch (result) {
@@ -51,7 +60,10 @@ export async function checkLLDBInstalled(): Promise<boolean> {
                             return reject(error);
                         }
                         break;
-                    case "No":
+                    case "Never":
+                        workspaceState.update("skip-check-lldb", true);
+                        break;
+                    case undefined:
                         break;
                 }
                 return resolve(false);
diff --git a/src/extension.ts b/src/extension.ts
index d7352df9a..5ca03dc66 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -46,7 +46,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<Api> {
         context.subscriptions.push(workspaceContext);
 
         // setup swift version of LLDB. Don't await on this as it can run in the background
-        workspaceContext.setupLLDB();
+        workspaceContext.setupLLDB(context);
 
         // listen for workspace folder changes and active text editor changes
         workspaceContext.setupEventListeners();

From ceea97a6745826d3df1b627acdce8bf5e3a7f111 Mon Sep 17 00:00:00 2001
From: Adam Fowler <adamfowler71@gmail.com>
Date: Thu, 16 Mar 2023 18:39:00 +0000
Subject: [PATCH 3/4] No need to install CodeLLDB for test anymore

---
 test/runTest.ts | 23 +----------------------
 1 file changed, 1 insertion(+), 22 deletions(-)

diff --git a/test/runTest.ts b/test/runTest.ts
index a4af7b377..7a7351171 100644
--- a/test/runTest.ts
+++ b/test/runTest.ts
@@ -12,13 +12,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-import * as cp from "child_process";
 import * as path from "path";
-import {
-    runTests,
-    downloadAndUnzipVSCode,
-    resolveCliPathFromVSCodeExecutablePath,
-} from "@vscode/test-electron";
+import { runTests } from "@vscode/test-electron";
 
 async function main() {
     try {
@@ -30,22 +25,6 @@ async function main() {
         // Passed to --extensionTestsPath
         const extensionTestsPath = path.resolve(__dirname, "./suite/index");
 
-        const vscodeExecutablePath = await downloadAndUnzipVSCode();
-        const cliPath = resolveCliPathFromVSCodeExecutablePath(vscodeExecutablePath);
-
-        // Use cp.spawn / cp.exec for custom setup
-        console.log(`${cliPath} --install-extension vadimcn.vscode-lldb`);
-        const { stdout, stderr } = cp.spawnSync(
-            cliPath,
-            ["--install-extension", "vadimcn.vscode-lldb"],
-            {
-                encoding: "utf-8",
-                stdio: "inherit",
-            }
-        );
-        console.log(stdout);
-        console.log(stderr);
-
         // Download VS Code, unzip it and run the integration test
         await runTests({
             extensionDevelopmentPath,

From 509fd9ea6e85f91ff6612dd8af1c37bcdfb673b4 Mon Sep 17 00:00:00 2001
From: Adam Fowler <adamfowler71@gmail.com>
Date: Sat, 8 Apr 2023 19:02:08 +0100
Subject: [PATCH 4/4] Disable CodeLLDB dialog via setting

---
 package.json            |  8 +++++++-
 src/WorkspaceContext.ts |  4 ++--
 src/configuration.ts    |  4 ++++
 src/debugger/lldb.ts    | 16 +++++-----------
 src/extension.ts        |  2 +-
 5 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/package.json b/package.json
index 589b8e6bc..d655b0d6b 100644
--- a/package.json
+++ b/package.json
@@ -328,6 +328,12 @@
             "description": "The path of the SDK to compile against (`--sdk` parameter). The default SDK is determined by the environment on macOS and Windows.",
             "order": 3
           },
+          "swift.skipCodeLLDBCheck": {
+            "type": "boolean",
+            "default": false,
+            "description": "Skip check for CodeLLDB being installed.",
+            "order": 4
+          },
           "swift.diagnostics": {
             "type": "boolean",
             "default": false,
@@ -605,4 +611,4 @@
     "@types/lcov-parse": "1.0.0",
     "lcov-parse": "1.0.0"
   }
-}
+}
\ No newline at end of file
diff --git a/src/WorkspaceContext.ts b/src/WorkspaceContext.ts
index 3ba16a6e9..6c5599dc0 100644
--- a/src/WorkspaceContext.ts
+++ b/src/WorkspaceContext.ts
@@ -350,8 +350,8 @@ export class WorkspaceContext implements vscode.Disposable {
         return { dispose: () => this.observers.delete(fn) };
     }
 
-    async setupLLDB(extContext: vscode.ExtensionContext) {
-        await checkLLDBInstalled(extContext.globalState).then(
+    async setupLLDB() {
+        await checkLLDBInstalled().then(
             async result => {
                 if (result) {
                     this.setLLDBVersion();
diff --git a/src/configuration.ts b/src/configuration.ts
index 4cddcbab4..d4004d4df 100644
--- a/src/configuration.ts
+++ b/src/configuration.ts
@@ -141,6 +141,10 @@ const configuration = {
             .get<boolean>("backgroundCompilation", false);
     },
     /** output additional diagnostics */
+    get skipCodeLLDBCheck(): boolean {
+        return vscode.workspace.getConfiguration("swift").get<boolean>("skipCodeLLDBCheck", false);
+    },
+    /** output additional diagnostics */
     get diagnostics(): boolean {
         return vscode.workspace.getConfiguration("swift").get<boolean>("diagnostics", false);
     },
diff --git a/src/debugger/lldb.ts b/src/debugger/lldb.ts
index 2e14f8b05..92c579836 100644
--- a/src/debugger/lldb.ts
+++ b/src/debugger/lldb.ts
@@ -21,21 +21,20 @@ import * as fs from "fs/promises";
 import { execFile } from "../utilities/utilities";
 import { Result } from "../utilities/result";
 import { SwiftToolchain } from "../toolchain/toolchain";
+import configuration from "../configuration";
 
 /**
  * Check if CodeLLDB extension is installed and offer to install it if it is not.
  * @returns Whether extension was installed
  */
-export async function checkLLDBInstalled(workspaceState: vscode.Memento): Promise<boolean> {
+export async function checkLLDBInstalled(): Promise<boolean> {
     const lldbExtension = vscode.extensions.getExtension("vadimcn.vscode-lldb");
     // if extension is in list return true
     if (lldbExtension) {
-        // reset skip check flag
-        workspaceState.update("skip-check-lldb", false);
         return true;
     }
     // if workspace is set to ignore LLDB check then return
-    if (workspaceState.get("skip-check-lldb") === true) {
+    if (configuration.skipCodeLLDBCheck === true) {
         return false;
     }
     // otherwise display menu asking if user wants to install it
@@ -47,22 +46,17 @@ export async function checkLLDBInstalled(workspaceState: vscode.Memento): Promis
                     modal: true,
                     detail: "The Swift extension requires it to enable debugging.",
                 },
-                "Yes",
-                "Never"
+                "Install"
             )
             .then(async result => {
                 switch (result) {
-                    case "Yes":
+                    case "Install":
                         try {
                             await installCodeLLDB();
                             return resolve(true);
                         } catch (error) {
                             return reject(error);
                         }
-                        break;
-                    case "Never":
-                        workspaceState.update("skip-check-lldb", true);
-                        break;
                     case undefined:
                         break;
                 }
diff --git a/src/extension.ts b/src/extension.ts
index 5ca03dc66..d7352df9a 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -46,7 +46,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<Api> {
         context.subscriptions.push(workspaceContext);
 
         // setup swift version of LLDB. Don't await on this as it can run in the background
-        workspaceContext.setupLLDB(context);
+        workspaceContext.setupLLDB();
 
         // listen for workspace folder changes and active text editor changes
         workspaceContext.setupEventListeners();