llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: None (DriftProc)

<details>
<summary>Changes</summary>

Add variable substitution support for some settings of the LLDB DAP VS Code 
extension, include `lldb-dap.executable-path`, `lldb-dap.arguments` and 
`lldb-dap.environment`.

Partially solve #<!-- -->183008.

---
Full diff: https://github.com/llvm/llvm-project/pull/183989.diff


2 Files Affected:

- (modified) lldb/tools/lldb-dap/extension/src/debug-adapter-factory.ts (+6-5) 
- (modified) lldb/tools/lldb-dap/extension/src/utils.ts (+73) 


``````````diff
diff --git a/lldb/tools/lldb-dap/extension/src/debug-adapter-factory.ts 
b/lldb/tools/lldb-dap/extension/src/debug-adapter-factory.ts
index e415097d1b8be..dd93afeca03d2 100644
--- a/lldb/tools/lldb-dap/extension/src/debug-adapter-factory.ts
+++ b/lldb/tools/lldb-dap/extension/src/debug-adapter-factory.ts
@@ -6,7 +6,7 @@ import * as vscode from "vscode";
 import { LogFilePathProvider, LogType } from "./logging";
 import { ErrorWithNotification } from "./ui/error-with-notification";
 import { ConfigureButton, OpenSettingsButton } from "./ui/show-error-message";
-import { expandUser } from "./utils";
+import { expandUser, substitute } from "./utils";
 
 const exec = util.promisify(child_process.execFile);
 
@@ -130,7 +130,7 @@ async function getDAPExecutable(
 
   // Check if the executable was provided in the extension's configuration.
   const config = vscode.workspace.getConfiguration("lldb-dap", 
workspaceFolder);
-  const configPath = expandUser(config.get<string>("executable-path") ?? "");
+  const configPath = expandUser(await 
substitute(config.get<string>("executable-path") ?? ""));
   if (configPath && configPath.length !== 0) {
     if (!(await isExecutable(configPath))) {
       throw new ErrorWithNotification(
@@ -187,9 +187,10 @@ async function getDAPArguments(
     return debugConfigArgs;
   }
   // Fall back on the workspace configuration.
-  return vscode.workspace
+  return await substitute(
+    vscode.workspace
     .getConfiguration("lldb-dap", workspaceFolder)
-    .get<string[]>("arguments", []);
+    .get<string[]>("arguments", []));
 }
 
 /**
@@ -234,7 +235,7 @@ async function getDAPEnvironment(
   const config = vscode.workspace.workspaceFile
     ? vscode.workspace.getConfiguration("lldb-dap")
     : vscode.workspace.getConfiguration("lldb-dap", workspaceFolder);
-  return config.get<{ [key: string]: string }>("environment") || {};
+  return await substitute(config.get<{ [key: string]: string }>("environment") 
|| {});
 }
 
 /**
diff --git a/lldb/tools/lldb-dap/extension/src/utils.ts 
b/lldb/tools/lldb-dap/extension/src/utils.ts
index 310642175abae..d12ba96599997 100644
--- a/lldb/tools/lldb-dap/extension/src/utils.ts
+++ b/lldb/tools/lldb-dap/extension/src/utils.ts
@@ -1,5 +1,6 @@
 import * as os from "os";
 import * as path from "path";
+import * as vscode from "vscode";
 
 /**
  * Expands the character `~` to the user's home directory
@@ -39,3 +40,75 @@ export function expandUser(file_path: string): string {
 
   return file_path;
 }
+
+// Traverse a JSON value, replacing placeholders in all strings.
+export async function substitute<T>(val: T): Promise<T> {
+  if (typeof val === "string") {
+    const replacementPattern = /\$\{(.*?)\}/g;
+    const replacementPromises: Promise<string|undefined>[] = [];
+    const matches = val.matchAll(replacementPattern);
+    for (const match of matches) {
+      // match[1] is the first captured group
+      replacementPromises.push(replacement(match[1]));
+    }
+    const replacements = await Promise.all(replacementPromises);
+    val = val.replace(
+              replacementPattern,
+              // If there's no replacement available, keep the placeholder.
+              match => replacements.shift() ?? match) as unknown as T;
+  } else if (Array.isArray(val)) {
+    val = await Promise.all(val.map(substitute)) as T;
+  } else if (typeof val === "object") {
+    // Substitute values but not keys, so we don't deal with collisions.
+    const result = {} as {[k: string]: any};
+    for (const key in val) {
+      result[key] = await substitute(val[key]);
+    }
+    val = result as T;
+  }
+  return val;
+}
+
+// Subset of substitution variables that are most likely to be useful.
+// https://code.visualstudio.com/docs/editor/variables-reference
+async function replacement(name: string): Promise<string|undefined> {
+  if (name === "userHome") {
+    return os.homedir();
+  }
+  if (name === "workspaceRoot" || name === "workspaceFolder" ||
+      name === "cwd") {
+    if (vscode.workspace.rootPath !== undefined)
+      return vscode.workspace.rootPath;
+    if (vscode.window.activeTextEditor !== undefined)
+      return path.dirname(vscode.window.activeTextEditor.document.uri.fsPath);
+    return process.cwd();
+  }
+  if (name === "workspaceFolderBasename" &&
+      vscode.workspace.rootPath !== undefined) {
+    return path.basename(vscode.workspace.rootPath);
+  }
+  const envPrefix = "env:";
+  if (name.startsWith(envPrefix))
+    return process.env[name.substr(envPrefix.length)] ?? "";
+  const configPrefix = "config:";
+  if (name.startsWith(configPrefix)) {
+    const config = vscode.workspace.getConfiguration().get(
+        name.substr(configPrefix.length));
+    return (typeof config === "string") ? config : undefined;
+  }
+  const commandPrefix = "command:";
+  if (name.startsWith(commandPrefix)) {
+    const commandId = name.substr(commandPrefix.length);
+    try {
+      return await vscode.commands.executeCommand(commandId);
+    } catch (error) {
+      console.warn(`LLDB DAP: Error resolving command '${commandId}':`, error);
+      vscode.window.showWarningMessage(
+          `LLDB DAP: Failed to resolve ${commandId}`);
+
+      return undefined;
+    }
+  }
+
+  return undefined;
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/183989
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to