diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 7a0e5db6..95378b57 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -45,9 +45,6 @@ main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **argum #if defined(FUZZY_SEARCH_H) && !defined(FZY_INIT_MANUAL) fzy_init(); #endif -#if defined(TXTI_H) && !defined(TXTI_INIT_MANUAL) - txti_init(); -#endif #if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL) dmn_init(); #endif diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index 4b3feae2..e1c30fb6 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -1398,19 +1398,6 @@ df_entity_fuzzy_item_array_from_entity_array_needle(Arena *arena, DF_EntityArray return result; } -//- rjf: entity -> text info - -internal TXTI_Handle -df_txti_handle_from_entity(DF_Entity *entity) -{ - TXTI_Handle handle = {0}; - Temp scratch = scratch_begin(0, 0); - String8 path = df_full_path_from_entity(scratch.arena, entity); - handle = txti_handle_from_path(path); - scratch_end(scratch); - return handle; -} - //- rjf: full path building, from file/folder entities internal String8 @@ -7123,10 +7110,8 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) DF_EntityList existing_processes = df_query_cached_entity_list_with_kind(DF_EntityKind_Process); if(existing_processes.count == 0) { - Temp scratch = scratch_begin(0, 0); - DF_Entity *session_log = df_log_from_entity(df_entity_root()); - TXTI_Handle session_log_handle = df_txti_handle_from_entity(session_log); - txti_reload(session_log_handle, df_full_path_from_entity(scratch.arena, session_log)); + MTX_Op op = {r1u64(0, 0xffffffffffffffffull), str8_lit("[new session]\n")}; + mtx_push_op(df_state->output_log_key, op); DF_EntityList bps = df_query_cached_entity_list_with_kind(DF_EntityKind_Breakpoint); for(DF_EntityNode *n = bps.first; n != 0; n = n->next) { @@ -7315,25 +7300,6 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) { MTX_Op op = {r1u64(max_U64, max_U64), event->string}; mtx_push_op(df_state->output_log_key, op); -#if 0 - String8 string = event->string; - DF_Entity *root = df_entity_root(); - DF_Entity *thread = df_entity_from_ctrl_handle(event->machine_id, event->entity); - DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); - DF_Entity *machine = df_entity_ancestor_from_kind(process, DF_EntityKind_Machine); - DF_Entity *root_log = df_log_from_entity(root); - DF_Entity *thread_log = df_log_from_entity(thread); - DF_Entity *process_log = df_log_from_entity(process); - DF_Entity *machine_log = df_log_from_entity(machine); - TXTI_Handle root_log_handle = df_txti_handle_from_entity(root_log); - TXTI_Handle thread_log_handle = df_txti_handle_from_entity(thread_log); - TXTI_Handle process_log_handle = df_txti_handle_from_entity(process_log); - TXTI_Handle machine_log_handle = df_txti_handle_from_entity(machine_log); - txti_append(root_log_handle, string); - txti_append(thread_log_handle, string); - txti_append(process_log_handle, string); - txti_append(machine_log_handle, string); -#endif }break; case CTRL_EventKind_ThreadName: diff --git a/src/df/core/df_core.h b/src/df/core/df_core.h index ead3bd9f..95825753 100644 --- a/src/df/core/df_core.h +++ b/src/df/core/df_core.h @@ -1536,9 +1536,6 @@ internal DF_EntityArray df_entity_array_from_list(Arena *arena, DF_EntityList *l internal DF_EntityFuzzyItemArray df_entity_fuzzy_item_array_from_entity_list_needle(Arena *arena, DF_EntityList *list, String8 needle); internal DF_EntityFuzzyItemArray df_entity_fuzzy_item_array_from_entity_array_needle(Arena *arena, DF_EntityArray *array, String8 needle); -//- rjf: entity -> text info -internal TXTI_Handle df_txti_handle_from_entity(DF_Entity *entity); - //- rjf: full path building, from file/folder entities internal String8 df_full_path_from_entity(Arena *arena, DF_Entity *entity); diff --git a/src/df/gfx/df_gfx.c b/src/df/gfx/df_gfx.c index a804bc40..61853333 100644 --- a/src/df/gfx/df_gfx.c +++ b/src/df/gfx/df_gfx.c @@ -12479,188 +12479,6 @@ df_do_txt_controls(TXT_TextInfo *info, String8 data, U64 line_count_per_page, Tx return change; } -internal B32 -df_do_txti_controls(TXTI_Handle handle, U64 line_count_per_page, TxtPt *cursor, TxtPt *mark, S64 *preferred_column) -{ - Temp scratch = scratch_begin(0, 0); - B32 change = 0; - UI_EventList *events = ui_events(); - TXTI_BufferInfo buffer_info = txti_buffer_info_from_handle(scratch.arena, handle); - for(UI_EventNode *n = events->first, *next = 0; n != 0; n = next) - { - next = n->next; - B32 taken = 0; - if(n->v.kind != UI_EventKind_Navigate && n->v.kind != UI_EventKind_Edit) - { - continue; - } - String8 line = txti_string_from_handle_line_num(scratch.arena, handle, cursor->line); - UI_TxtOp single_line_op = ui_single_line_txt_op_from_event(scratch.arena, &n->v, line, *cursor, *mark); - - //- rjf: invalid single-line op or endpoint units => try multiline - if(n->v.delta_unit == UI_EventDeltaUnit_Whole || single_line_op.flags & UI_TxtOpFlag_Invalid) - { - U64 line_count = buffer_info.total_line_count; - String8 prev_line = txti_string_from_handle_line_num(scratch.arena, handle, cursor->line-1); - String8 next_line = txti_string_from_handle_line_num(scratch.arena, handle, cursor->line+1); - Vec2S32 delta = n->v.delta_2s32; - - //- rjf: wrap lines right - if(n->v.delta_unit != UI_EventDeltaUnit_Whole && delta.x > 0 && cursor->column == line.size+1 && cursor->line+1 <= line_count) - { - cursor->line += 1; - cursor->column = 1; - *preferred_column = 1; - change = 1; - taken = 1; - } - - //- rjf: wrap lines left - if(n->v.delta_unit != UI_EventDeltaUnit_Whole && delta.x < 0 && cursor->column == 1 && cursor->line-1 >= 1) - { - cursor->line -= 1; - cursor->column = prev_line.size+1; - *preferred_column = prev_line.size+1; - change = 1; - taken = 1; - } - - //- rjf: movement down (plain) - if(n->v.delta_unit == UI_EventDeltaUnit_Char && delta.y > 0 && cursor->line+1 <= line_count) - { - cursor->line += 1; - cursor->column = Min(*preferred_column, next_line.size+1); - change = 1; - taken = 1; - } - - //- rjf: movement up (plain) - if(n->v.delta_unit == UI_EventDeltaUnit_Char && delta.y < 0 && cursor->line-1 >= 1) - { - cursor->line -= 1; - cursor->column = Min(*preferred_column, prev_line.size+1); - change = 1; - taken = 1; - } - - //- rjf: movement down (chunk) - if(n->v.delta_unit == UI_EventDeltaUnit_Word && delta.y > 0 && cursor->line+1 <= line_count) - { - for(S64 line_num = cursor->line+1; line_num <= line_count; line_num += 1) - { - String8 line = txti_string_from_handle_line_num(scratch.arena, handle, line_num); - U64 line_size = line.size; - if(line_size == 0) - { - cursor->line = line_num; - cursor->column = 1; - break; - } - else if(line_num == line_count) - { - cursor->line = line_num; - cursor->column = line_size+1; - } - } - change = 1; - taken = 1; - } - - //- rjf: movement up (chunk) - if(n->v.delta_unit == UI_EventDeltaUnit_Word && delta.y < 0 && cursor->line-1 >= 1) - { - for(S64 line_num = cursor->line-1; line_num > 0; line_num -= 1) - { - String8 line = txti_string_from_handle_line_num(scratch.arena, handle, line_num); - U64 line_size = line.size; - if(line_size == 0) - { - cursor->line = line_num; - cursor->column = 1; - break; - } - else if(line_num == 1) - { - cursor->line = line_num; - cursor->column = 1; - } - } - change = 1; - taken = 1; - } - - //- rjf: movement down (page) - if(n->v.delta_unit == UI_EventDeltaUnit_Page && delta.y > 0) - { - cursor->line += line_count_per_page; - cursor->column = 1; - cursor->line = Clamp(1, cursor->line, line_count); - change = 1; - taken = 1; - } - - //- rjf: movement up (page) - if(n->v.delta_unit == UI_EventDeltaUnit_Page && delta.y < 0) - { - cursor->line -= line_count_per_page; - cursor->column = 1; - cursor->line = Clamp(1, cursor->line, line_count); - change = 1; - taken = 1; - } - - //- rjf: movement to endpoint (+) - if(n->v.delta_unit == UI_EventDeltaUnit_Whole && (delta.y > 0 || delta.x > 0)) - { - *cursor = txt_pt(line_count, buffer_info.last_line_size); - change = 1; - taken = 1; - } - - //- rjf: movement to endpoint (-) - if(n->v.delta_unit == UI_EventDeltaUnit_Whole && (delta.y < 0 || delta.x < 0)) - { - *cursor = txt_pt(1, 1); - change = 1; - taken = 1; - } - - //- rjf: stick mark to cursor, when we don't want to keep it in the same spot - if(!(n->v.flags & UI_EventFlag_KeepMark)) - { - *mark = *cursor; - } - } - - //- rjf: valid single-line op => do single-line op - else - { - *cursor = single_line_op.cursor; - *mark = single_line_op.mark; - *preferred_column = cursor->column; - change = 1; - taken = 1; - } - - //- rjf: copy - if(n->v.flags & UI_EventFlag_Copy) - { - String8 text = txti_string_from_handle_txt_rng(scratch.arena, handle, txt_rng(*cursor, *mark)); - os_set_clipboard_text(text); - taken = 1; - } - - //- rjf: consume - if(taken) - { - ui_eat_event(events, n); - } - } - - scratch_end(scratch); - return change; -} - //////////////////////////////// //~ rjf: UI Widgets: Fancy Labels diff --git a/src/df/gfx/df_gfx.h b/src/df/gfx/df_gfx.h index 9e8244c9..8b9f469c 100644 --- a/src/df/gfx/df_gfx.h +++ b/src/df/gfx/df_gfx.h @@ -1084,7 +1084,6 @@ internal DF_CodeSliceSignal df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, E internal DF_CodeSliceSignal df_code_slicef(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *preferred_column, char *fmt, ...); internal B32 df_do_txt_controls(TXT_TextInfo *info, String8 data, U64 line_count_per_page, TxtPt *cursor, TxtPt *mark, S64 *preferred_column); -internal B32 df_do_txti_controls(TXTI_Handle handle, U64 line_count_per_page, TxtPt *cursor, TxtPt *mark, S64 *preferred_column); //////////////////////////////// //~ rjf: UI Widgets: Fancy Labels diff --git a/src/mutable_text/mutable_text.c b/src/mutable_text/mutable_text.c index 92f2c0ed..d1b8ff87 100644 --- a/src/mutable_text/mutable_text.c +++ b/src/mutable_text/mutable_text.c @@ -115,8 +115,8 @@ mtx_mut_thread__entry_point(void *p) //- rjf: construct new buffer if(op.range.max != op.range.min || op.replace.size != 0) { - Arena *arena = arena_alloc(); U64 new_data_size = data.size + op.replace.size - dim_1u64(op.range); + Arena *arena = arena_alloc__sized(new_data_size + ARENA_HEADER_SIZE, new_data_size + ARENA_HEADER_SIZE); U8 *new_data_base = push_array_no_zero(arena, U8, new_data_size); String8 pre_replace_data = str8_substr(data, r1u64(0, op.range.min)); String8 post_replace_data = str8_substr(data, r1u64(op.range.max, data.size)); diff --git a/src/raddbg/raddbg.c b/src/raddbg/raddbg.c index f69d40ed..5d74a2ee 100644 --- a/src/raddbg/raddbg.c +++ b/src/raddbg/raddbg.c @@ -77,14 +77,6 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data) // F32 dt = 1.f/target_hz; - ////////////////////////////// - //- rjf: last frame before sleep -> disable txti change detection - // - if(df_gfx_state->num_frames_requested == 0) - { - txti_set_external_change_detection_enabled(0); - } - ////////////////////////////// //- rjf: get events from the OS // @@ -94,11 +86,6 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data) events = os_get_events(scratch.arena, df_gfx_state->num_frames_requested == 0); } - ////////////////////////////// - //- rjf: enable txti change detection - // - txti_set_external_change_detection_enabled(1); - ////////////////////////////// //- rjf: begin measuring actual per-frame work // diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index f68eb1b4..98b59d30 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -38,7 +38,6 @@ #include "text_cache/text_cache.h" #include "mutable_text/mutable_text.h" #include "path/path.h" -#include "txti/txti.h" #include "coff/coff.h" #include "pe/pe.h" #include "codeview/codeview.h" @@ -79,7 +78,6 @@ #include "text_cache/text_cache.c" #include "mutable_text/mutable_text.c" #include "path/path.c" -#include "txti/txti.c" #include "coff/coff.c" #include "pe/pe.c" #include "codeview/codeview.c" diff --git a/src/txti/txti.c b/src/txti/txti.c deleted file mode 100644 index 9fc4cf06..00000000 --- a/src/txti/txti.c +++ /dev/null @@ -1,895 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void -txti_init(void) -{ - Arena *arena = arena_alloc(); - txti_state = push_array(arena, TXTI_State, 1); - txti_state->arena = arena; - txti_state->entity_map.slots_count = 1024; - txti_state->entity_map.slots = push_array(txti_state->arena, TXTI_EntitySlot, txti_state->entity_map.slots_count); - txti_state->entity_map_stripes.count = 64; - txti_state->entity_map_stripes.v = push_array(txti_state->arena, TXTI_Stripe, txti_state->entity_map_stripes.count); - for(U64 idx = 0; idx < txti_state->entity_map_stripes.count; idx += 1) - { - txti_state->entity_map_stripes.v[idx].arena = arena_alloc(); - txti_state->entity_map_stripes.v[idx].cv = os_condition_variable_alloc(); - txti_state->entity_map_stripes.v[idx].rw_mutex = os_rw_mutex_alloc(); - } - txti_state->mut_thread_count = Clamp(1, os_logical_core_count(), 4); - txti_state->mut_threads = push_array(txti_state->arena, TXTI_MutThread, txti_state->mut_thread_count); - for(U64 idx = 0; idx < txti_state->mut_thread_count; idx += 1) - { - TXTI_MutThread *thread = &txti_state->mut_threads[idx]; - thread->msg_arena = arena_alloc(); - thread->msg_mutex = os_mutex_alloc(); - thread->msg_cv = os_condition_variable_alloc(); - thread->thread = os_launch_thread(txti_mut_thread_entry_point, (void *)idx, 0); - } - txti_state->detector_thread = os_launch_thread(txti_detector_thread_entry_point, 0, 0); -} - -//////////////////////////////// -//~ rjf: Basic Helpers - -internal U64 -txti_hash_from_string(String8 string) -{ - U64 result = 5381; - for(U64 i = 0; i < string.size; i += 1) - { - result = ((result << 5) + result) + string.str[i]; - } - return result; -} - -//////////////////////////////// -//~ rjf: Message Type Functions - -internal void -txti_msg_list_push(Arena *arena, TXTI_MsgList *msgs, TXTI_Msg *msg) -{ - TXTI_MsgNode *node = push_array(arena, TXTI_MsgNode, 1); - MemoryCopyStruct(&node->v, msg); - SLLQueuePush(msgs->first, msgs->last, node); - msgs->count += 1; -} - -internal void -txti_msg_list_concat_in_place(TXTI_MsgList *dst, TXTI_MsgList *src) -{ - if(dst->last == 0) - { - MemoryCopyStruct(dst, src); - } - else if(src->first) - { - dst->last->next = src->first; - dst->last = src->last; - dst->count += src->count; - } - MemoryZeroStruct(src); -} - -internal TXTI_MsgList -txti_msg_list_deep_copy(Arena *arena, TXTI_MsgList *src) -{ - TXTI_MsgList dst = {0}; - for(TXTI_MsgNode *src_n = src->first; src_n != 0; src_n = src_n->next) - { - TXTI_MsgNode *dst_n = push_array(arena, TXTI_MsgNode, 1); - SLLQueuePush(dst.first, dst.last, dst_n); - dst.count += 1; - MemoryCopyStruct(&dst_n->v, &src_n->v); - dst_n->v.string = push_str8_copy(arena, src_n->v.string); - } - return dst; -} - -//////////////////////////////// -//~ rjf: Entities API - -//- rjf: opening entities & correllation w/ path - -internal TXTI_Handle -txti_handle_from_path(String8 path) -{ - TXTI_Handle handle = {0}; - { - // rjf: path -> hash * slot *stripe - U64 hash = txti_hash_from_string(path); - U64 slot_idx = hash%txti_state->entity_map.slots_count; - U64 stripe_idx = slot_idx%txti_state->entity_map_stripes.count; - TXTI_EntitySlot *slot = &txti_state->entity_map.slots[slot_idx]; - TXTI_Stripe *stripe = &txti_state->entity_map_stripes.v[stripe_idx]; - - // rjf: determine if entity exists (shared lock) - TXTI_Entity *found_entity = 0; - OS_MutexScopeR(stripe->rw_mutex) - { - for(TXTI_Entity *entity = slot->first; entity != 0; entity = entity->next) - { - if(str8_match(entity->path, path, 0)) - { - found_entity = entity; - break; - } - } - if(found_entity != 0) - { - handle.u64[0] = hash; - handle.u64[1] = found_entity->id; - } - } - - // rjf: if entity does not exist -> exclusive lock & check again -- if still - // does not exist, then build it - if(found_entity == 0) OS_MutexScopeW(stripe->rw_mutex) - { - for(TXTI_Entity *entity = slot->first; entity != 0; entity = entity->next) - { - if(str8_match(entity->path, path, 0)) - { - found_entity = entity; - break; - } - } - if(found_entity == 0) - { - TXTI_Entity *entity = push_array(stripe->arena, TXTI_Entity, 1); - entity->path = push_str8_copy(stripe->arena, path); - entity->id = ins_atomic_u64_inc_eval(&txti_state->entity_id_gen); - for(U64 idx = 0; idx < TXTI_ENTITY_BUFFER_COUNT; idx += 1) - { - TXTI_Buffer *buffer = &entity->buffers[idx]; - buffer->data_arena = arena_alloc__sized(GB(32), KB(64)); - buffer->analysis_arena = arena_alloc__sized(GB(32), KB(64)); - buffer->data_arena->align = 1; - } - SLLQueuePush(slot->first, slot->last, entity); - found_entity = entity; - } - handle.u64[0] = hash; - handle.u64[1] = found_entity->id; - } - } - return handle; -} - -//- rjf: buffer introspection - -internal TXTI_BufferInfo -txti_buffer_info_from_handle(Arena *arena, TXTI_Handle handle) -{ - TXTI_BufferInfo result = {0}; - U64 hash = handle.u64[0]; - U64 id = handle.u64[1]; - U64 slot_idx = hash%txti_state->entity_map.slots_count; - U64 stripe_idx = slot_idx%txti_state->entity_map_stripes.count; - TXTI_EntitySlot *slot = &txti_state->entity_map.slots[slot_idx]; - TXTI_Stripe *stripe = &txti_state->entity_map_stripes.v[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) - { - TXTI_Entity *entity = 0; - for(TXTI_Entity *e = slot->first; e != 0; e = e->next) - { - if(e->id == id) - { - entity = e; - break; - } - } - if(entity != 0) - { - TXTI_Buffer *buffer = &entity->buffers[entity->buffer_apply_gen%TXTI_ENTITY_BUFFER_COUNT]; - result.path = push_str8_copy(arena, entity->path); - result.timestamp = entity->timestamp; - result.line_end_kind = entity->line_end_kind; - result.total_line_count = buffer->lines_count; - result.max_line_size = buffer->lines_max_size; - result.mut_gen = entity->mut_gen; - result.buffer_apply_gen = entity->buffer_apply_gen; - result.bytes_processed = ins_atomic_u64_eval(&entity->bytes_processed); - result.bytes_to_process = ins_atomic_u64_eval(&entity->bytes_to_process); - } - } - result.total_line_count = Max(1, result.total_line_count); - return result; -} - -internal TXTI_Slice -txti_slice_from_handle_line_range(Arena *arena, TXTI_Handle handle, Rng1S64 line_range) -{ - ProfBeginFunction(); - TXTI_Slice result = {0}; - Temp scratch = scratch_begin(&arena, 1); - U64 hash = handle.u64[0]; - U64 id = handle.u64[1]; - U64 slot_idx = hash%txti_state->entity_map.slots_count; - U64 stripe_idx = slot_idx%txti_state->entity_map_stripes.count; - TXTI_EntitySlot *slot = &txti_state->entity_map.slots[slot_idx]; - TXTI_Stripe *stripe = &txti_state->entity_map_stripes.v[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) - { - TXTI_Entity *entity = 0; - for(TXTI_Entity *e = slot->first; e != 0; e = e->next) - { - if(e->id == id) - { - entity = e; - break; - } - } - if(entity != 0) - { - TXTI_Buffer *buffer = &entity->buffers[entity->buffer_apply_gen%TXTI_ENTITY_BUFFER_COUNT]; - Rng1S64 line_range_clamped = r1s64(Clamp(1, line_range.min, (S64)buffer->lines_count), Clamp(1, line_range.max, (S64)buffer->lines_count)); - - // rjf: allocate output arrays - result.line_count = (U64)dim_1s64(line_range_clamped)+1; - result.line_text = push_array(arena, String8, result.line_count); - result.line_ranges = push_array(arena, Rng1U64, result.line_count); - result.line_tokens = push_array(arena, TXT_TokenArray, result.line_count); - - // rjf: fill line ranges & text - U64 line_slice_idx = 0; - U64 line_buffer_idx = line_range_clamped.min-1; - ProfScope("fill line ranges & text") - for(S64 line_num = line_range_clamped.min; - line_num <= line_range_clamped.max && line_buffer_idx < buffer->lines_count; - line_num += 1, - line_slice_idx += 1, - line_buffer_idx += 1) - { - Rng1U64 range = buffer->lines_ranges[line_buffer_idx]; - String8 line_text_internal = str8_substr(buffer->data, range); - result.line_ranges[line_slice_idx] = range; - result.line_text[line_slice_idx] = push_str8_copy(arena, line_text_internal); - } - - // rjf: binary search to find first token - TXT_Token *tokens_first = 0; - ProfScope("binary search to find first token") - { - Rng1U64 slice_range = r1u64(result.line_ranges[0].min, result.line_ranges[result.line_count-1].max); - U64 min_idx = 0; - U64 opl_idx = buffer->tokens.count; - for(;;) - { - U64 mid_idx = (opl_idx+min_idx)/2; - if(mid_idx >= opl_idx) - { - break; - } - TXT_Token *mid_token = &buffer->tokens.v[mid_idx]; - if(mid_token->range.min > slice_range.max) - { - opl_idx = mid_idx; - } - else if(mid_token->range.max < slice_range.min) - { - min_idx = mid_idx; - } - else if(tokens_first == 0 || mid_token->range.min < tokens_first->range.min) - { - tokens_first = mid_token; - opl_idx = mid_idx; - } - if(mid_idx == min_idx && mid_idx+1 == opl_idx) - { - break; - } - } - } - - // rjf: grab per-line tokens - TXT_TokenList *line_tokens_lists = push_array(scratch.arena, TXT_TokenList, result.line_count); - if(tokens_first != 0) ProfScope("grab per-line tokens") - { - TXT_Token *tokens_opl = buffer->tokens.v+buffer->tokens.count; - U64 line_slice_idx = 0; - for(TXT_Token *token = tokens_first; token < tokens_opl && line_slice_idx < result.line_count;) - { - if(token->range.min < result.line_ranges[line_slice_idx].max) - { - if(token->range.max > result.line_ranges[line_slice_idx].min) - { - txt_token_list_push(scratch.arena, &line_tokens_lists[line_slice_idx], token); - } - B32 need_token_advance = 0; - B32 need_line_advance = 0; - if(token->range.max >= result.line_ranges[line_slice_idx].max) - { - need_line_advance = 1; - } - if(token->range.max <= result.line_ranges[line_slice_idx].max) - { - need_token_advance += 1; - } - if(need_line_advance) { line_slice_idx += 1; } - if(need_token_advance) { token += 1; } - } - else - { - line_slice_idx += 1; - } - } - } - - // rjf: bake per-line tokens to arrays - for(U64 line_slice_idx = 0; line_slice_idx < result.line_count; line_slice_idx += 1) - { - result.line_tokens[line_slice_idx] = txt_token_array_from_list(arena, &line_tokens_lists[line_slice_idx]); - } - } - } - scratch_end(scratch); - ProfEnd(); - return result; -} - -internal String8 -txti_string_from_handle_txt_rng(Arena *arena, TXTI_Handle handle, TxtRng range) -{ - String8 result = {0}; - Temp scratch = scratch_begin(&arena, 1); - { - Rng1S64 line_range = r1s64(ClampBot(1, range.min.line), ClampBot(1, range.max.line)); - TXTI_BufferInfo info = txti_buffer_info_from_handle(scratch.arena, handle); - TXTI_Slice slice = txti_slice_from_handle_line_range(scratch.arena, handle, line_range); - String8List line_strings = {0}; - for(U64 line_idx = 0; line_idx < slice.line_count; line_idx += 1) - { - String8 line_text = slice.line_text[line_idx]; - if(line_idx == slice.line_count-1) - { - line_text = str8_prefix(line_text, range.max.column-1); - } - if(line_idx == 0) - { - line_text = str8_skip(line_text, range.min.column-1); - } - str8_list_push(scratch.arena, &line_strings, line_text); - } - StringJoin join = {0}; - switch(info.line_end_kind) - { - default: - case TXT_LineEndKind_LF:{join.sep = str8_lit("\n");}break; - case TXT_LineEndKind_CRLF:{join.sep = str8_lit("\r\n");}break; - } - result = str8_list_join(arena, &line_strings, &join); - } - scratch_end(scratch); - return result; -} - -internal String8 -txti_string_from_handle_line_num(Arena *arena, TXTI_Handle handle, S64 line_num) -{ - String8 result = {0}; - TXTI_Slice slice = txti_slice_from_handle_line_range(arena, handle, r1s64(line_num, line_num)); - if(slice.line_count != 0) - { - result = slice.line_text[0]; - } - return result; -} - -internal Rng1U64 -txti_expr_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 TxtRng -txti_expr_range_from_handle_pt(TXTI_Handle handle, TxtPt pt) -{ - TxtRng result = {0}; - Temp scratch = scratch_begin(0, 0); - TXTI_Slice slice = txti_slice_from_handle_line_range(scratch.arena, handle, r1s64(pt.line, pt.line)); - if(slice.line_count != 0) - { - // rjf: unpack line info - String8 line_text = slice.line_text[0]; - Rng1U64 line_range = slice.line_ranges[0]; - TXT_TokenArray line_tokens = slice.line_tokens[0]; - 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 - Rng1U64 expr_off_rng = txti_expr_range_from_line_off_range_string_tokens(pt_off, line_range, line_text, &line_tokens); - - // rjf: convert offset range into text range - result = txt_rng(txt_pt(pt.line, 1+(expr_off_rng.min-line_range.min)), txt_pt(pt.line, 1+(expr_off_rng.max-line_range.min))); - } - scratch_end(scratch); - return result; -} - -//- rjf: buffer mutations - -internal void -txti_reload(TXTI_Handle handle, String8 path) -{ - U64 hash = handle.u64[0]; - U64 id = handle.u64[1]; - U64 mut_thread_idx = id%txti_state->mut_thread_count; - TXTI_MutThread *mut_thread = &txti_state->mut_threads[mut_thread_idx]; - OS_MutexScope(mut_thread->msg_mutex) - { - TXTI_MsgNode *node = push_array(mut_thread->msg_arena, TXTI_MsgNode, 1); - TXTI_Msg *msg = &node->v; - msg->kind = TXTI_MsgKind_Reload; - msg->handle = handle; - msg->string = push_str8_copy(mut_thread->msg_arena, path); - SLLQueuePush(mut_thread->msg_list.first, mut_thread->msg_list.last, node); - mut_thread->msg_list.count += 1; - } - os_condition_variable_broadcast(mut_thread->msg_cv); -} - -internal void -txti_append(TXTI_Handle handle, String8 string) -{ - U64 hash = handle.u64[0]; - U64 id = handle.u64[1]; - U64 mut_thread_idx = id%txti_state->mut_thread_count; - TXTI_MutThread *mut_thread = &txti_state->mut_threads[mut_thread_idx]; - OS_MutexScope(mut_thread->msg_mutex) - { - TXTI_MsgNode *node = push_array(mut_thread->msg_arena, TXTI_MsgNode, 1); - TXTI_Msg *msg = &node->v; - msg->kind = TXTI_MsgKind_Append; - msg->handle = handle; - msg->string = push_str8_copy(mut_thread->msg_arena, string); - SLLQueuePush(mut_thread->msg_list.first, mut_thread->msg_list.last, node); - mut_thread->msg_list.count += 1; - } - os_condition_variable_broadcast(mut_thread->msg_cv); -} - -//- rjf: buffer external change detection enabling/disabling - -internal void -txti_set_external_change_detection_enabled(B32 enabled) -{ - U64 enabled_u64 = (U64)enabled; - ins_atomic_u64_eval_assign(&txti_state->detector_thread_enabled, enabled_u64); -} - -//////////////////////////////// -//~ rjf: Mutator Threads - -internal void -txti_mut_thread_entry_point(void *p) -{ - U64 mut_thread_idx = (U64)p; - ThreadNameF("[txti] mut #%I64u", mut_thread_idx); - TXTI_MutThread *mut_thread = &txti_state->mut_threads[mut_thread_idx]; - for(;;) - { - //- rjf: begin - Temp scratch = scratch_begin(0, 0); - - //- rjf: pull messages - TXTI_MsgList msgs = {0}; - OS_MutexScope(mut_thread->msg_mutex) for(;;) - { - if(mut_thread->msg_list.count != 0) - { - msgs = txti_msg_list_deep_copy(scratch.arena, &mut_thread->msg_list); - MemoryZeroStruct(&mut_thread->msg_list); - arena_clear(mut_thread->msg_arena); - break; - } - os_condition_variable_wait(mut_thread->msg_cv, mut_thread->msg_mutex, max_U64); - } - - //- rjf: process msgs - for(TXTI_MsgNode *msg_n = msgs.first; msg_n != 0; msg_n = msg_n->next) ProfScope("process msg") - { - //- rjf: unpack message - TXTI_Msg *msg = &msg_n->v; - U64 hash = msg->handle.u64[0]; - U64 id = msg->handle.u64[1]; - U64 slot_idx = hash%txti_state->entity_map.slots_count; - U64 stripe_idx = slot_idx%txti_state->entity_map_stripes.count; - TXTI_EntitySlot *slot = &txti_state->entity_map.slots[slot_idx]; - TXTI_Stripe *stripe = &txti_state->entity_map_stripes.v[stripe_idx]; - - //- rjf: load file if we need it - B32 load_valid = 0; - String8 file_contents = {0}; - TXT_LangKind lang_kind = TXT_LangKind_Null; - U64 timestamp = 0; - if(msg->kind == TXTI_MsgKind_Reload) ProfScope("reload file") - { - FileProperties pre_load_props = os_properties_from_file_path(msg->string); - OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, msg->string); - file_contents = os_string_from_file_range(scratch.arena, file, r1u64(0, pre_load_props.size)); - lang_kind = txt_lang_kind_from_extension(str8_skip_last_dot(msg->string)); - os_file_close(file); - FileProperties post_load_props = os_properties_from_file_path(msg->string); - load_valid = (post_load_props.modified == pre_load_props.modified); - if(load_valid) - { - timestamp = pre_load_props.modified; - } - } - - //- rjf: nonzero lang kind -> unpack lang info - TXT_LangLexFunctionType *lex_function = txt_lex_function_from_lang_kind(lang_kind); - - //- rjf: detect line end kind - TXT_LineEndKind line_end_kind = TXT_LineEndKind_Null; - if(load_valid) - { - U64 lf_count = 0; - U64 cr_count = 0; - for(U64 idx = 0; idx < file_contents.size && idx < 1024; idx += 1) - { - if(file_contents.str[idx] == '\r') - { - cr_count += 1; - } - if(file_contents.str[idx] == '\n') - { - lf_count += 1; - } - } - if(cr_count >= lf_count/2 && lf_count >= 1) - { - line_end_kind = TXT_LineEndKind_CRLF; - } - else if(lf_count >= 1) - { - line_end_kind = TXT_LineEndKind_LF; - } - } - - //- rjf: obtain initial buffer_apply_gen, reset byte processing counters - U64 initial_buffer_apply_gen = 0; - ProfScope("obtain initial buffer_apply_gen") OS_MutexScopeR(stripe->rw_mutex) - { - TXTI_Entity *entity = 0; - for(TXTI_Entity *e = slot->first; e != 0; e = e->next) - { - if(e->id == id) - { - entity = e; - break; - } - } - if(entity != 0) - { - initial_buffer_apply_gen = entity->buffer_apply_gen; - if(msg->kind == TXTI_MsgKind_Reload) - { - ins_atomic_u64_eval_assign(&entity->bytes_processed, 0); - ins_atomic_u64_eval_assign(&entity->bytes_to_process, file_contents.size + !!lex_function*file_contents.size); - } - } - } - - //- rjf: apply edits - ProfScope("apply edits") - { - for(U64 buffer_apply_idx = 0; - buffer_apply_idx < TXTI_ENTITY_BUFFER_COUNT; - buffer_apply_idx += 1) - ProfScope("apply edit #%i", (int)buffer_apply_idx) - { - // rjf: last buffer we're going to edit? -> bump buffer_apply_gen, - // so that before we touch this last buffer, all readers of this - // entity will get the already-modified buffers. - if(buffer_apply_idx == TXTI_ENTITY_BUFFER_COUNT-1) - { - ProfScope("exclusive lock -> buffer swap") OS_MutexScopeW(stripe->rw_mutex) - { - TXTI_Entity *entity = 0; - for(TXTI_Entity *e = slot->first; e != 0; e = e->next) - { - if(e->id == id) - { - entity = e; - break; - } - } - if(entity != 0) - { - entity->buffer_apply_gen += 1; - if(line_end_kind != TXT_LineEndKind_Null) - { - entity->line_end_kind = line_end_kind; - } - if(lang_kind != TXT_LangKind_Null) - { - entity->lang_kind = lang_kind; - } - if(timestamp != 0) - { - entity->timestamp = timestamp; - } - } - } - } - - // rjf: apply edit to this buffer. - // - // NOTE(rjf): all edits can apply *with a shared mutex lock*, - // because only the mutator thread for this buffer can touch the - // non-currently-viewable buffers. we only need to have an - // exclusive lock to bump the buffer_apply_gen (to change the - // actively viewable buffer). - // - ProfScope("apply edit") OS_MutexScopeR(stripe->rw_mutex) - { - TXTI_Entity *entity = 0; - for(TXTI_Entity *e = slot->first; e != 0; e = e->next) - { - if(e->id == id) - { - entity = e; - break; - } - } - if(entity != 0) - { - TXTI_Buffer *buffer = &entity->buffers[(initial_buffer_apply_gen+1+buffer_apply_idx)%TXTI_ENTITY_BUFFER_COUNT]; - - // rjf: clear old analysis data - arena_clear(buffer->analysis_arena); - buffer->lines_count = 0; - buffer->lines_ranges = 0; - buffer->lines_max_size = 0; - MemoryZeroStruct(&buffer->tokens); - - // rjf: perform edit to buffer data - switch(msg->kind) - { - default:{}break; - - // rjf: replace range - case TXTI_MsgKind_Append: ProfScope("append") - { - U8 *append_data_buffer = push_array_no_zero(buffer->data_arena, U8, msg->string.size); - MemoryCopy(append_data_buffer, msg->string.str, msg->string.size); - buffer->data.size += msg->string.size; - if(buffer->data.str == 0 && msg->string.size != 0) - { - buffer->data.str = append_data_buffer; - } - }break; - - // rjf: reload from disk - case TXTI_MsgKind_Reload: ProfScope("reload") - { - arena_clear(buffer->data_arena); - if(file_contents.size != 0) - { - buffer->data = push_str8_copy(buffer->data_arena, file_contents); - } - else - { - MemoryZeroStruct(&buffer->data); - } - }break; - } - - // rjf: parse & store line range info - ProfScope("parse & store line range info") - { - // rjf: count # of lines - U64 line_count = 1; - U64 byte_process_start_idx = 0; - for(U64 idx = 0; idx < buffer->data.size; idx += 1) - { - if(buffer_apply_idx == 0 && idx-byte_process_start_idx >= 1000) - { - ins_atomic_u64_add_eval(&entity->bytes_processed, (idx-byte_process_start_idx)); - byte_process_start_idx = idx; - } - if(buffer->data.str[idx] == '\n' || buffer->data.str[idx] == '\r') - { - line_count += 1; - if(buffer->data.str[idx] == '\r') - { - idx += 1; - } - } - } - - // rjf: allocate & store line ranges - ProfScope("allocate & store line ranges") - { - buffer->lines_count = line_count; - buffer->lines_ranges = push_array_no_zero(buffer->analysis_arena, Rng1U64, buffer->lines_count); - U64 line_idx = 0; - U64 line_start_idx = 0; - for(U64 idx = 0; idx <= buffer->data.size; idx += 1) - { - if(idx == buffer->data.size || buffer->data.str[idx] == '\n' || buffer->data.str[idx] == '\r') - { - Rng1U64 line_range = r1u64(line_start_idx, idx); - U64 line_size = dim_1u64(line_range); - buffer->lines_ranges[line_idx] = line_range; - buffer->lines_max_size = Max(buffer->lines_max_size, line_size); - line_idx += 1; - line_start_idx = idx+1; - if(idx < buffer->data.size && buffer->data.str[idx] == '\r') - { - line_start_idx += 1; - idx += 1; - } - } - } - } - } - - // rjf: lex file contents - if(lex_function != 0) ProfScope("lex text") - { - buffer->tokens = lex_function(buffer->analysis_arena, buffer_apply_idx == 0 ? &entity->bytes_processed : 0, buffer->data); - } - - // rjf: mark final process counter - if(buffer_apply_idx == 0) - { - ins_atomic_u64_eval_assign(&entity->bytes_processed, entity->bytes_to_process); - } - - // rjf: mark task completion - if(buffer_apply_idx == TXTI_ENTITY_BUFFER_COUNT-1) - { - ins_atomic_u64_eval_assign(&entity->working_count, 0); - } - } - } - } - } - } - - //- rjf: end - scratch_end(scratch); - } -} - -//////////////////////////////// -//~ rjf: Detector Thread - -internal void -txti_detector_thread_entry_point(void *p) -{ - ThreadNameF("[txti] detector"); - for(;;) - { - if(ins_atomic_u64_eval(&txti_state->detector_thread_enabled)) - { - U64 slots_per_stripe = txti_state->entity_map.slots_count/txti_state->entity_map_stripes.count; - for(U64 stripe_idx = 0; stripe_idx < txti_state->entity_map_stripes.count; stripe_idx += 1) - { - TXTI_Stripe *stripe = &txti_state->entity_map_stripes.v[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) for(U64 slot_in_stripe_idx = 0; slot_in_stripe_idx < slots_per_stripe; slot_in_stripe_idx += 1) - { - U64 slot_idx = stripe_idx*slots_per_stripe + slot_in_stripe_idx; - TXTI_EntitySlot *slot = &txti_state->entity_map.slots[slot_idx]; - for(TXTI_Entity *entity = slot->first; entity != 0; entity = entity->next) - { - FileProperties props = os_properties_from_file_path(entity->path); - U64 entity_timestamp = entity->timestamp; - if(props.modified != entity_timestamp && ins_atomic_u64_eval(&entity->working_count) == 0) - { - TXTI_Handle handle = {txti_hash_from_string(entity->path), entity->id}; - txti_reload(handle, entity->path); - ins_atomic_u64_inc_eval(&entity->working_count); - } - } - } - } - } - os_sleep_milliseconds(100); - } -} diff --git a/src/txti/txti.h b/src/txti/txti.h deleted file mode 100644 index 48b1844b..00000000 --- a/src/txti/txti.h +++ /dev/null @@ -1,286 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef TXTI_H -#define TXTI_H - -//////////////////////////////// -//~ NOTE(rjf): Text Info Layer Overview (8/30/2023) -// -// This layer's purpose is to provide access to a mutable cache of parsed -// information about textual data, backed by filesystem contents. This -// cache associates unique handles (`TXTI_Handle`) with "entities", where -// entities contain information about textual contents of each line, how many -// lines of text the entity contains, and the tokenization of each line. -// -// While it is generally correct for a debugger to only provide read-only UIs -// for text viewing (so that the user does not mistakenly modify a buffer and -// continue debugging with it, even if the line or symbol info is no longer -// reflective of the source code), there are cases where read/write buffers are -// useful, and so this layer needs to support that, and the disabling of writes -// can remain as a high-level UI decision (rather than a lack of capability of -// the debugger). Mutable buffers may be used for editing config files (or -// otherwise any files that are not relevant to actively-used debug info), -// or debug logs. -// -// This layer is also responsible for hot-reloading changed files from disk, -// *and* for reporting conflicts, if a buffer was mutated within the process, -// but was also modified on disk. -// -// In order to avoid hanging UI while larger files are being edited or lexed, -// all buffer loading, mutation, & parsing happen on "mutator threads". These -// threads consume messages (`TXTI_Msg`), which command them to reload a file -// from disk, or to replace textual ranges in a buffer. After completing those -// operations, the buffer is lexed/parsed. -// -// Entities have *two* buffer data structures -- this allows a mutator thread -// to apply edits to one while the other can be read by user threads. For each -// editing operation, the mutator threads apply identical operations in a -// *rotation-based* order. If the currently-viewable buffer is slot 0, the edit -// will first be applied to slot 1, and before edits are reflected in slot 0, -// the mutator thread will bump a "buffer mutation counter", such that before -// any edits are made to slot 0, the viewable buffer is changed to being within -// slot *1*. -// -// Importantly, entities map to a *unique* mutator thread -- it is not possible -// for multiple mutator threads to be attempting to write to the same entity at -// the same time, as this could not produce meaningful or coherent results. -// This way, all edits to each entity are applied serially. - -//////////////////////////////// -//~ rjf: Handle Type - -typedef struct TXTI_Handle TXTI_Handle; -struct TXTI_Handle -{ - U64 u64[2]; -}; - -//////////////////////////////// -//~ rjf: Buffer Entity Types - -#define TXTI_ENTITY_BUFFER_COUNT 2 - -typedef struct TXTI_Buffer TXTI_Buffer; -struct TXTI_Buffer -{ - // rjf: arenas - Arena *data_arena; - Arena *analysis_arena; - - // rjf: raw textual data - String8 data; - - // rjf: line range info - U64 lines_count; - Rng1U64 *lines_ranges; - U64 lines_max_size; - - // rjf: tokens - TXT_TokenArray tokens; -}; - -typedef struct TXTI_Entity TXTI_Entity; -struct TXTI_Entity -{ - // rjf: top-level info - TXTI_Entity *next; - String8 path; - U64 id; - U64 timestamp; - U64 mut_gen; - - // rjf: metadata - TXT_LineEndKind line_end_kind; - TXT_LangKind lang_kind; - U64 bytes_processed; - U64 bytes_to_process; - U64 working_count; - - // rjf: double-buffered mutable text buffers - U64 buffer_apply_gen; - TXTI_Buffer buffers[TXTI_ENTITY_BUFFER_COUNT]; -}; - -typedef struct TXTI_EntitySlot TXTI_EntitySlot; -struct TXTI_EntitySlot -{ - TXTI_Entity *first; - TXTI_Entity *last; -}; - -typedef struct TXTI_EntityMap TXTI_EntityMap; -struct TXTI_EntityMap -{ - U64 slots_count; - TXTI_EntitySlot *slots; -}; - -//////////////////////////////// -//~ rjf: Striped Access Types - -typedef struct TXTI_Stripe TXTI_Stripe; -struct TXTI_Stripe -{ - Arena *arena; - OS_Handle cv; - OS_Handle rw_mutex; -}; - -typedef struct TXTI_StripeTable TXTI_StripeTable; -struct TXTI_StripeTable -{ - U64 count; - TXTI_Stripe *v; -}; - -//////////////////////////////// -//~ rjf: Entity Introspection Result Types - -typedef struct TXTI_BufferInfo TXTI_BufferInfo; -struct TXTI_BufferInfo -{ - String8 path; - U64 timestamp; - TXT_LineEndKind line_end_kind; - TXT_LangKind lang_kind; - U64 total_line_count; - U64 last_line_size; - U64 max_line_size; - U64 mut_gen; - U64 buffer_apply_gen; - U64 bytes_processed; - U64 bytes_to_process; -}; - -typedef struct TXTI_Slice TXTI_Slice; -struct TXTI_Slice -{ - U64 line_count; - String8 *line_text; - Rng1U64 *line_ranges; - TXT_TokenArray *line_tokens; -}; - -//////////////////////////////// -//~ rjf: User -> Mutator Thread Messages - -typedef enum TXTI_MsgKind -{ - TXTI_MsgKind_Null, - TXTI_MsgKind_Append, - TXTI_MsgKind_Reload, - TXTI_MsgKind_COUNT -} -TXTI_MsgKind; - -typedef struct TXTI_Msg TXTI_Msg; -struct TXTI_Msg -{ - TXTI_MsgKind kind; - TXTI_Handle handle; - String8 string; -}; - -typedef struct TXTI_MsgNode TXTI_MsgNode; -struct TXTI_MsgNode -{ - TXTI_MsgNode *next; - TXTI_Msg v; -}; - -typedef struct TXTI_MsgList TXTI_MsgList; -struct TXTI_MsgList -{ - TXTI_MsgNode *first; - TXTI_MsgNode *last; - U64 count; -}; - -//////////////////////////////// -//~ rjf: Central State - -typedef struct TXTI_MutThread TXTI_MutThread; -struct TXTI_MutThread -{ - OS_Handle thread; - Arena *msg_arena; - TXTI_MsgList msg_list; - OS_Handle msg_mutex; - OS_Handle msg_cv; -}; - -typedef struct TXTI_State TXTI_State; -struct TXTI_State -{ - // rjf: arena - Arena *arena; - - // rjf: entities state - TXTI_EntityMap entity_map; - TXTI_StripeTable entity_map_stripes; - U64 entity_id_gen; - - // rjf: mutator threads - U64 mut_thread_count; - TXTI_MutThread *mut_threads; - - // rjf: detector thread - U64 detector_thread_enabled; - OS_Handle detector_thread; -}; - -//////////////////////////////// -//~ rjf: Globals - -global TXTI_State *txti_state = 0; - -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void txti_init(void); - -//////////////////////////////// -//~ rjf: Basic Helpers - -internal U64 txti_hash_from_string(String8 string); - -//////////////////////////////// -//~ rjf: Message Type Functions - -internal void txti_msg_list_push(Arena *arena, TXTI_MsgList *msgs, TXTI_Msg *msg); -internal void txti_msg_list_concat_in_place(TXTI_MsgList *dst, TXTI_MsgList *src); -internal TXTI_MsgList txti_msg_list_deep_copy(Arena *arena, TXTI_MsgList *src); - -//////////////////////////////// -//~ rjf: Entities API - -//- rjf: opening entities & correllation w/ path -internal TXTI_Handle txti_handle_from_path(String8 path); - -//- rjf: buffer introspection -internal TXTI_BufferInfo txti_buffer_info_from_handle(Arena *arena, TXTI_Handle handle); -internal TXTI_Slice txti_slice_from_handle_line_range(Arena *arena, TXTI_Handle handle, Rng1S64 line_range); -internal String8 txti_string_from_handle_txt_rng(Arena *arena, TXTI_Handle handle, TxtRng range); -internal String8 txti_string_from_handle_line_num(Arena *arena, TXTI_Handle handle, S64 line_num); -internal Rng1U64 txti_expr_range_from_line_off_range_string_tokens(U64 off, Rng1U64 line_range, String8 line_text, TXT_TokenArray *line_tokens); -internal TxtRng txti_expr_range_from_handle_pt(TXTI_Handle handle, TxtPt pt); - -//- rjf: buffer mutations -internal void txti_reload(TXTI_Handle handle, String8 path); -internal void txti_append(TXTI_Handle handle, String8 string); - -//- rjf: buffer external change detection enabling/disabling -internal void txti_set_external_change_detection_enabled(B32 enabled); - -//////////////////////////////// -//~ rjf: Mutator Threads - -internal void txti_mut_thread_entry_point(void *p); - -//////////////////////////////// -//~ rjf: Detector Thread - -internal void txti_detector_thread_entry_point(void *p); - -#endif //TXTI_H