11#include "lldb/Host/Config.h"
14#if CURSES_HAVE_NCURSES_CURSES_H
15#include <ncurses/curses.h>
16#include <ncurses/panel.h>
63#include "llvm/ADT/StringRef.h"
96#define KEY_SHIFT_TAB (KEY_MAX + 1)
97#define KEY_ALT_ENTER (KEY_MAX + 2)
105typedef std::shared_ptr<Menu> MenuSP;
106typedef std::shared_ptr<MenuDelegate> MenuDelegateSP;
107typedef std::shared_ptr<Window> WindowSP;
108typedef std::shared_ptr<WindowDelegate> WindowDelegateSP;
109typedef std::vector<MenuSP> Menus;
110typedef std::vector<WindowSP> Windows;
111typedef std::vector<WindowDelegateSP> WindowDelegates;
114type summary add -s
"x=${var.x}, y=${var.y}" curses::Point
115type summary add -s
"w=${var.width}, h=${var.height}" curses::Size
116type summary add -s
"${var.origin%S} ${var.size%S}" curses::Rect
123 Point(
int _x = 0,
int _y = 0) : x(_x), y(_y) {}
130 Point &operator+=(
const Point &rhs) {
136 void Dump() { printf(
"(x=%i, y=%i)\n", x, y); }
139bool operator==(
const Point &lhs,
const Point &rhs) {
140 return lhs.x == rhs.x && lhs.y == rhs.y;
143bool operator!=(
const Point &lhs,
const Point &rhs) {
144 return lhs.x != rhs.x || lhs.y != rhs.y;
150 Size(
int w = 0,
int h = 0) : width(w), height(h) {}
157 void Dump() { printf(
"(w=%i, h=%i)\n", width, height); }
160bool operator==(
const Size &lhs,
const Size &rhs) {
161 return lhs.width == rhs.width && lhs.height == rhs.height;
164bool operator!=(
const Size &lhs,
const Size &rhs) {
165 return lhs.width != rhs.width || lhs.height != rhs.height;
172 Rect() : origin(), size() {}
174 Rect(
const Point &p,
const Size &s) : origin(p), size(s) {}
182 printf(
"(x=%i, y=%i), w=%i, h=%i)\n", origin.x, origin.y, size.width,
186 void Inset(
int w,
int h) {
187 if (size.width > w * 2)
191 if (size.height > h * 2)
192 size.height -= h * 2;
198 Rect MakeStatusBar() {
200 if (size.height > 1) {
201 status_bar.origin.x = origin.x;
202 status_bar.origin.y = size.height;
203 status_bar.size.width = size.width;
204 status_bar.size.height = 1;
214 if (size.height > 1) {
215 menubar.origin.x = origin.x;
216 menubar.origin.y = origin.y;
217 menubar.size.width = size.width;
218 menubar.size.height = 1;
225 void HorizontalSplitPercentage(
float top_percentage, Rect &top,
226 Rect &bottom)
const {
227 float top_height = top_percentage * size.height;
228 HorizontalSplit(top_height, top, bottom);
231 void HorizontalSplit(
int top_height, Rect &top, Rect &bottom)
const {
233 if (top_height < size.height) {
234 top.size.height = top_height;
235 bottom.origin.x = origin.x;
236 bottom.origin.y = origin.y + top.size.height;
237 bottom.size.width = size.width;
238 bottom.size.height = size.height - top.size.height;
244 void VerticalSplitPercentage(
float left_percentage, Rect &left,
246 float left_width = left_percentage * size.width;
247 VerticalSplit(left_width, left, right);
250 void VerticalSplit(
int left_width, Rect &left, Rect &right)
const {
252 if (left_width < size.width) {
253 left.size.width = left_width;
254 right.origin.x = origin.x + left.size.width;
255 right.origin.y = origin.y;
256 right.size.width = size.width - left.size.width;
257 right.size.height = size.height;
264bool operator==(
const Rect &lhs,
const Rect &rhs) {
265 return lhs.origin == rhs.origin && lhs.size == rhs.size;
268bool operator!=(
const Rect &lhs,
const Rect &rhs) {
269 return lhs.origin != rhs.origin || lhs.size != rhs.size;
272enum HandleCharResult {
278enum class MenuActionResult {
286 const char *description;
312 LastColorPairIndex = MagentaOnWhite
315class WindowDelegate {
317 virtual ~WindowDelegate() =
default;
319 virtual bool WindowDelegateDraw(Window &window,
bool force) {
323 virtual HandleCharResult WindowDelegateHandleChar(Window &window,
int key) {
324 return eKeyNotHandled;
327 virtual const char *WindowDelegateGetHelpText() {
return nullptr; }
329 virtual KeyHelp *WindowDelegateGetKeyHelp() {
return nullptr; }
332class HelpDialogDelegate :
public WindowDelegate {
334 HelpDialogDelegate(
const char *text, KeyHelp *key_help_array);
336 ~HelpDialogDelegate()
override;
338 bool WindowDelegateDraw(Window &window,
bool force)
override;
340 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override;
342 size_t GetNumLines()
const {
return m_text.GetSize(); }
344 size_t GetMaxLineLength()
const {
return m_text.GetMaxStringLength(); }
348 int m_first_visible_line = 0;
357 enum class Type { Window, Pad };
359 Surface(Surface::Type type) : m_type(type) {}
361 WINDOW *get() {
return m_window; }
363 operator WINDOW *() {
return m_window; }
365 Surface SubSurface(Rect bounds) {
366 Surface subSurface(m_type);
367 if (m_type == Type::Pad)
368 subSurface.m_window =
369 ::subpad(m_window, bounds.size.height, bounds.size.width,
370 bounds.origin.y, bounds.origin.x);
372 subSurface.m_window =
373 ::derwin(m_window, bounds.size.height, bounds.size.width,
374 bounds.origin.y, bounds.origin.x);
379 void CopyToSurface(Surface &target, Point source_origin, Point target_origin,
381 ::copywin(m_window, target.get(), source_origin.y, source_origin.x,
382 target_origin.y, target_origin.x,
383 target_origin.y + size.height - 1,
384 target_origin.x + size.width - 1,
false);
387 int GetCursorX()
const {
return getcurx(m_window); }
388 int GetCursorY()
const {
return getcury(m_window); }
389 void MoveCursor(
int x,
int y) { ::wmove(m_window, y, x); }
391 void AttributeOn(attr_t attr) { ::wattron(m_window, attr); }
392 void AttributeOff(attr_t attr) { ::wattroff(m_window, attr); }
394 int GetMaxX()
const {
return getmaxx(m_window); }
395 int GetMaxY()
const {
return getmaxy(m_window); }
396 int GetWidth()
const {
return GetMaxX(); }
397 int GetHeight()
const {
return GetMaxY(); }
398 Size GetSize()
const {
return Size(GetWidth(), GetHeight()); }
400 Rect GetFrame()
const {
return Rect(Point(), GetSize()); }
402 void Clear() { ::wclear(m_window); }
403 void Erase() { ::werase(m_window); }
405 void SetBackground(
int color_pair_idx) {
406 ::wbkgd(m_window, COLOR_PAIR(color_pair_idx));
409 void PutChar(
int ch) { ::waddch(m_window, ch); }
410 void PutCString(
const char *s,
int len = -1) { ::waddnstr(m_window, s, len); }
412 void PutCStringTruncated(
int right_pad,
const char *s,
int len = -1) {
413 int bytes_left = GetWidth() - GetCursorX();
414 if (bytes_left > right_pad) {
415 bytes_left -= right_pad;
416 ::waddnstr(m_window, s, len < 0 ? bytes_left : std::min(bytes_left, len));
420 void Printf(
const char *format, ...) __attribute__((format(printf, 2, 3))) {
422 va_start(args, format);
423 vw_printw(m_window, format, args);
427 void PrintfTruncated(
int right_pad,
const char *format, ...)
428 __attribute__((format(printf, 3, 4))) {
430 va_start(args, format);
434 PutCStringTruncated(right_pad, strm.
GetData());
437 void VerticalLine(
int n, chtype v_char = ACS_VLINE) {
438 ::wvline(m_window, v_char, n);
440 void HorizontalLine(
int n, chtype h_char = ACS_HLINE) {
441 ::whline(m_window, h_char, n);
443 void Box(chtype v_char = ACS_VLINE, chtype h_char = ACS_HLINE) {
444 ::box(m_window, v_char, h_char);
447 void TitledBox(
const char *title, chtype v_char = ACS_VLINE,
448 chtype h_char = ACS_HLINE) {
450 int title_offset = 2;
451 MoveCursor(title_offset, 0);
453 PutCString(title, GetWidth() - title_offset);
457 void Box(
const Rect &bounds, chtype v_char = ACS_VLINE,
458 chtype h_char = ACS_HLINE) {
459 MoveCursor(bounds.origin.x, bounds.origin.y);
460 VerticalLine(bounds.size.height);
461 HorizontalLine(bounds.size.width);
462 PutChar(ACS_ULCORNER);
464 MoveCursor(bounds.origin.x + bounds.size.width - 1, bounds.origin.y);
465 VerticalLine(bounds.size.height);
466 PutChar(ACS_URCORNER);
468 MoveCursor(bounds.origin.x, bounds.origin.y + bounds.size.height - 1);
469 HorizontalLine(bounds.size.width);
470 PutChar(ACS_LLCORNER);
472 MoveCursor(bounds.origin.x + bounds.size.width - 1,
473 bounds.origin.y + bounds.size.height - 1);
474 PutChar(ACS_LRCORNER);
477 void TitledBox(
const Rect &bounds,
const char *title,
478 chtype v_char = ACS_VLINE, chtype h_char = ACS_HLINE) {
479 Box(bounds, v_char, h_char);
480 int title_offset = 2;
481 MoveCursor(bounds.origin.x + title_offset, bounds.origin.y);
483 PutCString(title, bounds.size.width - title_offset);
492 bool OutputColoredStringTruncated(
int right_pad, StringRef
string,
493 size_t skip_first_count,
494 bool use_blue_background) {
498 wattr_get(m_window, &saved_attr, &saved_pair,
nullptr);
499 if (use_blue_background)
500 ::wattron(m_window, COLOR_PAIR(WhiteOnBlue));
501 while (!
string.empty()) {
503 if (esc_pos == StringRef::npos) {
504 string =
string.substr(skip_first_count);
505 if (!
string.empty()) {
506 PutCStringTruncated(right_pad,
string.data(),
string.size());
512 if (skip_first_count > 0) {
513 int skip = std::min(esc_pos, skip_first_count);
514 string =
string.substr(
skip);
515 skip_first_count -=
skip;
519 PutCStringTruncated(right_pad,
string.data(), esc_pos);
521 string =
string.drop_front(esc_pos);
533 if (!!
string.consumeInteger(10, value) ||
536 llvm::errs() <<
"No valid color code in color escape sequence.\n";
541 <<
"' in color escape sequence.\n";
545 wattr_set(m_window, saved_attr, saved_pair,
nullptr);
546 if (use_blue_background)
547 ::wattron(m_window, COLOR_PAIR(WhiteOnBlue));
549 ::wattron(m_window, A_UNDERLINE);
553 (use_blue_background ? 8 : 0)));
556 wattr_set(m_window, saved_attr, saved_pair,
nullptr);
562 WINDOW *m_window =
nullptr;
565class Pad :
public Surface {
567 Pad(Size size) : Surface(Surface::
Type::Pad) {
568 m_window = ::newpad(size.height, size.width);
571 ~Pad() { ::delwin(m_window); }
574class Window :
public Surface {
576 Window(
const char *name)
577 : Surface(Surface::
Type::Window), m_name(name), m_panel(nullptr),
578 m_parent(nullptr), m_subwindows(), m_delegate_sp(),
580 m_prev_active_window_idx(
UINT32_MAX), m_delete(false),
581 m_needs_update(true), m_can_activate(true), m_is_subwin(false) {}
583 Window(
const char *name, WINDOW *w,
bool del =
true)
584 : Surface(Surface::
Type::Window), m_name(name), m_panel(nullptr),
585 m_parent(nullptr), m_subwindows(), m_delegate_sp(),
587 m_prev_active_window_idx(
UINT32_MAX), m_delete(del),
588 m_needs_update(true), m_can_activate(true), m_is_subwin(false) {
593 Window(
const char *name,
const Rect &bounds)
594 : Surface(Surface::
Type::Window), m_name(name), m_panel(nullptr),
595 m_parent(nullptr), m_subwindows(), m_delegate_sp(),
597 m_prev_active_window_idx(
UINT32_MAX), m_delete(false),
598 m_needs_update(true), m_can_activate(true), m_is_subwin(false) {
599 Reset(::newwin(bounds.size.height, bounds.size.width, bounds.origin.y,
608 void Reset(WINDOW *w =
nullptr,
bool del =
true) {
613 ::del_panel(m_panel);
616 if (m_window && m_delete) {
623 m_panel = ::new_panel(m_window);
629 Rect GetBounds()
const {
return Rect(GetParentOrigin(), GetSize()); }
631 Rect GetCenteredRect(
int width,
int height) {
632 Size size = GetSize();
633 width = std::min(size.width, width);
634 height = std::min(size.height, height);
635 int x = (size.width - width) / 2;
636 int y = (size.height - height) / 2;
637 return Rect(Point(x, y), Size(width, height));
640 int GetChar() { return ::wgetch(m_window); }
641 Point GetParentOrigin()
const {
return Point(GetParentX(), GetParentY()); }
642 int GetParentX()
const {
return getparx(m_window); }
643 int GetParentY()
const {
return getpary(m_window); }
644 void MoveWindow(
int x,
int y) { MoveWindow(Point(x, y)); }
645 void Resize(
int w,
int h) { ::wresize(m_window, h, w); }
646 void Resize(
const Size &size) {
647 ::wresize(m_window, size.height, size.width);
649 void MoveWindow(
const Point &origin) {
650 const bool moving_window = origin != GetParentOrigin();
651 if (m_is_subwin && moving_window) {
653 Size size = GetSize();
654 Reset(::subwin(m_parent->m_window, size.height, size.width, origin.y,
658 ::mvwin(m_window, origin.y, origin.x);
662 void SetBounds(
const Rect &bounds) {
663 const bool moving_window = bounds.origin != GetParentOrigin();
664 if (m_is_subwin && moving_window) {
666 Reset(::subwin(m_parent->m_window, bounds.size.height, bounds.size.width,
667 bounds.origin.y, bounds.origin.x),
671 MoveWindow(bounds.origin);
677 ::touchwin(m_window);
682 WindowSP CreateSubWindow(
const char *name,
const Rect &bounds,
684 auto get_window = [
this, &bounds]() {
686 ? ::subwin(m_window, bounds.size.height, bounds.size.width,
687 bounds.origin.y, bounds.origin.x)
688 : ::newwin(bounds.size.height, bounds.size.width,
689 bounds.origin.y, bounds.origin.x);
691 WindowSP subwindow_sp = std::make_shared<Window>(name, get_window(),
true);
692 subwindow_sp->m_is_subwin = subwindow_sp.operator bool();
693 subwindow_sp->m_parent =
this;
695 m_prev_active_window_idx = m_curr_active_window_idx;
696 m_curr_active_window_idx = m_subwindows.size();
698 m_subwindows.push_back(subwindow_sp);
699 ::top_panel(subwindow_sp->m_panel);
700 m_needs_update =
true;
704 bool RemoveSubWindow(Window *window) {
705 Windows::iterator pos, end = m_subwindows.end();
707 for (pos = m_subwindows.begin(); pos != end; ++pos, ++i) {
708 if ((*pos).get() == window) {
709 if (m_prev_active_window_idx == i)
711 else if (m_prev_active_window_idx !=
UINT32_MAX &&
712 m_prev_active_window_idx > i)
713 --m_prev_active_window_idx;
715 if (m_curr_active_window_idx == i)
717 else if (m_curr_active_window_idx !=
UINT32_MAX &&
718 m_curr_active_window_idx > i)
719 --m_curr_active_window_idx;
721 m_subwindows.erase(pos);
722 m_needs_update =
true;
733 WindowSP FindSubWindow(
const char *name) {
734 Windows::iterator pos, end = m_subwindows.end();
736 for (pos = m_subwindows.begin(); pos != end; ++pos, ++i) {
737 if ((*pos)->m_name == name)
743 void RemoveSubWindows() {
746 for (Windows::iterator pos = m_subwindows.begin();
747 pos != m_subwindows.end(); pos = m_subwindows.erase(pos)) {
757 void DrawTitleBox(
const char *title,
const char *bottom_message =
nullptr) {
760 attr = A_BOLD | COLOR_PAIR(BlackOnWhite);
769 if (title && title[0]) {
775 if (bottom_message && bottom_message[0]) {
776 int bottom_message_length = strlen(bottom_message);
777 int x = GetWidth() - 3 - (bottom_message_length + 2);
780 MoveCursor(x, GetHeight() - 1);
782 PutCString(bottom_message);
785 MoveCursor(1, GetHeight() - 1);
787 PutCStringTruncated(1, bottom_message);
794 virtual void Draw(
bool force) {
795 if (m_delegate_sp && m_delegate_sp->WindowDelegateDraw(*
this, force))
798 for (
auto &subwindow_sp : m_subwindows)
799 subwindow_sp->Draw(force);
802 bool CreateHelpSubwindow() {
804 const char *text = m_delegate_sp->WindowDelegateGetHelpText();
805 KeyHelp *key_help = m_delegate_sp->WindowDelegateGetKeyHelp();
806 if ((text && text[0]) || key_help) {
807 std::unique_ptr<HelpDialogDelegate> help_delegate_up(
808 new HelpDialogDelegate(text, key_help));
809 const size_t num_lines = help_delegate_up->GetNumLines();
810 const size_t max_length = help_delegate_up->GetMaxLineLength();
811 Rect bounds = GetBounds();
813 if (max_length + 4 <
static_cast<size_t>(bounds.size.width)) {
814 bounds.origin.x += (bounds.size.width - max_length + 4) / 2;
815 bounds.size.width = max_length + 4;
817 if (bounds.size.width > 100) {
818 const int inset_w = bounds.size.width / 4;
819 bounds.origin.x += inset_w;
820 bounds.size.width -= 2 * inset_w;
824 if (num_lines + 2 <
static_cast<size_t>(bounds.size.height)) {
825 bounds.origin.y += (bounds.size.height - num_lines + 2) / 2;
826 bounds.size.height = num_lines + 2;
828 if (bounds.size.height > 100) {
829 const int inset_h = bounds.size.height / 4;
830 bounds.origin.y += inset_h;
831 bounds.size.height -= 2 * inset_h;
834 WindowSP help_window_sp;
835 Window *parent_window = GetParent();
837 help_window_sp = parent_window->CreateSubWindow(
"Help", bounds,
true);
839 help_window_sp = CreateSubWindow(
"Help", bounds,
true);
840 help_window_sp->SetDelegate(
841 WindowDelegateSP(help_delegate_up.release()));
848 virtual HandleCharResult HandleChar(
int key) {
850 HandleCharResult result = eKeyNotHandled;
851 WindowSP active_window_sp = GetActiveWindow();
852 if (active_window_sp) {
853 result = active_window_sp->HandleChar(key);
854 if (result != eKeyNotHandled)
859 result = m_delegate_sp->WindowDelegateHandleChar(*
this, key);
860 if (result != eKeyNotHandled)
868 Windows subwindows(m_subwindows);
869 for (
auto subwindow_sp : subwindows) {
870 if (!subwindow_sp->m_can_activate) {
871 HandleCharResult result = subwindow_sp->HandleChar(key);
872 if (result != eKeyNotHandled)
877 return eKeyNotHandled;
880 WindowSP GetActiveWindow() {
881 if (!m_subwindows.empty()) {
882 if (m_curr_active_window_idx >= m_subwindows.size()) {
883 if (m_prev_active_window_idx < m_subwindows.size()) {
884 m_curr_active_window_idx = m_prev_active_window_idx;
886 }
else if (IsActive()) {
891 const size_t num_subwindows = m_subwindows.size();
892 for (
size_t i = 0; i < num_subwindows; ++i) {
893 if (m_subwindows[i]->GetCanBeActive()) {
894 m_curr_active_window_idx = i;
901 if (m_curr_active_window_idx < m_subwindows.size())
902 return m_subwindows[m_curr_active_window_idx];
907 bool GetCanBeActive()
const {
return m_can_activate; }
909 void SetCanBeActive(
bool b) { m_can_activate = b; }
911 void SetDelegate(
const WindowDelegateSP &delegate_sp) {
912 m_delegate_sp = delegate_sp;
915 Window *GetParent()
const {
return m_parent; }
917 bool IsActive()
const {
919 return m_parent->GetActiveWindow().get() ==
this;
924 void SelectNextWindowAsActive() {
926 const int num_subwindows = m_subwindows.size();
929 m_prev_active_window_idx = m_curr_active_window_idx;
930 start_idx = m_curr_active_window_idx + 1;
932 for (
int idx = start_idx; idx < num_subwindows; ++idx) {
933 if (m_subwindows[idx]->GetCanBeActive()) {
934 m_curr_active_window_idx = idx;
938 for (
int idx = 0; idx < start_idx; ++idx) {
939 if (m_subwindows[idx]->GetCanBeActive()) {
940 m_curr_active_window_idx = idx;
946 void SelectPreviousWindowAsActive() {
948 const int num_subwindows = m_subwindows.size();
949 int start_idx = num_subwindows - 1;
951 m_prev_active_window_idx = m_curr_active_window_idx;
952 start_idx = m_curr_active_window_idx - 1;
954 for (
int idx = start_idx; idx >= 0; --idx) {
955 if (m_subwindows[idx]->GetCanBeActive()) {
956 m_curr_active_window_idx = idx;
960 for (
int idx = num_subwindows - 1; idx > start_idx; --idx) {
961 if (m_subwindows[idx]->GetCanBeActive()) {
962 m_curr_active_window_idx = idx;
968 const char *
GetName()
const {
return m_name.c_str(); }
974 Windows m_subwindows;
975 WindowDelegateSP m_delegate_sp;
976 uint32_t m_curr_active_window_idx;
977 uint32_t m_prev_active_window_idx;
984 Window(
const Window &) =
delete;
985 const Window &operator=(
const Window &) =
delete;
996struct ScrollContext {
1000 ScrollContext(
int line) : start(line), end(line) {}
1001 ScrollContext(
int _start,
int _end) : start(_start), end(_end) {}
1003 void Offset(
int offset) {
1009class FieldDelegate {
1011 virtual ~FieldDelegate() =
default;
1015 virtual int FieldDelegateGetHeight() = 0;
1022 virtual ScrollContext FieldDelegateGetScrollContext() {
1023 return ScrollContext(0, FieldDelegateGetHeight() - 1);
1029 virtual void FieldDelegateDraw(Surface &surface,
bool is_selected) = 0;
1032 virtual HandleCharResult FieldDelegateHandleChar(
int key) {
1033 return eKeyNotHandled;
1040 virtual void FieldDelegateExitCallback() {}
1054 virtual bool FieldDelegateOnFirstOrOnlyElement() {
return true; }
1058 virtual bool FieldDelegateOnLastOrOnlyElement() {
return true; }
1061 virtual void FieldDelegateSelectFirstElement() {}
1064 virtual void FieldDelegateSelectLastElement() {}
1067 virtual bool FieldDelegateHasError() {
return false; }
1069 bool FieldDelegateIsVisible() {
return m_is_visible; }
1071 void FieldDelegateHide() { m_is_visible =
false; }
1073 void FieldDelegateShow() { m_is_visible =
true; }
1076 bool m_is_visible =
true;
1079typedef std::unique_ptr<FieldDelegate> FieldDelegateUP;
1081class TextFieldDelegate :
public FieldDelegate {
1083 TextFieldDelegate(
const char *label,
const char *content,
bool required)
1084 : m_label(label), m_required(required) {
1086 m_content = content;
1099 int GetFieldHeight() {
return 3; }
1103 int FieldDelegateGetHeight()
override {
1104 int height = GetFieldHeight();
1105 if (FieldDelegateHasError())
1111 int GetCursorXPosition() {
return m_cursor_position - m_first_visibile_char; }
1113 int GetContentLength() {
return m_content.length(); }
1115 void DrawContent(Surface &surface,
bool is_selected) {
1116 UpdateScrolling(surface.GetWidth());
1118 surface.MoveCursor(0, 0);
1119 const char *text = m_content.c_str() + m_first_visibile_char;
1120 surface.PutCString(text, surface.GetWidth());
1123 surface.MoveCursor(GetCursorXPosition(), 0);
1125 surface.AttributeOn(A_REVERSE);
1126 if (m_cursor_position == GetContentLength())
1128 surface.PutChar(
' ');
1130 surface.PutChar(m_content[m_cursor_position]);
1132 surface.AttributeOff(A_REVERSE);
1135 void DrawField(Surface &surface,
bool is_selected) {
1136 surface.TitledBox(m_label.c_str());
1138 Rect content_bounds = surface.GetFrame();
1139 content_bounds.Inset(1, 1);
1140 Surface content_surface = surface.SubSurface(content_bounds);
1142 DrawContent(content_surface, is_selected);
1145 void DrawError(Surface &surface) {
1146 if (!FieldDelegateHasError())
1148 surface.MoveCursor(0, 0);
1149 surface.AttributeOn(COLOR_PAIR(RedOnBlack));
1150 surface.PutChar(ACS_DIAMOND);
1151 surface.PutChar(
' ');
1152 surface.PutCStringTruncated(1, GetError().c_str());
1153 surface.AttributeOff(COLOR_PAIR(RedOnBlack));
1156 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
1157 Rect frame = surface.GetFrame();
1158 Rect field_bounds, error_bounds;
1159 frame.HorizontalSplit(GetFieldHeight(), field_bounds, error_bounds);
1160 Surface field_surface = surface.SubSurface(field_bounds);
1161 Surface error_surface = surface.SubSurface(error_bounds);
1163 DrawField(field_surface, is_selected);
1164 DrawError(error_surface);
1168 int GetLastVisibleCharPosition(
int width) {
1169 int position = m_first_visibile_char + width - 1;
1170 return std::min(position, GetContentLength());
1173 void UpdateScrolling(
int width) {
1174 if (m_cursor_position < m_first_visibile_char) {
1175 m_first_visibile_char = m_cursor_position;
1179 if (m_cursor_position > GetLastVisibleCharPosition(width))
1180 m_first_visibile_char = m_cursor_position - (width - 1);
1185 void MoveCursorRight() {
1186 if (m_cursor_position < GetContentLength())
1187 m_cursor_position++;
1190 void MoveCursorLeft() {
1191 if (m_cursor_position > 0)
1192 m_cursor_position--;
1195 void MoveCursorToStart() { m_cursor_position = 0; }
1197 void MoveCursorToEnd() { m_cursor_position = GetContentLength(); }
1200 if (m_first_visibile_char > 0)
1201 m_first_visibile_char--;
1206 void InsertChar(
char character) {
1207 m_content.insert(m_cursor_position, 1, character);
1208 m_cursor_position++;
1214 void RemovePreviousChar() {
1215 if (m_cursor_position == 0)
1218 m_content.erase(m_cursor_position - 1, 1);
1219 m_cursor_position--;
1225 void RemoveNextChar() {
1226 if (m_cursor_position == GetContentLength())
1229 m_content.erase(m_cursor_position, 1);
1235 m_content.erase(m_cursor_position);
1241 m_cursor_position = 0;
1247 virtual bool IsAcceptableChar(
int key) {
1252 return isprint(key);
1255 HandleCharResult FieldDelegateHandleChar(
int key)
override {
1256 if (IsAcceptableChar(key)) {
1258 InsertChar((
char)key);
1265 MoveCursorToStart();
1281 RemovePreviousChar();
1297 return eKeyNotHandled;
1300 bool FieldDelegateHasError()
override {
return !m_error.empty(); }
1302 void FieldDelegateExitCallback()
override {
1303 if (!IsSpecified() && m_required)
1304 SetError(
"This field is required!");
1307 bool IsSpecified() {
return !m_content.empty(); }
1309 void ClearError() { m_error.clear(); }
1311 const std::string &GetError() {
return m_error; }
1313 void SetError(
const char *
error) { m_error =
error; }
1315 const std::string &
GetText() {
return m_content; }
1317 void SetText(
const char *text) {
1318 if (text ==
nullptr) {
1326 std::string m_label;
1329 std::string m_content;
1332 int m_cursor_position = 0;
1334 int m_first_visibile_char = 0;
1336 std::string m_error;
1339class IntegerFieldDelegate :
public TextFieldDelegate {
1341 IntegerFieldDelegate(
const char *label,
int content,
bool required)
1342 : TextFieldDelegate(label, std::to_string(content).c_str(), required) {}
1345 bool IsAcceptableChar(
int key)
override {
return isdigit(key); }
1348 int GetInteger() {
return std::stoi(m_content); }
1351class FileFieldDelegate :
public TextFieldDelegate {
1353 FileFieldDelegate(
const char *label,
const char *content,
bool need_to_exist,
1355 : TextFieldDelegate(label, content, required),
1356 m_need_to_exist(need_to_exist) {}
1358 void FieldDelegateExitCallback()
override {
1359 TextFieldDelegate::FieldDelegateExitCallback();
1363 if (!m_need_to_exist)
1366 FileSpec file = GetResolvedFileSpec();
1368 SetError(
"File doesn't exist!");
1372 SetError(
"Not a file!");
1377 FileSpec GetFileSpec() {
1378 FileSpec file_spec(GetPath());
1382 FileSpec GetResolvedFileSpec() {
1383 FileSpec file_spec(GetPath());
1388 const std::string &GetPath() {
return m_content; }
1391 bool m_need_to_exist;
1394class DirectoryFieldDelegate :
public TextFieldDelegate {
1396 DirectoryFieldDelegate(
const char *label,
const char *content,
1397 bool need_to_exist,
bool required)
1398 : TextFieldDelegate(label, content, required),
1399 m_need_to_exist(need_to_exist) {}
1401 void FieldDelegateExitCallback()
override {
1402 TextFieldDelegate::FieldDelegateExitCallback();
1406 if (!m_need_to_exist)
1409 FileSpec file = GetResolvedFileSpec();
1411 SetError(
"Directory doesn't exist!");
1415 SetError(
"Not a directory!");
1420 FileSpec GetFileSpec() {
1421 FileSpec file_spec(GetPath());
1425 FileSpec GetResolvedFileSpec() {
1426 FileSpec file_spec(GetPath());
1431 const std::string &GetPath() {
return m_content; }
1434 bool m_need_to_exist;
1437class ArchFieldDelegate :
public TextFieldDelegate {
1439 ArchFieldDelegate(
const char *label,
const char *content,
bool required)
1440 : TextFieldDelegate(label, content, required) {}
1442 void FieldDelegateExitCallback()
override {
1443 TextFieldDelegate::FieldDelegateExitCallback();
1447 if (!GetArchSpec().IsValid())
1448 SetError(
"Not a valid arch!");
1451 const std::string &GetArchString() {
return m_content; }
1453 ArchSpec GetArchSpec() {
return ArchSpec(GetArchString()); }
1456class BooleanFieldDelegate :
public FieldDelegate {
1458 BooleanFieldDelegate(
const char *label,
bool content)
1459 : m_label(label), m_content(content) {}
1466 int FieldDelegateGetHeight()
override {
return 1; }
1468 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
1469 surface.MoveCursor(0, 0);
1470 surface.PutChar(
'[');
1472 surface.AttributeOn(A_REVERSE);
1473 surface.PutChar(m_content ? ACS_DIAMOND :
' ');
1475 surface.AttributeOff(A_REVERSE);
1476 surface.PutChar(
']');
1477 surface.PutChar(
' ');
1478 surface.PutCString(m_label.c_str());
1481 void ToggleContent() { m_content = !m_content; }
1483 void SetContentToTrue() { m_content =
true; }
1485 void SetContentToFalse() { m_content =
false; }
1487 HandleCharResult FieldDelegateHandleChar(
int key)
override {
1495 SetContentToFalse();
1506 return eKeyNotHandled;
1510 bool GetBoolean() {
return m_content; }
1513 std::string m_label;
1517class ChoicesFieldDelegate :
public FieldDelegate {
1519 ChoicesFieldDelegate(
const char *label,
int number_of_visible_choices,
1520 std::vector<std::string> choices)
1521 : m_label(label), m_number_of_visible_choices(number_of_visible_choices),
1522 m_choices(choices) {}
1536 int FieldDelegateGetHeight()
override {
1537 return m_number_of_visible_choices + 2;
1540 int GetNumberOfChoices() {
return m_choices.size(); }
1543 int GetLastVisibleChoice() {
1544 int index = m_first_visibile_choice + m_number_of_visible_choices;
1545 return std::min(index, GetNumberOfChoices()) - 1;
1548 void DrawContent(Surface &surface,
bool is_selected) {
1549 int choices_to_draw = GetLastVisibleChoice() - m_first_visibile_choice + 1;
1550 for (
int i = 0; i < choices_to_draw; i++) {
1551 surface.MoveCursor(0, i);
1552 int current_choice = m_first_visibile_choice + i;
1553 const char *text = m_choices[current_choice].c_str();
1554 bool highlight = is_selected && current_choice == m_choice;
1556 surface.AttributeOn(A_REVERSE);
1557 surface.PutChar(current_choice == m_choice ? ACS_DIAMOND :
' ');
1558 surface.PutCString(text);
1560 surface.AttributeOff(A_REVERSE);
1564 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
1567 surface.TitledBox(m_label.c_str());
1569 Rect content_bounds = surface.GetFrame();
1570 content_bounds.Inset(1, 1);
1571 Surface content_surface = surface.SubSurface(content_bounds);
1573 DrawContent(content_surface, is_selected);
1576 void SelectPrevious() {
1582 if (m_choice < GetNumberOfChoices() - 1)
1586 void UpdateScrolling() {
1587 if (m_choice > GetLastVisibleChoice()) {
1588 m_first_visibile_choice = m_choice - (m_number_of_visible_choices - 1);
1592 if (m_choice < m_first_visibile_choice)
1593 m_first_visibile_choice = m_choice;
1596 HandleCharResult FieldDelegateHandleChar(
int key)
override {
1607 return eKeyNotHandled;
1611 std::string GetChoiceContent() {
return m_choices[m_choice]; }
1614 int GetChoice() {
return m_choice; }
1616 void SetChoice(llvm::StringRef choice) {
1617 for (
int i = 0; i < GetNumberOfChoices(); i++) {
1618 if (choice == m_choices[i]) {
1626 std::string m_label;
1627 int m_number_of_visible_choices;
1628 std::vector<std::string> m_choices;
1632 int m_first_visibile_choice = 0;
1635class PlatformPluginFieldDelegate :
public ChoicesFieldDelegate {
1637 PlatformPluginFieldDelegate(Debugger &debugger)
1638 : ChoicesFieldDelegate(
"Platform Plugin", 3, GetPossiblePluginNames()) {
1641 SetChoice(platform_sp->GetPluginName());
1644 std::vector<std::string> GetPossiblePluginNames() {
1645 std::vector<std::string> names;
1647 for (llvm::StringRef name =
1650 names.push_back(name.str());
1654 std::string GetPluginName() {
1655 std::string plugin_name = GetChoiceContent();
1660class ProcessPluginFieldDelegate :
public ChoicesFieldDelegate {
1662 ProcessPluginFieldDelegate()
1663 : ChoicesFieldDelegate(
"Process Plugin", 3, GetPossiblePluginNames()) {}
1665 std::vector<std::string> GetPossiblePluginNames() {
1666 std::vector<std::string> names;
1667 names.push_back(
"<default>");
1672 names.push_back(name.str());
1676 std::string GetPluginName() {
1677 std::string plugin_name = GetChoiceContent();
1678 if (plugin_name ==
"<default>")
1684class LazyBooleanFieldDelegate :
public ChoicesFieldDelegate {
1686 LazyBooleanFieldDelegate(
const char *label,
const char *calculate_label)
1687 : ChoicesFieldDelegate(label, 3, GetPossibleOptions(calculate_label)) {}
1689 static constexpr const char *kNo =
"No";
1690 static constexpr const char *kYes =
"Yes";
1692 std::vector<std::string> GetPossibleOptions(
const char *calculate_label) {
1693 std::vector<std::string> options;
1694 options.push_back(calculate_label);
1695 options.push_back(kYes);
1696 options.push_back(kNo);
1701 std::string choice = GetChoiceContent();
1704 else if (choice == kYes)
1711template <
class T>
class ListFieldDelegate :
public FieldDelegate {
1713 ListFieldDelegate(
const char *label, T default_field)
1714 : m_label(label), m_default_field(default_field),
1715 m_selection_type(SelectionType::NewButton) {}
1720 enum class SelectionType { Field, RemoveButton, NewButton };
1736 int FieldDelegateGetHeight()
override {
1740 for (
int i = 0; i < GetNumberOfFields(); i++) {
1741 height += m_fields[i].FieldDelegateGetHeight();
1748 ScrollContext FieldDelegateGetScrollContext()
override {
1749 int height = FieldDelegateGetHeight();
1750 if (m_selection_type == SelectionType::NewButton)
1751 return ScrollContext(height - 2, height - 1);
1753 FieldDelegate &field = m_fields[m_selection_index];
1754 ScrollContext context = field.FieldDelegateGetScrollContext();
1758 for (
int i = 0; i < m_selection_index; i++) {
1759 offset += m_fields[i].FieldDelegateGetHeight();
1761 context.Offset(offset);
1765 if (context.start == 1)
1770 if (context.end == height - 3)
1776 void DrawRemoveButton(Surface &surface,
int highlight) {
1777 surface.MoveCursor(1, surface.GetHeight() / 2);
1779 surface.AttributeOn(A_REVERSE);
1780 surface.PutCString(
"[Remove]");
1782 surface.AttributeOff(A_REVERSE);
1785 void DrawFields(Surface &surface,
bool is_selected) {
1787 int width = surface.GetWidth();
1788 for (
int i = 0; i < GetNumberOfFields(); i++) {
1789 int height = m_fields[i].FieldDelegateGetHeight();
1790 Rect bounds = Rect(Point(0, line), Size(width, height));
1791 Rect field_bounds, remove_button_bounds;
1792 bounds.VerticalSplit(bounds.size.width -
sizeof(
" [Remove]"),
1793 field_bounds, remove_button_bounds);
1794 Surface field_surface = surface.SubSurface(field_bounds);
1795 Surface remove_button_surface = surface.SubSurface(remove_button_bounds);
1797 bool is_element_selected = m_selection_index == i && is_selected;
1798 bool is_field_selected =
1799 is_element_selected && m_selection_type == SelectionType::Field;
1800 bool is_remove_button_selected =
1801 is_element_selected &&
1802 m_selection_type == SelectionType::RemoveButton;
1803 m_fields[i].FieldDelegateDraw(field_surface, is_field_selected);
1804 DrawRemoveButton(remove_button_surface, is_remove_button_selected);
1810 void DrawNewButton(Surface &surface,
bool is_selected) {
1811 const char *button_text =
"[New]";
1812 int x = (surface.GetWidth() -
sizeof(button_text) - 1) / 2;
1813 surface.MoveCursor(x, 0);
1815 is_selected && m_selection_type == SelectionType::NewButton;
1817 surface.AttributeOn(A_REVERSE);
1818 surface.PutCString(button_text);
1820 surface.AttributeOff(A_REVERSE);
1823 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
1824 surface.TitledBox(m_label.c_str());
1826 Rect content_bounds = surface.GetFrame();
1827 content_bounds.Inset(1, 1);
1828 Rect fields_bounds, new_button_bounds;
1829 content_bounds.HorizontalSplit(content_bounds.size.height - 1,
1830 fields_bounds, new_button_bounds);
1831 Surface fields_surface = surface.SubSurface(fields_bounds);
1832 Surface new_button_surface = surface.SubSurface(new_button_bounds);
1834 DrawFields(fields_surface, is_selected);
1835 DrawNewButton(new_button_surface, is_selected);
1838 void AddNewField() {
1839 m_fields.push_back(m_default_field);
1840 m_selection_index = GetNumberOfFields() - 1;
1841 m_selection_type = SelectionType::Field;
1842 FieldDelegate &field = m_fields[m_selection_index];
1843 field.FieldDelegateSelectFirstElement();
1846 void RemoveField() {
1847 m_fields.erase(m_fields.begin() + m_selection_index);
1848 if (m_selection_index != 0)
1849 m_selection_index--;
1851 if (GetNumberOfFields() > 0) {
1852 m_selection_type = SelectionType::Field;
1853 FieldDelegate &field = m_fields[m_selection_index];
1854 field.FieldDelegateSelectFirstElement();
1856 m_selection_type = SelectionType::NewButton;
1859 HandleCharResult SelectNext(
int key) {
1860 if (m_selection_type == SelectionType::NewButton)
1861 return eKeyNotHandled;
1863 if (m_selection_type == SelectionType::RemoveButton) {
1864 if (m_selection_index == GetNumberOfFields() - 1) {
1865 m_selection_type = SelectionType::NewButton;
1868 m_selection_index++;
1869 m_selection_type = SelectionType::Field;
1870 FieldDelegate &next_field = m_fields[m_selection_index];
1871 next_field.FieldDelegateSelectFirstElement();
1875 FieldDelegate &field = m_fields[m_selection_index];
1876 if (!field.FieldDelegateOnLastOrOnlyElement()) {
1877 return field.FieldDelegateHandleChar(key);
1880 field.FieldDelegateExitCallback();
1882 m_selection_type = SelectionType::RemoveButton;
1886 HandleCharResult SelectPrevious(
int key) {
1887 if (FieldDelegateOnFirstOrOnlyElement())
1888 return eKeyNotHandled;
1890 if (m_selection_type == SelectionType::RemoveButton) {
1891 m_selection_type = SelectionType::Field;
1892 FieldDelegate &field = m_fields[m_selection_index];
1893 field.FieldDelegateSelectLastElement();
1897 if (m_selection_type == SelectionType::NewButton) {
1898 m_selection_type = SelectionType::RemoveButton;
1899 m_selection_index = GetNumberOfFields() - 1;
1903 FieldDelegate &field = m_fields[m_selection_index];
1904 if (!field.FieldDelegateOnFirstOrOnlyElement()) {
1905 return field.FieldDelegateHandleChar(key);
1908 field.FieldDelegateExitCallback();
1910 m_selection_type = SelectionType::RemoveButton;
1911 m_selection_index--;
1917 HandleCharResult SelectNextInList(
int key) {
1918 assert(m_selection_type == SelectionType::Field);
1920 FieldDelegate &field = m_fields[m_selection_index];
1921 if (field.FieldDelegateHandleChar(key) == eKeyHandled)
1924 if (!field.FieldDelegateOnLastOrOnlyElement())
1925 return eKeyNotHandled;
1927 field.FieldDelegateExitCallback();
1929 if (m_selection_index == GetNumberOfFields() - 1) {
1930 m_selection_type = SelectionType::NewButton;
1934 m_selection_index++;
1935 FieldDelegate &next_field = m_fields[m_selection_index];
1936 next_field.FieldDelegateSelectFirstElement();
1940 HandleCharResult FieldDelegateHandleChar(
int key)
override {
1945 switch (m_selection_type) {
1946 case SelectionType::NewButton:
1949 case SelectionType::RemoveButton:
1952 case SelectionType::Field:
1953 return SelectNextInList(key);
1957 return SelectNext(key);
1959 return SelectPrevious(key);
1966 if (m_selection_type == SelectionType::Field) {
1967 return m_fields[m_selection_index].FieldDelegateHandleChar(key);
1970 return eKeyNotHandled;
1973 bool FieldDelegateOnLastOrOnlyElement()
override {
1974 if (m_selection_type == SelectionType::NewButton) {
1980 bool FieldDelegateOnFirstOrOnlyElement()
override {
1981 if (m_selection_type == SelectionType::NewButton &&
1982 GetNumberOfFields() == 0)
1985 if (m_selection_type == SelectionType::Field && m_selection_index == 0) {
1986 FieldDelegate &field = m_fields[m_selection_index];
1987 return field.FieldDelegateOnFirstOrOnlyElement();
1993 void FieldDelegateSelectFirstElement()
override {
1994 if (GetNumberOfFields() == 0) {
1995 m_selection_type = SelectionType::NewButton;
1999 m_selection_type = SelectionType::Field;
2000 m_selection_index = 0;
2003 void FieldDelegateSelectLastElement()
override {
2004 m_selection_type = SelectionType::NewButton;
2007 int GetNumberOfFields() {
return m_fields.size(); }
2010 T &GetField(
int index) {
return m_fields[index]; }
2013 std::string m_label;
2017 std::vector<T> m_fields;
2018 int m_selection_index = 0;
2020 SelectionType m_selection_type;
2023class ArgumentsFieldDelegate :
public ListFieldDelegate<TextFieldDelegate> {
2025 ArgumentsFieldDelegate()
2026 : ListFieldDelegate(
"Arguments",
2027 TextFieldDelegate(
"Argument",
"", false)) {}
2029 Args GetArguments() {
2031 for (
int i = 0; i < GetNumberOfFields(); i++) {
2037 void AddArguments(
const Args &arguments) {
2040 TextFieldDelegate &field = GetField(GetNumberOfFields() - 1);
2046template <
class KeyFieldDelegateType,
class ValueFieldDelegateType>
2047class MappingFieldDelegate :
public FieldDelegate {
2049 MappingFieldDelegate(KeyFieldDelegateType key_field,
2050 ValueFieldDelegateType value_field)
2051 : m_key_field(key_field), m_value_field(value_field),
2052 m_selection_type(SelectionType::Key) {}
2055 enum class SelectionType { Key, Value };
2068 int FieldDelegateGetHeight()
override {
2069 return std::max(m_key_field.FieldDelegateGetHeight(),
2070 m_value_field.FieldDelegateGetHeight());
2073 void DrawArrow(Surface &surface) {
2074 surface.MoveCursor(0, 1);
2075 surface.PutChar(ACS_RARROW);
2078 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
2079 Rect bounds = surface.GetFrame();
2080 Rect key_field_bounds, arrow_and_value_field_bounds;
2081 bounds.VerticalSplit(bounds.size.width / 2, key_field_bounds,
2082 arrow_and_value_field_bounds);
2083 Rect arrow_bounds, value_field_bounds;
2084 arrow_and_value_field_bounds.VerticalSplit(1, arrow_bounds,
2085 value_field_bounds);
2087 Surface key_field_surface = surface.SubSurface(key_field_bounds);
2088 Surface arrow_surface = surface.SubSurface(arrow_bounds);
2089 Surface value_field_surface = surface.SubSurface(value_field_bounds);
2091 bool key_is_selected =
2092 m_selection_type == SelectionType::Key && is_selected;
2093 m_key_field.FieldDelegateDraw(key_field_surface, key_is_selected);
2094 DrawArrow(arrow_surface);
2095 bool value_is_selected =
2096 m_selection_type == SelectionType::Value && is_selected;
2097 m_value_field.FieldDelegateDraw(value_field_surface, value_is_selected);
2100 HandleCharResult SelectNext(
int key) {
2101 if (FieldDelegateOnLastOrOnlyElement())
2102 return eKeyNotHandled;
2104 if (!m_key_field.FieldDelegateOnLastOrOnlyElement()) {
2105 return m_key_field.FieldDelegateHandleChar(key);
2108 m_key_field.FieldDelegateExitCallback();
2109 m_selection_type = SelectionType::Value;
2110 m_value_field.FieldDelegateSelectFirstElement();
2114 HandleCharResult SelectPrevious(
int key) {
2115 if (FieldDelegateOnFirstOrOnlyElement())
2116 return eKeyNotHandled;
2118 if (!m_value_field.FieldDelegateOnFirstOrOnlyElement()) {
2119 return m_value_field.FieldDelegateHandleChar(key);
2122 m_value_field.FieldDelegateExitCallback();
2123 m_selection_type = SelectionType::Key;
2124 m_key_field.FieldDelegateSelectLastElement();
2131 HandleCharResult SelectNextField(
int key) {
2132 if (m_selection_type == SelectionType::Value) {
2133 return m_value_field.FieldDelegateHandleChar(key);
2136 if (m_key_field.FieldDelegateHandleChar(key) == eKeyHandled)
2139 if (!m_key_field.FieldDelegateOnLastOrOnlyElement())
2140 return eKeyNotHandled;
2142 m_key_field.FieldDelegateExitCallback();
2143 m_selection_type = SelectionType::Value;
2144 m_value_field.FieldDelegateSelectFirstElement();
2148 HandleCharResult FieldDelegateHandleChar(
int key)
override {
2151 return SelectNextField(key);
2153 return SelectNext(key);
2155 return SelectPrevious(key);
2161 if (m_selection_type == SelectionType::Key)
2162 return m_key_field.FieldDelegateHandleChar(key);
2164 return m_value_field.FieldDelegateHandleChar(key);
2166 return eKeyNotHandled;
2169 bool FieldDelegateOnFirstOrOnlyElement()
override {
2170 return m_selection_type == SelectionType::Key;
2173 bool FieldDelegateOnLastOrOnlyElement()
override {
2174 return m_selection_type == SelectionType::Value;
2177 void FieldDelegateSelectFirstElement()
override {
2178 m_selection_type = SelectionType::Key;
2181 void FieldDelegateSelectLastElement()
override {
2182 m_selection_type = SelectionType::Value;
2185 bool FieldDelegateHasError()
override {
2186 return m_key_field.FieldDelegateHasError() ||
2187 m_value_field.FieldDelegateHasError();
2190 KeyFieldDelegateType &GetKeyField() {
return m_key_field; }
2192 ValueFieldDelegateType &GetValueField() {
return m_value_field; }
2195 KeyFieldDelegateType m_key_field;
2196 ValueFieldDelegateType m_value_field;
2198 SelectionType m_selection_type;
2201class EnvironmentVariableNameFieldDelegate :
public TextFieldDelegate {
2203 EnvironmentVariableNameFieldDelegate(
const char *content)
2204 : TextFieldDelegate(
"Name", content, true) {}
2207 bool IsAcceptableChar(
int key)
override {
2208 return TextFieldDelegate::IsAcceptableChar(key) && key !=
'=';
2211 const std::string &
GetName() {
return m_content; }
2214class EnvironmentVariableFieldDelegate
2215 :
public MappingFieldDelegate<EnvironmentVariableNameFieldDelegate,
2216 TextFieldDelegate> {
2218 EnvironmentVariableFieldDelegate()
2219 : MappingFieldDelegate(
2220 EnvironmentVariableNameFieldDelegate(
""),
2221 TextFieldDelegate(
"Value",
"", false)) {}
2223 const std::string &
GetName() {
return GetKeyField().GetName(); }
2225 const std::string &GetValue() {
return GetValueField().GetText(); }
2227 void SetName(
const char *name) {
return GetKeyField().SetText(name); }
2229 void SetValue(
const char *value) {
return GetValueField().SetText(value); }
2232class EnvironmentVariableListFieldDelegate
2233 :
public ListFieldDelegate<EnvironmentVariableFieldDelegate> {
2235 EnvironmentVariableListFieldDelegate(
const char *label)
2236 : ListFieldDelegate(label, EnvironmentVariableFieldDelegate()) {}
2238 Environment GetEnvironment() {
2239 Environment environment;
2240 for (
int i = 0; i < GetNumberOfFields(); i++) {
2242 std::make_pair(GetField(i).
GetName(), GetField(i).GetValue()));
2247 void AddEnvironmentVariables(
const Environment &environment) {
2248 for (
auto &variable : environment) {
2250 EnvironmentVariableFieldDelegate &field =
2251 GetField(GetNumberOfFields() - 1);
2252 field.SetName(variable.getKey().str().c_str());
2253 field.SetValue(variable.getValue().c_str());
2260 FormAction(
const char *label, std::function<
void(Window &)> action)
2261 : m_action(action) {
2267 void Draw(Surface &surface,
bool is_selected) {
2268 int x = (surface.GetWidth() - m_label.length()) / 2;
2269 surface.MoveCursor(x, 0);
2271 surface.AttributeOn(A_REVERSE);
2272 surface.PutChar(
'[');
2273 surface.PutCString(m_label.c_str());
2274 surface.PutChar(
']');
2276 surface.AttributeOff(A_REVERSE);
2279 void Execute(Window &window) { m_action(window); }
2281 const std::string &GetLabel() {
return m_label; }
2284 std::string m_label;
2285 std::function<void(Window &)> m_action;
2290 FormDelegate() =
default;
2292 virtual ~FormDelegate() =
default;
2294 virtual std::string
GetName() = 0;
2296 virtual void UpdateFieldsVisibility() {}
2298 FieldDelegate *GetField(uint32_t field_index) {
2299 if (field_index < m_fields.size())
2300 return m_fields[field_index].get();
2304 FormAction &GetAction(
int action_index) {
return m_actions[action_index]; }
2306 int GetNumberOfFields() {
return m_fields.size(); }
2308 int GetNumberOfActions() {
return m_actions.size(); }
2310 bool HasError() {
return !m_error.empty(); }
2312 void ClearError() { m_error.clear(); }
2314 const std::string &GetError() {
return m_error; }
2316 void SetError(
const char *
error) { m_error =
error; }
2321 bool CheckFieldsValidity() {
2322 for (
int i = 0; i < GetNumberOfFields(); i++) {
2323 GetField(i)->FieldDelegateExitCallback();
2324 if (GetField(i)->FieldDelegateHasError()) {
2325 SetError(
"Some fields are invalid!");
2334 TextFieldDelegate *AddTextField(
const char *label,
const char *content,
2336 TextFieldDelegate *delegate =
2337 new TextFieldDelegate(label, content, required);
2338 m_fields.push_back(FieldDelegateUP(delegate));
2342 FileFieldDelegate *AddFileField(
const char *label,
const char *content,
2343 bool need_to_exist,
bool required) {
2344 FileFieldDelegate *delegate =
2345 new FileFieldDelegate(label, content, need_to_exist, required);
2346 m_fields.push_back(FieldDelegateUP(delegate));
2350 DirectoryFieldDelegate *AddDirectoryField(
const char *label,
2351 const char *content,
2352 bool need_to_exist,
bool required) {
2353 DirectoryFieldDelegate *delegate =
2354 new DirectoryFieldDelegate(label, content, need_to_exist, required);
2355 m_fields.push_back(FieldDelegateUP(delegate));
2359 ArchFieldDelegate *AddArchField(
const char *label,
const char *content,
2361 ArchFieldDelegate *delegate =
2362 new ArchFieldDelegate(label, content, required);
2363 m_fields.push_back(FieldDelegateUP(delegate));
2367 IntegerFieldDelegate *AddIntegerField(
const char *label,
int content,
2369 IntegerFieldDelegate *delegate =
2370 new IntegerFieldDelegate(label, content, required);
2371 m_fields.push_back(FieldDelegateUP(delegate));
2375 BooleanFieldDelegate *AddBooleanField(
const char *label,
bool content) {
2376 BooleanFieldDelegate *delegate =
new BooleanFieldDelegate(label, content);
2377 m_fields.push_back(FieldDelegateUP(delegate));
2381 LazyBooleanFieldDelegate *AddLazyBooleanField(
const char *label,
2382 const char *calculate_label) {
2383 LazyBooleanFieldDelegate *delegate =
2384 new LazyBooleanFieldDelegate(label, calculate_label);
2385 m_fields.push_back(FieldDelegateUP(delegate));
2389 ChoicesFieldDelegate *AddChoicesField(
const char *label,
int height,
2390 std::vector<std::string> choices) {
2391 ChoicesFieldDelegate *delegate =
2392 new ChoicesFieldDelegate(label, height, choices);
2393 m_fields.push_back(FieldDelegateUP(delegate));
2397 PlatformPluginFieldDelegate *AddPlatformPluginField(Debugger &debugger) {
2398 PlatformPluginFieldDelegate *delegate =
2399 new PlatformPluginFieldDelegate(debugger);
2400 m_fields.push_back(FieldDelegateUP(delegate));
2404 ProcessPluginFieldDelegate *AddProcessPluginField() {
2405 ProcessPluginFieldDelegate *delegate =
new ProcessPluginFieldDelegate();
2406 m_fields.push_back(FieldDelegateUP(delegate));
2411 ListFieldDelegate<T> *AddListField(
const char *label, T default_field) {
2412 ListFieldDelegate<T> *delegate =
2413 new ListFieldDelegate<T>(label, default_field);
2414 m_fields.push_back(FieldDelegateUP(delegate));
2418 ArgumentsFieldDelegate *AddArgumentsField() {
2419 ArgumentsFieldDelegate *delegate =
new ArgumentsFieldDelegate();
2420 m_fields.push_back(FieldDelegateUP(delegate));
2424 template <
class K,
class V>
2425 MappingFieldDelegate<K, V> *AddMappingField(K key_field, V value_field) {
2426 MappingFieldDelegate<K, V> *delegate =
2427 new MappingFieldDelegate<K, V>(key_field, value_field);
2428 m_fields.push_back(FieldDelegateUP(delegate));
2432 EnvironmentVariableNameFieldDelegate *
2433 AddEnvironmentVariableNameField(
const char *content) {
2434 EnvironmentVariableNameFieldDelegate *delegate =
2435 new EnvironmentVariableNameFieldDelegate(content);
2436 m_fields.push_back(FieldDelegateUP(delegate));
2440 EnvironmentVariableFieldDelegate *AddEnvironmentVariableField() {
2441 EnvironmentVariableFieldDelegate *delegate =
2442 new EnvironmentVariableFieldDelegate();
2443 m_fields.push_back(FieldDelegateUP(delegate));
2447 EnvironmentVariableListFieldDelegate *
2448 AddEnvironmentVariableListField(
const char *label) {
2449 EnvironmentVariableListFieldDelegate *delegate =
2450 new EnvironmentVariableListFieldDelegate(label);
2451 m_fields.push_back(FieldDelegateUP(delegate));
2457 void AddAction(
const char *label, std::function<
void(Window &)> action) {
2458 m_actions.push_back(FormAction(label, action));
2462 std::vector<FieldDelegateUP> m_fields;
2463 std::vector<FormAction> m_actions;
2465 std::string m_error;
2468typedef std::shared_ptr<FormDelegate> FormDelegateSP;
2470class FormWindowDelegate :
public WindowDelegate {
2472 FormWindowDelegate(FormDelegateSP &delegate_sp) : m_delegate_sp(delegate_sp) {
2473 assert(m_delegate_sp->GetNumberOfActions() > 0);
2474 if (m_delegate_sp->GetNumberOfFields() > 0)
2475 m_selection_type = SelectionType::Field;
2477 m_selection_type = SelectionType::Action;
2483 enum class SelectionType { Field, Action };
2501 int GetErrorHeight() {
2502 if (m_delegate_sp->HasError())
2508 int GetActionsHeight() {
2509 if (m_delegate_sp->GetNumberOfActions() > 0)
2515 int GetContentHeight() {
2517 height += GetErrorHeight();
2518 for (
int i = 0; i < m_delegate_sp->GetNumberOfFields(); i++) {
2519 if (!m_delegate_sp->GetField(i)->FieldDelegateIsVisible())
2521 height += m_delegate_sp->GetField(i)->FieldDelegateGetHeight();
2523 height += GetActionsHeight();
2527 ScrollContext GetScrollContext() {
2528 if (m_selection_type == SelectionType::Action)
2529 return ScrollContext(GetContentHeight() - 1);
2531 FieldDelegate *field = m_delegate_sp->GetField(m_selection_index);
2532 ScrollContext context = field->FieldDelegateGetScrollContext();
2534 int offset = GetErrorHeight();
2535 for (
int i = 0; i < m_selection_index; i++) {
2536 if (!m_delegate_sp->GetField(i)->FieldDelegateIsVisible())
2538 offset += m_delegate_sp->GetField(i)->FieldDelegateGetHeight();
2540 context.Offset(offset);
2544 if (context.start == GetErrorHeight())
2550 void UpdateScrolling(Surface &surface) {
2551 ScrollContext context = GetScrollContext();
2552 int content_height = GetContentHeight();
2553 int surface_height = surface.GetHeight();
2554 int visible_height = std::min(content_height, surface_height);
2555 int last_visible_line = m_first_visible_line + visible_height - 1;
2560 if (last_visible_line > content_height - 1) {
2561 m_first_visible_line = content_height - visible_height;
2564 if (context.start < m_first_visible_line) {
2565 m_first_visible_line = context.start;
2569 if (context.end > last_visible_line) {
2570 m_first_visible_line = context.end - visible_height + 1;
2574 void DrawError(Surface &surface) {
2575 if (!m_delegate_sp->HasError())
2577 surface.MoveCursor(0, 0);
2578 surface.AttributeOn(COLOR_PAIR(RedOnBlack));
2579 surface.PutChar(ACS_DIAMOND);
2580 surface.PutChar(
' ');
2581 surface.PutCStringTruncated(1, m_delegate_sp->GetError().c_str());
2582 surface.AttributeOff(COLOR_PAIR(RedOnBlack));
2584 surface.MoveCursor(0, 1);
2585 surface.HorizontalLine(surface.GetWidth());
2588 void DrawFields(Surface &surface) {
2590 int width = surface.GetWidth();
2591 bool a_field_is_selected = m_selection_type == SelectionType::Field;
2592 for (
int i = 0; i < m_delegate_sp->GetNumberOfFields(); i++) {
2593 FieldDelegate *field = m_delegate_sp->GetField(i);
2594 if (!field->FieldDelegateIsVisible())
2596 bool is_field_selected = a_field_is_selected && m_selection_index == i;
2597 int height = field->FieldDelegateGetHeight();
2598 Rect bounds = Rect(Point(0, line), Size(width, height));
2599 Surface field_surface = surface.SubSurface(bounds);
2600 field->FieldDelegateDraw(field_surface, is_field_selected);
2605 void DrawActions(Surface &surface) {
2606 int number_of_actions = m_delegate_sp->GetNumberOfActions();
2607 int width = surface.GetWidth() / number_of_actions;
2608 bool an_action_is_selected = m_selection_type == SelectionType::Action;
2610 for (
int i = 0; i < number_of_actions; i++) {
2611 bool is_action_selected = an_action_is_selected && m_selection_index == i;
2612 FormAction &action = m_delegate_sp->GetAction(i);
2613 Rect bounds = Rect(Point(x, 0), Size(width, 1));
2614 Surface action_surface = surface.SubSurface(bounds);
2615 action.Draw(action_surface, is_action_selected);
2620 void DrawElements(Surface &surface) {
2621 Rect frame = surface.GetFrame();
2622 Rect fields_bounds, actions_bounds;
2623 frame.HorizontalSplit(surface.GetHeight() - GetActionsHeight(),
2624 fields_bounds, actions_bounds);
2625 Surface fields_surface = surface.SubSurface(fields_bounds);
2626 Surface actions_surface = surface.SubSurface(actions_bounds);
2628 DrawFields(fields_surface);
2629 DrawActions(actions_surface);
2635 void DrawContent(Surface &surface) {
2636 UpdateScrolling(surface);
2638 int width = surface.GetWidth();
2639 int height = GetContentHeight();
2640 Pad pad = Pad(Size(width, height));
2642 Rect frame = pad.GetFrame();
2643 Rect error_bounds, elements_bounds;
2644 frame.HorizontalSplit(GetErrorHeight(), error_bounds, elements_bounds);
2645 Surface error_surface = pad.SubSurface(error_bounds);
2646 Surface elements_surface = pad.SubSurface(elements_bounds);
2648 DrawError(error_surface);
2649 DrawElements(elements_surface);
2651 int copy_height = std::min(surface.GetHeight(), pad.GetHeight());
2652 pad.CopyToSurface(surface, Point(0, m_first_visible_line), Point(),
2653 Size(width, copy_height));
2656 void DrawSubmitHint(Surface &surface,
bool is_active) {
2657 surface.MoveCursor(2, surface.GetHeight() - 1);
2659 surface.AttributeOn(A_BOLD | COLOR_PAIR(BlackOnWhite));
2660 surface.Printf(
"[Press Alt+Enter to %s]",
2661 m_delegate_sp->GetAction(0).GetLabel().c_str());
2663 surface.AttributeOff(A_BOLD | COLOR_PAIR(BlackOnWhite));
2666 bool WindowDelegateDraw(Window &window,
bool force)
override {
2667 m_delegate_sp->UpdateFieldsVisibility();
2671 window.DrawTitleBox(m_delegate_sp->GetName().c_str(),
2672 "Press Esc to Cancel");
2673 DrawSubmitHint(window, window.IsActive());
2675 Rect content_bounds = window.GetFrame();
2676 content_bounds.Inset(2, 2);
2677 Surface content_surface = window.SubSurface(content_bounds);
2679 DrawContent(content_surface);
2683 void SkipNextHiddenFields() {
2685 if (m_delegate_sp->GetField(m_selection_index)->FieldDelegateIsVisible())
2688 if (m_selection_index == m_delegate_sp->GetNumberOfFields() - 1) {
2689 m_selection_type = SelectionType::Action;
2690 m_selection_index = 0;
2694 m_selection_index++;
2698 HandleCharResult SelectNext(
int key) {
2699 if (m_selection_type == SelectionType::Action) {
2700 if (m_selection_index < m_delegate_sp->GetNumberOfActions() - 1) {
2701 m_selection_index++;
2705 m_selection_index = 0;
2706 m_selection_type = SelectionType::Field;
2707 SkipNextHiddenFields();
2708 if (m_selection_type == SelectionType::Field) {
2709 FieldDelegate *next_field = m_delegate_sp->GetField(m_selection_index);
2710 next_field->FieldDelegateSelectFirstElement();
2715 FieldDelegate *field = m_delegate_sp->GetField(m_selection_index);
2716 if (!field->FieldDelegateOnLastOrOnlyElement()) {
2717 return field->FieldDelegateHandleChar(key);
2720 field->FieldDelegateExitCallback();
2722 if (m_selection_index == m_delegate_sp->GetNumberOfFields() - 1) {
2723 m_selection_type = SelectionType::Action;
2724 m_selection_index = 0;
2728 m_selection_index++;
2729 SkipNextHiddenFields();
2731 if (m_selection_type == SelectionType::Field) {
2732 FieldDelegate *next_field = m_delegate_sp->GetField(m_selection_index);
2733 next_field->FieldDelegateSelectFirstElement();
2739 void SkipPreviousHiddenFields() {
2741 if (m_delegate_sp->GetField(m_selection_index)->FieldDelegateIsVisible())
2744 if (m_selection_index == 0) {
2745 m_selection_type = SelectionType::Action;
2746 m_selection_index = 0;
2750 m_selection_index--;
2754 HandleCharResult SelectPrevious(
int key) {
2755 if (m_selection_type == SelectionType::Action) {
2756 if (m_selection_index > 0) {
2757 m_selection_index--;
2760 m_selection_index = m_delegate_sp->GetNumberOfFields() - 1;
2761 m_selection_type = SelectionType::Field;
2762 SkipPreviousHiddenFields();
2763 if (m_selection_type == SelectionType::Field) {
2764 FieldDelegate *previous_field =
2765 m_delegate_sp->GetField(m_selection_index);
2766 previous_field->FieldDelegateSelectLastElement();
2771 FieldDelegate *field = m_delegate_sp->GetField(m_selection_index);
2772 if (!field->FieldDelegateOnFirstOrOnlyElement()) {
2773 return field->FieldDelegateHandleChar(key);
2776 field->FieldDelegateExitCallback();
2778 if (m_selection_index == 0) {
2779 m_selection_type = SelectionType::Action;
2780 m_selection_index = m_delegate_sp->GetNumberOfActions() - 1;
2784 m_selection_index--;
2785 SkipPreviousHiddenFields();
2787 if (m_selection_type == SelectionType::Field) {
2788 FieldDelegate *previous_field =
2789 m_delegate_sp->GetField(m_selection_index);
2790 previous_field->FieldDelegateSelectLastElement();
2796 void ExecuteAction(Window &window,
int index) {
2797 FormAction &action = m_delegate_sp->GetAction(index);
2798 action.Execute(window);
2799 if (m_delegate_sp->HasError()) {
2800 m_first_visible_line = 0;
2801 m_selection_index = 0;
2802 m_selection_type = SelectionType::Field;
2808 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override {
2813 if (m_selection_type == SelectionType::Action) {
2814 ExecuteAction(window, m_selection_index);
2819 ExecuteAction(window, 0);
2825 SelectPrevious(key);
2828 window.GetParent()->RemoveSubWindow(&window);
2836 if (m_selection_type == SelectionType::Field) {
2837 FieldDelegate *field = m_delegate_sp->GetField(m_selection_index);
2838 if (field->FieldDelegateHandleChar(key) == eKeyHandled)
2849 SelectPrevious(key);
2859 FormDelegateSP m_delegate_sp;
2861 int m_selection_index = 0;
2863 SelectionType m_selection_type;
2865 int m_first_visible_line = 0;
2872class DetachOrKillProcessFormDelegate :
public FormDelegate {
2874 DetachOrKillProcessFormDelegate(
Process *process) : m_process(process) {
2875 SetError(
"There is a running process, either detach or kill it.");
2877 m_keep_stopped_field =
2878 AddBooleanField(
"Keep process stopped when detaching.",
false);
2880 AddAction(
"Detach", [
this](Window &window) { Detach(window); });
2881 AddAction(
"Kill", [
this](Window &window) { Kill(window); });
2884 std::string
GetName()
override {
return "Detach/Kill Process"; }
2886 void Kill(Window &window) {
2887 Status destroy_status(m_process->Destroy(
false));
2888 if (destroy_status.Fail()) {
2889 SetError(
"Failed to kill process.");
2892 window.GetParent()->RemoveSubWindow(&window);
2895 void Detach(Window &window) {
2896 Status detach_status(m_process->Detach(m_keep_stopped_field->GetBoolean()));
2897 if (detach_status.Fail()) {
2898 SetError(
"Failed to detach from process.");
2901 window.GetParent()->RemoveSubWindow(&window);
2906 BooleanFieldDelegate *m_keep_stopped_field;
2909class ProcessAttachFormDelegate :
public FormDelegate {
2911 ProcessAttachFormDelegate(Debugger &debugger, WindowSP main_window_sp)
2912 : m_debugger(debugger), m_main_window_sp(main_window_sp) {
2913 std::vector<std::string> types;
2914 types.push_back(std::string(
"Name"));
2915 types.push_back(std::string(
"PID"));
2916 m_type_field = AddChoicesField(
"Attach By", 2, types);
2917 m_pid_field = AddIntegerField(
"PID", 0,
true);
2919 AddTextField(
"Process Name", GetDefaultProcessName().c_str(),
true);
2920 m_continue_field = AddBooleanField(
"Continue once attached.",
false);
2921 m_wait_for_field = AddBooleanField(
"Wait for process to launch.",
false);
2922 m_include_existing_field =
2923 AddBooleanField(
"Include existing processes.",
false);
2924 m_show_advanced_field = AddBooleanField(
"Show advanced settings.",
false);
2925 m_plugin_field = AddProcessPluginField();
2927 AddAction(
"Attach", [
this](Window &window) { Attach(window); });
2930 std::string
GetName()
override {
return "Attach Process"; }
2932 void UpdateFieldsVisibility()
override {
2933 if (m_type_field->GetChoiceContent() ==
"Name") {
2934 m_pid_field->FieldDelegateHide();
2935 m_name_field->FieldDelegateShow();
2936 m_wait_for_field->FieldDelegateShow();
2937 if (m_wait_for_field->GetBoolean())
2938 m_include_existing_field->FieldDelegateShow();
2940 m_include_existing_field->FieldDelegateHide();
2942 m_pid_field->FieldDelegateShow();
2943 m_name_field->FieldDelegateHide();
2944 m_wait_for_field->FieldDelegateHide();
2945 m_include_existing_field->FieldDelegateHide();
2947 if (m_show_advanced_field->GetBoolean())
2948 m_plugin_field->FieldDelegateShow();
2950 m_plugin_field->FieldDelegateHide();
2955 std::string GetDefaultProcessName() {
2956 Target *target = m_debugger
2957 .GetSelectedExecutionContext(
2960 if (target ==
nullptr)
2967 return module_sp->GetFileSpec().GetFilename().str();
2970 bool StopRunningProcess() {
2971 ExecutionContext exe_ctx =
2972 m_debugger.GetCommandInterpreter().GetExecutionContext();
2978 if (!(process && process->
IsAlive()))
2981 FormDelegateSP form_delegate_sp =
2982 FormDelegateSP(
new DetachOrKillProcessFormDelegate(process));
2983 Rect bounds = m_main_window_sp->GetCenteredRect(85, 8);
2984 WindowSP form_window_sp = m_main_window_sp->CreateSubWindow(
2985 form_delegate_sp->GetName().c_str(), bounds,
true);
2986 WindowDelegateSP window_delegate_sp =
2987 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
2988 form_window_sp->SetDelegate(window_delegate_sp);
2994 Target *target = m_debugger
2995 .GetSelectedExecutionContext(
2999 if (target !=
nullptr)
3003 m_debugger.GetTargetList().CreateTarget(
3006 target = new_target_sp.get();
3008 if (target ==
nullptr)
3009 SetError(
"Failed to create target.");
3011 m_debugger.GetTargetList().SetSelectedTarget(new_target_sp);
3016 ProcessAttachInfo GetAttachInfo() {
3017 ProcessAttachInfo attach_info;
3019 if (m_type_field->GetChoiceContent() ==
"Name") {
3021 FileSpec::Style::native);
3023 if (m_wait_for_field->GetBoolean())
3033 void Attach(Window &window) {
3036 bool all_fields_are_valid = CheckFieldsValidity();
3037 if (!all_fields_are_valid)
3040 bool process_is_running = StopRunningProcess();
3041 if (process_is_running)
3044 Target *target = GetTarget();
3048 StreamString stream;
3049 ProcessAttachInfo attach_info = GetAttachInfo();
3052 if (status.
Fail()) {
3059 SetError(
"Attached sucessfully but target has no process.");
3064 process_sp->Resume();
3066 window.GetParent()->RemoveSubWindow(&window);
3070 Debugger &m_debugger;
3071 WindowSP m_main_window_sp;
3073 ChoicesFieldDelegate *m_type_field;
3074 IntegerFieldDelegate *m_pid_field;
3075 TextFieldDelegate *m_name_field;
3076 BooleanFieldDelegate *m_continue_field;
3077 BooleanFieldDelegate *m_wait_for_field;
3078 BooleanFieldDelegate *m_include_existing_field;
3079 BooleanFieldDelegate *m_show_advanced_field;
3080 ProcessPluginFieldDelegate *m_plugin_field;
3083class TargetCreateFormDelegate :
public FormDelegate {
3085 TargetCreateFormDelegate(Debugger &debugger) : m_debugger(debugger) {
3086 m_executable_field = AddFileField(
"Executable",
"",
true,
3088 m_core_file_field = AddFileField(
"Core File",
"",
true,
3090 m_symbol_file_field = AddFileField(
3091 "Symbol File",
"",
true,
false);
3092 m_show_advanced_field = AddBooleanField(
"Show advanced settings.",
false);
3093 m_remote_file_field = AddFileField(
3094 "Remote File",
"",
false,
false);
3095 m_arch_field = AddArchField(
"Architecture",
"",
false);
3096 m_platform_field = AddPlatformPluginField(debugger);
3097 m_load_dependent_files_field =
3098 AddChoicesField(
"Load Dependents", 3, GetLoadDependentFilesChoices());
3100 AddAction(
"Create", [
this](Window &window) { CreateTarget(window); });
3103 std::string
GetName()
override {
return "Create Target"; }
3105 void UpdateFieldsVisibility()
override {
3106 if (m_show_advanced_field->GetBoolean()) {
3107 m_remote_file_field->FieldDelegateShow();
3108 m_arch_field->FieldDelegateShow();
3109 m_platform_field->FieldDelegateShow();
3110 m_load_dependent_files_field->FieldDelegateShow();
3112 m_remote_file_field->FieldDelegateHide();
3113 m_arch_field->FieldDelegateHide();
3114 m_platform_field->FieldDelegateHide();
3115 m_load_dependent_files_field->FieldDelegateHide();
3119 static constexpr const char *kLoadDependentFilesNo =
"No";
3120 static constexpr const char *kLoadDependentFilesYes =
"Yes";
3121 static constexpr const char *kLoadDependentFilesExecOnly =
"Executable only";
3123 std::vector<std::string> GetLoadDependentFilesChoices() {
3124 std::vector<std::string> load_dependents_options;
3125 load_dependents_options.push_back(kLoadDependentFilesExecOnly);
3126 load_dependents_options.push_back(kLoadDependentFilesYes);
3127 load_dependents_options.push_back(kLoadDependentFilesNo);
3128 return load_dependents_options;
3132 std::string choice = m_load_dependent_files_field->GetChoiceContent();
3133 if (choice == kLoadDependentFilesNo)
3135 if (choice == kLoadDependentFilesYes)
3140 OptionGroupPlatform GetPlatformOptions() {
3141 OptionGroupPlatform platform_options(
false);
3142 platform_options.SetPlatformName(m_platform_field->GetPluginName().c_str());
3143 return platform_options;
3147 OptionGroupPlatform platform_options = GetPlatformOptions();
3149 Status status = m_debugger.GetTargetList().CreateTarget(
3150 m_debugger, m_executable_field->GetPath(),
3151 m_arch_field->GetArchString(), GetLoadDependentFiles(),
3152 &platform_options, target_sp);
3154 if (status.
Fail()) {
3159 m_debugger.GetTargetList().SetSelectedTarget(target_sp);
3164 void SetSymbolFile(
TargetSP target_sp) {
3165 if (!m_symbol_file_field->IsSpecified())
3168 ModuleSP module_sp(target_sp->GetExecutableModule());
3172 module_sp->SetSymbolFileFileSpec(
3173 m_symbol_file_field->GetResolvedFileSpec());
3176 void SetCoreFile(
TargetSP target_sp) {
3177 if (!m_core_file_field->IsSpecified())
3180 FileSpec core_file_spec = m_core_file_field->GetResolvedFileSpec();
3182 FileSpec core_file_directory_spec;
3184 target_sp->AppendExecutableSearchPaths(core_file_directory_spec);
3186 ProcessSP process_sp(target_sp->CreateProcess(
3187 m_debugger.GetListener(), llvm::StringRef(), &core_file_spec,
false));
3190 SetError(
"Unknown core file format!");
3194 Status status = process_sp->LoadCore();
3195 if (status.
Fail()) {
3196 SetError(
"Unknown core file format!");
3201 void SetRemoteFile(
TargetSP target_sp) {
3202 if (!m_remote_file_field->IsSpecified())
3205 ModuleSP module_sp(target_sp->GetExecutableModule());
3209 FileSpec remote_file_spec = m_remote_file_field->GetFileSpec();
3210 module_sp->SetPlatformFileSpec(remote_file_spec);
3213 void RemoveTarget(
TargetSP target_sp) {
3214 m_debugger.GetTargetList().DeleteTarget(target_sp);
3217 void CreateTarget(Window &window) {
3220 bool all_fields_are_valid = CheckFieldsValidity();
3221 if (!all_fields_are_valid)
3228 SetSymbolFile(target_sp);
3230 RemoveTarget(target_sp);
3234 SetCoreFile(target_sp);
3236 RemoveTarget(target_sp);
3240 SetRemoteFile(target_sp);
3242 RemoveTarget(target_sp);
3246 window.GetParent()->RemoveSubWindow(&window);
3250 Debugger &m_debugger;
3252 FileFieldDelegate *m_executable_field;
3253 FileFieldDelegate *m_core_file_field;
3254 FileFieldDelegate *m_symbol_file_field;
3255 BooleanFieldDelegate *m_show_advanced_field;
3256 FileFieldDelegate *m_remote_file_field;
3257 ArchFieldDelegate *m_arch_field;
3258 PlatformPluginFieldDelegate *m_platform_field;
3259 ChoicesFieldDelegate *m_load_dependent_files_field;
3262class ProcessLaunchFormDelegate :
public FormDelegate {
3264 ProcessLaunchFormDelegate(Debugger &debugger, WindowSP main_window_sp)
3265 : m_debugger(debugger), m_main_window_sp(main_window_sp) {
3267 m_arguments_field = AddArgumentsField();
3268 SetArgumentsFieldDefaultValue();
3269 m_target_environment_field =
3270 AddEnvironmentVariableListField(
"Target Environment Variables");
3271 SetTargetEnvironmentFieldDefaultValue();
3272 m_working_directory_field = AddDirectoryField(
3273 "Working Directory", GetDefaultWorkingDirectory().c_str(),
true,
false);
3275 m_show_advanced_field = AddBooleanField(
"Show advanced settings.",
false);
3277 m_stop_at_entry_field = AddBooleanField(
"Stop at entry point.",
false);
3278 m_detach_on_error_field =
3279 AddBooleanField(
"Detach on error.", GetDefaultDetachOnError());
3280 m_disable_aslr_field =
3281 AddBooleanField(
"Disable ASLR", GetDefaultDisableASLR());
3282 m_plugin_field = AddProcessPluginField();
3283 m_arch_field = AddArchField(
"Architecture",
"",
false);
3284 m_shell_field = AddFileField(
"Shell",
"",
true,
false);
3285 m_expand_shell_arguments_field =
3286 AddBooleanField(
"Expand shell arguments.",
false);
3288 m_disable_standard_io_field =
3289 AddBooleanField(
"Disable Standard IO", GetDefaultDisableStandardIO());
3290 m_standard_output_field =
3291 AddFileField(
"Standard Output File",
"",
false,
3293 m_standard_error_field =
3294 AddFileField(
"Standard Error File",
"",
false,
3296 m_standard_input_field =
3297 AddFileField(
"Standard Input File",
"",
false,
3300 m_show_inherited_environment_field =
3301 AddBooleanField(
"Show inherited environment variables.",
false);
3302 m_inherited_environment_field =
3303 AddEnvironmentVariableListField(
"Inherited Environment Variables");
3304 SetInheritedEnvironmentFieldDefaultValue();
3306 AddAction(
"Launch", [
this](Window &window) { Launch(window); });
3309 std::string
GetName()
override {
return "Launch Process"; }
3311 void UpdateFieldsVisibility()
override {
3312 if (m_show_advanced_field->GetBoolean()) {
3313 m_stop_at_entry_field->FieldDelegateShow();
3314 m_detach_on_error_field->FieldDelegateShow();
3315 m_disable_aslr_field->FieldDelegateShow();
3316 m_plugin_field->FieldDelegateShow();
3317 m_arch_field->FieldDelegateShow();
3318 m_shell_field->FieldDelegateShow();
3319 m_expand_shell_arguments_field->FieldDelegateShow();
3320 m_disable_standard_io_field->FieldDelegateShow();
3321 if (m_disable_standard_io_field->GetBoolean()) {
3322 m_standard_input_field->FieldDelegateHide();
3323 m_standard_output_field->FieldDelegateHide();
3324 m_standard_error_field->FieldDelegateHide();
3326 m_standard_input_field->FieldDelegateShow();
3327 m_standard_output_field->FieldDelegateShow();
3328 m_standard_error_field->FieldDelegateShow();
3330 m_show_inherited_environment_field->FieldDelegateShow();
3331 if (m_show_inherited_environment_field->GetBoolean())
3332 m_inherited_environment_field->FieldDelegateShow();
3334 m_inherited_environment_field->FieldDelegateHide();
3336 m_stop_at_entry_field->FieldDelegateHide();
3337 m_detach_on_error_field->FieldDelegateHide();
3338 m_disable_aslr_field->FieldDelegateHide();
3339 m_plugin_field->FieldDelegateHide();
3340 m_arch_field->FieldDelegateHide();
3341 m_shell_field->FieldDelegateHide();
3342 m_expand_shell_arguments_field->FieldDelegateHide();
3343 m_disable_standard_io_field->FieldDelegateHide();
3344 m_standard_input_field->FieldDelegateHide();
3345 m_standard_output_field->FieldDelegateHide();
3346 m_standard_error_field->FieldDelegateHide();
3347 m_show_inherited_environment_field->FieldDelegateHide();
3348 m_inherited_environment_field->FieldDelegateHide();
3354 void SetArgumentsFieldDefaultValue() {
3356 .GetSelectedExecutionContext(
3359 if (target ==
nullptr)
3362 const Args &target_arguments =
3363 target->GetProcessLaunchInfo().GetArguments();
3364 m_arguments_field->AddArguments(target_arguments);
3367 void SetTargetEnvironmentFieldDefaultValue() {
3369 .GetSelectedExecutionContext(
3372 if (target ==
nullptr)
3375 const Environment &target_environment = target->GetTargetEnvironment();
3376 m_target_environment_field->AddEnvironmentVariables(target_environment);
3379 void SetInheritedEnvironmentFieldDefaultValue() {
3381 .GetSelectedExecutionContext(
3384 if (target ==
nullptr)
3387 const Environment &inherited_environment =
3388 target->GetInheritedEnvironment();
3389 m_inherited_environment_field->AddEnvironmentVariables(
3390 inherited_environment);
3393 std::string GetDefaultWorkingDirectory() {
3395 .GetSelectedExecutionContext(
3398 if (target ==
nullptr)
3402 return platform->GetWorkingDirectory().GetPath();
3405 bool GetDefaultDisableASLR() {
3407 .GetSelectedExecutionContext(
3410 if (target ==
nullptr)
3413 return target->GetDisableASLR();
3416 bool GetDefaultDisableStandardIO() {
3418 .GetSelectedExecutionContext(
3421 if (target ==
nullptr)
3424 return target->GetDisableSTDIO();
3427 bool GetDefaultDetachOnError() {
3429 .GetSelectedExecutionContext(
3432 if (target ==
nullptr)
3435 return target->GetDetachOnError();
3441 void GetExecutableSettings(ProcessLaunchInfo &launch_info) {
3443 .GetSelectedExecutionContext(
3446 ModuleSP executable_module = target->GetExecutableModule();
3447 if (!executable_module)
3449 llvm::StringRef target_settings_argv0 = target->GetArg0();
3451 if (!target_settings_argv0.empty()) {
3462 void GetArguments(ProcessLaunchInfo &launch_info) {
3464 .GetSelectedExecutionContext(
3467 Args arguments = m_arguments_field->GetArguments();
3471 void GetEnvironment(ProcessLaunchInfo &launch_info) {
3472 Environment target_environment =
3473 m_target_environment_field->GetEnvironment();
3474 Environment inherited_environment =
3475 m_inherited_environment_field->GetEnvironment();
3477 target_environment.end());
3479 inherited_environment.end());
3482 void GetWorkingDirectory(ProcessLaunchInfo &launch_info) {
3483 if (m_working_directory_field->IsSpecified())
3485 m_working_directory_field->GetResolvedFileSpec());
3488 void GetStopAtEntry(ProcessLaunchInfo &launch_info) {
3489 if (m_stop_at_entry_field->GetBoolean())
3490 launch_info.
GetFlags().
Set(eLaunchFlagStopAtEntry);
3495 void GetDetachOnError(ProcessLaunchInfo &launch_info) {
3496 if (m_detach_on_error_field->GetBoolean())
3497 launch_info.
GetFlags().
Set(eLaunchFlagDetachOnError);
3502 void GetDisableASLR(ProcessLaunchInfo &launch_info) {
3503 if (m_disable_aslr_field->GetBoolean())
3504 launch_info.
GetFlags().
Set(eLaunchFlagDisableASLR);
3509 void GetPlugin(ProcessLaunchInfo &launch_info) {
3513 void GetArch(ProcessLaunchInfo &launch_info) {
3514 if (!m_arch_field->IsSpecified())
3518 .GetSelectedExecutionContext(
3522 target_sp ? target_sp->GetPlatform() :
PlatformSP();
3524 platform_sp.get(), m_arch_field->GetArchString());
3527 void GetShell(ProcessLaunchInfo &launch_info) {
3528 if (!m_shell_field->IsSpecified())
3531 launch_info.
SetShell(m_shell_field->GetResolvedFileSpec());
3533 m_expand_shell_arguments_field->GetBoolean());
3536 void GetStandardIO(ProcessLaunchInfo &launch_info) {
3537 if (m_disable_standard_io_field->GetBoolean()) {
3538 launch_info.
GetFlags().
Set(eLaunchFlagDisableSTDIO);
3543 if (m_standard_input_field->IsSpecified()) {
3544 if (action.
Open(STDIN_FILENO, m_standard_input_field->GetFileSpec(),
true,
3548 if (m_standard_output_field->IsSpecified()) {
3549 if (action.
Open(STDOUT_FILENO, m_standard_output_field->GetFileSpec(),
3553 if (m_standard_error_field->IsSpecified()) {
3554 if (action.
Open(STDERR_FILENO, m_standard_error_field->GetFileSpec(),
3560 void GetInheritTCC(ProcessLaunchInfo &launch_info) {
3561 if (
Target *target = m_debugger
3562 .GetSelectedExecutionContext(
3565 target && target->GetInheritTCC())
3566 launch_info.
GetFlags().
Set(eLaunchFlagInheritTCCFromParent);
3569 ProcessLaunchInfo GetLaunchInfo() {
3570 ProcessLaunchInfo launch_info;
3572 GetExecutableSettings(launch_info);
3573 GetArguments(launch_info);
3574 GetEnvironment(launch_info);
3575 GetWorkingDirectory(launch_info);
3576 GetStopAtEntry(launch_info);
3577 GetDetachOnError(launch_info);
3578 GetDisableASLR(launch_info);
3579 GetPlugin(launch_info);
3580 GetArch(launch_info);
3581 GetShell(launch_info);
3582 GetStandardIO(launch_info);
3583 GetInheritTCC(launch_info);
3588 bool StopRunningProcess() {
3589 ExecutionContext exe_ctx =
3590 m_debugger.GetCommandInterpreter().GetExecutionContext();
3596 if (!(process && process->
IsAlive()))
3599 FormDelegateSP form_delegate_sp =
3600 FormDelegateSP(
new DetachOrKillProcessFormDelegate(process));
3601 Rect bounds = m_main_window_sp->GetCenteredRect(85, 8);
3602 WindowSP form_window_sp = m_main_window_sp->CreateSubWindow(
3603 form_delegate_sp->GetName().c_str(), bounds,
true);
3604 WindowDelegateSP window_delegate_sp =
3605 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
3606 form_window_sp->SetDelegate(window_delegate_sp);
3612 Target *target = m_debugger
3613 .GetSelectedExecutionContext(
3617 if (target ==
nullptr) {
3618 SetError(
"No target exists!");
3624 if (exe_module_sp ==
nullptr) {
3625 SetError(
"No executable in target!");
3632 void Launch(Window &window) {
3635 bool all_fields_are_valid = CheckFieldsValidity();
3636 if (!all_fields_are_valid)
3639 bool process_is_running = StopRunningProcess();
3640 if (process_is_running)
3643 Target *target = GetTarget();
3647 StreamString stream;
3648 ProcessLaunchInfo launch_info = GetLaunchInfo();
3651 if (status.
Fail()) {
3658 SetError(
"Launched successfully but target has no process!");
3662 window.GetParent()->RemoveSubWindow(&window);
3666 Debugger &m_debugger;
3667 WindowSP m_main_window_sp;
3669 ArgumentsFieldDelegate *m_arguments_field;
3670 EnvironmentVariableListFieldDelegate *m_target_environment_field;
3671 DirectoryFieldDelegate *m_working_directory_field;
3673 BooleanFieldDelegate *m_show_advanced_field;
3675 BooleanFieldDelegate *m_stop_at_entry_field;
3676 BooleanFieldDelegate *m_detach_on_error_field;
3677 BooleanFieldDelegate *m_disable_aslr_field;
3678 ProcessPluginFieldDelegate *m_plugin_field;
3679 ArchFieldDelegate *m_arch_field;
3680 FileFieldDelegate *m_shell_field;
3681 BooleanFieldDelegate *m_expand_shell_arguments_field;
3682 BooleanFieldDelegate *m_disable_standard_io_field;
3683 FileFieldDelegate *m_standard_input_field;
3684 FileFieldDelegate *m_standard_output_field;
3685 FileFieldDelegate *m_standard_error_field;
3687 BooleanFieldDelegate *m_show_inherited_environment_field;
3688 EnvironmentVariableListFieldDelegate *m_inherited_environment_field;
3695class SearcherDelegate {
3697 SearcherDelegate() =
default;
3699 virtual ~SearcherDelegate() =
default;
3701 virtual int GetNumberOfMatches() = 0;
3704 virtual const std::string &GetMatchTextAtIndex(
int index) = 0;
3708 virtual void UpdateMatches(
const std::string &text) = 0;
3712 virtual void ExecuteCallback(
int match_index) = 0;
3715typedef std::shared_ptr<SearcherDelegate> SearcherDelegateSP;
3717class SearcherWindowDelegate :
public WindowDelegate {
3719 SearcherWindowDelegate(SearcherDelegateSP &delegate_sp)
3720 : m_delegate_sp(delegate_sp), m_text_field(
"Search",
"", false) {
3742 int GetLastVisibleMatch(
int height) {
3743 int index = m_first_visible_match + height;
3744 return std::min(index, m_delegate_sp->GetNumberOfMatches()) - 1;
3747 int GetNumberOfVisibleMatches(
int height) {
3748 return GetLastVisibleMatch(height) - m_first_visible_match + 1;
3751 void UpdateScrolling(Surface &surface) {
3752 if (m_selected_match < m_first_visible_match) {
3753 m_first_visible_match = m_selected_match;
3757 int height = surface.GetHeight();
3758 int last_visible_match = GetLastVisibleMatch(height);
3759 if (m_selected_match > last_visible_match) {
3760 m_first_visible_match = m_selected_match - height + 1;
3764 void DrawMatches(Surface &surface) {
3765 if (m_delegate_sp->GetNumberOfMatches() == 0)
3768 UpdateScrolling(surface);
3770 int count = GetNumberOfVisibleMatches(surface.GetHeight());
3771 for (
int i = 0; i < count; i++) {
3772 surface.MoveCursor(1, i);
3773 int current_match = m_first_visible_match + i;
3774 if (current_match == m_selected_match)
3775 surface.AttributeOn(A_REVERSE);
3777 m_delegate_sp->GetMatchTextAtIndex(current_match).c_str());
3778 if (current_match == m_selected_match)
3779 surface.AttributeOff(A_REVERSE);
3783 void DrawContent(Surface &surface) {
3784 Rect content_bounds = surface.GetFrame();
3785 Rect text_field_bounds, matchs_bounds;
3786 content_bounds.HorizontalSplit(m_text_field.FieldDelegateGetHeight(),
3787 text_field_bounds, matchs_bounds);
3788 Surface text_field_surface = surface.SubSurface(text_field_bounds);
3789 Surface matches_surface = surface.SubSurface(matchs_bounds);
3791 m_text_field.FieldDelegateDraw(text_field_surface,
true);
3792 DrawMatches(matches_surface);
3795 bool WindowDelegateDraw(Window &window,
bool force)
override {
3798 window.DrawTitleBox(window.GetName(),
"Press Esc to Cancel");
3800 Rect content_bounds = window.GetFrame();
3801 content_bounds.Inset(2, 2);
3802 Surface content_surface = window.SubSurface(content_bounds);
3804 DrawContent(content_surface);
3809 if (m_selected_match != m_delegate_sp->GetNumberOfMatches() - 1)
3813 void SelectPrevious() {
3814 if (m_selected_match != 0)
3818 void ExecuteCallback(Window &window) {
3819 m_delegate_sp->ExecuteCallback(m_selected_match);
3820 window.GetParent()->RemoveSubWindow(&window);
3823 void UpdateMatches() {
3824 m_delegate_sp->UpdateMatches(m_text_field.GetText());
3825 m_selected_match = 0;
3828 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override {
3833 ExecuteCallback(window);
3844 window.GetParent()->RemoveSubWindow(&window);
3850 if (m_text_field.FieldDelegateHandleChar(key) == eKeyHandled)
3857 SearcherDelegateSP m_delegate_sp;
3858 TextFieldDelegate m_text_field;
3860 int m_selected_match = 0;
3862 int m_first_visible_match = 0;
3872class CommonCompletionSearcherDelegate :
public SearcherDelegate {
3874 typedef std::function<void(
const std::string &)> CallbackType;
3876 CommonCompletionSearcherDelegate(Debugger &debugger, uint32_t completion_mask,
3877 CallbackType callback)
3878 : m_debugger(debugger), m_completion_mask(completion_mask),
3879 m_callback(callback) {}
3881 int GetNumberOfMatches()
override {
return m_matches.GetSize(); }
3883 const std::string &GetMatchTextAtIndex(
int index)
override {
3884 return m_matches[index];
3887 void UpdateMatches(
const std::string &text)
override {
3888 CompletionResult result;
3889 CompletionRequest request(text.c_str(), text.size(), result);
3891 m_debugger.GetCommandInterpreter(), m_completion_mask, request,
3896 void ExecuteCallback(
int match_index)
override {
3897 m_callback(m_matches[match_index]);
3901 Debugger &m_debugger;
3903 uint32_t m_completion_mask;
3906 CallbackType m_callback;
3907 StringList m_matches;
3916 virtual ~MenuDelegate() =
default;
3918 virtual MenuActionResult MenuDelegateAction(Menu &menu) = 0;
3921class Menu :
public WindowDelegate {
3923 enum class Type {
Invalid, Bar, Item, Separator };
3929 Menu(
const char *name,
const char *key_name,
int key_value,
3930 uint64_t identifier);
3932 ~Menu()
override =
default;
3934 const MenuDelegateSP &GetDelegate()
const {
return m_delegate_sp; }
3936 void SetDelegate(
const MenuDelegateSP &delegate_sp) {
3937 m_delegate_sp = delegate_sp;
3940 void RecalculateNameLengths();
3942 void AddSubmenu(
const MenuSP &menu_sp);
3944 int DrawAndRunMenu(Window &window);
3946 void DrawMenuTitle(Window &window,
bool highlight);
3948 bool WindowDelegateDraw(Window &window,
bool force)
override;
3950 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override;
3952 MenuActionResult ActionPrivate(Menu &menu) {
3953 MenuActionResult result = MenuActionResult::NotHandled;
3954 if (m_delegate_sp) {
3955 result = m_delegate_sp->MenuDelegateAction(menu);
3956 if (result != MenuActionResult::NotHandled)
3958 }
else if (m_parent) {
3959 result = m_parent->ActionPrivate(menu);
3960 if (result != MenuActionResult::NotHandled)
3963 return m_canned_result;
3966 MenuActionResult Action() {
3969 return ActionPrivate(*
this);
3972 void SetCannedResult(MenuActionResult result) { m_canned_result = result; }
3974 Menus &GetSubmenus() {
return m_submenus; }
3976 const Menus &GetSubmenus()
const {
return m_submenus; }
3978 int GetSelectedSubmenuIndex()
const {
return m_selected; }
3980 void SetSelectedSubmenuIndex(
int idx) { m_selected = idx; }
3982 Type GetType()
const {
return m_type; }
3984 int GetStartingColumn()
const {
return m_start_col; }
3986 void SetStartingColumn(
int col) { m_start_col = col; }
3988 int GetKeyValue()
const {
return m_key_value; }
3990 std::string &
GetName() {
return m_name; }
3992 int GetDrawWidth()
const {
3993 return m_max_submenu_name_length + m_max_submenu_key_name_length + 8;
3996 uint64_t GetIdentifier()
const {
return m_identifier; }
3998 void SetIdentifier(uint64_t identifier) { m_identifier = identifier; }
4002 std::string m_key_name;
4003 uint64_t m_identifier;
4007 int m_max_submenu_name_length;
4008 int m_max_submenu_key_name_length;
4012 WindowSP m_menu_window_sp;
4013 MenuActionResult m_canned_result;
4014 MenuDelegateSP m_delegate_sp;
4018Menu::Menu(Type type)
4019 : m_name(), m_key_name(), m_identifier(0), m_type(type), m_key_value(0),
4020 m_start_col(0), m_max_submenu_name_length(0),
4021 m_max_submenu_key_name_length(0), m_selected(0), m_parent(nullptr),
4022 m_submenus(), m_canned_result(MenuActionResult::NotHandled),
4026Menu::Menu(
const char *name,
const char *key_name,
int key_value,
4027 uint64_t identifier)
4028 : m_name(), m_key_name(), m_identifier(identifier), m_type(
Type::
Invalid),
4029 m_key_value(key_value), m_start_col(0), m_max_submenu_name_length(0),
4030 m_max_submenu_key_name_length(0), m_selected(0), m_parent(nullptr),
4031 m_submenus(), m_canned_result(MenuActionResult::NotHandled),
4033 if (name && name[0]) {
4035 m_type = Type::Item;
4036 if (key_name && key_name[0])
4037 m_key_name = key_name;
4039 m_type = Type::Separator;
4043void Menu::RecalculateNameLengths() {
4044 m_max_submenu_name_length = 0;
4045 m_max_submenu_key_name_length = 0;
4046 Menus &submenus = GetSubmenus();
4047 const size_t num_submenus = submenus.size();
4048 for (
size_t i = 0; i < num_submenus; ++i) {
4049 Menu *submenu = submenus[i].get();
4050 if (
static_cast<size_t>(m_max_submenu_name_length) < submenu->m_name.size())
4051 m_max_submenu_name_length = submenu->m_name.size();
4052 if (
static_cast<size_t>(m_max_submenu_key_name_length) <
4053 submenu->m_key_name.size())
4054 m_max_submenu_key_name_length = submenu->m_key_name.size();
4058void Menu::AddSubmenu(
const MenuSP &menu_sp) {
4059 menu_sp->m_parent =
this;
4060 if (
static_cast<size_t>(m_max_submenu_name_length) < menu_sp->m_name.size())
4061 m_max_submenu_name_length = menu_sp->m_name.size();
4062 if (
static_cast<size_t>(m_max_submenu_key_name_length) <
4063 menu_sp->m_key_name.size())
4064 m_max_submenu_key_name_length = menu_sp->m_key_name.size();
4065 m_submenus.push_back(menu_sp);
4068void Menu::DrawMenuTitle(Window &window,
bool highlight) {
4069 if (m_type == Type::Separator) {
4070 window.MoveCursor(0, window.GetCursorY());
4071 window.PutChar(ACS_LTEE);
4072 int width = window.GetWidth();
4075 for (
int i = 0; i < width; ++i)
4076 window.PutChar(ACS_HLINE);
4078 window.PutChar(ACS_RTEE);
4080 const int shortcut_key = m_key_value;
4081 bool underlined_shortcut =
false;
4082 const attr_t highlight_attr = A_REVERSE;
4084 window.AttributeOn(highlight_attr);
4085 if (llvm::isPrint(shortcut_key)) {
4086 size_t lower_pos = m_name.find(tolower(shortcut_key));
4087 size_t upper_pos = m_name.find(toupper(shortcut_key));
4088 const char *name = m_name.c_str();
4089 size_t pos = std::min<size_t>(lower_pos, upper_pos);
4090 if (pos != std::string::npos) {
4091 underlined_shortcut =
true;
4093 window.PutCString(name, pos);
4096 const attr_t shortcut_attr = A_UNDERLINE | A_BOLD;
4097 window.AttributeOn(shortcut_attr);
4098 window.PutChar(name[0]);
4099 window.AttributeOff(shortcut_attr);
4102 window.PutCString(name);
4106 if (!underlined_shortcut) {
4107 window.PutCString(m_name.c_str());
4111 window.AttributeOff(highlight_attr);
4113 if (m_key_name.empty()) {
4114 if (!underlined_shortcut && llvm::isPrint(m_key_value)) {
4115 window.AttributeOn(COLOR_PAIR(MagentaOnWhite));
4116 window.Printf(
" (%c)", m_key_value);
4117 window.AttributeOff(COLOR_PAIR(MagentaOnWhite));
4120 window.AttributeOn(COLOR_PAIR(MagentaOnWhite));
4121 window.Printf(
" (%s)", m_key_name.c_str());
4122 window.AttributeOff(COLOR_PAIR(MagentaOnWhite));
4127bool Menu::WindowDelegateDraw(Window &window,
bool force) {
4128 Menus &submenus = GetSubmenus();
4129 const size_t num_submenus = submenus.size();
4130 const int selected_idx = GetSelectedSubmenuIndex();
4131 Menu::Type menu_type = GetType();
4132 switch (menu_type) {
4133 case Menu::Type::Bar: {
4134 window.SetBackground(BlackOnWhite);
4135 window.MoveCursor(0, 0);
4136 for (
size_t i = 0; i < num_submenus; ++i) {
4137 Menu *menu = submenus[i].get();
4139 window.PutChar(
' ');
4140 menu->SetStartingColumn(window.GetCursorX());
4141 window.PutCString(
"| ");
4142 menu->DrawMenuTitle(window,
false);
4144 window.PutCString(
" |");
4147 case Menu::Type::Item: {
4154 window.SetBackground(BlackOnWhite);
4156 for (
size_t i = 0; i < num_submenus; ++i) {
4157 const bool is_selected = (i ==
static_cast<size_t>(selected_idx));
4158 window.MoveCursor(x, y + i);
4164 submenus[i]->DrawMenuTitle(window, is_selected);
4166 window.MoveCursor(cursor_x, cursor_y);
4170 case Menu::Type::Separator:
4176HandleCharResult Menu::WindowDelegateHandleChar(Window &window,
int key) {
4177 HandleCharResult result = eKeyNotHandled;
4179 Menus &submenus = GetSubmenus();
4180 const size_t num_submenus = submenus.size();
4181 const int selected_idx = GetSelectedSubmenuIndex();
4182 Menu::Type menu_type = GetType();
4183 if (menu_type == Menu::Type::Bar) {
4189 if (selected_idx <
static_cast<int>(num_submenus))
4190 run_menu_sp = submenus[selected_idx];
4191 else if (!submenus.empty())
4192 run_menu_sp = submenus.front();
4193 result = eKeyHandled;
4198 if (m_selected >=
static_cast<int>(num_submenus))
4200 if (m_selected <
static_cast<int>(num_submenus))
4201 run_menu_sp = submenus[m_selected];
4202 else if (!submenus.empty())
4203 run_menu_sp = submenus.front();
4204 result = eKeyHandled;
4210 m_selected = num_submenus - 1;
4211 if (m_selected <
static_cast<int>(num_submenus))
4212 run_menu_sp = submenus[m_selected];
4213 else if (!submenus.empty())
4214 run_menu_sp = submenus.front();
4215 result = eKeyHandled;
4219 for (
size_t i = 0; i < num_submenus; ++i) {
4220 if (submenus[i]->GetKeyValue() == key) {
4221 SetSelectedSubmenuIndex(i);
4222 run_menu_sp = submenus[i];
4223 result = eKeyHandled;
4234 if (run_menu_sp->Action() == MenuActionResult::Quit)
4235 return eQuitApplication;
4238 menu_bounds.origin.x = run_menu_sp->GetStartingColumn();
4239 menu_bounds.origin.y = 1;
4240 menu_bounds.size.width = run_menu_sp->GetDrawWidth();
4241 menu_bounds.size.height = run_menu_sp->GetSubmenus().size() + 2;
4242 if (m_menu_window_sp)
4243 window.GetParent()->RemoveSubWindow(m_menu_window_sp.get());
4245 m_menu_window_sp = window.GetParent()->CreateSubWindow(
4246 run_menu_sp->GetName().c_str(), menu_bounds,
true);
4247 m_menu_window_sp->SetDelegate(run_menu_sp);
4249 }
else if (menu_type == Menu::Type::Item) {
4252 if (m_submenus.size() > 1) {
4253 const int start_select = m_selected;
4254 while (++m_selected != start_select) {
4255 if (
static_cast<size_t>(m_selected) >= num_submenus)
4257 if (m_submenus[m_selected]->GetType() == Type::Separator)
4267 if (m_submenus.size() > 1) {
4268 const int start_select = m_selected;
4269 while (--m_selected != start_select) {
4270 if (m_selected <
static_cast<int>(0))
4271 m_selected = num_submenus - 1;
4272 if (m_submenus[m_selected]->GetType() == Type::Separator)
4282 if (
static_cast<size_t>(selected_idx) < num_submenus) {
4283 if (submenus[selected_idx]->Action() == MenuActionResult::Quit)
4284 return eQuitApplication;
4285 window.GetParent()->RemoveSubWindow(&window);
4292 window.GetParent()->RemoveSubWindow(&window);
4296 for (
size_t i = 0; i < num_submenus; ++i) {
4297 Menu *menu = submenus[i].get();
4298 if (menu->GetKeyValue() == key) {
4299 SetSelectedSubmenuIndex(i);
4300 window.GetParent()->RemoveSubWindow(&window);
4301 if (menu->Action() == MenuActionResult::Quit)
4302 return eQuitApplication;
4308 }
else if (menu_type == Menu::Type::Separator) {
4315 Application(FILE *in, FILE *out) : m_window_sp(), m_in(in), m_out(out) {}
4318 m_window_delegates.clear();
4319 m_window_sp.reset();
4321 ::delscreen(m_screen);
4327 m_screen = ::newterm(
nullptr, m_out, m_in);
4331 ::keypad(stdscr, TRUE);
4334 void Terminate() { ::endwin(); }
4336 void Run(Debugger &debugger) {
4338 int delay_in_tenths_of_a_second = 1;
4346 halfdelay(delay_in_tenths_of_a_second);
4352 llvm::StringRef broadcaster_class_process(
4356 m_update_screen =
true;
4357#if defined(__APPLE__)
4358 std::deque<int> escape_chars;
4362 if (m_update_screen) {
4363 m_window_sp->Draw(
false);
4371 m_window_sp->MoveCursor(0, 0);
4374 m_update_screen =
false;
4377#if defined(__APPLE__)
4382 if (escape_chars.empty())
4383 ch = m_window_sp->GetChar();
4385 ch = escape_chars.front();
4386 escape_chars.pop_front();
4388 if (ch == KEY_ESCAPE) {
4389 int ch2 = m_window_sp->GetChar();
4391 int ch3 = m_window_sp->GetChar();
4406 escape_chars.push_back(ch2);
4408 escape_chars.push_back(ch3);
4411 }
else if (ch2 != -1)
4412 escape_chars.push_back(ch2);
4415 int ch = m_window_sp->GetChar();
4419 if (feof(m_in) || ferror(m_in)) {
4424 while (listener_sp->PeekAtNextEvent()) {
4425 listener_sp->GetEvent(event_sp, std::chrono::seconds(0));
4428 Broadcaster *broadcaster = event_sp->GetBroadcaster();
4430 llvm::StringRef broadcaster_class(
4432 if (broadcaster_class == broadcaster_class_process) {
4433 m_update_screen =
true;
4441 HandleCharResult key_result = m_window_sp->HandleChar(ch);
4442 switch (key_result) {
4444 m_update_screen =
true;
4446 case eKeyNotHandled:
4448 redrawwin(m_window_sp->get());
4449 m_update_screen =
true;
4452 case eQuitApplication:
4462 WindowSP &GetMainWindow() {
4464 m_window_sp = std::make_shared<Window>(
"main", stdscr,
false);
4468 void TerminalSizeChanged() {
4471 Rect content_bounds = m_window_sp->GetFrame();
4472 m_window_sp->SetBounds(content_bounds);
4473 if (WindowSP menubar_window_sp = m_window_sp->FindSubWindow(
"Menubar"))
4474 menubar_window_sp->SetBounds(content_bounds.MakeMenuBar());
4475 if (WindowSP status_window_sp = m_window_sp->FindSubWindow(
"Status"))
4476 status_window_sp->SetBounds(content_bounds.MakeStatusBar());
4478 WindowSP source_window_sp = m_window_sp->FindSubWindow(
"Source");
4479 WindowSP variables_window_sp = m_window_sp->FindSubWindow(
"Variables");
4480 WindowSP registers_window_sp = m_window_sp->FindSubWindow(
"Registers");
4481 WindowSP threads_window_sp = m_window_sp->FindSubWindow(
"Threads");
4483 Rect threads_bounds;
4484 Rect source_variables_bounds;
4485 content_bounds.VerticalSplitPercentage(0.80, source_variables_bounds,
4487 if (threads_window_sp)
4488 threads_window_sp->SetBounds(threads_bounds);
4490 source_variables_bounds = content_bounds;
4493 Rect variables_registers_bounds;
4494 source_variables_bounds.HorizontalSplitPercentage(
4495 0.70, source_bounds, variables_registers_bounds);
4496 if (variables_window_sp || registers_window_sp) {
4497 if (variables_window_sp && registers_window_sp) {
4498 Rect variables_bounds;
4499 Rect registers_bounds;
4500 variables_registers_bounds.VerticalSplitPercentage(
4501 0.50, variables_bounds, registers_bounds);
4502 variables_window_sp->SetBounds(variables_bounds);
4503 registers_window_sp->SetBounds(registers_bounds);
4504 }
else if (variables_window_sp) {
4505 variables_window_sp->SetBounds(variables_registers_bounds);
4507 registers_window_sp->SetBounds(variables_registers_bounds);
4510 source_bounds = source_variables_bounds;
4513 source_window_sp->SetBounds(source_bounds);
4516 redrawwin(m_window_sp->get());
4517 m_update_screen =
true;
4521 WindowSP m_window_sp;
4522 WindowDelegates m_window_delegates;
4523 SCREEN *m_screen =
nullptr;
4526 bool m_update_screen =
false;
4535 ValueObjectUpdater value;
4538 uint32_t children_stop_id = 0;
4542 bool might_have_children;
4543 bool expanded =
false;
4544 bool calculated_children =
false;
4545 std::vector<Row> children;
4548 : value(v), parent(p),
4549 might_have_children(v ? v->MightHaveChildren() : false) {}
4551 size_t GetDepth()
const {
4553 return 1 + parent->GetDepth();
4557 void Expand() { expanded =
true; }
4559 std::vector<Row> &GetChildren() {
4561 auto stop_id = process_sp->GetStopID();
4562 if (process_sp && stop_id != children_stop_id) {
4563 children_stop_id = stop_id;
4564 calculated_children =
false;
4566 if (!calculated_children) {
4568 calculated_children =
true;
4571 const uint32_t num_children = valobj->GetNumChildrenIgnoringErrors();
4572 for (
size_t i = 0; i < num_children; ++i) {
4573 children.push_back(Row(valobj->GetChildAtIndex(i),
this));
4582 calculated_children =
false;
4586 void DrawTree(Window &window) {
4588 parent->DrawTreeForChild(window,
this, 0);
4590 if (might_have_children &&
4591 (!calculated_children || !GetChildren().empty())) {
4609 window.PutChar(ACS_DIAMOND);
4610 window.PutChar(ACS_HLINE);
4614 void DrawTreeForChild(Window &window, Row *child, uint32_t reverse_depth) {
4616 parent->DrawTreeForChild(window,
this, reverse_depth + 1);
4618 if (&GetChildren().back() == child) {
4620 if (reverse_depth == 0) {
4621 window.PutChar(ACS_LLCORNER);
4622 window.PutChar(ACS_HLINE);
4624 window.PutChar(
' ');
4625 window.PutChar(
' ');
4628 if (reverse_depth == 0) {
4629 window.PutChar(ACS_LTEE);
4630 window.PutChar(ACS_HLINE);
4632 window.PutChar(ACS_VLINE);
4633 window.PutChar(
' ');
4639struct DisplayOptions {
4647 TreeDelegate() =
default;
4648 virtual ~TreeDelegate() =
default;
4650 virtual void TreeDelegateDrawTreeItem(TreeItem &item, Window &window) = 0;
4651 virtual void TreeDelegateGenerateChildren(TreeItem &item) = 0;
4652 virtual void TreeDelegateUpdateSelection(TreeItem &root,
int &selection_index,
4653 TreeItem *&selected_item) {}
4656 virtual bool TreeDelegateItemSelected(TreeItem &item) = 0;
4657 virtual bool TreeDelegateExpandRootByDefault() {
return false; }
4661 virtual bool TreeDelegateShouldDraw() {
return true; }
4664typedef std::shared_ptr<TreeDelegate> TreeDelegateSP;
4666struct TreeItemData {
4667 TreeItemData(TreeItem *parent, TreeDelegate &delegate,
4668 bool might_have_children,
bool is_expanded)
4669 : m_parent(parent), m_delegate(&delegate),
4670 m_might_have_children(might_have_children), m_is_expanded(is_expanded) {
4675 TreeDelegate *m_delegate;
4676 void *m_user_data =
nullptr;
4677 uint64_t m_identifier = 0;
4681 bool m_might_have_children;
4682 bool m_is_expanded =
false;
4685class TreeItem :
public TreeItemData {
4687 TreeItem(TreeItem *parent, TreeDelegate &delegate,
bool might_have_children)
4688 : TreeItemData(parent, delegate, might_have_children,
4690 ? delegate.TreeDelegateExpandRootByDefault()
4694 TreeItem(
const TreeItem &) =
delete;
4695 TreeItem &operator=(
const TreeItem &rhs) =
delete;
4697 TreeItem &operator=(TreeItem &&rhs) {
4699 TreeItemData::operator=(std::move(rhs));
4700 AdoptChildren(rhs.m_children);
4705 TreeItem(TreeItem &&rhs) : TreeItemData(std::move(rhs)) {
4706 AdoptChildren(rhs.m_children);
4709 size_t GetDepth()
const {
4711 return 1 + m_parent->GetDepth();
4715 int GetRowIndex()
const {
return m_row_idx; }
4717 void ClearChildren() { m_children.clear(); }
4719 void Resize(
size_t n, TreeDelegate &delegate,
bool might_have_children) {
4720 if (m_children.size() >= n) {
4721 m_children.erase(m_children.begin() + n, m_children.end());
4724 m_children.reserve(n);
4725 std::generate_n(std::back_inserter(m_children), n - m_children.size(),
4726 [&, parent =
this]() {
4727 return TreeItem(parent, delegate, might_have_children);
4731 TreeItem &operator[](
size_t i) {
return m_children[i]; }
4733 void SetRowIndex(
int row_idx) { m_row_idx = row_idx; }
4736 m_delegate->TreeDelegateGenerateChildren(*
this);
4737 return m_children.size();
4740 void ItemWasSelected() { m_delegate->TreeDelegateItemSelected(*
this); }
4742 void CalculateRowIndexes(
int &row_idx) {
4743 SetRowIndex(row_idx);
4746 const bool expanded = IsExpanded();
4750 if (m_parent ==
nullptr || expanded)
4753 for (
auto &item : m_children) {
4755 item.CalculateRowIndexes(row_idx);
4757 item.SetRowIndex(-1);
4761 TreeItem *GetParent() {
return m_parent; }
4763 bool IsExpanded()
const {
return m_is_expanded; }
4765 void Expand() { m_is_expanded =
true; }
4767 void Unexpand() { m_is_expanded =
false; }
4769 bool Draw(Window &window,
const int first_visible_row,
4770 const uint32_t selected_row_idx,
int &row_idx,
int &num_rows_left) {
4771 if (num_rows_left <= 0)
4774 if (m_row_idx >= first_visible_row) {
4775 window.MoveCursor(2, row_idx + 1);
4778 m_parent->DrawTreeForChild(window,
this, 0);
4780 if (m_might_have_children) {
4798 window.PutChar(ACS_DIAMOND);
4799 window.PutChar(ACS_HLINE);
4801 bool highlight = (selected_row_idx ==
static_cast<size_t>(m_row_idx)) &&
4805 window.AttributeOn(A_REVERSE);
4807 m_delegate->TreeDelegateDrawTreeItem(*
this, window);
4810 window.AttributeOff(A_REVERSE);
4815 if (num_rows_left <= 0)
4819 for (
auto &item : m_children) {
4822 if (!item.Draw(window, first_visible_row, selected_row_idx, row_idx,
4827 return num_rows_left >= 0;
4830 void DrawTreeForChild(Window &window, TreeItem *child,
4831 uint32_t reverse_depth) {
4833 m_parent->DrawTreeForChild(window,
this, reverse_depth + 1);
4835 if (&m_children.back() == child) {
4837 if (reverse_depth == 0) {
4838 window.PutChar(ACS_LLCORNER);
4839 window.PutChar(ACS_HLINE);
4841 window.PutChar(
' ');
4842 window.PutChar(
' ');
4845 if (reverse_depth == 0) {
4846 window.PutChar(ACS_LTEE);
4847 window.PutChar(ACS_HLINE);
4849 window.PutChar(ACS_VLINE);
4850 window.PutChar(
' ');
4855 TreeItem *GetItemForRowIndex(uint32_t row_idx) {
4856 if (
static_cast<uint32_t
>(m_row_idx) == row_idx)
4858 if (m_children.empty())
4861 for (
auto &item : m_children) {
4862 TreeItem *selected_item_ptr = item.GetItemForRowIndex(row_idx);
4863 if (selected_item_ptr)
4864 return selected_item_ptr;
4870 void *GetUserData()
const {
return m_user_data; }
4872 void SetUserData(
void *user_data) { m_user_data = user_data; }
4874 uint64_t GetIdentifier()
const {
return m_identifier; }
4876 void SetIdentifier(uint64_t identifier) { m_identifier = identifier; }
4878 const std::string &
GetText()
const {
return m_text; }
4880 void SetText(
const char *text) {
4881 if (text ==
nullptr) {
4888 void SetMightHaveChildren(
bool b) { m_might_have_children = b; }
4891 void AdoptChildren(std::vector<TreeItem> &children) {
4892 m_children = std::move(children);
4893 for (
auto &child : m_children)
4894 child.m_parent =
this;
4897 std::vector<TreeItem> m_children;
4900class TreeWindowDelegate :
public WindowDelegate {
4902 TreeWindowDelegate(Debugger &debugger,
const TreeDelegateSP &delegate_sp)
4903 : m_debugger(debugger), m_delegate_sp(delegate_sp),
4904 m_root(nullptr, *delegate_sp, true) {}
4906 int NumVisibleRows()
const {
return m_max_y - m_min_y; }
4908 bool WindowDelegateDraw(Window &window,
bool force)
override {
4911 m_max_x = window.GetWidth() - 1;
4912 m_max_y = window.GetHeight() - 1;
4915 window.DrawTitleBox(window.GetName());
4917 if (!m_delegate_sp->TreeDelegateShouldDraw()) {
4918 m_selected_item =
nullptr;
4922 const int num_visible_rows = NumVisibleRows();
4924 m_root.CalculateRowIndexes(m_num_rows);
4925 m_delegate_sp->TreeDelegateUpdateSelection(m_root, m_selected_row_idx,
4931 if (m_first_visible_row > 0 && m_num_rows < num_visible_rows)
4932 m_first_visible_row = 0;
4935 if (m_selected_row_idx < m_first_visible_row)
4936 m_first_visible_row = m_selected_row_idx;
4937 else if (m_first_visible_row + num_visible_rows <= m_selected_row_idx)
4938 m_first_visible_row = m_selected_row_idx - num_visible_rows + 1;
4941 int num_rows_left = num_visible_rows;
4942 m_root.Draw(window, m_first_visible_row, m_selected_row_idx, row_idx,
4945 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4950 const char *WindowDelegateGetHelpText()
override {
4951 return "Thread window keyboard shortcuts:";
4954 KeyHelp *WindowDelegateGetKeyHelp()
override {
4955 static curses::KeyHelp g_source_view_key_help[] = {
4956 {KEY_UP,
"Select previous item"},
4957 {KEY_DOWN,
"Select next item"},
4958 {KEY_RIGHT,
"Expand the selected item"},
4960 "Unexpand the selected item or select parent if not expanded"},
4961 {KEY_PPAGE,
"Page up"},
4962 {KEY_NPAGE,
"Page down"},
4963 {
'h',
"Show help dialog"},
4964 {
' ',
"Toggle item expansion"},
4968 return g_source_view_key_help;
4971 HandleCharResult WindowDelegateHandleChar(Window &window,
int c)
override {
4976 if (m_first_visible_row > 0) {
4977 if (m_first_visible_row > m_max_y)
4978 m_first_visible_row -= m_max_y;
4980 m_first_visible_row = 0;
4981 m_selected_row_idx = m_first_visible_row;
4982 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4983 if (m_selected_item)
4984 m_selected_item->ItemWasSelected();
4991 if (m_num_rows > m_max_y) {
4992 if (m_first_visible_row + m_max_y < m_num_rows) {
4993 m_first_visible_row += m_max_y;
4994 m_selected_row_idx = m_first_visible_row;
4995 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4996 if (m_selected_item)
4997 m_selected_item->ItemWasSelected();
5003 if (m_selected_row_idx > 0) {
5004 --m_selected_row_idx;
5005 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
5006 if (m_selected_item)
5007 m_selected_item->ItemWasSelected();
5012 if (m_selected_row_idx + 1 < m_num_rows) {
5013 ++m_selected_row_idx;
5014 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
5015 if (m_selected_item)
5016 m_selected_item->ItemWasSelected();
5021 if (m_selected_item) {
5022 if (!m_selected_item->IsExpanded())
5023 m_selected_item->Expand();
5028 if (m_selected_item) {
5029 if (m_selected_item->IsExpanded())
5030 m_selected_item->Unexpand();
5031 else if (m_selected_item->GetParent()) {
5032 m_selected_row_idx = m_selected_item->GetParent()->GetRowIndex();
5033 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
5034 if (m_selected_item)
5035 m_selected_item->ItemWasSelected();
5042 if (m_selected_item) {
5043 if (m_selected_item->IsExpanded())
5044 m_selected_item->Unexpand();
5046 m_selected_item->Expand();
5051 window.CreateHelpSubwindow();
5057 return eKeyNotHandled;
5061 Debugger &m_debugger;
5062 TreeDelegateSP m_delegate_sp;
5064 TreeItem *m_selected_item =
nullptr;
5066 int m_selected_row_idx = 0;
5067 int m_first_visible_row = 0;
5076class TextTreeDelegate :
public TreeDelegate {
5078 TextTreeDelegate() : TreeDelegate() {}
5080 ~TextTreeDelegate()
override =
default;
5082 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5083 window.PutCStringTruncated(1, item.GetText().c_str());
5086 void TreeDelegateGenerateChildren(TreeItem &item)
override {}
5088 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5091class FrameTreeDelegate :
public TreeDelegate {
5093 FrameTreeDelegate() : TreeDelegate() {
5095 "#${frame.index}: {${function.name}${function.pc-offset}}}", m_format);
5098 ~FrameTreeDelegate()
override =
default;
5100 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5103 const uint64_t frame_idx = item.GetIdentifier();
5107 const SymbolContext &sc =
5108 frame_sp->GetSymbolContext(eSymbolContextEverything);
5109 ExecutionContext exe_ctx(frame_sp);
5110 if (FormatEntity::Formatter(&sc, &exe_ctx,
nullptr,
false,
false)
5111 .
Format(m_format, strm)) {
5113 window.PutCStringTruncated(right_pad, strm.
GetString().str().c_str());
5119 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5123 bool TreeDelegateItemSelected(TreeItem &item)
override {
5126 thread->
GetProcess()->GetThreadList().SetSelectedThreadByID(
5128 const uint64_t frame_idx = item.GetIdentifier();
5136 FormatEntity::Entry m_format;
5139class ThreadTreeDelegate :
public TreeDelegate {
5141 ThreadTreeDelegate(Debugger &debugger)
5142 : TreeDelegate(), m_debugger(debugger) {
5144 "reason = ${thread.stop-reason}}",
5148 ~ThreadTreeDelegate()
override =
default;
5151 return m_debugger.GetCommandInterpreter()
5152 .GetExecutionContext()
5156 ThreadSP GetThread(
const TreeItem &item) {
5159 return process_sp->GetThreadList().FindThreadByID(item.GetIdentifier());
5163 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5164 ThreadSP thread_sp = GetThread(item);
5167 ExecutionContext exe_ctx(thread_sp);
5168 if (FormatEntity::Formatter(
nullptr, &exe_ctx,
nullptr,
false,
false)
5169 .
Format(m_format, strm)) {
5171 window.PutCStringTruncated(right_pad, strm.
GetString().str().c_str());
5176 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5178 if (process_sp && process_sp->IsAlive()) {
5179 StateType state = process_sp->GetState();
5181 ThreadSP thread_sp = GetThread(item);
5183 if (m_stop_id == process_sp->GetStopID() &&
5184 thread_sp->GetID() == m_tid)
5186 if (!m_frame_delegate_sp) {
5188 m_frame_delegate_sp = std::make_shared<FrameTreeDelegate>();
5191 m_stop_id = process_sp->GetStopID();
5192 m_tid = thread_sp->GetID();
5194 size_t num_frames = thread_sp->GetStackFrameCount();
5195 item.Resize(num_frames, *m_frame_delegate_sp,
false);
5196 for (
size_t i = 0; i < num_frames; ++i) {
5197 item[i].SetUserData(thread_sp.get());
5198 item[i].SetIdentifier(i);
5204 item.ClearChildren();
5207 bool TreeDelegateItemSelected(TreeItem &item)
override {
5209 if (process_sp && process_sp->IsAlive()) {
5210 StateType state = process_sp->GetState();
5212 ThreadSP thread_sp = GetThread(item);
5214 ThreadList &thread_list = thread_sp->GetProcess()->GetThreadList();
5215 std::lock_guard<std::recursive_mutex> guard(thread_list.
GetMutex());
5217 if (selected_thread_sp->GetID() != thread_sp->GetID()) {
5228 Debugger &m_debugger;
5229 std::shared_ptr<FrameTreeDelegate> m_frame_delegate_sp;
5232 FormatEntity::Entry m_format;
5235class ThreadsTreeDelegate :
public TreeDelegate {
5237 ThreadsTreeDelegate(Debugger &debugger)
5238 : TreeDelegate(), m_thread_delegate_sp(), m_debugger(debugger) {
5243 ~ThreadsTreeDelegate()
override =
default;
5246 return m_debugger.GetCommandInterpreter()
5247 .GetExecutionContext()
5251 bool TreeDelegateShouldDraw()
override {
5262 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5264 if (process_sp && process_sp->IsAlive()) {
5266 ExecutionContext exe_ctx(process_sp);
5267 if (FormatEntity::Formatter(
nullptr, &exe_ctx,
nullptr,
false,
false)
5268 .
Format(m_format, strm)) {
5270 window.PutCStringTruncated(right_pad, strm.
GetString().str().c_str());
5275 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5277 m_update_selection =
false;
5278 if (process_sp && process_sp->IsAlive()) {
5279 StateType state = process_sp->GetState();
5281 const uint32_t stop_id = process_sp->GetStopID();
5282 if (m_stop_id == stop_id)
5285 m_stop_id = stop_id;
5286 m_update_selection =
true;
5288 if (!m_thread_delegate_sp) {
5291 m_thread_delegate_sp =
5292 std::make_shared<ThreadTreeDelegate>(m_debugger);
5295 ThreadList &threads = process_sp->GetThreadList();
5296 std::lock_guard<std::recursive_mutex> guard(threads.
GetMutex());
5298 size_t num_threads = threads.
GetSize();
5299 item.Resize(num_threads, *m_thread_delegate_sp,
false);
5300 for (
size_t i = 0; i < num_threads; ++i) {
5302 item[i].SetIdentifier(thread->GetID());
5303 item[i].SetMightHaveChildren(
true);
5304 if (selected_thread->GetID() == thread->GetID())
5310 item.ClearChildren();
5313 void TreeDelegateUpdateSelection(TreeItem &root,
int &selection_index,
5314 TreeItem *&selected_item)
override {
5315 if (!m_update_selection)
5319 if (!(process_sp && process_sp->IsAlive()))
5322 StateType state = process_sp->GetState();
5326 ThreadList &threads = process_sp->GetThreadList();
5327 std::lock_guard<std::recursive_mutex> guard(threads.
GetMutex());
5329 size_t num_threads = threads.
GetSize();
5330 for (
size_t i = 0; i < num_threads; ++i) {
5332 if (selected_thread->GetID() == thread->GetID()) {
5335 selection_index = selected_item->GetRowIndex();
5341 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5343 bool TreeDelegateExpandRootByDefault()
override {
return true; }
5346 std::shared_ptr<ThreadTreeDelegate> m_thread_delegate_sp;
5347 Debugger &m_debugger;
5349 bool m_update_selection =
false;
5350 FormatEntity::Entry m_format;
5353class BreakpointLocationTreeDelegate :
public TreeDelegate {
5355 BreakpointLocationTreeDelegate(Debugger &debugger)
5356 : TreeDelegate(), m_debugger(debugger) {}
5358 ~BreakpointLocationTreeDelegate()
override =
default;
5361 ExecutionContext exe_ctx(
5362 m_debugger.GetCommandInterpreter().GetExecutionContext());
5367 Breakpoint *breakpoint = (Breakpoint *)item.GetUserData();
5371 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5373 Process *process = GetProcess();
5374 StreamString stream;
5375 stream.
Printf(
"%i.%i: ", breakpoint_location->GetBreakpoint().GetID(),
5376 breakpoint_location->GetID());
5377 Address address = breakpoint_location->GetAddress();
5380 window.PutCStringTruncated(1, stream.
GetString().str().c_str());
5386 Address address = breakpoint_location->GetAddress();
5387 SymbolContext symbol_context;
5391 StreamString module_stream;
5393 symbol_context.
module_sp->GetFileSpec().Dump(
5398 if (symbol_context.
comp_unit !=
nullptr) {
5399 StreamString compile_unit_stream;
5400 compile_unit_stream.
PutCString(
"compile unit = ");
5405 if (symbol_context.
function !=
nullptr) {
5406 StreamString function_stream;
5414 StreamString location_stream;
5421 if (symbol_context.
symbol) {
5422 StreamString symbol_stream;
5423 if (breakpoint_location->IsReExported())
5424 symbol_stream.
PutCString(
"re-exported target = ");
5433 Process *process = GetProcess();
5435 StreamString address_stream;
5440 BreakpointSiteSP breakpoint_site = breakpoint_location->GetBreakpointSite();
5441 if (breakpoint_location->IsIndirect() && breakpoint_site) {
5442 Address resolved_address;
5443 resolved_address.
SetLoadAddress(breakpoint_site->GetLoadAddress(),
5444 &breakpoint_location->GetTarget());
5445 const Symbol *resolved_symbol =
5447 if (resolved_symbol) {
5448 StreamString indirect_target_stream;
5449 indirect_target_stream.
PutCString(
"indirect target = ");
5456 bool is_resolved = breakpoint_location->IsResolved();
5457 StreamString resolved_stream;
5458 resolved_stream.
Printf(
"resolved = %s", is_resolved ?
"true" :
"false");
5461 bool is_hardware = is_resolved && breakpoint_site->IsHardware();
5462 StreamString hardware_stream;
5463 hardware_stream.
Printf(
"hardware = %s", is_hardware ?
"true" :
"false");
5466 StreamString hit_count_stream;
5467 hit_count_stream.
Printf(
"hit count = %-4u",
5468 breakpoint_location->GetHitCount());
5474 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5476 StringList details = ComputeDetailsList(breakpoint_location);
5478 if (!m_string_delegate_sp)
5479 m_string_delegate_sp = std::make_shared<TextTreeDelegate>();
5481 item.Resize(details.
GetSize(), *m_string_delegate_sp,
false);
5482 for (
size_t i = 0; i < details.
GetSize(); i++) {
5487 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5490 Debugger &m_debugger;
5491 std::shared_ptr<TextTreeDelegate> m_string_delegate_sp;
5494class BreakpointTreeDelegate :
public TreeDelegate {
5496 BreakpointTreeDelegate(Debugger &debugger)
5497 : TreeDelegate(), m_debugger(debugger),
5498 m_breakpoint_location_delegate_sp() {}
5500 ~BreakpointTreeDelegate()
override =
default;
5504 .GetSelectedExecutionContext(
5507 BreakpointList &breakpoints = target->GetBreakpointList(
false);
5511 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5513 StreamString stream;
5514 stream.
Format(
"{0}: ", breakpoint->GetID());
5515 breakpoint->GetResolverDescription(&stream);
5516 breakpoint->GetFilterDescription(&stream);
5517 window.PutCStringTruncated(1, stream.
GetString().str().c_str());
5520 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5523 if (!m_breakpoint_location_delegate_sp)
5524 m_breakpoint_location_delegate_sp =
5525 std::make_shared<BreakpointLocationTreeDelegate>(m_debugger);
5527 item.Resize(breakpoint->GetNumLocations(),
5528 *m_breakpoint_location_delegate_sp,
true);
5529 for (
size_t i = 0; i < breakpoint->GetNumLocations(); i++) {
5530 item[i].SetIdentifier(i);
5531 item[i].SetUserData(breakpoint.get());
5535 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5538 Debugger &m_debugger;
5539 std::shared_ptr<BreakpointLocationTreeDelegate>
5540 m_breakpoint_location_delegate_sp;
5543class BreakpointsTreeDelegate :
public TreeDelegate {
5545 BreakpointsTreeDelegate(Debugger &debugger)
5546 : TreeDelegate(), m_debugger(debugger), m_breakpoint_delegate_sp() {}
5548 ~BreakpointsTreeDelegate()
override =
default;
5550 bool TreeDelegateShouldDraw()
override {
5552 .GetSelectedExecutionContext(
5561 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5562 window.PutCString(
"Breakpoints");
5565 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5567 .GetSelectedExecutionContext(
5571 BreakpointList &breakpoints = target->GetBreakpointList(
false);
5572 std::unique_lock<std::recursive_mutex> lock;
5575 if (!m_breakpoint_delegate_sp)
5576 m_breakpoint_delegate_sp =
5577 std::make_shared<BreakpointTreeDelegate>(m_debugger);
5579 item.Resize(breakpoints.
GetSize(), *m_breakpoint_delegate_sp,
true);
5580 for (
size_t i = 0; i < breakpoints.
GetSize(); i++) {
5581 item[i].SetIdentifier(i);
5585 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5587 bool TreeDelegateExpandRootByDefault()
override {
return true; }
5590 Debugger &m_debugger;
5591 std::shared_ptr<BreakpointTreeDelegate> m_breakpoint_delegate_sp;
5594class ValueObjectListDelegate :
public WindowDelegate {
5596 ValueObjectListDelegate() : m_rows() {}
5598 ValueObjectListDelegate(ValueObjectList &valobj_list) : m_rows() {
5599 SetValues(valobj_list);
5602 ~ValueObjectListDelegate()
override =
default;
5604 void SetValues(ValueObjectList &valobj_list) {
5605 m_selected_row =
nullptr;
5606 m_selected_row_idx = 0;
5607 m_first_visible_row = 0;
5610 for (
auto &valobj_sp : valobj_list.
GetObjects())
5611 m_rows.push_back(Row(valobj_sp,
nullptr));
5614 bool WindowDelegateDraw(Window &window,
bool force)
override {
5618 m_max_x = window.GetWidth() - 1;
5619 m_max_y = window.GetHeight() - 1;
5622 window.DrawTitleBox(window.GetName());
5624 const int num_visible_rows = NumVisibleRows();
5625 const int num_rows = CalculateTotalNumberRows(m_rows);
5630 if (m_first_visible_row > 0 && num_rows < num_visible_rows)
5631 m_first_visible_row = 0;
5634 if (m_selected_row_idx < m_first_visible_row)
5635 m_first_visible_row = m_selected_row_idx;
5636 else if (m_first_visible_row + num_visible_rows <= m_selected_row_idx)
5637 m_first_visible_row = m_selected_row_idx - num_visible_rows + 1;
5639 DisplayRows(window, m_rows, g_options);
5642 m_selected_row = GetRowForRowIndex(m_selected_row_idx);
5646 window.MoveCursor(m_selected_row->x, m_selected_row->y);
5651 KeyHelp *WindowDelegateGetKeyHelp()
override {
5652 static curses::KeyHelp g_source_view_key_help[] = {
5653 {KEY_UP,
"Select previous item"},
5654 {KEY_DOWN,
"Select next item"},
5655 {KEY_RIGHT,
"Expand selected item"},
5656 {KEY_LEFT,
"Unexpand selected item or select parent if not expanded"},
5657 {KEY_PPAGE,
"Page up"},
5658 {KEY_NPAGE,
"Page down"},
5659 {
'A',
"Format as annotated address"},
5660 {
'b',
"Format as binary"},
5661 {
'B',
"Format as hex bytes with ASCII"},
5662 {
'c',
"Format as character"},
5663 {
'd',
"Format as a signed integer"},
5664 {
'D',
"Format selected value using the default format for the type"},
5665 {
'f',
"Format as float"},
5666 {
'h',
"Show help dialog"},
5667 {
'i',
"Format as instructions"},
5668 {
'o',
"Format as octal"},
5669 {
'p',
"Format as pointer"},
5670 {
's',
"Format as C string"},
5671 {
't',
"Toggle showing/hiding type names"},
5672 {
'u',
"Format as an unsigned integer"},
5673 {
'x',
"Format as hex"},
5674 {
'X',
"Format as uppercase hex"},
5675 {
' ',
"Toggle item expansion"},
5679 return g_source_view_key_help;
5682 HandleCharResult WindowDelegateHandleChar(Window &window,
int c)
override {
5699 if (m_selected_row) {
5700 auto valobj_sp = m_selected_row->value.GetSP();
5702 valobj_sp->SetFormat(FormatForChar(c));
5708 g_options.show_types = !g_options.show_types;
5714 if (m_first_visible_row > 0) {
5715 if (
static_cast<int>(m_first_visible_row) > m_max_y)
5716 m_first_visible_row -= m_max_y;
5718 m_first_visible_row = 0;
5719 m_selected_row_idx = m_first_visible_row;
5726 if (m_num_rows >
static_cast<size_t>(m_max_y)) {
5727 if (m_first_visible_row + m_max_y < m_num_rows) {
5728 m_first_visible_row += m_max_y;
5729 m_selected_row_idx = m_first_visible_row;
5735 if (m_selected_row_idx > 0)
5736 --m_selected_row_idx;
5740 if (m_selected_row_idx + 1 < m_num_rows)
5741 ++m_selected_row_idx;
5745 if (m_selected_row) {
5746 if (!m_selected_row->expanded)
5747 m_selected_row->Expand();
5752 if (m_selected_row) {
5753 if (m_selected_row->expanded)
5754 m_selected_row->Unexpand();
5755 else if (m_selected_row->parent)
5756 m_selected_row_idx = m_selected_row->parent->row_idx;
5762 if (m_selected_row) {
5763 if (m_selected_row->expanded)
5764 m_selected_row->Unexpand();
5766 m_selected_row->Expand();
5771 window.CreateHelpSubwindow();
5777 return eKeyNotHandled;
5781 std::vector<Row> m_rows;
5782 Row *m_selected_row =
nullptr;
5783 uint32_t m_selected_row_idx = 0;
5784 uint32_t m_first_visible_row = 0;
5785 uint32_t m_num_rows = 0;
5791 static Format FormatForChar(
int c) {
5825 bool DisplayRowObject(Window &window, Row &row, DisplayOptions &options,
5826 bool highlight,
bool last_child) {
5827 ValueObject *valobj = row.value.GetSP().get();
5829 if (valobj ==
nullptr)
5832 const char *type_name =
5838 window.MoveCursor(row.x, row.y);
5840 row.DrawTree(window);
5843 window.AttributeOn(A_REVERSE);
5845 if (type_name && type_name[0])
5846 window.PrintfTruncated(1,
"(%s) ", type_name);
5848 if (name && name[0])
5849 window.PutCStringTruncated(1, name);
5851 attr_t changd_attr = 0;
5853 changd_attr = COLOR_PAIR(RedOnBlack) | A_BOLD;
5855 if (value && value[0]) {
5856 window.PutCStringTruncated(1,
" = ");
5858 window.AttributeOn(changd_attr);
5859 window.PutCStringTruncated(1, value);
5861 window.AttributeOff(changd_attr);
5864 if (summary && summary[0]) {
5865 window.PutCStringTruncated(1,
" ");
5867 window.AttributeOn(changd_attr);
5868 window.PutCStringTruncated(1, summary);
5870 window.AttributeOff(changd_attr);
5874 window.AttributeOff(A_REVERSE);
5879 void DisplayRows(Window &window, std::vector<Row> &rows,
5880 DisplayOptions &options) {
5884 bool window_is_active = window.IsActive();
5885 for (
auto &row : rows) {
5886 const bool last_child = row.parent && &rows[rows.size() - 1] == &row;
5888 row.row_idx = m_num_rows;
5889 if ((m_num_rows >= m_first_visible_row) &&
5890 ((m_num_rows - m_first_visible_row) <
5891 static_cast<size_t>(NumVisibleRows()))) {
5893 row.y = m_num_rows - m_first_visible_row + 1;
5894 if (DisplayRowObject(window, row, options,
5896 m_num_rows == m_selected_row_idx,
5910 auto &children = row.GetChildren();
5911 if (!children.empty()) {
5912 DisplayRows(window, children, options);
5918 int CalculateTotalNumberRows(std::vector<Row> &rows) {
5920 for (
auto &row : rows) {
5923 row_count += CalculateTotalNumberRows(row.GetChildren());
5928 static Row *GetRowForRowIndexImpl(std::vector<Row> &rows,
size_t &row_index) {
5929 for (
auto &row : rows) {
5935 auto &children = row.GetChildren();
5936 if (!children.empty()) {
5937 Row *result = GetRowForRowIndexImpl(children, row_index);
5947 Row *GetRowForRowIndex(
size_t row_index) {
5948 return GetRowForRowIndexImpl(m_rows, row_index);
5951 int NumVisibleRows()
const {
return m_max_y - m_min_y; }
5953 static DisplayOptions g_options;
5956class FrameVariablesWindowDelegate :
public ValueObjectListDelegate {
5958 FrameVariablesWindowDelegate(Debugger &debugger)
5959 : ValueObjectListDelegate(), m_debugger(debugger) {}
5961 ~FrameVariablesWindowDelegate()
override =
default;
5963 const char *WindowDelegateGetHelpText()
override {
5964 return "Frame variable window keyboard shortcuts:";
5967 bool WindowDelegateDraw(Window &window,
bool force)
override {
5968 ExecutionContext exe_ctx(
5969 m_debugger.GetCommandInterpreter().GetExecutionContext());
5971 Block *frame_block =
nullptr;
5972 StackFrame *frame =
nullptr;
5985 ValueObjectList local_values;
5988 if (m_frame_block != frame_block) {
5989 m_frame_block = frame_block;
6000 ValueObjectSP synthetic_value_sp = value_sp->GetSyntheticValue();
6001 if (synthetic_value_sp)
6002 local_values.
Append(synthetic_value_sp);
6004 local_values.
Append(value_sp);
6008 SetValues(local_values);
6012 m_frame_block =
nullptr;
6014 SetValues(local_values);
6017 return ValueObjectListDelegate::WindowDelegateDraw(window, force);
6021 Debugger &m_debugger;
6022 Block *m_frame_block =
nullptr;
6025class RegistersWindowDelegate :
public ValueObjectListDelegate {
6027 RegistersWindowDelegate(Debugger &debugger)
6028 : ValueObjectListDelegate(), m_debugger(debugger) {}
6030 ~RegistersWindowDelegate()
override =
default;
6032 const char *WindowDelegateGetHelpText()
override {
6033 return "Register window keyboard shortcuts:";
6036 bool WindowDelegateDraw(Window &window,
bool force)
override {
6037 ExecutionContext exe_ctx(
6038 m_debugger.GetCommandInterpreter().GetExecutionContext());
6041 ValueObjectList value_list;
6047 const uint32_t num_sets = reg_ctx->GetRegisterSetCount();
6048 for (uint32_t set_idx = 0; set_idx < num_sets; ++set_idx) {
6053 SetValues(value_list);
6057 if (process && process->
IsAlive())
6062 SetValues(value_list);
6065 return ValueObjectListDelegate::WindowDelegateDraw(window, force);
6069 Debugger &m_debugger;
6073static const char *CursesKeyToCString(
int ch) {
6074 static char g_desc[32];
6075 if (ch >= KEY_F0 && ch < KEY_F0 + 64) {
6076 snprintf(g_desc,
sizeof(g_desc),
"F%u", ch - KEY_F0);
6093 return "delete-line";
6095 return "insert-line";
6097 return "delete-char";
6099 return "insert-char";
6103 return "clear-to-eos";
6105 return "clear-to-eol";
6107 return "scroll-forward";
6109 return "scroll-backward";
6119 return "clear-all-tabs";
6125 return "lower-left key";
6127 return "upper left of keypad";
6129 return "upper right of keypad";
6131 return "center of keypad";
6133 return "lower left of keypad";
6135 return "lower right of keypad";
6137 return "back-tab key";
6141 return "cancel key";
6145 return "command key";
6149 return "create key";
6161 return "message key";
6169 return "options key";
6171 return "previous key";
6175 return "reference key";
6177 return "refresh key";
6179 return "replace key";
6181 return "restart key";
6183 return "resume key";
6187 return "shifted begin key";
6189 return "shifted cancel key";
6191 return "shifted command key";
6193 return "shifted copy key";
6195 return "shifted create key";
6197 return "shifted delete-character key";
6199 return "shifted delete-line key";
6201 return "select key";
6203 return "shifted end key";
6205 return "shifted clear-to-end-of-line key";
6207 return "shifted exit key";
6209 return "shifted find key";
6211 return "shifted help key";
6213 return "shifted home key";
6215 return "shifted insert-character key";
6217 return "shifted left-arrow key";
6219 return "shifted message key";
6221 return "shifted move key";
6223 return "shifted next key";
6225 return "shifted options key";
6227 return "shifted previous key";
6229 return "shifted print key";
6231 return "shifted redo key";
6233 return "shifted replace key";
6235 return "shifted right-arrow key";
6237 return "shifted resume key";
6239 return "shifted save key";
6241 return "shifted suspend key";
6243 return "shifted undo key";
6245 return "suspend key";
6249 return "Mouse event has occurred";
6251 return "Terminal resize event";
6254 return "We were interrupted by an event";
6265 if (llvm::isPrint(ch))
6266 snprintf(g_desc,
sizeof(g_desc),
"%c", ch);
6268 snprintf(g_desc,
sizeof(g_desc),
"\\x%2.2x", ch);
6274HelpDialogDelegate::HelpDialogDelegate(
const char *text,
6275 KeyHelp *key_help_array)
6277 if (text && text[0]) {
6278 m_text.SplitIntoLines(text);
6279 m_text.AppendString(
"");
6281 if (key_help_array) {
6282 for (KeyHelp *key = key_help_array; key->ch; ++key) {
6284 key_description.
Printf(
"%10s - %s", CursesKeyToCString(key->ch),
6286 m_text.AppendString(key_description.
GetString());
6291HelpDialogDelegate::~HelpDialogDelegate() =
default;
6293bool HelpDialogDelegate::WindowDelegateDraw(Window &window,
bool force) {
6295 const int window_height = window.GetHeight();
6298 const int min_y = y;
6299 const int max_y = window_height - 1 - y;
6300 const size_t num_visible_lines = max_y - min_y + 1;
6301 const size_t num_lines = m_text.GetSize();
6302 const char *bottom_message;
6303 if (num_lines <= num_visible_lines)
6304 bottom_message =
"Press any key to exit";
6306 bottom_message =
"Use arrows to scroll, any other key to exit";
6307 window.DrawTitleBox(window.GetName(), bottom_message);
6308 while (y <= max_y) {
6309 window.MoveCursor(x, y);
6310 window.PutCStringTruncated(
6311 1, m_text.GetStringAtIndex(m_first_visible_line + y - min_y));
6317HandleCharResult HelpDialogDelegate::WindowDelegateHandleChar(Window &window,
6320 const size_t num_lines = m_text.GetSize();
6321 const size_t num_visible_lines = window.GetHeight() - 2;
6323 if (num_lines <= num_visible_lines) {
6330 if (m_first_visible_line > 0)
6331 --m_first_visible_line;
6335 if (m_first_visible_line + num_visible_lines < num_lines)
6336 ++m_first_visible_line;
6341 if (m_first_visible_line > 0) {
6342 if (
static_cast<size_t>(m_first_visible_line) >= num_visible_lines)
6343 m_first_visible_line -= num_visible_lines;
6345 m_first_visible_line = 0;
6351 if (m_first_visible_line + num_visible_lines < num_lines) {
6352 m_first_visible_line += num_visible_lines;
6353 if (
static_cast<size_t>(m_first_visible_line) > num_lines)
6354 m_first_visible_line = num_lines - num_visible_lines;
6364 window.GetParent()->RemoveSubWindow(&window);
6368class ApplicationDelegate :
public WindowDelegate,
public MenuDelegate {
6376 eMenuID_TargetCreate,
6377 eMenuID_TargetDelete,
6380 eMenuID_ProcessAttach,
6381 eMenuID_ProcessDetachResume,
6382 eMenuID_ProcessDetachSuspended,
6383 eMenuID_ProcessLaunch,
6384 eMenuID_ProcessContinue,
6385 eMenuID_ProcessHalt,
6386 eMenuID_ProcessKill,
6389 eMenuID_ThreadStepIn,
6390 eMenuID_ThreadStepOver,
6391 eMenuID_ThreadStepOut,
6394 eMenuID_ViewBacktrace,
6395 eMenuID_ViewRegisters,
6397 eMenuID_ViewVariables,
6398 eMenuID_ViewBreakpoints,
6404 ApplicationDelegate(Application &app, Debugger &debugger)
6405 : WindowDelegate(), MenuDelegate(), m_app(app), m_debugger(debugger) {}
6407 ~ApplicationDelegate()
override =
default;
6409 bool WindowDelegateDraw(Window &window,
bool force)
override {
6413 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override {
6416 window.SelectNextWindowAsActive();
6420 window.SelectPreviousWindowAsActive();
6424 window.CreateHelpSubwindow();
6428 return eQuitApplication;
6433 return eKeyNotHandled;
6436 const char *WindowDelegateGetHelpText()
override {
6437 return "Welcome to the LLDB curses GUI.\n\n"
6438 "Press the TAB key to change the selected view.\n"
6439 "Each view has its own keyboard shortcuts, press 'h' to open a "
6440 "dialog to display them.\n\n"
6441 "Common key bindings for all views:";
6444 KeyHelp *WindowDelegateGetKeyHelp()
override {
6445 static curses::KeyHelp g_source_view_key_help[] = {
6446 {
'\t',
"Select next view"},
6447 {KEY_BTAB,
"Select previous view"},
6448 {
'h',
"Show help dialog with view specific key bindings"},
6451 {KEY_UP,
"Select previous"},
6452 {KEY_DOWN,
"Select next"},
6453 {KEY_LEFT,
"Unexpand or select parent"},
6454 {KEY_RIGHT,
"Expand"},
6455 {KEY_PPAGE,
"Page up"},
6456 {KEY_NPAGE,
"Page down"},
6458 return g_source_view_key_help;
6461 MenuActionResult MenuDelegateAction(Menu &menu)
override {
6462 switch (menu.GetIdentifier()) {
6463 case eMenuID_TargetCreate: {
6464 WindowSP main_window_sp = m_app.GetMainWindow();
6465 FormDelegateSP form_delegate_sp =
6466 FormDelegateSP(
new TargetCreateFormDelegate(m_debugger));
6467 Rect bounds = main_window_sp->GetCenteredRect(80, 19);
6468 WindowSP form_window_sp = main_window_sp->CreateSubWindow(
6469 form_delegate_sp->GetName().c_str(), bounds,
true);
6470 WindowDelegateSP window_delegate_sp =
6471 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
6472 form_window_sp->SetDelegate(window_delegate_sp);
6473 return MenuActionResult::Handled;
6475 case eMenuID_ThreadStepIn: {
6476 ExecutionContext exe_ctx =
6477 m_debugger.GetCommandInterpreter().GetExecutionContext();
6480 if (process && process->
IsAlive() &&
6485 return MenuActionResult::Handled;
6487 case eMenuID_ThreadStepOut: {
6488 ExecutionContext exe_ctx =
6489 m_debugger.GetCommandInterpreter().GetExecutionContext();
6492 if (process && process->
IsAlive() &&
6495 uint32_t frame_idx =
6501 return MenuActionResult::Handled;
6503 case eMenuID_ThreadStepOver: {
6504 ExecutionContext exe_ctx =
6505 m_debugger.GetCommandInterpreter().GetExecutionContext();
6508 if (process && process->
IsAlive() &&
6513 return MenuActionResult::Handled;
6515 case eMenuID_ProcessAttach: {
6516 WindowSP main_window_sp = m_app.GetMainWindow();
6517 FormDelegateSP form_delegate_sp = FormDelegateSP(
6518 new ProcessAttachFormDelegate(m_debugger, main_window_sp));
6519 Rect bounds = main_window_sp->GetCenteredRect(80, 22);
6520 WindowSP form_window_sp = main_window_sp->CreateSubWindow(
6521 form_delegate_sp->GetName().c_str(), bounds,
true);
6522 WindowDelegateSP window_delegate_sp =
6523 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
6524 form_window_sp->SetDelegate(window_delegate_sp);
6525 return MenuActionResult::Handled;
6527 case eMenuID_ProcessLaunch: {
6528 WindowSP main_window_sp = m_app.GetMainWindow();
6529 FormDelegateSP form_delegate_sp = FormDelegateSP(
6530 new ProcessLaunchFormDelegate(m_debugger, main_window_sp));
6531 Rect bounds = main_window_sp->GetCenteredRect(80, 22);
6532 WindowSP form_window_sp = main_window_sp->CreateSubWindow(
6533 form_delegate_sp->GetName().c_str(), bounds,
true);
6534 WindowDelegateSP window_delegate_sp =
6535 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
6536 form_window_sp->SetDelegate(window_delegate_sp);
6537 return MenuActionResult::Handled;
6540 case eMenuID_ProcessContinue: {
6541 ExecutionContext exe_ctx =
6542 m_debugger.GetCommandInterpreter().GetExecutionContext();
6545 if (process && process->
IsAlive() &&
6550 return MenuActionResult::Handled;
6552 case eMenuID_ProcessKill: {
6553 ExecutionContext exe_ctx =
6554 m_debugger.GetCommandInterpreter().GetExecutionContext();
6557 if (process && process->
IsAlive())
6561 return MenuActionResult::Handled;
6563 case eMenuID_ProcessHalt: {
6564 ExecutionContext exe_ctx =
6565 m_debugger.GetCommandInterpreter().GetExecutionContext();
6568 if (process && process->
IsAlive())
6572 return MenuActionResult::Handled;
6574 case eMenuID_ProcessDetachResume:
6575 case eMenuID_ProcessDetachSuspended: {
6576 ExecutionContext exe_ctx =
6577 m_debugger.GetCommandInterpreter().GetExecutionContext();
6580 if (process && process->
IsAlive())
6581 process->
Detach(menu.GetIdentifier() ==
6582 eMenuID_ProcessDetachSuspended);
6585 return MenuActionResult::Handled;
6587 case eMenuID_Process: {
6591 Menus &submenus = menu.GetSubmenus();
6592 ExecutionContext exe_ctx =
6593 m_debugger.GetCommandInterpreter().GetExecutionContext();
6595 if (process && process->
IsAlive() &&
6597 if (submenus.size() == 7)
6598 menu.AddSubmenu(std::make_shared<Menu>(Menu::Type::Separator));
6599 else if (submenus.size() > 8)
6600 submenus.erase(submenus.begin() + 8, submenus.end());
6603 std::lock_guard<std::recursive_mutex> guard(threads.
GetMutex());
6604 size_t num_threads = threads.
GetSize();
6605 for (
size_t i = 0; i < num_threads; ++i) {
6607 char menu_char =
'\0';
6609 menu_char =
'1' + i;
6610 StreamString thread_menu_title;
6611 thread_menu_title.
Printf(
"Thread %u", thread_sp->GetIndexID());
6612 const char *thread_name = thread_sp->GetName();
6613 if (thread_name && thread_name[0])
6614 thread_menu_title.
Printf(
" %s", thread_name);
6616 const char *queue_name = thread_sp->GetQueueName();
6617 if (queue_name && queue_name[0])
6618 thread_menu_title.
Printf(
" %s", queue_name);
6620 menu.AddSubmenu(std::make_shared<Menu>(
6621 thread_menu_title.
GetString().str().c_str(),
nullptr, menu_char,
6622 thread_sp->GetID()));
6624 }
else if (submenus.size() > 7) {
6627 submenus.erase(submenus.begin() + 7, submenus.end());
6631 menu.RecalculateNameLengths();
6633 return MenuActionResult::Handled;
6635 case eMenuID_ViewVariables: {
6636 WindowSP main_window_sp = m_app.GetMainWindow();
6637 WindowSP source_window_sp = main_window_sp->FindSubWindow(
"Source");
6638 WindowSP variables_window_sp = main_window_sp->FindSubWindow(
"Variables");
6639 WindowSP registers_window_sp = main_window_sp->FindSubWindow(
"Registers");
6640 const Rect source_bounds = source_window_sp->GetBounds();
6642 if (variables_window_sp) {
6643 const Rect variables_bounds = variables_window_sp->GetBounds();
6645 main_window_sp->RemoveSubWindow(variables_window_sp.get());
6647 if (registers_window_sp) {
6650 Rect registers_bounds = variables_bounds;
6651 registers_bounds.size.width = source_bounds.size.width;
6652 registers_window_sp->SetBounds(registers_bounds);
6656 source_window_sp->Resize(source_bounds.size.width,
6657 source_bounds.size.height +
6658 variables_bounds.size.height);
6661 Rect new_variables_rect;
6662 if (registers_window_sp) {
6666 const Rect variables_bounds = registers_window_sp->GetBounds();
6667 Rect new_registers_rect;
6668 variables_bounds.VerticalSplitPercentage(0.50, new_variables_rect,
6669 new_registers_rect);
6670 registers_window_sp->SetBounds(new_registers_rect);
6673 Rect new_source_rect;
6674 source_bounds.HorizontalSplitPercentage(0.70, new_source_rect,
6675 new_variables_rect);
6676 source_window_sp->SetBounds(new_source_rect);
6678 WindowSP new_window_sp = main_window_sp->CreateSubWindow(
6679 "Variables", new_variables_rect,
false);
6680 new_window_sp->SetDelegate(
6681 WindowDelegateSP(
new FrameVariablesWindowDelegate(m_debugger)));
6685 return MenuActionResult::Handled;
6687 case eMenuID_ViewRegisters: {
6688 WindowSP main_window_sp = m_app.GetMainWindow();
6689 WindowSP source_window_sp = main_window_sp->FindSubWindow(
"Source");
6690 WindowSP variables_window_sp = main_window_sp->FindSubWindow(
"Variables");
6691 WindowSP registers_window_sp = main_window_sp->FindSubWindow(
"Registers");
6692 const Rect source_bounds = source_window_sp->GetBounds();
6694 if (registers_window_sp) {
6695 if (variables_window_sp) {
6696 const Rect variables_bounds = variables_window_sp->GetBounds();
6700 variables_window_sp->Resize(variables_bounds.size.width +
6701 registers_window_sp->GetWidth(),
6702 variables_bounds.size.height);
6706 source_window_sp->Resize(source_bounds.size.width,
6707 source_bounds.size.height +
6708 registers_window_sp->GetHeight());
6710 main_window_sp->RemoveSubWindow(registers_window_sp.get());
6713 if (variables_window_sp) {
6717 const Rect variables_bounds = variables_window_sp->GetBounds();
6719 variables_bounds.VerticalSplitPercentage(0.50, new_vars_rect,
6721 variables_window_sp->SetBounds(new_vars_rect);
6724 Rect new_source_rect;
6725 source_bounds.HorizontalSplitPercentage(0.70, new_source_rect,
6727 source_window_sp->SetBounds(new_source_rect);
6729 WindowSP new_window_sp =
6730 main_window_sp->CreateSubWindow(
"Registers", new_regs_rect,
false);
6731 new_window_sp->SetDelegate(
6732 WindowDelegateSP(
new RegistersWindowDelegate(m_debugger)));
6736 return MenuActionResult::Handled;
6738 case eMenuID_ViewBreakpoints: {
6739 WindowSP main_window_sp = m_app.GetMainWindow();
6740 WindowSP threads_window_sp = main_window_sp->FindSubWindow(
"Threads");
6741 WindowSP breakpoints_window_sp =
6742 main_window_sp->FindSubWindow(
"Breakpoints");
6743 const Rect threads_bounds = threads_window_sp->GetBounds();
6750 if (breakpoints_window_sp) {
6751 threads_window_sp->Resize(threads_bounds.size.width,
6752 threads_bounds.size.height +
6753 breakpoints_window_sp->GetHeight());
6754 main_window_sp->RemoveSubWindow(breakpoints_window_sp.get());
6756 Rect new_threads_bounds, breakpoints_bounds;
6757 threads_bounds.HorizontalSplitPercentage(0.70, new_threads_bounds,
6758 breakpoints_bounds);
6759 threads_window_sp->SetBounds(new_threads_bounds);
6760 breakpoints_window_sp = main_window_sp->CreateSubWindow(
6761 "Breakpoints", breakpoints_bounds,
false);
6762 TreeDelegateSP breakpoints_delegate_sp(
6763 new BreakpointsTreeDelegate(m_debugger));
6764 breakpoints_window_sp->SetDelegate(WindowDelegateSP(
6765 new TreeWindowDelegate(m_debugger, breakpoints_delegate_sp)));
6768 return MenuActionResult::Handled;
6771 case eMenuID_HelpGUIHelp:
6772 m_app.GetMainWindow()->CreateHelpSubwindow();
6773 return MenuActionResult::Handled;
6779 return MenuActionResult::NotHandled;
6784 Debugger &m_debugger;
6787class StatusBarWindowDelegate :
public WindowDelegate {
6789 StatusBarWindowDelegate(Debugger &debugger) : m_debugger(debugger) {
6793 ~StatusBarWindowDelegate()
override =
default;
6795 bool WindowDelegateDraw(Window &window,
bool force)
override {
6796 ExecutionContext exe_ctx =
6797 m_debugger.GetCommandInterpreter().GetExecutionContext();
6802 window.SetBackground(BlackOnWhite);
6803 window.MoveCursor(0, 0);
6806 window.Printf(
"Process: %5" PRIu64
" %10s", process->
GetID(),
6812 FormatEntity::Formatter(
nullptr, &exe_ctx,
nullptr,
false,
false)
6813 .
Format(m_format, strm)) {
6814 window.MoveCursor(40, 0);
6815 window.PutCStringTruncated(1, strm.
GetString().str().c_str());
6818 window.MoveCursor(60, 0);
6820 window.Printf(
"Frame: %3u PC = 0x%16.16" PRIx64,
6827 if (exit_desc && exit_desc[0])
6828 window.Printf(
" with status = %i (%s)", exit_status, exit_desc);
6830 window.Printf(
" with status = %i", exit_status);
6837 Debugger &m_debugger;
6838 FormatEntity::Entry m_format;
6841class SourceFileWindowDelegate :
public WindowDelegate {
6843 SourceFileWindowDelegate(Debugger &debugger)
6844 : WindowDelegate(), m_debugger(debugger) {}
6846 ~SourceFileWindowDelegate()
override =
default;
6848 void Update(
const SymbolContext &sc) { m_sc = sc; }
6850 uint32_t NumVisibleLines()
const {
return m_max_y - m_min_y; }
6852 const char *WindowDelegateGetHelpText()
override {
6853 return "Source/Disassembly window keyboard shortcuts:";
6856 KeyHelp *WindowDelegateGetKeyHelp()
override {
6857 static curses::KeyHelp g_source_view_key_help[] = {
6858 {KEY_RETURN,
"Run to selected line with one shot breakpoint"},
6859 {KEY_UP,
"Select previous source line"},
6860 {KEY_DOWN,
"Select next source line"},
6861 {KEY_LEFT,
"Scroll to the left"},
6862 {KEY_RIGHT,
"Scroll to the right"},
6863 {KEY_PPAGE,
"Page up"},
6864 {KEY_NPAGE,
"Page down"},
6865 {
'b',
"Set breakpoint on selected source/disassembly line"},
6866 {
'c',
"Continue process"},
6867 {
'D',
"Detach with process suspended"},
6868 {
'h',
"Show help dialog"},
6869 {
'n',
"Step over (source line)"},
6870 {
'N',
"Step over (single instruction)"},
6871 {
'f',
"Step out (finish)"},
6872 {
's',
"Step in (source line)"},
6873 {
'S',
"Step in (single instruction)"},
6875 {
'd',
"Frame down"},
6879 return g_source_view_key_help;
6882 bool WindowDelegateDraw(Window &window,
bool force)
override {
6883 ExecutionContext exe_ctx =
6884 m_debugger.GetCommandInterpreter().GetExecutionContext();
6886 Thread *thread =
nullptr;
6888 bool update_location =
false;
6893 update_location =
true;
6899 m_max_x = window.GetMaxX() - 1;
6900 m_max_y = window.GetMaxY() - 1;
6902 const uint32_t num_visible_lines = NumVisibleLines();
6904 bool set_selected_line_to_pc =
false;
6906 if (update_location) {
6907 const bool process_alive = process->
IsAlive();
6908 bool thread_changed =
false;
6909 if (process_alive) {
6913 auto tid = thread->
GetID();
6914 thread_changed = tid != m_tid;
6918 thread_changed =
true;
6923 const uint32_t stop_id = process ? process->
GetStopID() : 0;
6924 const bool stop_id_changed = stop_id != m_stop_id;
6925 bool frame_changed =
false;
6926 m_stop_id = stop_id;
6929 m_sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
6930 if (m_sc.module_sp) {
6931 m_title.Format(
"{0}", m_sc.module_sp->GetFileSpec().GetFilename());
6932 llvm::StringRef func_name = m_sc.GetFunctionName().GetStringRef();
6933 if (!func_name.empty())
6934 m_title.Format(
"`{0}", func_name);
6936 const uint32_t frame_idx = frame_sp->GetFrameIndex();
6937 frame_changed = frame_idx != m_frame_idx;
6938 m_frame_idx = frame_idx;
6945 const bool context_changed =
6946 thread_changed || frame_changed || stop_id_changed;
6948 if (process_alive) {
6949 if (m_sc.line_entry.IsValid()) {
6950 m_pc_line = m_sc.line_entry.line;
6954 if (context_changed)
6955 m_selected_line = m_pc_line;
6957 if (m_file_sp && m_file_sp->GetSupportFile()->GetSpecOnly() ==
6958 m_sc.line_entry.GetFile()) {
6961 if (m_selected_line >=
static_cast<size_t>(m_first_visible_line)) {
6962 if (m_selected_line >= m_first_visible_line + num_visible_lines)
6963 m_first_visible_line = m_selected_line - 10;
6965 if (m_selected_line > 10)
6966 m_first_visible_line = m_selected_line - 10;
6968 m_first_visible_line = 0;
6972 m_selected_line = m_pc_line;
6974 m_debugger.GetSourceManager().GetFile(m_sc.line_entry.file_sp);
6976 const size_t num_lines = m_file_sp->GetNumLines();
6978 for (
size_t n = num_lines; n >= 10; n = n / 10)
6981 if (num_lines < num_visible_lines ||
6982 m_selected_line < num_visible_lines)
6983 m_first_visible_line = 0;
6985 m_first_visible_line = m_selected_line - 10;
6992 if (!m_file_sp || m_file_sp->GetNumLines() == 0) {
6994 bool prefer_file_cache =
false;
6995 if (m_sc.function) {
6996 if (m_disassembly_scope != m_sc.function) {
6997 m_disassembly_scope = m_sc.function;
6998 m_disassembly_sp = m_sc.function->GetInstructions(
6999 exe_ctx,
nullptr, !prefer_file_cache);
7000 if (m_disassembly_sp)
7001 set_selected_line_to_pc =
true;
7003 set_selected_line_to_pc = context_changed;
7005 }
else if (m_sc.symbol) {
7006 if (m_disassembly_scope != m_sc.symbol) {
7007 m_disassembly_scope = m_sc.symbol;
7008 m_disassembly_sp = m_sc.symbol->GetInstructions(
7009 exe_ctx,
nullptr, prefer_file_cache);
7010 if (m_disassembly_sp)
7011 set_selected_line_to_pc =
true;
7013 set_selected_line_to_pc = context_changed;
7022 const int window_width = window.GetWidth();
7024 window.DrawTitleBox(
"Sources");
7025 if (!m_title.GetString().empty()) {
7026 window.AttributeOn(A_REVERSE);
7027 window.MoveCursor(1, 1);
7028 window.PutChar(
' ');
7029 window.PutCStringTruncated(1, m_title.GetString().str().c_str());
7030 int x = window.GetCursorX();
7031 if (x < window_width - 1) {
7032 window.Printf(
"%*s", window_width - x - 1,
"");
7034 window.AttributeOff(A_REVERSE);
7038 const size_t num_source_lines = GetNumSourceLines();
7039 if (num_source_lines > 0) {
7041 BreakpointLines bp_lines;
7044 const size_t num_bps = bp_list.
GetSize();
7045 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
7047 const size_t num_bps_locs = bp_sp->GetNumLocations();
7048 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs; ++bp_loc_idx) {
7050 bp_sp->GetLocationAtIndex(bp_loc_idx);
7051 LineEntry bp_loc_line_entry;
7052 if (bp_loc_sp->GetAddress().CalculateSymbolContextLineEntry(
7053 bp_loc_line_entry)) {
7054 if (m_file_sp->GetSupportFile()->GetSpecOnly() ==
7055 bp_loc_line_entry.
GetFile()) {
7056 bp_lines.insert(bp_loc_line_entry.
line);
7063 for (
size_t i = 0; i < num_visible_lines; ++i) {
7064 const uint32_t curr_line = m_first_visible_line + i;
7065 if (curr_line < num_source_lines) {
7066 const int line_y = m_min_y + i;
7067 window.MoveCursor(1, line_y);
7068 const bool is_pc_line = curr_line == m_pc_line;
7069 const bool line_is_selected = m_selected_line == curr_line;
7073 attr_t highlight_attr = 0;
7075 if (line_is_selected && !is_pc_line)
7076 highlight_attr = A_REVERSE;
7078 if (bp_lines.find(curr_line + 1) != bp_lines.end())
7079 bp_attr = COLOR_PAIR(BlackOnWhite);
7082 window.AttributeOn(bp_attr);
7084 window.Printf(
" %*u ", m_line_width, curr_line + 1);
7087 window.AttributeOff(bp_attr);
7089 window.PutChar(ACS_VLINE);
7092 window.PutChar(ACS_DIAMOND);
7094 window.PutChar(
' ');
7097 window.AttributeOn(highlight_attr);
7099 StreamString lineStream;
7101 std::optional<size_t> column;
7102 if (is_pc_line && m_sc.line_entry.IsValid() && m_sc.line_entry.column)
7103 column = m_sc.line_entry.column - 1;
7104 m_file_sp->DisplaySourceLines(curr_line + 1, column, 0, 0,
7106 StringRef line = lineStream.
GetString();
7107 if (line.ends_with(
"\n"))
7108 line = line.drop_back();
7109 bool wasWritten = window.OutputColoredStringTruncated(
7110 1, line, m_first_visible_column, is_pc_line);
7111 if (!wasWritten && (line_is_selected || is_pc_line)) {
7115 window.PutCStringTruncated(
7116 1, line.empty() && m_first_visible_column == 0 ?
" " :
"<");
7119 if (is_pc_line && frame_sp &&
7120 frame_sp->GetConcreteFrameIndex() == 0) {
7125 const char *stop_description = stop_info_sp->GetDescription();
7126 if (stop_description && stop_description[0]) {
7127 size_t stop_description_len = strlen(stop_description);
7128 int desc_x = window_width - stop_description_len - 16;
7129 if (desc_x - window.GetCursorX() > 0)
7130 window.Printf(
"%*s", desc_x - window.GetCursorX(),
"");
7131 window.MoveCursor(window_width - stop_description_len - 16,
7133 const attr_t stop_reason_attr = COLOR_PAIR(WhiteOnBlue);
7134 window.AttributeOn(stop_reason_attr);
7135 window.PrintfTruncated(1,
" <<< Thread %u: %s ",
7137 window.AttributeOff(stop_reason_attr);
7140 window.Printf(
"%*s", window_width - window.GetCursorX() - 1,
"");
7144 window.AttributeOff(highlight_attr);
7150 size_t num_disassembly_lines = GetNumDisassemblyLines();
7151 if (num_disassembly_lines > 0) {
7153 BreakpointAddrs bp_file_addrs;
7157 const size_t num_bps = bp_list.
GetSize();
7158 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
7160 const size_t num_bps_locs = bp_sp->GetNumLocations();
7161 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs;
7164 bp_sp->GetLocationAtIndex(bp_loc_idx);
7165 bp_file_addrs.insert(bp_loc_sp->GetAddress().GetFileAddress());
7170 const attr_t selected_highlight_attr = A_REVERSE;
7171 const attr_t pc_highlight_attr = COLOR_PAIR(WhiteOnBlue);
7175 InstructionList &insts = m_disassembly_sp->GetInstructionList();
7179 pc_address = frame_sp->GetFrameCodeAddress();
7180 const uint32_t pc_idx =
7184 if (set_selected_line_to_pc) {
7185 m_selected_line = pc_idx;
7188 const uint32_t non_visible_pc_offset = (num_visible_lines / 5);
7189 if (
static_cast<size_t>(m_first_visible_line) >= num_disassembly_lines)
7190 m_first_visible_line = 0;
7192 if (pc_idx < num_disassembly_lines) {
7193 if (pc_idx <
static_cast<uint32_t
>(m_first_visible_line) ||
7194 pc_idx >= m_first_visible_line + num_visible_lines)
7195 m_first_visible_line = pc_idx - non_visible_pc_offset;
7198 for (
size_t i = 0; i < num_visible_lines; ++i) {
7199 const uint32_t inst_idx = m_first_visible_line + i;
7204 const int line_y = m_min_y + i;
7205 window.MoveCursor(1, line_y);
7206 const bool is_pc_line = frame_sp && inst_idx == pc_idx;
7207 const bool line_is_selected = m_selected_line == inst_idx;
7210 attr_t highlight_attr = 0;
7213 highlight_attr = pc_highlight_attr;
7214 else if (line_is_selected)
7215 highlight_attr = selected_highlight_attr;
7218 bp_file_addrs.end())
7219 bp_attr = COLOR_PAIR(BlackOnWhite);
7222 window.AttributeOn(bp_attr);
7224 window.Printf(
" 0x%16.16llx ",
7225 static_cast<unsigned long long>(
7229 window.AttributeOff(bp_attr);
7231 window.PutChar(ACS_VLINE);
7234 window.PutChar(ACS_DIAMOND);
7236 window.PutChar(
' ');
7239 window.AttributeOn(highlight_attr);
7241 const char *mnemonic = inst->
GetMnemonic(&exe_ctx);
7242 const char *operands = inst->
GetOperands(&exe_ctx);
7243 const char *comment = inst->
GetComment(&exe_ctx);
7245 if (mnemonic !=
nullptr && mnemonic[0] ==
'\0')
7247 if (operands !=
nullptr && operands[0] ==
'\0')
7249 if (comment !=
nullptr && comment[0] ==
'\0')
7254 if (mnemonic !=
nullptr && operands !=
nullptr && comment !=
nullptr)
7255 strm.
Printf(
"%-8s %-25s ; %s", mnemonic, operands, comment);
7256 else if (mnemonic !=
nullptr && operands !=
nullptr)
7257 strm.
Printf(
"%-8s %s", mnemonic, operands);
7258 else if (mnemonic !=
nullptr)
7262 window.PutCStringTruncated(
7264 strm.
GetString().substr(m_first_visible_column).data());
7266 if (is_pc_line && frame_sp &&
7267 frame_sp->GetConcreteFrameIndex() == 0) {
7272 const char *stop_description = stop_info_sp->GetDescription();
7273 if (stop_description && stop_description[0]) {
7274 size_t stop_description_len = strlen(stop_description);
7275 int desc_x = window_width - stop_description_len - 16;
7276 if (desc_x - window.GetCursorX() > 0)
7277 window.Printf(
"%*s", desc_x - window.GetCursorX(),
"");
7278 window.MoveCursor(window_width - stop_description_len - 15,
7281 window.PrintfTruncated(1,
"<<< Thread %u: %s ",
7286 window.Printf(
"%*s", window_width - window.GetCursorX() - 1,
"");
7290 window.AttributeOff(highlight_attr);
7297 size_t GetNumLines() {
7298 size_t num_lines = GetNumSourceLines();
7300 num_lines = GetNumDisassemblyLines();
7304 size_t GetNumSourceLines()
const {
7306 return m_file_sp->GetNumLines();
7310 size_t GetNumDisassemblyLines()
const {
7311 if (m_disassembly_sp)
7312 return m_disassembly_sp->GetInstructionList().GetSize();
7316 HandleCharResult WindowDelegateHandleChar(Window &window,
int c)
override {
7317 const uint32_t num_visible_lines = NumVisibleLines();
7318 const size_t num_lines = GetNumLines();
7324 if (
static_cast<uint32_t
>(m_first_visible_line) > num_visible_lines)
7325 m_first_visible_line -= num_visible_lines;
7327 m_first_visible_line = 0;
7328 m_selected_line = m_first_visible_line;
7335 if (m_first_visible_line + num_visible_lines < num_lines)
7336 m_first_visible_line += num_visible_lines;
7337 else if (num_lines < num_visible_lines)
7338 m_first_visible_line = 0;
7340 m_first_visible_line = num_lines - num_visible_lines;
7341 m_selected_line = m_first_visible_line;
7346 if (m_selected_line > 0) {
7348 if (
static_cast<size_t>(m_first_visible_line) > m_selected_line)
7349 m_first_visible_line = m_selected_line;
7354 if (m_selected_line + 1 < num_lines) {
7356 if (m_first_visible_line + num_visible_lines < m_selected_line)
7357 m_first_visible_line++;
7362 if (m_first_visible_column > 0)
7363 --m_first_visible_column;
7367 ++m_first_visible_column;
7374 if (GetNumSourceLines() > 0) {
7375 ExecutionContext exe_ctx =
7376 m_debugger.GetCommandInterpreter().GetExecutionContext();
7380 m_file_sp->GetSupportFile()->GetSpecOnly(),
7391 bp_sp->GetOptions().SetOneShot(
true);
7394 }
else if (m_selected_line < GetNumDisassemblyLines()) {
7395 const Instruction *inst = m_disassembly_sp->GetInstructionList()
7396 .GetInstructionAtIndex(m_selected_line)
7398 ExecutionContext exe_ctx =
7399 m_debugger.GetCommandInterpreter().GetExecutionContext();
7407 bp_sp->GetOptions().SetOneShot(
true);
7414 ToggleBreakpointOnSelectedLine();
7419 ExecutionContext exe_ctx =
7420 m_debugger.GetCommandInterpreter().GetExecutionContext();
7429 ExecutionContext exe_ctx =
7430 m_debugger.GetCommandInterpreter().GetExecutionContext();
7439 ExecutionContext exe_ctx =
7440 m_debugger.GetCommandInterpreter().GetExecutionContext();
7444 uint32_t frame_idx =
7454 ExecutionContext exe_ctx =
7455 m_debugger.GetCommandInterpreter().GetExecutionContext();
7458 bool source_step = (c ==
'n');
7467 ExecutionContext exe_ctx =
7468 m_debugger.GetCommandInterpreter().GetExecutionContext();
7471 bool source_step = (c ==
's');
7480 ExecutionContext exe_ctx =
7481 m_debugger.GetCommandInterpreter().GetExecutionContext();
7484 uint32_t frame_idx =
7490 else if (c ==
'd' && frame_idx > 0)
7499 window.CreateHelpSubwindow();
7505 return eKeyNotHandled;
7508 void ToggleBreakpointOnSelectedLine() {
7509 ExecutionContext exe_ctx =
7510 m_debugger.GetCommandInterpreter().GetExecutionContext();
7513 if (GetNumSourceLines() > 0) {
7516 const size_t num_bps = bp_list.
GetSize();
7517 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
7519 const size_t num_bps_locs = bp_sp->GetNumLocations();
7520 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs; ++bp_loc_idx) {
7522 bp_sp->GetLocationAtIndex(bp_loc_idx);
7523 LineEntry bp_loc_line_entry;
7524 if (bp_loc_sp->GetAddress().CalculateSymbolContextLineEntry(
7525 bp_loc_line_entry)) {
7526 if (m_file_sp->GetSupportFile()->GetSpecOnly() ==
7527 bp_loc_line_entry.
GetFile() &&
7528 m_selected_line + 1 == bp_loc_line_entry.
line) {
7541 m_file_sp->GetSupportFile()->GetSpecOnly(),
7553 assert(GetNumDisassemblyLines() > 0);
7554 assert(m_selected_line < GetNumDisassemblyLines());
7555 const Instruction *inst = m_disassembly_sp->GetInstructionList()
7556 .GetInstructionAtIndex(m_selected_line)
7561 const size_t num_bps = bp_list.
GetSize();
7562 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
7564 const size_t num_bps_locs = bp_sp->GetNumLocations();
7565 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs; ++bp_loc_idx) {
7567 bp_sp->GetLocationAtIndex(bp_loc_idx);
7568 LineEntry bp_loc_line_entry;
7570 bp_loc_sp->GetAddress().GetFileAddress();
7589 typedef std::set<uint32_t> BreakpointLines;
7590 typedef std::set<lldb::addr_t> BreakpointAddrs;
7592 Debugger &m_debugger;
7595 SymbolContextScope *m_disassembly_scope =
nullptr;
7597 StreamString m_title;
7599 int m_line_width = 4;
7600 uint32_t m_selected_line = 0;
7601 uint32_t m_pc_line = 0;
7602 uint32_t m_stop_id = 0;
7604 int m_first_visible_line = 0;
7605 int m_first_visible_column = 0;
7612DisplayOptions ValueObjectListDelegate::g_options = {
true};
7620 m_app_up = std::make_unique<Application>(
7625 std::shared_ptr<ApplicationDelegate> app_delegate_sp(
7628 MenuDelegateSP app_menu_delegate_sp =
7629 std::static_pointer_cast<MenuDelegate>(app_delegate_sp);
7630 MenuSP lldb_menu_sp(
7631 new Menu(
"LLDB",
"F1", KEY_F(1), ApplicationDelegate::eMenuID_LLDB));
7632 MenuSP exit_menuitem_sp(
7633 new Menu(
"Exit",
nullptr,
'x', ApplicationDelegate::eMenuID_LLDBExit));
7634 exit_menuitem_sp->SetCannedResult(MenuActionResult::Quit);
7635 lldb_menu_sp->AddSubmenu(std::make_shared<Menu>(
7636 "About LLDB",
nullptr,
'a', ApplicationDelegate::eMenuID_LLDBAbout));
7637 lldb_menu_sp->AddSubmenu(std::make_shared<Menu>(Menu::Type::Separator));
7638 lldb_menu_sp->AddSubmenu(exit_menuitem_sp);
7640 MenuSP target_menu_sp(
new Menu(
"Target",
"F2", KEY_F(2),
7641 ApplicationDelegate::eMenuID_Target));
7642 target_menu_sp->AddSubmenu(std::make_shared<Menu>(
7643 "Create",
nullptr,
'c', ApplicationDelegate::eMenuID_TargetCreate));
7644 target_menu_sp->AddSubmenu(std::make_shared<Menu>(
7645 "Delete",
nullptr,
'd', ApplicationDelegate::eMenuID_TargetDelete));
7647 MenuSP process_menu_sp(
new Menu(
"Process",
"F3", KEY_F(3),
7648 ApplicationDelegate::eMenuID_Process));
7649 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7650 "Attach",
nullptr,
'a', ApplicationDelegate::eMenuID_ProcessAttach));
7651 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7652 "Detach and resume",
nullptr,
'd',
7653 ApplicationDelegate::eMenuID_ProcessDetachResume));
7654 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7655 "Detach suspended",
nullptr,
's',
7656 ApplicationDelegate::eMenuID_ProcessDetachSuspended));
7657 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7658 "Launch",
nullptr,
'l', ApplicationDelegate::eMenuID_ProcessLaunch));
7659 process_menu_sp->AddSubmenu(std::make_shared<Menu>(Menu::Type::Separator));
7660 process_menu_sp->AddSubmenu(
7661 std::make_shared<Menu>(
"Continue",
nullptr,
'c',
7662 ApplicationDelegate::eMenuID_ProcessContinue));
7663 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7664 "Halt",
nullptr,
'h', ApplicationDelegate::eMenuID_ProcessHalt));
7665 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7666 "Kill",
nullptr,
'k', ApplicationDelegate::eMenuID_ProcessKill));
7668 MenuSP thread_menu_sp(
new Menu(
"Thread",
"F4", KEY_F(4),
7669 ApplicationDelegate::eMenuID_Thread));
7670 thread_menu_sp->AddSubmenu(std::make_shared<Menu>(
7671 "Step In",
nullptr,
'i', ApplicationDelegate::eMenuID_ThreadStepIn));
7672 thread_menu_sp->AddSubmenu(
7673 std::make_shared<Menu>(
"Step Over",
nullptr,
'v',
7674 ApplicationDelegate::eMenuID_ThreadStepOver));
7675 thread_menu_sp->AddSubmenu(std::make_shared<Menu>(
7676 "Step Out",
nullptr,
'o', ApplicationDelegate::eMenuID_ThreadStepOut));
7678 MenuSP view_menu_sp(
7679 new Menu(
"View",
"F5", KEY_F(5), ApplicationDelegate::eMenuID_View));
7680 view_menu_sp->AddSubmenu(std::make_shared<Menu>(
7681 "Backtrace",
nullptr,
't', ApplicationDelegate::eMenuID_ViewBacktrace));
7682 view_menu_sp->AddSubmenu(std::make_shared<Menu>(
7683 "Registers",
nullptr,
'r', ApplicationDelegate::eMenuID_ViewRegisters));
7684 view_menu_sp->AddSubmenu(std::make_shared<Menu>(
7685 "Source",
nullptr,
's', ApplicationDelegate::eMenuID_ViewSource));
7686 view_menu_sp->AddSubmenu(std::make_shared<Menu>(
7687 "Variables",
nullptr,
'v', ApplicationDelegate::eMenuID_ViewVariables));
7688 view_menu_sp->AddSubmenu(
7689 std::make_shared<Menu>(
"Breakpoints",
nullptr,
'b',
7690 ApplicationDelegate::eMenuID_ViewBreakpoints));
7692 MenuSP help_menu_sp(
7693 new Menu(
"Help",
"F6", KEY_F(6), ApplicationDelegate::eMenuID_Help));
7694 help_menu_sp->AddSubmenu(std::make_shared<Menu>(
7695 "GUI Help",
nullptr,
'g', ApplicationDelegate::eMenuID_HelpGUIHelp));
7698 WindowSP &main_window_sp =
m_app_up->GetMainWindow();
7700 MenuSP menubar_sp(
new Menu(Menu::Type::Bar));
7701 menubar_sp->AddSubmenu(lldb_menu_sp);
7702 menubar_sp->AddSubmenu(target_menu_sp);
7703 menubar_sp->AddSubmenu(process_menu_sp);
7704 menubar_sp->AddSubmenu(thread_menu_sp);
7705 menubar_sp->AddSubmenu(view_menu_sp);
7706 menubar_sp->AddSubmenu(help_menu_sp);
7707 menubar_sp->SetDelegate(app_menu_delegate_sp);
7709 Rect content_bounds = main_window_sp->GetFrame();
7710 Rect menubar_bounds = content_bounds.MakeMenuBar();
7711 Rect status_bounds = content_bounds.MakeStatusBar();
7713 Rect variables_bounds;
7714 Rect threads_bounds;
7715 Rect source_variables_bounds;
7716 content_bounds.VerticalSplitPercentage(0.80, source_variables_bounds,
7718 source_variables_bounds.HorizontalSplitPercentage(0.70, source_bounds,
7721 WindowSP menubar_window_sp =
7722 main_window_sp->CreateSubWindow(
"Menubar", menubar_bounds,
false);
7725 menubar_window_sp->SetCanBeActive(
7727 menubar_window_sp->SetDelegate(menubar_sp);
7729 WindowSP source_window_sp(
7730 main_window_sp->CreateSubWindow(
"Source", source_bounds,
true));
7731 WindowSP variables_window_sp(
7732 main_window_sp->CreateSubWindow(
"Variables", variables_bounds,
false));
7733 WindowSP threads_window_sp(
7734 main_window_sp->CreateSubWindow(
"Threads", threads_bounds,
false));
7735 WindowSP status_window_sp(
7736 main_window_sp->CreateSubWindow(
"Status", status_bounds,
false));
7737 status_window_sp->SetCanBeActive(
7739 main_window_sp->SetDelegate(
7740 std::static_pointer_cast<WindowDelegate>(app_delegate_sp));
7741 source_window_sp->SetDelegate(
7742 WindowDelegateSP(
new SourceFileWindowDelegate(
m_debugger)));
7743 variables_window_sp->SetDelegate(
7744 WindowDelegateSP(
new FrameVariablesWindowDelegate(
m_debugger)));
7745 TreeDelegateSP thread_delegate_sp(
new ThreadsTreeDelegate(
m_debugger));
7746 threads_window_sp->SetDelegate(WindowDelegateSP(
7747 new TreeWindowDelegate(
m_debugger, thread_delegate_sp)));
7748 status_window_sp->SetDelegate(
7749 WindowDelegateSP(
new StatusBarWindowDelegate(
m_debugger)));
7752 init_pair(1, COLOR_BLACK, COLOR_BLACK);
7753 init_pair(2, COLOR_RED, COLOR_BLACK);
7754 init_pair(3, COLOR_GREEN, COLOR_BLACK);
7755 init_pair(4, COLOR_YELLOW, COLOR_BLACK);
7756 init_pair(5, COLOR_BLUE, COLOR_BLACK);
7757 init_pair(6, COLOR_MAGENTA, COLOR_BLACK);
7758 init_pair(7, COLOR_CYAN, COLOR_BLACK);
7759 init_pair(8, COLOR_WHITE, COLOR_BLACK);
7761 init_pair(9, COLOR_BLACK, COLOR_BLUE);
7762 init_pair(10, COLOR_RED, COLOR_BLUE);
7763 init_pair(11, COLOR_GREEN, COLOR_BLUE);
7764 init_pair(12, COLOR_YELLOW, COLOR_BLUE);
7765 init_pair(13, COLOR_BLUE, COLOR_BLUE);
7766 init_pair(14, COLOR_MAGENTA, COLOR_BLUE);
7767 init_pair(15, COLOR_CYAN, COLOR_BLUE);
7768 init_pair(16, COLOR_WHITE, COLOR_BLUE);
7770 init_pair(17, COLOR_BLACK, COLOR_WHITE);
7771 init_pair(18, COLOR_MAGENTA, COLOR_WHITE);
7772 static_assert(LastColorPairIndex == 18,
"Color indexes do not match.");
7774 define_key(
"\033[Z", KEY_SHIFT_TAB);
7775 define_key(
"\033\015", KEY_ALT_ENTER);
7791 return m_debugger.GetCommandInterpreter().IOHandlerInterrupt(*
this);
#define ANSI_CTRL_UNDERLINE
#define ANSI_FG_COLOR_BLACK
#define ANSI_FG_COLOR_WHITE
static llvm::raw_ostream & error(Stream &strm)
static llvm::Expected< uint32_t > GetNumChildren(ValueObject *size)
static StringRef GetText(const lldb_private::DataExtractor &data)
Returns the JSON text in the buffer, which is not null-terminated and may be zero padded past the end...
static void skip(TSLexer *lexer)
static llvm::StringRef GetName(XcodeSDK::Type type)
lldb::addr_t GetLoadAddress(Target *target) const
Get the load address.
bool SetLoadAddress(lldb::addr_t load_addr, Target *target, bool allow_section_end=false)
Set the address to represent load_addr.
uint32_t CalculateSymbolContext(SymbolContext *sc, lldb::SymbolContextItem resolve_scope=lldb::eSymbolContextEverything) const
Reconstruct a symbol context from an address.
lldb::addr_t GetOpcodeLoadAddress(Target *target, AddressClass addr_class=AddressClass::eInvalid) const
Get the load address as an opcode load address.
@ DumpStyleInvalid
Invalid dump style.
@ DumpStyleModuleWithFileAddress
Display as the file address with the module name prepended (if any).
@ DumpStyleResolvedDescription
Display the details about what an address resolves to.
@ DumpStyleLoadAddress
Display as the load address (if resolved).
bool Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, DumpStyle fallback_style=DumpStyleInvalid, uint32_t addr_byte_size=UINT32_MAX, bool all_ranges=false, std::optional< Stream::HighlightSettings > settings=std::nullopt) const
Dump a description of this object to a Stream.
lldb::addr_t GetFileAddress() const
Get the file address.
bool IsValid() const
Check if the object state is valid.
Symbol * CalculateSymbolContextSymbol() const
void AppendArguments(const Args &rhs)
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
void AppendArgument(llvm::StringRef arg_str, char quote_char='\0')
Appends a new argument to the end of the list argument list.
const char * GetArgumentAtIndex(size_t idx) const
Gets the null-terminated C string argument pointer for the argument at index idx.
void GetListMutex(std::unique_lock< std::recursive_mutex > &lock)
Sets the passed in Locker to hold the Breakpoint List mutex.
size_t GetSize() const
Returns the number of elements in this breakpoint list.
lldb::BreakpointSP GetBreakpointAtIndex(size_t i) const
Returns a shared pointer to the breakpoint with index i.
lldb::BreakpointLocationSP GetLocationAtIndex(size_t index, bool use_facade=true)
Get breakpoint locations by index.
virtual llvm::StringRef GetBroadcasterClass() const
This needs to be filled in if you are going to register the broadcaster with the broadcaster manager ...
static bool InvokeCommonCompletionCallbacks(CommandInterpreter &interpreter, uint32_t completion_mask, lldb_private::CompletionRequest &request, SearchFilter *searcher)
const FileSpec & GetPrimaryFile() const
Return the primary source spec associated with this compile unit.
void GetMatches(StringList &matches) const
Adds all collected completion matches to the given list.
const char * GetCString() const
Get the string value as a C string.
const char * AsCString(const char *value_if_empty) const
Get the string value as a C string.
A class to manage flag bits.
void CancelForwardEvents(const lldb::ListenerSP &listener_sp)
void EnableForwardEvents(const lldb::ListenerSP &listener_sp)
PlatformList & GetPlatformList()
std::pair< iterator, bool > insert(llvm::StringRef KeyEqValue)
void SetFrameSP(const lldb::StackFrameSP &frame_sp)
Set accessor to set only the frame shared pointer.
bool HasThreadScope() const
Returns true the ExecutionContext object contains a valid target, process, and thread.
bool HasProcessScope() const
Returns true the ExecutionContext object contains a valid target and process.
StackFrame * GetFramePtr() const
Returns a pointer to the frame object.
Process & GetProcessRef() const
Returns a reference to the process object.
Target * GetTargetPtr() const
Returns a pointer to the target object.
bool HasTargetScope() const
Returns true the ExecutionContext object contains a valid target.
Target & GetTargetRef() const
Returns a reference to the target object.
Process * GetProcessPtr() const
Returns a pointer to the process object.
Thread & GetThreadRef() const
Returns a reference to the thread object.
Thread * GetThreadPtr() const
Returns a pointer to the thread object.
bool Open(int fd, const FileSpec &file_spec, bool read, bool write)
Configure this action to open a file.
void SetFile(llvm::StringRef path, Style style)
Change the file specified with a new path.
llvm::StringRef GetFilename() const
Filename string const get accessor.
llvm::StringRef GetDirectory() const
Directory string const get accessor.
void SetDirectory(llvm::StringRef directory)
Directory string set accessor.
static FileSystem & Instance()
void Resolve(llvm::SmallVectorImpl< char > &path, bool force_make_absolute=false)
Resolve path to make it canonical.
ValueType Clear(ValueType mask=~static_cast< ValueType >(0))
Clear one or more flags.
ValueType Set(ValueType mask)
Set one or more flags by logical OR'ing mask with the current flags.
ConstString GetName() const
IOHandlerCursesGUI(Debugger &debugger)
std::unique_ptr< curses::Application > m_app_up
void Deactivate() override
~IOHandlerCursesGUI() override
bool Interrupt() override
void TerminalSizeChanged() override
lldb::LockableStreamFileSP m_output_sp
uint32_t GetIndexOfInstructionAtAddress(const Address &addr)
lldb::InstructionSP GetInstructionAtIndex(size_t idx) const
const Address & GetAddress() const
const char * GetMnemonic(const ExecutionContext *exe_ctx, bool markup=false)
const char * GetComment(const ExecutionContext *exe_ctx)
const char * GetOperands(const ExecutionContext *exe_ctx, bool markup=false)
static lldb::ListenerSP MakeListener(llvm::StringRef name)
static llvm::StringRef GetPlatformPluginNameAtIndex(uint32_t idx)
static llvm::StringRef GetProcessPluginNameAtIndex(uint32_t idx)
void SetContinueOnceAttached(bool b)
void SetWaitForLaunch(bool b)
void SetProcessPluginName(llvm::StringRef plugin)
bool GetContinueOnceAttached() const
void SetIgnoreExisting(bool b)
void SetExecutableFile(const FileSpec &exe_file, bool add_exe_file_as_first_arg)
void SetProcessID(lldb::pid_t pid)
FileSpec & GetExecutableFile()
Environment & GetEnvironment()
ArchSpec & GetArchitecture()
void AppendFileAction(const FileActionImpl &info)
void SetShell(const FileSpec &shell)
void SetProcessPluginName(llvm::StringRef plugin)
void SetShellExpandArguments(bool expand)
void SetWorkingDirectory(const FileSpec &working_dir)
lldb::pid_t GetID() const
Returns the pid of the process or LLDB_INVALID_PROCESS_ID if there is no known pid.
Status Destroy(bool force_kill)
Kills the process and shuts down all threads that were spawned to track and monitor the process.
ThreadList & GetThreadList()
Status Resume()
Resumes all of a process's threads as configured using the Thread run control functions.
int GetExitStatus()
Get the exit status for a process.
Status Detach(bool keep_stopped)
Detaches from a running or stopped process.
lldb::StateType GetState()
Get accessor for the current process state.
const char * GetExitDescription()
Get a textual description of what the process exited.
static llvm::StringRef GetStaticBroadcasterClass()
virtual bool IsAlive()
Check if a process is still alive.
uint32_t GetStopID() const
Status Halt(bool clear_thread_plans=false, bool use_run_lock=true)
Halts a running process.
std::shared_ptr< File > FileSP
virtual lldb::RegisterContextSP GetRegisterContext()
Get the RegisterContext for this frame, if possible.
virtual StackID & GetStackID()
virtual lldb::ValueObjectSP GetValueObjectForFrameVariable(const lldb::VariableSP &variable_sp, lldb::DynamicValueType use_dynamic)
Create a ValueObject for a given Variable in this StackFrame.
virtual VariableList * GetVariableList(bool get_file_globals, bool include_synthetic_vars, Status *error_ptr)
Retrieve the list of variables whose scope either:
virtual uint32_t GetFrameIndex() const
Query this frame to find what frame it is in this Thread's StackFrameList.
virtual Block * GetFrameBlock()
Get the current lexical scope block for this StackFrame, if possible.
virtual const Address & GetFrameCodeAddress()
Get an Address for the current pc value in this StackFrame.
bool Fail() const
Test for error condition.
const char * AsCString(const char *default_error_str="unknown error") const
Get the error string associated with the current error.
const char * GetData() const
llvm::StringRef GetString() const
void Format(const char *format, Args &&... args)
Forwards the arguments to llvm::formatv and writes to the stream.
llvm::raw_ostream & AsRawOstream()
Returns a raw_ostream that forwards the data to this Stream object.
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
size_t size_t PrintfVarArg(const char *format, va_list args)
void AppendString(const std::string &s)
const char * GetStringAtIndex(size_t idx) const
Function * function
The Function for a given query.
lldb::ModuleSP module_sp
The Module for a given query.
CompileUnit * comp_unit
The CompileUnit for a given query.
Symbol * symbol
The Symbol for a given query.
LineEntry line_entry
The LineEntry for a given query.
ConstString GetName() const
BreakpointList & GetBreakpointList(bool internal=false)
const lldb::ProcessSP & GetProcessSP() const
bool RemoveBreakpointByID(lldb::break_id_t break_id)
Status Launch(ProcessLaunchInfo &launch_info, Stream *stream)
lldb::ModuleSP GetExecutableModule()
Gets the module for the main executable.
lldb::BreakpointSP CreateBreakpoint(const FileSpecList *containingModules, const FileSpec &file, uint32_t line_no, uint32_t column, lldb::addr_t offset, LazyBool check_inlines, LazyBool skip_prologue, bool internal, bool request_hardware, LazyBool move_to_nearest_code)
Status Attach(ProcessAttachInfo &attach_info, Stream *stream)
lldb::ThreadSP GetSelectedThread()
uint32_t GetSize(bool can_update=true)
bool SetSelectedThreadByID(lldb::tid_t tid, bool notify=false)
lldb::ThreadSP GetThreadAtIndex(uint32_t idx, bool can_update=true)
std::recursive_mutex & GetMutex() const override
virtual lldb::StackFrameSP GetStackFrameAtIndex(uint32_t idx)
uint32_t GetIndexID() const
lldb::StackFrameSP GetSelectedFrame(SelectMostRelevant select_most_relevant)
virtual Status StepOver(bool source_step, LazyBool step_out_avoids_code_without_debug_info=eLazyBoolCalculate)
Default implementation for stepping over.
uint32_t GetSelectedFrameIndex(SelectMostRelevant select_most_relevant)
lldb::ProcessSP GetProcess() const
virtual Status StepOut(uint32_t frame_idx=0)
Default implementation for stepping out.
bool SetSelectedFrameByIndex(uint32_t frame_idx, bool broadcast=false)
lldb::StopInfoSP GetStopInfo()
virtual uint32_t GetStackFrameCount()
GetStackFrameCount can be expensive.
virtual Status StepIn(bool source_step, LazyBool step_in_avoids_code_without_debug_info=eLazyBoolCalculate, LazyBool step_out_avoids_code_without_debug_info=eLazyBoolCalculate)
Default implementation for stepping into.
const std::vector< lldb::ValueObjectSP > & GetObjects() const
void Append(const lldb::ValueObjectSP &val_obj_sp)
static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope, lldb::RegisterContextSP ®_ctx_sp, uint32_t set_idx)
lldb::ProcessSP GetProcessSP() const
lldb::ValueObjectSP GetSP()
Gets the correct value object from the root object for a given process stop ID.
virtual ConstString GetTypeName()
virtual const char * GetValueAsCString()
ConstString GetName() const
const char * GetSummaryAsCString(lldb::LanguageType lang=lldb::eLanguageTypeUnknown)
#define LLDB_INVALID_THREAD_ID
#define UNUSED_IF_ASSERT_DISABLED(x)
@ SelectMostRelevantFrame
A class that represents a running process on the host machine.
bool operator!=(const Address &lhs, const Address &rhs)
bool StateIsStoppedState(lldb::StateType state, bool must_exist)
Check if a state represents a state where the process or thread is stopped.
bool StateIsRunningState(lldb::StateType state)
Check if a state represents a state where the process or thread is running.
const char * StateAsCString(lldb::StateType state)
Converts a StateType to a C string.
bool operator==(const Address &lhs, const Address &rhs)
std::shared_ptr< lldb_private::StackFrame > StackFrameSP
std::shared_ptr< lldb_private::BreakpointSite > BreakpointSiteSP
std::shared_ptr< lldb_private::BreakpointLocation > BreakpointLocationSP
std::shared_ptr< lldb_private::Thread > ThreadSP
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
Format
Display format definitions.
@ eFormatCString
Null-terminated C strings.
@ eFormatInstruction
Disassemble an opcode.
@ eFormatAddressInfo
Describe what an address points to (func + offset with file/line, symbol + offset,...
std::shared_ptr< lldb_private::Platform > PlatformSP
StateType
Process and Thread States.
@ eStateExited
Process has exited and can't be examined.
std::shared_ptr< lldb_private::Breakpoint > BreakpointSP
std::shared_ptr< lldb_private::Process > ProcessSP
std::shared_ptr< lldb_private::Disassembler > DisassemblerSP
std::shared_ptr< lldb_private::Event > EventSP
std::shared_ptr< lldb_private::Listener > ListenerSP
std::shared_ptr< lldb_private::Variable > VariableSP
std::shared_ptr< lldb_private::StopInfo > StopInfoSP
std::shared_ptr< lldb_private::Target > TargetSP
std::shared_ptr< lldb_private::RegisterContext > RegisterContextSP
std::shared_ptr< lldb_private::Module > ModuleSP
uint32_t line
The source line number, or LLDB_INVALID_LINE_NUMBER if there is no line number information.
bool DumpStopContext(Stream *s, bool show_fullpaths) const
Dumps information specific to a process that stops at this line entry to the supplied stream s.
const FileSpec & GetFile() const
Helper to access the file.
lldb::user_id_t GetID() const
Get accessor for the user ID.