Skip to content

[lldb] Correctly restore the cursor column after resizing the statusline #145823

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lldb/include/lldb/Core/Debugger.h
Original file line number Diff line number Diff line change
@@ -133,6 +133,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,

void SetAsyncExecution(bool async);

CursorPosition GetIOHandlerCursorPosition();

lldb::FileSP GetInputFileSP() { return m_input_file_sp; }
File &GetInputFile() { return *m_input_file_sp; }

7 changes: 7 additions & 0 deletions lldb/include/lldb/Core/IOHandler.h
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
#define LLDB_CORE_IOHANDLER_H

#include "lldb/Host/Config.h"
#include "lldb/Host/Terminal.h"
#include "lldb/Utility/CompletionRequest.h"
#include "lldb/Utility/Flags.h"
#include "lldb/Utility/Predicate.h"
@@ -113,6 +114,10 @@ class IOHandler {

virtual const char *GetHelpPrologue() { return nullptr; }

virtual CursorPosition GetCursorPosition() const {
return {std::nullopt, std::nullopt};
}

int GetInputFD();

int GetOutputFD();
@@ -404,6 +409,8 @@ class IOHandlerEditline : public IOHandler {

void PrintAsync(const char *s, size_t len, bool is_stdout) override;

virtual CursorPosition GetCursorPosition() const override;

private:
#if LLDB_ENABLE_LIBEDIT
bool IsInputCompleteCallback(Editline *editline, StringList &lines);
3 changes: 3 additions & 0 deletions lldb/include/lldb/Host/Editline.h
Original file line number Diff line number Diff line change
@@ -35,6 +35,7 @@
#include <vector>

#include "lldb/Host/StreamFile.h"
#include "lldb/Host/Terminal.h"
#include "lldb/lldb-private.h"

#if !defined(_WIN32) && !defined(__ANDROID__)
@@ -267,6 +268,8 @@ class Editline {

size_t GetTerminalHeight() { return m_terminal_height; }

CursorPosition GetCursorPosition();

private:
/// Sets the lowest line number for multi-line editing sessions. A value of
/// zero suppresses line number printing in the prompt.
5 changes: 5 additions & 0 deletions lldb/include/lldb/Host/Terminal.h
Original file line number Diff line number Diff line change
@@ -169,6 +169,11 @@ class TerminalState {
lldb::pid_t m_process_group = -1; ///< Cached process group information.
};

struct CursorPosition {
std::optional<unsigned> cols;
std::optional<unsigned> rows;
};

} // namespace lldb_private

#endif // LLDB_HOST_TERMINAL_H
8 changes: 8 additions & 0 deletions lldb/source/Core/Debugger.cpp
Original file line number Diff line number Diff line change
@@ -1240,6 +1240,14 @@ void Debugger::DispatchInputEndOfFile() {
reader_sp->GotEOF();
}

CursorPosition Debugger::GetIOHandlerCursorPosition() {
std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
IOHandlerSP reader_sp(m_io_handler_stack.Top());
if (reader_sp)
return reader_sp->GetCursorPosition();
return {std::nullopt, std::nullopt};
}

void Debugger::ClearIOHandlers() {
// The bottom input reader should be the main debugger input reader. We do
// not want to close that one here.
8 changes: 8 additions & 0 deletions lldb/source/Core/IOHandler.cpp
Original file line number Diff line number Diff line change
@@ -634,6 +634,14 @@ void IOHandlerEditline::GotEOF() {
#endif
}

CursorPosition IOHandlerEditline::GetCursorPosition() const {
#if LLDB_ENABLE_LIBEDIT
if (m_editline_up)
return m_editline_up->GetCursorPosition();
#endif
return {std::nullopt, std::nullopt};
}

void IOHandlerEditline::PrintAsync(const char *s, size_t len, bool is_stdout) {
#if LLDB_ENABLE_LIBEDIT
if (m_editline_up) {
33 changes: 25 additions & 8 deletions lldb/source/Core/Statusline.cpp
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@
#define ANSI_TO_START_OF_ROW ESCAPE "[%u;1f"
#define ANSI_REVERSE_VIDEO ESCAPE "[7m"
#define ANSI_UP_ROWS ESCAPE "[%dA"
#define ANSI_SET_COLUMN_N ESCAPE "[%uG"

using namespace lldb;
using namespace lldb_private;
@@ -103,19 +104,35 @@ void Statusline::UpdateScrollWindow(ScrollWindowMode mode) {
(mode == DisableStatusline) ? m_terminal_height : m_terminal_height - 1;

LockedStreamFile locked_stream = stream_sp->Lock();

if (mode == EnableStatusline) {
// Get the cursor position before we potentially change the cursor position.
CursorPosition cursor_position = m_debugger.GetIOHandlerCursorPosition();

// Move everything on the screen up to make space for the statusline. This
// is going to move the cursor to the start of the next line which we need
// to undo.
locked_stream << '\n';

// First move the cursor back up. We can't use ANSI_SAVE/RESTORE_CURSOR
// here, because the old and new position differ if everything on the screen
// moved up.
locked_stream.Printf(ANSI_UP_ROWS, 1);

// Finally move the cursor back to the correct column, if the IOHandler was
// able to tell us where that was.
if (cursor_position.cols)
locked_stream.Printf(ANSI_SET_COLUMN_N, *cursor_position.cols);
}

// Adjust the scroll window.
locked_stream << ANSI_SAVE_CURSOR;
locked_stream.Printf(ANSI_SET_SCROLL_ROWS, scroll_height);
locked_stream << ANSI_RESTORE_CURSOR;
switch (mode) {
case EnableStatusline:
// Move everything on the screen up.
locked_stream.Printf(ANSI_UP_ROWS, 1);
locked_stream << '\n';
break;
case DisableStatusline:

if (mode == DisableStatusline) {
// Clear the screen below to hide the old statusline.
locked_stream << ANSI_CLEAR_BELOW;
break;
}
}

14 changes: 14 additions & 0 deletions lldb/source/Host/common/Editline.cpp
Original file line number Diff line number Diff line change
@@ -398,6 +398,20 @@ int Editline::GetLineIndexForLocation(CursorLocation location, int cursor_row) {
return line;
}

CursorPosition Editline::GetCursorPosition() {
if (!m_editline)
return {};

const LineInfoW *info = el_wline(m_editline);
if (!info)
return {};

const size_t editline_cursor_col =
(int)((info->cursor - info->buffer) + GetPromptWidth()) + 1;

return {editline_cursor_col, std::nullopt};
}

void Editline::MoveCursor(CursorLocation from, CursorLocation to) {
const LineInfoW *info = el_wline(m_editline);
int editline_cursor_position =