10#include "lldb/Host/Config.h"
13#if CURSES_HAVE_NCURSES_CURSES_H
14#include <ncurses/curses.h>
15#include <ncurses/panel.h>
61#include "llvm/ADT/StringRef.h"
94#define KEY_SHIFT_TAB (KEY_MAX + 1)
95#define KEY_ALT_ENTER (KEY_MAX + 2)
102typedef std::shared_ptr<Menu> MenuSP;
103typedef std::shared_ptr<MenuDelegate> MenuDelegateSP;
104typedef std::shared_ptr<Window> WindowSP;
105typedef std::shared_ptr<WindowDelegate> WindowDelegateSP;
106typedef std::vector<MenuSP> Menus;
107typedef std::vector<WindowSP> Windows;
108typedef std::vector<WindowDelegateSP> WindowDelegates;
111type summary add -s
"x=${var.x}, y=${var.y}" curses::Point
112type summary add -s
"w=${var.width}, h=${var.height}" curses::Size
113type summary add -s
"${var.origin%S} ${var.size%S}" curses::Rect
120 Point(
int _x = 0,
int _y = 0) : x(_x), y(_y) {}
127 Point &operator+=(
const Point &rhs) {
133 void Dump() { printf(
"(x=%i, y=%i)\n", x, y); }
136bool operator==(
const Point &lhs,
const Point &rhs) {
137 return lhs.x == rhs.x && lhs.y == rhs.y;
140bool operator!=(
const Point &lhs,
const Point &rhs) {
141 return lhs.x != rhs.x || lhs.y != rhs.y;
147 Size(
int w = 0,
int h = 0) : width(w), height(h) {}
154 void Dump() { printf(
"(w=%i, h=%i)\n", width, height); }
157bool operator==(
const Size &lhs,
const Size &rhs) {
158 return lhs.width == rhs.width && lhs.height == rhs.height;
161bool operator!=(
const Size &lhs,
const Size &rhs) {
162 return lhs.width != rhs.width || lhs.height != rhs.height;
169 Rect() : origin(), size() {}
171 Rect(
const Point &p,
const Size &s) : origin(p), size(s) {}
179 printf(
"(x=%i, y=%i), w=%i, h=%i)\n", origin.x, origin.y, size.width,
183 void Inset(
int w,
int h) {
184 if (size.width > w * 2)
188 if (size.height > h * 2)
189 size.height -= h * 2;
195 Rect MakeStatusBar() {
197 if (size.height > 1) {
198 status_bar.origin.x = origin.x;
199 status_bar.origin.y = size.height;
200 status_bar.size.width = size.width;
201 status_bar.size.height = 1;
211 if (size.height > 1) {
212 menubar.origin.x = origin.x;
213 menubar.origin.y = origin.y;
214 menubar.size.width = size.width;
215 menubar.size.height = 1;
222 void HorizontalSplitPercentage(
float top_percentage, Rect &top,
223 Rect &bottom)
const {
224 float top_height = top_percentage * size.height;
225 HorizontalSplit(top_height, top, bottom);
228 void HorizontalSplit(
int top_height, Rect &top, Rect &bottom)
const {
230 if (top_height < size.height) {
231 top.size.height = top_height;
232 bottom.origin.x = origin.x;
233 bottom.origin.y = origin.y + top.size.height;
234 bottom.size.width = size.width;
235 bottom.size.height = size.height - top.size.height;
241 void VerticalSplitPercentage(
float left_percentage, Rect &left,
243 float left_width = left_percentage * size.width;
244 VerticalSplit(left_width, left, right);
247 void VerticalSplit(
int left_width, Rect &left, Rect &right)
const {
249 if (left_width < size.width) {
250 left.size.width = left_width;
251 right.origin.x = origin.x + left.size.width;
252 right.origin.y = origin.y;
253 right.size.width = size.width - left.size.width;
254 right.size.height = size.height;
261bool operator==(
const Rect &lhs,
const Rect &rhs) {
262 return lhs.origin == rhs.origin && lhs.size == rhs.size;
265bool operator!=(
const Rect &lhs,
const Rect &rhs) {
266 return lhs.origin != rhs.origin || lhs.size != rhs.size;
269enum HandleCharResult {
275enum class MenuActionResult {
283 const char *description;
309 LastColorPairIndex = MagentaOnWhite
312class WindowDelegate {
314 virtual ~WindowDelegate() =
default;
316 virtual bool WindowDelegateDraw(Window &window,
bool force) {
320 virtual HandleCharResult WindowDelegateHandleChar(Window &window,
int key) {
321 return eKeyNotHandled;
324 virtual const char *WindowDelegateGetHelpText() {
return nullptr; }
326 virtual KeyHelp *WindowDelegateGetKeyHelp() {
return nullptr; }
329class HelpDialogDelegate :
public WindowDelegate {
331 HelpDialogDelegate(
const char *text, KeyHelp *key_help_array);
333 ~HelpDialogDelegate()
override;
335 bool WindowDelegateDraw(Window &window,
bool force)
override;
337 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override;
339 size_t GetNumLines()
const {
return m_text.GetSize(); }
341 size_t GetMaxLineLength()
const {
return m_text.GetMaxStringLength(); }
345 int m_first_visible_line = 0;
354 enum class Type { Window, Pad };
356 Surface(Surface::Type type) : m_type(type) {}
358 WINDOW *get() {
return m_window; }
360 operator WINDOW *() {
return m_window; }
362 Surface SubSurface(Rect bounds) {
363 Surface subSurface(m_type);
364 if (m_type == Type::Pad)
365 subSurface.m_window =
366 ::subpad(m_window, bounds.size.height, bounds.size.width,
367 bounds.origin.y, bounds.origin.x);
369 subSurface.m_window =
370 ::derwin(m_window, bounds.size.height, bounds.size.width,
371 bounds.origin.y, bounds.origin.x);
376 void CopyToSurface(Surface &target, Point source_origin, Point target_origin,
378 ::copywin(m_window, target.get(), source_origin.y, source_origin.x,
379 target_origin.y, target_origin.x,
380 target_origin.y + size.height - 1,
381 target_origin.x + size.width - 1,
false);
384 int GetCursorX()
const {
return getcurx(m_window); }
385 int GetCursorY()
const {
return getcury(m_window); }
386 void MoveCursor(
int x,
int y) { ::wmove(m_window, y, x); }
388 void AttributeOn(attr_t attr) { ::wattron(m_window, attr); }
389 void AttributeOff(attr_t attr) { ::wattroff(m_window, attr); }
391 int GetMaxX()
const {
return getmaxx(m_window); }
392 int GetMaxY()
const {
return getmaxy(m_window); }
393 int GetWidth()
const {
return GetMaxX(); }
394 int GetHeight()
const {
return GetMaxY(); }
395 Size GetSize()
const {
return Size(GetWidth(), GetHeight()); }
397 Rect GetFrame()
const {
return Rect(Point(), GetSize()); }
399 void Clear() { ::wclear(m_window); }
400 void Erase() { ::werase(m_window); }
402 void SetBackground(
int color_pair_idx) {
403 ::wbkgd(m_window, COLOR_PAIR(color_pair_idx));
406 void PutChar(
int ch) { ::waddch(m_window, ch); }
407 void PutCString(
const char *s,
int len = -1) { ::waddnstr(m_window, s, len); }
409 void PutCStringTruncated(
int right_pad,
const char *s,
int len = -1) {
410 int bytes_left = GetWidth() - GetCursorX();
411 if (bytes_left > right_pad) {
412 bytes_left -= right_pad;
413 ::waddnstr(m_window, s, len < 0 ? bytes_left : std::min(bytes_left, len));
417 void Printf(
const char *format, ...) __attribute__((format(printf, 2, 3))) {
419 va_start(args, format);
420 vw_printw(m_window, format, args);
424 void PrintfTruncated(
int right_pad,
const char *format, ...)
425 __attribute__((format(printf, 3, 4))) {
427 va_start(args, format);
431 PutCStringTruncated(right_pad, strm.
GetData());
434 void VerticalLine(
int n, chtype v_char = ACS_VLINE) {
435 ::wvline(m_window, v_char, n);
437 void HorizontalLine(
int n, chtype h_char = ACS_HLINE) {
438 ::whline(m_window, h_char, n);
440 void Box(chtype v_char = ACS_VLINE, chtype h_char = ACS_HLINE) {
441 ::box(m_window, v_char, h_char);
444 void TitledBox(
const char *title, chtype v_char = ACS_VLINE,
445 chtype h_char = ACS_HLINE) {
447 int title_offset = 2;
448 MoveCursor(title_offset, 0);
450 PutCString(title, GetWidth() - title_offset);
454 void Box(
const Rect &bounds, chtype v_char = ACS_VLINE,
455 chtype h_char = ACS_HLINE) {
456 MoveCursor(bounds.origin.x, bounds.origin.y);
457 VerticalLine(bounds.size.height);
458 HorizontalLine(bounds.size.width);
459 PutChar(ACS_ULCORNER);
461 MoveCursor(bounds.origin.x + bounds.size.width - 1, bounds.origin.y);
462 VerticalLine(bounds.size.height);
463 PutChar(ACS_URCORNER);
465 MoveCursor(bounds.origin.x, bounds.origin.y + bounds.size.height - 1);
466 HorizontalLine(bounds.size.width);
467 PutChar(ACS_LLCORNER);
469 MoveCursor(bounds.origin.x + bounds.size.width - 1,
470 bounds.origin.y + bounds.size.height - 1);
471 PutChar(ACS_LRCORNER);
474 void TitledBox(
const Rect &bounds,
const char *title,
475 chtype v_char = ACS_VLINE, chtype h_char = ACS_HLINE) {
476 Box(bounds, v_char, h_char);
477 int title_offset = 2;
478 MoveCursor(bounds.origin.x + title_offset, bounds.origin.y);
480 PutCString(title, bounds.size.width - title_offset);
489 bool OutputColoredStringTruncated(
int right_pad, StringRef
string,
490 size_t skip_first_count,
491 bool use_blue_background) {
495 wattr_get(m_window, &saved_attr, &saved_pair,
nullptr);
496 if (use_blue_background)
497 ::wattron(m_window, COLOR_PAIR(WhiteOnBlue));
498 while (!
string.empty()) {
500 if (esc_pos == StringRef::npos) {
501 string =
string.substr(skip_first_count);
502 if (!
string.empty()) {
503 PutCStringTruncated(right_pad,
string.data(),
string.size());
509 if (skip_first_count > 0) {
510 int skip = std::min(esc_pos, skip_first_count);
511 string =
string.substr(skip);
512 skip_first_count -= skip;
516 PutCStringTruncated(right_pad,
string.data(), esc_pos);
518 string =
string.drop_front(esc_pos);
530 if (!!
string.consumeInteger(10, value) ||
533 llvm::errs() <<
"No valid color code in color escape sequence.\n";
538 <<
"' in color escape sequence.\n";
542 wattr_set(m_window, saved_attr, saved_pair,
nullptr);
543 if (use_blue_background)
544 ::wattron(m_window, COLOR_PAIR(WhiteOnBlue));
546 ::wattron(m_window, A_UNDERLINE);
550 (use_blue_background ? 8 : 0)));
553 wattr_set(m_window, saved_attr, saved_pair,
nullptr);
559 WINDOW *m_window =
nullptr;
562class Pad :
public Surface {
564 Pad(Size size) : Surface(Surface::
Type::Pad) {
565 m_window = ::newpad(size.height, size.width);
568 ~Pad() { ::delwin(m_window); }
571class Window :
public Surface {
573 Window(
const char *name)
574 : Surface(Surface::
Type::Window), m_name(name), m_panel(nullptr),
575 m_parent(nullptr), m_subwindows(), m_delegate_sp(),
577 m_prev_active_window_idx(
UINT32_MAX), m_delete(false),
578 m_needs_update(true), m_can_activate(true), m_is_subwin(false) {}
580 Window(
const char *name, WINDOW *w,
bool del =
true)
581 : Surface(Surface::
Type::Window), m_name(name), m_panel(nullptr),
582 m_parent(nullptr), m_subwindows(), m_delegate_sp(),
584 m_prev_active_window_idx(
UINT32_MAX), m_delete(del),
585 m_needs_update(true), m_can_activate(true), m_is_subwin(false) {
590 Window(
const char *name,
const Rect &bounds)
591 : Surface(Surface::
Type::Window), m_name(name), m_panel(nullptr),
592 m_parent(nullptr), m_subwindows(), m_delegate_sp(),
594 m_prev_active_window_idx(
UINT32_MAX), m_delete(false),
595 m_needs_update(true), m_can_activate(true), m_is_subwin(false) {
596 Reset(::newwin(bounds.size.height, bounds.size.width, bounds.origin.y,
605 void Reset(WINDOW *w =
nullptr,
bool del =
true) {
610 ::del_panel(m_panel);
613 if (m_window && m_delete) {
620 m_panel = ::new_panel(m_window);
626 Rect GetBounds()
const {
return Rect(GetParentOrigin(), GetSize()); }
628 Rect GetCenteredRect(
int width,
int height) {
629 Size size = GetSize();
630 width = std::min(size.width, width);
631 height = std::min(size.height, height);
632 int x = (size.width - width) / 2;
633 int y = (size.height - height) / 2;
634 return Rect(Point(x, y), Size(width, height));
637 int GetChar() { return ::wgetch(m_window); }
638 Point GetParentOrigin()
const {
return Point(GetParentX(), GetParentY()); }
639 int GetParentX()
const {
return getparx(m_window); }
640 int GetParentY()
const {
return getpary(m_window); }
641 void MoveWindow(
int x,
int y) { MoveWindow(Point(x, y)); }
642 void Resize(
int w,
int h) { ::wresize(m_window, h, w); }
643 void Resize(
const Size &size) {
644 ::wresize(m_window, size.height, size.width);
646 void MoveWindow(
const Point &origin) {
647 const bool moving_window = origin != GetParentOrigin();
648 if (m_is_subwin && moving_window) {
650 Size size = GetSize();
651 Reset(::subwin(m_parent->m_window, size.height, size.width, origin.y,
655 ::mvwin(m_window, origin.y, origin.x);
659 void SetBounds(
const Rect &bounds) {
660 const bool moving_window = bounds.origin != GetParentOrigin();
661 if (m_is_subwin && moving_window) {
663 Reset(::subwin(m_parent->m_window, bounds.size.height, bounds.size.width,
664 bounds.origin.y, bounds.origin.x),
668 MoveWindow(bounds.origin);
674 ::touchwin(m_window);
679 WindowSP CreateSubWindow(
const char *name,
const Rect &bounds,
681 auto get_window = [
this, &bounds]() {
683 ? ::subwin(m_window, bounds.size.height, bounds.size.width,
684 bounds.origin.y, bounds.origin.x)
685 : ::newwin(bounds.size.height, bounds.size.width,
686 bounds.origin.y, bounds.origin.x);
688 WindowSP subwindow_sp = std::make_shared<Window>(name, get_window(),
true);
689 subwindow_sp->m_is_subwin = subwindow_sp.operator bool();
690 subwindow_sp->m_parent =
this;
692 m_prev_active_window_idx = m_curr_active_window_idx;
693 m_curr_active_window_idx = m_subwindows.size();
695 m_subwindows.push_back(subwindow_sp);
696 ::top_panel(subwindow_sp->m_panel);
697 m_needs_update =
true;
701 bool RemoveSubWindow(Window *window) {
702 Windows::iterator pos, end = m_subwindows.end();
704 for (pos = m_subwindows.begin(); pos != end; ++pos, ++i) {
705 if ((*pos).get() == window) {
706 if (m_prev_active_window_idx == i)
708 else if (m_prev_active_window_idx !=
UINT32_MAX &&
709 m_prev_active_window_idx > i)
710 --m_prev_active_window_idx;
712 if (m_curr_active_window_idx == i)
714 else if (m_curr_active_window_idx !=
UINT32_MAX &&
715 m_curr_active_window_idx > i)
716 --m_curr_active_window_idx;
718 m_subwindows.erase(pos);
719 m_needs_update =
true;
730 WindowSP FindSubWindow(
const char *name) {
731 Windows::iterator pos, end = m_subwindows.end();
733 for (pos = m_subwindows.begin(); pos != end; ++pos, ++i) {
734 if ((*pos)->m_name == name)
740 void RemoveSubWindows() {
743 for (Windows::iterator pos = m_subwindows.begin();
744 pos != m_subwindows.end(); pos = m_subwindows.erase(pos)) {
754 void DrawTitleBox(
const char *title,
const char *bottom_message =
nullptr) {
757 attr = A_BOLD | COLOR_PAIR(BlackOnWhite);
766 if (title && title[0]) {
772 if (bottom_message && bottom_message[0]) {
773 int bottom_message_length = strlen(bottom_message);
774 int x = GetWidth() - 3 - (bottom_message_length + 2);
777 MoveCursor(x, GetHeight() - 1);
779 PutCString(bottom_message);
782 MoveCursor(1, GetHeight() - 1);
784 PutCStringTruncated(1, bottom_message);
791 virtual void Draw(
bool force) {
792 if (m_delegate_sp && m_delegate_sp->WindowDelegateDraw(*
this, force))
795 for (
auto &subwindow_sp : m_subwindows)
796 subwindow_sp->Draw(force);
799 bool CreateHelpSubwindow() {
801 const char *text = m_delegate_sp->WindowDelegateGetHelpText();
802 KeyHelp *key_help = m_delegate_sp->WindowDelegateGetKeyHelp();
803 if ((text && text[0]) || key_help) {
804 std::unique_ptr<HelpDialogDelegate> help_delegate_up(
805 new HelpDialogDelegate(text, key_help));
806 const size_t num_lines = help_delegate_up->GetNumLines();
807 const size_t max_length = help_delegate_up->GetMaxLineLength();
808 Rect bounds = GetBounds();
810 if (max_length + 4 <
static_cast<size_t>(bounds.size.width)) {
811 bounds.origin.x += (bounds.size.width - max_length + 4) / 2;
812 bounds.size.width = max_length + 4;
814 if (bounds.size.width > 100) {
815 const int inset_w = bounds.size.width / 4;
816 bounds.origin.x += inset_w;
817 bounds.size.width -= 2 * inset_w;
821 if (num_lines + 2 <
static_cast<size_t>(bounds.size.height)) {
822 bounds.origin.y += (bounds.size.height - num_lines + 2) / 2;
823 bounds.size.height = num_lines + 2;
825 if (bounds.size.height > 100) {
826 const int inset_h = bounds.size.height / 4;
827 bounds.origin.y += inset_h;
828 bounds.size.height -= 2 * inset_h;
831 WindowSP help_window_sp;
832 Window *parent_window = GetParent();
834 help_window_sp = parent_window->CreateSubWindow(
"Help", bounds,
true);
836 help_window_sp = CreateSubWindow(
"Help", bounds,
true);
837 help_window_sp->SetDelegate(
838 WindowDelegateSP(help_delegate_up.release()));
845 virtual HandleCharResult HandleChar(
int key) {
847 HandleCharResult result = eKeyNotHandled;
848 WindowSP active_window_sp = GetActiveWindow();
849 if (active_window_sp) {
850 result = active_window_sp->HandleChar(key);
851 if (result != eKeyNotHandled)
856 result = m_delegate_sp->WindowDelegateHandleChar(*
this, key);
857 if (result != eKeyNotHandled)
865 Windows subwindows(m_subwindows);
866 for (
auto subwindow_sp : subwindows) {
867 if (!subwindow_sp->m_can_activate) {
868 HandleCharResult result = subwindow_sp->HandleChar(key);
869 if (result != eKeyNotHandled)
874 return eKeyNotHandled;
877 WindowSP GetActiveWindow() {
878 if (!m_subwindows.empty()) {
879 if (m_curr_active_window_idx >= m_subwindows.size()) {
880 if (m_prev_active_window_idx < m_subwindows.size()) {
881 m_curr_active_window_idx = m_prev_active_window_idx;
883 }
else if (IsActive()) {
888 const size_t num_subwindows = m_subwindows.size();
889 for (
size_t i = 0; i < num_subwindows; ++i) {
890 if (m_subwindows[i]->GetCanBeActive()) {
891 m_curr_active_window_idx = i;
898 if (m_curr_active_window_idx < m_subwindows.size())
899 return m_subwindows[m_curr_active_window_idx];
904 bool GetCanBeActive()
const {
return m_can_activate; }
906 void SetCanBeActive(
bool b) { m_can_activate = b; }
908 void SetDelegate(
const WindowDelegateSP &delegate_sp) {
909 m_delegate_sp = delegate_sp;
912 Window *GetParent()
const {
return m_parent; }
914 bool IsActive()
const {
916 return m_parent->GetActiveWindow().get() ==
this;
921 void SelectNextWindowAsActive() {
923 const int num_subwindows = m_subwindows.size();
926 m_prev_active_window_idx = m_curr_active_window_idx;
927 start_idx = m_curr_active_window_idx + 1;
929 for (
int idx = start_idx; idx < num_subwindows; ++idx) {
930 if (m_subwindows[idx]->GetCanBeActive()) {
931 m_curr_active_window_idx = idx;
935 for (
int idx = 0; idx < start_idx; ++idx) {
936 if (m_subwindows[idx]->GetCanBeActive()) {
937 m_curr_active_window_idx = idx;
943 void SelectPreviousWindowAsActive() {
945 const int num_subwindows = m_subwindows.size();
946 int start_idx = num_subwindows - 1;
948 m_prev_active_window_idx = m_curr_active_window_idx;
949 start_idx = m_curr_active_window_idx - 1;
951 for (
int idx = start_idx; idx >= 0; --idx) {
952 if (m_subwindows[idx]->GetCanBeActive()) {
953 m_curr_active_window_idx = idx;
957 for (
int idx = num_subwindows - 1; idx > start_idx; --idx) {
958 if (m_subwindows[idx]->GetCanBeActive()) {
959 m_curr_active_window_idx = idx;
965 const char *
GetName()
const {
return m_name.c_str(); }
971 Windows m_subwindows;
972 WindowDelegateSP m_delegate_sp;
973 uint32_t m_curr_active_window_idx;
974 uint32_t m_prev_active_window_idx;
981 Window(
const Window &) =
delete;
982 const Window &operator=(
const Window &) =
delete;
993struct ScrollContext {
997 ScrollContext(
int line) : start(line), end(line) {}
998 ScrollContext(
int _start,
int _end) : start(_start), end(_end) {}
1000 void Offset(
int offset) {
1006class FieldDelegate {
1008 virtual ~FieldDelegate() =
default;
1012 virtual int FieldDelegateGetHeight() = 0;
1019 virtual ScrollContext FieldDelegateGetScrollContext() {
1020 return ScrollContext(0, FieldDelegateGetHeight() - 1);
1026 virtual void FieldDelegateDraw(Surface &surface,
bool is_selected) = 0;
1029 virtual HandleCharResult FieldDelegateHandleChar(
int key) {
1030 return eKeyNotHandled;
1037 virtual void FieldDelegateExitCallback() {}
1051 virtual bool FieldDelegateOnFirstOrOnlyElement() {
return true; }
1055 virtual bool FieldDelegateOnLastOrOnlyElement() {
return true; }
1058 virtual void FieldDelegateSelectFirstElement() {}
1061 virtual void FieldDelegateSelectLastElement() {}
1064 virtual bool FieldDelegateHasError() {
return false; }
1066 bool FieldDelegateIsVisible() {
return m_is_visible; }
1068 void FieldDelegateHide() { m_is_visible =
false; }
1070 void FieldDelegateShow() { m_is_visible =
true; }
1073 bool m_is_visible =
true;
1076typedef std::unique_ptr<FieldDelegate> FieldDelegateUP;
1078class TextFieldDelegate :
public FieldDelegate {
1080 TextFieldDelegate(
const char *label,
const char *content,
bool required)
1081 : m_label(label), m_required(required) {
1083 m_content = content;
1096 int GetFieldHeight() {
return 3; }
1100 int FieldDelegateGetHeight()
override {
1101 int height = GetFieldHeight();
1102 if (FieldDelegateHasError())
1108 int GetCursorXPosition() {
return m_cursor_position - m_first_visibile_char; }
1110 int GetContentLength() {
return m_content.length(); }
1112 void DrawContent(Surface &surface,
bool is_selected) {
1113 UpdateScrolling(surface.GetWidth());
1115 surface.MoveCursor(0, 0);
1116 const char *text = m_content.c_str() + m_first_visibile_char;
1117 surface.PutCString(text, surface.GetWidth());
1120 surface.MoveCursor(GetCursorXPosition(), 0);
1122 surface.AttributeOn(A_REVERSE);
1123 if (m_cursor_position == GetContentLength())
1125 surface.PutChar(
' ');
1127 surface.PutChar(m_content[m_cursor_position]);
1129 surface.AttributeOff(A_REVERSE);
1132 void DrawField(Surface &surface,
bool is_selected) {
1133 surface.TitledBox(m_label.c_str());
1135 Rect content_bounds = surface.GetFrame();
1136 content_bounds.Inset(1, 1);
1137 Surface content_surface = surface.SubSurface(content_bounds);
1139 DrawContent(content_surface, is_selected);
1142 void DrawError(Surface &surface) {
1143 if (!FieldDelegateHasError())
1145 surface.MoveCursor(0, 0);
1146 surface.AttributeOn(COLOR_PAIR(RedOnBlack));
1147 surface.PutChar(ACS_DIAMOND);
1148 surface.PutChar(
' ');
1149 surface.PutCStringTruncated(1, GetError().c_str());
1150 surface.AttributeOff(COLOR_PAIR(RedOnBlack));
1153 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
1154 Rect frame = surface.GetFrame();
1155 Rect field_bounds, error_bounds;
1156 frame.HorizontalSplit(GetFieldHeight(), field_bounds, error_bounds);
1157 Surface field_surface = surface.SubSurface(field_bounds);
1158 Surface error_surface = surface.SubSurface(error_bounds);
1160 DrawField(field_surface, is_selected);
1161 DrawError(error_surface);
1165 int GetLastVisibleCharPosition(
int width) {
1166 int position = m_first_visibile_char + width - 1;
1167 return std::min(position, GetContentLength());
1170 void UpdateScrolling(
int width) {
1171 if (m_cursor_position < m_first_visibile_char) {
1172 m_first_visibile_char = m_cursor_position;
1176 if (m_cursor_position > GetLastVisibleCharPosition(width))
1177 m_first_visibile_char = m_cursor_position - (width - 1);
1182 void MoveCursorRight() {
1183 if (m_cursor_position < GetContentLength())
1184 m_cursor_position++;
1187 void MoveCursorLeft() {
1188 if (m_cursor_position > 0)
1189 m_cursor_position--;
1192 void MoveCursorToStart() { m_cursor_position = 0; }
1194 void MoveCursorToEnd() { m_cursor_position = GetContentLength(); }
1197 if (m_first_visibile_char > 0)
1198 m_first_visibile_char--;
1203 void InsertChar(
char character) {
1204 m_content.insert(m_cursor_position, 1, character);
1205 m_cursor_position++;
1211 void RemovePreviousChar() {
1212 if (m_cursor_position == 0)
1215 m_content.erase(m_cursor_position - 1, 1);
1216 m_cursor_position--;
1222 void RemoveNextChar() {
1223 if (m_cursor_position == GetContentLength())
1226 m_content.erase(m_cursor_position, 1);
1232 m_content.erase(m_cursor_position);
1238 m_cursor_position = 0;
1244 virtual bool IsAcceptableChar(
int key) {
1249 return isprint(key);
1252 HandleCharResult FieldDelegateHandleChar(
int key)
override {
1253 if (IsAcceptableChar(key)) {
1255 InsertChar((
char)key);
1262 MoveCursorToStart();
1278 RemovePreviousChar();
1294 return eKeyNotHandled;
1297 bool FieldDelegateHasError()
override {
return !m_error.empty(); }
1299 void FieldDelegateExitCallback()
override {
1300 if (!IsSpecified() && m_required)
1301 SetError(
"This field is required!");
1304 bool IsSpecified() {
return !m_content.empty(); }
1306 void ClearError() { m_error.clear(); }
1308 const std::string &GetError() {
return m_error; }
1310 void SetError(
const char *
error) { m_error =
error; }
1312 const std::string &GetText() {
return m_content; }
1314 void SetText(
const char *text) {
1315 if (text ==
nullptr) {
1323 std::string m_label;
1326 std::string m_content;
1329 int m_cursor_position = 0;
1331 int m_first_visibile_char = 0;
1333 std::string m_error;
1336class IntegerFieldDelegate :
public TextFieldDelegate {
1338 IntegerFieldDelegate(
const char *label,
int content,
bool required)
1339 : TextFieldDelegate(label, std::to_string(content).c_str(), required) {}
1342 bool IsAcceptableChar(
int key)
override {
return isdigit(key); }
1345 int GetInteger() {
return std::stoi(m_content); }
1348class FileFieldDelegate :
public TextFieldDelegate {
1350 FileFieldDelegate(
const char *label,
const char *content,
bool need_to_exist,
1352 : TextFieldDelegate(label, content, required),
1353 m_need_to_exist(need_to_exist) {}
1355 void FieldDelegateExitCallback()
override {
1356 TextFieldDelegate::FieldDelegateExitCallback();
1360 if (!m_need_to_exist)
1363 FileSpec file = GetResolvedFileSpec();
1365 SetError(
"File doesn't exist!");
1369 SetError(
"Not a file!");
1385 const std::string &GetPath() {
return m_content; }
1388 bool m_need_to_exist;
1391class DirectoryFieldDelegate :
public TextFieldDelegate {
1393 DirectoryFieldDelegate(
const char *label,
const char *content,
1394 bool need_to_exist,
bool required)
1395 : TextFieldDelegate(label, content, required),
1396 m_need_to_exist(need_to_exist) {}
1398 void FieldDelegateExitCallback()
override {
1399 TextFieldDelegate::FieldDelegateExitCallback();
1403 if (!m_need_to_exist)
1406 FileSpec file = GetResolvedFileSpec();
1408 SetError(
"Directory doesn't exist!");
1412 SetError(
"Not a directory!");
1428 const std::string &GetPath() {
return m_content; }
1431 bool m_need_to_exist;
1434class ArchFieldDelegate :
public TextFieldDelegate {
1436 ArchFieldDelegate(
const char *label,
const char *content,
bool required)
1437 : TextFieldDelegate(label, content, required) {}
1439 void FieldDelegateExitCallback()
override {
1440 TextFieldDelegate::FieldDelegateExitCallback();
1444 if (!GetArchSpec().IsValid())
1445 SetError(
"Not a valid arch!");
1448 const std::string &GetArchString() {
return m_content; }
1453class BooleanFieldDelegate :
public FieldDelegate {
1455 BooleanFieldDelegate(
const char *label,
bool content)
1456 : m_label(label), m_content(content) {}
1463 int FieldDelegateGetHeight()
override {
return 1; }
1465 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
1466 surface.MoveCursor(0, 0);
1467 surface.PutChar(
'[');
1469 surface.AttributeOn(A_REVERSE);
1470 surface.PutChar(m_content ? ACS_DIAMOND :
' ');
1472 surface.AttributeOff(A_REVERSE);
1473 surface.PutChar(
']');
1474 surface.PutChar(
' ');
1475 surface.PutCString(m_label.c_str());
1478 void ToggleContent() { m_content = !m_content; }
1480 void SetContentToTrue() { m_content =
true; }
1482 void SetContentToFalse() { m_content =
false; }
1484 HandleCharResult FieldDelegateHandleChar(
int key)
override {
1492 SetContentToFalse();
1503 return eKeyNotHandled;
1507 bool GetBoolean() {
return m_content; }
1510 std::string m_label;
1514class ChoicesFieldDelegate :
public FieldDelegate {
1516 ChoicesFieldDelegate(
const char *label,
int number_of_visible_choices,
1517 std::vector<std::string> choices)
1518 : m_label(label), m_number_of_visible_choices(number_of_visible_choices),
1519 m_choices(choices) {}
1533 int FieldDelegateGetHeight()
override {
1534 return m_number_of_visible_choices + 2;
1537 int GetNumberOfChoices() {
return m_choices.size(); }
1540 int GetLastVisibleChoice() {
1541 int index = m_first_visibile_choice + m_number_of_visible_choices;
1542 return std::min(index, GetNumberOfChoices()) - 1;
1545 void DrawContent(Surface &surface,
bool is_selected) {
1546 int choices_to_draw = GetLastVisibleChoice() - m_first_visibile_choice + 1;
1547 for (
int i = 0; i < choices_to_draw; i++) {
1548 surface.MoveCursor(0, i);
1549 int current_choice = m_first_visibile_choice + i;
1550 const char *text = m_choices[current_choice].c_str();
1551 bool highlight = is_selected && current_choice == m_choice;
1553 surface.AttributeOn(A_REVERSE);
1554 surface.PutChar(current_choice == m_choice ? ACS_DIAMOND :
' ');
1555 surface.PutCString(text);
1557 surface.AttributeOff(A_REVERSE);
1561 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
1564 surface.TitledBox(m_label.c_str());
1566 Rect content_bounds = surface.GetFrame();
1567 content_bounds.Inset(1, 1);
1568 Surface content_surface = surface.SubSurface(content_bounds);
1570 DrawContent(content_surface, is_selected);
1573 void SelectPrevious() {
1579 if (m_choice < GetNumberOfChoices() - 1)
1583 void UpdateScrolling() {
1584 if (m_choice > GetLastVisibleChoice()) {
1585 m_first_visibile_choice = m_choice - (m_number_of_visible_choices - 1);
1589 if (m_choice < m_first_visibile_choice)
1590 m_first_visibile_choice = m_choice;
1593 HandleCharResult FieldDelegateHandleChar(
int key)
override {
1604 return eKeyNotHandled;
1608 std::string GetChoiceContent() {
return m_choices[m_choice]; }
1611 int GetChoice() {
return m_choice; }
1613 void SetChoice(llvm::StringRef choice) {
1614 for (
int i = 0; i < GetNumberOfChoices(); i++) {
1615 if (choice == m_choices[i]) {
1623 std::string m_label;
1624 int m_number_of_visible_choices;
1625 std::vector<std::string> m_choices;
1629 int m_first_visibile_choice = 0;
1632class PlatformPluginFieldDelegate :
public ChoicesFieldDelegate {
1634 PlatformPluginFieldDelegate(
Debugger &debugger)
1635 : ChoicesFieldDelegate(
"Platform Plugin", 3, GetPossiblePluginNames()) {
1638 SetChoice(platform_sp->GetPluginName());
1641 std::vector<std::string> GetPossiblePluginNames() {
1642 std::vector<std::string> names;
1644 for (llvm::StringRef name =
1647 names.push_back(name.str());
1651 std::string GetPluginName() {
1652 std::string plugin_name = GetChoiceContent();
1657class ProcessPluginFieldDelegate :
public ChoicesFieldDelegate {
1659 ProcessPluginFieldDelegate()
1660 : ChoicesFieldDelegate(
"Process Plugin", 3, GetPossiblePluginNames()) {}
1662 std::vector<std::string> GetPossiblePluginNames() {
1663 std::vector<std::string> names;
1664 names.push_back(
"<default>");
1669 names.push_back(name.str());
1673 std::string GetPluginName() {
1674 std::string plugin_name = GetChoiceContent();
1675 if (plugin_name ==
"<default>")
1681class LazyBooleanFieldDelegate :
public ChoicesFieldDelegate {
1683 LazyBooleanFieldDelegate(
const char *label,
const char *calculate_label)
1684 : ChoicesFieldDelegate(label, 3, GetPossibleOptions(calculate_label)) {}
1686 static constexpr const char *kNo =
"No";
1687 static constexpr const char *kYes =
"Yes";
1689 std::vector<std::string> GetPossibleOptions(
const char *calculate_label) {
1690 std::vector<std::string> options;
1691 options.push_back(calculate_label);
1692 options.push_back(kYes);
1693 options.push_back(kNo);
1698 std::string choice = GetChoiceContent();
1701 else if (choice == kYes)
1708template <
class T>
class ListFieldDelegate :
public FieldDelegate {
1710 ListFieldDelegate(
const char *label, T default_field)
1711 : m_label(label), m_default_field(default_field),
1712 m_selection_type(SelectionType::NewButton) {}
1717 enum class SelectionType { Field, RemoveButton, NewButton };
1733 int FieldDelegateGetHeight()
override {
1737 for (
int i = 0; i < GetNumberOfFields(); i++) {
1738 height += m_fields[i].FieldDelegateGetHeight();
1745 ScrollContext FieldDelegateGetScrollContext()
override {
1746 int height = FieldDelegateGetHeight();
1747 if (m_selection_type == SelectionType::NewButton)
1748 return ScrollContext(height - 2, height - 1);
1750 FieldDelegate &field = m_fields[m_selection_index];
1751 ScrollContext context = field.FieldDelegateGetScrollContext();
1755 for (
int i = 0; i < m_selection_index; i++) {
1756 offset += m_fields[i].FieldDelegateGetHeight();
1758 context.Offset(offset);
1762 if (context.start == 1)
1767 if (context.end == height - 3)
1773 void DrawRemoveButton(Surface &surface,
int highlight) {
1774 surface.MoveCursor(1, surface.GetHeight() / 2);
1776 surface.AttributeOn(A_REVERSE);
1777 surface.PutCString(
"[Remove]");
1779 surface.AttributeOff(A_REVERSE);
1782 void DrawFields(Surface &surface,
bool is_selected) {
1784 int width = surface.GetWidth();
1785 for (
int i = 0; i < GetNumberOfFields(); i++) {
1786 int height = m_fields[i].FieldDelegateGetHeight();
1787 Rect bounds = Rect(Point(0, line), Size(width, height));
1788 Rect field_bounds, remove_button_bounds;
1789 bounds.VerticalSplit(bounds.size.width -
sizeof(
" [Remove]"),
1790 field_bounds, remove_button_bounds);
1791 Surface field_surface = surface.SubSurface(field_bounds);
1792 Surface remove_button_surface = surface.SubSurface(remove_button_bounds);
1794 bool is_element_selected = m_selection_index == i && is_selected;
1795 bool is_field_selected =
1796 is_element_selected && m_selection_type == SelectionType::Field;
1797 bool is_remove_button_selected =
1798 is_element_selected &&
1799 m_selection_type == SelectionType::RemoveButton;
1800 m_fields[i].FieldDelegateDraw(field_surface, is_field_selected);
1801 DrawRemoveButton(remove_button_surface, is_remove_button_selected);
1807 void DrawNewButton(Surface &surface,
bool is_selected) {
1808 const char *button_text =
"[New]";
1809 int x = (surface.GetWidth() -
sizeof(button_text) - 1) / 2;
1810 surface.MoveCursor(x, 0);
1812 is_selected && m_selection_type == SelectionType::NewButton;
1814 surface.AttributeOn(A_REVERSE);
1815 surface.PutCString(button_text);
1817 surface.AttributeOff(A_REVERSE);
1820 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
1821 surface.TitledBox(m_label.c_str());
1823 Rect content_bounds = surface.GetFrame();
1824 content_bounds.Inset(1, 1);
1825 Rect fields_bounds, new_button_bounds;
1826 content_bounds.HorizontalSplit(content_bounds.size.height - 1,
1827 fields_bounds, new_button_bounds);
1828 Surface fields_surface = surface.SubSurface(fields_bounds);
1829 Surface new_button_surface = surface.SubSurface(new_button_bounds);
1831 DrawFields(fields_surface, is_selected);
1832 DrawNewButton(new_button_surface, is_selected);
1835 void AddNewField() {
1836 m_fields.push_back(m_default_field);
1837 m_selection_index = GetNumberOfFields() - 1;
1838 m_selection_type = SelectionType::Field;
1839 FieldDelegate &field = m_fields[m_selection_index];
1840 field.FieldDelegateSelectFirstElement();
1843 void RemoveField() {
1844 m_fields.erase(m_fields.begin() + m_selection_index);
1845 if (m_selection_index != 0)
1846 m_selection_index--;
1848 if (GetNumberOfFields() > 0) {
1849 m_selection_type = SelectionType::Field;
1850 FieldDelegate &field = m_fields[m_selection_index];
1851 field.FieldDelegateSelectFirstElement();
1853 m_selection_type = SelectionType::NewButton;
1856 HandleCharResult SelectNext(
int key) {
1857 if (m_selection_type == SelectionType::NewButton)
1858 return eKeyNotHandled;
1860 if (m_selection_type == SelectionType::RemoveButton) {
1861 if (m_selection_index == GetNumberOfFields() - 1) {
1862 m_selection_type = SelectionType::NewButton;
1865 m_selection_index++;
1866 m_selection_type = SelectionType::Field;
1867 FieldDelegate &next_field = m_fields[m_selection_index];
1868 next_field.FieldDelegateSelectFirstElement();
1872 FieldDelegate &field = m_fields[m_selection_index];
1873 if (!field.FieldDelegateOnLastOrOnlyElement()) {
1874 return field.FieldDelegateHandleChar(key);
1877 field.FieldDelegateExitCallback();
1879 m_selection_type = SelectionType::RemoveButton;
1883 HandleCharResult SelectPrevious(
int key) {
1884 if (FieldDelegateOnFirstOrOnlyElement())
1885 return eKeyNotHandled;
1887 if (m_selection_type == SelectionType::RemoveButton) {
1888 m_selection_type = SelectionType::Field;
1889 FieldDelegate &field = m_fields[m_selection_index];
1890 field.FieldDelegateSelectLastElement();
1894 if (m_selection_type == SelectionType::NewButton) {
1895 m_selection_type = SelectionType::RemoveButton;
1896 m_selection_index = GetNumberOfFields() - 1;
1900 FieldDelegate &field = m_fields[m_selection_index];
1901 if (!field.FieldDelegateOnFirstOrOnlyElement()) {
1902 return field.FieldDelegateHandleChar(key);
1905 field.FieldDelegateExitCallback();
1907 m_selection_type = SelectionType::RemoveButton;
1908 m_selection_index--;
1914 HandleCharResult SelectNextInList(
int key) {
1915 assert(m_selection_type == SelectionType::Field);
1917 FieldDelegate &field = m_fields[m_selection_index];
1918 if (field.FieldDelegateHandleChar(key) == eKeyHandled)
1921 if (!field.FieldDelegateOnLastOrOnlyElement())
1922 return eKeyNotHandled;
1924 field.FieldDelegateExitCallback();
1926 if (m_selection_index == GetNumberOfFields() - 1) {
1927 m_selection_type = SelectionType::NewButton;
1931 m_selection_index++;
1932 FieldDelegate &next_field = m_fields[m_selection_index];
1933 next_field.FieldDelegateSelectFirstElement();
1937 HandleCharResult FieldDelegateHandleChar(
int key)
override {
1942 switch (m_selection_type) {
1943 case SelectionType::NewButton:
1946 case SelectionType::RemoveButton:
1949 case SelectionType::Field:
1950 return SelectNextInList(key);
1954 return SelectNext(key);
1956 return SelectPrevious(key);
1963 if (m_selection_type == SelectionType::Field) {
1964 return m_fields[m_selection_index].FieldDelegateHandleChar(key);
1967 return eKeyNotHandled;
1970 bool FieldDelegateOnLastOrOnlyElement()
override {
1971 if (m_selection_type == SelectionType::NewButton) {
1977 bool FieldDelegateOnFirstOrOnlyElement()
override {
1978 if (m_selection_type == SelectionType::NewButton &&
1979 GetNumberOfFields() == 0)
1982 if (m_selection_type == SelectionType::Field && m_selection_index == 0) {
1983 FieldDelegate &field = m_fields[m_selection_index];
1984 return field.FieldDelegateOnFirstOrOnlyElement();
1990 void FieldDelegateSelectFirstElement()
override {
1991 if (GetNumberOfFields() == 0) {
1992 m_selection_type = SelectionType::NewButton;
1996 m_selection_type = SelectionType::Field;
1997 m_selection_index = 0;
2000 void FieldDelegateSelectLastElement()
override {
2001 m_selection_type = SelectionType::NewButton;
2004 int GetNumberOfFields() {
return m_fields.size(); }
2007 T &GetField(
int index) {
return m_fields[index]; }
2010 std::string m_label;
2014 std::vector<T> m_fields;
2015 int m_selection_index = 0;
2017 SelectionType m_selection_type;
2020class ArgumentsFieldDelegate :
public ListFieldDelegate<TextFieldDelegate> {
2022 ArgumentsFieldDelegate()
2023 : ListFieldDelegate(
"Arguments",
2024 TextFieldDelegate(
"Argument",
"", false)) {}
2026 Args GetArguments() {
2028 for (
int i = 0; i < GetNumberOfFields(); i++) {
2034 void AddArguments(
const Args &arguments) {
2037 TextFieldDelegate &field = GetField(GetNumberOfFields() - 1);
2043template <
class KeyFieldDelegateType,
class ValueFieldDelegateType>
2044class MappingFieldDelegate :
public FieldDelegate {
2046 MappingFieldDelegate(KeyFieldDelegateType key_field,
2047 ValueFieldDelegateType value_field)
2048 : m_key_field(key_field), m_value_field(value_field),
2049 m_selection_type(SelectionType::Key) {}
2052 enum class SelectionType { Key,
Value };
2065 int FieldDelegateGetHeight()
override {
2066 return std::max(m_key_field.FieldDelegateGetHeight(),
2067 m_value_field.FieldDelegateGetHeight());
2070 void DrawArrow(Surface &surface) {
2071 surface.MoveCursor(0, 1);
2072 surface.PutChar(ACS_RARROW);
2075 void FieldDelegateDraw(Surface &surface,
bool is_selected)
override {
2076 Rect bounds = surface.GetFrame();
2077 Rect key_field_bounds, arrow_and_value_field_bounds;
2078 bounds.VerticalSplit(bounds.size.width / 2, key_field_bounds,
2079 arrow_and_value_field_bounds);
2080 Rect arrow_bounds, value_field_bounds;
2081 arrow_and_value_field_bounds.VerticalSplit(1, arrow_bounds,
2082 value_field_bounds);
2084 Surface key_field_surface = surface.SubSurface(key_field_bounds);
2085 Surface arrow_surface = surface.SubSurface(arrow_bounds);
2086 Surface value_field_surface = surface.SubSurface(value_field_bounds);
2088 bool key_is_selected =
2089 m_selection_type == SelectionType::Key && is_selected;
2090 m_key_field.FieldDelegateDraw(key_field_surface, key_is_selected);
2091 DrawArrow(arrow_surface);
2092 bool value_is_selected =
2093 m_selection_type == SelectionType::Value && is_selected;
2094 m_value_field.FieldDelegateDraw(value_field_surface, value_is_selected);
2097 HandleCharResult SelectNext(
int key) {
2098 if (FieldDelegateOnLastOrOnlyElement())
2099 return eKeyNotHandled;
2101 if (!m_key_field.FieldDelegateOnLastOrOnlyElement()) {
2102 return m_key_field.FieldDelegateHandleChar(key);
2105 m_key_field.FieldDelegateExitCallback();
2106 m_selection_type = SelectionType::Value;
2107 m_value_field.FieldDelegateSelectFirstElement();
2111 HandleCharResult SelectPrevious(
int key) {
2112 if (FieldDelegateOnFirstOrOnlyElement())
2113 return eKeyNotHandled;
2115 if (!m_value_field.FieldDelegateOnFirstOrOnlyElement()) {
2116 return m_value_field.FieldDelegateHandleChar(key);
2119 m_value_field.FieldDelegateExitCallback();
2120 m_selection_type = SelectionType::Key;
2121 m_key_field.FieldDelegateSelectLastElement();
2128 HandleCharResult SelectNextField(
int key) {
2129 if (m_selection_type == SelectionType::Value) {
2130 return m_value_field.FieldDelegateHandleChar(key);
2133 if (m_key_field.FieldDelegateHandleChar(key) == eKeyHandled)
2136 if (!m_key_field.FieldDelegateOnLastOrOnlyElement())
2137 return eKeyNotHandled;
2139 m_key_field.FieldDelegateExitCallback();
2140 m_selection_type = SelectionType::Value;
2141 m_value_field.FieldDelegateSelectFirstElement();
2145 HandleCharResult FieldDelegateHandleChar(
int key)
override {
2148 return SelectNextField(key);
2150 return SelectNext(key);
2152 return SelectPrevious(key);
2158 if (m_selection_type == SelectionType::Key)
2159 return m_key_field.FieldDelegateHandleChar(key);
2161 return m_value_field.FieldDelegateHandleChar(key);
2163 return eKeyNotHandled;
2166 bool FieldDelegateOnFirstOrOnlyElement()
override {
2167 return m_selection_type == SelectionType::Key;
2170 bool FieldDelegateOnLastOrOnlyElement()
override {
2171 return m_selection_type == SelectionType::Value;
2174 void FieldDelegateSelectFirstElement()
override {
2175 m_selection_type = SelectionType::Key;
2178 void FieldDelegateSelectLastElement()
override {
2179 m_selection_type = SelectionType::Value;
2182 bool FieldDelegateHasError()
override {
2183 return m_key_field.FieldDelegateHasError() ||
2184 m_value_field.FieldDelegateHasError();
2187 KeyFieldDelegateType &GetKeyField() {
return m_key_field; }
2189 ValueFieldDelegateType &GetValueField() {
return m_value_field; }
2192 KeyFieldDelegateType m_key_field;
2193 ValueFieldDelegateType m_value_field;
2195 SelectionType m_selection_type;
2198class EnvironmentVariableNameFieldDelegate :
public TextFieldDelegate {
2200 EnvironmentVariableNameFieldDelegate(
const char *content)
2201 : TextFieldDelegate(
"Name", content, true) {}
2204 bool IsAcceptableChar(
int key)
override {
2205 return TextFieldDelegate::IsAcceptableChar(key) && key !=
'=';
2208 const std::string &
GetName() {
return m_content; }
2211class EnvironmentVariableFieldDelegate
2212 :
public MappingFieldDelegate<EnvironmentVariableNameFieldDelegate,
2213 TextFieldDelegate> {
2215 EnvironmentVariableFieldDelegate()
2216 : MappingFieldDelegate(
2217 EnvironmentVariableNameFieldDelegate(
""),
2218 TextFieldDelegate(
"Value",
"", false)) {}
2220 const std::string &
GetName() {
return GetKeyField().GetName(); }
2222 const std::string &GetValue() {
return GetValueField().GetText(); }
2224 void SetName(
const char *name) {
return GetKeyField().SetText(name); }
2226 void SetValue(
const char *value) {
return GetValueField().SetText(value); }
2229class EnvironmentVariableListFieldDelegate
2230 :
public ListFieldDelegate<EnvironmentVariableFieldDelegate> {
2232 EnvironmentVariableListFieldDelegate(
const char *label)
2233 : ListFieldDelegate(label, EnvironmentVariableFieldDelegate()) {}
2237 for (
int i = 0; i < GetNumberOfFields(); i++) {
2239 std::make_pair(GetField(i).
GetName(), GetField(i).GetValue()));
2244 void AddEnvironmentVariables(
const Environment &environment) {
2245 for (
auto &variable : environment) {
2247 EnvironmentVariableFieldDelegate &field =
2248 GetField(GetNumberOfFields() - 1);
2249 field.SetName(variable.getKey().str().c_str());
2250 field.SetValue(variable.getValue().c_str());
2257 FormAction(
const char *label, std::function<
void(Window &)> action)
2258 : m_action(action) {
2264 void Draw(Surface &surface,
bool is_selected) {
2265 int x = (surface.GetWidth() - m_label.length()) / 2;
2266 surface.MoveCursor(x, 0);
2268 surface.AttributeOn(A_REVERSE);
2269 surface.PutChar(
'[');
2270 surface.PutCString(m_label.c_str());
2271 surface.PutChar(
']');
2273 surface.AttributeOff(A_REVERSE);
2276 void Execute(Window &window) { m_action(window); }
2278 const std::string &GetLabel() {
return m_label; }
2281 std::string m_label;
2282 std::function<void(Window &)> m_action;
2287 FormDelegate() =
default;
2289 virtual ~FormDelegate() =
default;
2291 virtual std::string
GetName() = 0;
2293 virtual void UpdateFieldsVisibility() {}
2295 FieldDelegate *GetField(uint32_t field_index) {
2296 if (field_index < m_fields.size())
2297 return m_fields[field_index].get();
2301 FormAction &GetAction(
int action_index) {
return m_actions[action_index]; }
2303 int GetNumberOfFields() {
return m_fields.size(); }
2305 int GetNumberOfActions() {
return m_actions.size(); }
2307 bool HasError() {
return !m_error.empty(); }
2309 void ClearError() { m_error.clear(); }
2311 const std::string &GetError() {
return m_error; }
2313 void SetError(
const char *
error) { m_error =
error; }
2318 bool CheckFieldsValidity() {
2319 for (
int i = 0; i < GetNumberOfFields(); i++) {
2320 GetField(i)->FieldDelegateExitCallback();
2321 if (GetField(i)->FieldDelegateHasError()) {
2322 SetError(
"Some fields are invalid!");
2331 TextFieldDelegate *AddTextField(
const char *label,
const char *content,
2333 TextFieldDelegate *delegate =
2334 new TextFieldDelegate(label, content, required);
2335 m_fields.push_back(FieldDelegateUP(delegate));
2339 FileFieldDelegate *AddFileField(
const char *label,
const char *content,
2340 bool need_to_exist,
bool required) {
2341 FileFieldDelegate *delegate =
2342 new FileFieldDelegate(label, content, need_to_exist, required);
2343 m_fields.push_back(FieldDelegateUP(delegate));
2347 DirectoryFieldDelegate *AddDirectoryField(
const char *label,
2348 const char *content,
2349 bool need_to_exist,
bool required) {
2350 DirectoryFieldDelegate *delegate =
2351 new DirectoryFieldDelegate(label, content, need_to_exist, required);
2352 m_fields.push_back(FieldDelegateUP(delegate));
2356 ArchFieldDelegate *AddArchField(
const char *label,
const char *content,
2358 ArchFieldDelegate *delegate =
2359 new ArchFieldDelegate(label, content, required);
2360 m_fields.push_back(FieldDelegateUP(delegate));
2364 IntegerFieldDelegate *AddIntegerField(
const char *label,
int content,
2366 IntegerFieldDelegate *delegate =
2367 new IntegerFieldDelegate(label, content, required);
2368 m_fields.push_back(FieldDelegateUP(delegate));
2372 BooleanFieldDelegate *AddBooleanField(
const char *label,
bool content) {
2373 BooleanFieldDelegate *delegate =
new BooleanFieldDelegate(label, content);
2374 m_fields.push_back(FieldDelegateUP(delegate));
2378 LazyBooleanFieldDelegate *AddLazyBooleanField(
const char *label,
2379 const char *calculate_label) {
2380 LazyBooleanFieldDelegate *delegate =
2381 new LazyBooleanFieldDelegate(label, calculate_label);
2382 m_fields.push_back(FieldDelegateUP(delegate));
2386 ChoicesFieldDelegate *AddChoicesField(
const char *label,
int height,
2387 std::vector<std::string> choices) {
2388 ChoicesFieldDelegate *delegate =
2389 new ChoicesFieldDelegate(label, height, choices);
2390 m_fields.push_back(FieldDelegateUP(delegate));
2394 PlatformPluginFieldDelegate *AddPlatformPluginField(
Debugger &debugger) {
2395 PlatformPluginFieldDelegate *delegate =
2396 new PlatformPluginFieldDelegate(debugger);
2397 m_fields.push_back(FieldDelegateUP(delegate));
2401 ProcessPluginFieldDelegate *AddProcessPluginField() {
2402 ProcessPluginFieldDelegate *delegate =
new ProcessPluginFieldDelegate();
2403 m_fields.push_back(FieldDelegateUP(delegate));
2408 ListFieldDelegate<T> *AddListField(
const char *label, T default_field) {
2409 ListFieldDelegate<T> *delegate =
2410 new ListFieldDelegate<T>(label, default_field);
2411 m_fields.push_back(FieldDelegateUP(delegate));
2415 ArgumentsFieldDelegate *AddArgumentsField() {
2416 ArgumentsFieldDelegate *delegate =
new ArgumentsFieldDelegate();
2417 m_fields.push_back(FieldDelegateUP(delegate));
2421 template <
class K,
class V>
2422 MappingFieldDelegate<K, V> *AddMappingField(K key_field, V value_field) {
2423 MappingFieldDelegate<K, V> *delegate =
2424 new MappingFieldDelegate<K, V>(key_field, value_field);
2425 m_fields.push_back(FieldDelegateUP(delegate));
2429 EnvironmentVariableNameFieldDelegate *
2430 AddEnvironmentVariableNameField(
const char *content) {
2431 EnvironmentVariableNameFieldDelegate *delegate =
2432 new EnvironmentVariableNameFieldDelegate(content);
2433 m_fields.push_back(FieldDelegateUP(delegate));
2437 EnvironmentVariableFieldDelegate *AddEnvironmentVariableField() {
2438 EnvironmentVariableFieldDelegate *delegate =
2439 new EnvironmentVariableFieldDelegate();
2440 m_fields.push_back(FieldDelegateUP(delegate));
2444 EnvironmentVariableListFieldDelegate *
2445 AddEnvironmentVariableListField(
const char *label) {
2446 EnvironmentVariableListFieldDelegate *delegate =
2447 new EnvironmentVariableListFieldDelegate(label);
2448 m_fields.push_back(FieldDelegateUP(delegate));
2454 void AddAction(
const char *label, std::function<
void(Window &)> action) {
2455 m_actions.push_back(FormAction(label, action));
2459 std::vector<FieldDelegateUP> m_fields;
2460 std::vector<FormAction> m_actions;
2462 std::string m_error;
2465typedef std::shared_ptr<FormDelegate> FormDelegateSP;
2467class FormWindowDelegate :
public WindowDelegate {
2469 FormWindowDelegate(FormDelegateSP &delegate_sp) : m_delegate_sp(delegate_sp) {
2470 assert(m_delegate_sp->GetNumberOfActions() > 0);
2471 if (m_delegate_sp->GetNumberOfFields() > 0)
2472 m_selection_type = SelectionType::Field;
2474 m_selection_type = SelectionType::Action;
2480 enum class SelectionType { Field, Action };
2498 int GetErrorHeight() {
2499 if (m_delegate_sp->HasError())
2505 int GetActionsHeight() {
2506 if (m_delegate_sp->GetNumberOfActions() > 0)
2512 int GetContentHeight() {
2514 height += GetErrorHeight();
2515 for (
int i = 0; i < m_delegate_sp->GetNumberOfFields(); i++) {
2516 if (!m_delegate_sp->GetField(i)->FieldDelegateIsVisible())
2518 height += m_delegate_sp->GetField(i)->FieldDelegateGetHeight();
2520 height += GetActionsHeight();
2524 ScrollContext GetScrollContext() {
2525 if (m_selection_type == SelectionType::Action)
2526 return ScrollContext(GetContentHeight() - 1);
2528 FieldDelegate *field = m_delegate_sp->GetField(m_selection_index);
2529 ScrollContext context = field->FieldDelegateGetScrollContext();
2531 int offset = GetErrorHeight();
2532 for (
int i = 0; i < m_selection_index; i++) {
2533 if (!m_delegate_sp->GetField(i)->FieldDelegateIsVisible())
2535 offset += m_delegate_sp->GetField(i)->FieldDelegateGetHeight();
2537 context.Offset(offset);
2541 if (context.start == GetErrorHeight())
2547 void UpdateScrolling(Surface &surface) {
2548 ScrollContext context = GetScrollContext();
2549 int content_height = GetContentHeight();
2550 int surface_height = surface.GetHeight();
2551 int visible_height = std::min(content_height, surface_height);
2552 int last_visible_line = m_first_visible_line + visible_height - 1;
2557 if (last_visible_line > content_height - 1) {
2558 m_first_visible_line = content_height - visible_height;
2561 if (context.start < m_first_visible_line) {
2562 m_first_visible_line = context.start;
2566 if (context.end > last_visible_line) {
2567 m_first_visible_line = context.end - visible_height + 1;
2571 void DrawError(Surface &surface) {
2572 if (!m_delegate_sp->HasError())
2574 surface.MoveCursor(0, 0);
2575 surface.AttributeOn(COLOR_PAIR(RedOnBlack));
2576 surface.PutChar(ACS_DIAMOND);
2577 surface.PutChar(
' ');
2578 surface.PutCStringTruncated(1, m_delegate_sp->GetError().c_str());
2579 surface.AttributeOff(COLOR_PAIR(RedOnBlack));
2581 surface.MoveCursor(0, 1);
2582 surface.HorizontalLine(surface.GetWidth());
2585 void DrawFields(Surface &surface) {
2587 int width = surface.GetWidth();
2588 bool a_field_is_selected = m_selection_type == SelectionType::Field;
2589 for (
int i = 0; i < m_delegate_sp->GetNumberOfFields(); i++) {
2590 FieldDelegate *field = m_delegate_sp->GetField(i);
2591 if (!field->FieldDelegateIsVisible())
2593 bool is_field_selected = a_field_is_selected && m_selection_index == i;
2594 int height = field->FieldDelegateGetHeight();
2595 Rect bounds = Rect(Point(0, line), Size(width, height));
2596 Surface field_surface = surface.SubSurface(bounds);
2597 field->FieldDelegateDraw(field_surface, is_field_selected);
2602 void DrawActions(Surface &surface) {
2603 int number_of_actions = m_delegate_sp->GetNumberOfActions();
2604 int width = surface.GetWidth() / number_of_actions;
2605 bool an_action_is_selected = m_selection_type == SelectionType::Action;
2607 for (
int i = 0; i < number_of_actions; i++) {
2608 bool is_action_selected = an_action_is_selected && m_selection_index == i;
2609 FormAction &action = m_delegate_sp->GetAction(i);
2610 Rect bounds = Rect(Point(x, 0), Size(width, 1));
2611 Surface action_surface = surface.SubSurface(bounds);
2612 action.Draw(action_surface, is_action_selected);
2617 void DrawElements(Surface &surface) {
2618 Rect frame = surface.GetFrame();
2619 Rect fields_bounds, actions_bounds;
2620 frame.HorizontalSplit(surface.GetHeight() - GetActionsHeight(),
2621 fields_bounds, actions_bounds);
2622 Surface fields_surface = surface.SubSurface(fields_bounds);
2623 Surface actions_surface = surface.SubSurface(actions_bounds);
2625 DrawFields(fields_surface);
2626 DrawActions(actions_surface);
2632 void DrawContent(Surface &surface) {
2633 UpdateScrolling(surface);
2635 int width = surface.GetWidth();
2636 int height = GetContentHeight();
2637 Pad pad = Pad(Size(width, height));
2639 Rect frame = pad.GetFrame();
2640 Rect error_bounds, elements_bounds;
2641 frame.HorizontalSplit(GetErrorHeight(), error_bounds, elements_bounds);
2642 Surface error_surface = pad.SubSurface(error_bounds);
2643 Surface elements_surface = pad.SubSurface(elements_bounds);
2645 DrawError(error_surface);
2646 DrawElements(elements_surface);
2648 int copy_height = std::min(surface.GetHeight(), pad.GetHeight());
2649 pad.CopyToSurface(surface, Point(0, m_first_visible_line), Point(),
2650 Size(width, copy_height));
2653 void DrawSubmitHint(Surface &surface,
bool is_active) {
2654 surface.MoveCursor(2, surface.GetHeight() - 1);
2656 surface.AttributeOn(A_BOLD | COLOR_PAIR(BlackOnWhite));
2657 surface.Printf(
"[Press Alt+Enter to %s]",
2658 m_delegate_sp->GetAction(0).GetLabel().c_str());
2660 surface.AttributeOff(A_BOLD | COLOR_PAIR(BlackOnWhite));
2663 bool WindowDelegateDraw(Window &window,
bool force)
override {
2664 m_delegate_sp->UpdateFieldsVisibility();
2668 window.DrawTitleBox(m_delegate_sp->GetName().c_str(),
2669 "Press Esc to Cancel");
2670 DrawSubmitHint(window, window.IsActive());
2672 Rect content_bounds = window.GetFrame();
2673 content_bounds.Inset(2, 2);
2674 Surface content_surface = window.SubSurface(content_bounds);
2676 DrawContent(content_surface);
2680 void SkipNextHiddenFields() {
2682 if (m_delegate_sp->GetField(m_selection_index)->FieldDelegateIsVisible())
2685 if (m_selection_index == m_delegate_sp->GetNumberOfFields() - 1) {
2686 m_selection_type = SelectionType::Action;
2687 m_selection_index = 0;
2691 m_selection_index++;
2695 HandleCharResult SelectNext(
int key) {
2696 if (m_selection_type == SelectionType::Action) {
2697 if (m_selection_index < m_delegate_sp->GetNumberOfActions() - 1) {
2698 m_selection_index++;
2702 m_selection_index = 0;
2703 m_selection_type = SelectionType::Field;
2704 SkipNextHiddenFields();
2705 if (m_selection_type == SelectionType::Field) {
2706 FieldDelegate *next_field = m_delegate_sp->GetField(m_selection_index);
2707 next_field->FieldDelegateSelectFirstElement();
2712 FieldDelegate *field = m_delegate_sp->GetField(m_selection_index);
2713 if (!field->FieldDelegateOnLastOrOnlyElement()) {
2714 return field->FieldDelegateHandleChar(key);
2717 field->FieldDelegateExitCallback();
2719 if (m_selection_index == m_delegate_sp->GetNumberOfFields() - 1) {
2720 m_selection_type = SelectionType::Action;
2721 m_selection_index = 0;
2725 m_selection_index++;
2726 SkipNextHiddenFields();
2728 if (m_selection_type == SelectionType::Field) {
2729 FieldDelegate *next_field = m_delegate_sp->GetField(m_selection_index);
2730 next_field->FieldDelegateSelectFirstElement();
2736 void SkipPreviousHiddenFields() {
2738 if (m_delegate_sp->GetField(m_selection_index)->FieldDelegateIsVisible())
2741 if (m_selection_index == 0) {
2742 m_selection_type = SelectionType::Action;
2743 m_selection_index = 0;
2747 m_selection_index--;
2751 HandleCharResult SelectPrevious(
int key) {
2752 if (m_selection_type == SelectionType::Action) {
2753 if (m_selection_index > 0) {
2754 m_selection_index--;
2757 m_selection_index = m_delegate_sp->GetNumberOfFields() - 1;
2758 m_selection_type = SelectionType::Field;
2759 SkipPreviousHiddenFields();
2760 if (m_selection_type == SelectionType::Field) {
2761 FieldDelegate *previous_field =
2762 m_delegate_sp->GetField(m_selection_index);
2763 previous_field->FieldDelegateSelectLastElement();
2768 FieldDelegate *field = m_delegate_sp->GetField(m_selection_index);
2769 if (!field->FieldDelegateOnFirstOrOnlyElement()) {
2770 return field->FieldDelegateHandleChar(key);
2773 field->FieldDelegateExitCallback();
2775 if (m_selection_index == 0) {
2776 m_selection_type = SelectionType::Action;
2777 m_selection_index = m_delegate_sp->GetNumberOfActions() - 1;
2781 m_selection_index--;
2782 SkipPreviousHiddenFields();
2784 if (m_selection_type == SelectionType::Field) {
2785 FieldDelegate *previous_field =
2786 m_delegate_sp->GetField(m_selection_index);
2787 previous_field->FieldDelegateSelectLastElement();
2793 void ExecuteAction(Window &window,
int index) {
2794 FormAction &action = m_delegate_sp->GetAction(index);
2795 action.Execute(window);
2796 if (m_delegate_sp->HasError()) {
2797 m_first_visible_line = 0;
2798 m_selection_index = 0;
2799 m_selection_type = SelectionType::Field;
2805 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override {
2810 if (m_selection_type == SelectionType::Action) {
2811 ExecuteAction(window, m_selection_index);
2816 ExecuteAction(window, 0);
2822 SelectPrevious(key);
2825 window.GetParent()->RemoveSubWindow(&window);
2833 if (m_selection_type == SelectionType::Field) {
2834 FieldDelegate *field = m_delegate_sp->GetField(m_selection_index);
2835 if (field->FieldDelegateHandleChar(key) == eKeyHandled)
2846 SelectPrevious(key);
2856 FormDelegateSP m_delegate_sp;
2858 int m_selection_index = 0;
2860 SelectionType m_selection_type;
2862 int m_first_visible_line = 0;
2869class DetachOrKillProcessFormDelegate :
public FormDelegate {
2871 DetachOrKillProcessFormDelegate(
Process *process) : m_process(process) {
2872 SetError(
"There is a running process, either detach or kill it.");
2874 m_keep_stopped_field =
2875 AddBooleanField(
"Keep process stopped when detaching.",
false);
2877 AddAction(
"Detach", [
this](Window &window) { Detach(window); });
2878 AddAction(
"Kill", [
this](Window &window) { Kill(window); });
2881 std::string
GetName()
override {
return "Detach/Kill Process"; }
2883 void Kill(Window &window) {
2884 Status destroy_status(m_process->Destroy(
false));
2885 if (destroy_status.Fail()) {
2886 SetError(
"Failed to kill process.");
2889 window.GetParent()->RemoveSubWindow(&window);
2892 void Detach(Window &window) {
2893 Status detach_status(m_process->Detach(m_keep_stopped_field->GetBoolean()));
2894 if (detach_status.Fail()) {
2895 SetError(
"Failed to detach from process.");
2898 window.GetParent()->RemoveSubWindow(&window);
2903 BooleanFieldDelegate *m_keep_stopped_field;
2906class ProcessAttachFormDelegate :
public FormDelegate {
2908 ProcessAttachFormDelegate(
Debugger &debugger, WindowSP main_window_sp)
2909 : m_debugger(debugger), m_main_window_sp(main_window_sp) {
2910 std::vector<std::string> types;
2911 types.push_back(std::string(
"Name"));
2912 types.push_back(std::string(
"PID"));
2913 m_type_field = AddChoicesField(
"Attach By", 2, types);
2914 m_pid_field = AddIntegerField(
"PID", 0,
true);
2916 AddTextField(
"Process Name", GetDefaultProcessName().c_str(),
true);
2917 m_continue_field = AddBooleanField(
"Continue once attached.",
false);
2918 m_wait_for_field = AddBooleanField(
"Wait for process to launch.",
false);
2919 m_include_existing_field =
2920 AddBooleanField(
"Include existing processes.",
false);
2921 m_show_advanced_field = AddBooleanField(
"Show advanced settings.",
false);
2922 m_plugin_field = AddProcessPluginField();
2924 AddAction(
"Attach", [
this](Window &window) { Attach(window); });
2927 std::string
GetName()
override {
return "Attach Process"; }
2929 void UpdateFieldsVisibility()
override {
2930 if (m_type_field->GetChoiceContent() ==
"Name") {
2931 m_pid_field->FieldDelegateHide();
2932 m_name_field->FieldDelegateShow();
2933 m_wait_for_field->FieldDelegateShow();
2934 if (m_wait_for_field->GetBoolean())
2935 m_include_existing_field->FieldDelegateShow();
2937 m_include_existing_field->FieldDelegateHide();
2939 m_pid_field->FieldDelegateShow();
2940 m_name_field->FieldDelegateHide();
2941 m_wait_for_field->FieldDelegateHide();
2942 m_include_existing_field->FieldDelegateHide();
2944 if (m_show_advanced_field->GetBoolean())
2945 m_plugin_field->FieldDelegateShow();
2947 m_plugin_field->FieldDelegateHide();
2952 std::string GetDefaultProcessName() {
2953 Target *target = m_debugger.GetSelectedTarget().get();
2954 if (target ==
nullptr)
2958 if (!module_sp->IsExecutable())
2961 return module_sp->GetFileSpec().GetFilename().AsCString();
2964 bool StopRunningProcess() {
2966 m_debugger.GetCommandInterpreter().GetExecutionContext();
2972 if (!(process && process->
IsAlive()))
2975 FormDelegateSP form_delegate_sp =
2976 FormDelegateSP(
new DetachOrKillProcessFormDelegate(process));
2977 Rect bounds = m_main_window_sp->GetCenteredRect(85, 8);
2978 WindowSP form_window_sp = m_main_window_sp->CreateSubWindow(
2979 form_delegate_sp->GetName().c_str(), bounds,
true);
2980 WindowDelegateSP window_delegate_sp =
2981 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
2982 form_window_sp->SetDelegate(window_delegate_sp);
2988 Target *target = m_debugger.GetSelectedTarget().get();
2990 if (target !=
nullptr)
2994 m_debugger.GetTargetList().CreateTarget(
2997 target = new_target_sp.get();
2999 if (target ==
nullptr)
3000 SetError(
"Failed to create target.");
3002 m_debugger.GetTargetList().SetSelectedTarget(new_target_sp);
3010 if (m_type_field->GetChoiceContent() ==
"Name") {
3012 FileSpec::Style::native);
3014 if (m_wait_for_field->GetBoolean())
3024 void Attach(Window &window) {
3027 bool all_fields_are_valid = CheckFieldsValidity();
3028 if (!all_fields_are_valid)
3031 bool process_is_running = StopRunningProcess();
3032 if (process_is_running)
3035 Target *target = GetTarget();
3043 if (status.
Fail()) {
3050 SetError(
"Attached sucessfully but target has no process.");
3055 process_sp->Resume();
3057 window.GetParent()->RemoveSubWindow(&window);
3062 WindowSP m_main_window_sp;
3064 ChoicesFieldDelegate *m_type_field;
3065 IntegerFieldDelegate *m_pid_field;
3066 TextFieldDelegate *m_name_field;
3067 BooleanFieldDelegate *m_continue_field;
3068 BooleanFieldDelegate *m_wait_for_field;
3069 BooleanFieldDelegate *m_include_existing_field;
3070 BooleanFieldDelegate *m_show_advanced_field;
3071 ProcessPluginFieldDelegate *m_plugin_field;
3074class TargetCreateFormDelegate :
public FormDelegate {
3076 TargetCreateFormDelegate(
Debugger &debugger) : m_debugger(debugger) {
3077 m_executable_field = AddFileField(
"Executable",
"",
true,
3079 m_core_file_field = AddFileField(
"Core File",
"",
true,
3081 m_symbol_file_field = AddFileField(
3082 "Symbol File",
"",
true,
false);
3083 m_show_advanced_field = AddBooleanField(
"Show advanced settings.",
false);
3084 m_remote_file_field = AddFileField(
3085 "Remote File",
"",
false,
false);
3086 m_arch_field = AddArchField(
"Architecture",
"",
false);
3087 m_platform_field = AddPlatformPluginField(debugger);
3088 m_load_dependent_files_field =
3089 AddChoicesField(
"Load Dependents", 3, GetLoadDependentFilesChoices());
3091 AddAction(
"Create", [
this](Window &window) { CreateTarget(window); });
3094 std::string
GetName()
override {
return "Create Target"; }
3096 void UpdateFieldsVisibility()
override {
3097 if (m_show_advanced_field->GetBoolean()) {
3098 m_remote_file_field->FieldDelegateShow();
3099 m_arch_field->FieldDelegateShow();
3100 m_platform_field->FieldDelegateShow();
3101 m_load_dependent_files_field->FieldDelegateShow();
3103 m_remote_file_field->FieldDelegateHide();
3104 m_arch_field->FieldDelegateHide();
3105 m_platform_field->FieldDelegateHide();
3106 m_load_dependent_files_field->FieldDelegateHide();
3110 static constexpr const char *kLoadDependentFilesNo =
"No";
3111 static constexpr const char *kLoadDependentFilesYes =
"Yes";
3112 static constexpr const char *kLoadDependentFilesExecOnly =
"Executable only";
3114 std::vector<std::string> GetLoadDependentFilesChoices() {
3115 std::vector<std::string> load_dependents_options;
3116 load_dependents_options.push_back(kLoadDependentFilesExecOnly);
3117 load_dependents_options.push_back(kLoadDependentFilesYes);
3118 load_dependents_options.push_back(kLoadDependentFilesNo);
3119 return load_dependents_options;
3123 std::string choice = m_load_dependent_files_field->GetChoiceContent();
3124 if (choice == kLoadDependentFilesNo)
3126 if (choice == kLoadDependentFilesYes)
3133 platform_options.SetPlatformName(m_platform_field->GetPluginName().c_str());
3134 return platform_options;
3140 Status status = m_debugger.GetTargetList().CreateTarget(
3141 m_debugger, m_executable_field->GetPath(),
3142 m_arch_field->GetArchString(), GetLoadDependentFiles(),
3143 &platform_options, target_sp);
3145 if (status.
Fail()) {
3150 m_debugger.GetTargetList().SetSelectedTarget(target_sp);
3155 void SetSymbolFile(
TargetSP target_sp) {
3156 if (!m_symbol_file_field->IsSpecified())
3159 ModuleSP module_sp(target_sp->GetExecutableModule());
3163 module_sp->SetSymbolFileFileSpec(
3164 m_symbol_file_field->GetResolvedFileSpec());
3167 void SetCoreFile(
TargetSP target_sp) {
3168 if (!m_core_file_field->IsSpecified())
3171 FileSpec core_file_spec = m_core_file_field->GetResolvedFileSpec();
3175 target_sp->AppendExecutableSearchPaths(core_file_directory_spec);
3177 ProcessSP process_sp(target_sp->CreateProcess(
3178 m_debugger.GetListener(), llvm::StringRef(), &core_file_spec,
false));
3181 SetError(
"Unknown core file format!");
3185 Status status = process_sp->LoadCore();
3186 if (status.
Fail()) {
3187 SetError(
"Unknown core file format!");
3192 void SetRemoteFile(
TargetSP target_sp) {
3193 if (!m_remote_file_field->IsSpecified())
3196 ModuleSP module_sp(target_sp->GetExecutableModule());
3200 FileSpec remote_file_spec = m_remote_file_field->GetFileSpec();
3201 module_sp->SetPlatformFileSpec(remote_file_spec);
3204 void RemoveTarget(
TargetSP target_sp) {
3205 m_debugger.GetTargetList().DeleteTarget(target_sp);
3208 void CreateTarget(Window &window) {
3211 bool all_fields_are_valid = CheckFieldsValidity();
3212 if (!all_fields_are_valid)
3219 SetSymbolFile(target_sp);
3221 RemoveTarget(target_sp);
3225 SetCoreFile(target_sp);
3227 RemoveTarget(target_sp);
3231 SetRemoteFile(target_sp);
3233 RemoveTarget(target_sp);
3237 window.GetParent()->RemoveSubWindow(&window);
3243 FileFieldDelegate *m_executable_field;
3244 FileFieldDelegate *m_core_file_field;
3245 FileFieldDelegate *m_symbol_file_field;
3246 BooleanFieldDelegate *m_show_advanced_field;
3247 FileFieldDelegate *m_remote_file_field;
3248 ArchFieldDelegate *m_arch_field;
3249 PlatformPluginFieldDelegate *m_platform_field;
3250 ChoicesFieldDelegate *m_load_dependent_files_field;
3253class ProcessLaunchFormDelegate :
public FormDelegate {
3255 ProcessLaunchFormDelegate(
Debugger &debugger, WindowSP main_window_sp)
3256 : m_debugger(debugger), m_main_window_sp(main_window_sp) {
3258 m_arguments_field = AddArgumentsField();
3259 SetArgumentsFieldDefaultValue();
3260 m_target_environment_field =
3261 AddEnvironmentVariableListField(
"Target Environment Variables");
3262 SetTargetEnvironmentFieldDefaultValue();
3263 m_working_directory_field = AddDirectoryField(
3264 "Working Directory", GetDefaultWorkingDirectory().c_str(),
true,
false);
3266 m_show_advanced_field = AddBooleanField(
"Show advanced settings.",
false);
3268 m_stop_at_entry_field = AddBooleanField(
"Stop at entry point.",
false);
3269 m_detach_on_error_field =
3270 AddBooleanField(
"Detach on error.", GetDefaultDetachOnError());
3271 m_disable_aslr_field =
3272 AddBooleanField(
"Disable ASLR", GetDefaultDisableASLR());
3273 m_plugin_field = AddProcessPluginField();
3274 m_arch_field = AddArchField(
"Architecture",
"",
false);
3275 m_shell_field = AddFileField(
"Shell",
"",
true,
false);
3276 m_expand_shell_arguments_field =
3277 AddBooleanField(
"Expand shell arguments.",
false);
3279 m_disable_standard_io_field =
3280 AddBooleanField(
"Disable Standard IO", GetDefaultDisableStandardIO());
3281 m_standard_output_field =
3282 AddFileField(
"Standard Output File",
"",
false,
3284 m_standard_error_field =
3285 AddFileField(
"Standard Error File",
"",
false,
3287 m_standard_input_field =
3288 AddFileField(
"Standard Input File",
"",
false,
3291 m_show_inherited_environment_field =
3292 AddBooleanField(
"Show inherited environment variables.",
false);
3293 m_inherited_environment_field =
3294 AddEnvironmentVariableListField(
"Inherited Environment Variables");
3295 SetInheritedEnvironmentFieldDefaultValue();
3297 AddAction(
"Launch", [
this](Window &window) { Launch(window); });
3300 std::string
GetName()
override {
return "Launch Process"; }
3302 void UpdateFieldsVisibility()
override {
3303 if (m_show_advanced_field->GetBoolean()) {
3304 m_stop_at_entry_field->FieldDelegateShow();
3305 m_detach_on_error_field->FieldDelegateShow();
3306 m_disable_aslr_field->FieldDelegateShow();
3307 m_plugin_field->FieldDelegateShow();
3308 m_arch_field->FieldDelegateShow();
3309 m_shell_field->FieldDelegateShow();
3310 m_expand_shell_arguments_field->FieldDelegateShow();
3311 m_disable_standard_io_field->FieldDelegateShow();
3312 if (m_disable_standard_io_field->GetBoolean()) {
3313 m_standard_input_field->FieldDelegateHide();
3314 m_standard_output_field->FieldDelegateHide();
3315 m_standard_error_field->FieldDelegateHide();
3317 m_standard_input_field->FieldDelegateShow();
3318 m_standard_output_field->FieldDelegateShow();
3319 m_standard_error_field->FieldDelegateShow();
3321 m_show_inherited_environment_field->FieldDelegateShow();
3322 if (m_show_inherited_environment_field->GetBoolean())
3323 m_inherited_environment_field->FieldDelegateShow();
3325 m_inherited_environment_field->FieldDelegateHide();
3327 m_stop_at_entry_field->FieldDelegateHide();
3328 m_detach_on_error_field->FieldDelegateHide();
3329 m_disable_aslr_field->FieldDelegateHide();
3330 m_plugin_field->FieldDelegateHide();
3331 m_arch_field->FieldDelegateHide();
3332 m_shell_field->FieldDelegateHide();
3333 m_expand_shell_arguments_field->FieldDelegateHide();
3334 m_disable_standard_io_field->FieldDelegateHide();
3335 m_standard_input_field->FieldDelegateHide();
3336 m_standard_output_field->FieldDelegateHide();
3337 m_standard_error_field->FieldDelegateHide();
3338 m_show_inherited_environment_field->FieldDelegateHide();
3339 m_inherited_environment_field->FieldDelegateHide();
3345 void SetArgumentsFieldDefaultValue() {
3346 TargetSP target = m_debugger.GetSelectedTarget();
3347 if (target ==
nullptr)
3350 const Args &target_arguments =
3351 target->GetProcessLaunchInfo().GetArguments();
3352 m_arguments_field->AddArguments(target_arguments);
3355 void SetTargetEnvironmentFieldDefaultValue() {
3356 TargetSP target = m_debugger.GetSelectedTarget();
3357 if (target ==
nullptr)
3360 const Environment &target_environment = target->GetTargetEnvironment();
3361 m_target_environment_field->AddEnvironmentVariables(target_environment);
3364 void SetInheritedEnvironmentFieldDefaultValue() {
3365 TargetSP target = m_debugger.GetSelectedTarget();
3366 if (target ==
nullptr)
3370 target->GetInheritedEnvironment();
3371 m_inherited_environment_field->AddEnvironmentVariables(
3372 inherited_environment);
3375 std::string GetDefaultWorkingDirectory() {
3376 TargetSP target = m_debugger.GetSelectedTarget();
3377 if (target ==
nullptr)
3381 return platform->GetWorkingDirectory().GetPath();
3384 bool GetDefaultDisableASLR() {
3385 TargetSP target = m_debugger.GetSelectedTarget();
3386 if (target ==
nullptr)
3389 return target->GetDisableASLR();
3392 bool GetDefaultDisableStandardIO() {
3393 TargetSP target = m_debugger.GetSelectedTarget();
3394 if (target ==
nullptr)
3397 return target->GetDisableSTDIO();
3400 bool GetDefaultDetachOnError() {
3401 TargetSP target = m_debugger.GetSelectedTarget();
3402 if (target ==
nullptr)
3405 return target->GetDetachOnError();
3412 TargetSP target = m_debugger.GetSelectedTarget();
3413 ModuleSP executable_module = target->GetExecutableModule();
3414 llvm::StringRef target_settings_argv0 = target->GetArg0();
3416 if (!target_settings_argv0.empty()) {
3428 TargetSP target = m_debugger.GetSelectedTarget();
3429 Args arguments = m_arguments_field->GetArguments();
3435 m_target_environment_field->GetEnvironment();
3437 m_inherited_environment_field->GetEnvironment();
3439 target_environment.end());
3441 inherited_environment.end());
3445 if (m_working_directory_field->IsSpecified())
3447 m_working_directory_field->GetResolvedFileSpec());
3451 if (m_stop_at_entry_field->GetBoolean())
3452 launch_info.
GetFlags().
Set(eLaunchFlagStopAtEntry);
3458 if (m_detach_on_error_field->GetBoolean())
3459 launch_info.
GetFlags().
Set(eLaunchFlagDetachOnError);
3465 if (m_disable_aslr_field->GetBoolean())
3466 launch_info.
GetFlags().
Set(eLaunchFlagDisableASLR);
3476 if (!m_arch_field->IsSpecified())
3479 TargetSP target_sp = m_debugger.GetSelectedTarget();
3481 target_sp ? target_sp->GetPlatform() :
PlatformSP();
3483 platform_sp.get(), m_arch_field->GetArchString());
3487 if (!m_shell_field->IsSpecified())
3490 launch_info.
SetShell(m_shell_field->GetResolvedFileSpec());
3492 m_expand_shell_arguments_field->GetBoolean());
3496 if (m_disable_standard_io_field->GetBoolean()) {
3497 launch_info.
GetFlags().
Set(eLaunchFlagDisableSTDIO);
3502 if (m_standard_input_field->IsSpecified()) {
3503 if (action.
Open(STDIN_FILENO, m_standard_input_field->GetFileSpec(),
true,
3507 if (m_standard_output_field->IsSpecified()) {
3508 if (action.
Open(STDOUT_FILENO, m_standard_output_field->GetFileSpec(),
3512 if (m_standard_error_field->IsSpecified()) {
3513 if (action.
Open(STDERR_FILENO, m_standard_error_field->GetFileSpec(),
3520 if (m_debugger.GetSelectedTarget()->GetInheritTCC())
3521 launch_info.
GetFlags().
Set(eLaunchFlagInheritTCCFromParent);
3527 GetExecutableSettings(launch_info);
3528 GetArguments(launch_info);
3529 GetEnvironment(launch_info);
3530 GetWorkingDirectory(launch_info);
3531 GetStopAtEntry(launch_info);
3532 GetDetachOnError(launch_info);
3533 GetDisableASLR(launch_info);
3534 GetPlugin(launch_info);
3535 GetArch(launch_info);
3536 GetShell(launch_info);
3537 GetStandardIO(launch_info);
3538 GetInheritTCC(launch_info);
3543 bool StopRunningProcess() {
3545 m_debugger.GetCommandInterpreter().GetExecutionContext();
3551 if (!(process && process->
IsAlive()))
3554 FormDelegateSP form_delegate_sp =
3555 FormDelegateSP(
new DetachOrKillProcessFormDelegate(process));
3556 Rect bounds = m_main_window_sp->GetCenteredRect(85, 8);
3557 WindowSP form_window_sp = m_main_window_sp->CreateSubWindow(
3558 form_delegate_sp->GetName().c_str(), bounds,
true);
3559 WindowDelegateSP window_delegate_sp =
3560 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
3561 form_window_sp->SetDelegate(window_delegate_sp);
3567 Target *target = m_debugger.GetSelectedTarget().get();
3569 if (target ==
nullptr) {
3570 SetError(
"No target exists!");
3576 if (exe_module_sp ==
nullptr) {
3577 SetError(
"No executable in target!");
3584 void Launch(Window &window) {
3587 bool all_fields_are_valid = CheckFieldsValidity();
3588 if (!all_fields_are_valid)
3591 bool process_is_running = StopRunningProcess();
3592 if (process_is_running)
3595 Target *target = GetTarget();
3603 if (status.
Fail()) {
3610 SetError(
"Launched successfully but target has no process!");
3614 window.GetParent()->RemoveSubWindow(&window);
3619 WindowSP m_main_window_sp;
3621 ArgumentsFieldDelegate *m_arguments_field;
3622 EnvironmentVariableListFieldDelegate *m_target_environment_field;
3623 DirectoryFieldDelegate *m_working_directory_field;
3625 BooleanFieldDelegate *m_show_advanced_field;
3627 BooleanFieldDelegate *m_stop_at_entry_field;
3628 BooleanFieldDelegate *m_detach_on_error_field;
3629 BooleanFieldDelegate *m_disable_aslr_field;
3630 ProcessPluginFieldDelegate *m_plugin_field;
3631 ArchFieldDelegate *m_arch_field;
3632 FileFieldDelegate *m_shell_field;
3633 BooleanFieldDelegate *m_expand_shell_arguments_field;
3634 BooleanFieldDelegate *m_disable_standard_io_field;
3635 FileFieldDelegate *m_standard_input_field;
3636 FileFieldDelegate *m_standard_output_field;
3637 FileFieldDelegate *m_standard_error_field;
3639 BooleanFieldDelegate *m_show_inherited_environment_field;
3640 EnvironmentVariableListFieldDelegate *m_inherited_environment_field;
3647class SearcherDelegate {
3649 SearcherDelegate() =
default;
3651 virtual ~SearcherDelegate() =
default;
3653 virtual int GetNumberOfMatches() = 0;
3656 virtual const std::string &GetMatchTextAtIndex(
int index) = 0;
3660 virtual void UpdateMatches(
const std::string &text) = 0;
3664 virtual void ExecuteCallback(
int match_index) = 0;
3667typedef std::shared_ptr<SearcherDelegate> SearcherDelegateSP;
3669class SearcherWindowDelegate :
public WindowDelegate {
3671 SearcherWindowDelegate(SearcherDelegateSP &delegate_sp)
3672 : m_delegate_sp(delegate_sp), m_text_field(
"Search",
"", false) {
3694 int GetLastVisibleMatch(
int height) {
3695 int index = m_first_visible_match + height;
3696 return std::min(index, m_delegate_sp->GetNumberOfMatches()) - 1;
3699 int GetNumberOfVisibleMatches(
int height) {
3700 return GetLastVisibleMatch(height) - m_first_visible_match + 1;
3703 void UpdateScrolling(Surface &surface) {
3704 if (m_selected_match < m_first_visible_match) {
3705 m_first_visible_match = m_selected_match;
3709 int height = surface.GetHeight();
3710 int last_visible_match = GetLastVisibleMatch(height);
3711 if (m_selected_match > last_visible_match) {
3712 m_first_visible_match = m_selected_match - height + 1;
3716 void DrawMatches(Surface &surface) {
3717 if (m_delegate_sp->GetNumberOfMatches() == 0)
3720 UpdateScrolling(surface);
3722 int count = GetNumberOfVisibleMatches(surface.GetHeight());
3723 for (
int i = 0; i < count; i++) {
3724 surface.MoveCursor(1, i);
3725 int current_match = m_first_visible_match + i;
3726 if (current_match == m_selected_match)
3727 surface.AttributeOn(A_REVERSE);
3729 m_delegate_sp->GetMatchTextAtIndex(current_match).c_str());
3730 if (current_match == m_selected_match)
3731 surface.AttributeOff(A_REVERSE);
3735 void DrawContent(Surface &surface) {
3736 Rect content_bounds = surface.GetFrame();
3737 Rect text_field_bounds, matchs_bounds;
3738 content_bounds.HorizontalSplit(m_text_field.FieldDelegateGetHeight(),
3739 text_field_bounds, matchs_bounds);
3740 Surface text_field_surface = surface.SubSurface(text_field_bounds);
3741 Surface matches_surface = surface.SubSurface(matchs_bounds);
3743 m_text_field.FieldDelegateDraw(text_field_surface,
true);
3744 DrawMatches(matches_surface);
3747 bool WindowDelegateDraw(Window &window,
bool force)
override {
3750 window.DrawTitleBox(window.GetName(),
"Press Esc to Cancel");
3752 Rect content_bounds = window.GetFrame();
3753 content_bounds.Inset(2, 2);
3754 Surface content_surface = window.SubSurface(content_bounds);
3756 DrawContent(content_surface);
3761 if (m_selected_match != m_delegate_sp->GetNumberOfMatches() - 1)
3765 void SelectPrevious() {
3766 if (m_selected_match != 0)
3770 void ExecuteCallback(Window &window) {
3771 m_delegate_sp->ExecuteCallback(m_selected_match);
3772 window.GetParent()->RemoveSubWindow(&window);
3775 void UpdateMatches() {
3776 m_delegate_sp->UpdateMatches(m_text_field.GetText());
3777 m_selected_match = 0;
3780 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override {
3785 ExecuteCallback(window);
3796 window.GetParent()->RemoveSubWindow(&window);
3802 if (m_text_field.FieldDelegateHandleChar(key) == eKeyHandled)
3809 SearcherDelegateSP m_delegate_sp;
3810 TextFieldDelegate m_text_field;
3812 int m_selected_match = 0;
3814 int m_first_visible_match = 0;
3824class CommonCompletionSearcherDelegate :
public SearcherDelegate {
3826 typedef std::function<void(
const std::string &)> CallbackType;
3828 CommonCompletionSearcherDelegate(
Debugger &debugger, uint32_t completion_mask,
3829 CallbackType callback)
3830 : m_debugger(debugger), m_completion_mask(completion_mask),
3831 m_callback(callback) {}
3833 int GetNumberOfMatches()
override {
return m_matches.GetSize(); }
3835 const std::string &GetMatchTextAtIndex(
int index)
override {
3836 return m_matches[index];
3839 void UpdateMatches(
const std::string &text)
override {
3843 m_debugger.GetCommandInterpreter(), m_completion_mask, request,
3848 void ExecuteCallback(
int match_index)
override {
3849 m_callback(m_matches[match_index]);
3855 uint32_t m_completion_mask;
3858 CallbackType m_callback;
3868 virtual ~MenuDelegate() =
default;
3870 virtual MenuActionResult MenuDelegateAction(Menu &menu) = 0;
3873class Menu :
public WindowDelegate {
3875 enum class Type {
Invalid, Bar, Item, Separator };
3881 Menu(
const char *name,
const char *key_name,
int key_value,
3882 uint64_t identifier);
3884 ~Menu()
override =
default;
3886 const MenuDelegateSP &GetDelegate()
const {
return m_delegate_sp; }
3888 void SetDelegate(
const MenuDelegateSP &delegate_sp) {
3889 m_delegate_sp = delegate_sp;
3892 void RecalculateNameLengths();
3894 void AddSubmenu(
const MenuSP &menu_sp);
3896 int DrawAndRunMenu(Window &window);
3898 void DrawMenuTitle(Window &window,
bool highlight);
3900 bool WindowDelegateDraw(Window &window,
bool force)
override;
3902 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override;
3904 MenuActionResult ActionPrivate(Menu &menu) {
3905 MenuActionResult result = MenuActionResult::NotHandled;
3906 if (m_delegate_sp) {
3907 result = m_delegate_sp->MenuDelegateAction(menu);
3908 if (result != MenuActionResult::NotHandled)
3910 }
else if (m_parent) {
3911 result = m_parent->ActionPrivate(menu);
3912 if (result != MenuActionResult::NotHandled)
3915 return m_canned_result;
3918 MenuActionResult Action() {
3921 return ActionPrivate(*
this);
3924 void SetCannedResult(MenuActionResult result) { m_canned_result = result; }
3926 Menus &GetSubmenus() {
return m_submenus; }
3928 const Menus &GetSubmenus()
const {
return m_submenus; }
3930 int GetSelectedSubmenuIndex()
const {
return m_selected; }
3932 void SetSelectedSubmenuIndex(
int idx) { m_selected = idx; }
3934 Type GetType()
const {
return m_type; }
3936 int GetStartingColumn()
const {
return m_start_col; }
3938 void SetStartingColumn(
int col) { m_start_col = col; }
3940 int GetKeyValue()
const {
return m_key_value; }
3942 std::string &
GetName() {
return m_name; }
3944 int GetDrawWidth()
const {
3945 return m_max_submenu_name_length + m_max_submenu_key_name_length + 8;
3948 uint64_t GetIdentifier()
const {
return m_identifier; }
3950 void SetIdentifier(uint64_t identifier) { m_identifier = identifier; }
3954 std::string m_key_name;
3955 uint64_t m_identifier;
3959 int m_max_submenu_name_length;
3960 int m_max_submenu_key_name_length;
3964 WindowSP m_menu_window_sp;
3965 MenuActionResult m_canned_result;
3966 MenuDelegateSP m_delegate_sp;
3970Menu::Menu(
Type type)
3971 : m_name(), m_key_name(), m_identifier(0), m_type(type), m_key_value(0),
3972 m_start_col(0), m_max_submenu_name_length(0),
3973 m_max_submenu_key_name_length(0), m_selected(0), m_parent(nullptr),
3974 m_submenus(), m_canned_result(MenuActionResult::NotHandled),
3978Menu::Menu(
const char *name,
const char *key_name,
int key_value,
3979 uint64_t identifier)
3980 : m_name(), m_key_name(), m_identifier(identifier), m_type(
Type::
Invalid),
3981 m_key_value(key_value), m_start_col(0), m_max_submenu_name_length(0),
3982 m_max_submenu_key_name_length(0), m_selected(0), m_parent(nullptr),
3983 m_submenus(), m_canned_result(MenuActionResult::NotHandled),
3985 if (name && name[0]) {
3987 m_type = Type::Item;
3988 if (key_name && key_name[0])
3989 m_key_name = key_name;
3991 m_type = Type::Separator;
3995void Menu::RecalculateNameLengths() {
3996 m_max_submenu_name_length = 0;
3997 m_max_submenu_key_name_length = 0;
3998 Menus &submenus = GetSubmenus();
3999 const size_t num_submenus = submenus.size();
4000 for (
size_t i = 0; i < num_submenus; ++i) {
4001 Menu *submenu = submenus[i].get();
4002 if (
static_cast<size_t>(m_max_submenu_name_length) < submenu->m_name.size())
4003 m_max_submenu_name_length = submenu->m_name.size();
4004 if (
static_cast<size_t>(m_max_submenu_key_name_length) <
4005 submenu->m_key_name.size())
4006 m_max_submenu_key_name_length = submenu->m_key_name.size();
4010void Menu::AddSubmenu(
const MenuSP &menu_sp) {
4011 menu_sp->m_parent =
this;
4012 if (
static_cast<size_t>(m_max_submenu_name_length) < menu_sp->m_name.size())
4013 m_max_submenu_name_length = menu_sp->m_name.size();
4014 if (
static_cast<size_t>(m_max_submenu_key_name_length) <
4015 menu_sp->m_key_name.size())
4016 m_max_submenu_key_name_length = menu_sp->m_key_name.size();
4017 m_submenus.push_back(menu_sp);
4020void Menu::DrawMenuTitle(Window &window,
bool highlight) {
4021 if (m_type == Type::Separator) {
4022 window.MoveCursor(0, window.GetCursorY());
4023 window.PutChar(ACS_LTEE);
4024 int width = window.GetWidth();
4027 for (
int i = 0; i < width; ++i)
4028 window.PutChar(ACS_HLINE);
4030 window.PutChar(ACS_RTEE);
4032 const int shortcut_key = m_key_value;
4033 bool underlined_shortcut =
false;
4034 const attr_t highlight_attr = A_REVERSE;
4036 window.AttributeOn(highlight_attr);
4037 if (llvm::isPrint(shortcut_key)) {
4038 size_t lower_pos = m_name.find(tolower(shortcut_key));
4039 size_t upper_pos = m_name.find(toupper(shortcut_key));
4040 const char *name = m_name.c_str();
4041 size_t pos = std::min<size_t>(lower_pos, upper_pos);
4042 if (pos != std::string::npos) {
4043 underlined_shortcut =
true;
4045 window.PutCString(name, pos);
4048 const attr_t shortcut_attr = A_UNDERLINE | A_BOLD;
4049 window.AttributeOn(shortcut_attr);
4050 window.PutChar(name[0]);
4051 window.AttributeOff(shortcut_attr);
4054 window.PutCString(name);
4058 if (!underlined_shortcut) {
4059 window.PutCString(m_name.c_str());
4063 window.AttributeOff(highlight_attr);
4065 if (m_key_name.empty()) {
4066 if (!underlined_shortcut && llvm::isPrint(m_key_value)) {
4067 window.AttributeOn(COLOR_PAIR(MagentaOnWhite));
4068 window.Printf(
" (%c)", m_key_value);
4069 window.AttributeOff(COLOR_PAIR(MagentaOnWhite));
4072 window.AttributeOn(COLOR_PAIR(MagentaOnWhite));
4073 window.Printf(
" (%s)", m_key_name.c_str());
4074 window.AttributeOff(COLOR_PAIR(MagentaOnWhite));
4079bool Menu::WindowDelegateDraw(Window &window,
bool force) {
4080 Menus &submenus = GetSubmenus();
4081 const size_t num_submenus = submenus.size();
4082 const int selected_idx = GetSelectedSubmenuIndex();
4083 Menu::Type menu_type = GetType();
4084 switch (menu_type) {
4085 case Menu::Type::Bar: {
4086 window.SetBackground(BlackOnWhite);
4087 window.MoveCursor(0, 0);
4088 for (
size_t i = 0; i < num_submenus; ++i) {
4089 Menu *menu = submenus[i].get();
4091 window.PutChar(
' ');
4092 menu->SetStartingColumn(window.GetCursorX());
4093 window.PutCString(
"| ");
4094 menu->DrawMenuTitle(window,
false);
4096 window.PutCString(
" |");
4099 case Menu::Type::Item: {
4106 window.SetBackground(BlackOnWhite);
4108 for (
size_t i = 0; i < num_submenus; ++i) {
4109 const bool is_selected = (i ==
static_cast<size_t>(selected_idx));
4110 window.MoveCursor(x, y + i);
4116 submenus[i]->DrawMenuTitle(window, is_selected);
4118 window.MoveCursor(cursor_x, cursor_y);
4122 case Menu::Type::Separator:
4128HandleCharResult Menu::WindowDelegateHandleChar(Window &window,
int key) {
4129 HandleCharResult result = eKeyNotHandled;
4131 Menus &submenus = GetSubmenus();
4132 const size_t num_submenus = submenus.size();
4133 const int selected_idx = GetSelectedSubmenuIndex();
4134 Menu::Type menu_type = GetType();
4135 if (menu_type == Menu::Type::Bar) {
4141 if (selected_idx <
static_cast<int>(num_submenus))
4142 run_menu_sp = submenus[selected_idx];
4143 else if (!submenus.empty())
4144 run_menu_sp = submenus.front();
4145 result = eKeyHandled;
4150 if (m_selected >=
static_cast<int>(num_submenus))
4152 if (m_selected <
static_cast<int>(num_submenus))
4153 run_menu_sp = submenus[m_selected];
4154 else if (!submenus.empty())
4155 run_menu_sp = submenus.front();
4156 result = eKeyHandled;
4162 m_selected = num_submenus - 1;
4163 if (m_selected <
static_cast<int>(num_submenus))
4164 run_menu_sp = submenus[m_selected];
4165 else if (!submenus.empty())
4166 run_menu_sp = submenus.front();
4167 result = eKeyHandled;
4171 for (
size_t i = 0; i < num_submenus; ++i) {
4172 if (submenus[i]->GetKeyValue() == key) {
4173 SetSelectedSubmenuIndex(i);
4174 run_menu_sp = submenus[i];
4175 result = eKeyHandled;
4186 if (run_menu_sp->Action() == MenuActionResult::Quit)
4187 return eQuitApplication;
4190 menu_bounds.origin.x = run_menu_sp->GetStartingColumn();
4191 menu_bounds.origin.y = 1;
4192 menu_bounds.size.width = run_menu_sp->GetDrawWidth();
4193 menu_bounds.size.height = run_menu_sp->GetSubmenus().size() + 2;
4194 if (m_menu_window_sp)
4195 window.GetParent()->RemoveSubWindow(m_menu_window_sp.get());
4197 m_menu_window_sp = window.GetParent()->CreateSubWindow(
4198 run_menu_sp->GetName().c_str(), menu_bounds,
true);
4199 m_menu_window_sp->SetDelegate(run_menu_sp);
4201 }
else if (menu_type == Menu::Type::Item) {
4204 if (m_submenus.size() > 1) {
4205 const int start_select = m_selected;
4206 while (++m_selected != start_select) {
4207 if (
static_cast<size_t>(m_selected) >= num_submenus)
4209 if (m_submenus[m_selected]->GetType() == Type::Separator)
4219 if (m_submenus.size() > 1) {
4220 const int start_select = m_selected;
4221 while (--m_selected != start_select) {
4222 if (m_selected <
static_cast<int>(0))
4223 m_selected = num_submenus - 1;
4224 if (m_submenus[m_selected]->GetType() == Type::Separator)
4234 if (
static_cast<size_t>(selected_idx) < num_submenus) {
4235 if (submenus[selected_idx]->Action() == MenuActionResult::Quit)
4236 return eQuitApplication;
4237 window.GetParent()->RemoveSubWindow(&window);
4244 window.GetParent()->RemoveSubWindow(&window);
4248 for (
size_t i = 0; i < num_submenus; ++i) {
4249 Menu *menu = submenus[i].get();
4250 if (menu->GetKeyValue() == key) {
4251 SetSelectedSubmenuIndex(i);
4252 window.GetParent()->RemoveSubWindow(&window);
4253 if (menu->Action() == MenuActionResult::Quit)
4254 return eQuitApplication;
4260 }
else if (menu_type == Menu::Type::Separator) {
4267 Application(FILE *in, FILE *out) : m_window_sp(), m_in(in), m_out(out) {}
4270 m_window_delegates.clear();
4271 m_window_sp.reset();
4273 ::delscreen(m_screen);
4279 m_screen = ::newterm(
nullptr, m_out, m_in);
4283 ::keypad(stdscr, TRUE);
4286 void Terminate() { ::endwin(); }
4290 int delay_in_tenths_of_a_second = 1;
4298 halfdelay(delay_in_tenths_of_a_second);
4307 m_update_screen =
true;
4308#if defined(__APPLE__)
4309 std::deque<int> escape_chars;
4313 if (m_update_screen) {
4314 m_window_sp->Draw(
false);
4322 m_window_sp->MoveCursor(0, 0);
4325 m_update_screen =
false;
4328#if defined(__APPLE__)
4333 if (escape_chars.empty())
4334 ch = m_window_sp->GetChar();
4336 ch = escape_chars.front();
4337 escape_chars.pop_front();
4339 if (ch == KEY_ESCAPE) {
4340 int ch2 = m_window_sp->GetChar();
4342 int ch3 = m_window_sp->GetChar();
4357 escape_chars.push_back(ch2);
4359 escape_chars.push_back(ch3);
4362 }
else if (ch2 != -1)
4363 escape_chars.push_back(ch2);
4366 int ch = m_window_sp->GetChar();
4370 if (feof(m_in) || ferror(m_in)) {
4375 while (listener_sp->PeekAtNextEvent()) {
4376 listener_sp->GetEvent(event_sp, std::chrono::seconds(0));
4379 Broadcaster *broadcaster = event_sp->GetBroadcaster();
4384 if (broadcaster_class == broadcaster_class_process) {
4385 m_update_screen =
true;
4393 HandleCharResult key_result = m_window_sp->HandleChar(ch);
4394 switch (key_result) {
4396 m_update_screen =
true;
4398 case eKeyNotHandled:
4400 redrawwin(m_window_sp->get());
4401 m_update_screen =
true;
4404 case eQuitApplication:
4414 WindowSP &GetMainWindow() {
4416 m_window_sp = std::make_shared<Window>(
"main", stdscr,
false);
4420 void TerminalSizeChanged() {
4423 Rect content_bounds = m_window_sp->GetFrame();
4424 m_window_sp->SetBounds(content_bounds);
4425 if (WindowSP menubar_window_sp = m_window_sp->FindSubWindow(
"Menubar"))
4426 menubar_window_sp->SetBounds(content_bounds.MakeMenuBar());
4427 if (WindowSP status_window_sp = m_window_sp->FindSubWindow(
"Status"))
4428 status_window_sp->SetBounds(content_bounds.MakeStatusBar());
4430 WindowSP source_window_sp = m_window_sp->FindSubWindow(
"Source");
4431 WindowSP variables_window_sp = m_window_sp->FindSubWindow(
"Variables");
4432 WindowSP registers_window_sp = m_window_sp->FindSubWindow(
"Registers");
4433 WindowSP threads_window_sp = m_window_sp->FindSubWindow(
"Threads");
4435 Rect threads_bounds;
4436 Rect source_variables_bounds;
4437 content_bounds.VerticalSplitPercentage(0.80, source_variables_bounds,
4439 if (threads_window_sp)
4440 threads_window_sp->SetBounds(threads_bounds);
4442 source_variables_bounds = content_bounds;
4445 Rect variables_registers_bounds;
4446 source_variables_bounds.HorizontalSplitPercentage(
4447 0.70, source_bounds, variables_registers_bounds);
4448 if (variables_window_sp || registers_window_sp) {
4449 if (variables_window_sp && registers_window_sp) {
4450 Rect variables_bounds;
4451 Rect registers_bounds;
4452 variables_registers_bounds.VerticalSplitPercentage(
4453 0.50, variables_bounds, registers_bounds);
4454 variables_window_sp->SetBounds(variables_bounds);
4455 registers_window_sp->SetBounds(registers_bounds);
4456 }
else if (variables_window_sp) {
4457 variables_window_sp->SetBounds(variables_registers_bounds);
4459 registers_window_sp->SetBounds(variables_registers_bounds);
4462 source_bounds = source_variables_bounds;
4465 source_window_sp->SetBounds(source_bounds);
4468 redrawwin(m_window_sp->get());
4469 m_update_screen =
true;
4473 WindowSP m_window_sp;
4474 WindowDelegates m_window_delegates;
4475 SCREEN *m_screen =
nullptr;
4478 bool m_update_screen =
false;
4489 uint32_t children_stop_id = 0;
4493 bool might_have_children;
4494 bool expanded =
false;
4495 bool calculated_children =
false;
4496 std::vector<Row> children;
4499 : value(v), parent(p),
4500 might_have_children(v ? v->MightHaveChildren() : false) {}
4502 size_t GetDepth()
const {
4504 return 1 + parent->GetDepth();
4508 void Expand() { expanded =
true; }
4510 std::vector<Row> &GetChildren() {
4512 auto stop_id = process_sp->GetStopID();
4513 if (process_sp && stop_id != children_stop_id) {
4514 children_stop_id = stop_id;
4515 calculated_children =
false;
4517 if (!calculated_children) {
4519 calculated_children =
true;
4522 const uint32_t num_children = valobj->GetNumChildrenIgnoringErrors();
4523 for (
size_t i = 0; i < num_children; ++i) {
4524 children.push_back(Row(valobj->GetChildAtIndex(i),
this));
4533 calculated_children =
false;
4537 void DrawTree(Window &window) {
4539 parent->DrawTreeForChild(window,
this, 0);
4541 if (might_have_children &&
4542 (!calculated_children || !GetChildren().empty())) {
4560 window.PutChar(ACS_DIAMOND);
4561 window.PutChar(ACS_HLINE);
4565 void DrawTreeForChild(Window &window, Row *child, uint32_t reverse_depth) {
4567 parent->DrawTreeForChild(window,
this, reverse_depth + 1);
4569 if (&GetChildren().back() == child) {
4571 if (reverse_depth == 0) {
4572 window.PutChar(ACS_LLCORNER);
4573 window.PutChar(ACS_HLINE);
4575 window.PutChar(
' ');
4576 window.PutChar(
' ');
4579 if (reverse_depth == 0) {
4580 window.PutChar(ACS_LTEE);
4581 window.PutChar(ACS_HLINE);
4583 window.PutChar(ACS_VLINE);
4584 window.PutChar(
' ');
4590struct DisplayOptions {
4598 TreeDelegate() =
default;
4599 virtual ~TreeDelegate() =
default;
4601 virtual void TreeDelegateDrawTreeItem(TreeItem &item, Window &window) = 0;
4602 virtual void TreeDelegateGenerateChildren(TreeItem &item) = 0;
4603 virtual void TreeDelegateUpdateSelection(TreeItem &root,
int &selection_index,
4604 TreeItem *&selected_item) {}
4607 virtual bool TreeDelegateItemSelected(TreeItem &item) = 0;
4608 virtual bool TreeDelegateExpandRootByDefault() {
return false; }
4612 virtual bool TreeDelegateShouldDraw() {
return true; }
4615typedef std::shared_ptr<TreeDelegate> TreeDelegateSP;
4617struct TreeItemData {
4618 TreeItemData(TreeItem *parent, TreeDelegate &delegate,
4619 bool might_have_children,
bool is_expanded)
4620 : m_parent(parent), m_delegate(&delegate),
4621 m_might_have_children(might_have_children), m_is_expanded(is_expanded) {
4626 TreeDelegate *m_delegate;
4627 void *m_user_data =
nullptr;
4628 uint64_t m_identifier = 0;
4632 bool m_might_have_children;
4633 bool m_is_expanded =
false;
4636class TreeItem :
public TreeItemData {
4638 TreeItem(TreeItem *parent, TreeDelegate &delegate,
bool might_have_children)
4639 : TreeItemData(parent, delegate, might_have_children,
4641 ? delegate.TreeDelegateExpandRootByDefault()
4645 TreeItem(
const TreeItem &) =
delete;
4646 TreeItem &operator=(
const TreeItem &rhs) =
delete;
4648 TreeItem &operator=(TreeItem &&rhs) {
4650 TreeItemData::operator=(std::move(rhs));
4651 AdoptChildren(rhs.m_children);
4656 TreeItem(TreeItem &&rhs) : TreeItemData(std::move(rhs)) {
4657 AdoptChildren(rhs.m_children);
4660 size_t GetDepth()
const {
4662 return 1 + m_parent->GetDepth();
4666 int GetRowIndex()
const {
return m_row_idx; }
4668 void ClearChildren() { m_children.clear(); }
4670 void Resize(
size_t n, TreeDelegate &delegate,
bool might_have_children) {
4671 if (m_children.size() >= n) {
4672 m_children.erase(m_children.begin() + n, m_children.end());
4675 m_children.reserve(n);
4676 std::generate_n(std::back_inserter(m_children), n - m_children.size(),
4677 [&, parent =
this]() {
4678 return TreeItem(parent, delegate, might_have_children);
4682 TreeItem &operator[](
size_t i) {
return m_children[i]; }
4684 void SetRowIndex(
int row_idx) { m_row_idx = row_idx; }
4686 size_t GetNumChildren() {
4687 m_delegate->TreeDelegateGenerateChildren(*
this);
4688 return m_children.size();
4691 void ItemWasSelected() { m_delegate->TreeDelegateItemSelected(*
this); }
4693 void CalculateRowIndexes(
int &row_idx) {
4694 SetRowIndex(row_idx);
4697 const bool expanded = IsExpanded();
4701 if (m_parent ==
nullptr || expanded)
4704 for (
auto &item : m_children) {
4706 item.CalculateRowIndexes(row_idx);
4708 item.SetRowIndex(-1);
4712 TreeItem *GetParent() {
return m_parent; }
4714 bool IsExpanded()
const {
return m_is_expanded; }
4716 void Expand() { m_is_expanded =
true; }
4718 void Unexpand() { m_is_expanded =
false; }
4720 bool Draw(Window &window,
const int first_visible_row,
4721 const uint32_t selected_row_idx,
int &row_idx,
int &num_rows_left) {
4722 if (num_rows_left <= 0)
4725 if (m_row_idx >= first_visible_row) {
4726 window.MoveCursor(2, row_idx + 1);
4729 m_parent->DrawTreeForChild(window,
this, 0);
4731 if (m_might_have_children) {
4749 window.PutChar(ACS_DIAMOND);
4750 window.PutChar(ACS_HLINE);
4752 bool highlight = (selected_row_idx ==
static_cast<size_t>(m_row_idx)) &&
4756 window.AttributeOn(A_REVERSE);
4758 m_delegate->TreeDelegateDrawTreeItem(*
this, window);
4761 window.AttributeOff(A_REVERSE);
4766 if (num_rows_left <= 0)
4770 for (
auto &item : m_children) {
4773 if (!item.Draw(window, first_visible_row, selected_row_idx, row_idx,
4778 return num_rows_left >= 0;
4781 void DrawTreeForChild(Window &window, TreeItem *child,
4782 uint32_t reverse_depth) {
4784 m_parent->DrawTreeForChild(window,
this, reverse_depth + 1);
4786 if (&m_children.back() == child) {
4788 if (reverse_depth == 0) {
4789 window.PutChar(ACS_LLCORNER);
4790 window.PutChar(ACS_HLINE);
4792 window.PutChar(
' ');
4793 window.PutChar(
' ');
4796 if (reverse_depth == 0) {
4797 window.PutChar(ACS_LTEE);
4798 window.PutChar(ACS_HLINE);
4800 window.PutChar(ACS_VLINE);
4801 window.PutChar(
' ');
4806 TreeItem *GetItemForRowIndex(uint32_t row_idx) {
4807 if (
static_cast<uint32_t
>(m_row_idx) == row_idx)
4809 if (m_children.empty())
4812 for (
auto &item : m_children) {
4813 TreeItem *selected_item_ptr = item.GetItemForRowIndex(row_idx);
4814 if (selected_item_ptr)
4815 return selected_item_ptr;
4821 void *GetUserData()
const {
return m_user_data; }
4823 void SetUserData(
void *user_data) { m_user_data = user_data; }
4825 uint64_t GetIdentifier()
const {
return m_identifier; }
4827 void SetIdentifier(uint64_t identifier) { m_identifier = identifier; }
4829 const std::string &GetText()
const {
return m_text; }
4831 void SetText(
const char *text) {
4832 if (text ==
nullptr) {
4839 void SetMightHaveChildren(
bool b) { m_might_have_children = b; }
4842 void AdoptChildren(std::vector<TreeItem> &children) {
4843 m_children = std::move(children);
4844 for (
auto &child : m_children)
4845 child.m_parent =
this;
4848 std::vector<TreeItem> m_children;
4851class TreeWindowDelegate :
public WindowDelegate {
4853 TreeWindowDelegate(
Debugger &debugger,
const TreeDelegateSP &delegate_sp)
4854 : m_debugger(debugger), m_delegate_sp(delegate_sp),
4855 m_root(nullptr, *delegate_sp, true) {}
4857 int NumVisibleRows()
const {
return m_max_y - m_min_y; }
4859 bool WindowDelegateDraw(Window &window,
bool force)
override {
4862 m_max_x = window.GetWidth() - 1;
4863 m_max_y = window.GetHeight() - 1;
4866 window.DrawTitleBox(window.GetName());
4868 if (!m_delegate_sp->TreeDelegateShouldDraw()) {
4869 m_selected_item =
nullptr;
4873 const int num_visible_rows = NumVisibleRows();
4875 m_root.CalculateRowIndexes(m_num_rows);
4876 m_delegate_sp->TreeDelegateUpdateSelection(m_root, m_selected_row_idx,
4882 if (m_first_visible_row > 0 && m_num_rows < num_visible_rows)
4883 m_first_visible_row = 0;
4886 if (m_selected_row_idx < m_first_visible_row)
4887 m_first_visible_row = m_selected_row_idx;
4888 else if (m_first_visible_row + num_visible_rows <= m_selected_row_idx)
4889 m_first_visible_row = m_selected_row_idx - num_visible_rows + 1;
4892 int num_rows_left = num_visible_rows;
4893 m_root.Draw(window, m_first_visible_row, m_selected_row_idx, row_idx,
4896 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4901 const char *WindowDelegateGetHelpText()
override {
4902 return "Thread window keyboard shortcuts:";
4905 KeyHelp *WindowDelegateGetKeyHelp()
override {
4906 static curses::KeyHelp g_source_view_key_help[] = {
4907 {KEY_UP,
"Select previous item"},
4908 {KEY_DOWN,
"Select next item"},
4909 {KEY_RIGHT,
"Expand the selected item"},
4911 "Unexpand the selected item or select parent if not expanded"},
4912 {KEY_PPAGE,
"Page up"},
4913 {KEY_NPAGE,
"Page down"},
4914 {
'h',
"Show help dialog"},
4915 {
' ',
"Toggle item expansion"},
4919 return g_source_view_key_help;
4922 HandleCharResult WindowDelegateHandleChar(Window &window,
int c)
override {
4927 if (m_first_visible_row > 0) {
4928 if (m_first_visible_row > m_max_y)
4929 m_first_visible_row -= m_max_y;
4931 m_first_visible_row = 0;
4932 m_selected_row_idx = m_first_visible_row;
4933 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4934 if (m_selected_item)
4935 m_selected_item->ItemWasSelected();
4942 if (m_num_rows > m_max_y) {
4943 if (m_first_visible_row + m_max_y < m_num_rows) {
4944 m_first_visible_row += m_max_y;
4945 m_selected_row_idx = m_first_visible_row;
4946 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4947 if (m_selected_item)
4948 m_selected_item->ItemWasSelected();
4954 if (m_selected_row_idx > 0) {
4955 --m_selected_row_idx;
4956 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4957 if (m_selected_item)
4958 m_selected_item->ItemWasSelected();
4963 if (m_selected_row_idx + 1 < m_num_rows) {
4964 ++m_selected_row_idx;
4965 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4966 if (m_selected_item)
4967 m_selected_item->ItemWasSelected();
4972 if (m_selected_item) {
4973 if (!m_selected_item->IsExpanded())
4974 m_selected_item->Expand();
4979 if (m_selected_item) {
4980 if (m_selected_item->IsExpanded())
4981 m_selected_item->Unexpand();
4982 else if (m_selected_item->GetParent()) {
4983 m_selected_row_idx = m_selected_item->GetParent()->GetRowIndex();
4984 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4985 if (m_selected_item)
4986 m_selected_item->ItemWasSelected();
4993 if (m_selected_item) {
4994 if (m_selected_item->IsExpanded())
4995 m_selected_item->Unexpand();
4997 m_selected_item->Expand();
5002 window.CreateHelpSubwindow();
5008 return eKeyNotHandled;
5013 TreeDelegateSP m_delegate_sp;
5015 TreeItem *m_selected_item =
nullptr;
5017 int m_selected_row_idx = 0;
5018 int m_first_visible_row = 0;
5027class TextTreeDelegate :
public TreeDelegate {
5029 TextTreeDelegate() : TreeDelegate() {}
5031 ~TextTreeDelegate()
override =
default;
5033 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5034 window.PutCStringTruncated(1, item.GetText().c_str());
5037 void TreeDelegateGenerateChildren(TreeItem &item)
override {}
5039 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5042class FrameTreeDelegate :
public TreeDelegate {
5044 FrameTreeDelegate() : TreeDelegate() {
5046 "#${frame.index}: {${function.name}${function.pc-offset}}}", m_format);
5049 ~FrameTreeDelegate()
override =
default;
5051 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5054 const uint64_t frame_idx = item.GetIdentifier();
5059 frame_sp->GetSymbolContext(eSymbolContextEverything);
5062 nullptr,
false,
false)) {
5064 window.PutCStringTruncated(right_pad, strm.
GetString().str().c_str());
5070 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5074 bool TreeDelegateItemSelected(TreeItem &item)
override {
5077 thread->
GetProcess()->GetThreadList().SetSelectedThreadByID(
5079 const uint64_t frame_idx = item.GetIdentifier();
5090class ThreadTreeDelegate :
public TreeDelegate {
5092 ThreadTreeDelegate(
Debugger &debugger)
5093 : TreeDelegate(), m_debugger(debugger) {
5095 "reason = ${thread.stop-reason}}",
5099 ~ThreadTreeDelegate()
override =
default;
5102 return m_debugger.GetCommandInterpreter()
5103 .GetExecutionContext()
5107 ThreadSP GetThread(
const TreeItem &item) {
5110 return process_sp->GetThreadList().FindThreadByID(item.GetIdentifier());
5114 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5115 ThreadSP thread_sp = GetThread(item);
5120 nullptr,
false,
false)) {
5122 window.PutCStringTruncated(right_pad, strm.
GetString().str().c_str());
5127 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5129 if (process_sp && process_sp->IsAlive()) {
5130 StateType state = process_sp->GetState();
5132 ThreadSP thread_sp = GetThread(item);
5134 if (m_stop_id == process_sp->GetStopID() &&
5135 thread_sp->GetID() == m_tid)
5137 if (!m_frame_delegate_sp) {
5139 m_frame_delegate_sp = std::make_shared<FrameTreeDelegate>();
5142 m_stop_id = process_sp->GetStopID();
5143 m_tid = thread_sp->GetID();
5145 size_t num_frames = thread_sp->GetStackFrameCount();
5146 item.Resize(num_frames, *m_frame_delegate_sp,
false);
5147 for (
size_t i = 0; i < num_frames; ++i) {
5148 item[i].SetUserData(thread_sp.get());
5149 item[i].SetIdentifier(i);
5155 item.ClearChildren();
5158 bool TreeDelegateItemSelected(TreeItem &item)
override {
5160 if (process_sp && process_sp->IsAlive()) {
5161 StateType state = process_sp->GetState();
5163 ThreadSP thread_sp = GetThread(item);
5165 ThreadList &thread_list = thread_sp->GetProcess()->GetThreadList();
5166 std::lock_guard<std::recursive_mutex> guard(thread_list.
GetMutex());
5168 if (selected_thread_sp->GetID() != thread_sp->GetID()) {
5180 std::shared_ptr<FrameTreeDelegate> m_frame_delegate_sp;
5186class ThreadsTreeDelegate :
public TreeDelegate {
5188 ThreadsTreeDelegate(
Debugger &debugger)
5189 : TreeDelegate(), m_thread_delegate_sp(), m_debugger(debugger) {
5194 ~ThreadsTreeDelegate()
override =
default;
5197 return m_debugger.GetCommandInterpreter()
5198 .GetExecutionContext()
5202 bool TreeDelegateShouldDraw()
override {
5213 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5215 if (process_sp && process_sp->IsAlive()) {
5219 nullptr,
false,
false)) {
5221 window.PutCStringTruncated(right_pad, strm.
GetString().str().c_str());
5226 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5228 m_update_selection =
false;
5229 if (process_sp && process_sp->IsAlive()) {
5230 StateType state = process_sp->GetState();
5232 const uint32_t stop_id = process_sp->GetStopID();
5233 if (m_stop_id == stop_id)
5236 m_stop_id = stop_id;
5237 m_update_selection =
true;
5239 if (!m_thread_delegate_sp) {
5242 m_thread_delegate_sp =
5243 std::make_shared<ThreadTreeDelegate>(m_debugger);
5246 ThreadList &threads = process_sp->GetThreadList();
5247 std::lock_guard<std::recursive_mutex> guard(threads.
GetMutex());
5249 size_t num_threads = threads.
GetSize();
5250 item.Resize(num_threads, *m_thread_delegate_sp,
false);
5251 for (
size_t i = 0; i < num_threads; ++i) {
5253 item[i].SetIdentifier(thread->GetID());
5254 item[i].SetMightHaveChildren(
true);
5255 if (selected_thread->GetID() == thread->GetID())
5261 item.ClearChildren();
5264 void TreeDelegateUpdateSelection(TreeItem &root,
int &selection_index,
5265 TreeItem *&selected_item)
override {
5266 if (!m_update_selection)
5270 if (!(process_sp && process_sp->IsAlive()))
5273 StateType state = process_sp->GetState();
5277 ThreadList &threads = process_sp->GetThreadList();
5278 std::lock_guard<std::recursive_mutex> guard(threads.
GetMutex());
5280 size_t num_threads = threads.
GetSize();
5281 for (
size_t i = 0; i < num_threads; ++i) {
5283 if (selected_thread->GetID() == thread->GetID()) {
5286 selection_index = selected_item->GetRowIndex();
5292 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5294 bool TreeDelegateExpandRootByDefault()
override {
return true; }
5297 std::shared_ptr<ThreadTreeDelegate> m_thread_delegate_sp;
5300 bool m_update_selection =
false;
5304class BreakpointLocationTreeDelegate :
public TreeDelegate {
5306 BreakpointLocationTreeDelegate(
Debugger &debugger)
5307 : TreeDelegate(), m_debugger(debugger) {}
5309 ~BreakpointLocationTreeDelegate()
override =
default;
5313 m_debugger.GetCommandInterpreter().GetExecutionContext());
5322 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5324 Process *process = GetProcess();
5326 stream.
Printf(
"%i.%i: ", breakpoint_location->GetBreakpoint().GetID(),
5327 breakpoint_location->GetID());
5328 Address address = breakpoint_location->GetAddress();
5331 window.PutCStringTruncated(1, stream.
GetString().str().c_str());
5337 Address address = breakpoint_location->GetAddress();
5344 symbol_context.
module_sp->GetFileSpec().Dump(
5349 if (symbol_context.
comp_unit !=
nullptr) {
5351 compile_unit_stream.
PutCString(
"compile unit = ");
5353 &compile_unit_stream);
5356 if (symbol_context.
function !=
nullptr) {
5372 if (symbol_context.
symbol) {
5374 if (breakpoint_location->IsReExported())
5375 symbol_stream.
PutCString(
"re-exported target = ");
5384 Process *process = GetProcess();
5391 BreakpointSiteSP breakpoint_site = breakpoint_location->GetBreakpointSite();
5392 if (breakpoint_location->IsIndirect() && breakpoint_site) {
5394 resolved_address.
SetLoadAddress(breakpoint_site->GetLoadAddress(),
5395 &breakpoint_location->GetTarget());
5397 if (resolved_symbol) {
5399 indirect_target_stream.
PutCString(
"indirect target = ");
5406 bool is_resolved = breakpoint_location->IsResolved();
5408 resolved_stream.
Printf(
"resolved = %s", is_resolved ?
"true" :
"false");
5411 bool is_hardware = is_resolved && breakpoint_site->IsHardware();
5413 hardware_stream.
Printf(
"hardware = %s", is_hardware ?
"true" :
"false");
5417 hit_count_stream.
Printf(
"hit count = %-4u",
5418 breakpoint_location->GetHitCount());
5424 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5426 StringList details = ComputeDetailsList(breakpoint_location);
5428 if (!m_string_delegate_sp)
5429 m_string_delegate_sp = std::make_shared<TextTreeDelegate>();
5431 item.Resize(details.
GetSize(), *m_string_delegate_sp,
false);
5432 for (
size_t i = 0; i < details.
GetSize(); i++) {
5437 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5441 std::shared_ptr<TextTreeDelegate> m_string_delegate_sp;
5444class BreakpointTreeDelegate :
public TreeDelegate {
5446 BreakpointTreeDelegate(
Debugger &debugger)
5447 : TreeDelegate(), m_debugger(debugger),
5448 m_breakpoint_location_delegate_sp() {}
5450 ~BreakpointTreeDelegate()
override =
default;
5453 TargetSP target = m_debugger.GetSelectedTarget();
5458 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5461 stream.
Format(
"{0}: ", breakpoint->GetID());
5462 breakpoint->GetResolverDescription(&stream);
5463 breakpoint->GetFilterDescription(&stream);
5464 window.PutCStringTruncated(1, stream.
GetString().str().c_str());
5467 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5470 if (!m_breakpoint_location_delegate_sp)
5471 m_breakpoint_location_delegate_sp =
5472 std::make_shared<BreakpointLocationTreeDelegate>(m_debugger);
5474 item.Resize(breakpoint->GetNumLocations(),
5475 *m_breakpoint_location_delegate_sp,
true);
5476 for (
size_t i = 0; i < breakpoint->GetNumLocations(); i++) {
5477 item[i].SetIdentifier(i);
5478 item[i].SetUserData(breakpoint.get());
5482 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5486 std::shared_ptr<BreakpointLocationTreeDelegate>
5487 m_breakpoint_location_delegate_sp;
5490class BreakpointsTreeDelegate :
public TreeDelegate {
5492 BreakpointsTreeDelegate(
Debugger &debugger)
5493 : TreeDelegate(), m_debugger(debugger), m_breakpoint_delegate_sp() {}
5495 ~BreakpointsTreeDelegate()
override =
default;
5497 bool TreeDelegateShouldDraw()
override {
5498 TargetSP target = m_debugger.GetSelectedTarget();
5505 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5506 window.PutCString(
"Breakpoints");
5509 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5510 TargetSP target = m_debugger.GetSelectedTarget();
5513 std::unique_lock<std::recursive_mutex> lock;
5516 if (!m_breakpoint_delegate_sp)
5517 m_breakpoint_delegate_sp =
5518 std::make_shared<BreakpointTreeDelegate>(m_debugger);
5520 item.Resize(breakpoints.
GetSize(), *m_breakpoint_delegate_sp,
true);
5521 for (
size_t i = 0; i < breakpoints.
GetSize(); i++) {
5522 item[i].SetIdentifier(i);
5526 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5528 bool TreeDelegateExpandRootByDefault()
override {
return true; }
5532 std::shared_ptr<BreakpointTreeDelegate> m_breakpoint_delegate_sp;
5535class ValueObjectListDelegate :
public WindowDelegate {
5537 ValueObjectListDelegate() : m_rows() {}
5540 SetValues(valobj_list);
5543 ~ValueObjectListDelegate()
override =
default;
5546 m_selected_row =
nullptr;
5547 m_selected_row_idx = 0;
5548 m_first_visible_row = 0;
5551 for (
auto &valobj_sp : valobj_list.
GetObjects())
5552 m_rows.push_back(Row(valobj_sp,
nullptr));
5555 bool WindowDelegateDraw(Window &window,
bool force)
override {
5559 m_max_x = window.GetWidth() - 1;
5560 m_max_y = window.GetHeight() - 1;
5563 window.DrawTitleBox(window.GetName());
5565 const int num_visible_rows = NumVisibleRows();
5566 const int num_rows = CalculateTotalNumberRows(m_rows);
5571 if (m_first_visible_row > 0 && num_rows < num_visible_rows)
5572 m_first_visible_row = 0;
5575 if (m_selected_row_idx < m_first_visible_row)
5576 m_first_visible_row = m_selected_row_idx;
5577 else if (m_first_visible_row + num_visible_rows <= m_selected_row_idx)
5578 m_first_visible_row = m_selected_row_idx - num_visible_rows + 1;
5580 DisplayRows(window, m_rows, g_options);
5583 m_selected_row = GetRowForRowIndex(m_selected_row_idx);
5587 window.MoveCursor(m_selected_row->x, m_selected_row->y);
5592 KeyHelp *WindowDelegateGetKeyHelp()
override {
5593 static curses::KeyHelp g_source_view_key_help[] = {
5594 {KEY_UP,
"Select previous item"},
5595 {KEY_DOWN,
"Select next item"},
5596 {KEY_RIGHT,
"Expand selected item"},
5597 {KEY_LEFT,
"Unexpand selected item or select parent if not expanded"},
5598 {KEY_PPAGE,
"Page up"},
5599 {KEY_NPAGE,
"Page down"},
5600 {
'A',
"Format as annotated address"},
5601 {
'b',
"Format as binary"},
5602 {
'B',
"Format as hex bytes with ASCII"},
5603 {
'c',
"Format as character"},
5604 {
'd',
"Format as a signed integer"},
5605 {
'D',
"Format selected value using the default format for the type"},
5606 {
'f',
"Format as float"},
5607 {
'h',
"Show help dialog"},
5608 {
'i',
"Format as instructions"},
5609 {
'o',
"Format as octal"},
5610 {
'p',
"Format as pointer"},
5611 {
's',
"Format as C string"},
5612 {
't',
"Toggle showing/hiding type names"},
5613 {
'u',
"Format as an unsigned integer"},
5614 {
'x',
"Format as hex"},
5615 {
'X',
"Format as uppercase hex"},
5616 {
' ',
"Toggle item expansion"},
5620 return g_source_view_key_help;
5623 HandleCharResult WindowDelegateHandleChar(Window &window,
int c)
override {
5640 if (m_selected_row) {
5641 auto valobj_sp = m_selected_row->value.GetSP();
5643 valobj_sp->SetFormat(FormatForChar(c));
5649 g_options.show_types = !g_options.show_types;
5655 if (m_first_visible_row > 0) {
5656 if (
static_cast<int>(m_first_visible_row) > m_max_y)
5657 m_first_visible_row -= m_max_y;
5659 m_first_visible_row = 0;
5660 m_selected_row_idx = m_first_visible_row;
5667 if (m_num_rows >
static_cast<size_t>(m_max_y)) {
5668 if (m_first_visible_row + m_max_y < m_num_rows) {
5669 m_first_visible_row += m_max_y;
5670 m_selected_row_idx = m_first_visible_row;
5676 if (m_selected_row_idx > 0)
5677 --m_selected_row_idx;
5681 if (m_selected_row_idx + 1 < m_num_rows)
5682 ++m_selected_row_idx;
5686 if (m_selected_row) {
5687 if (!m_selected_row->expanded)
5688 m_selected_row->Expand();
5693 if (m_selected_row) {
5694 if (m_selected_row->expanded)
5695 m_selected_row->Unexpand();
5696 else if (m_selected_row->parent)
5697 m_selected_row_idx = m_selected_row->parent->row_idx;
5703 if (m_selected_row) {
5704 if (m_selected_row->expanded)
5705 m_selected_row->Unexpand();
5707 m_selected_row->Expand();
5712 window.CreateHelpSubwindow();
5718 return eKeyNotHandled;
5722 std::vector<Row> m_rows;
5723 Row *m_selected_row =
nullptr;
5724 uint32_t m_selected_row_idx = 0;
5725 uint32_t m_first_visible_row = 0;
5726 uint32_t m_num_rows = 0;
5732 static Format FormatForChar(
int c) {
5766 bool DisplayRowObject(Window &window, Row &row, DisplayOptions &options,
5767 bool highlight,
bool last_child) {
5770 if (valobj ==
nullptr)
5773 const char *type_name =
5779 window.MoveCursor(row.x, row.y);
5781 row.DrawTree(window);
5784 window.AttributeOn(A_REVERSE);
5786 if (type_name && type_name[0])
5787 window.PrintfTruncated(1,
"(%s) ", type_name);
5789 if (name && name[0])
5790 window.PutCStringTruncated(1, name);
5792 attr_t changd_attr = 0;
5794 changd_attr = COLOR_PAIR(RedOnBlack) | A_BOLD;
5796 if (value && value[0]) {
5797 window.PutCStringTruncated(1,
" = ");
5799 window.AttributeOn(changd_attr);
5800 window.PutCStringTruncated(1, value);
5802 window.AttributeOff(changd_attr);
5805 if (summary && summary[0]) {
5806 window.PutCStringTruncated(1,
" ");
5808 window.AttributeOn(changd_attr);
5809 window.PutCStringTruncated(1, summary);
5811 window.AttributeOff(changd_attr);
5815 window.AttributeOff(A_REVERSE);
5820 void DisplayRows(Window &window, std::vector<Row> &rows,
5821 DisplayOptions &options) {
5825 bool window_is_active = window.IsActive();
5826 for (
auto &row : rows) {
5827 const bool last_child = row.parent && &rows[rows.size() - 1] == &row;
5829 row.row_idx = m_num_rows;
5830 if ((m_num_rows >= m_first_visible_row) &&
5831 ((m_num_rows - m_first_visible_row) <
5832 static_cast<size_t>(NumVisibleRows()))) {
5834 row.y = m_num_rows - m_first_visible_row + 1;
5835 if (DisplayRowObject(window, row, options,
5837 m_num_rows == m_selected_row_idx,
5851 auto &children = row.GetChildren();
5852 if (!children.empty()) {
5853 DisplayRows(window, children, options);
5859 int CalculateTotalNumberRows(std::vector<Row> &rows) {
5861 for (
auto &row : rows) {
5864 row_count += CalculateTotalNumberRows(row.GetChildren());
5869 static Row *GetRowForRowIndexImpl(std::vector<Row> &rows,
size_t &row_index) {
5870 for (
auto &row : rows) {
5876 auto &children = row.GetChildren();
5877 if (!children.empty()) {
5878 Row *result = GetRowForRowIndexImpl(children, row_index);
5888 Row *GetRowForRowIndex(
size_t row_index) {
5889 return GetRowForRowIndexImpl(m_rows, row_index);
5892 int NumVisibleRows()
const {
return m_max_y - m_min_y; }
5894 static DisplayOptions g_options;
5897class FrameVariablesWindowDelegate :
public ValueObjectListDelegate {
5899 FrameVariablesWindowDelegate(
Debugger &debugger)
5900 : ValueObjectListDelegate(), m_debugger(debugger) {}
5902 ~FrameVariablesWindowDelegate()
override =
default;
5904 const char *WindowDelegateGetHelpText()
override {
5905 return "Frame variable window keyboard shortcuts:";
5908 bool WindowDelegateDraw(Window &window,
bool force)
override {
5910 m_debugger.GetCommandInterpreter().GetExecutionContext());
5912 Block *frame_block =
nullptr;
5929 if (m_frame_block != frame_block) {
5930 m_frame_block = frame_block;
5939 ValueObjectSP synthetic_value_sp = value_sp->GetSyntheticValue();
5940 if (synthetic_value_sp)
5941 local_values.
Append(synthetic_value_sp);
5943 local_values.
Append(value_sp);
5947 SetValues(local_values);
5951 m_frame_block =
nullptr;
5953 SetValues(local_values);
5956 return ValueObjectListDelegate::WindowDelegateDraw(window, force);
5961 Block *m_frame_block =
nullptr;
5964class RegistersWindowDelegate :
public ValueObjectListDelegate {
5966 RegistersWindowDelegate(
Debugger &debugger)
5967 : ValueObjectListDelegate(), m_debugger(debugger) {}
5969 ~RegistersWindowDelegate()
override =
default;
5971 const char *WindowDelegateGetHelpText()
override {
5972 return "Register window keyboard shortcuts:";
5975 bool WindowDelegateDraw(Window &window,
bool force)
override {
5977 m_debugger.GetCommandInterpreter().GetExecutionContext());
5986 const uint32_t num_sets = reg_ctx->GetRegisterSetCount();
5987 for (uint32_t set_idx = 0; set_idx < num_sets; ++set_idx) {
5992 SetValues(value_list);
5996 if (process && process->
IsAlive())
6001 SetValues(value_list);
6004 return ValueObjectListDelegate::WindowDelegateDraw(window, force);
6012static const char *CursesKeyToCString(
int ch) {
6013 static char g_desc[32];
6014 if (ch >= KEY_F0 && ch < KEY_F0 + 64) {
6015 snprintf(g_desc,
sizeof(g_desc),
"F%u", ch - KEY_F0);
6032 return "delete-line";
6034 return "insert-line";
6036 return "delete-char";
6038 return "insert-char";
6042 return "clear-to-eos";
6044 return "clear-to-eol";
6046 return "scroll-forward";
6048 return "scroll-backward";
6058 return "clear-all-tabs";
6064 return "lower-left key";
6066 return "upper left of keypad";
6068 return "upper right of keypad";
6070 return "center of keypad";
6072 return "lower left of keypad";
6074 return "lower right of keypad";
6076 return "back-tab key";
6080 return "cancel key";
6084 return "command key";
6088 return "create key";
6100 return "message key";
6108 return "options key";
6110 return "previous key";
6114 return "reference key";
6116 return "refresh key";
6118 return "replace key";
6120 return "restart key";
6122 return "resume key";
6126 return "shifted begin key";
6128 return "shifted cancel key";
6130 return "shifted command key";
6132 return "shifted copy key";
6134 return "shifted create key";
6136 return "shifted delete-character key";
6138 return "shifted delete-line key";
6140 return "select key";
6142 return "shifted end key";
6144 return "shifted clear-to-end-of-line key";
6146 return "shifted exit key";
6148 return "shifted find key";
6150 return "shifted help key";
6152 return "shifted home key";
6154 return "shifted insert-character key";
6156 return "shifted left-arrow key";
6158 return "shifted message key";
6160 return "shifted move key";
6162 return "shifted next key";
6164 return "shifted options key";
6166 return "shifted previous key";
6168 return "shifted print key";
6170 return "shifted redo key";
6172 return "shifted replace key";
6174 return "shifted right-arrow key";
6176 return "shifted resume key";
6178 return "shifted save key";
6180 return "shifted suspend key";
6182 return "shifted undo key";
6184 return "suspend key";
6188 return "Mouse event has occurred";
6190 return "Terminal resize event";
6193 return "We were interrupted by an event";
6204 if (llvm::isPrint(ch))
6205 snprintf(g_desc,
sizeof(g_desc),
"%c", ch);
6207 snprintf(g_desc,
sizeof(g_desc),
"\\x%2.2x", ch);
6213HelpDialogDelegate::HelpDialogDelegate(
const char *text,
6214 KeyHelp *key_help_array)
6216 if (text && text[0]) {
6217 m_text.SplitIntoLines(text);
6218 m_text.AppendString(
"");
6220 if (key_help_array) {
6221 for (KeyHelp *key = key_help_array; key->ch; ++key) {
6223 key_description.
Printf(
"%10s - %s", CursesKeyToCString(key->ch),
6225 m_text.AppendString(key_description.
GetString());
6230HelpDialogDelegate::~HelpDialogDelegate() =
default;
6232bool HelpDialogDelegate::WindowDelegateDraw(Window &window,
bool force) {
6234 const int window_height = window.GetHeight();
6237 const int min_y = y;
6238 const int max_y = window_height - 1 - y;
6239 const size_t num_visible_lines = max_y - min_y + 1;
6240 const size_t num_lines = m_text.GetSize();
6241 const char *bottom_message;
6242 if (num_lines <= num_visible_lines)
6243 bottom_message =
"Press any key to exit";
6245 bottom_message =
"Use arrows to scroll, any other key to exit";
6246 window.DrawTitleBox(window.GetName(), bottom_message);
6247 while (y <= max_y) {
6248 window.MoveCursor(x, y);
6249 window.PutCStringTruncated(
6250 1, m_text.GetStringAtIndex(m_first_visible_line + y - min_y));
6256HandleCharResult HelpDialogDelegate::WindowDelegateHandleChar(Window &window,
6259 const size_t num_lines = m_text.GetSize();
6260 const size_t num_visible_lines = window.GetHeight() - 2;
6262 if (num_lines <= num_visible_lines) {
6269 if (m_first_visible_line > 0)
6270 --m_first_visible_line;
6274 if (m_first_visible_line + num_visible_lines < num_lines)
6275 ++m_first_visible_line;
6280 if (m_first_visible_line > 0) {
6281 if (
static_cast<size_t>(m_first_visible_line) >= num_visible_lines)
6282 m_first_visible_line -= num_visible_lines;
6284 m_first_visible_line = 0;
6290 if (m_first_visible_line + num_visible_lines < num_lines) {
6291 m_first_visible_line += num_visible_lines;
6292 if (
static_cast<size_t>(m_first_visible_line) > num_lines)
6293 m_first_visible_line = num_lines - num_visible_lines;
6303 window.GetParent()->RemoveSubWindow(&window);
6307class ApplicationDelegate :
public WindowDelegate,
public MenuDelegate {
6315 eMenuID_TargetCreate,
6316 eMenuID_TargetDelete,
6319 eMenuID_ProcessAttach,
6320 eMenuID_ProcessDetachResume,
6321 eMenuID_ProcessDetachSuspended,
6322 eMenuID_ProcessLaunch,
6323 eMenuID_ProcessContinue,
6324 eMenuID_ProcessHalt,
6325 eMenuID_ProcessKill,
6328 eMenuID_ThreadStepIn,
6329 eMenuID_ThreadStepOver,
6330 eMenuID_ThreadStepOut,
6333 eMenuID_ViewBacktrace,
6334 eMenuID_ViewRegisters,
6336 eMenuID_ViewVariables,
6337 eMenuID_ViewBreakpoints,
6343 ApplicationDelegate(Application &app,
Debugger &debugger)
6344 : WindowDelegate(), MenuDelegate(), m_app(app), m_debugger(debugger) {}
6346 ~ApplicationDelegate()
override =
default;
6348 bool WindowDelegateDraw(Window &window,
bool force)
override {
6352 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override {
6355 window.SelectNextWindowAsActive();
6359 window.SelectPreviousWindowAsActive();
6363 window.CreateHelpSubwindow();
6367 return eQuitApplication;
6372 return eKeyNotHandled;
6375 const char *WindowDelegateGetHelpText()
override {
6376 return "Welcome to the LLDB curses GUI.\n\n"
6377 "Press the TAB key to change the selected view.\n"
6378 "Each view has its own keyboard shortcuts, press 'h' to open a "
6379 "dialog to display them.\n\n"
6380 "Common key bindings for all views:";
6383 KeyHelp *WindowDelegateGetKeyHelp()
override {
6384 static curses::KeyHelp g_source_view_key_help[] = {
6385 {
'\t',
"Select next view"},
6386 {KEY_BTAB,
"Select previous view"},
6387 {
'h',
"Show help dialog with view specific key bindings"},
6390 {KEY_UP,
"Select previous"},
6391 {KEY_DOWN,
"Select next"},
6392 {KEY_LEFT,
"Unexpand or select parent"},
6393 {KEY_RIGHT,
"Expand"},
6394 {KEY_PPAGE,
"Page up"},
6395 {KEY_NPAGE,
"Page down"},
6397 return g_source_view_key_help;
6400 MenuActionResult MenuDelegateAction(Menu &menu)
override {
6401 switch (menu.GetIdentifier()) {
6402 case eMenuID_TargetCreate: {
6403 WindowSP main_window_sp = m_app.GetMainWindow();
6404 FormDelegateSP form_delegate_sp =
6405 FormDelegateSP(
new TargetCreateFormDelegate(m_debugger));
6406 Rect bounds = main_window_sp->GetCenteredRect(80, 19);
6407 WindowSP form_window_sp = main_window_sp->CreateSubWindow(
6408 form_delegate_sp->GetName().c_str(), bounds,
true);
6409 WindowDelegateSP window_delegate_sp =
6410 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
6411 form_window_sp->SetDelegate(window_delegate_sp);
6412 return MenuActionResult::Handled;
6414 case eMenuID_ThreadStepIn: {
6416 m_debugger.GetCommandInterpreter().GetExecutionContext();
6419 if (process && process->
IsAlive() &&
6424 return MenuActionResult::Handled;
6426 case eMenuID_ThreadStepOut: {
6428 m_debugger.GetCommandInterpreter().GetExecutionContext();
6431 if (process && process->
IsAlive() &&
6434 uint32_t frame_idx =
6440 return MenuActionResult::Handled;
6442 case eMenuID_ThreadStepOver: {
6444 m_debugger.GetCommandInterpreter().GetExecutionContext();
6447 if (process && process->
IsAlive() &&
6452 return MenuActionResult::Handled;
6454 case eMenuID_ProcessAttach: {
6455 WindowSP main_window_sp = m_app.GetMainWindow();
6456 FormDelegateSP form_delegate_sp = FormDelegateSP(
6457 new ProcessAttachFormDelegate(m_debugger, main_window_sp));
6458 Rect bounds = main_window_sp->GetCenteredRect(80, 22);
6459 WindowSP form_window_sp = main_window_sp->CreateSubWindow(
6460 form_delegate_sp->GetName().c_str(), bounds,
true);
6461 WindowDelegateSP window_delegate_sp =
6462 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
6463 form_window_sp->SetDelegate(window_delegate_sp);
6464 return MenuActionResult::Handled;
6466 case eMenuID_ProcessLaunch: {
6467 WindowSP main_window_sp = m_app.GetMainWindow();
6468 FormDelegateSP form_delegate_sp = FormDelegateSP(
6469 new ProcessLaunchFormDelegate(m_debugger, main_window_sp));
6470 Rect bounds = main_window_sp->GetCenteredRect(80, 22);
6471 WindowSP form_window_sp = main_window_sp->CreateSubWindow(
6472 form_delegate_sp->GetName().c_str(), bounds,
true);
6473 WindowDelegateSP window_delegate_sp =
6474 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
6475 form_window_sp->SetDelegate(window_delegate_sp);
6476 return MenuActionResult::Handled;
6479 case eMenuID_ProcessContinue: {
6481 m_debugger.GetCommandInterpreter().GetExecutionContext();
6484 if (process && process->
IsAlive() &&
6489 return MenuActionResult::Handled;
6491 case eMenuID_ProcessKill: {
6493 m_debugger.GetCommandInterpreter().GetExecutionContext();
6496 if (process && process->
IsAlive())
6500 return MenuActionResult::Handled;
6502 case eMenuID_ProcessHalt: {
6504 m_debugger.GetCommandInterpreter().GetExecutionContext();
6507 if (process && process->
IsAlive())
6511 return MenuActionResult::Handled;
6513 case eMenuID_ProcessDetachResume:
6514 case eMenuID_ProcessDetachSuspended: {
6516 m_debugger.GetCommandInterpreter().GetExecutionContext();
6519 if (process && process->
IsAlive())
6520 process->
Detach(menu.GetIdentifier() ==
6521 eMenuID_ProcessDetachSuspended);
6524 return MenuActionResult::Handled;
6526 case eMenuID_Process: {
6530 Menus &submenus = menu.GetSubmenus();
6532 m_debugger.GetCommandInterpreter().GetExecutionContext();
6534 if (process && process->
IsAlive() &&
6536 if (submenus.size() == 7)
6537 menu.AddSubmenu(MenuSP(
new Menu(Menu::Type::Separator)));
6538 else if (submenus.size() > 8)
6539 submenus.erase(submenus.begin() + 8, submenus.end());
6542 std::lock_guard<std::recursive_mutex> guard(threads.
GetMutex());
6543 size_t num_threads = threads.
GetSize();
6544 for (
size_t i = 0; i < num_threads; ++i) {
6546 char menu_char =
'\0';
6548 menu_char =
'1' + i;
6550 thread_menu_title.
Printf(
"Thread %u", thread_sp->GetIndexID());
6551 const char *thread_name = thread_sp->GetName();
6552 if (thread_name && thread_name[0])
6553 thread_menu_title.
Printf(
" %s", thread_name);
6555 const char *queue_name = thread_sp->GetQueueName();
6556 if (queue_name && queue_name[0])
6557 thread_menu_title.
Printf(
" %s", queue_name);
6560 MenuSP(
new Menu(thread_menu_title.
GetString().str().c_str(),
6561 nullptr, menu_char, thread_sp->GetID())));
6563 }
else if (submenus.size() > 7) {
6566 submenus.erase(submenus.begin() + 7, submenus.end());
6570 menu.RecalculateNameLengths();
6572 return MenuActionResult::Handled;
6574 case eMenuID_ViewVariables: {
6575 WindowSP main_window_sp = m_app.GetMainWindow();
6576 WindowSP source_window_sp = main_window_sp->FindSubWindow(
"Source");
6577 WindowSP variables_window_sp = main_window_sp->FindSubWindow(
"Variables");
6578 WindowSP registers_window_sp = main_window_sp->FindSubWindow(
"Registers");
6579 const Rect source_bounds = source_window_sp->GetBounds();
6581 if (variables_window_sp) {
6582 const Rect variables_bounds = variables_window_sp->GetBounds();
6584 main_window_sp->RemoveSubWindow(variables_window_sp.get());
6586 if (registers_window_sp) {
6589 Rect registers_bounds = variables_bounds;
6590 registers_bounds.size.width = source_bounds.size.width;
6591 registers_window_sp->SetBounds(registers_bounds);
6595 source_window_sp->Resize(source_bounds.size.width,
6596 source_bounds.size.height +
6597 variables_bounds.size.height);
6600 Rect new_variables_rect;
6601 if (registers_window_sp) {
6605 const Rect variables_bounds = registers_window_sp->GetBounds();
6606 Rect new_registers_rect;
6607 variables_bounds.VerticalSplitPercentage(0.50, new_variables_rect,
6608 new_registers_rect);
6609 registers_window_sp->SetBounds(new_registers_rect);
6612 Rect new_source_rect;
6613 source_bounds.HorizontalSplitPercentage(0.70, new_source_rect,
6614 new_variables_rect);
6615 source_window_sp->SetBounds(new_source_rect);
6617 WindowSP new_window_sp = main_window_sp->CreateSubWindow(
6618 "Variables", new_variables_rect,
false);
6619 new_window_sp->SetDelegate(
6620 WindowDelegateSP(
new FrameVariablesWindowDelegate(m_debugger)));
6624 return MenuActionResult::Handled;
6626 case eMenuID_ViewRegisters: {
6627 WindowSP main_window_sp = m_app.GetMainWindow();
6628 WindowSP source_window_sp = main_window_sp->FindSubWindow(
"Source");
6629 WindowSP variables_window_sp = main_window_sp->FindSubWindow(
"Variables");
6630 WindowSP registers_window_sp = main_window_sp->FindSubWindow(
"Registers");
6631 const Rect source_bounds = source_window_sp->GetBounds();
6633 if (registers_window_sp) {
6634 if (variables_window_sp) {
6635 const Rect variables_bounds = variables_window_sp->GetBounds();
6639 variables_window_sp->Resize(variables_bounds.size.width +
6640 registers_window_sp->GetWidth(),
6641 variables_bounds.size.height);
6645 source_window_sp->Resize(source_bounds.size.width,
6646 source_bounds.size.height +
6647 registers_window_sp->GetHeight());
6649 main_window_sp->RemoveSubWindow(registers_window_sp.get());
6652 if (variables_window_sp) {
6656 const Rect variables_bounds = variables_window_sp->GetBounds();
6658 variables_bounds.VerticalSplitPercentage(0.50, new_vars_rect,
6660 variables_window_sp->SetBounds(new_vars_rect);
6663 Rect new_source_rect;
6664 source_bounds.HorizontalSplitPercentage(0.70, new_source_rect,
6666 source_window_sp->SetBounds(new_source_rect);
6668 WindowSP new_window_sp =
6669 main_window_sp->CreateSubWindow(
"Registers", new_regs_rect,
false);
6670 new_window_sp->SetDelegate(
6671 WindowDelegateSP(
new RegistersWindowDelegate(m_debugger)));
6675 return MenuActionResult::Handled;
6677 case eMenuID_ViewBreakpoints: {
6678 WindowSP main_window_sp = m_app.GetMainWindow();
6679 WindowSP threads_window_sp = main_window_sp->FindSubWindow(
"Threads");
6680 WindowSP breakpoints_window_sp =
6681 main_window_sp->FindSubWindow(
"Breakpoints");
6682 const Rect threads_bounds = threads_window_sp->GetBounds();
6689 if (breakpoints_window_sp) {
6690 threads_window_sp->Resize(threads_bounds.size.width,
6691 threads_bounds.size.height +
6692 breakpoints_window_sp->GetHeight());
6693 main_window_sp->RemoveSubWindow(breakpoints_window_sp.get());
6695 Rect new_threads_bounds, breakpoints_bounds;
6696 threads_bounds.HorizontalSplitPercentage(0.70, new_threads_bounds,
6697 breakpoints_bounds);
6698 threads_window_sp->SetBounds(new_threads_bounds);
6699 breakpoints_window_sp = main_window_sp->CreateSubWindow(
6700 "Breakpoints", breakpoints_bounds,
false);
6701 TreeDelegateSP breakpoints_delegate_sp(
6702 new BreakpointsTreeDelegate(m_debugger));
6703 breakpoints_window_sp->SetDelegate(WindowDelegateSP(
6704 new TreeWindowDelegate(m_debugger, breakpoints_delegate_sp)));
6707 return MenuActionResult::Handled;
6710 case eMenuID_HelpGUIHelp:
6711 m_app.GetMainWindow()->CreateHelpSubwindow();
6712 return MenuActionResult::Handled;
6718 return MenuActionResult::NotHandled;
6726class StatusBarWindowDelegate :
public WindowDelegate {
6728 StatusBarWindowDelegate(
Debugger &debugger) : m_debugger(debugger) {
6732 ~StatusBarWindowDelegate()
override =
default;
6734 bool WindowDelegateDraw(Window &window,
bool force)
override {
6736 m_debugger.GetCommandInterpreter().GetExecutionContext();
6741 window.SetBackground(BlackOnWhite);
6742 window.MoveCursor(0, 0);
6745 window.Printf(
"Process: %5" PRIu64
" %10s", process->
GetID(),
6751 nullptr,
nullptr,
false,
false)) {
6752 window.MoveCursor(40, 0);
6753 window.PutCStringTruncated(1, strm.
GetString().str().c_str());
6756 window.MoveCursor(60, 0);
6758 window.
Printf(
"Frame: %3u PC = 0x%16.16" PRIx64,
6765 if (exit_desc && exit_desc[0])
6766 window.Printf(
" with status = %i (%s)", exit_status, exit_desc);
6768 window.Printf(
" with status = %i", exit_status);
6779class SourceFileWindowDelegate :
public WindowDelegate {
6781 SourceFileWindowDelegate(
Debugger &debugger)
6782 : WindowDelegate(), m_debugger(debugger), m_sc(), m_file_sp(),
6783 m_disassembly_sp(), m_disassembly_range(), m_title() {}
6785 ~SourceFileWindowDelegate()
override =
default;
6789 uint32_t NumVisibleLines()
const {
return m_max_y - m_min_y; }
6791 const char *WindowDelegateGetHelpText()
override {
6792 return "Source/Disassembly window keyboard shortcuts:";
6795 KeyHelp *WindowDelegateGetKeyHelp()
override {
6796 static curses::KeyHelp g_source_view_key_help[] = {
6797 {KEY_RETURN,
"Run to selected line with one shot breakpoint"},
6798 {KEY_UP,
"Select previous source line"},
6799 {KEY_DOWN,
"Select next source line"},
6800 {KEY_LEFT,
"Scroll to the left"},
6801 {KEY_RIGHT,
"Scroll to the right"},
6802 {KEY_PPAGE,
"Page up"},
6803 {KEY_NPAGE,
"Page down"},
6804 {
'b',
"Set breakpoint on selected source/disassembly line"},
6805 {
'c',
"Continue process"},
6806 {
'D',
"Detach with process suspended"},
6807 {
'h',
"Show help dialog"},
6808 {
'n',
"Step over (source line)"},
6809 {
'N',
"Step over (single instruction)"},
6810 {
'f',
"Step out (finish)"},
6811 {
's',
"Step in (source line)"},
6812 {
'S',
"Step in (single instruction)"},
6814 {
'd',
"Frame down"},
6818 return g_source_view_key_help;
6821 bool WindowDelegateDraw(Window &window,
bool force)
override {
6823 m_debugger.GetCommandInterpreter().GetExecutionContext();
6825 Thread *thread =
nullptr;
6827 bool update_location =
false;
6832 update_location =
true;
6838 m_max_x = window.GetMaxX() - 1;
6839 m_max_y = window.GetMaxY() - 1;
6841 const uint32_t num_visible_lines = NumVisibleLines();
6843 bool set_selected_line_to_pc =
false;
6845 if (update_location) {
6846 const bool process_alive = process->
IsAlive();
6847 bool thread_changed =
false;
6848 if (process_alive) {
6852 auto tid = thread->
GetID();
6853 thread_changed = tid != m_tid;
6857 thread_changed =
true;
6862 const uint32_t stop_id = process ? process->
GetStopID() : 0;
6863 const bool stop_id_changed = stop_id != m_stop_id;
6864 bool frame_changed =
false;
6865 m_stop_id = stop_id;
6868 m_sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
6869 if (m_sc.module_sp) {
6871 "%s", m_sc.module_sp->GetFileSpec().GetFilename().GetCString());
6874 m_title.Printf(
"`%s", func_name.
GetCString());
6876 const uint32_t frame_idx = frame_sp->GetFrameIndex();
6877 frame_changed = frame_idx != m_frame_idx;
6878 m_frame_idx = frame_idx;
6885 const bool context_changed =
6886 thread_changed || frame_changed || stop_id_changed;
6888 if (process_alive) {
6889 if (m_sc.line_entry.IsValid()) {
6890 m_pc_line = m_sc.line_entry.line;
6894 if (context_changed)
6895 m_selected_line = m_pc_line;
6897 if (m_file_sp && m_file_sp->GetSupportFile()->GetSpecOnly() ==
6898 m_sc.line_entry.GetFile()) {
6901 if (m_selected_line >=
static_cast<size_t>(m_first_visible_line)) {
6902 if (m_selected_line >= m_first_visible_line + num_visible_lines)
6903 m_first_visible_line = m_selected_line - 10;
6905 if (m_selected_line > 10)
6906 m_first_visible_line = m_selected_line - 10;
6908 m_first_visible_line = 0;
6912 m_selected_line = m_pc_line;
6914 m_debugger.GetSourceManager().GetFile(m_sc.line_entry.file_sp);
6916 const size_t num_lines = m_file_sp->GetNumLines();
6918 for (
size_t n = num_lines; n >= 10; n = n / 10)
6921 if (num_lines < num_visible_lines ||
6922 m_selected_line < num_visible_lines)
6923 m_first_visible_line = 0;
6925 m_first_visible_line = m_selected_line - 10;
6932 if (!m_file_sp || m_file_sp->GetNumLines() == 0) {
6934 bool prefer_file_cache =
false;
6935 if (m_sc.function) {
6936 if (m_disassembly_scope != m_sc.function) {
6937 m_disassembly_scope = m_sc.function;
6938 m_disassembly_sp = m_sc.function->GetInstructions(
6939 exe_ctx,
nullptr, !prefer_file_cache);
6940 if (m_disassembly_sp) {
6941 set_selected_line_to_pc =
true;
6942 m_disassembly_range = m_sc.function->GetAddressRange();
6944 m_disassembly_range.Clear();
6947 set_selected_line_to_pc = context_changed;
6949 }
else if (m_sc.symbol) {
6950 if (m_disassembly_scope != m_sc.symbol) {
6951 m_disassembly_scope = m_sc.symbol;
6952 m_disassembly_sp = m_sc.symbol->GetInstructions(
6953 exe_ctx,
nullptr, prefer_file_cache);
6954 if (m_disassembly_sp) {
6955 set_selected_line_to_pc =
true;
6956 m_disassembly_range.GetBaseAddress() =
6957 m_sc.symbol->GetAddress();
6958 m_disassembly_range.SetByteSize(m_sc.symbol->GetByteSize());
6960 m_disassembly_range.Clear();
6963 set_selected_line_to_pc = context_changed;
6972 const int window_width = window.GetWidth();
6974 window.DrawTitleBox(
"Sources");
6975 if (!m_title.GetString().empty()) {
6976 window.AttributeOn(A_REVERSE);
6977 window.MoveCursor(1, 1);
6978 window.PutChar(
' ');
6979 window.PutCStringTruncated(1, m_title.GetString().str().c_str());
6980 int x = window.GetCursorX();
6981 if (x < window_width - 1) {
6982 window.Printf(
"%*s", window_width - x - 1,
"");
6984 window.AttributeOff(A_REVERSE);
6988 const size_t num_source_lines = GetNumSourceLines();
6989 if (num_source_lines > 0) {
6991 BreakpointLines bp_lines;
6994 const size_t num_bps = bp_list.
GetSize();
6995 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
6997 const size_t num_bps_locs = bp_sp->GetNumLocations();
6998 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs; ++bp_loc_idx) {
7000 bp_sp->GetLocationAtIndex(bp_loc_idx);
7002 if (bp_loc_sp->GetAddress().CalculateSymbolContextLineEntry(
7003 bp_loc_line_entry)) {
7004 if (m_file_sp->GetSupportFile()->GetSpecOnly() ==
7005 bp_loc_line_entry.
GetFile()) {
7006 bp_lines.insert(bp_loc_line_entry.
line);
7013 for (
size_t i = 0; i < num_visible_lines; ++i) {
7014 const uint32_t curr_line = m_first_visible_line + i;
7015 if (curr_line < num_source_lines) {
7016 const int line_y = m_min_y + i;
7017 window.MoveCursor(1, line_y);
7018 const bool is_pc_line = curr_line == m_pc_line;
7019 const bool line_is_selected = m_selected_line == curr_line;
7023 attr_t highlight_attr = 0;
7025 if (line_is_selected && !is_pc_line)
7026 highlight_attr = A_REVERSE;
7028 if (bp_lines.find(curr_line + 1) != bp_lines.end())
7029 bp_attr = COLOR_PAIR(BlackOnWhite);
7032 window.AttributeOn(bp_attr);
7034 window.Printf(
" %*u ", m_line_width, curr_line + 1);
7037 window.AttributeOff(bp_attr);
7039 window.PutChar(ACS_VLINE);
7042 window.PutChar(ACS_DIAMOND);
7044 window.PutChar(
' ');
7047 window.AttributeOn(highlight_attr);
7051 std::optional<size_t> column;
7052 if (is_pc_line && m_sc.line_entry.IsValid() && m_sc.line_entry.column)
7053 column = m_sc.line_entry.column - 1;
7054 m_file_sp->DisplaySourceLines(curr_line + 1, column, 0, 0,
7056 StringRef line = lineStream.
GetString();
7057 if (line.ends_with(
"\n"))
7058 line = line.drop_back();
7059 bool wasWritten = window.OutputColoredStringTruncated(
7060 1, line, m_first_visible_column, is_pc_line);
7061 if (!wasWritten && (line_is_selected || is_pc_line)) {
7065 window.PutCStringTruncated(
7066 1, line.empty() && m_first_visible_column == 0 ?
" " :
"<");
7069 if (is_pc_line && frame_sp &&
7070 frame_sp->GetConcreteFrameIndex() == 0) {
7075 const char *stop_description = stop_info_sp->GetDescription();
7076 if (stop_description && stop_description[0]) {
7077 size_t stop_description_len = strlen(stop_description);
7078 int desc_x = window_width - stop_description_len - 16;
7079 if (desc_x - window.GetCursorX() > 0)
7080 window.Printf(
"%*s", desc_x - window.GetCursorX(),
"");
7081 window.MoveCursor(window_width - stop_description_len - 16,
7083 const attr_t stop_reason_attr = COLOR_PAIR(WhiteOnBlue);
7084 window.AttributeOn(stop_reason_attr);
7085 window.PrintfTruncated(1,
" <<< Thread %u: %s ",
7087 window.AttributeOff(stop_reason_attr);
7090 window.Printf(
"%*s", window_width - window.GetCursorX() - 1,
"");
7094 window.AttributeOff(highlight_attr);
7100 size_t num_disassembly_lines = GetNumDisassemblyLines();
7101 if (num_disassembly_lines > 0) {
7103 BreakpointAddrs bp_file_addrs;
7107 const size_t num_bps = bp_list.
GetSize();
7108 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
7110 const size_t num_bps_locs = bp_sp->GetNumLocations();
7111 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs;
7114 bp_sp->GetLocationAtIndex(bp_loc_idx);
7117 bp_loc_sp->GetAddress().GetFileAddress();
7119 if (m_disassembly_range.ContainsFileAddress(file_addr))
7120 bp_file_addrs.insert(file_addr);
7126 const attr_t selected_highlight_attr = A_REVERSE;
7127 const attr_t pc_highlight_attr = COLOR_PAIR(WhiteOnBlue);
7135 pc_address = frame_sp->GetFrameCodeAddress();
7136 const uint32_t pc_idx =
7140 if (set_selected_line_to_pc) {
7141 m_selected_line = pc_idx;
7144 const uint32_t non_visible_pc_offset = (num_visible_lines / 5);
7145 if (
static_cast<size_t>(m_first_visible_line) >= num_disassembly_lines)
7146 m_first_visible_line = 0;
7148 if (pc_idx < num_disassembly_lines) {
7149 if (pc_idx <
static_cast<uint32_t
>(m_first_visible_line) ||
7150 pc_idx >= m_first_visible_line + num_visible_lines)
7151 m_first_visible_line = pc_idx - non_visible_pc_offset;
7154 for (
size_t i = 0; i < num_visible_lines; ++i) {
7155 const uint32_t inst_idx = m_first_visible_line + i;
7160 const int line_y = m_min_y + i;
7161 window.MoveCursor(1, line_y);
7162 const bool is_pc_line = frame_sp && inst_idx == pc_idx;
7163 const bool line_is_selected = m_selected_line == inst_idx;
7166 attr_t highlight_attr = 0;
7169 highlight_attr = pc_highlight_attr;
7170 else if (line_is_selected)
7171 highlight_attr = selected_highlight_attr;
7174 bp_file_addrs.end())
7175 bp_attr = COLOR_PAIR(BlackOnWhite);
7178 window.AttributeOn(bp_attr);
7180 window.Printf(
" 0x%16.16llx ",
7181 static_cast<unsigned long long>(
7185 window.AttributeOff(bp_attr);
7187 window.PutChar(ACS_VLINE);
7190 window.PutChar(ACS_DIAMOND);
7192 window.PutChar(
' ');
7195 window.AttributeOn(highlight_attr);
7197 const char *mnemonic = inst->
GetMnemonic(&exe_ctx);
7198 const char *operands = inst->
GetOperands(&exe_ctx);
7199 const char *comment = inst->
GetComment(&exe_ctx);
7201 if (mnemonic !=
nullptr && mnemonic[0] ==
'\0')
7203 if (operands !=
nullptr && operands[0] ==
'\0')
7205 if (comment !=
nullptr && comment[0] ==
'\0')
7210 if (mnemonic !=
nullptr && operands !=
nullptr && comment !=
nullptr)
7211 strm.
Printf(
"%-8s %-25s ; %s", mnemonic, operands, comment);
7212 else if (mnemonic !=
nullptr && operands !=
nullptr)
7213 strm.
Printf(
"%-8s %s", mnemonic, operands);
7214 else if (mnemonic !=
nullptr)
7215 strm.
Printf(
"%s", mnemonic);
7218 window.PutCStringTruncated(
7220 strm.
GetString().substr(m_first_visible_column).data());
7222 if (is_pc_line && frame_sp &&
7223 frame_sp->GetConcreteFrameIndex() == 0) {
7228 const char *stop_description = stop_info_sp->GetDescription();
7229 if (stop_description && stop_description[0]) {
7230 size_t stop_description_len = strlen(stop_description);
7231 int desc_x = window_width - stop_description_len - 16;
7232 if (desc_x - window.GetCursorX() > 0)
7233 window.Printf(
"%*s", desc_x - window.GetCursorX(),
"");
7234 window.MoveCursor(window_width - stop_description_len - 15,
7237 window.PrintfTruncated(1,
"<<< Thread %u: %s ",
7242 window.Printf(
"%*s", window_width - window.GetCursorX() - 1,
"");
7246 window.AttributeOff(highlight_attr);
7253 size_t GetNumLines() {
7254 size_t num_lines = GetNumSourceLines();
7256 num_lines = GetNumDisassemblyLines();
7260 size_t GetNumSourceLines()
const {
7262 return m_file_sp->GetNumLines();
7266 size_t GetNumDisassemblyLines()
const {
7267 if (m_disassembly_sp)
7268 return m_disassembly_sp->GetInstructionList().GetSize();
7272 HandleCharResult WindowDelegateHandleChar(Window &window,
int c)
override {
7273 const uint32_t num_visible_lines = NumVisibleLines();
7274 const size_t num_lines = GetNumLines();
7280 if (
static_cast<uint32_t
>(m_first_visible_line) > num_visible_lines)
7281 m_first_visible_line -= num_visible_lines;
7283 m_first_visible_line = 0;
7284 m_selected_line = m_first_visible_line;
7291 if (m_first_visible_line + num_visible_lines < num_lines)
7292 m_first_visible_line += num_visible_lines;
7293 else if (num_lines < num_visible_lines)
7294 m_first_visible_line = 0;
7296 m_first_visible_line = num_lines - num_visible_lines;
7297 m_selected_line = m_first_visible_line;
7302 if (m_selected_line > 0) {
7304 if (
static_cast<size_t>(m_first_visible_line) > m_selected_line)
7305 m_first_visible_line = m_selected_line;
7310 if (m_selected_line + 1 < num_lines) {
7312 if (m_first_visible_line + num_visible_lines < m_selected_line)
7313 m_first_visible_line++;
7318 if (m_first_visible_column > 0)
7319 --m_first_visible_column;
7323 ++m_first_visible_column;
7330 if (GetNumSourceLines() > 0) {
7332 m_debugger.GetCommandInterpreter().GetExecutionContext();
7336 m_file_sp->GetSupportFile()->GetSpecOnly(),
7347 bp_sp->GetOptions().SetOneShot(
true);
7350 }
else if (m_selected_line < GetNumDisassemblyLines()) {
7351 const Instruction *inst = m_disassembly_sp->GetInstructionList()
7352 .GetInstructionAtIndex(m_selected_line)
7355 m_debugger.GetCommandInterpreter().GetExecutionContext();
7363 bp_sp->GetOptions().SetOneShot(
true);
7370 ToggleBreakpointOnSelectedLine();
7376 m_debugger.GetCommandInterpreter().GetExecutionContext();
7386 m_debugger.GetCommandInterpreter().GetExecutionContext();
7396 m_debugger.GetCommandInterpreter().GetExecutionContext();
7400 uint32_t frame_idx =
7411 m_debugger.GetCommandInterpreter().GetExecutionContext();
7414 bool source_step = (c ==
'n');
7424 m_debugger.GetCommandInterpreter().GetExecutionContext();
7427 bool source_step = (c ==
's');
7437 m_debugger.GetCommandInterpreter().GetExecutionContext();
7440 uint32_t frame_idx =
7446 else if (c ==
'd' && frame_idx > 0)
7455 window.CreateHelpSubwindow();
7461 return eKeyNotHandled;
7464 void ToggleBreakpointOnSelectedLine() {
7466 m_debugger.GetCommandInterpreter().GetExecutionContext();
7469 if (GetNumSourceLines() > 0) {
7472 const size_t num_bps = bp_list.
GetSize();
7473 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
7475 const size_t num_bps_locs = bp_sp->GetNumLocations();
7476 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs; ++bp_loc_idx) {
7478 bp_sp->GetLocationAtIndex(bp_loc_idx);
7480 if (bp_loc_sp->GetAddress().CalculateSymbolContextLineEntry(
7481 bp_loc_line_entry)) {
7482 if (m_file_sp->GetSupportFile()->GetSpecOnly() ==
7483 bp_loc_line_entry.
GetFile() &&
7484 m_selected_line + 1 == bp_loc_line_entry.
line) {
7497 m_file_sp->GetSupportFile()->GetSpecOnly(),
7509 assert(GetNumDisassemblyLines() > 0);
7510 assert(m_selected_line < GetNumDisassemblyLines());
7511 const Instruction *inst = m_disassembly_sp->GetInstructionList()
7512 .GetInstructionAtIndex(m_selected_line)
7517 const size_t num_bps = bp_list.
GetSize();
7518 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
7520 const size_t num_bps_locs = bp_sp->GetNumLocations();
7521 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs; ++bp_loc_idx) {
7523 bp_sp->GetLocationAtIndex(bp_loc_idx);
7526 bp_loc_sp->GetAddress().GetFileAddress();
7545 typedef std::set<uint32_t> BreakpointLines;
7546 typedef std::set<lldb::addr_t> BreakpointAddrs;
7556 int m_line_width = 4;
7557 uint32_t m_selected_line = 0;
7558 uint32_t m_pc_line = 0;
7559 uint32_t m_stop_id = 0;
7561 int m_first_visible_line = 0;
7562 int m_first_visible_column = 0;
7569DisplayOptions ValueObjectListDelegate::g_options = {
true};
7580 std::shared_ptr<ApplicationDelegate> app_delegate_sp(
7583 MenuDelegateSP app_menu_delegate_sp =
7584 std::static_pointer_cast<MenuDelegate>(app_delegate_sp);
7585 MenuSP lldb_menu_sp(
7586 new Menu(
"LLDB",
"F1", KEY_F(1), ApplicationDelegate::eMenuID_LLDB));
7587 MenuSP exit_menuitem_sp(
7588 new Menu(
"Exit",
nullptr,
'x', ApplicationDelegate::eMenuID_LLDBExit));
7589 exit_menuitem_sp->SetCannedResult(MenuActionResult::Quit);
7590 lldb_menu_sp->AddSubmenu(MenuSP(
new Menu(
7591 "About LLDB",
nullptr,
'a', ApplicationDelegate::eMenuID_LLDBAbout)));
7592 lldb_menu_sp->AddSubmenu(MenuSP(
new Menu(Menu::Type::Separator)));
7593 lldb_menu_sp->AddSubmenu(exit_menuitem_sp);
7595 MenuSP target_menu_sp(
new Menu(
"Target",
"F2", KEY_F(2),
7596 ApplicationDelegate::eMenuID_Target));
7597 target_menu_sp->AddSubmenu(MenuSP(
new Menu(
7598 "Create",
nullptr,
'c', ApplicationDelegate::eMenuID_TargetCreate)));
7599 target_menu_sp->AddSubmenu(MenuSP(
new Menu(
7600 "Delete",
nullptr,
'd', ApplicationDelegate::eMenuID_TargetDelete)));
7602 MenuSP process_menu_sp(
new Menu(
"Process",
"F3", KEY_F(3),
7603 ApplicationDelegate::eMenuID_Process));
7604 process_menu_sp->AddSubmenu(MenuSP(
new Menu(
7605 "Attach",
nullptr,
'a', ApplicationDelegate::eMenuID_ProcessAttach)));
7606 process_menu_sp->AddSubmenu(
7607 MenuSP(
new Menu(
"Detach and resume",
nullptr,
'd',
7608 ApplicationDelegate::eMenuID_ProcessDetachResume)));
7609 process_menu_sp->AddSubmenu(
7610 MenuSP(
new Menu(
"Detach suspended",
nullptr,
's',
7611 ApplicationDelegate::eMenuID_ProcessDetachSuspended)));
7612 process_menu_sp->AddSubmenu(MenuSP(
new Menu(
7613 "Launch",
nullptr,
'l', ApplicationDelegate::eMenuID_ProcessLaunch)));
7614 process_menu_sp->AddSubmenu(MenuSP(
new Menu(Menu::Type::Separator)));
7615 process_menu_sp->AddSubmenu(
7616 MenuSP(
new Menu(
"Continue",
nullptr,
'c',
7617 ApplicationDelegate::eMenuID_ProcessContinue)));
7618 process_menu_sp->AddSubmenu(MenuSP(
new Menu(
7619 "Halt",
nullptr,
'h', ApplicationDelegate::eMenuID_ProcessHalt)));
7620 process_menu_sp->AddSubmenu(MenuSP(
new Menu(
7621 "Kill",
nullptr,
'k', ApplicationDelegate::eMenuID_ProcessKill)));
7623 MenuSP thread_menu_sp(
new Menu(
"Thread",
"F4", KEY_F(4),
7624 ApplicationDelegate::eMenuID_Thread));
7625 thread_menu_sp->AddSubmenu(MenuSP(
new Menu(
7626 "Step In",
nullptr,
'i', ApplicationDelegate::eMenuID_ThreadStepIn)));
7627 thread_menu_sp->AddSubmenu(
7628 MenuSP(
new Menu(
"Step Over",
nullptr,
'v',
7629 ApplicationDelegate::eMenuID_ThreadStepOver)));
7630 thread_menu_sp->AddSubmenu(MenuSP(
new Menu(
7631 "Step Out",
nullptr,
'o', ApplicationDelegate::eMenuID_ThreadStepOut)));
7633 MenuSP view_menu_sp(
7634 new Menu(
"View",
"F5", KEY_F(5), ApplicationDelegate::eMenuID_View));
7635 view_menu_sp->AddSubmenu(
7636 MenuSP(
new Menu(
"Backtrace",
nullptr,
't',
7637 ApplicationDelegate::eMenuID_ViewBacktrace)));
7638 view_menu_sp->AddSubmenu(
7639 MenuSP(
new Menu(
"Registers",
nullptr,
'r',
7640 ApplicationDelegate::eMenuID_ViewRegisters)));
7641 view_menu_sp->AddSubmenu(MenuSP(
new Menu(
7642 "Source",
nullptr,
's', ApplicationDelegate::eMenuID_ViewSource)));
7643 view_menu_sp->AddSubmenu(
7644 MenuSP(
new Menu(
"Variables",
nullptr,
'v',
7645 ApplicationDelegate::eMenuID_ViewVariables)));
7646 view_menu_sp->AddSubmenu(
7647 MenuSP(
new Menu(
"Breakpoints",
nullptr,
'b',
7648 ApplicationDelegate::eMenuID_ViewBreakpoints)));
7650 MenuSP help_menu_sp(
7651 new Menu(
"Help",
"F6", KEY_F(6), ApplicationDelegate::eMenuID_Help));
7652 help_menu_sp->AddSubmenu(MenuSP(
new Menu(
7653 "GUI Help",
nullptr,
'g', ApplicationDelegate::eMenuID_HelpGUIHelp)));
7656 WindowSP &main_window_sp =
m_app_ap->GetMainWindow();
7658 MenuSP menubar_sp(
new Menu(Menu::Type::Bar));
7659 menubar_sp->AddSubmenu(lldb_menu_sp);
7660 menubar_sp->AddSubmenu(target_menu_sp);
7661 menubar_sp->AddSubmenu(process_menu_sp);
7662 menubar_sp->AddSubmenu(thread_menu_sp);
7663 menubar_sp->AddSubmenu(view_menu_sp);
7664 menubar_sp->AddSubmenu(help_menu_sp);
7665 menubar_sp->SetDelegate(app_menu_delegate_sp);
7667 Rect content_bounds = main_window_sp->GetFrame();
7668 Rect menubar_bounds = content_bounds.MakeMenuBar();
7669 Rect status_bounds = content_bounds.MakeStatusBar();
7671 Rect variables_bounds;
7672 Rect threads_bounds;
7673 Rect source_variables_bounds;
7674 content_bounds.VerticalSplitPercentage(0.80, source_variables_bounds,
7676 source_variables_bounds.HorizontalSplitPercentage(0.70, source_bounds,
7679 WindowSP menubar_window_sp =
7680 main_window_sp->CreateSubWindow(
"Menubar", menubar_bounds,
false);
7683 menubar_window_sp->SetCanBeActive(
7685 menubar_window_sp->SetDelegate(menubar_sp);
7687 WindowSP source_window_sp(
7688 main_window_sp->CreateSubWindow(
"Source", source_bounds,
true));
7689 WindowSP variables_window_sp(
7690 main_window_sp->CreateSubWindow(
"Variables", variables_bounds,
false));
7691 WindowSP threads_window_sp(
7692 main_window_sp->CreateSubWindow(
"Threads", threads_bounds,
false));
7693 WindowSP status_window_sp(
7694 main_window_sp->CreateSubWindow(
"Status", status_bounds,
false));
7695 status_window_sp->SetCanBeActive(
7697 main_window_sp->SetDelegate(
7698 std::static_pointer_cast<WindowDelegate>(app_delegate_sp));
7699 source_window_sp->SetDelegate(
7700 WindowDelegateSP(
new SourceFileWindowDelegate(
m_debugger)));
7701 variables_window_sp->SetDelegate(
7702 WindowDelegateSP(
new FrameVariablesWindowDelegate(
m_debugger)));
7703 TreeDelegateSP thread_delegate_sp(
new ThreadsTreeDelegate(
m_debugger));
7704 threads_window_sp->SetDelegate(WindowDelegateSP(
7705 new TreeWindowDelegate(
m_debugger, thread_delegate_sp)));
7706 status_window_sp->SetDelegate(
7707 WindowDelegateSP(
new StatusBarWindowDelegate(
m_debugger)));
7710 init_pair(1, COLOR_BLACK, COLOR_BLACK);
7711 init_pair(2, COLOR_RED, COLOR_BLACK);
7712 init_pair(3, COLOR_GREEN, COLOR_BLACK);
7713 init_pair(4, COLOR_YELLOW, COLOR_BLACK);
7714 init_pair(5, COLOR_BLUE, COLOR_BLACK);
7715 init_pair(6, COLOR_MAGENTA, COLOR_BLACK);
7716 init_pair(7, COLOR_CYAN, COLOR_BLACK);
7717 init_pair(8, COLOR_WHITE, COLOR_BLACK);
7719 init_pair(9, COLOR_BLACK, COLOR_BLUE);
7720 init_pair(10, COLOR_RED, COLOR_BLUE);
7721 init_pair(11, COLOR_GREEN, COLOR_BLUE);
7722 init_pair(12, COLOR_YELLOW, COLOR_BLUE);
7723 init_pair(13, COLOR_BLUE, COLOR_BLUE);
7724 init_pair(14, COLOR_MAGENTA, COLOR_BLUE);
7725 init_pair(15, COLOR_CYAN, COLOR_BLUE);
7726 init_pair(16, COLOR_WHITE, COLOR_BLUE);
7728 init_pair(17, COLOR_BLACK, COLOR_WHITE);
7729 init_pair(18, COLOR_MAGENTA, COLOR_WHITE);
7730 static_assert(LastColorPairIndex == 18,
"Color indexes do not match.");
7732 define_key(
"\033[Z", KEY_SHIFT_TAB);
7733 define_key(
"\033\015", KEY_ALT_ENTER);
#define ANSI_CTRL_UNDERLINE
#define ANSI_FG_COLOR_BLACK
#define ANSI_FG_COLOR_WHITE
static llvm::raw_ostream & error(Stream &strm)
static llvm::StringRef GetName(XcodeSDK::Type type)
A section + offset based address range class.
A section + offset based address class.
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
An architecture specification class.
A command line argument class.
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.
A class that describes a single lexical block.
General Outline: Allows adding and removing breakpoints and find by ID and index.
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.
General Outline: A breakpoint has four main parts, a filter, a resolver, the list of breakpoint locat...
lldb::BreakpointLocationSP GetLocationAtIndex(size_t index)
Get breakpoint locations by index.
An event broadcasting class.
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)
bool IOHandlerInterrupt(IOHandler &io_handler) override
const FileSpec & GetPrimaryFile() const
Return the primary source spec associated with this compile unit.
"lldb/Utility/ArgCompletionRequest.h"
void GetMatches(StringList &matches) const
Adds all collected completion matches to the given list.
A uniqued constant string class.
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
void Dump(Stream *s, const char *value_if_empty=nullptr) const
Dump the object description to a stream.
void Clear()
Clear this object's state.
const char * GetCString() const
Get the string value as a C string.
A class to manage flag bits.
void CancelForwardEvents(const lldb::ListenerSP &listener_sp)
CommandInterpreter & GetCommandInterpreter()
void EnableForwardEvents(const lldb::ListenerSP &listener_sp)
PlatformList & GetPlatformList()
std::pair< iterator, bool > insert(llvm::StringRef KeyEqValue)
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
void SetFrameSP(const lldb::StackFrameSP &frame_sp)
Set accessor to set only the frame shared pointer.
bool HasThreadScope() const
Returns true the ExecutionContext object contains a valid target, process, and thread.
bool HasProcessScope() const
Returns true the ExecutionContext object contains a valid target and process.
StackFrame * GetFramePtr() const
Returns a pointer to the frame object.
Process & GetProcessRef() const
Returns a reference to the process object.
Target * GetTargetPtr() const
Returns a pointer to the target object.
bool HasTargetScope() const
Returns true the ExecutionContext object contains a valid target.
Target & GetTargetRef() const
Returns a reference to the target object.
Process * GetProcessPtr() const
Returns a pointer to the process object.
Thread & GetThreadRef() const
Returns a reference to the thread object.
Thread * GetThreadPtr() const
Returns a pointer to the thread object.
bool Open(int fd, const FileSpec &file_spec, bool read, bool write)
void SetFile(llvm::StringRef path, Style style)
Change the file specified with a new path.
void SetDirectory(ConstString directory)
Directory string set accessor.
const ConstString & GetFilename() const
Filename string const get accessor.
const ConstString & GetDirectory() const
Directory string const get accessor.
void Resolve(llvm::SmallVectorImpl< char > &path)
Resolve path to make it canonical.
static FileSystem & Instance()
ValueType Clear(ValueType mask=~static_cast< ValueType >(0))
Clear one or more flags.
ValueType Set(ValueType mask)
Set one or more flags by logical OR'ing mask with the current flags.
ConstString GetName() const
IOHandlerCursesGUI(Debugger &debugger)
void Deactivate() override
~IOHandlerCursesGUI() override
bool Interrupt() override
void TerminalSizeChanged() override
curses::ApplicationAP m_app_ap
uint32_t GetIndexOfInstructionAtAddress(const Address &addr)
lldb::InstructionSP GetInstructionAtIndex(size_t idx) const
const Address & GetAddress() const
const char * GetMnemonic(const ExecutionContext *exe_ctx, bool markup=false)
const char * GetComment(const ExecutionContext *exe_ctx)
const char * GetOperands(const ExecutionContext *exe_ctx, bool markup=false)
static lldb::ListenerSP MakeListener(const char *name)
static llvm::StringRef GetPlatformPluginNameAtIndex(uint32_t idx)
static llvm::StringRef GetProcessPluginNameAtIndex(uint32_t idx)
void SetContinueOnceAttached(bool b)
void SetWaitForLaunch(bool b)
void SetProcessPluginName(llvm::StringRef plugin)
bool GetContinueOnceAttached() const
void SetIgnoreExisting(bool b)
void SetExecutableFile(const FileSpec &exe_file, bool add_exe_file_as_first_arg)
void SetProcessID(lldb::pid_t pid)
FileSpec & GetExecutableFile()
Environment & GetEnvironment()
ArchSpec & GetArchitecture()
void SetShell(const FileSpec &shell)
void SetProcessPluginName(llvm::StringRef plugin)
void AppendFileAction(const FileAction &info)
void SetShellExpandArguments(bool expand)
void SetWorkingDirectory(const FileSpec &working_dir)
A plug-in interface definition class for debugging a process.
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
This base class provides an interface to stack frames.
VariableList * GetVariableList(bool get_file_globals, Status *error_ptr)
Retrieve the list of variables that are in scope at this StackFrame's pc.
lldb::RegisterContextSP GetRegisterContext()
Get the RegisterContext for this frame, if possible.
lldb::ValueObjectSP GetValueObjectForFrameVariable(const lldb::VariableSP &variable_sp, lldb::DynamicValueType use_dynamic)
Create a ValueObject for a given Variable in this StackFrame.
uint32_t GetFrameIndex() const
Query this frame to find what frame it is in this Thread's StackFrameList.
Block * GetFrameBlock()
Get the current lexical scope block for this StackFrame, if possible.
const Address & GetFrameCodeAddress()
Get an Address for the current pc value in this StackFrame.
bool Fail() const
Test for error condition.
const char * AsCString(const char *default_error_str="unknown error") const
Get the error string associated with the current error.
const char * GetData() const
llvm::StringRef GetString() const
void Format(const char *format, Args &&... args)
llvm::raw_ostream & AsRawOstream()
Returns a raw_ostream that forwards the data to this Stream object.
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
size_t size_t PrintfVarArg(const char *format, va_list args)
void AppendString(const std::string &s)
const char * GetStringAtIndex(size_t idx) const
"lldb/Symbol/SymbolContextScope.h" Inherit from this if your object is part of a symbol context and c...
Defines a symbol context baton that can be handed other debug core functions.
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.
A collection of ValueObject values that.
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)
A value object class that is seeded with the static variable value and it vends the user facing value...
lldb::ProcessSP GetProcessSP() const
lldb::ValueObjectSP GetSP()
Gets the correct value object from the root object for a given process stop ID.
lldb::ValueObjectSP GetSP()
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)
#define LLDB_INVALID_ADDRESS
@ 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.
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.
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
bool LLDB_API operator==(const SBAddress &lhs, const SBAddress &rhs)
std::shared_ptr< lldb_private::RegisterContext > RegisterContextSP
std::shared_ptr< lldb_private::Module > ModuleSP
A line table entry class.
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.