https://github.com/walter-erquinigo updated 
https://github.com/llvm/llvm-project/pull/69238

>From 19295d5fe84c1f06f3e5d712d5af39f8ef48286c Mon Sep 17 00:00:00 2001
From: walter erquinigo <wal...@modular.com>
Date: Mon, 16 Oct 2023 15:08:20 -0400
Subject: [PATCH] [lldb-vscode] Allow specifying a custom escape character for
 LLDB commands

We've been using the backtick as our escape character, however that leads to a 
weird experience on VS Code, because on most hosts, as soon as you type the 
backtick on VS Code, the IDE will introduce another backtick. As changing the 
default escape character might be out of question because other plugins might 
rely on it, we can instead introduce an option to change this variable upon 
lldb-vscode initialization.
FWIW, my users will be using : instead ot the backtick.
---
 .../tools/lldb-vscode/lldbvscode_testcase.py  |  4 ++
 .../test/tools/lldb-vscode/vscode.py          |  9 +++-
 .../lldb-vscode/console/TestVSCode_console.py | 46 +++++++++++++++++--
 lldb/tools/lldb-vscode/JSONUtils.cpp          | 10 ++--
 lldb/tools/lldb-vscode/JSONUtils.h            | 11 +++--
 lldb/tools/lldb-vscode/VSCode.cpp             | 11 +++--
 lldb/tools/lldb-vscode/VSCode.h               |  1 +
 lldb/tools/lldb-vscode/lldb-vscode.cpp        |  4 ++
 lldb/tools/lldb-vscode/package.json           | 10 ++++
 9 files changed, 90 insertions(+), 16 deletions(-)

diff --git 
a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py 
b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py
index 8cd4e8454c89099..2e4a13b2fa2eed3 100644
--- 
a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py
+++ 
b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py
@@ -351,6 +351,7 @@ def launch(
         postRunCommands=None,
         enableAutoVariableSummaries=False,
         enableSyntheticChildDebugging=False,
+        commandEscapePrefix="`",
     ):
         """Sending launch request to vscode"""
 
@@ -389,6 +390,7 @@ def cleanup():
             postRunCommands=postRunCommands,
             enableAutoVariableSummaries=enableAutoVariableSummaries,
             enableSyntheticChildDebugging=enableSyntheticChildDebugging,
+            commandEscapePrefix=commandEscapePrefix,
         )
 
         if expectFailure:
@@ -425,6 +427,7 @@ def build_and_launch(
         lldbVSCodeEnv=None,
         enableAutoVariableSummaries=False,
         enableSyntheticChildDebugging=False,
+        commandEscapePrefix="`",
     ):
         """Build the default Makefile target, create the VSCode debug adaptor,
         and launch the process.
@@ -455,4 +458,5 @@ def build_and_launch(
             postRunCommands=postRunCommands,
             enableAutoVariableSummaries=enableAutoVariableSummaries,
             enableSyntheticChildDebugging=enableSyntheticChildDebugging,
+            commandEscapePrefix=commandEscapePrefix,
         )
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py 
b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
index 5ee0800b27a5699..d5e213d3e13db8f 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
@@ -731,6 +731,7 @@ def request_launch(
         postRunCommands=None,
         enableAutoVariableSummaries=False,
         enableSyntheticChildDebugging=False,
+        commandEscapePrefix="`",
     ):
         args_dict = {"program": program}
         if args:
@@ -774,6 +775,7 @@ def request_launch(
             args_dict["postRunCommands"] = postRunCommands
         args_dict["enableAutoVariableSummaries"] = enableAutoVariableSummaries
         args_dict["enableSyntheticChildDebugging"] = 
enableSyntheticChildDebugging
+        args_dict["commandEscapePrefix"] = commandEscapePrefix
         command_dict = {"command": "launch", "type": "request", "arguments": 
args_dict}
         response = self.send_recv(command_dict)
 
@@ -1015,7 +1017,12 @@ def terminate(self):
 
 class DebugAdaptor(DebugCommunication):
     def __init__(
-        self, executable=None, port=None, init_commands=[], log_file=None, 
env=None
+        self,
+        executable=None,
+        port=None,
+        init_commands=[],
+        log_file=None,
+        env=None,
     ):
         self.process = None
         if executable is not None:
diff --git a/lldb/test/API/tools/lldb-vscode/console/TestVSCode_console.py 
b/lldb/test/API/tools/lldb-vscode/console/TestVSCode_console.py
index d28e98b37c589dd..8eb02257ec6c5c5 100644
--- a/lldb/test/API/tools/lldb-vscode/console/TestVSCode_console.py
+++ b/lldb/test/API/tools/lldb-vscode/console/TestVSCode_console.py
@@ -2,16 +2,20 @@
 Test lldb-vscode setBreakpoints request
 """
 
+import lldbvscode_testcase
 import vscode
+from lldbsuite.test import lldbutil
 from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-from lldbsuite.test import lldbutil
-import lldbvscode_testcase
 
 
 class TestVSCode_console(lldbvscode_testcase.VSCodeTestCaseBase):
