11#include "lldb/Host/Config.h"
14#if CURSES_HAVE_NCURSES_CURSES_H
15#include <ncurses/curses.h>
16#include <ncurses/panel.h>
63#include "llvm/ADT/StringRef.h"
96#define KEY_SHIFT_TAB (KEY_MAX + 1)
97#define KEY_ALT_ENTER (KEY_MAX + 2)
105typedef std::shared_ptr<Menu> MenuSP;
106typedef std::shared_ptr<MenuDelegate> MenuDelegateSP;
107typedef std::shared_ptr<Window> WindowSP;
108typedef std::shared_ptr<WindowDelegate> WindowDelegateSP;
109typedef std::vector<MenuSP> Menus;
110typedef std::vector<WindowSP> Windows;
111typedef std::vector<WindowDelegateSP> WindowDelegates;
114type summary add -s
"x=${var.x}, y=${var.y}" curses::Point
115type summary add -s
"w=${var.width}, h=${var.height}" curses::Size
116type summary add -s
"${var.origin%S} ${var.size%S}" curses::Rect
123 Point(
int _x = 0,
int _y = 0) : x(_x), y(_y) {}
130 Point &operator+=(
const Point &rhs) {
136 void Dump() { printf(
"(x=%i, y=%i)\n", x, y); }
139bool operator==(
const Point &lhs,
const Point &rhs) {
140 return lhs.x == rhs.x && lhs.y == rhs.y;
143bool operator!=(
const Point &lhs,
const Point &rhs) {
144 return lhs.x != rhs.x || lhs.y != rhs.y;
150 Size(
int w = 0,
int h = 0) : width(w), height(h) {}
157 void Dump() { printf(
"(w=%i, h=%i)\n", width, height); }
160bool operator==(
const Size &lhs,
const Size &rhs) {
161 return lhs.width == rhs.width && lhs.height == rhs.height;
164bool operator!=(
const Size &lhs,
const Size &rhs) {
165 return lhs.width != rhs.width || lhs.height != rhs.height;
172 Rect() : origin(), size() {}
174 Rect(
const Point &p,
const Size &s) : origin(p), size(s) {}
182 printf(
"(x=%i, y=%i), w=%i, h=%i)\n", origin.x, origin.y, size.width,
186 void Inset(
int w,
int h) {
187 if (size.width > w * 2)
191 if (size.height > h * 2)
192 size.height -= h * 2;
198 Rect MakeStatusBar() {
200 if (size.height > 1) {
201 status_bar.origin.x = origin.x;
202 status_bar.origin.y = size.height;
203 status_bar.size.width = size.width;
204 status_bar.size.height = 1;
214 if (size.height > 1) {
215 menubar.origin.x = origin.x;
216 menubar.origin.y = origin.y;
217 menubar.size.width = size.width;
218 menubar.size.height = 1;
225 void HorizontalSplitPercentage(
float top_percentage, Rect &top,
226 Rect &bottom)
const {
227 float top_height = top_percentage * size.height;
228 HorizontalSplit(top_height, top, bottom);
231 void HorizontalSplit(
int top_height, Rect &top, Rect &bottom)
const {
233 if (top_height < size.height) {
234 top.size.height = top_height;
235 bottom.origin.x = origin.x;
236 bottom.origin.y = origin.y + top.size.height;
237 bottom.size.width = size.width;
238 bottom.size.height = size.height - top.size.height;
244 void VerticalSplitPercentage(
float left_percentage, Rect &left,
246 float left_width = left_percentage * size.width;
247 VerticalSplit(left_width, left, right);
250 void VerticalSplit(
int left_width, Rect &left, Rect &right)
const {
252 if (left_width < size.width) {
253 left.size.width = left_width;
254 right.origin.x = origin.x + left.size.width;
255 right.origin.y = origin.y;
256 right.size.width = size.width - left.size.width;
257 right.size.height = size.height;
264bool operator==(
const Rect &lhs,
const Rect &rhs) {
265 return lhs.origin == rhs.origin && lhs.size == rhs.size;
268bool operator!=(
const Rect &lhs,
const Rect &rhs) {
269 return lhs.origin != rhs.origin || lhs.size != rhs.size;
272enum HandleCharResult {
278enum class MenuActionResult {
286 const char *description;
312 LastColorPairIndex = MagentaOnWhite
315class WindowDelegate {
317 virtual ~WindowDelegate() =
default;
319 virtual bool WindowDelegateDraw(Window &window,
bool force) {
323 virtual HandleCharResult WindowDelegateHandleChar(Window &window,
int key) {
324 return eKeyNotHandled;
327 virtual const char *WindowDelegateGetHelpText() {
return nullptr; }
329 virtual KeyHelp *WindowDelegateGetKeyHelp() {
return nullptr; }
332class HelpDialogDelegate :
public WindowDelegate {
334 HelpDialogDelegate(
const char *text, KeyHelp *key_help_array);
336 ~HelpDialogDelegate()
override;
338 bool WindowDelegateDraw(Window &window,
bool force)
override;
340 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override;
342 size_t GetNumLines()
const {
return m_text.GetSize(); }
344 size_t GetMaxLineLength()
const {
return m_text.GetMaxStringLength(); }
348 int m_first_visible_line = 0;
357 enum class Type { Window, Pad };
359 Surface(Surface::Type type) : m_type(type) {}
361 WINDOW *get() {
return m_window; }
363 operator WINDOW *() {
return m_window; }
365 Surface SubSurface(Rect bounds) {
366 Surface subSurface(m_type);
367 if (m_type == Type::Pad)
368 subSurface.m_window =
369 ::subpad(m_window, bounds.size.height, bounds.size.width,
370 bounds.origin.y, bounds.origin.x);
372 subSurface.m_window =
373 ::derwin(m_window, bounds.size.height, bounds.size.width,
374 bounds.origin.y, bounds.origin.x);
379 void CopyToSurface(Surface &target, Point source_origin, Point target_origin,
381 ::copywin(m_window, target.get(), source_origin.y, source_origin.x,
382 target_origin.y, target_origin.x,
383 target_origin.y + size.height - 1,
384 target_origin.x + size.width - 1,
false);
387 int GetCursorX()
const {
return getcurx(m_window); }
388 int GetCursorY()
const {
return getcury(m_window); }
389 void MoveCursor(
int x,
int y) { ::wmove(m_window, y, x); }
391 void AttributeOn(attr_t attr) { ::wattron(m_window, attr); }
392 void AttributeOff(attr_t attr) { ::wattroff(m_window, attr); }
394 int GetMaxX()
const {
return getmaxx(m_window); }
395 int GetMaxY()
const {
return getmaxy(m_window); }
396 int GetWidth()
const {
return GetMaxX(); }
397 int GetHeight()
const {
return GetMaxY(); }
398 Size GetSize()
const {
return Size(GetWidth(), GetHeight()); }
400 Rect GetFrame()
const {
return Rect(Point(), GetSize()); }
402 void Clear() { ::wclear(m_window); }
403 void Erase() { ::werase(m_window); }
405 void SetBackground(
int color_pair_idx) {
406 ::wbkgd(m_window, COLOR_PAIR(color_pair_idx));
409 void PutChar(
int ch) { ::waddch(m_window, ch); }
410 void PutCString(
const char *s,
int len = -1) { ::waddnstr(m_window, s, len); }
412 void PutCStringTruncated(
int right_pad,
const char *s,
int len = -1) {
413 int bytes_left = GetWidth() - GetCursorX();
414 if (bytes_left > right_pad) {
415 bytes_left -= right_pad;
416 ::waddnstr(m_window, s, len < 0 ? bytes_left : std::min(bytes_left, len));
420 void Printf(
const char *format, ...) __attribute__((format(printf, 2, 3))) {
422 va_start(args, format);
423 vw_printw(m_window, format, args);
427 void PrintfTruncated(
int right_pad,
const char *format, ...)
428 __attribute__((format(printf, 3, 4))) {
430 va_start(args, format);
434 PutCStringTruncated(right_pad, strm.
GetData());
437 void VerticalLine(
int n, chtype v_char = ACS_VLINE) {
438 ::wvline(m_window, v_char, n);
440 void HorizontalLine(
int n, chtype h_char = ACS_HLINE) {
441 ::whline(m_window, h_char, n);
443 void Box(chtype v_char = ACS_VLINE, chtype h_char = ACS_HLINE) {
444 ::box(m_window, v_char, h_char);
447 void TitledBox(
const char *title, chtype v_char = ACS_VLINE,
448 chtype h_char = ACS_HLINE) {
450 int title_offset = 2;
451 MoveCursor(title_offset, 0);
453 PutCString(title, GetWidth() - title_offset);
457 void Box(
const Rect &bounds, chtype v_char = ACS_VLINE,
458 chtype h_char = ACS_HLINE) {
459 MoveCursor(bounds.origin.x, bounds.origin.y);
460 VerticalLine(bounds.size.height);
461 HorizontalLine(bounds.size.width);
462 PutChar(ACS_ULCORNER);
464 MoveCursor(bounds.origin.x + bounds.size.width - 1, bounds.origin.y);
465 VerticalLine(bounds.size.height);
466 PutChar(ACS_URCORNER);
468 MoveCursor(bounds.origin.x, bounds.origin.y + bounds.size.height - 1);
469 HorizontalLine(bounds.size.width);
470 PutChar(ACS_LLCORNER);
472 MoveCursor(bounds.origin.x + bounds.size.width - 1,
473 bounds.origin.y + bounds.size.height - 1);
474 PutChar(ACS_LRCORNER);
477 void TitledBox(
const Rect &bounds,
const char *title,
478 chtype v_char = ACS_VLINE, chtype h_char = ACS_HLINE) {
479 Box(bounds, v_char, h_char);
480 int title_offset = 2;
481 MoveCursor(bounds.origin.x + title_offset, bounds.origin.y);
483 PutCString(title, bounds.size.width - title_offset);
492 bool OutputColoredStringTruncated(
int right_pad, StringRef
string,
493 size_t skip_first_count,
494 bool use_blue_background) {
498 wattr_get(m_window, &saved_attr, &saved_pair,
nullptr);
499 if (use_blue_background)
500 ::wattron(m_window, COLOR_PAIR(WhiteOnBlue));
501 while (!
string.empty()) {
503 if (esc_pos == StringRef::npos) {
504 string =
string.substr(skip_first_count);
505 if (!
string.empty()) {
506 PutCStringTruncated(right_pad,
string.data(),
string.size());
512 if (skip_first_count > 0) {
513 int skip = std::min(esc_pos, skip_first_count);
514 string =
string.substr(
skip);
515 skip_first_count -=
skip;
519 PutCStringTruncated(right_pad,
string.data(), esc_pos);
521 string =
string.drop_front(esc_pos);
533 if (!!
string.consumeInteger(10, value) ||
536 llvm::errs() <<
"No valid color code in color escape sequence.\n";
541 <<
"' in color escape sequence.\n";
545 wattr_set(m_window, saved_attr, saved_pair,
nullptr);
546 if (use_blue_background)
547 ::wattron(m_window, COLOR_PAIR(WhiteOnBlue));
549 ::wattron(m_window, A_UNDERLINE);
553 (use_blue_background ? 8 : 0)));
556 wattr_set(m_window, saved_attr, saved_pair,
nullptr);
562 WINDOW *m_window =
nullptr;
565class Pad :
public Surface {
567 Pad(Size size) : Surface(Surface::
Type::Pad) {
568 m_window = ::newpad(size.height, size.width);
571 ~Pad() { ::delwin(m_window); }
574class Window :
public Surface {
576 Window(
const char *name)
577 : Surface(Surface::
Type::Window), m_name(name), m_panel(nullptr),
578 m_parent(nullptr), m_subwindows(), m_delegate_sp(),
580 m_prev_active_window_idx(
UINT32_MAX), m_delete(false),
581 m_needs_update(true), m_can_activate(true), m_is_subwin(false) {}
583 Window(
const char *name, WINDOW *w,
bool del =
true)
584 : Surface(Surface::
Type::Window), m_name(name), m_panel(nullptr),
585 m_parent(nullptr), m_subwindows(), m_delegate_sp(),
587 m_prev_active_window_idx(
UINT32_MAX), m_delete(del),
588 m_needs_update(true), m_can_activate(true), m_is_subwin(false) {
593 Window(
const char *name,
const Rect &bounds)
594 : Surface(Surface::
Type::Window), m_name(name), m_panel(nullptr),
595 m_parent(nullptr), m_subwindows(), m_delegate_sp(),
597 m_prev_active_window_idx(
UINT32_MAX), m_delete(false),
598 m_needs_update(true), m_can_activate(true), m_is_subwin(false) {
599 Reset(::newwin(bounds.size.height, bounds.size.width, bounds.origin.y,
608 void Reset(WINDOW *w =
nullptr,
bool del =
true) {
613 ::del_panel(m_panel);
616 if (m_window && m_delete) {
623 m_panel = ::new_panel(m_window);
629 Rect GetBounds()
const {
return Rect(GetParentOrigin(), GetSize()); }
631 Rect GetCenteredRect(
int width,
int height) {
632 Size size = GetSize();
633 width = std::min(size.width, width);
634 height = std::min(size.height, height);
635 int x = (size.width - width) / 2;
636 int y = (size.height - height) / 2;
637 return Rect(Point(x, y), Size(width, height));
640 int GetChar() { return ::wgetch(m_window); }
641 Point GetParentOrigin()
const {
return Point(GetParentX(), GetParentY()); }
642 int GetParentX()
const {
return getparx(m_window); }
643 int GetParentY()
const {
return getpary(m_window); }
644 void MoveWindow(
int x,
int y) { MoveWindow(Point(x, y)); }
645 void Resize(
int w,
int h) { ::wresize(m_window, h, w); }
646 void Resize(
const Size &size) {
647 ::wresize(m_window, size.height, size.width);
649 void MoveWindow(
const Point &origin) {
650 const bool moving_window = origin != GetParentOrigin();
651 if (m_is_subwin && moving_window) {
653 Size size = GetSize();
654 Reset(::subwin(m_parent->m_window, size.height, size.width, origin.y,
658 ::mvwin(m_window, origin.y, origin.x);
662 void SetBounds(
const Rect &bounds) {
663 const bool moving_window = bounds.origin != GetParentOrigin();
664 if (m_is_subwin && moving_window) {
666 Reset(::subwin(m_parent->m_window, bounds.size.height, bounds.size.width,
667 bounds.origin.y, bounds.origin.x),
671 MoveWindow(bounds.origin);
677 ::touchwin(m_window);
682 WindowSP CreateSubWindow(
const char *name,
const Rect &bounds,
684 auto get_window = [
this, &bounds]() {
686 ? ::subwin(m_window, bounds.size.height, bounds.size.width,
687 bounds.origin.y, bounds.origin.x)
688 : ::newwin(bounds.size.height, bounds.size.width,
689 bounds.origin.y, bounds.origin.x);
691 WindowSP subwindow_sp = std::make_shared<Window>(name, get_window(),
true);
692 subwindow_sp->m_is_subwin = subwindow_sp.operator bool();
693 subwindow_sp->m_parent =
this;
695 m_prev_active_window_idx = m_curr_active_window_idx;
696 m_curr_active_window_idx = m_subwindows.size();
698 m_subwindows.push_back(subwindow_sp);
699 ::top_panel(subwindow_sp->m_panel);
700 m_needs_update =
true;
704 bool RemoveSubWindow(Window *window) {
705 Windows::iterator pos, end = m_subwindows.end();
707 for (pos = m_subwindows.begin(); pos != end; ++pos, ++i) {
708 if ((*pos).get() == window) {
709 if (m_prev_active_window_idx == i)
711 else if (m_prev_active_window_idx !=
UINT32_MAX &&
712 m_prev_active_window_idx > i)
713 --m_prev_active_window_idx;
715 if (m_curr_active_window_idx == i)
717 else if (m_curr_active_window_idx !=
UINT32_MAX &&
718 m_curr_active_window_idx > i)
719 --m_curr_active_window_idx;
721 m_subwindows.erase(pos);
722 m_needs_update =
true;
733 WindowSP FindSubWindow(
const char *name) {
734 Windows::iterator pos, end = m_subwindows.end();
736 for (pos = m_subwindows.begin(); pos != end; ++pos, ++i) {
737 if ((*pos)->m_name == name)
743 void RemoveSubWindows() {
746 for (Windows::iterator pos = m_subwindows.begin();
747 pos != m_subwindows.end(); pos = m_subwindows.erase(pos)) {
757 void DrawTitleBox(
const char *title,
const char *bottom_message =
nullptr) {
760 attr = A_BOLD | COLOR_PAIR(BlackOnWhite);
769 if (title && title[0]) {
775 if (bottom_message && bottom_message[0]) {
776 int bottom_message_length = strlen(bottom_message);
777 int x = GetWidth() - 3 - (bottom_message_length + 2);
780 MoveCursor(x, GetHeight() - 1);
782 PutCString(bottom_message);
785 MoveCursor(1, GetHeight() - 1);
787 PutCStringTruncated(1, bottom_message);
794 virtual void Draw(
bool force) {
795 if (m_delegate_sp && m_delegate_sp->WindowDelegateDraw(*
this, force))
798 for (
auto &subwindow_sp : m_subwindows)
799 subwindow_sp->Draw(force);
802 bool CreateHelpSubwindow() {
804 const char *text = m_delegate_sp->WindowDelegateGetHelpText();
805 KeyHelp *key_help = m_delegate_sp->WindowDelegateGetKeyHelp();
806 if ((text && text[0]) || key_help) {
807 std::unique_ptr<HelpDialogDelegate> help_delegate_up(
808 new HelpDialogDelegate(text, key_help));
809 const size_t num_lines = help_delegate_up->GetNumLines();
810 const size_t max_length = help_delegate_up->GetMaxLineLength();
811 Rect bounds = GetBounds();
813 if (max_length + 4 <
static_cast<size_t>(bounds.size.width)) {
814 bounds.origin.x += (bounds.size.width - max_length + 4) / 2;
815 bounds.size.width = max_length + 4;
817 if (bounds.size.width > 100) {
818 const int inset_w = bounds.size.width / 4;
819 bounds.origin.x += inset_w;
820 bounds.size.width -= 2 * inset_w;
824 if (num_lines + 2 <
static_cast<size_t>(bounds.size.height)) {
825 bounds.origin.y += (bounds.size.height - num_lines + 2) / 2;
826 bounds.size.height = num_lines + 2;
828 if (bounds.size.height > 100) {
829 const int inset_h = bounds.size.height / 4;
830 bounds.origin.y += inset_h;
831 bounds.size.height -= 2 * inset_h;
834 WindowSP help_window_sp;
835 Window *parent_window = GetParent();
837 help_window_sp = parent_window->CreateSubWindow(
"Help", bounds,
true);
839 help_window_sp = CreateSubWindow(
"Help", bounds,
true);
840 help_window_sp->SetDelegate(
841 WindowDelegateSP(help_delegate_up.release()));
848 virtual HandleCharResult HandleChar(
int key) {
850 HandleCharResult result = eKeyNotHandled;
851 WindowSP active_window_sp = GetActiveWindow();
852 if (active_window_sp) {
853 result = active_window_sp->HandleChar(key);
854 if (result != eKeyNotHandled)
859 result = m_delegate_sp->WindowDelegateHandleChar(*
this, key);
860 if (result != eKeyNotHandled)
868 Windows subwindows(m_subwindows);
869 for (
auto subwindow_sp : subwindows) {
870 if (!subwindow_sp->m_can_activate) {
871 HandleCharResult result = subwindow_sp->HandleChar(key);
872 if (result != eKeyNotHandled)
877 return eKeyNotHandled;
880 WindowSP GetActiveWindow() {
881 if (!m_subwindows.empty()) {
882 if (m_curr_active_window_idx >= m_subwindows.size()) {
883 if (m_prev_active_window_idx < m_subwindows.size()) {
884 m_curr_active_window_idx = m_prev_active_window_idx;
886 }
else if (IsActive()) {
891 const size_t num_subwindows = m_subwindows.size();
892 for (
size_t i = 0; i < num_subwindows; ++i) {
893 if (m_subwindows[i]->GetCanBeActive()) {
894 m_curr_active_window_idx = i;
901 if (m_curr_active_window_idx < m_subwindows.size())
902 return m_subwindows[m_curr_active_window_idx];
907 bool GetCanBeActive()
const {
return m_can_activate; }
909 void SetCanBeActive(
bool b) { m_can_activate = b; }
911 void SetDelegate(
const WindowDelegateSP &delegate_sp) {
912 m_delegate_sp = delegate_sp;
915 Window *GetParent()
const {
return m_parent; }
917 bool IsActive()
const {
919 return m_parent->GetActiveWindow().get() ==
this;
924 void SelectNextWindowAsActive() {
926 const int num_subwindows = m_subwindows.size();
929 m_prev_active_window_idx = m_curr_active_window_idx;
930 start_idx = m_curr_active_window_idx + 1;
932 for (
int idx = start_idx; idx < num_subwindows; ++idx) {
933 if (m_subwindows[idx]->GetCanBeActive()) {
934 m_curr_active_window_idx = idx;
938 for (
int idx = 0; idx < start_idx; ++idx) {
939 if (m_subwindows[idx]->GetCanBeActive()) {
940 m_curr_active_window_idx = idx;
946 void SelectPreviousWindowAsActive() {
948 const int num_subwindows = m_subwindows.size();
949 int start_idx = num_subwindows - 1;
951 m_prev_active_window_idx = m_curr_active_window_idx;
952 start_idx = m_curr_active_window_idx - 1;
954 for (
int idx = start_idx; idx >= 0; --idx) {
955 if (m_subwindows[idx]->GetCanBeActive()) {
956 m_curr_active_window_idx = idx;
960 for (
int idx = num_subwindows - 1; idx > start_idx; --idx) {
961 if (m_subwindows[idx]->GetCanBeActive()) {
962 m_curr_active_window_idx = idx;
968 const char *
GetName()
const {
return m_name.c_str(); }
974 Windows m_subwindows;
975 WindowDelegateSP m_delegate_sp;
976 uint32_t m_curr_active_window_idx;
977 uint32_t m_prev_active_window_idx;
984 Window(
const Window &) =
delete;
985 const Window &operator=(
const Window &) =
delete;
996struct ScrollContext {
1000 ScrollContext(
int line) : start(line), end(line) {}
1001 ScrollContext(
int _start,
int _end) : start(_start), end(_end) {}
1003 void Offset(
int offset) {
1009class FieldDelegate {
1011 virtual ~FieldDelegate() =
default;
1015 virtual int FieldDelegateGetHeight() = 0;
1022 virtual ScrollContext FieldDelegateGetScrollContext() {
1023 return ScrollContext(0, FieldDelegateGetHeight() - 1);
1029 virtual void FieldDelegateDraw(Surface &surface,
bool is_selected) = 0;
1032 virtual HandleCharResult FieldDelegateHandleChar(
int key) {
1033 return eKeyNotHandled;
1040 virtual void FieldDelegateExitCallback() {}
1054 virtual bool FieldDelegateOnFirstOrOnlyElement() {
return true; }
1058 virtual bool FieldDelegateOnLastOrOnlyElement() {
return true; }
1061 virtual void FieldDelegateSelectFirstElement() {}
1064 virtual void FieldDelegateSelectLastElement() {}
1067 virtual bool FieldDelegateHasError() {
return false; }
1069 bool FieldDelegateIsVisible() {
return m_is_visible; }
1071 void FieldDelegateHide() { m_is_visible =
false; }
1073 void FieldDelegateShow() { m_is_visible =
true; }
1076 bool m_is_visible =
true;
1079typedef std::unique_ptr<FieldDelegate> FieldDelegateUP;
1081class TextFieldDelegate :
public FieldDelegate {
1083 TextFieldDelegate(
const char *label,
const char *content,
bool required)
1084 : m_label(label), m_required(required) {
1086 m_content = content;
1099 int GetFieldHeight() {
return 3; }
1103 int FieldDelegateGetHeight()
override {
1104 int height = GetFieldHeight();
1105 if (FieldDelegateHasError())
1111 int GetCursorXPosition() {
return m_cursor_position - m_first_visibile_char; }
1113 int GetContentLength() {
return m_content.length(); }
1115 void DrawContent(Surface &surface,
bool is_selected) {
1116 UpdateScrolling(surface.GetWidth());
1118 surface.MoveCursor(0, 0);
1119 const char *text = m_content.c_str() + m_first_visibile_char;
1120 surface.PutCString(text, surface.GetWidth());
1123 surface.MoveCursor(GetCursorXPosition(), 0);
1125 surface.AttributeOn(A_REVERSE);
1126 if (m_cursor_position == GetContentLength())
1128 surface.PutChar(
' ');
1130 surface.PutChar(m_content[m_cursor_position]);
1132 surface.AttributeOff(A_REVERSE);
1135 void DrawField(Surface &surface,
bool is_selected) {
1136 surface.TitledBox(m_label.c_str());
1138 Rect content_bounds = surface.GetFrame();
1139 content_bounds.Inset(1, 1);
1140 Surface content_surface = surface.SubSurface(content_bounds);
1142 DrawContent(content_surface, is_selected);
1145 void DrawError(Surface &surface) {
1146 if (!FieldDelegateHasError())
1148 surface.MoveCursor(0, 0);
1149 surface.AttributeOn(COLOR_PAIR(RedOnBlack));
1150 surface.PutChar(ACS_DIAMOND);
1151 surface.PutChar(
' ');
1152 surface.PutCStringTruncated(1, GetError().c_str());
1153 surface.AttributeOff(COLOR_PAIR(RedOnBlack));
1156 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
1157 Rect frame = surface.GetFrame();
1158 Rect field_bounds, error_bounds;
1159 frame.HorizontalSplit(GetFieldHeight(), field_bounds, error_bounds);
1160 Surface field_surface = surface.SubSurface(field_bounds);
1161 Surface error_surface = surface.SubSurface(error_bounds);
1163 DrawField(field_surface, is_selected);
1164 DrawError(error_surface);
1168 int GetLastVisibleCharPosition(
int width) {
1169 int position = m_first_visibile_char + width - 1;
1170 return std::min(position, GetContentLength());
1173 void UpdateScrolling(
int width) {
1174 if (m_cursor_position < m_first_visibile_char) {
1175 m_first_visibile_char = m_cursor_position;
1179 if (m_cursor_position > GetLastVisibleCharPosition(width))
1180 m_first_visibile_char = m_cursor_position - (width - 1);
1185 void MoveCursorRight() {
1186 if (m_cursor_position < GetContentLength())
1187 m_cursor_position++;
1190 void MoveCursorLeft() {
1191 if (m_cursor_position > 0)
1192 m_cursor_position--;
1195 void MoveCursorToStart() { m_cursor_position = 0; }
1197 void MoveCursorToEnd() { m_cursor_position = GetContentLength(); }
1200 if (m_first_visibile_char > 0)
1201 m_first_visibile_char--;
1206 void InsertChar(
char character) {
1207 m_content.insert(m_cursor_position, 1, character);
1208 m_cursor_position++;
1214 void RemovePreviousChar() {
1215 if (m_cursor_position == 0)
1218 m_content.erase(m_cursor_position - 1, 1);
1219 m_cursor_position--;
1225 void RemoveNextChar() {
1226 if (m_cursor_position == GetContentLength())
1229 m_content.erase(m_cursor_position, 1);
1235 m_content.erase(m_cursor_position);
1241 m_cursor_position = 0;
1247 virtual bool IsAcceptableChar(
int key) {
1252 return isprint(key);
1255 HandleCharResult FieldDelegateHandleChar(
int key)
override {
1256 if (IsAcceptableChar(key)) {
1258 InsertChar((
char)key);
1265 MoveCursorToStart();
1281 RemovePreviousChar();
1297 return eKeyNotHandled;
1300 bool FieldDelegateHasError()
override {
return !m_error.empty(); }
1302 void FieldDelegateExitCallback()
override {
1303 if (!IsSpecified() && m_required)
1304 SetError(
"This field is required!");
1307 bool IsSpecified() {
return !m_content.empty(); }
1309 void ClearError() { m_error.clear(); }
1311 const std::string &GetError() {
return m_error; }
1313 void SetError(
const char *
error) { m_error =
error; }
1315 const std::string &GetText() {
return m_content; }
1317 void SetText(
const char *text) {
1318 if (text ==
nullptr) {
1326 std::string m_label;
1329 std::string m_content;
1332 int m_cursor_position = 0;
1334 int m_first_visibile_char = 0;
1336 std::string m_error;
1339class IntegerFieldDelegate :
public TextFieldDelegate {
1341 IntegerFieldDelegate(
const char *label,
int content,
bool required)
1342 : TextFieldDelegate(label, std::to_string(content).c_str(), required) {}
1345 bool IsAcceptableChar(
int key)
override {
return isdigit(key); }
1348 int GetInteger() {
return std::stoi(m_content); }
1351class FileFieldDelegate :
public TextFieldDelegate {
1353 FileFieldDelegate(
const char *label,
const char *content,
bool need_to_exist,
1355 : TextFieldDelegate(label, content, required),
1356 m_need_to_exist(need_to_exist) {}
1358 void FieldDelegateExitCallback()
override {
1359 TextFieldDelegate::FieldDelegateExitCallback();
1363 if (!m_need_to_exist)
1366 FileSpec file = GetResolvedFileSpec();
1368 SetError(
"File doesn't exist!");
1372 SetError(
"Not a file!");
1377 FileSpec GetFileSpec() {
1378 FileSpec file_spec(GetPath());
1382 FileSpec GetResolvedFileSpec() {
1383 FileSpec file_spec(GetPath());
1388 const std::string &GetPath() {
return m_content; }
1391 bool m_need_to_exist;
1394class DirectoryFieldDelegate :
public TextFieldDelegate {
1396 DirectoryFieldDelegate(
const char *label,
const char *content,
1397 bool need_to_exist,
bool required)
1398 : TextFieldDelegate(label, content, required),
1399 m_need_to_exist(need_to_exist) {}
1401 void FieldDelegateExitCallback()
override {
1402 TextFieldDelegate::FieldDelegateExitCallback();
1406 if (!m_need_to_exist)
1409 FileSpec file = GetResolvedFileSpec();
1411 SetError(
"Directory doesn't exist!");
1415 SetError(
"Not a directory!");
1420 FileSpec GetFileSpec() {
1421 FileSpec file_spec(GetPath());
1425 FileSpec GetResolvedFileSpec() {
1426 FileSpec file_spec(GetPath());
1431 const std::string &GetPath() {
return m_content; }
1434 bool m_need_to_exist;
1437class ArchFieldDelegate :
public TextFieldDelegate {
1439 ArchFieldDelegate(
const char *label,
const char *content,
bool required)
1440 : TextFieldDelegate(label, content, required) {}
1442 void FieldDelegateExitCallback()
override {
1443 TextFieldDelegate::FieldDelegateExitCallback();
1447 if (!GetArchSpec().IsValid())
1448 SetError(
"Not a valid arch!");
1451 const std::string &GetArchString() {
return m_content; }
1453 ArchSpec GetArchSpec() {
return ArchSpec(GetArchString()); }
1456class BooleanFieldDelegate :
public FieldDelegate {
1458 BooleanFieldDelegate(
const char *label,
bool content)
1459 : m_label(label), m_content(content) {}
1466 int FieldDelegateGetHeight()
override {
return 1; }
1468 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
1469 surface.MoveCursor(0, 0);
1470 surface.PutChar(
'[');
1472 surface.AttributeOn(A_REVERSE);
1473 surface.PutChar(m_content ? ACS_DIAMOND :
' ');
1475 surface.AttributeOff(A_REVERSE);
1476 surface.PutChar(
']');
1477 surface.PutChar(
' ');
1478 surface.PutCString(m_label.c_str());
1481 void ToggleContent() { m_content = !m_content; }
1483 void SetContentToTrue() { m_content =
true; }
1485 void SetContentToFalse() { m_content =
false; }
1487 HandleCharResult FieldDelegateHandleChar(
int key)
override {
1495 SetContentToFalse();
1506 return eKeyNotHandled;
1510 bool GetBoolean() {
return m_content; }
1513 std::string m_label;
1517class ChoicesFieldDelegate :
public FieldDelegate {
1519 ChoicesFieldDelegate(
const char *label,
int number_of_visible_choices,
1520 std::vector<std::string> choices)
1521 : m_label(label), m_number_of_visible_choices(number_of_visible_choices),
1522 m_choices(choices) {}
1536 int FieldDelegateGetHeight()
override {
1537 return m_number_of_visible_choices + 2;
1540 int GetNumberOfChoices() {
return m_choices.size(); }
1543 int GetLastVisibleChoice() {
1544 int index = m_first_visibile_choice + m_number_of_visible_choices;
1545 return std::min(index, GetNumberOfChoices()) - 1;
1548 void DrawContent(Surface &surface,
bool is_selected) {
1549 int choices_to_draw = GetLastVisibleChoice() - m_first_visibile_choice + 1;
1550 for (
int i = 0; i < choices_to_draw; i++) {
1551 surface.MoveCursor(0, i);
1552 int current_choice = m_first_visibile_choice + i;
1553 const char *text = m_choices[current_choice].c_str();
1554 bool highlight = is_selected && current_choice == m_choice;
1556 surface.AttributeOn(A_REVERSE);
1557 surface.PutChar(current_choice == m_choice ? ACS_DIAMOND :
' ');
1558 surface.PutCString(text);
1560 surface.AttributeOff(A_REVERSE);
1564 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
1567 surface.TitledBox(m_label.c_str());
1569 Rect content_bounds = surface.GetFrame();
1570 content_bounds.Inset(1, 1);
1571 Surface content_surface = surface.SubSurface(content_bounds);
1573 DrawContent(content_surface, is_selected);
1576 void SelectPrevious() {
1582 if (m_choice < GetNumberOfChoices() - 1)
1586 void UpdateScrolling() {
1587 if (m_choice > GetLastVisibleChoice()) {
1588 m_first_visibile_choice = m_choice - (m_number_of_visible_choices - 1);
1592 if (m_choice < m_first_visibile_choice)
1593 m_first_visibile_choice = m_choice;
1596 HandleCharResult FieldDelegateHandleChar(
int key)
override {
1607 return eKeyNotHandled;
1611 std::string GetChoiceContent() {
return m_choices[m_choice]; }
1614 int GetChoice() {
return m_choice; }
1616 void SetChoice(llvm::StringRef choice) {
1617 for (
int i = 0; i < GetNumberOfChoices(); i++) {
1618 if (choice == m_choices[i]) {
1626 std::string m_label;
1627 int m_number_of_visible_choices;
1628 std::vector<std::string> m_choices;
1632 int m_first_visibile_choice = 0;
1635class PlatformPluginFieldDelegate :
public ChoicesFieldDelegate {
1637 PlatformPluginFieldDelegate(Debugger &debugger)
1638 : ChoicesFieldDelegate(
"Platform Plugin", 3, GetPossiblePluginNames()) {
1641 SetChoice(platform_sp->GetPluginName());
1644 std::vector<std::string> GetPossiblePluginNames() {
1645 std::vector<std::string> names;
1647 for (llvm::StringRef name =
1650 names.push_back(name.str());
1654 std::string GetPluginName() {
1655 std::string plugin_name = GetChoiceContent();
1660class ProcessPluginFieldDelegate :
public ChoicesFieldDelegate {
1662 ProcessPluginFieldDelegate()
1663 : ChoicesFieldDelegate(
"Process Plugin", 3, GetPossiblePluginNames()) {}
1665 std::vector<std::string> GetPossiblePluginNames() {
1666 std::vector<std::string> names;
1667 names.push_back(
"<default>");
1672 names.push_back(name.str());
1676 std::string GetPluginName() {
1677 std::string plugin_name = GetChoiceContent();
1678 if (plugin_name ==
"<default>")
1684class LazyBooleanFieldDelegate :
public ChoicesFieldDelegate {
1686 LazyBooleanFieldDelegate(
const char *label,
const char *calculate_label)
1687 : ChoicesFieldDelegate(label, 3, GetPossibleOptions(calculate_label)) {}
1689 static constexpr const char *kNo =
"No";
1690 static constexpr const char *kYes =
"Yes";
1692 std::vector<std::string> GetPossibleOptions(
const char *calculate_label) {
1693 std::vector<std::string> options;
1694 options.push_back(calculate_label);
1695 options.push_back(kYes);
1696 options.push_back(kNo);
1701 std::string choice = GetChoiceContent();
1704 else if (choice == kYes)
1711template <
class T>
class ListFieldDelegate :
public FieldDelegate {
1713 ListFieldDelegate(
const char *label, T default_field)
1714 : m_label(label), m_default_field(default_field),
1715 m_selection_type(SelectionType::NewButton) {}
1720 enum class SelectionType { Field, RemoveButton, NewButton };
1736 int FieldDelegateGetHeight()
override {
1740 for (
int i = 0; i < GetNumberOfFields(); i++) {
1741 height += m_fields[i].FieldDelegateGetHeight();
1748 ScrollContext FieldDelegateGetScrollContext()
override {
1749 int height = FieldDelegateGetHeight();
1750 if (m_selection_type == SelectionType::NewButton)
1751 return ScrollContext(height - 2, height - 1);
1753 FieldDelegate &field = m_fields[m_selection_index];
1754 ScrollContext context = field.FieldDelegateGetScrollContext();
1758 for (
int i = 0; i < m_selection_index; i++) {
1759 offset += m_fields[i].FieldDelegateGetHeight();
1761 context.Offset(offset);
1765 if (context.start == 1)
1770 if (context.end == height - 3)
1776 void DrawRemoveButton(Surface &surface,
int highlight) {
1777 surface.MoveCursor(1, surface.GetHeight() / 2);
1779 surface.AttributeOn(A_REVERSE);
1780 surface.PutCString(
"[Remove]");
1782 surface.AttributeOff(A_REVERSE);
1785 void DrawFields(Surface &surface,
bool is_selected) {
1787 int width = surface.GetWidth();
1788 for (
int i = 0; i < GetNumberOfFields(); i++) {
1789 int height = m_fields[i].FieldDelegateGetHeight();
1790 Rect bounds = Rect(Point(0, line), Size(width, height));
1791 Rect field_bounds, remove_button_bounds;
1792 bounds.VerticalSplit(bounds.size.width -
sizeof(
" [Remove]"),
1793 field_bounds, remove_button_bounds);
1794 Surface field_surface = surface.SubSurface(field_bounds);
1795 Surface remove_button_surface = surface.SubSurface(remove_button_bounds);
1797 bool is_element_selected = m_selection_index == i && is_selected;
1798 bool is_field_selected =
1799 is_element_selected && m_selection_type == SelectionType::Field;
1800 bool is_remove_button_selected =
1801 is_element_selected &&
1802 m_selection_type == SelectionType::RemoveButton;
1803 m_fields[i].FieldDelegateDraw(field_surface, is_field_selected);
1804 DrawRemoveButton(remove_button_surface, is_remove_button_selected);
1810 void DrawNewButton(Surface &surface,
bool is_selected) {
1811 const char *button_text =
"[New]";
1812 int x = (surface.GetWidth() -
sizeof(button_text) - 1) / 2;
1813 surface.MoveCursor(x, 0);
1815 is_selected && m_selection_type == SelectionType::NewButton;
1817 surface.AttributeOn(A_REVERSE);
1818 surface.PutCString(button_text);
1820 surface.AttributeOff(A_REVERSE);
1823 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
1824 surface.TitledBox(m_label.c_str());
1826 Rect content_bounds = surface.GetFrame();
1827 content_bounds.Inset(1, 1);
1828 Rect fields_bounds, new_button_bounds;
1829 content_bounds.HorizontalSplit(content_bounds.size.height - 1,
1830 fields_bounds, new_button_bounds);
1831 Surface fields_surface = surface.SubSurface(fields_bounds);
1832 Surface new_button_surface = surface.SubSurface(new_button_bounds);
1834 DrawFields(fields_surface, is_selected);
1835 DrawNewButton(new_button_surface, is_selected);
1838 void AddNewField() {
1839 m_fields.push_back(m_default_field);
1840 m_selection_index = GetNumberOfFields() - 1;
1841 m_selection_type = SelectionType::Field;
1842 FieldDelegate &field = m_fields[m_selection_index];
1843 field.FieldDelegateSelectFirstElement();
1846 void RemoveField() {
1847 m_fields.erase(m_fields.begin() + m_selection_index);
1848 if (m_selection_index != 0)
1849 m_selection_index--;
1851 if (GetNumberOfFields() > 0) {
1852 m_selection_type = SelectionType::Field;
1853 FieldDelegate &field = m_fields[m_selection_index];
1854 field.FieldDelegateSelectFirstElement();
1856 m_selection_type = SelectionType::NewButton;
1859 HandleCharResult SelectNext(
int key) {
1860 if (m_selection_type == SelectionType::NewButton)
1861 return eKeyNotHandled;
1863 if (m_selection_type == SelectionType::RemoveButton) {
1864 if (m_selection_index == GetNumberOfFields() - 1) {
1865 m_selection_type = SelectionType::NewButton;
1868 m_selection_index++;
1869 m_selection_type = SelectionType::Field;
1870 FieldDelegate &next_field = m_fields[m_selection_index];
1871 next_field.FieldDelegateSelectFirstElement();
1875 FieldDelegate &field = m_fields[m_selection_index];
1876 if (!field.FieldDelegateOnLastOrOnlyElement()) {
1877 return field.FieldDelegateHandleChar(key);
1880 field.FieldDelegateExitCallback();
1882 m_selection_type = SelectionType::RemoveButton;
1886 HandleCharResult SelectPrevious(
int key) {
1887 if (FieldDelegateOnFirstOrOnlyElement())
1888 return eKeyNotHandled;
1890 if (m_selection_type == SelectionType::RemoveButton) {
1891 m_selection_type = SelectionType::Field;
1892 FieldDelegate &field = m_fields[m_selection_index];
1893 field.FieldDelegateSelectLastElement();
1897 if (m_selection_type == SelectionType::NewButton) {
1898 m_selection_type = SelectionType::RemoveButton;
1899 m_selection_index = GetNumberOfFields() - 1;
1903 FieldDelegate &field = m_fields[m_selection_index];
1904 if (!field.FieldDelegateOnFirstOrOnlyElement()) {
1905 return field.FieldDelegateHandleChar(key);
1908 field.FieldDelegateExitCallback();
1910 m_selection_type = SelectionType::RemoveButton;
1911 m_selection_index--;
1917 HandleCharResult SelectNextInList(
int key) {
1918 assert(m_selection_type == SelectionType::Field);
1920 FieldDelegate &field = m_fields[m_selection_index];
1921 if (field.FieldDelegateHandleChar(key) == eKeyHandled)
1924 if (!field.FieldDelegateOnLastOrOnlyElement())
1925 return eKeyNotHandled;
1927 field.FieldDelegateExitCallback();
1929 if (m_selection_index == GetNumberOfFields() - 1) {
1930 m_selection_type = SelectionType::NewButton;
1934 m_selection_index++;
1935 FieldDelegate &next_field = m_fields[m_selection_index];
1936 next_field.FieldDelegateSelectFirstElement();
1940 HandleCharResult FieldDelegateHandleChar(
int key)
override {
1945 switch (m_selection_type) {
1946 case SelectionType::NewButton:
1949 case SelectionType::RemoveButton:
1952 case SelectionType::Field:
1953 return SelectNextInList(key);
1957 return SelectNext(key);
1959 return SelectPrevious(key);
1966 if (m_selection_type == SelectionType::Field) {
1967 return m_fields[m_selection_index].FieldDelegateHandleChar(key);
1970 return eKeyNotHandled;
1973 bool FieldDelegateOnLastOrOnlyElement()
override {
1974 if (m_selection_type == SelectionType::NewButton) {
1980 bool FieldDelegateOnFirstOrOnlyElement()
override {
1981 if (m_selection_type == SelectionType::NewButton &&
1982 GetNumberOfFields() == 0)
1985 if (m_selection_type == SelectionType::Field && m_selection_index == 0) {
1986 FieldDelegate &field = m_fields[m_selection_index];
1987 return field.FieldDelegateOnFirstOrOnlyElement();
1993 void FieldDelegateSelectFirstElement()
override {
1994 if (GetNumberOfFields() == 0) {
1995 m_selection_type = SelectionType::NewButton;
1999 m_selection_type = SelectionType::Field;
2000 m_selection_index = 0;
2003 void FieldDelegateSelectLastElement()
override {
2004 m_selection_type = SelectionType::NewButton;
2007 int GetNumberOfFields() {
return m_fields.size(); }
2010 T &GetField(
int index) {
return m_fields[index]; }
2013 std::string m_label;
2017 std::vector<T> m_fields;
2018 int m_selection_index = 0;
2020 SelectionType m_selection_type;
2023class ArgumentsFieldDelegate :
public ListFieldDelegate<TextFieldDelegate> {
2025 ArgumentsFieldDelegate()
2026 : ListFieldDelegate(
"Arguments",
2027 TextFieldDelegate(
"Argument",
"", false)) {}
2029 Args GetArguments() {
2031 for (
int i = 0; i < GetNumberOfFields(); i++) {
2037 void AddArguments(
const Args &arguments) {
2040 TextFieldDelegate &field = GetField(GetNumberOfFields() - 1);
2046template <
class KeyFieldDelegateType,
class ValueFieldDelegateType>
2047class MappingFieldDelegate :
public FieldDelegate {
2049 MappingFieldDelegate(KeyFieldDelegateType key_field,
2050 ValueFieldDelegateType value_field)
2051 : m_key_field(key_field), m_value_field(value_field),
2052 m_selection_type(SelectionType::Key) {}
2055 enum class SelectionType { Key, Value };
2068 int FieldDelegateGetHeight()
override {
2069 return std::max(m_key_field.FieldDelegateGetHeight(),
2070 m_value_field.FieldDelegateGetHeight());
2073 void DrawArrow(Surface &surface) {
2074 surface.MoveCursor(0, 1);
2075 surface.PutChar(ACS_RARROW);
2078 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
2079 Rect bounds = surface.GetFrame();
2080 Rect key_field_bounds, arrow_and_value_field_bounds;
2081 bounds.VerticalSplit(bounds.size.width / 2, key_field_bounds,
2082 arrow_and_value_field_bounds);
2083 Rect arrow_bounds, value_field_bounds;
2084 arrow_and_value_field_bounds.VerticalSplit(1, arrow_bounds,
2085 value_field_bounds);
2087 Surface key_field_surface = surface.SubSurface(key_field_bounds);
2088 Surface arrow_surface = surface.SubSurface(arrow_bounds);
2089 Surface value_field_surface = surface.SubSurface(value_field_bounds);
2091 bool key_is_selected =
2092 m_selection_type == SelectionType::Key && is_selected;
2093 m_key_field.FieldDelegateDraw(key_field_surface, key_is_selected);
2094 DrawArrow(arrow_surface);
2095 bool value_is_selected =
2096 m_selection_type == SelectionType::Value && is_selected;
2097 m_value_field.FieldDelegateDraw(value_field_surface, value_is_selected);
2100 HandleCharResult SelectNext(
int key) {
2101 if (FieldDelegateOnLastOrOnlyElement())
2102 return eKeyNotHandled;
2104 if (!m_key_field.FieldDelegateOnLastOrOnlyElement()) {
2105 return m_key_field.FieldDelegateHandleChar(key);
2108 m_key_field.FieldDelegateExitCallback();
2109 m_selection_type = SelectionType::Value;
2110 m_value_field.FieldDelegateSelectFirstElement();
2114 HandleCharResult SelectPrevious(
int key) {
2115 if (FieldDelegateOnFirstOrOnlyElement())
2116 return eKeyNotHandled;
2118 if (!m_value_field.FieldDelegateOnFirstOrOnlyElement()) {
2119 return m_value_field.FieldDelegateHandleChar(key);
2122 m_value_field.FieldDelegateExitCallback();
2123 m_selection_type = SelectionType::Key;
2124 m_key_field.FieldDelegateSelectLastElement();
2131 HandleCharResult SelectNextField(
int key) {
2132 if (m_selection_type == SelectionType::Value) {
2133 return m_value_field.FieldDelegateHandleChar(key);
2136 if (m_key_field.FieldDelegateHandleChar(key) == eKeyHandled)
2139 if (!m_key_field.FieldDelegateOnLastOrOnlyElement())
2140 return eKeyNotHandled;
2142 m_key_field.FieldDelegateExitCallback();
2143 m_selection_type = SelectionType::Value;
2144 m_value_field.FieldDelegateSelectFirstElement();
2148 HandleCharResult FieldDelegateHandleChar(
int key)
override {
2151 return SelectNextField(key);
2153 return SelectNext(key);
2155 return SelectPrevious(key);
2161 if (m_selection_type == SelectionType::Key)
2162 return m_key_field.FieldDelegateHandleChar(key);
2164 return m_value_field.FieldDelegateHandleChar(key);
2166 return eKeyNotHandled;
2169 bool FieldDelegateOnFirstOrOnlyElement()
override {
2170 return m_selection_type == SelectionType::Key;
2173 bool FieldDelegateOnLastOrOnlyElement()
override {
2174 return m_selection_type == SelectionType::Value;
2177 void FieldDelegateSelectFirstElement()
override {
2178 m_selection_type = SelectionType::Key;
2181 void FieldDelegateSelectLastElement()
override {
2182 m_selection_type = SelectionType::Value;
2185 bool FieldDelegateHasError()
override {
2186 return m_key_field.FieldDelegateHasError() ||
2187 m_value_field.FieldDelegateHasError();
2190 KeyFieldDelegateType &GetKeyField() {
return m_key_field; }
2192 ValueFieldDelegateType &GetValueField() {
return m_value_field; }
2195 KeyFieldDelegateType m_key_field;
2196 ValueFieldDelegateType m_value_field;
2198 SelectionType m_selection_type;
2201class EnvironmentVariableNameFieldDelegate :
public TextFieldDelegate {
2203 EnvironmentVariableNameFieldDelegate(
const char *content)
2204 : TextFieldDelegate(
"Name", content, true) {}
2207 bool IsAcceptableChar(
int key)
override {
2208 return TextFieldDelegate::IsAcceptableChar(key) && key !=
'=';
2211 const std::string &
GetName() {
return m_content; }
2214class EnvironmentVariableFieldDelegate
2215 :
public MappingFieldDelegate<EnvironmentVariableNameFieldDelegate,
2216 TextFieldDelegate> {
2218 EnvironmentVariableFieldDelegate()
2219 : MappingFieldDelegate(
2220 EnvironmentVariableNameFieldDelegate(
""),
2221 TextFieldDelegate(
"Value",
"", false)) {}
2223 const std::string &
GetName() {
return GetKeyField().GetName(); }
2225 const std::string &GetValue() {
return GetValueField().GetText(); }
2227 void SetName(
const char *name) {
return GetKeyField().SetText(name); }
2229 void SetValue(
const char *value) {
return GetValueField().SetText(value); }
2232class EnvironmentVariableListFieldDelegate
2233 :
public ListFieldDelegate<EnvironmentVariableFieldDelegate> {
2235 EnvironmentVariableListFieldDelegate(
const char *label)
2236 : ListFieldDelegate(label, EnvironmentVariableFieldDelegate()) {}
2238 Environment GetEnvironment() {
2239 Environment environment;
2240 for (
int i = 0; i < GetNumberOfFields(); i++) {
2242 std::make_pair(GetField(i).
GetName(), GetField(i).GetValue()));
2247 void AddEnvironmentVariables(
const Environment &environment) {
2248 for (
auto &variable : environment) {
2250 EnvironmentVariableFieldDelegate &field =
2251 GetField(GetNumberOfFields() - 1);
2252 field.SetName(variable.getKey().str().c_str());
2253 field.SetValue(variable.getValue().c_str());
2260 FormAction(
const char *label, std::function<
void(Window &)> action)
2261 : m_action(action) {
2267 void Draw(Surface &surface,
bool is_selected) {
2268 int x = (surface.GetWidth() - m_label.length()) / 2;
2269 surface.MoveCursor(x, 0);
2271 surface.AttributeOn(A_REVERSE);
2272 surface.PutChar(
'[');
2273 surface.PutCString(m_label.c_str());
2274 surface.PutChar(
']');
2276 surface.AttributeOff(A_REVERSE);
2279 void Execute(Window &window) { m_action(window); }
2281 const std::string &GetLabel() {
return m_label; }
2284 std::string m_label;
2285 std::function<void(Window &)> m_action;
2290 FormDelegate() =
default;
2292 virtual ~FormDelegate() =
default;
2294 virtual std::string
GetName() = 0;
2296 virtual void UpdateFieldsVisibility() {}
2298 FieldDelegate *GetField(uint32_t field_index) {
2299 if (field_index < m_fields.size())
2300 return m_fields[field_index].get();
2304 FormAction &GetAction(
int action_index) {
return m_actions[action_index]; }
2306 int GetNumberOfFields() {
return m_fields.size(); }
2308 int GetNumberOfActions() {
return m_actions.size(); }
2310 bool HasError() {
return !m_error.empty(); }
2312 void ClearError() { m_error.clear(); }
2314 const std::string &GetError() {
return m_error; }
2316 void SetError(
const char *
error) { m_error =
error; }
2321 bool CheckFieldsValidity() {
2322 for (
int i = 0; i < GetNumberOfFields(); i++) {
2323 GetField(i)->FieldDelegateExitCallback();
2324 if (GetField(i)->FieldDelegateHasError()) {
2325 SetError(
"Some fields are invalid!");
2334 TextFieldDelegate *AddTextField(
const char *label,
const char *content,
2336 TextFieldDelegate *delegate =
2337 new TextFieldDelegate(label, content, required);
2338 m_fields.push_back(FieldDelegateUP(delegate));
2342 FileFieldDelegate *AddFileField(
const char *label,
const char *content,
2343 bool need_to_exist,
bool required) {
2344 FileFieldDelegate *delegate =
2345 new FileFieldDelegate(label, content, need_to_exist, required);
2346 m_fields.push_back(FieldDelegateUP(delegate));
2350 DirectoryFieldDelegate *AddDirectoryField(
const char *label,
2351 const char *content,
2352 bool need_to_exist,
bool required) {
2353 DirectoryFieldDelegate *delegate =
2354 new DirectoryFieldDelegate(label, content, need_to_exist, required);
2355 m_fields.push_back(FieldDelegateUP(delegate));
2359 ArchFieldDelegate *AddArchField(
const char *label,
const char *content,
2361 ArchFieldDelegate *delegate =
2362 new ArchFieldDelegate(label, content, required);
2363 m_fields.push_back(FieldDelegateUP(delegate));
2367 IntegerFieldDelegate *AddIntegerField(
const char *label,
int content,
2369 IntegerFieldDelegate *delegate =
2370 new IntegerFieldDelegate(label, content, required);
2371 m_fields.push_back(FieldDelegateUP(delegate));
2375 BooleanFieldDelegate *AddBooleanField(
const char *label,
bool content) {
2376 BooleanFieldDelegate *delegate =
new BooleanFieldDelegate(label, content);
2377 m_fields.push_back(FieldDelegateUP(delegate));
2381 LazyBooleanFieldDelegate *AddLazyBooleanField(
const char *label,
2382 const char *calculate_label) {
2383 LazyBooleanFieldDelegate *delegate =
2384 new LazyBooleanFieldDelegate(label, calculate_label);
2385 m_fields.push_back(FieldDelegateUP(delegate));
2389 ChoicesFieldDelegate *AddChoicesField(
const char *label,
int height,
2390 std::vector<std::string> choices) {
2391 ChoicesFieldDelegate *delegate =
2392 new ChoicesFieldDelegate(label, height, choices);
2393 m_fields.push_back(FieldDelegateUP(delegate));
2397 PlatformPluginFieldDelegate *AddPlatformPluginField(Debugger &debugger) {
2398 PlatformPluginFieldDelegate *delegate =
2399 new PlatformPluginFieldDelegate(debugger);
2400 m_fields.push_back(FieldDelegateUP(delegate));
2404 ProcessPluginFieldDelegate *AddProcessPluginField() {
2405 ProcessPluginFieldDelegate *delegate =
new ProcessPluginFieldDelegate();
2406 m_fields.push_back(FieldDelegateUP(delegate));
2411 ListFieldDelegate<T> *AddListField(
const char *label, T default_field) {
2412 ListFieldDelegate<T> *delegate =
2413 new ListFieldDelegate<T>(label, default_field);
2414 m_fields.push_back(FieldDelegateUP(delegate));
2418 ArgumentsFieldDelegate *AddArgumentsField() {
2419 ArgumentsFieldDelegate *delegate =
new ArgumentsFieldDelegate();
2420 m_fields.push_back(FieldDelegateUP(delegate));
2424 template <
class K,
class V>
2425 MappingFieldDelegate<K, V> *AddMappingField(K key_field, V value_field) {
2426 MappingFieldDelegate<K, V> *delegate =
2427 new MappingFieldDelegate<K, V>(key_field, value_field);
2428 m_fields.push_back(FieldDelegateUP(delegate));
2432 EnvironmentVariableNameFieldDelegate *
2433 AddEnvironmentVariableNameField(
const char *content) {
2434 EnvironmentVariableNameFieldDelegate *delegate =
2435 new EnvironmentVariableNameFieldDelegate(content);
2436 m_fields.push_back(FieldDelegateUP(delegate));
2440 EnvironmentVariableFieldDelegate *AddEnvironmentVariableField() {
2441 EnvironmentVariableFieldDelegate *delegate =
2442 new EnvironmentVariableFieldDelegate();
2443 m_fields.push_back(FieldDelegateUP(delegate));
2447 EnvironmentVariableListFieldDelegate *
2448 AddEnvironmentVariableListField(
const char *label) {
2449 EnvironmentVariableListFieldDelegate *delegate =
2450 new EnvironmentVariableListFieldDelegate(label);
2451 m_fields.push_back(FieldDelegateUP(delegate));
2457 void AddAction(
const char *label, std::function<
void(Window &)> action) {
2458 m_actions.push_back(FormAction(label, action));
2462 std::vector<FieldDelegateUP> m_fields;
2463 std::vector<FormAction> m_actions;
2465 std::string m_error;
2468typedef std::shared_ptr<FormDelegate> FormDelegateSP;
2470class FormWindowDelegate :
public WindowDelegate {
2472 FormWindowDelegate(FormDelegateSP &delegate_sp) : m_delegate_sp(delegate_sp) {
2473 assert(m_delegate_sp->GetNumberOfActions() > 0);
2474 if (m_delegate_sp->GetNumberOfFields() > 0)
2475 m_selection_type = SelectionType::Field;
2477 m_selection_type = SelectionType::Action;
2483 enum class SelectionType { Field, Action };
2501 int GetErrorHeight() {
2502 if (m_delegate_sp->HasError())
2508 int GetActionsHeight() {
2509 if (m_delegate_sp->GetNumberOfActions() > 0)
2515 int GetContentHeight() {
2517 height += GetErrorHeight();
2518 for (
int i = 0; i < m_delegate_sp->GetNumberOfFields(); i++) {
2519 if (!m_delegate_sp->GetField(i)->FieldDelegateIsVisible())
2521 height += m_delegate_sp->GetField(i)->FieldDelegateGetHeight();
2523 height += GetActionsHeight();
2527 ScrollContext GetScrollContext() {
2528 if (m_selection_type == SelectionType::Action)
2529 return ScrollContext(GetContentHeight() - 1);
2531 FieldDelegate *field = m_delegate_sp->GetField(m_selection_index);
2532 ScrollContext context = field->FieldDelegateGetScrollContext();
2534 int offset = GetErrorHeight();
2535 for (
int i = 0; i < m_selection_index; i++) {
2536 if (!m_delegate_sp->GetField(i)->FieldDelegateIsVisible())
2538 offset += m_delegate_sp->GetField(i)->FieldDelegateGetHeight();
2540 context.Offset(offset);
2544 if (context.start == GetErrorHeight())
2550 void UpdateScrolling(Surface &surface) {
2551 ScrollContext context = GetScrollContext();
2552 int content_height = GetContentHeight();
2553 int surface_height = surface.GetHeight();
2554 int visible_height = std::min(content_height, surface_height);
2555 int last_visible_line = m_first_visible_line + visible_height - 1;
2560 if (last_visible_line > content_height - 1) {
2561 m_first_visible_line = content_height - visible_height;
2564 if (context.start < m_first_visible_line) {
2565 m_first_visible_line = context.start;
2569 if (context.end > last_visible_line) {
2570 m_first_visible_line = context.end - visible_height + 1;
2574 void DrawError(Surface &surface) {
2575 if (!m_delegate_sp->HasError())
2577 surface.MoveCursor(0, 0);
2578 surface.AttributeOn(COLOR_PAIR(RedOnBlack));
2579 surface.PutChar(ACS_DIAMOND);
2580 surface.PutChar(
' ');
2581 surface.PutCStringTruncated(1, m_delegate_sp->GetError().c_str());
2582 surface.AttributeOff(COLOR_PAIR(RedOnBlack));
2584 surface.MoveCursor(0, 1);
2585 surface.HorizontalLine(surface.GetWidth());
2588 void DrawFields(Surface &surface) {
2590 int width = surface.GetWidth();
2591 bool a_field_is_selected = m_selection_type == SelectionType::Field;
2592 for (
int i = 0; i < m_delegate_sp->GetNumberOfFields(); i++) {
2593 FieldDelegate *field = m_delegate_sp->GetField(i);
2594 if (!field->FieldDelegateIsVisible())
2596 bool is_field_selected = a_field_is_selected && m_selection_index == i;
2597 int height = field->FieldDelegateGetHeight();
2598 Rect bounds = Rect(Point(0, line), Size(width, height));
2599 Surface field_surface = surface.SubSurface(bounds);
2600 field->FieldDelegateDraw(field_surface, is_field_selected);
2605 void DrawActions(Surface &surface) {
2606 int number_of_actions = m_delegate_sp->GetNumberOfActions();
2607 int width = surface.GetWidth() / number_of_actions;
2608 bool an_action_is_selected = m_selection_type == SelectionType::Action;
2610 for (
int i = 0; i < number_of_actions; i++) {
2611 bool is_action_selected = an_action_is_selected && m_selection_index == i;
2612 FormAction &action = m_delegate_sp->GetAction(i);
2613 Rect bounds = Rect(Point(x, 0), Size(width, 1));
2614 Surface action_surface = surface.SubSurface(bounds);
2615 action.Draw(action_surface, is_action_selected);
2620 void DrawElements(Surface &surface) {
2621 Rect frame = surface.GetFrame();
2622 Rect fields_bounds, actions_bounds;
2623 frame.HorizontalSplit(surface.GetHeight() - GetActionsHeight(),
2624 fields_bounds, actions_bounds);
2625 Surface fields_surface = surface.SubSurface(fields_bounds);
2626 Surface actions_surface = surface.SubSurface(actions_bounds);
2628 DrawFields(fields_surface);
2629 DrawActions(actions_surface);
2635 void DrawContent(Surface &surface) {
2636 UpdateScrolling(surface);
2638 int width = surface.GetWidth();
2639 int height = GetContentHeight();
2640 Pad pad = Pad(Size(width, height));
2642 Rect frame = pad.GetFrame();
2643 Rect error_bounds, elements_bounds;
2644 frame.HorizontalSplit(GetErrorHeight(), error_bounds, elements_bounds);
2645 Surface error_surface = pad.SubSurface(error_bounds);
2646 Surface elements_surface = pad.SubSurface(elements_bounds);
2648 DrawError(error_surface);
2649 DrawElements(elements_surface);
2651 int copy_height = std::min(surface.GetHeight(), pad.GetHeight());
2652 pad.CopyToSurface(surface, Point(0, m_first_visible_line), Point(),
2653 Size(width, copy_height));
2656 void DrawSubmitHint(Surface &surface,
bool is_active) {
2657 surface.MoveCursor(2, surface.GetHeight() - 1);
2659 surface.AttributeOn(A_BOLD | COLOR_PAIR(BlackOnWhite));
2660 surface.Printf(
"[Press Alt+Enter to %s]",
2661 m_delegate_sp->GetAction(0).GetLabel().c_str());
2663 surface.AttributeOff(A_BOLD | COLOR_PAIR(BlackOnWhite));
2666 bool WindowDelegateDraw(Window &window,
bool force)
override {
2667 m_delegate_sp->UpdateFieldsVisibility();
2671 window.DrawTitleBox(m_delegate_sp->GetName().c_str(),
2672 "Press Esc to Cancel");
2673 DrawSubmitHint(window, window.IsActive());
2675 Rect content_bounds = window.GetFrame();
2676 content_bounds.Inset(2, 2);
2677 Surface content_surface = window.SubSurface(content_bounds);
2679 DrawContent(content_surface);
2683 void SkipNextHiddenFields() {
2685 if (m_delegate_sp->GetField(m_selection_index)->FieldDelegateIsVisible())
2688 if (m_selection_index == m_delegate_sp->GetNumberOfFields() - 1) {
2689 m_selection_type = SelectionType::Action;
2690 m_selection_index = 0;
2694 m_selection_index++;
2698 HandleCharResult SelectNext(
int key) {
2699 if (m_selection_type == SelectionType::Action) {
2700 if (m_selection_index < m_delegate_sp->GetNumberOfActions() - 1) {
2701 m_selection_index++;
2705 m_selection_index = 0;
2706 m_selection_type = SelectionType::Field;
2707 SkipNextHiddenFields();
2708 if (m_selection_type == SelectionType::Field) {
2709 FieldDelegate *next_field = m_delegate_sp->GetField(m_selection_index);
2710 next_field->FieldDelegateSelectFirstElement();
2715 FieldDelegate *field = m_delegate_sp->GetField(m_selection_index);
2716 if (!field->FieldDelegateOnLastOrOnlyElement()) {
2717 return field->FieldDelegateHandleChar(key);
2720 field->FieldDelegateExitCallback();
2722 if (m_selection_index == m_delegate_sp->GetNumberOfFields() - 1) {
2723 m_selection_type = SelectionType::Action;
2724 m_selection_index = 0;
2728 m_selection_index++;
2729 SkipNextHiddenFields();
2731 if (m_selection_type == SelectionType::Field) {
2732 FieldDelegate *next_field = m_delegate_sp->GetField(m_selection_index);
2733 next_field->FieldDelegateSelectFirstElement();
2739 void SkipPreviousHiddenFields() {
2741 if (m_delegate_sp->GetField(m_selection_index)->FieldDelegateIsVisible())
2744 if (m_selection_index == 0) {
2745 m_selection_type = SelectionType::Action;
2746 m_selection_index = 0;
2750 m_selection_index--;
2754 HandleCharResult SelectPrevious(
int key) {
2755 if (m_selection_type == SelectionType::Action) {
2756 if (m_selection_index > 0) {
2757 m_selection_index--;
2760 m_selection_index = m_delegate_sp->GetNumberOfFields() - 1;
2761 m_selection_type = SelectionType::Field;
2762 SkipPreviousHiddenFields();
2763 if (m_selection_type == SelectionType::Field) {
2764 FieldDelegate *previous_field =
2765 m_delegate_sp->GetField(m_selection_index);
2766 previous_field->FieldDelegateSelectLastElement();
2771 FieldDelegate *field = m_delegate_sp->GetField(m_selection_index);
2772 if (!field->FieldDelegateOnFirstOrOnlyElement()) {
2773 return field->FieldDelegateHandleChar(key);
2776 field->FieldDelegateExitCallback();
2778 if (m_selection_index == 0) {
2779 m_selection_type = SelectionType::Action;
2780 m_selection_index = m_delegate_sp->GetNumberOfActions() - 1;
2784 m_selection_index--;
2785 SkipPreviousHiddenFields();
2787 if (m_selection_type == SelectionType::Field) {
2788 FieldDelegate *previous_field =
2789 m_delegate_sp->GetField(m_selection_index);
2790 previous_field->FieldDelegateSelectLastElement();
2796 void ExecuteAction(Window &window,
int index) {
2797 FormAction &action = m_delegate_sp->GetAction(index);
2798 action.Execute(window);
2799 if (m_delegate_sp->HasError()) {
2800 m_first_visible_line = 0;
2801 m_selection_index = 0;
2802 m_selection_type = SelectionType::Field;
2808 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override {
2813 if (m_selection_type == SelectionType::Action) {
2814 ExecuteAction(window, m_selection_index);
2819 ExecuteAction(window, 0);
2825 SelectPrevious(key);
2828 window.GetParent()->RemoveSubWindow(&window);
2836 if (m_selection_type == SelectionType::Field) {
2837 FieldDelegate *field = m_delegate_sp->GetField(m_selection_index);
2838 if (field->FieldDelegateHandleChar(key) == eKeyHandled)
2849 SelectPrevious(key);
2859 FormDelegateSP m_delegate_sp;
2861 int m_selection_index = 0;
2863 SelectionType m_selection_type;
2865 int m_first_visible_line = 0;
2872class DetachOrKillProcessFormDelegate :
public FormDelegate {
2874 DetachOrKillProcessFormDelegate(
Process *process) : m_process(process) {
2875 SetError(
"There is a running process, either detach or kill it.");
2877 m_keep_stopped_field =
2878 AddBooleanField(
"Keep process stopped when detaching.",
false);
2880 AddAction(
"Detach", [
this](Window &window) { Detach(window); });
2881 AddAction(
"Kill", [
this](Window &window) { Kill(window); });
2884 std::string
GetName()
override {
return "Detach/Kill Process"; }
2886 void Kill(Window &window) {
2887 Status destroy_status(m_process->Destroy(
false));
2888 if (destroy_status.Fail()) {
2889 SetError(
"Failed to kill process.");
2892 window.GetParent()->RemoveSubWindow(&window);
2895 void Detach(Window &window) {
2896 Status detach_status(m_process->Detach(m_keep_stopped_field->GetBoolean()));
2897 if (detach_status.Fail()) {
2898 SetError(
"Failed to detach from process.");
2901 window.GetParent()->RemoveSubWindow(&window);
2906 BooleanFieldDelegate *m_keep_stopped_field;
2909class ProcessAttachFormDelegate :
public FormDelegate {
2911 ProcessAttachFormDelegate(Debugger &debugger, WindowSP main_window_sp)
2912 : m_debugger(debugger), m_main_window_sp(main_window_sp) {
2913 std::vector<std::string> types;
2914 types.push_back(std::string(
"Name"));
2915 types.push_back(std::string(
"PID"));
2916 m_type_field = AddChoicesField(
"Attach By", 2, types);
2917 m_pid_field = AddIntegerField(
"PID", 0,
true);
2919 AddTextField(
"Process Name", GetDefaultProcessName().c_str(),
true);
2920 m_continue_field = AddBooleanField(
"Continue once attached.",
false);
2921 m_wait_for_field = AddBooleanField(
"Wait for process to launch.",
false);
2922 m_include_existing_field =
2923 AddBooleanField(
"Include existing processes.",
false);
2924 m_show_advanced_field = AddBooleanField(
"Show advanced settings.",
false);
2925 m_plugin_field = AddProcessPluginField();
2927 AddAction(
"Attach", [
this](Window &window) { Attach(window); });
2930 std::string
GetName()
override {
return "Attach Process"; }
2932 void UpdateFieldsVisibility()
override {
2933 if (m_type_field->GetChoiceContent() ==
"Name") {
2934 m_pid_field->FieldDelegateHide();
2935 m_name_field->FieldDelegateShow();
2936 m_wait_for_field->FieldDelegateShow();
2937 if (m_wait_for_field->GetBoolean())
2938 m_include_existing_field->FieldDelegateShow();
2940 m_include_existing_field->FieldDelegateHide();
2942 m_pid_field->FieldDelegateShow();
2943 m_name_field->FieldDelegateHide();
2944 m_wait_for_field->FieldDelegateHide();
2945 m_include_existing_field->FieldDelegateHide();
2947 if (m_show_advanced_field->GetBoolean())
2948 m_plugin_field->FieldDelegateShow();
2950 m_plugin_field->FieldDelegateHide();
2955 std::string GetDefaultProcessName() {
2956 Target *target = m_debugger
2957 .GetSelectedExecutionContext(
2960 if (target ==
nullptr)
2964 if (!module_sp->IsExecutable())
2967 return module_sp->GetFileSpec().GetFilename().GetString();
2970 bool StopRunningProcess() {
2971 ExecutionContext exe_ctx =
2972 m_debugger.GetCommandInterpreter().GetExecutionContext();
2978 if (!(process && process->
IsAlive()))
2981 FormDelegateSP form_delegate_sp =
2982 FormDelegateSP(
new DetachOrKillProcessFormDelegate(process));
2983 Rect bounds = m_main_window_sp->GetCenteredRect(85, 8);
2984 WindowSP form_window_sp = m_main_window_sp->CreateSubWindow(
2985 form_delegate_sp->GetName().c_str(), bounds,
true);
2986 WindowDelegateSP window_delegate_sp =
2987 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
2988 form_window_sp->SetDelegate(window_delegate_sp);
2994 Target *target = m_debugger
2995 .GetSelectedExecutionContext(
2999 if (target !=
nullptr)
3003 m_debugger.GetTargetList().CreateTarget(
3006 target = new_target_sp.get();
3008 if (target ==
nullptr)
3009 SetError(
"Failed to create target.");
3011 m_debugger.GetTargetList().SetSelectedTarget(new_target_sp);
3016 ProcessAttachInfo GetAttachInfo() {
3017 ProcessAttachInfo attach_info;
3019 if (m_type_field->GetChoiceContent() ==
"Name") {
3021 FileSpec::Style::native);
3023 if (m_wait_for_field->GetBoolean())
3033 void Attach(Window &window) {
3036 bool all_fields_are_valid = CheckFieldsValidity();
3037 if (!all_fields_are_valid)
3040 bool process_is_running = StopRunningProcess();
3041 if (process_is_running)
3044 Target *target = GetTarget();
3048 StreamString stream;
3049 ProcessAttachInfo attach_info = GetAttachInfo();
3052 if (status.
Fail()) {
3059 SetError(
"Attached sucessfully but target has no process.");
3064 process_sp->Resume();
3066 window.GetParent()->RemoveSubWindow(&window);
3070 Debugger &m_debugger;
3071 WindowSP m_main_window_sp;
3073 ChoicesFieldDelegate *m_type_field;
3074 IntegerFieldDelegate *m_pid_field;
3075 TextFieldDelegate *m_name_field;
3076 BooleanFieldDelegate *m_continue_field;
3077 BooleanFieldDelegate *m_wait_for_field;
3078 BooleanFieldDelegate *m_include_existing_field;
3079 BooleanFieldDelegate *m_show_advanced_field;
3080 ProcessPluginFieldDelegate *m_plugin_field;
3083class TargetCreateFormDelegate :
public FormDelegate {
3085 TargetCreateFormDelegate(Debugger &debugger) : m_debugger(debugger) {
3086 m_executable_field = AddFileField(
"Executable",
"",
true,
3088 m_core_file_field = AddFileField(
"Core File",
"",
true,
3090 m_symbol_file_field = AddFileField(
3091 "Symbol File",
"",
true,
false);
3092 m_show_advanced_field = AddBooleanField(
"Show advanced settings.",
false);
3093 m_remote_file_field = AddFileField(
3094 "Remote File",
"",
false,
false);
3095 m_arch_field = AddArchField(
"Architecture",
"",
false);
3096 m_platform_field = AddPlatformPluginField(debugger);
3097 m_load_dependent_files_field =
3098 AddChoicesField(
"Load Dependents", 3, GetLoadDependentFilesChoices());
3100 AddAction(
"Create", [
this](Window &window) { CreateTarget(window); });
3103 std::string
GetName()
override {
return "Create Target"; }
3105 void UpdateFieldsVisibility()
override {
3106 if (m_show_advanced_field->GetBoolean()) {
3107 m_remote_file_field->FieldDelegateShow();
3108 m_arch_field->FieldDelegateShow();
3109 m_platform_field->FieldDelegateShow();
3110 m_load_dependent_files_field->FieldDelegateShow();
3112 m_remote_file_field->FieldDelegateHide();
3113 m_arch_field->FieldDelegateHide();
3114 m_platform_field->FieldDelegateHide();
3115 m_load_dependent_files_field->FieldDelegateHide();
3119 static constexpr const char *kLoadDependentFilesNo =
"No";
3120 static constexpr const char *kLoadDependentFilesYes =
"Yes";
3121 static constexpr const char *kLoadDependentFilesExecOnly =
"Executable only";
3123 std::vector<std::string> GetLoadDependentFilesChoices() {
3124 std::vector<std::string> load_dependents_options;
3125 load_dependents_options.push_back(kLoadDependentFilesExecOnly);
3126 load_dependents_options.push_back(kLoadDependentFilesYes);
3127 load_dependents_options.push_back(kLoadDependentFilesNo);
3128 return load_dependents_options;
3132 std::string choice = m_load_dependent_files_field->GetChoiceContent();
3133 if (choice == kLoadDependentFilesNo)
3135 if (choice == kLoadDependentFilesYes)
3140 OptionGroupPlatform GetPlatformOptions() {
3141 OptionGroupPlatform platform_options(
false);
3142 platform_options.SetPlatformName(m_platform_field->GetPluginName().c_str());
3143 return platform_options;
3147 OptionGroupPlatform platform_options = GetPlatformOptions();
3149 Status status = m_debugger.GetTargetList().CreateTarget(
3150 m_debugger, m_executable_field->GetPath(),
3151 m_arch_field->GetArchString(), GetLoadDependentFiles(),
3152 &platform_options, target_sp);
3154 if (status.
Fail()) {
3159 m_debugger.GetTargetList().SetSelectedTarget(target_sp);
3164 void SetSymbolFile(
TargetSP target_sp) {
3165 if (!m_symbol_file_field->IsSpecified())
3168 ModuleSP module_sp(target_sp->GetExecutableModule());
3172 module_sp->SetSymbolFileFileSpec(
3173 m_symbol_file_field->GetResolvedFileSpec());
3176 void SetCoreFile(
TargetSP target_sp) {
3177 if (!m_core_file_field->IsSpecified())
3180 FileSpec core_file_spec = m_core_file_field->GetResolvedFileSpec();
3182 FileSpec core_file_directory_spec;
3184 target_sp->AppendExecutableSearchPaths(core_file_directory_spec);
3186 ProcessSP process_sp(target_sp->CreateProcess(
3187 m_debugger.GetListener(), llvm::StringRef(), &core_file_spec,
false));
3190 SetError(
"Unknown core file format!");
3194 Status status = process_sp->LoadCore();
3195 if (status.
Fail()) {
3196 SetError(
"Unknown core file format!");
3201 void SetRemoteFile(
TargetSP target_sp) {
3202 if (!m_remote_file_field->IsSpecified())
3205 ModuleSP module_sp(target_sp->GetExecutableModule());
3209 FileSpec remote_file_spec = m_remote_file_field->GetFileSpec();
3210 module_sp->SetPlatformFileSpec(remote_file_spec);
3213 void RemoveTarget(
TargetSP target_sp) {
3214 m_debugger.GetTargetList().DeleteTarget(target_sp);
3217 void CreateTarget(Window &window) {
3220 bool all_fields_are_valid = CheckFieldsValidity();
3221 if (!all_fields_are_valid)
3228 SetSymbolFile(target_sp);
3230 RemoveTarget(target_sp);
3234 SetCoreFile(target_sp);
3236 RemoveTarget(target_sp);
3240 SetRemoteFile(target_sp);
3242 RemoveTarget(target_sp);
3246 window.GetParent()->RemoveSubWindow(&window);
3250 Debugger &m_debugger;
3252 FileFieldDelegate *m_executable_field;
3253 FileFieldDelegate *m_core_file_field;
3254 FileFieldDelegate *m_symbol_file_field;
3255 BooleanFieldDelegate *m_show_advanced_field;
3256 FileFieldDelegate *m_remote_file_field;
3257 ArchFieldDelegate *m_arch_field;
3258 PlatformPluginFieldDelegate *m_platform_field;
3259 ChoicesFieldDelegate *m_load_dependent_files_field;
3262class ProcessLaunchFormDelegate :
public FormDelegate {
3264 ProcessLaunchFormDelegate(Debugger &debugger, WindowSP main_window_sp)
3265 : m_debugger(debugger), m_main_window_sp(main_window_sp) {
3267 m_arguments_field = AddArgumentsField();
3268 SetArgumentsFieldDefaultValue();
3269 m_target_environment_field =
3270 AddEnvironmentVariableListField(
"Target Environment Variables");
3271 SetTargetEnvironmentFieldDefaultValue();
3272 m_working_directory_field = AddDirectoryField(
3273 "Working Directory", GetDefaultWorkingDirectory().c_str(),
true,
false);
3275 m_show_advanced_field = AddBooleanField(
"Show advanced settings.",
false);
3277 m_stop_at_entry_field = AddBooleanField(
"Stop at entry point.",
false);
3278 m_detach_on_error_field =
3279 AddBooleanField(
"Detach on error.", GetDefaultDetachOnError());
3280 m_disable_aslr_field =
3281 AddBooleanField(
"Disable ASLR", GetDefaultDisableASLR());
3282 m_plugin_field = AddProcessPluginField();
3283 m_arch_field = AddArchField(
"Architecture",
"",
false);
3284 m_shell_field = AddFileField(
"Shell",
"",
true,
false);
3285 m_expand_shell_arguments_field =
3286 AddBooleanField(
"Expand shell arguments.",
false);
3288 m_disable_standard_io_field =
3289 AddBooleanField(
"Disable Standard IO", GetDefaultDisableStandardIO());
3290 m_standard_output_field =
3291 AddFileField(
"Standard Output File",
"",
false,
3293 m_standard_error_field =
3294 AddFileField(
"Standard Error File",
"",
false,
3296 m_standard_input_field =
3297 AddFileField(
"Standard Input File",
"",
false,
3300 m_show_inherited_environment_field =
3301 AddBooleanField(
"Show inherited environment variables.",
false);
3302 m_inherited_environment_field =
3303 AddEnvironmentVariableListField(
"Inherited Environment Variables");
3304 SetInheritedEnvironmentFieldDefaultValue();
3306 AddAction(
"Launch", [
this](Window &window) { Launch(window); });
3309 std::string
GetName()
override {
return "Launch Process"; }
3311 void UpdateFieldsVisibility()
override {
3312 if (m_show_advanced_field->GetBoolean()) {
3313 m_stop_at_entry_field->FieldDelegateShow();
3314 m_detach_on_error_field->FieldDelegateShow();
3315 m_disable_aslr_field->FieldDelegateShow();
3316 m_plugin_field->FieldDelegateShow();
3317 m_arch_field->FieldDelegateShow();
3318 m_shell_field->FieldDelegateShow();
3319 m_expand_shell_arguments_field->FieldDelegateShow();
3320 m_disable_standard_io_field->FieldDelegateShow();
3321 if (m_disable_standard_io_field->GetBoolean()) {
3322 m_standard_input_field->FieldDelegateHide();
3323 m_standard_output_field->FieldDelegateHide();
3324 m_standard_error_field->FieldDelegateHide();
3326 m_standard_input_field->FieldDelegateShow();
3327 m_standard_output_field->FieldDelegateShow();
3328 m_standard_error_field->FieldDelegateShow();
3330 m_show_inherited_environment_field->FieldDelegateShow();
3331 if (m_show_inherited_environment_field->GetBoolean())
3332 m_inherited_environment_field->FieldDelegateShow();
3334 m_inherited_environment_field->FieldDelegateHide();
3336 m_stop_at_entry_field->FieldDelegateHide();
3337 m_detach_on_error_field->FieldDelegateHide();
3338 m_disable_aslr_field->FieldDelegateHide();
3339 m_plugin_field->FieldDelegateHide();
3340 m_arch_field->FieldDelegateHide();
3341 m_shell_field->FieldDelegateHide();
3342 m_expand_shell_arguments_field->FieldDelegateHide();
3343 m_disable_standard_io_field->FieldDelegateHide();
3344 m_standard_input_field->FieldDelegateHide();
3345 m_standard_output_field->FieldDelegateHide();
3346 m_standard_error_field->FieldDelegateHide();
3347 m_show_inherited_environment_field->FieldDelegateHide();
3348 m_inherited_environment_field->FieldDelegateHide();
3354 void SetArgumentsFieldDefaultValue() {
3356 .GetSelectedExecutionContext(
3359 if (target ==
nullptr)
3362 const Args &target_arguments =
3363 target->GetProcessLaunchInfo().GetArguments();
3364 m_arguments_field->AddArguments(target_arguments);
3367 void SetTargetEnvironmentFieldDefaultValue() {
3369 .GetSelectedExecutionContext(
3372 if (target ==
nullptr)
3375 const Environment &target_environment = target->GetTargetEnvironment();
3376 m_target_environment_field->AddEnvironmentVariables(target_environment);
3379 void SetInheritedEnvironmentFieldDefaultValue() {
3381 .GetSelectedExecutionContext(
3384 if (target ==
nullptr)
3387 const Environment &inherited_environment =
3388 target->GetInheritedEnvironment();
3389 m_inherited_environment_field->AddEnvironmentVariables(
3390 inherited_environment);
3393 std::string GetDefaultWorkingDirectory() {
3395 .GetSelectedExecutionContext(
3398 if (target ==
nullptr)
3402 return platform->GetWorkingDirectory().GetPath();
3405 bool GetDefaultDisableASLR() {
3407 .GetSelectedExecutionContext(
3410 if (target ==
nullptr)
3413 return target->GetDisableASLR();
3416 bool GetDefaultDisableStandardIO() {
3418 .GetSelectedExecutionContext(
3421 if (target ==
nullptr)
3424 return target->GetDisableSTDIO();
3427 bool GetDefaultDetachOnError() {
3429 .GetSelectedExecutionContext(
3432 if (target ==
nullptr)
3435 return target->GetDetachOnError();
3441 void GetExecutableSettings(ProcessLaunchInfo &launch_info) {
3443 .GetSelectedExecutionContext(
3446 ModuleSP executable_module = target->GetExecutableModule();
3447 llvm::StringRef target_settings_argv0 = target->GetArg0();
3449 if (!target_settings_argv0.empty()) {
3460 void GetArguments(ProcessLaunchInfo &launch_info) {
3462 .GetSelectedExecutionContext(
3465 Args arguments = m_arguments_field->GetArguments();
3469 void GetEnvironment(ProcessLaunchInfo &launch_info) {
3470 Environment target_environment =
3471 m_target_environment_field->GetEnvironment();
3472 Environment inherited_environment =
3473 m_inherited_environment_field->GetEnvironment();
3475 target_environment.end());
3477 inherited_environment.end());
3480 void GetWorkingDirectory(ProcessLaunchInfo &launch_info) {
3481 if (m_working_directory_field->IsSpecified())
3483 m_working_directory_field->GetResolvedFileSpec());
3486 void GetStopAtEntry(ProcessLaunchInfo &launch_info) {
3487 if (m_stop_at_entry_field->GetBoolean())
3488 launch_info.
GetFlags().
Set(eLaunchFlagStopAtEntry);
3493 void GetDetachOnError(ProcessLaunchInfo &launch_info) {
3494 if (m_detach_on_error_field->GetBoolean())
3495 launch_info.
GetFlags().
Set(eLaunchFlagDetachOnError);
3500 void GetDisableASLR(ProcessLaunchInfo &launch_info) {
3501 if (m_disable_aslr_field->GetBoolean())
3502 launch_info.
GetFlags().
Set(eLaunchFlagDisableASLR);
3507 void GetPlugin(ProcessLaunchInfo &launch_info) {
3511 void GetArch(ProcessLaunchInfo &launch_info) {
3512 if (!m_arch_field->IsSpecified())
3516 .GetSelectedExecutionContext(
3520 target_sp ? target_sp->GetPlatform() :
PlatformSP();
3522 platform_sp.get(), m_arch_field->GetArchString());
3525 void GetShell(ProcessLaunchInfo &launch_info) {
3526 if (!m_shell_field->IsSpecified())
3529 launch_info.
SetShell(m_shell_field->GetResolvedFileSpec());
3531 m_expand_shell_arguments_field->GetBoolean());
3534 void GetStandardIO(ProcessLaunchInfo &launch_info) {
3535 if (m_disable_standard_io_field->GetBoolean()) {
3536 launch_info.
GetFlags().
Set(eLaunchFlagDisableSTDIO);
3541 if (m_standard_input_field->IsSpecified()) {
3542 if (action.
Open(STDIN_FILENO, m_standard_input_field->GetFileSpec(),
true,
3546 if (m_standard_output_field->IsSpecified()) {
3547 if (action.
Open(STDOUT_FILENO, m_standard_output_field->GetFileSpec(),
3551 if (m_standard_error_field->IsSpecified()) {
3552 if (action.
Open(STDERR_FILENO, m_standard_error_field->GetFileSpec(),
3558 void GetInheritTCC(ProcessLaunchInfo &launch_info) {
3559 if (
Target *target = m_debugger
3560 .GetSelectedExecutionContext(
3563 target && target->GetInheritTCC())
3564 launch_info.
GetFlags().
Set(eLaunchFlagInheritTCCFromParent);
3567 ProcessLaunchInfo GetLaunchInfo() {
3568 ProcessLaunchInfo launch_info;
3570 GetExecutableSettings(launch_info);
3571 GetArguments(launch_info);
3572 GetEnvironment(launch_info);
3573 GetWorkingDirectory(launch_info);
3574 GetStopAtEntry(launch_info);
3575 GetDetachOnError(launch_info);
3576 GetDisableASLR(launch_info);
3577 GetPlugin(launch_info);
3578 GetArch(launch_info);
3579 GetShell(launch_info);
3580 GetStandardIO(launch_info);
3581 GetInheritTCC(launch_info);
3586 bool StopRunningProcess() {
3587 ExecutionContext exe_ctx =
3588 m_debugger.GetCommandInterpreter().GetExecutionContext();
3594 if (!(process && process->
IsAlive()))
3597 FormDelegateSP form_delegate_sp =
3598 FormDelegateSP(
new DetachOrKillProcessFormDelegate(process));
3599 Rect bounds = m_main_window_sp->GetCenteredRect(85, 8);
3600 WindowSP form_window_sp = m_main_window_sp->CreateSubWindow(
3601 form_delegate_sp->GetName().c_str(), bounds,
true);
3602 WindowDelegateSP window_delegate_sp =
3603 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
3604 form_window_sp->SetDelegate(window_delegate_sp);
3610 Target *target = m_debugger
3611 .GetSelectedExecutionContext(
3615 if (target ==
nullptr) {
3616 SetError(
"No target exists!");
3622 if (exe_module_sp ==
nullptr) {
3623 SetError(
"No executable in target!");
3630 void Launch(Window &window) {
3633 bool all_fields_are_valid = CheckFieldsValidity();
3634 if (!all_fields_are_valid)
3637 bool process_is_running = StopRunningProcess();
3638 if (process_is_running)
3641 Target *target = GetTarget();
3645 StreamString stream;
3646 ProcessLaunchInfo launch_info = GetLaunchInfo();
3649 if (status.
Fail()) {
3656 SetError(
"Launched successfully but target has no process!");
3660 window.GetParent()->RemoveSubWindow(&window);
3664 Debugger &m_debugger;
3665 WindowSP m_main_window_sp;
3667 ArgumentsFieldDelegate *m_arguments_field;
3668 EnvironmentVariableListFieldDelegate *m_target_environment_field;
3669 DirectoryFieldDelegate *m_working_directory_field;
3671 BooleanFieldDelegate *m_show_advanced_field;
3673 BooleanFieldDelegate *m_stop_at_entry_field;
3674 BooleanFieldDelegate *m_detach_on_error_field;
3675 BooleanFieldDelegate *m_disable_aslr_field;
3676 ProcessPluginFieldDelegate *m_plugin_field;
3677 ArchFieldDelegate *m_arch_field;
3678 FileFieldDelegate *m_shell_field;
3679 BooleanFieldDelegate *m_expand_shell_arguments_field;
3680 BooleanFieldDelegate *m_disable_standard_io_field;
3681 FileFieldDelegate *m_standard_input_field;
3682 FileFieldDelegate *m_standard_output_field;
3683 FileFieldDelegate *m_standard_error_field;
3685 BooleanFieldDelegate *m_show_inherited_environment_field;
3686 EnvironmentVariableListFieldDelegate *m_inherited_environment_field;
3693class SearcherDelegate {
3695 SearcherDelegate() =
default;
3697 virtual ~SearcherDelegate() =
default;
3699 virtual int GetNumberOfMatches() = 0;
3702 virtual const std::string &GetMatchTextAtIndex(
int index) = 0;
3706 virtual void UpdateMatches(
const std::string &text) = 0;
3710 virtual void ExecuteCallback(
int match_index) = 0;
3713typedef std::shared_ptr<SearcherDelegate> SearcherDelegateSP;
3715class SearcherWindowDelegate :
public WindowDelegate {
3717 SearcherWindowDelegate(SearcherDelegateSP &delegate_sp)
3718 : m_delegate_sp(delegate_sp), m_text_field(
"Search",
"", false) {
3740 int GetLastVisibleMatch(
int height) {
3741 int index = m_first_visible_match + height;
3742 return std::min(index, m_delegate_sp->GetNumberOfMatches()) - 1;
3745 int GetNumberOfVisibleMatches(
int height) {
3746 return GetLastVisibleMatch(height) - m_first_visible_match + 1;
3749 void UpdateScrolling(Surface &surface) {
3750 if (m_selected_match < m_first_visible_match) {
3751 m_first_visible_match = m_selected_match;
3755 int height = surface.GetHeight();
3756 int last_visible_match = GetLastVisibleMatch(height);
3757 if (m_selected_match > last_visible_match) {
3758 m_first_visible_match = m_selected_match - height + 1;
3762 void DrawMatches(Surface &surface) {
3763 if (m_delegate_sp->GetNumberOfMatches() == 0)
3766 UpdateScrolling(surface);
3768 int count = GetNumberOfVisibleMatches(surface.GetHeight());
3769 for (
int i = 0; i < count; i++) {
3770 surface.MoveCursor(1, i);
3771 int current_match = m_first_visible_match + i;
3772 if (current_match == m_selected_match)
3773 surface.AttributeOn(A_REVERSE);
3775 m_delegate_sp->GetMatchTextAtIndex(current_match).c_str());
3776 if (current_match == m_selected_match)
3777 surface.AttributeOff(A_REVERSE);
3781 void DrawContent(Surface &surface) {
3782 Rect content_bounds = surface.GetFrame();
3783 Rect text_field_bounds, matchs_bounds;
3784 content_bounds.HorizontalSplit(m_text_field.FieldDelegateGetHeight(),
3785 text_field_bounds, matchs_bounds);
3786 Surface text_field_surface = surface.SubSurface(text_field_bounds);
3787 Surface matches_surface = surface.SubSurface(matchs_bounds);
3789 m_text_field.FieldDelegateDraw(text_field_surface,
true);
3790 DrawMatches(matches_surface);
3793 bool WindowDelegateDraw(Window &window,
bool force)
override {
3796 window.DrawTitleBox(window.GetName(),
"Press Esc to Cancel");
3798 Rect content_bounds = window.GetFrame();
3799 content_bounds.Inset(2, 2);
3800 Surface content_surface = window.SubSurface(content_bounds);
3802 DrawContent(content_surface);
3807 if (m_selected_match != m_delegate_sp->GetNumberOfMatches() - 1)
3811 void SelectPrevious() {
3812 if (m_selected_match != 0)
3816 void ExecuteCallback(Window &window) {
3817 m_delegate_sp->ExecuteCallback(m_selected_match);
3818 window.GetParent()->RemoveSubWindow(&window);
3821 void UpdateMatches() {
3822 m_delegate_sp->UpdateMatches(m_text_field.GetText());
3823 m_selected_match = 0;
3826 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override {
3831 ExecuteCallback(window);
3842 window.GetParent()->RemoveSubWindow(&window);
3848 if (m_text_field.FieldDelegateHandleChar(key) == eKeyHandled)
3855 SearcherDelegateSP m_delegate_sp;
3856 TextFieldDelegate m_text_field;
3858 int m_selected_match = 0;
3860 int m_first_visible_match = 0;
3870class CommonCompletionSearcherDelegate :
public SearcherDelegate {
3872 typedef std::function<void(
const std::string &)> CallbackType;
3874 CommonCompletionSearcherDelegate(Debugger &debugger, uint32_t completion_mask,
3875 CallbackType callback)
3876 : m_debugger(debugger), m_completion_mask(completion_mask),
3877 m_callback(callback) {}
3879 int GetNumberOfMatches()
override {
return m_matches.GetSize(); }
3881 const std::string &GetMatchTextAtIndex(
int index)
override {
3882 return m_matches[index];
3885 void UpdateMatches(
const std::string &text)
override {
3886 CompletionResult result;
3887 CompletionRequest request(text.c_str(), text.size(), result);
3889 m_debugger.GetCommandInterpreter(), m_completion_mask, request,
3894 void ExecuteCallback(
int match_index)
override {
3895 m_callback(m_matches[match_index]);
3899 Debugger &m_debugger;
3901 uint32_t m_completion_mask;
3904 CallbackType m_callback;
3905 StringList m_matches;
3914 virtual ~MenuDelegate() =
default;
3916 virtual MenuActionResult MenuDelegateAction(Menu &menu) = 0;
3919class Menu :
public WindowDelegate {
3921 enum class Type {
Invalid, Bar, Item, Separator };
3927 Menu(
const char *name,
const char *key_name,
int key_value,
3928 uint64_t identifier);
3930 ~Menu()
override =
default;
3932 const MenuDelegateSP &GetDelegate()
const {
return m_delegate_sp; }
3934 void SetDelegate(
const MenuDelegateSP &delegate_sp) {
3935 m_delegate_sp = delegate_sp;
3938 void RecalculateNameLengths();
3940 void AddSubmenu(
const MenuSP &menu_sp);
3942 int DrawAndRunMenu(Window &window);
3944 void DrawMenuTitle(Window &window,
bool highlight);
3946 bool WindowDelegateDraw(Window &window,
bool force)
override;
3948 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override;
3950 MenuActionResult ActionPrivate(Menu &menu) {
3951 MenuActionResult result = MenuActionResult::NotHandled;
3952 if (m_delegate_sp) {
3953 result = m_delegate_sp->MenuDelegateAction(menu);
3954 if (result != MenuActionResult::NotHandled)
3956 }
else if (m_parent) {
3957 result = m_parent->ActionPrivate(menu);
3958 if (result != MenuActionResult::NotHandled)
3961 return m_canned_result;
3964 MenuActionResult Action() {
3967 return ActionPrivate(*
this);
3970 void SetCannedResult(MenuActionResult result) { m_canned_result = result; }
3972 Menus &GetSubmenus() {
return m_submenus; }
3974 const Menus &GetSubmenus()
const {
return m_submenus; }
3976 int GetSelectedSubmenuIndex()
const {
return m_selected; }
3978 void SetSelectedSubmenuIndex(
int idx) { m_selected = idx; }
3980 Type GetType()
const {
return m_type; }
3982 int GetStartingColumn()
const {
return m_start_col; }
3984 void SetStartingColumn(
int col) { m_start_col = col; }
3986 int GetKeyValue()
const {
return m_key_value; }
3988 std::string &
GetName() {
return m_name; }
3990 int GetDrawWidth()
const {
3991 return m_max_submenu_name_length + m_max_submenu_key_name_length + 8;
3994 uint64_t GetIdentifier()
const {
return m_identifier; }
3996 void SetIdentifier(uint64_t identifier) { m_identifier = identifier; }
4000 std::string m_key_name;
4001 uint64_t m_identifier;
4005 int m_max_submenu_name_length;
4006 int m_max_submenu_key_name_length;
4010 WindowSP m_menu_window_sp;
4011 MenuActionResult m_canned_result;
4012 MenuDelegateSP m_delegate_sp;
4016Menu::Menu(Type type)
4017 : m_name(), m_key_name(), m_identifier(0), m_type(type), m_key_value(0),
4018 m_start_col(0), m_max_submenu_name_length(0),
4019 m_max_submenu_key_name_length(0), m_selected(0), m_parent(nullptr),
4020 m_submenus(), m_canned_result(MenuActionResult::NotHandled),
4024Menu::Menu(
const char *name,
const char *key_name,
int key_value,
4025 uint64_t identifier)
4026 : m_name(), m_key_name(), m_identifier(identifier), m_type(
Type::
Invalid),
4027 m_key_value(key_value), m_start_col(0), m_max_submenu_name_length(0),
4028 m_max_submenu_key_name_length(0), m_selected(0), m_parent(nullptr),
4029 m_submenus(), m_canned_result(MenuActionResult::NotHandled),
4031 if (name && name[0]) {
4033 m_type = Type::Item;
4034 if (key_name && key_name[0])
4035 m_key_name = key_name;
4037 m_type = Type::Separator;
4041void Menu::RecalculateNameLengths() {
4042 m_max_submenu_name_length = 0;
4043 m_max_submenu_key_name_length = 0;
4044 Menus &submenus = GetSubmenus();
4045 const size_t num_submenus = submenus.size();
4046 for (
size_t i = 0; i < num_submenus; ++i) {
4047 Menu *submenu = submenus[i].get();
4048 if (
static_cast<size_t>(m_max_submenu_name_length) < submenu->m_name.size())
4049 m_max_submenu_name_length = submenu->m_name.size();
4050 if (
static_cast<size_t>(m_max_submenu_key_name_length) <
4051 submenu->m_key_name.size())
4052 m_max_submenu_key_name_length = submenu->m_key_name.size();
4056void Menu::AddSubmenu(
const MenuSP &menu_sp) {
4057 menu_sp->m_parent =
this;
4058 if (
static_cast<size_t>(m_max_submenu_name_length) < menu_sp->m_name.size())
4059 m_max_submenu_name_length = menu_sp->m_name.size();
4060 if (
static_cast<size_t>(m_max_submenu_key_name_length) <
4061 menu_sp->m_key_name.size())
4062 m_max_submenu_key_name_length = menu_sp->m_key_name.size();
4063 m_submenus.push_back(menu_sp);
4066void Menu::DrawMenuTitle(Window &window,
bool highlight) {
4067 if (m_type == Type::Separator) {
4068 window.MoveCursor(0, window.GetCursorY());
4069 window.PutChar(ACS_LTEE);
4070 int width = window.GetWidth();
4073 for (
int i = 0; i < width; ++i)
4074 window.PutChar(ACS_HLINE);
4076 window.PutChar(ACS_RTEE);
4078 const int shortcut_key = m_key_value;
4079 bool underlined_shortcut =
false;
4080 const attr_t highlight_attr = A_REVERSE;
4082 window.AttributeOn(highlight_attr);
4083 if (llvm::isPrint(shortcut_key)) {
4084 size_t lower_pos = m_name.find(tolower(shortcut_key));
4085 size_t upper_pos = m_name.find(toupper(shortcut_key));
4086 const char *name = m_name.c_str();
4087 size_t pos = std::min<size_t>(lower_pos, upper_pos);
4088 if (pos != std::string::npos) {
4089 underlined_shortcut =
true;
4091 window.PutCString(name, pos);
4094 const attr_t shortcut_attr = A_UNDERLINE | A_BOLD;
4095 window.AttributeOn(shortcut_attr);
4096 window.PutChar(name[0]);
4097 window.AttributeOff(shortcut_attr);
4100 window.PutCString(name);
4104 if (!underlined_shortcut) {
4105 window.PutCString(m_name.c_str());
4109 window.AttributeOff(highlight_attr);
4111 if (m_key_name.empty()) {
4112 if (!underlined_shortcut && llvm::isPrint(m_key_value)) {
4113 window.AttributeOn(COLOR_PAIR(MagentaOnWhite));
4114 window.Printf(
" (%c)", m_key_value);
4115 window.AttributeOff(COLOR_PAIR(MagentaOnWhite));
4118 window.AttributeOn(COLOR_PAIR(MagentaOnWhite));
4119 window.Printf(
" (%s)", m_key_name.c_str());
4120 window.AttributeOff(COLOR_PAIR(MagentaOnWhite));
4125bool Menu::WindowDelegateDraw(Window &window,
bool force) {
4126 Menus &submenus = GetSubmenus();
4127 const size_t num_submenus = submenus.size();
4128 const int selected_idx = GetSelectedSubmenuIndex();
4129 Menu::Type menu_type = GetType();
4130 switch (menu_type) {
4131 case Menu::Type::Bar: {
4132 window.SetBackground(BlackOnWhite);
4133 window.MoveCursor(0, 0);
4134 for (
size_t i = 0; i < num_submenus; ++i) {
4135 Menu *menu = submenus[i].get();
4137 window.PutChar(
' ');
4138 menu->SetStartingColumn(window.GetCursorX());
4139 window.PutCString(
"| ");
4140 menu->DrawMenuTitle(window,
false);
4142 window.PutCString(
" |");
4145 case Menu::Type::Item: {
4152 window.SetBackground(BlackOnWhite);
4154 for (
size_t i = 0; i < num_submenus; ++i) {
4155 const bool is_selected = (i ==
static_cast<size_t>(selected_idx));
4156 window.MoveCursor(x, y + i);
4162 submenus[i]->DrawMenuTitle(window, is_selected);
4164 window.MoveCursor(cursor_x, cursor_y);
4168 case Menu::Type::Separator:
4174HandleCharResult Menu::WindowDelegateHandleChar(Window &window,
int key) {
4175 HandleCharResult result = eKeyNotHandled;
4177 Menus &submenus = GetSubmenus();
4178 const size_t num_submenus = submenus.size();
4179 const int selected_idx = GetSelectedSubmenuIndex();
4180 Menu::Type menu_type = GetType();
4181 if (menu_type == Menu::Type::Bar) {
4187 if (selected_idx <
static_cast<int>(num_submenus))
4188 run_menu_sp = submenus[selected_idx];
4189 else if (!submenus.empty())
4190 run_menu_sp = submenus.front();
4191 result = eKeyHandled;
4196 if (m_selected >=
static_cast<int>(num_submenus))
4198 if (m_selected <
static_cast<int>(num_submenus))
4199 run_menu_sp = submenus[m_selected];
4200 else if (!submenus.empty())
4201 run_menu_sp = submenus.front();
4202 result = eKeyHandled;
4208 m_selected = num_submenus - 1;
4209 if (m_selected <
static_cast<int>(num_submenus))
4210 run_menu_sp = submenus[m_selected];
4211 else if (!submenus.empty())
4212 run_menu_sp = submenus.front();
4213 result = eKeyHandled;
4217 for (
size_t i = 0; i < num_submenus; ++i) {
4218 if (submenus[i]->GetKeyValue() == key) {
4219 SetSelectedSubmenuIndex(i);
4220 run_menu_sp = submenus[i];
4221 result = eKeyHandled;
4232 if (run_menu_sp->Action() == MenuActionResult::Quit)
4233 return eQuitApplication;
4236 menu_bounds.origin.x = run_menu_sp->GetStartingColumn();
4237 menu_bounds.origin.y = 1;
4238 menu_bounds.size.width = run_menu_sp->GetDrawWidth();
4239 menu_bounds.size.height = run_menu_sp->GetSubmenus().size() + 2;
4240 if (m_menu_window_sp)
4241 window.GetParent()->RemoveSubWindow(m_menu_window_sp.get());
4243 m_menu_window_sp = window.GetParent()->CreateSubWindow(
4244 run_menu_sp->GetName().c_str(), menu_bounds,
true);
4245 m_menu_window_sp->SetDelegate(run_menu_sp);
4247 }
else if (menu_type == Menu::Type::Item) {
4250 if (m_submenus.size() > 1) {
4251 const int start_select = m_selected;
4252 while (++m_selected != start_select) {
4253 if (
static_cast<size_t>(m_selected) >= num_submenus)
4255 if (m_submenus[m_selected]->GetType() == Type::Separator)
4265 if (m_submenus.size() > 1) {
4266 const int start_select = m_selected;
4267 while (--m_selected != start_select) {
4268 if (m_selected <
static_cast<int>(0))
4269 m_selected = num_submenus - 1;
4270 if (m_submenus[m_selected]->GetType() == Type::Separator)
4280 if (
static_cast<size_t>(selected_idx) < num_submenus) {
4281 if (submenus[selected_idx]->Action() == MenuActionResult::Quit)
4282 return eQuitApplication;
4283 window.GetParent()->RemoveSubWindow(&window);
4290 window.GetParent()->RemoveSubWindow(&window);
4294 for (
size_t i = 0; i < num_submenus; ++i) {
4295 Menu *menu = submenus[i].get();
4296 if (menu->GetKeyValue() == key) {
4297 SetSelectedSubmenuIndex(i);
4298 window.GetParent()->RemoveSubWindow(&window);
4299 if (menu->Action() == MenuActionResult::Quit)
4300 return eQuitApplication;
4306 }
else if (menu_type == Menu::Type::Separator) {
4313 Application(FILE *in, FILE *out) : m_window_sp(), m_in(in), m_out(out) {}
4316 m_window_delegates.clear();
4317 m_window_sp.reset();
4319 ::delscreen(m_screen);
4325 m_screen = ::newterm(
nullptr, m_out, m_in);
4329 ::keypad(stdscr, TRUE);
4332 void Terminate() { ::endwin(); }
4334 void Run(Debugger &debugger) {
4336 int delay_in_tenths_of_a_second = 1;
4344 halfdelay(delay_in_tenths_of_a_second);
4353 m_update_screen =
true;
4354#if defined(__APPLE__)
4355 std::deque<int> escape_chars;
4359 if (m_update_screen) {
4360 m_window_sp->Draw(
false);
4368 m_window_sp->MoveCursor(0, 0);
4371 m_update_screen =
false;
4374#if defined(__APPLE__)
4379 if (escape_chars.empty())
4380 ch = m_window_sp->GetChar();
4382 ch = escape_chars.front();
4383 escape_chars.pop_front();
4385 if (ch == KEY_ESCAPE) {
4386 int ch2 = m_window_sp->GetChar();
4388 int ch3 = m_window_sp->GetChar();
4403 escape_chars.push_back(ch2);
4405 escape_chars.push_back(ch3);
4408 }
else if (ch2 != -1)
4409 escape_chars.push_back(ch2);
4412 int ch = m_window_sp->GetChar();
4416 if (feof(m_in) || ferror(m_in)) {
4421 while (listener_sp->PeekAtNextEvent()) {
4422 listener_sp->GetEvent(event_sp, std::chrono::seconds(0));
4425 Broadcaster *broadcaster = event_sp->GetBroadcaster();
4428 ConstString broadcaster_class(
4430 if (broadcaster_class == broadcaster_class_process) {
4431 m_update_screen =
true;
4439 HandleCharResult key_result = m_window_sp->HandleChar(ch);
4440 switch (key_result) {
4442 m_update_screen =
true;
4444 case eKeyNotHandled:
4446 redrawwin(m_window_sp->get());
4447 m_update_screen =
true;
4450 case eQuitApplication:
4460 WindowSP &GetMainWindow() {
4462 m_window_sp = std::make_shared<Window>(
"main", stdscr,
false);
4466 void TerminalSizeChanged() {
4469 Rect content_bounds = m_window_sp->GetFrame();
4470 m_window_sp->SetBounds(content_bounds);
4471 if (WindowSP menubar_window_sp = m_window_sp->FindSubWindow(
"Menubar"))
4472 menubar_window_sp->SetBounds(content_bounds.MakeMenuBar());
4473 if (WindowSP status_window_sp = m_window_sp->FindSubWindow(
"Status"))
4474 status_window_sp->SetBounds(content_bounds.MakeStatusBar());
4476 WindowSP source_window_sp = m_window_sp->FindSubWindow(
"Source");
4477 WindowSP variables_window_sp = m_window_sp->FindSubWindow(
"Variables");
4478 WindowSP registers_window_sp = m_window_sp->FindSubWindow(
"Registers");
4479 WindowSP threads_window_sp = m_window_sp->FindSubWindow(
"Threads");
4481 Rect threads_bounds;
4482 Rect source_variables_bounds;
4483 content_bounds.VerticalSplitPercentage(0.80, source_variables_bounds,
4485 if (threads_window_sp)
4486 threads_window_sp->SetBounds(threads_bounds);
4488 source_variables_bounds = content_bounds;
4491 Rect variables_registers_bounds;
4492 source_variables_bounds.HorizontalSplitPercentage(
4493 0.70, source_bounds, variables_registers_bounds);
4494 if (variables_window_sp || registers_window_sp) {
4495 if (variables_window_sp && registers_window_sp) {
4496 Rect variables_bounds;
4497 Rect registers_bounds;
4498 variables_registers_bounds.VerticalSplitPercentage(
4499 0.50, variables_bounds, registers_bounds);
4500 variables_window_sp->SetBounds(variables_bounds);
4501 registers_window_sp->SetBounds(registers_bounds);
4502 }
else if (variables_window_sp) {
4503 variables_window_sp->SetBounds(variables_registers_bounds);
4505 registers_window_sp->SetBounds(variables_registers_bounds);
4508 source_bounds = source_variables_bounds;
4511 source_window_sp->SetBounds(source_bounds);
4514 redrawwin(m_window_sp->get());
4515 m_update_screen =
true;
4519 WindowSP m_window_sp;
4520 WindowDelegates m_window_delegates;
4521 SCREEN *m_screen =
nullptr;
4524 bool m_update_screen =
false;
4533 ValueObjectUpdater value;
4536 uint32_t children_stop_id = 0;
4540 bool might_have_children;
4541 bool expanded =
false;
4542 bool calculated_children =
false;
4543 std::vector<Row> children;
4546 : value(v), parent(p),
4547 might_have_children(v ? v->MightHaveChildren() : false) {}
4549 size_t GetDepth()
const {
4551 return 1 + parent->GetDepth();
4555 void Expand() { expanded =
true; }
4557 std::vector<Row> &GetChildren() {
4559 auto stop_id = process_sp->GetStopID();
4560 if (process_sp && stop_id != children_stop_id) {
4561 children_stop_id = stop_id;
4562 calculated_children =
false;
4564 if (!calculated_children) {
4566 calculated_children =
true;
4569 const uint32_t num_children = valobj->GetNumChildrenIgnoringErrors();
4570 for (
size_t i = 0; i < num_children; ++i) {
4571 children.push_back(Row(valobj->GetChildAtIndex(i),
this));
4580 calculated_children =
false;
4584 void DrawTree(Window &window) {
4586 parent->DrawTreeForChild(window,
this, 0);
4588 if (might_have_children &&
4589 (!calculated_children || !GetChildren().empty())) {
4607 window.PutChar(ACS_DIAMOND);
4608 window.PutChar(ACS_HLINE);
4612 void DrawTreeForChild(Window &window, Row *child, uint32_t reverse_depth) {
4614 parent->DrawTreeForChild(window,
this, reverse_depth + 1);
4616 if (&GetChildren().back() == child) {
4618 if (reverse_depth == 0) {
4619 window.PutChar(ACS_LLCORNER);
4620 window.PutChar(ACS_HLINE);
4622 window.PutChar(
' ');
4623 window.PutChar(
' ');
4626 if (reverse_depth == 0) {
4627 window.PutChar(ACS_LTEE);
4628 window.PutChar(ACS_HLINE);
4630 window.PutChar(ACS_VLINE);
4631 window.PutChar(
' ');
4637struct DisplayOptions {
4645 TreeDelegate() =
default;
4646 virtual ~TreeDelegate() =
default;
4648 virtual void TreeDelegateDrawTreeItem(TreeItem &item, Window &window) = 0;
4649 virtual void TreeDelegateGenerateChildren(TreeItem &item) = 0;
4650 virtual void TreeDelegateUpdateSelection(TreeItem &root,
int &selection_index,
4651 TreeItem *&selected_item) {}
4654 virtual bool TreeDelegateItemSelected(TreeItem &item) = 0;
4655 virtual bool TreeDelegateExpandRootByDefault() {
return false; }
4659 virtual bool TreeDelegateShouldDraw() {
return true; }
4662typedef std::shared_ptr<TreeDelegate> TreeDelegateSP;
4664struct TreeItemData {
4665 TreeItemData(TreeItem *parent, TreeDelegate &delegate,
4666 bool might_have_children,
bool is_expanded)
4667 : m_parent(parent), m_delegate(&delegate),
4668 m_might_have_children(might_have_children), m_is_expanded(is_expanded) {
4673 TreeDelegate *m_delegate;
4674 void *m_user_data =
nullptr;
4675 uint64_t m_identifier = 0;
4679 bool m_might_have_children;
4680 bool m_is_expanded =
false;
4683class TreeItem :
public TreeItemData {
4685 TreeItem(TreeItem *parent, TreeDelegate &delegate,
bool might_have_children)
4686 : TreeItemData(parent, delegate, might_have_children,
4688 ? delegate.TreeDelegateExpandRootByDefault()
4692 TreeItem(
const TreeItem &) =
delete;
4693 TreeItem &operator=(
const TreeItem &rhs) =
delete;
4695 TreeItem &operator=(TreeItem &&rhs) {
4697 TreeItemData::operator=(std::move(rhs));
4698 AdoptChildren(rhs.m_children);
4703 TreeItem(TreeItem &&rhs) : TreeItemData(std::move(rhs)) {
4704 AdoptChildren(rhs.m_children);
4707 size_t GetDepth()
const {
4709 return 1 + m_parent->GetDepth();
4713 int GetRowIndex()
const {
return m_row_idx; }
4715 void ClearChildren() { m_children.clear(); }
4717 void Resize(
size_t n, TreeDelegate &delegate,
bool might_have_children) {
4718 if (m_children.size() >= n) {
4719 m_children.erase(m_children.begin() + n, m_children.end());
4722 m_children.reserve(n);
4723 std::generate_n(std::back_inserter(m_children), n - m_children.size(),
4724 [&, parent =
this]() {
4725 return TreeItem(parent, delegate, might_have_children);
4729 TreeItem &operator[](
size_t i) {
return m_children[i]; }
4731 void SetRowIndex(
int row_idx) { m_row_idx = row_idx; }
4733 size_t GetNumChildren() {
4734 m_delegate->TreeDelegateGenerateChildren(*
this);
4735 return m_children.size();
4738 void ItemWasSelected() { m_delegate->TreeDelegateItemSelected(*
this); }
4740 void CalculateRowIndexes(
int &row_idx) {
4741 SetRowIndex(row_idx);
4744 const bool expanded = IsExpanded();
4748 if (m_parent ==
nullptr || expanded)
4751 for (
auto &item : m_children) {
4753 item.CalculateRowIndexes(row_idx);
4755 item.SetRowIndex(-1);
4759 TreeItem *GetParent() {
return m_parent; }
4761 bool IsExpanded()
const {
return m_is_expanded; }
4763 void Expand() { m_is_expanded =
true; }
4765 void Unexpand() { m_is_expanded =
false; }
4767 bool Draw(Window &window,
const int first_visible_row,
4768 const uint32_t selected_row_idx,
int &row_idx,
int &num_rows_left) {
4769 if (num_rows_left <= 0)
4772 if (m_row_idx >= first_visible_row) {
4773 window.MoveCursor(2, row_idx + 1);
4776 m_parent->DrawTreeForChild(window,
this, 0);
4778 if (m_might_have_children) {
4796 window.PutChar(ACS_DIAMOND);
4797 window.PutChar(ACS_HLINE);
4799 bool highlight = (selected_row_idx ==
static_cast<size_t>(m_row_idx)) &&
4803 window.AttributeOn(A_REVERSE);
4805 m_delegate->TreeDelegateDrawTreeItem(*
this, window);
4808 window.AttributeOff(A_REVERSE);
4813 if (num_rows_left <= 0)
4817 for (
auto &item : m_children) {
4820 if (!item.Draw(window, first_visible_row, selected_row_idx, row_idx,
4825 return num_rows_left >= 0;
4828 void DrawTreeForChild(Window &window, TreeItem *child,
4829 uint32_t reverse_depth) {
4831 m_parent->DrawTreeForChild(window,
this, reverse_depth + 1);
4833 if (&m_children.back() == child) {
4835 if (reverse_depth == 0) {
4836 window.PutChar(ACS_LLCORNER);
4837 window.PutChar(ACS_HLINE);
4839 window.PutChar(
' ');
4840 window.PutChar(
' ');
4843 if (reverse_depth == 0) {
4844 window.PutChar(ACS_LTEE);
4845 window.PutChar(ACS_HLINE);
4847 window.PutChar(ACS_VLINE);
4848 window.PutChar(
' ');
4853 TreeItem *GetItemForRowIndex(uint32_t row_idx) {
4854 if (
static_cast<uint32_t
>(m_row_idx) == row_idx)
4856 if (m_children.empty())
4859 for (
auto &item : m_children) {
4860 TreeItem *selected_item_ptr = item.GetItemForRowIndex(row_idx);
4861 if (selected_item_ptr)
4862 return selected_item_ptr;
4868 void *GetUserData()
const {
return m_user_data; }
4870 void SetUserData(
void *user_data) { m_user_data = user_data; }
4872 uint64_t GetIdentifier()
const {
return m_identifier; }
4874 void SetIdentifier(uint64_t identifier) { m_identifier = identifier; }
4876 const std::string &GetText()
const {
return m_text; }
4878 void SetText(
const char *text) {
4879 if (text ==
nullptr) {
4886 void SetMightHaveChildren(
bool b) { m_might_have_children = b; }
4889 void AdoptChildren(std::vector<TreeItem> &children) {
4890 m_children = std::move(children);
4891 for (
auto &child : m_children)
4892 child.m_parent =
this;
4895 std::vector<TreeItem> m_children;
4898class TreeWindowDelegate :
public WindowDelegate {
4900 TreeWindowDelegate(Debugger &debugger,
const TreeDelegateSP &delegate_sp)
4901 : m_debugger(debugger), m_delegate_sp(delegate_sp),
4902 m_root(nullptr, *delegate_sp, true) {}
4904 int NumVisibleRows()
const {
return m_max_y - m_min_y; }
4906 bool WindowDelegateDraw(Window &window,
bool force)
override {
4909 m_max_x = window.GetWidth() - 1;
4910 m_max_y = window.GetHeight() - 1;
4913 window.DrawTitleBox(window.GetName());
4915 if (!m_delegate_sp->TreeDelegateShouldDraw()) {
4916 m_selected_item =
nullptr;
4920 const int num_visible_rows = NumVisibleRows();
4922 m_root.CalculateRowIndexes(m_num_rows);
4923 m_delegate_sp->TreeDelegateUpdateSelection(m_root, m_selected_row_idx,
4929 if (m_first_visible_row > 0 && m_num_rows < num_visible_rows)
4930 m_first_visible_row = 0;
4933 if (m_selected_row_idx < m_first_visible_row)
4934 m_first_visible_row = m_selected_row_idx;
4935 else if (m_first_visible_row + num_visible_rows <= m_selected_row_idx)
4936 m_first_visible_row = m_selected_row_idx - num_visible_rows + 1;
4939 int num_rows_left = num_visible_rows;
4940 m_root.Draw(window, m_first_visible_row, m_selected_row_idx, row_idx,
4943 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4948 const char *WindowDelegateGetHelpText()
override {
4949 return "Thread window keyboard shortcuts:";
4952 KeyHelp *WindowDelegateGetKeyHelp()
override {
4953 static curses::KeyHelp g_source_view_key_help[] = {
4954 {KEY_UP,
"Select previous item"},
4955 {KEY_DOWN,
"Select next item"},
4956 {KEY_RIGHT,
"Expand the selected item"},
4958 "Unexpand the selected item or select parent if not expanded"},
4959 {KEY_PPAGE,
"Page up"},
4960 {KEY_NPAGE,
"Page down"},
4961 {
'h',
"Show help dialog"},
4962 {
' ',
"Toggle item expansion"},
4966 return g_source_view_key_help;
4969 HandleCharResult WindowDelegateHandleChar(Window &window,
int c)
override {
4974 if (m_first_visible_row > 0) {
4975 if (m_first_visible_row > m_max_y)
4976 m_first_visible_row -= m_max_y;
4978 m_first_visible_row = 0;
4979 m_selected_row_idx = m_first_visible_row;
4980 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4981 if (m_selected_item)
4982 m_selected_item->ItemWasSelected();
4989 if (m_num_rows > m_max_y) {
4990 if (m_first_visible_row + m_max_y < m_num_rows) {
4991 m_first_visible_row += m_max_y;
4992 m_selected_row_idx = m_first_visible_row;
4993 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4994 if (m_selected_item)
4995 m_selected_item->ItemWasSelected();
5001 if (m_selected_row_idx > 0) {
5002 --m_selected_row_idx;
5003 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
5004 if (m_selected_item)
5005 m_selected_item->ItemWasSelected();
5010 if (m_selected_row_idx + 1 < m_num_rows) {
5011 ++m_selected_row_idx;
5012 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
5013 if (m_selected_item)
5014 m_selected_item->ItemWasSelected();
5019 if (m_selected_item) {
5020 if (!m_selected_item->IsExpanded())
5021 m_selected_item->Expand();
5026 if (m_selected_item) {
5027 if (m_selected_item->IsExpanded())
5028 m_selected_item->Unexpand();
5029 else if (m_selected_item->GetParent()) {
5030 m_selected_row_idx = m_selected_item->GetParent()->GetRowIndex();
5031 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
5032 if (m_selected_item)
5033 m_selected_item->ItemWasSelected();
5040 if (m_selected_item) {
5041 if (m_selected_item->IsExpanded())
5042 m_selected_item->Unexpand();
5044 m_selected_item->Expand();
5049 window.CreateHelpSubwindow();
5055 return eKeyNotHandled;
5059 Debugger &m_debugger;
5060 TreeDelegateSP m_delegate_sp;
5062 TreeItem *m_selected_item =
nullptr;
5064 int m_selected_row_idx = 0;
5065 int m_first_visible_row = 0;
5074class TextTreeDelegate :
public TreeDelegate {
5076 TextTreeDelegate() : TreeDelegate() {}
5078 ~TextTreeDelegate()
override =
default;
5080 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5081 window.PutCStringTruncated(1, item.GetText().c_str());
5084 void TreeDelegateGenerateChildren(TreeItem &item)
override {}
5086 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5089class FrameTreeDelegate :
public TreeDelegate {
5091 FrameTreeDelegate() : TreeDelegate() {
5093 "#${frame.index}: {${function.name}${function.pc-offset}}}", m_format);
5096 ~FrameTreeDelegate()
override =
default;
5098 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5101 const uint64_t frame_idx = item.GetIdentifier();
5105 const SymbolContext &sc =
5106 frame_sp->GetSymbolContext(eSymbolContextEverything);
5107 ExecutionContext exe_ctx(frame_sp);
5108 if (FormatEntity::Formatter(&sc, &exe_ctx,
nullptr,
false,
false)
5109 .
Format(m_format, strm)) {
5111 window.PutCStringTruncated(right_pad, strm.
GetString().str().c_str());
5117 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5121 bool TreeDelegateItemSelected(TreeItem &item)
override {
5124 thread->
GetProcess()->GetThreadList().SetSelectedThreadByID(
5126 const uint64_t frame_idx = item.GetIdentifier();
5134 FormatEntity::Entry m_format;
5137class ThreadTreeDelegate :
public TreeDelegate {
5139 ThreadTreeDelegate(Debugger &debugger)
5140 : TreeDelegate(), m_debugger(debugger) {
5142 "reason = ${thread.stop-reason}}",
5146 ~ThreadTreeDelegate()
override =
default;
5149 return m_debugger.GetCommandInterpreter()
5150 .GetExecutionContext()
5154 ThreadSP GetThread(
const TreeItem &item) {
5157 return process_sp->GetThreadList().FindThreadByID(item.GetIdentifier());
5161 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5162 ThreadSP thread_sp = GetThread(item);
5165 ExecutionContext exe_ctx(thread_sp);
5166 if (FormatEntity::Formatter(
nullptr, &exe_ctx,
nullptr,
false,
false)
5167 .
Format(m_format, strm)) {
5169 window.PutCStringTruncated(right_pad, strm.
GetString().str().c_str());
5174 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5176 if (process_sp && process_sp->IsAlive()) {
5177 StateType state = process_sp->GetState();
5179 ThreadSP thread_sp = GetThread(item);
5181 if (m_stop_id == process_sp->GetStopID() &&
5182 thread_sp->GetID() == m_tid)
5184 if (!m_frame_delegate_sp) {
5186 m_frame_delegate_sp = std::make_shared<FrameTreeDelegate>();
5189 m_stop_id = process_sp->GetStopID();
5190 m_tid = thread_sp->GetID();
5192 size_t num_frames = thread_sp->GetStackFrameCount();
5193 item.Resize(num_frames, *m_frame_delegate_sp,
false);
5194 for (
size_t i = 0; i < num_frames; ++i) {
5195 item[i].SetUserData(thread_sp.get());
5196 item[i].SetIdentifier(i);
5202 item.ClearChildren();
5205 bool TreeDelegateItemSelected(TreeItem &item)
override {
5207 if (process_sp && process_sp->IsAlive()) {
5208 StateType state = process_sp->GetState();
5210 ThreadSP thread_sp = GetThread(item);
5212 ThreadList &thread_list = thread_sp->GetProcess()->GetThreadList();
5213 std::lock_guard<std::recursive_mutex> guard(thread_list.
GetMutex());
5215 if (selected_thread_sp->GetID() != thread_sp->GetID()) {
5226 Debugger &m_debugger;
5227 std::shared_ptr<FrameTreeDelegate> m_frame_delegate_sp;
5230 FormatEntity::Entry m_format;
5233class ThreadsTreeDelegate :
public TreeDelegate {
5235 ThreadsTreeDelegate(Debugger &debugger)
5236 : TreeDelegate(), m_thread_delegate_sp(), m_debugger(debugger) {
5241 ~ThreadsTreeDelegate()
override =
default;
5244 return m_debugger.GetCommandInterpreter()
5245 .GetExecutionContext()
5249 bool TreeDelegateShouldDraw()
override {
5260 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5262 if (process_sp && process_sp->IsAlive()) {
5264 ExecutionContext exe_ctx(process_sp);
5265 if (FormatEntity::Formatter(
nullptr, &exe_ctx,
nullptr,
false,
false)
5266 .
Format(m_format, strm)) {
5268 window.PutCStringTruncated(right_pad, strm.
GetString().str().c_str());
5273 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5275 m_update_selection =
false;
5276 if (process_sp && process_sp->IsAlive()) {
5277 StateType state = process_sp->GetState();
5279 const uint32_t stop_id = process_sp->GetStopID();
5280 if (m_stop_id == stop_id)
5283 m_stop_id = stop_id;
5284 m_update_selection =
true;
5286 if (!m_thread_delegate_sp) {
5289 m_thread_delegate_sp =
5290 std::make_shared<ThreadTreeDelegate>(m_debugger);
5293 ThreadList &threads = process_sp->GetThreadList();
5294 std::lock_guard<std::recursive_mutex> guard(threads.
GetMutex());
5296 size_t num_threads = threads.
GetSize();
5297 item.Resize(num_threads, *m_thread_delegate_sp,
false);
5298 for (
size_t i = 0; i < num_threads; ++i) {
5300 item[i].SetIdentifier(thread->GetID());
5301 item[i].SetMightHaveChildren(
true);
5302 if (selected_thread->GetID() == thread->GetID())
5308 item.ClearChildren();
5311 void TreeDelegateUpdateSelection(TreeItem &root,
int &selection_index,
5312 TreeItem *&selected_item)
override {
5313 if (!m_update_selection)
5317 if (!(process_sp && process_sp->IsAlive()))
5320 StateType state = process_sp->GetState();
5324 ThreadList &threads = process_sp->GetThreadList();
5325 std::lock_guard<std::recursive_mutex> guard(threads.
GetMutex());
5327 size_t num_threads = threads.
GetSize();
5328 for (
size_t i = 0; i < num_threads; ++i) {
5330 if (selected_thread->GetID() == thread->GetID()) {
5333 selection_index = selected_item->GetRowIndex();
5339 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5341 bool TreeDelegateExpandRootByDefault()
override {
return true; }
5344 std::shared_ptr<ThreadTreeDelegate> m_thread_delegate_sp;
5345 Debugger &m_debugger;
5347 bool m_update_selection =
false;
5348 FormatEntity::Entry m_format;
5351class BreakpointLocationTreeDelegate :
public TreeDelegate {
5353 BreakpointLocationTreeDelegate(Debugger &debugger)
5354 : TreeDelegate(), m_debugger(debugger) {}
5356 ~BreakpointLocationTreeDelegate()
override =
default;
5359 ExecutionContext exe_ctx(
5360 m_debugger.GetCommandInterpreter().GetExecutionContext());
5365 Breakpoint *breakpoint = (Breakpoint *)item.GetUserData();
5369 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5371 Process *process = GetProcess();
5372 StreamString stream;
5373 stream.
Printf(
"%i.%i: ", breakpoint_location->GetBreakpoint().GetID(),
5374 breakpoint_location->GetID());
5375 Address address = breakpoint_location->GetAddress();
5378 window.PutCStringTruncated(1, stream.
GetString().str().c_str());
5384 Address address = breakpoint_location->GetAddress();
5385 SymbolContext symbol_context;
5389 StreamString module_stream;
5391 symbol_context.
module_sp->GetFileSpec().Dump(
5396 if (symbol_context.
comp_unit !=
nullptr) {
5397 StreamString compile_unit_stream;
5398 compile_unit_stream.
PutCString(
"compile unit = ");
5400 &compile_unit_stream);
5403 if (symbol_context.
function !=
nullptr) {
5404 StreamString function_stream;
5412 StreamString location_stream;
5419 if (symbol_context.
symbol) {
5420 StreamString symbol_stream;
5421 if (breakpoint_location->IsReExported())
5422 symbol_stream.
PutCString(
"re-exported target = ");
5431 Process *process = GetProcess();
5433 StreamString address_stream;
5438 BreakpointSiteSP breakpoint_site = breakpoint_location->GetBreakpointSite();
5439 if (breakpoint_location->IsIndirect() && breakpoint_site) {
5440 Address resolved_address;
5441 resolved_address.
SetLoadAddress(breakpoint_site->GetLoadAddress(),
5442 &breakpoint_location->GetTarget());
5443 const Symbol *resolved_symbol =
5445 if (resolved_symbol) {
5446 StreamString indirect_target_stream;
5447 indirect_target_stream.
PutCString(
"indirect target = ");
5454 bool is_resolved = breakpoint_location->IsResolved();
5455 StreamString resolved_stream;
5456 resolved_stream.
Printf(
"resolved = %s", is_resolved ?
"true" :
"false");
5459 bool is_hardware = is_resolved && breakpoint_site->IsHardware();
5460 StreamString hardware_stream;
5461 hardware_stream.
Printf(
"hardware = %s", is_hardware ?
"true" :
"false");
5464 StreamString hit_count_stream;
5465 hit_count_stream.
Printf(
"hit count = %-4u",
5466 breakpoint_location->GetHitCount());
5472 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5474 StringList details = ComputeDetailsList(breakpoint_location);
5476 if (!m_string_delegate_sp)
5477 m_string_delegate_sp = std::make_shared<TextTreeDelegate>();
5479 item.Resize(details.
GetSize(), *m_string_delegate_sp,
false);
5480 for (
size_t i = 0; i < details.
GetSize(); i++) {
5485 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5488 Debugger &m_debugger;
5489 std::shared_ptr<TextTreeDelegate> m_string_delegate_sp;
5492class BreakpointTreeDelegate :
public TreeDelegate {
5494 BreakpointTreeDelegate(Debugger &debugger)
5495 : TreeDelegate(), m_debugger(debugger),
5496 m_breakpoint_location_delegate_sp() {}
5498 ~BreakpointTreeDelegate()
override =
default;
5502 .GetSelectedExecutionContext(
5505 BreakpointList &breakpoints = target->GetBreakpointList(
false);
5509 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5511 StreamString stream;
5512 stream.
Format(
"{0}: ", breakpoint->GetID());
5513 breakpoint->GetResolverDescription(&stream);
5514 breakpoint->GetFilterDescription(&stream);
5515 window.PutCStringTruncated(1, stream.
GetString().str().c_str());
5518 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5521 if (!m_breakpoint_location_delegate_sp)
5522 m_breakpoint_location_delegate_sp =
5523 std::make_shared<BreakpointLocationTreeDelegate>(m_debugger);
5525 item.Resize(breakpoint->GetNumLocations(),
5526 *m_breakpoint_location_delegate_sp,
true);
5527 for (
size_t i = 0; i < breakpoint->GetNumLocations(); i++) {
5528 item[i].SetIdentifier(i);
5529 item[i].SetUserData(breakpoint.get());
5533 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5536 Debugger &m_debugger;
5537 std::shared_ptr<BreakpointLocationTreeDelegate>
5538 m_breakpoint_location_delegate_sp;
5541class BreakpointsTreeDelegate :
public TreeDelegate {
5543 BreakpointsTreeDelegate(Debugger &debugger)
5544 : TreeDelegate(), m_debugger(debugger), m_breakpoint_delegate_sp() {}
5546 ~BreakpointsTreeDelegate()
override =
default;
5548 bool TreeDelegateShouldDraw()
override {
5550 .GetSelectedExecutionContext(
5559 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5560 window.PutCString(
"Breakpoints");
5563 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5565 .GetSelectedExecutionContext(
5569 BreakpointList &breakpoints = target->GetBreakpointList(
false);
5570 std::unique_lock<std::recursive_mutex> lock;
5573 if (!m_breakpoint_delegate_sp)
5574 m_breakpoint_delegate_sp =
5575 std::make_shared<BreakpointTreeDelegate>(m_debugger);
5577 item.Resize(breakpoints.
GetSize(), *m_breakpoint_delegate_sp,
true);
5578 for (
size_t i = 0; i < breakpoints.
GetSize(); i++) {
5579 item[i].SetIdentifier(i);
5583 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5585 bool TreeDelegateExpandRootByDefault()
override {
return true; }
5588 Debugger &m_debugger;
5589 std::shared_ptr<BreakpointTreeDelegate> m_breakpoint_delegate_sp;
5592class ValueObjectListDelegate :
public WindowDelegate {
5594 ValueObjectListDelegate() : m_rows() {}
5596 ValueObjectListDelegate(ValueObjectList &valobj_list) : m_rows() {
5597 SetValues(valobj_list);
5600 ~ValueObjectListDelegate()
override =
default;
5602 void SetValues(ValueObjectList &valobj_list) {
5603 m_selected_row =
nullptr;
5604 m_selected_row_idx = 0;
5605 m_first_visible_row = 0;
5608 for (
auto &valobj_sp : valobj_list.
GetObjects())
5609 m_rows.push_back(Row(valobj_sp,
nullptr));
5612 bool WindowDelegateDraw(Window &window,
bool force)
override {
5616 m_max_x = window.GetWidth() - 1;
5617 m_max_y = window.GetHeight() - 1;
5620 window.DrawTitleBox(window.GetName());
5622 const int num_visible_rows = NumVisibleRows();
5623 const int num_rows = CalculateTotalNumberRows(m_rows);
5628 if (m_first_visible_row > 0 && num_rows < num_visible_rows)
5629 m_first_visible_row = 0;
5632 if (m_selected_row_idx < m_first_visible_row)
5633 m_first_visible_row = m_selected_row_idx;
5634 else if (m_first_visible_row + num_visible_rows <= m_selected_row_idx)
5635 m_first_visible_row = m_selected_row_idx - num_visible_rows + 1;
5637 DisplayRows(window, m_rows, g_options);
5640 m_selected_row = GetRowForRowIndex(m_selected_row_idx);
5644 window.MoveCursor(m_selected_row->x, m_selected_row->y);
5649 KeyHelp *WindowDelegateGetKeyHelp()
override {
5650 static curses::KeyHelp g_source_view_key_help[] = {
5651 {KEY_UP,
"Select previous item"},
5652 {KEY_DOWN,
"Select next item"},
5653 {KEY_RIGHT,
"Expand selected item"},
5654 {KEY_LEFT,
"Unexpand selected item or select parent if not expanded"},
5655 {KEY_PPAGE,
"Page up"},
5656 {KEY_NPAGE,
"Page down"},
5657 {
'A',
"Format as annotated address"},
5658 {
'b',
"Format as binary"},
5659 {
'B',
"Format as hex bytes with ASCII"},
5660 {
'c',
"Format as character"},
5661 {
'd',
"Format as a signed integer"},
5662 {
'D',
"Format selected value using the default format for the type"},
5663 {
'f',
"Format as float"},
5664 {
'h',
"Show help dialog"},
5665 {
'i',
"Format as instructions"},
5666 {
'o',
"Format as octal"},
5667 {
'p',
"Format as pointer"},
5668 {
's',
"Format as C string"},
5669 {
't',
"Toggle showing/hiding type names"},
5670 {
'u',
"Format as an unsigned integer"},
5671 {
'x',
"Format as hex"},
5672 {
'X',
"Format as uppercase hex"},
5673 {
' ',
"Toggle item expansion"},
5677 return g_source_view_key_help;
5680 HandleCharResult WindowDelegateHandleChar(Window &window,
int c)
override {
5697 if (m_selected_row) {
5698 auto valobj_sp = m_selected_row->value.GetSP();
5700 valobj_sp->SetFormat(FormatForChar(c));
5706 g_options.show_types = !g_options.show_types;
5712 if (m_first_visible_row > 0) {
5713 if (
static_cast<int>(m_first_visible_row) > m_max_y)
5714 m_first_visible_row -= m_max_y;
5716 m_first_visible_row = 0;
5717 m_selected_row_idx = m_first_visible_row;
5724 if (m_num_rows >
static_cast<size_t>(m_max_y)) {
5725 if (m_first_visible_row + m_max_y < m_num_rows) {
5726 m_first_visible_row += m_max_y;
5727 m_selected_row_idx = m_first_visible_row;
5733 if (m_selected_row_idx > 0)
5734 --m_selected_row_idx;
5738 if (m_selected_row_idx + 1 < m_num_rows)
5739 ++m_selected_row_idx;
5743 if (m_selected_row) {
5744 if (!m_selected_row->expanded)
5745 m_selected_row->Expand();
5750 if (m_selected_row) {
5751 if (m_selected_row->expanded)
5752 m_selected_row->Unexpand();
5753 else if (m_selected_row->parent)
5754 m_selected_row_idx = m_selected_row->parent->row_idx;
5760 if (m_selected_row) {
5761 if (m_selected_row->expanded)
5762 m_selected_row->Unexpand();
5764 m_selected_row->Expand();
5769 window.CreateHelpSubwindow();
5775 return eKeyNotHandled;
5779 std::vector<Row> m_rows;
5780 Row *m_selected_row =
nullptr;
5781 uint32_t m_selected_row_idx = 0;
5782 uint32_t m_first_visible_row = 0;
5783 uint32_t m_num_rows = 0;
5789 static Format FormatForChar(
int c) {
5823 bool DisplayRowObject(Window &window, Row &row, DisplayOptions &options,
5824 bool highlight,
bool last_child) {
5825 ValueObject *valobj = row.value.GetSP().get();
5827 if (valobj ==
nullptr)
5830 const char *type_name =
5836 window.MoveCursor(row.x, row.y);
5838 row.DrawTree(window);
5841 window.AttributeOn(A_REVERSE);
5843 if (type_name && type_name[0])
5844 window.PrintfTruncated(1,
"(%s) ", type_name);
5846 if (name && name[0])
5847 window.PutCStringTruncated(1, name);
5849 attr_t changd_attr = 0;
5851 changd_attr = COLOR_PAIR(RedOnBlack) | A_BOLD;
5853 if (value && value[0]) {
5854 window.PutCStringTruncated(1,
" = ");
5856 window.AttributeOn(changd_attr);
5857 window.PutCStringTruncated(1, value);
5859 window.AttributeOff(changd_attr);
5862 if (summary && summary[0]) {
5863 window.PutCStringTruncated(1,
" ");
5865 window.AttributeOn(changd_attr);
5866 window.PutCStringTruncated(1, summary);
5868 window.AttributeOff(changd_attr);
5872 window.AttributeOff(A_REVERSE);
5877 void DisplayRows(Window &window, std::vector<Row> &rows,
5878 DisplayOptions &options) {
5882 bool window_is_active = window.IsActive();
5883 for (
auto &row : rows) {
5884 const bool last_child = row.parent && &rows[rows.size() - 1] == &row;
5886 row.row_idx = m_num_rows;
5887 if ((m_num_rows >= m_first_visible_row) &&
5888 ((m_num_rows - m_first_visible_row) <
5889 static_cast<size_t>(NumVisibleRows()))) {
5891 row.y = m_num_rows - m_first_visible_row + 1;
5892 if (DisplayRowObject(window, row, options,
5894 m_num_rows == m_selected_row_idx,
5908 auto &children = row.GetChildren();
5909 if (!children.empty()) {
5910 DisplayRows(window, children, options);
5916 int CalculateTotalNumberRows(std::vector<Row> &rows) {
5918 for (
auto &row : rows) {
5921 row_count += CalculateTotalNumberRows(row.GetChildren());
5926 static Row *GetRowForRowIndexImpl(std::vector<Row> &rows,
size_t &row_index) {
5927 for (
auto &row : rows) {
5933 auto &children = row.GetChildren();
5934 if (!children.empty()) {
5935 Row *result = GetRowForRowIndexImpl(children, row_index);
5945 Row *GetRowForRowIndex(
size_t row_index) {
5946 return GetRowForRowIndexImpl(m_rows, row_index);
5949 int NumVisibleRows()
const {
return m_max_y - m_min_y; }
5951 static DisplayOptions g_options;
5954class FrameVariablesWindowDelegate :
public ValueObjectListDelegate {
5956 FrameVariablesWindowDelegate(Debugger &debugger)
5957 : ValueObjectListDelegate(), m_debugger(debugger) {}
5959 ~FrameVariablesWindowDelegate()
override =
default;
5961 const char *WindowDelegateGetHelpText()
override {
5962 return "Frame variable window keyboard shortcuts:";
5965 bool WindowDelegateDraw(Window &window,
bool force)
override {
5966 ExecutionContext exe_ctx(
5967 m_debugger.GetCommandInterpreter().GetExecutionContext());
5969 Block *frame_block =
nullptr;
5970 StackFrame *frame =
nullptr;
5983 ValueObjectList local_values;
5986 if (m_frame_block != frame_block) {
5987 m_frame_block = frame_block;
5998 ValueObjectSP synthetic_value_sp = value_sp->GetSyntheticValue();
5999 if (synthetic_value_sp)
6000 local_values.
Append(synthetic_value_sp);
6002 local_values.
Append(value_sp);
6006 SetValues(local_values);
6010 m_frame_block =
nullptr;
6012 SetValues(local_values);
6015 return ValueObjectListDelegate::WindowDelegateDraw(window, force);
6019 Debugger &m_debugger;
6020 Block *m_frame_block =
nullptr;
6023class RegistersWindowDelegate :
public ValueObjectListDelegate {
6025 RegistersWindowDelegate(Debugger &debugger)
6026 : ValueObjectListDelegate(), m_debugger(debugger) {}
6028 ~RegistersWindowDelegate()
override =
default;
6030 const char *WindowDelegateGetHelpText()
override {
6031 return "Register window keyboard shortcuts:";
6034 bool WindowDelegateDraw(Window &window,
bool force)
override {
6035 ExecutionContext exe_ctx(
6036 m_debugger.GetCommandInterpreter().GetExecutionContext());
6039 ValueObjectList value_list;
6045 const uint32_t num_sets = reg_ctx->GetRegisterSetCount();
6046 for (uint32_t set_idx = 0; set_idx < num_sets; ++set_idx) {
6051 SetValues(value_list);
6055 if (process && process->
IsAlive())
6060 SetValues(value_list);
6063 return ValueObjectListDelegate::WindowDelegateDraw(window, force);
6067 Debugger &m_debugger;
6071static const char *CursesKeyToCString(
int ch) {
6072 static char g_desc[32];
6073 if (ch >= KEY_F0 && ch < KEY_F0 + 64) {
6074 snprintf(g_desc,
sizeof(g_desc),
"F%u", ch - KEY_F0);
6091 return "delete-line";
6093 return "insert-line";
6095 return "delete-char";
6097 return "insert-char";
6101 return "clear-to-eos";
6103 return "clear-to-eol";
6105 return "scroll-forward";
6107 return "scroll-backward";
6117 return "clear-all-tabs";
6123 return "lower-left key";
6125 return "upper left of keypad";
6127 return "upper right of keypad";
6129 return "center of keypad";
6131 return "lower left of keypad";
6133 return "lower right of keypad";
6135 return "back-tab key";
6139 return "cancel key";
6143 return "command key";
6147 return "create key";
6159 return "message key";
6167 return "options key";
6169 return "previous key";
6173 return "reference key";
6175 return "refresh key";
6177 return "replace key";
6179 return "restart key";
6181 return "resume key";
6185 return "shifted begin key";
6187 return "shifted cancel key";
6189 return "shifted command key";
6191 return "shifted copy key";
6193 return "shifted create key";
6195 return "shifted delete-character key";
6197 return "shifted delete-line key";
6199 return "select key";
6201 return "shifted end key";
6203 return "shifted clear-to-end-of-line key";
6205 return "shifted exit key";
6207 return "shifted find key";
6209 return "shifted help key";
6211 return "shifted home key";
6213 return "shifted insert-character key";
6215 return "shifted left-arrow key";
6217 return "shifted message key";
6219 return "shifted move key";
6221 return "shifted next key";
6223 return "shifted options key";
6225 return "shifted previous key";
6227 return "shifted print key";
6229 return "shifted redo key";
6231 return "shifted replace key";
6233 return "shifted right-arrow key";
6235 return "shifted resume key";
6237 return "shifted save key";
6239 return "shifted suspend key";
6241 return "shifted undo key";
6243 return "suspend key";
6247 return "Mouse event has occurred";
6249 return "Terminal resize event";
6252 return "We were interrupted by an event";
6263 if (llvm::isPrint(ch))
6264 snprintf(g_desc,
sizeof(g_desc),
"%c", ch);
6266 snprintf(g_desc,
sizeof(g_desc),
"\\x%2.2x", ch);
6272HelpDialogDelegate::HelpDialogDelegate(
const char *text,
6273 KeyHelp *key_help_array)
6275 if (text && text[0]) {
6276 m_text.SplitIntoLines(text);
6277 m_text.AppendString(
"");
6279 if (key_help_array) {
6280 for (KeyHelp *key = key_help_array; key->ch; ++key) {
6282 key_description.
Printf(
"%10s - %s", CursesKeyToCString(key->ch),
6284 m_text.AppendString(key_description.
GetString());
6289HelpDialogDelegate::~HelpDialogDelegate() =
default;
6291bool HelpDialogDelegate::WindowDelegateDraw(Window &window,
bool force) {
6293 const int window_height = window.GetHeight();
6296 const int min_y = y;
6297 const int max_y = window_height - 1 - y;
6298 const size_t num_visible_lines = max_y - min_y + 1;
6299 const size_t num_lines = m_text.GetSize();
6300 const char *bottom_message;
6301 if (num_lines <= num_visible_lines)
6302 bottom_message =
"Press any key to exit";
6304 bottom_message =
"Use arrows to scroll, any other key to exit";
6305 window.DrawTitleBox(window.GetName(), bottom_message);
6306 while (y <= max_y) {
6307 window.MoveCursor(x, y);
6308 window.PutCStringTruncated(
6309 1, m_text.GetStringAtIndex(m_first_visible_line + y - min_y));
6315HandleCharResult HelpDialogDelegate::WindowDelegateHandleChar(Window &window,
6318 const size_t num_lines = m_text.GetSize();
6319 const size_t num_visible_lines = window.GetHeight() - 2;
6321 if (num_lines <= num_visible_lines) {
6328 if (m_first_visible_line > 0)
6329 --m_first_visible_line;
6333 if (m_first_visible_line + num_visible_lines < num_lines)
6334 ++m_first_visible_line;
6339 if (m_first_visible_line > 0) {
6340 if (
static_cast<size_t>(m_first_visible_line) >= num_visible_lines)
6341 m_first_visible_line -= num_visible_lines;
6343 m_first_visible_line = 0;
6349 if (m_first_visible_line + num_visible_lines < num_lines) {
6350 m_first_visible_line += num_visible_lines;
6351 if (
static_cast<size_t>(m_first_visible_line) > num_lines)
6352 m_first_visible_line = num_lines - num_visible_lines;
6362 window.GetParent()->RemoveSubWindow(&window);
6366class ApplicationDelegate :
public WindowDelegate,
public MenuDelegate {
6374 eMenuID_TargetCreate,
6375 eMenuID_TargetDelete,
6378 eMenuID_ProcessAttach,
6379 eMenuID_ProcessDetachResume,
6380 eMenuID_ProcessDetachSuspended,
6381 eMenuID_ProcessLaunch,
6382 eMenuID_ProcessContinue,
6383 eMenuID_ProcessHalt,
6384 eMenuID_ProcessKill,
6387 eMenuID_ThreadStepIn,
6388 eMenuID_ThreadStepOver,
6389 eMenuID_ThreadStepOut,
6392 eMenuID_ViewBacktrace,
6393 eMenuID_ViewRegisters,
6395 eMenuID_ViewVariables,
6396 eMenuID_ViewBreakpoints,
6402 ApplicationDelegate(Application &app, Debugger &debugger)
6403 : WindowDelegate(), MenuDelegate(), m_app(app), m_debugger(debugger) {}
6405 ~ApplicationDelegate()
override =
default;
6407 bool WindowDelegateDraw(Window &window,
bool force)
override {
6411 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override {
6414 window.SelectNextWindowAsActive();
6418 window.SelectPreviousWindowAsActive();
6422 window.CreateHelpSubwindow();
6426 return eQuitApplication;
6431 return eKeyNotHandled;
6434 const char *WindowDelegateGetHelpText()
override {
6435 return "Welcome to the LLDB curses GUI.\n\n"
6436 "Press the TAB key to change the selected view.\n"
6437 "Each view has its own keyboard shortcuts, press 'h' to open a "
6438 "dialog to display them.\n\n"
6439 "Common key bindings for all views:";
6442 KeyHelp *WindowDelegateGetKeyHelp()
override {
6443 static curses::KeyHelp g_source_view_key_help[] = {
6444 {
'\t',
"Select next view"},
6445 {KEY_BTAB,
"Select previous view"},
6446 {
'h',
"Show help dialog with view specific key bindings"},
6449 {KEY_UP,
"Select previous"},
6450 {KEY_DOWN,
"Select next"},
6451 {KEY_LEFT,
"Unexpand or select parent"},
6452 {KEY_RIGHT,
"Expand"},
6453 {KEY_PPAGE,
"Page up"},
6454 {KEY_NPAGE,
"Page down"},
6456 return g_source_view_key_help;
6459 MenuActionResult MenuDelegateAction(Menu &menu)
override {
6460 switch (menu.GetIdentifier()) {
6461 case eMenuID_TargetCreate: {
6462 WindowSP main_window_sp = m_app.GetMainWindow();
6463 FormDelegateSP form_delegate_sp =
6464 FormDelegateSP(
new TargetCreateFormDelegate(m_debugger));
6465 Rect bounds = main_window_sp->GetCenteredRect(80, 19);
6466 WindowSP form_window_sp = main_window_sp->CreateSubWindow(
6467 form_delegate_sp->GetName().c_str(), bounds,
true);
6468 WindowDelegateSP window_delegate_sp =
6469 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
6470 form_window_sp->SetDelegate(window_delegate_sp);
6471 return MenuActionResult::Handled;
6473 case eMenuID_ThreadStepIn: {
6474 ExecutionContext exe_ctx =
6475 m_debugger.GetCommandInterpreter().GetExecutionContext();
6478 if (process && process->
IsAlive() &&
6483 return MenuActionResult::Handled;
6485 case eMenuID_ThreadStepOut: {
6486 ExecutionContext exe_ctx =
6487 m_debugger.GetCommandInterpreter().GetExecutionContext();
6490 if (process && process->
IsAlive() &&
6493 uint32_t frame_idx =
6499 return MenuActionResult::Handled;
6501 case eMenuID_ThreadStepOver: {
6502 ExecutionContext exe_ctx =
6503 m_debugger.GetCommandInterpreter().GetExecutionContext();
6506 if (process && process->
IsAlive() &&
6511 return MenuActionResult::Handled;
6513 case eMenuID_ProcessAttach: {
6514 WindowSP main_window_sp = m_app.GetMainWindow();
6515 FormDelegateSP form_delegate_sp = FormDelegateSP(
6516 new ProcessAttachFormDelegate(m_debugger, main_window_sp));
6517 Rect bounds = main_window_sp->GetCenteredRect(80, 22);
6518 WindowSP form_window_sp = main_window_sp->CreateSubWindow(
6519 form_delegate_sp->GetName().c_str(), bounds,
true);
6520 WindowDelegateSP window_delegate_sp =
6521 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
6522 form_window_sp->SetDelegate(window_delegate_sp);
6523 return MenuActionResult::Handled;
6525 case eMenuID_ProcessLaunch: {
6526 WindowSP main_window_sp = m_app.GetMainWindow();
6527 FormDelegateSP form_delegate_sp = FormDelegateSP(
6528 new ProcessLaunchFormDelegate(m_debugger, main_window_sp));
6529 Rect bounds = main_window_sp->GetCenteredRect(80, 22);
6530 WindowSP form_window_sp = main_window_sp->CreateSubWindow(
6531 form_delegate_sp->GetName().c_str(), bounds,
true);
6532 WindowDelegateSP window_delegate_sp =
6533 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
6534 form_window_sp->SetDelegate(window_delegate_sp);
6535 return MenuActionResult::Handled;
6538 case eMenuID_ProcessContinue: {
6539 ExecutionContext exe_ctx =
6540 m_debugger.GetCommandInterpreter().GetExecutionContext();
6543 if (process && process->
IsAlive() &&
6548 return MenuActionResult::Handled;
6550 case eMenuID_ProcessKill: {
6551 ExecutionContext exe_ctx =
6552 m_debugger.GetCommandInterpreter().GetExecutionContext();
6555 if (process && process->
IsAlive())
6559 return MenuActionResult::Handled;
6561 case eMenuID_ProcessHalt: {
6562 ExecutionContext exe_ctx =
6563 m_debugger.GetCommandInterpreter().GetExecutionContext();
6566 if (process && process->
IsAlive())
6570 return MenuActionResult::Handled;
6572 case eMenuID_ProcessDetachResume:
6573 case eMenuID_ProcessDetachSuspended: {
6574 ExecutionContext exe_ctx =
6575 m_debugger.GetCommandInterpreter().GetExecutionContext();
6578 if (process && process->
IsAlive())
6579 process->
Detach(menu.GetIdentifier() ==
6580 eMenuID_ProcessDetachSuspended);
6583 return MenuActionResult::Handled;
6585 case eMenuID_Process: {
6589 Menus &submenus = menu.GetSubmenus();
6590 ExecutionContext exe_ctx =
6591 m_debugger.GetCommandInterpreter().GetExecutionContext();
6593 if (process && process->
IsAlive() &&
6595 if (submenus.size() == 7)
6596 menu.AddSubmenu(std::make_shared<Menu>(Menu::Type::Separator));
6597 else if (submenus.size() > 8)
6598 submenus.erase(submenus.begin() + 8, submenus.end());
6601 std::lock_guard<std::recursive_mutex> guard(threads.
GetMutex());
6602 size_t num_threads = threads.
GetSize();
6603 for (
size_t i = 0; i < num_threads; ++i) {
6605 char menu_char =
'\0';
6607 menu_char =
'1' + i;
6608 StreamString thread_menu_title;
6609 thread_menu_title.
Printf(
"Thread %u", thread_sp->GetIndexID());
6610 const char *thread_name = thread_sp->GetName();
6611 if (thread_name && thread_name[0])
6612 thread_menu_title.
Printf(
" %s", thread_name);
6614 const char *queue_name = thread_sp->GetQueueName();
6615 if (queue_name && queue_name[0])
6616 thread_menu_title.
Printf(
" %s", queue_name);
6618 menu.AddSubmenu(std::make_shared<Menu>(
6619 thread_menu_title.
GetString().str().c_str(),
nullptr, menu_char,
6620 thread_sp->GetID()));
6622 }
else if (submenus.size() > 7) {
6625 submenus.erase(submenus.begin() + 7, submenus.end());
6629 menu.RecalculateNameLengths();
6631 return MenuActionResult::Handled;
6633 case eMenuID_ViewVariables: {
6634 WindowSP main_window_sp = m_app.GetMainWindow();
6635 WindowSP source_window_sp = main_window_sp->FindSubWindow(
"Source");
6636 WindowSP variables_window_sp = main_window_sp->FindSubWindow(
"Variables");
6637 WindowSP registers_window_sp = main_window_sp->FindSubWindow(
"Registers");
6638 const Rect source_bounds = source_window_sp->GetBounds();
6640 if (variables_window_sp) {
6641 const Rect variables_bounds = variables_window_sp->GetBounds();
6643 main_window_sp->RemoveSubWindow(variables_window_sp.get());
6645 if (registers_window_sp) {
6648 Rect registers_bounds = variables_bounds;
6649 registers_bounds.size.width = source_bounds.size.width;
6650 registers_window_sp->SetBounds(registers_bounds);
6654 source_window_sp->Resize(source_bounds.size.width,
6655 source_bounds.size.height +
6656 variables_bounds.size.height);
6659 Rect new_variables_rect;
6660 if (registers_window_sp) {
6664 const Rect variables_bounds = registers_window_sp->GetBounds();
6665 Rect new_registers_rect;
6666 variables_bounds.VerticalSplitPercentage(0.50, new_variables_rect,
6667 new_registers_rect);
6668 registers_window_sp->SetBounds(new_registers_rect);
6671 Rect new_source_rect;
6672 source_bounds.HorizontalSplitPercentage(0.70, new_source_rect,
6673 new_variables_rect);
6674 source_window_sp->SetBounds(new_source_rect);
6676 WindowSP new_window_sp = main_window_sp->CreateSubWindow(
6677 "Variables", new_variables_rect,
false);
6678 new_window_sp->SetDelegate(
6679 WindowDelegateSP(
new FrameVariablesWindowDelegate(m_debugger)));
6683 return MenuActionResult::Handled;
6685 case eMenuID_ViewRegisters: {
6686 WindowSP main_window_sp = m_app.GetMainWindow();
6687 WindowSP source_window_sp = main_window_sp->FindSubWindow(
"Source");
6688 WindowSP variables_window_sp = main_window_sp->FindSubWindow(
"Variables");
6689 WindowSP registers_window_sp = main_window_sp->FindSubWindow(
"Registers");
6690 const Rect source_bounds = source_window_sp->GetBounds();
6692 if (registers_window_sp) {
6693 if (variables_window_sp) {
6694 const Rect variables_bounds = variables_window_sp->GetBounds();
6698 variables_window_sp->Resize(variables_bounds.size.width +
6699 registers_window_sp->GetWidth(),
6700 variables_bounds.size.height);
6704 source_window_sp->Resize(source_bounds.size.width,
6705 source_bounds.size.height +
6706 registers_window_sp->GetHeight());
6708 main_window_sp->RemoveSubWindow(registers_window_sp.get());
6711 if (variables_window_sp) {
6715 const Rect variables_bounds = variables_window_sp->GetBounds();
6717 variables_bounds.VerticalSplitPercentage(0.50, new_vars_rect,
6719 variables_window_sp->SetBounds(new_vars_rect);
6722 Rect new_source_rect;
6723 source_bounds.HorizontalSplitPercentage(0.70, new_source_rect,
6725 source_window_sp->SetBounds(new_source_rect);
6727 WindowSP new_window_sp =
6728 main_window_sp->CreateSubWindow(
"Registers", new_regs_rect,
false);
6729 new_window_sp->SetDelegate(
6730 WindowDelegateSP(
new RegistersWindowDelegate(m_debugger)));
6734 return MenuActionResult::Handled;
6736 case eMenuID_ViewBreakpoints: {
6737 WindowSP main_window_sp = m_app.GetMainWindow();
6738 WindowSP threads_window_sp = main_window_sp->FindSubWindow(
"Threads");
6739 WindowSP breakpoints_window_sp =
6740 main_window_sp->FindSubWindow(
"Breakpoints");
6741 const Rect threads_bounds = threads_window_sp->GetBounds();
6748 if (breakpoints_window_sp) {
6749 threads_window_sp->Resize(threads_bounds.size.width,
6750 threads_bounds.size.height +
6751 breakpoints_window_sp->GetHeight());
6752 main_window_sp->RemoveSubWindow(breakpoints_window_sp.get());
6754 Rect new_threads_bounds, breakpoints_bounds;
6755 threads_bounds.HorizontalSplitPercentage(0.70, new_threads_bounds,
6756 breakpoints_bounds);
6757 threads_window_sp->SetBounds(new_threads_bounds);
6758 breakpoints_window_sp = main_window_sp->CreateSubWindow(
6759 "Breakpoints", breakpoints_bounds,
false);
6760 TreeDelegateSP breakpoints_delegate_sp(
6761 new BreakpointsTreeDelegate(m_debugger));
6762 breakpoints_window_sp->SetDelegate(WindowDelegateSP(
6763 new TreeWindowDelegate(m_debugger, breakpoints_delegate_sp)));
6766 return MenuActionResult::Handled;
6769 case eMenuID_HelpGUIHelp:
6770 m_app.GetMainWindow()->CreateHelpSubwindow();
6771 return MenuActionResult::Handled;
6777 return MenuActionResult::NotHandled;
6782 Debugger &m_debugger;
6785class StatusBarWindowDelegate :
public WindowDelegate {
6787 StatusBarWindowDelegate(Debugger &debugger) : m_debugger(debugger) {
6791 ~StatusBarWindowDelegate()
override =
default;
6793 bool WindowDelegateDraw(Window &window,
bool force)
override {
6794 ExecutionContext exe_ctx =
6795 m_debugger.GetCommandInterpreter().GetExecutionContext();
6800 window.SetBackground(BlackOnWhite);
6801 window.MoveCursor(0, 0);
6804 window.Printf(
"Process: %5" PRIu64
" %10s", process->
GetID(),
6810 FormatEntity::Formatter(
nullptr, &exe_ctx,
nullptr,
false,
false)
6811 .
Format(m_format, strm)) {
6812 window.MoveCursor(40, 0);
6813 window.PutCStringTruncated(1, strm.
GetString().str().c_str());
6816 window.MoveCursor(60, 0);
6818 window.Printf(
"Frame: %3u PC = 0x%16.16" PRIx64,
6825 if (exit_desc && exit_desc[0])
6826 window.Printf(
" with status = %i (%s)", exit_status, exit_desc);
6828 window.Printf(
" with status = %i", exit_status);
6835 Debugger &m_debugger;
6836 FormatEntity::Entry m_format;
6839class SourceFileWindowDelegate :
public WindowDelegate {
6841 SourceFileWindowDelegate(Debugger &debugger)
6842 : WindowDelegate(), m_debugger(debugger) {}
6844 ~SourceFileWindowDelegate()
override =
default;
6846 void Update(
const SymbolContext &sc) { m_sc = sc; }
6848 uint32_t NumVisibleLines()
const {
return m_max_y - m_min_y; }
6850 const char *WindowDelegateGetHelpText()
override {
6851 return "Source/Disassembly window keyboard shortcuts:";
6854 KeyHelp *WindowDelegateGetKeyHelp()
override {
6855 static curses::KeyHelp g_source_view_key_help[] = {
6856 {KEY_RETURN,
"Run to selected line with one shot breakpoint"},
6857 {KEY_UP,
"Select previous source line"},
6858 {KEY_DOWN,
"Select next source line"},
6859 {KEY_LEFT,
"Scroll to the left"},
6860 {KEY_RIGHT,
"Scroll to the right"},
6861 {KEY_PPAGE,
"Page up"},
6862 {KEY_NPAGE,
"Page down"},
6863 {
'b',
"Set breakpoint on selected source/disassembly line"},
6864 {
'c',
"Continue process"},
6865 {
'D',
"Detach with process suspended"},
6866 {
'h',
"Show help dialog"},
6867 {
'n',
"Step over (source line)"},
6868 {
'N',
"Step over (single instruction)"},
6869 {
'f',
"Step out (finish)"},
6870 {
's',
"Step in (source line)"},
6871 {
'S',
"Step in (single instruction)"},
6873 {
'd',
"Frame down"},
6877 return g_source_view_key_help;
6880 bool WindowDelegateDraw(Window &window,
bool force)
override {
6881 ExecutionContext exe_ctx =
6882 m_debugger.GetCommandInterpreter().GetExecutionContext();
6884 Thread *thread =
nullptr;
6886 bool update_location =
false;
6891 update_location =
true;
6897 m_max_x = window.GetMaxX() - 1;
6898 m_max_y = window.GetMaxY() - 1;
6900 const uint32_t num_visible_lines = NumVisibleLines();
6902 bool set_selected_line_to_pc =
false;
6904 if (update_location) {
6905 const bool process_alive = process->
IsAlive();
6906 bool thread_changed =
false;
6907 if (process_alive) {
6911 auto tid = thread->
GetID();
6912 thread_changed = tid != m_tid;
6916 thread_changed =
true;
6921 const uint32_t stop_id = process ? process->
GetStopID() : 0;
6922 const bool stop_id_changed = stop_id != m_stop_id;
6923 bool frame_changed =
false;
6924 m_stop_id = stop_id;
6927 m_sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
6928 if (m_sc.module_sp) {
6930 "%s", m_sc.module_sp->GetFileSpec().GetFilename().GetCString());
6931 ConstString func_name = m_sc.GetFunctionName();
6933 m_title.Printf(
"`%s", func_name.
GetCString());
6935 const uint32_t frame_idx = frame_sp->GetFrameIndex();
6936 frame_changed = frame_idx != m_frame_idx;
6937 m_frame_idx = frame_idx;
6944 const bool context_changed =
6945 thread_changed || frame_changed || stop_id_changed;
6947 if (process_alive) {
6948 if (m_sc.line_entry.IsValid()) {
6949 m_pc_line = m_sc.line_entry.line;
6953 if (context_changed)
6954 m_selected_line = m_pc_line;
6956 if (m_file_sp && m_file_sp->GetSupportFile()->GetSpecOnly() ==
6957 m_sc.line_entry.GetFile()) {
6960 if (m_selected_line >=
static_cast<size_t>(m_first_visible_line)) {
6961 if (m_selected_line >= m_first_visible_line + num_visible_lines)
6962 m_first_visible_line = m_selected_line - 10;
6964 if (m_selected_line > 10)
6965 m_first_visible_line = m_selected_line - 10;
6967 m_first_visible_line = 0;
6971 m_selected_line = m_pc_line;
6973 m_debugger.GetSourceManager().GetFile(m_sc.line_entry.file_sp);
6975 const size_t num_lines = m_file_sp->GetNumLines();
6977 for (
size_t n = num_lines; n >= 10; n = n / 10)
6980 if (num_lines < num_visible_lines ||
6981 m_selected_line < num_visible_lines)
6982 m_first_visible_line = 0;
6984 m_first_visible_line = m_selected_line - 10;
6991 if (!m_file_sp || m_file_sp->GetNumLines() == 0) {
6993 bool prefer_file_cache =
false;
6994 if (m_sc.function) {
6995 if (m_disassembly_scope != m_sc.function) {
6996 m_disassembly_scope = m_sc.function;
6997 m_disassembly_sp = m_sc.function->GetInstructions(
6998 exe_ctx,
nullptr, !prefer_file_cache);
6999 if (m_disassembly_sp)
7000 set_selected_line_to_pc =
true;
7002 set_selected_line_to_pc = context_changed;
7004 }
else if (m_sc.symbol) {
7005 if (m_disassembly_scope != m_sc.symbol) {
7006 m_disassembly_scope = m_sc.symbol;
7007 m_disassembly_sp = m_sc.symbol->GetInstructions(
7008 exe_ctx,
nullptr, prefer_file_cache);
7009 if (m_disassembly_sp)
7010 set_selected_line_to_pc =
true;
7012 set_selected_line_to_pc = context_changed;
7021 const int window_width = window.GetWidth();
7023 window.DrawTitleBox(
"Sources");
7024 if (!m_title.GetString().empty()) {
7025 window.AttributeOn(A_REVERSE);
7026 window.MoveCursor(1, 1);
7027 window.PutChar(
' ');
7028 window.PutCStringTruncated(1, m_title.GetString().str().c_str());
7029 int x = window.GetCursorX();
7030 if (x < window_width - 1) {
7031 window.Printf(
"%*s", window_width - x - 1,
"");
7033 window.AttributeOff(A_REVERSE);
7037 const size_t num_source_lines = GetNumSourceLines();
7038 if (num_source_lines > 0) {
7040 BreakpointLines bp_lines;
7043 const size_t num_bps = bp_list.
GetSize();
7044 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
7046 const size_t num_bps_locs = bp_sp->GetNumLocations();
7047 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs; ++bp_loc_idx) {
7049 bp_sp->GetLocationAtIndex(bp_loc_idx);
7050 LineEntry bp_loc_line_entry;
7051 if (bp_loc_sp->GetAddress().CalculateSymbolContextLineEntry(
7052 bp_loc_line_entry)) {
7053 if (m_file_sp->GetSupportFile()->GetSpecOnly() ==
7054 bp_loc_line_entry.
GetFile()) {
7055 bp_lines.insert(bp_loc_line_entry.
line);
7062 for (
size_t i = 0; i < num_visible_lines; ++i) {
7063 const uint32_t curr_line = m_first_visible_line + i;
7064 if (curr_line < num_source_lines) {
7065 const int line_y = m_min_y + i;
7066 window.MoveCursor(1, line_y);
7067 const bool is_pc_line = curr_line == m_pc_line;
7068 const bool line_is_selected = m_selected_line == curr_line;
7072 attr_t highlight_attr = 0;
7074 if (line_is_selected && !is_pc_line)
7075 highlight_attr = A_REVERSE;
7077 if (bp_lines.find(curr_line + 1) != bp_lines.end())
7078 bp_attr = COLOR_PAIR(BlackOnWhite);
7081 window.AttributeOn(bp_attr);
7083 window.Printf(
" %*u ", m_line_width, curr_line + 1);
7086 window.AttributeOff(bp_attr);
7088 window.PutChar(ACS_VLINE);
7091 window.PutChar(ACS_DIAMOND);
7093 window.PutChar(
' ');
7096 window.AttributeOn(highlight_attr);
7098 StreamString lineStream;
7100 std::optional<size_t> column;
7101 if (is_pc_line && m_sc.line_entry.IsValid() && m_sc.line_entry.column)
7102 column = m_sc.line_entry.column - 1;
7103 m_file_sp->DisplaySourceLines(curr_line + 1, column, 0, 0,
7105 StringRef line = lineStream.
GetString();
7106 if (line.ends_with(
"\n"))
7107 line = line.drop_back();
7108 bool wasWritten = window.OutputColoredStringTruncated(
7109 1, line, m_first_visible_column, is_pc_line);
7110 if (!wasWritten && (line_is_selected || is_pc_line)) {
7114 window.PutCStringTruncated(
7115 1, line.empty() && m_first_visible_column == 0 ?
" " :
"<");
7118 if (is_pc_line && frame_sp &&
7119 frame_sp->GetConcreteFrameIndex() == 0) {
7124 const char *stop_description = stop_info_sp->GetDescription();
7125 if (stop_description && stop_description[0]) {
7126 size_t stop_description_len = strlen(stop_description);
7127 int desc_x = window_width - stop_description_len - 16;
7128 if (desc_x - window.GetCursorX() > 0)
7129 window.Printf(
"%*s", desc_x - window.GetCursorX(),
"");
7130 window.MoveCursor(window_width - stop_description_len - 16,
7132 const attr_t stop_reason_attr = COLOR_PAIR(WhiteOnBlue);
7133 window.AttributeOn(stop_reason_attr);
7134 window.PrintfTruncated(1,
" <<< Thread %u: %s ",
7136 window.AttributeOff(stop_reason_attr);
7139 window.Printf(
"%*s", window_width - window.GetCursorX() - 1,
"");
7143 window.AttributeOff(highlight_attr);
7149 size_t num_disassembly_lines = GetNumDisassemblyLines();
7150 if (num_disassembly_lines > 0) {
7152 BreakpointAddrs bp_file_addrs;
7156 const size_t num_bps = bp_list.
GetSize();
7157 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
7159 const size_t num_bps_locs = bp_sp->GetNumLocations();
7160 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs;
7163 bp_sp->GetLocationAtIndex(bp_loc_idx);
7164 bp_file_addrs.insert(bp_loc_sp->GetAddress().GetFileAddress());
7169 const attr_t selected_highlight_attr = A_REVERSE;
7170 const attr_t pc_highlight_attr = COLOR_PAIR(WhiteOnBlue);
7174 InstructionList &insts = m_disassembly_sp->GetInstructionList();
7178 pc_address = frame_sp->GetFrameCodeAddress();
7179 const uint32_t pc_idx =
7183 if (set_selected_line_to_pc) {
7184 m_selected_line = pc_idx;
7187 const uint32_t non_visible_pc_offset = (num_visible_lines / 5);
7188 if (
static_cast<size_t>(m_first_visible_line) >= num_disassembly_lines)
7189 m_first_visible_line = 0;
7191 if (pc_idx < num_disassembly_lines) {
7192 if (pc_idx <
static_cast<uint32_t
>(m_first_visible_line) ||
7193 pc_idx >= m_first_visible_line + num_visible_lines)
7194 m_first_visible_line = pc_idx - non_visible_pc_offset;
7197 for (
size_t i = 0; i < num_visible_lines; ++i) {
7198 const uint32_t inst_idx = m_first_visible_line + i;
7203 const int line_y = m_min_y + i;
7204 window.MoveCursor(1, line_y);
7205 const bool is_pc_line = frame_sp && inst_idx == pc_idx;
7206 const bool line_is_selected = m_selected_line == inst_idx;
7209 attr_t highlight_attr = 0;
7212 highlight_attr = pc_highlight_attr;
7213 else if (line_is_selected)
7214 highlight_attr = selected_highlight_attr;
7217 bp_file_addrs.end())
7218 bp_attr = COLOR_PAIR(BlackOnWhite);
7221 window.AttributeOn(bp_attr);
7223 window.Printf(
" 0x%16.16llx ",
7224 static_cast<unsigned long long>(
7228 window.AttributeOff(bp_attr);
7230 window.PutChar(ACS_VLINE);
7233 window.PutChar(ACS_DIAMOND);
7235 window.PutChar(
' ');
7238 window.AttributeOn(highlight_attr);
7240 const char *mnemonic = inst->
GetMnemonic(&exe_ctx);
7241 const char *operands = inst->
GetOperands(&exe_ctx);
7242 const char *comment = inst->
GetComment(&exe_ctx);
7244 if (mnemonic !=
nullptr && mnemonic[0] ==
'\0')
7246 if (operands !=
nullptr && operands[0] ==
'\0')
7248 if (comment !=
nullptr && comment[0] ==
'\0')
7253 if (mnemonic !=
nullptr && operands !=
nullptr && comment !=
nullptr)
7254 strm.
Printf(
"%-8s %-25s ; %s", mnemonic, operands, comment);
7255 else if (mnemonic !=
nullptr && operands !=
nullptr)
7256 strm.
Printf(
"%-8s %s", mnemonic, operands);
7257 else if (mnemonic !=
nullptr)
7258 strm.
Printf(
"%s", mnemonic);
7261 window.PutCStringTruncated(
7263 strm.
GetString().substr(m_first_visible_column).data());
7265 if (is_pc_line && frame_sp &&
7266 frame_sp->GetConcreteFrameIndex() == 0) {
7271 const char *stop_description = stop_info_sp->GetDescription();
7272 if (stop_description && stop_description[0]) {
7273 size_t stop_description_len = strlen(stop_description);
7274 int desc_x = window_width - stop_description_len - 16;
7275 if (desc_x - window.GetCursorX() > 0)
7276 window.Printf(
"%*s", desc_x - window.GetCursorX(),
"");
7277 window.MoveCursor(window_width - stop_description_len - 15,
7280 window.PrintfTruncated(1,
"<<< Thread %u: %s ",
7285 window.Printf(
"%*s", window_width - window.GetCursorX() - 1,
"");
7289 window.AttributeOff(highlight_attr);
7296 size_t GetNumLines() {
7297 size_t num_lines = GetNumSourceLines();
7299 num_lines = GetNumDisassemblyLines();
7303 size_t GetNumSourceLines()
const {
7305 return m_file_sp->GetNumLines();
7309 size_t GetNumDisassemblyLines()
const {
7310 if (m_disassembly_sp)
7311 return m_disassembly_sp->GetInstructionList().GetSize();
7315 HandleCharResult WindowDelegateHandleChar(Window &window,
int c)
override {
7316 const uint32_t num_visible_lines = NumVisibleLines();
7317 const size_t num_lines = GetNumLines();
7323 if (
static_cast<uint32_t
>(m_first_visible_line) > num_visible_lines)
7324 m_first_visible_line -= num_visible_lines;
7326 m_first_visible_line = 0;
7327 m_selected_line = m_first_visible_line;
7334 if (m_first_visible_line + num_visible_lines < num_lines)
7335 m_first_visible_line += num_visible_lines;
7336 else if (num_lines < num_visible_lines)
7337 m_first_visible_line = 0;
7339 m_first_visible_line = num_lines - num_visible_lines;
7340 m_selected_line = m_first_visible_line;
7345 if (m_selected_line > 0) {
7347 if (
static_cast<size_t>(m_first_visible_line) > m_selected_line)
7348 m_first_visible_line = m_selected_line;
7353 if (m_selected_line + 1 < num_lines) {
7355 if (m_first_visible_line + num_visible_lines < m_selected_line)
7356 m_first_visible_line++;
7361 if (m_first_visible_column > 0)
7362 --m_first_visible_column;
7366 ++m_first_visible_column;
7373 if (GetNumSourceLines() > 0) {
7374 ExecutionContext exe_ctx =
7375 m_debugger.GetCommandInterpreter().GetExecutionContext();
7379 m_file_sp->GetSupportFile()->GetSpecOnly(),
7390 bp_sp->GetOptions().SetOneShot(
true);
7393 }
else if (m_selected_line < GetNumDisassemblyLines()) {
7394 const Instruction *inst = m_disassembly_sp->GetInstructionList()
7395 .GetInstructionAtIndex(m_selected_line)
7397 ExecutionContext exe_ctx =
7398 m_debugger.GetCommandInterpreter().GetExecutionContext();
7406 bp_sp->GetOptions().SetOneShot(
true);
7413 ToggleBreakpointOnSelectedLine();
7418 ExecutionContext exe_ctx =
7419 m_debugger.GetCommandInterpreter().GetExecutionContext();
7428 ExecutionContext exe_ctx =
7429 m_debugger.GetCommandInterpreter().GetExecutionContext();
7438 ExecutionContext exe_ctx =
7439 m_debugger.GetCommandInterpreter().GetExecutionContext();
7443 uint32_t frame_idx =
7453 ExecutionContext exe_ctx =
7454 m_debugger.GetCommandInterpreter().GetExecutionContext();
7457 bool source_step = (c ==
'n');
7466 ExecutionContext exe_ctx =
7467 m_debugger.GetCommandInterpreter().GetExecutionContext();
7470 bool source_step = (c ==
's');
7479 ExecutionContext exe_ctx =
7480 m_debugger.GetCommandInterpreter().GetExecutionContext();
7483 uint32_t frame_idx =
7489 else if (c ==
'd' && frame_idx > 0)
7498 window.CreateHelpSubwindow();
7504 return eKeyNotHandled;
7507 void ToggleBreakpointOnSelectedLine() {
7508 ExecutionContext exe_ctx =
7509 m_debugger.GetCommandInterpreter().GetExecutionContext();
7512 if (GetNumSourceLines() > 0) {
7515 const size_t num_bps = bp_list.
GetSize();
7516 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
7518 const size_t num_bps_locs = bp_sp->GetNumLocations();
7519 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs; ++bp_loc_idx) {
7521 bp_sp->GetLocationAtIndex(bp_loc_idx);
7522 LineEntry bp_loc_line_entry;
7523 if (bp_loc_sp->GetAddress().CalculateSymbolContextLineEntry(
7524 bp_loc_line_entry)) {
7525 if (m_file_sp->GetSupportFile()->GetSpecOnly() ==
7526 bp_loc_line_entry.
GetFile() &&
7527 m_selected_line + 1 == bp_loc_line_entry.
line) {
7540 m_file_sp->GetSupportFile()->GetSpecOnly(),
7552 assert(GetNumDisassemblyLines() > 0);
7553 assert(m_selected_line < GetNumDisassemblyLines());
7554 const Instruction *inst = m_disassembly_sp->GetInstructionList()
7555 .GetInstructionAtIndex(m_selected_line)
7560 const size_t num_bps = bp_list.
GetSize();
7561 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
7563 const size_t num_bps_locs = bp_sp->GetNumLocations();
7564 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs; ++bp_loc_idx) {
7566 bp_sp->GetLocationAtIndex(bp_loc_idx);
7567 LineEntry bp_loc_line_entry;
7569 bp_loc_sp->GetAddress().GetFileAddress();
7588 typedef std::set<uint32_t> BreakpointLines;
7589 typedef std::set<lldb::addr_t> BreakpointAddrs;
7591 Debugger &m_debugger;
7594 SymbolContextScope *m_disassembly_scope =
nullptr;
7596 StreamString m_title;
7598 int m_line_width = 4;
7599 uint32_t m_selected_line = 0;
7600 uint32_t m_pc_line = 0;
7601 uint32_t m_stop_id = 0;
7603 int m_first_visible_line = 0;
7604 int m_first_visible_column = 0;
7611DisplayOptions ValueObjectListDelegate::g_options = {
true};
7619 m_app_up = std::make_unique<Application>(
7624 std::shared_ptr<ApplicationDelegate> app_delegate_sp(
7627 MenuDelegateSP app_menu_delegate_sp =
7628 std::static_pointer_cast<MenuDelegate>(app_delegate_sp);
7629 MenuSP lldb_menu_sp(
7630 new Menu(
"LLDB",
"F1", KEY_F(1), ApplicationDelegate::eMenuID_LLDB));
7631 MenuSP exit_menuitem_sp(
7632 new Menu(
"Exit",
nullptr,
'x', ApplicationDelegate::eMenuID_LLDBExit));
7633 exit_menuitem_sp->SetCannedResult(MenuActionResult::Quit);
7634 lldb_menu_sp->AddSubmenu(std::make_shared<Menu>(
7635 "About LLDB",
nullptr,
'a', ApplicationDelegate::eMenuID_LLDBAbout));
7636 lldb_menu_sp->AddSubmenu(std::make_shared<Menu>(Menu::Type::Separator));
7637 lldb_menu_sp->AddSubmenu(exit_menuitem_sp);
7639 MenuSP target_menu_sp(
new Menu(
"Target",
"F2", KEY_F(2),
7640 ApplicationDelegate::eMenuID_Target));
7641 target_menu_sp->AddSubmenu(std::make_shared<Menu>(
7642 "Create",
nullptr,
'c', ApplicationDelegate::eMenuID_TargetCreate));
7643 target_menu_sp->AddSubmenu(std::make_shared<Menu>(
7644 "Delete",
nullptr,
'd', ApplicationDelegate::eMenuID_TargetDelete));
7646 MenuSP process_menu_sp(
new Menu(
"Process",
"F3", KEY_F(3),
7647 ApplicationDelegate::eMenuID_Process));
7648 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7649 "Attach",
nullptr,
'a', ApplicationDelegate::eMenuID_ProcessAttach));
7650 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7651 "Detach and resume",
nullptr,
'd',
7652 ApplicationDelegate::eMenuID_ProcessDetachResume));
7653 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7654 "Detach suspended",
nullptr,
's',
7655 ApplicationDelegate::eMenuID_ProcessDetachSuspended));
7656 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7657 "Launch",
nullptr,
'l', ApplicationDelegate::eMenuID_ProcessLaunch));
7658 process_menu_sp->AddSubmenu(std::make_shared<Menu>(Menu::Type::Separator));
7659 process_menu_sp->AddSubmenu(
7660 std::make_shared<Menu>(
"Continue",
nullptr,
'c',
7661 ApplicationDelegate::eMenuID_ProcessContinue));
7662 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7663 "Halt",
nullptr,
'h', ApplicationDelegate::eMenuID_ProcessHalt));
7664 process_menu_sp->AddSubmenu(std::make_shared<Menu>(
7665 "Kill",
nullptr,
'k', ApplicationDelegate::eMenuID_ProcessKill));
7667 MenuSP thread_menu_sp(
new Menu(
"Thread",
"F4", KEY_F(4),
7668 ApplicationDelegate::eMenuID_Thread));
7669 thread_menu_sp->AddSubmenu(std::make_shared<Menu>(
7670 "Step In",
nullptr,
'i', ApplicationDelegate::eMenuID_ThreadStepIn));
7671 thread_menu_sp->AddSubmenu(
7672 std::make_shared<Menu>(
"Step Over",
nullptr,
'v',
7673 ApplicationDelegate::eMenuID_ThreadStepOver));
7674 thread_menu_sp->AddSubmenu(std::make_shared<Menu>(
7675 "Step Out",
nullptr,
'o', ApplicationDelegate::eMenuID_ThreadStepOut));
7677 MenuSP view_menu_sp(
7678 new Menu(
"View",
"F5", KEY_F(5), ApplicationDelegate::eMenuID_View));
7679 view_menu_sp->AddSubmenu(std::make_shared<Menu>(
7680 "Backtrace",
nullptr,
't', ApplicationDelegate::eMenuID_ViewBacktrace));
7681 view_menu_sp->AddSubmenu(std::make_shared<Menu>(
7682 "Registers",
nullptr,
'r', ApplicationDelegate::eMenuID_ViewRegisters));
7683 view_menu_sp->AddSubmenu(std::make_shared<Menu>(
7684 "Source",
nullptr,
's', ApplicationDelegate::eMenuID_ViewSource));
7685 view_menu_sp->AddSubmenu(std::make_shared<Menu>(
7686 "Variables",
nullptr,
'v', ApplicationDelegate::eMenuID_ViewVariables));
7687 view_menu_sp->AddSubmenu(
7688 std::make_shared<Menu>(
"Breakpoints",
nullptr,
'b',
7689 ApplicationDelegate::eMenuID_ViewBreakpoints));
7691 MenuSP help_menu_sp(
7692 new Menu(
"Help",
"F6", KEY_F(6), ApplicationDelegate::eMenuID_Help));
7693 help_menu_sp->AddSubmenu(std::make_shared<Menu>(
7694 "GUI Help",
nullptr,
'g', ApplicationDelegate::eMenuID_HelpGUIHelp));
7697 WindowSP &main_window_sp =
m_app_up->GetMainWindow();
7699 MenuSP menubar_sp(
new Menu(Menu::Type::Bar));
7700 menubar_sp->AddSubmenu(lldb_menu_sp);
7701 menubar_sp->AddSubmenu(target_menu_sp);
7702 menubar_sp->AddSubmenu(process_menu_sp);
7703 menubar_sp->AddSubmenu(thread_menu_sp);
7704 menubar_sp->AddSubmenu(view_menu_sp);
7705 menubar_sp->AddSubmenu(help_menu_sp);
7706 menubar_sp->SetDelegate(app_menu_delegate_sp);
7708 Rect content_bounds = main_window_sp->GetFrame();
7709 Rect menubar_bounds = content_bounds.MakeMenuBar();
7710 Rect status_bounds = content_bounds.MakeStatusBar();
7712 Rect variables_bounds;
7713 Rect threads_bounds;
7714 Rect source_variables_bounds;
7715 content_bounds.VerticalSplitPercentage(0.80, source_variables_bounds,
7717 source_variables_bounds.HorizontalSplitPercentage(0.70, source_bounds,
7720 WindowSP menubar_window_sp =
7721 main_window_sp->CreateSubWindow(
"Menubar", menubar_bounds,
false);
7724 menubar_window_sp->SetCanBeActive(
7726 menubar_window_sp->SetDelegate(menubar_sp);
7728 WindowSP source_window_sp(
7729 main_window_sp->CreateSubWindow(
"Source", source_bounds,
true));
7730 WindowSP variables_window_sp(
7731 main_window_sp->CreateSubWindow(
"Variables", variables_bounds,
false));
7732 WindowSP threads_window_sp(
7733 main_window_sp->CreateSubWindow(
"Threads", threads_bounds,
false));
7734 WindowSP status_window_sp(
7735 main_window_sp->CreateSubWindow(
"Status", status_bounds,
false));
7736 status_window_sp->SetCanBeActive(
7738 main_window_sp->SetDelegate(
7739 std::static_pointer_cast<WindowDelegate>(app_delegate_sp));
7740 source_window_sp->SetDelegate(
7741 WindowDelegateSP(
new SourceFileWindowDelegate(
m_debugger)));
7742 variables_window_sp->SetDelegate(
7743 WindowDelegateSP(
new FrameVariablesWindowDelegate(
m_debugger)));
7744 TreeDelegateSP thread_delegate_sp(
new ThreadsTreeDelegate(
m_debugger));
7745 threads_window_sp->SetDelegate(WindowDelegateSP(
7746 new TreeWindowDelegate(
m_debugger, thread_delegate_sp)));
7747 status_window_sp->SetDelegate(
7748 WindowDelegateSP(
new StatusBarWindowDelegate(
m_debugger)));
7751 init_pair(1, COLOR_BLACK, COLOR_BLACK);
7752 init_pair(2, COLOR_RED, COLOR_BLACK);
7753 init_pair(3, COLOR_GREEN, COLOR_BLACK);
7754 init_pair(4, COLOR_YELLOW, COLOR_BLACK);
7755 init_pair(5, COLOR_BLUE, COLOR_BLACK);
7756 init_pair(6, COLOR_MAGENTA, COLOR_BLACK);
7757 init_pair(7, COLOR_CYAN, COLOR_BLACK);
7758 init_pair(8, COLOR_WHITE, COLOR_BLACK);
7760 init_pair(9, COLOR_BLACK, COLOR_BLUE);
7761 init_pair(10, COLOR_RED, COLOR_BLUE);
7762 init_pair(11, COLOR_GREEN, COLOR_BLUE);
7763 init_pair(12, COLOR_YELLOW, COLOR_BLUE);
7764 init_pair(13, COLOR_BLUE, COLOR_BLUE);
7765 init_pair(14, COLOR_MAGENTA, COLOR_BLUE);
7766 init_pair(15, COLOR_CYAN, COLOR_BLUE);
7767 init_pair(16, COLOR_WHITE, COLOR_BLUE);
7769 init_pair(17, COLOR_BLACK, COLOR_WHITE);
7770 init_pair(18, COLOR_MAGENTA, COLOR_WHITE);
7771 static_assert(LastColorPairIndex == 18,
"Color indexes do not match.");
7773 define_key(
"\033[Z", KEY_SHIFT_TAB);
7774 define_key(
"\033\015", KEY_ALT_ENTER);
7790 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 void skip(TSLexer *lexer)
static llvm::StringRef GetName(XcodeSDK::Type type)
lldb::addr_t GetLoadAddress(Target *target) const
Get the load address.
bool SetLoadAddress(lldb::addr_t load_addr, Target *target, bool allow_section_end=false)
Set the address to represent load_addr.
uint32_t CalculateSymbolContext(SymbolContext *sc, lldb::SymbolContextItem resolve_scope=lldb::eSymbolContextEverything) const
Reconstruct a symbol context from an address.
lldb::addr_t GetOpcodeLoadAddress(Target *target, AddressClass addr_class=AddressClass::eInvalid) const
Get the load address as an opcode load address.
@ DumpStyleInvalid
Invalid dump style.
@ DumpStyleModuleWithFileAddress
Display as the file address with the module name prepended (if any).
@ DumpStyleResolvedDescription
Display the details about what an address resolves to.
@ DumpStyleLoadAddress
Display as the load address (if resolved).
bool Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, DumpStyle fallback_style=DumpStyleInvalid, uint32_t addr_byte_size=UINT32_MAX, bool all_ranges=false, std::optional< Stream::HighlightSettings > settings=std::nullopt) const
Dump a description of this object to a Stream.
lldb::addr_t GetFileAddress() const
Get the file address.
bool IsValid() const
Check if the object state is valid.
Symbol * CalculateSymbolContextSymbol() const
void AppendArguments(const Args &rhs)
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
void AppendArgument(llvm::StringRef arg_str, char quote_char='\0')
Appends a new argument to the end of the list argument list.
const char * GetArgumentAtIndex(size_t idx) const
Gets the NULL terminated C string argument pointer for the argument at index idx.
void GetListMutex(std::unique_lock< std::recursive_mutex > &lock)
Sets the passed in Locker to hold the Breakpoint List mutex.
size_t GetSize() const
Returns the number of elements in this breakpoint list.
lldb::BreakpointSP GetBreakpointAtIndex(size_t i) const
Returns a shared pointer to the breakpoint with index i.
lldb::BreakpointLocationSP GetLocationAtIndex(size_t index, bool use_facade=true)
Get breakpoint locations by index.
virtual llvm::StringRef GetBroadcasterClass() const
This needs to be filled in if you are going to register the broadcaster with the broadcaster manager ...
static bool InvokeCommonCompletionCallbacks(CommandInterpreter &interpreter, uint32_t completion_mask, lldb_private::CompletionRequest &request, SearchFilter *searcher)
const FileSpec & GetPrimaryFile() const
Return the primary source spec associated with this compile unit.
void GetMatches(StringList &matches) const
Adds all collected completion matches to the given list.
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.
const char * AsCString(const char *value_if_empty) const
Get the string value as a C string.
A class to manage flag bits.
void CancelForwardEvents(const lldb::ListenerSP &listener_sp)
void EnableForwardEvents(const lldb::ListenerSP &listener_sp)
PlatformList & GetPlatformList()
std::pair< iterator, bool > insert(llvm::StringRef KeyEqValue)
void SetFrameSP(const lldb::StackFrameSP &frame_sp)
Set accessor to set only the frame shared pointer.
bool HasThreadScope() const
Returns true the ExecutionContext object contains a valid target, process, and thread.
bool HasProcessScope() const
Returns true the ExecutionContext object contains a valid target and process.
StackFrame * GetFramePtr() const
Returns a pointer to the frame object.
Process & GetProcessRef() const
Returns a reference to the process object.
Target * GetTargetPtr() const
Returns a pointer to the target object.
bool HasTargetScope() const
Returns true the ExecutionContext object contains a valid target.
Target & GetTargetRef() const
Returns a reference to the target object.
Process * GetProcessPtr() const
Returns a pointer to the process object.
Thread & GetThreadRef() const
Returns a reference to the thread object.
Thread * GetThreadPtr() const
Returns a pointer to the thread object.
bool Open(int fd, const FileSpec &file_spec, bool read, bool write)
Configure this action to open a file.
void SetFile(llvm::StringRef path, Style style)
Change the file specified with a new path.
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.
static FileSystem & Instance()
void Resolve(llvm::SmallVectorImpl< char > &path, bool force_make_absolute=false)
Resolve path to make it canonical.
ValueType Clear(ValueType mask=~static_cast< ValueType >(0))
Clear one or more flags.
ValueType Set(ValueType mask)
Set one or more flags by logical OR'ing mask with the current flags.
ConstString GetName() const
IOHandlerCursesGUI(Debugger &debugger)
std::unique_ptr< curses::Application > m_app_up
void Deactivate() override
~IOHandlerCursesGUI() override
bool Interrupt() override
void TerminalSizeChanged() override
lldb::LockableStreamFileSP m_output_sp
uint32_t GetIndexOfInstructionAtAddress(const Address &addr)
lldb::InstructionSP GetInstructionAtIndex(size_t idx) const
const Address & GetAddress() const
const char * GetMnemonic(const ExecutionContext *exe_ctx, bool markup=false)
const char * GetComment(const ExecutionContext *exe_ctx)
const char * GetOperands(const ExecutionContext *exe_ctx, bool markup=false)
static lldb::ListenerSP MakeListener(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 AppendFileAction(const FileActionImpl &info)
void SetShell(const FileSpec &shell)
void SetProcessPluginName(llvm::StringRef plugin)
void SetShellExpandArguments(bool expand)
void SetWorkingDirectory(const FileSpec &working_dir)
lldb::pid_t GetID() const
Returns the pid of the process or LLDB_INVALID_PROCESS_ID if there is no known pid.
Status Destroy(bool force_kill)
Kills the process and shuts down all threads that were spawned to track and monitor the process.
ThreadList & GetThreadList()
Status Resume()
Resumes all of a process's threads as configured using the Thread run control functions.
int GetExitStatus()
Get the exit status for a process.
Status Detach(bool keep_stopped)
Detaches from a running or stopped process.
lldb::StateType GetState()
Get accessor for the current process state.
const char * GetExitDescription()
Get a textual description of what the process exited.
static llvm::StringRef GetStaticBroadcasterClass()
virtual bool IsAlive()
Check if a process is still alive.
uint32_t GetStopID() const
Status Halt(bool clear_thread_plans=false, bool use_run_lock=true)
Halts a running process.
std::shared_ptr< File > FileSP
virtual lldb::RegisterContextSP GetRegisterContext()
Get the RegisterContext for this frame, if possible.
virtual StackID & GetStackID()
virtual lldb::ValueObjectSP GetValueObjectForFrameVariable(const lldb::VariableSP &variable_sp, lldb::DynamicValueType use_dynamic)
Create a ValueObject for a given Variable in this StackFrame.
virtual VariableList * GetVariableList(bool get_file_globals, bool include_synthetic_vars, Status *error_ptr)
Retrieve the list of variables whose scope either:
virtual uint32_t GetFrameIndex() const
Query this frame to find what frame it is in this Thread's StackFrameList.
virtual Block * GetFrameBlock()
Get the current lexical scope block for this StackFrame, if possible.
virtual const Address & GetFrameCodeAddress()
Get an Address for the current pc value in this StackFrame.
bool Fail() const
Test for error condition.
const char * AsCString(const char *default_error_str="unknown error") const
Get the error string associated with the current error.
const char * GetData() const
llvm::StringRef GetString() const
void Format(const char *format, Args &&... args)
Forwards the arguments to llvm::formatv and writes to the stream.
llvm::raw_ostream & AsRawOstream()
Returns a raw_ostream that forwards the data to this Stream object.
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
size_t size_t PrintfVarArg(const char *format, va_list args)
void AppendString(const std::string &s)
const char * GetStringAtIndex(size_t idx) const
Function * function
The Function for a given query.
lldb::ModuleSP module_sp
The Module for a given query.
CompileUnit * comp_unit
The CompileUnit for a given query.
Symbol * symbol
The Symbol for a given query.
LineEntry line_entry
The LineEntry for a given query.
ConstString GetName() const
BreakpointList & GetBreakpointList(bool internal=false)
const lldb::ProcessSP & GetProcessSP() const
bool RemoveBreakpointByID(lldb::break_id_t break_id)
Status Launch(ProcessLaunchInfo &launch_info, Stream *stream)
lldb::ModuleSP GetExecutableModule()
Gets the module for the main executable.
lldb::BreakpointSP CreateBreakpoint(const FileSpecList *containingModules, const FileSpec &file, uint32_t line_no, uint32_t column, lldb::addr_t offset, LazyBool check_inlines, LazyBool skip_prologue, bool internal, bool request_hardware, LazyBool move_to_nearest_code)
Status Attach(ProcessAttachInfo &attach_info, Stream *stream)
lldb::ThreadSP GetSelectedThread()
uint32_t GetSize(bool can_update=true)
bool SetSelectedThreadByID(lldb::tid_t tid, bool notify=false)
lldb::ThreadSP GetThreadAtIndex(uint32_t idx, bool can_update=true)
std::recursive_mutex & GetMutex() const override
virtual lldb::StackFrameSP GetStackFrameAtIndex(uint32_t idx)
uint32_t GetIndexID() const
lldb::StackFrameSP GetSelectedFrame(SelectMostRelevant select_most_relevant)
virtual Status StepOver(bool source_step, LazyBool step_out_avoids_code_without_debug_info=eLazyBoolCalculate)
Default implementation for stepping over.
uint32_t GetSelectedFrameIndex(SelectMostRelevant select_most_relevant)
lldb::ProcessSP GetProcess() const
virtual Status StepOut(uint32_t frame_idx=0)
Default implementation for stepping out.
bool SetSelectedFrameByIndex(uint32_t frame_idx, bool broadcast=false)
lldb::StopInfoSP GetStopInfo()
virtual uint32_t GetStackFrameCount()
GetStackFrameCount can be expensive.
virtual Status StepIn(bool source_step, LazyBool step_in_avoids_code_without_debug_info=eLazyBoolCalculate, LazyBool step_out_avoids_code_without_debug_info=eLazyBoolCalculate)
Default implementation for stepping into.
const std::vector< lldb::ValueObjectSP > & GetObjects() const
void Append(const lldb::ValueObjectSP &val_obj_sp)
static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope, lldb::RegisterContextSP ®_ctx_sp, uint32_t set_idx)
lldb::ProcessSP GetProcessSP() const
lldb::ValueObjectSP GetSP()
Gets the correct value object from the root object for a given process stop ID.
virtual ConstString GetTypeName()
virtual const char * GetValueAsCString()
ConstString GetName() const
const char * GetSummaryAsCString(lldb::LanguageType lang=lldb::eLanguageTypeUnknown)
#define LLDB_INVALID_THREAD_ID
#define UNUSED_IF_ASSERT_DISABLED(x)
@ SelectMostRelevantFrame
A class that represents a running process on the host machine.
bool operator!=(const Address &lhs, const Address &rhs)
bool StateIsStoppedState(lldb::StateType state, bool must_exist)
Check if a state represents a state where the process or thread is stopped.
bool StateIsRunningState(lldb::StateType state)
Check if a state represents a state where the process or thread is running.
const char * StateAsCString(lldb::StateType state)
Converts a StateType to a C string.
bool operator==(const Address &lhs, const Address &rhs)
std::shared_ptr< lldb_private::StackFrame > StackFrameSP
std::shared_ptr< lldb_private::BreakpointSite > BreakpointSiteSP
std::shared_ptr< lldb_private::BreakpointLocation > BreakpointLocationSP
std::shared_ptr< lldb_private::Thread > ThreadSP
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
Format
Display format definitions.
@ eFormatCString
NULL terminated C strings.
@ eFormatInstruction
Disassemble an opcode.
@ eFormatAddressInfo
Describe what an address points to (func + offset with file/line, symbol + offset,...
std::shared_ptr< lldb_private::Platform > PlatformSP
StateType
Process and Thread States.
@ eStateExited
Process has exited and can't be examined.
std::shared_ptr< lldb_private::Breakpoint > BreakpointSP
std::shared_ptr< lldb_private::Process > ProcessSP
std::shared_ptr< lldb_private::Disassembler > DisassemblerSP
std::shared_ptr< lldb_private::Event > EventSP
std::shared_ptr< lldb_private::Listener > ListenerSP
std::shared_ptr< lldb_private::Variable > VariableSP
std::shared_ptr< lldb_private::StopInfo > StopInfoSP
std::shared_ptr< lldb_private::Target > TargetSP
std::shared_ptr< lldb_private::RegisterContext > RegisterContextSP
std::shared_ptr< lldb_private::Module > ModuleSP
uint32_t line
The source line number, or LLDB_INVALID_LINE_NUMBER if there is no line number information.
bool DumpStopContext(Stream *s, bool show_fullpaths) const
Dumps information specific to a process that stops at this line entry to the supplied stream s.
const FileSpec & GetFile() const
Helper to access the file.
lldb::user_id_t GetID() const
Get accessor for the user ID.