11#include "lldb/Host/Config.h"
14#if CURSES_HAVE_NCURSES_CURSES_H
15#include <ncurses/curses.h>
16#include <ncurses/panel.h>
63#include "llvm/ADT/StringRef.h"
96#define KEY_SHIFT_TAB (KEY_MAX + 1)
97#define KEY_ALT_ENTER (KEY_MAX + 2)
105typedef std::shared_ptr<Menu> MenuSP;
106typedef std::shared_ptr<MenuDelegate> MenuDelegateSP;
107typedef std::shared_ptr<Window> WindowSP;
108typedef std::shared_ptr<WindowDelegate> WindowDelegateSP;
109typedef std::vector<MenuSP> Menus;
110typedef std::vector<WindowSP> Windows;
111typedef std::vector<WindowDelegateSP> WindowDelegates;
114type summary add -s
"x=${var.x}, y=${var.y}" curses::Point
115type summary add -s
"w=${var.width}, h=${var.height}" curses::Size
116type summary add -s
"${var.origin%S} ${var.size%S}" curses::Rect
123 Point(
int _x = 0,
int _y = 0) : x(_x), y(_y) {}
130 Point &operator+=(
const Point &rhs) {
136 void Dump() { printf(
"(x=%i, y=%i)\n", x, y); }
139bool operator==(
const Point &lhs,
const Point &rhs) {
140 return lhs.x == rhs.x && lhs.y == rhs.y;
143bool operator!=(
const Point &lhs,
const Point &rhs) {
144 return lhs.x != rhs.x || lhs.y != rhs.y;
150 Size(
int w = 0,
int h = 0) : width(w), height(h) {}
157 void Dump() { printf(
"(w=%i, h=%i)\n", width, height); }
160bool operator==(
const Size &lhs,
const Size &rhs) {
161 return lhs.width == rhs.width && lhs.height == rhs.height;
164bool operator!=(
const Size &lhs,
const Size &rhs) {
165 return lhs.width != rhs.width || lhs.height != rhs.height;
172 Rect() : origin(), size() {}
174 Rect(
const Point &p,
const Size &s) : origin(p), size(s) {}
182 printf(
"(x=%i, y=%i), w=%i, h=%i)\n", origin.x, origin.y, size.width,
186 void Inset(
int w,
int h) {
187 if (size.width > w * 2)
191 if (size.height > h * 2)
192 size.height -= h * 2;
198 Rect MakeStatusBar() {
200 if (size.height > 1) {
201 status_bar.origin.x = origin.x;
202 status_bar.origin.y = size.height;
203 status_bar.size.width = size.width;
204 status_bar.size.height = 1;
214 if (size.height > 1) {
215 menubar.origin.x = origin.x;
216 menubar.origin.y = origin.y;
217 menubar.size.width = size.width;
218 menubar.size.height = 1;
225 void HorizontalSplitPercentage(
float top_percentage, Rect &top,
226 Rect &bottom)
const {
227 float top_height = top_percentage * size.height;
228 HorizontalSplit(top_height, top, bottom);
231 void HorizontalSplit(
int top_height, Rect &top, Rect &bottom)
const {
233 if (top_height < size.height) {
234 top.size.height = top_height;
235 bottom.origin.x = origin.x;
236 bottom.origin.y = origin.y + top.size.height;
237 bottom.size.width = size.width;
238 bottom.size.height = size.height - top.size.height;
244 void VerticalSplitPercentage(
float left_percentage, Rect &left,
246 float left_width = left_percentage * size.width;
247 VerticalSplit(left_width, left, right);
250 void VerticalSplit(
int left_width, Rect &left, Rect &right)
const {
252 if (left_width < size.width) {
253 left.size.width = left_width;
254 right.origin.x = origin.x + left.size.width;
255 right.origin.y = origin.y;
256 right.size.width = size.width - left.size.width;
257 right.size.height = size.height;
264bool operator==(
const Rect &lhs,
const Rect &rhs) {
265 return lhs.origin == rhs.origin && lhs.size == rhs.size;
268bool operator!=(
const Rect &lhs,
const Rect &rhs) {
269 return lhs.origin != rhs.origin || lhs.size != rhs.size;
272enum HandleCharResult {
278enum class MenuActionResult {
286 const char *description;
312 LastColorPairIndex = MagentaOnWhite
315class WindowDelegate {
317 virtual ~WindowDelegate() =
default;
319 virtual bool WindowDelegateDraw(Window &window,
bool force) {
323 virtual HandleCharResult WindowDelegateHandleChar(Window &window,
int key) {
324 return eKeyNotHandled;
327 virtual const char *WindowDelegateGetHelpText() {
return nullptr; }
329 virtual KeyHelp *WindowDelegateGetKeyHelp() {
return nullptr; }
332class HelpDialogDelegate :
public WindowDelegate {
334 HelpDialogDelegate(
const char *text, KeyHelp *key_help_array);
336 ~HelpDialogDelegate()
override;
338 bool WindowDelegateDraw(Window &window,
bool force)
override;
340 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override;
342 size_t GetNumLines()
const {
return m_text.GetSize(); }
344 size_t GetMaxLineLength()
const {
return m_text.GetMaxStringLength(); }
348 int m_first_visible_line = 0;
357 enum class Type { Window, Pad };
359 Surface(Surface::Type type) : m_type(type) {}
361 WINDOW *get() {
return m_window; }
363 operator WINDOW *() {
return m_window; }
365 Surface SubSurface(Rect bounds) {
366 Surface subSurface(m_type);
367 if (m_type == Type::Pad)
368 subSurface.m_window =
369 ::subpad(m_window, bounds.size.height, bounds.size.width,
370 bounds.origin.y, bounds.origin.x);
372 subSurface.m_window =
373 ::derwin(m_window, bounds.size.height, bounds.size.width,
374 bounds.origin.y, bounds.origin.x);
379 void CopyToSurface(Surface &target, Point source_origin, Point target_origin,
381 ::copywin(m_window, target.get(), source_origin.y, source_origin.x,
382 target_origin.y, target_origin.x,
383 target_origin.y + size.height - 1,
384 target_origin.x + size.width - 1,
false);
387 int GetCursorX()
const {
return getcurx(m_window); }
388 int GetCursorY()
const {
return getcury(m_window); }
389 void MoveCursor(
int x,
int y) { ::wmove(m_window, y, x); }
391 void AttributeOn(attr_t attr) { ::wattron(m_window, attr); }
392 void AttributeOff(attr_t attr) { ::wattroff(m_window, attr); }
394 int GetMaxX()
const {
return getmaxx(m_window); }
395 int GetMaxY()
const {
return getmaxy(m_window); }
396 int GetWidth()
const {
return GetMaxX(); }
397 int GetHeight()
const {
return GetMaxY(); }
398 Size GetSize()
const {
return Size(GetWidth(), GetHeight()); }
400 Rect GetFrame()
const {
return Rect(Point(), GetSize()); }
402 void Clear() { ::wclear(m_window); }
403 void Erase() { ::werase(m_window); }
405 void SetBackground(
int color_pair_idx) {
406 ::wbkgd(m_window, COLOR_PAIR(color_pair_idx));
409 void PutChar(
int ch) { ::waddch(m_window, ch); }
410 void PutCString(
const char *s,
int len = -1) { ::waddnstr(m_window, s, len); }
412 void PutCStringTruncated(
int right_pad,
const char *s,
int len = -1) {
413 int bytes_left = GetWidth() - GetCursorX();
414 if (bytes_left > right_pad) {
415 bytes_left -= right_pad;
416 ::waddnstr(m_window, s, len < 0 ? bytes_left : std::min(bytes_left, len));
420 void Printf(
const char *format, ...) __attribute__((format(printf, 2, 3))) {
422 va_start(args, format);
423 vw_printw(m_window, format, args);
427 void PrintfTruncated(
int right_pad,
const char *format, ...)
428 __attribute__((format(printf, 3, 4))) {
430 va_start(args, format);
434 PutCStringTruncated(right_pad, strm.
GetData());
437 void VerticalLine(
int n, chtype v_char = ACS_VLINE) {
438 ::wvline(m_window, v_char, n);
440 void HorizontalLine(
int n, chtype h_char = ACS_HLINE) {
441 ::whline(m_window, h_char, n);
443 void Box(chtype v_char = ACS_VLINE, chtype h_char = ACS_HLINE) {
444 ::box(m_window, v_char, h_char);
447 void TitledBox(
const char *title, chtype v_char = ACS_VLINE,
448 chtype h_char = ACS_HLINE) {
450 int title_offset = 2;
451 MoveCursor(title_offset, 0);
453 PutCString(title, GetWidth() - title_offset);
457 void Box(
const Rect &bounds, chtype v_char = ACS_VLINE,
458 chtype h_char = ACS_HLINE) {
459 MoveCursor(bounds.origin.x, bounds.origin.y);
460 VerticalLine(bounds.size.height);
461 HorizontalLine(bounds.size.width);
462 PutChar(ACS_ULCORNER);
464 MoveCursor(bounds.origin.x + bounds.size.width - 1, bounds.origin.y);
465 VerticalLine(bounds.size.height);
466 PutChar(ACS_URCORNER);
468 MoveCursor(bounds.origin.x, bounds.origin.y + bounds.size.height - 1);
469 HorizontalLine(bounds.size.width);
470 PutChar(ACS_LLCORNER);
472 MoveCursor(bounds.origin.x + bounds.size.width - 1,
473 bounds.origin.y + bounds.size.height - 1);
474 PutChar(ACS_LRCORNER);
477 void TitledBox(
const Rect &bounds,
const char *title,
478 chtype v_char = ACS_VLINE, chtype h_char = ACS_HLINE) {
479 Box(bounds, v_char, h_char);
480 int title_offset = 2;
481 MoveCursor(bounds.origin.x + title_offset, bounds.origin.y);
483 PutCString(title, bounds.size.width - title_offset);
492 bool OutputColoredStringTruncated(
int right_pad, StringRef
string,
493 size_t skip_first_count,
494 bool use_blue_background) {
498 wattr_get(m_window, &saved_attr, &saved_pair,
nullptr);
499 if (use_blue_background)
500 ::wattron(m_window, COLOR_PAIR(WhiteOnBlue));
501 while (!
string.empty()) {
503 if (esc_pos == StringRef::npos) {
504 string =
string.substr(skip_first_count);
505 if (!
string.empty()) {
506 PutCStringTruncated(right_pad,
string.data(),
string.size());
512 if (skip_first_count > 0) {
513 int skip = std::min(esc_pos, skip_first_count);
514 string =
string.substr(skip);
515 skip_first_count -= skip;
519 PutCStringTruncated(right_pad,
string.data(), esc_pos);
521 string =
string.drop_front(esc_pos);
533 if (!!
string.consumeInteger(10, value) ||
536 llvm::errs() <<
"No valid color code in color escape sequence.\n";
541 <<
"' in color escape sequence.\n";
545 wattr_set(m_window, saved_attr, saved_pair,
nullptr);
546 if (use_blue_background)
547 ::wattron(m_window, COLOR_PAIR(WhiteOnBlue));
549 ::wattron(m_window, A_UNDERLINE);
553 (use_blue_background ? 8 : 0)));
556 wattr_set(m_window, saved_attr, saved_pair,
nullptr);
562 WINDOW *m_window =
nullptr;
565class Pad :
public Surface {
567 Pad(Size size) : Surface(Surface::
Type::Pad) {
568 m_window = ::newpad(size.height, size.width);
571 ~Pad() { ::delwin(m_window); }
574class Window :
public Surface {
576 Window(
const char *name)
577 : Surface(Surface::
Type::Window), m_name(name), m_panel(nullptr),
578 m_parent(nullptr), m_subwindows(), m_delegate_sp(),
580 m_prev_active_window_idx(
UINT32_MAX), m_delete(false),
581 m_needs_update(true), m_can_activate(true), m_is_subwin(false) {}
583 Window(
const char *name, WINDOW *w,
bool del =
true)
584 : Surface(Surface::
Type::Window), m_name(name), m_panel(nullptr),
585 m_parent(nullptr), m_subwindows(), m_delegate_sp(),
587 m_prev_active_window_idx(
UINT32_MAX), m_delete(del),
588 m_needs_update(true), m_can_activate(true), m_is_subwin(false) {
593 Window(
const char *name,
const Rect &bounds)
594 : Surface(Surface::
Type::Window), m_name(name), m_panel(nullptr),
595 m_parent(nullptr), m_subwindows(), m_delegate_sp(),
597 m_prev_active_window_idx(
UINT32_MAX), m_delete(false),
598 m_needs_update(true), m_can_activate(true), m_is_subwin(false) {
599 Reset(::newwin(bounds.size.height, bounds.size.width, bounds.origin.y,
608 void Reset(WINDOW *w =
nullptr,
bool del =
true) {
613 ::del_panel(m_panel);
616 if (m_window && m_delete) {
623 m_panel = ::new_panel(m_window);
629 Rect GetBounds()
const {
return Rect(GetParentOrigin(), GetSize()); }
631 Rect GetCenteredRect(
int width,
int height) {
632 Size size = GetSize();
633 width = std::min(size.width, width);
634 height = std::min(size.height, height);
635 int x = (size.width - width) / 2;
636 int y = (size.height - height) / 2;
637 return Rect(Point(x, y), Size(width, height));
640 int GetChar() { return ::wgetch(m_window); }
641 Point GetParentOrigin()
const {
return Point(GetParentX(), GetParentY()); }
642 int GetParentX()
const {
return getparx(m_window); }
643 int GetParentY()
const {
return getpary(m_window); }
644 void MoveWindow(
int x,
int y) { MoveWindow(Point(x, y)); }
645 void Resize(
int w,
int h) { ::wresize(m_window, h, w); }
646 void Resize(
const Size &size) {
647 ::wresize(m_window, size.height, size.width);
649 void MoveWindow(
const Point &origin) {
650 const bool moving_window = origin != GetParentOrigin();
651 if (m_is_subwin && moving_window) {
653 Size size = GetSize();
654 Reset(::subwin(m_parent->m_window, size.height, size.width, origin.y,
658 ::mvwin(m_window, origin.y, origin.x);
662 void SetBounds(
const Rect &bounds) {
663 const bool moving_window = bounds.origin != GetParentOrigin();
664 if (m_is_subwin && moving_window) {
666 Reset(::subwin(m_parent->m_window, bounds.size.height, bounds.size.width,
667 bounds.origin.y, bounds.origin.x),
671 MoveWindow(bounds.origin);
677 ::touchwin(m_window);
682 WindowSP CreateSubWindow(
const char *name,
const Rect &bounds,
684 auto get_window = [
this, &bounds]() {
686 ? ::subwin(m_window, bounds.size.height, bounds.size.width,
687 bounds.origin.y, bounds.origin.x)
688 : ::newwin(bounds.size.height, bounds.size.width,
689 bounds.origin.y, bounds.origin.x);
691 WindowSP subwindow_sp = std::make_shared<Window>(name, get_window(),
true);
692 subwindow_sp->m_is_subwin = subwindow_sp.operator bool();
693 subwindow_sp->m_parent =
this;
695 m_prev_active_window_idx = m_curr_active_window_idx;
696 m_curr_active_window_idx = m_subwindows.size();
698 m_subwindows.push_back(subwindow_sp);
699 ::top_panel(subwindow_sp->m_panel);
700 m_needs_update =
true;
704 bool RemoveSubWindow(Window *window) {
705 Windows::iterator pos, end = m_subwindows.end();
707 for (pos = m_subwindows.begin(); pos != end; ++pos, ++i) {
708 if ((*pos).get() == window) {
709 if (m_prev_active_window_idx == i)
711 else if (m_prev_active_window_idx !=
UINT32_MAX &&
712 m_prev_active_window_idx > i)
713 --m_prev_active_window_idx;
715 if (m_curr_active_window_idx == i)
717 else if (m_curr_active_window_idx !=
UINT32_MAX &&
718 m_curr_active_window_idx > i)
719 --m_curr_active_window_idx;
721 m_subwindows.erase(pos);
722 m_needs_update =
true;
733 WindowSP FindSubWindow(
const char *name) {
734 Windows::iterator pos, end = m_subwindows.end();
736 for (pos = m_subwindows.begin(); pos != end; ++pos, ++i) {
737 if ((*pos)->m_name == name)
743 void RemoveSubWindows() {
746 for (Windows::iterator pos = m_subwindows.begin();
747 pos != m_subwindows.end(); pos = m_subwindows.erase(pos)) {
757 void DrawTitleBox(
const char *title,
const char *bottom_message =
nullptr) {
760 attr = A_BOLD | COLOR_PAIR(BlackOnWhite);
769 if (title && title[0]) {
775 if (bottom_message && bottom_message[0]) {
776 int bottom_message_length = strlen(bottom_message);
777 int x = GetWidth() - 3 - (bottom_message_length + 2);
780 MoveCursor(x, GetHeight() - 1);
782 PutCString(bottom_message);
785 MoveCursor(1, GetHeight() - 1);
787 PutCStringTruncated(1, bottom_message);
794 virtual void Draw(
bool force) {
795 if (m_delegate_sp && m_delegate_sp->WindowDelegateDraw(*
this, force))
798 for (
auto &subwindow_sp : m_subwindows)
799 subwindow_sp->Draw(force);
802 bool CreateHelpSubwindow() {
804 const char *text = m_delegate_sp->WindowDelegateGetHelpText();
805 KeyHelp *key_help = m_delegate_sp->WindowDelegateGetKeyHelp();
806 if ((text && text[0]) || key_help) {
807 std::unique_ptr<HelpDialogDelegate> help_delegate_up(
808 new HelpDialogDelegate(text, key_help));
809 const size_t num_lines = help_delegate_up->GetNumLines();
810 const size_t max_length = help_delegate_up->GetMaxLineLength();
811 Rect bounds = GetBounds();
813 if (max_length + 4 <
static_cast<size_t>(bounds.size.width)) {
814 bounds.origin.x += (bounds.size.width - max_length + 4) / 2;
815 bounds.size.width = max_length + 4;
817 if (bounds.size.width > 100) {
818 const int inset_w = bounds.size.width / 4;
819 bounds.origin.x += inset_w;
820 bounds.size.width -= 2 * inset_w;
824 if (num_lines + 2 <
static_cast<size_t>(bounds.size.height)) {
825 bounds.origin.y += (bounds.size.height - num_lines + 2) / 2;
826 bounds.size.height = num_lines + 2;
828 if (bounds.size.height > 100) {
829 const int inset_h = bounds.size.height / 4;
830 bounds.origin.y += inset_h;
831 bounds.size.height -= 2 * inset_h;
834 WindowSP help_window_sp;
835 Window *parent_window = GetParent();
837 help_window_sp = parent_window->CreateSubWindow(
"Help", bounds,
true);
839 help_window_sp = CreateSubWindow(
"Help", bounds,
true);
840 help_window_sp->SetDelegate(
841 WindowDelegateSP(help_delegate_up.release()));
848 virtual HandleCharResult HandleChar(
int key) {
850 HandleCharResult result = eKeyNotHandled;
851 WindowSP active_window_sp = GetActiveWindow();
852 if (active_window_sp) {
853 result = active_window_sp->HandleChar(key);
854 if (result != eKeyNotHandled)
859 result = m_delegate_sp->WindowDelegateHandleChar(*
this, key);
860 if (result != eKeyNotHandled)
868 Windows subwindows(m_subwindows);
869 for (
auto subwindow_sp : subwindows) {
870 if (!subwindow_sp->m_can_activate) {
871 HandleCharResult result = subwindow_sp->HandleChar(key);
872 if (result != eKeyNotHandled)
877 return eKeyNotHandled;
880 WindowSP GetActiveWindow() {
881 if (!m_subwindows.empty()) {
882 if (m_curr_active_window_idx >= m_subwindows.size()) {
883 if (m_prev_active_window_idx < m_subwindows.size()) {
884 m_curr_active_window_idx = m_prev_active_window_idx;
886 }
else if (IsActive()) {
891 const size_t num_subwindows = m_subwindows.size();
892 for (
size_t i = 0; i < num_subwindows; ++i) {
893 if (m_subwindows[i]->GetCanBeActive()) {
894 m_curr_active_window_idx = i;
901 if (m_curr_active_window_idx < m_subwindows.size())
902 return m_subwindows[m_curr_active_window_idx];
907 bool GetCanBeActive()
const {
return m_can_activate; }
909 void SetCanBeActive(
bool b) { m_can_activate = b; }
911 void SetDelegate(
const WindowDelegateSP &delegate_sp) {
912 m_delegate_sp = delegate_sp;
915 Window *GetParent()
const {
return m_parent; }
917 bool IsActive()
const {
919 return m_parent->GetActiveWindow().get() ==
this;
924 void SelectNextWindowAsActive() {
926 const int num_subwindows = m_subwindows.size();
929 m_prev_active_window_idx = m_curr_active_window_idx;
930 start_idx = m_curr_active_window_idx + 1;
932 for (
int idx = start_idx; idx < num_subwindows; ++idx) {
933 if (m_subwindows[idx]->GetCanBeActive()) {
934 m_curr_active_window_idx = idx;
938 for (
int idx = 0; idx < start_idx; ++idx) {
939 if (m_subwindows[idx]->GetCanBeActive()) {
940 m_curr_active_window_idx = idx;
946 void SelectPreviousWindowAsActive() {
948 const int num_subwindows = m_subwindows.size();
949 int start_idx = num_subwindows - 1;
951 m_prev_active_window_idx = m_curr_active_window_idx;
952 start_idx = m_curr_active_window_idx - 1;
954 for (
int idx = start_idx; idx >= 0; --idx) {
955 if (m_subwindows[idx]->GetCanBeActive()) {
956 m_curr_active_window_idx = idx;
960 for (
int idx = num_subwindows - 1; idx > start_idx; --idx) {
961 if (m_subwindows[idx]->GetCanBeActive()) {
962 m_curr_active_window_idx = idx;
968 const char *
GetName()
const {
return m_name.c_str(); }
974 Windows m_subwindows;
975 WindowDelegateSP m_delegate_sp;
976 uint32_t m_curr_active_window_idx;
977 uint32_t m_prev_active_window_idx;
984 Window(
const Window &) =
delete;
985 const Window &operator=(
const Window &) =
delete;
996struct ScrollContext {
1000 ScrollContext(
int line) : start(line), end(line) {}
1001 ScrollContext(
int _start,
int _end) : start(_start), end(_end) {}
1003 void Offset(
int offset) {
1009class FieldDelegate {
1011 virtual ~FieldDelegate() =
default;
1015 virtual int FieldDelegateGetHeight() = 0;
1022 virtual ScrollContext FieldDelegateGetScrollContext() {
1023 return ScrollContext(0, FieldDelegateGetHeight() - 1);
1029 virtual void FieldDelegateDraw(Surface &surface,
bool is_selected) = 0;
1032 virtual HandleCharResult FieldDelegateHandleChar(
int key) {
1033 return eKeyNotHandled;
1040 virtual void FieldDelegateExitCallback() {}
1054 virtual bool FieldDelegateOnFirstOrOnlyElement() {
return true; }
1058 virtual bool FieldDelegateOnLastOrOnlyElement() {
return true; }
1061 virtual void FieldDelegateSelectFirstElement() {}
1064 virtual void FieldDelegateSelectLastElement() {}
1067 virtual bool FieldDelegateHasError() {
return false; }
1069 bool FieldDelegateIsVisible() {
return m_is_visible; }
1071 void FieldDelegateHide() { m_is_visible =
false; }
1073 void FieldDelegateShow() { m_is_visible =
true; }
1076 bool m_is_visible =
true;
1079typedef std::unique_ptr<FieldDelegate> FieldDelegateUP;
1081class TextFieldDelegate :
public FieldDelegate {
1083 TextFieldDelegate(
const char *label,
const char *content,
bool required)
1084 : m_label(label), m_required(required) {
1086 m_content = content;
1099 int GetFieldHeight() {
return 3; }
1103 int FieldDelegateGetHeight()
override {
1104 int height = GetFieldHeight();
1105 if (FieldDelegateHasError())
1111 int GetCursorXPosition() {
return m_cursor_position - m_first_visibile_char; }
1113 int GetContentLength() {
return m_content.length(); }
1115 void DrawContent(Surface &surface,
bool is_selected) {
1116 UpdateScrolling(surface.GetWidth());
1118 surface.MoveCursor(0, 0);
1119 const char *text = m_content.c_str() + m_first_visibile_char;
1120 surface.PutCString(text, surface.GetWidth());
1123 surface.MoveCursor(GetCursorXPosition(), 0);
1125 surface.AttributeOn(A_REVERSE);
1126 if (m_cursor_position == GetContentLength())
1128 surface.PutChar(
' ');
1130 surface.PutChar(m_content[m_cursor_position]);
1132 surface.AttributeOff(A_REVERSE);
1135 void DrawField(Surface &surface,
bool is_selected) {
1136 surface.TitledBox(m_label.c_str());
1138 Rect content_bounds = surface.GetFrame();
1139 content_bounds.Inset(1, 1);
1140 Surface content_surface = surface.SubSurface(content_bounds);
1142 DrawContent(content_surface, is_selected);
1145 void DrawError(Surface &surface) {
1146 if (!FieldDelegateHasError())
1148 surface.MoveCursor(0, 0);
1149 surface.AttributeOn(COLOR_PAIR(RedOnBlack));
1150 surface.PutChar(ACS_DIAMOND);
1151 surface.PutChar(
' ');
1152 surface.PutCStringTruncated(1, GetError().c_str());
1153 surface.AttributeOff(COLOR_PAIR(RedOnBlack));
1156 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
1157 Rect frame = surface.GetFrame();
1158 Rect field_bounds, error_bounds;
1159 frame.HorizontalSplit(GetFieldHeight(), field_bounds, error_bounds);
1160 Surface field_surface = surface.SubSurface(field_bounds);
1161 Surface error_surface = surface.SubSurface(error_bounds);
1163 DrawField(field_surface, is_selected);
1164 DrawError(error_surface);
1168 int GetLastVisibleCharPosition(
int width) {
1169 int position = m_first_visibile_char + width - 1;
1170 return std::min(position, GetContentLength());
1173 void UpdateScrolling(
int width) {
1174 if (m_cursor_position < m_first_visibile_char) {
1175 m_first_visibile_char = m_cursor_position;
1179 if (m_cursor_position > GetLastVisibleCharPosition(width))
1180 m_first_visibile_char = m_cursor_position - (width - 1);
1185 void MoveCursorRight() {
1186 if (m_cursor_position < GetContentLength())
1187 m_cursor_position++;
1190 void MoveCursorLeft() {
1191 if (m_cursor_position > 0)
1192 m_cursor_position--;
1195 void MoveCursorToStart() { m_cursor_position = 0; }
1197 void MoveCursorToEnd() { m_cursor_position = GetContentLength(); }
1200 if (m_first_visibile_char > 0)
1201 m_first_visibile_char--;
1206 void InsertChar(
char character) {
1207 m_content.insert(m_cursor_position, 1, character);
1208 m_cursor_position++;
1214 void RemovePreviousChar() {
1215 if (m_cursor_position == 0)
1218 m_content.erase(m_cursor_position - 1, 1);
1219 m_cursor_position--;
1225 void RemoveNextChar() {
1226 if (m_cursor_position == GetContentLength())
1229 m_content.erase(m_cursor_position, 1);
1235 m_content.erase(m_cursor_position);
1241 m_cursor_position = 0;
1247 virtual bool IsAcceptableChar(
int key) {
1252 return isprint(key);
1255 HandleCharResult FieldDelegateHandleChar(
int key)
override {
1256 if (IsAcceptableChar(key)) {
1258 InsertChar((
char)key);
1265 MoveCursorToStart();
1281 RemovePreviousChar();
1297 return eKeyNotHandled;
1300 bool FieldDelegateHasError()
override {
return !m_error.empty(); }
1302 void FieldDelegateExitCallback()
override {
1303 if (!IsSpecified() && m_required)
1304 SetError(
"This field is required!");
1307 bool IsSpecified() {
return !m_content.empty(); }
1309 void ClearError() { m_error.clear(); }
1311 const std::string &GetError() {
return m_error; }
1313 void SetError(
const char *
error) { m_error =
error; }
1315 const std::string &GetText() {
return m_content; }
1317 void SetText(
const char *text) {
1318 if (text ==
nullptr) {
1326 std::string m_label;
1329 std::string m_content;
1332 int m_cursor_position = 0;
1334 int m_first_visibile_char = 0;
1336 std::string m_error;
1339class IntegerFieldDelegate :
public TextFieldDelegate {
1341 IntegerFieldDelegate(
const char *label,
int content,
bool required)
1342 : TextFieldDelegate(label, std::to_string(content).c_str(), required) {}
1345 bool IsAcceptableChar(
int key)
override {
return isdigit(key); }
1348 int GetInteger() {
return std::stoi(m_content); }
1351class FileFieldDelegate :
public TextFieldDelegate {
1353 FileFieldDelegate(
const char *label,
const char *content,
bool need_to_exist,
1355 : TextFieldDelegate(label, content, required),
1356 m_need_to_exist(need_to_exist) {}
1358 void FieldDelegateExitCallback()
override {
1359 TextFieldDelegate::FieldDelegateExitCallback();
1363 if (!m_need_to_exist)
1366 FileSpec file = GetResolvedFileSpec();
1368 SetError(
"File doesn't exist!");
1372 SetError(
"Not a file!");
1377 FileSpec GetFileSpec() {
1378 FileSpec file_spec(GetPath());
1382 FileSpec GetResolvedFileSpec() {
1383 FileSpec file_spec(GetPath());
1388 const std::string &GetPath() {
return m_content; }
1391 bool m_need_to_exist;
1394class DirectoryFieldDelegate :
public TextFieldDelegate {
1396 DirectoryFieldDelegate(
const char *label,
const char *content,
1397 bool need_to_exist,
bool required)
1398 : TextFieldDelegate(label, content, required),
1399 m_need_to_exist(need_to_exist) {}
1401 void FieldDelegateExitCallback()
override {
1402 TextFieldDelegate::FieldDelegateExitCallback();
1406 if (!m_need_to_exist)
1409 FileSpec file = GetResolvedFileSpec();
1411 SetError(
"Directory doesn't exist!");
1415 SetError(
"Not a directory!");
1420 FileSpec GetFileSpec() {
1421 FileSpec file_spec(GetPath());
1425 FileSpec GetResolvedFileSpec() {
1426 FileSpec file_spec(GetPath());
1431 const std::string &GetPath() {
return m_content; }
1434 bool m_need_to_exist;
1437class ArchFieldDelegate :
public TextFieldDelegate {
1439 ArchFieldDelegate(
const char *label,
const char *content,
bool required)
1440 : TextFieldDelegate(label, content, required) {}
1442 void FieldDelegateExitCallback()
override {
1443 TextFieldDelegate::FieldDelegateExitCallback();
1447 if (!GetArchSpec().IsValid())
1448 SetError(
"Not a valid arch!");
1451 const std::string &GetArchString() {
return m_content; }
1453 ArchSpec GetArchSpec() {
return ArchSpec(GetArchString()); }
1456class BooleanFieldDelegate :
public FieldDelegate {
1458 BooleanFieldDelegate(
const char *label,
bool content)
1459 : m_label(label), m_content(content) {}
1466 int FieldDelegateGetHeight()
override {
return 1; }
1468 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
1469 surface.MoveCursor(0, 0);
1470 surface.PutChar(
'[');
1472 surface.AttributeOn(A_REVERSE);
1473 surface.PutChar(m_content ? ACS_DIAMOND :
' ');
1475 surface.AttributeOff(A_REVERSE);
1476 surface.PutChar(
']');
1477 surface.PutChar(
' ');
1478 surface.PutCString(m_label.c_str());
1481 void ToggleContent() { m_content = !m_content; }
1483 void SetContentToTrue() { m_content =
true; }
1485 void SetContentToFalse() { m_content =
false; }
1487 HandleCharResult FieldDelegateHandleChar(
int key)
override {
1495 SetContentToFalse();
1506 return eKeyNotHandled;
1510 bool GetBoolean() {
return m_content; }
1513 std::string m_label;
1517class ChoicesFieldDelegate :
public FieldDelegate {
1519 ChoicesFieldDelegate(
const char *label,
int number_of_visible_choices,
1520 std::vector<std::string> choices)
1521 : m_label(label), m_number_of_visible_choices(number_of_visible_choices),
1522 m_choices(choices) {}
1536 int FieldDelegateGetHeight()
override {
1537 return m_number_of_visible_choices + 2;
1540 int GetNumberOfChoices() {
return m_choices.size(); }
1543 int GetLastVisibleChoice() {
1544 int index = m_first_visibile_choice + m_number_of_visible_choices;
1545 return std::min(index, GetNumberOfChoices()) - 1;
1548 void DrawContent(Surface &surface,
bool is_selected) {
1549 int choices_to_draw = GetLastVisibleChoice() - m_first_visibile_choice + 1;
1550 for (
int i = 0; i < choices_to_draw; i++) {
1551 surface.MoveCursor(0, i);
1552 int current_choice = m_first_visibile_choice + i;
1553 const char *text = m_choices[current_choice].c_str();
1554 bool highlight = is_selected && current_choice == m_choice;
1556 surface.AttributeOn(A_REVERSE);
1557 surface.PutChar(current_choice == m_choice ? ACS_DIAMOND :
' ');
1558 surface.PutCString(text);
1560 surface.AttributeOff(A_REVERSE);
1564 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
1567 surface.TitledBox(m_label.c_str());
1569 Rect content_bounds = surface.GetFrame();
1570 content_bounds.Inset(1, 1);
1571 Surface content_surface = surface.SubSurface(content_bounds);
1573 DrawContent(content_surface, is_selected);
1576 void SelectPrevious() {
1582 if (m_choice < GetNumberOfChoices() - 1)
1586 void UpdateScrolling() {
1587 if (m_choice > GetLastVisibleChoice()) {
1588 m_first_visibile_choice = m_choice - (m_number_of_visible_choices - 1);
1592 if (m_choice < m_first_visibile_choice)
1593 m_first_visibile_choice = m_choice;
1596 HandleCharResult FieldDelegateHandleChar(
int key)
override {
1607 return eKeyNotHandled;
1611 std::string GetChoiceContent() {
return m_choices[m_choice]; }
1614 int GetChoice() {
return m_choice; }
1616 void SetChoice(llvm::StringRef choice) {
1617 for (
int i = 0; i < GetNumberOfChoices(); i++) {
1618 if (choice == m_choices[i]) {
1626 std::string m_label;
1627 int m_number_of_visible_choices;
1628 std::vector<std::string> m_choices;
1632 int m_first_visibile_choice = 0;
1635class PlatformPluginFieldDelegate :
public ChoicesFieldDelegate {
1637 PlatformPluginFieldDelegate(Debugger &debugger)
1638 : ChoicesFieldDelegate(
"Platform Plugin", 3, GetPossiblePluginNames()) {
1641 SetChoice(platform_sp->GetPluginName());
1644 std::vector<std::string> GetPossiblePluginNames() {
1645 std::vector<std::string> names;
1647 for (llvm::StringRef name =
1650 names.push_back(name.str());
1654 std::string GetPluginName() {
1655 std::string plugin_name = GetChoiceContent();
1660class ProcessPluginFieldDelegate :
public ChoicesFieldDelegate {
1662 ProcessPluginFieldDelegate()
1663 : ChoicesFieldDelegate(
"Process Plugin", 3, GetPossiblePluginNames()) {}
1665 std::vector<std::string> GetPossiblePluginNames() {
1666 std::vector<std::string> names;
1667 names.push_back(
"<default>");
1672 names.push_back(name.str());
1676 std::string GetPluginName() {
1677 std::string plugin_name = GetChoiceContent();
1678 if (plugin_name ==
"<default>")
1684class LazyBooleanFieldDelegate :
public ChoicesFieldDelegate {
1686 LazyBooleanFieldDelegate(
const char *label,
const char *calculate_label)
1687 : ChoicesFieldDelegate(label, 3, GetPossibleOptions(calculate_label)) {}
1689 static constexpr const char *kNo =
"No";
1690 static constexpr const char *kYes =
"Yes";
1692 std::vector<std::string> GetPossibleOptions(
const char *calculate_label) {
1693 std::vector<std::string> options;
1694 options.push_back(calculate_label);
1695 options.push_back(kYes);
1696 options.push_back(kNo);
1701 std::string choice = GetChoiceContent();
1704 else if (choice == kYes)
1711template <
class T>
class ListFieldDelegate :
public FieldDelegate {
1713 ListFieldDelegate(
const char *label, T default_field)
1714 : m_label(label), m_default_field(default_field),
1715 m_selection_type(SelectionType::NewButton) {}
1720 enum class SelectionType { Field, RemoveButton, NewButton };
1736 int FieldDelegateGetHeight()
override {
1740 for (
int i = 0; i < GetNumberOfFields(); i++) {
1741 height += m_fields[i].FieldDelegateGetHeight();
1748 ScrollContext FieldDelegateGetScrollContext()
override {
1749 int height = FieldDelegateGetHeight();
1750 if (m_selection_type == SelectionType::NewButton)
1751 return ScrollContext(height - 2, height - 1);
1753 FieldDelegate &field = m_fields[m_selection_index];
1754 ScrollContext context = field.FieldDelegateGetScrollContext();
1758 for (
int i = 0; i < m_selection_index; i++) {
1759 offset += m_fields[i].FieldDelegateGetHeight();
1761 context.Offset(offset);
1765 if (context.start == 1)
1770 if (context.end == height - 3)
1776 void DrawRemoveButton(Surface &surface,
int highlight) {
1777 surface.MoveCursor(1, surface.GetHeight() / 2);
1779 surface.AttributeOn(A_REVERSE);
1780 surface.PutCString(
"[Remove]");
1782 surface.AttributeOff(A_REVERSE);
1785 void DrawFields(Surface &surface,
bool is_selected) {
1787 int width = surface.GetWidth();
1788 for (
int i = 0; i < GetNumberOfFields(); i++) {
1789 int height = m_fields[i].FieldDelegateGetHeight();
1790 Rect bounds = Rect(Point(0, line), Size(width, height));
1791 Rect field_bounds, remove_button_bounds;
1792 bounds.VerticalSplit(bounds.size.width -
sizeof(
" [Remove]"),
1793 field_bounds, remove_button_bounds);
1794 Surface field_surface = surface.SubSurface(field_bounds);
1795 Surface remove_button_surface = surface.SubSurface(remove_button_bounds);
1797 bool is_element_selected = m_selection_index == i && is_selected;
1798 bool is_field_selected =
1799 is_element_selected && m_selection_type == SelectionType::Field;
1800 bool is_remove_button_selected =
1801 is_element_selected &&
1802 m_selection_type == SelectionType::RemoveButton;
1803 m_fields[i].FieldDelegateDraw(field_surface, is_field_selected);
1804 DrawRemoveButton(remove_button_surface, is_remove_button_selected);
1810 void DrawNewButton(Surface &surface,
bool is_selected) {
1811 const char *button_text =
"[New]";
1812 int x = (surface.GetWidth() -
sizeof(button_text) - 1) / 2;
1813 surface.MoveCursor(x, 0);
1815 is_selected && m_selection_type == SelectionType::NewButton;
1817 surface.AttributeOn(A_REVERSE);
1818 surface.PutCString(button_text);
1820 surface.AttributeOff(A_REVERSE);
1823 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
1824 surface.TitledBox(m_label.c_str());
1826 Rect content_bounds = surface.GetFrame();
1827 content_bounds.Inset(1, 1);
1828 Rect fields_bounds, new_button_bounds;
1829 content_bounds.HorizontalSplit(content_bounds.size.height - 1,
1830 fields_bounds, new_button_bounds);
1831 Surface fields_surface = surface.SubSurface(fields_bounds);
1832 Surface new_button_surface = surface.SubSurface(new_button_bounds);
1834 DrawFields(fields_surface, is_selected);
1835 DrawNewButton(new_button_surface, is_selected);
1838 void AddNewField() {
1839 m_fields.push_back(m_default_field);
1840 m_selection_index = GetNumberOfFields() - 1;
1841 m_selection_type = SelectionType::Field;
1842 FieldDelegate &field = m_fields[m_selection_index];
1843 field.FieldDelegateSelectFirstElement();
1846 void RemoveField() {
1847 m_fields.erase(m_fields.begin() + m_selection_index);
1848 if (m_selection_index != 0)
1849 m_selection_index--;
1851 if (GetNumberOfFields() > 0) {
1852 m_selection_type = SelectionType::Field;
1853 FieldDelegate &field = m_fields[m_selection_index];
1854 field.FieldDelegateSelectFirstElement();
1856 m_selection_type = SelectionType::NewButton;
1859 HandleCharResult SelectNext(
int key) {
1860 if (m_selection_type == SelectionType::NewButton)
1861 return eKeyNotHandled;
1863 if (m_selection_type == SelectionType::RemoveButton) {
1864 if (m_selection_index == GetNumberOfFields() - 1) {
1865 m_selection_type = SelectionType::NewButton;
1868 m_selection_index++;
1869 m_selection_type = SelectionType::Field;
1870 FieldDelegate &next_field = m_fields[m_selection_index];
1871 next_field.FieldDelegateSelectFirstElement();
1875 FieldDelegate &field = m_fields[m_selection_index];
1876 if (!field.FieldDelegateOnLastOrOnlyElement()) {
1877 return field.FieldDelegateHandleChar(key);
1880 field.FieldDelegateExitCallback();
1882 m_selection_type = SelectionType::RemoveButton;
1886 HandleCharResult SelectPrevious(
int key) {
1887 if (FieldDelegateOnFirstOrOnlyElement())
1888 return eKeyNotHandled;
1890 if (m_selection_type == SelectionType::RemoveButton) {
1891 m_selection_type = SelectionType::Field;
1892 FieldDelegate &field = m_fields[m_selection_index];
1893 field.FieldDelegateSelectLastElement();
1897 if (m_selection_type == SelectionType::NewButton) {
1898 m_selection_type = SelectionType::RemoveButton;
1899 m_selection_index = GetNumberOfFields() - 1;
1903 FieldDelegate &field = m_fields[m_selection_index];
1904 if (!field.FieldDelegateOnFirstOrOnlyElement()) {
1905 return field.FieldDelegateHandleChar(key);
1908 field.FieldDelegateExitCallback();
1910 m_selection_type = SelectionType::RemoveButton;
1911 m_selection_index--;
1917 HandleCharResult SelectNextInList(
int key) {
1918 assert(m_selection_type == SelectionType::Field);
1920 FieldDelegate &field = m_fields[m_selection_index];
1921 if (field.FieldDelegateHandleChar(key) == eKeyHandled)
1924 if (!field.FieldDelegateOnLastOrOnlyElement())
1925 return eKeyNotHandled;
1927 field.FieldDelegateExitCallback();
1929 if (m_selection_index == GetNumberOfFields() - 1) {
1930 m_selection_type = SelectionType::NewButton;
1934 m_selection_index++;
1935 FieldDelegate &next_field = m_fields[m_selection_index];
1936 next_field.FieldDelegateSelectFirstElement();
1940 HandleCharResult FieldDelegateHandleChar(
int key)
override {
1945 switch (m_selection_type) {
1946 case SelectionType::NewButton:
1949 case SelectionType::RemoveButton:
1952 case SelectionType::Field:
1953 return SelectNextInList(key);
1957 return SelectNext(key);
1959 return SelectPrevious(key);
1966 if (m_selection_type == SelectionType::Field) {
1967 return m_fields[m_selection_index].FieldDelegateHandleChar(key);
1970 return eKeyNotHandled;
1973 bool FieldDelegateOnLastOrOnlyElement()
override {
1974 if (m_selection_type == SelectionType::NewButton) {
1980 bool FieldDelegateOnFirstOrOnlyElement()
override {
1981 if (m_selection_type == SelectionType::NewButton &&
1982 GetNumberOfFields() == 0)
1985 if (m_selection_type == SelectionType::Field && m_selection_index == 0) {
1986 FieldDelegate &field = m_fields[m_selection_index];
1987 return field.FieldDelegateOnFirstOrOnlyElement();
1993 void FieldDelegateSelectFirstElement()
override {
1994 if (GetNumberOfFields() == 0) {
1995 m_selection_type = SelectionType::NewButton;
1999 m_selection_type = SelectionType::Field;
2000 m_selection_index = 0;
2003 void FieldDelegateSelectLastElement()
override {
2004 m_selection_type = SelectionType::NewButton;
2007 int GetNumberOfFields() {
return m_fields.size(); }
2010 T &GetField(
int index) {
return m_fields[index]; }
2013 std::string m_label;
2017 std::vector<T> m_fields;
2018 int m_selection_index = 0;
2020 SelectionType m_selection_type;
2023class ArgumentsFieldDelegate :
public ListFieldDelegate<TextFieldDelegate> {
2025 ArgumentsFieldDelegate()
2026 : ListFieldDelegate(
"Arguments",
2027 TextFieldDelegate(
"Argument",
"", false)) {}
2029 Args GetArguments() {
2031 for (
int i = 0; i < GetNumberOfFields(); i++) {
2037 void AddArguments(
const Args &arguments) {
2040 TextFieldDelegate &field = GetField(GetNumberOfFields() - 1);
2046template <
class KeyFieldDelegateType,
class ValueFieldDelegateType>
2047class MappingFieldDelegate :
public FieldDelegate {
2049 MappingFieldDelegate(KeyFieldDelegateType key_field,
2050 ValueFieldDelegateType value_field)
2051 : m_key_field(key_field), m_value_field(value_field),
2052 m_selection_type(SelectionType::Key) {}
2055 enum class SelectionType { Key, Value };
2068 int FieldDelegateGetHeight()
override {
2069 return std::max(m_key_field.FieldDelegateGetHeight(),
2070 m_value_field.FieldDelegateGetHeight());
2073 void DrawArrow(Surface &surface) {
2074 surface.MoveCursor(0, 1);
2075 surface.PutChar(ACS_RARROW);
2078 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
2079 Rect bounds = surface.GetFrame();
2080 Rect key_field_bounds, arrow_and_value_field_bounds;
2081 bounds.VerticalSplit(bounds.size.width / 2, key_field_bounds,
2082 arrow_and_value_field_bounds);
2083 Rect arrow_bounds, value_field_bounds;
2084 arrow_and_value_field_bounds.VerticalSplit(1, arrow_bounds,
2085 value_field_bounds);
2087 Surface key_field_surface = surface.SubSurface(key_field_bounds);
2088 Surface arrow_surface = surface.SubSurface(arrow_bounds);
2089 Surface value_field_surface = surface.SubSurface(value_field_bounds);
2091 bool key_is_selected =
2092 m_selection_type == SelectionType::Key && is_selected;
2093 m_key_field.FieldDelegateDraw(key_field_surface, key_is_selected);
2094 DrawArrow(arrow_surface);
2095 bool value_is_selected =
2096 m_selection_type == SelectionType::Value && is_selected;
2097 m_value_field.FieldDelegateDraw(value_field_surface, value_is_selected);
2100 HandleCharResult SelectNext(
int key) {
2101 if (FieldDelegateOnLastOrOnlyElement())
2102 return eKeyNotHandled;
2104 if (!m_key_field.FieldDelegateOnLastOrOnlyElement()) {
2105 return m_key_field.FieldDelegateHandleChar(key);
2108 m_key_field.FieldDelegateExitCallback();
2109 m_selection_type = SelectionType::Value;
2110 m_value_field.FieldDelegateSelectFirstElement();
2114 HandleCharResult SelectPrevious(
int key) {
2115 if (FieldDelegateOnFirstOrOnlyElement())
2116 return eKeyNotHandled;
2118 if (!m_value_field.FieldDelegateOnFirstOrOnlyElement()) {
2119 return m_value_field.FieldDelegateHandleChar(key);
2122 m_value_field.FieldDelegateExitCallback();
2123 m_selection_type = SelectionType::Key;
2124 m_key_field.FieldDelegateSelectLastElement();
2131 HandleCharResult SelectNextField(
int key) {
2132 if (m_selection_type == SelectionType::Value) {
2133 return m_value_field.FieldDelegateHandleChar(key);
2136 if (m_key_field.FieldDelegateHandleChar(key) == eKeyHandled)
2139 if (!m_key_field.FieldDelegateOnLastOrOnlyElement())
2140 return eKeyNotHandled;
2142 m_key_field.FieldDelegateExitCallback();
2143 m_selection_type = SelectionType::Value;
2144 m_value_field.FieldDelegateSelectFirstElement();
2148 HandleCharResult FieldDelegateHandleChar(
int key)
override {
2151 return SelectNextField(key);
2153 return SelectNext(key);
2155 return SelectPrevious(key);
2161 if (m_selection_type == SelectionType::Key)
2162 return m_key_field.FieldDelegateHandleChar(key);
2164 return m_value_field.FieldDelegateHandleChar(key);
2166 return eKeyNotHandled;
2169 bool FieldDelegateOnFirstOrOnlyElement()
override {
2170 return m_selection_type == SelectionType::Key;
2173 bool FieldDelegateOnLastOrOnlyElement()
override {
2174 return m_selection_type == SelectionType::Value;
2177 void FieldDelegateSelectFirstElement()
override {
2178 m_selection_type = SelectionType::Key;
2181 void FieldDelegateSelectLastElement()
override {
2182 m_selection_type = SelectionType::Value;
2185 bool FieldDelegateHasError()
override {
2186 return m_key_field.FieldDelegateHasError() ||
2187 m_value_field.FieldDelegateHasError();
2190 KeyFieldDelegateType &GetKeyField() {
return m_key_field; }
2192 ValueFieldDelegateType &GetValueField() {
return m_value_field; }
2195 KeyFieldDelegateType m_key_field;
2196 ValueFieldDelegateType m_value_field;
2198 SelectionType m_selection_type;
2201class EnvironmentVariableNameFieldDelegate :
public TextFieldDelegate {
2203 EnvironmentVariableNameFieldDelegate(
const char *content)
2204 : TextFieldDelegate(
"Name", content, true) {}
2207 bool IsAcceptableChar(
int key)
override {
2208 return TextFieldDelegate::IsAcceptableChar(key) && key !=
'=';
2211 const std::string &
GetName() {
return m_content; }
2214class EnvironmentVariableFieldDelegate
2215 :
public MappingFieldDelegate<EnvironmentVariableNameFieldDelegate,
2216 TextFieldDelegate> {
2218 EnvironmentVariableFieldDelegate()
2219 : MappingFieldDelegate(
2220 EnvironmentVariableNameFieldDelegate(
""),
2221 TextFieldDelegate(
"Value",
"", false)) {}
2223 const std::string &
GetName() {
return GetKeyField().GetName(); }
2225 const std::string &GetValue() {
return GetValueField().GetText(); }
2227 void SetName(
const char *name) {
return GetKeyField().SetText(name); }
2229 void SetValue(
const char *value) {
return GetValueField().SetText(value); }
2232class EnvironmentVariableListFieldDelegate
2233 :
public ListFieldDelegate<EnvironmentVariableFieldDelegate> {
2235 EnvironmentVariableListFieldDelegate(
const char *label)
2236 : ListFieldDelegate(label, EnvironmentVariableFieldDelegate()) {}
2238 Environment GetEnvironment() {
2239 Environment environment;
2240 for (
int i = 0; i < GetNumberOfFields(); i++) {
2242 std::make_pair(GetField(i).
GetName(), GetField(i).GetValue()));
2247 void AddEnvironmentVariables(
const Environment &environment) {
2248 for (
auto &variable : environment) {
2250 EnvironmentVariableFieldDelegate &field =
2251 GetField(GetNumberOfFields() - 1);
2252 field.SetName(variable.getKey().str().c_str());
2253 field.SetValue(variable.getValue().c_str());
2260 FormAction(
const char *label, std::function<
void(Window &)> action)
2261 : m_action(action) {
2267 void Draw(Surface &surface,
bool is_selected) {
2268 int x = (surface.GetWidth() - m_label.length()) / 2;
2269 surface.MoveCursor(x, 0);
2271 surface.AttributeOn(A_REVERSE);
2272 surface.PutChar(
'[');
2273 surface.PutCString(m_label.c_str());
2274 surface.PutChar(
']');
2276 surface.AttributeOff(A_REVERSE);
2279 void Execute(Window &window) { m_action(window); }
2281 const std::string &GetLabel() {
return m_label; }
2284 std::string m_label;
2285 std::function<void(Window &)> m_action;
2290 FormDelegate() =
default;
2292 virtual ~FormDelegate() =
default;
2294 virtual std::string
GetName() = 0;
2296 virtual void UpdateFieldsVisibility() {}
2298 FieldDelegate *GetField(uint32_t field_index) {
2299 if (field_index < m_fields.size())
2300 return m_fields[field_index].get();
2304 FormAction &GetAction(
int action_index) {
return m_actions[action_index]; }
2306 int GetNumberOfFields() {
return m_fields.size(); }
2308 int GetNumberOfActions() {
return m_actions.size(); }
2310 bool HasError() {
return !m_error.empty(); }
2312 void ClearError() { m_error.clear(); }
2314 const std::string &GetError() {
return m_error; }
2316 void SetError(
const char *
error) { m_error =
error; }
2321 bool CheckFieldsValidity() {
2322 for (
int i = 0; i < GetNumberOfFields(); i++) {
2323 GetField(i)->FieldDelegateExitCallback();
2324 if (GetField(i)->FieldDelegateHasError()) {
2325 SetError(
"Some fields are invalid!");
2334 TextFieldDelegate *AddTextField(
const char *label,
const char *content,
2336 TextFieldDelegate *delegate =
2337 new TextFieldDelegate(label, content, required);
2338 m_fields.push_back(FieldDelegateUP(delegate));
2342 FileFieldDelegate *AddFileField(
const char *label,
const char *content,
2343 bool need_to_exist,
bool required) {
2344 FileFieldDelegate *delegate =
2345 new FileFieldDelegate(label, content, need_to_exist, required);
2346 m_fields.push_back(FieldDelegateUP(delegate));
2350 DirectoryFieldDelegate *AddDirectoryField(
const char *label,
2351 const char *content,
2352 bool need_to_exist,
bool required) {
2353 DirectoryFieldDelegate *delegate =
2354 new DirectoryFieldDelegate(label, content, need_to_exist, required);
2355 m_fields.push_back(FieldDelegateUP(delegate));
2359 ArchFieldDelegate *AddArchField(
const char *label,
const char *content,
2361 ArchFieldDelegate *delegate =
2362 new ArchFieldDelegate(label, content, required);
2363 m_fields.push_back(FieldDelegateUP(delegate));
2367 IntegerFieldDelegate *AddIntegerField(
const char *label,
int content,
2369 IntegerFieldDelegate *delegate =
2370 new IntegerFieldDelegate(label, content, required);
2371 m_fields.push_back(FieldDelegateUP(delegate));
2375 BooleanFieldDelegate *AddBooleanField(
const char *label,
bool content) {
2376 BooleanFieldDelegate *delegate =
new BooleanFieldDelegate(label, content);
2377 m_fields.push_back(FieldDelegateUP(delegate));
2381 LazyBooleanFieldDelegate *AddLazyBooleanField(
const char *label,
2382 const char *calculate_label) {
2383 LazyBooleanFieldDelegate *delegate =
2384 new LazyBooleanFieldDelegate(label, calculate_label);
2385 m_fields.push_back(FieldDelegateUP(delegate));
2389 ChoicesFieldDelegate *AddChoicesField(
const char *label,
int height,
2390 std::vector<std::string> choices) {
2391 ChoicesFieldDelegate *delegate =
2392 new ChoicesFieldDelegate(label, height, choices);
2393 m_fields.push_back(FieldDelegateUP(delegate));
2397 PlatformPluginFieldDelegate *AddPlatformPluginField(Debugger &debugger) {
2398 PlatformPluginFieldDelegate *delegate =
2399 new PlatformPluginFieldDelegate(debugger);
2400 m_fields.push_back(FieldDelegateUP(delegate));
2404 ProcessPluginFieldDelegate *AddProcessPluginField() {
2405 ProcessPluginFieldDelegate *delegate =
new ProcessPluginFieldDelegate();
2406 m_fields.push_back(FieldDelegateUP(delegate));
2411 ListFieldDelegate<T> *AddListField(
const char *label, T default_field) {
2412 ListFieldDelegate<T> *delegate =
2413 new ListFieldDelegate<T>(label, default_field);
2414 m_fields.push_back(FieldDelegateUP(delegate));
2418 ArgumentsFieldDelegate *AddArgumentsField() {
2419 ArgumentsFieldDelegate *delegate =
new ArgumentsFieldDelegate();
2420 m_fields.push_back(FieldDelegateUP(delegate));
2424 template <
class K,
class V>
2425 MappingFieldDelegate<K, V> *AddMappingField(K key_field, V value_field) {
2426 MappingFieldDelegate<K, V> *delegate =
2427 new MappingFieldDelegate<K, V>(key_field, value_field);
2428 m_fields.push_back(FieldDelegateUP(delegate));
2432 EnvironmentVariableNameFieldDelegate *
2433 AddEnvironmentVariableNameField(
const char *content) {
2434 EnvironmentVariableNameFieldDelegate *delegate =
2435 new EnvironmentVariableNameFieldDelegate(content);
2436 m_fields.push_back(FieldDelegateUP(delegate));
2440 EnvironmentVariableFieldDelegate *AddEnvironmentVariableField() {
2441 EnvironmentVariableFieldDelegate *delegate =
2442 new EnvironmentVariableFieldDelegate();
2443 m_fields.push_back(FieldDelegateUP(delegate));
2447 EnvironmentVariableListFieldDelegate *
2448 AddEnvironmentVariableListField(
const char *label) {
2449 EnvironmentVariableListFieldDelegate *delegate =
2450 new EnvironmentVariableListFieldDelegate(label);
2451 m_fields.push_back(FieldDelegateUP(delegate));
2457 void AddAction(
const char *label, std::function<
void(Window &)> action) {
2458 m_actions.push_back(FormAction(label, action));
2462 std::vector<FieldDelegateUP> m_fields;
2463 std::vector<FormAction> m_actions;
2465 std::string m_error;
2468typedef std::shared_ptr<FormDelegate> FormDelegateSP;
2470class FormWindowDelegate :
public WindowDelegate {
2472 FormWindowDelegate(FormDelegateSP &delegate_sp) : m_delegate_sp(delegate_sp) {
2473 assert(m_delegate_sp->GetNumberOfActions() > 0);
2474 if (m_delegate_sp->GetNumberOfFields() > 0)
2475 m_selection_type = SelectionType::Field;
2477 m_selection_type = SelectionType::Action;
2483 enum class SelectionType { Field, Action };
2501 int GetErrorHeight() {
2502 if (m_delegate_sp->HasError())
2508 int GetActionsHeight() {
2509 if (m_delegate_sp->GetNumberOfActions() > 0)
2515 int GetContentHeight() {
2517 height += GetErrorHeight();
2518 for (
int i = 0; i < m_delegate_sp->GetNumberOfFields(); i++) {
2519 if (!m_delegate_sp->GetField(i)->FieldDelegateIsVisible())
2521 height += m_delegate_sp->GetField(i)->FieldDelegateGetHeight();
2523 height += GetActionsHeight();
2527 ScrollContext GetScrollContext() {
2528 if (m_selection_type == SelectionType::Action)
2529 return ScrollContext(GetContentHeight() - 1);
2531 FieldDelegate *field = m_delegate_sp->GetField(m_selection_index);
2532 ScrollContext context = field->FieldDelegateGetScrollContext();
2534 int offset = GetErrorHeight();
2535 for (
int i = 0; i < m_selection_index; i++) {
2536 if (!m_delegate_sp->GetField(i)->FieldDelegateIsVisible())
2538 offset += m_delegate_sp->GetField(i)->FieldDelegateGetHeight();
2540 context.Offset(offset);
2544 if (context.start == GetErrorHeight())
2550 void UpdateScrolling(Surface &surface) {
2551 ScrollContext context = GetScrollContext();
2552 int content_height = GetContentHeight();
2553 int surface_height = surface.GetHeight();
2554 int visible_height = std::min(content_height, surface_height);
2555 int last_visible_line = m_first_visible_line + visible_height - 1;
2560 if (last_visible_line > content_height - 1) {
2561 m_first_visible_line = content_height - visible_height;
2564 if (context.start < m_first_visible_line) {
2565 m_first_visible_line = context.start;
2569 if (context.end > last_visible_line) {
2570 m_first_visible_line = context.end - visible_height + 1;
2574 void DrawError(Surface &surface) {
2575 if (!m_delegate_sp->HasError())
2577 surface.MoveCursor(0, 0);
2578 surface.AttributeOn(COLOR_PAIR(RedOnBlack));
2579 surface.PutChar(ACS_DIAMOND);
2580 surface.PutChar(
' ');
2581 surface.PutCStringTruncated(1, m_delegate_sp->GetError().c_str());
2582 surface.AttributeOff(COLOR_PAIR(RedOnBlack));
2584 surface.MoveCursor(0, 1);
2585 surface.HorizontalLine(surface.GetWidth());
2588 void DrawFields(Surface &surface) {
2590 int width = surface.GetWidth();
2591 bool a_field_is_selected = m_selection_type == SelectionType::Field;
2592 for (
int i = 0; i < m_delegate_sp->GetNumberOfFields(); i++) {
2593 FieldDelegate *field = m_delegate_sp->GetField(i);
2594 if (!field->FieldDelegateIsVisible())
2596 bool is_field_selected = a_field_is_selected && m_selection_index == i;
2597 int height = field->FieldDelegateGetHeight();
2598 Rect bounds = Rect(Point(0, line), Size(width, height));
2599 Surface field_surface = surface.SubSurface(bounds);
2600 field->FieldDelegateDraw(field_surface, is_field_selected);
2605 void DrawActions(Surface &surface) {
2606 int number_of_actions = m_delegate_sp->GetNumberOfActions();
2607 int width = surface.GetWidth() / number_of_actions;
2608 bool an_action_is_selected = m_selection_type == SelectionType::Action;
2610 for (
int i = 0; i < number_of_actions; i++) {
2611 bool is_action_selected = an_action_is_selected && m_selection_index == i;
2612 FormAction &action = m_delegate_sp->GetAction(i);
2613 Rect bounds = Rect(Point(x, 0), Size(width, 1));
2614 Surface action_surface = surface.SubSurface(bounds);
2615 action.Draw(action_surface, is_action_selected);
2620 void DrawElements(Surface &surface) {
2621 Rect frame = surface.GetFrame();
2622 Rect fields_bounds, actions_bounds;
2623 frame.HorizontalSplit(surface.GetHeight() - GetActionsHeight(),
2624 fields_bounds, actions_bounds);
2625 Surface fields_surface = surface.SubSurface(fields_bounds);
2626 Surface actions_surface = surface.SubSurface(actions_bounds);
2628 DrawFields(fields_surface);
2629 DrawActions(actions_surface);
2635 void DrawContent(Surface &surface) {
2636 UpdateScrolling(surface);
2638 int width = surface.GetWidth();
2639 int height = GetContentHeight();
2640 Pad pad = Pad(Size(width, height));
2642 Rect frame = pad.GetFrame();
2643 Rect error_bounds, elements_bounds;
2644 frame.HorizontalSplit(GetErrorHeight(), error_bounds, elements_bounds);
2645 Surface error_surface = pad.SubSurface(error_bounds);
2646 Surface elements_surface = pad.SubSurface(elements_bounds);
2648 DrawError(error_surface);
2649 DrawElements(elements_surface);
2651 int copy_height = std::min(surface.GetHeight(), pad.GetHeight());
2652 pad.CopyToSurface(surface, Point(0, m_first_visible_line), Point(),
2653 Size(width, copy_height));
2656 void DrawSubmitHint(Surface &surface,
bool is_active) {
2657 surface.MoveCursor(2, surface.GetHeight() - 1);
2659 surface.AttributeOn(A_BOLD | COLOR_PAIR(BlackOnWhite));
2660 surface.Printf(
"[Press Alt+Enter to %s]",
2661 m_delegate_sp->GetAction(0).GetLabel().c_str());
2663 surface.AttributeOff(A_BOLD | COLOR_PAIR(BlackOnWhite));
2666 bool WindowDelegateDraw(Window &window,
bool force)
override {
2667 m_delegate_sp->UpdateFieldsVisibility();
2671 window.DrawTitleBox(m_delegate_sp->GetName().c_str(),
2672 "Press Esc to Cancel");
2673 DrawSubmitHint(window, window.IsActive());
2675 Rect content_bounds = window.GetFrame();
2676 content_bounds.Inset(2, 2);
2677 Surface content_surface = window.SubSurface(content_bounds);
2679 DrawContent(content_surface);
2683 void SkipNextHiddenFields() {
2685 if (m_delegate_sp->GetField(m_selection_index)->FieldDelegateIsVisible())
2688 if (m_selection_index == m_delegate_sp->GetNumberOfFields() - 1) {
2689 m_selection_type = SelectionType::Action;
2690 m_selection_index = 0;
2694 m_selection_index++;
2698 HandleCharResult SelectNext(
int key) {
2699 if (m_selection_type == SelectionType::Action) {
2700 if (m_selection_index < m_delegate_sp->GetNumberOfActions() - 1) {
2701 m_selection_index++;
2705 m_selection_index = 0;
2706 m_selection_type = SelectionType::Field;
2707 SkipNextHiddenFields();
2708 if (m_selection_type == SelectionType::Field) {
2709 FieldDelegate *next_field = m_delegate_sp->GetField(m_selection_index);
2710 next_field->FieldDelegateSelectFirstElement();
2715 FieldDelegate *field = m_delegate_sp->GetField(m_selection_index);
2716 if (!field->FieldDelegateOnLastOrOnlyElement()) {
2717 return field->FieldDelegateHandleChar(key);
2720 field->FieldDelegateExitCallback();
2722 if (m_selection_index == m_delegate_sp->GetNumberOfFields() - 1) {
2723 m_selection_type = SelectionType::Action;
2724 m_selection_index = 0;
2728 m_selection_index++;
2729 SkipNextHiddenFields();
2731 if (m_selection_type == SelectionType::Field) {
2732 FieldDelegate *next_field = m_delegate_sp->GetField(m_selection_index);
2733 next_field->FieldDelegateSelectFirstElement();
2739 void SkipPreviousHiddenFields() {
2741 if (m_delegate_sp->GetField(m_selection_index)->FieldDelegateIsVisible())
2744 if (m_selection_index == 0) {
2745 m_selection_type = SelectionType::Action;
2746 m_selection_index = 0;
2750 m_selection_index--;
2754 HandleCharResult SelectPrevious(
int key) {
2755 if (m_selection_type == SelectionType::Action) {
2756 if (m_selection_index > 0) {
2757 m_selection_index--;
2760 m_selection_index = m_delegate_sp->GetNumberOfFields() - 1;
2761 m_selection_type = SelectionType::Field;
2762 SkipPreviousHiddenFields();
2763 if (m_selection_type == SelectionType::Field) {
2764 FieldDelegate *previous_field =
2765 m_delegate_sp->GetField(m_selection_index);
2766 previous_field->FieldDelegateSelectLastElement();
2771 FieldDelegate *field = m_delegate_sp->GetField(m_selection_index);
2772 if (!field->FieldDelegateOnFirstOrOnlyElement()) {
2773 return field->FieldDelegateHandleChar(key);
2776 field->FieldDelegateExitCallback();
2778 if (m_selection_index == 0) {
2779 m_selection_type = SelectionType::Action;
2780 m_selection_index = m_delegate_sp->GetNumberOfActions() - 1;
2784 m_selection_index--;
2785 SkipPreviousHiddenFields();
2787 if (m_selection_type == SelectionType::Field) {
2788 FieldDelegate *previous_field =
2789 m_delegate_sp->GetField(m_selection_index);
2790 previous_field->FieldDelegateSelectLastElement();
2796 void ExecuteAction(Window &window,
int index) {
2797 FormAction &action = m_delegate_sp->GetAction(index);
2798 action.Execute(window);
2799 if (m_delegate_sp->HasError()) {
2800 m_first_visible_line = 0;
2801 m_selection_index = 0;
2802 m_selection_type = SelectionType::Field;
2808 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override {
2813 if (m_selection_type == SelectionType::Action) {
2814 ExecuteAction(window, m_selection_index);
2819 ExecuteAction(window, 0);
2825 SelectPrevious(key);
2828 window.GetParent()->RemoveSubWindow(&window);
2836 if (m_selection_type == SelectionType::Field) {
2837 FieldDelegate *field = m_delegate_sp->GetField(m_selection_index);
2838 if (field->FieldDelegateHandleChar(key) == eKeyHandled)
2849 SelectPrevious(key);
2859 FormDelegateSP m_delegate_sp;
2861 int m_selection_index = 0;
2863 SelectionType m_selection_type;
2865 int m_first_visible_line = 0;
2872class DetachOrKillProcessFormDelegate :
public FormDelegate {
2874 DetachOrKillProcessFormDelegate(
Process *process) : m_process(process) {
2875 SetError(
"There is a running process, either detach or kill it.");
2877 m_keep_stopped_field =
2878 AddBooleanField(
"Keep process stopped when detaching.",
false);
2880 AddAction(
"Detach", [
this](Window &window) { Detach(window); });
2881 AddAction(
"Kill", [
this](Window &window) { Kill(window); });
2884 std::string
GetName()
override {
return "Detach/Kill Process"; }
2886 void Kill(Window &window) {
2887 Status destroy_status(m_process->Destroy(
false));
2888 if (destroy_status.Fail()) {
2889 SetError(
"Failed to kill process.");
2892 window.GetParent()->RemoveSubWindow(&window);
2895 void Detach(Window &window) {
2896 Status detach_status(m_process->Detach(m_keep_stopped_field->GetBoolean()));
2897 if (detach_status.Fail()) {
2898 SetError(
"Failed to detach from process.");
2901 window.GetParent()->RemoveSubWindow(&window);
2906 BooleanFieldDelegate *m_keep_stopped_field;
2909class ProcessAttachFormDelegate :
public FormDelegate {
2911 ProcessAttachFormDelegate(Debugger &debugger, WindowSP main_window_sp)
2912 : m_debugger(debugger), m_main_window_sp(main_window_sp) {
2913 std::vector<std::string> types;
2914 types.push_back(std::string(
"Name"));
2915 types.push_back(std::string(
"PID"));
2916 m_type_field = AddChoicesField(
"Attach By", 2, types);
2917 m_pid_field = AddIntegerField(
"PID", 0,
true);
2919 AddTextField(
"Process Name", GetDefaultProcessName().c_str(),
true);
2920 m_continue_field = AddBooleanField(
"Continue once attached.",
false);
2921 m_wait_for_field = AddBooleanField(
"Wait for process to launch.",
false);
2922 m_include_existing_field =
2923 AddBooleanField(
"Include existing processes.",
false);
2924 m_show_advanced_field = AddBooleanField(
"Show advanced settings.",
false);
2925 m_plugin_field = AddProcessPluginField();
2927 AddAction(
"Attach", [
this](Window &window) { Attach(window); });
2930 std::string
GetName()
override {
return "Attach Process"; }
2932 void UpdateFieldsVisibility()
override {
2933 if (m_type_field->GetChoiceContent() ==
"Name") {
2934 m_pid_field->FieldDelegateHide();
2935 m_name_field->FieldDelegateShow();
2936 m_wait_for_field->FieldDelegateShow();
2937 if (m_wait_for_field->GetBoolean())
2938 m_include_existing_field->FieldDelegateShow();
2940 m_include_existing_field->FieldDelegateHide();
2942 m_pid_field->FieldDelegateShow();
2943 m_name_field->FieldDelegateHide();
2944 m_wait_for_field->FieldDelegateHide();
2945 m_include_existing_field->FieldDelegateHide();
2947 if (m_show_advanced_field->GetBoolean())
2948 m_plugin_field->FieldDelegateShow();
2950 m_plugin_field->FieldDelegateHide();
2955 std::string GetDefaultProcessName() {
2956 Target *target = m_debugger.GetSelectedTarget().get();
2957 if (target ==
nullptr)
2961 if (!module_sp->IsExecutable())
2964 return module_sp->GetFileSpec().GetFilename().AsCString();
2967 bool StopRunningProcess() {
2968 ExecutionContext exe_ctx =
2969 m_debugger.GetCommandInterpreter().GetExecutionContext();
2975 if (!(process && process->
IsAlive()))
2978 FormDelegateSP form_delegate_sp =
2979 FormDelegateSP(
new DetachOrKillProcessFormDelegate(process));
2980 Rect bounds = m_main_window_sp->GetCenteredRect(85, 8);
2981 WindowSP form_window_sp = m_main_window_sp->CreateSubWindow(
2982 form_delegate_sp->GetName().c_str(), bounds,
true);
2983 WindowDelegateSP window_delegate_sp =
2984 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
2985 form_window_sp->SetDelegate(window_delegate_sp);
2991 Target *target = m_debugger.GetSelectedTarget().get();
2993 if (target !=
nullptr)
2997 m_debugger.GetTargetList().CreateTarget(
3000 target = new_target_sp.get();
3002 if (target ==
nullptr)
3003 SetError(
"Failed to create target.");
3005 m_debugger.GetTargetList().SetSelectedTarget(new_target_sp);
3010 ProcessAttachInfo GetAttachInfo() {
3011 ProcessAttachInfo attach_info;
3013 if (m_type_field->GetChoiceContent() ==
"Name") {
3015 FileSpec::Style::native);
3017 if (m_wait_for_field->GetBoolean())
3027 void Attach(Window &window) {
3030 bool all_fields_are_valid = CheckFieldsValidity();
3031 if (!all_fields_are_valid)
3034 bool process_is_running = StopRunningProcess();
3035 if (process_is_running)
3038 Target *target = GetTarget();
3042 StreamString stream;
3043 ProcessAttachInfo attach_info = GetAttachInfo();
3046 if (status.
Fail()) {
3053 SetError(
"Attached sucessfully but target has no process.");
3058 process_sp->Resume();
3060 window.GetParent()->RemoveSubWindow(&window);
3064 Debugger &m_debugger;
3065 WindowSP m_main_window_sp;
3067 ChoicesFieldDelegate *m_type_field;
3068 IntegerFieldDelegate *m_pid_field;
3069 TextFieldDelegate *m_name_field;
3070 BooleanFieldDelegate *m_continue_field;
3071 BooleanFieldDelegate *m_wait_for_field;
3072 BooleanFieldDelegate *m_include_existing_field;
3073 BooleanFieldDelegate *m_show_advanced_field;
3074 ProcessPluginFieldDelegate *m_plugin_field;
3077class TargetCreateFormDelegate :
public FormDelegate {
3079 TargetCreateFormDelegate(Debugger &debugger) : m_debugger(debugger) {
3080 m_executable_field = AddFileField(
"Executable",
"",
true,
3082 m_core_file_field = AddFileField(
"Core File",
"",
true,
3084 m_symbol_file_field = AddFileField(
3085 "Symbol File",
"",
true,
false);
3086 m_show_advanced_field = AddBooleanField(
"Show advanced settings.",
false);
3087 m_remote_file_field = AddFileField(
3088 "Remote File",
"",
false,
false);
3089 m_arch_field = AddArchField(
"Architecture",
"",
false);
3090 m_platform_field = AddPlatformPluginField(debugger);
3091 m_load_dependent_files_field =
3092 AddChoicesField(
"Load Dependents", 3, GetLoadDependentFilesChoices());
3094 AddAction(
"Create", [
this](Window &window) { CreateTarget(window); });
3097 std::string
GetName()
override {
return "Create Target"; }
3099 void UpdateFieldsVisibility()
override {
3100 if (m_show_advanced_field->GetBoolean()) {
3101 m_remote_file_field->FieldDelegateShow();
3102 m_arch_field->FieldDelegateShow();
3103 m_platform_field->FieldDelegateShow();
3104 m_load_dependent_files_field->FieldDelegateShow();
3106 m_remote_file_field->FieldDelegateHide();
3107 m_arch_field->FieldDelegateHide();
3108 m_platform_field->FieldDelegateHide();
3109 m_load_dependent_files_field->FieldDelegateHide();
3113 static constexpr const char *kLoadDependentFilesNo =
"No";
3114 static constexpr const char *kLoadDependentFilesYes =
"Yes";
3115 static constexpr const char *kLoadDependentFilesExecOnly =
"Executable only";
3117 std::vector<std::string> GetLoadDependentFilesChoices() {
3118 std::vector<std::string> load_dependents_options;
3119 load_dependents_options.push_back(kLoadDependentFilesExecOnly);
3120 load_dependents_options.push_back(kLoadDependentFilesYes);
3121 load_dependents_options.push_back(kLoadDependentFilesNo);
3122 return load_dependents_options;
3126 std::string choice = m_load_dependent_files_field->GetChoiceContent();
3127 if (choice == kLoadDependentFilesNo)
3129 if (choice == kLoadDependentFilesYes)
3134 OptionGroupPlatform GetPlatformOptions() {
3135 OptionGroupPlatform platform_options(
false);
3136 platform_options.SetPlatformName(m_platform_field->GetPluginName().c_str());
3137 return platform_options;
3141 OptionGroupPlatform platform_options = GetPlatformOptions();
3143 Status status = m_debugger.GetTargetList().CreateTarget(
3144 m_debugger, m_executable_field->GetPath(),
3145 m_arch_field->GetArchString(), GetLoadDependentFiles(),
3146 &platform_options, target_sp);
3148 if (status.
Fail()) {
3153 m_debugger.GetTargetList().SetSelectedTarget(target_sp);
3158 void SetSymbolFile(
TargetSP target_sp) {
3159 if (!m_symbol_file_field->IsSpecified())
3162 ModuleSP module_sp(target_sp->GetExecutableModule());
3166 module_sp->SetSymbolFileFileSpec(
3167 m_symbol_file_field->GetResolvedFileSpec());
3170 void SetCoreFile(
TargetSP target_sp) {
3171 if (!m_core_file_field->IsSpecified())
3174 FileSpec core_file_spec = m_core_file_field->GetResolvedFileSpec();
3176 FileSpec core_file_directory_spec;
3178 target_sp->AppendExecutableSearchPaths(core_file_directory_spec);
3180 ProcessSP process_sp(target_sp->CreateProcess(
3181 m_debugger.GetListener(), llvm::StringRef(), &core_file_spec,
false));
3184 SetError(
"Unknown core file format!");
3188 Status status = process_sp->LoadCore();
3189 if (status.
Fail()) {
3190 SetError(
"Unknown core file format!");
3195 void SetRemoteFile(
TargetSP target_sp) {
3196 if (!m_remote_file_field->IsSpecified())
3199 ModuleSP module_sp(target_sp->GetExecutableModule());
3203 FileSpec remote_file_spec = m_remote_file_field->GetFileSpec();
3204 module_sp->SetPlatformFileSpec(remote_file_spec);
3207 void RemoveTarget(
TargetSP target_sp) {
3208 m_debugger.GetTargetList().DeleteTarget(target_sp);
3211 void CreateTarget(Window &window) {
3214 bool all_fields_are_valid = CheckFieldsValidity();
3215 if (!all_fields_are_valid)
3222 SetSymbolFile(target_sp);
3224 RemoveTarget(target_sp);
3228 SetCoreFile(target_sp);
3230 RemoveTarget(target_sp);
3234 SetRemoteFile(target_sp);
3236 RemoveTarget(target_sp);
3240 window.GetParent()->RemoveSubWindow(&window);
3244 Debugger &m_debugger;
3246 FileFieldDelegate *m_executable_field;
3247 FileFieldDelegate *m_core_file_field;
3248 FileFieldDelegate *m_symbol_file_field;
3249 BooleanFieldDelegate *m_show_advanced_field;
3250 FileFieldDelegate *m_remote_file_field;
3251 ArchFieldDelegate *m_arch_field;
3252 PlatformPluginFieldDelegate *m_platform_field;
3253 ChoicesFieldDelegate *m_load_dependent_files_field;
3256class ProcessLaunchFormDelegate :
public FormDelegate {
3258 ProcessLaunchFormDelegate(Debugger &debugger, WindowSP main_window_sp)
3259 : m_debugger(debugger), m_main_window_sp(main_window_sp) {
3261 m_arguments_field = AddArgumentsField();
3262 SetArgumentsFieldDefaultValue();
3263 m_target_environment_field =
3264 AddEnvironmentVariableListField(
"Target Environment Variables");
3265 SetTargetEnvironmentFieldDefaultValue();
3266 m_working_directory_field = AddDirectoryField(
3267 "Working Directory", GetDefaultWorkingDirectory().c_str(),
true,
false);
3269 m_show_advanced_field = AddBooleanField(
"Show advanced settings.",
false);
3271 m_stop_at_entry_field = AddBooleanField(
"Stop at entry point.",
false);
3272 m_detach_on_error_field =
3273 AddBooleanField(
"Detach on error.", GetDefaultDetachOnError());
3274 m_disable_aslr_field =
3275 AddBooleanField(
"Disable ASLR", GetDefaultDisableASLR());
3276 m_plugin_field = AddProcessPluginField();
3277 m_arch_field = AddArchField(
"Architecture",
"",
false);
3278 m_shell_field = AddFileField(
"Shell",
"",
true,
false);
3279 m_expand_shell_arguments_field =
3280 AddBooleanField(
"Expand shell arguments.",
false);
3282 m_disable_standard_io_field =
3283 AddBooleanField(
"Disable Standard IO", GetDefaultDisableStandardIO());
3284 m_standard_output_field =
3285 AddFileField(
"Standard Output File",
"",
false,
3287 m_standard_error_field =
3288 AddFileField(
"Standard Error File",
"",
false,
3290 m_standard_input_field =
3291 AddFileField(
"Standard Input File",
"",
false,
3294 m_show_inherited_environment_field =
3295 AddBooleanField(
"Show inherited environment variables.",
false);
3296 m_inherited_environment_field =
3297 AddEnvironmentVariableListField(
"Inherited Environment Variables");
3298 SetInheritedEnvironmentFieldDefaultValue();
3300 AddAction(
"Launch", [
this](Window &window) { Launch(window); });
3303 std::string
GetName()
override {
return "Launch Process"; }
3305 void UpdateFieldsVisibility()
override {
3306 if (m_show_advanced_field->GetBoolean()) {
3307 m_stop_at_entry_field->FieldDelegateShow();
3308 m_detach_on_error_field->FieldDelegateShow();
3309 m_disable_aslr_field->FieldDelegateShow();
3310 m_plugin_field->FieldDelegateShow();
3311 m_arch_field->FieldDelegateShow();
3312 m_shell_field->FieldDelegateShow();
3313 m_expand_shell_arguments_field->FieldDelegateShow();
3314 m_disable_standard_io_field->FieldDelegateShow();
3315 if (m_disable_standard_io_field->GetBoolean()) {
3316 m_standard_input_field->FieldDelegateHide();
3317 m_standard_output_field->FieldDelegateHide();
3318 m_standard_error_field->FieldDelegateHide();
3320 m_standard_input_field->FieldDelegateShow();
3321 m_standard_output_field->FieldDelegateShow();
3322 m_standard_error_field->FieldDelegateShow();
3324 m_show_inherited_environment_field->FieldDelegateShow();
3325 if (m_show_inherited_environment_field->GetBoolean())
3326 m_inherited_environment_field->FieldDelegateShow();
3328 m_inherited_environment_field->FieldDelegateHide();
3330 m_stop_at_entry_field->FieldDelegateHide();
3331 m_detach_on_error_field->FieldDelegateHide();
3332 m_disable_aslr_field->FieldDelegateHide();
3333 m_plugin_field->FieldDelegateHide();
3334 m_arch_field->FieldDelegateHide();
3335 m_shell_field->FieldDelegateHide();
3336 m_expand_shell_arguments_field->FieldDelegateHide();
3337 m_disable_standard_io_field->FieldDelegateHide();
3338 m_standard_input_field->FieldDelegateHide();
3339 m_standard_output_field->FieldDelegateHide();
3340 m_standard_error_field->FieldDelegateHide();
3341 m_show_inherited_environment_field->FieldDelegateHide();
3342 m_inherited_environment_field->FieldDelegateHide();
3348 void SetArgumentsFieldDefaultValue() {
3349 TargetSP target = m_debugger.GetSelectedTarget();
3350 if (target ==
nullptr)
3353 const Args &target_arguments =
3354 target->GetProcessLaunchInfo().GetArguments();
3355 m_arguments_field->AddArguments(target_arguments);
3358 void SetTargetEnvironmentFieldDefaultValue() {
3359 TargetSP target = m_debugger.GetSelectedTarget();
3360 if (target ==
nullptr)
3363 const Environment &target_environment = target->GetTargetEnvironment();
3364 m_target_environment_field->AddEnvironmentVariables(target_environment);
3367 void SetInheritedEnvironmentFieldDefaultValue() {
3368 TargetSP target = m_debugger.GetSelectedTarget();
3369 if (target ==
nullptr)
3372 const Environment &inherited_environment =
3373 target->GetInheritedEnvironment();
3374 m_inherited_environment_field->AddEnvironmentVariables(
3375 inherited_environment);
3378 std::string GetDefaultWorkingDirectory() {
3379 TargetSP target = m_debugger.GetSelectedTarget();
3380 if (target ==
nullptr)
3384 return platform->GetWorkingDirectory().GetPath();
3387 bool GetDefaultDisableASLR() {
3388 TargetSP target = m_debugger.GetSelectedTarget();
3389 if (target ==
nullptr)
3392 return target->GetDisableASLR();
3395 bool GetDefaultDisableStandardIO() {
3396 TargetSP target = m_debugger.GetSelectedTarget();
3397 if (target ==
nullptr)
3400 return target->GetDisableSTDIO();
3403 bool GetDefaultDetachOnError() {
3404 TargetSP target = m_debugger.GetSelectedTarget();
3405 if (target ==
nullptr)
3408 return target->GetDetachOnError();
3414 void GetExecutableSettings(ProcessLaunchInfo &launch_info) {
3415 TargetSP target = m_debugger.GetSelectedTarget();
3416 ModuleSP executable_module = target->GetExecutableModule();
3417 llvm::StringRef target_settings_argv0 = target->GetArg0();
3419 if (!target_settings_argv0.empty()) {
3430 void GetArguments(ProcessLaunchInfo &launch_info) {
3431 TargetSP target = m_debugger.GetSelectedTarget();
3432 Args arguments = m_arguments_field->GetArguments();
3436 void GetEnvironment(ProcessLaunchInfo &launch_info) {
3437 Environment target_environment =
3438 m_target_environment_field->GetEnvironment();
3439 Environment inherited_environment =
3440 m_inherited_environment_field->GetEnvironment();
3442 target_environment.end());
3444 inherited_environment.end());
3447 void GetWorkingDirectory(ProcessLaunchInfo &launch_info) {
3448 if (m_working_directory_field->IsSpecified())
3450 m_working_directory_field->GetResolvedFileSpec());
3453 void GetStopAtEntry(ProcessLaunchInfo &launch_info) {
3454 if (m_stop_at_entry_field->GetBoolean())
3455 launch_info.
GetFlags().
Set(eLaunchFlagStopAtEntry);
3460 void GetDetachOnError(ProcessLaunchInfo &launch_info) {
3461 if (m_detach_on_error_field->GetBoolean())
3462 launch_info.
GetFlags().
Set(eLaunchFlagDetachOnError);
3467 void GetDisableASLR(ProcessLaunchInfo &launch_info) {
3468 if (m_disable_aslr_field->GetBoolean())
3469 launch_info.
GetFlags().
Set(eLaunchFlagDisableASLR);
3474 void GetPlugin(ProcessLaunchInfo &launch_info) {
3478 void GetArch(ProcessLaunchInfo &launch_info) {
3479 if (!m_arch_field->IsSpecified())
3482 TargetSP target_sp = m_debugger.GetSelectedTarget();
3484 target_sp ? target_sp->GetPlatform() :
PlatformSP();
3486 platform_sp.get(), m_arch_field->GetArchString());
3489 void GetShell(ProcessLaunchInfo &launch_info) {
3490 if (!m_shell_field->IsSpecified())
3493 launch_info.
SetShell(m_shell_field->GetResolvedFileSpec());
3495 m_expand_shell_arguments_field->GetBoolean());
3498 void GetStandardIO(ProcessLaunchInfo &launch_info) {
3499 if (m_disable_standard_io_field->GetBoolean()) {
3500 launch_info.
GetFlags().
Set(eLaunchFlagDisableSTDIO);
3505 if (m_standard_input_field->IsSpecified()) {
3506 if (action.
Open(STDIN_FILENO, m_standard_input_field->GetFileSpec(),
true,
3510 if (m_standard_output_field->IsSpecified()) {
3511 if (action.
Open(STDOUT_FILENO, m_standard_output_field->GetFileSpec(),
3515 if (m_standard_error_field->IsSpecified()) {
3516 if (action.
Open(STDERR_FILENO, m_standard_error_field->GetFileSpec(),
3522 void GetInheritTCC(ProcessLaunchInfo &launch_info) {
3523 if (m_debugger.GetSelectedTarget()->GetInheritTCC())
3524 launch_info.
GetFlags().
Set(eLaunchFlagInheritTCCFromParent);
3527 ProcessLaunchInfo GetLaunchInfo() {
3528 ProcessLaunchInfo launch_info;
3530 GetExecutableSettings(launch_info);
3531 GetArguments(launch_info);
3532 GetEnvironment(launch_info);
3533 GetWorkingDirectory(launch_info);
3534 GetStopAtEntry(launch_info);
3535 GetDetachOnError(launch_info);
3536 GetDisableASLR(launch_info);
3537 GetPlugin(launch_info);
3538 GetArch(launch_info);
3539 GetShell(launch_info);
3540 GetStandardIO(launch_info);
3541 GetInheritTCC(launch_info);
3546 bool StopRunningProcess() {
3547 ExecutionContext exe_ctx =
3548 m_debugger.GetCommandInterpreter().GetExecutionContext();
3554 if (!(process && process->
IsAlive()))
3557 FormDelegateSP form_delegate_sp =
3558 FormDelegateSP(
new DetachOrKillProcessFormDelegate(process));
3559 Rect bounds = m_main_window_sp->GetCenteredRect(85, 8);
3560 WindowSP form_window_sp = m_main_window_sp->CreateSubWindow(
3561 form_delegate_sp->GetName().c_str(), bounds,
true);
3562 WindowDelegateSP window_delegate_sp =
3563 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
3564 form_window_sp->SetDelegate(window_delegate_sp);
3570 Target *target = m_debugger.GetSelectedTarget().get();
3572 if (target ==
nullptr) {
3573 SetError(
"No target exists!");
3579 if (exe_module_sp ==
nullptr) {
3580 SetError(
"No executable in target!");
3587 void Launch(Window &window) {
3590 bool all_fields_are_valid = CheckFieldsValidity();
3591 if (!all_fields_are_valid)
3594 bool process_is_running = StopRunningProcess();
3595 if (process_is_running)
3598 Target *target = GetTarget();
3602 StreamString stream;
3603 ProcessLaunchInfo launch_info = GetLaunchInfo();
3606 if (status.
Fail()) {
3613 SetError(
"Launched successfully but target has no process!");
3617 window.GetParent()->RemoveSubWindow(&window);
3621 Debugger &m_debugger;
3622 WindowSP m_main_window_sp;
3624 ArgumentsFieldDelegate *m_arguments_field;
3625 EnvironmentVariableListFieldDelegate *m_target_environment_field;
3626 DirectoryFieldDelegate *m_working_directory_field;
3628 BooleanFieldDelegate *m_show_advanced_field;
3630 BooleanFieldDelegate *m_stop_at_entry_field;
3631 BooleanFieldDelegate *m_detach_on_error_field;
3632 BooleanFieldDelegate *m_disable_aslr_field;
3633 ProcessPluginFieldDelegate *m_plugin_field;
3634 ArchFieldDelegate *m_arch_field;
3635 FileFieldDelegate *m_shell_field;
3636 BooleanFieldDelegate *m_expand_shell_arguments_field;
3637 BooleanFieldDelegate *m_disable_standard_io_field;
3638 FileFieldDelegate *m_standard_input_field;
3639 FileFieldDelegate *m_standard_output_field;
3640 FileFieldDelegate *m_standard_error_field;
3642 BooleanFieldDelegate *m_show_inherited_environment_field;
3643 EnvironmentVariableListFieldDelegate *m_inherited_environment_field;
3650class SearcherDelegate {
3652 SearcherDelegate() =
default;
3654 virtual ~SearcherDelegate() =
default;
3656 virtual int GetNumberOfMatches() = 0;
3659 virtual const std::string &GetMatchTextAtIndex(
int index) = 0;
3663 virtual void UpdateMatches(
const std::string &text) = 0;
3667 virtual void ExecuteCallback(
int match_index) = 0;
3670typedef std::shared_ptr<SearcherDelegate> SearcherDelegateSP;
3672class SearcherWindowDelegate :
public WindowDelegate {
3674 SearcherWindowDelegate(SearcherDelegateSP &delegate_sp)
3675 : m_delegate_sp(delegate_sp), m_text_field(
"Search",
"", false) {
3697 int GetLastVisibleMatch(
int height) {
3698 int index = m_first_visible_match + height;
3699 return std::min(index, m_delegate_sp->GetNumberOfMatches()) - 1;
3702 int GetNumberOfVisibleMatches(
int height) {
3703 return GetLastVisibleMatch(height) - m_first_visible_match + 1;
3706 void UpdateScrolling(Surface &surface) {
3707 if (m_selected_match < m_first_visible_match) {
3708 m_first_visible_match = m_selected_match;
3712 int height = surface.GetHeight();
3713 int last_visible_match = GetLastVisibleMatch(height);
3714 if (m_selected_match > last_visible_match) {
3715 m_first_visible_match = m_selected_match - height + 1;
3719 void DrawMatches(Surface &surface) {
3720 if (m_delegate_sp->GetNumberOfMatches() == 0)
3723 UpdateScrolling(surface);
3725 int count = GetNumberOfVisibleMatches(surface.GetHeight());
3726 for (
int i = 0; i < count; i++) {
3727 surface.MoveCursor(1, i);
3728 int current_match = m_first_visible_match + i;
3729 if (current_match == m_selected_match)
3730 surface.AttributeOn(A_REVERSE);
3732 m_delegate_sp->GetMatchTextAtIndex(current_match).c_str());
3733 if (current_match == m_selected_match)
3734 surface.AttributeOff(A_REVERSE);
3738 void DrawContent(Surface &surface) {
3739 Rect content_bounds = surface.GetFrame();
3740 Rect text_field_bounds, matchs_bounds;
3741 content_bounds.HorizontalSplit(m_text_field.FieldDelegateGetHeight(),
3742 text_field_bounds, matchs_bounds);
3743 Surface text_field_surface = surface.SubSurface(text_field_bounds);
3744 Surface matches_surface = surface.SubSurface(matchs_bounds);
3746 m_text_field.FieldDelegateDraw(text_field_surface,
true);
3747 DrawMatches(matches_surface);
3750 bool WindowDelegateDraw(Window &window,
bool force)
override {
3753 window.DrawTitleBox(window.GetName(),
"Press Esc to Cancel");
3755 Rect content_bounds = window.GetFrame();
3756 content_bounds.Inset(2, 2);
3757 Surface content_surface = window.SubSurface(content_bounds);
3759 DrawContent(content_surface);
3764 if (m_selected_match != m_delegate_sp->GetNumberOfMatches() - 1)
3768 void SelectPrevious() {
3769 if (m_selected_match != 0)
3773 void ExecuteCallback(Window &window) {
3774 m_delegate_sp->ExecuteCallback(m_selected_match);
3775 window.GetParent()->RemoveSubWindow(&window);
3778 void UpdateMatches() {
3779 m_delegate_sp->UpdateMatches(m_text_field.GetText());
3780 m_selected_match = 0;
3783 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override {
3788 ExecuteCallback(window);
3799 window.GetParent()->RemoveSubWindow(&window);
3805 if (m_text_field.FieldDelegateHandleChar(key) == eKeyHandled)
3812 SearcherDelegateSP m_delegate_sp;
3813 TextFieldDelegate m_text_field;
3815 int m_selected_match = 0;
3817 int m_first_visible_match = 0;
3827class CommonCompletionSearcherDelegate :
public SearcherDelegate {
3829 typedef std::function<void(
const std::string &)> CallbackType;
3831 CommonCompletionSearcherDelegate(Debugger &debugger, uint32_t completion_mask,
3832 CallbackType callback)
3833 : m_debugger(debugger), m_completion_mask(completion_mask),
3834 m_callback(callback) {}
3836 int GetNumberOfMatches()
override {
return m_matches.GetSize(); }
3838 const std::string &GetMatchTextAtIndex(
int index)
override {
3839 return m_matches[index];
3842 void UpdateMatches(
const std::string &text)
override {
3843 CompletionResult result;
3844 CompletionRequest request(text.c_str(), text.size(), result);
3846 m_debugger.GetCommandInterpreter(), m_completion_mask, request,
3851 void ExecuteCallback(
int match_index)
override {
3852 m_callback(m_matches[match_index]);
3856 Debugger &m_debugger;
3858 uint32_t m_completion_mask;
3861 CallbackType m_callback;
3862 StringList m_matches;
3871 virtual ~MenuDelegate() =
default;
3873 virtual MenuActionResult MenuDelegateAction(Menu &menu) = 0;
3876class Menu :
public WindowDelegate {
3878 enum class Type {
Invalid, Bar, Item, Separator };
3884 Menu(
const char *name,
const char *key_name,
int key_value,
3885 uint64_t identifier);
3887 ~Menu()
override =
default;
3889 const MenuDelegateSP &GetDelegate()
const {
return m_delegate_sp; }
3891 void SetDelegate(
const MenuDelegateSP &delegate_sp) {
3892 m_delegate_sp = delegate_sp;
3895 void RecalculateNameLengths();
3897 void AddSubmenu(
const MenuSP &menu_sp);
3899 int DrawAndRunMenu(Window &window);
3901 void DrawMenuTitle(Window &window,
bool highlight);
3903 bool WindowDelegateDraw(Window &window,
bool force)
override;
3905 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override;
3907 MenuActionResult ActionPrivate(Menu &menu) {
3908 MenuActionResult result = MenuActionResult::NotHandled;
3909 if (m_delegate_sp) {
3910 result = m_delegate_sp->MenuDelegateAction(menu);
3911 if (result != MenuActionResult::NotHandled)
3913 }
else if (m_parent) {
3914 result = m_parent->ActionPrivate(menu);
3915 if (result != MenuActionResult::NotHandled)
3918 return m_canned_result;
3921 MenuActionResult Action() {
3924 return ActionPrivate(*
this);
3927 void SetCannedResult(MenuActionResult result) { m_canned_result = result; }
3929 Menus &GetSubmenus() {
return m_submenus; }
3931 const Menus &GetSubmenus()
const {
return m_submenus; }
3933 int GetSelectedSubmenuIndex()
const {
return m_selected; }
3935 void SetSelectedSubmenuIndex(
int idx) { m_selected = idx; }
3937 Type GetType()
const {
return m_type; }
3939 int GetStartingColumn()
const {
return m_start_col; }
3941 void SetStartingColumn(
int col) { m_start_col = col; }
3943 int GetKeyValue()
const {
return m_key_value; }
3945 std::string &
GetName() {
return m_name; }
3947 int GetDrawWidth()
const {
3948 return m_max_submenu_name_length + m_max_submenu_key_name_length + 8;
3951 uint64_t GetIdentifier()
const {
return m_identifier; }
3953 void SetIdentifier(uint64_t identifier) { m_identifier = identifier; }
3957 std::string m_key_name;
3958 uint64_t m_identifier;
3962 int m_max_submenu_name_length;
3963 int m_max_submenu_key_name_length;
3967 WindowSP m_menu_window_sp;
3968 MenuActionResult m_canned_result;
3969 MenuDelegateSP m_delegate_sp;
3973Menu::Menu(Type type)
3974 : m_name(), m_key_name(), m_identifier(0), m_type(type), m_key_value(0),
3975 m_start_col(0), m_max_submenu_name_length(0),
3976 m_max_submenu_key_name_length(0), m_selected(0), m_parent(nullptr),
3977 m_submenus(), m_canned_result(MenuActionResult::NotHandled),
3981Menu::Menu(
const char *name,
const char *key_name,
int key_value,
3982 uint64_t identifier)
3983 : m_name(), m_key_name(), m_identifier(identifier), m_type(
Type::
Invalid),
3984 m_key_value(key_value), m_start_col(0), m_max_submenu_name_length(0),
3985 m_max_submenu_key_name_length(0), m_selected(0), m_parent(nullptr),
3986 m_submenus(), m_canned_result(MenuActionResult::NotHandled),
3988 if (name && name[0]) {
3990 m_type = Type::Item;
3991 if (key_name && key_name[0])
3992 m_key_name = key_name;
3994 m_type = Type::Separator;
3998void Menu::RecalculateNameLengths() {
3999 m_max_submenu_name_length = 0;
4000 m_max_submenu_key_name_length = 0;
4001 Menus &submenus = GetSubmenus();
4002 const size_t num_submenus = submenus.size();
4003 for (
size_t i = 0; i < num_submenus; ++i) {
4004 Menu *submenu = submenus[i].get();
4005 if (
static_cast<size_t>(m_max_submenu_name_length) < submenu->m_name.size())
4006 m_max_submenu_name_length = submenu->m_name.size();
4007 if (
static_cast<size_t>(m_max_submenu_key_name_length) <
4008 submenu->m_key_name.size())
4009 m_max_submenu_key_name_length = submenu->m_key_name.size();
4013void Menu::AddSubmenu(
const MenuSP &menu_sp) {
4014 menu_sp->m_parent =
this;
4015 if (
static_cast<size_t>(m_max_submenu_name_length) < menu_sp->m_name.size())
4016 m_max_submenu_name_length = menu_sp->m_name.size();
4017 if (
static_cast<size_t>(m_max_submenu_key_name_length) <
4018 menu_sp->m_key_name.size())
4019 m_max_submenu_key_name_length = menu_sp->m_key_name.size();
4020 m_submenus.push_back(menu_sp);
4023void Menu::DrawMenuTitle(Window &window,
bool highlight) {
4024 if (m_type == Type::Separator) {
4025 window.MoveCursor(0, window.GetCursorY());
4026 window.PutChar(ACS_LTEE);
4027 int width = window.GetWidth();
4030 for (
int i = 0; i < width; ++i)
4031 window.PutChar(ACS_HLINE);
4033 window.PutChar(ACS_RTEE);
4035 const int shortcut_key = m_key_value;
4036 bool underlined_shortcut =
false;
4037 const attr_t highlight_attr = A_REVERSE;
4039 window.AttributeOn(highlight_attr);
4040 if (llvm::isPrint(shortcut_key)) {
4041 size_t lower_pos = m_name.find(tolower(shortcut_key));
4042 size_t upper_pos = m_name.find(toupper(shortcut_key));
4043 const char *name = m_name.c_str();
4044 size_t pos = std::min<size_t>(lower_pos, upper_pos);
4045 if (pos != std::string::npos) {
4046 underlined_shortcut =
true;
4048 window.PutCString(name, pos);
4051 const attr_t shortcut_attr = A_UNDERLINE | A_BOLD;
4052 window.AttributeOn(shortcut_attr);
4053 window.PutChar(name[0]);
4054 window.AttributeOff(shortcut_attr);
4057 window.PutCString(name);
4061 if (!underlined_shortcut) {
4062 window.PutCString(m_name.c_str());
4066 window.AttributeOff(highlight_attr);
4068 if (m_key_name.empty()) {
4069 if (!underlined_shortcut && llvm::isPrint(m_key_value)) {
4070 window.AttributeOn(COLOR_PAIR(MagentaOnWhite));
4071 window.Printf(
" (%c)", m_key_value);
4072 window.AttributeOff(COLOR_PAIR(MagentaOnWhite));
4075 window.AttributeOn(COLOR_PAIR(MagentaOnWhite));
4076 window.Printf(
" (%s)", m_key_name.c_str());
4077 window.AttributeOff(COLOR_PAIR(MagentaOnWhite));
4082bool Menu::WindowDelegateDraw(Window &window,
bool force) {
4083 Menus &submenus = GetSubmenus();
4084 const size_t num_submenus = submenus.size();
4085 const int selected_idx = GetSelectedSubmenuIndex();
4086 Menu::Type menu_type = GetType();
4087 switch (menu_type) {
4088 case Menu::Type::Bar: {
4089 window.SetBackground(BlackOnWhite);
4090 window.MoveCursor(0, 0);
4091 for (
size_t i = 0; i < num_submenus; ++i) {
4092 Menu *menu = submenus[i].get();
4094 window.PutChar(
' ');
4095 menu->SetStartingColumn(window.GetCursorX());
4096 window.PutCString(
"| ");
4097 menu->DrawMenuTitle(window,
false);
4099 window.PutCString(
" |");
4102 case Menu::Type::Item: {
4109 window.SetBackground(BlackOnWhite);
4111 for (
size_t i = 0; i < num_submenus; ++i) {
4112 const bool is_selected = (i ==
static_cast<size_t>(selected_idx));
4113 window.MoveCursor(x, y + i);
4119 submenus[i]->DrawMenuTitle(window, is_selected);
4121 window.MoveCursor(cursor_x, cursor_y);
4125 case Menu::Type::Separator:
4131HandleCharResult Menu::WindowDelegateHandleChar(Window &window,
int key) {
4132 HandleCharResult result = eKeyNotHandled;
4134 Menus &submenus = GetSubmenus();
4135 const size_t num_submenus = submenus.size();
4136 const int selected_idx = GetSelectedSubmenuIndex();
4137 Menu::Type menu_type = GetType();
4138 if (menu_type == Menu::Type::Bar) {
4144 if (selected_idx <
static_cast<int>(num_submenus))
4145 run_menu_sp = submenus[selected_idx];
4146 else if (!submenus.empty())
4147 run_menu_sp = submenus.front();
4148 result = eKeyHandled;
4153 if (m_selected >=
static_cast<int>(num_submenus))
4155 if (m_selected <
static_cast<int>(num_submenus))
4156 run_menu_sp = submenus[m_selected];
4157 else if (!submenus.empty())
4158 run_menu_sp = submenus.front();
4159 result = eKeyHandled;
4165 m_selected = num_submenus - 1;
4166 if (m_selected <
static_cast<int>(num_submenus))
4167 run_menu_sp = submenus[m_selected];
4168 else if (!submenus.empty())
4169 run_menu_sp = submenus.front();
4170 result = eKeyHandled;
4174 for (
size_t i = 0; i < num_submenus; ++i) {
4175 if (submenus[i]->GetKeyValue() == key) {
4176 SetSelectedSubmenuIndex(i);
4177 run_menu_sp = submenus[i];
4178 result = eKeyHandled;
4189 if (run_menu_sp->Action() == MenuActionResult::Quit)
4190 return eQuitApplication;
4193 menu_bounds.origin.x = run_menu_sp->GetStartingColumn();
4194 menu_bounds.origin.y = 1;
4195 menu_bounds.size.width = run_menu_sp->GetDrawWidth();
4196 menu_bounds.size.height = run_menu_sp->GetSubmenus().size() + 2;
4197 if (m_menu_window_sp)
4198 window.GetParent()->RemoveSubWindow(m_menu_window_sp.get());
4200 m_menu_window_sp = window.GetParent()->CreateSubWindow(
4201 run_menu_sp->GetName().c_str(), menu_bounds,
true);
4202 m_menu_window_sp->SetDelegate(run_menu_sp);
4204 }
else if (menu_type == Menu::Type::Item) {
4207 if (m_submenus.size() > 1) {
4208 const int start_select = m_selected;
4209 while (++m_selected != start_select) {
4210 if (
static_cast<size_t>(m_selected) >= num_submenus)
4212 if (m_submenus[m_selected]->GetType() == Type::Separator)
4222 if (m_submenus.size() > 1) {
4223 const int start_select = m_selected;
4224 while (--m_selected != start_select) {
4225 if (m_selected <
static_cast<int>(0))
4226 m_selected = num_submenus - 1;
4227 if (m_submenus[m_selected]->GetType() == Type::Separator)
4237 if (
static_cast<size_t>(selected_idx) < num_submenus) {
4238 if (submenus[selected_idx]->Action() == MenuActionResult::Quit)
4239 return eQuitApplication;
4240 window.GetParent()->RemoveSubWindow(&window);
4247 window.GetParent()->RemoveSubWindow(&window);
4251 for (
size_t i = 0; i < num_submenus; ++i) {
4252 Menu *menu = submenus[i].get();
4253 if (menu->GetKeyValue() == key) {
4254 SetSelectedSubmenuIndex(i);
4255 window.GetParent()->RemoveSubWindow(&window);
4256 if (menu->Action() == MenuActionResult::Quit)
4257 return eQuitApplication;
4263 }
else if (menu_type == Menu::Type::Separator) {
4270 Application(FILE *in, FILE *out) : m_window_sp(), m_in(in), m_out(out) {}
4273 m_window_delegates.clear();
4274 m_window_sp.reset();
4276 ::delscreen(m_screen);
4282 m_screen = ::newterm(
nullptr, m_out, m_in);
4286 ::keypad(stdscr, TRUE);
4289 void Terminate() { ::endwin(); }
4291 void Run(Debugger &debugger) {
4293 int delay_in_tenths_of_a_second = 1;
4301 halfdelay(delay_in_tenths_of_a_second);
4310 m_update_screen =
true;
4311#if defined(__APPLE__)
4312 std::deque<int> escape_chars;
4316 if (m_update_screen) {
4317 m_window_sp->Draw(
false);
4325 m_window_sp->MoveCursor(0, 0);
4328 m_update_screen =
false;
4331#if defined(__APPLE__)
4336 if (escape_chars.empty())
4337 ch = m_window_sp->GetChar();
4339 ch = escape_chars.front();
4340 escape_chars.pop_front();
4342 if (ch == KEY_ESCAPE) {
4343 int ch2 = m_window_sp->GetChar();
4345 int ch3 = m_window_sp->GetChar();
4360 escape_chars.push_back(ch2);
4362 escape_chars.push_back(ch3);
4365 }
else if (ch2 != -1)
4366 escape_chars.push_back(ch2);
4369 int ch = m_window_sp->GetChar();
4373 if (feof(m_in) || ferror(m_in)) {
4378 while (listener_sp->PeekAtNextEvent()) {
4379 listener_sp->GetEvent(event_sp, std::chrono::seconds(0));
4382 Broadcaster *broadcaster = event_sp->GetBroadcaster();
4385 ConstString broadcaster_class(
4387 if (broadcaster_class == broadcaster_class_process) {
4388 m_update_screen =
true;
4396 HandleCharResult key_result = m_window_sp->HandleChar(ch);
4397 switch (key_result) {
4399 m_update_screen =
true;
4401 case eKeyNotHandled:
4403 redrawwin(m_window_sp->get());
4404 m_update_screen =
true;
4407 case eQuitApplication:
4417 WindowSP &GetMainWindow() {
4419 m_window_sp = std::make_shared<Window>(
"main", stdscr,
false);
4423 void TerminalSizeChanged() {
4426 Rect content_bounds = m_window_sp->GetFrame();
4427 m_window_sp->SetBounds(content_bounds);
4428 if (WindowSP menubar_window_sp = m_window_sp->FindSubWindow(
"Menubar"))
4429 menubar_window_sp->SetBounds(content_bounds.MakeMenuBar());
4430 if (WindowSP status_window_sp = m_window_sp->FindSubWindow(
"Status"))
4431 status_window_sp->SetBounds(content_bounds.MakeStatusBar());
4433 WindowSP source_window_sp = m_window_sp->FindSubWindow(
"Source");
4434 WindowSP variables_window_sp = m_window_sp->FindSubWindow(
"Variables");
4435 WindowSP registers_window_sp = m_window_sp->FindSubWindow(
"Registers");
4436 WindowSP threads_window_sp = m_window_sp->FindSubWindow(
"Threads");
4438 Rect threads_bounds;
4439 Rect source_variables_bounds;
4440 content_bounds.VerticalSplitPercentage(0.80, source_variables_bounds,
4442 if (threads_window_sp)
4443 threads_window_sp->SetBounds(threads_bounds);
4445 source_variables_bounds = content_bounds;
4448 Rect variables_registers_bounds;
4449 source_variables_bounds.HorizontalSplitPercentage(
4450 0.70, source_bounds, variables_registers_bounds);
4451 if (variables_window_sp || registers_window_sp) {
4452 if (variables_window_sp && registers_window_sp) {
4453 Rect variables_bounds;
4454 Rect registers_bounds;
4455 variables_registers_bounds.VerticalSplitPercentage(
4456 0.50, variables_bounds, registers_bounds);
4457 variables_window_sp->SetBounds(variables_bounds);
4458 registers_window_sp->SetBounds(registers_bounds);
4459 }
else if (variables_window_sp) {
4460 variables_window_sp->SetBounds(variables_registers_bounds);
4462 registers_window_sp->SetBounds(variables_registers_bounds);
4465 source_bounds = source_variables_bounds;
4468 source_window_sp->SetBounds(source_bounds);
4471 redrawwin(m_window_sp->get());
4472 m_update_screen =
true;
4476 WindowSP m_window_sp;
4477 WindowDelegates m_window_delegates;
4478 SCREEN *m_screen =
nullptr;
4481 bool m_update_screen =
false;
4490 ValueObjectUpdater value;
4493 uint32_t children_stop_id = 0;
4497 bool might_have_children;
4498 bool expanded =
false;
4499 bool calculated_children =
false;
4500 std::vector<Row> children;
4503 : value(v), parent(p),
4504 might_have_children(v ? v->MightHaveChildren() : false) {}
4506 size_t GetDepth()
const {
4508 return 1 + parent->GetDepth();
4512 void Expand() { expanded =
true; }
4514 std::vector<Row> &GetChildren() {
4516 auto stop_id = process_sp->GetStopID();
4517 if (process_sp && stop_id != children_stop_id) {
4518 children_stop_id = stop_id;
4519 calculated_children =
false;
4521 if (!calculated_children) {
4523 calculated_children =
true;
4526 const uint32_t num_children = valobj->GetNumChildrenIgnoringErrors();
4527 for (
size_t i = 0; i < num_children; ++i) {
4528 children.push_back(Row(valobj->GetChildAtIndex(i),
this));
4537 calculated_children =
false;
4541 void DrawTree(Window &window) {
4543 parent->DrawTreeForChild(window,
this, 0);
4545 if (might_have_children &&
4546 (!calculated_children || !GetChildren().empty())) {
4564 window.PutChar(ACS_DIAMOND);
4565 window.PutChar(ACS_HLINE);
4569 void DrawTreeForChild(Window &window, Row *child, uint32_t reverse_depth) {
4571 parent->DrawTreeForChild(window,
this, reverse_depth + 1);
4573 if (&GetChildren().back() == child) {
4575 if (reverse_depth == 0) {
4576 window.PutChar(ACS_LLCORNER);
4577 window.PutChar(ACS_HLINE);
4579 window.PutChar(
' ');
4580 window.PutChar(
' ');
4583 if (reverse_depth == 0) {
4584 window.PutChar(ACS_LTEE);
4585 window.PutChar(ACS_HLINE);
4587 window.PutChar(ACS_VLINE);
4588 window.PutChar(
' ');
4594struct DisplayOptions {
4602 TreeDelegate() =
default;
4603 virtual ~TreeDelegate() =
default;
4605 virtual void TreeDelegateDrawTreeItem(TreeItem &item, Window &window) = 0;
4606 virtual void TreeDelegateGenerateChildren(TreeItem &item) = 0;
4607 virtual void TreeDelegateUpdateSelection(TreeItem &root,
int &selection_index,
4608 TreeItem *&selected_item) {}
4611 virtual bool TreeDelegateItemSelected(TreeItem &item) = 0;
4612 virtual bool TreeDelegateExpandRootByDefault() {
return false; }
4616 virtual bool TreeDelegateShouldDraw() {
return true; }
4619typedef std::shared_ptr<TreeDelegate> TreeDelegateSP;
4621struct TreeItemData {
4622 TreeItemData(TreeItem *parent, TreeDelegate &delegate,
4623 bool might_have_children,
bool is_expanded)
4624 : m_parent(parent), m_delegate(&delegate),
4625 m_might_have_children(might_have_children), m_is_expanded(is_expanded) {
4630 TreeDelegate *m_delegate;
4631 void *m_user_data =
nullptr;
4632 uint64_t m_identifier = 0;
4636 bool m_might_have_children;
4637 bool m_is_expanded =
false;
4640class TreeItem :
public TreeItemData {
4642 TreeItem(TreeItem *parent, TreeDelegate &delegate,
bool might_have_children)
4643 : TreeItemData(parent, delegate, might_have_children,
4645 ? delegate.TreeDelegateExpandRootByDefault()
4649 TreeItem(
const TreeItem &) =
delete;
4650 TreeItem &operator=(
const TreeItem &rhs) =
delete;
4652 TreeItem &operator=(TreeItem &&rhs) {
4654 TreeItemData::operator=(std::move(rhs));
4655 AdoptChildren(rhs.m_children);
4660 TreeItem(TreeItem &&rhs) : TreeItemData(std::move(rhs)) {
4661 AdoptChildren(rhs.m_children);
4664 size_t GetDepth()
const {
4666 return 1 + m_parent->GetDepth();
4670 int GetRowIndex()
const {
return m_row_idx; }
4672 void ClearChildren() { m_children.clear(); }
4674 void Resize(
size_t n, TreeDelegate &delegate,
bool might_have_children) {
4675 if (m_children.size() >= n) {
4676 m_children.erase(m_children.begin() + n, m_children.end());
4679 m_children.reserve(n);
4680 std::generate_n(std::back_inserter(m_children), n - m_children.size(),
4681 [&, parent =
this]() {
4682 return TreeItem(parent, delegate, might_have_children);
4686 TreeItem &operator[](
size_t i) {
return m_children[i]; }
4688 void SetRowIndex(
int row_idx) { m_row_idx = row_idx; }
4690 size_t GetNumChildren() {
4691 m_delegate->TreeDelegateGenerateChildren(*
this);
4692 return m_children.size();
4695 void ItemWasSelected() { m_delegate->TreeDelegateItemSelected(*
this); }
4697 void CalculateRowIndexes(
int &row_idx) {
4698 SetRowIndex(row_idx);
4701 const bool expanded = IsExpanded();
4705 if (m_parent ==
nullptr || expanded)
4708 for (
auto &item : m_children) {
4710 item.CalculateRowIndexes(row_idx);
4712 item.SetRowIndex(-1);
4716 TreeItem *GetParent() {
return m_parent; }
4718 bool IsExpanded()
const {
return m_is_expanded; }
4720 void Expand() { m_is_expanded =
true; }
4722 void Unexpand() { m_is_expanded =
false; }
4724 bool Draw(Window &window,
const int first_visible_row,
4725 const uint32_t selected_row_idx,
int &row_idx,
int &num_rows_left) {
4726 if (num_rows_left <= 0)
4729 if (m_row_idx >= first_visible_row) {
4730 window.MoveCursor(2, row_idx + 1);
4733 m_parent->DrawTreeForChild(window,
this, 0);
4735 if (m_might_have_children) {
4753 window.PutChar(ACS_DIAMOND);
4754 window.PutChar(ACS_HLINE);
4756 bool highlight = (selected_row_idx ==
static_cast<size_t>(m_row_idx)) &&
4760 window.AttributeOn(A_REVERSE);
4762 m_delegate->TreeDelegateDrawTreeItem(*
this, window);
4765 window.AttributeOff(A_REVERSE);
4770 if (num_rows_left <= 0)
4774 for (
auto &item : m_children) {
4777 if (!item.Draw(window, first_visible_row, selected_row_idx, row_idx,
4782 return num_rows_left >= 0;
4785 void DrawTreeForChild(Window &window, TreeItem *child,
4786 uint32_t reverse_depth) {
4788 m_parent->DrawTreeForChild(window,
this, reverse_depth + 1);
4790 if (&m_children.back() == child) {
4792 if (reverse_depth == 0) {
4793 window.PutChar(ACS_LLCORNER);
4794 window.PutChar(ACS_HLINE);
4796 window.PutChar(
' ');
4797 window.PutChar(
' ');
4800 if (reverse_depth == 0) {
4801 window.PutChar(ACS_LTEE);
4802 window.PutChar(ACS_HLINE);
4804 window.PutChar(ACS_VLINE);
4805 window.PutChar(
' ');
4810 TreeItem *GetItemForRowIndex(uint32_t row_idx) {
4811 if (
static_cast<uint32_t
>(m_row_idx) == row_idx)
4813 if (m_children.empty())
4816 for (
auto &item : m_children) {
4817 TreeItem *selected_item_ptr = item.GetItemForRowIndex(row_idx);
4818 if (selected_item_ptr)
4819 return selected_item_ptr;
4825 void *GetUserData()
const {
return m_user_data; }
4827 void SetUserData(
void *user_data) { m_user_data = user_data; }
4829 uint64_t GetIdentifier()
const {
return m_identifier; }
4831 void SetIdentifier(uint64_t identifier) { m_identifier = identifier; }
4833 const std::string &GetText()
const {
return m_text; }
4835 void SetText(
const char *text) {
4836 if (text ==
nullptr) {
4843 void SetMightHaveChildren(
bool b) { m_might_have_children = b; }
4846 void AdoptChildren(std::vector<TreeItem> &children) {
4847 m_children = std::move(children);
4848 for (
auto &child : m_children)
4849 child.m_parent =
this;
4852 std::vector<TreeItem> m_children;
4855class TreeWindowDelegate :
public WindowDelegate {
4857 TreeWindowDelegate(Debugger &debugger,
const TreeDelegateSP &delegate_sp)
4858 : m_debugger(debugger), m_delegate_sp(delegate_sp),
4859 m_root(nullptr, *delegate_sp, true) {}
4861 int NumVisibleRows()
const {
return m_max_y - m_min_y; }
4863 bool WindowDelegateDraw(Window &window,
bool force)
override {
4866 m_max_x = window.GetWidth() - 1;
4867 m_max_y = window.GetHeight() - 1;
4870 window.DrawTitleBox(window.GetName());
4872 if (!m_delegate_sp->TreeDelegateShouldDraw()) {
4873 m_selected_item =
nullptr;
4877 const int num_visible_rows = NumVisibleRows();
4879 m_root.CalculateRowIndexes(m_num_rows);
4880 m_delegate_sp->TreeDelegateUpdateSelection(m_root, m_selected_row_idx,
4886 if (m_first_visible_row > 0 && m_num_rows < num_visible_rows)
4887 m_first_visible_row = 0;
4890 if (m_selected_row_idx < m_first_visible_row)
4891 m_first_visible_row = m_selected_row_idx;
4892 else if (m_first_visible_row + num_visible_rows <= m_selected_row_idx)
4893 m_first_visible_row = m_selected_row_idx - num_visible_rows + 1;
4896 int num_rows_left = num_visible_rows;
4897 m_root.Draw(window, m_first_visible_row, m_selected_row_idx, row_idx,
4900 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4905 const char *WindowDelegateGetHelpText()
override {
4906 return "Thread window keyboard shortcuts:";
4909 KeyHelp *WindowDelegateGetKeyHelp()
override {
4910 static curses::KeyHelp g_source_view_key_help[] = {
4911 {KEY_UP,
"Select previous item"},
4912 {KEY_DOWN,
"Select next item"},
4913 {KEY_RIGHT,
"Expand the selected item"},
4915 "Unexpand the selected item or select parent if not expanded"},
4916 {KEY_PPAGE,
"Page up"},
4917 {KEY_NPAGE,
"Page down"},
4918 {
'h',
"Show help dialog"},
4919 {
' ',
"Toggle item expansion"},
4923 return g_source_view_key_help;
4926 HandleCharResult WindowDelegateHandleChar(Window &window,
int c)
override {
4931 if (m_first_visible_row > 0) {
4932 if (m_first_visible_row > m_max_y)
4933 m_first_visible_row -= m_max_y;
4935 m_first_visible_row = 0;
4936 m_selected_row_idx = m_first_visible_row;
4937 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4938 if (m_selected_item)
4939 m_selected_item->ItemWasSelected();
4946 if (m_num_rows > m_max_y) {
4947 if (m_first_visible_row + m_max_y < m_num_rows) {
4948 m_first_visible_row += m_max_y;
4949 m_selected_row_idx = m_first_visible_row;
4950 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4951 if (m_selected_item)
4952 m_selected_item->ItemWasSelected();
4958 if (m_selected_row_idx > 0) {
4959 --m_selected_row_idx;
4960 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4961 if (m_selected_item)
4962 m_selected_item->ItemWasSelected();
4967 if (m_selected_row_idx + 1 < m_num_rows) {
4968 ++m_selected_row_idx;
4969 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4970 if (m_selected_item)
4971 m_selected_item->ItemWasSelected();
4976 if (m_selected_item) {
4977 if (!m_selected_item->IsExpanded())
4978 m_selected_item->Expand();
4983 if (m_selected_item) {
4984 if (m_selected_item->IsExpanded())
4985 m_selected_item->Unexpand();
4986 else if (m_selected_item->GetParent()) {
4987 m_selected_row_idx = m_selected_item->GetParent()->GetRowIndex();
4988 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4989 if (m_selected_item)
4990 m_selected_item->ItemWasSelected();
4997 if (m_selected_item) {
4998 if (m_selected_item->IsExpanded())
4999 m_selected_item->Unexpand();
5001 m_selected_item->Expand();
5006 window.CreateHelpSubwindow();
5012 return eKeyNotHandled;
5016 Debugger &m_debugger;
5017 TreeDelegateSP m_delegate_sp;
5019 TreeItem *m_selected_item =
nullptr;
5021 int m_selected_row_idx = 0;
5022 int m_first_visible_row = 0;
5031class TextTreeDelegate :
public TreeDelegate {
5033 TextTreeDelegate() : TreeDelegate() {}
5035 ~TextTreeDelegate()
override =
default;
5037 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5038 window.PutCStringTruncated(1, item.GetText().c_str());
5041 void TreeDelegateGenerateChildren(TreeItem &item)
override {}
5043 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5046class FrameTreeDelegate :
public TreeDelegate {
5048 FrameTreeDelegate() : TreeDelegate() {
5050 "#${frame.index}: {${function.name}${function.pc-offset}}}", m_format);
5053 ~FrameTreeDelegate()
override =
default;
5055 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5058 const uint64_t frame_idx = item.GetIdentifier();
5062 const SymbolContext &sc =
5063 frame_sp->GetSymbolContext(eSymbolContextEverything);
5064 ExecutionContext exe_ctx(frame_sp);
5065 if (FormatEntity::Formatter(&sc, &exe_ctx,
nullptr,
false,
false)
5066 .
Format(m_format, strm)) {
5068 window.PutCStringTruncated(right_pad, strm.
GetString().str().c_str());
5074 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5078 bool TreeDelegateItemSelected(TreeItem &item)
override {
5081 thread->
GetProcess()->GetThreadList().SetSelectedThreadByID(
5083 const uint64_t frame_idx = item.GetIdentifier();
5091 FormatEntity::Entry m_format;
5094class ThreadTreeDelegate :
public TreeDelegate {
5096 ThreadTreeDelegate(Debugger &debugger)
5097 : TreeDelegate(), m_debugger(debugger) {
5099 "reason = ${thread.stop-reason}}",
5103 ~ThreadTreeDelegate()
override =
default;
5106 return m_debugger.GetCommandInterpreter()
5107 .GetExecutionContext()
5111 ThreadSP GetThread(
const TreeItem &item) {
5114 return process_sp->GetThreadList().FindThreadByID(item.GetIdentifier());
5118 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5119 ThreadSP thread_sp = GetThread(item);
5122 ExecutionContext exe_ctx(thread_sp);
5123 if (FormatEntity::Formatter(
nullptr, &exe_ctx,
nullptr,
false,
false)
5124 .
Format(m_format, strm)) {
5126 window.PutCStringTruncated(right_pad, strm.
GetString().str().c_str());
5131 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5133 if (process_sp && process_sp->IsAlive()) {
5134 StateType state = process_sp->GetState();
5136 ThreadSP thread_sp = GetThread(item);
5138 if (m_stop_id == process_sp->GetStopID() &&
5139 thread_sp->GetID() == m_tid)
5141 if (!m_frame_delegate_sp) {
5143 m_frame_delegate_sp = std::make_shared<FrameTreeDelegate>();
5146 m_stop_id = process_sp->GetStopID();
5147 m_tid = thread_sp->GetID();
5149 size_t num_frames = thread_sp->GetStackFrameCount();
5150 item.Resize(num_frames, *m_frame_delegate_sp,
false);
5151 for (
size_t i = 0; i < num_frames; ++i) {
5152 item[i].SetUserData(thread_sp.get());
5153 item[i].SetIdentifier(i);
5159 item.ClearChildren();
5162 bool TreeDelegateItemSelected(TreeItem &item)
override {
5164 if (process_sp && process_sp->IsAlive()) {
5165 StateType state = process_sp->GetState();
5167 ThreadSP thread_sp = GetThread(item);
5169 ThreadList &thread_list = thread_sp->GetProcess()->GetThreadList();
5170 std::lock_guard<std::recursive_mutex> guard(thread_list.
GetMutex());
5172 if (selected_thread_sp->GetID() != thread_sp->GetID()) {
5183 Debugger &m_debugger;
5184 std::shared_ptr<FrameTreeDelegate> m_frame_delegate_sp;
5187 FormatEntity::Entry m_format;
5190class ThreadsTreeDelegate :
public TreeDelegate {
5192 ThreadsTreeDelegate(Debugger &debugger)
5193 : TreeDelegate(), m_thread_delegate_sp(), m_debugger(debugger) {
5198 ~ThreadsTreeDelegate()
override =
default;
5201 return m_debugger.GetCommandInterpreter()
5202 .GetExecutionContext()
5206 bool TreeDelegateShouldDraw()
override {
5217 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5219 if (process_sp && process_sp->IsAlive()) {
5221 ExecutionContext exe_ctx(process_sp);
5222 if (FormatEntity::Formatter(
nullptr, &exe_ctx,
nullptr,
false,
false)
5223 .
Format(m_format, strm)) {
5225 window.PutCStringTruncated(right_pad, strm.
GetString().str().c_str());
5230 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5232 m_update_selection =
false;
5233 if (process_sp && process_sp->IsAlive()) {
5234 StateType state = process_sp->GetState();
5236 const uint32_t stop_id = process_sp->GetStopID();
5237 if (m_stop_id == stop_id)
5240 m_stop_id = stop_id;
5241 m_update_selection =
true;
5243 if (!m_thread_delegate_sp) {
5246 m_thread_delegate_sp =
5247 std::make_shared<ThreadTreeDelegate>(m_debugger);
5250 ThreadList &threads = process_sp->GetThreadList();
5251 std::lock_guard<std::recursive_mutex> guard(threads.
GetMutex());
5253 size_t num_threads = threads.
GetSize();
5254 item.Resize(num_threads, *m_thread_delegate_sp,
false);
5255 for (
size_t i = 0; i < num_threads; ++i) {
5257 item[i].SetIdentifier(thread->GetID());
5258 item[i].SetMightHaveChildren(
true);
5259 if (selected_thread->GetID() == thread->GetID())
5265 item.ClearChildren();
5268 void TreeDelegateUpdateSelection(TreeItem &root,
int &selection_index,
5269 TreeItem *&selected_item)
override {
5270 if (!m_update_selection)
5274 if (!(process_sp && process_sp->IsAlive()))
5277 StateType state = process_sp->GetState();
5281 ThreadList &threads = process_sp->GetThreadList();
5282 std::lock_guard<std::recursive_mutex> guard(threads.
GetMutex());
5284 size_t num_threads = threads.
GetSize();
5285 for (
size_t i = 0; i < num_threads; ++i) {
5287 if (selected_thread->GetID() == thread->GetID()) {
5290 selection_index = selected_item->GetRowIndex();
5296 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5298 bool TreeDelegateExpandRootByDefault()
override {
return true; }
5301 std::shared_ptr<ThreadTreeDelegate> m_thread_delegate_sp;
5302 Debugger &m_debugger;
5304 bool m_update_selection =
false;
5305 FormatEntity::Entry m_format;
5308class BreakpointLocationTreeDelegate :
public TreeDelegate {
5310 BreakpointLocationTreeDelegate(Debugger &debugger)
5311 : TreeDelegate(), m_debugger(debugger) {}
5313 ~BreakpointLocationTreeDelegate()
override =
default;
5316 ExecutionContext exe_ctx(
5317 m_debugger.GetCommandInterpreter().GetExecutionContext());
5322 Breakpoint *breakpoint = (Breakpoint *)item.GetUserData();
5326 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5328 Process *process = GetProcess();
5329 StreamString stream;
5330 stream.
Printf(
"%i.%i: ", breakpoint_location->GetBreakpoint().GetID(),
5331 breakpoint_location->GetID());
5332 Address address = breakpoint_location->GetAddress();
5335 window.PutCStringTruncated(1, stream.
GetString().str().c_str());
5341 Address address = breakpoint_location->GetAddress();
5342 SymbolContext symbol_context;
5346 StreamString module_stream;
5348 symbol_context.
module_sp->GetFileSpec().Dump(
5353 if (symbol_context.
comp_unit !=
nullptr) {
5354 StreamString compile_unit_stream;
5355 compile_unit_stream.
PutCString(
"compile unit = ");
5357 &compile_unit_stream);
5360 if (symbol_context.
function !=
nullptr) {
5361 StreamString function_stream;
5369 StreamString location_stream;
5376 if (symbol_context.
symbol) {
5377 StreamString symbol_stream;
5378 if (breakpoint_location->IsReExported())
5379 symbol_stream.
PutCString(
"re-exported target = ");
5388 Process *process = GetProcess();
5390 StreamString address_stream;
5395 BreakpointSiteSP breakpoint_site = breakpoint_location->GetBreakpointSite();
5396 if (breakpoint_location->IsIndirect() && breakpoint_site) {
5397 Address resolved_address;
5398 resolved_address.
SetLoadAddress(breakpoint_site->GetLoadAddress(),
5399 &breakpoint_location->GetTarget());
5401 if (resolved_symbol) {
5402 StreamString indirect_target_stream;
5403 indirect_target_stream.
PutCString(
"indirect target = ");
5410 bool is_resolved = breakpoint_location->IsResolved();
5411 StreamString resolved_stream;
5412 resolved_stream.
Printf(
"resolved = %s", is_resolved ?
"true" :
"false");
5415 bool is_hardware = is_resolved && breakpoint_site->IsHardware();
5416 StreamString hardware_stream;
5417 hardware_stream.
Printf(
"hardware = %s", is_hardware ?
"true" :
"false");
5420 StreamString hit_count_stream;
5421 hit_count_stream.
Printf(
"hit count = %-4u",
5422 breakpoint_location->GetHitCount());
5428 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5430 StringList details = ComputeDetailsList(breakpoint_location);
5432 if (!m_string_delegate_sp)
5433 m_string_delegate_sp = std::make_shared<TextTreeDelegate>();
5435 item.Resize(details.
GetSize(), *m_string_delegate_sp,
false);
5436 for (
size_t i = 0; i < details.
GetSize(); i++) {
5441 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5444 Debugger &m_debugger;
5445 std::shared_ptr<TextTreeDelegate> m_string_delegate_sp;
5448class BreakpointTreeDelegate :
public TreeDelegate {
5450 BreakpointTreeDelegate(Debugger &debugger)
5451 : TreeDelegate(), m_debugger(debugger),
5452 m_breakpoint_location_delegate_sp() {}
5454 ~BreakpointTreeDelegate()
override =
default;
5457 TargetSP target = m_debugger.GetSelectedTarget();
5458 BreakpointList &breakpoints = target->GetBreakpointList(
false);
5462 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5464 StreamString stream;
5465 stream.
Format(
"{0}: ", breakpoint->GetID());
5466 breakpoint->GetResolverDescription(&stream);
5467 breakpoint->GetFilterDescription(&stream);
5468 window.PutCStringTruncated(1, stream.
GetString().str().c_str());
5471 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5474 if (!m_breakpoint_location_delegate_sp)
5475 m_breakpoint_location_delegate_sp =
5476 std::make_shared<BreakpointLocationTreeDelegate>(m_debugger);
5478 item.Resize(breakpoint->GetNumLocations(),
5479 *m_breakpoint_location_delegate_sp,
true);
5480 for (
size_t i = 0; i < breakpoint->GetNumLocations(); i++) {
5481 item[i].SetIdentifier(i);
5482 item[i].SetUserData(breakpoint.get());
5486 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5489 Debugger &m_debugger;
5490 std::shared_ptr<BreakpointLocationTreeDelegate>
5491 m_breakpoint_location_delegate_sp;
5494class BreakpointsTreeDelegate :
public TreeDelegate {
5496 BreakpointsTreeDelegate(Debugger &debugger)
5497 : TreeDelegate(), m_debugger(debugger), m_breakpoint_delegate_sp() {}
5499 ~BreakpointsTreeDelegate()
override =
default;
5501 bool TreeDelegateShouldDraw()
override {
5502 TargetSP target = m_debugger.GetSelectedTarget();
5509 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5510 window.PutCString(
"Breakpoints");
5513 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5514 TargetSP target = m_debugger.GetSelectedTarget();
5516 BreakpointList &breakpoints = target->GetBreakpointList(
false);
5517 std::unique_lock<std::recursive_mutex> lock;
5520 if (!m_breakpoint_delegate_sp)
5521 m_breakpoint_delegate_sp =
5522 std::make_shared<BreakpointTreeDelegate>(m_debugger);
5524 item.Resize(breakpoints.
GetSize(), *m_breakpoint_delegate_sp,
true);
5525 for (
size_t i = 0; i < breakpoints.
GetSize(); i++) {
5526 item[i].SetIdentifier(i);
5530 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5532 bool TreeDelegateExpandRootByDefault()
override {
return true; }
5535 Debugger &m_debugger;
5536 std::shared_ptr<BreakpointTreeDelegate> m_breakpoint_delegate_sp;
5539class ValueObjectListDelegate :
public WindowDelegate {
5541 ValueObjectListDelegate() : m_rows() {}
5543 ValueObjectListDelegate(ValueObjectList &valobj_list) : m_rows() {
5544 SetValues(valobj_list);
5547 ~ValueObjectListDelegate()
override =
default;
5549 void SetValues(ValueObjectList &valobj_list) {
5550 m_selected_row =
nullptr;
5551 m_selected_row_idx = 0;
5552 m_first_visible_row = 0;
5555 for (
auto &valobj_sp : valobj_list.
GetObjects())
5556 m_rows.push_back(Row(valobj_sp,
nullptr));
5559 bool WindowDelegateDraw(Window &window,
bool force)
override {
5563 m_max_x = window.GetWidth() - 1;
5564 m_max_y = window.GetHeight() - 1;
5567 window.DrawTitleBox(window.GetName());
5569 const int num_visible_rows = NumVisibleRows();
5570 const int num_rows = CalculateTotalNumberRows(m_rows);
5575 if (m_first_visible_row > 0 && num_rows < num_visible_rows)
5576 m_first_visible_row = 0;
5579 if (m_selected_row_idx < m_first_visible_row)
5580 m_first_visible_row = m_selected_row_idx;
5581 else if (m_first_visible_row + num_visible_rows <= m_selected_row_idx)
5582 m_first_visible_row = m_selected_row_idx - num_visible_rows + 1;
5584 DisplayRows(window, m_rows, g_options);
5587 m_selected_row = GetRowForRowIndex(m_selected_row_idx);
5591 window.MoveCursor(m_selected_row->x, m_selected_row->y);
5596 KeyHelp *WindowDelegateGetKeyHelp()
override {
5597 static curses::KeyHelp g_source_view_key_help[] = {
5598 {KEY_UP,
"Select previous item"},
5599 {KEY_DOWN,
"Select next item"},
5600 {KEY_RIGHT,
"Expand selected item"},
5601 {KEY_LEFT,
"Unexpand selected item or select parent if not expanded"},
5602 {KEY_PPAGE,
"Page up"},
5603 {KEY_NPAGE,
"Page down"},
5604 {
'A',
"Format as annotated address"},
5605 {
'b',
"Format as binary"},
5606 {
'B',
"Format as hex bytes with ASCII"},
5607 {
'c',
"Format as character"},
5608 {
'd',
"Format as a signed integer"},
5609 {
'D',
"Format selected value using the default format for the type"},
5610 {
'f',
"Format as float"},
5611 {
'h',
"Show help dialog"},
5612 {
'i',
"Format as instructions"},
5613 {
'o',
"Format as octal"},
5614 {
'p',
"Format as pointer"},
5615 {
's',
"Format as C string"},
5616 {
't',
"Toggle showing/hiding type names"},
5617 {
'u',
"Format as an unsigned integer"},
5618 {
'x',
"Format as hex"},
5619 {
'X',
"Format as uppercase hex"},
5620 {
' ',
"Toggle item expansion"},
5624 return g_source_view_key_help;
5627 HandleCharResult WindowDelegateHandleChar(Window &window,
int c)
override {
5644 if (m_selected_row) {
5645 auto valobj_sp = m_selected_row->value.GetSP();
5647 valobj_sp->SetFormat(FormatForChar(c));
5653 g_options.show_types = !g_options.show_types;
5659 if (m_first_visible_row > 0) {
5660 if (
static_cast<int>(m_first_visible_row) > m_max_y)
5661 m_first_visible_row -= m_max_y;
5663 m_first_visible_row = 0;
5664 m_selected_row_idx = m_first_visible_row;
5671 if (m_num_rows >
static_cast<size_t>(m_max_y)) {
5672 if (m_first_visible_row + m_max_y < m_num_rows) {
5673 m_first_visible_row += m_max_y;
5674 m_selected_row_idx = m_first_visible_row;
5680 if (m_selected_row_idx > 0)
5681 --m_selected_row_idx;
5685 if (m_selected_row_idx + 1 < m_num_rows)
5686 ++m_selected_row_idx;
5690 if (m_selected_row) {
5691 if (!m_selected_row->expanded)
5692 m_selected_row->Expand();
5697 if (m_selected_row) {
5698 if (m_selected_row->expanded)
5699 m_selected_row->Unexpand();
5700 else if (m_selected_row->parent)
5701 m_selected_row_idx = m_selected_row->parent->row_idx;
5707 if (m_selected_row) {
5708 if (m_selected_row->expanded)
5709 m_selected_row->Unexpand();
5711 m_selected_row->Expand();
5716 window.CreateHelpSubwindow();
5722 return eKeyNotHandled;
5726 std::vector<Row> m_rows;
5727 Row *m_selected_row =
nullptr;
5728 uint32_t m_selected_row_idx = 0;
5729 uint32_t m_first_visible_row = 0;
5730 uint32_t m_num_rows = 0;
5736 static Format FormatForChar(
int c) {
5770 bool DisplayRowObject(Window &window, Row &row, DisplayOptions &options,
5771 bool highlight,
bool last_child) {
5772 ValueObject *valobj = row.value.GetSP().get();
5774 if (valobj ==
nullptr)
5777 const char *type_name =
5783 window.MoveCursor(row.x, row.y);
5785 row.DrawTree(window);
5788 window.AttributeOn(A_REVERSE);
5790 if (type_name && type_name[0])
5791 window.PrintfTruncated(1,
"(%s) ", type_name);
5793 if (name && name[0])
5794 window.PutCStringTruncated(1, name);
5796 attr_t changd_attr = 0;
5798 changd_attr = COLOR_PAIR(RedOnBlack) | A_BOLD;
5800 if (value && value[0]) {
5801 window.PutCStringTruncated(1,
" = ");
5803 window.AttributeOn(changd_attr);
5804 window.PutCStringTruncated(1, value);
5806 window.AttributeOff(changd_attr);
5809 if (summary && summary[0]) {
5810 window.PutCStringTruncated(1,
" ");
5812 window.AttributeOn(changd_attr);
5813 window.PutCStringTruncated(1, summary);
5815 window.AttributeOff(changd_attr);
5819 window.AttributeOff(A_REVERSE);
5824 void DisplayRows(Window &window, std::vector<Row> &rows,
5825 DisplayOptions &options) {
5829 bool window_is_active = window.IsActive();
5830 for (
auto &row : rows) {
5831 const bool last_child = row.parent && &rows[rows.size() - 1] == &row;
5833 row.row_idx = m_num_rows;
5834 if ((m_num_rows >= m_first_visible_row) &&
5835 ((m_num_rows - m_first_visible_row) <
5836 static_cast<size_t>(NumVisibleRows()))) {
5838 row.y = m_num_rows - m_first_visible_row + 1;
5839 if (DisplayRowObject(window, row, options,
5841 m_num_rows == m_selected_row_idx,
5855 auto &children = row.GetChildren();
5856 if (!children.empty()) {
5857 DisplayRows(window, children, options);
5863 int CalculateTotalNumberRows(std::vector<Row> &rows) {
5865 for (
auto &row : rows) {
5868 row_count += CalculateTotalNumberRows(row.GetChildren());
5873 static Row *GetRowForRowIndexImpl(std::vector<Row> &rows,
size_t &row_index) {
5874 for (
auto &row : rows) {
5880 auto &children = row.GetChildren();
5881 if (!children.empty()) {
5882 Row *result = GetRowForRowIndexImpl(children, row_index);
5892 Row *GetRowForRowIndex(
size_t row_index) {
5893 return GetRowForRowIndexImpl(m_rows, row_index);
5896 int NumVisibleRows()
const {
return m_max_y - m_min_y; }
5898 static DisplayOptions g_options;
5901class FrameVariablesWindowDelegate :
public ValueObjectListDelegate {
5903 FrameVariablesWindowDelegate(Debugger &debugger)
5904 : ValueObjectListDelegate(), m_debugger(debugger) {}
5906 ~FrameVariablesWindowDelegate()
override =
default;
5908 const char *WindowDelegateGetHelpText()
override {
5909 return "Frame variable window keyboard shortcuts:";
5912 bool WindowDelegateDraw(Window &window,
bool force)
override {
5913 ExecutionContext exe_ctx(
5914 m_debugger.GetCommandInterpreter().GetExecutionContext());
5916 Block *frame_block =
nullptr;
5917 StackFrame *frame =
nullptr;
5930 ValueObjectList local_values;
5933 if (m_frame_block != frame_block) {
5934 m_frame_block = frame_block;
5943 ValueObjectSP synthetic_value_sp = value_sp->GetSyntheticValue();
5944 if (synthetic_value_sp)
5945 local_values.
Append(synthetic_value_sp);
5947 local_values.
Append(value_sp);
5951 SetValues(local_values);
5955 m_frame_block =
nullptr;
5957 SetValues(local_values);
5960 return ValueObjectListDelegate::WindowDelegateDraw(window, force);
5964 Debugger &m_debugger;
5965 Block *m_frame_block =
nullptr;
5968class RegistersWindowDelegate :
public ValueObjectListDelegate {
5970 RegistersWindowDelegate(Debugger &debugger)
5971 : ValueObjectListDelegate(), m_debugger(debugger) {}
5973 ~RegistersWindowDelegate()
override =
default;
5975 const char *WindowDelegateGetHelpText()
override {
5976 return "Register window keyboard shortcuts:";
5979 bool WindowDelegateDraw(Window &window,
bool force)
override {
5980 ExecutionContext exe_ctx(
5981 m_debugger.GetCommandInterpreter().GetExecutionContext());
5984 ValueObjectList value_list;
5990 const uint32_t num_sets = reg_ctx->GetRegisterSetCount();
5991 for (uint32_t set_idx = 0; set_idx < num_sets; ++set_idx) {
5996 SetValues(value_list);
6000 if (process && process->
IsAlive())
6005 SetValues(value_list);
6008 return ValueObjectListDelegate::WindowDelegateDraw(window, force);
6012 Debugger &m_debugger;
6016static const char *CursesKeyToCString(
int ch) {
6017 static char g_desc[32];
6018 if (ch >= KEY_F0 && ch < KEY_F0 + 64) {
6019 snprintf(g_desc,
sizeof(g_desc),
"F%u", ch - KEY_F0);
6036 return "delete-line";
6038 return "insert-line";
6040 return "delete-char";
6042 return "insert-char";
6046 return "clear-to-eos";
6048 return "clear-to-eol";
6050 return "scroll-forward";
6052 return "scroll-backward";
6062 return "clear-all-tabs";
6068 return "lower-left key";
6070 return "upper left of keypad";
6072 return "upper right of keypad";
6074 return "center of keypad";
6076 return "lower left of keypad";
6078 return "lower right of keypad";
6080 return "back-tab key";
6084 return "cancel key";
6088 return "command key";
6092 return "create key";
6104 return "message key";
6112 return "options key";
6114 return "previous key";
6118 return "reference key";
6120 return "refresh key";
6122 return "replace key";
6124 return "restart key";
6126 return "resume key";
6130 return "shifted begin key";
6132 return "shifted cancel key";
6134 return "shifted command key";
6136 return "shifted copy key";
6138 return "shifted create key";
6140 return "shifted delete-character key";
6142 return "shifted delete-line key";
6144 return "select key";
6146 return "shifted end key";
6148 return "shifted clear-to-end-of-line key";
6150 return "shifted exit key";
6152 return "shifted find key";
6154 return "shifted help key";
6156 return "shifted home key";
6158 return "shifted insert-character key";
6160 return "shifted left-arrow key";
6162 return "shifted message key";
6164 return "shifted move key";
6166 return "shifted next key";
6168 return "shifted options key";
6170 return "shifted previous key";
6172 return "shifted print key";
6174 return "shifted redo key";
6176 return "shifted replace key";
6178 return "shifted right-arrow key";
6180 return "shifted resume key";
6182 return "shifted save key";
6184 return "shifted suspend key";
6186 return "shifted undo key";
6188 return "suspend key";
6192 return "Mouse event has occurred";
6194 return "Terminal resize event";
6197 return "We were interrupted by an event";
6208 if (llvm::isPrint(ch))
6209 snprintf(g_desc,
sizeof(g_desc),
"%c", ch);
6211 snprintf(g_desc,
sizeof(g_desc),
"\\x%2.2x", ch);
6217HelpDialogDelegate::HelpDialogDelegate(
const char *text,
6218 KeyHelp *key_help_array)
6220 if (text && text[0]) {
6221 m_text.SplitIntoLines(text);
6222 m_text.AppendString(
"");
6224 if (key_help_array) {
6225 for (KeyHelp *key = key_help_array; key->ch; ++key) {
6227 key_description.
Printf(
"%10s - %s", CursesKeyToCString(key->ch),
6229 m_text.AppendString(key_description.
GetString());
6234HelpDialogDelegate::~HelpDialogDelegate() =
default;
6236bool HelpDialogDelegate::WindowDelegateDraw(Window &window,
bool force) {
6238 const int window_height = window.GetHeight();
6241 const int min_y = y;
6242 const int max_y = window_height - 1 - y;
6243 const size_t num_visible_lines = max_y - min_y + 1;
6244 const size_t num_lines = m_text.GetSize();
6245 const char *bottom_message;
6246 if (num_lines <= num_visible_lines)
6247 bottom_message =
"Press any key to exit";
6249 bottom_message =
"Use arrows to scroll, any other key to exit";
6250 window.DrawTitleBox(window.GetName(), bottom_message);
6251 while (y <= max_y) {
6252 window.MoveCursor(x, y);
6253 window.PutCStringTruncated(
6254 1, m_text.GetStringAtIndex(m_first_visible_line + y - min_y));
6260HandleCharResult HelpDialogDelegate::WindowDelegateHandleChar(Window &window,
6263 const size_t num_lines = m_text.GetSize();
6264 const size_t num_visible_lines = window.GetHeight() - 2;
6266 if (num_lines <= num_visible_lines) {
6273 if (m_first_visible_line > 0)
6274 --m_first_visible_line;
6278 if (m_first_visible_line + num_visible_lines < num_lines)
6279 ++m_first_visible_line;
6284 if (m_first_visible_line > 0) {
6285 if (
static_cast<size_t>(m_first_visible_line) >= num_visible_lines)
6286 m_first_visible_line -= num_visible_lines;
6288 m_first_visible_line = 0;
6294 if (m_first_visible_line + num_visible_lines < num_lines) {
6295 m_first_visible_line += num_visible_lines;
6296 if (
static_cast<size_t>(m_first_visible_line) > num_lines)
6297 m_first_visible_line = num_lines - num_visible_lines;
6307 window.GetParent()->RemoveSubWindow(&window);
6311class ApplicationDelegate :
public WindowDelegate,
public MenuDelegate {
6319 eMenuID_TargetCreate,
6320 eMenuID_TargetDelete,
6323 eMenuID_ProcessAttach,
6324 eMenuID_ProcessDetachResume,
6325 eMenuID_ProcessDetachSuspended,
6326 eMenuID_ProcessLaunch,
6327 eMenuID_ProcessContinue,
6328 eMenuID_ProcessHalt,
6329 eMenuID_ProcessKill,
6332 eMenuID_ThreadStepIn,
6333 eMenuID_ThreadStepOver,
6334 eMenuID_ThreadStepOut,
6337 eMenuID_ViewBacktrace,
6338 eMenuID_ViewRegisters,
6340 eMenuID_ViewVariables,
6341 eMenuID_ViewBreakpoints,
6347 ApplicationDelegate(Application &app, Debugger &debugger)
6348 : WindowDelegate(), MenuDelegate(), m_app(app), m_debugger(debugger) {}
6350 ~ApplicationDelegate()
override =
default;
6352 bool WindowDelegateDraw(Window &window,
bool force)
override {
6356 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override {
6359 window.SelectNextWindowAsActive();
6363 window.SelectPreviousWindowAsActive();
6367 window.CreateHelpSubwindow();
6371 return eQuitApplication;
6376 return eKeyNotHandled;
6379 const char *WindowDelegateGetHelpText()
override {
6380 return "Welcome to the LLDB curses GUI.\n\n"
6381 "Press the TAB key to change the selected view.\n"
6382 "Each view has its own keyboard shortcuts, press 'h' to open a "
6383 "dialog to display them.\n\n"
6384 "Common key bindings for all views:";
6387 KeyHelp *WindowDelegateGetKeyHelp()
override {
6388 static curses::KeyHelp g_source_view_key_help[] = {
6389 {
'\t',
"Select next view"},
6390 {KEY_BTAB,
"Select previous view"},
6391 {
'h',
"Show help dialog with view specific key bindings"},
6394 {KEY_UP,
"Select previous"},
6395 {KEY_DOWN,
"Select next"},
6396 {KEY_LEFT,
"Unexpand or select parent"},
6397 {KEY_RIGHT,
"Expand"},
6398 {KEY_PPAGE,
"Page up"},
6399 {KEY_NPAGE,
"Page down"},
6401 return g_source_view_key_help;
6404 MenuActionResult MenuDelegateAction(Menu &menu)
override {
6405 switch (menu.GetIdentifier()) {
6406 case eMenuID_TargetCreate: {
6407 WindowSP main_window_sp = m_app.GetMainWindow();
6408 FormDelegateSP form_delegate_sp =
6409 FormDelegateSP(
new TargetCreateFormDelegate(m_debugger));
6410 Rect bounds = main_window_sp->GetCenteredRect(80, 19);
6411 WindowSP form_window_sp = main_window_sp->CreateSubWindow(
6412 form_delegate_sp->GetName().c_str(), bounds,
true);
6413 WindowDelegateSP window_delegate_sp =
6414 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
6415 form_window_sp->SetDelegate(window_delegate_sp);
6416 return MenuActionResult::Handled;
6418 case eMenuID_ThreadStepIn: {
6419 ExecutionContext exe_ctx =
6420 m_debugger.GetCommandInterpreter().GetExecutionContext();
6423 if (process && process->
IsAlive() &&
6428 return MenuActionResult::Handled;
6430 case eMenuID_ThreadStepOut: {
6431 ExecutionContext exe_ctx =
6432 m_debugger.GetCommandInterpreter().GetExecutionContext();
6435 if (process && process->
IsAlive() &&
6438 uint32_t frame_idx =
6444 return MenuActionResult::Handled;
6446 case eMenuID_ThreadStepOver: {
6447 ExecutionContext exe_ctx =
6448 m_debugger.GetCommandInterpreter().GetExecutionContext();
6451 if (process && process->
IsAlive() &&
6456 return MenuActionResult::Handled;
6458 case eMenuID_ProcessAttach: {
6459 WindowSP main_window_sp = m_app.GetMainWindow();
6460 FormDelegateSP form_delegate_sp = FormDelegateSP(
6461 new ProcessAttachFormDelegate(m_debugger, main_window_sp));
6462 Rect bounds = main_window_sp->GetCenteredRect(80, 22);
6463 WindowSP form_window_sp = main_window_sp->CreateSubWindow(
6464 form_delegate_sp->GetName().c_str(), bounds,
true);
6465 WindowDelegateSP window_delegate_sp =
6466 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
6467 form_window_sp->SetDelegate(window_delegate_sp);
6468 return MenuActionResult::Handled;
6470 case eMenuID_ProcessLaunch: {
6471 WindowSP main_window_sp = m_app.GetMainWindow();
6472 FormDelegateSP form_delegate_sp = FormDelegateSP(
6473 new ProcessLaunchFormDelegate(m_debugger, main_window_sp));
6474 Rect bounds = main_window_sp->GetCenteredRect(80, 22);
6475 WindowSP form_window_sp = main_window_sp->CreateSubWindow(
6476 form_delegate_sp->GetName().c_str(), bounds,
true);
6477 WindowDelegateSP window_delegate_sp =
6478 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
6479 form_window_sp->SetDelegate(window_delegate_sp);
6480 return MenuActionResult::Handled;
6483 case eMenuID_ProcessContinue: {
6484 ExecutionContext exe_ctx =
6485 m_debugger.GetCommandInterpreter().GetExecutionContext();
6488 if (process && process->
IsAlive() &&
6493 return MenuActionResult::Handled;
6495 case eMenuID_ProcessKill: {
6496 ExecutionContext exe_ctx =
6497 m_debugger.GetCommandInterpreter().GetExecutionContext();
6500 if (process && process->
IsAlive())
6504 return MenuActionResult::Handled;
6506 case eMenuID_ProcessHalt: {
6507 ExecutionContext exe_ctx =
6508 m_debugger.GetCommandInterpreter().GetExecutionContext();
6511 if (process && process->
IsAlive())
6515 return MenuActionResult::Handled;
6517 case eMenuID_ProcessDetachResume:
6518 case eMenuID_ProcessDetachSuspended: {
6519 ExecutionContext exe_ctx =
6520 m_debugger.GetCommandInterpreter().GetExecutionContext();
6523 if (process && process->
IsAlive())
6524 process->
Detach(menu.GetIdentifier() ==
6525 eMenuID_ProcessDetachSuspended);
6528 return MenuActionResult::Handled;
6530 case eMenuID_Process: {
6534 Menus &submenus = menu.GetSubmenus();
6535 ExecutionContext exe_ctx =
6536 m_debugger.GetCommandInterpreter().GetExecutionContext();
6538 if (process && process->
IsAlive() &&
6540 if (submenus.size() == 7)
6541 menu.AddSubmenu(std::make_shared<Menu>(Menu::Type::Separator));
6542 else if (submenus.size() > 8)
6543 submenus.erase(submenus.begin() + 8, submenus.end());
6546 std::lock_guard<std::recursive_mutex> guard(threads.
GetMutex());
6547 size_t num_threads = threads.
GetSize();
6548 for (
size_t i = 0; i < num_threads; ++i) {
6550 char menu_char =
'\0';
6552 menu_char =
'1' + i;
6553 StreamString thread_menu_title;
6554 thread_menu_title.
Printf(
"Thread %u", thread_sp->GetIndexID());
6555 const char *thread_name = thread_sp->GetName();
6556 if (thread_name && thread_name[0])
6557 thread_menu_title.
Printf(
" %s", thread_name);
6559 const char *queue_name = thread_sp->GetQueueName();
6560 if (queue_name && queue_name[0])
6561 thread_menu_title.
Printf(
" %s", queue_name);
6563 menu.AddSubmenu(std::make_shared<Menu>(
6564 thread_menu_title.
GetString().str().c_str(),
nullptr, menu_char,
6565 thread_sp->GetID()));
6567 }
else if (submenus.size() > 7) {
6570 submenus.erase(submenus.begin() + 7, submenus.end());
6574 menu.RecalculateNameLengths();
6576 return MenuActionResult::Handled;
6578 case eMenuID_ViewVariables: {
6579 WindowSP main_window_sp = m_app.GetMainWindow();
6580 WindowSP source_window_sp = main_window_sp->FindSubWindow(
"Source");
6581 WindowSP variables_window_sp = main_window_sp->FindSubWindow(
"Variables");
6582 WindowSP registers_window_sp = main_window_sp->FindSubWindow(
"Registers");
6583 const Rect source_bounds = source_window_sp->GetBounds();
6585 if (variables_window_sp) {
6586 const Rect variables_bounds = variables_window_sp->GetBounds();
6588 main_window_sp->RemoveSubWindow(variables_window_sp.get());
6590 if (registers_window_sp) {
6593 Rect registers_bounds = variables_bounds;
6594 registers_bounds.size.width = source_bounds.size.width;
6595 registers_window_sp->SetBounds(registers_bounds);
6599 source_window_sp->Resize(source_bounds.size.width,
6600 source_bounds.size.height +
6601 variables_bounds.size.height);
6604 Rect new_variables_rect;
6605 if (registers_window_sp) {
6609 const Rect variables_bounds = registers_window_sp->GetBounds();
6610 Rect new_registers_rect;
6611 variables_bounds.VerticalSplitPercentage(0.50, new_variables_rect,
6612 new_registers_rect);
6613 registers_window_sp->SetBounds(new_registers_rect);
6616 Rect new_source_rect;
6617 source_bounds.HorizontalSplitPercentage(0.70, new_source_rect,
6618 new_variables_rect);
6619 source_window_sp->SetBounds(new_source_rect);
6621 WindowSP new_window_sp = main_window_sp->CreateSubWindow(
6622 "Variables", new_variables_rect,
false);
6623 new_window_sp->SetDelegate(
6624 WindowDelegateSP(
new FrameVariablesWindowDelegate(m_debugger)));
6628 return MenuActionResult::Handled;
6630 case eMenuID_ViewRegisters: {
6631 WindowSP main_window_sp = m_app.GetMainWindow();
6632 WindowSP source_window_sp = main_window_sp->FindSubWindow(
"Source");
6633 WindowSP variables_window_sp = main_window_sp->FindSubWindow(
"Variables");
6634 WindowSP registers_window_sp = main_window_sp->FindSubWindow(
"Registers");
6635 const Rect source_bounds = source_window_sp->GetBounds();
6637 if (registers_window_sp) {
6638 if (variables_window_sp) {
6639 const Rect variables_bounds = variables_window_sp->GetBounds();
6643 variables_window_sp->Resize(variables_bounds.size.width +
6644 registers_window_sp->GetWidth(),
6645 variables_bounds.size.height);
6649 source_window_sp->Resize(source_bounds.size.width,
6650 source_bounds.size.height +
6651 registers_window_sp->GetHeight());
6653 main_window_sp->RemoveSubWindow(registers_window_sp.get());
6656 if (variables_window_sp) {
6660 const Rect variables_bounds = variables_window_sp->GetBounds();
6662 variables_bounds.VerticalSplitPercentage(0.50, new_vars_rect,
6664 variables_window_sp->SetBounds(new_vars_rect);
6667 Rect new_source_rect;
6668 source_bounds.HorizontalSplitPercentage(0.70, new_source_rect,
6670 source_window_sp->SetBounds(new_source_rect);
6672 WindowSP new_window_sp =
6673 main_window_sp->CreateSubWindow(
"Registers", new_regs_rect,
false);
6674 new_window_sp->SetDelegate(
6675 WindowDelegateSP(
new RegistersWindowDelegate(m_debugger)));
6679 return MenuActionResult::Handled;
6681 case eMenuID_ViewBreakpoints: {
6682 WindowSP main_window_sp = m_app.GetMainWindow();
6683 WindowSP threads_window_sp = main_window_sp->FindSubWindow(
"Threads");
6684 WindowSP breakpoints_window_sp =
6685 main_window_sp->FindSubWindow(
"Breakpoints");
6686 const Rect threads_bounds = threads_window_sp->GetBounds();
6693 if (breakpoints_window_sp) {
6694 threads_window_sp->Resize(threads_bounds.size.width,
6695 threads_bounds.size.height +
6696 breakpoints_window_sp->GetHeight());
6697 main_window_sp->RemoveSubWindow(breakpoints_window_sp.get());
6699 Rect new_threads_bounds, breakpoints_bounds;
6700 threads_bounds.HorizontalSplitPercentage(0.70, new_threads_bounds,
6701 breakpoints_bounds);
6702 threads_window_sp->SetBounds(new_threads_bounds);
6703 breakpoints_window_sp = main_window_sp->CreateSubWindow(
6704 "Breakpoints", breakpoints_bounds,
false);
6705 TreeDelegateSP breakpoints_delegate_sp(
6706 new BreakpointsTreeDelegate(m_debugger));
6707 breakpoints_window_sp->SetDelegate(WindowDelegateSP(
6708 new TreeWindowDelegate(m_debugger, breakpoints_delegate_sp)));
6711 return MenuActionResult::Handled;
6714 case eMenuID_HelpGUIHelp:
6715 m_app.GetMainWindow()->CreateHelpSubwindow();
6716 return MenuActionResult::Handled;
6722 return MenuActionResult::NotHandled;
6727 Debugger &m_debugger;
6730class StatusBarWindowDelegate :
public WindowDelegate {
6732 StatusBarWindowDelegate(Debugger &debugger) : m_debugger(debugger) {
6736 ~StatusBarWindowDelegate()
override =
default;
6738 bool WindowDelegateDraw(Window &window,
bool force)
override {
6739 ExecutionContext exe_ctx =
6740 m_debugger.GetCommandInterpreter().GetExecutionContext();
6745 window.SetBackground(BlackOnWhite);
6746 window.MoveCursor(0, 0);
6749 window.Printf(
"Process: %5" PRIu64
" %10s", process->
GetID(),
6755 FormatEntity::Formatter(
nullptr, &exe_ctx,
nullptr,
false,
false)
6756 .
Format(m_format, strm)) {
6757 window.MoveCursor(40, 0);
6758 window.PutCStringTruncated(1, strm.
GetString().str().c_str());
6761 window.MoveCursor(60, 0);
6763 window.Printf(
"Frame: %3u PC = 0x%16.16" PRIx64,
6770 if (exit_desc && exit_desc[0])
6771 window.Printf(
" with status = %i (%s)", exit_status, exit_desc);
6773 window.Printf(
" with status = %i", exit_status);
6780 Debugger &m_debugger;
6781 FormatEntity::Entry m_format;
6784class SourceFileWindowDelegate :
public WindowDelegate {
6786 SourceFileWindowDelegate(Debugger &debugger)
6787 : WindowDelegate(), m_debugger(debugger) {}
6789 ~SourceFileWindowDelegate()
override =
default;
6791 void Update(
const SymbolContext &sc) { m_sc = sc; }
6793 uint32_t NumVisibleLines()
const {
return m_max_y - m_min_y; }
6795 const char *WindowDelegateGetHelpText()
override {
6796 return "Source/Disassembly window keyboard shortcuts:";
6799 KeyHelp *WindowDelegateGetKeyHelp()
override {
6800 static curses::KeyHelp g_source_view_key_help[] = {
6801 {KEY_RETURN,
"Run to selected line with one shot breakpoint"},
6802 {KEY_UP,
"Select previous source line"},
6803 {KEY_DOWN,
"Select next source line"},
6804 {KEY_LEFT,
"Scroll to the left"},
6805 {KEY_RIGHT,
"Scroll to the right"},
6806 {KEY_PPAGE,
"Page up"},
6807 {KEY_NPAGE,
"Page down"},
6808 {
'b',
"Set breakpoint on selected source/disassembly line"},
6809 {
'c',
"Continue process"},
6810 {
'D',
"Detach with process suspended"},
6811 {
'h',
"Show help dialog"},
6812 {
'n',
"Step over (source line)"},
6813 {
'N',
"Step over (single instruction)"},
6814 {
'f',
"Step out (finish)"},
6815 {
's',
"Step in (source line)"},
6816 {
'S',
"Step in (single instruction)"},
6818 {
'd',
"Frame down"},
6822 return g_source_view_key_help;
6825 bool WindowDelegateDraw(Window &window,
bool force)
override {
6826 ExecutionContext exe_ctx =
6827 m_debugger.GetCommandInterpreter().GetExecutionContext();
6829 Thread *thread =
nullptr;
6831 bool update_location =
false;
6836 update_location =
true;
6842 m_max_x = window.GetMaxX() - 1;
6843 m_max_y = window.GetMaxY() - 1;
6845 const uint32_t num_visible_lines = NumVisibleLines();
6847 bool set_selected_line_to_pc =
false;
6849 if (update_location) {
6850 const bool process_alive = process->
IsAlive();
6851 bool thread_changed =
false;
6852 if (process_alive) {
6856 auto tid = thread->
GetID();
6857 thread_changed = tid != m_tid;
6861 thread_changed =
true;
6866 const uint32_t stop_id = process ? process->
GetStopID() : 0;
6867 const bool stop_id_changed = stop_id != m_stop_id;
6868 bool frame_changed =
false;
6869 m_stop_id = stop_id;
6872 m_sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
6873 if (m_sc.module_sp) {
6875 "%s", m_sc.module_sp->GetFileSpec().GetFilename().GetCString());
6876 ConstString func_name = m_sc.GetFunctionName();
6878 m_title.Printf(
"`%s", func_name.
GetCString());
6880 const uint32_t frame_idx = frame_sp->GetFrameIndex();
6881 frame_changed = frame_idx != m_frame_idx;
6882 m_frame_idx = frame_idx;
6889 const bool context_changed =
6890 thread_changed || frame_changed || stop_id_changed;
6892 if (process_alive) {
6893 if (m_sc.line_entry.IsValid()) {
6894 m_pc_line = m_sc.line_entry.line;
6898 if (context_changed)
6899 m_selected_line = m_pc_line;
6901 if (m_file_sp && m_file_sp->GetSupportFile()->GetSpecOnly() ==
6902 m_sc.line_entry.GetFile()) {
6905 if (m_selected_line >=
static_cast<size_t>(m_first_visible_line)) {
6906 if (m_selected_line >= m_first_visible_line + num_visible_lines)
6907 m_first_visible_line = m_selected_line - 10;
6909 if (m_selected_line > 10)
6910 m_first_visible_line = m_selected_line - 10;
6912 m_first_visible_line = 0;
6916 m_selected_line = m_pc_line;
6918 m_debugger.GetSourceManager().GetFile(m_sc.line_entry.file_sp);
6920 const size_t num_lines = m_file_sp->GetNumLines();
6922 for (
size_t n = num_lines; n >= 10; n = n / 10)
6925 if (num_lines < num_visible_lines ||
6926 m_selected_line < num_visible_lines)
6927 m_first_visible_line = 0;
6929 m_first_visible_line = m_selected_line - 10;
6936 if (!m_file_sp || m_file_sp->GetNumLines() == 0) {
6938 bool prefer_file_cache =
false;
6939 if (m_sc.function) {
6940 if (m_disassembly_scope != m_sc.function) {
6941 m_disassembly_scope = m_sc.function;
6942 m_disassembly_sp = m_sc.function->GetInstructions(
6943 exe_ctx,
nullptr, !prefer_file_cache);
6944 if (m_disassembly_sp)
6945 set_selected_line_to_pc =
true;
6947 set_selected_line_to_pc = context_changed;
6949 }
else if (m_sc.symbol) {
6950 if (m_disassembly_scope != m_sc.symbol) {
6951 m_disassembly_scope = m_sc.symbol;
6952 m_disassembly_sp = m_sc.symbol->GetInstructions(
6953 exe_ctx,
nullptr, prefer_file_cache);
6954 if (m_disassembly_sp)
6955 set_selected_line_to_pc =
true;
6957 set_selected_line_to_pc = context_changed;
6966 const int window_width = window.GetWidth();
6968 window.DrawTitleBox(
"Sources");
6969 if (!m_title.GetString().empty()) {
6970 window.AttributeOn(A_REVERSE);
6971 window.MoveCursor(1, 1);
6972 window.PutChar(
' ');
6973 window.PutCStringTruncated(1, m_title.GetString().str().c_str());
6974 int x = window.GetCursorX();
6975 if (x < window_width - 1) {
6976 window.Printf(
"%*s", window_width - x - 1,
"");
6978 window.AttributeOff(A_REVERSE);
6982 const size_t num_source_lines = GetNumSourceLines();
6983 if (num_source_lines > 0) {
6985 BreakpointLines bp_lines;
6988 const size_t num_bps = bp_list.
GetSize();
6989 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
6991 const size_t num_bps_locs = bp_sp->GetNumLocations();
6992 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs; ++bp_loc_idx) {
6994 bp_sp->GetLocationAtIndex(bp_loc_idx);
6995 LineEntry bp_loc_line_entry;
6996 if (bp_loc_sp->GetAddress().CalculateSymbolContextLineEntry(
6997 bp_loc_line_entry)) {
6998 if (m_file_sp->GetSupportFile()->GetSpecOnly() ==
6999 bp_loc_line_entry.
GetFile()) {
7000 bp_lines.insert(bp_loc_line_entry.
line);
7007 for (
size_t i = 0; i < num_visible_lines; ++i) {
7008 const uint32_t curr_line = m_first_visible_line + i;
7009 if (curr_line < num_source_lines) {
7010 const int line_y = m_min_y + i;
7011 window.MoveCursor(1, line_y);
7012 const bool is_pc_line = curr_line == m_pc_line;
7013 const bool line_is_selected = m_selected_line == curr_line;
7017 attr_t highlight_attr = 0;
7019 if (line_is_selected && !is_pc_line)
7020 highlight_attr = A_REVERSE;
7022 if (bp_lines.find(curr_line + 1) != bp_lines.end())
7023 bp_attr = COLOR_PAIR(BlackOnWhite);
7026 window.AttributeOn(bp_attr);
7028 window.Printf(
" %*u ", m_line_width, curr_line + 1);
7031 window.AttributeOff(bp_attr);
7033 window.PutChar(ACS_VLINE);
7036 window.PutChar(ACS_DIAMOND);
7038 window.PutChar(
' ');
7041 window.AttributeOn(highlight_attr);
7043 StreamString lineStream;
7045 std::optional<size_t> column;
7046 if (is_pc_line && m_sc.line_entry.IsValid() && m_sc.line_entry.column)
7047 column = m_sc.line_entry.column - 1;
7048 m_file_sp->DisplaySourceLines(curr_line + 1, column, 0, 0,
7050 StringRef line = lineStream.
GetString();
7051 if (line.ends_with(
"\n"))
7052 line = line.drop_back();
7053 bool wasWritten = window.OutputColoredStringTruncated(
7054 1, line, m_first_visible_column, is_pc_line);
7055 if (!wasWritten && (line_is_selected || is_pc_line)) {
7059 window.PutCStringTruncated(
7060 1, line.empty() && m_first_visible_column == 0 ?
" " :
"<");
7063 if (is_pc_line && frame_sp &&
7064 frame_sp->GetConcreteFrameIndex() == 0) {
7069 const char *stop_description = stop_info_sp->GetDescription();
7070 if (stop_description && stop_description[0]) {
7071 size_t stop_description_len = strlen(stop_description);
7072 int desc_x = window_width - stop_description_len - 16;
7073 if (desc_x - window.GetCursorX() > 0)
7074 window.Printf(
"%*s", desc_x - window.GetCursorX(),
"");
7075 window.MoveCursor(window_width - stop_description_len - 16,
7077 const attr_t stop_reason_attr = COLOR_PAIR(WhiteOnBlue);
7078 window.AttributeOn(stop_reason_attr);
7079 window.PrintfTruncated(1,
" <<< Thread %u: %s ",
7081 window.AttributeOff(stop_reason_attr);
7084 window.Printf(
"%*s", window_width - window.GetCursorX() - 1,
"");
7088 window.AttributeOff(highlight_attr);
7094 size_t num_disassembly_lines = GetNumDisassemblyLines();
7095 if (num_disassembly_lines > 0) {
7097 BreakpointAddrs bp_file_addrs;
7101 const size_t num_bps = bp_list.
GetSize();
7102 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
7104 const size_t num_bps_locs = bp_sp->GetNumLocations();
7105 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs;
7108 bp_sp->GetLocationAtIndex(bp_loc_idx);
7109 bp_file_addrs.insert(bp_loc_sp->GetAddress().GetFileAddress());
7114 const attr_t selected_highlight_attr = A_REVERSE;
7115 const attr_t pc_highlight_attr = COLOR_PAIR(WhiteOnBlue);
7119 InstructionList &insts = m_disassembly_sp->GetInstructionList();
7123 pc_address = frame_sp->GetFrameCodeAddress();
7124 const uint32_t pc_idx =
7128 if (set_selected_line_to_pc) {
7129 m_selected_line = pc_idx;
7132 const uint32_t non_visible_pc_offset = (num_visible_lines / 5);
7133 if (
static_cast<size_t>(m_first_visible_line) >= num_disassembly_lines)
7134 m_first_visible_line = 0;
7136 if (pc_idx < num_disassembly_lines) {
7137 if (pc_idx <
static_cast<uint32_t
>(m_first_visible_line) ||
7138 pc_idx >= m_first_visible_line + num_visible_lines)
7139 m_first_visible_line = pc_idx - non_visible_pc_offset;
7142 for (
size_t i = 0; i < num_visible_lines; ++i) {
7143 const uint32_t inst_idx = m_first_visible_line + i;
7148 const int line_y = m_min_y + i;
7149 window.MoveCursor(1, line_y);
7150 const bool is_pc_line = frame_sp && inst_idx == pc_idx;
7151 const bool line_is_selected = m_selected_line == inst_idx;
7154 attr_t highlight_attr = 0;
7157 highlight_attr = pc_highlight_attr;
7158 else if (line_is_selected)
7159 highlight_attr = selected_highlight_attr;
7162 bp_file_addrs.end())
7163 bp_attr = COLOR_PAIR(BlackOnWhite);
7166 window.AttributeOn(bp_attr);
7168 window.Printf(
" 0x%16.16llx ",
7169 static_cast<unsigned long long>(
7173 window.AttributeOff(bp_attr);
7175 window.PutChar(ACS_VLINE);
7178 window.PutChar(ACS_DIAMOND);
7180 window.PutChar(
' ');
7183 window.AttributeOn(highlight_attr);
7185 const char *mnemonic = inst->
GetMnemonic(&exe_ctx);
7186 const char *operands = inst->
GetOperands(&exe_ctx);
7187 const char *comment = inst->
GetComment(&exe_ctx);
7189 if (mnemonic !=
nullptr && mnemonic[0] ==
'\0')
7191 if (operands !=
nullptr && operands[0] ==
'\0')
7193 if (comment !=
nullptr && comment[0] ==
'\0')
7198 if (mnemonic !=
nullptr && operands !=
nullptr && comment !=
nullptr)
7199 strm.
Printf(
"%-8s %-25s ; %s", mnemonic, operands, comment);
7200 else if (mnemonic !=
nullptr && operands !=
nullptr)
7201 strm.
Printf(
"%-8s %s", mnemonic, operands);
7202 else if (mnemonic !=
nullptr)
7203 strm.
Printf(
"%s", mnemonic);
7206 window.PutCStringTruncated(
7208 strm.
GetString().substr(m_first_visible_column).data());
7210 if (is_pc_line && frame_sp &&
7211 frame_sp->GetConcreteFrameIndex() == 0) {
7216 const char *stop_description = stop_info_sp->GetDescription();
7217 if (stop_description && stop_description[0]) {
7218 size_t stop_description_len = strlen(stop_description);
7219 int desc_x = window_width - stop_description_len - 16;
7220 if (desc_x - window.GetCursorX() > 0)
7221 window.Printf(
"%*s", desc_x - window.GetCursorX(),
"");
7222 window.MoveCursor(window_width - stop_description_len - 15,
7225 window.PrintfTruncated(1,
"<<< Thread %u: %s ",
7230 window.Printf(
"%*s", window_width - window.GetCursorX() - 1,
"");
7234 window.AttributeOff(highlight_attr);
7241 size_t GetNumLines() {
7242 size_t num_lines = GetNumSourceLines();
7244 num_lines = GetNumDisassemblyLines();
7248 size_t GetNumSourceLines()
const {
7250 return m_file_sp->GetNumLines();
7254 size_t GetNumDisassemblyLines()
const {
7255 if (m_disassembly_sp)
7256 return m_disassembly_sp->GetInstructionList().GetSize();
7260 HandleCharResult WindowDelegateHandleChar(Window &window,
int c)
override {
7261 const uint32_t num_visible_lines = NumVisibleLines();
7262 const size_t num_lines = GetNumLines();
7268 if (
static_cast<uint32_t
>(m_first_visible_line) > num_visible_lines)
7269 m_first_visible_line -= num_visible_lines;
7271 m_first_visible_line = 0;
7272 m_selected_line = m_first_visible_line;
7279 if (m_first_visible_line + num_visible_lines < num_lines)
7280 m_first_visible_line += num_visible_lines;
7281 else if (num_lines < num_visible_lines)
7282 m_first_visible_line = 0;
7284 m_first_visible_line = num_lines - num_visible_lines;
7285 m_selected_line = m_first_visible_line;
7290 if (m_selected_line > 0) {
7292 if (
static_cast<size_t>(m_first_visible_line) > m_selected_line)
7293 m_first_visible_line = m_selected_line;
7298 if (m_selected_line + 1 < num_lines) {
7300 if (m_first_visible_line + num_visible_lines < m_selected_line)
7301 m_first_visible_line++;
7306 if (m_first_visible_column > 0)
7307 --m_first_visible_column;
7311 ++m_first_visible_column;
7318 if (GetNumSourceLines() > 0) {
7319 ExecutionContext exe_ctx =
7320 m_debugger.GetCommandInterpreter().GetExecutionContext();
7324 m_file_sp->GetSupportFile()->GetSpecOnly(),
7335 bp_sp->GetOptions().SetOneShot(
true);
7338 }
else if (m_selected_line < GetNumDisassemblyLines()) {
7339 const Instruction *inst = m_disassembly_sp->GetInstructionList()
7340 .GetInstructionAtIndex(m_selected_line)
7342 ExecutionContext exe_ctx =
7343 m_debugger.GetCommandInterpreter().GetExecutionContext();
7351 bp_sp->GetOptions().SetOneShot(
true);
7358 ToggleBreakpointOnSelectedLine();
7363 ExecutionContext exe_ctx =
7364 m_debugger.GetCommandInterpreter().GetExecutionContext();
7373 ExecutionContext exe_ctx =
7374 m_debugger.GetCommandInterpreter().GetExecutionContext();
7383 ExecutionContext exe_ctx =
7384 m_debugger.GetCommandInterpreter().GetExecutionContext();
7388 uint32_t frame_idx =
7398 ExecutionContext exe_ctx =
7399 m_debugger.GetCommandInterpreter().GetExecutionContext();
7402 bool source_step = (c ==
'n');
7411 ExecutionContext exe_ctx =
7412 m_debugger.GetCommandInterpreter().GetExecutionContext();
7415 bool source_step = (c ==
's');
7424 ExecutionContext exe_ctx =
7425 m_debugger.GetCommandInterpreter().GetExecutionContext();
7428 uint32_t frame_idx =
7434 else if (c ==
'd' && frame_idx > 0)
7443 window.CreateHelpSubwindow();
7449 return eKeyNotHandled;
7452 void ToggleBreakpointOnSelectedLine() {
7453 ExecutionContext exe_ctx =
7454 m_debugger.GetCommandInterpreter().GetExecutionContext();
7457 if (GetNumSourceLines() > 0) {
7460 const size_t num_bps = bp_list.
GetSize();
7461 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
7463 const size_t num_bps_locs = bp_sp->GetNumLocations();
7464 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs; ++bp_loc_idx) {
7466 bp_sp->GetLocationAtIndex(bp_loc_idx);
7467 LineEntry bp_loc_line_entry;
7468 if (bp_loc_sp->GetAddress().CalculateSymbolContextLineEntry(
7469 bp_loc_line_entry)) {
7470 if (m_file_sp->GetSupportFile()->GetSpecOnly() ==
7471 bp_loc_line_entry.
GetFile() &&
7472 m_selected_line + 1 == bp_loc_line_entry.
line) {
7485 m_file_sp->GetSupportFile()->GetSpecOnly(),
7497 assert(GetNumDisassemblyLines() > 0);
7498 assert(m_selected_line < GetNumDisassemblyLines());
7499 const Instruction *inst = m_disassembly_sp->GetInstructionList()
7500 .GetInstructionAtIndex(m_selected_line)
7505 const size_t num_bps = bp_list.
GetSize();
7506 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
7508 const size_t num_bps_locs = bp_sp->GetNumLocations();
7509 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs; ++bp_loc_idx) {
7511 bp_sp->GetLocationAtIndex(bp_loc_idx);
7512 LineEntry bp_loc_line_entry;
7514 bp_loc_sp->GetAddress().GetFileAddress();
7533 typedef std::set<uint32_t> BreakpointLines;
7534 typedef std::set<lldb::addr_t> BreakpointAddrs;
7536 Debugger &m_debugger;
7539 SymbolContextScope *m_disassembly_scope =
nullptr;
7541 StreamString m_title;
7543 int m_line_width = 4;
7544 uint32_t m_selected_line = 0;
7545 uint32_t m_pc_line = 0;
7546 uint32_t m_stop_id = 0;
7548 int m_first_visible_line = 0;
7549 int m_first_visible_column = 0;
7556DisplayOptions ValueObjectListDelegate::g_options = {
true};
7564 m_app_up = std::make_unique<Application>(
7569 std::shared_ptr<ApplicationDelegate> app_delegate_sp(
7572 MenuDelegateSP app_menu_delegate_sp =
7573 std::static_pointer_cast<MenuDelegate>(app_delegate_sp);
7574 MenuSP lldb_menu_sp(
7575 new Menu(
"LLDB",
"F1", KEY_F(1), ApplicationDelegate::eMenuID_LLDB));
7576 MenuSP exit_menuitem_sp(
7577 new Menu(
"Exit",
nullptr,
'x', ApplicationDelegate::eMenuID_LLDBExit));
7578 exit_menuitem_sp->SetCannedResult(MenuActionResult::Quit);
7579 lldb_menu_sp->AddSubmenu(std::make_shared<Menu>(
7580 "About LLDB",
nullptr,
'a', ApplicationDelegate::eMenuID_LLDBAbout));
7581 lldb_menu_sp->AddSubmenu(std::make_shared<Menu>(Menu::Type::Separator));
7582 lldb_menu_sp->AddSubmenu(exit_menuitem_sp);
7584 MenuSP target_menu_sp(
new Menu(
"Target",
"F2", KEY_F(2),
7585 ApplicationDelegate::eMenuID_Target));
7586 target_menu_sp->AddSubmenu(std::make_shared<Menu>(
7587 "Create",
nullptr,
'c', ApplicationDelegate::eMenuID_TargetCreate));
7588 target_menu_sp->AddSubmenu(std::make_shared<Menu>(
7589 "Delete",
nullptr,
'd', ApplicationDelegate::eMenuID_TargetDelete));
7591 MenuSP process_menu_sp(
new Menu(
"Process",
"F3", KEY_F(3),
7592 ApplicationDelegate::eMenuID_Process));
7593 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7594 "Attach",
nullptr,
'a', ApplicationDelegate::eMenuID_ProcessAttach));
7595 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7596 "Detach and resume",
nullptr,
'd',
7597 ApplicationDelegate::eMenuID_ProcessDetachResume));
7598 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7599 "Detach suspended",
nullptr,
's',
7600 ApplicationDelegate::eMenuID_ProcessDetachSuspended));
7601 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7602 "Launch",
nullptr,
'l', ApplicationDelegate::eMenuID_ProcessLaunch));
7603 process_menu_sp->AddSubmenu(std::make_shared<Menu>(Menu::Type::Separator));
7604 process_menu_sp->AddSubmenu(
7605 std::make_shared<Menu>(
"Continue",
nullptr,
'c',
7606 ApplicationDelegate::eMenuID_ProcessContinue));
7607 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7608 "Halt",
nullptr,
'h', ApplicationDelegate::eMenuID_ProcessHalt));
7609 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7610 "Kill",
nullptr,
'k', ApplicationDelegate::eMenuID_ProcessKill));
7612 MenuSP thread_menu_sp(
new Menu(
"Thread",
"F4", KEY_F(4),
7613 ApplicationDelegate::eMenuID_Thread));
7614 thread_menu_sp->AddSubmenu(std::make_shared<Menu>(
7615 "Step In",
nullptr,
'i', ApplicationDelegate::eMenuID_ThreadStepIn));
7616 thread_menu_sp->AddSubmenu(
7617 std::make_shared<Menu>(
"Step Over",
nullptr,
'v',
7618 ApplicationDelegate::eMenuID_ThreadStepOver));
7619 thread_menu_sp->AddSubmenu(std::make_shared<Menu>(
7620 "Step Out",
nullptr,
'o', ApplicationDelegate::eMenuID_ThreadStepOut));
7622 MenuSP view_menu_sp(
7623 new Menu(
"View",
"F5", KEY_F(5), ApplicationDelegate::eMenuID_View));
7624 view_menu_sp->AddSubmenu(std::make_shared<Menu>(
7625 "Backtrace",
nullptr,
't', ApplicationDelegate::eMenuID_ViewBacktrace));
7626 view_menu_sp->AddSubmenu(std::make_shared<Menu>(
7627 "Registers",
nullptr,
'r', ApplicationDelegate::eMenuID_ViewRegisters));
7628 view_menu_sp->AddSubmenu(std::make_shared<Menu>(
7629 "Source",
nullptr,
's', ApplicationDelegate::eMenuID_ViewSource));
7630 view_menu_sp->AddSubmenu(std::make_shared<Menu>(
7631 "Variables",
nullptr,
'v', ApplicationDelegate::eMenuID_ViewVariables));
7632 view_menu_sp->AddSubmenu(
7633 std::make_shared<Menu>(
"Breakpoints",
nullptr,
'b',
7634 ApplicationDelegate::eMenuID_ViewBreakpoints));
7636 MenuSP help_menu_sp(
7637 new Menu(
"Help",
"F6", KEY_F(6), ApplicationDelegate::eMenuID_Help));
7638 help_menu_sp->AddSubmenu(std::make_shared<Menu>(
7639 "GUI Help",
nullptr,
'g', ApplicationDelegate::eMenuID_HelpGUIHelp));
7642 WindowSP &main_window_sp =
m_app_up->GetMainWindow();
7644 MenuSP menubar_sp(
new Menu(Menu::Type::Bar));
7645 menubar_sp->AddSubmenu(lldb_menu_sp);
7646 menubar_sp->AddSubmenu(target_menu_sp);
7647 menubar_sp->AddSubmenu(process_menu_sp);
7648 menubar_sp->AddSubmenu(thread_menu_sp);
7649 menubar_sp->AddSubmenu(view_menu_sp);
7650 menubar_sp->AddSubmenu(help_menu_sp);
7651 menubar_sp->SetDelegate(app_menu_delegate_sp);
7653 Rect content_bounds = main_window_sp->GetFrame();
7654 Rect menubar_bounds = content_bounds.MakeMenuBar();
7655 Rect status_bounds = content_bounds.MakeStatusBar();
7657 Rect variables_bounds;
7658 Rect threads_bounds;
7659 Rect source_variables_bounds;
7660 content_bounds.VerticalSplitPercentage(0.80, source_variables_bounds,
7662 source_variables_bounds.HorizontalSplitPercentage(0.70, source_bounds,
7665 WindowSP menubar_window_sp =
7666 main_window_sp->CreateSubWindow(
"Menubar", menubar_bounds,
false);
7669 menubar_window_sp->SetCanBeActive(
7671 menubar_window_sp->SetDelegate(menubar_sp);
7673 WindowSP source_window_sp(
7674 main_window_sp->CreateSubWindow(
"Source", source_bounds,
true));
7675 WindowSP variables_window_sp(
7676 main_window_sp->CreateSubWindow(
"Variables", variables_bounds,
false));
7677 WindowSP threads_window_sp(
7678 main_window_sp->CreateSubWindow(
"Threads", threads_bounds,
false));
7679 WindowSP status_window_sp(
7680 main_window_sp->CreateSubWindow(
"Status", status_bounds,
false));
7681 status_window_sp->SetCanBeActive(
7683 main_window_sp->SetDelegate(
7684 std::static_pointer_cast<WindowDelegate>(app_delegate_sp));
7685 source_window_sp->SetDelegate(
7686 WindowDelegateSP(
new SourceFileWindowDelegate(
m_debugger)));
7687 variables_window_sp->SetDelegate(
7688 WindowDelegateSP(
new FrameVariablesWindowDelegate(
m_debugger)));
7689 TreeDelegateSP thread_delegate_sp(
new ThreadsTreeDelegate(
m_debugger));
7690 threads_window_sp->SetDelegate(WindowDelegateSP(
7691 new TreeWindowDelegate(
m_debugger, thread_delegate_sp)));
7692 status_window_sp->SetDelegate(
7693 WindowDelegateSP(
new StatusBarWindowDelegate(
m_debugger)));
7696 init_pair(1, COLOR_BLACK, COLOR_BLACK);
7697 init_pair(2, COLOR_RED, COLOR_BLACK);
7698 init_pair(3, COLOR_GREEN, COLOR_BLACK);
7699 init_pair(4, COLOR_YELLOW, COLOR_BLACK);
7700 init_pair(5, COLOR_BLUE, COLOR_BLACK);
7701 init_pair(6, COLOR_MAGENTA, COLOR_BLACK);
7702 init_pair(7, COLOR_CYAN, COLOR_BLACK);
7703 init_pair(8, COLOR_WHITE, COLOR_BLACK);
7705 init_pair(9, COLOR_BLACK, COLOR_BLUE);
7706 init_pair(10, COLOR_RED, COLOR_BLUE);
7707 init_pair(11, COLOR_GREEN, COLOR_BLUE);
7708 init_pair(12, COLOR_YELLOW, COLOR_BLUE);
7709 init_pair(13, COLOR_BLUE, COLOR_BLUE);
7710 init_pair(14, COLOR_MAGENTA, COLOR_BLUE);
7711 init_pair(15, COLOR_CYAN, COLOR_BLUE);
7712 init_pair(16, COLOR_WHITE, COLOR_BLUE);
7714 init_pair(17, COLOR_BLACK, COLOR_WHITE);
7715 init_pair(18, COLOR_MAGENTA, COLOR_WHITE);
7716 static_assert(LastColorPairIndex == 18,
"Color indexes do not match.");
7718 define_key(
"\033[Z", KEY_SHIFT_TAB);
7719 define_key(
"\033\015", KEY_ALT_ENTER);
7735 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, bool use_facade=true)
Get breakpoint locations by index.
virtual llvm::StringRef GetBroadcasterClass() const
This needs to be filled in if you are going to register the broadcaster with the broadcaster manager ...
static bool InvokeCommonCompletionCallbacks(CommandInterpreter &interpreter, uint32_t completion_mask, lldb_private::CompletionRequest &request, SearchFilter *searcher)
const FileSpec & GetPrimaryFile() const
Return the primary source spec associated with this compile unit.
void GetMatches(StringList &matches) const
Adds all collected completion matches to the given list.
const char * 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
virtual VariableList * GetVariableList(bool get_file_globals, Status *error_ptr)
Retrieve the list of variables whose scope either:
virtual lldb::RegisterContextSP GetRegisterContext()
Get the RegisterContext for this frame, if possible.
virtual StackID & GetStackID()
virtual lldb::ValueObjectSP GetValueObjectForFrameVariable(const lldb::VariableSP &variable_sp, lldb::DynamicValueType use_dynamic)
Create a ValueObject for a given Variable in this StackFrame.
virtual uint32_t GetFrameIndex() const
Query this frame to find what frame it is in this Thread's StackFrameList.
virtual Block * GetFrameBlock()
Get the current lexical scope block for this StackFrame, if possible.
virtual const Address & GetFrameCodeAddress()
Get an Address for the current pc value in this StackFrame.
bool Fail() const
Test for error condition.
const char * AsCString(const char *default_error_str="unknown error") const
Get the error string associated with the current error.
const char * GetData() const
llvm::StringRef GetString() const
void Format(const char *format, Args &&... args)
llvm::raw_ostream & AsRawOstream()
Returns a raw_ostream that forwards the data to this Stream object.
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
size_t size_t PrintfVarArg(const char *format, va_list args)
void AppendString(const std::string &s)
const char * GetStringAtIndex(size_t idx) const
Function * function
The Function for a given query.
lldb::ModuleSP module_sp
The Module for a given query.
CompileUnit * comp_unit
The CompileUnit for a given query.
Symbol * symbol
The Symbol for a given query.
LineEntry line_entry
The LineEntry for a given query.
ConstString GetName() const
BreakpointList & GetBreakpointList(bool internal=false)
const lldb::ProcessSP & GetProcessSP() const
bool RemoveBreakpointByID(lldb::break_id_t break_id)
Status Launch(ProcessLaunchInfo &launch_info, Stream *stream)
lldb::ModuleSP GetExecutableModule()
Gets the module for the main executable.
lldb::BreakpointSP CreateBreakpoint(const FileSpecList *containingModules, const FileSpec &file, uint32_t line_no, uint32_t column, lldb::addr_t offset, LazyBool check_inlines, LazyBool skip_prologue, bool internal, bool request_hardware, LazyBool move_to_nearest_code)
Status Attach(ProcessAttachInfo &attach_info, Stream *stream)
lldb::ThreadSP GetSelectedThread()
uint32_t GetSize(bool can_update=true)
bool SetSelectedThreadByID(lldb::tid_t tid, bool notify=false)
lldb::ThreadSP GetThreadAtIndex(uint32_t idx, bool can_update=true)
std::recursive_mutex & GetMutex() const override
virtual lldb::StackFrameSP GetStackFrameAtIndex(uint32_t idx)
uint32_t GetIndexID() const
lldb::StackFrameSP GetSelectedFrame(SelectMostRelevant select_most_relevant)
virtual Status StepOver(bool source_step, LazyBool step_out_avoids_code_without_debug_info=eLazyBoolCalculate)
Default implementation for stepping over.
uint32_t GetSelectedFrameIndex(SelectMostRelevant select_most_relevant)
lldb::ProcessSP GetProcess() const
virtual Status StepOut(uint32_t frame_idx=0)
Default implementation for stepping out.
bool SetSelectedFrameByIndex(uint32_t frame_idx, bool broadcast=false)
lldb::StopInfoSP GetStopInfo()
virtual uint32_t GetStackFrameCount()
GetStackFrameCount can be expensive.
virtual Status StepIn(bool source_step, LazyBool step_in_avoids_code_without_debug_info=eLazyBoolCalculate, LazyBool step_out_avoids_code_without_debug_info=eLazyBoolCalculate)
Default implementation for stepping into.
const std::vector< lldb::ValueObjectSP > & GetObjects() const
void Append(const lldb::ValueObjectSP &val_obj_sp)
static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope, lldb::RegisterContextSP ®_ctx_sp, uint32_t set_idx)
lldb::ProcessSP GetProcessSP() const
lldb::ValueObjectSP GetSP()
Gets the correct value object from the root object for a given process stop ID.
virtual ConstString GetTypeName()
virtual const char * GetValueAsCString()
ConstString GetName() const
const char * GetSummaryAsCString(lldb::LanguageType lang=lldb::eLanguageTypeUnknown)
#define LLDB_INVALID_THREAD_ID
#define UNUSED_IF_ASSERT_DISABLED(x)
@ SelectMostRelevantFrame
A class that represents a running process on the host machine.
bool operator!=(const Address &lhs, const Address &rhs)
bool StateIsStoppedState(lldb::StateType state, bool must_exist)
Check if a state represents a state where the process or thread is stopped.
bool StateIsRunningState(lldb::StateType state)
Check if a state represents a state where the process or thread is running.
const char * StateAsCString(lldb::StateType state)
Converts a StateType to a C string.
bool operator==(const Address &lhs, const Address &rhs)
std::shared_ptr< lldb_private::StackFrame > StackFrameSP
std::shared_ptr< lldb_private::BreakpointSite > BreakpointSiteSP
std::shared_ptr< lldb_private::BreakpointLocation > BreakpointLocationSP
std::shared_ptr< lldb_private::Thread > ThreadSP
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
Format
Display format definitions.
@ eFormatCString
NULL terminated C strings.
@ eFormatInstruction
Disassemble an opcode.
@ eFormatAddressInfo
Describe what an address points to (func + offset with file/line, symbol + offset,...
std::shared_ptr< lldb_private::Platform > PlatformSP
StateType
Process and Thread States.
@ eStateExited
Process has exited and can't be examined.
std::shared_ptr< lldb_private::Breakpoint > BreakpointSP
std::shared_ptr< lldb_private::Process > ProcessSP
std::shared_ptr< lldb_private::Disassembler > DisassemblerSP
std::shared_ptr< lldb_private::Event > EventSP
std::shared_ptr< lldb_private::Listener > ListenerSP
std::shared_ptr< lldb_private::Variable > VariableSP
std::shared_ptr< lldb_private::StopInfo > StopInfoSP
std::shared_ptr< lldb_private::Target > TargetSP
std::shared_ptr< lldb_private::RegisterContext > RegisterContextSP
std::shared_ptr< lldb_private::Module > ModuleSP
uint32_t line
The source line number, or LLDB_INVALID_LINE_NUMBER if there is no line number information.
bool DumpStopContext(Stream *s, bool show_fullpaths) const
Dumps information specific to a process that stops at this line entry to the supplied stream s.
const FileSpec & GetFile() const
Helper to access the file.
lldb::user_id_t GetID() const
Get accessor for the user ID.