Skip to content

Commit 2e12634

Browse files
committed
Add statusline
1 parent 82c5d98 commit 2e12634

File tree

6 files changed

+312
-80
lines changed

6 files changed

+312
-80
lines changed

lldb/include/lldb/Core/Debugger.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "lldb/Core/FormatEntity.h"
2020
#include "lldb/Core/IOHandler.h"
2121
#include "lldb/Core/SourceManager.h"
22+
#include "lldb/Core/Statusline.h"
2223
#include "lldb/Core/UserSettingsController.h"
2324
#include "lldb/Host/HostThread.h"
2425
#include "lldb/Host/StreamFile.h"
@@ -308,6 +309,10 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
308309

309310
bool SetShowProgress(bool show_progress);
310311

312+
bool GetShowStatusline() const;
313+
314+
std::vector<FormatEntity::Entry> GetStatuslineFormat() const;
315+
311316
llvm::StringRef GetShowProgressAnsiPrefix() const;
312317

313318
llvm::StringRef GetShowProgressAnsiSuffix() const;
@@ -728,7 +733,7 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
728733
IOHandlerStack m_io_handler_stack;
729734
std::recursive_mutex m_io_handler_synchronous_mutex;
730735

731-
std::optional<uint64_t> m_current_event_id;
736+
std::optional<Statusline> m_statusline;
732737

733738
llvm::StringMap<std::weak_ptr<LogHandler>> m_stream_handlers;
734739
std::shared_ptr<CallbackLogHandler> m_callback_handler_sp;
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//===-- Statusline.h -----------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
#include "lldb/Core/Debugger.h"
9+
#include "llvm/ADT/SmallVector.h"
10+
#include <string>
11+
#ifndef LLDB_CORE_STATUSBAR_H
12+
#define LLDB_CORE_STATUSBAR_H
13+
14+
namespace lldb_private {
15+
class Statusline {
16+
public:
17+
Statusline(Debugger &debugger);
18+
~Statusline();
19+
20+
void Enable();
21+
void Disable();
22+
23+
void Clear();
24+
void Update();
25+
26+
void ReportProgress(const ProgressEventData &data);
27+
28+
void TerminalSizeChanged() { m_terminal_size_has_changed = 1; }
29+
30+
private:
31+
// Draw the statusline with the given text.
32+
void Draw(llvm::StringRef msg);
33+
34+
// Update terminal dimensions.
35+
void UpdateTerminalProperties();
36+
37+
// Set the scroll window to the given height.
38+
void SetScrollWindow(uint64_t height);
39+
40+
// Write at the given column.
41+
void AddAtPosition(uint64_t col, llvm::StringRef str);
42+
43+
// Clear the statusline (without redrawing the background).
44+
void Reset();
45+
46+
bool IsSupported() const;
47+
48+
lldb::thread_result_t StatuslineThread();
49+
50+
Debugger &m_debugger;
51+
52+
struct ProgressReport {
53+
uint64_t id;
54+
std::string message;
55+
};
56+
llvm::SmallVector<ProgressReport, 8> m_progress_reports;
57+
std::optional<ProgressReport> m_progress_report;
58+
59+
volatile std::sig_atomic_t m_terminal_size_has_changed = 1;
60+
uint64_t m_terminal_width = 0;
61+
uint64_t m_terminal_height = 0;
62+
uint64_t m_scroll_height = 0;
63+
64+
std::string m_ansi_prefix = "${ansi.bg.cyan}${ansi.fg.black}";
65+
std::string m_ansi_suffix = "${ansi.normal}";
66+
llvm::SmallVector<FormatEntity::Entry> m_components;
67+
};
68+
} // namespace lldb_private
69+
#endif // LLDB_CORE_STATUSBAR_H

