From ee9017d5dba0375a3ae0413406c76caa9048c9b6 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 30 Apr 2025 10:50:36 -0700 Subject: [PATCH] cfg schema-based path relativization on save, derelativization on load; omit for file path maps --- src/path/path.c | 10 +-- src/raddbg/generated/raddbg.meta.c | 6 +- src/raddbg/generated/raddbg.meta.h | 2 +- src/raddbg/raddbg.mdesk | 4 +- src/raddbg/raddbg_core.c | 133 ++++++++++++++++++++++------- src/raddbg/raddbg_core.h | 4 +- 6 files changed, 118 insertions(+), 41 deletions(-) diff --git a/src/path/path.c b/src/path/path.c index fa384748..a6b79995 100644 --- a/src/path/path.c +++ b/src/path/path.c @@ -90,7 +90,7 @@ path_absolute_dst_from_relative_dst_src(Arena *arena, String8 dst, String8 src) if(dst_style == PathStyle_Relative) { Temp scratch = scratch_begin(&arena, 1); - String8 dst_from_src_absolute = push_str8f(scratch.arena, "%S/%S", src, dst); + String8 dst_from_src_absolute = push_str8f(scratch.arena, "%S/%S", str8_chop_last_slash(src), dst); String8 dst_from_src_absolute_normalized = path_normalized_from_string(arena, dst_from_src_absolute); result = dst_from_src_absolute_normalized; scratch_end(scratch); @@ -160,10 +160,10 @@ path_char_from_style(PathStyle style) String8 result = str8_zero(); switch (style) { - case PathStyle_Null: break; - case PathStyle_Relative: break; - case PathStyle_WindowsAbsolute: result = str8_lit("\\"); break; - case PathStyle_UnixAbsolute: result = str8_lit("/"); break; + case PathStyle_Null: break; + case PathStyle_Relative: break; + case PathStyle_WindowsAbsolute: result = str8_lit("\\"); break; + case PathStyle_UnixAbsolute: result = str8_lit("/"); break; } return result; } diff --git a/src/raddbg/generated/raddbg.meta.c b/src/raddbg/generated/raddbg.meta.c index f2f9b8e3..2e058d84 100644 --- a/src/raddbg/generated/raddbg.meta.c +++ b/src/raddbg/generated/raddbg.meta.c @@ -52,7 +52,7 @@ str8_lit_comp(""), str8_lit_comp(""), }; -RD_VocabInfo rd_vocab_info_table[325] = +RD_VocabInfo rd_vocab_info_table[327] = { {str8_lit_comp("auto_view_rule"), str8_lit_comp("auto_view_rules"), str8_lit_comp("Auto View Rule"), str8_lit_comp("Auto View Rules"), RD_IconKind_Binoculars}, {str8_lit_comp("file_path_map"), str8_lit_comp("file_path_maps"), str8_lit_comp("File Path Map"), str8_lit_comp("File Path Maps"), RD_IconKind_FileOutline}, @@ -87,6 +87,8 @@ RD_VocabInfo rd_vocab_info_table[325] = {str8_lit_comp("recent_file"), str8_lit_comp("recent_files"), str8_lit_comp("Recent File"), str8_lit_comp("Recent Files"), RD_IconKind_FileOutline}, {str8_lit_comp("src"), str8_lit_comp("srcs"), str8_lit_comp("Source"), str8_lit_comp("Sources"), RD_IconKind_Null}, {str8_lit_comp("dst"), str8_lit_comp("dsts"), str8_lit_comp("Destination"), str8_lit_comp("Destinations"), RD_IconKind_Null}, +{str8_lit_comp("source"), str8_lit_comp("sources"), str8_lit_comp("Source"), str8_lit_comp("Sources"), RD_IconKind_Null}, +{str8_lit_comp("dest"), str8_lit_comp("dests"), str8_lit_comp("Destination"), str8_lit_comp("Destinations"), RD_IconKind_Null}, {str8_lit_comp("conversion_task"), str8_lit_comp("conversion_tasks"), str8_lit_comp("Conversion Task"), str8_lit_comp("Conversion Tasks"), RD_IconKind_Null}, {str8_lit_comp("conversion_fail"), str8_lit_comp("conversion_fails"), str8_lit_comp("Conversion Fail"), str8_lit_comp("Conversion Fails"), RD_IconKind_Null}, {str8_lit_comp("lang"), str8_lit_comp("langs"), str8_lit_comp("Language"), str8_lit_comp("Languages"), RD_IconKind_Null}, @@ -398,7 +400,7 @@ RD_NameSchemaInfo rd_name_schema_info_table[23] = {str8_lit_comp("target"), str8_lit_comp("@row_commands(enable_cfg, launch_and_run, launch_and_step_into, duplicate_cfg, remove_cfg)\n@collection_commands(add_target)\nx:\n{\n 'label': code_string,\n 'executable': path,\n 'arguments': string,\n 'working_directory': path,\n 'entry_point': code_string,\n 'stdout_path': path,\n 'stderr_path': path,\n 'stdin_path': path,\n 'environment': query,\n 'debug_subprocesses': bool,\n @no_expand @default(0) 'enabled': bool,\n}\n")}, {str8_lit_comp("breakpoint"), str8_lit_comp("@row_commands(enable_cfg, duplicate_cfg, remove_cfg)\n@collection_commands(toggle_breakpoint, add_breakpoint, add_address_breakpoint)\nx:\n{\n 'label': code_string,\n 'condition': code_string,\n 'source_location': string,\n 'address_location': code_string,\n 'hit_count': u64,\n 'address_range_size': @or(0, 1, 2, 4, 8) u64,\n 'break_on_write': bool,\n 'break_on_read': bool,\n 'break_on_execute': bool,\n @no_expand @default(1) 'enabled': bool,\n}\n")}, {str8_lit_comp("watch_pin"), str8_lit_comp("@row_commands(duplicate_cfg, remove_cfg)\n@collection_commands(add_watch_pin, toggle_watch_pin)\nx:\n{\n 'expression': code_string,\n 'source_location': string,\n 'address_location': code_string,\n}\n")}, -{str8_lit_comp("file_path_map"), str8_lit_comp("@collection_commands(add_file_path_map) @row_commands(remove_cfg) x:{'source':path, 'dest':path}")}, +{str8_lit_comp("file_path_map"), str8_lit_comp("@collection_commands(add_file_path_map) @row_commands(remove_cfg) x:{'source': @absolute path, 'dest': @absolute path}")}, {str8_lit_comp("auto_view_rule"), str8_lit_comp("@collection_commands(add_auto_view_rule) @row_commands(remove_cfg) x:{'type':code_string, 'view_rule':code_string}")}, {str8_lit_comp("recent_project"), str8_lit_comp("x:{'path':path}")}, {str8_lit_comp("recent_file"), str8_lit_comp("x:{'path':path}")}, diff --git a/src/raddbg/generated/raddbg.meta.h b/src/raddbg/generated/raddbg.meta.h index bcf7a129..30edd248 100644 --- a/src/raddbg/generated/raddbg.meta.h +++ b/src/raddbg/generated/raddbg.meta.h @@ -678,7 +678,7 @@ Z(getting_started)\ C_LINKAGE_BEGIN extern String8 rd_tab_fast_path_view_name_table[20]; extern String8 rd_tab_fast_path_query_name_table[20]; -extern RD_VocabInfo rd_vocab_info_table[325]; +extern RD_VocabInfo rd_vocab_info_table[327]; extern RD_NameSchemaInfo rd_name_schema_info_table[23]; extern Rng1U64 rd_reg_slot_range_table[43]; extern String8 rd_binding_version_remap_old_name_table[8]; diff --git a/src/raddbg/raddbg.mdesk b/src/raddbg/raddbg.mdesk index 05f7754f..56d66c5e 100644 --- a/src/raddbg/raddbg.mdesk +++ b/src/raddbg/raddbg.mdesk @@ -112,6 +112,8 @@ RD_VocabTable: {recent_file _ "Recent File" _ FileOutline } {src _ "Source" _ Null } {dst _ "Destination" _ Null } + {source _ "Source" _ Null } + {dest _ "Destination" _ Null } {conversion_task _ "Conversion Task" _ Null } {conversion_fail _ "Conversion Fail" _ Null } {lang _ "Language" _ Null } @@ -581,7 +583,7 @@ RD_VocabTable: //- rjf: file path maps { file_path_map, - ```@collection_commands(add_file_path_map) @row_commands(remove_cfg) x:{'source':path, 'dest':path}```, + ```@collection_commands(add_file_path_map) @row_commands(remove_cfg) x:{'source': @absolute path, 'dest': @absolute path}```, } //- rjf: auto view rules diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 7b02edd6..2303d532 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -607,11 +607,15 @@ rd_cfg_array_from_list(Arena *arena, RD_CfgList *list) } internal RD_CfgList -rd_cfg_tree_list_from_string(Arena *arena, String8 string) +rd_cfg_tree_list_from_string(Arena *arena, String8 root_path, String8 string) { RD_CfgList result = {0}; Temp scratch = scratch_begin(&arena, 1); + + //- rjf: parse the string as metadesk MD_Node *root = md_tree_from_string(scratch.arena, string); + + //- rjf: iterate the top-level metadesk trees, generate new cfg trees for each for MD_EachNode(tln, root->first) { RD_Cfg *dst_root_n = &rd_nil_cfg; @@ -619,14 +623,39 @@ rd_cfg_tree_list_from_string(Arena *arena, String8 string) MD_NodeRec rec = {0}; for(MD_Node *src_n = tln; !md_node_is_nil(src_n); src_n = rec.next) { + // rjf: lookup schema for this string + MD_Node *schema = &md_nil_node; + { + MD_NodePtrList schemas = rd_schemas_from_name(dst_active_parent_n->parent->string); + for(MD_NodePtrNode *n = schemas.first; n != 0 && schema == &md_nil_node; n = n->next) + { + schema = md_child_from_string(n->v, dst_active_parent_n->string, 0); + } + } + + // rjf: extract & transform metadesk node's string (it is raw textual data, so we need to + // go escaped -> raw, and derelativize paths) + String8 dst_n_string = {0}; + { + String8 src_n_string = src_n->string; + String8 src_n_string__raw = raw_from_escaped_str8(scratch.arena, src_n_string); + if(str8_match(schema->first->string, str8_lit("path"), 0) && + !md_node_has_tag(schema->first, str8_lit("absolute"), 0)) + { + src_n_string__raw = path_absolute_dst_from_relative_dst_src(scratch.arena, src_n_string__raw, root_path); + } + dst_n_string = src_n_string__raw; + } + + // rjf: allocate, fill, & insert new cfg for this metadesk node RD_Cfg *dst_n = rd_cfg_alloc(); - String8 src_n_string = src_n->string; - String8 src_n_string__raw = raw_from_escaped_str8(scratch.arena, src_n_string); - rd_cfg_equip_string(dst_n, src_n_string__raw); + rd_cfg_equip_string(dst_n, dst_n_string); if(dst_active_parent_n != &rd_nil_cfg) { rd_cfg_insert_child(dst_active_parent_n, dst_active_parent_n->last, dst_n); } + + // rjf: recurse rec = md_node_rec_depth_first_pre(src_n, tln); if(dst_active_parent_n == &rd_nil_cfg) { @@ -648,7 +677,7 @@ rd_cfg_tree_list_from_string(Arena *arena, String8 string) } internal String8 -rd_string_from_cfg_tree(Arena *arena, RD_Cfg *cfg) +rd_string_from_cfg_tree(Arena *arena, String8 root_path, RD_Cfg *cfg) { Temp scratch = scratch_begin(&arena, 1); String8List strings = {0}; @@ -658,49 +687,92 @@ rd_string_from_cfg_tree(Arena *arena, RD_Cfg *cfg) { NestTask *next; RD_Cfg *cfg; + MD_Node *schema; B32 is_simple; }; NestTask *top_nest_task = 0; RD_CfgRec rec = {0}; for(RD_Cfg *c = cfg; c != &rd_nil_cfg; c = rec.next) { + // rjf: look up parent's schemas + MD_NodePtrList schemas = {0}; + if(top_nest_task != 0) + { + RD_Cfg *parent = top_nest_task->cfg; + schemas = rd_schemas_from_name(parent->string); + } + + // rjf: look up child schema + MD_Node *c_schema = &md_nil_node; + for(MD_NodePtrNode *n = schemas.first; n != 0 && c_schema == &md_nil_node; n = n->next) + { + c_schema = md_child_from_string(n->v, c->string, 0); + } + // rjf: push name of this node if(c->string.size != 0 || c->first == &rd_nil_cfg) { + // rjf: extract the textualized form for this string (we may need to escape / relativize) + String8 c_serialized_string = c->string; + { + MD_Node *c_schema = &md_nil_node; + if(top_nest_task != 0) + { + c_schema = top_nest_task->schema; + } + + // rjf: paths -> relativize + if(str8_match(c_schema->first->string, str8_lit("path"), 0) && + !md_node_has_tag(c_schema->first, str8_lit("absolute"), 0)) + { + String8 path_absolute = c->string; + String8 path_relative = path_relative_dst_from_absolute_dst_src(arena, path_absolute, root_path); + c_serialized_string = path_relative; + } + + // rjf: all strings -> escape + c_serialized_string = escaped_from_raw_str8(arena, c_serialized_string); + } + + // rjf: generate all strings for this node's string String8List c_name_strings = {0}; - B32 name_can_be_pushed_standalone = 0; { - Temp temp = temp_begin(scratch.arena); - MD_TokenizeResult c_name_tokenize = md_tokenize_from_text(temp.arena, c->string); - name_can_be_pushed_standalone = (c_name_tokenize.tokens.count == 1 && c_name_tokenize.tokens.v[0].flags & (MD_TokenFlag_Identifier| - MD_TokenFlag_Numeric| - MD_TokenFlag_StringLiteral| - MD_TokenFlag_Symbol)); - temp_end(temp); - } - if(name_can_be_pushed_standalone) - { - str8_list_push(scratch.arena, &c_name_strings, c->string); - } - else - { - String8 c_name_escaped = escaped_from_raw_str8(scratch.arena, c->string); - str8_list_push(scratch.arena, &c_name_strings, str8_lit("\"")); - str8_list_push(scratch.arena, &c_name_strings, c_name_escaped); - str8_list_push(scratch.arena, &c_name_strings, str8_lit("\"")); + B32 name_can_be_pushed_standalone = 0; + { + Temp temp = temp_begin(scratch.arena); + MD_TokenizeResult c_name_tokenize = md_tokenize_from_text(temp.arena, c_serialized_string); + name_can_be_pushed_standalone = (c_name_tokenize.tokens.count == 1 && c_name_tokenize.tokens.v[0].flags & (MD_TokenFlag_Identifier| + MD_TokenFlag_Numeric| + MD_TokenFlag_StringLiteral| + MD_TokenFlag_Symbol)); + temp_end(temp); + } + if(name_can_be_pushed_standalone) + { + str8_list_push(scratch.arena, &c_name_strings, c_serialized_string); + } + else + { + str8_list_push(scratch.arena, &c_name_strings, str8_lit("\"")); + str8_list_push(scratch.arena, &c_name_strings, c_serialized_string); + str8_list_push(scratch.arena, &c_name_strings, str8_lit("\"")); + } } + + // rjf: if we're in a simple nesting task, then just break children by space if(top_nest_task != 0 && top_nest_task->is_simple) { str8_list_push(scratch.arena, &strings, str8_lit(" ")); } + + // rjf: join c's strings with main string list str8_list_concat_in_place(&strings, &c_name_strings); } // rjf: grab next recursion rec = rd_cfg_rec__depth_first(cfg, c); - // rjf: determine if this node is simple, and can be encoded on a single line - - // if so, push a new nesting task onto the stack + // rjf: push a new nesting task before descending to children if(c->first != &rd_nil_cfg) { B32 is_simple_children_list = 1; @@ -714,6 +786,7 @@ rd_string_from_cfg_tree(Arena *arena, RD_Cfg *cfg) } NestTask *task = push_array(scratch.arena, NestTask, 1); task->cfg = c; + task->schema = c_schema; task->is_simple = is_simple_children_list; SLLStackPush(top_nest_task, task); } @@ -5717,7 +5790,7 @@ rd_window_frame(void) { ThemeTask *t = push_array(scratch.arena, ThemeTask, 1); SLLQueuePushFront(first_task, last_task, t); - t->tree = md_tree_from_string(scratch.arena, rd_string_from_cfg_tree(scratch.arena, n->v)); + t->tree = md_tree_from_string(scratch.arena, rd_string_from_cfg_tree(scratch.arena, str8_zero(), n->v)); } } @@ -12707,7 +12780,7 @@ rd_frame(void) for(String8Node *text_n = raddbg_data_text_parts.first; text_n != 0; text_n = text_n->next) { String8 text = text_n->string; - RD_CfgList cfgs = rd_cfg_tree_list_from_string(scratch.arena, text); + RD_CfgList cfgs = rd_cfg_tree_list_from_string(scratch.arena, str8_zero(), text); String8 module_name = ctrl_string_from_handle(scratch.arena, module->handle); for(RD_CfgNode *n = cfgs.first; n != 0; n = n->next, cfg_idx += 1) { @@ -13098,7 +13171,7 @@ rd_frame(void) RD_CfgList file_cfg_list = {0}; if(file_is_okay) { - file_cfg_list = rd_cfg_tree_list_from_string(scratch.arena, file_data); + file_cfg_list = rd_cfg_tree_list_from_string(scratch.arena, file_path, file_data); } //- rjf: store path @@ -13221,7 +13294,7 @@ rd_frame(void) str8_list_pushf(scratch.arena, &strings, "// raddbg %s %S file\n\n", BUILD_VERSION_STRING_LITERAL, bucket_name); for(RD_Cfg *child = tree_root->first; child != &rd_nil_cfg; child = child->next) { - str8_list_push(scratch.arena, &strings, rd_string_from_cfg_tree(scratch.arena, child)); + str8_list_push(scratch.arena, &strings, rd_string_from_cfg_tree(scratch.arena, dst_path, child)); } String8 data = str8_list_join(scratch.arena, &strings, 0); B32 temp_write_good = os_write_data_to_file_path(temp_path, data); diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index 1f0b487f..2a8d332f 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -865,8 +865,8 @@ internal RD_Cfg *rd_cfg_child_from_string_or_parent(RD_Cfg *parent, String8 stri internal RD_CfgList rd_cfg_child_list_from_string(Arena *arena, RD_Cfg *parent, String8 string); internal RD_CfgList rd_cfg_top_level_list_from_string(Arena *arena, String8 string); internal RD_CfgArray rd_cfg_array_from_list(Arena *arena, RD_CfgList *list); -internal RD_CfgList rd_cfg_tree_list_from_string(Arena *arena, String8 string); -internal String8 rd_string_from_cfg_tree(Arena *arena, RD_Cfg *cfg); +internal RD_CfgList rd_cfg_tree_list_from_string(Arena *arena, String8 root_path, String8 string); +internal String8 rd_string_from_cfg_tree(Arena *arena, String8 root_path, RD_Cfg *cfg); internal RD_CfgRec rd_cfg_rec__depth_first(RD_Cfg *root, RD_Cfg *cfg); internal void rd_cfg_list_push(Arena *arena, RD_CfgList *list, RD_Cfg *cfg); internal void rd_cfg_list_push_front(Arena *arena, RD_CfgList *list, RD_Cfg *cfg);