diff --git a/src/df/gfx/df_views.c b/src/df/gfx/df_views.c index d10e8d73..3b7ffdef 100644 --- a/src/df/gfx/df_views.c +++ b/src/df/gfx/df_views.c @@ -4958,46 +4958,92 @@ DF_VIEW_CMD_FUNCTION_DEF(Code) case DF_CoreCmdKind_GoToNameAtCursor: { Temp scratch = scratch_begin(0, 0); - TXTI_Handle txti_handle = df_txti_handle_from_entity(entity); - TxtRng expr_range = txt_rng(tv->cursor, tv->mark); - if(txt_pt_match(tv->cursor, tv->mark)) + TXT_Scope *txt_scope = txt_scope_open(); + HS_Scope *hs_scope = hs_scope_open(); { - expr_range = txti_expr_range_from_handle_pt(txti_handle, tv->cursor); + // rjf: unpack entity info + String8 path = df_full_path_from_entity(scratch.arena, entity); + U128 key = fs_key_from_path(path); + TXT_LangKind lang_kind = txt_lang_kind_from_extension(str8_skip_last_dot(path)); + U128 hash = {0}; + TXT_TextInfo text_info = txt_text_info_from_key_lang(txt_scope, key, lang_kind, &hash); + String8 data = hs_data_from_hash(hs_scope, hash); + + // rjf: determine expression range + Rng1U64 expr_range = {0}; + { + TxtRng selection_range = txt_rng(tv->cursor, tv->mark); + if(txt_pt_match(selection_range.min, selection_range.max)) + { + expr_range = txt_expr_off_range_from_info_data_pt(&text_info, data, tv->cursor); + } + else + { + expr_range = r1u64(txt_off_from_info_pt(&text_info, selection_range.min), txt_off_from_info_pt(&text_info, selection_range.max)); + } + } + + // rjf: expression range -> text + String8 expr_text = str8_substr(data, expr_range); + + // rjf: go to name + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.entity = df_handle_from_entity(entity); + params.string = expr_text; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_GoToName)); } - String8 expr_text = txti_string_from_handle_txt_rng(scratch.arena, txti_handle, expr_range); - - // rjf: go to name - DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); - params.entity = df_handle_from_entity(entity); - params.string = expr_text; - df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); - df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_GoToName)); - + hs_scope_close(hs_scope); + txt_scope_close(txt_scope); scratch_end(scratch); }break; case DF_CoreCmdKind_ToggleWatchExpressionAtCursor: { Temp scratch = scratch_begin(0, 0); - TXTI_Handle txti_handle = df_txti_handle_from_entity(entity); - TxtRng expr_range = txt_rng(tv->cursor, tv->mark); - if(txt_pt_match(tv->cursor, tv->mark)) + TXT_Scope *txt_scope = txt_scope_open(); + HS_Scope *hs_scope = hs_scope_open(); { - expr_range = txti_expr_range_from_handle_pt(txti_handle, tv->cursor); + // rjf: unpack entity info + String8 path = df_full_path_from_entity(scratch.arena, entity); + U128 key = fs_key_from_path(path); + TXT_LangKind lang_kind = txt_lang_kind_from_extension(str8_skip_last_dot(path)); + U128 hash = {0}; + TXT_TextInfo text_info = txt_text_info_from_key_lang(txt_scope, key, lang_kind, &hash); + String8 data = hs_data_from_hash(hs_scope, hash); + + // rjf: determine expression range + Rng1U64 expr_range = {0}; + { + TxtRng selection_range = txt_rng(tv->cursor, tv->mark); + if(txt_pt_match(selection_range.min, selection_range.max)) + { + expr_range = txt_expr_off_range_from_info_data_pt(&text_info, data, tv->cursor); + } + else + { + expr_range = r1u64(txt_off_from_info_pt(&text_info, selection_range.min), txt_off_from_info_pt(&text_info, selection_range.max)); + } + } + + // rjf: expression range -> text + String8 expr_text = str8_substr(data, expr_range); + + // rjf: toggle watch expr + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.string = expr_text; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ToggleWatchExpression)); + + // rjf: flash marker for grabbed expr + DF_Entity *flash_marker = df_entity_alloc(0, entity, DF_EntityKind_FlashMarker); + df_entity_equip_death_timer(flash_marker, 0.5f); + df_entity_equip_txt_pt(flash_marker, txt_pt_from_info_off__linear_scan(&text_info, expr_range.min)); + df_entity_equip_txt_pt_alt(flash_marker, txt_pt_from_info_off__linear_scan(&text_info, expr_range.max)); + df_entity_equip_color_rgba(flash_marker, df_rgba_from_theme_color(DF_ThemeColor_Highlight0)); + scratch_end(scratch); } - String8 expr_text = txti_string_from_handle_txt_rng(scratch.arena, txti_handle, expr_range); - - // rjf: toggle watch expr - DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); - params.string = expr_text; - df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); - df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ToggleWatchExpression)); - - // rjf: flash marker for grabbed expr - DF_Entity *flash_marker = df_entity_alloc(0, entity, DF_EntityKind_FlashMarker); - df_entity_equip_death_timer(flash_marker, 0.5f); - df_entity_equip_txt_pt(flash_marker, expr_range.min); - df_entity_equip_txt_pt_alt(flash_marker, expr_range.max); - df_entity_equip_color_rgba(flash_marker, df_rgba_from_theme_color(DF_ThemeColor_Highlight0)); + hs_scope_close(hs_scope); + txt_scope_close(txt_scope); scratch_end(scratch); }break; case DF_CoreCmdKind_PickFile: diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index cc6f025d..8120912d 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -37,55 +37,71 @@ fs_init(void) //~ rjf: Cache Interaction internal U128 -fs_hash_from_path(String8 path, U64 rewind_count, U64 endt_us) +fs_hash_from_path(String8 path, U64 endt_us) { Temp scratch = scratch_begin(0, 0); + U128 result = {0}; path = path_normalized_from_string(scratch.arena, path); U128 path_key = hs_hash_from_data(path); - U128 result = hs_hash_from_key(path_key, rewind_count); - if(u128_match(result, u128_zero())) + for(U64 rewind_idx = 0; rewind_idx < 2; rewind_idx += 1) { - U64 slot_idx = path_key.u64[0]%fs_shared->slots_count; - U64 stripe_idx = slot_idx%fs_shared->stripes_count; - FS_Slot *slot = &fs_shared->slots[slot_idx]; - FS_Stripe *stripe = &fs_shared->stripes[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) for(;;) + result = hs_hash_from_key(path_key, rewind_idx); + if(!u128_match(result, u128_zero())) { - FS_Node *node = 0; - for(FS_Node *n = slot->first; n != 0; n = n->next) + break; + } + else if(u128_match(result, u128_zero()) && rewind_idx == 0) + { + U64 slot_idx = path_key.u64[0]%fs_shared->slots_count; + U64 stripe_idx = slot_idx%fs_shared->stripes_count; + FS_Slot *slot = &fs_shared->slots[slot_idx]; + FS_Stripe *stripe = &fs_shared->stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) for(;;) { - if(str8_match(path, n->path, 0)) + FS_Node *node = 0; + for(FS_Node *n = slot->first; n != 0; n = n->next) + { + if(str8_match(path, n->path, 0)) + { + node = n; + break; + } + } + if(node == 0) OS_MutexScopeRWPromote(stripe->rw_mutex) + { + node = push_array(stripe->arena, FS_Node, 1); + SLLQueuePush(slot->first, slot->last, node); + node->path = push_str8_copy(stripe->arena, path); + } + if(os_now_microseconds() >= ins_atomic_u64_eval(&node->last_time_requested_us)+1000000 && + fs_u2s_enqueue_path(path, endt_us)) + { + ins_atomic_u64_eval_assign(&node->last_time_requested_us, os_now_microseconds()); + } + result = hs_hash_from_key(path_key, 0); + if(u128_match(result, u128_zero()) && os_now_microseconds() <= endt_us) + { + os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); + } + else { - node = n; break; } } - if(node == 0) OS_MutexScopeRWPromote(stripe->rw_mutex) - { - node = push_array(stripe->arena, FS_Node, 1); - SLLQueuePush(slot->first, slot->last, node); - node->path = push_str8_copy(stripe->arena, path); - } - if(os_now_microseconds() >= ins_atomic_u64_eval(&node->last_time_requested_us)+1000000 && - fs_u2s_enqueue_path(path, endt_us)) - { - ins_atomic_u64_eval_assign(&node->last_time_requested_us, os_now_microseconds()); - } - result = hs_hash_from_key(path_key, rewind_count); - if(u128_match(result, u128_zero()) && os_now_microseconds() <= endt_us) - { - os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); - } - else - { - break; - } } } scratch_end(scratch); return result; } +internal U128 +fs_key_from_path(String8 path) +{ + U128 key = hs_hash_from_data(path); + fs_hash_from_path(path, 0); + return key; +} + //////////////////////////////// //~ rjf: Streamer Threads diff --git a/src/file_stream/file_stream.h b/src/file_stream/file_stream.h index 8ff10f43..6a491e44 100644 --- a/src/file_stream/file_stream.h +++ b/src/file_stream/file_stream.h @@ -74,7 +74,8 @@ internal void fs_init(void); //////////////////////////////// //~ rjf: Cache Interaction -internal U128 fs_hash_from_path(String8 path, U64 rewind_count, U64 endt_us); +internal U128 fs_hash_from_path(String8 path, U64 endt_us); +internal U128 fs_key_from_path(String8 path); //////////////////////////////// //~ rjf: Streamer Threads diff --git a/src/raddbg/raddbg.h b/src/raddbg/raddbg.h index df1afddc..29893def 100644 --- a/src/raddbg/raddbg.h +++ b/src/raddbg/raddbg.h @@ -19,7 +19,6 @@ // ctrl+C // [ ] UI_NavActions, OS_Event -> UI_Event (single event stream) // -// [ ] committing needs to happen when navigating focus away for any reason // [ ] better discoverability for view rules - have better help hover tooltip, // info on arguments, and better autocomplete lister // diff --git a/src/text_cache/text_cache.c b/src/text_cache/text_cache.c index c70e299d..105d4877 100644 --- a/src/text_cache/text_cache.c +++ b/src/text_cache/text_cache.c @@ -841,6 +841,191 @@ txt_text_info_from_key_lang(TXT_Scope *scope, U128 key, TXT_LangKind lang, U128 return result; } +//////////////////////////////// +//~ rjf: Text Info Extractor Helpers + +internal U64 +txt_off_from_info_pt(TXT_TextInfo *info, TxtPt pt) +{ + U64 off = 0; + if(1 <= pt.line && pt.line <= info->lines_count) + { + Rng1U64 line_range = info->lines_ranges[pt.line-1]; + off = line_range.min + (pt.column-1); + } + return off; +} + +internal TxtPt +txt_pt_from_info_off__linear_scan(TXT_TextInfo *info, U64 off) +{ + TxtPt pt = {0}; + { + for(U64 line_idx = 0; line_idx < info->lines_count; line_idx += 1) + { + if(contains_1u64(info->lines_ranges[line_idx], off)) + { + pt.line = (S64)line_idx + 1; + pt.column = (S64)(off - info->lines_ranges[line_idx].min) + 1; + } + } + } + return pt; +} + +internal TXT_TokenArray +txt_token_array_from_info_line_num__linear_scan(TXT_TextInfo *info, S64 line_num) +{ + TXT_TokenArray line_tokens = {0}; + if(1 <= line_num && line_num <= info->lines_count) + { + Rng1U64 line_range = info->lines_ranges[line_num-1]; + for(U64 token_idx = 0; token_idx < info->tokens.count; token_idx += 1) + { + Rng1U64 token_range = info->tokens.v[token_idx].range; + Rng1U64 token_x_line = intersect_1u64(token_range, line_range); + if(token_x_line.max > token_x_line.min) + { + if(line_tokens.v == 0) + { + line_tokens.v = info->tokens.v+token_idx; + } + line_tokens.count += 1; + } + else if(line_tokens.v != 0) + { + break; + } + } + } + return line_tokens; +} + +internal Rng1U64 +txt_expr_off_range_from_line_off_range_string_tokens(U64 off, Rng1U64 line_range, String8 line_text, TXT_TokenArray *line_tokens) +{ + Rng1U64 result = {0}; + Temp scratch = scratch_begin(0, 0); + { + // rjf: unpack line info + TXT_Token *line_tokens_first = line_tokens->v; + TXT_Token *line_tokens_opl = line_tokens->v+line_tokens->count; + + // rjf: find token containing `off` + TXT_Token *pt_token = 0; + for(TXT_Token *token = line_tokens_first; + token < line_tokens_opl; + token += 1) + { + if(contains_1u64(token->range, off)) + { + Rng1U64 token_range_clamped = intersect_1u64(line_range, token->range); + String8 token_string = str8_substr(line_text, r1u64(token_range_clamped.max - line_range.min, token_range_clamped.max - line_range.min)); + B32 token_ender = 0; + switch(token->kind) + { + default:{}break; + case TXT_TokenKind_Symbol: + { + token_ender = (str8_match(token_string, str8_lit("]"), 0)); + }break; + case TXT_TokenKind_Identifier: + case TXT_TokenKind_Keyword: + case TXT_TokenKind_String: + case TXT_TokenKind_Meta: + { + token_ender = 1; + }break; + } + if(token_ender) + { + pt_token = token; + } + break; + } + } + + // rjf: found token containing `off`? -> mark that as our initial range + if(pt_token != 0) + { + result = pt_token->range; + } + + // rjf: walk back from pt_token - try to find plausible start of expression + if(pt_token != 0) + { + B32 walkback_done = 0; + S32 nest = 0; + for(TXT_Token *wb_token = pt_token; + wb_token >= line_tokens_first && walkback_done == 0; + wb_token -= 1) + { + Rng1U64 wb_token_range_clamped = intersect_1u64(line_range, wb_token->range); + String8 wb_token_string = str8_substr(line_text, r1u64(wb_token_range_clamped.min - line_range.min, wb_token_range_clamped.max - line_range.min)); + B32 include_wb_token = 0; + switch(wb_token->kind) + { + default:{}break; + case TXT_TokenKind_Symbol: + { + B32 is_scope_resolution = str8_match(wb_token_string, str8_lit("::"), 0); + B32 is_dot = str8_match(wb_token_string, str8_lit("."), 0); + B32 is_arrow = str8_match(wb_token_string, str8_lit("->"), 0); + B32 is_open_bracket = str8_match(wb_token_string, str8_lit("["), 0); + B32 is_close_bracket = str8_match(wb_token_string, str8_lit("]"), 0); + nest -= !!(is_open_bracket); + nest += !!(is_close_bracket); + if(is_scope_resolution || + is_dot || + is_arrow || + is_open_bracket|| + is_close_bracket) + { + include_wb_token = 1; + } + }break; + case TXT_TokenKind_Identifier: + { + include_wb_token = 1; + }break; + } + if(include_wb_token) + { + result = union_1u64(result, wb_token->range); + } + else if(nest == 0) + { + walkback_done = 1; + } + } + } + } + scratch_end(scratch); + return result; +} + +internal Rng1U64 +txt_expr_off_range_from_info_data_pt(TXT_TextInfo *info, String8 data, TxtPt pt) +{ + Rng1U64 result = {0}; + Temp scratch = scratch_begin(0, 0); + if(1 <= pt.line && pt.line <= info->lines_count) + { + // rjf: unpack line info + Rng1U64 line_range = info->lines_ranges[pt.line-1]; + String8 line_text = str8_substr(data, line_range); + TXT_TokenArray line_tokens = txt_token_array_from_info_line_num__linear_scan(info, pt.line); + TXT_Token *line_tokens_first = line_tokens.v; + TXT_Token *line_tokens_opl = line_tokens.v+line_tokens.count; + U64 pt_off = line_range.min + (pt.column-1); + + // rjf: grab offset range of expression + result = txt_expr_off_range_from_line_off_range_string_tokens(pt_off, line_range, line_text, &line_tokens); + } + scratch_end(scratch); + return result; +} + //////////////////////////////// //~ rjf: Transfer Threads diff --git a/src/text_cache/text_cache.h b/src/text_cache/text_cache.h index d5501ff9..d46f84e3 100644 --- a/src/text_cache/text_cache.h +++ b/src/text_cache/text_cache.h @@ -262,6 +262,15 @@ internal void txt_scope_touch_node__stripe_r_guarded(TXT_Scope *scope, TXT_Node internal TXT_TextInfo txt_text_info_from_hash_lang(TXT_Scope *scope, U128 hash, TXT_LangKind lang); internal TXT_TextInfo txt_text_info_from_key_lang(TXT_Scope *scope, U128 key, TXT_LangKind lang, U128 *hash_out); +//////////////////////////////// +//~ rjf: Text Info Extractor Helpers + +internal U64 txt_off_from_info_pt(TXT_TextInfo *info, TxtPt pt); +internal TxtPt txt_pt_from_info_off__linear_scan(TXT_TextInfo *info, U64 off); +internal TXT_TokenArray txt_token_array_from_info_line_num__linear_scan(TXT_TextInfo *info, S64 line_num); +internal Rng1U64 txt_expr_off_range_from_line_off_range_string_tokens(U64 off, Rng1U64 line_range, String8 line_text, TXT_TokenArray *line_tokens); +internal Rng1U64 txt_expr_off_range_from_info_data_pt(TXT_TextInfo *info, String8 data, TxtPt pt); + //////////////////////////////// //~ rjf: Transfer Threads