10 #include "lldb/Host/Config.h"
12 #if LLDB_ENABLE_CURSES
13 #if CURSES_HAVE_NCURSES_CURSES_H
14 #include <ncurses/curses.h>
15 #include <ncurses/panel.h>
22 #if defined(__APPLE__)
42 #if LLDB_ENABLE_CURSES
62 #include "llvm/ADT/StringRef.h"
78 #include <type_traits>
82 using llvm::StringRef;
85 #if LLDB_ENABLE_CURSES
92 #define KEY_DELETE 127
94 #define KEY_SHIFT_TAB (KEY_MAX + 1)
95 #define KEY_ALT_ENTER (KEY_MAX + 2)
101 class WindowDelegate;
102 typedef std::shared_ptr<Menu> MenuSP;
103 typedef std::shared_ptr<MenuDelegate> MenuDelegateSP;
104 typedef std::shared_ptr<Window> WindowSP;
105 typedef std::shared_ptr<WindowDelegate> WindowDelegateSP;
106 typedef std::vector<MenuSP> Menus;
107 typedef std::vector<WindowSP> Windows;
108 typedef std::vector<WindowDelegateSP> WindowDelegates;
111 type summary add -s
"x=${var.x}, y=${var.y}" curses::Point
112 type summary add -s
"w=${var.width}, h=${var.height}" curses::Size
113 type 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); }
136 bool operator==(
const Point &lhs,
const Point &rhs) {
137 return lhs.x == rhs.x && lhs.y == rhs.y;
140 bool 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); }
157 bool operator==(
const Size &lhs,
const Size &rhs) {
158 return lhs.width == rhs.width && lhs.height == rhs.height;
161 bool 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;
261 bool operator==(
const Rect &lhs,
const Rect &rhs) {
262 return lhs.origin == rhs.origin && lhs.size == rhs.size;
265 bool operator!=(
const Rect &lhs,
const Rect &rhs) {
266 return lhs.origin != rhs.origin || lhs.size != rhs.size;
269 enum HandleCharResult {
275 enum class MenuActionResult {
283 const char *description;
309 LastColorPairIndex = MagentaOnWhite
312 class 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; }
329 class 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, ...)
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;
562 class Pad :
public Surface {
564 Pad(Size size) : Surface(Surface::
Type::Pad) {
565 m_window = ::newpad(size.height, size.width);
568 ~Pad() { ::delwin(m_window); }
571 class 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;
981 Window(
const Window &) =
delete;
982 const Window &operator=(
const Window &) =
delete;
993 struct ScrollContext {
997 ScrollContext(
int line) : start(line), end(line) {}
998 ScrollContext(
int _start,
int _end) : start(_start), end(_end) {}
1000 void Offset(
int offset) {
1006 class 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;
1076 typedef std::unique_ptr<FieldDelegate> FieldDelegateUP;
1078 class 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(); }
1312 const std::string &GetText() {
return m_content; }
1314 void SetText(
const char *text) {
1315 if (text ==
nullptr) {
1329 int m_cursor_position = 0;
1331 int m_first_visibile_char = 0;
1336 class 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); }
1348 class 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();
1364 if (!FileSystem::Instance().Exists(file)) {
1368 if (FileSystem::Instance().IsDirectory(file)) {
1381 FileSystem::Instance().Resolve(file_spec);
1385 const std::string &GetPath() {
return m_content; }
1388 bool m_need_to_exist;
1391 class 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();
1407 if (!FileSystem::Instance().Exists(file)) {
1408 SetError(
"Directory doesn't exist!");
1411 if (!FileSystem::Instance().IsDirectory(file)) {
1424 FileSystem::Instance().Resolve(file_spec);
1428 const std::string &GetPath() {
return m_content; }
1431 bool m_need_to_exist;
1434 class 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())
1448 const std::string &GetArchString() {
return m_content; }
1453 class 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; }
1514 class 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]) {
1624 int m_number_of_visible_choices;
1625 std::vector<std::string> m_choices;
1629 int m_first_visibile_choice = 0;
1632 class 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 =
1645 PluginManager::GetPlatformPluginNameAtIndex(i++);
1646 !name.empty(); name = PluginManager::GetProcessPluginNameAtIndex(i++))
1647 names.push_back(name.str());
1657 class 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>");
1667 for (llvm::StringRef name = PluginManager::GetProcessPluginNameAtIndex(i++);
1668 !name.empty(); name = PluginManager::GetProcessPluginNameAtIndex(i++))
1669 names.push_back(name.str());
1675 if (plugin_name ==
"<default>")
1681 class 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);
1701 else if (choice == kYes)
1708 template <
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]; }
2014 std::vector<T> m_fields;
2015 int m_selection_index = 0;
2017 SelectionType m_selection_type;
2020 class 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);
2043 template <
class KeyFieldDelegateType,
class ValueFieldDelegateType>
2044 class 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;
2198 class 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 !=
'=';
2211 class EnvironmentVariableFieldDelegate
2212 :
public MappingFieldDelegate<EnvironmentVariableNameFieldDelegate,
2213 TextFieldDelegate> {
2215 EnvironmentVariableFieldDelegate()
2216 : MappingFieldDelegate(
2217 EnvironmentVariableNameFieldDelegate(
""),
2218 TextFieldDelegate(
"Value",
"", false)) {}
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); }
2229 class 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); }
2282 std::function<void(Window &)> m_action;
2285 class FormDelegate {
2287 FormDelegate() =
default;
2289 virtual ~FormDelegate() =
default;
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(); }
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;
2465 typedef std::shared_ptr<FormDelegate> FormDelegateSP;
2467 class 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;
2869 class 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); });
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;
2906 class 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;
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); });
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();
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)
2993 TargetSP new_target_sp;
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;
3074 class 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); });
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_depentents_options;
3116 load_depentents_options.push_back(kLoadDependentFilesExecOnly);
3117 load_depentents_options.push_back(kLoadDependentFilesYes);
3118 load_depentents_options.push_back(kLoadDependentFilesNo);
3119 return load_depentents_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;
3137 TargetSP GetTarget() {
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(
"Unable to find process plug-in for core file!");
3185 Status status = process_sp->LoadCore();
3186 if (status.
Fail()) {
3187 SetError(
"Can't find plug-in for core file!");
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)
3215 TargetSP target_sp = GetTarget();
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;
3253 class 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); });
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);
3376 TargetSP target = m_debugger.GetSelectedTarget();
3377 if (target ==
nullptr)
3380 PlatformSP platform = target->GetPlatform();
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();
3480 PlatformSP platform_sp =
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) {
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;
3647 class 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;
3667 typedef std::shared_ptr<SearcherDelegate> SearcherDelegateSP;
3669 class 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;
3824 class 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 {
3842 CommandCompletions::InvokeCommonCompletionCallbacks(
3843 m_debugger.GetCommandInterpreter(), m_completion_mask, request,
3848 void ExecuteCallback(
int match_index)
override {
3849 m_callback(m_matches[match_index]);
3858 CallbackType m_callback;
3866 class MenuDelegate {
3868 virtual ~MenuDelegate() =
default;
3870 virtual MenuActionResult MenuDelegateAction(Menu &menu) = 0;
3873 class 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; }
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; }
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;
3970 Menu::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),
3978 Menu::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;
3995 void 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();
4010 void 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);
4020 void 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));
4079 bool 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:
4128 HandleCharResult 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);
4302 ListenerSP listener_sp(
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;
4493 bool might_have_children;
4494 bool expanded =
false;
4495 bool calculated_children =
false;
4496 std::vector<Row> children;
4498 Row(
const ValueObjectSP &v, Row *p)
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;
4520 ValueObjectSP valobj = value.
GetSP();
4522 const size_t num_children = valobj->GetNumChildren();
4523 for (
size_t i = 0; i < num_children; ++i) {
4524 children.push_back(Row(valobj->GetChildAtIndex(i,
true),
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(
' ');
4590 struct DisplayOptions {
4596 class TreeDelegate {
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; }
4615 typedef std::shared_ptr<TreeDelegate> TreeDelegateSP;
4619 TreeItem(TreeItem *parent, TreeDelegate &delegate,
bool might_have_children)
4620 : m_parent(parent), m_delegate(delegate), m_children(),
4621 m_might_have_children(might_have_children) {
4622 if (m_parent ==
nullptr)
4623 m_is_expanded = m_delegate.TreeDelegateExpandRootByDefault();
4626 TreeItem &operator=(
const TreeItem &rhs) {
4628 m_parent = rhs.m_parent;
4629 m_delegate = rhs.m_delegate;
4630 m_user_data = rhs.m_user_data;
4631 m_identifier = rhs.m_identifier;
4632 m_row_idx = rhs.m_row_idx;
4633 m_children = rhs.m_children;
4634 m_might_have_children = rhs.m_might_have_children;
4635 m_is_expanded = rhs.m_is_expanded;
4640 TreeItem(
const TreeItem &) =
default;
4642 size_t GetDepth()
const {
4644 return 1 + m_parent->GetDepth();
4648 int GetRowIndex()
const {
return m_row_idx; }
4650 void ClearChildren() { m_children.clear(); }
4652 void Resize(
size_t n,
const TreeItem &t) { m_children.resize(n, t); }
4654 TreeItem &operator[](
size_t i) {
return m_children[i]; }
4656 void SetRowIndex(
int row_idx) { m_row_idx = row_idx; }
4658 size_t GetNumChildren() {
4659 m_delegate.TreeDelegateGenerateChildren(*
this);
4660 return m_children.size();
4663 void ItemWasSelected() { m_delegate.TreeDelegateItemSelected(*
this); }
4665 void CalculateRowIndexes(
int &row_idx) {
4666 SetRowIndex(row_idx);
4669 const bool expanded = IsExpanded();
4673 if (m_parent ==
nullptr || expanded)
4676 for (
auto &item : m_children) {
4678 item.CalculateRowIndexes(row_idx);
4680 item.SetRowIndex(-1);
4684 TreeItem *GetParent() {
return m_parent; }
4686 bool IsExpanded()
const {
return m_is_expanded; }
4688 void Expand() { m_is_expanded =
true; }
4690 void Unexpand() { m_is_expanded =
false; }
4692 bool Draw(Window &window,
const int first_visible_row,
4693 const uint32_t selected_row_idx,
int &row_idx,
int &num_rows_left) {
4694 if (num_rows_left <= 0)
4697 if (m_row_idx >= first_visible_row) {
4698 window.MoveCursor(2, row_idx + 1);
4701 m_parent->DrawTreeForChild(window,
this, 0);
4703 if (m_might_have_children) {
4721 window.PutChar(ACS_DIAMOND);
4722 window.PutChar(ACS_HLINE);
4724 bool highlight = (selected_row_idx ==
static_cast<size_t>(m_row_idx)) &&
4728 window.AttributeOn(A_REVERSE);
4730 m_delegate.TreeDelegateDrawTreeItem(*
this, window);
4733 window.AttributeOff(A_REVERSE);
4738 if (num_rows_left <= 0)
4742 for (
auto &item : m_children) {
4745 if (!item.Draw(window, first_visible_row, selected_row_idx, row_idx,
4750 return num_rows_left >= 0;
4753 void DrawTreeForChild(Window &window, TreeItem *child,
4756 m_parent->DrawTreeForChild(window,
this, reverse_depth + 1);
4758 if (&m_children.back() == child) {
4760 if (reverse_depth == 0) {
4761 window.PutChar(ACS_LLCORNER);
4762 window.PutChar(ACS_HLINE);
4764 window.PutChar(
' ');
4765 window.PutChar(
' ');
4768 if (reverse_depth == 0) {
4769 window.PutChar(ACS_LTEE);
4770 window.PutChar(ACS_HLINE);
4772 window.PutChar(ACS_VLINE);
4773 window.PutChar(
' ');
4778 TreeItem *GetItemForRowIndex(
uint32_t row_idx) {
4779 if (
static_cast<uint32_t>(m_row_idx) == row_idx)
4781 if (m_children.empty())
4784 for (
auto &item : m_children) {
4785 TreeItem *selected_item_ptr = item.GetItemForRowIndex(row_idx);
4786 if (selected_item_ptr)
4787 return selected_item_ptr;
4793 void *GetUserData()
const {
return m_user_data; }
4795 void SetUserData(
void *user_data) { m_user_data = user_data; }
4797 uint64_t GetIdentifier()
const {
return m_identifier; }
4799 void SetIdentifier(uint64_t identifier) { m_identifier = identifier; }
4801 const std::string &GetText()
const {
return m_text; }
4803 void SetText(
const char *text) {
4804 if (text ==
nullptr) {
4811 void SetMightHaveChildren(
bool b) { m_might_have_children = b; }
4815 TreeDelegate &m_delegate;
4816 void *m_user_data =
nullptr;
4817 uint64_t m_identifier = 0;
4821 std::vector<TreeItem> m_children;
4822 bool m_might_have_children;
4823 bool m_is_expanded =
false;
4826 class TreeWindowDelegate :
public WindowDelegate {
4828 TreeWindowDelegate(
Debugger &debugger,
const TreeDelegateSP &delegate_sp)
4829 : m_debugger(debugger), m_delegate_sp(delegate_sp),
4830 m_root(nullptr, *delegate_sp, true) {}
4832 int NumVisibleRows()
const {
return m_max_y - m_min_y; }
4834 bool WindowDelegateDraw(Window &window,
bool force)
override {
4837 m_max_x = window.GetWidth() - 1;
4838 m_max_y = window.GetHeight() - 1;
4841 window.DrawTitleBox(window.GetName());
4843 if (!m_delegate_sp->TreeDelegateShouldDraw()) {
4844 m_selected_item =
nullptr;
4848 const int num_visible_rows = NumVisibleRows();
4850 m_root.CalculateRowIndexes(m_num_rows);
4851 m_delegate_sp->TreeDelegateUpdateSelection(m_root, m_selected_row_idx,
4857 if (m_first_visible_row > 0 && m_num_rows < num_visible_rows)
4858 m_first_visible_row = 0;
4861 if (m_selected_row_idx < m_first_visible_row)
4862 m_first_visible_row = m_selected_row_idx;
4863 else if (m_first_visible_row + num_visible_rows <= m_selected_row_idx)
4864 m_first_visible_row = m_selected_row_idx - num_visible_rows + 1;
4867 int num_rows_left = num_visible_rows;
4868 m_root.Draw(window, m_first_visible_row, m_selected_row_idx, row_idx,
4871 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4876 const char *WindowDelegateGetHelpText()
override {
4877 return "Thread window keyboard shortcuts:";
4880 KeyHelp *WindowDelegateGetKeyHelp()
override {
4881 static curses::KeyHelp g_source_view_key_help[] = {
4882 {KEY_UP,
"Select previous item"},
4883 {KEY_DOWN,
"Select next item"},
4884 {KEY_RIGHT,
"Expand the selected item"},
4886 "Unexpand the selected item or select parent if not expanded"},
4887 {KEY_PPAGE,
"Page up"},
4888 {KEY_NPAGE,
"Page down"},
4889 {
'h',
"Show help dialog"},
4890 {
' ',
"Toggle item expansion"},
4894 return g_source_view_key_help;
4897 HandleCharResult WindowDelegateHandleChar(Window &window,
int c)
override {
4902 if (m_first_visible_row > 0) {
4903 if (m_first_visible_row > m_max_y)
4904 m_first_visible_row -= m_max_y;
4906 m_first_visible_row = 0;
4907 m_selected_row_idx = m_first_visible_row;
4908 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4909 if (m_selected_item)
4910 m_selected_item->ItemWasSelected();
4917 if (m_num_rows > m_max_y) {
4918 if (m_first_visible_row + m_max_y < m_num_rows) {
4919 m_first_visible_row += m_max_y;
4920 m_selected_row_idx = m_first_visible_row;
4921 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4922 if (m_selected_item)
4923 m_selected_item->ItemWasSelected();
4929 if (m_selected_row_idx > 0) {
4930 --m_selected_row_idx;
4931 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4932 if (m_selected_item)
4933 m_selected_item->ItemWasSelected();
4938 if (m_selected_row_idx + 1 < m_num_rows) {
4939 ++m_selected_row_idx;
4940 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4941 if (m_selected_item)
4942 m_selected_item->ItemWasSelected();
4947 if (m_selected_item) {
4948 if (!m_selected_item->IsExpanded())
4949 m_selected_item->Expand();
4954 if (m_selected_item) {
4955 if (m_selected_item->IsExpanded())
4956 m_selected_item->Unexpand();
4957 else if (m_selected_item->GetParent()) {
4958 m_selected_row_idx = m_selected_item->GetParent()->GetRowIndex();
4959 m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
4960 if (m_selected_item)
4961 m_selected_item->ItemWasSelected();
4968 if (m_selected_item) {
4969 if (m_selected_item->IsExpanded())
4970 m_selected_item->Unexpand();
4972 m_selected_item->Expand();
4977 window.CreateHelpSubwindow();
4983 return eKeyNotHandled;
4988 TreeDelegateSP m_delegate_sp;
4990 TreeItem *m_selected_item =
nullptr;
4992 int m_selected_row_idx = 0;
4993 int m_first_visible_row = 0;
5002 class TextTreeDelegate :
public TreeDelegate {
5004 TextTreeDelegate() : TreeDelegate() {}
5006 ~TextTreeDelegate()
override =
default;
5008 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5009 window.PutCStringTruncated(1, item.GetText().c_str());
5012 void TreeDelegateGenerateChildren(TreeItem &item)
override {}
5014 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5017 class FrameTreeDelegate :
public TreeDelegate {
5019 FrameTreeDelegate() : TreeDelegate() {
5020 FormatEntity::Parse(
5021 "#${frame.index}: {${function.name}${function.pc-offset}}}", m_format);
5024 ~FrameTreeDelegate()
override =
default;
5026 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5029 const uint64_t frame_idx = item.GetIdentifier();
5034 frame_sp->GetSymbolContext(eSymbolContextEverything);
5037 nullptr,
false,
false)) {
5039 window.PutCStringTruncated(right_pad, strm.
GetString().str().c_str());
5045 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5049 bool TreeDelegateItemSelected(TreeItem &item)
override {
5052 thread->
GetProcess()->GetThreadList().SetSelectedThreadByID(
5054 const uint64_t frame_idx = item.GetIdentifier();
5065 class ThreadTreeDelegate :
public TreeDelegate {
5067 ThreadTreeDelegate(
Debugger &debugger)
5068 : TreeDelegate(), m_debugger(debugger) {
5069 FormatEntity::Parse(
"thread #${thread.index}: tid = ${thread.id}{, stop "
5070 "reason = ${thread.stop-reason}}",
5074 ~ThreadTreeDelegate()
override =
default;
5076 ProcessSP GetProcess() {
5077 return m_debugger.GetCommandInterpreter()
5078 .GetExecutionContext()
5082 ThreadSP GetThread(
const TreeItem &item) {
5083 ProcessSP process_sp = GetProcess();
5085 return process_sp->GetThreadList().FindThreadByID(item.GetIdentifier());
5089 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5090 ThreadSP thread_sp = GetThread(item);
5095 nullptr,
false,
false)) {
5097 window.PutCStringTruncated(right_pad, strm.
GetString().str().c_str());
5102 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5103 ProcessSP process_sp = GetProcess();
5104 if (process_sp && process_sp->IsAlive()) {
5105 StateType state = process_sp->GetState();
5107 ThreadSP thread_sp = GetThread(item);
5109 if (m_stop_id == process_sp->GetStopID() &&
5110 thread_sp->GetID() == m_tid)
5112 if (!m_frame_delegate_sp) {
5114 m_frame_delegate_sp = std::make_shared<FrameTreeDelegate>();
5117 m_stop_id = process_sp->GetStopID();
5118 m_tid = thread_sp->GetID();
5120 TreeItem t(&item, *m_frame_delegate_sp,
false);
5121 size_t num_frames = thread_sp->GetStackFrameCount();
5122 item.Resize(num_frames, t);
5123 for (
size_t i = 0; i < num_frames; ++i) {
5124 item[i].SetUserData(thread_sp.get());
5125 item[i].SetIdentifier(i);
5131 item.ClearChildren();
5134 bool TreeDelegateItemSelected(TreeItem &item)
override {
5135 ProcessSP process_sp = GetProcess();
5136 if (process_sp && process_sp->IsAlive()) {
5137 StateType state = process_sp->GetState();
5139 ThreadSP thread_sp = GetThread(item);
5141 ThreadList &thread_list = thread_sp->GetProcess()->GetThreadList();
5142 std::lock_guard<std::recursive_mutex> guard(thread_list.
GetMutex());
5144 if (selected_thread_sp->GetID() != thread_sp->GetID()) {
5156 std::shared_ptr<FrameTreeDelegate> m_frame_delegate_sp;
5162 class ThreadsTreeDelegate :
public TreeDelegate {
5164 ThreadsTreeDelegate(
Debugger &debugger)
5165 : TreeDelegate(), m_thread_delegate_sp(), m_debugger(debugger) {
5166 FormatEntity::Parse(
"process ${process.id}{, name = ${process.name}}",
5170 ~ThreadsTreeDelegate()
override =
default;
5172 ProcessSP GetProcess() {
5173 return m_debugger.GetCommandInterpreter()
5174 .GetExecutionContext()
5178 bool TreeDelegateShouldDraw()
override {
5179 ProcessSP process = GetProcess();
5189 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5190 ProcessSP process_sp = GetProcess();
5191 if (process_sp && process_sp->IsAlive()) {
5195 nullptr,
false,
false)) {
5197 window.PutCStringTruncated(right_pad, strm.
GetString().str().c_str());
5202 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5203 ProcessSP process_sp = GetProcess();
5204 m_update_selection =
false;
5205 if (process_sp && process_sp->IsAlive()) {
5206 StateType state = process_sp->GetState();
5208 const uint32_t stop_id = process_sp->GetStopID();
5209 if (m_stop_id == stop_id)
5212 m_stop_id = stop_id;
5213 m_update_selection =
true;
5215 if (!m_thread_delegate_sp) {
5218 m_thread_delegate_sp =
5219 std::make_shared<ThreadTreeDelegate>(m_debugger);
5222 TreeItem t(&item, *m_thread_delegate_sp,
false);
5223 ThreadList &threads = process_sp->GetThreadList();
5224 std::lock_guard<std::recursive_mutex> guard(threads.
GetMutex());
5226 size_t num_threads = threads.
GetSize();
5227 item.Resize(num_threads, t);
5228 for (
size_t i = 0; i < num_threads; ++i) {
5230 item[i].SetIdentifier(thread->GetID());
5231 item[i].SetMightHaveChildren(
true);
5232 if (selected_thread->GetID() == thread->GetID())
5238 item.ClearChildren();
5241 void TreeDelegateUpdateSelection(TreeItem &root,
int &selection_index,
5242 TreeItem *&selected_item)
override {
5243 if (!m_update_selection)
5246 ProcessSP process_sp = GetProcess();
5247 if (!(process_sp && process_sp->IsAlive()))
5250 StateType state = process_sp->GetState();
5254 ThreadList &threads = process_sp->GetThreadList();
5255 std::lock_guard<std::recursive_mutex> guard(threads.
GetMutex());
5257 size_t num_threads = threads.
GetSize();
5258 for (
size_t i = 0; i < num_threads; ++i) {
5260 if (selected_thread->GetID() == thread->GetID()) {
5261 selected_item = &root[i][thread->GetSelectedFrameIndex()];
5262 selection_index = selected_item->GetRowIndex();
5268 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5270 bool TreeDelegateExpandRootByDefault()
override {
return true; }
5273 std::shared_ptr<ThreadTreeDelegate> m_thread_delegate_sp;
5276 bool m_update_selection =
false;
5280 class BreakpointLocationTreeDelegate :
public TreeDelegate {
5282 BreakpointLocationTreeDelegate(
Debugger &debugger)
5283 : TreeDelegate(), m_debugger(debugger) {}
5285 ~BreakpointLocationTreeDelegate()
override =
default;
5289 m_debugger.GetCommandInterpreter().GetExecutionContext());
5293 BreakpointLocationSP GetBreakpointLocation(
const TreeItem &item) {
5298 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5299 BreakpointLocationSP breakpoint_location = GetBreakpointLocation(item);
5300 Process *process = GetProcess();
5302 stream.
Printf(
"%i.%i: ", breakpoint_location->GetBreakpoint().GetID(),
5303 breakpoint_location->GetID());
5304 Address address = breakpoint_location->GetAddress();
5305 address.
Dump(&stream, process, Address::DumpStyleResolvedDescription,
5306 Address::DumpStyleInvalid);
5307 window.PutCStringTruncated(1, stream.
GetString().str().c_str());
5310 StringList ComputeDetailsList(BreakpointLocationSP breakpoint_location) {
5313 Address address = breakpoint_location->GetAddress();
5320 symbol_context.
module_sp->GetFileSpec().Dump(
5325 if (symbol_context.
comp_unit !=
nullptr) {
5327 compile_unit_stream.
PutCString(
"compile unit = ");
5329 &compile_unit_stream);
5332 if (symbol_context.
function !=
nullptr) {
5348 if (symbol_context.
symbol) {
5350 if (breakpoint_location->IsReExported())
5351 symbol_stream.
PutCString(
"re-exported target = ");
5360 Process *process = GetProcess();
5363 address.
Dump(&address_stream, process, Address::DumpStyleLoadAddress,
5364 Address::DumpStyleModuleWithFileAddress);
5367 BreakpointSiteSP breakpoint_site = breakpoint_location->GetBreakpointSite();
5368 if (breakpoint_location->IsIndirect() && breakpoint_site) {
5370 resolved_address.
SetLoadAddress(breakpoint_site->GetLoadAddress(),
5371 &breakpoint_location->GetTarget());
5373 if (resolved_symbol) {
5375 indirect_target_stream.
PutCString(
"indirect target = ");
5382 bool is_resolved = breakpoint_location->IsResolved();
5384 resolved_stream.
Printf(
"resolved = %s", is_resolved ?
"true" :
"false");
5387 bool is_hardware = is_resolved && breakpoint_site->IsHardware();
5389 hardware_stream.
Printf(
"hardware = %s", is_hardware ?
"true" :
"false");
5393 hit_count_stream.
Printf(
"hit count = %-4u",
5394 breakpoint_location->GetHitCount());
5400 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5401 BreakpointLocationSP breakpoint_location = GetBreakpointLocation(item);
5402 StringList details = ComputeDetailsList(breakpoint_location);
5404 if (!m_string_delegate_sp)
5405 m_string_delegate_sp = std::make_shared<TextTreeDelegate>();
5406 TreeItem details_tree_item(&item, *m_string_delegate_sp,
false);
5408 item.Resize(details.
GetSize(), details_tree_item);
5409 for (
size_t i = 0; i < details.
GetSize(); i++) {
5414 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5418 std::shared_ptr<TextTreeDelegate> m_string_delegate_sp;
5421 class BreakpointTreeDelegate :
public TreeDelegate {
5423 BreakpointTreeDelegate(
Debugger &debugger)
5424 : TreeDelegate(), m_debugger(debugger),
5425 m_breakpoint_location_delegate_sp() {}
5427 ~BreakpointTreeDelegate()
override =
default;
5429 BreakpointSP GetBreakpoint(
const TreeItem &item) {
5430 TargetSP target = m_debugger.GetSelectedTarget();
5435 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5436 BreakpointSP breakpoint = GetBreakpoint(item);
5438 stream.
Format(
"{0}: ", breakpoint->GetID());
5439 breakpoint->GetResolverDescription(&stream);
5440 breakpoint->GetFilterDescription(&stream);
5441 window.PutCStringTruncated(1, stream.
GetString().str().c_str());
5444 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5445 BreakpointSP breakpoint = GetBreakpoint(item);
5447 if (!m_breakpoint_location_delegate_sp)
5448 m_breakpoint_location_delegate_sp =
5449 std::make_shared<BreakpointLocationTreeDelegate>(m_debugger);
5450 TreeItem breakpoint_location_tree_item(
5451 &item, *m_breakpoint_location_delegate_sp,
true);
5453 item.Resize(breakpoint->GetNumLocations(), breakpoint_location_tree_item);
5454 for (
size_t i = 0; i < breakpoint->GetNumLocations(); i++) {
5455 item[i].SetIdentifier(i);
5456 item[i].SetUserData(breakpoint.get());
5460 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5464 std::shared_ptr<BreakpointLocationTreeDelegate>
5465 m_breakpoint_location_delegate_sp;
5468 class BreakpointsTreeDelegate :
public TreeDelegate {
5470 BreakpointsTreeDelegate(
Debugger &debugger)
5471 : TreeDelegate(), m_debugger(debugger), m_breakpoint_delegate_sp() {}
5473 ~BreakpointsTreeDelegate()
override =
default;
5475 bool TreeDelegateShouldDraw()
override {
5476 TargetSP target = m_debugger.GetSelectedTarget();
5483 void TreeDelegateDrawTreeItem(TreeItem &item, Window &window)
override {
5484 window.PutCString(
"Breakpoints");
5487 void TreeDelegateGenerateChildren(TreeItem &item)
override {
5488 TargetSP target = m_debugger.GetSelectedTarget();
5491 std::unique_lock<std::recursive_mutex> lock;
5494 if (!m_breakpoint_delegate_sp)
5495 m_breakpoint_delegate_sp =
5496 std::make_shared<BreakpointTreeDelegate>(m_debugger);
5497 TreeItem breakpoint_tree_item(&item, *m_breakpoint_delegate_sp,
true);
5499 item.Resize(breakpoints.
GetSize(), breakpoint_tree_item);
5500 for (
size_t i = 0; i < breakpoints.
GetSize(); i++) {
5501 item[i].SetIdentifier(i);
5505 bool TreeDelegateItemSelected(TreeItem &item)
override {
return false; }
5507 bool TreeDelegateExpandRootByDefault()
override {
return true; }
5511 std::shared_ptr<BreakpointTreeDelegate> m_breakpoint_delegate_sp;
5514 class ValueObjectListDelegate :
public WindowDelegate {
5516 ValueObjectListDelegate() : m_rows() {}
5519 SetValues(valobj_list);
5522 ~ValueObjectListDelegate()
override =
default;
5525 m_selected_row =
nullptr;
5526 m_selected_row_idx = 0;
5527 m_first_visible_row = 0;
5530 for (
auto &valobj_sp : valobj_list.
GetObjects())
5531 m_rows.push_back(Row(valobj_sp,
nullptr));
5534 bool WindowDelegateDraw(Window &window,
bool force)
override {
5538 m_max_x = window.GetWidth() - 1;
5539 m_max_y = window.GetHeight() - 1;
5542 window.DrawTitleBox(window.GetName());
5544 const int num_visible_rows = NumVisibleRows();
5545 const int num_rows = CalculateTotalNumberRows(m_rows);
5550 if (m_first_visible_row > 0 && num_rows < num_visible_rows)
5551 m_first_visible_row = 0;
5554 if (m_selected_row_idx < m_first_visible_row)
5555 m_first_visible_row = m_selected_row_idx;
5556 else if (m_first_visible_row + num_visible_rows <= m_selected_row_idx)
5557 m_first_visible_row = m_selected_row_idx - num_visible_rows + 1;
5559 DisplayRows(window, m_rows, g_options);
5562 m_selected_row = GetRowForRowIndex(m_selected_row_idx);
5566 window.MoveCursor(m_selected_row->x, m_selected_row->y);
5571 KeyHelp *WindowDelegateGetKeyHelp()
override {
5572 static curses::KeyHelp g_source_view_key_help[] = {
5573 {KEY_UP,
"Select previous item"},
5574 {KEY_DOWN,
"Select next item"},
5575 {KEY_RIGHT,
"Expand selected item"},
5576 {KEY_LEFT,
"Unexpand selected item or select parent if not expanded"},
5577 {KEY_PPAGE,
"Page up"},
5578 {KEY_NPAGE,
"Page down"},
5579 {
'A',
"Format as annotated address"},
5580 {
'b',
"Format as binary"},
5581 {
'B',
"Format as hex bytes with ASCII"},
5582 {
'c',
"Format as character"},
5583 {
'd',
"Format as a signed integer"},
5584 {
'D',
"Format selected value using the default format for the type"},
5585 {
'f',
"Format as float"},
5586 {
'h',
"Show help dialog"},
5587 {
'i',
"Format as instructions"},
5588 {
'o',
"Format as octal"},
5589 {
'p',
"Format as pointer"},
5590 {
's',
"Format as C string"},
5591 {
't',
"Toggle showing/hiding type names"},
5592 {
'u',
"Format as an unsigned integer"},
5593 {
'x',
"Format as hex"},
5594 {
'X',
"Format as uppercase hex"},
5595 {
' ',
"Toggle item expansion"},
5599 return g_source_view_key_help;
5602 HandleCharResult WindowDelegateHandleChar(Window &window,
int c)
override {
5619 if (m_selected_row) {
5620 auto valobj_sp = m_selected_row->value.GetSP();
5622 valobj_sp->SetFormat(FormatForChar(c));
5628 g_options.show_types = !g_options.show_types;
5634 if (m_first_visible_row > 0) {
5635 if (
static_cast<int>(m_first_visible_row) > m_max_y)
5636 m_first_visible_row -= m_max_y;
5638 m_first_visible_row = 0;
5639 m_selected_row_idx = m_first_visible_row;
5646 if (m_num_rows >
static_cast<size_t>(m_max_y)) {
5647 if (m_first_visible_row + m_max_y < m_num_rows) {
5648 m_first_visible_row += m_max_y;
5649 m_selected_row_idx = m_first_visible_row;
5655 if (m_selected_row_idx > 0)
5656 --m_selected_row_idx;
5660 if (m_selected_row_idx + 1 < m_num_rows)
5661 ++m_selected_row_idx;
5665 if (m_selected_row) {
5666 if (!m_selected_row->expanded)
5667 m_selected_row->Expand();
5672 if (m_selected_row) {
5673 if (m_selected_row->expanded)
5674 m_selected_row->Unexpand();
5675 else if (m_selected_row->parent)
5676 m_selected_row_idx = m_selected_row->parent->row_idx;
5682 if (m_selected_row) {
5683 if (m_selected_row->expanded)
5684 m_selected_row->Unexpand();
5686 m_selected_row->Expand();
5691 window.CreateHelpSubwindow();
5697 return eKeyNotHandled;
5701 std::vector<Row> m_rows;
5702 Row *m_selected_row =
nullptr;
5711 static Format FormatForChar(
int c) {
5745 bool DisplayRowObject(Window &window, Row &row, DisplayOptions &options,
5746 bool highlight,
bool last_child) {
5749 if (valobj ==
nullptr)
5752 const char *type_name =
5758 window.MoveCursor(row.x, row.y);
5760 row.DrawTree(window);
5763 window.AttributeOn(A_REVERSE);
5765 if (type_name && type_name[0])
5766 window.PrintfTruncated(1,
"(%s) ", type_name);
5768 if (name && name[0])
5769 window.PutCStringTruncated(1, name);
5771 attr_t changd_attr = 0;
5773 changd_attr = COLOR_PAIR(RedOnBlack) | A_BOLD;
5775 if (value && value[0]) {
5776 window.PutCStringTruncated(1,
" = ");
5778 window.AttributeOn(changd_attr);
5779 window.PutCStringTruncated(1, value);
5781 window.AttributeOff(changd_attr);
5784 if (summary && summary[0]) {
5785 window.PutCStringTruncated(1,
" ");
5787 window.AttributeOn(changd_attr);
5788 window.PutCStringTruncated(1, summary);
5790 window.AttributeOff(changd_attr);
5794 window.AttributeOff(A_REVERSE);
5799 void DisplayRows(Window &window, std::vector<Row> &rows,
5800 DisplayOptions &options) {
5804 bool window_is_active = window.IsActive();
5805 for (
auto &row : rows) {
5806 const bool last_child = row.parent && &rows[rows.size() - 1] == &row;
5808 row.row_idx = m_num_rows;
5809 if ((m_num_rows >= m_first_visible_row) &&
5810 ((m_num_rows - m_first_visible_row) <
5811 static_cast<size_t>(NumVisibleRows()))) {
5813 row.y = m_num_rows - m_first_visible_row + 1;
5814 if (DisplayRowObject(window, row, options,
5816 m_num_rows == m_selected_row_idx,
5830 auto &children = row.GetChildren();
5831 if (!children.empty()) {
5832 DisplayRows(window, children, options);
5838 int CalculateTotalNumberRows(std::vector<Row> &rows) {
5840 for (
auto &row : rows) {
5843 row_count += CalculateTotalNumberRows(row.GetChildren());
5848 static Row *GetRowForRowIndexImpl(std::vector<Row> &rows,
size_t &row_index) {
5849 for (
auto &row : rows) {
5855 auto &children = row.GetChildren();
5856 if (!children.empty()) {
5857 Row *result = GetRowForRowIndexImpl(children, row_index);
5867 Row *GetRowForRowIndex(
size_t row_index) {
5868 return GetRowForRowIndexImpl(m_rows, row_index);
5871 int NumVisibleRows()
const {
return m_max_y - m_min_y; }
5873 static DisplayOptions g_options;
5876 class FrameVariablesWindowDelegate :
public ValueObjectListDelegate {
5878 FrameVariablesWindowDelegate(
Debugger &debugger)
5879 : ValueObjectListDelegate(), m_debugger(debugger) {}
5881 ~FrameVariablesWindowDelegate()
override =
default;
5883 const char *WindowDelegateGetHelpText()
override {
5884 return "Frame variable window keyboard shortcuts:";
5887 bool WindowDelegateDraw(Window &window,
bool force)
override {
5889 m_debugger.GetCommandInterpreter().GetExecutionContext());
5891 Block *frame_block =
nullptr;
5908 if (m_frame_block != frame_block) {
5909 m_frame_block = frame_block;
5914 for (
const VariableSP &local_sp : *locals) {
5915 ValueObjectSP value_sp =
5918 ValueObjectSP synthetic_value_sp = value_sp->GetSyntheticValue();
5919 if (synthetic_value_sp)
5920 local_values.
Append(synthetic_value_sp);
5922 local_values.
Append(value_sp);
5926 SetValues(local_values);
5930 m_frame_block =
nullptr;
5932 SetValues(local_values);
5935 return ValueObjectListDelegate::WindowDelegateDraw(window, force);
5940 Block *m_frame_block =
nullptr;
5943 class RegistersWindowDelegate :
public ValueObjectListDelegate {
5945 RegistersWindowDelegate(
Debugger &debugger)
5946 : ValueObjectListDelegate(), m_debugger(debugger) {}
5948 ~RegistersWindowDelegate()
override =
default;
5950 const char *WindowDelegateGetHelpText()
override {
5951 return "Register window keyboard shortcuts:";
5954 bool WindowDelegateDraw(Window &window,
bool force)
override {
5956 m_debugger.GetCommandInterpreter().GetExecutionContext());
5965 const uint32_t num_sets = reg_ctx->GetRegisterSetCount();
5966 for (
uint32_t set_idx = 0; set_idx < num_sets; ++set_idx) {
5968 ValueObjectRegisterSet::Create(frame, reg_ctx, set_idx));
5971 SetValues(value_list);
5975 if (process && process->
IsAlive())
5980 SetValues(value_list);
5983 return ValueObjectListDelegate::WindowDelegateDraw(window, force);
5991 static const char *CursesKeyToCString(
int ch) {
5992 static char g_desc[32];
5993 if (ch >= KEY_F0 && ch < KEY_F0 + 64) {
5994 snprintf(g_desc,
sizeof(g_desc),
"F%u", ch - KEY_F0);
6011 return "delete-line";
6013 return "insert-line";
6015 return "delete-char";
6017 return "insert-char";
6021 return "clear-to-eos";
6023 return "clear-to-eol";
6025 return "scroll-forward";
6027 return "scroll-backward";
6037 return "clear-all-tabs";
6043 return "lower-left key";
6045 return "upper left of keypad";
6047 return "upper right of keypad";
6049 return "center of keypad";
6051 return "lower left of keypad";
6053 return "lower right of keypad";
6055 return "back-tab key";
6059 return "cancel key";
6063 return "command key";
6067 return "create key";
6079 return "message key";
6087 return "options key";
6089 return "previous key";
6093 return "reference key";
6095 return "refresh key";
6097 return "replace key";
6099 return "restart key";
6101 return "resume key";
6105 return "shifted begin key";
6107 return "shifted cancel key";
6109 return "shifted command key";
6111 return "shifted copy key";
6113 return "shifted create key";
6115 return "shifted delete-character key";
6117 return "shifted delete-line key";
6119 return "select key";
6121 return "shifted end key";
6123 return "shifted clear-to-end-of-line key";
6125 return "shifted exit key";
6127 return "shifted find key";
6129 return "shifted help key";
6131 return "shifted home key";
6133 return "shifted insert-character key";
6135 return "shifted left-arrow key";
6137 return "shifted message key";
6139 return "shifted move key";
6141 return "shifted next key";
6143 return "shifted options key";
6145 return "shifted previous key";
6147 return "shifted print key";
6149 return "shifted redo key";
6151 return "shifted replace key";
6153 return "shifted right-arrow key";
6155 return "shifted resume key";
6157 return "shifted save key";
6159 return "shifted suspend key";
6161 return "shifted undo key";
6163 return "suspend key";
6167 return "Mouse event has occurred";
6169 return "Terminal resize event";
6172 return "We were interrupted by an event";
6183 if (llvm::isPrint(ch))
6184 snprintf(g_desc,
sizeof(g_desc),
"%c", ch);
6186 snprintf(g_desc,
sizeof(g_desc),
"\\x%2.2x", ch);
6192 HelpDialogDelegate::HelpDialogDelegate(
const char *text,
6193 KeyHelp *key_help_array)
6195 if (text && text[0]) {
6196 m_text.SplitIntoLines(text);
6197 m_text.AppendString(
"");
6199 if (key_help_array) {
6200 for (KeyHelp *key = key_help_array; key->ch; ++key) {
6202 key_description.
Printf(
"%10s - %s", CursesKeyToCString(key->ch),
6204 m_text.AppendString(key_description.
GetString());
6209 HelpDialogDelegate::~HelpDialogDelegate() =
default;
6211 bool HelpDialogDelegate::WindowDelegateDraw(Window &window,
bool force) {
6213 const int window_height = window.GetHeight();
6216 const int min_y = y;
6217 const int max_y = window_height - 1 - y;
6218 const size_t num_visible_lines = max_y - min_y + 1;
6219 const size_t num_lines = m_text.GetSize();
6220 const char *bottom_message;
6221 if (num_lines <= num_visible_lines)
6222 bottom_message =
"Press any key to exit";
6224 bottom_message =
"Use arrows to scroll, any other key to exit";
6225 window.DrawTitleBox(window.GetName(), bottom_message);
6226 while (y <= max_y) {
6227 window.MoveCursor(x, y);
6228 window.PutCStringTruncated(
6229 1, m_text.GetStringAtIndex(m_first_visible_line + y - min_y));
6235 HandleCharResult HelpDialogDelegate::WindowDelegateHandleChar(Window &window,
6238 const size_t num_lines = m_text.GetSize();
6239 const size_t num_visible_lines = window.GetHeight() - 2;
6241 if (num_lines <= num_visible_lines) {
6248 if (m_first_visible_line > 0)
6249 --m_first_visible_line;
6253 if (m_first_visible_line + num_visible_lines < num_lines)
6254 ++m_first_visible_line;
6259 if (m_first_visible_line > 0) {
6260 if (
static_cast<size_t>(m_first_visible_line) >= num_visible_lines)
6261 m_first_visible_line -= num_visible_lines;
6263 m_first_visible_line = 0;
6269 if (m_first_visible_line + num_visible_lines < num_lines) {
6270 m_first_visible_line += num_visible_lines;
6271 if (
static_cast<size_t>(m_first_visible_line) > num_lines)
6272 m_first_visible_line = num_lines - num_visible_lines;
6282 window.GetParent()->RemoveSubWindow(&window);
6286 class ApplicationDelegate :
public WindowDelegate,
public MenuDelegate {
6294 eMenuID_TargetCreate,
6295 eMenuID_TargetDelete,
6298 eMenuID_ProcessAttach,
6299 eMenuID_ProcessDetachResume,
6300 eMenuID_ProcessDetachSuspended,
6301 eMenuID_ProcessLaunch,
6302 eMenuID_ProcessContinue,
6303 eMenuID_ProcessHalt,
6304 eMenuID_ProcessKill,
6307 eMenuID_ThreadStepIn,
6308 eMenuID_ThreadStepOver,
6309 eMenuID_ThreadStepOut,
6312 eMenuID_ViewBacktrace,
6313 eMenuID_ViewRegisters,
6315 eMenuID_ViewVariables,
6316 eMenuID_ViewBreakpoints,
6322 ApplicationDelegate(Application &app,
Debugger &debugger)
6323 : WindowDelegate(), MenuDelegate(), m_app(app), m_debugger(debugger) {}
6325 ~ApplicationDelegate()
override =
default;
6327 bool WindowDelegateDraw(Window &window,
bool force)
override {
6331 HandleCharResult WindowDelegateHandleChar(Window &window,
int key)
override {
6334 window.SelectNextWindowAsActive();
6338 window.SelectPreviousWindowAsActive();
6342 window.CreateHelpSubwindow();
6346 return eQuitApplication;
6351 return eKeyNotHandled;
6354 const char *WindowDelegateGetHelpText()
override {
6355 return "Welcome to the LLDB curses GUI.\n\n"
6356 "Press the TAB key to change the selected view.\n"
6357 "Each view has its own keyboard shortcuts, press 'h' to open a "
6358 "dialog to display them.\n\n"
6359 "Common key bindings for all views:";
6362 KeyHelp *WindowDelegateGetKeyHelp()
override {
6363 static curses::KeyHelp g_source_view_key_help[] = {
6364 {
'\t',
"Select next view"},
6365 {KEY_BTAB,
"Select previous view"},
6366 {
'h',
"Show help dialog with view specific key bindings"},
6369 {KEY_UP,
"Select previous"},
6370 {KEY_DOWN,
"Select next"},
6371 {KEY_LEFT,
"Unexpand or select parent"},
6372 {KEY_RIGHT,
"Expand"},
6373 {KEY_PPAGE,
"Page up"},
6374 {KEY_NPAGE,
"Page down"},
6376 return g_source_view_key_help;
6379 MenuActionResult MenuDelegateAction(Menu &menu)
override {
6380 switch (menu.GetIdentifier()) {
6381 case eMenuID_TargetCreate: {
6382 WindowSP main_window_sp = m_app.GetMainWindow();
6383 FormDelegateSP form_delegate_sp =
6384 FormDelegateSP(
new TargetCreateFormDelegate(m_debugger));
6385 Rect bounds = main_window_sp->GetCenteredRect(80, 19);
6386 WindowSP form_window_sp = main_window_sp->CreateSubWindow(
6387 form_delegate_sp->GetName().c_str(), bounds,
true);
6388 WindowDelegateSP window_delegate_sp =
6389 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
6390 form_window_sp->SetDelegate(window_delegate_sp);
6391 return MenuActionResult::Handled;
6393 case eMenuID_ThreadStepIn: {
6395 m_debugger.GetCommandInterpreter().GetExecutionContext();
6398 if (process && process->
IsAlive() &&
6403 return MenuActionResult::Handled;
6405 case eMenuID_ThreadStepOut: {
6407 m_debugger.GetCommandInterpreter().GetExecutionContext();
6410 if (process && process->
IsAlive() &&
6418 return MenuActionResult::Handled;
6420 case eMenuID_ThreadStepOver: {
6422 m_debugger.GetCommandInterpreter().GetExecutionContext();
6425 if (process && process->
IsAlive() &&
6430 return MenuActionResult::Handled;
6432 case eMenuID_ProcessAttach: {
6433 WindowSP main_window_sp = m_app.GetMainWindow();
6434 FormDelegateSP form_delegate_sp = FormDelegateSP(
6435 new ProcessAttachFormDelegate(m_debugger, main_window_sp));
6436 Rect bounds = main_window_sp->GetCenteredRect(80, 22);
6437 WindowSP form_window_sp = main_window_sp->CreateSubWindow(
6438 form_delegate_sp->GetName().c_str(), bounds,
true);
6439 WindowDelegateSP window_delegate_sp =
6440 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
6441 form_window_sp->SetDelegate(window_delegate_sp);
6442 return MenuActionResult::Handled;
6444 case eMenuID_ProcessLaunch: {
6445 WindowSP main_window_sp = m_app.GetMainWindow();
6446 FormDelegateSP form_delegate_sp = FormDelegateSP(
6447 new ProcessLaunchFormDelegate(m_debugger, main_window_sp));
6448 Rect bounds = main_window_sp->GetCenteredRect(80, 22);
6449 WindowSP form_window_sp = main_window_sp->CreateSubWindow(
6450 form_delegate_sp->GetName().c_str(), bounds,
true);
6451 WindowDelegateSP window_delegate_sp =
6452 WindowDelegateSP(
new FormWindowDelegate(form_delegate_sp));
6453 form_window_sp->SetDelegate(window_delegate_sp);
6454 return MenuActionResult::Handled;
6457 case eMenuID_ProcessContinue: {
6459 m_debugger.GetCommandInterpreter().GetExecutionContext();
6462 if (process && process->
IsAlive() &&
6467 return MenuActionResult::Handled;
6469 case eMenuID_ProcessKill: {
6471 m_debugger.GetCommandInterpreter().GetExecutionContext();
6474 if (process && process->
IsAlive())
6478 return MenuActionResult::Handled;
6480 case eMenuID_ProcessHalt: {
6482 m_debugger.GetCommandInterpreter().GetExecutionContext();
6485 if (process && process->
IsAlive())
6489 return MenuActionResult::Handled;
6491 case eMenuID_ProcessDetachResume:
6492 case eMenuID_ProcessDetachSuspended: {
6494 m_debugger.GetCommandInterpreter().GetExecutionContext();
6497 if (process && process->
IsAlive())
6498 process->
Detach(menu.GetIdentifier() ==
6499 eMenuID_ProcessDetachSuspended);
6502 return MenuActionResult::Handled;
6504 case eMenuID_Process: {
6508 Menus &submenus = menu.GetSubmenus();
6510 m_debugger.GetCommandInterpreter().GetExecutionContext();
6512 if (process && process->
IsAlive() &&
6514 if (submenus.size() == 7)
6515 menu.AddSubmenu(MenuSP(
new Menu(Menu::Type::Separator)));
6516 else if (submenus.size() > 8)
6517 submenus.erase(submenus.begin() + 8, submenus.end());
6520 std::lock_guard<std::recursive_mutex> guard(threads.
GetMutex());
6521 size_t num_threads = threads.
GetSize();
6522 for (
size_t i = 0; i < num_threads; ++i) {
6524 char menu_char =
'\0';
6526 menu_char =
'1' + i;
6528 thread_menu_title.
Printf(
"Thread %u", thread_sp->GetIndexID());
6529 const char *thread_name = thread_sp->GetName();
6530 if (thread_name && thread_name[0])
6531 thread_menu_title.
Printf(
" %s", thread_name);
6533 const char *queue_name = thread_sp->GetQueueName();
6534 if (queue_name && queue_name[0])
6535 thread_menu_title.
Printf(
" %s", queue_name);
6538 MenuSP(
new Menu(thread_menu_title.
GetString().str().c_str(),
6539 nullptr, menu_char, thread_sp->GetID())));
6541 }
else if (submenus.size() > 7) {
6544 submenus.erase(submenus.begin() + 7, submenus.end());
6548 menu.RecalculateNameLengths();
6550 return MenuActionResult::Handled;
6552 case eMenuID_ViewVariables: {
6553 WindowSP main_window_sp = m_app.GetMainWindow();
6554 WindowSP source_window_sp = main_window_sp->FindSubWindow(
"Source");
6555 WindowSP variables_window_sp = main_window_sp->FindSubWindow(
"Variables");
6556 WindowSP registers_window_sp = main_window_sp->FindSubWindow(
"Registers");
6557 const Rect source_bounds = source_window_sp->GetBounds();
6559 if (variables_window_sp) {
6560 const Rect variables_bounds = variables_window_sp->GetBounds();
6562 main_window_sp->RemoveSubWindow(variables_window_sp.get());
6564 if (registers_window_sp) {
6567 Rect registers_bounds = variables_bounds;
6568 registers_bounds.size.width = source_bounds.size.width;
6569 registers_window_sp->SetBounds(registers_bounds);
6573 source_window_sp->Resize(source_bounds.size.width,
6574 source_bounds.size.height +
6575 variables_bounds.size.height);
6578 Rect new_variables_rect;
6579 if (registers_window_sp) {
6583 const Rect variables_bounds = registers_window_sp->GetBounds();
6584 Rect new_registers_rect;
6585 variables_bounds.VerticalSplitPercentage(0.50, new_variables_rect,
6586 new_registers_rect);
6587 registers_window_sp->SetBounds(new_registers_rect);
6590 Rect new_source_rect;
6591 source_bounds.HorizontalSplitPercentage(0.70, new_source_rect,
6592 new_variables_rect);
6593 source_window_sp->SetBounds(new_source_rect);
6595 WindowSP new_window_sp = main_window_sp->CreateSubWindow(
6596 "Variables", new_variables_rect,
false);
6597 new_window_sp->SetDelegate(
6598 WindowDelegateSP(
new FrameVariablesWindowDelegate(m_debugger)));
6602 return MenuActionResult::Handled;
6604 case eMenuID_ViewRegisters: {
6605 WindowSP main_window_sp = m_app.GetMainWindow();
6606 WindowSP source_window_sp = main_window_sp->FindSubWindow(
"Source");
6607 WindowSP variables_window_sp = main_window_sp->FindSubWindow(
"Variables");
6608 WindowSP registers_window_sp = main_window_sp->FindSubWindow(
"Registers");
6609 const Rect source_bounds = source_window_sp->GetBounds();
6611 if (registers_window_sp) {
6612 if (variables_window_sp) {
6613 const Rect variables_bounds = variables_window_sp->GetBounds();
6617 variables_window_sp->Resize(variables_bounds.size.width +
6618 registers_window_sp->GetWidth(),
6619 variables_bounds.size.height);
6623 source_window_sp->Resize(source_bounds.size.width,
6624 source_bounds.size.height +
6625 registers_window_sp->GetHeight());
6627 main_window_sp->RemoveSubWindow(registers_window_sp.get());
6630 if (variables_window_sp) {
6634 const Rect variables_bounds = variables_window_sp->GetBounds();
6636 variables_bounds.VerticalSplitPercentage(0.50, new_vars_rect,
6638 variables_window_sp->SetBounds(new_vars_rect);
6641 Rect new_source_rect;
6642 source_bounds.HorizontalSplitPercentage(0.70, new_source_rect,
6644 source_window_sp->SetBounds(new_source_rect);
6646 WindowSP new_window_sp =
6647 main_window_sp->CreateSubWindow(
"Registers", new_regs_rect,
false);
6648 new_window_sp->SetDelegate(
6649 WindowDelegateSP(
new RegistersWindowDelegate(m_debugger)));
6653 return MenuActionResult::Handled;
6655 case eMenuID_ViewBreakpoints: {
6656 WindowSP main_window_sp = m_app.GetMainWindow();
6657 WindowSP threads_window_sp = main_window_sp->FindSubWindow(
"Threads");
6658 WindowSP breakpoints_window_sp =
6659 main_window_sp->FindSubWindow(
"Breakpoints");
6660 const Rect threads_bounds = threads_window_sp->GetBounds();
6667 if (breakpoints_window_sp) {
6668 threads_window_sp->Resize(threads_bounds.size.width,
6669 threads_bounds.size.height +
6670 breakpoints_window_sp->GetHeight());
6671 main_window_sp->RemoveSubWindow(breakpoints_window_sp.get());
6673 Rect new_threads_bounds, breakpoints_bounds;
6674 threads_bounds.HorizontalSplitPercentage(0.70, new_threads_bounds,
6675 breakpoints_bounds);
6676 threads_window_sp->SetBounds(new_threads_bounds);
6677 breakpoints_window_sp = main_window_sp->CreateSubWindow(
6678 "Breakpoints", breakpoints_bounds,
false);
6679 TreeDelegateSP breakpoints_delegate_sp(
6680 new BreakpointsTreeDelegate(m_debugger));
6681 breakpoints_window_sp->SetDelegate(WindowDelegateSP(
6682 new TreeWindowDelegate(m_debugger, breakpoints_delegate_sp)));
6685 return MenuActionResult::Handled;
6688 case eMenuID_HelpGUIHelp:
6689 m_app.GetMainWindow()->CreateHelpSubwindow();
6690 return MenuActionResult::Handled;
6696 return MenuActionResult::NotHandled;
6704 class StatusBarWindowDelegate :
public WindowDelegate {
6706 StatusBarWindowDelegate(
Debugger &debugger) : m_debugger(debugger) {
6710 ~StatusBarWindowDelegate()
override =
default;
6712 bool WindowDelegateDraw(Window &window,
bool force)
override {
6714 m_debugger.GetCommandInterpreter().GetExecutionContext();
6719 window.SetBackground(BlackOnWhite);
6720 window.MoveCursor(0, 0);
6723 window.Printf(
"Process: %5" PRIu64
" %10s", process->
GetID(),
6729 nullptr,
nullptr,
false,
false)) {
6730 window.MoveCursor(40, 0);
6731 window.PutCStringTruncated(1, strm.
GetString().str().c_str());
6734 window.MoveCursor(60, 0);
6736 window.Printf(
"Frame: %3u PC = 0x%16.16" PRIx64,
6743 if (exit_desc && exit_desc[0])
6744 window.Printf(
" with status = %i (%s)", exit_status, exit_desc);
6746 window.Printf(
" with status = %i", exit_status);
6757 class SourceFileWindowDelegate :
public WindowDelegate {
6759 SourceFileWindowDelegate(
Debugger &debugger)
6760 : WindowDelegate(), m_debugger(debugger), m_sc(), m_file_sp(),
6761 m_disassembly_sp(), m_disassembly_range(), m_title() {}
6763 ~SourceFileWindowDelegate()
override =
default;
6767 uint32_t NumVisibleLines()
const {
return m_max_y - m_min_y; }
6769 const char *WindowDelegateGetHelpText()
override {
6770 return "Source/Disassembly window keyboard shortcuts:";
6773 KeyHelp *WindowDelegateGetKeyHelp()
override {
6774 static curses::KeyHelp g_source_view_key_help[] = {
6775 {KEY_RETURN,
"Run to selected line with one shot breakpoint"},
6776 {KEY_UP,
"Select previous source line"},
6777 {KEY_DOWN,
"Select next source line"},
6778 {KEY_LEFT,
"Scroll to the left"},
6779 {KEY_RIGHT,
"Scroll to the right"},
6780 {KEY_PPAGE,
"Page up"},
6781 {KEY_NPAGE,
"Page down"},
6782 {
'b',
"Set breakpoint on selected source/disassembly line"},
6783 {
'c',
"Continue process"},
6784 {
'D',
"Detach with process suspended"},
6785 {
'h',
"Show help dialog"},
6786 {
'n',
"Step over (source line)"},
6787 {
'N',
"Step over (single instruction)"},
6788 {
'f',
"Step out (finish)"},
6789 {
's',
"Step in (source line)"},
6790 {
'S',
"Step in (single instruction)"},
6792 {
'd',
"Frame down"},
6796 return g_source_view_key_help;
6799 bool WindowDelegateDraw(Window &window,
bool force)
override {
6801 m_debugger.GetCommandInterpreter().GetExecutionContext();
6803 Thread *thread =
nullptr;
6805 bool update_location =
false;
6810 update_location =
true;
6816 m_max_x = window.GetMaxX() - 1;
6817 m_max_y = window.GetMaxY() - 1;
6819 const uint32_t num_visible_lines = NumVisibleLines();
6820 StackFrameSP frame_sp;
6821 bool set_selected_line_to_pc =
false;
6823 if (update_location) {
6824 const bool process_alive = process->
IsAlive();
6825 bool thread_changed =
false;
6826 if (process_alive) {
6830 auto tid = thread->
GetID();
6831 thread_changed = tid != m_tid;
6835 thread_changed =
true;
6841 const bool stop_id_changed = stop_id != m_stop_id;
6842 bool frame_changed =
false;
6843 m_stop_id = stop_id;
6846 m_sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
6847 if (m_sc.module_sp) {
6849 "%s", m_sc.module_sp->GetFileSpec().GetFilename().GetCString());
6852 m_title.Printf(
"`%s", func_name.
GetCString());
6854 const uint32_t frame_idx = frame_sp->GetFrameIndex();
6855 frame_changed = frame_idx != m_frame_idx;
6856 m_frame_idx = frame_idx;
6863 const bool context_changed =
6864 thread_changed || frame_changed || stop_id_changed;
6866 if (process_alive) {
6867 if (m_sc.line_entry.IsValid()) {
6868 m_pc_line = m_sc.line_entry.line;
6872 if (context_changed)
6873 m_selected_line = m_pc_line;
6875 if (m_file_sp && m_file_sp->GetFileSpec() == m_sc.line_entry.file) {
6878 if (m_selected_line >=
static_cast<size_t>(m_first_visible_line)) {
6879 if (m_selected_line >= m_first_visible_line + num_visible_lines)
6880 m_first_visible_line = m_selected_line - 10;
6882 if (m_selected_line > 10)
6883 m_first_visible_line = m_selected_line - 10;
6885 m_first_visible_line = 0;
6889 m_selected_line = m_pc_line;
6891 m_debugger.GetSourceManager().GetFile(m_sc.line_entry.file);
6893 const size_t num_lines = m_file_sp->GetNumLines();
6895 for (
size_t n = num_lines; n >= 10; n = n / 10)
6898 if (num_lines < num_visible_lines ||
6899 m_selected_line < num_visible_lines)
6900 m_first_visible_line = 0;
6902 m_first_visible_line = m_selected_line - 10;
6909 if (!m_file_sp || m_file_sp->GetNumLines() == 0) {
6911 bool prefer_file_cache =
false;
6912 if (m_sc.function) {
6913 if (m_disassembly_scope != m_sc.function) {
6914 m_disassembly_scope = m_sc.function;
6915 m_disassembly_sp = m_sc.function->GetInstructions(
6916 exe_ctx,
nullptr, !prefer_file_cache);
6917 if (m_disassembly_sp) {
6918 set_selected_line_to_pc =
true;
6919 m_disassembly_range = m_sc.function->GetAddressRange();
6921 m_disassembly_range.Clear();
6924 set_selected_line_to_pc = context_changed;
6926 }
else if (m_sc.symbol) {
6927 if (m_disassembly_scope != m_sc.symbol) {
6928 m_disassembly_scope = m_sc.symbol;
6929 m_disassembly_sp = m_sc.symbol->GetInstructions(
6930 exe_ctx,
nullptr, prefer_file_cache);
6931 if (m_disassembly_sp) {
6932 set_selected_line_to_pc =
true;
6933 m_disassembly_range.GetBaseAddress() =
6934 m_sc.symbol->GetAddress();
6935 m_disassembly_range.SetByteSize(m_sc.symbol->GetByteSize());
6937 m_disassembly_range.Clear();
6940 set_selected_line_to_pc = context_changed;
6949 const int window_width = window.GetWidth();
6951 window.DrawTitleBox(
"Sources");
6952 if (!m_title.GetString().empty()) {
6953 window.AttributeOn(A_REVERSE);
6954 window.MoveCursor(1, 1);
6955 window.PutChar(
' ');
6956 window.PutCStringTruncated(1, m_title.GetString().str().c_str());
6957 int x = window.GetCursorX();
6958 if (x < window_width - 1) {
6959 window.Printf(
"%*s", window_width - x - 1,
"");
6961 window.AttributeOff(A_REVERSE);
6965 const size_t num_source_lines = GetNumSourceLines();
6966 if (num_source_lines > 0) {
6968 BreakpointLines bp_lines;
6971 const size_t num_bps = bp_list.
GetSize();
6972 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
6974 const size_t num_bps_locs = bp_sp->GetNumLocations();
6975 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs; ++bp_loc_idx) {
6976 BreakpointLocationSP bp_loc_sp =
6977 bp_sp->GetLocationAtIndex(bp_loc_idx);
6979 if (bp_loc_sp->GetAddress().CalculateSymbolContextLineEntry(
6980 bp_loc_line_entry)) {
6981 if (m_file_sp->GetFileSpec() == bp_loc_line_entry.
file) {
6982 bp_lines.insert(bp_loc_line_entry.
line);
6989 for (
size_t i = 0; i < num_visible_lines; ++i) {
6990 const uint32_t curr_line = m_first_visible_line + i;
6991 if (curr_line < num_source_lines) {
6992 const int line_y = m_min_y + i;
6993 window.MoveCursor(1, line_y);
6994 const bool is_pc_line = curr_line == m_pc_line;
6995 const bool line_is_selected = m_selected_line == curr_line;
6999 attr_t highlight_attr = 0;
7001 if (line_is_selected && !is_pc_line)
7002 highlight_attr = A_REVERSE;
7004 if (bp_lines.find(curr_line + 1) != bp_lines.end())
7005 bp_attr = COLOR_PAIR(BlackOnWhite);
7008 window.AttributeOn(bp_attr);
7010 window.Printf(
" %*u ", m_line_width, curr_line + 1);
7013 window.AttributeOff(bp_attr);
7015 window.PutChar(ACS_VLINE);
7018 window.PutChar(ACS_DIAMOND);
7020 window.PutChar(
' ');
7023 window.AttributeOn(highlight_attr);
7027 llvm::Optional<size_t> column;
7028 if (is_pc_line && m_sc.line_entry.IsValid() && m_sc.line_entry.column)
7029 column = m_sc.line_entry.column - 1;
7030 m_file_sp->DisplaySourceLines(curr_line + 1, column, 0, 0,
7032 StringRef line = lineStream.
GetString();
7033 if (line.endswith(
"\n"))
7034 line = line.drop_back();
7035 bool wasWritten = window.OutputColoredStringTruncated(
7036 1, line, m_first_visible_column, is_pc_line);
7037 if (!wasWritten && (line_is_selected || is_pc_line)) {
7041 window.PutCStringTruncated(
7042 1, line.empty() && m_first_visible_column == 0 ?
" " :
"<");
7045 if (is_pc_line && frame_sp &&
7046 frame_sp->GetConcreteFrameIndex() == 0) {
7047 StopInfoSP stop_info_sp;
7051 const char *stop_description = stop_info_sp->GetDescription();
7052 if (stop_description && stop_description[0]) {
7053 size_t stop_description_len = strlen(stop_description);
7054 int desc_x = window_width - stop_description_len - 16;
7055 if (desc_x - window.GetCursorX() > 0)
7056 window.Printf(
"%*s", desc_x - window.GetCursorX(),
"");
7057 window.MoveCursor(window_width - stop_description_len - 16,
7059 const attr_t stop_reason_attr = COLOR_PAIR(WhiteOnBlue);
7060 window.AttributeOn(stop_reason_attr);
7061 window.PrintfTruncated(1,
" <<< Thread %u: %s ",
7063 window.AttributeOff(stop_reason_attr);
7066 window.Printf(
"%*s", window_width - window.GetCursorX() - 1,
"");
7070 window.AttributeOff(highlight_attr);
7076 size_t num_disassembly_lines = GetNumDisassemblyLines();
7077 if (num_disassembly_lines > 0) {
7079 BreakpointAddrs bp_file_addrs;
7083 const size_t num_bps = bp_list.
GetSize();
7084 for (
size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) {
7086 const size_t num_bps_locs = bp_sp->GetNumLocations();
7087 for (
size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs;
7089 BreakpointLocationSP bp_loc_sp =
7090 bp_sp->GetLocationAtIndex(bp_loc_idx);
7093 bp_loc_sp->GetAddress().GetFileAddress();
7095 if (m_disassembly_range.ContainsFileAddress(file_addr))
7096 bp_file_addrs.insert(file_addr);
7102 const attr_t selected_highlight_attr = A_REVERSE;
7103 const attr_t pc_highlight_attr = COLOR_PAIR(WhiteOnBlue);
7111 pc_address = frame_sp->GetFrameCodeAddress();