Skip to content

Commit 9c18edc

Browse files
authored
[lldb] Implement a statusline in LLDB (#121860)
Add a statusline to command-line LLDB to display information about the current state of the debugger. The statusline is a dedicated area displayed at the bottom of the screen. The information displayed is configurable through a setting consisting of LLDB’s format strings. Enablement ---------- The statusline is enabled by default, but can be disabled with the following setting: ``` (lldb) settings set show-statusline false ``` Configuration ------------- The statusline is configurable through the `statusline-format` setting. The default configuration shows the target name, the current file, the stop reason and any ongoing progress events. ``` (lldb) settings show statusline-format statusline-format (format-string) = "${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}" ``` The statusline supersedes the current progress reporting implementation. Consequently, the following settings no longer have any effect (but continue to exist to not break anyone's `.lldbinit`): ``` show-progress -- Whether to show progress or not if the debugger's output is an interactive color-enabled terminal. show-progress-ansi-prefix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the progress message. show-progress-ansi-suffix -- When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message. ``` Format Strings -------------- LLDB's format strings are documented in the LLDB documentation and on the website: https://lldb.llvm.org/use/formatting.html#format-strings. The current implementation is relatively limited but various improvements have been discussed in the RFC. One such improvement is being to display a string when a format string is empty. Right now, when launching LLDB without a target, the statusline will be empty, which is expected, but looks rather odd. RFC --- The full RFC can be found on Discourse: https://discourse.llvm.org/t/rfc-lldb-statusline/83948
1 parent 38aac86 commit 9c18edc

File tree

17 files changed

+479
-135
lines changed

17 files changed

+479
-135
lines changed

lldb/include/lldb/Core/Debugger.h

Lines changed: 26 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"
@@ -303,6 +304,10 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
303304

304305
bool SetShowProgress(bool show_progress);
305306

307+
bool GetShowStatusline() const;
308+
309+
const FormatEntity::Entry *GetStatuslineFormat() const;
310+
306311
llvm::StringRef GetShowProgressAnsiPrefix() const;
307312

308313
llvm::StringRef GetShowProgressAnsiSuffix() const;
@@ -412,6 +417,9 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
412417
/// Decrement the "interrupt requested" counter.
413418
void CancelInterruptRequest();
414419

420+
/// Redraw the statusline if enabled.
421+
void RedrawStatusline(bool update = true);
422+
415423
/// This is the correct way to query the state of Interruption.
416424
/// If you are on the RunCommandInterpreter thread, it will check the
417425
/// command interpreter state, and if it is on another thread it will
@@ -599,11 +607,20 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
599607
return m_source_file_cache;
600608
}
601609

610+
struct ProgressReport {
611+
uint64_t id;
612+
uint64_t completed;
613+
uint64_t total;
614+
std::string message;
615+
};
616+
std::optional<ProgressReport> GetCurrentProgressReport() const;
617+
602618
protected:
603619
friend class CommandInterpreter;
604620
friend class REPL;
605621
friend class Progress;
606622
friend class ProgressManager;
623+
friend class Statusline;
607624

608625
/// Report progress events.
609626
///
@@ -656,6 +673,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
656673
lldb::LockableStreamFileSP GetErrorStreamSP() { return m_error_stream_sp; }
657674
/// @}
658675

676+
bool StatuslineSupported();
677+
659678
void PushIOHandler(const lldb::IOHandlerSP &reader_sp,
660679
bool cancel_top_handler = true);
661680

@@ -732,7 +751,7 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
732751
IOHandlerStack m_io_handler_stack;
733752
std::recursive_mutex m_io_handler_synchronous_mutex;
734753

735-
std::optional<uint64_t> m_current_event_id;
754+
std::optional<Statusline> m_statusline;
736755

737756
llvm::StringMap<std::weak_ptr<LogHandler>> m_stream_handlers;
738757
std::shared_ptr<CallbackLogHandler> m_callback_handler_sp;
@@ -749,6 +768,12 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
749768
lldb::TargetSP m_dummy_target_sp;
750769
Diagnostics::CallbackID m_diagnostics_callback_id;
751770

771+
/// Bookkeeping for command line progress events.
772+
/// @{
773+
llvm::SmallVector<ProgressReport, 4> m_progress_reports;
774+
mutable std::mutex m_progress_reports_mutex;
775+
/// @}
776+
752777
std::mutex m_destroy_callback_mutex;
753778
lldb::callback_token_t m_destroy_callback_next_token = 0;
754779
struct DestroyCallbackInfo {

lldb/include/lldb/Core/FormatEntity.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,9 @@ struct Entry {
100100
LineEntryColumn,
101101
LineEntryStartAddress,
102102
LineEntryEndAddress,
103-
CurrentPCArrow
103+
CurrentPCArrow,
104+
ProgressCount,
105+
ProgressMessage,
104106
};
105107

106108
struct Definition {

lldb/include/lldb/Core/IOHandler.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,8 @@ class IOHandlerEditline : public IOHandler {
406406
std::optional<std::string> SuggestionCallback(llvm::StringRef line);
407407

408408
void AutoCompleteCallback(CompletionRequest &request);
409+
410+
void RedrawCallback();
409411
#endif
410412

411413
protected:

lldb/include/lldb/Core/Statusline.h

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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+
9+
#ifndef LLDB_CORE_STATUSLINE_H
10+
#define LLDB_CORE_STATUSLINE_H
11+
12+
#include "lldb/lldb-forward.h"
13+
#include "llvm/ADT/StringRef.h"
14+
#include <csignal>
15+
#include <cstdint>
16+
#include <string>
17+
18+
namespace lldb_private {
19+
class Statusline {
20+
public:
21+
Statusline(Debugger &debugger);
22+
~Statusline();
23+
24+
/// Reduce the scroll window and draw the statusline.
25+
void Enable();
26+
27+
/// Hide the statusline and extend the scroll window.
28+
void Disable();
29+
30+
/// Redraw the statusline. If update is false, this will redraw the last
31+
/// string.
32+
void Redraw(bool update = true);
33+
34+
/// Inform the statusline that the terminal dimensions have changed.
35+
void TerminalSizeChanged();
36+
37+
protected:
38+
/// Pad and trim the given string to fit to the given width.
39+
static std::string TrimAndPad(std::string str, size_t width);
40+
41+
private:
42+
/// Draw the statusline with the given text.
43+
void Draw(std::string msg);
44+
45+
/// Update terminal dimensions.
46+
void UpdateTerminalProperties();
47+
48+
enum ScrollWindowMode {
49+
ScrollWindowExtend,
50+
ScrollWindowShrink,
51+
};
52+
53+
/// Set the scroll window for the given mode.
54+
void UpdateScrollWindow(ScrollWindowMode mode);
55+
56+
/// Clear the statusline (without redrawing the background).
57+
void Reset();
58+
59+
Debugger &m_debugger;
60+
std::string m_last_str;
61+
62+
volatile std::sig_atomic_t m_terminal_size_has_changed = 1;
63+
uint64_t m_terminal_width = 0;
64+
uint64_t m_terminal_height = 0;
65+
};
66+
} // namespace lldb_private
67+
#endif // LLDB_CORE_STATUSLINE_H

lldb/include/lldb/Host/Editline.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ using SuggestionCallbackType =
102102

103103
using CompleteCallbackType = llvm::unique_function<void(CompletionRequest &)>;
104104

105+
using RedrawCallbackType = llvm::unique_function<void()>;
106+
105107
/// Status used to decide when and how to start editing another line in
106108
/// multi-line sessions.
107109
enum class EditorStatus {
@@ -194,6 +196,11 @@ class Editline {
194196
m_suggestion_callback = std::move(callback);
195197
}
196198

199+
/// Register a callback for redrawing the statusline.
200+
void SetRedrawCallback(RedrawCallbackType callback) {
201+
m_redraw_callback = std::move(callback);
202+
}
203+
197204
/// Register a callback for the tab key
198205
void SetAutoCompleteCallback(CompleteCallbackType callback) {
199206
m_completion_callback = std::move(callback);
@@ -409,6 +416,7 @@ class Editline {
409416

410417
CompleteCallbackType m_completion_callback;
411418
SuggestionCallbackType m_suggestion_callback;
419+
RedrawCallbackType m_redraw_callback;
412420

413421
bool m_color;
414422
std::string m_prompt_ansi_prefix;

lldb/packages/Python/lldbsuite/test/lldbtest.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,7 +772,10 @@ def setUpCommands(cls):
772772
'settings set symbols.clang-modules-cache-path "{}"'.format(
773773
configuration.lldb_module_cache_dir
774774
),
775+
# Disable colors by default.
775776
"settings set use-color false",
777+
# Disable the statusline by default.
778+
"settings set show-statusline false",
776779
]
777780

778781
# Set any user-overridden settings.

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", "FormatEntity">,
180+
Global,
181+
DefaultStringValue<"${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}">,
182+
Desc<"The default statusline format string.">;
175183
def UseSourceCache: Property<"use-source-cache", "Boolean">,
176184
Global,
177185
DefaultTrue,

0 commit comments

Comments
 (0)