support for raddbg_pin markup on-the-fly watch pin annotations

This commit is contained in:
Ryan Fleury
2025-03-26 11:38:32 -07:00
parent 29d430ca6c
commit bd35ea83fc
6 changed files with 142 additions and 55 deletions
+4 -3
View File
@@ -328,6 +328,7 @@ type_coverage_eval_tests(void)
raddbg_pin(basics);
raddbg_pin(fixed);
raddbg_pin(pointer);
raddbg_pin(dynamic, slice);
Struct_With_Embedded_Arrays swea = {0};
{
@@ -1642,8 +1643,8 @@ fancy_viz_eval_tests(void)
"}\n\n");
int x1 = 0;
raddbg_pin(long_string, "text");
raddbg_pin(code_string, "text: (lang:c)");
raddbg_pin(fancy_viz_eval_tests, "disasm: (arch:x64)");
raddbg_pin(code_string, "text(lang=c)");
raddbg_pin(fancy_viz_eval_tests, "disasm");
//- rjf: bitmaps
unsigned int background_color = 0x00000000;
@@ -1892,7 +1893,7 @@ fancy_viz_eval_tests(void)
136, 137, 138, 138, 139, 136, 140, 141, 142, 142, 143, 140, 144, 145, 146, 146, 147, 144, 148, 149, 150, 150, 151, 148,
152, 153, 154, 154, 155, 152, 156, 157, 158, 158, 159, 156, 160, 161, 162, 162, 163, 160, 164, 165, 166, 166, 167, 164,
};
raddbg_pin(index_data, "geo3d: { count:(sizeof index_data/4), vtx:(vertex_data), vtx_size:(sizeof vertex_data) }");
raddbg_pin(index_data, "geo3d(count = (sizeof index_data/4), vtx = (vertex_data), vtx_size = (sizeof vertex_data))");
int x3 = 0;
}
+3 -5
View File
@@ -4,7 +4,7 @@
//- GENERATED CODE
C_LINKAGE_BEGIN
RD_VocabInfo rd_vocab_info_table[308] =
RD_VocabInfo rd_vocab_info_table[307] =
{
{str8_lit_comp("auto_view_rule"), str8_lit_comp("auto_view_rules"), str8_lit_comp("Auto View Rule"), str8_lit_comp("Auto View Rules"), 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},
@@ -267,7 +267,6 @@ RD_VocabInfo rd_vocab_info_table[308] =
{str8_lit_comp("relocate_cfg"), str8_lit_comp(""), str8_lit_comp("Relocate Config Tree"), str8_lit_comp(""), RD_IconKind_Null},
{str8_lit_comp("add_breakpoint"), str8_lit_comp(""), str8_lit_comp("Add Breakpoint"), str8_lit_comp(""), RD_IconKind_CircleFilled},
{str8_lit_comp("add_address_breakpoint"), str8_lit_comp(""), str8_lit_comp("Add Address Breakpoint"), str8_lit_comp(""), RD_IconKind_CircleFilled},
{str8_lit_comp("add_function_breakpoint"), str8_lit_comp(""), str8_lit_comp("Add Function Breakpoint"), str8_lit_comp(""), RD_IconKind_CircleFilled},
{str8_lit_comp("toggle_breakpoint"), str8_lit_comp(""), str8_lit_comp("Toggle Breakpoint"), str8_lit_comp(""), RD_IconKind_CircleFilled},
{str8_lit_comp("enable_breakpoint"), str8_lit_comp(""), str8_lit_comp("Enable Breakpoint"), str8_lit_comp(""), RD_IconKind_CheckFilled},
{str8_lit_comp("disable_breakpoint"), str8_lit_comp(""), str8_lit_comp("Disable Breakpoint"), str8_lit_comp(""), RD_IconKind_CheckHollow},
@@ -324,7 +323,7 @@ RD_NameSchemaInfo rd_name_schema_info_table[16] =
{str8_lit_comp("memory"), str8_lit_comp("x:\n{\n 'size': code_string,\n @default(16) 'num_columns': @range[1, 64] u64,\n}\n")},
{str8_lit_comp("bitmap"), str8_lit_comp("x:\n{\n 'w': code_string,\n 'h': code_string,\n 'fmt': tex2dformat,\n}\n")},
{str8_lit_comp("target"), str8_lit_comp("@commands(enable_cfg, launch_and_run, launch_and_step_into, remove_cfg)\n@collection_commands(add_target)\nx:\n{\n 'label': code_string,\n 'executable': path,\n 'arguments': string,\n 'working_directory': path,\n 'entry_point': code_string,\n 'stdout_path': path,\n 'stderr_path': path,\n 'stdin_path': path,\n 'environment': query,\n 'debug_subprocesses': bool,\n @no_expand @default(0) 'enabled': bool,\n}\n")},
{str8_lit_comp("breakpoint"), str8_lit_comp("@commands(enable_cfg, remove_cfg)\n@collection_commands(toggle_breakpoint, add_breakpoint, add_address_breakpoint, add_function_breakpoint)\nx:\n{\n 'label': code_string,\n 'condition': code_string,\n 'source_location': path_pt,\n 'address_location': code_string,\n 'hit_count': u64,\n @no_expand @default(1) 'enabled': bool,\n}\n")},
{str8_lit_comp("breakpoint"), str8_lit_comp("@commands(enable_cfg, remove_cfg)\n@collection_commands(toggle_breakpoint, add_breakpoint, add_address_breakpoint)\nx:\n{\n 'label': code_string,\n 'condition': code_string,\n 'source_location': path_pt,\n 'address_location': code_string,\n 'hit_count': u64,\n @no_expand @default(1) 'enabled': bool,\n}\n")},
{str8_lit_comp("watch_pin"), str8_lit_comp("@commands(remove_cfg)\n@collection_commands(add_watch_pin)\nx:\n{\n 'expression': code_string,\n 'view_rule': code_string,\n 'source_location': path_pt,\n 'address_location': code_string,\n}\n")},
{str8_lit_comp("file_path_map"), str8_lit_comp("@collection_commands(add_file_path_map) @commands(remove_cfg) x:{'source':path, 'dest':path}")},
{str8_lit_comp("auto_view_rule"), str8_lit_comp("@collection_commands(add_auto_view_rule) @commands(remove_cfg) x:{'type':code_string, 'view_rule':code_string}")},
@@ -382,7 +381,7 @@ Rng1U64 rd_reg_slot_range_table[42] =
{OffsetOf(RD_Regs, os_event), OffsetOf(RD_Regs, os_event) + sizeof(OS_Event *)},
};
RD_CmdKindInfo rd_cmd_kind_info_table[216] =
RD_CmdKindInfo rd_cmd_kind_info_table[215] =
{
{0},
{ str8_lit_comp("launch_and_run"), str8_lit_comp("Starts debugging a new instance of a target, then runs."), str8_lit_comp("launch,start,run,target"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:targets"), str8_lit_comp(""), CTRL_EntityKind_Null}},
@@ -553,7 +552,6 @@ RD_CmdKindInfo rd_cmd_kind_info_table[216] =
{ str8_lit_comp("relocate_cfg"), str8_lit_comp("Relocates a config tree."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}},
{ str8_lit_comp("add_breakpoint"), str8_lit_comp("Places a breakpoint at a given location (file path and line number, address, or symbol name)."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}},
{ str8_lit_comp("add_address_breakpoint"), str8_lit_comp("Places a breakpoint on the specified address."), str8_lit_comp(""), str8_lit_comp("$breakpoints,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Expr, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}},
{ str8_lit_comp("add_function_breakpoint"), str8_lit_comp("Places a breakpoint on the first address(es) of the specified function."), str8_lit_comp(""), str8_lit_comp("$breakpoints,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Expr, str8_lit_comp("query:procedures"), str8_lit_comp("symbol_lister"), CTRL_EntityKind_Null}},
{ str8_lit_comp("toggle_breakpoint"), str8_lit_comp("Places or removes a breakpoint at a given location (file path and line number, address, or symbol name)."), str8_lit_comp(""), str8_lit_comp("$text_pt,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}},
{ str8_lit_comp("enable_breakpoint"), str8_lit_comp("Enables a breakpoint."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:breakpoints"), str8_lit_comp(""), CTRL_EntityKind_Null}},
{ str8_lit_comp("disable_breakpoint"), str8_lit_comp("Disables a breakpoint."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:breakpoints"), str8_lit_comp(""), CTRL_EntityKind_Null}},
+1 -2
View File
@@ -224,7 +224,6 @@ RD_CmdKind_DuplicateCfg,
RD_CmdKind_RelocateCfg,
RD_CmdKind_AddBreakpoint,
RD_CmdKind_AddAddressBreakpoint,
RD_CmdKind_AddFunctionBreakpoint,
RD_CmdKind_ToggleBreakpoint,
RD_CmdKind_EnableBreakpoint,
RD_CmdKind_DisableBreakpoint,
@@ -645,7 +644,7 @@ RD_Query query;
.os_event = rd_regs()->os_event,\
C_LINKAGE_BEGIN
extern RD_VocabInfo rd_vocab_info_table[308];
extern RD_VocabInfo rd_vocab_info_table[307];
extern RD_NameSchemaInfo rd_name_schema_info_table[16];
extern Rng1U64 rd_reg_slot_range_table[42];
extern String8 rd_binding_version_remap_old_name_table[8];
+1 -2
View File
@@ -241,7 +241,7 @@ RD_VocabTable:
breakpoint,
```
@commands(enable_cfg, remove_cfg)
@collection_commands(toggle_breakpoint, add_breakpoint, add_address_breakpoint, add_function_breakpoint)
@collection_commands(toggle_breakpoint, add_breakpoint, add_address_breakpoint)
x:
{
'label': code_string,
@@ -614,7 +614,6 @@ RD_CmdTable: // | | | |
//- rjf: breakpoints
{AddBreakpoint 1 1 "" Null null Nil Null 0 0 0 0 0 0 0 CircleFilled "add_breakpoint" "Add Breakpoint" "Places a breakpoint at a given location (file path and line number, address, or symbol name)." "" "" }
{AddAddressBreakpoint 1 0 "" Expr null Nil Null 0 0 0 0 1 1 1 CircleFilled "add_address_breakpoint" "Add Address Breakpoint" "Places a breakpoint on the specified address." "" "$breakpoints," }
{AddFunctionBreakpoint 1 0 "query:procedures" Expr symbol_lister Nil Null 0 0 0 0 1 1 1 CircleFilled "add_function_breakpoint" "Add Function Breakpoint" "Places a breakpoint on the first address(es) of the specified function." "" "$breakpoints," }
{ToggleBreakpoint 1 1 "" Null null Nil Null 0 0 0 0 0 0 0 CircleFilled "toggle_breakpoint" "Toggle Breakpoint" "Places or removes a breakpoint at a given location (file path and line number, address, or symbol name)." "" "$text_pt," }
{EnableBreakpoint 1 1 "query:breakpoints" Cfg null Breakpoint Null 0 0 0 0 0 0 1 CheckFilled "enable_breakpoint" "Enable Breakpoint" "Enables a breakpoint." "" "" }
{DisableBreakpoint 1 1 "query:breakpoints" Cfg null Breakpoint Null 0 0 0 0 0 0 1 CheckHollow "disable_breakpoint" "Disable Breakpoint" "Disables a breakpoint." "" "" }
+17 -5
View File
@@ -10047,12 +10047,17 @@ rd_window_frame(void)
// rjf: hot effect extension
if(box->flags & UI_BoxFlag_DrawHotEffects)
{
B32 is_hot = ui_key_match(box->key, ui_hot_key());
Vec4F32 hover_color = ui_color_from_tags_key_name(box->tags_key, str8_lit("hover"));
// rjf: brighten
{
Vec4F32 color = hover_color;
color.w *= t*0.05f;
color.w *= 0.05f;
if(!is_hot)
{
color.w *= t;
}
R_Rect2DInst *inst = dr_rect(pad_2f32(box->rect, 1.f), v4f32(0, 0, 0, 0), 0, 0, 1.f);
inst->colors[Corner_00] = color;
inst->colors[Corner_10] = color;
@@ -10063,7 +10068,11 @@ rd_window_frame(void)
if(box->hot_t > 0.01f) DR_ClipScope(box->rect)
{
Vec4F32 color = hover_color;
color.w *= 0.02f*t;
color.w *= 0.02f;
if(!is_hot)
{
color.w *= t;
}
Vec2F32 center = ui_mouse();
Vec2F32 box_dim = dim_2f32(box->rect);
F32 max_dim = Max(box_dim.x, box_dim.y);
@@ -10249,7 +10258,10 @@ rd_window_frame(void)
if(b->flags & UI_BoxFlag_DrawHotEffects)
{
Vec4F32 color = ui_color_from_tags_key_name(box->tags_key, str8_lit("hover"));
color.w *= b->hot_t;
if(!ui_key_match(b->key, ui_hot_key()))
{
color.w *= b->hot_t;
}
R_Rect2DInst *inst = dr_rect(b_border_rect, color, 0, 1.f, 1.f);
inst->colors[Corner_01].w *= 0.2f;
inst->colors[Corner_11].w *= 0.2f;
@@ -16322,7 +16334,8 @@ Z(getting_started)
case RD_CmdKind_DeselectCfg:
{
RD_Cfg *cfg = rd_cfg_from_id(rd_regs()->cfg);
rd_cfg_release(rd_cfg_child_from_string(cfg, str8_lit("enabled")));
RD_Cfg *enabled_root = rd_cfg_child_from_string_or_alloc(cfg, str8_lit("enabled"));
rd_cfg_new_replacef(enabled_root, "0");
}break;
case RD_CmdKind_RemoveCfg:
{
@@ -16441,7 +16454,6 @@ Z(getting_started)
}
}break;
case RD_CmdKind_AddAddressBreakpoint:
case RD_CmdKind_AddFunctionBreakpoint:
{
rd_cmd(RD_CmdKind_AddBreakpoint, .file_path = str8_zero());
}break;
+116 -38
View File
@@ -1872,57 +1872,135 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
line_num < params->line_num_range.max;
line_num += 1, line_idx += 1)
{
RD_CfgList pins = params->line_pins[line_idx];
if(pins.count != 0) UI_Parent(line_extras_boxes[line_idx])
RD_Font(RD_FontSlot_Code)
UI_FontSize(params->font_size)
UI_PrefHeight(ui_px(params->line_height_px, 1.f))
RD_CfgList immediate_pins = {0};
String8 line_text = params->line_text[line_idx];
for(U64 off = 0, next_off = line_text.size;
off < line_text.size;
off = next_off)
{
for(RD_CfgNode *n = pins.first; n != 0; n = n->next)
// rjf: find next opener
String8 markup_opener = str8_lit("raddbg_pin(");
next_off = str8_find_needle(line_text, off, markup_opener, 0);
next_off += markup_opener.size;
// rjf: extract contents of markup
String8 contents = {0};
S32 nest = 1;
for(U64 off2 = next_off; off2 < line_text.size; off2 += 1)
{
RD_Cfg *pin = n->v;
String8 pin_expr = rd_expr_from_cfg(pin);
String8 pin_view_rule = rd_view_rule_from_cfg(pin);
String8 full_pin_expr = push_str8f(scratch.arena, "%S => %S", pin_expr, pin_view_rule);
E_Eval eval = e_eval_from_string(scratch.arena, full_pin_expr);
String8 eval_string = {0};
if(!e_type_key_match(e_type_key_zero(), eval.irtree.type_key))
if(line_text.str[off2] == '(')
{
eval_string = rd_value_string_from_eval(scratch.arena, str8_zero(), EV_StringFlag_ReadOnlyDisplayRules, 10, params->font, params->font_size, params->font_size*60.f, eval);
nest += 1;
}
ui_spacer(ui_em(1.5f, 1.f));
ui_set_next_pref_width(ui_children_sum(1));
UI_Key pin_box_key = ui_key_from_stringf(ui_key_zero(), "###pin_%p", pin);
UI_Box *pin_box = ui_build_box_from_key(UI_BoxFlag_AnimatePos|
UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable)|
UI_BoxFlag_DrawHotEffects|
UI_BoxFlag_DrawBorder, pin_box_key);
UI_Parent(pin_box) UI_PrefWidth(ui_text_dim(10, 1))
else if(line_text.str[off2] == ')')
{
Vec4F32 pin_color = rd_color_from_cfg(pin);
if(pin_color.w == 0)
nest -= 1;
if(nest == 0)
{
pin_color = rd_rgba_from_theme_color(RD_ThemeColor_CodeDefault);
contents = str8_substr(line_text, r1u64(next_off, off2));
break;
}
UI_PrefWidth(ui_em(1.5f, 1.f))
RD_Font(RD_FontSlot_Icons)
UI_TextAlignment(UI_TextAlign_Center)
UI_Flags(UI_BoxFlag_DisableTextTrunc)
UI_TextColor(pin_color)
}
}
// rjf: gather arguments
String8List args = {0};
{
S32 nest = 0;
U64 arg_start_off = 0;
for(U64 contents_off = 0; contents_off <= contents.size; contents_off += 1)
{
if(contents_off == contents.size || contents.str[contents_off] == ',')
{
UI_Signal sig = ui_buttonf("%S###pin_nub", rd_icon_kind_text_table[RD_IconKind_Pin]);
if(ui_dragging(sig) && !contains_2f32(sig.box->rect, ui_mouse()))
String8 arg = str8_substr(contents, r1u64(arg_start_off, contents_off));
str8_list_push(scratch.arena, &args, arg);
arg_start_off = contents_off+1;
}
if(contents_off < contents.size)
{
if(contents.str[contents_off] == '(')
{
RD_RegsScope(.cfg = pin->id) rd_drag_begin(RD_RegSlot_Cfg);
nest += 1;
}
else if(contents.str[contents_off] == ')')
{
nest -= 1;
}
}
rd_code_label(0.8f, 1, rd_rgba_from_theme_color(RD_ThemeColor_CodeDefault), pin_expr);
rd_code_label(0.6f, 1, rd_rgba_from_theme_color(RD_ThemeColor_CodeDefault), eval_string);
}
UI_Signal pin_sig = ui_signal_from_box(pin_box);
if(ui_key_match(pin_box_key, ui_hot_key()))
}
// rjf: extract fixed arguments
String8 expr_string = {0};
String8 view_rule_string = {0};
if(args.first != 0)
{
expr_string = args.first->string;
}
if(args.first->next != 0)
{
view_rule_string = args.first->next->string;
}
// rjf: build immediate pin for this markup
if(expr_string.size != 0)
{
RD_Cfg *immediate_root = rd_immediate_cfg_from_keyf("markup_pin_%I64x_%I64x", line_num, off);
RD_Cfg *pin = rd_cfg_child_from_string_or_alloc(immediate_root, str8_lit("watch_pin"));
RD_Cfg *expr = rd_cfg_child_from_string_or_alloc(pin, str8_lit("expression"));
RD_Cfg *view_rule = rd_cfg_child_from_string_or_alloc(pin, str8_lit("view_rule"));
rd_cfg_new_replace(expr, expr_string);
rd_cfg_new_replace(view_rule, view_rule_string);
rd_cfg_list_push(scratch.arena, &immediate_pins, pin);
}
}
RD_CfgList pin_lists[] =
{
params->line_pins[line_idx],
immediate_pins,
};
for EachElement(list_idx, pin_lists)
{
RD_CfgList pins = pin_lists[list_idx];
if(pins.count != 0) UI_Parent(line_extras_boxes[line_idx])
RD_Font(RD_FontSlot_Code)
UI_FontSize(params->font_size)
UI_PrefHeight(ui_px(params->line_height_px, 1.f))
{
for(RD_CfgNode *n = pins.first; n != 0; n = n->next)
{
rd_set_hover_eval(v2f32(pin_box->rect.x0, pin_box->rect.y1-2.f), pin_expr, pin_view_rule);
RD_Cfg *pin = n->v;
String8 pin_expr = rd_expr_from_cfg(pin);
String8 pin_view_rule = rd_view_rule_from_cfg(pin);
String8 full_pin_expr = push_str8f(scratch.arena, "%S => %S", pin_expr, pin_view_rule);
E_Eval eval = e_eval_from_string(scratch.arena, full_pin_expr);
String8 eval_string = {0};
if(!e_type_key_match(e_type_key_zero(), eval.irtree.type_key))
{
eval_string = rd_value_string_from_eval(scratch.arena, str8_zero(), EV_StringFlag_ReadOnlyDisplayRules, 10, params->font, params->font_size, params->font_size*60.f, eval);
}
ui_spacer(ui_em(1.5f, 1.f));
ui_set_next_pref_width(ui_children_sum(1));
UI_Key pin_box_key = ui_key_from_stringf(ui_key_zero(), "###pin_%p", pin);
UI_Box *pin_box = ui_build_box_from_key(UI_BoxFlag_AnimatePos|
UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable)|
UI_BoxFlag_DrawHotEffects|
UI_BoxFlag_DrawBorder, pin_box_key);
UI_Parent(pin_box) UI_PrefWidth(ui_text_dim(10, 1))
{
Vec4F32 pin_color = rd_color_from_cfg(pin);
if(pin_color.w == 0)
{
pin_color = rd_rgba_from_theme_color(RD_ThemeColor_CodeDefault);
}
rd_code_label(0.8f, 1, rd_rgba_from_theme_color(RD_ThemeColor_CodeDefault), pin_expr);
rd_code_label(0.6f, 1, rd_rgba_from_theme_color(RD_ThemeColor_CodeDefault), eval_string);
}
UI_Signal pin_sig = ui_signal_from_box(pin_box);
if(ui_key_match(pin_box_key, ui_hot_key()))
{
rd_set_hover_eval(v2f32(pin_box->rect.x0, pin_box->rect.y1-2.f), pin_expr, pin_view_rule);
}
}
}
}