Skip to content

Commit e179e50

Browse files
committed
[lldb-dap] Add external terminal support
1 parent 2fe0feb commit e179e50

File tree

10 files changed

+91
-16
lines changed

10 files changed

+91
-16
lines changed

lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -894,7 +894,7 @@ def request_launch(
894894
disableASLR=False,
895895
disableSTDIO=False,
896896
shellExpandArguments=False,
897-
runInTerminal=False,
897+
runInTerminal: Union[bool, str] = False,
898898
enableAutoVariableSummaries=False,
899899
displayExtendedBacktrace=False,
900900
enableSyntheticChildDebugging=False,

lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def test_failing_launch_program(self):
4646

4747
def test_failing_launch_commands_and_run_in_terminal(self):
4848
"""
49-
Tests launching with an invalid program.
49+
Tests launching with launch commands in an integrated terminal.
5050
"""
5151
program = self.getBuildArtifact("a.out")
5252
self.create_debug_adapter()
@@ -60,6 +60,20 @@ def test_failing_launch_commands_and_run_in_terminal(self):
6060
self.get_dict_value(response, ["body", "error", "format"]),
6161
)
6262

63+
def test_failing_run_in_terminal(self):
64+
"""
65+
Tests launching in terminal with an invalid terminal type.
66+
"""
67+
program = self.getBuildArtifact("a.out")
68+
self.create_debug_adapter()
69+
response = self.launch(program, runInTerminal="invalid", expectFailure=True)
70+
self.assertFalse(response["success"])
71+
self.assertTrue(self.get_dict_value(response, ["body", "error", "showUser"]))
72+
self.assertRegex(
73+
response["body"]["error"]["format"],
74+
r"unexpected value, expected 'console', 'integrated' or 'external' at arguments.runInTerminal",
75+
)
76+
6377
@skipIfWindows
6478
def test_termination(self):
6579
"""

lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ namespace lldb_dap {
2323
/// Launch request; value of command field is 'launch'.
2424
Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const {
2525
// Validate that we have a well formed launch request.
26-
if (!arguments.launchCommands.empty() && arguments.runInTerminal)
26+
if (!arguments.launchCommands.empty() &&
27+
arguments.terminal != protocol::eConsole)
2728
return make_error<DAPError>(
2829
"'launchCommands' and 'runInTerminal' are mutually exclusive");
2930

lldb/tools/lldb-dap/Handler/RequestHandler.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) {
8080

8181
llvm::json::Object reverse_request = CreateRunInTerminalReverseRequest(
8282
arguments.configuration.program, arguments.args, arguments.env,
83-
arguments.cwd, comm_file.m_path, debugger_pid);
83+
arguments.cwd, comm_file.m_path, debugger_pid,
84+
arguments.terminal == protocol::eExternal);
8485
dap.SendReverseRequest<LogFailureResponseHandler>("runInTerminal",
8586
std::move(reverse_request));
8687

@@ -192,7 +193,7 @@ llvm::Error BaseRequestHandler::LaunchProcess(
192193
// about process state changes during the launch.
193194
ScopeSyncMode scope_sync_mode(dap.debugger);
194195

195-
if (arguments.runInTerminal) {
196+
if (arguments.terminal != protocol::eConsole) {
196197
if (llvm::Error err = RunInTerminal(dap, arguments))
197198
return err;
198199
} else if (launchCommands.empty()) {

lldb/tools/lldb-dap/JSONUtils.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,11 +1168,15 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit) {
11681168
llvm::json::Object CreateRunInTerminalReverseRequest(
11691169
llvm::StringRef program, const std::vector<std::string> &args,
11701170
const llvm::StringMap<std::string> &env, llvm::StringRef cwd,
1171-
llvm::StringRef comm_file, lldb::pid_t debugger_pid) {
1171+
llvm::StringRef comm_file, lldb::pid_t debugger_pid, bool external) {
11721172
llvm::json::Object run_in_terminal_args;
1173-
// This indicates the IDE to open an embedded terminal, instead of opening
1174-
// the terminal in a new window.
1175-
run_in_terminal_args.try_emplace("kind", "integrated");
1173+
if (external)
1174+
// This indicates the IDE to open an external terminal window.
1175+
run_in_terminal_args.try_emplace("kind", "external");
1176+
else
1177+
// This indicates the IDE to open an embedded terminal, instead of opening
1178+
// the terminal in a new window.
1179+
run_in_terminal_args.try_emplace("kind", "integrated");
11761180

11771181
// The program path must be the first entry in the "args" field
11781182
std::vector<std::string> req_args = {DAP::debug_adapter_path.str(),

lldb/tools/lldb-dap/JSONUtils.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,13 +441,17 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit);
441441
/// launcher uses it on Linux tell the kernel that it should allow the
442442
/// debugger process to attach.
443443
///
444+
/// \param[in] external
445+
/// If set to true, the program will run in an external console window
446+
/// instead of IDE's integrated terminal.
447+
///
444448
/// \return
445449
/// A "runInTerminal" JSON object that follows the specification outlined by
446450
/// Microsoft.
447451
llvm::json::Object CreateRunInTerminalReverseRequest(
448452
llvm::StringRef program, const std::vector<std::string> &args,
449453
const llvm::StringMap<std::string> &env, llvm::StringRef cwd,
450-
llvm::StringRef comm_file, lldb::pid_t debugger_pid);
454+
llvm::StringRef comm_file, lldb::pid_t debugger_pid, bool external);
451455

452456
/// Create a "Terminated" JSON object that contains statistics
453457
///

lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,37 @@ json::Value toJSON(const BreakpointLocationsResponseBody &BLRB) {
262262
return json::Object{{"breakpoints", BLRB.breakpoints}};
263263
}
264264

265+
bool fromJSON(const json::Value &Params, Terminal &T, json::Path P) {
266+
auto oldFormatTerminal = Params.getAsBoolean();
267+
if (oldFormatTerminal) {
268+
if (*oldFormatTerminal)
269+
T = eIntegrated;
270+
else
271+
T = eConsole;
272+
return true;
273+
}
274+
auto newFormatTerminal = Params.getAsString();
275+
if (!newFormatTerminal) {
276+
P.report("expected a string");
277+
return false;
278+
}
279+
280+
std::optional<Terminal> terminal =
281+
StringSwitch<std::optional<Terminal>>(*newFormatTerminal)
282+
.Case("console", eConsole)
283+
.Case("integrated", eIntegrated)
284+
.Case("external", eExternal)
285+
.Default(std::nullopt);
286+
if (!terminal) {
287+
P.report(
288+
"unexpected value, expected 'console', 'integrated' or 'external'");
289+
return false;
290+
}
291+
292+
T = *terminal;
293+
return true;
294+
}
295+
265296
bool fromJSON(const json::Value &Params, LaunchRequestArguments &LRA,
266297
json::Path P) {
267298
json::ObjectMapper O(Params, P);
@@ -273,8 +304,7 @@ bool fromJSON(const json::Value &Params, LaunchRequestArguments &LRA,
273304
O.mapOptional("disableASLR", LRA.disableASLR) &&
274305
O.mapOptional("disableSTDIO", LRA.disableSTDIO) &&
275306
O.mapOptional("shellExpandArguments", LRA.shellExpandArguments) &&
276-
277-
O.mapOptional("runInTerminal", LRA.runInTerminal) &&
307+
O.mapOptional("runInTerminal", LRA.terminal) &&
278308
parseEnv(Params, LRA.env, P);
279309
}
280310

lldb/tools/lldb-dap/Protocol/ProtocolRequests.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,8 @@ struct Configuration {
242242
std::string platformName;
243243
};
244244

245+
enum Terminal : unsigned { eConsole, eIntegrated, eExternal };
246+
245247
/// lldb-dap specific launch arguments.
246248
struct LaunchRequestArguments {
247249
/// Common lldb-dap configuration values for launching/attaching operations.
@@ -292,7 +294,7 @@ struct LaunchRequestArguments {
292294

293295
/// Launch the program inside an integrated terminal in the IDE. Useful for
294296
/// debugging interactive command line programs.
295-
bool runInTerminal = false;
297+
Terminal terminal = eConsole;
296298

297299
/// @}
298300
};

lldb/tools/lldb-dap/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ contain the following key/value pairs:
236236
| **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.
237237
| **stopOnEntry** | boolean | | Whether to stop program immediately after launching.
238238
| **runInTerminal** | boolean | | Launch the program inside an integrated terminal in the IDE. Useful for debugging interactive command line programs.
239+
| **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.
239240
| **launchCommands** | [string] | | LLDB commands executed to launch the program.
240241

241242
For JSON configurations of `"type": "attach"`, the JSON configuration can contain

lldb/tools/lldb-dap/package.json

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -526,9 +526,27 @@
526526
"default": []
527527
},
528528
"runInTerminal": {
529-
"type": "boolean",
530-
"description": "Launch the program inside an integrated terminal in the IDE. Useful for debugging interactive command line programs",
531-
"default": false
529+
"anyOf": [
530+
{
531+
"type": "boolean",
532+
"description": "Launch the program inside an integrated terminal in the IDE. Useful for debugging interactive command line programs",
533+
"default": false
534+
},
535+
{
536+
"type": "string",
537+
"enum": [
538+
"console",
539+
"integrated",
540+
"external"
541+
],
542+
"enumDescriptions": [
543+
"Launch the program inside an integrated terminal in the IDE.",
544+
"Launch the program inside an external terminal window.",
545+
"Use Debug Console for output (input is not supported)."
546+
],
547+
"default": "console"
548+
}
549+
]
532550
},
533551
"timeout": {
534552
"type": "number",

0 commit comments

Comments
 (0)