enforce standalone 'expression' child for watch expressions in cfg tree, adjust eval / ui to work on that child, instead of assuming the first child of a watch expression node is the expression string itself - this will let us tag watch expressions with other info, like project / lock status etc.

This commit is contained in:
Ryan Fleury
2026-07-27 16:02:10 -07:00
parent 0b4c20b165
commit ec520227c5
6 changed files with 26 additions and 21 deletions
+1 -1
View File
@@ -71,5 +71,5 @@ target:
target:
{
executable: "../../Program Files/SuperTux/bin/supertux2.exe"
working_directory: "../../Program Files/SuperTux/bin/"
working_directory: "../../Program Files/SuperTux/bin"
}
+3 -2
View File
@@ -62,13 +62,14 @@ str8_lit_comp(""),
str8_lit_comp(""),
};
RD_VocabInfo rd_vocab_info_table[368] =
RD_VocabInfo rd_vocab_info_table[369] =
{
{str8_lit_comp("type_view"), str8_lit_comp("type_views"), str8_lit_comp("Type View"), str8_lit_comp("Type Views"), RD_IconKind_Binoculars},
{str8_lit_comp("file_path_map"), str8_lit_comp("file_path_maps"), str8_lit_comp("File Path Map"), str8_lit_comp("File Path Maps"), RD_IconKind_FileOutline},
{str8_lit_comp("watch_pin"), str8_lit_comp("watch_pins"), str8_lit_comp("Watch Pin"), str8_lit_comp("Watch Pins"), RD_IconKind_Pin},
{str8_lit_comp("debug_info"), str8_lit_comp("debug_infos"), str8_lit_comp("Debug Info"), str8_lit_comp("Debug Info"), RD_IconKind_Module},
{str8_lit_comp("watch"), str8_lit_comp("watches"), str8_lit_comp("Watch"), str8_lit_comp("Watches"), RD_IconKind_Binoculars},
{str8_lit_comp("watch_expression"), str8_lit_comp("watch_expressions"), str8_lit_comp("Watch Expression"), str8_lit_comp("Watch Expressions"), RD_IconKind_Binoculars},
{str8_lit_comp("view"), str8_lit_comp("views"), str8_lit_comp("View"), str8_lit_comp("Views"), RD_IconKind_Binoculars},
{str8_lit_comp("breakpoint"), str8_lit_comp("breakpoints"), str8_lit_comp("Breakpoint"), str8_lit_comp("Breakpoints"), RD_IconKind_CircleFilled},
{str8_lit_comp("condition"), str8_lit_comp("conditions"), str8_lit_comp("Condition"), str8_lit_comp("Conditions"), RD_IconKind_Null},
@@ -456,7 +457,7 @@ RD_NameSchemaInfo rd_name_schema_info_table[39] =
{str8_lit_comp("array"), 1, str8_lit_comp("x:{ @description('An expression of the base address of the array.') 'base_address': expr_string, @description('The number of elements in the array.') count}")},
{str8_lit_comp("slice"), 1, str8_lit_comp("x:{ @description('An expression of a structure that is to be interpreted as a slice.') 'expression': expr_string}")},
{str8_lit_comp("list"), 1, str8_lit_comp("x:\n{\n @description(\"An expression describing the first node in the list.\")\n 'expression': expr_string,\n @order(0) @description(\"The name of the member which encodes the link to the next node.\")\n 'member_name': code_string,\n}\n")},
{str8_lit_comp("watch"), 0, str8_lit_comp("@inherit(tab) x:\n{\n @override @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': expr_string,\n @no_expand 'watches': set,\n}\n")},
{str8_lit_comp("watch"), 0, str8_lit_comp("@inherit(tab) x:\n{\n @override @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': expr_string,\n @no_expand 'watch_expressions': set,\n}\n")},
{str8_lit_comp("text"), 1, str8_lit_comp("@inherit(tab) @expand_commands(@output clear_output) x:\n{\n @description(\"An expression to describe data which should be viewed as text or code.\")\n 'expression': expr_string,\n @optional @description(\"The language that the text should be interpreted as being within. Used for syntax highlighting and other parsing features.\")\n 'lang': code_string,\n @no_callee_helper @default(1) @description(\"Controls whether or not line numbers are shown.\")\n 'show_line_numbers':bool,\n @no_callee_helper @default(1) @display_name('Line Wrapping') @description(\"Splits textual lines into multiple visual lines, so that all text is within the visible area.\")\n 'line_wrapping': bool,\n @no_callee_helper @default(0) @display_name('Scroll To Bottom On Change') @description(\"Scrolls to the bottom if the text is changed.\")\n 'scroll_to_bottom_on_change': bool,\n @no_callee_helper @no_revert @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}\n")},
{str8_lit_comp("disasm"), 1, str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression to describe the base address or offset of the disassembly.\")\n 'expression': expr_string,\n @optional @description(\"The maximum number of bytes to disassemble.\")\n 'size': expr_string,\n @optional @description(\"The architecture to interpret the data as when disassembling.\")\n 'arch': code_string,\n @optional @description(\"The syntax style to use when displaying the disassembly textually.\")\n 'syntax': code_string,\n @no_callee_helper @default(1) @description(\"Controls whether or not addresses are shown in the disassembly text.\")\n 'show_addresses': bool,\n @no_callee_helper @default(0) @description(\"Controls whether or not code bytes are shown in the disassembly text.\")\n 'show_code_bytes': bool,\n @no_callee_helper @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 @no_callee_helper @default(1) @description(\"Controls whether or not disassembly text is decorated with symbol names.\")\n 'show_symbol_names': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not line numbers are shown.\")\n 'show_line_numbers': bool,\n}\n")},
{str8_lit_comp("memory"), 1, str8_lit_comp("@inherit(tab) x:\n{\n @display_name(\"Base Address\") @description(\"An expression which refers to the base address of data which should be viewed as memory.\")\n 'expression': expr_string,\n @no_callee_helper @display_name(\"Zoom\") @description(\"The zoom level for displaying bytes in the memory view.\")\n @default(1.0) 'zoom': @range[0.5, 2] f32,\n @optional @display_name(\"Address Range Size\") @description(\"The number of bytes of the viewed memory range.\")\n 'size': expr_string,\n @no_callee_helper @display_name(\"Cursor Address\") @description(\"The address of the cursor.\")\n 'cursor': expr_string,\n @no_callee_helper @default(1) @display_name(\"Cursor Size\") @description(\"The size, in bytes, of the cursor.\")\n 'cursor_size': @range[1, 16] u64,\n @optional @expand_if(\"!$.auto_columns\") @default(16) @description(\"The number of columns to build before building new rows.\")\n 'num_columns': @range[1, 64] u64,\n @optional @default(16) @display_name(\"Default Radix\") @description(\"The default radix with which numeric values should be displayed, when peeking.\")\n @or(2, 8, 10, 16)\n 'default_radix': u64,\n @no_callee_helper @default(1) @display_name(\"Track Mark To Cursor\") @description(\"Ensures that the mark always follows the cursor, if the cursor value is updated.\")\n 'track_mark_to_cursor': bool,\n @no_callee_helper @default(1) @display_name(\"Allow Mutation\") @description(\"Allows operations which mutate memory.\")\n 'allow_mutation': bool,\n @no_callee_helper @default(0) @display_name(\"Automatically Size Columns\") @description(\"Determines the number of columns based on the available space.\")\n 'auto_columns': bool,\n @no_callee_helper @default(1) @display_name(\"Peek As Unsigned\") 'peek_as_unsigned': bool,\n @no_callee_helper @default(1) @display_name(\"Peek As Signed\") 'peek_as_signed': bool,\n @no_callee_helper @default(1) @display_name(\"Peek As Float\") 'peek_as_float': bool,\n @no_callee_helper @display_name(\"Extra Peek Types\") @description(\"A list of types as which to interpret selected memory.\")\n 'peek_types': set,\n}\n")},
+1 -1
View File
@@ -623,7 +623,7 @@ Z(getting_started)\
C_LINKAGE_BEGIN
extern String8 rd_tab_fast_path_view_name_table[25];
extern String8 rd_tab_fast_path_query_name_table[25];
extern RD_VocabInfo rd_vocab_info_table[368];
extern RD_VocabInfo rd_vocab_info_table[369];
extern RD_NameSchemaInfo rd_name_schema_info_table[39];
extern String8 rd_reg_slot_code_name_table[54];
extern Rng1U64 rd_reg_slot_range_table[54];
+2 -1
View File
@@ -94,6 +94,7 @@ RD_VocabTable:
{watch_pin _ "Watch Pin" _ Pin }
{debug_info _ "Debug Info" "Debug Info" Module }
{watch watches "Watch" "Watches" Binoculars }
{watch_expression _ "Watch Expression" _ Binoculars }
{view _ "View" _ Binoculars }
{breakpoint _ "Breakpoint" _ CircleFilled }
{condition _ "Condition" _ Null }
@@ -560,7 +561,7 @@ RD_VocabTable:
'label': code_string,
@description("The root expression which is evaluated to produce the watch window.")
'expression': expr_string,
@no_expand 'watches': set,
@no_expand 'watch_expressions': set,
}
```
}
+16 -14
View File
@@ -2034,7 +2034,7 @@ rd_view_ui(Rng2F32 rect)
{
if(expr_string.size == 0)
{
expr_string = str8f(scratch.arena, "query:config.$%I64x.watches", rd_regs()->view);
expr_string = str8f(scratch.arena, "query:config.$%I64x.watch_expressions", rd_regs()->view);
}
E_Eval eval = e_eval_from_string(expr_string);
RD_WatchViewState *ewv = rd_view_state(RD_WatchViewState);
@@ -2778,13 +2778,13 @@ rd_view_ui(Rng2F32 rect)
{
CFG_Node *cfg = row_info.group_cfg_child;
String8 child_key = {0}; // str8_lit("expression");
if(str8_match(row_info.group_cfg_name, s("watch_expression"), 0))
{
child_key = s("expression");
}
if(cfg == &cfg_nil_node && editing_complete && new_string.size != 0)
{
CFG_Node *new_cfg_parent = row_info.group_cfg_parent;
if(new_cfg_parent != &cfg_nil_node)
{
child_key = str8_zero();
}
if(new_cfg_parent == &cfg_nil_node)
{
CFG_NodePtrList all_cfgs = cfg_node_top_level_list_from_string(scratch.arena, row_info.group_cfg_name);
@@ -3526,8 +3526,9 @@ rd_view_ui(Rng2F32 rect)
if(cfg == &cfg_nil_node)
{
cfg = cfg_node_alloc(rd_state->cfg);
cfg_node_equip_stringf(rd_state->cfg, cfg, "watch");
cfg_node_new(rd_state->cfg, cfg, drag_regs->expr);
cfg_node_equip_stringf(rd_state->cfg, cfg, "watch_expression");
CFG_Node *expr = cfg_node_new(rd_state->cfg, cfg, s("expression"));
cfg_node_new(rd_state->cfg, expr, drag_regs->expr);
}
cfg_node_insert_child(rd_state->cfg, drag_parent_cfg, drag_prev_cfg, cfg);
}break;
@@ -12187,10 +12188,10 @@ rd_frame(void)
{
continue;
}
if(str8_match(child->string, str8_lit("watch"), 0))
if(str8_match(child->string, str8_lit("watch_expression"), 0))
{
CFG_Node *watch = child;
String8 expr = watch->first->string;
String8 expr = cfg_node_child_from_string(watch, s("expression"))->first->string;
E_Parse parse = e_parse_from_string(expr);
if(parse.msgs.max_kind == E_MsgKind_Null)
{
@@ -12383,10 +12384,10 @@ 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_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, str8_lit("watch_expressions"),
e_type_key_cons(.kind = E_TypeKind_Set,
.flags = E_TypeFlag_EditableChildren|E_TypeFlag_StubSingleLineExpansion,
.name = str8_lit("watches"),
.name = str8_lit("watch_expressions"),
.irext = E_TYPE_IREXT_FUNCTION_NAME(watches),
.access = E_TYPE_ACCESS_FUNCTION_NAME(watches),
.expand =
@@ -16563,7 +16564,7 @@ rd_frame(void)
{
continue;
}
if(str8_match(child->string, str8_lit("watch"), 0) && str8_match(child->first->string, rd_regs()->string, 0))
if(str8_match(child->string, str8_lit("watch_expression"), 0) && str8_match(child->first->string, rd_regs()->string, 0))
{
existing_watch = child;
break;
@@ -16579,8 +16580,9 @@ rd_frame(void)
// rjf: otherwise, create it
else if(watch_tab != &cfg_nil_node)
{
CFG_Node *watch = cfg_node_new(rd_state->cfg, watch_tab, str8_lit("watch"));
cfg_node_new(rd_state->cfg, watch, rd_regs()->string);
CFG_Node *watch = cfg_node_new(rd_state->cfg, watch_tab, s("watch_expression"));
CFG_Node *expr = cfg_node_new(rd_state->cfg, watch, s("expression"));
cfg_node_new(rd_state->cfg, expr, rd_regs()->string);
}
}break;
+3 -2
View File
@@ -1389,7 +1389,7 @@ E_TYPE_IREXT_FUNCTION_DEF(watches)
for(CFG_Node *child = target->first; child != &cfg_nil_node; child = child->next)
{
if(rd_cfg_is_project_filtered(child)) {continue;}
if(str8_match(child->string, str8_lit("watch"), 0))
if(str8_match(child->string, str8_lit("watch_expression"), 0))
{
cfg_node_ptr_list_push(scratch.arena, &cfgs, child);
}
@@ -1461,7 +1461,8 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(watches)
if(cfg_idx < accel->cfgs.count)
{
CFG_Node *cfg = accel->cfgs.v[cfg_idx];
evals_out[idx] = e_eval_from_string(cfg->first->string);
CFG_Node *expr = cfg_node_child_from_string(cfg, s("expression"));
evals_out[idx] = e_eval_from_string(expr->first->string);
}
}
}