LLDB mainline
Statusline.cpp
Go to the documentation of this file.
1//===-- Statusline.cpp ---------------------------------------------------===//
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
10#include "lldb/Core/Debugger.h"
15#include "lldb/Target/Process.h"
19#include "llvm/ADT/StringRef.h"
20#include "llvm/Support/Locale.h"
21
22#define ESCAPE "\x1b"
23#define ANSI_NORMAL ESCAPE "[0m"
24#define ANSI_SAVE_CURSOR ESCAPE "7"
25#define ANSI_RESTORE_CURSOR ESCAPE "8"
26#define ANSI_CLEAR_BELOW ESCAPE "[J"
27#define ANSI_CLEAR_SCREEN ESCAPE "[2J"
28#define ANSI_SET_SCROLL_ROWS ESCAPE "[1;%ur"
29#define ANSI_TO_START_OF_ROW ESCAPE "[%u;1f"
30#define ANSI_REVERSE_VIDEO ESCAPE "[7m"
31#define ANSI_UP_ROWS ESCAPE "[%dA"
32#define ANSI_DISABLE_AUTO_WRAP ESCAPE "[?7l"
33#define ANSI_ENABLE_AUTO_WRAP ESCAPE "[?7h"
34
35using namespace lldb;
36using namespace lldb_private;
37
39 : m_debugger(debugger), m_terminal_width(m_debugger.GetTerminalWidth()),
40 m_terminal_height(m_debugger.GetTerminalHeight()) {}
41
43
45 // The dimensions the statusline was last drawn at, needed to clear it before
46 // redrawing at the new size.
47 const uint64_t prev_width = m_terminal_width;
48 const uint64_t prev_height = m_terminal_height;
49
50 m_terminal_width = m_debugger.GetTerminalWidth();
51 m_terminal_height = m_debugger.GetTerminalHeight();
52
53 UpdateScrollWindow(ResizeStatusline, prev_width, prev_height);
54
55 // Redraw the old statusline.
56 Redraw(std::nullopt);
57}
58
59void Statusline::Enable(std::optional<ExecutionContextRef> exe_ctx_ref) {
60 // Reduce the scroll window to make space for the status bar below.
62
63 // Draw the statusline.
64 Redraw(exe_ctx_ref);
65}
66
68 // Extend the scroll window to cover the status bar.
70}
71
72void Statusline::Draw(std::string str) {
73 lldb::LockableStreamFileSP stream_sp = m_debugger.GetOutputStreamSP();
74 if (!stream_sp)
75 return;
76
78
79 LockedStreamFile locked_stream = stream_sp->Lock();
80 locked_stream << ANSI_SAVE_CURSOR;
81 // A statusline wider than the terminal (e.g. a stale width mid-resize) would
82 // wrap onto the row above; with autowrap off it is clipped at the margin.
83 locked_stream << ANSI_DISABLE_AUTO_WRAP;
84 locked_stream.Printf(ANSI_TO_START_OF_ROW,
85 static_cast<unsigned>(m_terminal_height));
86
87 // Use "reverse video" to make sure the statusline has a background. Only do
88 // this when colors are disabled, and rely on the statusline format otherwise.
89 if (!m_debugger.GetUseColor())
90 locked_stream << ANSI_REVERSE_VIDEO;
91
92 locked_stream << str;
93 locked_stream << ANSI_NORMAL;
94 locked_stream << ANSI_ENABLE_AUTO_WRAP;
95 locked_stream << ANSI_RESTORE_CURSOR;
96}
97
98void Statusline::UpdateScrollWindow(ScrollWindowMode mode, uint64_t prev_width,
99 uint64_t prev_height) {
100 assert(m_terminal_width != 0 && m_terminal_height != 0);
101
102 lldb::LockableStreamFileSP stream_sp = m_debugger.GetOutputStreamSP();
103 if (!stream_sp)
104 return;
105
106 const unsigned reduced_scroll_rows = m_terminal_height - 1;
107 { // Scope for locked_stream:
108 LockedStreamFile locked_stream = stream_sp->Lock();
109
110 switch (mode) {
111 case EnableStatusline:
112 // Move everything on the screen up.
113 locked_stream << '\n';
114 locked_stream.Printf(ANSI_UP_ROWS, 1);
115 // Reduce the scroll window.
116 locked_stream << ANSI_SAVE_CURSOR;
117 locked_stream.Printf(ANSI_SET_SCROLL_ROWS, reduced_scroll_rows);
118 locked_stream << ANSI_RESTORE_CURSOR;
119 break;
121 // Reset the scroll window.
122 locked_stream << ANSI_SAVE_CURSOR;
123 locked_stream.Printf(ANSI_SET_SCROLL_ROWS,
124 static_cast<unsigned>(m_terminal_height));
125 locked_stream << ANSI_RESTORE_CURSOR;
126 // Clear the screen below to hide the old statusline.
127 locked_stream << ANSI_CLEAR_BELOW;
128 break;
129 case ResizeStatusline: {
130 // The old statusline is still on screen after a resize: a width shrink
131 // reflows that full-width line into ceil(prev_width / width) rows at the
132 // bottom, and growing taller strands it at its old row. Clear from the
133 // topmost row it can occupy to the bottom (preserving the scrollback
134 // above), then re-establish the scroll region. DECSTBM homes the cursor,
135 // so save and restore it.
136 const unsigned height = static_cast<unsigned>(m_terminal_height);
137 unsigned reflow = 1;
138 if (prev_width > m_terminal_width && m_terminal_width > 0)
139 reflow = llvm::divideCeil(prev_width, m_terminal_width);
140 if (reflow >= height)
141 reflow = height - 1;
142 unsigned first_row = height - reflow + 1;
143 if (prev_height > 0 && prev_height < first_row)
144 first_row = static_cast<unsigned>(prev_height);
145 if (first_row < 1)
146 first_row = 1;
147
148 // A height shrink can leave the prompt on the row the statusline is about
149 // to occupy, because the terminal reclaims the row below the cursor
150 // instead of scrolling the cursor up. Scroll up one row to lift the
151 // prompt clear, like EnableStatusline; the overlap is only ever the
152 // single statusline row, and this is a no-op unless the cursor sits at
153 // the bottom of the scroll region.
154 if (prev_height > m_terminal_height) {
155 locked_stream << '\n';
156 locked_stream.Printf(ANSI_UP_ROWS, 1);
157 }
158
159 locked_stream << ANSI_SAVE_CURSOR;
160 locked_stream.Printf(ANSI_TO_START_OF_ROW, first_row);
161 locked_stream << ANSI_CLEAR_BELOW;
162 locked_stream.Printf(ANSI_SET_SCROLL_ROWS, reduced_scroll_rows);
163 locked_stream << ANSI_RESTORE_CURSOR;
164 break;
165 }
166 }
167 }
168 m_debugger.RefreshIOHandler();
169}
170
172
173void Statusline::Redraw(std::optional<ExecutionContextRef> exe_ctx_ref) {
174 // Update the cached execution context.
175 if (exe_ctx_ref)
176 m_exe_ctx_ref = *exe_ctx_ref;
177
178 // Lock the execution context.
179 ExecutionContext exe_ctx =
180 m_exe_ctx_ref.Lock(/*thread_and_frame_only_if_stopped=*/false);
181
182 // Compute the symbol context if we're stopped.
183 SymbolContext sym_ctx;
184 llvm::Expected<StoppedExecutionContext> stopped_exe_ctx =
186 if (stopped_exe_ctx) {
187 // The StoppedExecutionContext only ensures that we hold the run lock.
188 // The process could be in an exited or unloaded state and have no frame.
189 if (auto frame_sp = stopped_exe_ctx->GetFrameSP())
190 sym_ctx = frame_sp->GetSymbolContext(eSymbolContextEverything);
191 } else {
192 // We can draw the statusline without being stopped.
193 llvm::consumeError(stopped_exe_ctx.takeError());
194 }
195
196 StreamString stream;
197 FormatEntity::Entry format = m_debugger.GetStatuslineFormat();
198 FormatEntity::Formatter(&sym_ctx, &exe_ctx, nullptr, false, false)
199 .Format(format, stream);
200
201 Draw(stream.GetString().str());
202}
#define ANSI_SET_SCROLL_ROWS
#define ANSI_TO_START_OF_ROW
#define ANSI_UP_ROWS
#define ANSI_SAVE_CURSOR
#define ANSI_NORMAL
#define ANSI_ENABLE_AUTO_WRAP
#define ANSI_RESTORE_CURSOR
#define ANSI_REVERSE_VIDEO
#define ANSI_CLEAR_BELOW
#define ANSI_DISABLE_AUTO_WRAP
A class to manage flag bits.
Definition Debugger.h:100
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
bool Format(const Entry &entry, Stream &s, ValueObject *valobj=nullptr)
void UpdateScrollWindow(ScrollWindowMode mode, uint64_t prev_width=0, uint64_t prev_height=0)
Set the scroll window for the given mode.
void TerminalSizeChanged()
Inform the statusline that the terminal dimensions have changed.
void Enable(std::optional< ExecutionContextRef > exe_ctx_ref)
Reduce the scroll window and draw the statusline.
Statusline(Debugger &debugger)
void ClearExecutionContext()
Clear the cached execution context to discard stale pointers.
void Redraw(std::optional< ExecutionContextRef > exe_ctx_ref)
Redraw the statusline.
void Disable()
Hide the statusline and extend the scroll window.
ExecutionContextRef m_exe_ctx_ref
Cached copy of the execution context that allows us to redraw the statusline.
Definition Statusline.h:61
void Draw(std::string msg)
Draw the statusline with the given text.
llvm::StringRef GetString() const
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
Defines a symbol context baton that can be handed other debug core functions.
std::string TrimAndPad(llvm::StringRef str, size_t visible_length, char padding=' ')
A class that represents a running process on the host machine.
llvm::Expected< StoppedExecutionContext > GetStoppedExecutionContext(const ExecutionContextRef *exe_ctx_ref_ptr)
std::shared_ptr< lldb_private::LockableStreamFile > LockableStreamFileSP