fix a few details in new eval visualization block tree generation algorithm; fix row generation; start fitting new system into hover eval as a first test

This commit is contained in:
Ryan Fleury
2024-09-25 13:17:17 -07:00
parent 9c3d2cd5ab
commit a87c032305
3 changed files with 249 additions and 40 deletions
+227 -26
View File
@@ -510,6 +510,8 @@ ev2_block_tree_from_expr(Arena *arena, EV_View *view, String8 string, E_Expr *ex
tree.root->expr = expr;
tree.root->view_rules = view_rules;
tree.root->semantic_row_count = tree.root->visual_row_count = 1;
tree.total_semantic_row_count += 1;
tree.total_visual_row_count += 1;
//- rjf: iterate all expansions & generate blocks for each
typedef struct Task Task;
@@ -517,14 +519,17 @@ ev2_block_tree_from_expr(Arena *arena, EV_View *view, String8 string, E_Expr *ex
{
Task *next;
EV2_Block *parent_block;
E_Expr *expr;
EV_Key key;
EV_ViewRuleList *view_rules;
U64 split_relative_idx;
};
Task start_task = {0, tree.root, 1};
Task start_task = {0, tree.root, expr, tree.root->key, view_rules, 1};
Task *first_task = &start_task;
Task *last_task = first_task;
for(Task *t = first_task; t != 0; t = t->next)
{
EV_ExpandNode *expand_node = ev_expand_node_from_key(view, t->parent_block->key);
EV_ExpandNode *expand_node = ev_expand_node_from_key(view, t->key);
// rjf: skip if not expanded
if(!expand_node || !expand_node->expanded)
@@ -533,9 +538,9 @@ ev2_block_tree_from_expr(Arena *arena, EV_View *view, String8 string, E_Expr *ex
}
// rjf: get expansion view rule info
EV_ViewRuleInfo *expand_view_rule_info = &ev_nil_view_rule_info;
EV_ViewRuleInfo *expand_view_rule_info = default_expand_view_rule_info;
MD_Node *expand_params = &md_nil_node;
for(EV_ViewRuleNode *n = t->parent_block->view_rules->first; n != 0; n = n->next)
for(EV_ViewRuleNode *n = t->view_rules->first; n != 0; n = n->next)
{
EV_ViewRuleInfo *info = ev_view_rule_info_from_string(n->v.root->string);
if(info->expr_expand != 0)
@@ -546,17 +551,17 @@ ev2_block_tree_from_expr(Arena *arena, EV_View *view, String8 string, E_Expr *ex
}
// rjf: get expansion info
EV_ExpandResult expand_result = expand_view_rule_info->expr_expand(arena, t->parent_block->expr, expand_params, r1u64(0, 0));
EV_ExpandResult expand_result = expand_view_rule_info->expr_expand(arena, t->expr, expand_params, r1u64(0, 0));
// rjf: generate block for expansion
EV2_Block *expansion_block = push_array(arena, EV2_Block, 1);
MemoryCopyStruct(expansion_block, &ev2_nil_block);
DLLPushBack(t->parent_block->first, t->parent_block->last, expansion_block);
DLLPushBack_NPZ(&ev2_nil_block, t->parent_block->first, t->parent_block->last, expansion_block, next, prev);
expansion_block->parent = t->parent_block;
expansion_block->key = t->parent_block->key;
expansion_block->key = t->key;
expansion_block->split_relative_idx = t->split_relative_idx;
expansion_block->expr = t->parent_block->expr;
expansion_block->view_rules = t->parent_block->view_rules;
expansion_block->expr = t->expr;
expansion_block->view_rules = t->view_rules;
expansion_block->expand_view_rule_info = expand_view_rule_info;
expansion_block->expand_view_rule_params = expand_params;
expansion_block->semantic_row_count = expand_result.total_semantic_row_count;
@@ -564,14 +569,24 @@ ev2_block_tree_from_expr(Arena *arena, EV_View *view, String8 string, E_Expr *ex
tree.total_semantic_row_count += expand_result.total_semantic_row_count;
tree.total_visual_row_count += expand_result.total_visual_row_count;
// rjf: iterate children expansions, generate children blocks for each
// rjf: iterate children expansions, recurse
// TODO(rjf): need to iterate these in index order, rather than "child_num" (which needs to be renamed to "child_id") order
for(EV_ExpandNode *child = expand_node->first; child != 0; child = child->next)
{
Task *task = push_array(scratch.arena, Task, 1);
SLLQueuePush(first_task, last_task, task);
task->parent_block = expansion_block;
task->split_relative_idx = child->key.child_num - 1; // TODO(rjf): key -> index
U64 split_relative_idx = child->key.child_num - 1; // TODO(rjf): key -> index
EV_ExpandResult child_expand = expand_view_rule_info->expr_expand(arena, t->expr, expand_params, r1u64(split_relative_idx, split_relative_idx+1));
if(child_expand.row_exprs_count > 0)
{
EV_ViewRuleList *child_view_rules = ev_view_rule_list_from_inheritance(arena, t->view_rules);
// TODO(rjf): need to mix in child's view rules
Task *task = push_array(scratch.arena, Task, 1);
SLLQueuePush(first_task, last_task, task);
task->parent_block = expansion_block;
task->expr = child_expand.row_exprs[0];
task->key = child->key;
task->view_rules = child_view_rules;
task->split_relative_idx = split_relative_idx;
}
}
}
scratch_end(scratch);
@@ -579,6 +594,77 @@ ev2_block_tree_from_expr(Arena *arena, EV_View *view, String8 string, E_Expr *ex
return tree;
}
internal EV2_BlockTree
ev2_block_tree_from_string(Arena *arena, EV_View *view, String8 string, EV_ViewRuleList *view_rules)
{
EV2_BlockTree tree = {0};
Temp scratch = scratch_begin(&arena, 1);
{
// rjf: parse expression
E_TokenArray tokens = e_token_array_from_text(scratch.arena, string);
E_Parse parse = e_parse_expr_from_text_tokens(arena, string, &tokens);
// rjf: extract view rules, encoded via fastpaths in expression string
String8List fastpath_view_rules = {0};
{
U64 parse_opl = (parse.last_token >= tokens.v + tokens.count ? string.size : parse.last_token->range.min);
U64 comma_pos = str8_find_needle(string, parse_opl, str8_lit(","), 0);
U64 passthrough_pos = str8_find_needle(string, parse_opl, str8_lit("--"), 0);
if(comma_pos < string.size && comma_pos < passthrough_pos)
{
String8 comma_extension = str8_skip_chop_whitespace(str8_substr(string, r1u64(comma_pos+1, passthrough_pos)));
if(str8_match(comma_extension, str8_lit("x"), StringMatchFlag_CaseInsensitive))
{
str8_list_pushf(arena, &fastpath_view_rules, "hex");
}
else if(str8_match(comma_extension, str8_lit("b"), StringMatchFlag_CaseInsensitive))
{
str8_list_pushf(arena, &fastpath_view_rules, "bin");
}
else if(str8_match(comma_extension, str8_lit("o"), StringMatchFlag_CaseInsensitive))
{
str8_list_pushf(arena, &fastpath_view_rules, "oct");
}
else if(comma_extension.size != 0)
{
str8_list_pushf(arena, &fastpath_view_rules, "array:{%S}", comma_extension);
}
}
if(passthrough_pos < string.size)
{
String8 passthrough_view_rule = str8_skip_chop_whitespace(str8_skip(string, passthrough_pos+2));
if(passthrough_view_rule.size != 0)
{
str8_list_push(arena, &fastpath_view_rules, passthrough_view_rule);
}
}
}
// rjf: build full list of view rules
EV_ViewRuleList *all_view_rules = ev_view_rule_list_copy(arena, view_rules);
for(String8Node *n = fastpath_view_rules.first; n != 0; n = n->next)
{
ev_view_rule_list_push_string(arena, all_view_rules, n->string);
}
// rjf: produce tree
tree = ev2_block_tree_from_expr(arena, view, string, parse.expr, all_view_rules);
}
scratch_end(scratch);
return tree;
}
internal U64
ev2_depth_from_block(EV2_Block *block)
{
U64 depth = 0;
for(EV2_Block *b = block->parent; b != &ev2_nil_block; b = b->parent)
{
depth += 1;
}
return depth;
}
internal EV2_WindowedRowList
ev2_windowed_row_list_from_block_tree(Arena *arena, EV_View *view, EV2_BlockTree *block_tree, Rng1U64 visible_range)
{
@@ -599,7 +685,10 @@ ev2_windowed_row_list_from_block_tree(Arena *arena, EV_View *view, EV2_BlockTree
{
// rjf: get block-relative range, truncated by split position of next child
Rng1U64 block_relative_range = t->block_relative_range;
block_relative_range.max = Min(t->next_child->split_relative_idx, block_relative_range.max);
if(t->next_child != &ev2_nil_block)
{
block_relative_range.max = t->next_child->split_relative_idx+1;
}
U64 block_num_visual_rows = dim_1u64(block_relative_range);
// rjf: get global range of this block
@@ -627,27 +716,50 @@ ev2_windowed_row_list_from_block_tree(Arena *arena, EV_View *view, EV2_BlockTree
// rjf: sum & advance
visual_idx_off += block_num_visual_rows;
rows.count_before_visual += num_skipped;
// rjf: generate rows before next splitting child
if(block_relative_range__windowed.max > block_relative_range__windowed.min)
{
EV_ExpandResult expand = t->block->expand_view_rule_info->expr_expand(arena, t->block->expr, t->block->expand_view_rule_params, block_relative_range__windowed);
for EachIndex(idx, expand.row_exprs_count)
// rjf: no expansion operator applied -> push row for block expression; pass through block info
if(t->block->expand_view_rule_info == &ev_nil_view_rule_info)
{
U64 row_visual_size = expand.row_exprs_num_visual_rows[idx];
U64 child_id = block_relative_range.min + idx + 1; // TODO(rjf): index -> key
EV2_Row *row = push_array(arena, EV2_Row, 1);
SLLQueuePush(rows.first, rows.last, row);
rows.count += 1;
row->block = t->block;
row->key = ev_key_make(ev_hash_from_key(row->block->key), child_id);
row->visual_size = row_visual_size;
row->key = t->block->key;
row->visual_size = t->block->visual_row_count;
row->visual_size_skipped = 0; // TODO(rjf)
row->visual_size_chopped = 0; // TODO(rjf)
row->string = t->block->string;
row->expr = expand.row_exprs[idx];
row->member = expand.row_members[idx];
row->view_rules = ev_view_rule_list_from_inheritance(arena, t->block->view_rules);
// TODO(rjf): mix in view rules based on row's key, row's type
row->expr = t->block->expr;
row->member = &e_member_nil;
row->view_rules = t->block->view_rules;
}
// rjf: expansion operator applied -> call, and add rows for all expressions in the viewable range
else
{
EV_ExpandResult expand = t->block->expand_view_rule_info->expr_expand(arena, t->block->expr, t->block->expand_view_rule_params, block_relative_range__windowed);
for EachIndex(idx, expand.row_exprs_count)
{
U64 row_visual_size = expand.row_exprs_num_visual_rows[idx];
U64 child_id = block_relative_range.min + idx + 1; // TODO(rjf): index -> key
EV2_Row *row = push_array(arena, EV2_Row, 1);
SLLQueuePush(rows.first, rows.last, row);
rows.count += 1;
row->block = t->block;
row->key = ev_key_make(ev_hash_from_key(row->block->key), child_id);
row->visual_size = row_visual_size;
row->visual_size_skipped = 0; // TODO(rjf)
row->visual_size_chopped = 0; // TODO(rjf)
row->string = t->block->string;
row->expr = expand.row_exprs[idx];
row->member = expand.row_members[idx];
row->view_rules = ev_view_rule_list_from_inheritance(arena, t->block->view_rules);
// TODO(rjf): mix in view rules based on row's key, row's type
}
}
}
@@ -663,7 +775,7 @@ ev2_windowed_row_list_from_block_tree(Arena *arena, EV_View *view, EV2_BlockTree
child_task->block_relative_range = r1u64(0, t->next_child->visual_row_count);
// rjf: generate task for post-child rows, if any, after children
Rng1U64 remainder_range = r1u64(t->next_child->split_relative_idx, t->block_relative_range.max);
Rng1U64 remainder_range = r1u64(t->next_child->split_relative_idx+1, t->block_relative_range.max);
if(remainder_range.max > remainder_range.min)
{
BlockTask *remainder_task = push_array(scratch.arena, BlockTask, 1);
@@ -680,6 +792,95 @@ ev2_windowed_row_list_from_block_tree(Arena *arena, EV_View *view, EV2_BlockTree
return rows;
}
internal String8
ev2_expr_string_from_row(Arena *arena, EV2_Row *row, EV_StringFlags flags)
{
String8 result = row->string;
E_Expr *notable_expr = row->expr;
for(B32 good = 0; !good;)
{
switch(notable_expr->kind)
{
default:{good = 1;}break;
case E_ExprKind_Address:
case E_ExprKind_Deref:
case E_ExprKind_Cast:
{
notable_expr = notable_expr->last;
}break;
case E_ExprKind_Ref:
{
notable_expr = notable_expr->ref;
}break;
}
}
if(result.size == 0) switch(notable_expr->kind)
{
default:
{
result = e_string_from_expr(arena, notable_expr);
}break;
case E_ExprKind_ArrayIndex:
{
result = push_str8f(arena, "[%S]", e_string_from_expr(arena, notable_expr->last));
}break;
case E_ExprKind_MemberAccess:
{
if(flags & EV_StringFlag_PrettyNames && row->member->pretty_name.size != 0)
{
result = push_str8_copy(arena, row->member->pretty_name);
}
else
{
result = push_str8f(arena, ".%S", e_string_from_expr(arena, notable_expr->last));
}
}break;
}
return result;
}
internal B32
ev2_row_is_expandable(EV2_Row *row)
{
B32 result = 0;
{
// rjf: determine if view rules force expandability
if(!result)
{
for(EV_ViewRuleNode *n = row->view_rules->first; n != 0; n = n->next)
{
EV_ViewRuleInfo *info = ev_view_rule_info_from_string(n->v.root->string);
if(info->flags & EV_ViewRuleInfoFlag_Expandable)
{
result = 1;
break;
}
}
}
// rjf: determine if type info force expandability
if(!result)
{
Temp scratch = scratch_begin(0, 0);
E_IRTreeAndType irtree = e_irtree_and_type_from_expr(scratch.arena, row->expr);
result = ev_type_key_and_mode_is_expandable(irtree.type_key, irtree.mode);
scratch_end(scratch);
}
}
return result;
}
internal B32
ev2_row_is_editable(EV2_Row *row)
{
B32 result = 0;
Temp scratch = scratch_begin(0, 0);
E_IRTreeAndType irtree = e_irtree_and_type_from_expr(scratch.arena, row->expr);
result = ev_type_key_is_editable(irtree.type_key);
scratch_end(scratch);
return result;
}
////////////////////////////////
//~ rjf: Block Building
@@ -460,7 +460,12 @@ internal E_Expr *ev_expr_from_expr_view_rules(Arena *arena, E_Expr *expr, EV_Vie
//~ rjf: Block Building (v2)
internal EV2_BlockTree ev2_block_tree_from_expr(Arena *arena, EV_View *view, String8 string, E_Expr *expr, EV_ViewRuleList *view_rules);
internal EV2_BlockTree ev2_block_tree_from_string(Arena *arena, EV_View *view, String8 string, EV_ViewRuleList *view_rules);
internal U64 ev2_depth_from_block(EV2_Block *block);
internal EV2_WindowedRowList ev2_windowed_row_list_from_block_tree(Arena *arena, EV_View *view, EV2_BlockTree *block_tree, Rng1U64 visible_range);
internal String8 ev2_expr_string_from_row(Arena *arena, EV2_Row *row, EV_StringFlags flags);
internal B32 ev2_row_is_expandable(EV2_Row *row);
internal B32 ev2_row_is_editable(EV2_Row *row);
////////////////////////////////
//~ rjf: Block Building
+17 -14
View File
@@ -5825,17 +5825,19 @@ rd_window_frame(RD_Window *ws)
EV_View *ev_view = rd_ev_view_from_key(d_hash_from_string(ev_view_key_string));
EV_Key parent_key = ev_key_make(5381, 1);
EV_Key key = ev_key_make(ev_hash_from_key(parent_key), 1);
EV_BlockList viz_blocks = ev_block_list_from_view_expr_keys(scratch.arena, ev_view, str8_zero(), &top_level_view_rules, expr, parent_key, key, 0);
EV2_BlockTree block_tree = ev2_block_tree_from_string(scratch.arena, ev_view, expr, &top_level_view_rules);
// EV_BlockList viz_blocks = ev_block_list_from_view_expr_keys(scratch.arena, ev_view, str8_zero(), &top_level_view_rules, expr, parent_key, key, 0);
CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(eval.space);
U32 default_radix = (entity->kind == CTRL_EntityKind_Thread ? 16 : 10);
EV_WindowedRowList viz_rows = ev_windowed_row_list_from_block_list(scratch.arena, ev_view, r1s64(0, 50), &viz_blocks);
EV2_WindowedRowList rows = ev2_windowed_row_list_from_block_tree(scratch.arena, ev_view, &block_tree, r1u64(0, 50));
// EV_WindowedRowList viz_rows = ev_windowed_row_list_from_block_list(scratch.arena, ev_view, r1s64(0, 50), &viz_blocks);
//- rjf: animate
{
// rjf: animate height
{
F32 fish_rate = rd_setting_val_from_code(RD_SettingCode_MenuAnimations).s32 ? 1 - pow_f32(2, (-60.f * rd_state->frame_dt)) : 1.f;
F32 hover_eval_container_height_target = row_height * Min(30, viz_blocks.total_visual_row_count);
F32 hover_eval_container_height_target = row_height * Min(30, block_tree.total_visual_row_count);
ws->hover_eval_num_visible_rows_t += (hover_eval_container_height_target - ws->hover_eval_num_visible_rows_t) * fish_rate;
if(abs_f32(hover_eval_container_height_target - ws->hover_eval_num_visible_rows_t) > 0.5f)
{
@@ -5867,11 +5869,11 @@ rd_window_frame(RD_Window *ws)
F32 width_px = 40.f*ui_top_font_size();
F32 expr_column_width_px = 10.f*ui_top_font_size();
F32 value_column_width_px = 30.f*ui_top_font_size();
if(viz_rows.first != 0)
if(rows.first != 0)
{
EV_Row *row = viz_rows.first;
EV2_Row *row = rows.first;
E_Eval row_eval = e_eval_from_expr(scratch.arena, row->expr);
String8 row_expr_string = ev_expr_string_from_row(scratch.arena, row, 0);
String8 row_expr_string = ev2_expr_string_from_row(scratch.arena, row, 0);
String8 row_display_value = rd_value_string_from_eval(scratch.arena, EV_StringFlag_ReadOnlyDisplayRules, default_radix, ui_top_font(), ui_top_font_size(), 500.f, row_eval, row->member, row->view_rules);
expr_column_width_px = fnt_dim_from_tag_size_string(ui_top_font(), ui_top_font_size(), 0, 0, row_expr_string).x + ui_top_font_size()*5.f;
value_column_width_px = fnt_dim_from_tag_size_string(ui_top_font(), ui_top_font_size(), 0, 0, row_display_value).x + ui_top_font_size()*5.f;
@@ -5915,15 +5917,16 @@ rd_window_frame(RD_Window *ws)
UI_Parent(hover_eval_box) UI_PrefHeight(ui_px(row_height, 1.f))
{
//- rjf: build rows
for(EV_Row *row = viz_rows.first; row != 0; row = row->next)
for(EV2_Row *row = rows.first; row != 0; row = row->next)
{
//- rjf: unpack row
U64 row_depth = ev2_depth_from_block(row->block);
E_Eval row_eval = e_eval_from_expr(scratch.arena, row->expr);
String8 row_expr_string = ev_expr_string_from_row(scratch.arena, row, 0);
String8 row_expr_string = ev2_expr_string_from_row(scratch.arena, row, 0);
String8 row_edit_value = rd_value_string_from_eval(scratch.arena, 0, default_radix, ui_top_font(), ui_top_font_size(), 500.f, row_eval, row->member, row->view_rules);
String8 row_display_value = rd_value_string_from_eval(scratch.arena, EV_StringFlag_ReadOnlyDisplayRules, default_radix, ui_top_font(), ui_top_font_size(), 500.f, row_eval, row->member, row->view_rules);
B32 row_is_editable = ev_row_is_editable(row);
B32 row_is_expandable = ev_row_is_expandable(row);
B32 row_is_editable = ev2_row_is_editable(row);
B32 row_is_expandable = ev2_row_is_expandable(row);
//- rjf: determine if row's data is fresh and/or bad
B32 row_is_fresh = 0;
@@ -5959,9 +5962,9 @@ rd_window_frame(RD_Window *ws)
UI_WidthFill UI_Row
{
ui_spacer(ui_em(0.75f, 1.f));
if(row->depth > 0)
if(row_depth > 0)
{
for(S32 indent = 0; indent < row->depth; indent += 1)
for(U64 indent = 0; indent < row_depth; indent += 1)
{
ui_spacer(ui_em(0.75f, 1.f));
UI_Flags(UI_BoxFlag_DrawSideLeft) ui_spacer(ui_em(1.5f, 1.f));
@@ -5973,7 +5976,7 @@ rd_window_frame(RD_Window *ws)
UI_PrefWidth(ui_em(1.5f, 1))
if(ui_pressed(ui_expanderf(row_is_expanded, "###%I64x_%I64x_is_expanded", row->key.parent_hash, row->key.child_num)))
{
ev_key_set_expansion(ev_view, row->parent_key, row->key, !row_is_expanded);
ev_key_set_expansion(ev_view, row->block->key, row->key, !row_is_expanded);
}
if(!row_is_expandable)
{
@@ -6023,7 +6026,7 @@ rd_window_frame(RD_Window *ws)
rd_code_label(1.f, 1, rd_rgba_from_theme_color(RD_ThemeColor_CodeDefault), row_display_value);
}
}
if(row == viz_rows.first)
if(row == rows.first)
{
UI_TextAlignment(UI_TextAlign_Center) UI_PrefWidth(ui_em(3.f, 1.f))
UI_CornerRadius00(0)