-    def check_lldb_command(self, lldb_command, contains_string, assert_msg):
-        response = self.vscode.request_evaluate("`%s" % (lldb_command), 
context="repl")
+    def check_lldb_command(
+        self, lldb_command, contains_string, assert_msg, 
command_escape_prefix="`"
+    ):
+        response = self.vscode.request_evaluate(
+            f"{command_escape_prefix}{lldb_command}", context="repl"
+        )
         output = response["body"]["result"]
         self.assertIn(
             contains_string,
@@ -66,3 +70,37 @@ def test_scopes_variables_setVariable_evaluate(self):
         # currently selected frame.
 
         self.check_lldb_command("frame select", "frame #1", "frame 1 is 
selected")
+
+    @skipIfWindows
+    @skipIfRemote
+    def test_custom_escape_prefix(self):
+        program = self.getBuildArtifact("a.out")
+        self.build_and_launch(program, commandEscapePrefix="::")
+        source = "main.cpp"
+        breakpoint1_line = line_number(source, "// breakpoint 1")
+        breakpoint_ids = self.set_source_breakpoints(source, 
[breakpoint1_line])
+        self.continue_to_breakpoints(breakpoint_ids)
+
+        self.check_lldb_command(
+            "help",
+            "For more information on any command",
+            "Help can be invoked",
+            command_escape_prefix="::",
+        )
+
+    @skipIfWindows
+    @skipIfRemote
+    def test_empty_escape_prefix(self):
+        program = self.getBuildArtifact("a.out")
+        self.build_and_launch(program, commandEscapePrefix="")
+        source = "main.cpp"
+        breakpoint1_line = line_number(source, "// breakpoint 1")
+        breakpoint_ids = self.set_source_breakpoints(source, 
[breakpoint1_line])
+        self.continue_to_breakpoints(breakpoint_ids)
+
+        self.check_lldb_command(
+            "help",
+            "For more information on any command",
+            "Help can be invoked",
+            command_escape_prefix="",
+        )
diff --git a/lldb/tools/lldb-vscode/JSONUtils.cpp 
b/lldb/tools/lldb-vscode/JSONUtils.cpp
index 6cf753170d8429f..1c3061b68bf7e07 100644
--- a/lldb/tools/lldb-vscode/JSONUtils.cpp
+++ b/lldb/tools/lldb-vscode/JSONUtils.cpp
@@ -46,15 +46,17 @@ llvm::StringRef GetAsString(const llvm::json::Value &value) 
{
 }
 
 // Gets a string from a JSON object using the key, or returns an empty string.
-llvm::StringRef GetString(const llvm::json::Object &obj, llvm::StringRef key) {
+llvm::StringRef GetString(const llvm::json::Object &obj, llvm::StringRef key,
+                          llvm::StringRef defaultValue) {
   if (std::optional<llvm::StringRef> value = obj.getString(key))
     return *value;
-  return llvm::StringRef();
+  return defaultValue;
 }
 
-llvm::StringRef GetString(const llvm::json::Object *obj, llvm::StringRef key) {
+llvm::StringRef GetString(const llvm::json::Object *obj, llvm::StringRef key,
+                          llvm::StringRef defaultValue) {
   if (obj == nullptr)
-    return llvm::StringRef();
+    return defaultValue;
   return GetString(*obj, key);
 }
 
diff --git a/lldb/tools/lldb-vscode/JSONUtils.h 
b/lldb/tools/lldb-vscode/JSONUtils.h
index 2013147f5d3532a..092d428031839b4 100644
--- a/lldb/tools/lldb-vscode/JSONUtils.h
+++ b/lldb/tools/lldb-vscode/JSONUtils.h
@@ -52,12 +52,17 @@ llvm::StringRef GetAsString(const llvm::json::Value &value);
 /// \param[in] key
 ///     The key to use when extracting the value
 ///
+/// \param[in] defaultValue
+///     The default value to return if the key is not present
+///
 /// \return
 ///     A llvm::StringRef that contains the string value for the
-///     specified \a key, or an empty string if there is no key that
+///     specified \a key, or the default value if there is no key that
 ///     matches or if the value is not a string.
-llvm::StringRef GetString(const llvm::json::Object &obj, llvm::StringRef key);
-llvm::StringRef GetString(const llvm::json::Object *obj, llvm::StringRef key);
+llvm::StringRef GetString(const llvm::json::Object &obj, llvm::StringRef key,
+                          llvm::StringRef defaultValue = "");
+llvm::StringRef GetString(const llvm::json::Object *obj, llvm::StringRef key,
+                          llvm::StringRef defaultValue = "");
 
 /// Extract the unsigned integer value for the specified key from
 /// the specified object.
diff --git a/lldb/tools/lldb-vscode/VSCode.cpp 
b/lldb/tools/lldb-vscode/VSCode.cpp
index 1384604c48371b7..5fa1d313d717811 100644
--- a/lldb/tools/lldb-vscode/VSCode.cpp
+++ b/lldb/tools/lldb-vscode/VSCode.cpp
@@ -384,9 +384,10 @@ llvm::json::Value VSCode::CreateTopLevelScopes() {
 
 ExpressionContext VSCode::DetectExpressionContext(lldb::SBFrame &frame,
                                                   std::string &text) {
-  // Include ` as an escape hatch.
-  if (!text.empty() && text[0] == '`') {
-    text = text.substr(1);
+  // Include the escape hatch prefix.
+  if (!text.empty() &&
+      llvm::StringRef(text).starts_with(g_vsc.command_escape_prefix)) {
+    text = text.substr(g_vsc.command_escape_prefix.size());
     return ExpressionContext::Command;
   }
 
@@ -418,7 +419,9 @@ ExpressionContext 
VSCode::DetectExpressionContext(lldb::SBFrame &frame,
         if (!auto_repl_mode_collision_warning) {
           llvm::errs() << "Variable expression '" << text
                        << "' is hiding an lldb command, prefix an expression "
-                          "with ` to ensure it runs as a lldb command.\n";
+                          "with "
+                       << g_vsc.command_escape_prefix
+                       << " to ensure it runs as a lldb command.\n";
           auto_repl_mode_collision_warning = true;
         }
         return ExpressionContext::Variable;
diff --git a/lldb/tools/lldb-vscode/VSCode.h b/lldb/tools/lldb-vscode/VSCode.h
index 59bb11c71e67203..aea37ffdf27bbc1 100644
--- a/lldb/tools/lldb-vscode/VSCode.h
+++ b/lldb/tools/lldb-vscode/VSCode.h
@@ -188,6 +188,7 @@ struct VSCode {
   ReplModeRequestHandler repl_mode_request_handler;
   ReplMode repl_mode;
   bool auto_repl_mode_collision_warning;
+  std::string command_escape_prefix = "`";
 
   VSCode();
   ~VSCode();
diff --git a/lldb/tools/lldb-vscode/lldb-vscode.cpp 
b/lldb/tools/lldb-vscode/lldb-vscode.cpp
index 3904d430c49b4cd..65e36ad05df9cdd 100644
--- a/lldb/tools/lldb-vscode/lldb-vscode.cpp
+++ b/lldb/tools/lldb-vscode/lldb-vscode.cpp
@@ -651,6 +651,8 @@ void request_attach(const llvm::json::Object &request) {
       GetBoolean(arguments, "enableAutoVariableSummaries", false);
   g_vsc.enable_synthetic_child_debugging =
       GetBoolean(arguments, "enableSyntheticChildDebugging", false);
+  g_vsc.command_escape_prefix =
+      GetString(arguments, "commandEscapePrefix", "`");
 
   // This is a hack for loading DWARF in .o files on Mac where the .o files
   // in the debug map of the main executable have relative paths which require
@@ -1802,6 +1804,8 @@ void request_launch(const llvm::json::Object &request) {
       GetBoolean(arguments, "enableAutoVariableSummaries", false);
   g_vsc.enable_synthetic_child_debugging =
       GetBoolean(arguments, "enableSyntheticChildDebugging", false);
+  g_vsc.command_escape_prefix =
+      GetString(arguments, "commandEscapePrefix", "`");
 
   // This is a hack for loading DWARF in .o files on Mac where the .o files
   // in the debug map of the main executable have relative paths which require
diff --git a/lldb/tools/lldb-vscode/package.json 
b/lldb/tools/lldb-vscode/package.json
index 1b3d452f92ab86a..8927490ad092212 100644
--- a/lldb/tools/lldb-vscode/package.json
+++ b/lldb/tools/lldb-vscode/package.json
@@ -250,6 +250,11 @@
                                                                "type": 
"boolean",
                                                                "description": 
"If a variable is displayed using a synthetic children, also display the actual 
contents of the variable at the end under a [raw] entry. This is useful when 
creating sythetic child plug-ins as it lets you see the actual contents of the 
variable.",
                                                                "default": false
+                                                       },
+                                                       "commandEscapePrefix": {
+                                                               "type": 
"string",
+                                                               "description": 
"The escape prefix to use for executing regular LLDB commands in the Debug 
Console, instead of printing variables. Defaults to a back-tick (`). If it's an 
empty string, then all expression in the Debug Console are treated as regular 
LLDB commands.",
+                                                               "default": "`"
                                                        }
                                                }
                                        },
@@ -339,6 +344,11 @@
                                                                "type": 
"boolean",
                                                                "description": 
"If a variable is displayed using a synthetic children, also display the actual 
contents of the variable at the end under a [raw] entry. This is useful when 
creating sythetic child plug-ins as it lets you see the actual contents of the 
variable.",
                                                                "default": false
+                                                       },
+                                                       "commandEscapePrefix": {
+                                                               "type": 
"string",
+                                                               "description": 
"The escape prefix character to use for executing regular LLDB commands in the 
Debug Console, instead of printing variables. Defaults to a back-tick (`). If 
empty, then all expression in the Debug Console are treated as regular LLDB 
commands.",
+                                                               "default": "`"
                                                        }
                                                }
                                        }

_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to