mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-30 01:46:05 +00:00
[lldb-vscode] Allow specifying a custom escape prefix for LLDB commands (#69238)
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.
This commit is contained in:
parent
d72aa10a9a
commit
10664813fc
@ -731,6 +731,7 @@ class DebugCommunication(object):
|
|||||||
postRunCommands=None,
|
postRunCommands=None,
|
||||||
enableAutoVariableSummaries=False,
|
enableAutoVariableSummaries=False,
|
||||||
enableSyntheticChildDebugging=False,
|
enableSyntheticChildDebugging=False,
|
||||||
|
commandEscapePrefix="`",
|
||||||
):
|
):
|
||||||
args_dict = {"program": program}
|
args_dict = {"program": program}
|
||||||
if args:
|
if args:
|
||||||
@ -774,6 +775,7 @@ class DebugCommunication(object):
|
|||||||
args_dict["postRunCommands"] = postRunCommands
|
args_dict["postRunCommands"] = postRunCommands
|
||||||
args_dict["enableAutoVariableSummaries"] = enableAutoVariableSummaries
|
args_dict["enableAutoVariableSummaries"] = enableAutoVariableSummaries
|
||||||
args_dict["enableSyntheticChildDebugging"] = enableSyntheticChildDebugging
|
args_dict["enableSyntheticChildDebugging"] = enableSyntheticChildDebugging
|
||||||
|
args_dict["commandEscapePrefix"] = commandEscapePrefix
|
||||||
command_dict = {"command": "launch", "type": "request", "arguments": args_dict}
|
command_dict = {"command": "launch", "type": "request", "arguments": args_dict}
|
||||||
response = self.send_recv(command_dict)
|
response = self.send_recv(command_dict)
|
||||||
|
|
||||||
@ -1015,7 +1017,12 @@ class DebugCommunication(object):
|
|||||||
|
|
||||||
class DebugAdaptorServer(DebugCommunication):
|
class DebugAdaptorServer(DebugCommunication):
|
||||||
def __init__(
|
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
|
self.process = None
|
||||||
if executable is not None:
|
if executable is not None:
|
||||||
|
@ -351,6 +351,7 @@ class DAPTestCaseBase(TestBase):
|
|||||||
postRunCommands=None,
|
postRunCommands=None,
|
||||||
enableAutoVariableSummaries=False,
|
enableAutoVariableSummaries=False,
|
||||||
enableSyntheticChildDebugging=False,
|
enableSyntheticChildDebugging=False,
|
||||||
|
commandEscapePrefix="`",
|
||||||
):
|
):
|
||||||
"""Sending launch request to dap"""
|
"""Sending launch request to dap"""
|
||||||
|
|
||||||
@ -389,6 +390,7 @@ class DAPTestCaseBase(TestBase):
|
|||||||
postRunCommands=postRunCommands,
|
postRunCommands=postRunCommands,
|
||||||
enableAutoVariableSummaries=enableAutoVariableSummaries,
|
enableAutoVariableSummaries=enableAutoVariableSummaries,
|
||||||
enableSyntheticChildDebugging=enableSyntheticChildDebugging,
|
enableSyntheticChildDebugging=enableSyntheticChildDebugging,
|
||||||
|
commandEscapePrefix=commandEscapePrefix,
|
||||||
)
|
)
|
||||||
|
|
||||||
if expectFailure:
|
if expectFailure:
|
||||||
@ -425,6 +427,7 @@ class DAPTestCaseBase(TestBase):
|
|||||||
lldbDAPEnv=None,
|
lldbDAPEnv=None,
|
||||||
enableAutoVariableSummaries=False,
|
enableAutoVariableSummaries=False,
|
||||||
enableSyntheticChildDebugging=False,
|
enableSyntheticChildDebugging=False,
|
||||||
|
commandEscapePrefix="`",
|
||||||
):
|
):
|
||||||
"""Build the default Makefile target, create the DAP debug adaptor,
|
"""Build the default Makefile target, create the DAP debug adaptor,
|
||||||
and launch the process.
|
and launch the process.
|
||||||
@ -455,4 +458,5 @@ class DAPTestCaseBase(TestBase):
|
|||||||
postRunCommands=postRunCommands,
|
postRunCommands=postRunCommands,
|
||||||
enableAutoVariableSummaries=enableAutoVariableSummaries,
|
enableAutoVariableSummaries=enableAutoVariableSummaries,
|
||||||
enableSyntheticChildDebugging=enableSyntheticChildDebugging,
|
enableSyntheticChildDebugging=enableSyntheticChildDebugging,
|
||||||
|
commandEscapePrefix=commandEscapePrefix,
|
||||||
)
|
)
|
||||||
|
@ -3,16 +3,18 @@ Test lldb-dap setBreakpoints request
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import dap_server
|
import dap_server
|
||||||
|
import lldbdap_testcase
|
||||||
|
from lldbsuite.test import lldbutil
|
||||||
from lldbsuite.test.decorators import *
|
from lldbsuite.test.decorators import *
|
||||||
from lldbsuite.test.lldbtest import *
|
from lldbsuite.test.lldbtest import *
|
||||||
from lldbsuite.test import lldbutil
|
|
||||||
import lldbdap_testcase
|
|
||||||
|
|
||||||
|
|
||||||
class TestDAP_console(lldbdap_testcase.DAPTestCaseBase):
|
class TestDAP_console(lldbdap_testcase.DAPTestCaseBase):
|
||||||
def check_lldb_command(self, lldb_command, contains_string, assert_msg):
|
def check_lldb_command(
|
||||||
|
self, lldb_command, contains_string, assert_msg, command_escape_prefix="`"
|
||||||
|
):
|
||||||
response = self.dap_server.request_evaluate(
|
response = self.dap_server.request_evaluate(
|
||||||
"`%s" % (lldb_command), context="repl"
|
f"{command_escape_prefix}{lldb_command}", context="repl"
|
||||||
)
|
)
|
||||||
output = response["body"]["result"]
|
output = response["body"]["result"]
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
@ -68,3 +70,37 @@ class TestDAP_console(lldbdap_testcase.DAPTestCaseBase):
|
|||||||
# currently selected frame.
|
# currently selected frame.
|
||||||
|
|
||||||
self.check_lldb_command("frame select", "frame #1", "frame 1 is selected")
|
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="",
|
||||||
|
)
|
||||||
|
@ -382,9 +382,10 @@ llvm::json::Value DAP::CreateTopLevelScopes() {
|
|||||||
|
|
||||||
ExpressionContext DAP::DetectExpressionContext(lldb::SBFrame &frame,
|
ExpressionContext DAP::DetectExpressionContext(lldb::SBFrame &frame,
|
||||||
std::string &text) {
|
std::string &text) {
|
||||||
// Include ` as an escape hatch.
|
// Include the escape hatch prefix.
|
||||||
if (!text.empty() && text[0] == '`') {
|
if (!text.empty() &&
|
||||||
text = text.substr(1);
|
llvm::StringRef(text).starts_with(g_dap.command_escape_prefix)) {
|
||||||
|
text = text.substr(g_dap.command_escape_prefix.size());
|
||||||
return ExpressionContext::Command;
|
return ExpressionContext::Command;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,7 +417,9 @@ ExpressionContext DAP::DetectExpressionContext(lldb::SBFrame &frame,
|
|||||||
if (!auto_repl_mode_collision_warning) {
|
if (!auto_repl_mode_collision_warning) {
|
||||||
llvm::errs() << "Variable expression '" << text
|
llvm::errs() << "Variable expression '" << text
|
||||||
<< "' is hiding an lldb command, prefix an expression "
|
<< "' is hiding an lldb command, prefix an expression "
|
||||||
"with ` to ensure it runs as a lldb command.\n";
|
"with '"
|
||||||
|
<< g_dap.command_escape_prefix
|
||||||
|
<< "' to ensure it runs as a lldb command.\n";
|
||||||
auto_repl_mode_collision_warning = true;
|
auto_repl_mode_collision_warning = true;
|
||||||
}
|
}
|
||||||
return ExpressionContext::Variable;
|
return ExpressionContext::Variable;
|
||||||
|
@ -188,6 +188,7 @@ struct DAP {
|
|||||||
ReplModeRequestHandler repl_mode_request_handler;
|
ReplModeRequestHandler repl_mode_request_handler;
|
||||||
ReplMode repl_mode;
|
ReplMode repl_mode;
|
||||||
bool auto_repl_mode_collision_warning;
|
bool auto_repl_mode_collision_warning;
|
||||||
|
std::string command_escape_prefix = "`";
|
||||||
|
|
||||||
DAP();
|
DAP();
|
||||||
~DAP();
|
~DAP();
|
||||||
|
@ -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.
|
// 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))
|
if (std::optional<llvm::StringRef> value = obj.getString(key))
|
||||||
return *value;
|
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)
|
if (obj == nullptr)
|
||||||
return llvm::StringRef();
|
return defaultValue;
|
||||||
return GetString(*obj, key);
|
return GetString(*obj, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,12 +52,17 @@ llvm::StringRef GetAsString(const llvm::json::Value &value);
|
|||||||
/// \param[in] key
|
/// \param[in] key
|
||||||
/// The key to use when extracting the value
|
/// The key to use when extracting the value
|
||||||
///
|
///
|
||||||
|
/// \param[in] defaultValue
|
||||||
|
/// The default value to return if the key is not present
|
||||||
|
///
|
||||||
/// \return
|
/// \return
|
||||||
/// A llvm::StringRef that contains the string value for the
|
/// 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.
|
/// 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
|
/// Extract the unsigned integer value for the specified key from
|
||||||
/// the specified object.
|
/// the specified object.
|
||||||
|
@ -651,6 +651,8 @@ void request_attach(const llvm::json::Object &request) {
|
|||||||
GetBoolean(arguments, "enableAutoVariableSummaries", false);
|
GetBoolean(arguments, "enableAutoVariableSummaries", false);
|
||||||
g_dap.enable_synthetic_child_debugging =
|
g_dap.enable_synthetic_child_debugging =
|
||||||
GetBoolean(arguments, "enableSyntheticChildDebugging", false);
|
GetBoolean(arguments, "enableSyntheticChildDebugging", false);
|
||||||
|
g_dap.command_escape_prefix =
|
||||||
|
GetString(arguments, "commandEscapePrefix", "`");
|
||||||
|
|
||||||
// This is a hack for loading DWARF in .o files on Mac where the .o files
|
// 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
|
// in the debug map of the main executable have relative paths which require
|
||||||
@ -1801,6 +1803,8 @@ void request_launch(const llvm::json::Object &request) {
|
|||||||
GetBoolean(arguments, "enableAutoVariableSummaries", false);
|
GetBoolean(arguments, "enableAutoVariableSummaries", false);
|
||||||
g_dap.enable_synthetic_child_debugging =
|
g_dap.enable_synthetic_child_debugging =
|
||||||
GetBoolean(arguments, "enableSyntheticChildDebugging", false);
|
GetBoolean(arguments, "enableSyntheticChildDebugging", false);
|
||||||
|
g_dap.command_escape_prefix =
|
||||||
|
GetString(arguments, "commandEscapePrefix", "`");
|
||||||
|
|
||||||
// This is a hack for loading DWARF in .o files on Mac where the .o files
|
// 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
|
// in the debug map of the main executable have relative paths which require
|
||||||
|
@ -250,6 +250,11 @@
|
|||||||
"type": "boolean",
|
"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.",
|
"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
|
"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",
|
"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.",
|
"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
|
"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": "`"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user