Skip to content

Commit 72921a4

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

File tree

12 files changed

+109
-32
lines changed

12 files changed

+109
-32
lines changed

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

Lines changed: 3 additions & 3 deletions
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+
console: Optional[str] = None,
898898
enableAutoVariableSummaries=False,
899899
displayExtendedBacktrace=False,
900900
enableSyntheticChildDebugging=False,
@@ -944,8 +944,8 @@ def request_launch(
944944
args_dict["launchCommands"] = launchCommands
945945
if sourceMap:
946946
args_dict["sourceMap"] = sourceMap
947-
if runInTerminal:
948-
args_dict["runInTerminal"] = runInTerminal
947+
if console:
948+
args_dict["console"] = console
949949
if postRunCommands:
950950
args_dict["postRunCommands"] = postRunCommands
951951
if customFrameFormat:

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

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,22 +44,39 @@ def test_failing_launch_program(self):
4444
"'{0}' does not exist".format(program), response["body"]["error"]["format"]
4545
)
4646

47-
def test_failing_launch_commands_and_run_in_terminal(self):
47+
def test_failing_launch_commands_and_console(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()
5353
response = self.launch(
54-
program, launchCommands=["a b c"], runInTerminal=True, expectFailure=True
54+
program,
55+
launchCommands=["a b c"],
56+
console="integratedTerminal",
57+
expectFailure=True,
5558
)
5659
self.assertFalse(response["success"])
5760
self.assertTrue(self.get_dict_value(response, ["body", "error", "showUser"]))
5861
self.assertEqual(
59-
"'launchCommands' and 'runInTerminal' are mutually exclusive",
62+
"'launchCommands' and non-internal 'console' are mutually exclusive",
6063
self.get_dict_value(response, ["body", "error", "format"]),
6164
)
6265

66+
def test_failing_console(self):
67+
"""
68+
Tests launching in console with an invalid terminal type.
69+
"""
70+
program = self.getBuildArtifact("a.out")
71+
self.create_debug_adapter()
72+
response = self.launch(program, console="invalid", expectFailure=True)
73+
self.assertFalse(response["success"])
74+
self.assertTrue(self.get_dict_value(response, ["body", "error", "showUser"]))
75+
self.assertRegex(
76+
response["body"]["error"]["format"],
77+
r"unexpected value, expected 'internalConsole\', 'integratedTerminal\' or 'externalTerminal\' at arguments.console",
78+
)
79+
6380
@skipIfWindows
6481
def test_termination(self):
6582
"""

lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_runInTerminal.py renamed to lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_console.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111

1212
@skipIfBuildType(["debug"])
13-
class TestDAP_restart_runInTerminal(lldbdap_testcase.DAPTestCaseBase):
13+
class TestDAP_restart_console(lldbdap_testcase.DAPTestCaseBase):
1414
def verify_stopped_on_entry(self, stopped_events: List[Dict[str, Any]]):
1515
seen_stopped_event = 0
1616
for stopped_event in stopped_events:
@@ -44,7 +44,7 @@ def test_basic_functionality(self):
4444
line_B = line_number("main.c", "// breakpoint B")
4545

4646
program = self.getBuildArtifact("a.out")
47-
self.build_and_launch(program, runInTerminal=True)
47+
self.build_and_launch(program, console="integratedTerminal")
4848
[bp_A, bp_B] = self.set_source_breakpoints("main.c", [line_A, line_B])
4949

5050
# Verify we hit A, then B.
@@ -86,10 +86,10 @@ def test_basic_functionality(self):
8686
@skipIf(oslist=["linux"], archs=["arm$"]) # Always times out on buildbot
8787
def test_stopOnEntry(self):
8888
"""
89-
Check that stopOnEntry works correctly when using runInTerminal.
89+
Check that stopOnEntry works correctly when using console.
9090
"""
9191
program = self.getBuildArtifact("a.out")
92-
self.build_and_launch(program, runInTerminal=True, stopOnEntry=True)
92+
self.build_and_launch(program, console="integratedTerminal", stopOnEntry=True)
9393
[bp_main] = self.set_function_breakpoints(["main"])
9494

9595
self.dap_server.request_continue() # sends configuration done

lldb/test/API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def test_runInTerminal(self):
3737
program = self.getBuildArtifact("a.out")
3838
source = "main.c"
3939
self.build_and_launch(
40-
program, runInTerminal=True, args=["foobar"], env=["FOO=bar"]
40+
program, console="integratedTerminal", args=["foobar"], env=["FOO=bar"]
4141
)
4242

4343
self.assertEqual(
@@ -83,7 +83,7 @@ def test_runInTerminalWithObjectEnv(self):
8383
launch the inferior with the correct environment variables using an object.
8484
"""
8585
program = self.getBuildArtifact("a.out")
86-
self.build_and_launch(program, runInTerminal=True, env={"FOO": "BAR"})
86+
self.build_and_launch(program, console="integratedTerminal", env={"FOO": "BAR"})
8787

8888
self.assertEqual(
8989
len(self.dap_server.reverse_requests),
@@ -105,7 +105,7 @@ def test_runInTerminalInvalidTarget(self):
105105
self.build_and_create_debug_adapter()
106106
response = self.launch(
107107
"INVALIDPROGRAM",
108-
runInTerminal=True,
108+
console="integratedTerminal",
109109
args=["foobar"],
110110
env=["FOO=bar"],
111111
expectFailure=True,

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ 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.console != protocol::eConsoleInternal)
2728
return make_error<DAPError>(
28-
"'launchCommands' and 'runInTerminal' are mutually exclusive");
29+
"'launchCommands' and non-internal 'console' are mutually exclusive");
2930

3031
dap.SetConfiguration(arguments.configuration, /*is_attach=*/false);
3132
dap.last_launch_request = arguments;

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.console == protocol::eConsoleExternalTerminal);
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.console != protocol::eConsoleInternal) {
196197
if (llvm::Error err = RunInTerminal(dap, arguments))
197198
return err;
198199
} else if (launchCommands.empty()) {

lldb/tools/lldb-dap/JSONUtils.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,12 +1168,16 @@ 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");
1176-
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");
1180+
}
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(),
11791183
"--comm-file", comm_file.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 terminal 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: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,34 @@ json::Value toJSON(const BreakpointLocationsResponseBody &BLRB) {
262262
return json::Object{{"breakpoints", BLRB.breakpoints}};
263263
}
264264

