From bd35ea83fc06509ec85573eb52cb43c780b6a464 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 26 Mar 2025 11:38:32 -0700 Subject: [PATCH] support for raddbg_pin markup on-the-fly watch pin annotations --- src/mule/mule_main.cpp | 7 +- src/raddbg/generated/raddbg.meta.c | 8 +- src/raddbg/generated/raddbg.meta.h | 3 +- src/raddbg/raddbg.mdesk | 3 +- src/raddbg/raddbg_core.c | 22 ++++- src/raddbg/raddbg_widgets.c | 154 ++++++++++++++++++++++------- 6 files changed, 142 insertions(+), 55 deletions(-) diff --git a/src/mule/mule_main.cpp b/src/mule/mule_main.cpp index 54c38c44..4742f35f 100644 --- a/src/mule/mule_main.cpp +++ b/src/mule/mule_main.cpp @@ -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; } diff --git a/src/raddbg/generated/raddbg.meta.c b/src/raddbg/generated/raddbg.meta.c index 580643ca..0e0c1425 100644 --- a/src/raddbg/generated/raddbg.meta.c +++ b/src/raddbg/generated/raddbg.meta.c @@ -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}}, diff --git a/src/raddbg/generated/raddbg.meta.h b/src/raddbg/generated/raddbg.meta.h index 079f6938..1839748b 100644 --- a/src/raddbg/generated/raddbg.meta.h +++ b/src/raddbg/generated/raddbg.meta.h @@ -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]; diff --git a/src/raddbg/raddbg.mdesk b/src/raddbg/raddbg.mdesk index 4a74ce1a..e535d07d 100644 --- a/src/raddbg/raddbg.mdesk +++ b/src/raddbg/raddbg.mdesk @@ -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." "" "" } diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 03ff2988..4100c2df 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -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; diff --git a/src/raddbg/raddbg_widgets.c b/src/raddbg/raddbg_widgets.c index b88ebf2f..b7725900 100644 --- a/src/raddbg/raddbg_widgets.c +++ b/src/raddbg/raddbg_widgets.c @@ -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); + } } } }