From 9805f8cd203fc0880d751f4b0055fecefc037a58 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 19 Feb 2025 08:37:34 -0800 Subject: [PATCH] begin work on lister-flavored watch windows; begin on using that for the query ui --- src/eval/eval_ir.c | 6 +- src/os/core/win32/os_core_win32.c | 21 + src/raddbg/raddbg_core.c | 659 +++++------------------------- src/raddbg/raddbg_core.h | 3 - src/raddbg/raddbg_views.c | 28 +- src/raddbg/raddbg_widgets.c | 567 +++++++++++++++++++++++++ src/raddbg/raddbg_widgets.h | 8 + 7 files changed, 711 insertions(+), 581 deletions(-) diff --git a/src/eval/eval_ir.c b/src/eval/eval_ir.c index 68eaf957..54c09a1f 100644 --- a/src/eval/eval_ir.c +++ b/src/eval/eval_ir.c @@ -169,7 +169,7 @@ E_LOOKUP_RANGE_FUNCTION_DEF(folder) if(0 <= idx && idx < accel->folders.count) { String8 folder_name = accel->folders.v[idx - 0]; - String8 folder_path = push_str8f(scratch.arena, "%S/%S", accel->folder_path, folder_name); + String8 folder_path = push_str8f(scratch.arena, "%S%s%S", accel->folder_path, accel->folder_path.size != 0 ? "/" : "", folder_name); expr = e_push_expr(arena, E_ExprKind_LeafValue, 0); expr->type_key = e_type_key_cons(.kind = E_TypeKind_Set, .name = str8_lit("folder")); expr->space = e_space_make(E_SpaceKind_FileSystem); @@ -179,7 +179,7 @@ E_LOOKUP_RANGE_FUNCTION_DEF(folder) else if(accel->folders.count <= idx && idx < accel->folders.count + accel->files.count) { String8 file_name = accel->files.v[idx - accel->folders.count]; - String8 file_path = push_str8f(scratch.arena, "%S/%S", accel->folder_path, file_name); + String8 file_path = push_str8f(scratch.arena, "%S%s%S", accel->folder_path, accel->folder_path.size != 0 ? "/" : "", file_name); expr = e_push_expr(arena, E_ExprKind_LeafValue, 0); expr->type_key = e_type_key_cons(.kind = E_TypeKind_Set, .name = str8_lit("file")); expr->space = e_space_make(E_SpaceKind_FileSystem); @@ -2253,7 +2253,7 @@ E_IRGEN_FUNCTION_DEF(default) Temp scratch = scratch_begin(&arena, 1); String8 file_path = path_normalized_from_string(scratch.arena, expr->string); FileProperties props = os_properties_from_file_path(file_path); - if(props.flags & FilePropertyFlag_IsFolder) + if(props.flags & FilePropertyFlag_IsFolder || props.modified == 0) { E_Space space = e_space_make(E_SpaceKind_FileSystem); result.root = e_irtree_set_space(arena, space, e_irtree_const_u(arena, e_id_from_string(file_path))); diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index 6a0e0281..f6ab35c3 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -547,6 +547,27 @@ os_properties_from_file_path(String8 path) os_w32_dense_time_from_file_time(&props.modified, &find_data.ftLastWriteTime); props.flags = os_w32_file_property_flags_from_dwFileAttributes(find_data.dwFileAttributes); } + else + { + Temp scratch = scratch_begin(0, 0); + WCHAR buffer[512] = {0}; + DWORD length = GetLogicalDriveStringsW(sizeof(buffer), buffer); + U64 last_slash_pos = str8_find_needle(path, 0, str8_lit("/"), StringMatchFlag_SlashInsensitive); + String8 path_trimmed = str8_prefix(path, last_slash_pos); + for(U64 off = 0; off < (U64)length;) + { + String16 next_drive_string_16 = str16_cstring((U16 *)buffer+off); + off += next_drive_string_16.size+1; + String8 next_drive_string = str8_from_16(scratch.arena, next_drive_string_16); + next_drive_string = str8_chop_last_slash(next_drive_string); + if(str8_match(path_trimmed, next_drive_string, StringMatchFlag_CaseInsensitive)) + { + props.flags |= FilePropertyFlag_IsFolder; + break; + } + } + scratch_end(scratch); + } FindClose(handle); scratch_end(scratch); return props; diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 7ece409f..32dda593 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -2090,362 +2090,7 @@ rd_target_from_cfg(Arena *arena, RD_Cfg *cfg) return target; } -internal DR_FStrList -rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg) -{ - DR_FStrList result = {0}; - { - Temp scratch = scratch_begin(&arena, 1); - - //- rjf: unpack config - B32 is_disabled = rd_disabled_from_cfg(cfg); - RD_Location loc = rd_location_from_cfg(cfg); - D_Target target = rd_target_from_cfg(scratch.arena, cfg); - String8 label_string = rd_label_from_cfg(cfg); - String8 expr_string = rd_expr_from_cfg(cfg); - String8 collection_name = {0}; - String8 file_path = {0}; - Vec4F32 rgba = rd_color_from_cfg(cfg); - if(rgba.w == 0) - { - rgba = ui_color_from_name(str8_lit("text")); - } - Vec4F32 rgba_secondary = rgba; - UI_TagF("weak") - { - rgba_secondary = ui_color_from_name(str8_lit("text")); - } - RD_IconKind icon_kind = rd_icon_kind_from_code_name(cfg->string); - B32 is_from_command_line = 0; - { - RD_Cfg *cmd_line_root = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("command_line")); - for(RD_Cfg *p = cfg->parent; p != &rd_nil_cfg; p = p->parent) - { - if(p == cmd_line_root) - { - is_from_command_line = 1; - break; - } - } - } - B32 is_within_window = 0; - { - for(RD_Cfg *p = cfg->parent; p != &rd_nil_cfg; p = p->parent) - { - if(str8_match(p->string, str8_lit("window"), 0)) - { - is_within_window = 1; - break; - } - } - } - if(expr_string.size != 0) - { - String8 query_name = rd_query_from_eval_string(arena, expr_string); - if(query_name.size != 0 && !str8_match(query_name, str8_lit("watches"), 0)) - { - String8 query_code_name = query_name; - String8 query_display_name = rd_display_from_code_name(query_code_name); - collection_name = query_display_name; - if(query_display_name.size == 0) - { - query_code_name = rd_singular_from_code_name_plural(query_name); - collection_name = rd_display_plural_from_code_name(query_code_name); - } - RD_IconKind query_icon_kind = rd_icon_kind_from_code_name(query_code_name); - if(query_icon_kind != RD_IconKind_Null) - { - icon_kind = query_icon_kind; - } - } - else - { - file_path = rd_file_path_from_eval_string(arena, expr_string); - if(file_path.size != 0) - { - icon_kind = RD_IconKind_FileOutline; - } - } - } - - //- rjf: set up color/size for all parts of the title - // - // the "running" part implies that it changes as things are added - - // so if a primary title is pushed, we can make the rest of the title - // more faded/smaller, but only after a primary title is pushed, - // which could be caused by many different potential parts of a cfg. - // - DR_FStrParams params = {rd_font_from_slot(RD_FontSlot_Main), rd_raster_flags_from_slot(RD_FontSlot_Main), rgba, ui_top_font_size()}; - B32 running_is_secondary = 0; -#define start_secondary() if(!running_is_secondary){running_is_secondary = 1; params.color = rgba_secondary; params.size = ui_top_font_size()*0.95f;} - - //- rjf: push icon - if(icon_kind != RD_IconKind_Null) - { - dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[icon_kind], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = rgba_secondary); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - } - - //- rjf: push warning icon for command-line entities - if(is_from_command_line) - { - dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[RD_IconKind_Info], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = rgba_secondary); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - } - - //- rjf: push view title, if from window, and no file path - if(is_within_window && file_path.size == 0 && collection_name.size == 0) - { - String8 view_display_name = rd_display_from_code_name(cfg->string); - if(view_display_name.size != 0) - { - dr_fstrs_push_new(arena, &result, ¶ms, view_display_name); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - start_secondary(); - } - } - - //- rjf: push label - if(label_string.size != 0) - { - dr_fstrs_push_new(arena, &result, ¶ms, label_string, .font = rd_font_from_slot(RD_FontSlot_Code), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Code)); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - start_secondary(); - } - - //- rjf: push collection name - if(collection_name.size != 0) - { - dr_fstrs_push_new(arena, &result, ¶ms, collection_name); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - start_secondary(); - } - - //- rjf: query is file path - do specific file name strings - else if(file_path.size != 0) - { - // rjf: compute disambiguated file name - String8List qualifiers = {0}; - String8 file_name = str8_skip_last_slash(file_path); - if(rd_state->ambiguous_path_slots_count != 0) - { - U64 hash = d_hash_from_string__case_insensitive(file_name); - U64 slot_idx = hash%rd_state->ambiguous_path_slots_count; - RD_AmbiguousPathNode *node = 0; - { - for(RD_AmbiguousPathNode *n = rd_state->ambiguous_path_slots[slot_idx]; - n != 0; - n = n->next) - { - if(str8_match(n->name, file_name, StringMatchFlag_CaseInsensitive)) - { - node = n; - break; - } - } - } - if(node != 0 && node->paths.node_count > 1) - { - // rjf: get all colliding paths - String8Array collisions = str8_array_from_list(scratch.arena, &node->paths); - - // rjf: get all reversed path parts for each collision - String8List *collision_parts_reversed = push_array(scratch.arena, String8List, collisions.count); - for EachIndex(idx, collisions.count) - { - String8List parts = str8_split_path(scratch.arena, collisions.v[idx]); - for(String8Node *n = parts.first; n != 0; n = n->next) - { - str8_list_push_front(scratch.arena, &collision_parts_reversed[idx], n->string); - } - } - - // rjf: get the search path & its reversed parts - String8List parts = str8_split_path(scratch.arena, file_path); - String8List parts_reversed = {0}; - for(String8Node *n = parts.first; n != 0; n = n->next) - { - str8_list_push_front(scratch.arena, &parts_reversed, n->string); - } - - // rjf: iterate all collision part reversed lists, in lock-step with - // search path; disqualify until we only have one path remaining; gather - // qualifiers - { - U64 num_collisions_left = collisions.count; - String8Node **collision_nodes = push_array(scratch.arena, String8Node *, collisions.count); - for EachIndex(idx, collisions.count) - { - collision_nodes[idx] = collision_parts_reversed[idx].first; - } - for(String8Node *n = parts_reversed.first; num_collisions_left > 1 && n != 0; n = n->next) - { - B32 part_is_qualifier = 0; - for EachIndex(idx, collisions.count) - { - if(collision_nodes[idx] != 0 && !str8_match(collision_nodes[idx]->string, n->string, StringMatchFlag_CaseInsensitive)) - { - collision_nodes[idx] = 0; - num_collisions_left -= 1; - part_is_qualifier = 1; - } - else if(collision_nodes[idx] != 0) - { - collision_nodes[idx] = collision_nodes[idx]->next; - } - } - if(part_is_qualifier) - { - str8_list_push_front(scratch.arena, &qualifiers, n->string); - } - } - } - } - } - - // rjf: push qualifiers - for(String8Node *n = qualifiers.first; n != 0; n = n->next) - { - String8 string = push_str8f(arena, "<%S> ", n->string); - dr_fstrs_push_new(arena, &result, ¶ms, string, .color = ui_top_palette()->text_weak); - } - - // rjf: push file name - dr_fstrs_push_new(arena, &result, ¶ms, push_str8_copy(arena, str8_skip_last_slash(file_path))); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - start_secondary(); - } - - //- rjf: cfg has expression attached -> use that - else if(expr_string.size != 0 && !str8_match(cfg->string, str8_lit("watch"), 0)) - { - dr_fstrs_push_new(arena, &result, ¶ms, expr_string, .font = rd_font_from_slot(RD_FontSlot_Code), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Code)); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - start_secondary(); - } - - //- rjf: push text location - if(loc.file_path.size != 0) - { - String8 location_string = push_str8f(arena, "%S:%I64d:%I64d", str8_skip_last_slash(loc.file_path), loc.pt.line, loc.pt.column); - dr_fstrs_push_new(arena, &result, ¶ms, location_string); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - start_secondary(); - } - - //- rjf: push target executable name - if(target.exe.size != 0) - { - dr_fstrs_push_new(arena, &result, ¶ms, str8_skip_last_slash(target.exe)); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - start_secondary(); - } - - //- rjf: push target arguments - if(target.args.size != 0) - { - dr_fstrs_push_new(arena, &result, ¶ms, target.args); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - } - - //- rjf: push conditions - { - String8 condition = rd_cfg_child_from_string(cfg, str8_lit("condition"))->first->string; - if(condition.size != 0) - { - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("if "), .font = rd_font_from_slot(RD_FontSlot_Code), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Code)); - RD_Font(RD_FontSlot_Code) - { - DR_FStrList fstrs = rd_fstrs_from_code_string(arena, 1.f, 0, params.color, condition); - dr_fstrs_concat_in_place(&result, &fstrs); - } - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - } - } - - //- rjf: push disabled marker - if(is_disabled) - { - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("(Disabled)")); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - } - - //- rjf: push hit count - { - String8 hit_count_value_string = rd_cfg_child_from_string(cfg, str8_lit("hit_count"))->first->string; - U64 hit_count = 0; - if(try_u64_from_str8_c_rules(hit_count_value_string, &hit_count)) - { - String8 hit_count_text = push_str8f(arena, "(%I64u hit%s)", hit_count, hit_count == 1 ? "" : "s"); - dr_fstrs_push_new(arena, &result, ¶ms, hit_count_text); - } - } - - //- rjf: special case: auto view rule - if(str8_match(cfg->string, str8_lit("auto_view_rule"), 0)) - { - String8 src_string = rd_cfg_child_from_string(cfg, str8_lit("source"))->first->string; - String8 dst_string = rd_cfg_child_from_string(cfg, str8_lit("dest"))->first->string; - Vec4F32 src_color = rgba; - Vec4F32 dst_color = rgba; - DR_FStrList src_fstrs = {0}; - DR_FStrList dst_fstrs = {0}; - if(src_string.size == 0) - { - src_string = str8_lit("(type)"); - src_color = ui_top_palette()->text_weak; - dr_fstrs_push_new(arena, &src_fstrs, ¶ms, src_string, .color = src_color); - } - else RD_Font(RD_FontSlot_Code) - { - src_fstrs = rd_fstrs_from_code_string(arena, 1.f, 0, src_color, src_string); - } - if(dst_string.size == 0) - { - dst_string = str8_lit("(view rule)"); - dst_color = ui_top_palette()->text_weak; - dr_fstrs_push_new(arena, &dst_fstrs, ¶ms, dst_string, .color = dst_color); - } - else RD_Font(RD_FontSlot_Code) - { - dst_fstrs = rd_fstrs_from_code_string(arena, 1.f, 0, dst_color, dst_string); - } - dr_fstrs_concat_in_place(&result, &src_fstrs); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[RD_IconKind_RightArrow], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = ui_top_palette()->text_weak); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - dr_fstrs_concat_in_place(&result, &dst_fstrs); - } - - //- rjf: special case: file path maps - if(str8_match(cfg->string, str8_lit("file_path_map"), 0)) - { - String8 src_string = rd_cfg_child_from_string(cfg, str8_lit("source"))->first->string; - String8 dst_string = rd_cfg_child_from_string(cfg, str8_lit("dest"))->first->string; - Vec4F32 src_color = rgba; - Vec4F32 dst_color = rgba; - if(src_string.size == 0) - { - src_string = str8_lit("(source path)"); - src_color = ui_top_palette()->text_weak; - } - if(dst_string.size == 0) - { - dst_string = str8_lit("(destination path)"); - dst_color = ui_top_palette()->text_weak; - } - dr_fstrs_push_new(arena, &result, ¶ms, src_string, .color = src_color); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[RD_IconKind_RightArrow], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = ui_top_palette()->text_weak); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - dr_fstrs_push_new(arena, &result, ¶ms, dst_string, .color = dst_color); - } - -#undef start_secondary - scratch_end(scratch); - } - return result; -} + internal MD_Node * rd_schema_from_name(Arena *arena, String8 name) @@ -2733,145 +2378,6 @@ rd_name_from_ctrl_entity(Arena *arena, CTRL_Entity *entity) return string; } -internal DR_FStrList -rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_extras) -{ - DR_FStrList result = {0}; - - //- rjf: unpack entity info - F32 extras_size = ui_top_font_size()*0.95f; - Vec4F32 color = rd_color_from_ctrl_entity(entity); - if(color.w == 0) - { - color = ui_top_palette()->text; - } - Vec4F32 secondary_color = ui_top_palette()->text_weak; - String8 name = rd_name_from_ctrl_entity(arena, entity); - RD_IconKind icon_kind = RD_IconKind_Null; - B32 name_is_code = 0; - switch(entity->kind) - { - default:{}break; - case CTRL_EntityKind_Machine: {icon_kind = RD_IconKind_Machine;}break; - case CTRL_EntityKind_Process: {icon_kind = RD_IconKind_Threads;}break; - case CTRL_EntityKind_Thread: {icon_kind = RD_IconKind_Thread; name_is_code = 1;}break; - case CTRL_EntityKind_Module: {icon_kind = RD_IconKind_Module;}break; - } - - //- rjf: set up drawing params - DR_FStrParams params = {rd_font_from_slot(RD_FontSlot_Code), rd_raster_flags_from_slot(RD_FontSlot_Code), color, ui_top_font_size()}; - - //- rjf: push icon - if(icon_kind != RD_IconKind_Null) - { - dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[icon_kind], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = secondary_color); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - } - - //- rjf: push frozen icon, if frozen - if((entity->kind == CTRL_EntityKind_Machine || - entity->kind == CTRL_EntityKind_Process || - entity->kind == CTRL_EntityKind_Thread) && - ctrl_entity_tree_is_frozen(entity)) - { - dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[RD_IconKind_Locked], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = ui_top_palette()->background_bad); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - } - - //- rjf: push containing process prefix - if(entity->kind == CTRL_EntityKind_Thread || - entity->kind == CTRL_EntityKind_Module) - { - CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process); - if(processes.count > 1) - { - CTRL_Entity *process = ctrl_entity_ancestor_from_kind(entity, CTRL_EntityKind_Process); - String8 process_name = rd_name_from_ctrl_entity(arena, process); - Vec4F32 process_color = rd_color_from_ctrl_entity(process); - if(process_color.w == 0) - { - process_color = color; - } - if(process_name.size != 0) - { - dr_fstrs_push_new(arena, &result, ¶ms, process_name, .font = rd_font_from_slot(RD_FontSlot_Main), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Main), .color = process_color); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - dr_fstrs_push_new(arena, &result, ¶ms, push_str8f(arena, "(PID: %I64u)", process->id), .font = rd_font_from_slot(RD_FontSlot_Main), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Main), .color = secondary_color, .size = ui_top_font_size()*0.9f); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" / "), .color = secondary_color); - } - } - } - - //- rjf: push name - dr_fstrs_push_new(arena, &result, ¶ms, name, - .font = rd_font_from_slot(name_is_code ? RD_FontSlot_Code : RD_FontSlot_Main), - .raster_flags = rd_raster_flags_from_slot(name_is_code ? RD_FontSlot_Code : RD_FontSlot_Main), - .color = color); - - //- rjf: push PID - if(entity->kind == CTRL_EntityKind_Process) - { - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - dr_fstrs_push_new(arena, &result, ¶ms, push_str8f(arena, " (PID: %I64u)", entity->id), .font = rd_font_from_slot(RD_FontSlot_Main), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Main), .color = secondary_color, .size = ui_top_font_size()*0.85f); - } - - //- rjf: threads get callstack extras - if(entity->kind == CTRL_EntityKind_Thread && include_extras) - { - Vec4F32 symbol_color = ui_color_from_name(str8_lit("code_symbol")); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - DI_Scope *di_scope = di_scope_open(); - CTRL_Entity *process = ctrl_entity_ancestor_from_kind(entity, CTRL_EntityKind_Process); - Arch arch = entity->arch; - CTRL_Unwind unwind = d_query_cached_unwind_from_thread(entity); - for(U64 idx = 0, limit = 6; idx < unwind.frames.count && idx < limit; idx += 1) - { - CTRL_UnwindFrame *f = &unwind.frames.v[unwind.frames.count - 1 - idx]; - U64 rip_vaddr = regs_rip_from_arch_block(arch, f->regs); - CTRL_Entity *module = ctrl_module_from_process_vaddr(process, rip_vaddr); - U64 rip_voff = ctrl_voff_from_vaddr(module, rip_vaddr); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); - RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 0); - if(rdi != &di_rdi_parsed_nil) - { - RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, rip_voff); - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &name.size); - name = push_str8_copy(arena, name); - if(name.size != 0) - { - dr_fstrs_push_new(arena, &result, ¶ms, name, .size = extras_size, .color = symbol_color); - if(idx+1 < unwind.frames.count) - { - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" > "), .color = secondary_color, .size = extras_size); - if(idx+1 == limit) - { - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("..."), .color = secondary_color, .size = extras_size); - } - } - } - } - } - di_scope_close(di_scope); - } - - //- rjf: modules get debug info status extras - if(entity->kind == CTRL_EntityKind_Module && include_extras) - { - DI_Scope *di_scope = di_scope_open(); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(entity); - RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 0); - if(rdi->raw_data_size == 0) - { - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("(Symbols not found)"), .font = rd_font_from_slot(RD_FontSlot_Main), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Main), .size = extras_size, .color = secondary_color); - } - di_scope_close(di_scope); - } - - return result; -} - //////////////////////////////// //~ rjf: Evaluation Spaces @@ -4503,8 +4009,9 @@ rd_window_frame(void) RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); B32 window_is_focused = (os_window_is_focused(ws->os) || ws->window_temporarily_focused_ipc); B32 popup_is_open = (rd_state->popup_active); - B32 query_is_open = (ws->top_query_lister != 0); + B32 query_is_open = (rd_cfg_child_from_string(window, str8_lit("query")) != &rd_nil_cfg); B32 hover_eval_is_open = (!popup_is_open && + !query_is_open && ws->hover_eval_string.size != 0 && ws->hover_eval_first_frame_idx+20 < ws->hover_eval_last_frame_idx && rd_state->frame_index-ws->hover_eval_last_frame_idx < 20); @@ -5173,8 +4680,10 @@ ws->cfg_palettes[RD_PaletteCode_##name].selection = current->colors[RD_The } //////////////////////////// - //- rjf: do query lister stack controls + //- rjf: build listers // +#if 0 // TODO(rjf): @cfg + //- rjf: do query lister stack controls if(ws->top_query_lister != 0) { if(ui_slot_press(UI_EventActionSlot_Cancel)) @@ -5192,10 +4701,6 @@ ws->cfg_palettes[RD_PaletteCode_##name].selection = current->colors[RD_The scratch_end(scratch); } } - - //////////////////////////// - //- rjf: build listers - // for(ListerTask *task = first_lister_task; task != 0; task = task->next) { DI_Scope *di_scope = di_scope_open(); @@ -5490,6 +4995,7 @@ ws->cfg_palettes[RD_PaletteCode_##name].selection = current->colors[RD_The di_scope_close(di_scope); } +#endif #if 0 // TODO(rjf): @cfg_lister //////////////////////////// @@ -6115,6 +5621,92 @@ ws->cfg_palettes[RD_PaletteCode_##name].selection = current->colors[RD_The } } + //////////////////////////// + //- rjf: build query + // + { + RD_Cfg *query = rd_cfg_child_from_string(window, str8_lit("query")); + if(query != &rd_nil_cfg) + { + //- rjf: unpack query parameters + RD_Cfg *root = query; + RD_Cfg *view = rd_cfg_child_from_string_or_alloc(root, str8_lit("watch")); + rd_cfg_new(view, str8_lit("lister")); + RD_Cfg *expr = rd_cfg_child_from_string_or_alloc(view, str8_lit("expression")); + String8 query_expression = str8_lit("query:procedures"); + rd_cfg_new_replace(expr, query_expression); + E_Eval query_eval = e_eval_from_string(scratch.arena, query_expression); + F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); + + //- rjf: build + RD_RegsScope(.view = view->id) + { + Vec2F32 content_rect_center = center_2f32(content_rect); + Vec2F32 content_rect_dim = dim_2f32(content_rect); + EV_BlockTree predicted_block_tree = ev_block_tree_from_exprs(scratch.arena, rd_view_eval_view(), str8_zero(), query_eval.exprs); + F32 query_open_t = ui_anim(ui_key_from_string(ui_key_zero(), str8_lit("query_open_t")), 1.f); + F32 query_width_px = floor_f32(dim_2f32(content_rect).x * 0.35f); + F32 max_query_height_px = content_rect_dim.y*0.8f; + F32 query_height_px = max_query_height_px; + Rng2F32 query_rect = r2f32p(content_rect_center.x - query_width_px/2, + content_rect_center.y - max_query_height_px/2.f, + content_rect_center.x + query_width_px/2, + content_rect_center.y - max_query_height_px/2.f + query_height_px*query_open_t); + + RD_Font(RD_FontSlot_Code) + UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Main)) + UI_TagF("floating") + UI_Focus(UI_FocusKind_On) + UI_PrefHeight(ui_px(row_height_px, 1.f)) + { + //- rjf: build top-level container + UI_Box *container = &ui_nil_box; + UI_Rect(query_rect) + UI_Squish(0.25f-0.25f*query_open_t) + UI_Transparency(1.f-query_open_t) + UI_ChildLayoutAxis(Axis2_Y) + { + container = ui_build_box_from_string(UI_BoxFlag_Clickable| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawBackgroundBlur| + UI_BoxFlag_DisableFocusOverlay| + UI_BoxFlag_DrawDropShadow, + str8_lit("query_container")); + } + + //- rjf: fill container + UI_Parent(container) UI_Focus(UI_FocusKind_Null) + { + ui_set_next_pref_width(ui_pct(1, 0)); + ui_set_next_pref_height(ui_pct(1, 0)); + ui_set_next_child_layout_axis(Axis2_Y); + UI_Box *view_contents_container = ui_build_box_from_stringf(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_Clip, "###view_contents_container"); + UI_Parent(view_contents_container) UI_WidthFill + { + rd_view_ui(view_contents_container->rect); + } + } + } + } + + //- rjf: do interactions + if(ui_slot_press(UI_EventActionSlot_Cancel)) + { + rd_cmd(RD_CmdKind_CancelQuery); + } + if(ui_slot_press(UI_EventActionSlot_Accept)) + { + } + + //- rjf: build darkening rectangle over rest of screen + UI_Rect(window_rect) UI_TagF("inactive") + { + ui_build_box_from_key(UI_BoxFlag_DrawBackground, ui_key_zero()); + } + } + } + //////////////////////////// //- rjf: top bar // @@ -6820,7 +6412,7 @@ ws->cfg_palettes[RD_PaletteCode_##name].selection = current->colors[RD_The // rjf: close dropdown UI_Key close_ctx_menu_key = ui_key_from_stringf(ui_key_zero(), "###close_ctx_menu"); - UI_CtxMenu(close_ctx_menu_key) + UI_CtxMenu(close_ctx_menu_key) UI_TagF("implicit") { if(ui_clicked(rd_icon_buttonf(RD_IconKind_Window, 0, "Close Window"))) { @@ -10783,44 +10375,6 @@ rd_vocab_info_from_code_name_plural(String8 code_name_plural) return result; } -internal DR_FStrList -rd_title_fstrs_from_code_name(Arena *arena, String8 code_name) -{ - DR_FStrList result = {0}; - { - RD_VocabInfo *info = rd_vocab_info_from_code_name(code_name); - - //- rjf: set up color/size for all parts of the title - // - // the "running" part implies that it changes as things are added - - // so if a primary title is pushed, we can make the rest of the title - // more faded/smaller, but only after a primary title is pushed, - // which could be caused by many different potential parts of a cfg. - // - DR_FStrParams params = {rd_font_from_slot(RD_FontSlot_Main), rd_raster_flags_from_slot(RD_FontSlot_Main), ui_color_from_name(str8_lit("text")), ui_top_font_size()}; - - //- rjf: push icon - if(info->icon_kind != RD_IconKind_Null) UI_Tag(str8_lit("weak")) - { - dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[info->icon_kind], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = ui_color_from_name(str8_lit("text"))); - dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - } - - //- rjf: push display name - if(info->display_name.size != 0) - { - dr_fstrs_push_new(arena, &result, ¶ms, info->display_name); - } - - //- rjf: push code name as a fallback - else - { - dr_fstrs_push_new(arena, &result, ¶ms, code_name, .font = rd_font_from_slot(RD_FontSlot_Code), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Code)); - } - } - return result; -} - //////////////////////////////// //~ rjf: Continuous Frame Requests @@ -14704,19 +14258,10 @@ Z(getting_started) //- rjf: query stack case RD_CmdKind_PushQuery: { - RD_Cfg *wcfg = rd_cfg_from_id(rd_regs()->window); - RD_WindowState *ws = rd_window_state_from_cfg(wcfg); - if(ws != &rd_nil_window_state) - { - Arena *arena = arena_alloc(); - RD_Lister *lister = push_array(arena, RD_Lister, 1); - lister->arena = arena; - lister->regs = rd_regs_copy(lister->arena, rd_regs()); - lister->input_string_size = Min(rd_regs()->string.size, sizeof(lister->input_buffer)); - lister->input_cursor = lister->input_mark = txt_pt(1, lister->input_string_size+1); - MemoryCopy(lister->input_buffer, rd_regs()->string.str, lister->input_string_size); - SLLStackPush(ws->top_query_lister, lister); - } + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_Cfg *current_query = rd_cfg_child_from_string(window, str8_lit("query")); + rd_cfg_release(current_query); + RD_Cfg *new_query = rd_cfg_new(window, str8_lit("query")); }break; case RD_CmdKind_CompleteQuery: { @@ -14767,13 +14312,7 @@ Z(getting_started) case RD_CmdKind_CancelQuery: { RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); - RD_WindowState *ws = rd_window_state_from_cfg(window); - RD_Lister *top_lister = ws->top_query_lister; - if(top_lister != 0) - { - SLLStackPop(ws->top_query_lister); - arena_release(top_lister->arena); - } + rd_cfg_release(rd_cfg_child_from_string(window, str8_lit("query"))); }break; //- rjf: developer commands diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index 202ea108..10f2d07a 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -998,7 +998,6 @@ internal String8 rd_label_from_cfg(RD_Cfg *cfg); internal String8 rd_expr_from_cfg(RD_Cfg *cfg); internal String8 rd_view_rule_from_cfg(RD_Cfg *cfg); internal D_Target rd_target_from_cfg(Arena *arena, RD_Cfg *cfg); -internal DR_FStrList rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg); internal MD_Node *rd_schema_from_name(Arena *arena, String8 name); @@ -1019,7 +1018,6 @@ internal E_Expr *rd_tag_from_cfg(Arena *arena, RD_Cfg *cfg); internal Vec4F32 rd_color_from_ctrl_entity(CTRL_Entity *entity); internal String8 rd_name_from_ctrl_entity(Arena *arena, CTRL_Entity *entity); -internal DR_FStrList rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_extras); //////////////////////////////// //~ rjf: Evaluation Spaces @@ -1183,7 +1181,6 @@ internal RD_VocabInfo *rd_vocab_info_from_code_name_plural(String8 code_name_plu #define rd_display_plural_from_code_name(code_name) (rd_vocab_info_from_code_name(code_name)->display_name_plural) #define rd_icon_kind_from_code_name(code_name) (rd_vocab_info_from_code_name(code_name)->icon_kind) #define rd_singular_from_code_name_plural(code_name_plural) (rd_vocab_info_from_code_name_plural(code_name_plural)->code_name) -internal DR_FStrList rd_title_fstrs_from_code_name(Arena *arena, String8 code_name); //////////////////////////////// //~ rjf: Continuous Frame Requests diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index cef5752f..a1fee200 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -1030,6 +1030,12 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) { if(0){} + // rjf: lister rows + else if(rd_cfg_child_from_string(rd_cfg_from_id(rd_regs()->view), str8_lit("lister")) != &rd_nil_cfg) + { + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, .flags = RD_WatchCellFlag_Button, .pct = 1.f); + } + // rjf: top-level cfg rows else if(is_top_level && evalled_cfg != &rd_nil_cfg) { @@ -1116,16 +1122,9 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) DR_FStrParams params = {rd_font_from_slot(RD_FontSlot_Main), rd_raster_flags_from_slot(RD_FontSlot_Main), ui_top_palette()->text, ui_top_font_size()}; E_Type *type = e_type_from_key__cached(info.eval.type_key); String8 file_path = e_string_from_id(info.eval.value.u64); - String8 file_name = str8_skip_last_slash(file_path); + DR_FStrList fstrs = rd_title_fstrs_from_file_path(arena, file_path); if(str8_match(type->name, str8_lit("folder"), 0)) { - DR_FStrList fstrs = {0}; - if(file_name.size) - { - dr_fstrs_push_new(arena, &fstrs, ¶ms, rd_icon_kind_text_table[RD_IconKind_FolderClosedFilled], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = ui_top_palette()->text_weak); - dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" ")); - dr_fstrs_push_new(arena, &fstrs, ¶ms, file_name); - } rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Expr, .flags = RD_WatchCellFlag_Button|RD_WatchCellFlag_IsNonCode, .pct = 1.f, @@ -1139,13 +1138,6 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) RD_Cfg *w_cfg = style->first; F32 next_pct = 0; #define take_pct() (next_pct = (F32)f64_from_str8(w_cfg->string), w_cfg = w_cfg->next, next_pct) - DR_FStrList fstrs = {0}; - if(file_name.size) - { - dr_fstrs_push_new(arena, &fstrs, ¶ms, rd_icon_kind_text_table[RD_IconKind_FileOutline], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = ui_top_palette()->text_weak); - dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" ")); - dr_fstrs_push_new(arena, &fstrs, ¶ms, file_name); - } rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Expr, .flags = RD_WatchCellFlag_Button|RD_WatchCellFlag_IsNonCode, .default_pct = 0.35f, @@ -1435,6 +1427,12 @@ rd_info_from_watch_row_cell(Arena *arena, EV_Row *row, EV_StringFlags string_fla String8 cmd_name = rd_cmd_kind_info_table[cmd_kind].string; result.cmd_name = cmd_name; } + else if(result.eval.space.kind == E_SpaceKind_FileSystem) + { + String8 file_path = e_string_from_id(result.eval.value.u64); + result.fstrs = rd_title_fstrs_from_file_path(arena, file_path); + result.flags |= RD_WatchCellFlag_Button; + } }break; case RD_WatchCellKind_Eval: { diff --git a/src/raddbg/raddbg_widgets.c b/src/raddbg/raddbg_widgets.c index 0f6376d3..0088425b 100644 --- a/src/raddbg/raddbg_widgets.c +++ b/src/raddbg/raddbg_widgets.c @@ -1,6 +1,573 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +//////////////////////////////// +//~ rjf: UI Widgets: Fancy Title Strings + +internal DR_FStrList +rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg) +{ + DR_FStrList result = {0}; + { + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: unpack config + B32 is_disabled = rd_disabled_from_cfg(cfg); + RD_Location loc = rd_location_from_cfg(cfg); + D_Target target = rd_target_from_cfg(scratch.arena, cfg); + String8 label_string = rd_label_from_cfg(cfg); + String8 expr_string = rd_expr_from_cfg(cfg); + String8 collection_name = {0}; + String8 file_path = {0}; + Vec4F32 rgba = rd_color_from_cfg(cfg); + if(rgba.w == 0) + { + rgba = ui_color_from_name(str8_lit("text")); + } + Vec4F32 rgba_secondary = rgba; + UI_TagF("weak") + { + rgba_secondary = ui_color_from_name(str8_lit("text")); + } + RD_IconKind icon_kind = rd_icon_kind_from_code_name(cfg->string); + B32 is_from_command_line = 0; + { + RD_Cfg *cmd_line_root = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("command_line")); + for(RD_Cfg *p = cfg->parent; p != &rd_nil_cfg; p = p->parent) + { + if(p == cmd_line_root) + { + is_from_command_line = 1; + break; + } + } + } + B32 is_within_window = 0; + { + for(RD_Cfg *p = cfg->parent; p != &rd_nil_cfg; p = p->parent) + { + if(str8_match(p->string, str8_lit("window"), 0)) + { + is_within_window = 1; + break; + } + } + } + if(expr_string.size != 0) + { + String8 query_name = rd_query_from_eval_string(arena, expr_string); + if(query_name.size != 0 && !str8_match(query_name, str8_lit("watches"), 0)) + { + String8 query_code_name = query_name; + String8 query_display_name = rd_display_from_code_name(query_code_name); + collection_name = query_display_name; + if(query_display_name.size == 0) + { + query_code_name = rd_singular_from_code_name_plural(query_name); + collection_name = rd_display_plural_from_code_name(query_code_name); + } + RD_IconKind query_icon_kind = rd_icon_kind_from_code_name(query_code_name); + if(query_icon_kind != RD_IconKind_Null) + { + icon_kind = query_icon_kind; + } + } + else + { + file_path = rd_file_path_from_eval_string(arena, expr_string); + if(file_path.size != 0) + { + icon_kind = RD_IconKind_FileOutline; + } + } + } + + //- rjf: set up color/size for all parts of the title + // + // the "running" part implies that it changes as things are added - + // so if a primary title is pushed, we can make the rest of the title + // more faded/smaller, but only after a primary title is pushed, + // which could be caused by many different potential parts of a cfg. + // + DR_FStrParams params = {rd_font_from_slot(RD_FontSlot_Main), rd_raster_flags_from_slot(RD_FontSlot_Main), rgba, ui_top_font_size()}; + B32 running_is_secondary = 0; +#define start_secondary() if(!running_is_secondary){running_is_secondary = 1; params.color = rgba_secondary; params.size = ui_top_font_size()*0.95f;} + + //- rjf: push icon + if(icon_kind != RD_IconKind_Null) + { + dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[icon_kind], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = rgba_secondary); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + } + + //- rjf: push warning icon for command-line entities + if(is_from_command_line) + { + dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[RD_IconKind_Info], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = rgba_secondary); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + } + + //- rjf: push view title, if from window, and no file path + if(is_within_window && file_path.size == 0 && collection_name.size == 0) + { + String8 view_display_name = rd_display_from_code_name(cfg->string); + if(view_display_name.size != 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, view_display_name); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + start_secondary(); + } + } + + //- rjf: push label + if(label_string.size != 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, label_string, .font = rd_font_from_slot(RD_FontSlot_Code), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Code)); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + start_secondary(); + } + + //- rjf: push collection name + if(collection_name.size != 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, collection_name); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + start_secondary(); + } + + //- rjf: query is file path - do specific file name strings + else if(file_path.size != 0) + { + // rjf: compute disambiguated file name + String8List qualifiers = {0}; + String8 file_name = str8_skip_last_slash(file_path); + if(rd_state->ambiguous_path_slots_count != 0) + { + U64 hash = d_hash_from_string__case_insensitive(file_name); + U64 slot_idx = hash%rd_state->ambiguous_path_slots_count; + RD_AmbiguousPathNode *node = 0; + { + for(RD_AmbiguousPathNode *n = rd_state->ambiguous_path_slots[slot_idx]; + n != 0; + n = n->next) + { + if(str8_match(n->name, file_name, StringMatchFlag_CaseInsensitive)) + { + node = n; + break; + } + } + } + if(node != 0 && node->paths.node_count > 1) + { + // rjf: get all colliding paths + String8Array collisions = str8_array_from_list(scratch.arena, &node->paths); + + // rjf: get all reversed path parts for each collision + String8List *collision_parts_reversed = push_array(scratch.arena, String8List, collisions.count); + for EachIndex(idx, collisions.count) + { + String8List parts = str8_split_path(scratch.arena, collisions.v[idx]); + for(String8Node *n = parts.first; n != 0; n = n->next) + { + str8_list_push_front(scratch.arena, &collision_parts_reversed[idx], n->string); + } + } + + // rjf: get the search path & its reversed parts + String8List parts = str8_split_path(scratch.arena, file_path); + String8List parts_reversed = {0}; + for(String8Node *n = parts.first; n != 0; n = n->next) + { + str8_list_push_front(scratch.arena, &parts_reversed, n->string); + } + + // rjf: iterate all collision part reversed lists, in lock-step with + // search path; disqualify until we only have one path remaining; gather + // qualifiers + { + U64 num_collisions_left = collisions.count; + String8Node **collision_nodes = push_array(scratch.arena, String8Node *, collisions.count); + for EachIndex(idx, collisions.count) + { + collision_nodes[idx] = collision_parts_reversed[idx].first; + } + for(String8Node *n = parts_reversed.first; num_collisions_left > 1 && n != 0; n = n->next) + { + B32 part_is_qualifier = 0; + for EachIndex(idx, collisions.count) + { + if(collision_nodes[idx] != 0 && !str8_match(collision_nodes[idx]->string, n->string, StringMatchFlag_CaseInsensitive)) + { + collision_nodes[idx] = 0; + num_collisions_left -= 1; + part_is_qualifier = 1; + } + else if(collision_nodes[idx] != 0) + { + collision_nodes[idx] = collision_nodes[idx]->next; + } + } + if(part_is_qualifier) + { + str8_list_push_front(scratch.arena, &qualifiers, n->string); + } + } + } + } + } + + // rjf: push qualifiers + for(String8Node *n = qualifiers.first; n != 0; n = n->next) + { + String8 string = push_str8f(arena, "<%S> ", n->string); + dr_fstrs_push_new(arena, &result, ¶ms, string, .color = ui_top_palette()->text_weak); + } + + // rjf: push file name + dr_fstrs_push_new(arena, &result, ¶ms, push_str8_copy(arena, str8_skip_last_slash(file_path))); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + start_secondary(); + } + + //- rjf: cfg has expression attached -> use that + else if(expr_string.size != 0 && !str8_match(cfg->string, str8_lit("watch"), 0)) + { + dr_fstrs_push_new(arena, &result, ¶ms, expr_string, .font = rd_font_from_slot(RD_FontSlot_Code), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Code)); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + start_secondary(); + } + + //- rjf: push text location + if(loc.file_path.size != 0) + { + String8 location_string = push_str8f(arena, "%S:%I64d:%I64d", str8_skip_last_slash(loc.file_path), loc.pt.line, loc.pt.column); + dr_fstrs_push_new(arena, &result, ¶ms, location_string); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + start_secondary(); + } + + //- rjf: push target executable name + if(target.exe.size != 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, str8_skip_last_slash(target.exe)); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + start_secondary(); + } + + //- rjf: push target arguments + if(target.args.size != 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, target.args); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + } + + //- rjf: push conditions + { + String8 condition = rd_cfg_child_from_string(cfg, str8_lit("condition"))->first->string; + if(condition.size != 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("if "), .font = rd_font_from_slot(RD_FontSlot_Code), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Code)); + RD_Font(RD_FontSlot_Code) + { + DR_FStrList fstrs = rd_fstrs_from_code_string(arena, 1.f, 0, params.color, condition); + dr_fstrs_concat_in_place(&result, &fstrs); + } + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + } + } + + //- rjf: push disabled marker + if(is_disabled) + { + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("(Disabled)")); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + } + + //- rjf: push hit count + { + String8 hit_count_value_string = rd_cfg_child_from_string(cfg, str8_lit("hit_count"))->first->string; + U64 hit_count = 0; + if(try_u64_from_str8_c_rules(hit_count_value_string, &hit_count)) + { + String8 hit_count_text = push_str8f(arena, "(%I64u hit%s)", hit_count, hit_count == 1 ? "" : "s"); + dr_fstrs_push_new(arena, &result, ¶ms, hit_count_text); + } + } + + //- rjf: special case: auto view rule + if(str8_match(cfg->string, str8_lit("auto_view_rule"), 0)) + { + String8 src_string = rd_cfg_child_from_string(cfg, str8_lit("source"))->first->string; + String8 dst_string = rd_cfg_child_from_string(cfg, str8_lit("dest"))->first->string; + Vec4F32 src_color = rgba; + Vec4F32 dst_color = rgba; + DR_FStrList src_fstrs = {0}; + DR_FStrList dst_fstrs = {0}; + if(src_string.size == 0) + { + src_string = str8_lit("(type)"); + src_color = ui_top_palette()->text_weak; + dr_fstrs_push_new(arena, &src_fstrs, ¶ms, src_string, .color = src_color); + } + else RD_Font(RD_FontSlot_Code) + { + src_fstrs = rd_fstrs_from_code_string(arena, 1.f, 0, src_color, src_string); + } + if(dst_string.size == 0) + { + dst_string = str8_lit("(view rule)"); + dst_color = ui_top_palette()->text_weak; + dr_fstrs_push_new(arena, &dst_fstrs, ¶ms, dst_string, .color = dst_color); + } + else RD_Font(RD_FontSlot_Code) + { + dst_fstrs = rd_fstrs_from_code_string(arena, 1.f, 0, dst_color, dst_string); + } + dr_fstrs_concat_in_place(&result, &src_fstrs); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[RD_IconKind_RightArrow], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = ui_top_palette()->text_weak); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + dr_fstrs_concat_in_place(&result, &dst_fstrs); + } + + //- rjf: special case: file path maps + if(str8_match(cfg->string, str8_lit("file_path_map"), 0)) + { + String8 src_string = rd_cfg_child_from_string(cfg, str8_lit("source"))->first->string; + String8 dst_string = rd_cfg_child_from_string(cfg, str8_lit("dest"))->first->string; + Vec4F32 src_color = rgba; + Vec4F32 dst_color = rgba; + if(src_string.size == 0) + { + src_string = str8_lit("(source path)"); + src_color = ui_top_palette()->text_weak; + } + if(dst_string.size == 0) + { + dst_string = str8_lit("(destination path)"); + dst_color = ui_top_palette()->text_weak; + } + dr_fstrs_push_new(arena, &result, ¶ms, src_string, .color = src_color); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[RD_IconKind_RightArrow], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = ui_top_palette()->text_weak); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &result, ¶ms, dst_string, .color = dst_color); + } + +#undef start_secondary + scratch_end(scratch); + } + return result; +} + +internal DR_FStrList +rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_extras) +{ + DR_FStrList result = {0}; + + //- rjf: unpack entity info + F32 extras_size = ui_top_font_size()*0.95f; + Vec4F32 color = rd_color_from_ctrl_entity(entity); + if(color.w == 0) + { + color = ui_top_palette()->text; + } + Vec4F32 secondary_color = ui_top_palette()->text_weak; + String8 name = rd_name_from_ctrl_entity(arena, entity); + RD_IconKind icon_kind = RD_IconKind_Null; + B32 name_is_code = 0; + switch(entity->kind) + { + default:{}break; + case CTRL_EntityKind_Machine: {icon_kind = RD_IconKind_Machine;}break; + case CTRL_EntityKind_Process: {icon_kind = RD_IconKind_Threads;}break; + case CTRL_EntityKind_Thread: {icon_kind = RD_IconKind_Thread; name_is_code = 1;}break; + case CTRL_EntityKind_Module: {icon_kind = RD_IconKind_Module;}break; + } + + //- rjf: set up drawing params + DR_FStrParams params = {rd_font_from_slot(RD_FontSlot_Code), rd_raster_flags_from_slot(RD_FontSlot_Code), color, ui_top_font_size()}; + + //- rjf: push icon + if(icon_kind != RD_IconKind_Null) + { + dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[icon_kind], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = secondary_color); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + } + + //- rjf: push frozen icon, if frozen + if((entity->kind == CTRL_EntityKind_Machine || + entity->kind == CTRL_EntityKind_Process || + entity->kind == CTRL_EntityKind_Thread) && + ctrl_entity_tree_is_frozen(entity)) + { + dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[RD_IconKind_Locked], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = ui_top_palette()->background_bad); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + } + + //- rjf: push containing process prefix + if(entity->kind == CTRL_EntityKind_Thread || + entity->kind == CTRL_EntityKind_Module) + { + CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process); + if(processes.count > 1) + { + CTRL_Entity *process = ctrl_entity_ancestor_from_kind(entity, CTRL_EntityKind_Process); + String8 process_name = rd_name_from_ctrl_entity(arena, process); + Vec4F32 process_color = rd_color_from_ctrl_entity(process); + if(process_color.w == 0) + { + process_color = color; + } + if(process_name.size != 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, process_name, .font = rd_font_from_slot(RD_FontSlot_Main), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Main), .color = process_color); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &result, ¶ms, push_str8f(arena, "(PID: %I64u)", process->id), .font = rd_font_from_slot(RD_FontSlot_Main), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Main), .color = secondary_color, .size = ui_top_font_size()*0.9f); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" / "), .color = secondary_color); + } + } + } + + //- rjf: push name + dr_fstrs_push_new(arena, &result, ¶ms, name, + .font = rd_font_from_slot(name_is_code ? RD_FontSlot_Code : RD_FontSlot_Main), + .raster_flags = rd_raster_flags_from_slot(name_is_code ? RD_FontSlot_Code : RD_FontSlot_Main), + .color = color); + + //- rjf: push PID + if(entity->kind == CTRL_EntityKind_Process) + { + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &result, ¶ms, push_str8f(arena, " (PID: %I64u)", entity->id), .font = rd_font_from_slot(RD_FontSlot_Main), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Main), .color = secondary_color, .size = ui_top_font_size()*0.85f); + } + + //- rjf: threads get callstack extras + if(entity->kind == CTRL_EntityKind_Thread && include_extras) + { + Vec4F32 symbol_color = ui_color_from_name(str8_lit("code_symbol")); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + DI_Scope *di_scope = di_scope_open(); + CTRL_Entity *process = ctrl_entity_ancestor_from_kind(entity, CTRL_EntityKind_Process); + Arch arch = entity->arch; + CTRL_Unwind unwind = d_query_cached_unwind_from_thread(entity); + for(U64 idx = 0, limit = 6; idx < unwind.frames.count && idx < limit; idx += 1) + { + CTRL_UnwindFrame *f = &unwind.frames.v[unwind.frames.count - 1 - idx]; + U64 rip_vaddr = regs_rip_from_arch_block(arch, f->regs); + CTRL_Entity *module = ctrl_module_from_process_vaddr(process, rip_vaddr); + U64 rip_voff = ctrl_voff_from_vaddr(module, rip_vaddr); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 0); + if(rdi != &di_rdi_parsed_nil) + { + RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, rip_voff); + String8 name = {0}; + name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &name.size); + name = push_str8_copy(arena, name); + if(name.size != 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, name, .size = extras_size, .color = symbol_color); + if(idx+1 < unwind.frames.count) + { + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" > "), .color = secondary_color, .size = extras_size); + if(idx+1 == limit) + { + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("..."), .color = secondary_color, .size = extras_size); + } + } + } + } + } + di_scope_close(di_scope); + } + + //- rjf: modules get debug info status extras + if(entity->kind == CTRL_EntityKind_Module && include_extras) + { + DI_Scope *di_scope = di_scope_open(); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(entity); + RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 0); + if(rdi->raw_data_size == 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("(Symbols not found)"), .font = rd_font_from_slot(RD_FontSlot_Main), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Main), .size = extras_size, .color = secondary_color); + } + di_scope_close(di_scope); + } + + return result; +} + +internal DR_FStrList +rd_title_fstrs_from_code_name(Arena *arena, String8 code_name) +{ + DR_FStrList result = {0}; + { + RD_VocabInfo *info = rd_vocab_info_from_code_name(code_name); + + //- rjf: set up color/size for all parts of the title + // + // the "running" part implies that it changes as things are added - + // so if a primary title is pushed, we can make the rest of the title + // more faded/smaller, but only after a primary title is pushed, + // which could be caused by many different potential parts of a cfg. + // + DR_FStrParams params = {rd_font_from_slot(RD_FontSlot_Main), rd_raster_flags_from_slot(RD_FontSlot_Main), ui_color_from_name(str8_lit("text")), ui_top_font_size()}; + + //- rjf: push icon + if(info->icon_kind != RD_IconKind_Null) UI_Tag(str8_lit("weak")) + { + dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[info->icon_kind], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = ui_color_from_name(str8_lit("text"))); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + } + + //- rjf: push display name + if(info->display_name.size != 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, info->display_name); + } + + //- rjf: push code name as a fallback + else + { + dr_fstrs_push_new(arena, &result, ¶ms, code_name, .font = rd_font_from_slot(RD_FontSlot_Code), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Code)); + } + } + return result; +} + +internal DR_FStrList +rd_title_fstrs_from_file_path(Arena *arena, String8 file_path) +{ + DR_FStrList fstrs = {0}; + String8 file_name = str8_skip_last_slash(file_path); + FileProperties props = os_properties_from_file_path(file_path); + RD_IconKind icon_kind = RD_IconKind_FileOutline; + if(props.flags & FilePropertyFlag_IsFolder) + { + icon_kind = RD_IconKind_FolderClosedFilled; + } + if(file_path.size == 0 || str8_match(file_path, str8_lit("/"), StringMatchFlag_SlashInsensitive)) + { + icon_kind = RD_IconKind_Machine; + file_name = str8_lit("File System"); + } + DR_FStrParams params = {rd_font_from_slot(RD_FontSlot_Main), rd_raster_flags_from_slot(RD_FontSlot_Main), ui_color_from_name(str8_lit("text")), ui_top_font_size()}; + UI_TagF("weak") + { + dr_fstrs_push_new(arena, &fstrs, ¶ms, + rd_icon_kind_text_table[icon_kind], + .font = rd_font_from_slot(RD_FontSlot_Icons), + .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), + .color = ui_color_from_name(str8_lit("text"))); + } + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &fstrs, ¶ms, file_name); + return fstrs; +} + //////////////////////////////// //~ rjf: UI Widgets: Loading Overlay diff --git a/src/raddbg/raddbg_widgets.h b/src/raddbg/raddbg_widgets.h index 913375db..dfd3691c 100644 --- a/src/raddbg/raddbg_widgets.h +++ b/src/raddbg/raddbg_widgets.h @@ -95,6 +95,14 @@ struct RD_CodeSliceSignal #define RD_Palette(code) UI_Palette(rd_palette_from_code(code)) #define RD_Font(slot) UI_Font(rd_font_from_slot(slot)) UI_TextRasterFlags(rd_raster_flags_from_slot((slot))) +//////////////////////////////// +//~ rjf: UI Widgets: Fancy Title Strings + +internal DR_FStrList rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg); +internal DR_FStrList rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_extras); +internal DR_FStrList rd_title_fstrs_from_code_name(Arena *arena, String8 code_name); +internal DR_FStrList rd_title_fstrs_from_file_path(Arena *arena, String8 file_path); + //////////////////////////////// //~ rjf: UI Widgets: Loading Overlay