10#include "lldb/Host/Config.h"
13#if CURSES_HAVE_NCURSES_CURSES_H
14#include <ncurses/curses.h>
15#include <ncurses/panel.h>
62#include "llvm/ADT/StringRef.h"
95#define KEY_SHIFT_TAB (KEY_MAX + 1)
96#define KEY_ALT_ENTER (KEY_MAX + 2)
104typedef std::shared_ptr<Menu> MenuSP;
105typedef std::shared_ptr<MenuDelegate> MenuDelegateSP;
106typedef std::shared_ptr<Window> WindowSP;
107typedef std::shared_ptr<WindowDelegate> WindowDelegateSP;
108typedef std::vector<MenuSP> Menus;
109typedef std::vector<WindowSP> Windows;
110typedef std::vector<WindowDelegateSP> WindowDelegates;
113type summary add -s
"x=${var.x}, y=${var.y}" curses::Point
114type summary add -s
"w=${var.width}, h=${var.height}" curses::Size
115type summary add -s
"${var.origin%S} ${var.size%S}" curses::Rect
122 Point(
int _x = 0,
int _y = 0) : x(_x), y(_y) {}
129 Point &operator+=(
const Point &rhs) {
135 void Dump() { printf(
"(x=%i, y=%i)\n", x, y); }
138bool operator==(
const Point &lhs,
const Point &rhs) {
139 return lhs.x == rhs.x && lhs.y == rhs.y;
142bool operator!=(
const Point &lhs,
const Point &rhs) {
143 return lhs.x != rhs.x || lhs.y != rhs.y;
149 Size(
int w = 0,
int h = 0) : width(w), height(h) {}
156 void Dump() { printf(
"(w=%i, h=%i)\n", width, height); }
159bool operator==(
const Size &lhs,
const Size &rhs) {
160 return lhs.width == rhs.width && lhs.height == rhs.height;
163bool operator!=(
const Size &lhs,
const Size &rhs) {
164 return lhs.width != rhs.width || lhs.height != rhs.height;
171 Rect() : origin(), size() {}
173 Rect(
const Point &p,
const Size &s) : origin(p), size(s) {}
181 printf(
"(x=%i, y=%i), w=%i, h=%i)\n", origin.x, origin.y, size.width,
185 void Inset(
int w,
int h) {
186 if (size.width > w * 2)
190 if (size.height > h * 2)
191 size.height -= h * 2;
197 Rect MakeStatusBar() {
199 if (size.height > 1) {
200 status_bar.origin.x = origin.x;
201 status_bar.origin.y = size.height;
202 status_bar.size.width = size.width;
203 status_bar.size.height = 1;
213 if (size.height > 1) {
214 menubar.origin.x = origin.x;
215 menubar.origin.y = origin.y;
216 menubar.size.width = size.width;
217 menubar.size.height = 1;
224 void HorizontalSplitPercentage(
float top_percentage, Rect &top,
225 Rect &bottom)
const {
226 float top_height = top_percentage * size.height;
227 HorizontalSplit(top_height, top, bottom);
230 void HorizontalSplit(
int top_height, Rect &top, Rect &bottom)
const {
232 if (top_height < size.height) {
233 top.size.height = top_height;
234 bottom.origin.x = origin.x;
235 bottom.origin.y = origin.y + top.size.height;
236 bottom.size.width = size.width;
237 bottom.size.height = size.height - top.size.height;
243 void VerticalSplitPercentage(
float left_percentage, Rect &left,
245 float left_width = left_percentage * size.width;
246 VerticalSplit(left_width, left, right);
249 void VerticalSplit(
int left_width, Rect &left, Rect &right)
const {
251 if (left_width < size.width) {
252 left.size.width = left_width;
253 right.origin.x = origin.x + left.size.width;
254 right.origin.y = origin.y;
255 right.size.width = size.width - left.size.width;
256 right.size.height = size.height;
263bool operator==(
const Rect &lhs,
const Rect &rhs) {
264 return lhs.origin == rhs.origin && lhs.size == rhs.size;
267bool operator!=(
const Rect &lhs,
const Rect &rhs) {
268 return lhs.origin != rhs.origin || lhs.size != rhs.size;
271enum HandleCharResult {
277enum class MenuActionResult {
285 const char *description;
311 LastColorPairIndex = MagentaOnWhite
314class WindowDelegate {
316 virtual ~WindowDelegate() =
default;
318 virtual bool WindowDelegateDraw(Window &window,
bool force) {
322 virtual HandleCharResult WindowDelegateHandleChar(Window &window,
int key) {
323 return eKeyNotHandled;
326 virtual const char *WindowDelegateGetHelpText() {
return nullptr; }
328 virtual KeyHelp *WindowDelegateGetKeyHelp() {
return nullptr; }
331class HelpDialogDelegate :
public WindowDelegate {
333 HelpDialogDelegate(
const char *text, KeyHelp *key_help_array);
335 ~HelpDialogDelegate()
override;
337 bool WindowDelegateDraw(Window &window,
bool force)
override;
339 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override;
341 size_t GetNumLines()
const {
return m_text.GetSize(); }
343 size_t GetMaxLineLength()
const {
return m_text.GetMaxStringLength(); }
347 int m_first_visible_line = 0;
356 enum class Type { Window, Pad };
358 Surface(Surface::Type type) : m_type(type) {}
360 WINDOW *get() {
return m_window; }
362 operator WINDOW *() {
return m_window; }
364 Surface SubSurface(Rect bounds) {
365 Surface subSurface(m_type);
366 if (m_type == Type::Pad)
367 subSurface.m_window =
368 ::subpad(m_window, bounds.size.height, bounds.size.width,
369 bounds.origin.y, bounds.origin.x);
371 subSurface.m_window =
372 ::derwin(m_window, bounds.size.height, bounds.size.width,
373 bounds.origin.y, bounds.origin.x);
378 void CopyToSurface(Surface &target, Point source_origin, Point target_origin,
380 ::copywin(m_window, target.get(), source_origin.y, source_origin.x,
381 target_origin.y, target_origin.x,
382 target_origin.y + size.height - 1,
383 target_origin.x + size.width - 1,
false);
386 int GetCursorX()
const {
return getcurx(m_window); }
387 int GetCursorY()
const {
return getcury(m_window); }
388 void MoveCursor(
int x,
int y) { ::wmove(m_window, y, x); }
390 void AttributeOn(attr_t attr) { ::wattron(m_window, attr); }
391 void AttributeOff(attr_t attr) { ::wattroff(m_window, attr); }
393 int GetMaxX()
const {
return getmaxx(m_window); }
394 int GetMaxY()
const {
return getmaxy(m_window); }
395 int GetWidth()
const {
return GetMaxX(); }
396 int GetHeight()
const {
return GetMaxY(); }
397 Size GetSize()
const {
return Size(GetWidth(), GetHeight()); }
399 Rect GetFrame()
const {
return Rect(Point(), GetSize()); }
401 void Clear() { ::wclear(m_window); }
402 void Erase() { ::werase(m_window); }
404 void SetBackground(
int color_pair_idx) {
405 ::wbkgd(m_window, COLOR_PAIR(color_pair_idx));
408 void PutChar(
int ch) { ::waddch(m_window, ch); }
409 void PutCString(
const char *s,
int len = -1) { ::waddnstr(m_window, s, len); }
411 void PutCStringTruncated(
int right_pad,
const char *s,
int len = -1) {
412 int bytes_left = GetWidth() - GetCursorX();
413 if (bytes_left > right_pad) {
414 bytes_left -= right_pad;
415 ::waddnstr(m_window, s, len < 0 ? bytes_left : std::min(bytes_left, len));
419 void Printf(
const char *format, ...) __attribute__((format(printf, 2, 3))) {
421 va_start(args, format);
422 vw_printw(m_window, format, args);
426 void PrintfTruncated(
int right_pad,
const char *format, ...)
427 __attribute__((format(printf, 3, 4))) {
429 va_start(args, format);
433 PutCStringTruncated(right_pad, strm.
GetData());
436 void VerticalLine(
int n, chtype v_char = ACS_VLINE) {
437 ::wvline(m_window, v_char, n);
439 void HorizontalLine(
int n, chtype h_char = ACS_HLINE) {
440 ::whline(m_window, h_char, n);
442 void Box(chtype v_char = ACS_VLINE, chtype h_char = ACS_HLINE) {
443 ::box(m_window, v_char, h_char);
446 void TitledBox(
const char *title, chtype v_char = ACS_VLINE,
447 chtype h_char = ACS_HLINE) {
449 int title_offset = 2;
450 MoveCursor(title_offset, 0);
452 PutCString(title, GetWidth() - title_offset);
456 void Box(
const Rect &bounds, chtype v_char = ACS_VLINE,
457 chtype h_char = ACS_HLINE) {
458 MoveCursor(bounds.origin.x, bounds.origin.y);
459 VerticalLine(bounds.size.height);
460 HorizontalLine(bounds.size.width);
461 PutChar(ACS_ULCORNER);
463 MoveCursor(bounds.origin.x + bounds.size.width - 1, bounds.origin.y);
464 VerticalLine(bounds.size.height);
465 PutChar(ACS_URCORNER);
467 MoveCursor(bounds.origin.x, bounds.origin.y + bounds.size.height - 1);
468 HorizontalLine(bounds.size.width);
469 PutChar(ACS_LLCORNER);
471 MoveCursor(bounds.origin.x + bounds.size.width - 1,
472 bounds.origin.y + bounds.size.height - 1);
473 PutChar(ACS_LRCORNER);
476 void TitledBox(
const Rect &bounds,
const char *title,
477 chtype v_char = ACS_VLINE, chtype h_char = ACS_HLINE) {
478 Box(bounds, v_char, h_char);
479 int title_offset = 2;
480 MoveCursor(bounds.origin.x + title_offset, bounds.origin.y);
482 PutCString(title, bounds.size.width - title_offset);
491 bool OutputColoredStringTruncated(
int right_pad, StringRef
string,
492 size_t skip_first_count,
493 bool use_blue_background) {
497 wattr_get(m_window, &saved_attr, &saved_pair,
nullptr);
498 if (use_blue_background)
499 ::wattron(m_window, COLOR_PAIR(WhiteOnBlue));
500 while (!
string.empty()) {
502 if (esc_pos == StringRef::npos) {
503 string =
string.substr(skip_first_count);
504 if (!
string.empty()) {
505 PutCStringTruncated(right_pad,
string.data(),
string.size());
511 if (skip_first_count > 0) {
512 int skip = std::min(esc_pos, skip_first_count);
513 string =
string.substr(skip);
514 skip_first_count -= skip;
518 PutCStringTruncated(right_pad,
string.data(), esc_pos);
520 string =
string.drop_front(esc_pos);
532 if (!!
string.consumeInteger(10, value) ||
535 llvm::errs() <<
"No valid color code in color escape sequence.\n";
540 <<
"' in color escape sequence.\n";
544 wattr_set(m_window, saved_attr, saved_pair,
nullptr);
545 if (use_blue_background)
546 ::wattron(m_window, COLOR_PAIR(WhiteOnBlue));
548 ::wattron(m_window, A_UNDERLINE);
552 (use_blue_background ? 8 : 0)));
555 wattr_set(m_window, saved_attr, saved_pair,
nullptr);
561 WINDOW *m_window =
nullptr;
564class Pad :
public Surface {
566 Pad(Size size) : Surface(Surface::
Type::Pad) {
567 m_window = ::newpad(size.height, size.width);
570 ~Pad() { ::delwin(m_window); }
573class Window :
public Surface {
575 Window(
const char *name)
576 : Surface(Surface::
Type::Window), m_name(name), m_panel(nullptr),
577 m_parent(nullptr), m_subwindows(), m_delegate_sp(),
579 m_prev_active_window_idx(
UINT32_MAX), m_delete(false),
580 m_needs_update(true), m_can_activate(true), m_is_subwin(false) {}
582 Window(
const char *name, WINDOW *w,
bool del =
true)
583 : Surface(Surface::
Type::Window), m_name(name), m_panel(nullptr),
584 m_parent(nullptr), m_subwindows(), m_delegate_sp(),
586 m_prev_active_window_idx(
UINT32_MAX), m_delete(del),
587 m_needs_update(true), m_can_activate(true), m_is_subwin(false) {
592 Window(
const char *name,
const Rect &bounds)
593 : Surface(Surface::
Type::Window), m_name(name), m_panel(nullptr),
594 m_parent(nullptr), m_subwindows(), m_delegate_sp(),
596 m_prev_active_window_idx(
UINT32_MAX), m_delete(false),
597 m_needs_update(true), m_can_activate(true), m_is_subwin(false) {
598 Reset(::newwin(bounds.size.height, bounds.size.width, bounds.origin.y,
607 void Reset(WINDOW *w =
nullptr,
bool del =
true) {
612 ::del_panel(m_panel);
615 if (m_window && m_delete) {
622 m_panel = ::new_panel(m_window);
628 Rect GetBounds()
const {
return Rect(GetParentOrigin(), GetSize()); }
630 Rect GetCenteredRect(
int width,
int height) {
631 Size size = GetSize();
632 width = std::min(size.width, width);
633 height = std::min(size.height, height);
634 int x = (size.width - width) / 2;
635 int y = (size.height - height) / 2;
636 return Rect(Point(x, y), Size(width, height));
639 int GetChar() { return ::wgetch(m_window); }
640 Point GetParentOrigin()
const {
return Point(GetParentX(), GetParentY()); }
641 int GetParentX()
const {
return getparx(m_window); }
642 int GetParentY()
const {
return getpary(m_window); }
643 void MoveWindow(
int x,
int y) { MoveWindow(Point(x, y)); }
644 void Resize(
int w,
int h) { ::wresize(m_window, h, w); }
645 void Resize(
const Size &size) {
646 ::wresize(m_window, size.height, size.width);
648 void MoveWindow(
const Point &origin) {
649 const bool moving_window = origin != GetParentOrigin();
650 if (m_is_subwin && moving_window) {
652 Size size = GetSize();
653 Reset(::subwin(m_parent->m_window, size.height, size.width, origin.y,
657 ::mvwin(m_window, origin.y, origin.x);
661 void SetBounds(
const Rect &bounds) {
662 const bool moving_window = bounds.origin != GetParentOrigin();
663 if (m_is_subwin && moving_window) {
665 Reset(::subwin(m_parent->m_window, bounds.size.height, bounds.size.width,
666 bounds.origin.y, bounds.origin.x),
670 MoveWindow(bounds.origin);
676 ::touchwin(m_window);
681 WindowSP CreateSubWindow(
const char *name,
const Rect &bounds,
683 auto get_window = [
this, &bounds]() {
685 ? ::subwin(m_window, bounds.size.height, bounds.size.width,
686 bounds.origin.y, bounds.origin.x)
687 : ::newwin(bounds.size.height, bounds.size.width,
688 bounds.origin.y, bounds.origin.x);
690 WindowSP subwindow_sp = std::make_shared<Window>(name, get_window(),
true);
691 subwindow_sp->m_is_subwin = subwindow_sp.operator bool();
692 subwindow_sp->m_parent =
this;
694 m_prev_active_window_idx = m_curr_active_window_idx;
695 m_curr_active_window_idx = m_subwindows.size();
697 m_subwindows.push_back(subwindow_sp);
698 ::top_panel(subwindow_sp->m_panel);
699 m_needs_update =
true;
703 bool RemoveSubWindow(Window *window) {
704 Windows::iterator pos, end = m_subwindows.end();
706 for (pos = m_subwindows.begin(); pos != end; ++pos, ++i) {
707 if ((*pos).get() == window) {
708 if (m_prev_active_window_idx == i)
710 else if (m_prev_active_window_idx !=
UINT32_MAX &&
711 m_prev_active_window_idx > i)
712 --m_prev_active_window_idx;
714 if (m_curr_active_window_idx == i)
716 else if (m_curr_active_window_idx !=
UINT32_MAX &&
717 m_curr_active_window_idx > i)
718 --m_curr_active_window_idx;
720 m_subwindows.erase(pos);
721 m_needs_update =
true;
732 WindowSP FindSubWindow(
const char *name) {
733 Windows::iterator pos, end = m_subwindows.end();
735 for (pos = m_subwindows.begin(); pos != end; ++pos, ++i) {
736 if ((*pos)->m_name == name)
742 void RemoveSubWindows() {
745 for (Windows::iterator pos = m_subwindows.begin();
746 pos != m_subwindows.end(); pos = m_subwindows.erase(pos)) {
756 void DrawTitleBox(
const char *title,
const char *bottom_message =
nullptr) {
759 attr = A_BOLD | COLOR_PAIR(BlackOnWhite);
768 if (title && title[0]) {
774 if (bottom_message && bottom_message[0]) {
775 int bottom_message_length = strlen(bottom_message);
776 int x = GetWidth() - 3 - (bottom_message_length + 2);
779 MoveCursor(x, GetHeight() - 1);
781 PutCString(bottom_message);
784 MoveCursor(1, GetHeight() - 1);
786 PutCStringTruncated(1, bottom_message);
793 virtual void Draw(
bool force) {
794 if (m_delegate_sp && m_delegate_sp->WindowDelegateDraw(*
this, force))
797 for (
auto &subwindow_sp : m_subwindows)
798 subwindow_sp->Draw(force);
801 bool CreateHelpSubwindow() {
803 const char *text = m_delegate_sp->WindowDelegateGetHelpText();
804 KeyHelp *key_help = m_delegate_sp->WindowDelegateGetKeyHelp();
805 if ((text && text[0]) || key_help) {
806 std::unique_ptr<HelpDialogDelegate> help_delegate_up(
807 new HelpDialogDelegate(text, key_help));
808 const size_t num_lines = help_delegate_up->GetNumLines();
809 const size_t max_length = help_delegate_up->GetMaxLineLength();
810 Rect bounds = GetBounds();
812 if (max_length + 4 <
static_cast<size_t>(bounds.size.width)) {
813 bounds.origin.x += (bounds.size.width - max_length + 4) / 2;
814 bounds.size.width = max_length + 4;
816 if (bounds.size.width > 100) {
817 const int inset_w = bounds.size.width / 4;
818 bounds.origin.x += inset_w;
819 bounds.size.width -= 2 * inset_w;
823 if (num_lines + 2 <
static_cast<size_t>(bounds.size.height)) {
824 bounds.origin.y += (bounds.size.height - num_lines + 2) / 2;
825 bounds.size.height = num_lines + 2;
827 if (bounds.size.height > 100) {
828 const int inset_h = bounds.size.height / 4;
829 bounds.origin.y += inset_h;
830 bounds.size.height -= 2 * inset_h;
833 WindowSP help_window_sp;
834 Window *parent_window = GetParent();
836 help_window_sp = parent_window->CreateSubWindow(
"Help", bounds,
true);
838 help_window_sp = CreateSubWindow(
"Help", bounds,
true);
839 help_window_sp->SetDelegate(
840 WindowDelegateSP(help_delegate_up.release()));
847 virtual HandleCharResult HandleChar(
int key) {
849 HandleCharResult result = eKeyNotHandled;
850 WindowSP active_window_sp = GetActiveWindow();
851 if (active_window_sp) {
852 result = active_window_sp->HandleChar(key);
853 if (result != eKeyNotHandled)
858 result = m_delegate_sp->WindowDelegateHandleChar(*
this, key);
859 if (result != eKeyNotHandled)
867 Windows subwindows(m_subwindows);
868 for (
auto subwindow_sp : subwindows) {
869 if (!subwindow_sp->m_can_activate) {
870 HandleCharResult result = subwindow_sp->HandleChar(key);
871 if (result != eKeyNotHandled)
876 return eKeyNotHandled;
879 WindowSP GetActiveWindow() {
880 if (!m_subwindows.empty()) {
881 if (m_curr_active_window_idx >= m_subwindows.size()) {
882 if (m_prev_active_window_idx < m_subwindows.size()) {
883 m_curr_active_window_idx = m_prev_active_window_idx;
885 }
else if (IsActive()) {
890 const size_t num_subwindows = m_subwindows.size();
891 for (
size_t i = 0; i < num_subwindows; ++i) {
892 if (m_subwindows[i]->GetCanBeActive()) {
893 m_curr_active_window_idx = i;
900 if (m_curr_active_window_idx < m_subwindows.size())
901 return m_subwindows[m_curr_active_window_idx];
906 bool GetCanBeActive()
const {
return m_can_activate; }
908 void SetCanBeActive(
bool b) { m_can_activate = b; }
910 void SetDelegate(
const WindowDelegateSP &delegate_sp) {
911 m_delegate_sp = delegate_sp;
914 Window *GetParent()
const {
return m_parent; }
916 bool IsActive()
const {
918 return m_parent->GetActiveWindow().get() ==
this;
923 void SelectNextWindowAsActive() {
925 const int num_subwindows = m_subwindows.size();
928 m_prev_active_window_idx = m_curr_active_window_idx;
929 start_idx = m_curr_active_window_idx + 1;
931 for (
int idx = start_idx; idx < num_subwindows; ++idx) {
932 if (m_subwindows[idx]->GetCanBeActive()) {
933 m_curr_active_window_idx = idx;
937 for (
int idx = 0; idx < start_idx; ++idx) {
938 if (m_subwindows[idx]->GetCanBeActive()) {
939 m_curr_active_window_idx = idx;
945 void SelectPreviousWindowAsActive() {
947 const int num_subwindows = m_subwindows.size();
948 int start_idx = num_subwindows - 1;
950 m_prev_active_window_idx = m_curr_active_window_idx;
951 start_idx = m_curr_active_window_idx - 1;
953 for (
int idx = start_idx; idx >= 0; --idx) {
954 if (m_subwindows[idx]->GetCanBeActive()) {
955 m_curr_active_window_idx = idx;
959 for (
int idx = num_subwindows - 1; idx > start_idx; --idx) {
960 if (m_subwindows[idx]->GetCanBeActive()) {
961 m_curr_active_window_idx = idx;
967 const char *
GetName()
const {
return m_name.c_str(); }
973 Windows m_subwindows;
974 WindowDelegateSP m_delegate_sp;
975 uint32_t m_curr_active_window_idx;
976 uint32_t m_prev_active_window_idx;
983 Window(
const Window &) =
delete;
984 const Window &operator=(
const Window &) =
delete;
995struct ScrollContext {
999 ScrollContext(
int line) : start(line), end(line) {}
1000 ScrollContext(
int _start,
int _end) : start(_start), end(_end) {}
1002 void Offset(
int offset) {
1008class FieldDelegate {
1010 virtual ~FieldDelegate() =
default;
1014 virtual int FieldDelegateGetHeight() = 0;
1021 virtual ScrollContext FieldDelegateGetScrollContext() {
1022 return ScrollContext(0, FieldDelegateGetHeight() - 1);
1028 virtual void FieldDelegateDraw(Surface &surface,
bool is_selected) = 0;
1031 virtual HandleCharResult FieldDelegateHandleChar(
int key) {
1032 return eKeyNotHandled;
1039 virtual void FieldDelegateExitCallback() {}
1053 virtual bool FieldDelegateOnFirstOrOnlyElement() {
return true; }
1057 virtual bool FieldDelegateOnLastOrOnlyElement() {
return true; }
1060 virtual void FieldDelegateSelectFirstElement() {}
1063 virtual void FieldDelegateSelectLastElement() {}
1066 virtual bool FieldDelegateHasError() {
return false; }
1068 bool FieldDelegateIsVisible() {
return m_is_visible; }
1070 void FieldDelegateHide() { m_is_visible =
false; }
1072 void FieldDelegateShow() { m_is_visible =
true; }
1075 bool m_is_visible =
true;
1078typedef std::unique_ptr<FieldDelegate> FieldDelegateUP;
1080class TextFieldDelegate :
public FieldDelegate {
1082 TextFieldDelegate(
const char *label,
const char *content,
bool required)
1083 : m_label(label), m_required(required) {
1085 m_content = content;
1098 int GetFieldHeight() {
return 3; }
1102 int FieldDelegateGetHeight()
override {
1103 int height = GetFieldHeight();
1104 if (FieldDelegateHasError())
1110 int GetCursorXPosition() {
return m_cursor_position - m_first_visibile_char; }
1112 int GetContentLength() {
return m_content.length(); }
1114 void DrawContent(Surface &surface,
bool is_selected) {
1115 UpdateScrolling(surface.GetWidth());
1117 surface.MoveCursor(0, 0);
1118 const char *text = m_content.c_str() + m_first_visibile_char;
1119 surface.PutCString(text, surface.GetWidth());
1122 surface.MoveCursor(GetCursorXPosition(), 0);
1124 surface.AttributeOn(A_REVERSE);
1125 if (m_cursor_position == GetContentLength())
1127 surface.PutChar(
' ');
1129 surface.PutChar(m_content[m_cursor_position]);
1131 surface.AttributeOff(A_REVERSE);
1134 void DrawField(Surface &surface,
bool is_selected) {
1135 surface.TitledBox(m_label.c_str());
1137 Rect content_bounds = surface.GetFrame();
1138 content_bounds.Inset(1, 1);
1139 Surface content_surface = surface.SubSurface(content_bounds);
1141 DrawContent(content_surface, is_selected);
1144 void DrawError(Surface &surface) {
1145 if (!FieldDelegateHasError())
1147 surface.MoveCursor(0, 0);
1148 surface.AttributeOn(COLOR_PAIR(RedOnBlack));
1149 surface.PutChar(ACS_DIAMOND);
1150 surface.PutChar(
' ');
1151 surface.PutCStringTruncated(1, GetError().c_str());
1152 surface.AttributeOff(COLOR_PAIR(RedOnBlack));
1155 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
1156 Rect frame = surface.GetFrame();
1157 Rect field_bounds, error_bounds;
1158 frame.HorizontalSplit(GetFieldHeight(), field_bounds, error_bounds);
1159 Surface field_surface = surface.SubSurface(field_bounds);
1160 Surface error_surface = surface.SubSurface(error_bounds);
1162 DrawField(field_surface, is_selected);
1163 DrawError(error_surface);
1167 int GetLastVisibleCharPosition(
int width) {
1168 int position = m_first_visibile_char + width - 1;
1169 return std::min(position, GetContentLength());
1172 void UpdateScrolling(
int width) {
1173 if (m_cursor_position < m_first_visibile_char) {
1174 m_first_visibile_char = m_cursor_position;
1178 if (m_cursor_position > GetLastVisibleCharPosition(width))
1179 m_first_visibile_char = m_cursor_position - (width - 1);
1184 void MoveCursorRight() {
1185 if (m_cursor_position < GetContentLength())
1186 m_cursor_position++;
1189 void MoveCursorLeft() {
1190 if (m_cursor_position > 0)
1191 m_cursor_position--;
1194 void MoveCursorToStart() { m_cursor_position = 0; }
1196 void MoveCursorToEnd() { m_cursor_position = GetContentLength(); }
1199 if (m_first_visibile_char > 0)
1200 m_first_visibile_char--;
1205 void InsertChar(
char character) {
1206 m_content.insert(m_cursor_position, 1, character);
1207 m_cursor_position++;
1213 void RemovePreviousChar() {
1214 if (m_cursor_position == 0)
1217 m_content.erase(m_cursor_position - 1, 1);
1218 m_cursor_position--;
1224 void RemoveNextChar() {
1225 if (m_cursor_position == GetContentLength())
1228 m_content.erase(m_cursor_position, 1);
1234 m_content.erase(m_cursor_position);
1240 m_cursor_position = 0;
1246 virtual bool IsAcceptableChar(
int key) {
1251 return isprint(key);
1254 HandleCharResult FieldDelegateHandleChar(
int key)
override {
1255 if (IsAcceptableChar(key)) {
1257 InsertChar((
char)key);
1264 MoveCursorToStart();
1280 RemovePreviousChar();
1296 return eKeyNotHandled;
1299 bool FieldDelegateHasError()
override {
return !m_error.empty(); }
1301 void FieldDelegateExitCallback()
override {
1302 if (!IsSpecified() && m_required)
1303 SetError(
"This field is required!");
1306 bool IsSpecified() {
return !m_content.empty(); }
1308 void ClearError() { m_error.clear(); }
1310 const std::string &GetError() {
return m_error; }
1312 void SetError(
const char *
error) { m_error =
error; }
1314 const std::string &GetText() {
return m_content; }
1316 void SetText(
const char *text) {
1317 if (text ==
nullptr) {
1325 std::string m_label;
1328 std::string m_content;
1331 int m_cursor_position = 0;
1333 int m_first_visibile_char = 0;
1335 std::string m_error;
1338class IntegerFieldDelegate :
public TextFieldDelegate {
1340 IntegerFieldDelegate(
const char *label,
int content,
bool required)
1341 : TextFieldDelegate(label, std::to_string(content).c_str(), required) {}
1344 bool IsAcceptableChar(
int key)
override {
return isdigit(key); }
1347 int GetInteger() {
return std::stoi(m_content); }
1350class FileFieldDelegate :
public TextFieldDelegate {
1352 FileFieldDelegate(
const char *label,
const char *content,
bool need_to_exist,
1354 : TextFieldDelegate(label, content, required),
1355 m_need_to_exist(need_to_exist) {}
1357 void FieldDelegateExitCallback()
override {
1358 TextFieldDelegate::FieldDelegateExitCallback();
1362 if (!m_need_to_exist)
1365 FileSpec file = GetResolvedFileSpec();
1367 SetError(
"File doesn't exist!");
1371 SetError(
"Not a file!");
1376 FileSpec GetFileSpec() {
1377 FileSpec file_spec(GetPath());
1381 FileSpec GetResolvedFileSpec() {
1382 FileSpec file_spec(GetPath());
1387 const std::string &GetPath() {
return m_content; }
1390 bool m_need_to_exist;
1393class DirectoryFieldDelegate :
public TextFieldDelegate {
1395 DirectoryFieldDelegate(
const char *label,
const char *content,
1396 bool need_to_exist,
bool required)
1397 : TextFieldDelegate(label, content, required),
1398 m_need_to_exist(need_to_exist) {}
1400 void FieldDelegateExitCallback()
override {
1401 TextFieldDelegate::FieldDelegateExitCallback();
1405 if (!m_need_to_exist)
1408 FileSpec file = GetResolvedFileSpec();
1410 SetError(
"Directory doesn't exist!");
1414 SetError(
"Not a directory!");
1419 FileSpec GetFileSpec() {
1420 FileSpec file_spec(GetPath());
1424 FileSpec GetResolvedFileSpec() {
1425 FileSpec file_spec(GetPath());
1430 const std::string &GetPath() {
return m_content; }
1433 bool m_need_to_exist;
1436class ArchFieldDelegate :
public TextFieldDelegate {
1438 ArchFieldDelegate(
const char *label,
const char *content,
bool required)
1439 : TextFieldDelegate(label, content, required) {}
1441 void FieldDelegateExitCallback()
override {
1442 TextFieldDelegate::FieldDelegateExitCallback();
1446 if (!GetArchSpec().IsValid())
1447 SetError(
"Not a valid arch!");
1450 const std::string &GetArchString() {
return m_content; }
1452 ArchSpec GetArchSpec() {
return ArchSpec(GetArchString()); }
1455class BooleanFieldDelegate :
public FieldDelegate {
1457 BooleanFieldDelegate(
const char *label,
bool content)
1458 : m_label(label), m_content(content) {}
1465 int FieldDelegateGetHeight()
override {
return 1; }
1467 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
1468 surface.MoveCursor(0, 0);
1469 surface.PutChar(
'[');
1471 surface.AttributeOn(A_REVERSE);
1472 surface.PutChar(m_content ? ACS_DIAMOND :
' ');
1474 surface.AttributeOff(A_REVERSE);
1475 surface.PutChar(
']');
1476 surface.PutChar(
' ');
1477 surface.PutCString(m_label.c_str());
1480 void ToggleContent() { m_content = !m_content; }
1482 void SetContentToTrue() { m_content =
true; }
1484 void SetContentToFalse() { m_content =
false; }
1486 HandleCharResult FieldDelegateHandleChar(
int key)
override {
1494 SetContentToFalse();
1505 return eKeyNotHandled;
1509 bool GetBoolean() {
return m_content; }
1512 std::string m_label;
1516class ChoicesFieldDelegate :
public FieldDelegate {
1518 ChoicesFieldDelegate(
const char *label,
int number_of_visible_choices,
1519 std::vector<std::string> choices)
1520 : m_label(label), m_number_of_visible_choices(number_of_visible_choices),
1521 m_choices(choices) {}
1535 int FieldDelegateGetHeight()
override {
1536 return m_number_of_visible_choices + 2;
1539 int GetNumberOfChoices() {
return m_choices.size(); }
1542 int GetLastVisibleChoice() {
1543 int index = m_first_visibile_choice + m_number_of_visible_choices;
1544 return std::min(index, GetNumberOfChoices()) - 1;
1547 void DrawContent(Surface &surface,
bool is_selected) {
1548 int choices_to_draw = GetLastVisibleChoice() - m_first_visibile_choice + 1;
1549 for (
int i = 0; i < choices_to_draw; i++) {
1550 surface.MoveCursor(0, i);
1551 int current_choice = m_first_visibile_choice + i;
1552 const char *text = m_choices[current_choice].c_str();
1553 bool highlight = is_selected && current_choice == m_choice;
1555 surface.AttributeOn(A_REVERSE);
1556 surface.PutChar(current_choice == m_choice ? ACS_DIAMOND :
' ');
1557 surface.PutCString(text);
1559 surface.AttributeOff(A_REVERSE);
1563 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
1566 surface.TitledBox(m_label.c_str());
1568 Rect content_bounds = surface.GetFrame();
1569 content_bounds.Inset(1, 1);
1570 Surface content_surface = surface.SubSurface(content_bounds);
1572 DrawContent(content_surface, is_selected);
1575 void SelectPrevious() {
1581 if (m_choice < GetNumberOfChoices() - 1)
1585 void UpdateScrolling() {
1586 if (m_choice > GetLastVisibleChoice()) {
1587 m_first_visibile_choice = m_choice - (m_number_of_visible_choices - 1);
1591 if (m_choice < m_first_visibile_choice)
1592 m_first_visibile_choice = m_choice;
1595 HandleCharResult FieldDelegateHandleChar(
int key)
override {
1606 return eKeyNotHandled;
1610 std::string GetChoiceContent() {
return m_choices[m_choice]; }
1613 int GetChoice() {
return m_choice; }
1615 void SetChoice(llvm::StringRef choice) {
1616 for (
int i = 0; i < GetNumberOfChoices(); i++) {
1617 if (choice == m_choices[i]) {
1625 std::string m_label;
1626 int m_number_of_visible_choices;
1627 std::vector<std::string> m_choices;
1631 int m_first_visibile_choice = 0;
1634class PlatformPluginFieldDelegate :
public ChoicesFieldDelegate {
1636 PlatformPluginFieldDelegate(Debugger &debugger)
1637 : ChoicesFieldDelegate(
"Platform Plugin", 3, GetPossiblePluginNames()) {
1640 SetChoice(platform_sp->GetPluginName());
1643 std::vector<std::string> GetPossiblePluginNames() {
1644 std::vector<std::string> names;
1646 for (llvm::StringRef name =
1649 names.push_back(name.str());
1653 std::string GetPluginName() {
1654 std::string plugin_name = GetChoiceContent();
1659class ProcessPluginFieldDelegate :
public ChoicesFieldDelegate {
1661 ProcessPluginFieldDelegate()
1662 : ChoicesFieldDelegate(
"Process Plugin", 3, GetPossiblePluginNames()) {}
1664 std::vector<std::string> GetPossiblePluginNames() {
1665 std::vector<std::string> names;
1666 names.push_back(
"<default>");
1671 names.push_back(name.str());
1675 std::string GetPluginName() {
1676 std::string plugin_name = GetChoiceContent();
1677 if (plugin_name ==
"<default>")
1683class LazyBooleanFieldDelegate :
public ChoicesFieldDelegate {
1685 LazyBooleanFieldDelegate(
const char *label,
const char *calculate_label)
1686 : ChoicesFieldDelegate(label, 3, GetPossibleOptions(calculate_label)) {}
1688 static constexpr const char *kNo =
"No";
1689 static constexpr const char *kYes =
"Yes";
1691 std::vector<std::string> GetPossibleOptions(
const char *calculate_label) {
1692 std::vector<std::string> options;
1693 options.push_back(calculate_label);
1694 options.push_back(kYes);
1695 options.push_back(kNo);
1700 std::string choice = GetChoiceContent();
1703 else if (choice == kYes)
1710template <
class T>
class ListFieldDelegate :
public FieldDelegate {
1712 ListFieldDelegate(
const char *label, T default_field)
1713 : m_label(label), m_default_field(default_field),
1714 m_selection_type(SelectionType::NewButton) {}
1719 enum class SelectionType { Field, RemoveButton, NewButton };
1735 int FieldDelegateGetHeight()
override {
1739 for (
int i = 0; i < GetNumberOfFields(); i++) {
1740 height += m_fields[i].FieldDelegateGetHeight();
1747 ScrollContext FieldDelegateGetScrollContext()
override {
1748 int height = FieldDelegateGetHeight();
1749 if (m_selection_type == SelectionType::NewButton)
1750 return ScrollContext(height - 2, height - 1);
1752 FieldDelegate &field = m_fields[m_selection_index];
1753 ScrollContext context = field.FieldDelegateGetScrollContext();
1757 for (
int i = 0; i < m_selection_index; i++) {
1758 offset += m_fields[i].FieldDelegateGetHeight();
1760 context.Offset(offset);
1764 if (context.start == 1)
1769 if (context.end == height - 3)
1775 void DrawRemoveButton(Surface &surface,
int highlight) {
1776 surface.MoveCursor(1, surface.GetHeight() / 2);
1778 surface.AttributeOn(A_REVERSE);
1779 surface.PutCString(
"[Remove]");
1781 surface.AttributeOff(A_REVERSE);
1784 void DrawFields(Surface &surface,
bool is_selected) {
1786 int width = surface.GetWidth();
1787 for (
int i = 0; i < GetNumberOfFields(); i++) {
1788 int height = m_fields[i].FieldDelegateGetHeight();
1789 Rect bounds = Rect(Point(0, line), Size(width, height));
1790 Rect field_bounds, remove_button_bounds;
1791 bounds.VerticalSplit(bounds.size.width -
sizeof(
" [Remove]"),
1792 field_bounds, remove_button_bounds);
1793 Surface field_surface = surface.SubSurface(field_bounds);
1794 Surface remove_button_surface = surface.SubSurface(remove_button_bounds);
1796 bool is_element_selected = m_selection_index == i && is_selected;
1797 bool is_field_selected =
1798 is_element_selected && m_selection_type == SelectionType::Field;
1799 bool is_remove_button_selected =
1800 is_element_selected &&
1801 m_selection_type == SelectionType::RemoveButton;
1802 m_fields[i].FieldDelegateDraw(field_surface, is_field_selected);
1803 DrawRemoveButton(remove_button_surface, is_remove_button_selected);
1809 void DrawNewButton(Surface &surface,
bool is_selected) {
1810 const char *button_text =
"[New]";
1811 int x = (surface.GetWidth() -
sizeof(button_text) - 1) / 2;
1812 surface.MoveCursor(x, 0);
1814 is_selected && m_selection_type == SelectionType::NewButton;
1816 surface.AttributeOn(A_REVERSE);
1817 surface.PutCString(button_text);
1819 surface.AttributeOff(A_REVERSE);
1822 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
1823 surface.TitledBox(m_label.c_str());
1825 Rect content_bounds = surface.GetFrame();
1826 content_bounds.Inset(1, 1);
1827 Rect fields_bounds, new_button_bounds;
1828 content_bounds.HorizontalSplit(content_bounds.size.height - 1,
1829 fields_bounds, new_button_bounds);
1830 Surface fields_surface = surface.SubSurface(fields_bounds);
1831 Surface new_button_surface = surface.SubSurface(new_button_bounds);
1833 DrawFields(fields_surface, is_selected);
1834 DrawNewButton(new_button_surface, is_selected);
1837 void AddNewField() {
1838 m_fields.push_back(m_default_field);
1839 m_selection_index = GetNumberOfFields() - 1;
1840 m_selection_type = SelectionType::Field;
1841 FieldDelegate &field = m_fields[m_selection_index];
1842 field.FieldDelegateSelectFirstElement();
1845 void RemoveField() {
1846 m_fields.erase(m_fields.begin() + m_selection_index);
1847 if (m_selection_index != 0)
1848 m_selection_index--;
1850 if (GetNumberOfFields() > 0) {
1851 m_selection_type = SelectionType::Field;
1852 FieldDelegate &field = m_fields[m_selection_index];
1853 field.FieldDelegateSelectFirstElement();
1855 m_selection_type = SelectionType::NewButton;
1858 HandleCharResult SelectNext(
int key) {
1859 if (m_selection_type == SelectionType::NewButton)
1860 return eKeyNotHandled;
1862 if (m_selection_type == SelectionType::RemoveButton) {
1863 if (m_selection_index == GetNumberOfFields() - 1) {
1864 m_selection_type = SelectionType::NewButton;
1867 m_selection_index++;
1868 m_selection_type = SelectionType::Field;
1869 FieldDelegate &next_field = m_fields[m_selection_index];
1870 next_field.FieldDelegateSelectFirstElement();
1874 FieldDelegate &field = m_fields[m_selection_index];
1875 if (!field.FieldDelegateOnLastOrOnlyElement()) {
1876 return field.FieldDelegateHandleChar(key);
1879 field.FieldDelegateExitCallback();
1881 m_selection_type = SelectionType::RemoveButton;
1885 HandleCharResult SelectPrevious(
int key) {
1886 if (FieldDelegateOnFirstOrOnlyElement())
1887 return eKeyNotHandled;
1889 if (m_selection_type == SelectionType::RemoveButton) {
1890 m_selection_type = SelectionType::Field;
1891 FieldDelegate &field = m_fields[m_selection_index];
1892 field.FieldDelegateSelectLastElement();
1896 if (m_selection_type == SelectionType::NewButton) {
1897 m_selection_type = SelectionType::RemoveButton;
1898 m_selection_index = GetNumberOfFields() - 1;
1902 FieldDelegate &field = m_fields[m_selection_index];
1903 if (!field.FieldDelegateOnFirstOrOnlyElement()) {
1904 return field.FieldDelegateHandleChar(key);
1907 field.FieldDelegateExitCallback();
1909 m_selection_type = SelectionType::RemoveButton;
1910 m_selection_index--;
1916 HandleCharResult SelectNextInList(
int key) {
1917 assert(m_selection_type == SelectionType::Field);
1919 FieldDelegate &field = m_fields[m_selection_index];
1920 if (field.FieldDelegateHandleChar(key) == eKeyHandled)
1923 if (!field.FieldDelegateOnLastOrOnlyElement())
1924 return eKeyNotHandled;
1926 field.FieldDelegateExitCallback();
1928 if (m_selection_index == GetNumberOfFields() - 1) {
1929 m_selection_type = SelectionType::NewButton;
1933 m_selection_index++;
1934 FieldDelegate &next_field = m_fields[m_selection_index];
1935 next_field.FieldDelegateSelectFirstElement();
1939 HandleCharResult FieldDelegateHandleChar(
int key)
override {
1944 switch (m_selection_type) {
1945 case SelectionType::NewButton:
1948 case SelectionType::RemoveButton:
1951 case SelectionType::Field:
1952 return SelectNextInList(key);
1956 return SelectNext(key);
1958 return SelectPrevious(key);
1965 if (m_selection_type == SelectionType::Field) {
1966 return m_fields[m_selection_index].FieldDelegateHandleChar(key);
1969 return eKeyNotHandled;
1972 bool FieldDelegateOnLastOrOnlyElement()
override {
1973 if (m_selection_type == SelectionType::NewButton) {
1979 bool FieldDelegateOnFirstOrOnlyElement()
override {
1980 if (m_selection_type == SelectionType::NewButton &&
1981 GetNumberOfFields() == 0)
1984 if (m_selection_type == SelectionType::Field && m_selection_index == 0) {
1985 FieldDelegate &field = m_fields[m_selection_index];
1986 return field.FieldDelegateOnFirstOrOnlyElement();
1992 void FieldDelegateSelectFirstElement()
override {
1993 if (GetNumberOfFields() == 0) {
1994 m_selection_type = SelectionType::NewButton;
1998 m_selection_type = SelectionType::Field;
1999 m_selection_index = 0;
2002 void FieldDelegateSelectLastElement()
override {
2003 m_selection_type = SelectionType::NewButton;
2006 int GetNumberOfFields() {
return m_fields.size(); }
2009 T &GetField(
int index) {
return m_fields[index]; }
2012 std::string m_label;
2016 std::vector<T> m_fields;
2017 int m_selection_index = 0;
2019 SelectionType m_selection_type;
2022class ArgumentsFieldDelegate :
public ListFieldDelegate<TextFieldDelegate> {
2024 ArgumentsFieldDelegate()
2025 : ListFieldDelegate(
"Arguments",
2026 TextFieldDelegate(
"Argument",
"", false)) {}
2028 Args GetArguments() {
2030 for (
int i = 0; i < GetNumberOfFields(); i++) {
2036 void AddArguments(
const Args &arguments) {
2039 TextFieldDelegate &field = GetField(GetNumberOfFields() - 1);
2045template <
class KeyFieldDelegateType,
class ValueFieldDelegateType>
2046class MappingFieldDelegate :
public FieldDelegate {
2048 MappingFieldDelegate(KeyFieldDelegateType key_field,
2049 ValueFieldDelegateType value_field)
2050 : m_key_field(key_field), m_value_field(value_field),
2051 m_selection_type(SelectionType::Key) {}
2054 enum class SelectionType { Key, Value };
2067 int FieldDelegateGetHeight()
override {
2068 return std::max(m_key_field.FieldDelegateGetHeight(),
2069 m_value_field.FieldDelegateGetHeight());
2072 void DrawArrow(Surface &surface) {
2073 surface.MoveCursor(0, 1);
2074 surface.PutChar(ACS_RARROW);
2077 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
2078 Rect bounds = surface.GetFrame();
2079 Rect key_field_bounds, arrow_and_value_field_bounds;
2080 bounds.VerticalSplit(bounds.size.width / 2, key_field_bounds,
2081 arrow_and_value_field_bounds);
2082 Rect arrow_bounds, value_field_bounds;
2083 arrow_and_value_field_bounds.VerticalSplit(1, arrow_bounds,
2084 value_field_bounds);
2086 Surface key_field_surface = surface.SubSurface(key_field_bounds);
2087 Surface arrow_surface = surface.SubSurface(arrow_bounds);
2088 Surface value_field_surface = surface.SubSurface(value_field_bounds);
2090 bool key_is_selected =
2091 m_selection_type == SelectionType::Key && is_selected;
2092 m_key_field.FieldDelegateDraw(key_field_surface, key_is_selected);
2093 DrawArrow(arrow_surface);
2094 bool value_is_selected =
2095 m_selection_type == SelectionType::Value && is_selected;
2096 m_value_field.FieldDelegateDraw(value_field_surface, value_is_selected);
2099 HandleCharResult SelectNext(
int key) {
2100 if (FieldDelegateOnLastOrOnlyElement())
2101 return eKeyNotHandled;
2103 if (!m_key_field.FieldDelegateOnLastOrOnlyElement()) {
2104 return m_key_field.FieldDelegateHandleChar(key);
2107 m_key_field.FieldDelegateExitCallback();
2108 m_selection_type = SelectionType::Value;
2109 m_value_field.FieldDelegateSelectFirstElement();
2113 HandleCharResult SelectPrevious(
int key) {
2114 if (FieldDelegateOnFirstOrOnlyElement())
2115 return eKeyNotHandled;
2117 if (!m_value_field.FieldDelegateOnFirstOrOnlyElement()) {
2118 return m_value_field.FieldDelegateHandleChar(key);
2121 m_value_field.FieldDelegateExitCallback();
2122 m_selection_type = SelectionType::Key;
2123 m_key_field.FieldDelegateSelectLastElement();
2130 HandleCharResult SelectNextField(
int key) {
2131 if (m_selection_type == SelectionType::Value) {
2132 return m_value_field.FieldDelegateHandleChar(key);
2135 if (m_key_field.FieldDelegateHandleChar(key) == eKeyHandled)
2138 if (!m_key_field.FieldDelegateOnLastOrOnlyElement())
2139 return eKeyNotHandled;
2141 m_key_field.FieldDelegateExitCallback();
2142 m_selection_type = SelectionType::Value;
2143 m_value_field.FieldDelegateSelectFirstElement();
2147 HandleCharResult FieldDelegateHandleChar(
int key)
override {
2150 return SelectNextField(key);
2152 return SelectNext(key);
2154 return SelectPrevious(key);
2160 if (m_selection_type == SelectionType::Key)
2161 return m_key_field.FieldDelegateHandleChar(key);
2163 return m_value_field.FieldDelegateHandleChar(key);
2165 return eKeyNotHandled;
2168 bool FieldDelegateOnFirstOrOnlyElement()
override {
2169 return m_selection_type == SelectionType::Key;
2172 bool FieldDelegateOnLastOrOnlyElement()
override {
2173 return m_selection_type == SelectionType::Value;
2176 void FieldDelegateSelectFirstElement()
override {
2177 m_selection_type = SelectionType::Key;
2180 void FieldDelegateSelectLastElement()
override {
2181 m_selection_type = SelectionType::Value;
2184 bool FieldDelegateHasError()
override {
2185 return m_key_field.FieldDelegateHasError() ||
2186 m_value_field.FieldDelegateHasError();
2189 KeyFieldDelegateType &GetKeyField() {
return m_key_field; }
2191 ValueFieldDelegateType &GetValueField() {
return m_value_field; }
2194 KeyFieldDelegateType m_key_field;
2195 ValueFieldDelegateType m_value_field;
2197 SelectionType m_selection_type;
2200class EnvironmentVariableNameFieldDelegate :
public TextFieldDelegate {
2202 EnvironmentVariableNameFieldDelegate(
const char *content)
2203 : TextFieldDelegate(
"Name", content, true) {}
2206 bool IsAcceptableChar(
int key)
override {
2207 return TextFieldDelegate::IsAcceptableChar(key) && key !=
'=';
2210 const std::string &
GetName() {
return m_content; }
2213class EnvironmentVariableFieldDelegate
2214 :
public MappingFieldDelegate<EnvironmentVariableNameFieldDelegate,
2215 TextFieldDelegate> {
2217 EnvironmentVariableFieldDelegate()
2218 : MappingFieldDelegate(
2219 EnvironmentVariableNameFieldDelegate(
""),
2220 TextFieldDelegate(
"Value",
"", false)) {}
2222 const std::string &
GetName() {
return GetKeyField().GetName(); }
2224 const std::string &GetValue() {
return GetValueField().GetText(); }
2226 void SetName(
const char *name) {
return GetKeyField().SetText(name); }
2228 void SetValue(
const char *value) {
return GetValueField().SetText(value); }
2231class EnvironmentVariableListFieldDelegate
2232 :
public ListFieldDelegate<EnvironmentVariableFieldDelegate> {
2234 EnvironmentVariableListFieldDelegate(
const char *label)
2235 : ListFieldDelegate(label, EnvironmentVariableFieldDelegate()) {}
2237 Environment GetEnvironment() {
2238 Environment environment;
2239 for (
int i = 0; i < GetNumberOfFields(); i++) {
2241 std::make_pair(GetField(i).
GetName(), GetField(i).GetValue()));
2246 void AddEnvironmentVariables(
const Environment &environment) {
2247 for (
auto &variable : environment) {
2249 EnvironmentVariableFieldDelegate &field =
2250 GetField(GetNumberOfFields() - 1);
2251 field.SetName(variable.getKey().str().c_str());
2252 field.SetValue(variable.getValue().c_str());
2259 FormAction(
const char *label, std::function<
void(Window &)> action)
2260 : m_action(action) {
2266 void Draw(Surface &surface,
bool is_selected) {
2267 int x = (surface.GetWidth() - m_label.length()) / 2;
2268 surface.MoveCursor(x, 0);
2270 surface.AttributeOn(A_REVERSE);
2271 surface.PutChar(
'[');
2272 surface.PutCString(m_label.c_str());
2273 surface.PutChar(
']');
2275 surface.AttributeOff(A_REVERSE);
2278 void Execute(Window &window) { m_action(window); }
2280 const std::string &GetLabel() {
return m_label; }
2283 std::string m_label;
2284 std::function<void(Window &)> m_action;
2289 FormDelegate() =
default;
2291 virtual ~FormDelegate() =
default;
2293 virtual std::string
GetName() = 0;
2295 virtual void UpdateFieldsVisibility() {}
2297 FieldDelegate *GetField(uint32_t field_index) {
2298 if (field_index < m_fields.size())
2299 return m_fields[field_index].get();
2303 FormAction &GetAction(
int action_index) {
return m_actions[action_index]; }
2305 int GetNumberOfFields() {
return m_fields.size(); }
2307 int GetNumberOfActions() {
return m_actions.size(); }
2309 bool HasError() {
return !m_error.empty(); }
2311 void ClearError() { m_error.clear(); }
2313 const std::string &GetError() {
return m_error; }
2315 void SetError(
const char *
error) { m_error =
error; }
2320 bool CheckFieldsValidity() {
2321 for (
int i = 0; i < GetNumberOfFields(); i++) {
2322 GetField(i)->FieldDelegateExitCallback();
2323 if (GetField(i)->FieldDelegateHasError()) {
2324 SetError(
"Some fields are invalid!");
2333 TextFieldDelegate *AddTextField(
const char *label,
const char *content,
2335 TextFieldDelegate *delegate =
2336 new TextFieldDelegate(label, content, required);
2337 m_fields.push_back(FieldDelegateUP(delegate));
2341 FileFieldDelegate *AddFileField(
const char *label,
const char *content,
2342 bool need_to_exist,
bool required) {
2343 FileFieldDelegate *delegate =
2344 new FileFieldDelegate(label, content, need_to_exist, required);
2345 m_fields.push_back(FieldDelegateUP(delegate));
2349 DirectoryFieldDelegate *AddDirectoryField(
const char *label,
2350 const char *content,
2351 bool need_to_exist,
bool required) {
2352 DirectoryFieldDelegate *delegate =
2353 new DirectoryFieldDelegate(label, content, need_to_exist, required);
2354 m_fields.push_back(FieldDelegateUP(delegate));
2358 ArchFieldDelegate *AddArchField(
const char *label,
const char *content,
2360 ArchFieldDelegate *delegate =
2361 new ArchFieldDelegate(label, content, required);
2362 m_fields.push_back(FieldDelegateUP(delegate));
2366 IntegerFieldDelegate *AddIntegerField(
const char *label,
int content,
2368 IntegerFieldDelegate *delegate =
2369 new IntegerFieldDelegate(label, content, required);
2370 m_fields.push_back(FieldDelegateUP(delegate));
2374 BooleanFieldDelegate *AddBooleanField(
const char *label,
bool content) {
2375 BooleanFieldDelegate *delegate =
new BooleanFieldDelegate(label, content);
2376 m_fields.push_back(FieldDelegateUP(delegate));
2380 LazyBooleanFieldDelegate *AddLazyBooleanField(
const char *label,
2381 const char *calculate_label) {
2382 LazyBooleanFieldDelegate *delegate =
2383 new LazyBooleanFieldDelegate(label, calculate_label);
2384 m_fields.push_back(FieldDelegateUP(delegate));
2388 ChoicesFieldDelegate *AddChoicesField(
const char *label,
int height,
2389 std::vector<std::string> choices) {
2390 ChoicesFieldDelegate *delegate =
2391 new ChoicesFieldDelegate(label, height, choices);
2392 m_fields.push_back(FieldDelegateUP(delegate));
2396 PlatformPluginFieldDelegate *AddPlatformPluginField(Debugger &debugger) {
2397 PlatformPluginFieldDelegate *delegate =
2398 new PlatformPluginFieldDelegate(debugger);
2399 m_fields.push_back(FieldDelegateUP(delegate));
2403 ProcessPluginFieldDelegate *AddProcessPluginField() {
2404 ProcessPluginFieldDelegate *delegate =
new ProcessPluginFieldDelegate();
2405 m_fields.push_back(FieldDelegateUP(delegate));
2410 ListFieldDelegate<T> *AddListField(
const char *label, T default_field) {
2411 ListFieldDelegate<T> *delegate =
2412 new ListFieldDelegate<T>(label, default_field);
2413 m_fields.push_back(FieldDelegateUP(delegate));
2417 ArgumentsFieldDelegate *AddArgumentsField() {
2418 ArgumentsFieldDelegate *delegate =
new ArgumentsFieldDelegate();
2419 m_fields.push_back(FieldDelegateUP(delegate));
2423 template <
class K,
class V>
2424 MappingFieldDelegate<K, V> *AddMappingField(K key_field, V value_field) {
2425 MappingFieldDelegate<K, V> *delegate =
2426 new MappingFieldDelegate<K, V>(key_field, value_field);
2427 m_fields.push_back(FieldDelegateUP(delegate));
2431 EnvironmentVariableNameFieldDelegate *
2432 AddEnvironmentVariableNameField(
const char *content) {
2433 EnvironmentVariableNameFieldDelegate *delegate =
2434 new EnvironmentVariableNameFieldDelegate(content);
2435 m_fields.push_back(FieldDelegateUP(delegate));
2439 EnvironmentVariableFieldDelegate *AddEnvironmentVariableField() {
2440 EnvironmentVariableFieldDelegate *delegate =
2441 new EnvironmentVariableFieldDelegate();
2442 m_fields.push_back(FieldDelegateUP(delegate));
2446 EnvironmentVariableListFieldDelegate *
2447 AddEnvironmentVariableListField(
const char *label) {
2448 EnvironmentVariableListFieldDelegate *delegate =
2449 new EnvironmentVariableListFieldDelegate(label);
2450 m_fields.push_back(FieldDelegateUP(delegate));
2456 void AddAction(
const char *label, std::function<
void(Window &)> action) {
2457 m_actions.push_back(FormAction(label, action));
2461 std::vector<FieldDelegateUP> m_fields;
2462 std::vector<FormAction> m_actions;
2464 std::string m_error;
2467typedef std::shared_ptr<FormDelegate> FormDelegateSP;
2469class FormWindowDelegate :
public WindowDelegate {
2471 FormWindowDelegate(FormDelegateSP &delegate_sp) : m_delegate_sp(delegate_sp) {
2472 assert(m_delegate_sp->GetNumberOfActions() > 0);
2473 if (m_delegate_sp->GetNumberOfFields() > 0)
2474 m_selection_type = SelectionType::Field;
2476 m_selection_type = SelectionType::Action;
2482 enum class SelectionType { Field, Action };
2500 int GetErrorHeight() {
2501 if (m_delegate_sp->HasError())
2507 int GetActionsHeight() {
2508 if (m_delegate_sp->GetNumberOfActions() > 0)
2514 int GetContentHeight() {
2516 height += GetErrorHeight();
2517 for (
int i = 0; i < m_delegate_sp->GetNumberOfFields(); i++) {
2518 if (!m_delegate_sp->GetField(i)->FieldDelegateIsVisible())
2520 height += m_delegate_sp->GetField(i)->FieldDelegateGetHeight();
2522 height += GetActionsHeight();
2526 ScrollContext GetScrollContext() {
2527 if (m_selection_type == SelectionType::Action)
2528 return ScrollContext(GetContentHeight() - 1);
2530 FieldDelegate *field = m_delegate_sp->GetField(m_selection_index);
2531 ScrollContext context = field->FieldDelegateGetScrollContext();
2533 int offset = GetErrorHeight();
2534 for (
int i = 0; i < m_selection_index; i++) {
2535 if (!m_delegate_sp->GetField(i)->FieldDelegateIsVisible())
2537 offset += m_delegate_sp->GetField(i)->FieldDelegateGetHeight();
2539 context.Offset(offset);
2543 if (context.start == GetErrorHeight())
2549 void UpdateScrolling(Surface &surface) {
2550 ScrollContext context = GetScrollContext();
2551 int content_height = GetContentHeight();
2552 int surface_height = surface.GetHeight();
2553 int visible_height = std::min(content_height, surface_height);
2554 int last_visible_line = m_first_visible_line + visible_height - 1;
2559 if (last_visible_line > content_height - 1) {
2560 m_first_visible_line = content_height - visible_height;
2563 if (context.start < m_first_visible_line) {
2564 m_first_visible_line = context.start;
2568 if (context.end > last_visible_line) {
2569 m_first_visible_line = context.end - visible_height + 1;
2573 void DrawError(Surface &surface) {
2574 if (!m_delegate_sp->HasError())
2576 surface.MoveCursor(0, 0);
2577 surface.AttributeOn(COLOR_PAIR(RedOnBlack));
2578 surface.PutChar(ACS_DIAMOND);
2579 surface.PutChar(
' ');
2580 surface.PutCStringTruncated(1, m_delegate_sp->GetError().c_str());
2581 surface.AttributeOff(COLOR_PAIR(RedOnBlack));
2583 surface.MoveCursor(0, 1);
2584 surface.HorizontalLine(surface.GetWidth());
2587 void DrawFields(Surface &surface) {
2589 int width = surface.GetWidth();
2590 bool a_field_is_selected = m_selection_type == SelectionType::Field;
2591 for (
int i = 0; i < m_delegate_sp->GetNumberOfFields(); i++) {
2592 FieldDelegate *field = m_delegate_sp->GetField(i);
2593 if (!field->FieldDelegateIsVisible())
2595 bool is_field_selected = a_field_is_selected && m_selection_index == i;
2596 int height = field->FieldDelegateGetHeight();
2597 Rect bounds = Rect(Point(0, line), Size(width, height));
2598 Surface field_surface = surface.SubSurface(bounds);
2599 field->FieldDelegateDraw(field_surface, is_field_selected);
2604 void DrawActions(Surface &surface) {
2605 int number_of_actions = m_delegate_sp->GetNumberOfActions();
2606 int width = surface.GetWidth() / number_of_actions;
2607 bool an_action_is_selected = m_selection_type == SelectionType::Action;
2609 for (
int i = 0; i < number_of_actions; i++) {
2610 bool is_action_selected = an_action_is_selected && m_selection_index == i;
2611 FormAction &action = m_delegate_sp->GetAction(i);
2612 Rect bounds = Rect(Point(x, 0), Size(width, 1));
2613 Surface action_surface = surface.SubSurface(bounds);
2614 action.Draw(action_surface, is_action_selected);
2619 void DrawElements(Surface &surface) {
2620 Rect frame = surface.GetFrame();
2621 Rect fields_bounds, actions_bounds;
2622 frame.HorizontalSplit(surface.GetHeight() - GetActionsHeight(),
2623 fields_bounds, actions_bounds);
2624 Surface fields_surface = surface.SubSurface(fields_bounds);
2625 Surface actions_surface = surface.SubSurface(actions_bounds);
2627 DrawFields(fields_surface);
2628 DrawActions(actions_surface);
2634 void DrawContent(Surface &surface) {
2635 UpdateScrolling(surface);
2637 int width = surface.GetWidth();
2638 int height = GetContentHeight();
2639 Pad pad = Pad(Size(width, height));
2641 Rect frame = pad.GetFrame();
2642 Rect error_bounds, elements_bounds;
2643 frame.HorizontalSplit(GetErrorHeight(), error_bounds, elements_bounds);
2644 Surface error_surface = pad.SubSurface(error_bounds);
2645 Surface elements_surface = pad.SubSurface(elements_bounds);
2647 DrawError(error_surface);
2648 DrawElements(elements_surface);
2650 int copy_height = std::min(surface.GetHeight(), pad.GetHeight());
2651 pad.CopyToSurface(surface, Point(0, m_first_visible_line), Point(),
2652 Size(width, copy_height));
2655 void DrawSubmitHint(Surface &surface,
bool is_active) {
2656 surface.MoveCursor(2, surface.GetHeight() - 1);
2658 surface.AttributeOn(A_BOLD | COLOR_PAIR(BlackOnWhite));
2659 surface.Printf(
"[Press Alt+Enter to %s]",
2660 m_delegate_sp->GetAction(0).GetLabel().c_str());
2662 surface.AttributeOff(A_BOLD | COLOR_PAIR(BlackOnWhite));
2665 bool WindowDelegateDraw(Window &window,
bool force)
override {
2666 m_delegate_sp->UpdateFieldsVisibility();
2670 window.DrawTitleBox(m_delegate_sp->GetName().c_str(),
2671 "Press Esc to Cancel");
2672 DrawSubmitHint(window, window.IsActive());
2674 Rect content_bounds = window.GetFrame();
2675 content_bounds.Inset(2, 2);
2676 Surface content_surface = window.SubSurface(content_bounds);
2678 DrawContent(content_surface);
2682 void SkipNextHiddenFields() {
2684 if (m_delegate_sp->GetField(m_selection_index)->FieldDelegateIsVisible())
2687 if (m_selection_index == m_delegate_sp->GetNumberOfFields() - 1) {
2688 m_selection_type = SelectionType::Action;
2689 m_selection_index = 0;
2693 m_selection_index++;
2697 HandleCharResult SelectNext(
int key) {
2698 if (m_selection_type == SelectionType::Action) {
2699 if (m_selection_index < m_delegate_sp->GetNumberOfActions() - 1) {
2700 m_selection_index++;
2704 m_selection_index = 0;
2705 m_selection_type = SelectionType::Field;
2706 SkipNextHiddenFields();
2707 if (m_selection_type == SelectionType::Field) {
2708 FieldDelegate *next_field = m_delegate_sp->GetField(m_selection_index);
2709 next_field->FieldDelegateSelectFirstElement();
2714 FieldDelegate *field = m_delegate_sp->GetField(m_selection_index);
2715 if (!field->FieldDelegateOnLastOrOnlyElement()) {
2716 return field->FieldDelegateHandleChar(key);
2719 field->FieldDelegateExitCallback();
2721 if (m_selection_index == m_delegate_sp->GetNumberOfFields() - 1) {
2722 m_selection_type = SelectionType::Action;
2723 m_selection_index = 0;
2727 m_selection_index++;
2728 SkipNextHiddenFields();
2730 if (m_selection_type == SelectionType::Field) {
2731 FieldDelegate *next_field = m_delegate_sp->GetField(m_selection_index);
2732 next_field->FieldDelegateSelectFirstElement();
2738 void SkipPreviousHiddenFields() {
2740 if (m_delegate_sp->GetField(m_selection_index)->FieldDelegateIsVisible())
2743 if (m_selection_index == 0) {
2744 m_selection_type = SelectionType::Action;
2745 m_selection_index = 0;
2749 m_selection_index--;
2753 HandleCharResult SelectPrevious(
int key) {
2754 if (m_selection_type == SelectionType::Action) {
2755 if (m_selection_index > 0) {
2756 m_selection_index--;
2759 m_selection_index = m_delegate_sp->GetNumberOfFields() - 1;
2760 m_selection_type = SelectionType::Field;
2761 SkipPreviousHiddenFields();
2762 if (m_selection_type == SelectionType::Field) {
2763 FieldDelegate *previous_field =
2764 m_delegate_sp->GetField(m_selection_index);
2765 previous_field->FieldDelegateSelectLastElement();
2770 FieldDelegate *field = m_delegate_sp->GetField(m_selection_index);
2771 if (!field->FieldDelegateOnFirstOrOnlyElement()) {
2772 return field->FieldDelegateHandleChar(key);
2775 field->FieldDelegateExitCallback();
2777 if (m_selection_index == 0) {
2778 m_selection_type = SelectionType::Action;
2779 m_selection_index = m_delegate_sp->GetNumberOfActions() - 1;
2783 m_selection_index--;
2784 SkipPreviousHiddenFields();
2786 if (m_selection_type == SelectionType::Field) {
2787 FieldDelegate *previous_field =
2788 m_delegate_sp->GetField(m_selection_index);
2789 previous_field->FieldDelegateSelectLastElement();
2795 void ExecuteAction(Window &window,
int index) {
2796 FormAction &action = m_delegate_sp->GetAction(index);
2797 action.Execute(window);
2798 if (m_delegate_sp->HasError()) {
2799 m_first_visible_line = 0;
2800 m_selection_index = 0;
2801 m_selection_type = SelectionType::Field;
2807 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override {
2812 if (m_selection_type == SelectionType::Action) {
2813 ExecuteAction(window, m_selection_index);
2818 ExecuteAction(window, 0);
2824 SelectPrevious(key);
2827 window.GetParent()->RemoveSubWindow(&window);
2835 if (m_selection_type == SelectionType::Field) {
2836 FieldDelegate *field = m_delegate_sp->GetField(m_selection_index);
2837 if (field->FieldDelegateHandleChar(key) == eKeyHandled)
2848 SelectPrevious(key);
2858 FormDelegateSP m_delegate_sp;
2860 int m_selection_index = 0;
2862 SelectionType m_selection_type;
2864 int m_first_visible_line = 0;
2871class DetachOrKillProcessFormDelegate :
public FormDelegate {
2873 DetachOrKillProcessFormDelegate(
Process *process) : m_process(process) {
2874 SetError(
"There is a running process, either detach or kill it.");
2876 m_keep_stopped_field =
2877 AddBooleanField(
"Keep process stopped when detaching.",
false);
2879 AddAction(
"Detach", [
this](Window &window) { Detach(window); });
2880 AddAction(
"Kill", [
this](Window &window) { Kill(window); });
2883 std::string
GetName()
override {
return "Detach/Kill Process"; }
2885 void Kill(Window &window) {
2886 Status destroy_status(m_process->Destroy(
false));
2887 if (destroy_status.Fail()) {
2888 SetError(
"Failed to kill process.");
2891 window.GetParent()->RemoveSubWindow(&window);
2894 void Detach(Window &window) {
2895 Status detach_status(m_process->Detach(m_keep_stopped_field->GetBoolean()));
2896 if (detach_status.Fail()) {
2897 SetError(
"Failed to detach from process.");
2900 window.GetParent()->RemoveSubWindow(&window);
2905 BooleanFieldDelegate *m_keep_stopped_field;
2908class ProcessAttachFormDelegate :
public FormDelegate {
2910 ProcessAttachFormDelegate(Debugger &debugger, WindowSP main_window_sp)
2911 : m_debugger(debugger), m_main_window_sp(main_window_sp) {
2912 std::vector<std::string> types;
2913 types.push_back(std::string(
"Name"));
2914 types.push_back(std::string(
"PID"));
2915 m_type_field = AddChoicesField(
"Attach By", 2, types);
2916 m_pid_field = AddIntegerField(
"PID", 0,
true);
2918 AddTextField(
"Process Name", GetDefaultProcessName().c_str(),
true);
2919 m_continue_field = AddBooleanField(
"Continue once attached.",
false);
2920 m_wait_for_field = AddBooleanField(
"Wait for process to launch.",
false);
2921 m_include_existing_field =
2922 AddBooleanField(
"Include existing processes.",
false);
2923 m_show_advanced_field = AddBooleanField(
"Show advanced settings.",
false);
2924 m_plugin_field = AddProcessPluginField();
2926 AddAction(
"Attach", [
this](Window &window) { Attach(window); });
2929 std::string
GetName()
override {
return "Attach Process"; }
2931 void UpdateFieldsVisibility()
override {
2932 if (m_type_field->GetChoiceContent() ==
"Name") {
2933 m_pid_field->FieldDelegateHide();
2934 m_name_field->FieldDelegateShow();
2935 m_wait_for_field->FieldDelegateShow();
2936 if (m_wait_for_field->GetBoolean())
2937 m_include_existing_field->FieldDelegateShow();
2939 m_include_existing_field->FieldDelegateHide();
2941 m_pid_field->FieldDelegateShow();
2942 m_name_field->FieldDelegateHide();
2943 m_wait_for_field->FieldDelegateHide();
2944 m_include_existing_field->FieldDelegateHide();
2946 if (m_show_advanced_field->GetBoolean())
2947 m_plugin_field->FieldDelegateShow();
2949 m_plugin_field->FieldDelegateHide();
2954 std::string GetDefaultProcessName() {
2955 Target *target = m_debugger.GetSelectedTarget().get();
2956 if (target ==
nullptr)
2960 if (!module_sp->IsExecutable())
2963 return module_sp->GetFileSpec().GetFilename().AsCString();
2966 bool StopRunningProcess() {
2967 ExecutionContext exe_ctx =
2968 m_debugger.GetCommandInterpreter().GetExecutionContext();
2974 if (!(process && process->
IsAlive()))
2977 FormDelegateSP form_delegate_sp =
2978 FormDelegateSP(
new DetachOrKillProcessFormDelegate(process));
2979 Rect bounds = m_main_window_sp->GetCenteredRect(85, 8);
2980 WindowSP form_window_sp = m_main_window_sp->CreateSubWindow(
2981 form_delegate_sp->GetName().c_str(), bounds,
true);
2982 WindowDelegateSP window_delegate_sp =
2983 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
2984 form_window_sp->SetDelegate(window_delegate_sp);
2990 Target *target = m_debugger.GetSelectedTarget().get();
2992 if (target !=
nullptr)
2996 m_debugger.GetTargetList().CreateTarget(
2999 target = new_target_sp.get();
3001 if (target ==
nullptr)
3002 SetError(
"Failed to create target.");
3004 m_debugger.GetTargetList().SetSelectedTarget(new_target_sp);
3009 ProcessAttachInfo GetAttachInfo() {
3010 ProcessAttachInfo attach_info;
3012 if (m_type_field->GetChoiceContent() ==
"Name") {
3014 FileSpec::Style::native);
3016 if (m_wait_for_field->GetBoolean())
3026 void Attach(Window &window) {
3029 bool all_fields_are_valid = CheckFieldsValidity();
3030 if (!all_fields_are_valid)
3033 bool process_is_running = StopRunningProcess();
3034 if (process_is_running)
3037 Target *target = GetTarget();
3041 StreamString stream;
3042 ProcessAttachInfo attach_info = GetAttachInfo();
3045 if (status.
Fail()) {
3052 SetError(
"Attached sucessfully but target has no process.");
3057 process_sp->Resume();
3059 window.GetParent()->RemoveSubWindow(&window);
3063 Debugger &m_debugger;
3064 WindowSP m_main_window_sp;
3066 ChoicesFieldDelegate *m_type_field;
3067 IntegerFieldDelegate *m_pid_field;
3068 TextFieldDelegate *m_name_field;
3069 BooleanFieldDelegate *m_continue_field;
3070 BooleanFieldDelegate *m_wait_for_field;
3071 BooleanFieldDelegate *m_include_existing_field;
3072 BooleanFieldDelegate *m_show_advanced_field;
3073 ProcessPluginFieldDelegate *m_plugin_field;
3076class TargetCreateFormDelegate :
public FormDelegate {
3078 TargetCreateFormDelegate(Debugger &debugger) : m_debugger(debugger) {
3079 m_executable_field = AddFileField(
"Executable",
"",
true,
3081 m_core_file_field = AddFileField(
"Core File",
"",
true,
3083 m_symbol_file_field = AddFileField(
3084 "Symbol File",
"",
true,
false);
3085 m_show_advanced_field = AddBooleanField(
"Show advanced settings.",
false);
3086 m_remote_file_field = AddFileField(
3087 "Remote File",
"",
false,
false);
3088 m_arch_field = AddArchField(
"Architecture",
"",
false);
3089 m_platform_field = AddPlatformPluginField(debugger);
3090 m_load_dependent_files_field =
3091 AddChoicesField(
"Load Dependents", 3, GetLoadDependentFilesChoices());
3093 AddAction(
"Create", [
this](Window &window) { CreateTarget(window); });
3096 std::string
GetName()
override {
return "Create Target"; }
3098 void UpdateFieldsVisibility()
override {
3099 if (m_show_advanced_field->GetBoolean()) {
3100 m_remote_file_field->FieldDelegateShow();
3101 m_arch_field->FieldDelegateShow();
3102 m_platform_field->FieldDelegateShow();
3103 m_load_dependent_files_field->FieldDelegateShow();
3105 m_remote_file_field->FieldDelegateHide();
3106 m_arch_field->FieldDelegateHide();
3107 m_platform_field->FieldDelegateHide();
3108 m_load_dependent_files_field->FieldDelegateHide();
3112 static constexpr const char *kLoadDependentFilesNo =
"No";
3113 static constexpr const char *kLoadDependentFilesYes =
"Yes";
3114 static constexpr const char *kLoadDependentFilesExecOnly =
"Executable only";
3116 std::vector<std::string> GetLoadDependentFilesChoices() {
3117 std::vector<std::string> load_dependents_options;
3118 load_dependents_options.push_back(kLoadDependentFilesExecOnly);
3119 load_dependents_options.push_back(kLoadDependentFilesYes);
3120 load_dependents_options.push_back(kLoadDependentFilesNo);
3121 return load_dependents_options;
3125 std::string choice = m_load_dependent_files_field->GetChoiceContent();
3126 if (choice == kLoadDependentFilesNo)
3128 if (choice == kLoadDependentFilesYes)
3133 OptionGroupPlatform GetPlatformOptions() {
3134 OptionGroupPlatform platform_options(
false);
3135 platform_options.SetPlatformName(m_platform_field->GetPluginName().c_str());
3136 return platform_options;
3140 OptionGroupPlatform platform_options = GetPlatformOptions();
3142 Status status = m_debugger.GetTargetList().CreateTarget(
3143 m_debugger, m_executable_field->GetPath(),
3144 m_arch_field->GetArchString(), GetLoadDependentFiles(),
3145 &platform_options, target_sp);
3147 if (status.
Fail()) {
3152 m_debugger.GetTargetList().SetSelectedTarget(target_sp);
3157 void SetSymbolFile(
TargetSP target_sp) {
3158 if (!m_symbol_file_field->IsSpecified())
3161 ModuleSP module_sp(target_sp->GetExecutableModule());
3165 module_sp->SetSymbolFileFileSpec(
3166 m_symbol_file_field->GetResolvedFileSpec());
3169 void SetCoreFile(
TargetSP target_sp) {
3170 if (!m_core_file_field->IsSpecified())
3173 FileSpec core_file_spec = m_core_file_field->GetResolvedFileSpec();
3175 FileSpec core_file_directory_spec;
3177 target_sp->AppendExecutableSearchPaths(core_file_directory_spec);
3179 ProcessSP process_sp(target_sp->CreateProcess(
3180 m_debugger.GetListener(), llvm::StringRef(), &core_file_spec,
false));
3183 SetError(
"Unknown core file format!");
3187 Status status = process_sp->LoadCore();
3188 if (status.
Fail()) {
3189 SetError(
"Unknown core file format!");
3194 void SetRemoteFile(
TargetSP target_sp) {
3195 if (!m_remote_file_field->IsSpecified())
3198 ModuleSP module_sp(target_sp->GetExecutableModule());
3202 FileSpec remote_file_spec = m_remote_file_field->GetFileSpec();
3203 module_sp->SetPlatformFileSpec(remote_file_spec);
3206 void RemoveTarget(
TargetSP target_sp) {
3207 m_debugger.GetTargetList().DeleteTarget(target_sp);
3210 void CreateTarget(Window &window) {
3213 bool all_fields_are_valid = CheckFieldsValidity();
3214 if (!all_fields_are_valid)
3221 SetSymbolFile(target_sp);
3223 RemoveTarget(target_sp);
3227 SetCoreFile(target_sp);
3229 RemoveTarget(target_sp);
3233 SetRemoteFile(target_sp);
3235 RemoveTarget(target_sp);
3239 window.GetParent()->RemoveSubWindow(&window);
3243 Debugger &m_debugger;
3245 FileFieldDelegate *m_executable_field;
3246 FileFieldDelegate *m_core_file_field;
3247 FileFieldDelegate *m_symbol_file_field;
3248 BooleanFieldDelegate *m_show_advanced_field;
3249 FileFieldDelegate *m_remote_file_field;
3250 ArchFieldDelegate *m_arch_field;
3251 PlatformPluginFieldDelegate *m_platform_field;
3252 ChoicesFieldDelegate *m_load_dependent_files_field;
3255class ProcessLaunchFormDelegate :
public FormDelegate {
3257 ProcessLaunchFormDelegate(Debugger &debugger, WindowSP main_window_sp)
3258 : m_debugger(debugger), m_main_window_sp(main_window_sp) {
3260 m_arguments_field = AddArgumentsField();
3261 SetArgumentsFieldDefaultValue();
3262 m_target_environment_field =
3263 AddEnvironmentVariableListField(
"Target Environment Variables");
3264 SetTargetEnvironmentFieldDefaultValue();
3265 m_working_directory_field = AddDirectoryField(
3266 "Working Directory", GetDefaultWorkingDirectory().c_str(),
true,
false);
3268 m_show_advanced_field = AddBooleanField(
"Show advanced settings.",
false);
3270 m_stop_at_entry_field = AddBooleanField(
"Stop at entry point.",
false);
3271 m_detach_on_error_field =
3272 AddBooleanField(
"Detach on error.", GetDefaultDetachOnError());
3273 m_disable_aslr_field =
3274 AddBooleanField(
"Disable ASLR", GetDefaultDisableASLR());
3275 m_plugin_field = AddProcessPluginField();
3276 m_arch_field = AddArchField(
"Architecture",
"",
false);
3277 m_shell_field = AddFileField(
"Shell",
"",
true,
false);
3278 m_expand_shell_arguments_field =
3279 AddBooleanField(
"Expand shell arguments.",
false);
3281 m_disable_standard_io_field =
3282 AddBooleanField(
"Disable Standard IO", GetDefaultDisableStandardIO());
3283 m_standard_output_field =
3284 AddFileField(
"Standard Output File",
"",
false,
3286 m_standard_error_field =
3287 AddFileField(
"Standard Error File",
"",
false,
3289 m_standard_input_field =
3290 AddFileField(
"Standard Input File",
"",
false,
3293 m_show_inherited_environment_field =
3294 AddBooleanField(
"Show inherited environment variables.",
false);
3295 m_inherited_environment_field =
3296 AddEnvironmentVariableListField(
"Inherited Environment Variables");
3297 SetInheritedEnvironmentFieldDefaultValue();
3299 AddAction(
"Launch", [
this](Window &window) { Launch(window); });
3302 std::string
GetName()
override {
return "Launch Process"; }
3304 void UpdateFieldsVisibility()
override {
3305 if (m_show_advanced_field->GetBoolean()) {
3306 m_stop_at_entry_field->FieldDelegateShow();
3307 m_detach_on_error_field->FieldDelegateShow();
3308 m_disable_aslr_field->FieldDelegateShow();
3309 m_plugin_field->FieldDelegateShow();
3310 m_arch_field->FieldDelegateShow();
3311 m_shell_field->FieldDelegateShow();
3312 m_expand_shell_arguments_field->FieldDelegateShow();
3313 m_disable_standard_io_field->FieldDelegateShow();
3314 if (m_disable_standard_io_field->GetBoolean()) {
3315 m_standard_input_field->FieldDelegateHide();
3316 m_standard_output_field->FieldDelegateHide();
3317 m_standard_error_field->FieldDelegateHide();
3319 m_standard_input_field->FieldDelegateShow();
3320 m_standard_output_field->FieldDelegateShow();
3321 m_standard_error_field->FieldDelegateShow();
3323 m_show_inherited_environment_field->FieldDelegateShow();
3324 if (m_show_inherited_environment_field->GetBoolean())
3325 m_inherited_environment_field->FieldDelegateShow();
3327 m_inherited_environment_field->FieldDelegateHide();
3329 m_stop_at_entry_field->FieldDelegateHide();
3330 m_detach_on_error_field->FieldDelegateHide();
3331 m_disable_aslr_field->FieldDelegateHide();
3332 m_plugin_field->FieldDelegateHide();
3333 m_arch_field->FieldDelegateHide();
3334 m_shell_field->FieldDelegateHide();
3335 m_expand_shell_arguments_field->FieldDelegateHide();
3336 m_disable_standard_io_field->FieldDelegateHide();
3337 m_standard_input_field->FieldDelegateHide();
3338 m_standard_output_field->FieldDelegateHide();
3339 m_standard_error_field->FieldDelegateHide();
3340 m_show_inherited_environment_field->FieldDelegateHide();
3341 m_inherited_environment_field->FieldDelegateHide();
3347 void SetArgumentsFieldDefaultValue() {
3348 TargetSP target = m_debugger.GetSelectedTarget();
3349 if (target ==
nullptr)
3352 const Args &target_arguments =
3354 m_arguments_field->AddArguments(target_arguments);
3357 void SetTargetEnvironmentFieldDefaultValue() {
3358 TargetSP target = m_debugger.GetSelectedTarget();
3359 if (target ==
nullptr)
3362 const Environment &target_environment = target->GetTargetEnvironment();
3363 m_target_environment_field->AddEnvironmentVariables(target_environment);
3366 void SetInheritedEnvironmentFieldDefaultValue() {
3367 TargetSP target = m_debugger.GetSelectedTarget();
3368 if (target ==
nullptr)
3371 const Environment &inherited_environment =
3372 target->GetInheritedEnvironment();
3373 m_inherited_environment_field->AddEnvironmentVariables(
3374 inherited_environment);
3377 std::string GetDefaultWorkingDirectory() {
3378 TargetSP target = m_debugger.GetSelectedTarget();
3379 if (target ==
nullptr)
3383 return platform->GetWorkingDirectory().GetPath();
3386 bool GetDefaultDisableASLR() {
3387 TargetSP target = m_debugger.GetSelectedTarget();
3388 if (target ==
nullptr)
3391 return target->GetDisableASLR();
3394 bool GetDefaultDisableStandardIO() {
3395 TargetSP target = m_debugger.GetSelectedTarget();
3396 if (target ==
nullptr)
3399 return target->GetDisableSTDIO();
3402 bool GetDefaultDetachOnError() {
3403 TargetSP target = m_debugger.GetSelectedTarget();
3404 if (target ==
nullptr)
3407 return target->GetDetachOnError();
3413 void GetExecutableSettings(ProcessLaunchInfo &launch_info) {
3414 TargetSP target = m_debugger.GetSelectedTarget();
3415 ModuleSP executable_module = target->GetExecutableModule();
3416 llvm::StringRef target_settings_argv0 = target->GetArg0();
3418 if (!target_settings_argv0.empty()) {
3429 void GetArguments(ProcessLaunchInfo &launch_info) {
3430 TargetSP target = m_debugger.GetSelectedTarget();
3431 Args arguments = m_arguments_field->GetArguments();
3435 void GetEnvironment(ProcessLaunchInfo &launch_info) {
3436 Environment target_environment =
3437 m_target_environment_field->GetEnvironment();
3438 Environment inherited_environment =
3439 m_inherited_environment_field->GetEnvironment();
3441 target_environment.end());
3443 inherited_environment.end());
3446 void GetWorkingDirectory(ProcessLaunchInfo &launch_info) {
3447 if (m_working_directory_field->IsSpecified())
3449 m_working_directory_field->GetResolvedFileSpec());
3452 void GetStopAtEntry(ProcessLaunchInfo &launch_info) {
3453 if (m_stop_at_entry_field->GetBoolean())
3454 launch_info.
GetFlags().
Set(eLaunchFlagStopAtEntry);
3459 void GetDetachOnError(ProcessLaunchInfo &launch_info) {
3460 if (m_detach_on_error_field->GetBoolean())
3461 launch_info.
GetFlags().
Set(eLaunchFlagDetachOnError);
3466 void GetDisableASLR(ProcessLaunchInfo &launch_info) {
3467 if (m_disable_aslr_field->GetBoolean())
3468 launch_info.
GetFlags().
Set(eLaunchFlagDisableASLR);
3473 void GetPlugin(ProcessLaunchInfo &launch_info) {
3477 void GetArch(ProcessLaunchInfo &launch_info) {
3478 if (!m_arch_field->IsSpecified())
3481 TargetSP target_sp = m_debugger.GetSelectedTarget();
3483 target_sp ? target_sp->GetPlatform() :
PlatformSP();
3485 platform_sp.get(), m_arch_field->GetArchString());
3488 void GetShell(ProcessLaunchInfo &launch_info) {
3489 if (!m_shell_field->IsSpecified())
3492 launch_info.
SetShell(m_shell_field->GetResolvedFileSpec());
3494 m_expand_shell_arguments_field->GetBoolean());
3497 void GetStandardIO(ProcessLaunchInfo &launch_info) {
3498 if (m_disable_standard_io_field->GetBoolean()) {
3499 launch_info.
GetFlags().
Set(eLaunchFlagDisableSTDIO);
3504 if (m_standard_input_field->IsSpecified()) {
3505 if (action.
Open(STDIN_FILENO, m_standard_input_field->GetFileSpec(),
true,
3509 if (m_standard_output_field->IsSpecified()) {
3510 if (action.
Open(STDOUT_FILENO, m_standard_output_field->GetFileSpec(),
3514 if (m_standard_error_field->IsSpecified()) {
3515 if (action.
Open(STDERR_FILENO, m_standard_error_field->GetFileSpec(),
3521 void GetInheritTCC(ProcessLaunchInfo &launch_info) {
3522 if (m_debugger.GetSelectedTarget()->GetInheritTCC())
3523 launch_info.
GetFlags().
Set(eLaunchFlagInheritTCCFromParent);
3526 ProcessLaunchInfo GetLaunchInfo() {
3527 ProcessLaunchInfo launch_info;
3529 GetExecutableSettings(launch_info);
3530 GetArguments(launch_info);
3531 GetEnvironment(launch_info);
3532 GetWorkingDirectory(launch_info);
3533 GetStopAtEntry(launch_info);
3534 GetDetachOnError(launch_info);
3535 GetDisableASLR(launch_info);
3536 GetPlugin(launch_info);
3537 GetArch(launch_info);
3538 GetShell(launch_info);
3539 GetStandardIO(launch_info);
3540 GetInheritTCC(launch_info);
3545 bool StopRunningProcess() {
3546 ExecutionContext exe_ctx =
3547 m_debugger.GetCommandInterpreter().GetExecutionContext();
3553 if (!(process && process->
IsAlive()))
3556 FormDelegateSP form_delegate_sp =
3557 FormDelegateSP(
new DetachOrKillProcessFormDelegate(process));
3558 Rect bounds = m_main_window_sp->GetCenteredRect(85, 8);
3559 WindowSP form_window_sp = m_main_window_sp->CreateSubWindow(
3560 form_delegate_sp->GetName().c_str(), bounds,
true);
3561 WindowDelegateSP window_delegate_sp =
3562 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
3563 form_window_sp->SetDelegate(window_delegate_sp);
3569 Target *target = m_debugger.GetSelectedTarget().get();
3571 if (target ==
nullptr) {
3572 SetError(
"No target exists!");
3578 if (exe_module_sp ==
nullptr) {
3579 SetError(
"No executable in target!");
3586 void Launch(Window &window) {
3589 bool all_fields_are_valid = CheckFieldsValidity();
3590 if (!all_fields_are_valid)
3593 bool process_is_running = StopRunningProcess();
3594 if (process_is_running)
3597 Target *target = GetTarget();
3601 StreamString stream;
3602 ProcessLaunchInfo launch_info = GetLaunchInfo();
3605 if (status.
Fail()) {
3612 SetError(
"Launched successfully but target has no process!");
3616 window.GetParent()->RemoveSubWindow(&window);
3620 Debugger &m_debugger;
3621 WindowSP m_main_window_sp;
3623 ArgumentsFieldDelegate *m_arguments_field;
3624 EnvironmentVariableListFieldDelegate *m_target_environment_field;
3625 DirectoryFieldDelegate *m_working_directory_field;
3627 BooleanFieldDelegate *m_show_advanced_field;
3629 BooleanFieldDelegate *m_stop_at_entry_field;
3630 BooleanFieldDelegate *m_detach_on_error_field;
3631 BooleanFieldDelegate *m_disable_aslr_field;
3632 ProcessPluginFieldDelegate *m_plugin_field;
3633 ArchFieldDelegate *m_arch_field;
3634 FileFieldDelegate *m_shell_field;
3635 BooleanFieldDelegate *m_expand_shell_arguments_field;
3636 BooleanFieldDelegate *m_disable_standard_io_field;
3637 FileFieldDelegate *m_standard_input_field;
3638 FileFieldDelegate *m_standard_output_field;
3639 FileFieldDelegate *m_standard_error_field;
3641 BooleanFieldDelegate *m_show_inherited_environment_field;
3642 EnvironmentVariableListFieldDelegate *m_inherited_environment_field;
3649class SearcherDelegate {
3651 SearcherDelegate() =
default;
3653 virtual ~SearcherDelegate() =
default;
3655 virtual int GetNumberOfMatches() = 0;
3658 virtual const std::string &GetMatchTextAtIndex(
int index) = 0;
3662 virtual void UpdateMatches(
const std::string &text) = 0;
3666 virtual void ExecuteCallback(
int match_index) = 0;
3669typedef std::shared_ptr<SearcherDelegate> SearcherDelegateSP;
3671class SearcherWindowDelegate :
public WindowDelegate {
3673 SearcherWindowDelegate(SearcherDelegateSP &delegate_sp)
3674 : m_delegate_sp(delegate_sp), m_text_field(
"Search",
"", false) {
3696 int GetLastVisibleMatch(
int height) {
3697 int index = m_first_visible_match + height;
3698 return std::min(index, m_delegate_sp->GetNumberOfMatches()) - 1;
3701 int GetNumberOfVisibleMatches(
int height) {
3702 return GetLastVisibleMatch(height) - m_first_visible_match + 1;
3705 void UpdateScrolling(Surface &surface) {
3706 if (m_selected_match < m_first_visible_match) {
3707 m_first_visible_match = m_selected_match;
3711 int height = surface.GetHeight();
3712 int last_visible_match = GetLastVisibleMatch(height);
3713 if (m_selected_match > last_visible_match) {
3714 m_first_visible_match = m_selected_match - height + 1;
3718 void DrawMatches(Surface &surface) {
3719 if (m_delegate_sp->GetNumberOfMatches() == 0)
3722 UpdateScrolling(surface);
3724 int count = GetNumberOfVisibleMatches(surface.GetHeight());
3725 for (
int i = 0; i < count; i++) {
3726 surface.MoveCursor(1, i);
3727 int current_match = m_first_visible_match + i;
3728 if (current_match == m_selected_match)
3729 surface.AttributeOn(A_REVERSE);
3731 m_delegate_sp->GetMatchTextAtIndex(current_match).c_str());
3732 if (current_match == m_selected_match)
3733 surface.AttributeOff(A_REVERSE);
3737 void DrawContent(Surface &surface) {
3738 Rect content_bounds = surface.GetFrame();
3739 Rect text_field_bounds, matchs_bounds;
3740 content_bounds.HorizontalSplit(m_text_field.FieldDelegateGetHeight(),
3741 text_field_bounds, matchs_bounds);
3742 Surface text_field_surface = surface.SubSurface(text_field_bounds);
3743 Surface matches_surface = surface.SubSurface(matchs_bounds);
3745 m_text_field.FieldDelegateDraw(text_field_surface,
true);
3746 DrawMatches(matches_surface);
3749 bool WindowDelegateDraw(Window &window,
bool force)
override {
3752 window.DrawTitleBox(window.GetName(),
"Press Esc to Cancel");
3754 Rect content_bounds = window.GetFrame();
3755 content_bounds.Inset(2, 2);
3756 Surface content_surface = window.SubSurface(content_bounds);
3758 DrawContent(content_surface);
3763 if (m_selected_match != m_delegate_sp->GetNumberOfMatches() - 1)
3767 void SelectPrevious() {
3768 if (m_selected_match != 0)
3772 void ExecuteCallback(Window &window) {
3773 m_delegate_sp->ExecuteCallback(m_selected_match);
3774 window.GetParent()->RemoveSubWindow(&window);
3777 void UpdateMatches() {
3778 m_delegate_sp->UpdateMatches(m_text_field.GetText());
3779 m_selected_match = 0;
3782 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override {
3787 ExecuteCallback(window);
3798 window.GetParent()->RemoveSubWindow(&window);
3804 if (m_text_field.FieldDelegateHandleChar(key) == eKeyHandled)
3811 SearcherDelegateSP m_delegate_sp;
3812 TextFieldDelegate m_text_field;
3814 int m_selected_match = 0;
3816 int m_first_visible_match = 0;
3826class CommonCompletionSearcherDelegate :
public SearcherDelegate {
3828 typedef std::function<void(
const std::string &)> CallbackType;
3830 CommonCompletionSearcherDelegate(Debugger &debugger, uint32_t completion_mask,
3831 CallbackType callback)
3832 : m_debugger(debugger), m_completion_mask(completion_mask),
3833 m_callback(callback) {}
3835 int GetNumberOfMatches()
override {
return m_matches.GetSize(); }
3837 const std::string &GetMatchTextAtIndex(
int index)
override {
3838 return m_matches[index];
3841 void UpdateMatches(
const std::string &text)
override {
3842 CompletionResult result;
3843 CompletionRequest request(text.c_str(), text.size(), result);
3845 m_debugger.GetCommandInterpreter(), m_completion_mask, request,
3850 void ExecuteCallback(
int match_index)
override {
3851 m_callback(m_matches[match_index]);
3855 Debugger &m_debugger;
3857 uint32_t m_completion_mask;
3860 CallbackType m_callback;
3861 StringList m_matches;
3870 virtual ~MenuDelegate() =
default;
3872 virtual MenuActionResult MenuDelegateAction(Menu &menu) = 0;
3875class Menu :
public WindowDelegate {
3877 enum class Type {
Invalid, Bar, Item, Separator };
3883 Menu(
const char *name,
const char *key_name,
int key_value,
3884 uint64_t identifier);
3886 ~Menu()
override =
default;
3888 const MenuDelegateSP &GetDelegate()
const {
return m_delegate_sp; }
3890 void SetDelegate(
const MenuDelegateSP &delegate_sp) {
3891 m_delegate_sp = delegate_sp;
3894 void RecalculateNameLengths();
3896 void AddSubmenu(
const MenuSP &menu_sp);
3898 int DrawAndRunMenu(Window &window);
3900 void DrawMenuTitle(Window &window,
bool highlight);
3902 bool WindowDelegateDraw(Window &window,
bool force)
override;
3904 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override;
3906 MenuActionResult ActionPrivate(Menu &menu) {
3907 MenuActionResult result = MenuActionResult::NotHandled;
3908 if (m_delegate_sp) {
3909 result = m_delegate_sp->MenuDelegateAction(menu);
3910 if (result != MenuActionResult::NotHandled)
3912 }
else if (m_parent) {
3913 result = m_parent->ActionPrivate(menu);
3914 if (result != MenuActionResult::NotHandled)
3917 return m_canned_result;
3920 MenuActionResult Action() {
3923 return ActionPrivate(*
this);
3926 void SetCannedResult(MenuActionResult result) { m_canned_result = result; }
3928 Menus &GetSubmenus() {
return m_submenus; }
3930 const Menus &GetSubmenus()
const {
return m_submenus; }
3932 int GetSelectedSubmenuIndex()
const {
return m_selected; }
3934 void SetSelectedSubmenuIndex(
int idx) { m_selected = idx; }
3936 Type GetType()
const {
return m_type; }
3938 int GetStartingColumn()
const {
return m_start_col; }
3940 void SetStartingColumn(
int col) { m_start_col = col; }
3942 int GetKeyValue()
const {
return m_key_value; }
3944 std::string &
GetName() {
return m_name; }
3946 int GetDrawWidth()
const {
3947 return m_max_submenu_name_length + m_max_submenu_key_name_length + 8;
3950 uint64_t GetIdentifier()
const {
return m_identifier; }
3952 void SetIdentifier(uint64_t identifier) { m_identifier = identifier; }
3956 std::string m_key_name;
3957 uint64_t m_identifier;
3961 int m_max_submenu_name_length;
3962 int m_max_submenu_key_name_length;
3966 WindowSP m_menu_window_sp;
3967 MenuActionResult m_canned_result;
3968 MenuDelegateSP m_delegate_sp;
3972Menu::Menu(Type type)
3973 : m_name(), m_key_name(), m_identifier(0), m_type(type), m_key_value(0),
3974 m_start_col(0), m_max_submenu_name_length(0),
3975 m_max_submenu_key_name_length(0), m_selected(0), m_parent(nullptr),
3976 m_submenus(), m_canned_result(MenuActionResult::NotHandled),
3980Menu::Menu(
const char *name,
const char *key_name,
int key_value,
3981 uint64_t identifier)
3982 : m_name(), m_key_name(), m_identifier(identifier), m_type(
Type::
Invalid),
3983 m_key_value(key_value), m_start_col(0), m_max_submenu_name_length(0),
3984 m_max_submenu_key_name_length(0), m_selected(0), m_parent(nullptr),
3985 m_submenus(), m_canned_result(MenuActionResult::NotHandled),
3987 if (name && name[0]) {
3989 m_type = Type::Item;
3990 if (key_name && key_name[0])
3991 m_key_name = key_name;
3993 m_type = Type::Separator;
3997void Menu::RecalculateNameLengths() {
3998 m_max_submenu_name_length = 0;
3999 m_max_submenu_key_name_length = 0;
4000 Menus &submenus = GetSubmenus();
4001 const size_t num_submenus = submenus.size();
4002 for (
size_t i = 0; i < num_submenus; ++i) {
4003 Menu *submenu = submenus[i].get();
4004 if (
static_cast<size_t>(m_max_submenu_name_length) < submenu->m_name.size())
4005 m_max_submenu_name_length = submenu->m_name.size();
4006 if (
static_cast<size_t>(m_max_submenu_key_name_length) <
4007 submenu->m_key_name.size())
4008 m_max_submenu_key_name_length = submenu->m_key_name.size();
4012void Menu::AddSubmenu(
const MenuSP &menu_sp) {
4013 menu_sp->m_parent =
this;
4014 if (
static_cast<size_t>(m_max_submenu_name_length) < menu_sp->m_name.size())
4015 m_max_submenu_name_length = menu_sp->m_name.size();
4016 if (
static_cast<size_t>(m_max_submenu_key_name_length) <
4017 menu_sp->m_key_name.size())
4018 m_max_submenu_key_name_length = menu_sp->m_key_name.size();
4019 m_submenus.push_back(menu_sp);
4022void Menu::DrawMenuTitle(Window &window,
bool highlight) {
4023 if (m_type == Type::Separator) {
4024 window.MoveCursor(0, window.GetCursorY());
4025 window.PutChar(ACS_LTEE);
4026 int width = window.GetWidth();
4029 for (
int i = 0; i < width; ++i)
4030 window.PutChar(ACS_HLINE);
4032 window.PutChar(ACS_RTEE);
4034 const int shortcut_key = m_key_value;
4035 bool underlined_shortcut =
false;
4036 const attr_t highlight_attr = A_REVERSE;
4038 window.AttributeOn(highlight_attr);
4039 if (llvm::isPrint(shortcut_key)) {
4040 size_t lower_pos = m_name.find(tolower(shortcut_key));
4041 size_t upper_pos = m_name.find(toupper(shortcut_key));
4042 const char *name = m_name.c_str();
4043 size_t pos = std::min<size_t>(lower_pos, upper_pos);
4044 if (pos != std::string::npos) {
4045 underlined_shortcut =
true;
4047 window.PutCString(name, pos);
4050 const attr_t shortcut_attr = A_UNDERLINE | A_BOLD;
4051 window.AttributeOn(shortcut_attr);
4052 window.PutChar(name[0]);
4053 window.AttributeOff(shortcut_attr);
4056 window.PutCString(name);
4060 if (!underlined_shortcut) {
4061 window.PutCString(m_name.c_str());
4065 window.AttributeOff(highlight_attr);
4067 if (m_key_name.empty()) {
4068 if (!underlined_shortcut && llvm::isPrint(m_key_value)) {
4069 window.AttributeOn(COLOR_PAIR(MagentaOnWhite));
4070 window.Printf(
" (%c)", m_key_value);
4071 window.AttributeOff(COLOR_PAIR(MagentaOnWhite));
4074 window.AttributeOn(COLOR_PAIR(MagentaOnWhite));
4075 window.Printf(
" (%s)", m_key_name.c_str());
4076 window.AttributeOff(COLOR_PAIR(MagentaOnWhite));
4081bool Menu::WindowDelegateDraw(Window &window,
bool force) {
4082 Menus &submenus = GetSubmenus();
4083 const size_t num_submenus = submenus.size();
4084 const int selected_idx = GetSelectedSubmenuIndex();
4085 Menu::Type menu_type = GetType();
4086 switch (menu_type) {
4087 case Menu::Type::Bar: {
4088 window.SetBackground(BlackOnWhite);
4089 window.MoveCursor(0, 0);
4090 for (
size_t i = 0; i < num_submenus; ++i) {
4091 Menu *menu = submenus[i].get();
4093 window.PutChar(
' ');
4094 menu->SetStartingColumn(window.GetCursorX());
4095 window.PutCString(
"| ");
4096 menu->DrawMenuTitle(window,
false);
4098 window.PutCString(
" |");
4101 case Menu::Type::Item: {
4108 window.SetBackground(BlackOnWhite);
4110 for (
size_t i = 0; i < num_submenus; ++i) {
4111 const bool is_selected = (i ==
static_cast<size_t>(selected_idx));
4112 window.MoveCursor(x, y + i);
4118 submenus[i]->DrawMenuTitle(window, is_selected);
4120 window.MoveCursor(cursor_x, cursor_y);
4124 case Menu::Type::Separator:
4130HandleCharResult Menu::WindowDelegateHandleChar(Window &window,
int key) {
4131 HandleCharResult result = eKeyNotHandled;
4133 Menus &submenus = GetSubmenus();
4134 const size_t num_submenus = submenus.size();
4135 const int selected_idx = GetSelectedSubmenuIndex();
4136 Menu::Type menu_type = GetType();
4137 if (menu_type == Menu::Type::Bar) {
4143 if (selected_idx <
static_cast<int>(num_submenus))
4144 run_menu_sp = submenus[selected_idx];
4145 else if (!submenus.empty())
4146 run_menu_sp = submenus.front();
4147 result = eKeyHandled;
4152 if (m_selected >=
static_cast<int>(num_submenus))
4154 if (m_selected <
static_cast<int>(num_submenus))
4155 run_menu_sp = submenus[m_selected];
4156 else if (!submenus.empty())
4157 run_menu_sp = submenus.front();
4158 result = eKeyHandled;
4164 m_selected = num_submenus - 1;
4165 if (m_selected <
static_cast<int>(num_submenus))
4166 run_menu_sp = submenus[m_selected];
4167 else if (!submenus.empty())
4168 run_menu_sp = submenus.front();
4169 result = eKeyHandled;
4173 for (
size_t i = 0; i < num_submenus; ++i) {
4174 if (submenus[i]->GetKeyValue() == key) {
4175 SetSelectedSubmenuIndex(i);
4176 run_menu_sp = submenus[i];
4177 result = eKeyHandled;
4188 if (run_menu_sp->Action() == MenuActionResult::Quit)
4189 return eQuitApplication;
4192 menu_bounds.origin.x = run_menu_sp->GetStartingColumn();
4193 menu_bounds.origin.y = 1;
4194 menu_bounds.size.width = run_menu_sp->GetDrawWidth();
4195 menu_bounds.size.height = run_menu_sp->GetSubmenus().size() + 2;
4196 if (m_menu_window_sp)
4197 window.GetParent()->RemoveSubWindow(m_menu_window_sp.get());
4199 m_menu_window_sp = window.GetParent()->CreateSubWindow(
4200 run_menu_sp->GetName().c_str(), menu_bounds,
true);
4201 m_menu_window_sp->SetDelegate(run_menu_sp);
4203 }
else if (menu_type == Menu::Type::Item) {
4206 if (m_submenus.size() > 1) {
4207 const int start_select = m_selected;
4208 while (++m_selected != start_select) {
4209 if (
static_cast<size_t>(m_selected) >= num_submenus)
4211 if (m_submenus[m_selected]->GetType() == Type::Separator)
4221 if (m_submenus.size() > 1) {
4222 const int start_select = m_selected;
4223 while (--m_selected != start_select) {
4224 if (m_selected <
static_cast<int>(0))
4225 m_selected = num_submenus - 1;
4226 if (m_submenus[m_selected]->GetType() == Type::Separator)
4236 if (
static_cast<size_t>(selected_idx) < num_submenus) {
4237 if (submenus[selected_idx]->Action() == MenuActionResult::Quit)
4238 return eQuitApplication;
4239 window.GetParent()->RemoveSubWindow(&window);
4246 window.GetParent()->RemoveSubWindow(&window);
4250 for (
size_t i = 0; i < num_submenus; ++i) {
4251 Menu *menu = submenus[i].get();
4252 if (menu->GetKeyValue() == key) {
4253 SetSelectedSubmenuIndex(i);
4254 window.GetParent()->RemoveSubWindow(&window);
4255 if (menu->Action() == MenuActionResult::Quit)
4256 return eQuitApplication;
4262 }
else if (menu_type == Menu::Type::Separator) {
4269 Application(FILE *in, FILE *out) : m_window_sp(), m_in(in), m_out(out) {}
4272 m_window_delegates.clear();
4273 m_window_sp.reset();
4275 ::delscreen(m_screen);
4281 m_screen = ::newterm(
nullptr, m_out, m_in);
4285 ::keypad(stdscr, TRUE);
4288 void Terminate() { ::endwin(); }
4290 void Run(Debugger &debugger) {
4292 int delay_in_tenths_of_a_second = 1;
4300 halfdelay(delay_in_tenths_of_a_second);
4309 m_update_screen =
true;
4310#if defined(__APPLE__)
4311 std::deque<int> escape_chars;
4315 if (m_update_screen) {
4316 m_window_sp->Draw(
false);
4324 m_window_sp->MoveCursor(0, 0);
4327 m_update_screen =
false;
4330#if defined(__APPLE__)
4335 if (escape_chars.empty())
4336 ch = m_window_sp->GetChar();
4338 ch = escape_chars.front();
4339 escape_chars.pop_front();
4341 if (ch == KEY_ESCAPE) {
4342 int ch2 = m_window_sp->GetChar();
4344 int ch3 = m_window_sp->GetChar();
4359 escape_chars.push_back(ch2);
4361 escape_chars.push_back(ch3);
4364 }
else if (ch2 != -1)
4365 escape_chars.push_back(ch2);
4368 int ch = m_window_sp->GetChar();
4372 if (feof(m_in) || ferror(m_in)) {
4377 while (listener_sp->PeekAtNextEvent()) {
4378 listener_sp->GetEvent(event_sp, std::chrono::seconds(0));
4381 Broadcaster *broadcaster = event_sp->GetBroadcaster();
4384 ConstString broadcaster_class(
4386 if (broadcaster_class == broadcaster_class_process) {
4387 m_update_screen =
true;
4395 HandleCharResult key_result = m_window_sp->HandleChar(ch);
4396 switch (key_result) {
4398 m_update_screen =
true;
4400 case eKeyNotHandled:
4402 redrawwin(m_window_sp->get());
4403 m_update_screen =
true;
4406 case eQuitApplication:
4416 WindowSP &GetMainWindow() {
4418 m_window_sp = std::make_shared<Window>(
"main", stdscr,
false);
4422 void TerminalSizeChanged() {
4425 Rect content_bounds = m_window_sp->GetFrame();
4426 m_window_sp->SetBounds(content_bounds);
4427 if (WindowSP menubar_window_sp = m_window_sp->FindSubWindow(
"Menubar"))
4428 menubar_window_sp->SetBounds(content_bounds.MakeMenuBar());
4429 if (WindowSP status_window_sp = m_window_sp->FindSubWindow(
"Status"))
4430 status_window_sp->SetBounds(content_bounds.MakeStatusBar());
4432 WindowSP source_window_sp = m_window_sp->FindSubWindow(
"Source");
4433 WindowSP variables_window_sp = m_window_sp->FindSubWindow(
"Variables");
4434 WindowSP registers_window_sp = m_window_sp->FindSubWindow(
"Registers");
4435 WindowSP threads_window_sp = m_window_sp->FindSubWindow(
"Threads");
4437 Rect threads_bounds;
4438 Rect source_variables_bounds;
4439 content_bounds.VerticalSplitPercentage(0.80, source_variables_bounds,
4441 if (threads_window_sp)
4442 threads_window_sp->SetBounds(threads_bounds);
4444 source_variables_bounds = content_bounds;
4447 Rect variables_registers_bounds;
4448 source_variables_bounds.HorizontalSplitPercentage(
4449 0.70, source_bounds, variables_registers_bounds);
4450 if (variables_window_sp || registers_window_sp) {
4451 if (variables_window_sp && registers_window_sp) {
4452 Rect variables_bounds;
4453 Rect registers_bounds;
4454 variables_registers_bounds.VerticalSplitPercentage(
4455 0.50, variables_bounds, registers_bounds);
4456 variables_window_sp->SetBounds(variables_bounds);
4457 registers_window_sp->SetBounds(registers_bounds);
4458 }
else if (variables_window_sp) {
4459 variables_window_sp->SetBounds(variables_registers_bounds);
4461 registers_window_sp->SetBounds(variables_registers_bounds);
4464 source_bounds = source_variables_bounds;
4467 source_window_sp->SetBounds(source_bounds);
4470 redrawwin(m_window_sp->get());
4471 m_update_screen =
true;
4475 WindowSP m_window_sp;
4476 WindowDelegates m_window_delegates;
4477 SCREEN *m_screen =
nullptr;
4480 bool m_update_screen =
false;
4489 ValueObjectUpdater value;
4492 uint32_t children_stop_id = 0;
4496 bool might_have_children;
4497 bool expanded =
false;
4498 bool calculated_children =
false;
4499 std::vector<Row> children;
4502 : value(v), parent(p),
4503 might_have_children(v ? v->MightHaveChildren() : false) {}
4505 size_t GetDepth()
const {
4507 return 1 + parent->GetDepth();
4511 void Expand() { expanded =
true; }
4513 std::vector<Row> &GetChildren() {
4515 auto stop_id = process_sp->GetStopID();
4516 if (process_sp && stop_id != children_stop_id) {
4517 children_stop_id = stop_id;
4518 calculated_children =
false;
4520 if (!calculated_children) {
4522 calculated_children =
true;
4525 const uint32_t num_children = valobj->GetNumChildrenIgnoringErrors();
4526 for (
size_t i = 0; i < num_children; ++i) {
4527 children.push_back(Row(valobj->GetChildAtIndex(i),
this));
4536 calculated_children =
false;
4540 void DrawTree(Window &window) {
4542 parent->DrawTreeForChild(window,
this, 0);
4544 if (might_have_children &&
4545 (!calculated_children || !GetChildren().empty())) {
4563 window.PutChar(ACS_DIAMOND);
4564 window.PutChar(ACS_HLINE);
4568 void DrawTreeForChild(Window &window, Row *child, uint32_t reverse_depth) {
4570 parent->DrawTreeForChild(window,
this, reverse_depth + 1);
4572 if (&GetChildren().back() == child) {
4574 if (reverse_depth == 0) {
4575 window.PutChar(ACS_LLCORNER);
4576 window.PutChar(ACS_HLINE);
4578 window.PutChar(
' ');
4579 window.PutChar(
' ');
4582 if (reverse_depth == 0) {
4583 window.PutChar(ACS_LTEE);
4584 window.PutChar(ACS_HLINE);
4586 window.PutChar(ACS_VLINE);
4587 window.PutChar(
' ');
4593struct DisplayOptions {
4601 TreeDelegate() =
default;
4602 virtual ~TreeDelegate() =
default;
4604 virtual void TreeDelegateDrawTreeItem(TreeItem &item, Window &window) = 0;
4605 virtual void TreeDelegateGenerateChildren(TreeItem &item) = 0;
4606 virtual void TreeDelegateUpdateSelection(TreeItem &root,
int &selection_index,
4607 TreeItem *&selected_item) {}
4610 virtual bool TreeDelegateItemSelected(TreeItem &item) = 0;
4611 virtual bool TreeDelegateExpandRootByDefault() {
return false; }
4615 virtual bool TreeDelegateShouldDraw() {
return true; }
4618typedef std::shared_ptr<TreeDelegate> TreeDelegateSP;
4620struct TreeItemData {
4621 TreeItemData(TreeItem *parent, TreeDelegate &delegate,
4622 bool might_have_children,
bool is_expanded)
4623 : m_parent(parent), m_delegate(&delegate),
4624 m_might_have_children(might_have_children), m_is_expanded(is_expanded) {
4629 TreeDelegate *m_delegate;
4630 void *m_user_data =
nullptr;
4631 uint64_t m_identifier = 0;
4635 bool m_might_have_children;
4636 bool m_is_expanded =
false;
4639class TreeItem :
public TreeItemData {
4641 TreeItem(TreeItem *parent, TreeDelegate &delegate,
bool might_have_children)
4642 : TreeItemData(parent, delegate, might_have_children,
4644 ? delegate.TreeDelegateExpandRootByDefault()
4648 TreeItem(
const TreeItem &) =
delete;
4649 TreeItem &operator=(
const TreeItem &rhs) =
delete;
4651 TreeItem &operator=(TreeItem &&rhs) {
4653 TreeItemData::operator=(std::move(rhs));
4654 AdoptChildren(rhs.m_children);
4659 TreeItem(TreeItem &&rhs) : TreeItemData(std::move(rhs)) {
4660 AdoptChildren(rhs.m_children);
4663 size_t GetDepth()
const {
4665 return 1 + m_parent->GetDepth();
4669 int GetRowIndex()
const {
return m_row_idx; }
4671 void ClearChildren() { m_children.clear(); }
4673 void Resize(
size_t n, TreeDelegate &delegate,
bool might_have_children) {
4674 if (m_children.size() >= n) {
4675 m_children.erase(m_children.begin() + n, m_children.end());
4678 m_children.reserve(n);
4679 std::generate_n(std::back_inserter(m_children), n - m_children.size(),
4680 [&, parent =
this]() {
4681 return TreeItem(parent, delegate, might_have_children);
4685 TreeItem &operator[](
size_t i) {
return m_children[i]; }
4687 void SetRowIndex(
int row_idx) { m_row_idx = row_idx; }
4689 size_t GetNumChildren() {
4690 m_delegate->TreeDelegateGenerateChildren(*
this);
4691 return m_children.size();
4694 void ItemWasSelected() { m_delegate->TreeDelegateItemSelected(*
this); }
4696 void CalculateRowIndexes(
int &row_idx) {
4697 SetRowIndex(row_idx);
4700 const bool expanded = IsExpanded();
4704 if (m_parent ==
nullptr || expanded)
4707 for (
auto &item : m_children) {
4709 item.CalculateRowIndexes(row_idx);
4711 item.SetRowIndex(-1);
4715 TreeItem *GetParent() {
return m_parent; }
4717 bool IsExpanded()
const {
return m_is_expanded; }
4719 void Expand() { m_is_expanded =
true; }
4721 void Unexpand() { m_is_expanded =
false; }
4723 bool Draw(Window &window,
const int first_visible_row,
4724 const uint32_t selected_row_idx,
int &row_idx,
int &num_rows_left) {
4725 if (num_rows_left <= 0)
4728 if (m_row_idx >= first_visible_row) {
4729 window.MoveCursor(2, row_idx + 1);
4732 m_parent->DrawTreeForChild(window,
this, 0);
4734 if (m_might_have_children) {
4752 window.PutChar(ACS_DIAMOND);
4753 window.PutChar(ACS_HLINE);
4755 bool highlight = (selected_row_idx ==
static_cast<size_t>(m_row_idx)) &&
4759 window.AttributeOn(A_REVERSE);
4761 m_delegate->TreeDelegateDrawTreeItem(*
this, window);
4764 window.AttributeOff(A_REVERSE);
4769 if (num_rows_left <= 0)
4773 for (
auto &item : m_children) {
4776 if (!item.Draw(window, first_visible_row, selected_row_idx, row_idx,
4781 return num_rows_left >= 0;
4784 void DrawTreeForChild(Window &window, TreeItem *child,
4785 uint32_t reverse_depth) {
4787 m_parent->DrawTreeForChild(window,
this, reverse_depth + 1);
4789 if (&m_children.back() == child) {
4791 if (reverse_depth == 0) {
4792 window.PutChar(ACS_LLCORNER);
4793 window.PutChar(ACS_HLINE);
4795 window.PutChar(
' ');
4796 window.PutChar(
' ');
4799 if (reverse_depth == 0) {
4800 window.PutChar(ACS_LTEE);
4801 window.PutChar(ACS_HLINE);
4803 window.PutChar(ACS_VLINE);
4804 window.PutChar(
' ');
4809 TreeItem *GetItemForRowIndex(uint32_t row_idx) {
4810 if (
static_cast<uint32_t
>(m_row_idx) == row_idx)
4812 if (m_children.empty())
4815 for (
auto &item : m_children) {
4816 TreeItem *selected_item_ptr = item.GetItemForRowIndex(row_idx);
4817 if (selected_item_ptr)
4818 return selected_item_ptr;
4824 void *GetUserData()
const {
return m_user_data; }
4826 void SetUserData(
void *user_data) { m_user_data = user_data; }
4828 uint64_t GetIdentifier()
const {
return m_identifier; }
4830 void SetIdentifier(uint64_t identifier) { m_identifier = identifier; }
4832 const std::string &GetText()
const {
return m_text; }
4834 void SetText(
const char *text) {
4835 if (text ==
nullptr) {
4842 void SetMightHaveChildren(
bool b) { m_might_have_children = b; }
4845 void AdoptChildren(std::vector<TreeItem> &children) {
4846 m_children = std::move(children);
4847 for (
auto &child : m_children)
4848 child.m_parent =
this;
4851 std::vector<TreeItem> m_children;
4854class TreeWindowDelegate :
public WindowDelegate {
4856 TreeWindowDelegate(Debugger &debugger,
const TreeDelegateSP &delegate_sp)
4857 : m_debugger(debugger), m_delegate_sp(delegate_sp),
4858 m_root(nullptr, *delegate_sp, true) {}
4860 int NumVisibleRows()
const {
return m_max_y - m_min_y; }
4862 bool WindowDelegateDraw(Window &window,
bool force)
override {
4865 m_max_x = window.GetWidth() - 1;
4866 m_max_y = window.GetHeight() - 1;
4869 window.DrawTitleBox(window.GetName());
4871 if (!m_delegate_sp->TreeDelegateShouldDraw()) {
4872 m_selected_item =
nullptr;
4876 const int num_visible_rows = NumVisibleRows();
4878 m_root.CalculateRowIndexes(m_num_rows);
4879 m_delegate_sp->TreeDelegateUpdateSelection(m_root, m_selected_row_idx,
4885 if (m_first_visible_row > 0 && m_num_rows < num_visible_rows)
4886 m_first_visible_row = 0;
4889 if (m_selected_row_idx < m_first_visible_row)
4890 m_first_visible_row = m_selected_row_idx;
4891 else if (m_first_visible_row + num_visible_rows <= m_selected_row_idx)
4892 m_first_visible_row = m_selected_row_idx - num_visible_rows + 1;
4895 int num_rows_left = num_visible_rows;
4896 m_root.Draw(window, m_first_visible_row, m_selected_row_idx, row_idx,
4899 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4904 const char *WindowDelegateGetHelpText()
override {
4905 return "Thread window keyboard shortcuts:";
4908 KeyHelp *WindowDelegateGetKeyHelp()
override {
4909 static curses::KeyHelp g_source_view_key_help[] = {
4910 {KEY_UP,
"Select previous item"},
4911 {KEY_DOWN,
"Select next item"},
4912 {KEY_RIGHT,
"Expand the selected item"},
4914 "Unexpand the selected item or select parent if not expanded"},
4915 {KEY_PPAGE,
"Page up"},
4916 {KEY_NPAGE,
"Page down"},
4917 {
'h',
"Show help dialog"},
4918 {
' ',
"Toggle item expansion"},
4922 return g_source_view_key_help;
4925 HandleCharResult WindowDelegateHandleChar(Window &window,
int c)
override {
4930 if (m_first_visible_row > 0) {
4931 if (m_first_visible_row > m_max_y)
4932 m_first_visible_row -= m_max_y;
4934 m_first_visible_row = 0;
4935 m_selected_row_idx = m_first_visible_row;
4936 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4937 if (m_selected_item)
4938 m_selected_item->ItemWasSelected();
4945 if (m_num_rows > m_max_y) {
4946 if (m_first_visible_row + m_max_y < m_num_rows) {
4947 m_first_visible_row += m_max_y;
4948 m_selected_row_idx = m_first_visible_row;
4949 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4950 if (m_selected_item)
4951 m_selected_item->ItemWasSelected();
4957 if (m_selected_row_idx > 0) {
4958 --m_selected_row_idx;
4959 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4960 if (m_selected_item)
4961 m_selected_item->ItemWasSelected();
4966 if (m_selected_row_idx + 1 < m_num_rows) {
4967 ++m_selected_row_idx;
4968 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4969 if (m_selected_item)
4970 m_selected_item->ItemWasSelected();
4975 if (m_selected_item) {
4976 if (!m_selected_item->IsExpanded())
4977 m_selected_item->Expand();
4982 if (m_selected_item) {
4983 if (m_selected_item->IsExpanded())
4984 m_selected_item->Unexpand();
4985 else if (m_selected_item->GetParent()) {
4986 m_selected_row_idx = m_selected_item->GetParent()->GetRowIndex();
4987 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4988 if (m_selected_item)
4989 m_selected_item->ItemWasSelected();
4996 if (m_selected_item) {
4997 if (m_selected_item->IsExpanded())
4998 m_selected_item->Unexpand();
5000 m_selected_item->Expand();
5005 window.CreateHelpSubwindow();
5011 return eKeyNotHandled;
5015 Debugger &m_debugger;
5016 TreeDelegateSP m_delegate_sp;
5018 TreeItem *m_selected_item =
nullptr;
5020 int m_selected_row_idx = 0;
5021 int m_first_visible_row = 0;
5030class TextTreeDelegate :
public TreeDelegate {
5032 TextTreeDelegate() : TreeDelegate() {}
5034 ~TextTreeDelegate()
override =
default;
5036 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5037 window.PutCStringTruncated(1, item.GetText().c_str());
5040 void TreeDelegateGenerateChildren(TreeItem &item)
override {}
5042 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5045class FrameTreeDelegate :
public TreeDelegate {
5047 FrameTreeDelegate() : TreeDelegate() {
5049 "#${frame.index}: {${function.name}${function.pc-offset}}}", m_format);
5052 ~FrameTreeDelegate()
override =
default;
5054 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5057 const uint64_t frame_idx = item.GetIdentifier();
5061 const SymbolContext &sc =
5062 frame_sp->GetSymbolContext(eSymbolContextEverything);
5063 ExecutionContext exe_ctx(frame_sp);
5065 nullptr,
false,
false)) {
5067 window.PutCStringTruncated(right_pad, strm.
GetString().str().c_str());
5073 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5077 bool TreeDelegateItemSelected(TreeItem &item)
override {
5080 thread->
GetProcess()->GetThreadList().SetSelectedThreadByID(
5082 const uint64_t frame_idx = item.GetIdentifier();
5090 FormatEntity::Entry m_format;
5093class ThreadTreeDelegate :
public TreeDelegate {
5095 ThreadTreeDelegate(Debugger &debugger)
5096 : TreeDelegate(), m_debugger(debugger) {
5098 "reason = ${thread.stop-reason}}",
5102 ~ThreadTreeDelegate()
override =
default;
5105 return m_debugger.GetCommandInterpreter()
5106 .GetExecutionContext()
5110 ThreadSP GetThread(
const TreeItem &item) {
5113 return process_sp->GetThreadList().FindThreadByID(item.GetIdentifier());
5117 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5118 ThreadSP thread_sp = GetThread(item);
5121 ExecutionContext exe_ctx(thread_sp);
5123 nullptr,
false,
false)) {
5125 window.PutCStringTruncated(right_pad, strm.
GetString().str().c_str());
5130 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5132 if (process_sp && process_sp->IsAlive()) {
5133 StateType state = process_sp->GetState();
5135 ThreadSP thread_sp = GetThread(item);
5137 if (m_stop_id == process_sp->GetStopID() &&
5138 thread_sp->GetID() == m_tid)
5140 if (!m_frame_delegate_sp) {
5142 m_frame_delegate_sp = std::make_shared<FrameTreeDelegate>();
5145 m_stop_id = process_sp->GetStopID();
5146 m_tid = thread_sp->GetID();
5148 size_t num_frames = thread_sp->GetStackFrameCount();
5149 item.Resize(num_frames, *m_frame_delegate_sp,
false);
5150 for (
size_t i = 0; i < num_frames; ++i) {
5151 item[i].SetUserData(thread_sp.get());
5152 item[i].SetIdentifier(i);
5158 item.ClearChildren();
5161 bool TreeDelegateItemSelected(TreeItem &item)
override {
5163 if (process_sp && process_sp->IsAlive()) {
5164 StateType state = process_sp->GetState();
5166 ThreadSP thread_sp = GetThread(item);
5168 ThreadList &thread_list = thread_sp->GetProcess()->GetThreadList();
5169 std::lock_guard<std::recursive_mutex> guard(thread_list.
GetMutex());
5171 if (selected_thread_sp->GetID() != thread_sp->GetID()) {
5182 Debugger &m_debugger;
5183 std::shared_ptr<FrameTreeDelegate> m_frame_delegate_sp;
5186 FormatEntity::Entry m_format;
5189class ThreadsTreeDelegate :
public TreeDelegate {
5191 ThreadsTreeDelegate(Debugger &debugger)
5192 : TreeDelegate(), m_thread_delegate_sp(), m_debugger(debugger) {
5197 ~ThreadsTreeDelegate()
override =
default;
5200 return m_debugger.GetCommandInterpreter()
5201 .GetExecutionContext()
5205 bool TreeDelegateShouldDraw()
override {
5216 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5218 if (process_sp && process_sp->IsAlive()) {
5220 ExecutionContext exe_ctx(process_sp);
5222 nullptr,
false,
false)) {
5224 window.PutCStringTruncated(right_pad, strm.
GetString().str().c_str());
5229 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5231 m_update_selection =
false;
5232 if (process_sp && process_sp->IsAlive()) {
5233 StateType state = process_sp->GetState();
5235 const uint32_t stop_id = process_sp->GetStopID();
5236 if (m_stop_id == stop_id)
5239 m_stop_id = stop_id;
5240 m_update_selection =
true;
5242 if (!m_thread_delegate_sp) {
5245 m_thread_delegate_sp =
5246 std::make_shared<ThreadTreeDelegate>(m_debugger);
5249 ThreadList &threads = process_sp->GetThreadList();
5250 std::lock_guard<std::recursive_mutex> guard(threads.
GetMutex());
5252 size_t num_threads = threads.
GetSize();
5253 item.Resize(num_threads, *m_thread_delegate_sp,
false);
5254 for (
size_t i = 0; i < num_threads; ++i) {
5256 item[i].SetIdentifier(thread->GetID());
5257 item[i].SetMightHaveChildren(
true);
5258 if (selected_thread->GetID() == thread->GetID())
5264 item.ClearChildren();
5267 void TreeDelegateUpdateSelection(TreeItem &root,
int &selection_index,
5268 TreeItem *&selected_item)
override {
5269 if (!m_update_selection)
5273 if (!(process_sp && process_sp->IsAlive()))
5276 StateType state = process_sp->GetState();
5280 ThreadList &threads = process_sp->GetThreadList();
5281 std::lock_guard<std::recursive_mutex> guard(threads.
GetMutex());
5283 size_t num_threads = threads.
GetSize();
5284 for (
size_t i = 0; i < num_threads; ++i) {
5286 if (selected_thread->GetID() == thread->GetID()) {
5289 selection_index = selected_item->GetRowIndex();
5295 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5297 bool TreeDelegateExpandRootByDefault()
override {
return true; }
5300 std::shared_ptr<ThreadTreeDelegate> m_thread_delegate_sp;
5301 Debugger &m_debugger;
5303 bool m_update_selection =
false;
5304 FormatEntity::Entry m_format;
5307class BreakpointLocationTreeDelegate :
public TreeDelegate {
5309 BreakpointLocationTreeDelegate(Debugger &debugger)
5310 : TreeDelegate(), m_debugger(debugger) {}
5312 ~BreakpointLocationTreeDelegate()
override =
default;
5315 ExecutionContext exe_ctx(
5316 m_debugger.GetCommandInterpreter().GetExecutionContext());
5321 Breakpoint *breakpoint = (Breakpoint *)item.GetUserData();
5325 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5327 Process *process = GetProcess();
5328 StreamString stream;
5329 stream.
Printf(
"%i.%i: ", breakpoint_location->GetBreakpoint().GetID(),
5330 breakpoint_location->GetID());
5331 Address address = breakpoint_location->GetAddress();
5334 window.PutCStringTruncated(1, stream.
GetString().str().c_str());
5340 Address address = breakpoint_location->GetAddress();
5341 SymbolContext symbol_context;
5345 StreamString module_stream;
5347 symbol_context.
module_sp->GetFileSpec().Dump(
5352 if (symbol_context.
comp_unit !=
nullptr) {
5353 StreamString compile_unit_stream;
5354 compile_unit_stream.
PutCString(
"compile unit = ");
5356 &compile_unit_stream);
5359 if (symbol_context.
function !=
nullptr) {
5360 StreamString function_stream;
5368 StreamString location_stream;
5375 if (symbol_context.
symbol) {
5376 StreamString symbol_stream;
5377 if (breakpoint_location->IsReExported())
5378 symbol_stream.
PutCString(
"re-exported target = ");
5387 Process *process = GetProcess();
5389 StreamString address_stream;
5394 BreakpointSiteSP breakpoint_site = breakpoint_location->GetBreakpointSite();
5395 if (breakpoint_location->IsIndirect() && breakpoint_site) {
5396 Address resolved_address;
5397 resolved_address.
SetLoadAddress(breakpoint_site->GetLoadAddress(),
5398 &breakpoint_location->GetTarget());
5400 if (resolved_symbol) {
5401 StreamString indirect_target_stream;
5402 indirect_target_stream.
PutCString(
"indirect target = ");
5409 bool is_resolved = breakpoint_location->IsResolved();
5410 StreamString resolved_stream;
5411 resolved_stream.
Printf(
"resolved = %s", is_resolved ?
"true" :
"false");
5414 bool is_hardware = is_resolved && breakpoint_site->IsHardware();
5415 StreamString hardware_stream;
5416 hardware_stream.
Printf(
"hardware = %s", is_hardware ?
"true" :
"false");
5419 StreamString hit_count_stream;
5420 hit_count_stream.
Printf(
"hit count = %-4u",
5421 breakpoint_location->GetHitCount());
5427 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5429 StringList details = ComputeDetailsList(breakpoint_location);
5431 if (!m_string_delegate_sp)
5432 m_string_delegate_sp = std::make_shared<TextTreeDelegate>();
5434 item.Resize(details.
GetSize(), *m_string_delegate_sp,
false);
5435 for (
size_t i = 0; i < details.
GetSize(); i++) {
5440 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5443 Debugger &m_debugger;
5444 std::shared_ptr<TextTreeDelegate> m_string_delegate_sp;
5447class BreakpointTreeDelegate :
public TreeDelegate {
5449 BreakpointTreeDelegate(Debugger &debugger)
5450 : TreeDelegate(), m_debugger(debugger),
5451 m_breakpoint_location_delegate_sp() {}
5453 ~BreakpointTreeDelegate()
override =
default;
5456 TargetSP target = m_debugger.GetSelectedTarget();
5461 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5463 StreamString stream;
5464 stream.
Format(
"{0}: ", breakpoint->GetID());
5465 breakpoint->GetResolverDescription(&stream);
5466 breakpoint->GetFilterDescription(&stream);
5467 window.PutCStringTruncated(1, stream.
GetString().str().c_str());
5470 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5473 if (!m_breakpoint_location_delegate_sp)
5474 m_breakpoint_location_delegate_sp =
5475 std::make_shared<BreakpointLocationTreeDelegate>(m_debugger);
5477 item.Resize(breakpoint->GetNumLocations(),
5478 *m_breakpoint_location_delegate_sp,
true);
5479 for (
size_t i = 0; i < breakpoint->GetNumLocations(); i++) {
5480 item[i].SetIdentifier(i);
5481 item[i].SetUserData(breakpoint.get());
5485 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5488 Debugger &m_debugger;
5489 std::shared_ptr<BreakpointLocationTreeDelegate>
5490 m_breakpoint_location_delegate_sp;
5493class BreakpointsTreeDelegate :
public TreeDelegate {
5495 BreakpointsTreeDelegate(Debugger &debugger)
5496 : TreeDelegate(), m_debugger(debugger), m_breakpoint_delegate_sp() {}
5498 ~BreakpointsTreeDelegate()
override =
default;
5500 bool TreeDelegateShouldDraw()
override {
5501 TargetSP target = m_debugger.GetSelectedTarget();
5508 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5509 window.PutCString(
"Breakpoints");
5512 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5513 TargetSP target = m_debugger.GetSelectedTarget();
5515 BreakpointList &breakpoints = target->GetBreakpointList(
false);
5516 std::unique_lock<std::recursive_mutex> lock;
5519 if (!m_breakpoint_delegate_sp)
5520 m_breakpoint_delegate_sp =
5521 std::make_shared<BreakpointTreeDelegate>(m_debugger);
5523 item.Resize(breakpoints.
GetSize(), *m_breakpoint_delegate_sp,
true);
5524 for (
size_t i = 0; i < breakpoints.
GetSize(); i++) {
5525 item[i].SetIdentifier(i);
5529 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5531 bool TreeDelegateExpandRootByDefault()
override {
return true; }
5534 Debugger &m_debugger;
5535 std::shared_ptr<BreakpointTreeDelegate> m_breakpoint_delegate_sp;
5538class ValueObjectListDelegate :
public WindowDelegate {
5540 ValueObjectListDelegate() : m_rows() {}
5542 ValueObjectListDelegate(ValueObjectList &valobj_list) : m_rows() {
5543 SetValues(valobj_list);
5546 ~ValueObjectListDelegate()
override =
default;
5548 void SetValues(ValueObjectList &valobj_list) {
5549 m_selected_row =
nullptr;
5550 m_selected_row_idx = 0;
5551 m_first_visible_row = 0;
5554 for (
auto &valobj_sp : valobj_list.
GetObjects())
5555 m_rows.push_back(Row(valobj_sp,
nullptr));
5558 bool WindowDelegateDraw(Window &window,
bool force)
override {
5562 m_max_x = window.GetWidth() - 1;
5563 m_max_y = window.GetHeight() - 1;
5566 window.DrawTitleBox(window.GetName());
5568 const int num_visible_rows = NumVisibleRows();
5569 const int num_rows = CalculateTotalNumberRows(m_rows);
5574 if (m_first_visible_row > 0 && num_rows < num_visible_rows)
5575 m_first_visible_row = 0;
5578 if (m_selected_row_idx < m_first_visible_row)
5579 m_first_visible_row = m_selected_row_idx;
5580 else if (m_first_visible_row + num_visible_rows <= m_selected_row_idx)
5581 m_first_visible_row = m_selected_row_idx - num_visible_rows + 1;
5583 DisplayRows(window, m_rows, g_options);
5586 m_selected_row = GetRowForRowIndex(m_selected_row_idx);
5590 window.MoveCursor(m_selected_row->x, m_selected_row->y);
5595 KeyHelp *WindowDelegateGetKeyHelp()
override {
5596 static curses::KeyHelp g_source_view_key_help[] = {
5597 {KEY_UP,
"Select previous item"},
5598 {KEY_DOWN,
"Select next item"},
5599 {KEY_RIGHT,
"Expand selected item"},
5600 {KEY_LEFT,
"Unexpand selected item or select parent if not expanded"},
5601 {KEY_PPAGE,
"Page up"},
5602 {KEY_NPAGE,
"Page down"},
5603 {
'A',
"Format as annotated address"},
5604 {
'b',
"Format as binary"},
5605 {
'B',
"Format as hex bytes with ASCII"},
5606 {
'c',
"Format as character"},
5607 {
'd',
"Format as a signed integer"},
5608 {
'D',
"Format selected value using the default format for the type"},
5609 {
'f',
"Format as float"},
5610 {
'h',
"Show help dialog"},
5611 {
'i',
"Format as instructions"},
5612 {
'o',
"Format as octal"},
5613 {
'p',
"Format as pointer"},
5614 {
's',
"Format as C string"},
5615 {
't',
"Toggle showing/hiding type names"},
5616 {
'u',
"Format as an unsigned integer"},
5617 {
'x',
"Format as hex"},
5618 {
'X',
"Format as uppercase hex"},
5619 {
' ',
"Toggle item expansion"},
5623 return g_source_view_key_help;
5626 HandleCharResult WindowDelegateHandleChar(Window &window,
int c)
override {
5643 if (m_selected_row) {
5644 auto valobj_sp = m_selected_row->value.GetSP();
5646 valobj_sp->SetFormat(FormatForChar(c));
5652 g_options.show_types = !g_options.show_types;
5658 if (m_first_visible_row > 0) {
5659 if (
static_cast<int>(m_first_visible_row) > m_max_y)
5660 m_first_visible_row -= m_max_y;
5662 m_first_visible_row = 0;
5663 m_selected_row_idx = m_first_visible_row;
5670 if (m_num_rows >
static_cast<size_t>(m_max_y)) {
5671 if (m_first_visible_row + m_max_y < m_num_rows) {
5672 m_first_visible_row += m_max_y;
5673 m_selected_row_idx = m_first_visible_row;
5679 if (m_selected_row_idx > 0)
5680 --m_selected_row_idx;
5684 if (m_selected_row_idx + 1 < m_num_rows)
5685 ++m_selected_row_idx;
5689 if (m_selected_row) {
5690 if (!m_selected_row->expanded)
5691 m_selected_row->Expand();
5696 if (m_selected_row) {
5697 if (m_selected_row->expanded)
5698 m_selected_row->Unexpand();
5699 else if (m_selected_row->parent)
5700 m_selected_row_idx = m_selected_row->parent->row_idx;
5706 if (m_selected_row) {
5707 if (m_selected_row->expanded)
5708 m_selected_row->Unexpand();
5710 m_selected_row->Expand();
5715 window.CreateHelpSubwindow();
5721 return eKeyNotHandled;
5725 std::vector<Row> m_rows;
5726 Row *m_selected_row =
nullptr;
5727 uint32_t m_selected_row_idx = 0;
5728 uint32_t m_first_visible_row = 0;
5729 uint32_t m_num_rows = 0;
5735 static Format FormatForChar(
int c) {
5769 bool DisplayRowObject(Window &window, Row &row, DisplayOptions &options,
5770 bool highlight,
bool last_child) {
5771 ValueObject *valobj = row.value.GetSP().get();
5773 if (valobj ==
nullptr)
5776 const char *type_name =
5782 window.MoveCursor(row.x, row.y);
5784 row.DrawTree(window);
5787 window.AttributeOn(A_REVERSE);
5789 if (type_name && type_name[0])
5790 window.PrintfTruncated(1,
"(%s) ", type_name);
5792 if (name && name[0])
5793 window.PutCStringTruncated(1, name);
5795 attr_t changd_attr = 0;
5797 changd_attr = COLOR_PAIR(RedOnBlack) | A_BOLD;
5799 if (value && value[0]) {
5800 window.PutCStringTruncated(1,
" = ");
5802 window.AttributeOn(changd_attr);
5803 window.PutCStringTruncated(1, value);
5805 window.AttributeOff(changd_attr);
5808 if (summary && summary[0]) {
5809 window.PutCStringTruncated(1,
" ");
5811 window.AttributeOn(changd_attr);
5812 window.PutCStringTruncated(1, summary);
5814 window.AttributeOff(changd_attr);
5818 window.AttributeOff(A_REVERSE);
5823 void DisplayRows(Window &window, std::vector<Row> &rows,
5824 DisplayOptions &options) {
5828 bool window_is_active = window.IsActive();
5829 for (
auto &row : rows) {
5830 const bool last_child = row.parent && &rows[rows.size() - 1] == &row;
5832 row.row_idx = m_num_rows;
5833 if ((m_num_rows >= m_first_visible_row) &&
5834 ((m_num_rows - m_first_visible_row) <
5835 static_cast<size_t>(NumVisibleRows()))) {
5837 row.y = m_num_rows - m_first_visible_row + 1;
5838 if (DisplayRowObject(window, row, options,
5840 m_num_rows == m_selected_row_idx,
5854 auto &children = row.GetChildren();
5855 if (!children.empty()) {
5856 DisplayRows(window, children, options);
5862 int CalculateTotalNumberRows(std::vector<Row> &rows) {
5864 for (
auto &row : rows) {
5867 row_count += CalculateTotalNumberRows(row.GetChildren());
5872 static Row *GetRowForRowIndexImpl(std::vector<Row> &rows,
size_t &row_index) {
5873 for (
auto &row : rows) {
5879 auto &children = row.GetChildren();
5880 if (!children.empty()) {
5881 Row *result = GetRowForRowIndexImpl(children, row_index);
5891 Row *GetRowForRowIndex(
size_t row_index) {
5892 return GetRowForRowIndexImpl(m_rows, row_index);
5895 int NumVisibleRows()
const {
return m_max_y - m_min_y; }
5897 static DisplayOptions g_options;
5900class FrameVariablesWindowDelegate :
public ValueObjectListDelegate {
5902 FrameVariablesWindowDelegate(Debugger &debugger)
5903 : ValueObjectListDelegate(), m_debugger(debugger) {}
5905 ~FrameVariablesWindowDelegate()
override =
default;
5907 const char *WindowDelegateGetHelpText()
override {
5908 return "Frame variable window keyboard shortcuts:";
5911 bool WindowDelegateDraw(Window &window,
bool force)
override {
5912 ExecutionContext exe_ctx(
5913 m_debugger.GetCommandInterpreter().GetExecutionContext());
5915 Block *frame_block =
nullptr;
5916 StackFrame *frame =
nullptr;
5929 ValueObjectList local_values;
5932 if (m_frame_block != frame_block) {
5933 m_frame_block = frame_block;
5942 ValueObjectSP synthetic_value_sp = value_sp->GetSyntheticValue();
5943 if (synthetic_value_sp)
5944 local_values.
Append(synthetic_value_sp);
5946 local_values.
Append(value_sp);
5950 SetValues(local_values);
5954 m_frame_block =
nullptr;
5956 SetValues(local_values);
5959 return ValueObjectListDelegate::WindowDelegateDraw(window, force);
5963 Debugger &m_debugger;
5964 Block *m_frame_block =
nullptr;
5967class RegistersWindowDelegate :
public ValueObjectListDelegate {
5969 RegistersWindowDelegate(Debugger &debugger)
5970 : ValueObjectListDelegate(), m_debugger(debugger) {}
5972 ~RegistersWindowDelegate()
override =
default;
5974 const char *WindowDelegateGetHelpText()
override {
5975 return "Register window keyboard shortcuts:";
5978 bool WindowDelegateDraw(Window &window,
bool force)
override {
5979 ExecutionContext exe_ctx(
5980 m_debugger.GetCommandInterpreter().GetExecutionContext());
5983 ValueObjectList value_list;
5989 const uint32_t num_sets = reg_ctx->GetRegisterSetCount();
5990 for (uint32_t set_idx = 0; set_idx < num_sets; ++set_idx) {
5995 SetValues(value_list);
5999 if (process && process->
IsAlive())
6004 SetValues(value_list);
6007 return ValueObjectListDelegate::WindowDelegateDraw(window, force);
6011 Debugger &m_debugger;
6015static const char *CursesKeyToCString(
int ch) {
6016 static char g_desc[32];
6017 if (ch >= KEY_F0 && ch < KEY_F0 + 64) {
6018 snprintf(g_desc,
sizeof(g_desc),
"F%u", ch - KEY_F0);
6035 return "delete-line";
6037 return "insert-line";
6039 return "delete-char";
6041 return "insert-char";
6045 return "clear-to-eos";
6047 return "clear-to-eol";
6049 return "scroll-forward";
6051 return "scroll-backward";
6061 return "clear-all-tabs";
6067 return "lower-left key";
6069 return "upper left of keypad";
6071 return "upper right of keypad";
6073 return "center of keypad";
6075 return "lower left of keypad";
6077 return "lower right of keypad";
6079 return "back-tab key";
6083 return "cancel key";
6087 return "command key";
6091 return "create key";
6103 return "message key";
6111 return "options key";
6113 return "previous key";
6117 return "reference key";
6119 return "refresh key";
6121 return "replace key";
6123 return "restart key";
6125 return "resume key";
6129 return "shifted begin key";
6131 return "shifted cancel key";
6133 return "shifted command key";
6135 return "shifted copy key";
6137 return "shifted create key";
6139 return "shifted delete-character key";
6141 return "shifted delete-line key";
6143 return "select key";
6145 return "shifted end key";
6147 return "shifted clear-to-end-of-line key";
6149 return "shifted exit key";
6151 return "shifted find key";
6153 return "shifted help key";
6155 return "shifted home key";
6157 return "shifted insert-character key";
6159 return "shifted left-arrow key";
6161 return "shifted message key";
6163 return "shifted move key";
6165 return "shifted next key";
6167 return "shifted options key";
6169 return "shifted previous key";
6171 return "shifted print key";
6173 return "shifted redo key";
6175 return "shifted replace key";
6177 return "shifted right-arrow key";
6179 return "shifted resume key";
6181 return "shifted save key";
6183 return "shifted suspend key";
6185 return "shifted undo key";
6187 return "suspend key";
6191 return "Mouse event has occurred";
6193 return "Terminal resize event";
6196 return "We were interrupted by an event";
6207 if (llvm::isPrint(ch))
6208 snprintf(g_desc,
sizeof(g_desc),
"%c", ch);
6210 snprintf(g_desc,
sizeof(g_desc),
"\\x%2.2x", ch);
6216HelpDialogDelegate::HelpDialogDelegate(
const char *text,
6217 KeyHelp *key_help_array)
6219 if (text && text[0]) {
6220 m_text.SplitIntoLines(text);
6221 m_text.AppendString(
"");
6223 if (key_help_array) {
6224 for (KeyHelp *key = key_help_array; key->ch; ++key) {
6226 key_description.
Printf(
"%10s - %s", CursesKeyToCString(key->ch),
6228 m_text.AppendString(key_description.
GetString());
6233HelpDialogDelegate::~HelpDialogDelegate() =
default;
6235bool HelpDialogDelegate::WindowDelegateDraw(Window &window,
bool force) {
6237 const int window_height = window.GetHeight();
6240 const int min_y = y;
6241 const int max_y = window_height - 1 - y;
6242 const size_t num_visible_lines = max_y - min_y + 1;
6243 const size_t num_lines = m_text.GetSize();
6244 const char *bottom_message;
6245 if (num_lines <= num_visible_lines)
6246 bottom_message =
"Press any key to exit";
6248 bottom_message =
"Use arrows to scroll, any other key to exit";
6249 window.DrawTitleBox(window.GetName(), bottom_message);
6250 while (y <= max_y) {
6251 window.MoveCursor(x, y);
6252 window.PutCStringTruncated(
6253 1, m_text.GetStringAtIndex(m_first_visible_line + y - min_y));
6259HandleCharResult HelpDialogDelegate::WindowDelegateHandleChar(Window &window,
6262 const size_t num_lines = m_text.GetSize();
6263 const size_t num_visible_lines = window.GetHeight() - 2;
6265 if (num_lines <= num_visible_lines) {
6272 if (m_first_visible_line > 0)
6273 --m_first_visible_line;
6277 if (m_first_visible_line + num_visible_lines < num_lines)
6278 ++m_first_visible_line;
6283 if (m_first_visible_line > 0) {
6284 if (
static_cast<size_t>(m_first_visible_line) >= num_visible_lines)
6285 m_first_visible_line -= num_visible_lines;
6287 m_first_visible_line = 0;
6293 if (m_first_visible_line + num_visible_lines < num_lines) {
6294 m_first_visible_line += num_visible_lines;
6295 if (
static_cast<size_t>(m_first_visible_line) > num_lines)
6296 m_first_visible_line = num_lines - num_visible_lines;
6306 window.GetParent()->RemoveSubWindow(&window);
6310class ApplicationDelegate :
public WindowDelegate,
public MenuDelegate {
6318 eMenuID_TargetCreate,
6319 eMenuID_TargetDelete,
6322 eMenuID_ProcessAttach,
6323 eMenuID_ProcessDetachResume,
6324 eMenuID_ProcessDetachSuspended,
6325 eMenuID_ProcessLaunch,
6326 eMenuID_ProcessContinue,
6327 eMenuID_ProcessHalt,
6328 eMenuID_ProcessKill,
6331 eMenuID_ThreadStepIn,
6332 eMenuID_ThreadStepOver,
6333 eMenuID_ThreadStepOut,
6336 eMenuID_ViewBacktrace,
6337 eMenuID_ViewRegisters,
6339 eMenuID_ViewVariables,
6340 eMenuID_ViewBreakpoints,
6346 ApplicationDelegate(Application &app, Debugger &debugger)
6347 : WindowDelegate(), MenuDelegate(), m_app(app), m_debugger(debugger) {}
6349 ~ApplicationDelegate()
override =
default;
6351 bool WindowDelegateDraw(Window &window,
bool force)
override {
6355 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override {
6358 window.SelectNextWindowAsActive();
6362 window.SelectPreviousWindowAsActive();
6366 window.CreateHelpSubwindow();
6370 return eQuitApplication;
6375 return eKeyNotHandled;
6378 const char *WindowDelegateGetHelpText()
override {
6379 return "Welcome to the LLDB curses GUI.\n\n"
6380 "Press the TAB key to change the selected view.\n"
6381 "Each view has its own keyboard shortcuts, press 'h' to open a "
6382 "dialog to display them.\n\n"
6383 "Common key bindings for all views:";
6386 KeyHelp *WindowDelegateGetKeyHelp()
override {
6387 static curses::KeyHelp g_source_view_key_help[] = {
6388 {
'\t',
"Select next view"},
6389 {KEY_BTAB,
"Select previous view"},
6390 {
'h',
"Show help dialog with view specific key bindings"},
6393 {KEY_UP,
"Select previous"},
6394 {KEY_DOWN,
"Select next"},
6395 {KEY_LEFT,
"Unexpand or select parent"},
6396 {KEY_RIGHT,
"Expand"},
6397 {KEY_PPAGE,
"Page up"},
6398 {KEY_NPAGE,
"Page down"},
6400 return g_source_view_key_help;
6403 MenuActionResult MenuDelegateAction(Menu &menu)
override {
6404 switch (menu.GetIdentifier()) {
6405 case eMenuID_TargetCreate: {
6406 WindowSP main_window_sp = m_app.GetMainWindow();
6407 FormDelegateSP form_delegate_sp =
6408 FormDelegateSP(
new TargetCreateFormDelegate(m_debugger));
6409 Rect bounds = main_window_sp->GetCenteredRect(80, 19);
6410 WindowSP form_window_sp = main_window_sp->CreateSubWindow(
6411 form_delegate_sp->GetName().c_str(), bounds,
true);
6412 WindowDelegateSP window_delegate_sp =
6413 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
6414 form_window_sp->SetDelegate(window_delegate_sp);
6415 return MenuActionResult::Handled;
6417 case eMenuID_ThreadStepIn: {
6418 ExecutionContext exe_ctx =
6419 m_debugger.GetCommandInterpreter().GetExecutionContext();
6422 if (process && process->
IsAlive() &&
6427 return MenuActionResult::Handled;
6429 case eMenuID_ThreadStepOut: {
6430 ExecutionContext exe_ctx =
6431 m_debugger.GetCommandInterpreter().GetExecutionContext();
6434 if (process && process->
IsAlive() &&
6437 uint32_t frame_idx =
6443 return MenuActionResult::Handled;
6445 case eMenuID_ThreadStepOver: {
6446 ExecutionContext exe_ctx =
6447 m_debugger.GetCommandInterpreter().GetExecutionContext();
6450 if (process && process->
IsAlive() &&
6455 return MenuActionResult::Handled;
6457 case eMenuID_ProcessAttach: {
6458 WindowSP main_window_sp = m_app.GetMainWindow();
6459 FormDelegateSP form_delegate_sp = FormDelegateSP(
6460 new ProcessAttachFormDelegate(m_debugger, main_window_sp));
6461 Rect bounds = main_window_sp->GetCenteredRect(80, 22);
6462 WindowSP form_window_sp = main_window_sp->CreateSubWindow(
6463 form_delegate_sp->GetName().c_str(), bounds,
true);
6464 WindowDelegateSP window_delegate_sp =
6465 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
6466 form_window_sp->SetDelegate(window_delegate_sp);
6467 return MenuActionResult::Handled;
6469 case eMenuID_ProcessLaunch: {
6470 WindowSP main_window_sp = m_app.GetMainWindow();
6471 FormDelegateSP form_delegate_sp = FormDelegateSP(
6472 new ProcessLaunchFormDelegate(m_debugger, main_window_sp));
6473 Rect bounds = main_window_sp->GetCenteredRect(80, 22);
6474 WindowSP form_window_sp = main_window_sp->CreateSubWindow(
6475 form_delegate_sp->GetName().c_str(), bounds,
true);
6476 WindowDelegateSP window_delegate_sp =
6477 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
6478 form_window_sp->SetDelegate(window_delegate_sp);
6479 return MenuActionResult::Handled;
6482 case eMenuID_ProcessContinue: {
6483 ExecutionContext exe_ctx =
6484 m_debugger.GetCommandInterpreter().GetExecutionContext();
6487 if (process && process->
IsAlive() &&
6492 return MenuActionResult::Handled;
6494 case eMenuID_ProcessKill: {
6495 ExecutionContext exe_ctx =
6496 m_debugger.GetCommandInterpreter().GetExecutionContext();
6499 if (process && process->
IsAlive())
6503 return MenuActionResult::Handled;
6505 case eMenuID_ProcessHalt: {
6506 ExecutionContext exe_ctx =
6507 m_debugger.GetCommandInterpreter().GetExecutionContext();
6510 if (process && process->
IsAlive())
6514 return MenuActionResult::Handled;
6516 case eMenuID_ProcessDetachResume:
6517 case eMenuID_ProcessDetachSuspended: {
6518 ExecutionContext exe_ctx =
6519 m_debugger.GetCommandInterpreter().GetExecutionContext();
6522 if (process && process->
IsAlive())
6523 process->
Detach(menu.GetIdentifier() ==
6524 eMenuID_ProcessDetachSuspended);
6527 return MenuActionResult::Handled;
6529 case eMenuID_Process: {
6533 Menus &submenus = menu.GetSubmenus();
6534 ExecutionContext exe_ctx =
6535 m_debugger.GetCommandInterpreter().GetExecutionContext();
6537 if (process && process->
IsAlive() &&
6539 if (submenus.size() == 7)
6540 menu.AddSubmenu(std::make_shared<Menu>(Menu::Type::Separator));
6541 else if (submenus.size() > 8)
6542 submenus.erase(submenus.begin() + 8, submenus.end());
6545 std::lock_guard<std::recursive_mutex> guard(threads.
GetMutex());
6546 size_t num_threads = threads.
GetSize();
6547 for (
size_t i = 0; i < num_threads; ++i) {
6549 char menu_char =
'\0';
6551 menu_char =
'1' + i;
6552 StreamString thread_menu_title;
6553 thread_menu_title.
Printf(
"Thread %u", thread_sp->GetIndexID());
6554 const char *thread_name = thread_sp->GetName();
6555 if (thread_name && thread_name[0])
6556 thread_menu_title.
Printf(
" %s", thread_name);
6558 const char *queue_name = thread_sp->GetQueueName();
6559 if (queue_name && queue_name[0])
6560 thread_menu_title.
Printf(
" %s", queue_name);
6562 menu.AddSubmenu(std::make_shared<Menu>(
6563 thread_menu_title.
GetString().str().c_str(),
nullptr, menu_char,
6564 thread_sp->GetID()));
6566 }
else if (submenus.size() > 7) {
6569 submenus.erase(submenus.begin() + 7, submenus.end());
6573 menu.RecalculateNameLengths();
6575 return MenuActionResult::Handled;
6577 case eMenuID_ViewVariables: {
6578 WindowSP main_window_sp = m_app.GetMainWindow();
6579 WindowSP source_window_sp = main_window_sp->FindSubWindow(
"Source");
6580 WindowSP variables_window_sp = main_window_sp->FindSubWindow(
"Variables");
6581 WindowSP registers_window_sp = main_window_sp->FindSubWindow(
"Registers");
6582 const Rect source_bounds = source_window_sp->GetBounds();
6584 if (variables_window_sp) {
6585 const Rect variables_bounds = variables_window_sp->GetBounds();
6587 main_window_sp->RemoveSubWindow(variables_window_sp.get());
6589 if (registers_window_sp) {
6592 Rect registers_bounds = variables_bounds;
6593 registers_bounds.size.width = source_bounds.size.width;
6594 registers_window_sp->SetBounds(registers_bounds);
6598 source_window_sp->Resize(source_bounds.size.width,
6599 source_bounds.size.height +
6600 variables_bounds.size.height);
6603 Rect new_variables_rect;
6604 if (registers_window_sp) {
6608 const Rect variables_bounds = registers_window_sp->GetBounds();
6609 Rect new_registers_rect;
6610 variables_bounds.VerticalSplitPercentage(0.50, new_variables_rect,
6611 new_registers_rect);
6612 registers_window_sp->SetBounds(new_registers_rect);
6615 Rect new_source_rect;
6616 source_bounds.HorizontalSplitPercentage(0.70, new_source_rect,
6617 new_variables_rect);
6618 source_window_sp->SetBounds(new_source_rect);
6620 WindowSP new_window_sp = main_window_sp->CreateSubWindow(
6621 "Variables", new_variables_rect,
false);
6622 new_window_sp->SetDelegate(
6623 WindowDelegateSP(
new FrameVariablesWindowDelegate(m_debugger)));
6627 return MenuActionResult::Handled;
6629 case eMenuID_ViewRegisters: {
6630 WindowSP main_window_sp = m_app.GetMainWindow();
6631 WindowSP source_window_sp = main_window_sp->FindSubWindow(
"Source");
6632 WindowSP variables_window_sp = main_window_sp->FindSubWindow(
"Variables");
6633 WindowSP registers_window_sp = main_window_sp->FindSubWindow(
"Registers");
6634 const Rect source_bounds = source_window_sp->GetBounds();
6636 if (registers_window_sp) {
6637 if (variables_window_sp) {
6638 const Rect variables_bounds = variables_window_sp->GetBounds();
6642 variables_window_sp->Resize(variables_bounds.size.width +
6643 registers_window_sp->GetWidth(),
6644 variables_bounds.size.height);
6648 source_window_sp->Resize(source_bounds.size.width,
6649 source_bounds.size.height +
6650 registers_window_sp->GetHeight());
6652 main_window_sp->RemoveSubWindow(registers_window_sp.get());
6655 if (variables_window_sp) {
6659 const Rect variables_bounds = variables_window_sp->GetBounds();
6661 variables_bounds.VerticalSplitPercentage(0.50, new_vars_rect,
6663 variables_window_sp->SetBounds(new_vars_rect);
6666 Rect new_source_rect;
6667 source_bounds.HorizontalSplitPercentage(0.70, new_source_rect,
6669 source_window_sp->SetBounds(new_source_rect);
6671 WindowSP new_window_sp =
6672 main_window_sp->CreateSubWindow(
"Registers", new_regs_rect,
false);
6673 new_window_sp->SetDelegate(
6674 WindowDelegateSP(
new RegistersWindowDelegate(m_debugger)));
6678 return MenuActionResult::Handled;
6680 case eMenuID_ViewBreakpoints: {
6681 WindowSP main_window_sp = m_app.GetMainWindow();
6682 WindowSP threads_window_sp = main_window_sp->FindSubWindow(
"Threads");
6683 WindowSP breakpoints_window_sp =
6684 main_window_sp->FindSubWindow(
"Breakpoints");
6685 const Rect threads_bounds = threads_window_sp->GetBounds();
6692 if (breakpoints_window_sp) {
6693 threads_window_sp->Resize(threads_bounds.size.width,
6694 threads_bounds.size.height +
6695 breakpoints_window_sp->GetHeight());
6696 main_window_sp->RemoveSubWindow(breakpoints_window_sp.get());
6698 Rect new_threads_bounds, breakpoints_bounds;
6699 threads_bounds.HorizontalSplitPercentage(0.70, new_threads_bounds,
6700 breakpoints_bounds);
6701 threads_window_sp->SetBounds(new_threads_bounds);
6702 breakpoints_window_sp = main_window_sp->CreateSubWindow(
6703 "Breakpoints", breakpoints_bounds,
false);
6704 TreeDelegateSP breakpoints_delegate_sp(
6705 new BreakpointsTreeDelegate(m_debugger));
6706 breakpoints_window_sp->SetDelegate(WindowDelegateSP(
6707 new TreeWindowDelegate(m_debugger, breakpoints_delegate_sp)));
6710 return MenuActionResult::Handled;
6713 case eMenuID_HelpGUIHelp:
6714 m_app.GetMainWindow()->CreateHelpSubwindow();
6715 return MenuActionResult::Handled;
6721 return MenuActionResult::NotHandled;
6726 Debugger &m_debugger;
6729class StatusBarWindowDelegate :
public WindowDelegate {
6731 StatusBarWindowDelegate(Debugger &debugger) : m_debugger(debugger) {
6735 ~StatusBarWindowDelegate()
override =
default;
6737 bool WindowDelegateDraw(Window &window,
bool force)
override {
6738 ExecutionContext exe_ctx =
6739 m_debugger.GetCommandInterpreter().GetExecutionContext();
6744 window.SetBackground(BlackOnWhite);
6745 window.MoveCursor(0, 0);
6748 window.Printf(
"Process: %5" PRIu64
" %10s", process->
GetID(),
6754 nullptr,
nullptr,
false,
false)) {
6755 window.MoveCursor(40, 0);
6756 window.PutCStringTruncated(1, strm.
GetString().str().c_str());
6759 window.MoveCursor(60, 0);
6761 window.Printf(
"Frame: %3u PC = 0x%16.16" PRIx64,
6768 if (exit_desc && exit_desc[0])
6769 window.Printf(
" with status = %i (%s)", exit_status, exit_desc);
6771 window.Printf(
" with status = %i", exit_status);
6778 Debugger &m_debugger;
6779 FormatEntity::Entry m_format;
6782class SourceFileWindowDelegate :
public WindowDelegate {
6784 SourceFileWindowDelegate(Debugger &debugger)
6785 : WindowDelegate(), m_debugger(debugger) {}
6787 ~SourceFileWindowDelegate()
override =
default;
6789 void Update(
const SymbolContext &sc) { m_sc = sc; }
6791 uint32_t NumVisibleLines()
const {
return m_max_y - m_min_y; }
6793 const char *WindowDelegateGetHelpText()
override {
6794 return "Source/Disassembly window keyboard shortcuts:";
6797 KeyHelp *WindowDelegateGetKeyHelp()
override {
6798 static curses::KeyHelp g_source_view_key_help[] = {
6799 {KEY_RETURN,
"Run to selected line with one shot breakpoint"},
6800 {KEY_UP,
"Select previous source line"},
6801 {KEY_DOWN,
"Select next source line"},
6802 {KEY_LEFT,
"Scroll to the left"},
6803 {KEY_RIGHT,
"Scroll to the right"},
6804 {KEY_PPAGE,
"Page up"},
6805 {KEY_NPAGE,
"Page down"},
6806 {
'b',
"Set breakpoint on selected source/disassembly line"},
6807 {
'c',
"Continue process"},
6808 {
'D',
"Detach with process suspended"},
6809 {
'h',
"Show help dialog"},
6810 {
'n',
"Step over (source line)"},
6811 {
'N',
"Step over (single instruction)"},
6812 {
'f',
"Step out (finish)"},
6813 {
's',
"Step in (source line)"},
6814 {
'S',
"Step in (single instruction)"},
6816 {
'd',
"Frame down"},
6820 return g_source_view_key_help;
6823 bool WindowDelegateDraw(Window &window,
bool force)
override {
6824 ExecutionContext exe_ctx =
6825 m_debugger.GetCommandInterpreter().GetExecutionContext();
6827 Thread *thread =
nullptr;
6829 bool update_location =
false;
6834 update_location =
true;
6840 m_max_x = window.GetMaxX() - 1;
6841 m_max_y = window.GetMaxY() - 1;
6843 const uint32_t num_visible_lines = NumVisibleLines();
6845 bool set_selected_line_to_pc =
false;
6847 if (update_location) {
6848 const bool process_alive = process->
IsAlive();
6849 bool thread_changed =
false;
6850 if (process_alive) {
6854 auto tid = thread->
GetID();
6855 thread_changed = tid != m_tid;
6859 thread_changed =
true;
6864 const uint32_t stop_id = process ? process->
GetStopID() : 0;
6865 const bool stop_id_changed = stop_id != m_stop_id;
6866 bool frame_changed =
false;
6867 m_stop_id = stop_id;
6870 m_sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
6871 if (m_sc.module_sp) {
6873 "%s", m_sc.module_sp->GetFileSpec().GetFilename().GetCString());
6874 ConstString func_name = m_sc.GetFunctionName();
6876 m_title.Printf(
"`%s", func_name.
GetCString());
6878 const uint32_t frame_idx = frame_sp->GetFrameIndex();
6879 frame_changed = frame_idx != m_frame_idx;
6880 m_frame_idx = frame_idx;
6887 const bool context_changed =
6888 thread_changed || frame_changed || stop_id_changed;
6890 if (process_alive) {
6891 if (m_sc.line_entry.IsValid()) {
6892 m_pc_line = m_sc.line_entry.line;
6896 if (context_changed)
6897 m_selected_line = m_pc_line;
6899 if (m_file_sp && m_file_sp->GetSupportFile()->GetSpecOnly() ==
6900 m_sc.line_entry.GetFile()) {
6903 if (m_selected_line >=
static_cast<size_t>(m_first_visible_line)) {
6904 if (m_selected_line >= m_first_visible_line + num_visible_lines)
6905 m_first_visible_line = m_selected_line - 10;
6907 if (m_selected_line > 10)
6908 m_first_visible_line = m_selected_line - 10;
6910 m_first_visible_line = 0;
6914 m_selected_line = m_pc_line;
6916 m_debugger.GetSourceManager().GetFile(m_sc.line_entry.file_sp);
6918 const size_t num_lines = m_file_sp->GetNumLines();
6920 for (
size_t n = num_lines; n >= 10; n = n / 10)
6923 if (num_lines < num_visible_lines ||
6924 m_selected_line < num_visible_lines)
6925 m_first_visible_line = 0;
6927 m_first_visible_line = m_selected_line - 10;
6934 if (!m_file_sp || m_file_sp->GetNumLines() == 0) {
6936 bool prefer_file_cache =
false;
6937 if (m_sc.function) {
6938 if (m_disassembly_scope != m_sc.function) {
6939 m_disassembly_scope = m_sc.function;
6940 m_disassembly_sp = m_sc.function->GetInstructions(
6941 exe_ctx,
nullptr, !prefer_file_cache);
6942 if (m_disassembly_sp)
6943 set_selected_line_to_pc =
true;
6945 set_selected_line_to_pc = context_changed;
6947 }
else if (m_sc.symbol) {
6948 if (m_disassembly_scope != m_sc.symbol) {
6949 m_disassembly_scope = m_sc.symbol;
6950 m_disassembly_sp = m_sc.symbol->GetInstructions(
6951 exe_ctx,
nullptr, prefer_file_cache);
6952 if (m_disassembly_sp)
6953 set_selected_line_to_pc =
true;
6955 set_selected_line_to_pc = context_changed;
6964 const int window_width = window.GetWidth();
6966 window.DrawTitleBox(
"Sources");
6967 if (!m_title.GetString().empty()) {
6968 window.AttributeOn(A_REVERSE);
6969 window.MoveCursor(1, 1);
6970 window.PutChar(
' ');
6971 window.PutCStringTruncated(1, m_title.GetString().str().c_str());
6972 int x = window.GetCursorX();
6973 if (x < window_width - 1) {
6974 window.Printf(
"%*s", window_width - x - 1,
"");
6976 window.AttributeOff(A_REVERSE);
6980 const size_t num_source_lines = GetNumSourceLines();
6981 if (num_source_lines > 0) {
6983 BreakpointLines bp_lines;
6986 const size_t num_bps = bp_list.
GetSize();
6987 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
6989 const size_t num_bps_locs = bp_sp->GetNumLocations();
6990 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs; ++bp_loc_idx) {
6992 bp_sp->GetLocationAtIndex(bp_loc_idx);
6993 LineEntry bp_loc_line_entry;
6994 if (bp_loc_sp->GetAddress().CalculateSymbolContextLineEntry(
6995 bp_loc_line_entry)) {
6996 if (m_file_sp->GetSupportFile()->GetSpecOnly() ==
6997 bp_loc_line_entry.
GetFile()) {
6998 bp_lines.insert(bp_loc_line_entry.
line);
7005 for (
size_t i = 0; i < num_visible_lines; ++i) {
7006 const uint32_t curr_line = m_first_visible_line + i;
7007 if (curr_line < num_source_lines) {
7008 const int line_y = m_min_y + i;
7009 window.MoveCursor(1, line_y);
7010 const bool is_pc_line = curr_line == m_pc_line;
7011 const bool line_is_selected = m_selected_line == curr_line;
7015 attr_t highlight_attr = 0;
7017 if (line_is_selected && !is_pc_line)
7018 highlight_attr = A_REVERSE;
7020 if (bp_lines.find(curr_line + 1) != bp_lines.end())
7021 bp_attr = COLOR_PAIR(BlackOnWhite);
7024 window.AttributeOn(bp_attr);
7026 window.Printf(
" %*u ", m_line_width, curr_line + 1);
7029 window.AttributeOff(bp_attr);
7031 window.PutChar(ACS_VLINE);
7034 window.PutChar(ACS_DIAMOND);
7036 window.PutChar(
' ');
7039 window.AttributeOn(highlight_attr);
7041 StreamString lineStream;
7043 std::optional<size_t> column;
7044 if (is_pc_line && m_sc.line_entry.IsValid() && m_sc.line_entry.column)
7045 column = m_sc.line_entry.column - 1;
7046 m_file_sp->DisplaySourceLines(curr_line + 1, column, 0, 0,
7048 StringRef line = lineStream.
GetString();
7049 if (line.ends_with(
"\n"))
7050 line = line.drop_back();
7051 bool wasWritten = window.OutputColoredStringTruncated(
7052 1, line, m_first_visible_column, is_pc_line);
7053 if (!wasWritten && (line_is_selected || is_pc_line)) {
7057 window.PutCStringTruncated(
7058 1, line.empty() && m_first_visible_column == 0 ?
" " :
"<");
7061 if (is_pc_line && frame_sp &&
7062 frame_sp->GetConcreteFrameIndex() == 0) {
7067 const char *stop_description = stop_info_sp->GetDescription();
7068 if (stop_description && stop_description[0]) {
7069 size_t stop_description_len = strlen(stop_description);
7070 int desc_x = window_width - stop_description_len - 16;
7071 if (desc_x - window.GetCursorX() > 0)
7072 window.Printf(
"%*s", desc_x - window.GetCursorX(),
"");
7073 window.MoveCursor(window_width - stop_description_len - 16,
7075 const attr_t stop_reason_attr = COLOR_PAIR(WhiteOnBlue);
7076 window.AttributeOn(stop_reason_attr);
7077 window.PrintfTruncated(1,
" <<< Thread %u: %s ",
7079 window.AttributeOff(stop_reason_attr);
7082 window.Printf(
"%*s", window_width - window.GetCursorX() - 1,
"");
7086 window.AttributeOff(highlight_attr);
7092 size_t num_disassembly_lines = GetNumDisassemblyLines();
7093 if (num_disassembly_lines > 0) {
7095 BreakpointAddrs bp_file_addrs;
7099 const size_t num_bps = bp_list.
GetSize();
7100 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
7102 const size_t num_bps_locs = bp_sp->GetNumLocations();
7103 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs;
7106 bp_sp->GetLocationAtIndex(bp_loc_idx);
7107 bp_file_addrs.insert(bp_loc_sp->GetAddress().GetFileAddress());
7112 const attr_t selected_highlight_attr = A_REVERSE;
7113 const attr_t pc_highlight_attr = COLOR_PAIR(WhiteOnBlue);
7117 InstructionList &insts = m_disassembly_sp->GetInstructionList();
7121 pc_address = frame_sp->GetFrameCodeAddress();
7122 const uint32_t pc_idx =
7126 if (set_selected_line_to_pc) {
7127 m_selected_line = pc_idx;
7130 const uint32_t non_visible_pc_offset = (num_visible_lines / 5);
7131 if (
static_cast<size_t>(m_first_visible_line) >= num_disassembly_lines)
7132 m_first_visible_line = 0;
7134 if (pc_idx < num_disassembly_lines) {
7135 if (pc_idx <
static_cast<uint32_t
>(m_first_visible_line) ||
7136 pc_idx >= m_first_visible_line + num_visible_lines)
7137 m_first_visible_line = pc_idx - non_visible_pc_offset;
7140 for (
size_t i = 0; i < num_visible_lines; ++i) {
7141 const uint32_t inst_idx = m_first_visible_line + i;
7146 const int line_y = m_min_y + i;
7147 window.MoveCursor(1, line_y);
7148 const bool is_pc_line = frame_sp && inst_idx == pc_idx;
7149 const bool line_is_selected = m_selected_line == inst_idx;
7152 attr_t highlight_attr = 0;
7155 highlight_attr = pc_highlight_attr;
7156 else if (line_is_selected)
7157 highlight_attr = selected_highlight_attr;
7160 bp_file_addrs.end())
7161 bp_attr = COLOR_PAIR(BlackOnWhite);
7164 window.AttributeOn(bp_attr);
7166 window.Printf(
" 0x%16.16llx ",
7167 static_cast<unsigned long long>(
7171 window.AttributeOff(bp_attr);
7173 window.PutChar(ACS_VLINE);
7176 window.PutChar(ACS_DIAMOND);
7178 window.PutChar(
' ');
7181 window.AttributeOn(highlight_attr);
7183 const char *mnemonic = inst->
GetMnemonic(&exe_ctx);
7184 const char *operands = inst->
GetOperands(&exe_ctx);
7185 const char *comment = inst->
GetComment(&exe_ctx);
7187 if (mnemonic !=
nullptr && mnemonic[0] ==
'\0')
7189 if (operands !=
nullptr && operands[0] ==
'\0')
7191 if (comment !=
nullptr && comment[0] ==
'\0')
7196 if (mnemonic !=
nullptr && operands !=
nullptr && comment !=
nullptr)
7197 strm.
Printf(
"%-8s %-25s ; %s", mnemonic, operands, comment);
7198 else if (mnemonic !=
nullptr && operands !=
nullptr)
7199 strm.
Printf(
"%-8s %s", mnemonic, operands);
7200 else if (mnemonic !=
nullptr)
7201 strm.
Printf(
"%s", mnemonic);
7204 window.PutCStringTruncated(
7206 strm.
GetString().substr(m_first_visible_column).data());
7208 if (is_pc_line && frame_sp &&
7209 frame_sp->GetConcreteFrameIndex() == 0) {
7214 const char *stop_description = stop_info_sp->GetDescription();
7215 if (stop_description && stop_description[0]) {
7216 size_t stop_description_len = strlen(stop_description);
7217 int desc_x = window_width - stop_description_len - 16;
7218 if (desc_x - window.GetCursorX() > 0)
7219 window.Printf(
"%*s", desc_x - window.GetCursorX(),
"");
7220 window.MoveCursor(window_width - stop_description_len - 15,
7223 window.PrintfTruncated(1,
"<<< Thread %u: %s ",
7228 window.Printf(
"%*s", window_width - window.GetCursorX() - 1,
"");
7232 window.AttributeOff(highlight_attr);
7239 size_t GetNumLines() {
7240 size_t num_lines = GetNumSourceLines();
7242 num_lines = GetNumDisassemblyLines();
7246 size_t GetNumSourceLines()
const {
7248 return m_file_sp->GetNumLines();
7252 size_t GetNumDisassemblyLines()
const {
7253 if (m_disassembly_sp)
7254 return m_disassembly_sp->GetInstructionList().GetSize();
7258 HandleCharResult WindowDelegateHandleChar(Window &window,
int c)
override {
7259 const uint32_t num_visible_lines = NumVisibleLines();
7260 const size_t num_lines = GetNumLines();
7266 if (
static_cast<uint32_t
>(m_first_visible_line) > num_visible_lines)
7267 m_first_visible_line -= num_visible_lines;
7269 m_first_visible_line = 0;
7270 m_selected_line = m_first_visible_line;
7277 if (m_first_visible_line + num_visible_lines < num_lines)
7278 m_first_visible_line += num_visible_lines;
7279 else if (num_lines < num_visible_lines)
7280 m_first_visible_line = 0;
7282 m_first_visible_line = num_lines - num_visible_lines;
7283 m_selected_line = m_first_visible_line;
7288 if (m_selected_line > 0) {
7290 if (
static_cast<size_t>(m_first_visible_line) > m_selected_line)
7291 m_first_visible_line = m_selected_line;
7296 if (m_selected_line + 1 < num_lines) {
7298 if (m_first_visible_line + num_visible_lines < m_selected_line)
7299 m_first_visible_line++;
7304 if (m_first_visible_column > 0)
7305 --m_first_visible_column;
7309 ++m_first_visible_column;
7316 if (GetNumSourceLines() > 0) {
7317 ExecutionContext exe_ctx =
7318 m_debugger.GetCommandInterpreter().GetExecutionContext();
7322 m_file_sp->GetSupportFile()->GetSpecOnly(),
7333 bp_sp->GetOptions().SetOneShot(
true);
7336 }
else if (m_selected_line < GetNumDisassemblyLines()) {
7337 const Instruction *inst = m_disassembly_sp->GetInstructionList()
7338 .GetInstructionAtIndex(m_selected_line)
7340 ExecutionContext exe_ctx =
7341 m_debugger.GetCommandInterpreter().GetExecutionContext();
7349 bp_sp->GetOptions().SetOneShot(
true);
7356 ToggleBreakpointOnSelectedLine();
7361 ExecutionContext exe_ctx =
7362 m_debugger.GetCommandInterpreter().GetExecutionContext();
7371 ExecutionContext exe_ctx =
7372 m_debugger.GetCommandInterpreter().GetExecutionContext();
7381 ExecutionContext exe_ctx =
7382 m_debugger.GetCommandInterpreter().GetExecutionContext();
7386 uint32_t frame_idx =
7396 ExecutionContext exe_ctx =
7397 m_debugger.GetCommandInterpreter().GetExecutionContext();
7400 bool source_step = (c ==
'n');
7409 ExecutionContext exe_ctx =
7410 m_debugger.GetCommandInterpreter().GetExecutionContext();
7413 bool source_step = (c ==
's');
7422 ExecutionContext exe_ctx =
7423 m_debugger.GetCommandInterpreter().GetExecutionContext();
7426 uint32_t frame_idx =
7432 else if (c ==
'd' && frame_idx > 0)
7441 window.CreateHelpSubwindow();
7447 return eKeyNotHandled;
7450 void ToggleBreakpointOnSelectedLine() {
7451 ExecutionContext exe_ctx =
7452 m_debugger.GetCommandInterpreter().GetExecutionContext();
7455 if (GetNumSourceLines() > 0) {
7458 const size_t num_bps = bp_list.
GetSize();
7459 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
7461 const size_t num_bps_locs = bp_sp->GetNumLocations();
7462 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs; ++bp_loc_idx) {
7464 bp_sp->GetLocationAtIndex(bp_loc_idx);
7465 LineEntry bp_loc_line_entry;
7466 if (bp_loc_sp->GetAddress().CalculateSymbolContextLineEntry(
7467 bp_loc_line_entry)) {
7468 if (m_file_sp->GetSupportFile()->GetSpecOnly() ==
7469 bp_loc_line_entry.
GetFile() &&
7470 m_selected_line + 1 == bp_loc_line_entry.
line) {
7483 m_file_sp->GetSupportFile()->GetSpecOnly(),
7495 assert(GetNumDisassemblyLines() > 0);
7496 assert(m_selected_line < GetNumDisassemblyLines());
7497 const Instruction *inst = m_disassembly_sp->GetInstructionList()
7498 .GetInstructionAtIndex(m_selected_line)
7503 const size_t num_bps = bp_list.
GetSize();
7504 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
7506 const size_t num_bps_locs = bp_sp->GetNumLocations();
7507 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs; ++bp_loc_idx) {
7509 bp_sp->GetLocationAtIndex(bp_loc_idx);
7510 LineEntry bp_loc_line_entry;
7512 bp_loc_sp->GetAddress().GetFileAddress();
7531 typedef std::set<uint32_t> BreakpointLines;
7532 typedef std::set<lldb::addr_t> BreakpointAddrs;
7534 Debugger &m_debugger;
7537 SymbolContextScope *m_disassembly_scope =
nullptr;
7539 StreamString m_title;
7541 int m_line_width = 4;
7542 uint32_t m_selected_line = 0;
7543 uint32_t m_pc_line = 0;
7544 uint32_t m_stop_id = 0;
7546 int m_first_visible_line = 0;
7547 int m_first_visible_column = 0;
7554DisplayOptions ValueObjectListDelegate::g_options = {
true};
7562 m_app_up = std::make_unique<Application>(
7567 std::shared_ptr<ApplicationDelegate> app_delegate_sp(
7570 MenuDelegateSP app_menu_delegate_sp =
7571 std::static_pointer_cast<MenuDelegate>(app_delegate_sp);
7572 MenuSP lldb_menu_sp(
7573 new Menu(
"LLDB",
"F1", KEY_F(1), ApplicationDelegate::eMenuID_LLDB));
7574 MenuSP exit_menuitem_sp(
7575 new Menu(
"Exit",
nullptr,
'x', ApplicationDelegate::eMenuID_LLDBExit));
7576 exit_menuitem_sp->SetCannedResult(MenuActionResult::Quit);
7577 lldb_menu_sp->AddSubmenu(std::make_shared<Menu>(
7578 "About LLDB",
nullptr,
'a', ApplicationDelegate::eMenuID_LLDBAbout));
7579 lldb_menu_sp->AddSubmenu(std::make_shared<Menu>(Menu::Type::Separator));
7580 lldb_menu_sp->AddSubmenu(exit_menuitem_sp);
7582 MenuSP target_menu_sp(
new Menu(
"Target",
"F2", KEY_F(2),
7583 ApplicationDelegate::eMenuID_Target));
7584 target_menu_sp->AddSubmenu(std::make_shared<Menu>(
7585 "Create",
nullptr,
'c', ApplicationDelegate::eMenuID_TargetCreate));
7586 target_menu_sp->AddSubmenu(std::make_shared<Menu>(
7587 "Delete",
nullptr,
'd', ApplicationDelegate::eMenuID_TargetDelete));
7589 MenuSP process_menu_sp(
new Menu(
"Process",
"F3", KEY_F(3),
7590 ApplicationDelegate::eMenuID_Process));
7591 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7592 "Attach",
nullptr,
'a', ApplicationDelegate::eMenuID_ProcessAttach));
7593 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7594 "Detach and resume",
nullptr,
'd',
7595 ApplicationDelegate::eMenuID_ProcessDetachResume));
7596 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7597 "Detach suspended",
nullptr,
's',
7598 ApplicationDelegate::eMenuID_ProcessDetachSuspended));
7599 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7600 "Launch",
nullptr,
'l', ApplicationDelegate::eMenuID_ProcessLaunch));
7601 process_menu_sp->AddSubmenu(std::make_shared<Menu>(Menu::Type::Separator));
7602 process_menu_sp->AddSubmenu(
7603 std::make_shared<Menu>(
"Continue",
nullptr,
'c',
7604 ApplicationDelegate::eMenuID_ProcessContinue));
7605 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7606 "Halt",
nullptr,
'h', ApplicationDelegate::eMenuID_ProcessHalt));
7607 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7608 "Kill",
nullptr,
'k', ApplicationDelegate::eMenuID_ProcessKill));
7610 MenuSP thread_menu_sp(
new Menu(
"Thread",
"F4", KEY_F(4),
7611 ApplicationDelegate::eMenuID_Thread));
7612 thread_menu_sp->AddSubmenu(std::make_shared<Menu>(
7613 "Step In",
nullptr,
'i', ApplicationDelegate::eMenuID_ThreadStepIn));
7614 thread_menu_sp->AddSubmenu(
7615 std::make_shared<Menu>(
"Step Over",
nullptr,
'v',
7616 ApplicationDelegate::eMenuID_ThreadStepOver));
7617 thread_menu_sp->AddSubmenu(std::make_shared<Menu>(
7618 "Step Out",
nullptr,
'o', ApplicationDelegate::eMenuID_ThreadStepOut));
7620 MenuSP view_menu_sp(
7621 new Menu(
"View",
"F5", KEY_F(5), ApplicationDelegate::eMenuID_View));
7622 view_menu_sp->AddSubmenu(std::make_shared<Menu>(
7623 "Backtrace",
nullptr,
't', ApplicationDelegate::eMenuID_ViewBacktrace));
7624 view_menu_sp->AddSubmenu(std::make_shared<Menu>(
7625 "Registers",
nullptr,
'r', ApplicationDelegate::eMenuID_ViewRegisters));
7626 view_menu_sp->AddSubmenu(std::make_shared<Menu>(
7627 "Source",
nullptr,
's', ApplicationDelegate::eMenuID_ViewSource));
7628 view_menu_sp->AddSubmenu(std::make_shared<Menu>(
7629 "Variables",
nullptr,
'v', ApplicationDelegate::eMenuID_ViewVariables));
7630 view_menu_sp->AddSubmenu(
7631 std::make_shared<Menu>(
"Breakpoints",
nullptr,
'b',
7632 ApplicationDelegate::eMenuID_ViewBreakpoints));
7634 MenuSP help_menu_sp(
7635 new Menu(
"Help",
"F6", KEY_F(6), ApplicationDelegate::eMenuID_Help));
7636 help_menu_sp->AddSubmenu(std::make_shared<Menu>(
7637 "GUI Help",
nullptr,
'g', ApplicationDelegate::eMenuID_HelpGUIHelp));
7640 WindowSP &main_window_sp =
m_app_up->GetMainWindow();
7642 MenuSP menubar_sp(
new Menu(Menu::Type::Bar));
7643 menubar_sp->AddSubmenu(lldb_menu_sp);
7644 menubar_sp->AddSubmenu(target_menu_sp);
7645 menubar_sp->AddSubmenu(process_menu_sp);
7646 menubar_sp->AddSubmenu(thread_menu_sp);
7647 menubar_sp->AddSubmenu(view_menu_sp);
7648 menubar_sp->AddSubmenu(help_menu_sp);
7649 menubar_sp->SetDelegate(app_menu_delegate_sp);
7651 Rect content_bounds = main_window_sp->GetFrame();
7652 Rect menubar_bounds = content_bounds.MakeMenuBar();
7653 Rect status_bounds = content_bounds.MakeStatusBar();
7655 Rect variables_bounds;
7656 Rect threads_bounds;
7657 Rect source_variables_bounds;
7658 content_bounds.VerticalSplitPercentage(0.80, source_variables_bounds,
7660 source_variables_bounds.HorizontalSplitPercentage(0.70, source_bounds,
7663 WindowSP menubar_window_sp =
7664 main_window_sp->CreateSubWindow(
"Menubar", menubar_bounds,
false);
7667 menubar_window_sp->SetCanBeActive(
7669 menubar_window_sp->SetDelegate(menubar_sp);
7671 WindowSP source_window_sp(
7672 main_window_sp->CreateSubWindow(
"Source", source_bounds,
true));
7673 WindowSP variables_window_sp(
7674 main_window_sp->CreateSubWindow(
"Variables", variables_bounds,
false));
7675 WindowSP threads_window_sp(
7676 main_window_sp->CreateSubWindow(
"Threads", threads_bounds,
false));
7677 WindowSP status_window_sp(
7678 main_window_sp->CreateSubWindow(
"Status", status_bounds,
false));
7679 status_window_sp->SetCanBeActive(
7681 main_window_sp->SetDelegate(
7682 std::static_pointer_cast<WindowDelegate>(app_delegate_sp));
7683 source_window_sp->SetDelegate(
7684 WindowDelegateSP(
new SourceFileWindowDelegate(
m_debugger)));
7685 variables_window_sp->SetDelegate(
7686 WindowDelegateSP(
new FrameVariablesWindowDelegate(
m_debugger)));
7687 TreeDelegateSP thread_delegate_sp(
new ThreadsTreeDelegate(
m_debugger));
7688 threads_window_sp->SetDelegate(WindowDelegateSP(
7689 new TreeWindowDelegate(
m_debugger, thread_delegate_sp)));
7690 status_window_sp->SetDelegate(
7691 WindowDelegateSP(
new StatusBarWindowDelegate(
m_debugger)));
7694 init_pair(1, COLOR_BLACK, COLOR_BLACK);
7695 init_pair(2, COLOR_RED, COLOR_BLACK);
7696 init_pair(3, COLOR_GREEN, COLOR_BLACK);
7697 init_pair(4, COLOR_YELLOW, COLOR_BLACK);
7698 init_pair(5, COLOR_BLUE, COLOR_BLACK);
7699 init_pair(6, COLOR_MAGENTA, COLOR_BLACK);
7700 init_pair(7, COLOR_CYAN, COLOR_BLACK);
7701 init_pair(8, COLOR_WHITE, COLOR_BLACK);
7703 init_pair(9, COLOR_BLACK, COLOR_BLUE);
7704 init_pair(10, COLOR_RED, COLOR_BLUE);
7705 init_pair(11, COLOR_GREEN, COLOR_BLUE);
7706 init_pair(12, COLOR_YELLOW, COLOR_BLUE);
7707 init_pair(13, COLOR_BLUE, COLOR_BLUE);
7708 init_pair(14, COLOR_MAGENTA, COLOR_BLUE);
7709 init_pair(15, COLOR_CYAN, COLOR_BLUE);
7710 init_pair(16, COLOR_WHITE, COLOR_BLUE);
7712 init_pair(17, COLOR_BLACK, COLOR_WHITE);
7713 init_pair(18, COLOR_MAGENTA, COLOR_WHITE);
7714 static_assert(LastColorPairIndex == 18,
"Color indexes do not match.");
7716 define_key(
"\033[Z", KEY_SHIFT_TAB);
7717 define_key(
"\033\015", KEY_ALT_ENTER);
7733 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::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)
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 * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
void Dump(Stream *s, const char *value_if_empty=nullptr) const
Dump the object description to a stream.
const char * GetCString() 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)
void SetFile(llvm::StringRef path, Style style)
Change the file specified with a new path.
void SetDirectory(ConstString directory)
Directory string set accessor.
const ConstString & GetFilename() const
Filename string const get accessor.
const ConstString & GetDirectory() const
Directory string const get accessor.
void Resolve(llvm::SmallVectorImpl< char > &path)
Resolve path to make it canonical.
static FileSystem & Instance()
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(const char *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 SetShell(const FileSpec &shell)
void SetProcessPluginName(llvm::StringRef plugin)
void AppendFileAction(const FileAction &info)
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
VariableList * GetVariableList(bool get_file_globals, Status *error_ptr)
Retrieve the list of variables whose scope either:
lldb::RegisterContextSP GetRegisterContext()
Get the RegisterContext for this frame, if possible.
lldb::ValueObjectSP GetValueObjectForFrameVariable(const lldb::VariableSP &variable_sp, lldb::DynamicValueType use_dynamic)
Create a ValueObject for a given Variable in this StackFrame.
uint32_t GetFrameIndex() const
Query this frame to find what frame it is in this Thread's StackFrameList.
Block * GetFrameBlock()
Get the current lexical scope block for this StackFrame, if possible.
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)
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
const ProcessLaunchInfo & GetProcessLaunchInfo() 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.