eliminate watches as a top-level entity, nest watch expressions under tabs - allow many watch windows, each with their own set of expressions.

This commit is contained in:
Ryan Fleury
2025-04-26 10:27:21 -07:00
parent 09f248de59
commit 5103252a1b
6 changed files with 184 additions and 165 deletions
+2 -2
View File
@@ -30,7 +30,7 @@ str8_lit_comp("memory"),
String8 rd_tab_fast_path_query_name_table[20] =
{
str8_lit_comp("query:watches"),
str8_lit_comp(""),
str8_lit_comp("query:locals"),
str8_lit_comp("query:registers"),
str8_lit_comp("query:globals"),
@@ -378,7 +378,7 @@ RD_NameSchemaInfo rd_name_schema_info_table[21] =
{str8_lit_comp("project"), str8_lit_comp("x:\n{\n @default(2) @display_name('Project Tab Width') 'tab_width': @range[1, 32] u64,\n}\n")},
{str8_lit_comp("window"), str8_lit_comp("x:\n{\n //- rjf: text rasterization settings\n @default(1) @display_name('Smooth UI Text') @description(\"Controls whether or not UI text is fully anti-aliased, for a smoother appearance.\")\n 'smooth_ui_text': bool,\n @default(1) @display_name('Hint UI Text') @description(\"Controls whether or not UI text is hinted, for better text readability at small sizes.\")\n 'hint_ui_text': bool,\n @default(0) @display_name('Smooth Code Text') @description(\"Controls whether or not code text is fully anti-aliased, for a smoother appearance.\")\n 'smooth_code_text': bool,\n @default(1) @display_name('Hint Code Text') @description(\"Controls whether or not code text is hinted, for better text readability at small sizes.\")\n 'hint_code_text': bool,\n @default(11) @display_name('Window Font Size') @description(\"Controls the window's default font size. Does not apply to tabs with their own font size set.\")\n 'font_size': @range[6, 72] u64,\n\n //- rjf: size settings\n @default(3.f) @display_name('Window Row Height') @description(\"Controls the window's default row height, in multiples of the font size. Does not apply to tabs with their own row height set.\")\n 'row_height': @range[1.75f, 5.f] f32,\n @default(3.f) @description(\"Controls the height of tabs, in multiples of the font size.\")\n 'tab_height': @range[1.75f, 5.f] f32,\n}\n")},
{str8_lit_comp("tab"), str8_lit_comp("x:\n{\n @default(11) @display_name('Tab Font Size') @description(\"Controls the tab's font size.\")\n 'font_size': @range[6, 72] u64,\n}\n")},
{str8_lit_comp("watch"), str8_lit_comp("@inherit(tab) x:\n{\n @default(3.f) @display_name('Tab Row Height') @description(\"Controls the tab's row height, in multiples of the font size.\")\n 'row_height': @range[1.75f, 5.f] f32,\n @description(\"The root expression which is evaluated to produce the watch window.\")\n 'expression': code_string,\n}\n")},
{str8_lit_comp("watch"), str8_lit_comp("@inherit(tab) x:\n{\n @default(3.f) @display_name('Tab Row Height') @description(\"Controls the tab's row height, in multiples of the font size.\")\n 'row_height': @range[1.75f, 5.f] f32,\n 'label': code_string,\n @description(\"The root expression which is evaluated to produce the watch window.\")\n 'expression': code_string,\n @no_expand 'watches': query,\n}\n")},
{str8_lit_comp("text"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"The language that the text should be interpreted as being within. Used for syntax highlighting and other parsing features.\")\n 'lang': lang,\n @default(1) @description(\"Controls whether or not line numbers are shown.\")\n 'show_line_numbers':bool,\n @default(0) @display_name('Transient') @description(\"Controls whether or not this tab will be automatically replaced by the debugger when it snaps to new source code locations.\")\n 'auto': bool,\n @description(\"An expression to describe data which should be viewed as text or code.\")\n 'expression': code_string,\n}\n")},
{str8_lit_comp("disasm"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression to describe the base address or offset of the disassembly.\")\n 'expression': code_string,\n 'arch': arch,\n 'syntax': dasm_syntax,\n 'size': code_string,\n @default(1) @description(\"Controls whether or not addresses are shown in the disassembly text.\")\n 'show_addresses': bool,\n @default(0) @description(\"Controls whether or not code bytes are shown in the disassembly text.\")\n 'show_code_bytes': bool,\n @default(1) @description(\"Controls whether or not source lines, corresponding to disassembly instruction ranges, are shown in the disassembly text.\")\n 'show_source_lines': bool,\n @default(1) @description(\"Controls whether or not disassembly text is decorated with symbol names.\")\n 'show_symbol_names': bool,\n @default(1) @description(\"Controls whether or not line numbers are shown.\")\n 'show_line_numbers': bool,\n}\n")},
{str8_lit_comp("memory"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression to describe the base address or offset of the memory view.\")\n 'expression': code_string,\n @description(\"The number of bytes of the viewed memory range.\")\n 'size': code_string,\n @default(16) @description(\"The number of columns to build before building new rows.\")\n 'num_columns': @range[1, 64] u64,\n @default(1) @description(\"The number of bytes that each cell should represent.\")\n 'bytes_per_cell': @range[1, 8] u64,\n}\n")},
+17 -17
View File
@@ -600,23 +600,23 @@ RD_Query query;
};
#define RD_FixedTabXList \
X(watches)\
X(locals)\
X(registers)\
X(globals)\
X(thread_locals)\
X(types)\
X(procedures)\
X(call_stack)\
X(targets)\
X(breakpoints)\
X(watch_pins)\
X(threads)\
X(processes)\
X(machines)\
X(modules)\
X(file_path_maps)\
X(auto_view_rules)\
Y(watches, watch, "")\
X(locals) \
X(registers) \
X(globals) \
X(thread_locals) \
X(types) \
X(procedures) \
X(call_stack) \
X(targets) \
X(breakpoints) \
X(watch_pins) \
X(threads) \
X(processes) \
X(machines) \
X(modules) \
X(file_path_maps) \
X(auto_view_rules) \
Y(output, text, "query:output")\
Y(disasm, disasm, "")\
Y(memory, memory, "")\
+22 -20
View File
@@ -14,26 +14,26 @@
////////////////////////////////
//~ rjf: Fixed Tab Tables
@table(name display_name name_lower icon)
@table(name display_name name_lower is_query icon)
RD_WatchTabFastPathTable:
{
{Watch "Watch" watches Binoculars }
{Locals "Locals" locals Binoculars }
{Registers "Registers" registers Binoculars }
{Globals "Globals" globals Binoculars }
{ThreadLocals "Thread Locals" thread_locals Binoculars }
{Types "Types" types Binoculars }
{Procedures "Procedures" procedures Binoculars }
{CallStack "Call Stack" call_stack Thread }
{Targets "Targets" targets Target }
{Breakpoints "Breakpoints" breakpoints CircleFilled }
{WatchPins "Watch Pins" watch_pins Pin }
{Threads "Threads" threads Threads }
{Processes "Processes" processes Scheduler }
{Machines "Machines" machines Machine }
{Modules "Modules" modules Module }
{FilePathMaps "File Path Map" file_path_maps FileOutline }
{AutoViewRules "Auto View Rules" auto_view_rules Binoculars }
{Watch "Watch" watches 0 Binoculars }
{Locals "Locals" locals 1 Binoculars }
{Registers "Registers" registers 1 Binoculars }
{Globals "Globals" globals 1 Binoculars }
{ThreadLocals "Thread Locals" thread_locals 1 Binoculars }
{Types "Types" types 1 Binoculars }
{Procedures "Procedures" procedures 1 Binoculars }
{CallStack "Call Stack" call_stack 1 Thread }
{Targets "Targets" targets 1 Target }
{Breakpoints "Breakpoints" breakpoints 1 CircleFilled }
{WatchPins "Watch Pins" watch_pins 1 Pin }
{Threads "Threads" threads 1 Threads }
{Processes "Processes" processes 1 Scheduler }
{Machines "Machines" machines 1 Machine }
{Modules "Modules" modules 1 Module }
{FilePathMaps "File Path Map" file_path_maps 1 FileOutline }
{AutoViewRules "Auto View Rules" auto_view_rules 1 Binoculars }
}
@table(name display_name name_lower view query icon)
@@ -53,7 +53,7 @@ RD_FixedTabTable:
@gen
{
`#define RD_FixedTabXList \\`;
@expand(RD_WatchTabFastPathTable a) `X($(a.name_lower))\\`;
@expand(RD_WatchTabFastPathTable a) `$(a.is_query -> 'X(' .. a.name_lower .. ')') $(a.is_query == 0 -> 'Y(' .. a.name_lower .. ', watch, ""' .. ')')\\`;
@expand(RD_ViewTabFastPathTable a) `Y($(a.name_lower), $(a.view), "$(a.query)")\\`;
@expand(RD_FixedTabTable a) `Z($(a.name_lower))\\`;
``;
@@ -67,7 +67,7 @@ RD_FixedTabTable:
@data(String8) rd_tab_fast_path_query_name_table:
{
@expand(RD_WatchTabFastPathTable a) `str8_lit_comp("query:$(a.name_lower)")`,
@expand(RD_WatchTabFastPathTable a) `str8_lit_comp("$(a.is_query -> 'query:' .. a.name_lower)")`,
@expand(RD_ViewTabFastPathTable a) `str8_lit_comp("$(a.query)")`,
}
@@ -315,8 +315,10 @@ RD_VocabTable:
{
@default(3.f) @display_name('Tab Row Height') @description("Controls the tab's row height, in multiples of the font size.")
'row_height': @range[1.75f, 5.f] f32,
'label': code_string,
@description("The root expression which is evaluated to produce the watch window.")
'expression': code_string,
@no_expand 'watches': query,
}
```
}
+18 -17
View File
@@ -2721,6 +2721,10 @@ rd_view_ui(Rng2F32 rect)
Temp scratch = scratch_begin(0, 0);
RD_Font(RD_FontSlot_Code)
{
if(expr_string.size == 0)
{
expr_string = push_str8f(scratch.arena, "query:config.$%I64x.watches", rd_regs()->view);
}
E_Eval eval = e_eval_from_string(expr_string);
RD_WatchViewState *ewv = rd_view_state(RD_WatchViewState);
UI_ScrollPt2 scroll_pos = rd_view_scroll_pos();
@@ -3412,7 +3416,7 @@ rd_view_ui(Rng2F32 rect)
if(cell->flags & RD_WatchCellFlag_Expr && cell->flags & RD_WatchCellFlag_NoEval)
{
RD_Cfg *cfg = row_info.group_cfg_child;
String8 child_key = str8_lit("expression");
String8 child_key = {0}; // str8_lit("expression");
if(cfg == &rd_nil_cfg && editing_complete && new_string.size != 0)
{
RD_Cfg *new_cfg_parent = row_info.group_cfg_parent;
@@ -11981,22 +11985,6 @@ rd_frame(void)
}
}
//- rjf: add macro for watches group
{
String8 collection_name = str8_lit("watches");
E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, 0);
expr->space = e_space_make(RD_EvalSpaceKind_MetaQuery);
expr->type_key = e_type_key_cons(.kind = E_TypeKind_Set, .name = collection_name, .flags = E_TypeFlag_EditableChildren,
.expand =
{
.info = E_TYPE_EXPAND_INFO_FUNCTION_NAME(watches),
.range = E_TYPE_EXPAND_RANGE_FUNCTION_NAME(watches),
.id_from_num = E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(watches),
.num_from_id = E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(watches),
});
e_string2expr_map_insert(scratch.arena, macro_map, collection_name, expr);
}
//- rjf: add macros for all watches which define identifiers
RD_CfgList watches = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("watch"));
for(RD_CfgNode *n = watches.first; n != 0; n = n->next)
@@ -12205,6 +12193,19 @@ rd_frame(void)
.id_from_num = E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(environment),
.num_from_id = E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(environment),
}));
e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, str8_lit("watches"),
e_type_key_cons(.kind = E_TypeKind_Set,
.flags = E_TypeFlag_EditableChildren,
.name = str8_lit("watches"),
.irext = E_TYPE_IREXT_FUNCTION_NAME(watches),
.access = E_TYPE_ACCESS_FUNCTION_NAME(watches),
.expand =
{
.info = E_TYPE_EXPAND_INFO_FUNCTION_NAME(watches),
.range = E_TYPE_EXPAND_RANGE_FUNCTION_NAME(watches),
.id_from_num = E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(watches),
.num_from_id = E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(watches),
}));
e_string2typekey_map_insert(rd_frame_arena(),
rd_state->meta_name2type_map,
str8_lit("call_stack"),
+115 -101
View File
@@ -84,107 +84,6 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(commands)
}
}
////////////////////////////////
//~ rjf: `watches` Type Hooks
E_TYPE_EXPAND_INFO_FUNCTION_DEF(watches)
{
E_TypeExpandInfo result = {0};
Temp scratch = scratch_begin(&arena, 1);
{
RD_CfgList cfgs_list = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("watch"));
RD_CfgList cfgs_list__filtered = cfgs_list;
if(filter.size != 0)
{
MemoryZeroStruct(&cfgs_list__filtered);
for(RD_CfgNode *n = cfgs_list.first; n != 0; n = n->next)
{
String8 expr = rd_expr_from_cfg(n->v);
B32 passes_filter = 1;
if(filter.size != 0)
{
E_Eval eval = e_eval_from_string(expr);
E_Type *type = e_type_from_key__cached(eval.irtree.type_key);
if(type->kind != E_TypeKind_Set)
{
passes_filter = 0;
FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, expr);
if(matches.count == matches.needle_part_count)
{
passes_filter = 1;
}
}
}
if(passes_filter)
{
rd_cfg_list_push(scratch.arena, &cfgs_list__filtered, n->v);
}
}
}
RD_CfgArray *cfgs = push_array(arena, RD_CfgArray, 1);
cfgs[0] = rd_cfg_array_from_list(arena, &cfgs_list__filtered);
result.user_data = cfgs;
result.expr_count = cfgs->count + 1;
}
scratch_end(scratch);
return result;
}
E_TYPE_EXPAND_RANGE_FUNCTION_DEF(watches)
{
RD_CfgArray *cfgs = (RD_CfgArray *)user_data;
Rng1U64 legal_idx_range = r1u64(0, cfgs->count);
Rng1U64 read_range = intersect_1u64(idx_range, legal_idx_range);
U64 read_range_count = dim_1u64(read_range);
for(U64 idx = 0; idx < read_range_count; idx += 1)
{
U64 cfg_idx = read_range.min + idx;
if(cfg_idx < cfgs->count)
{
String8 expr_string = rd_cfg_child_from_string(cfgs->v[cfg_idx], str8_lit("expression"))->first->string;
evals_out[idx] = e_eval_from_string(expr_string);
}
}
}
E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(watches)
{
U64 id = 0;
RD_CfgArray *cfgs = (RD_CfgArray *)user_data;
if(1 <= num && num <= cfgs->count)
{
U64 idx = (num-1);
id = cfgs->v[idx]->id;
}
else if(num == cfgs->count+1)
{
id = max_U64;
}
return id;
}
E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(watches)
{
U64 num = 0;
RD_CfgArray *cfgs = (RD_CfgArray *)user_data;
if(id != 0 && id != max_U64)
{
for EachIndex(idx, cfgs->count)
{
if(cfgs->v[idx]->id == id)
{
num = idx+1;
break;
}
}
}
else if(id == max_U64)
{
num = cfgs->count + 1;
}
return num;
}
////////////////////////////////
//~ rjf: `locals` Type Hooks
@@ -1028,6 +927,121 @@ E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(environment)
return num;
}
////////////////////////////////
//~ rjf: `watches` Type Hooks
typedef struct RD_WatchesAccel RD_WatchesAccel;
struct RD_WatchesAccel
{
RD_CfgArray cfgs;
};
E_TYPE_IREXT_FUNCTION_DEF(watches)
{
RD_WatchesAccel *accel = push_array(arena, RD_WatchesAccel, 1);
{
Temp scratch = scratch_begin(&arena, 1);
E_OpList oplist = e_oplist_from_irtree(scratch.arena, irtree->root);
String8 bytecode = e_bytecode_from_oplist(scratch.arena, &oplist);
E_Interpretation interpret = e_interpret(bytecode);
E_Space space = interpret.space;
RD_Cfg *target = rd_cfg_from_eval_space(space);
RD_CfgList env_strings = {0};
for(RD_Cfg *child = target->first; child != &rd_nil_cfg; child = child->next)
{
if(str8_match(child->string, str8_lit("watch"), 0))
{
rd_cfg_list_push(scratch.arena, &env_strings, child);
}
}
accel->cfgs = rd_cfg_array_from_list(arena, &env_strings);
scratch_end(scratch);
}
E_IRExt result = {accel};
return result;
}
E_TYPE_ACCESS_FUNCTION_DEF(watches)
{
E_IRTreeAndType result = {&e_irnode_nil};
if(expr->kind == E_ExprKind_ArrayIndex)
{
RD_WatchesAccel *accel = (RD_WatchesAccel *)lhs_irtree->user_data;
RD_CfgArray *cfgs = &accel->cfgs;
E_Value rhs_value = e_value_from_expr(expr->first->next);
if(0 <= rhs_value.u64 && rhs_value.u64 < cfgs->count)
{
RD_Cfg *cfg = cfgs->v[rhs_value.u64];
result.root = e_irtree_set_space(arena, rd_eval_space_from_cfg(cfg), e_irtree_const_u(arena, 0));
result.type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), cfg->first->string.size, E_TypeFlag_IsCodeText);
result.mode = E_Mode_Offset;
}
}
return result;
}
E_TYPE_EXPAND_INFO_FUNCTION_DEF(watches)
{
RD_WatchesAccel *accel = (RD_WatchesAccel *)eval.irtree.user_data;
E_TypeExpandInfo result = {accel, accel->cfgs.count + 1};
return result;
}
E_TYPE_EXPAND_RANGE_FUNCTION_DEF(watches)
{
RD_WatchesAccel *accel = (RD_WatchesAccel *)user_data;
Rng1U64 legal_idx_range = r1u64(0, accel->cfgs.count);
Rng1U64 read_range = intersect_1u64(idx_range, legal_idx_range);
U64 read_range_count = dim_1u64(read_range);
for(U64 idx = 0; idx < read_range_count; idx += 1)
{
U64 cfg_idx = read_range.min + idx;
if(cfg_idx < accel->cfgs.count)
{
RD_Cfg *cfg = accel->cfgs.v[cfg_idx];
evals_out[idx] = e_eval_from_string(cfg->first->string);
}
}
}
E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(watches)
{
U64 id = 0;
RD_WatchesAccel *accel = (RD_WatchesAccel *)user_data;
if(1 <= num && num <= accel->cfgs.count)
{
U64 idx = (num-1);
id = accel->cfgs.v[idx]->id;
}
else if(num == accel->cfgs.count+1)
{
id = max_U64;
}
return id;
}
E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(watches)
{
U64 num = 0;
RD_WatchesAccel *accel = (RD_WatchesAccel *)user_data;
if(id != 0 && id != max_U64)
{
for EachIndex(idx, accel->cfgs.count)
{
if(accel->cfgs.v[idx]->id == id)
{
num = idx+1;
break;
}
}
}
else if(id == max_U64)
{
num = accel->cfgs.count + 1;
}
return num;
}
////////////////////////////////
//~ rjf: `unattached_processes` Type Hooks
+10 -8
View File
@@ -11,14 +11,6 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(commands);
E_TYPE_ACCESS_FUNCTION_DEF(commands);
E_TYPE_EXPAND_RANGE_FUNCTION_DEF(commands);
////////////////////////////////
//~ rjf: `watches` Type Hooks
E_TYPE_EXPAND_INFO_FUNCTION_DEF(watches);
E_TYPE_EXPAND_RANGE_FUNCTION_DEF(watches);
E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(watches);
E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(watches);
////////////////////////////////
//~ rjf: `locals` Type Hooks
@@ -71,6 +63,16 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(environment);
E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(environment);
E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(environment);
////////////////////////////////
//~ rjf: `watches` Type Hooks
E_TYPE_IREXT_FUNCTION_DEF(watches);
E_TYPE_ACCESS_FUNCTION_DEF(watches);
E_TYPE_EXPAND_INFO_FUNCTION_DEF(watches);
E_TYPE_EXPAND_RANGE_FUNCTION_DEF(watches);
E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(watches);
E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(watches);
////////////////////////////////
//~ rjf: `unattached_processes` Type Hooks