265+
bool fromJSON(const json::Value &Params, Console &C, json::Path P) {
266+
auto oldFormatConsole = Params.getAsBoolean();
267+
if (oldFormatConsole) {
268+
C = *oldFormatConsole ? eConsoleIntegratedTerminal : eConsoleInternal;
269+
return true;
270+
}
271+
auto newFormatConsole = Params.getAsString();
272+
if (!newFormatConsole) {
273+
P.report("expected a string");
274+
return false;
275+
}
276+
277+
std::optional<Console> console =
278+
StringSwitch<std::optional<Console>>(*newFormatConsole)
279+
.Case("internalConsole", eConsoleInternal)
280+
.Case("integratedTerminal", eConsoleIntegratedTerminal)
281+
.Case("externalTerminal", eConsoleExternalTerminal)
282+
.Default(std::nullopt);
283+
if (!console) {
284+
P.report("unexpected value, expected 'internalConsole', "
285+
"'integratedTerminal' or 'externalTerminal'");
286+
return false;
287+
}
288+
289+
C = *console;
290+
return true;
291+
}
292+
265293
bool fromJSON(const json::Value &Params, LaunchRequestArguments &LRA,
266294
json::Path P) {
267295
json::ObjectMapper O(Params, P);
@@ -273,9 +301,8 @@ bool fromJSON(const json::Value &Params, LaunchRequestArguments &LRA,
273301
O.mapOptional("disableASLR", LRA.disableASLR) &&
274302
O.mapOptional("disableSTDIO", LRA.disableSTDIO) &&
275303
O.mapOptional("shellExpandArguments", LRA.shellExpandArguments) &&
276-
277-
O.mapOptional("runInTerminal", LRA.runInTerminal) &&
278-
parseEnv(Params, LRA.env, P);
304+
O.mapOptional("runInTerminal", LRA.console) &&
305+
O.mapOptional("console", LRA.console) && parseEnv(Params, LRA.env, P);
279306
}
280307

281308
bool fromJSON(const json::Value &Params, AttachRequestArguments &ARA,

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

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

245+
enum Console : unsigned {
246+
eConsoleInternal,
247+
eConsoleIntegratedTerminal,
248+
eConsoleExternalTerminal
249+
};
250+
245251
/// lldb-dap specific launch arguments.
246252
struct LaunchRequestArguments {
247253
/// Common lldb-dap configuration values for launching/attaching operations.
@@ -290,9 +296,9 @@ struct LaunchRequestArguments {
290296
/// Set whether to shell expand arguments to the process when launching.
291297
bool shellExpandArguments = false;
292298

293-
/// Launch the program inside an integrated terminal in the IDE. Useful for
294-
/// debugging interactive command line programs.
295-
bool runInTerminal = false;
299+
/// Specify where to launch the program: internal console, integrated
300+
/// terminal or external terminal.
301+
Console console = eConsoleInternal;
296302

297303
/// @}
298304
};

0 commit comments

Comments
 (0)