Skip to content

Commit 044feb8

Browse files
committed
[lldb] Implement a statusline in LLDB (llvm#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 (cherry picked from commit 9c18edc)
1 parent 2e09c69 commit 044feb8

File tree

17 files changed

+480
-136
lines changed

17 files changed

+480
-136
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"
@@ -307,6 +308,10 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
307308

308309
bool SetShowProgress(bool show_progress);
309310

311+
bool GetShowStatusline() const;
312+
313+
const FormatEntity::Entry *GetStatuslineFormat() const;
314+
310315
llvm::StringRef GetShowProgressAnsiPrefix() const;
311316

312317
llvm::StringRef GetShowProgressAnsiSuffix() const;
@@ -420,6 +425,9 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
420425
/// Decrement the "interrupt requested" counter.
421426
void CancelInterruptRequest();
422427

428+
/// Redraw the statusline if enabled.
429+
void RedrawStatusline(bool update = true);
430+
423431
/// This is the correct way to query the state of Interruption.
424432
/// If you are on the RunCommandInterpreter thread, it will check the
425433
/// command interpreter state, and if it is on another thread it will
@@ -607,12 +615,21 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
607615
return m_source_file_cache;
608616
}
609617

618+
struct ProgressReport {
619+
uint64_t id;
620+
uint64_t completed;
621+
uint64_t total;
622+
std::string message;
623+
};
624+
std::optional<ProgressReport> GetCurrentProgressReport() const;
625+
610626
protected:
611627
friend class CommandInterpreter;
612628
friend class SwiftREPL;
613629
friend class REPL;
614630
friend class Progress;
615631
friend class ProgressManager;
632+
friend class Statusline;
616633

617634
/// Report progress events.
618635
///
@@ -665,6 +682,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
665682
lldb::LockableStreamFileSP GetErrorStreamSP() { return m_error_stream_sp; }
666683
/// @}
667684

685+
bool StatuslineSupported();
686+
668687
void PushIOHandler(const lldb::IOHandlerSP &reader_sp,
669688
bool cancel_top_handler = true);
670689

@@ -741,7 +760,7 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
741760
IOHandlerStack m_io_handler_stack;
742761
std::recursive_mutex m_io_handler_synchronous_mutex;
743762

744-
std::optional<uint64_t> m_current_event_id;
763+
std::optional<Statusline> m_statusline;
745764

746765
llvm::StringMap<std::weak_ptr<LogHandler>> m_stream_handlers;
747766
std::shared_ptr<CallbackLogHandler> m_callback_handler_sp;
@@ -758,6 +777,12 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
758777
lldb::TargetSP m_dummy_target_sp;
759778
Diagnostics::CallbackID m_diagnostics_callback_id;
760779

780+
/// Bookkeeping for command line progress events.
781+
/// @{
782+
llvm::SmallVector<ProgressReport, 4> m_progress_reports;
783+
mutable std::mutex m_progress_reports_mutex;
784+
/// @}
785+
761786
std::mutex m_destroy_callback_mutex;
762787
lldb::callback_token_t m_destroy_callback_next_token = 0;
763788
struct DestroyCallbackInfo {

lldb/include/lldb/Core/FormatEntity.h

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

105107
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: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,10 @@ def setUpCommands(cls):
771771
'settings set symbols.clang-modules-cache-path "{}"'.format(
772772
configuration.lldb_module_cache_dir
773773
),
774+
# Disable colors by default.
775+
"settings set use-color false",
776+
# Disable the statusline by default.
777+
"settings set show-statusline false",
774778
# Enable the swift metadata cache in order to speed up tests.
775779
"settings set symbols.enable-swift-metadata-cache true",
776780
'settings set symbols.swift-metadata-cache-path "{}"'.format(
@@ -779,7 +783,6 @@ def setUpCommands(cls):
779783
# Enable expensive validations in TypeSystemSwiftTypeRef.
780784
"settings set symbols.swift-validate-typesystem true",
781785
"settings set symbols.swift-typesystem-compiler-fallback true",
782-
"settings set use-color false",
783786
]
784787

785788
# Set any user-overridden settings.

lldb/source/Core/CMakeLists.txt

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

lldb/source/Core/CoreProperties.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,14 @@ let Definition = "debugger" in {
225225
Global,
226226
DefaultStringValue<"${ansi.normal}">,
227227
Desc<"When displaying progress in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the progress message.">;
228+
def ShowStatusline: Property<"show-statusline", "Boolean">,
229+
Global,
230+
DefaultTrue,
231+
Desc<"Whether to show a statusline at the bottom of the terminal.">;
232+
def StatuslineFormat: Property<"statusline-format", "FormatEntity">,
233+
Global,
234+
DefaultStringValue<"${ansi.bg.blue}${ansi.fg.black}{${target.file.basename}}{ | ${line.file.basename}:${line.number}:${line.column}}{ | ${thread.stop-reason}}{ | {${progress.count} }${progress.message}}">,
235+
Desc<"The default statusline format string.">;
228236
def UseSourceCache: Property<"use-source-cache", "Boolean">,
229237
Global,
230238
DefaultTrue,

0 commit comments

Comments
 (0)