lldb/source/Core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ add_lldb_library(lldbCore
4646
Opcode.cpp
4747
PluginManager.cpp
4848
Progress.cpp
49+
Statusline.cpp
4950
RichManglingContext.cpp
5051
SearchFilter.cpp
5152
Section.cpp

lldb/source/Core/CoreProperties.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,14 @@ let Definition = "debugger" in {
172172
Global,
173173
DefaultStringValue<"${ansi.normal}">,
174174
Desc<"When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.">;
175+
def ShowStatusline: Property<"show-statusline", "Boolean">,
176+
Global,
177+
DefaultTrue,
178+
Desc<"Whether to show a statusline at the bottom of the terminal.">;
179+
def StatuslineFormat: Property<"statusline-format", "FormatEntityList">,
180+
Global,
181+
DefaultStringValue<"${target.file.basename} ${line.file.basename}:${line.number}:${line.column} ${thread.stop-reason}">,
182+
Desc<"List of statusline format entities.">;
175183
def UseSourceCache: Property<"use-source-cache", "Boolean">,
176184
Global,
177185
DefaultTrue,

lldb/source/Core/Debugger.cpp

Lines changed: 36 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,8 @@ bool Debugger::SetTerminalWidth(uint64_t term_width) {
376376

377377
if (auto handler_sp = m_io_handler_stack.Top())
378378
handler_sp->TerminalSizeChanged();
379+
if (m_statusline)
380+
m_statusline->TerminalSizeChanged();
379381

380382
return success;
381383
}
@@ -392,6 +394,8 @@ bool Debugger::SetTerminalHeight(uint64_t term_height) {
392394

393395
if (auto handler_sp = m_io_handler_stack.Top())
394396
handler_sp->TerminalSizeChanged();
397+
if (m_statusline)
398+
m_statusline->TerminalSizeChanged();
395399

396400
return success;
397401
}
@@ -454,6 +458,17 @@ llvm::StringRef Debugger::GetShowProgressAnsiSuffix() const {
454458
idx, g_debugger_properties[idx].default_cstr_value);
455459
}
456460

461+
bool Debugger::GetShowStatusline() const {
462+
const uint32_t idx = ePropertyShowStatusline;
463+
return GetPropertyAtIndexAs<bool>(
464+
idx, g_debugger_properties[idx].default_uint_value != 0);
465+
}
466+
467+
std::vector<FormatEntity::Entry> Debugger::GetStatuslineFormat() const {
468+
const uint32_t idx = ePropertyStatuslineFormat;
469+
return GetPropertyAtIndexAs<std::vector<FormatEntity::Entry>>(idx, {});
470+
}
471+
457472
bool Debugger::GetUseAutosuggestion() const {
458473
const uint32_t idx = ePropertyShowAutosuggestion;
459474
return GetPropertyAtIndexAs<bool>(
@@ -1093,12 +1108,18 @@ void Debugger::SetErrorFile(FileSP file_sp) {
10931108
}
10941109

10951110
void Debugger::SaveInputTerminalState() {
1111+
if (m_statusline)
1112+
m_statusline->Disable();
10961113
int fd = GetInputFile().GetDescriptor();
10971114
if (fd != File::kInvalidDescriptor)
10981115
m_terminal_state.Save(fd, true);
10991116
}
11001117

1101-
void Debugger::RestoreInputTerminalState() { m_terminal_state.Restore(); }
1118+
void Debugger::RestoreInputTerminalState() {
1119+
m_terminal_state.Restore();
1120+
if (m_statusline)
1121+
m_statusline->Enable();
1122+
}
11021123

11031124
ExecutionContext Debugger::GetSelectedExecutionContext() {
11041125
bool adopt_selected = true;
@@ -1958,6 +1979,12 @@ lldb::thread_result_t Debugger::DefaultEventHandler() {
19581979
// are now listening to all required events so no events get missed
19591980
m_sync_broadcaster.BroadcastEvent(eBroadcastBitEventThreadIsListening);
19601981

1982+
if (!m_statusline && GetShowStatusline())
1983+
m_statusline.emplace(*this);
1984+
1985+
if (m_statusline)
1986+
m_statusline->Enable();
1987+
19611988
bool done = false;
19621989
while (!done) {
19631990
EventSP event_sp;
@@ -2016,8 +2043,14 @@ lldb::thread_result_t Debugger::DefaultEventHandler() {
20162043
if (m_forward_listener_sp)
20172044
m_forward_listener_sp->AddEvent(event_sp);
20182045
}
2046+
if (m_statusline)
2047+
m_statusline->Update();
20192048
}
20202049
}
2050+
2051+
if (m_statusline)
2052+
m_statusline->Disable();
2053+
20212054
return {};
20222055
}
20232056

@@ -2080,84 +2113,8 @@ void Debugger::HandleProgressEvent(const lldb::EventSP &event_sp) {
20802113
if (!data)
20812114
return;
20822115

2083-
// Do some bookkeeping for the current event, regardless of whether we're
2084-
// going to show the progress.
2085-
const uint64_t id = data->GetID();
2086-
if (m_current_event_id) {
2087-
Log *log = GetLog(LLDBLog::Events);
2088-
if (log && log->GetVerbose()) {
2089-
StreamString log_stream;
2090-
log_stream.AsRawOstream()
2091-
<< static_cast<void *>(this) << " Debugger(" << GetID()
2092-
<< ")::HandleProgressEvent( m_current_event_id = "
2093-
<< *m_current_event_id << ", data = { ";
2094-
data->Dump(&log_stream);
2095-
log_stream << " } )";
2096-
log->PutString(log_stream.GetString());
2097-
}
2098-
if (id != *m_current_event_id)
2099-
return;
2100-
if (data->GetCompleted() == data->GetTotal())
2101-
m_current_event_id.reset();
2102-
} else {
2103-
m_current_event_id = id;
2104-
}
2105-
2106-
// Decide whether we actually are going to show the progress. This decision
2107-
// can change between iterations so check it inside the loop.
2108-
if (!GetShowProgress())
2109-
return;
2110-
2111-
// Determine whether the current output file is an interactive terminal with
2112-
// color support. We assume that if we support ANSI escape codes we support
2113-
// vt100 escape codes.
2114-
File &file = GetOutputFile();
2115-
if (!file.GetIsInteractive() || !file.GetIsTerminalWithColors())
2116-
return;
2117-
2118-
StreamSP output = GetAsyncOutputStream();
2119-
2120-
// Print over previous line, if any.
2121-
output->Printf("\r");
2122-
2123-
if (data->GetCompleted() == data->GetTotal()) {
2124-
// Clear the current line.
2125-
output->Printf("\x1B[2K");
2126-
output->Flush();
2127-
return;
2128-
}
2129-
2130-
// Trim the progress message if it exceeds the window's width and print it.
2131-
std::string message = data->GetMessage();
2132-
if (data->IsFinite())
2133-
message = llvm::formatv("[{0}/{1}] {2}", data->GetCompleted(),
2134-
data->GetTotal(), message)
2135-
.str();
2136-
2137-
// Trim the progress message if it exceeds the window's width and print it.
2138-
const uint32_t term_width = GetTerminalWidth();
2139-
const uint32_t ellipsis = 3;
2140-
if (message.size() + ellipsis >= term_width)
2141-
message.resize(term_width - ellipsis);
2142-
2143-
const bool use_color = GetUseColor();
2144-
llvm::StringRef ansi_prefix = GetShowProgressAnsiPrefix();
2145-
if (!ansi_prefix.empty())
2146-
output->Printf(
2147-
"%s", ansi::FormatAnsiTerminalCodes(ansi_prefix, use_color).c_str());
2148-
2149-
output->Printf("%s...", message.c_str());
2150-
2151-
llvm::StringRef ansi_suffix = GetShowProgressAnsiSuffix();
2152-
if (!ansi_suffix.empty())
2153-
output->Printf(
2154-
"%s", ansi::FormatAnsiTerminalCodes(ansi_suffix, use_color).c_str());
2155-
2156-
// Clear until the end of the line.
2157-
output->Printf("\x1B[K\r");
2158-
2159-
// Flush the output.
2160-
output->Flush();
2116+
if (m_statusline)
2117+
m_statusline->ReportProgress(*data);
21612118
}
21622119

21632120
void Debugger::HandleDiagnosticEvent(const lldb::EventSP &event_sp) {

0 commit comments

Comments
 (0)