first pass at watch expr location locks - still some jank around the edges due to eval incompleteness, but works for basic cases

This commit is contained in:
Ryan Fleury
2026-07-28 11:18:00 -07:00
parent ae8960d563
commit 0fe5aa5a43
11 changed files with 258 additions and 149 deletions
+17
View File
@@ -1225,9 +1225,26 @@ d_modules_from_dbgi_key(Arena *arena, DI_Key dbgi_key)
return list;
}
internal D_Entity *
d_process_from_id(U64 id)
{
// TODO(rjf): @multimachine need machine ID here?
D_Entity *process = &d_entity_nil;
D_EntityArray processes = d_entity_array_from_kind(D_EntityKind_Process);
for EachIndex(idx, processes.count)
{
if(processes.v[idx]->id == id)
{
process = processes.v[idx];
}
}
return process;
}
internal D_Entity *
d_thread_from_id(U64 id)
{
// TODO(rjf): @multimachine need machine ID here?
D_Entity *thread = &d_entity_nil;
D_EntityArray threads = d_entity_array_from_kind(D_EntityKind_Thread);
for EachIndex(idx, threads.count)
+1
View File
@@ -519,6 +519,7 @@ internal void d_entity_equip_string(D_EntityCtxRWStore *store, D_Entity *entity,
internal D_EntityCtxLookupAccel *d_thread_entity_ctx_lookup_accel(void);
internal D_EntityArray d_entity_array_from_kind(D_EntityKind kind);
internal D_EntityList d_modules_from_dbgi_key(Arena *arena, DI_Key dbgi_key);
internal D_Entity *d_process_from_id(U64 id);
internal D_Entity *d_thread_from_id(U64 id);
//- rjf: applying events to entity caches
@@ -208,8 +208,6 @@ ev_view_alloc(void)
view->arena = arena;
view->expand_slots_count = 256;
view->expand_slots = push_array(arena, EV_ExpandSlot, view->expand_slots_count);
view->key_view_rule_slots_count = 256;
view->key_view_rule_slots = push_array(arena, EV_KeyViewRuleSlot, view->key_view_rule_slots_count);
return view;
}
@@ -246,36 +244,6 @@ ev_expansion_from_key(EV_View *view, EV_Key key)
return (node != 0 && node->expanded);
}
internal String8
ev_view_rule_from_key(EV_View *view, EV_Key key)
{
String8 result = {0};
//- rjf: key -> hash * slot idx * slot
U64 hash = ev_hash_from_key(key);
U64 slot_idx = hash%view->key_view_rule_slots_count;
EV_KeyViewRuleSlot *slot = &view->key_view_rule_slots[slot_idx];
//- rjf: slot -> existing node
EV_KeyViewRuleNode *existing_node = 0;
for(EV_KeyViewRuleNode *n = slot->first; n != 0; n = n->hash_next)
{
if(ev_key_match(n->key, key))
{
existing_node = n;
break;
}
}
//- rjf: node -> result
if(existing_node != 0)
{
result = str8(existing_node->buffer, existing_node->buffer_string_size);
}
return result;
}
internal void
ev_key_set_expansion(EV_View *view, EV_Key parent_key, EV_Key key, B32 expanded)
{
@@ -348,44 +316,6 @@ ev_key_set_expansion(EV_View *view, EV_Key parent_key, EV_Key key, B32 expanded)
}
}
internal void
ev_key_set_view_rule(EV_View *view, EV_Key key, String8 view_rule_string)
{
//- rjf: key -> hash * slot idx * slot
U64 hash = ev_hash_from_key(key);
U64 slot_idx = hash%view->key_view_rule_slots_count;
EV_KeyViewRuleSlot *slot = &view->key_view_rule_slots[slot_idx];
//- rjf: slot -> existing node
EV_KeyViewRuleNode *existing_node = 0;
for(EV_KeyViewRuleNode *n = slot->first; n != 0; n = n->hash_next)
{
if(ev_key_match(n->key, key))
{
existing_node = n;
break;
}
}
//- rjf: existing node * new node -> node
EV_KeyViewRuleNode *node = existing_node;
if(node == 0)
{
node = push_array(view->arena, EV_KeyViewRuleNode, 1);
DLLPushBack_NP(slot->first, slot->last, node, hash_next, hash_prev);
node->key = key;
node->buffer_cap = 512;
node->buffer = push_array(view->arena, U8, node->buffer_cap);
}
//- rjf: mutate node
if(node != 0)
{
node->buffer_string_size = ClampTop(view_rule_string.size, node->buffer_cap);
MemoryCopy(node->buffer, view_rule_string.str, node->buffer_string_size);
}
}
////////////////////////////////
//~ rjf: View Rule Info Table Building / Selection / Lookups
@@ -40,26 +40,6 @@ struct EV_ExpandSlot
EV_ExpandNode *last;
};
//- rjf: hash table for view rules
typedef struct EV_KeyViewRuleNode EV_KeyViewRuleNode;
struct EV_KeyViewRuleNode
{
EV_KeyViewRuleNode *hash_next;
EV_KeyViewRuleNode *hash_prev;
EV_Key key;
U8 *buffer;
U64 buffer_cap;
U64 buffer_string_size;
};
typedef struct EV_KeyViewRuleSlot EV_KeyViewRuleSlot;
struct EV_KeyViewRuleSlot
{
EV_KeyViewRuleNode *first;
EV_KeyViewRuleNode *last;
};
//- rjf: view state bundle
typedef struct EV_View EV_View;
@@ -69,9 +49,6 @@ struct EV_View
EV_ExpandSlot *expand_slots;
U64 expand_slots_count;
EV_ExpandNode *free_expand_node;
EV_KeyViewRuleSlot *key_view_rule_slots;
U64 key_view_rule_slots_count;
EV_KeyViewRuleNode *free_key_view_rule_node;
};
////////////////////////////////
@@ -328,9 +305,7 @@ internal void ev_view_release(EV_View *view);
//- rjf: lookups / mutations
internal EV_ExpandNode *ev_expand_node_from_key(EV_View *view, EV_Key key);
internal B32 ev_expansion_from_key(EV_View *view, EV_Key key);
internal String8 ev_view_rule_from_key(EV_View *view, EV_Key key);
internal void ev_key_set_expansion(EV_View *view, EV_Key parent_key, EV_Key key, B32 expanded);
internal void ev_key_set_view_rule(EV_View *view, EV_Key key, String8 view_rule_string);
////////////////////////////////
//~ rjf: View Rule Info Table Building / Selection / Lookups
+10 -3
View File
@@ -62,7 +62,7 @@ str8_lit_comp(""),
str8_lit_comp(""),
};
RD_VocabInfo rd_vocab_info_table[369] =
RD_VocabInfo rd_vocab_info_table[372] =
{
{str8_lit_comp("type_view"), str8_lit_comp("type_views"), str8_lit_comp("Type View"), str8_lit_comp("Type Views"), RD_IconKind_Binoculars},
{str8_lit_comp("file_path_map"), str8_lit_comp("file_path_maps"), str8_lit_comp("File Path Map"), str8_lit_comp("File Path Maps"), RD_IconKind_FileOutline},
@@ -300,6 +300,9 @@ RD_VocabInfo rd_vocab_info_table[369] =
{str8_lit_comp("accept"), str8_lit_comp(""), str8_lit_comp("Accept"), str8_lit_comp(""), RD_IconKind_CheckFilled},
{str8_lit_comp("cancel"), str8_lit_comp(""), str8_lit_comp("Cancel"), str8_lit_comp(""), RD_IconKind_X},
{str8_lit_comp("focus_menu"), str8_lit_comp(""), str8_lit_comp("Focus Menu"), str8_lit_comp(""), RD_IconKind_List},
{str8_lit_comp("lock"), str8_lit_comp(""), str8_lit_comp("Lock"), str8_lit_comp(""), RD_IconKind_Locked},
{str8_lit_comp("unlock"), str8_lit_comp(""), str8_lit_comp("Unlock"), str8_lit_comp(""), RD_IconKind_Unlocked},
{str8_lit_comp("toggle_lock"), str8_lit_comp(""), str8_lit_comp("Toggle Lock"), str8_lit_comp(""), RD_IconKind_Locked},
{str8_lit_comp("move_left"), str8_lit_comp(""), str8_lit_comp("Move Left"), str8_lit_comp(""), RD_IconKind_Null},
{str8_lit_comp("move_right"), str8_lit_comp(""), str8_lit_comp("Move Right"), str8_lit_comp(""), RD_IconKind_Null},
{str8_lit_comp("move_up"), str8_lit_comp(""), str8_lit_comp("Move Up"), str8_lit_comp(""), RD_IconKind_Null},
@@ -594,7 +597,7 @@ Rng1U64 rd_reg_slot_range_table[54] =
{OffsetOf(RD_Regs, wm_event), OffsetOf(RD_Regs, wm_event) + sizeof(WM_Event *)},
};
RD_CmdKindInfo rd_cmd_kind_info_table[256] =
RD_CmdKindInfo rd_cmd_kind_info_table[259] =
{
{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")}},
@@ -719,6 +722,9 @@ RD_CmdKindInfo rd_cmd_kind_info_table[256] =
{ str8_lit_comp("accept"), str8_lit_comp("Accepts current changes, or answers prompts in the affirmative."), 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("cancel"), str8_lit_comp("Rejects current changes, exits temporary menus, or answers prompts in the negative."), 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("focus_menu"), str8_lit_comp("Focuses the menu for the selected interface, if there is one."), 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("lock"), str8_lit_comp("Locks the current selection, if applicable."), 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("unlock"), str8_lit_comp("Unlocks the current selection, if applicable."), 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("toggle_lock"), str8_lit_comp("Toggles the lock state of the current selection, if applicable."), 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("move_left"), str8_lit_comp("Moves the cursor or selection left."), 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("move_right"), str8_lit_comp("Moves the cursor or selection right."), 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("move_up"), str8_lit_comp("Moves the cursor or selection up."), 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("")}},
@@ -854,7 +860,7 @@ RD_CmdKindInfo rd_cmd_kind_info_table[256] =
{ str8_lit_comp("geo3d"), str8_lit_comp("Opens a Geometry (3D) tab."), {0}, str8_lit_comp("{tab_commands}"), RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs},
};
struct {String8 string; CFG_Binding binding;} rd_default_binding_table[116] =
struct {String8 string; CFG_Binding binding;} rd_default_binding_table[117] =
{
{str8_lit_comp("kill_all"), {WM_Key_F5, 0 |WM_Modifier_Shift }},
{str8_lit_comp("step_into_inst"), {WM_Key_F11, 0 |WM_Modifier_Alt}},
@@ -907,6 +913,7 @@ struct {String8 string; CFG_Binding binding;} rd_default_binding_table[116] =
{str8_lit_comp("accept"), {WM_Key_Space, 0 }},
{str8_lit_comp("cancel"), {WM_Key_Esc, 0 }},
{str8_lit_comp("focus_menu"), {WM_Key_D, 0 |WM_Modifier_Alt}},
{str8_lit_comp("toggle_lock"), {WM_Key_L, 0 |WM_Modifier_Ctrl }},
{str8_lit_comp("move_left"), {WM_Key_Left, 0 }},
{str8_lit_comp("move_right"), {WM_Key_Right, 0 }},
{str8_lit_comp("move_up"), {WM_Key_Up, 0 }},
+4 -1
View File
@@ -190,6 +190,9 @@ RD_CmdKind_Edit,
RD_CmdKind_Accept,
RD_CmdKind_Cancel,
RD_CmdKind_FocusMenu,
RD_CmdKind_Lock,
RD_CmdKind_Unlock,
RD_CmdKind_ToggleLock,
RD_CmdKind_MoveLeft,
RD_CmdKind_MoveRight,
RD_CmdKind_MoveUp,
@@ -623,7 +626,7 @@ Z(getting_started)\
C_LINKAGE_BEGIN
extern String8 rd_tab_fast_path_view_name_table[25];
extern String8 rd_tab_fast_path_query_name_table[25];
extern RD_VocabInfo rd_vocab_info_table[369];
extern RD_VocabInfo rd_vocab_info_table[372];
extern RD_NameSchemaInfo rd_name_schema_info_table[39];
extern String8 rd_reg_slot_code_name_table[54];
extern Rng1U64 rd_reg_slot_range_table[54];
+4
View File
@@ -1087,6 +1087,9 @@ RD_CmdTable: // | | | |
{Accept 0 1 1 "" Null 0 0 0 0 0 0 0 CheckFilled "accept" "Accept" "Accepts current changes, or answers prompts in the affirmative." "" "" }
{Cancel 0 1 1 "" Null 0 0 0 0 0 0 0 X "cancel" "Cancel" "Rejects current changes, exits temporary menus, or answers prompts in the negative." "" "" }
{FocusMenu 0 1 1 "" Null 0 0 0 0 0 0 0 List "focus_menu" "Focus Menu" "Focuses the menu for the selected interface, if there is one." "" "" }
{Lock 0 1 1 "" Null 0 0 0 0 0 0 0 Locked "lock" "Lock" "Locks the current selection, if applicable." "" "" }
{Unlock 0 1 1 "" Null 0 0 0 0 0 0 0 Unlocked "unlock" "Unlock" "Unlocks the current selection, if applicable." "" "" }
{ToggleLock 0 1 1 "" Null 0 0 0 0 0 0 0 Locked "toggle_lock" "Toggle Lock" "Toggles the lock state of the current selection, if applicable." "" "" }
//- rjf: directional movement & text controls
{MoveLeft 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_left" "Move Left" "Moves the cursor or selection left." "" "" }
@@ -1373,6 +1376,7 @@ RD_DefaultBindingTable:
{ "accept" Space 0 0 0 }
{ "cancel" Esc 0 0 0 }
{ "focus_menu" D 0 0 alt }
{ "toggle_lock" L ctrl 0 0 }
//- rjf: directional movement & text controls
{ "move_left" Left 0 0 0 }
+155 -8
View File
@@ -2049,6 +2049,35 @@ rd_view_ui(Rng2F32 rect)
ewv->text_edit_arena = rd_push_view_arena();
}
//////////////////////////////
//- rjf: adjust locked expressions which have been invalidated
//
for(CFG_Node *child = view->first; child != &cfg_nil_node; child = child->next)
{
if(str8_match(child->string, s("watch_expression"), 0))
{
CFG_Node *locked = cfg_node_child_from_string(child, s("locked"));
if(locked != &cfg_nil_node)
{
CFG_Node *pid_cfg = cfg_node_child_from_string_or_alloc(rd_state->cfg, locked, s("pid"));
U64 pid = u64_from_str8(pid_cfg->first->string, 10);
D_Entity *process = d_process_from_id(pid);
if(process == &d_entity_nil)
{
D_Entity *current_process = d_entity_from_handle(rd_regs()->process);
if(current_process != &d_entity_nil)
{
cfg_node_new_replacef(rd_state->cfg, pid_cfg, "%I64u", current_process->id);
}
else
{
cfg_node_release(rd_state->cfg, locked);
}
}
}
}
}
//////////////////////////////
//- rjf: unpack arguments
//
@@ -2694,6 +2723,79 @@ rd_view_ui(Rng2F32 rect)
}
}
//////////////////////////
//- rjf: [table] do cell-granularity lock operations
//
if(!ewv->text_editing &&
(evt->slot == UI_EventActionSlot_Lock ||
evt->slot == UI_EventActionSlot_Unlock ||
evt->slot == UI_EventActionSlot_ToggleLock) &&
(selection_tbl.min.y != 0 || selection_tbl.max.y != 0))
{
EV_WindowedRowList rows = ev_rows_from_num_range(scratch.arena, eval_view, &block_ranges, r1u64(selection_tbl.min.y, selection_tbl.max.y+1));
EV_WindowedRowNode *row_node = rows.first;
if(row_node != 0)
{
taken = 1;
B32 next_locked = 0;
B32 found_next_locked = 0;
for(S64 y = selection_tbl.min.y; y <= selection_tbl.max.y && row_node != 0; y += 1, row_node = row_node->next)
{
// rjf: unpack row info
EV_Row *row = &row_node->row;
RD_WatchRowInfo row_info = rd_watch_row_info_from_row(scratch.arena, row);
CFG_Node *cfg = row_info.group_cfg_child;
// rjf: determine if row can be locked
B32 row_can_be_locked = 0;
if(str8_match(row_info.group_cfg_name, s("watch_expression"), 0) &&
cfg != &cfg_nil_node &&
row->eval.string.size != 0)
{
E_Space space = row->eval.space;
D_Entity *entity = rd_ctrl_entity_from_eval_space(space);
B32 is_memory_eval = (space.kind == D_EvalSpaceKind_Entity && entity->kind == D_EntityKind_Process);
row_can_be_locked = (is_memory_eval &&
(row->eval.irtree.mode == E_Mode_Offset) ||
(row->eval.irtree.mode == E_Mode_Value &&
e_type_kind_is_pointer_or_ref(e_type_kind_from_key(e_type_key_unwrap(row->eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative)))));
}
// rjf: determine if row is locked
B32 row_is_locked = (cfg_node_child_from_string(cfg, s("locked")) != &cfg_nil_node);
if(row_can_be_locked && !found_next_locked)
{
found_next_locked = 1;
next_locked = !row_is_locked;
}
// rjf: toggle lock on row
if(row_can_be_locked)
{
if(next_locked)
{
E_Space space = row->eval.space;
D_Entity *entity = rd_ctrl_entity_from_eval_space(space);
CFG_Node *locked = cfg_node_child_from_string_or_alloc(rd_state->cfg, cfg, s("locked"));
cfg_node_release_all_children(rd_state->cfg, locked);
CFG_Node *mid = cfg_node_new(rd_state->cfg, locked, s("mid"));
cfg_node_newf(rd_state->cfg, mid, "%I64u", entity->handle.machine_id);
CFG_Node *pid = cfg_node_new(rd_state->cfg, locked, s("pid"));
cfg_node_newf(rd_state->cfg, pid, "%I64u", entity->id);
CFG_Node *addr = cfg_node_new(rd_state->cfg, locked, s("addr"));
cfg_node_newf(rd_state->cfg, addr, "0x%I64x", row->eval.value.u64);
CFG_Node *type = cfg_node_new(rd_state->cfg, locked, s("type"));
cfg_node_new(rd_state->cfg, type, e_type_string_from_key(scratch.arena, row->eval.irtree.type_key));
}
else
{
cfg_node_release(rd_state->cfg, cfg_node_child_from_string(cfg, s("locked")));
}
}
}
}
}
//////////////////////////
//- rjf: [text] apply textual edits
//
@@ -4027,11 +4129,14 @@ rd_view_ui(Rng2F32 rect)
// rjf: determine if this cell can be locked
B32 cell_can_be_locked = 0;
if(str8_match(row_info->group_cfg_name, s("watch_expression"), 0) &&
cell_info.flags & RD_WatchCellFlag_Expr &&
cell->eval.string.size != 0 &&
cell->eval.msgs.count == 0)
!(cell_info.flags & RD_WatchCellFlag_Expr) &&
cell->eval.string.size != 0)
{
cell_can_be_locked = ((cell->eval.irtree.mode == E_Mode_Offset) ||
E_Space space = row->eval.space;
D_Entity *entity = rd_ctrl_entity_from_eval_space(space);
B32 is_memory_eval = (space.kind == D_EvalSpaceKind_Entity && entity->kind == D_EntityKind_Process);
cell_can_be_locked = (is_memory_eval &&
(cell->eval.irtree.mode == E_Mode_Offset) ||
(cell->eval.irtree.mode == E_Mode_Value &&
e_type_kind_is_pointer_or_ref(e_type_kind_from_key(e_type_key_unwrap(cell->eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative)))));
}
@@ -4264,14 +4369,24 @@ rd_view_ui(Rng2F32 rect)
}
// rjf: apply locks
if(next_cell_is_locked != cell_is_locked)
{
CFG_Node *cfg = row_info->group_cfg_child;
if(cfg != &cfg_nil_node)
if(next_cell_is_locked != cell_is_locked && cfg != &cfg_nil_node)
{
if(next_cell_is_locked)
{
cfg_node_child_from_string_or_alloc(rd_state->cfg, cfg, s("locked"));
E_Space space = row->eval.space;
D_Entity *entity = rd_ctrl_entity_from_eval_space(space);
CFG_Node *locked = cfg_node_child_from_string_or_alloc(rd_state->cfg, cfg, s("locked"));
cfg_node_release_all_children(rd_state->cfg, locked);
CFG_Node *mid = cfg_node_new(rd_state->cfg, locked, s("mid"));
cfg_node_newf(rd_state->cfg, mid, "%I64u", entity->handle.machine_id);
CFG_Node *pid = cfg_node_new(rd_state->cfg, locked, s("pid"));
cfg_node_newf(rd_state->cfg, pid, "%I64u", entity->id);
CFG_Node *addr = cfg_node_new(rd_state->cfg, locked, s("addr"));
cfg_node_newf(rd_state->cfg, addr, "0x%I64x", row->eval.value.u64);
CFG_Node *type = cfg_node_new(rd_state->cfg, locked, s("type"));
cfg_node_new(rd_state->cfg, type, e_type_string_from_key(scratch.arena, row->eval.irtree.type_key));
}
else
{
@@ -12338,12 +12453,17 @@ rd_frame(void)
}
if(kind == D_EntityKind_Process && d_handle_match(rd_base_regs()->process, entity->handle))
{
e_string2expr_map_insert(scratch.arena, macro_map, str8_lit("current_process"), expr);
e_string2expr_map_insert(scratch.arena, macro_map, s("current_process"), expr);
}
if(kind == D_EntityKind_Module && d_handle_match(rd_base_regs()->module, entity->handle))
{
e_string2expr_map_insert(scratch.arena, macro_map, str8_lit("current_module"), expr);
}
if(kind == D_EntityKind_Process)
{
String8 pid_string = str8f(scratch.arena, "process_%I64u", entity->id);
e_string2expr_map_insert(scratch.arena, macro_map, pid_string, expr);
}
}
}
@@ -16876,6 +16996,33 @@ rd_frame(void)
evt.slot = UI_EventActionSlot_FocusMenu;
ui_event_list_push(scratch.arena, &ws->ui_events, &evt);
}break;
case RD_CmdKind_Lock:
{
CFG_Node *window = cfg_node_from_id(rd_regs()->window);
RD_WindowState *ws = rd_window_state_from_cfg(window);
UI_Event evt = zero_struct;
evt.kind = UI_EventKind_Press;
evt.slot = UI_EventActionSlot_Lock;
ui_event_list_push(scratch.arena, &ws->ui_events, &evt);
}break;
case RD_CmdKind_Unlock:
{
CFG_Node *window = cfg_node_from_id(rd_regs()->window);
RD_WindowState *ws = rd_window_state_from_cfg(window);
UI_Event evt = zero_struct;
evt.kind = UI_EventKind_Press;
evt.slot = UI_EventActionSlot_Unlock;
ui_event_list_push(scratch.arena, &ws->ui_events, &evt);
}break;
case RD_CmdKind_ToggleLock:
{
CFG_Node *window = cfg_node_from_id(rd_regs()->window);
RD_WindowState *ws = rd_window_state_from_cfg(window);
UI_Event evt = zero_struct;
evt.kind = UI_EventKind_Press;
evt.slot = UI_EventActionSlot_ToggleLock;
ui_event_list_push(scratch.arena, &ws->ui_events, &evt);
}break;
//- rjf: directional movement & text controls
//
+17
View File
@@ -1462,9 +1462,26 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(watches)
{
CFG_Node *cfg = accel->cfgs.v[cfg_idx];
CFG_Node *expr = cfg_node_child_from_string(cfg, s("expression"));
CFG_Node *locked = cfg_node_child_from_string(cfg, s("locked"));
if(locked->first->string.size != 0)
{
String8 pid = cfg_node_child_from_string(locked, s("pid"))->first->string;
String8 type = cfg_node_child_from_string(locked, s("type"))->first->string;
String8 addr = cfg_node_child_from_string(locked, s("addr"))->first->string;
String8 lock_expr = str8f(arena, "*(cast(%S *)(process_%S.memory + %S))", type, pid, addr);
evals_out[idx] = e_eval_from_string(lock_expr);
evals_out[idx].string = expr->first->string;
if(evals_out[idx].msgs.count != 0)
{
evals_out[idx] = e_eval_from_string(expr->first->string);
}
}
else
{
evals_out[idx] = e_eval_from_string(expr->first->string);
}
}
}
}
E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(watches)
+46 -41
View File
@@ -3417,6 +3417,52 @@ rd_cell(RD_CellParams *params, String8 string)
}
}
//////////////////////////////
//- rjf: build lock
//
if(params->flags & RD_CellFlag_Lock && !is_focus_active && !is_focus_active_disabled) UI_Parent(box) UI_Focus(UI_FocusKind_Off)
{
// TODO(rjf): @hack
{
ui_spacer(ui_em(0.5f, 1.f));
}
B32 is_locked = (params->lock_out && params->lock_out[0]);
UI_PrefWidth(ui_em(2.f, 1.f))
UI_TagF(".")
UI_TagF(is_locked ? "pop" : "weak")
UI_TagF("implicit")
UI_Column
UI_Padding(ui_pct(1, 0))
UI_PrefHeight(ui_em(2.f, 1.f))
UI_CornerRadius(ui_top_font_size()*0.5f)
RD_Font(RD_FontSlot_Icons)
UI_TextAlignment(UI_TextAlign_Center)
{
UI_Box *lock_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|
UI_BoxFlag_DrawHotEffects|
UI_BoxFlag_DrawBorder|
UI_BoxFlag_DrawBackground|
UI_BoxFlag_DisableFocusOverlay|
UI_BoxFlag_DisableFocusBorder|
UI_BoxFlag_Clickable,
"%S###lock", rd_icon_kind_text_table[is_locked ? RD_IconKind_Locked : RD_IconKind_Unlocked]);
UI_Signal sig = ui_signal_from_box(lock_box);
if(ui_hovering(sig)) UI_Tooltip RD_Font(RD_FontSlot_Main)
{
ui_state->tooltip_anchor_key = lock_box->key;
UI_PrefWidth(ui_children_sum(1)) UI_Row
{
UI_PrefWidth(ui_text_dim(10, 1)) ui_label(is_locked ? s("Unlock Location") : s("Lock Location"));
rd_cmd_binding_buttons(rd_cmd_kind_info_table[RD_CmdKind_ToggleLock].string, s(""), 1, RD_CmdBindingButtonFlag_NoEdit);
}
}
if(ui_pressed(sig) && params->lock_out)
{
params->lock_out[0] ^= 1;
}
}
}
//////////////////////////////
//- rjf: build left-hand-side container box
//
@@ -3607,47 +3653,6 @@ rd_cell(RD_CellParams *params, String8 string)
}
}
//////////////////////////////
//- rjf: build lock
//
if(params->flags & RD_CellFlag_Lock && !is_focus_active && !is_focus_active_disabled) UI_Parent(box) UI_Focus(UI_FocusKind_Off)
{
UI_PrefWidth(ui_em(2.f, 1.f))
UI_TagF(".")
UI_TagF("weak")
UI_TagF("implicit")
UI_Column
UI_Padding(ui_pct(1, 0))
UI_PrefHeight(ui_em(2.f, 1.f))
UI_CornerRadius(ui_top_font_size()*0.5f)
RD_Font(RD_FontSlot_Icons)
UI_TextAlignment(UI_TextAlign_Center)
{
UI_Box *lock_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|
UI_BoxFlag_DrawHotEffects|
UI_BoxFlag_DrawBorder|
UI_BoxFlag_DrawBackground|
UI_BoxFlag_DisableFocusOverlay|
UI_BoxFlag_DisableFocusBorder|
UI_BoxFlag_Clickable,
"%S###lock", rd_icon_kind_text_table[(params->lock_out && params->lock_out[0]) ? RD_IconKind_Locked : RD_IconKind_Unlocked]);
UI_Signal sig = ui_signal_from_box(lock_box);
if(ui_hovering(sig)) UI_Tooltip RD_Font(RD_FontSlot_Main)
{
ui_state->tooltip_anchor_key = lock_box->key;
ui_label((params->lock_out && params->lock_out[0]) ? s("Unlock Evaluated Location") : s("Lock Evaluated Location"));
}
if(ui_pressed(sig) && params->lock_out)
{
params->lock_out[0] ^= 1;
}
}
// TODO(rjf): @hack
{
ui_spacer(ui_em(0.5f, 1.f));
}
}
//////////////////////////////
//- rjf: build toggle-switch
//
+3
View File
@@ -104,6 +104,9 @@ typedef enum UI_EventActionSlot
UI_EventActionSlot_Cancel,
UI_EventActionSlot_Edit,
UI_EventActionSlot_FocusMenu,
UI_EventActionSlot_Lock,
UI_EventActionSlot_Unlock,
UI_EventActionSlot_ToggleLock,
UI_EventActionSlot_COUNT
}
UI_EventActionSlot;