-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[lldb-dap] Add external terminal support #146950
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-lldb Author: None (DrSergei) ChangesPopular debugger extensions, such as cpptools ( Full diff: https://github.com/llvm/llvm-project/pull/146950.diff 10 Files Affected:
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
index 0fe36cd4bc71f..d8c1ffa6c00f0 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
@@ -890,7 +890,7 @@ def request_launch(
args: Optional[list[str]] = None,
cwd: Optional[str] = None,
env: Optional[dict[str, str]] = None,
- stopOnEntry=False,
+ stopOnEntry: Union[bool, str] = False,
disableASLR=False,
disableSTDIO=False,
shellExpandArguments=False,
diff --git a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py
index ae8142ae4f484..e8cb64dc9cf4e 100644
--- a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py
+++ b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py
@@ -46,7 +46,7 @@ def test_failing_launch_program(self):
def test_failing_launch_commands_and_run_in_terminal(self):
"""
- Tests launching with an invalid program.
+ Tests launching with a launch commands in integrated terminal.
"""
program = self.getBuildArtifact("a.out")
self.create_debug_adapter()
@@ -60,6 +60,22 @@ def test_failing_launch_commands_and_run_in_terminal(self):
self.get_dict_value(response, ["body", "error", "format"]),
)
+ def test_failing_run_in_terminal(self):
+ """
+ Tests launching in terminal.
+ """
+ program = self.getBuildArtifact("a.out")
+ self.create_debug_adapter()
+ response = self.launch(
+ program, runInTerminal="invalid", expectFailure=True
+ )
+ self.assertFalse(response["success"])
+ self.assertTrue(self.get_dict_value(response, ["body", "error", "showUser"]))
+ self.assertRegex(
+ response["body"]["error"]["format"],
+ r"unexpected value, expected 'console', 'integrated' or 'external' at arguments.runInTerminal",
+ )
+
@skipIfWindows
def test_termination(self):
"""
diff --git a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp
index 1d7b4b7009462..907d93021cd76 100644
--- a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp
@@ -23,7 +23,7 @@ namespace lldb_dap {
/// Launch request; value of command field is 'launch'.
Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const {
// Validate that we have a well formed launch request.
- if (!arguments.launchCommands.empty() && arguments.runInTerminal)
+ if (!arguments.launchCommands.empty() && arguments.terminal)
return make_error<DAPError>(
"'launchCommands' and 'runInTerminal' are mutually exclusive");
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
index 93bc80a38e29d..d2227cfffa18a 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
@@ -80,7 +80,8 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) {
llvm::json::Object reverse_request = CreateRunInTerminalReverseRequest(
arguments.configuration.program, arguments.args, arguments.env,
- arguments.cwd, comm_file.m_path, debugger_pid);
+ arguments.cwd, comm_file.m_path, debugger_pid,
+ arguments.terminal == protocol::eExternal);
dap.SendReverseRequest<LogFailureResponseHandler>("runInTerminal",
std::move(reverse_request));
@@ -192,7 +193,7 @@ llvm::Error BaseRequestHandler::LaunchProcess(
// about process state changes during the launch.
ScopeSyncMode scope_sync_mode(dap.debugger);
- if (arguments.runInTerminal) {
+ if (arguments.terminal) {
if (llvm::Error err = RunInTerminal(dap, arguments))
return err;
} else if (launchCommands.empty()) {
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp
index 08e65ab835a57..08e3e504689e7 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -1168,11 +1168,15 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit) {
llvm::json::Object CreateRunInTerminalReverseRequest(
llvm::StringRef program, const std::vector<std::string> &args,
const llvm::StringMap<std::string> &env, llvm::StringRef cwd,
- llvm::StringRef comm_file, lldb::pid_t debugger_pid) {
+ llvm::StringRef comm_file, lldb::pid_t debugger_pid, bool external) {
llvm::json::Object run_in_terminal_args;
- // This indicates the IDE to open an embedded terminal, instead of opening
- // the terminal in a new window.
- run_in_terminal_args.try_emplace("kind", "integrated");
+ if (external)
+ // This indicates the IDE to open an external terminal window.
+ run_in_terminal_args.try_emplace("kind", "external");
+ else
+ // This indicates the IDE to open an embedded terminal, instead of opening
+ // the terminal in a new window.
+ run_in_terminal_args.try_emplace("kind", "integrated");
// The program path must be the first entry in the "args" field
std::vector<std::string> req_args = {DAP::debug_adapter_path.str(),
diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h
index fd9a06931ebff..4a8feab741e4b 100644
--- a/lldb/tools/lldb-dap/JSONUtils.h
+++ b/lldb/tools/lldb-dap/JSONUtils.h
@@ -447,7 +447,7 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit);
llvm::json::Object CreateRunInTerminalReverseRequest(
llvm::StringRef program, const std::vector<std::string> &args,
const llvm::StringMap<std::string> &env, llvm::StringRef cwd,
- llvm::StringRef comm_file, lldb::pid_t debugger_pid);
+ llvm::StringRef comm_file, lldb::pid_t debugger_pid, bool external);
/// Create a "Terminated" JSON object that contains statistics
///
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
index 9bd84a6c898f9..f55efd185f9f6 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
@@ -262,6 +262,37 @@ json::Value toJSON(const BreakpointLocationsResponseBody &BLRB) {
return json::Object{{"breakpoints", BLRB.breakpoints}};
}
+bool fromJSON(const json::Value &Params, Terminal &T, json::Path P) {
+ auto oldFormatTerminal = Params.getAsBoolean();
+ if (oldFormatTerminal) {
+ if (*oldFormatTerminal)
+ T = eIntegrated;
+ else
+ T = eConsole;
+ return true;
+ }
+ auto newFormatTerminal = Params.getAsString();
+ if (!newFormatTerminal) {
+ P.report("expected a string");
+ return false;
+ }
+
+ std::optional<Terminal> terminal =
+ StringSwitch<std::optional<Terminal>>(*newFormatTerminal)
+ .Case("console", eConsole)
+ .Case("integrated", eIntegrated)
+ .Case("external", eExternal)
+ .Default(std::nullopt);
+ if (!terminal) {
+ P.report(
+ "unexpected value, expected 'console', 'integrated' or 'external'");
+ return false;
+ }
+
+ T = *terminal;
+ return true;
+}
+
bool fromJSON(const json::Value &Params, LaunchRequestArguments &LRA,
json::Path P) {
json::ObjectMapper O(Params, P);
@@ -273,8 +304,7 @@ bool fromJSON(const json::Value &Params, LaunchRequestArguments &LRA,
O.mapOptional("disableASLR", LRA.disableASLR) &&
O.mapOptional("disableSTDIO", LRA.disableSTDIO) &&
O.mapOptional("shellExpandArguments", LRA.shellExpandArguments) &&
-
- O.mapOptional("runInTerminal", LRA.runInTerminal) &&
+ O.mapOptional("runInTerminal", LRA.terminal) &&
parseEnv(Params, LRA.env, P);
}
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
index d4b816c72679b..2e72f50c63afe 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
@@ -242,6 +242,8 @@ struct Configuration {
std::string platformName;
};
+enum Terminal : unsigned { eConsole, eIntegrated, eExternal };
+
/// lldb-dap specific launch arguments.
struct LaunchRequestArguments {
/// Common lldb-dap configuration values for launching/attaching operations.
@@ -292,7 +294,7 @@ struct LaunchRequestArguments {
/// Launch the program inside an integrated terminal in the IDE. Useful for
/// debugging interactive command line programs.
- bool runInTerminal = false;
+ Terminal terminal = eConsole;
/// @}
};
diff --git a/lldb/tools/lldb-dap/README.md b/lldb/tools/lldb-dap/README.md
index 18bfa9d518b98..61d2cc06f99eb 100644
--- a/lldb/tools/lldb-dap/README.md
+++ b/lldb/tools/lldb-dap/README.md
@@ -236,6 +236,7 @@ contain the following key/value pairs:
| **env** | dictionary | | Environment variables to set when launching the program. The format of each environment variable string is "VAR=VALUE" for environment variables with values or just "VAR" for environment variables with no values.
| **stopOnEntry** | boolean | | Whether to stop program immediately after launching.
| **runInTerminal** | boolean | | Launch the program inside an integrated terminal in the IDE. Useful for debugging interactive command line programs.
+| **runInTerminal** | string | | Specifies where program should be launch: `integrated` for an integrated terminal in the IDE, `external` for external terminal window or `console` (default) for IDE debug console.
| **launchCommands** | [string] | | LLDB commands executed to launch the program.
For JSON configurations of `"type": "attach"`, the JSON configuration can contain
diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json
index b150dee792c34..cf5712261d051 100644
--- a/lldb/tools/lldb-dap/package.json
+++ b/lldb/tools/lldb-dap/package.json
@@ -526,9 +526,27 @@
"default": []
},
"runInTerminal": {
- "type": "boolean",
- "description": "Launch the program inside an integrated terminal in the IDE. Useful for debugging interactive command line programs",
- "default": false
+ "anyOf": [
+ {
+ "type": "boolean",
+ "description": "Launch the program inside an integrated terminal in the IDE. Useful for debugging interactive command line programs",
+ "default": false
+ },
+ {
+ "type": "string",
+ "enum": [
+ "console",
+ "integrated",
+ "external"
+ ],
+ "enumDescriptions": [
+ "Launch the program inside an integrated terminal in the IDE.",
+ "Launch the program inside an external terminal window.",
+ "Use Debug Console for output (input is not supported)."
+ ],
+ "default": "console"
+ }
+ ]
},
"timeout": {
"type": "number",
|
✅ With the latest revision this PR passed the Python code formatter. |
5e5f3b4
to
112050c
Compare
Popular debugger extensions, such as cpptools (
externalConsole
option) and codelldb (terminal
option), support launching program in external console. This patch change behavior ofrunInTerminal
option similar to codellb, but save old behavior if boolean value was set.