|
diff --git a/tdbg.cpp b/tdbg.cpp
|
| ... |
| 20 |
struct LayoutConfig { |
20 |
struct LayoutConfig { |
| 21 |
int log_height = 10; |
21 |
int log_height = 10; |
| 22 |
int status_height = 1; |
22 |
int status_height = 1; |
| 23 |
int breakpoints_height = 10; |
23 |
int watch_height = 15; |
| 24 |
int sidebar_width = 50; |
24 |
int sidebar_width = 50; |
| 25 |
} layout_config; |
25 |
} layout_config; |
| 26 |
|
26 |
|
| ... |
| 32 |
enum InputMode { |
32 |
enum InputMode { |
| 33 |
INPUT_MODE_NORMAL, |
33 |
INPUT_MODE_NORMAL, |
| 34 |
INPUT_MODE_BREAKPOINT, |
34 |
INPUT_MODE_BREAKPOINT, |
| 35 |
INPUT_MODE_VARIABLE |
35 |
INPUT_MODE_VARIABLE, |
|
|
36 |
INPUT_MODE_WATCH |
| 36 |
}; |
37 |
}; |
| 37 |
|
38 |
|
| 38 |
struct LLDBGuard { |
39 |
struct LLDBGuard { |
| ... |
| 160 |
return '?'; |
161 |
return '?'; |
| 161 |
} |
162 |
} |
| 162 |
|
163 |
|
| 163 |
void collect_variables_recursive(SBValue val, int indent, std::vector<VarLine>& lines, int width) { |
164 |
void collect_variables_recursive(SBValue val, int indent, std::vector<VarLine>& lines, int width, const std::string& name_override = "") { |
| 164 |
if (indent > 3) return; |
165 |
if (indent > 3) return; |
| 165 |
|
166 |
|
| 166 |
std::string original_name = val.GetName() ? val.GetName() : ""; |
167 |
std::string original_name = name_override.empty() ? (val.GetName() ? val.GetName() : "") : name_override; |
| 167 |
char type_char = get_type_char(val.GetType()); |
168 |
char type_char = get_type_char(val.GetType()); |
| 168 |
std::string prefix = std::string("(") + type_char + ") "; |
169 |
std::string prefix = std::string("(") + type_char + ") "; |
| 169 |
|
170 |
|
| ... |
| 503 |
} |
504 |
} |
| 504 |
} |
505 |
} |
| 505 |
|
506 |
|
|
|
507 |
void draw_watch_view(SBFrame& frame, int x, int y, int w, int h, const std::vector<std::string>& expressions, int scroll_offset) { |
|
|
508 |
draw_box(x, y, w, h, "Watch"); |
|
|
509 |
int cx = x + 1; |
|
|
510 |
int cy = y + 1; |
|
|
511 |
int ch = h - 2; |
|
|
512 |
int cw = w - 2; |
|
|
513 |
|
|
|
514 |
if (expressions.empty()) { |
|
|
515 |
draw_text(cx, cy, TB_DEFAULT, TB_DEFAULT, "No watch expressions."); |
|
|
516 |
return; |
|
|
517 |
} |
|
|
518 |
|
|
|
519 |
std::vector<VarLine> lines; |
|
|
520 |
for (const auto& expr : expressions) { |
|
|
521 |
SBValue val = frame.EvaluateExpression(expr.c_str()); |
|
|
522 |
if (val.IsValid() && !val.GetError().Fail()) { |
|
|
523 |
collect_variables_recursive(val, 0, lines, cw, expr); |
|
|
524 |
} else { |
|
|
525 |
VarLine vl; |
|
|
526 |
vl.text = expr + " = (error)"; |
|
|
527 |
if (val.GetError().GetCString()) { |
|
|
528 |
vl.text += ": " + std::string(val.GetError().GetCString()); |
|
|
529 |
} |
|
|
530 |
if ((int)vl.text.length() > cw) vl.text = vl.text.substr(0, cw - 3) + "..."; |
|
|
531 |
vl.indent = 0; |
|
|
532 |
vl.prefix_start = 0; |
|
|
533 |
vl.prefix_end = 0; |
|
|
534 |
lines.push_back(vl); |
|
|
535 |
} |
|
|
536 |
} |
|
|
537 |
|
|
|
538 |
int total_lines = (int)lines.size(); |
|
|
539 |
int display_count = std::min(total_lines, ch); |
|
|
540 |
|
|
|
541 |
for (int i = 0; i < display_count; ++i) { |
|
|
542 |
int line_idx = scroll_offset + i; |
|
|
543 |
if (line_idx < 0 || line_idx >= total_lines) continue; |
|
|
544 |
|
|
|
545 |
const VarLine& vl = lines[line_idx]; |
|
|
546 |
for (int j = 0; j < (int)vl.text.length() && j < cw; ++j) { |
|
|
547 |
uint16_t fg = TB_DEFAULT; |
|
|
548 |
if (j >= vl.prefix_start && j < vl.prefix_end) { |
|
|
549 |
fg = TB_BLACK | TB_BOLD; |
|
|
550 |
} |
|
|
551 |
tb_set_cell(cx + j, cy + i, vl.text[j], fg, TB_DEFAULT); |
|
|
552 |
} |
|
|
553 |
} |
|
|
554 |
|
|
|
555 |
// Draw scrollbar |
|
|
556 |
if (total_lines > ch) { |
|
|
557 |
int thumb_height = std::max(1, (ch * ch) / total_lines); |
|
|
558 |
int max_scroll = total_lines - ch; |
|
|
559 |
double scroll_percent = (double)scroll_offset / (double)max_scroll; |
|
|
560 |
int thumb_pos = (ch - thumb_height) * scroll_percent; |
|
|
561 |
|
|
|
562 |
for (int i = 0; i < ch; ++i) { |
|
|
563 |
uint32_t cell_char = SCROLLBAR_LINE; |
|
|
564 |
uint16_t fg = TB_DEFAULT; |
|
|
565 |
if (i >= thumb_pos && i < thumb_pos + thumb_height) { |
|
|
566 |
cell_char = SCROLLBAR_THUMB; |
|
|
567 |
fg = TB_WHITE; |
|
|
568 |
} |
|
|
569 |
tb_set_cell(x + w - 1, cy + i, cell_char, fg, TB_DEFAULT); |
|
|
570 |
} |
|
|
571 |
} |
|
|
572 |
} |
|
|
573 |
|
| 506 |
SBBreakpoint create_breakpoint(SBTarget& target, const std::string& input) { |
574 |
SBBreakpoint create_breakpoint(SBTarget& target, const std::string& input) { |
| 507 |
SBBreakpoint bp; |
575 |
SBBreakpoint bp; |
| 508 |
size_t colon_pos = input.rfind(':'); |
576 |
size_t colon_pos = input.rfind(':'); |
| ... |
| 523 |
} |
591 |
} |
| 524 |
|
592 |
|
| 525 |
void draw_log_view(int x, int y, int w, int h, const std::vector<std::string>& log_buffer, InputMode mode, const std::string& input_buffer, int scroll_offset) { |
593 |
void draw_log_view(int x, int y, int w, int h, const std::vector<std::string>& log_buffer, InputMode mode, const std::string& input_buffer, int scroll_offset) { |
| 526 |
bool input_mode = (mode == INPUT_MODE_BREAKPOINT || mode == INPUT_MODE_VARIABLE); |
594 |
bool input_mode = (mode == INPUT_MODE_BREAKPOINT || mode == INPUT_MODE_VARIABLE || mode == INPUT_MODE_WATCH); |
| 527 |
std::string title = input_mode ? "Input (Esc to Cancel)" : "Logs"; |
595 |
std::string title = input_mode ? "Input (Esc to Cancel)" : "Logs"; |
| 528 |
if (!input_mode && scroll_offset > 0) { |
596 |
if (!input_mode && scroll_offset > 0) { |
| 529 |
title += " (Scrolled up: " + std::to_string(scroll_offset) + ")"; |
597 |
title += " (Scrolled up: " + std::to_string(scroll_offset) + ")"; |
| ... |
| 539 |
std::string prompt; |
607 |
std::string prompt; |
| 540 |
if (mode == INPUT_MODE_BREAKPOINT) prompt = "Add Breakpoint: "; |
608 |
if (mode == INPUT_MODE_BREAKPOINT) prompt = "Add Breakpoint: "; |
| 541 |
else if (mode == INPUT_MODE_VARIABLE) prompt = "Print Variable: "; |
609 |
else if (mode == INPUT_MODE_VARIABLE) prompt = "Print Variable: "; |
|
|
610 |
else if (mode == INPUT_MODE_WATCH) prompt = "Watch Variable: "; |
| 542 |
|
611 |
|
| 543 |
prompt += input_buffer; |
612 |
prompt += input_buffer; |
| 544 |
if ((int)prompt.length() > cw) prompt = prompt.substr(prompt.length() - cw); |
613 |
if ((int)prompt.length() > cw) prompt = prompt.substr(prompt.length() - cw); |
| ... |
| 591 |
} |
660 |
} |
| 592 |
|
661 |
|
| 593 |
state_str += (mode == INPUT_MODE_NORMAL) |
662 |
state_str += (mode == INPUT_MODE_NORMAL) |
| 594 |
? " | r=Run, b=Add breakpoint, p=Print, n=Step Over, s=Step Into, o=Step Out, c=Continue, q=Quit" |
663 |
? " | r=Run, b=Add breakpoint, p=Print, w=Watch, n=Step Over, s=Step Into, o=Step Out, c=Continue, q=Quit" |
| 595 |
: " | Enter=Confirm, Esc=Cancel"; |
664 |
: " | Enter=Confirm, Esc=Cancel"; |
| 596 |
|
665 |
|
| 597 |
for (int x = 0; x < width; ++x) { |
666 |
for (int x = 0; x < width; ++x) { |
| ... |
| 653 |
std::string input_buffer; |
722 |
std::string input_buffer; |
| 654 |
std::string current_source_filename; |
723 |
std::string current_source_filename; |
| 655 |
std::vector<std::string> log_buffer; |
724 |
std::vector<std::string> log_buffer; |
|
|
725 |
std::vector<std::string> watch_expressions; |
| 656 |
int log_scroll_offset = 0; |
726 |
int log_scroll_offset = 0; |
| 657 |
int locals_scroll_offset = 0; |
727 |
int locals_scroll_offset = 0; |
|
|
728 |
int watch_scroll_offset = 0; |
| 658 |
int source_scroll_offset = 0; |
729 |
int source_scroll_offset = 0; |
| 659 |
uint64_t last_pc = 0; |
730 |
uint64_t last_pc = 0; |
| 660 |
SourceCache source_cache; |
731 |
SourceCache source_cache; |
| ... |
| 669 |
int height = tb_height(); |
740 |
int height = tb_height(); |
| 670 |
int main_window_height = height - layout_config.log_height - layout_config.status_height; |
741 |
int main_window_height = height - layout_config.log_height - layout_config.status_height; |
| 671 |
int split_x = width - layout_config.sidebar_width; |
742 |
int split_x = width - layout_config.sidebar_width; |
| 672 |
int locals_window_height = main_window_height - layout_config.breakpoints_height; |
743 |
int locals_window_height = main_window_height - layout_config.watch_height; |
| 673 |
|
744 |
|
| 674 |
SBFrame frame; |
745 |
SBFrame frame; |
| 675 |
if (process.IsValid() && process.GetState() != eStateExited) { |
746 |
if (process.IsValid() && process.GetState() != eStateExited) { |
| ... |
| 705 |
|
776 |
|
| 706 |
draw_source_view(frame, 0, 0, split_x, main_window_height, source_cache, source_scroll_offset); |
777 |
draw_source_view(frame, 0, 0, split_x, main_window_height, source_cache, source_scroll_offset); |
| 707 |
draw_variables_view(frame, split_x, 0, layout_config.sidebar_width, locals_window_height, locals_scroll_offset); |
778 |
draw_variables_view(frame, split_x, 0, layout_config.sidebar_width, locals_window_height, locals_scroll_offset); |
| 708 |
draw_breakpoints_view(target, split_x, locals_window_height, layout_config.sidebar_width, layout_config.breakpoints_height); |
779 |
draw_watch_view(frame, split_x, locals_window_height, layout_config.sidebar_width, layout_config.watch_height, watch_expressions, watch_scroll_offset); |
| 709 |
draw_log_view(0, main_window_height, width, layout_config.log_height, log_buffer, mode, input_buffer, log_scroll_offset); |
780 |
draw_log_view(0, main_window_height, split_x, layout_config.log_height, log_buffer, mode, input_buffer, log_scroll_offset); |
|
|
781 |
draw_breakpoints_view(target, split_x, main_window_height, layout_config.sidebar_width, layout_config.log_height); |
| 710 |
draw_status_bar(process, mode, width, height); |
782 |
draw_status_bar(process, mode, width, height); |
| 711 |
|
783 |
|
| 712 |
tb_present(); |
784 |
tb_present(); |
| ... |
| 772 |
} else if (ev.ch == 'p') { |
844 |
} else if (ev.ch == 'p') { |
| 773 |
mode = INPUT_MODE_VARIABLE; |
845 |
mode = INPUT_MODE_VARIABLE; |
| 774 |
input_buffer.clear(); |
846 |
input_buffer.clear(); |
|
|
847 |
} else if (ev.ch == 'w') { |
|
|
848 |
mode = INPUT_MODE_WATCH; |
|
|
849 |
input_buffer.clear(); |
| 775 |
} else { |
850 |
} else { |
| 776 |
if (process.IsValid() && process.GetState() == eStateStopped) { |
851 |
if (process.IsValid() && process.GetState() == eStateStopped) { |
| 777 |
switch (ev.ch) { |
852 |
switch (ev.ch) { |
| ... |
| 789 |
} |
864 |
} |
| 790 |
} |
865 |
} |
| 791 |
} |
866 |
} |
| 792 |
} else if (mode == INPUT_MODE_BREAKPOINT || mode == INPUT_MODE_VARIABLE) { |
867 |
} else if (mode == INPUT_MODE_BREAKPOINT || mode == INPUT_MODE_VARIABLE || mode == INPUT_MODE_WATCH) { |
| 793 |
if (ev.key == TB_KEY_ESC) { |
868 |
if (ev.key == TB_KEY_ESC) { |
| 794 |
mode = INPUT_MODE_NORMAL; |
869 |
mode = INPUT_MODE_NORMAL; |
| 795 |
input_buffer.clear(); |
870 |
input_buffer.clear(); |
| ... |
| 818 |
log_msg(log_buffer, err); |
893 |
log_msg(log_buffer, err); |
| 819 |
} |
894 |
} |
| 820 |
} |
895 |
} |
|
|
896 |
} else if (mode == INPUT_MODE_WATCH) { |
|
|
897 |
watch_expressions.push_back(input_buffer); |
|
|
898 |
log_msg(log_buffer, "Added to watch: " + input_buffer); |
| 821 |
} |
899 |
} |
| 822 |
} |
900 |
} |
| 823 |
mode = INPUT_MODE_NORMAL; |
901 |
mode = INPUT_MODE_NORMAL; |
| ... |
| 834 |
// Log window scrolling |
912 |
// Log window scrolling |
| 835 |
int log_start_y = main_window_height; |
913 |
int log_start_y = main_window_height; |
| 836 |
int log_end_y = tb_height() - layout_config.status_height; |
914 |
int log_end_y = tb_height() - layout_config.status_height; |
| 837 |
if (ev.y >= log_start_y && ev.y < log_end_y) { |
915 |
if (ev.x < split_x && ev.y >= log_start_y && ev.y < log_end_y) { |
| 838 |
if (ev.key == TB_KEY_MOUSE_WHEEL_UP) { |
916 |
if (ev.key == TB_KEY_MOUSE_WHEEL_UP) { |
| 839 |
int max_scroll = std::max(0, (int)log_buffer.size() - (layout_config.log_height - 2)); |
917 |
int max_scroll = std::max(0, (int)log_buffer.size() - (layout_config.log_height - 2)); |
| 840 |
if (log_scroll_offset < max_scroll) { |
918 |
if (log_scroll_offset < max_scroll) { |
| ... |
| 876 |
|
954 |
|
| 877 |
// Locals window scrolling |
955 |
// Locals window scrolling |
| 878 |
int split_x = tb_width() - layout_config.sidebar_width; |
956 |
int split_x = tb_width() - layout_config.sidebar_width; |
| 879 |
int locals_window_height = main_window_height - layout_config.breakpoints_height; |
957 |
int locals_window_height = main_window_height - layout_config.watch_height; |
| 880 |
if (ev.x >= split_x && ev.y < locals_window_height) { |
958 |
if (ev.x >= split_x && ev.y < locals_window_height) { |
| 881 |
std::vector<VarLine> lines; |
959 |
std::vector<VarLine> lines; |
| 882 |
if (frame.IsValid()) { |
960 |
if (frame.IsValid()) { |
| ... |
| 894 |
} else if (ev.key == TB_KEY_MOUSE_WHEEL_DOWN) { |
972 |
} else if (ev.key == TB_KEY_MOUSE_WHEEL_DOWN) { |
| 895 |
if (locals_scroll_offset < max_scroll) { |
973 |
if (locals_scroll_offset < max_scroll) { |
| 896 |
locals_scroll_offset++; |
974 |
locals_scroll_offset++; |
|
|
975 |
} |
|
|
976 |
} |
|
|
977 |
} |
|
|
978 |
|
|
|
979 |
// Watch window scrolling |
|
|
980 |
if (ev.x >= split_x && ev.y >= locals_window_height && ev.y < main_window_height) { |
|
|
981 |
std::vector<VarLine> lines; |
|
|
982 |
for (const auto& expr : watch_expressions) { |
|
|
983 |
SBValue val = frame.EvaluateExpression(expr.c_str()); |
|
|
984 |
if (val.IsValid() && !val.GetError().Fail()) { |
|
|
985 |
collect_variables_recursive(val, 0, lines, layout_config.sidebar_width - 2, expr); |
|
|
986 |
} else { |
|
|
987 |
VarLine vl; |
|
|
988 |
vl.text = expr + " = (error)"; |
|
|
989 |
lines.push_back(vl); |
|
|
990 |
} |
|
|
991 |
} |
|
|
992 |
int max_scroll = std::max(0, (int)lines.size() - (layout_config.watch_height - 2)); |
|
|
993 |
|
|
|
994 |
if (ev.key == TB_KEY_MOUSE_WHEEL_UP) { |
|
|
995 |
if (watch_scroll_offset > 0) { |
|
|
996 |
watch_scroll_offset--; |
|
|
997 |
} |
|
|
998 |
} else if (ev.key == TB_KEY_MOUSE_WHEEL_DOWN) { |
|
|
999 |
if (watch_scroll_offset < max_scroll) { |
|
|
1000 |
watch_scroll_offset++; |
| 897 |
} |
1001 |
} |
| 898 |
} |
1002 |
} |
| 899 |
} |
1003 |
} |
| ... |