Skip to content

Commit 578c03f

Browse files
authored
[lldb] Support OSC escape codes for native progress (#162162)
This PR adds support for emitting the OSC `9;4` sequences to show a GUI native progress bar. There's a limited number of terminal emulators that support this, so for now this requires explicit opt-in through a setting. I'm reusing the existing `show-progress` setting, which became a NOOP with the introduction of the statusline. The option now defaults to off. Implements #160369
1 parent ce8abef commit 578c03f

File tree

5 files changed

+60
-14
lines changed

5 files changed

+60
-14
lines changed

lldb/include/lldb/Core/Debugger.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,7 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
682682
lldb::LockableStreamFileSP GetErrorStreamSP() { return m_error_stream_sp; }
683683
/// @}
684684

685+
bool IsEscapeCodeCapableTTY();
685686
bool StatuslineSupported();
686687

687688
void PushIOHandler(const lldb::IOHandlerSP &reader_sp,

lldb/include/lldb/Utility/AnsiTerminal.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,17 @@
7272

7373
#define ANSI_ESC_START_LEN 2
7474

75+
// OSC (Operating System Commands)
76+
// https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
77+
#define OSC_ESCAPE_START "\033"
78+
#define OSC_ESCAPE_END "\x07"
79+
80+
// https://conemu.github.io/en/AnsiEscapeCodes.html#ConEmu_specific_OSC
81+
#define OSC_PROGRESS_REMOVE OSC_ESCAPE_START "]9;4;0;0" OSC_ESCAPE_END
82+
#define OSC_PROGRESS_SHOW OSC_ESCAPE_START "]9;4;1;%u" OSC_ESCAPE_END
83+
#define OSC_PROGRESS_ERROR OSC_ESCAPE_START "]9;4;2;%u" OSC_ESCAPE_END
84+
#define OSC_PROGRESS_INDETERMINATE OSC_ESCAPE_START "]9;4;3;%u" OSC_ESCAPE_END
85+
7586
#include "llvm/ADT/ArrayRef.h"
7687
#include "llvm/ADT/STLExtras.h"
7788
#include "llvm/ADT/StringRef.h"

lldb/source/Core/CoreProperties.td

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,12 @@ let Definition = "debugger" in {
162162
Global,
163163
DefaultTrue,
164164
Desc<"Whether to use Ansi color codes or not.">;
165-
def ShowProgress: Property<"show-progress", "Boolean">,
166-
Global,
167-
DefaultTrue,
168-
Desc<"Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.">;
165+
def ShowProgress
166+
: Property<"show-progress", "Boolean">,
167+
Global,
168+
DefaultFalse,
169+
Desc<"Whether to show progress using Operating System Command (OSC) "
170+
"Sequences in supporting terminal emulators.">;
169171
def ShowProgressAnsiPrefix: Property<"show-progress-ansi-prefix", "String">,
170172
Global,
171173
DefaultStringValue<"${ansi.faint}">,

lldb/source/Core/Debugger.cpp

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2066,19 +2066,23 @@ void Debugger::CancelForwardEvents(const ListenerSP &listener_sp) {
20662066
m_forward_listener_sp.reset();
20672067
}
20682068

2069+
bool Debugger::IsEscapeCodeCapableTTY() {
2070+
if (lldb::LockableStreamFileSP stream_sp = GetOutputStreamSP()) {
2071+
File &file = stream_sp->GetUnlockedFile();
2072+
return file.GetIsInteractive() && file.GetIsRealTerminal() &&
2073+
file.GetIsTerminalWithColors();
2074+
}
2075+
return false;
2076+
}
2077+
20692078
bool Debugger::StatuslineSupported() {
20702079
// We have trouble with the contol codes on Windows, see
20712080
// https://github.com/llvm/llvm-project/issues/134846.
20722081
#ifndef _WIN32
2073-
if (GetShowStatusline()) {
2074-
if (lldb::LockableStreamFileSP stream_sp = GetOutputStreamSP()) {
2075-
File &file = stream_sp->GetUnlockedFile();
2076-
return file.GetIsInteractive() && file.GetIsRealTerminal() &&
2077-
file.GetIsTerminalWithColors();
2078-
}
2079-
}
2080-
#endif
2082+
return GetShowStatusline() && IsEscapeCodeCapableTTY();
2083+
#else
20812084
return false;
2085+
#endif
20822086
}
20832087

20842088
static bool RequiresFollowChildWorkaround(const Process &process) {
@@ -2271,10 +2275,11 @@ void Debugger::HandleProgressEvent(const lldb::EventSP &event_sp) {
22712275
ProgressReport progress_report{data->GetID(), data->GetCompleted(),
22722276
data->GetTotal(), data->GetMessage()};
22732277

2274-
// Do some bookkeeping regardless of whether we're going to display
2275-
// progress reports.
22762278
{
22772279
std::lock_guard<std::mutex> guard(m_progress_reports_mutex);
2280+
2281+
// Do some bookkeeping regardless of whether we're going to display
2282+
// progress reports.
22782283
auto it = llvm::find_if(m_progress_reports, [&](const auto &report) {
22792284
return report.id == progress_report.id;
22802285
});
@@ -2287,6 +2292,30 @@ void Debugger::HandleProgressEvent(const lldb::EventSP &event_sp) {
22872292
} else {
22882293
m_progress_reports.push_back(progress_report);
22892294
}
2295+
2296+
// Show progress using Operating System Command (OSC) sequences.
2297+
if (GetShowProgress() && IsEscapeCodeCapableTTY()) {
2298+
if (lldb::LockableStreamFileSP stream_sp = GetOutputStreamSP()) {
2299+
2300+
// Clear progress if this was the last progress event.
2301+
if (m_progress_reports.empty()) {
2302+
stream_sp->Lock() << OSC_PROGRESS_REMOVE;
2303+
return;
2304+
}
2305+
2306+
const ProgressReport &report = m_progress_reports.back();
2307+
2308+
// Show indeterminate progress.
2309+
if (report.total == UINT64_MAX) {
2310+
stream_sp->Lock() << OSC_PROGRESS_INDETERMINATE;
2311+
return;
2312+
}
2313+
2314+
// Compute and show the progress value (0-100).
2315+
const unsigned value = (report.completed / report.total) * 100;
2316+
stream_sp->Lock().Printf(OSC_PROGRESS_SHOW, value);
2317+
}
2318+
}
22902319
}
22912320
}
22922321

llvm/docs/ReleaseNotes.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,9 @@ Changes to LLDB
170170

171171
* LLDB can now set breakpoints, show backtraces, and display variables when
172172
debugging Wasm with supported runtimes (WAMR and V8).
173+
* The `show-progress` setting, which became a NOOP with the introduction of the
174+
statusline, now defaults to off and controls using OSC escape codes to show a
175+
native progress bar in supporting terminals like Ghostty and ConEmu.
173176

174177
Changes to BOLT
175178
---------------------------------

0 commit comments

Comments
 (0)