diff --git a/4ed_edit.cpp b/4ed_edit.cpp index b1b93040..c72dc1e2 100644 --- a/4ed_edit.cpp +++ b/4ed_edit.cpp @@ -10,10 +10,30 @@ // TOP internal void -edit_pre_state_change(Models *models, Editing_File *file){ +pre_edit_state_change(Models *models, Editing_File *file){ file_add_dirty_flag(file, DirtyState_UnsavedChanges); } +internal void +pre_edit_history_prep(Editing_File *file, Edit_Behaviors behaviors){ + if (!behaviors.do_not_post_to_history){ + history_dump_records_after_index(&file->state.history, + file->state.current_record_index); + } +} + +internal void +post_edit_call_hook(Thread_Context *tctx, Models *models, Editing_File *file, + Range_i64 new_range, umem original_size){ + // NOTE(allen): edit range hook + if (models->buffer_edit_range != 0){ + Application_Links app = {}; + app.tctx = tctx; + app.cmd_context = models; + models->buffer_edit_range(&app, file->id, new_range, original_size); + } +} + internal void edit_fix_markers__write_workspace_markers(Dynamic_Workspace *workspace, Buffer_ID buffer_id, Cursor_With_Index *cursors, Cursor_With_Index *r_cursors, @@ -138,8 +158,14 @@ edit_fix_markers(Thread_Context *tctx, Models *models, Editing_File *file, Edit if (cursor_count > 0 || r_cursor_count > 0){ buffer_sort_cursors( cursors, cursor_count); buffer_sort_cursors(r_cursors, r_cursor_count); - buffer_update_cursors( cursors, cursor_count, edit.range.first, edit.range.one_past_last, edit.text.size, false); - buffer_update_cursors(r_cursors, r_cursor_count, edit.range.first, edit.range.one_past_last, edit.text.size, true); + + buffer_update_cursors( cursors, cursor_count, + edit.range.first, edit.range.one_past_last, + edit.text.size, false); + buffer_update_cursors(r_cursors, r_cursor_count, + edit.range.first, edit.range.one_past_last, + edit.text.size, true); + buffer_unsort_cursors( cursors, cursor_count); buffer_unsort_cursors(r_cursors, r_cursor_count); @@ -178,7 +204,20 @@ edit_fix_markers(Thread_Context *tctx, Models *models, Editing_File *file, Edit } internal void -edit_single(Thread_Context *tctx, Models *models, Editing_File *file, +file_end_file(Thread_Context *tctx, Models *models, Editing_File *file){ + if (models->end_buffer != 0){ + Application_Links app = {}; + app.tctx = tctx; + app.cmd_context = models; + models->end_buffer(&app, file->id); + } + Lifetime_Allocator *lifetime_allocator = &models->lifetime_allocator; + lifetime_free_object(lifetime_allocator, file->lifetime_object); + file->lifetime_object = lifetime_alloc_object(lifetime_allocator, DynamicWorkspace_Buffer, file); +} + +internal void +edit__apply(Thread_Context *tctx, Models *models, Editing_File *file, Interval_i64 range, String_Const_u8 string, Edit_Behaviors behaviors){ Edit edit = {}; edit.text = string; @@ -193,21 +232,13 @@ edit_single(Thread_Context *tctx, Models *models, Editing_File *file, // NOTE(allen): history update if (!behaviors.do_not_post_to_history){ - history_dump_records_after_index(&file->state.history, file->state.current_record_index); - history_record_edit(&models->global_history, &file->state.history, buffer, edit); - file->state.current_record_index = history_get_record_count(&file->state.history); + history_record_edit(&models->global_history, &file->state.history, buffer, + edit); + file->state.current_record_index = + history_get_record_count(&file->state.history); } - // NOTE(allen): fixing stuff beforewards???? - edit_pre_state_change(models, file); - - // NOTE(allen): save the original text for the edit range hook. - String_Const_u8 original_text = {}; - if (models->buffer_edit_range != 0){ - original_text = buffer_stringify(scratch, &file->state.buffer, edit.range); - } - - // NOTE(allen): expand spec, compute shift + // NOTE(allen): compute shift i64 shift_amount = replace_range_shift(edit.range, (i64)edit.text.size); // NOTE(allen): actual text replacement @@ -225,28 +256,18 @@ edit_single(Thread_Context *tctx, Models *models, Editing_File *file, // NOTE(allen): cursor fixing edit_fix_markers(tctx, models, file, edit); - - // NOTE(allen): edit range hook - if (models->buffer_edit_range != 0){ - Interval_i64 new_range = Ii64(edit.range.first, edit.range.first + edit.text.size); - Application_Links app = {}; - app.tctx = tctx;; - app.cmd_context = models; - models->buffer_edit_range(&app, file->id, new_range, original_text); - } } internal void -file_end_file(Thread_Context *tctx, Models *models, Editing_File *file){ - if (models->end_buffer != 0){ - Application_Links app = {}; - app.tctx = tctx; - app.cmd_context = models; - models->end_buffer(&app, file->id); - } - Lifetime_Allocator *lifetime_allocator = &models->lifetime_allocator; - lifetime_free_object(lifetime_allocator, file->lifetime_object); - file->lifetime_object = lifetime_alloc_object(lifetime_allocator, DynamicWorkspace_Buffer, file); +edit_single(Thread_Context *tctx, Models *models, Editing_File *file, + Range_i64 range, String_Const_u8 string, Edit_Behaviors behaviors){ + pre_edit_state_change(models, file); + pre_edit_history_prep(file, behaviors); + + edit__apply(tctx, models, file, range, string, behaviors); + + post_edit_call_hook(tctx, models, file, + Ii64_size(range.first, string.size), range_size(range)); } internal void @@ -395,25 +416,41 @@ internal b32 edit_batch(Thread_Context *tctx, Models *models, Editing_File *file, Batch_Edit *batch, Edit_Behaviors behaviors){ b32 result = true; + if (batch != 0){ + pre_edit_state_change(models, file); + pre_edit_history_prep(file, behaviors); + History_Record_Index start_index = 0; if (history_is_activated(&file->state.history)){ start_index = file->state.current_record_index; } + Range_i64 old_range = Ii64_neg_inf; + Range_i64 new_range = Ii64_neg_inf; + i64 shift = 0; for (Batch_Edit *edit = batch; edit != 0; edit = edit->next){ String_Const_u8 insert_string = edit->edit.text; - Interval_i64 edit_range = edit->edit.range; + + Range_i64 edit_range = edit->edit.range; + old_range.min = min(old_range.min, edit_range.min); + old_range.max = max(old_range.max, edit_range.max); + edit_range.first += shift; edit_range.one_past_last += shift; + + new_range.min = min(new_range.min, edit_range.min); + i64 new_max = (i64)(edit_range.min + insert_string.size); + new_range.max = max(new_range.max, new_max); + i64 size = buffer_size(&file->state.buffer); if (0 <= edit_range.first && edit_range.first <= edit_range.one_past_last && edit_range.one_past_last <= size){ - edit_single(tctx, models, file, edit_range, insert_string, behaviors); + edit__apply(tctx, models, file, edit_range, insert_string, behaviors); shift += replace_range_shift(edit_range, insert_string.size); } else{ @@ -428,7 +465,10 @@ edit_batch(Thread_Context *tctx, Models *models, Editing_File *file, edit_merge_history_range(tctx, models, file, start_index + 1, last_index, RecordMergeFlag_StateInRange_ErrorOut); } } + + post_edit_call_hook(tctx, models, file, new_range, range_size(old_range)); } + return(result); } diff --git a/custom/4coder_base_types.cpp b/custom/4coder_base_types.cpp index 3c7ef6c7..fa07aaa2 100644 --- a/custom/4coder_base_types.cpp +++ b/custom/4coder_base_types.cpp @@ -1797,6 +1797,11 @@ If32(){ return(interval); } +global Interval_i32 Ii32_neg_inf = {max_i32, min_i32}; +global Interval_i64 Ii64_neg_inf = {max_i64, min_i64}; +global Interval_u64 Iu64_neg_inf = {max_u64, 0}; +global Interval_f32 If32_neg_inf = {max_f32, -max_f32}; + internal b32 operator==(Interval_i32 a, Interval_i32 b){ return(a.min == b.min && a.max == b.max); diff --git a/custom/4coder_default_hooks.cpp b/custom/4coder_default_hooks.cpp index 8731558f..123a1a9e 100644 --- a/custom/4coder_default_hooks.cpp +++ b/custom/4coder_default_hooks.cpp @@ -794,10 +794,10 @@ BUFFER_HOOK_SIG(default_file_save){ } BUFFER_EDIT_RANGE_SIG(default_buffer_edit_range){ - // buffer_id, new_range, text + // buffer_id, new_range, original_size ProfileScope(app, "default edit range"); - Interval_i64 old_range = Ii64(new_range.first, new_range.first + text.size); + Interval_i64 old_range = Ii64(new_range.first, new_range.first + original_size); i64 insert_size = range_size(new_range); i64 text_shift = replace_range_shift(old_range, insert_size); @@ -812,63 +812,81 @@ BUFFER_EDIT_RANGE_SIG(default_buffer_edit_range){ else{ Token_Array *ptr = scope_attachment(app, scope, attachment_tokens, Token_Array); if (ptr != 0 && ptr->tokens != 0){ + ProfileBlockNamed(app, "attempt resync", profile_attempt_resync); + + Base_Allocator *allocator = managed_scope_allocator(app, scope); + + b32 do_full_relex = false; i64 token_index_first = token_relex_first(ptr, old_range.first, 1); i64 token_index_resync_guess = token_relex_resync(ptr, old_range.one_past_last, 16); - Token *token_first = ptr->tokens + token_index_first; - Token *token_resync = ptr->tokens + token_index_resync_guess; - - Range_i64 relex_range = - Ii64(token_first->pos, - token_resync->pos + token_resync->size + text_shift); - String_Const_u8 partial_text = push_buffer_range(app, scratch, buffer_id, - relex_range); - - Token_List relex_list = lex_full_input_cpp(scratch, partial_text); - if (relex_range.one_past_last < buffer_get_size(app, buffer_id)){ - token_drop_eof(&relex_list); - } - - Base_Allocator *allocator = managed_scope_allocator(app, scope); - - Token_Relex relex = token_relex(relex_list, relex_range.first - text_shift, - ptr->tokens, token_index_first, token_index_resync_guess); - - if (relex.successful_resync){ - i64 token_index_resync = relex.first_resync_index; - - Interval_i64 head = Ii64(0, token_index_first); - Interval_i64 replaced = Ii64(token_index_first, token_index_resync); - Interval_i64 tail = Ii64(token_index_resync, ptr->count); - i64 resynced_count = (token_index_resync_guess + 1) - token_index_resync; - i64 relexed_count = relex_list.total_count - resynced_count; - i64 tail_shift = relexed_count - (token_index_resync - token_index_first); - - i64 new_tokens_count = ptr->count + tail_shift; - Token *new_tokens = base_array(allocator, Token, new_tokens_count); - - Token *old_tokens = ptr->tokens; - block_copy_array_shift(new_tokens, old_tokens, head, 0); - token_fill_memory_from_list(new_tokens + replaced.first, &relex_list, relexed_count); - for (i64 i = 0, index = replaced.first; i < relexed_count; i += 1, index += 1){ - new_tokens[index].pos += relex_range.first; - } - for (i64 i = tail.first; i < tail.one_past_last; i += 1){ - old_tokens[i].pos += text_shift; - } - block_copy_array_shift(new_tokens, ptr->tokens, tail, tail_shift); - - base_free(allocator, ptr->tokens); - - ptr->tokens = new_tokens; - ptr->count = new_tokens_count; - ptr->max = new_tokens_count; + if (token_index_resync_guess - token_index_first >= 4000){ + do_full_relex = true; } else{ + Token *token_first = ptr->tokens + token_index_first; + Token *token_resync = ptr->tokens + token_index_resync_guess; + + Range_i64 relex_range = + Ii64(token_first->pos, + token_resync->pos + token_resync->size + text_shift); + String_Const_u8 partial_text = push_buffer_range(app, scratch, + buffer_id, + relex_range); + + Token_List relex_list = lex_full_input_cpp(scratch, partial_text); + if (relex_range.one_past_last < buffer_get_size(app, buffer_id)){ + token_drop_eof(&relex_list); + } + + Token_Relex relex = token_relex(relex_list, relex_range.first - text_shift, + ptr->tokens, token_index_first, token_index_resync_guess); + + profile_attempt_resync.close_now(); + + if (relex.successful_resync){ + ProfileBlock(app, "apply resync"); + + i64 token_index_resync = relex.first_resync_index; + + Interval_i64 head = Ii64(0, token_index_first); + Interval_i64 replaced = Ii64(token_index_first, token_index_resync); + Interval_i64 tail = Ii64(token_index_resync, ptr->count); + i64 resynced_count = (token_index_resync_guess + 1) - token_index_resync; + i64 relexed_count = relex_list.total_count - resynced_count; + i64 tail_shift = relexed_count - (token_index_resync - token_index_first); + + i64 new_tokens_count = ptr->count + tail_shift; + Token *new_tokens = base_array(allocator, Token, new_tokens_count); + + Token *old_tokens = ptr->tokens; + block_copy_array_shift(new_tokens, old_tokens, head, 0); + token_fill_memory_from_list(new_tokens + replaced.first, &relex_list, relexed_count); + for (i64 i = 0, index = replaced.first; i < relexed_count; i += 1, index += 1){ + new_tokens[index].pos += relex_range.first; + } + for (i64 i = tail.first; i < tail.one_past_last; i += 1){ + old_tokens[i].pos += text_shift; + } + block_copy_array_shift(new_tokens, ptr->tokens, tail, tail_shift); + + base_free(allocator, ptr->tokens); + + ptr->tokens = new_tokens; + ptr->count = new_tokens_count; + ptr->max = new_tokens_count; + } + else{ + do_full_relex = true; + } + } + + if (do_full_relex){ base_free(allocator, ptr->tokens); block_zero_struct(ptr); - *lex_task_ptr = async_task_no_dep(&global_async_system, do_full_lex_async, + *lex_task_ptr = async_task_no_dep(&global_async_system, + do_full_lex_async, make_data_struct(&buffer_id)); } } diff --git a/custom/4coder_eol.cpp b/custom/4coder_eol.cpp index 2f278bae..d654e001 100644 --- a/custom/4coder_eol.cpp +++ b/custom/4coder_eol.cpp @@ -14,6 +14,7 @@ rewrite_lines_to_crlf(Application_Links *app, Buffer_ID buffer){ Batch_Edit *first = 0; Batch_Edit *last = 0; + ProfileBlockNamed(app, "build batch edit", profile_batch); i64 pos = -1; Character_Predicate pred_cr = character_predicate_from_character('\r'); Character_Predicate pred_lf = character_predicate_from_character('\n'); @@ -46,6 +47,7 @@ rewrite_lines_to_crlf(Application_Links *app, Buffer_ID buffer){ edit->edit.range = Ii64(pos); } } + profile_batch.close_now(); buffer_batch_edit(app, buffer, first); } @@ -58,6 +60,7 @@ rewrite_lines_to_lf(Application_Links *app, Buffer_ID buffer){ Batch_Edit *first = 0; Batch_Edit *last = 0; + ProfileBlockNamed(app, "build batch edit", profile_batch); i64 pos = -1; Character_Predicate pred = character_predicate_from_character('\r'); for (;;){ @@ -73,7 +76,8 @@ rewrite_lines_to_lf(Application_Links *app, Buffer_ID buffer){ edit->edit.text = string_u8_litexpr(""); edit->edit.range = match.range; } - + profile_batch.close_now(); + buffer_batch_edit(app, buffer, first); } diff --git a/custom/4coder_types.h b/custom/4coder_types.h index 4707f12f..fc410da5 100644 --- a/custom/4coder_types.h +++ b/custom/4coder_types.h @@ -558,16 +558,17 @@ struct Buffer_Name_Conflict_Entry{ typedef void Buffer_Name_Resolver_Function(Application_Links *app, Buffer_Name_Conflict_Entry *conflicts, i32 conflict_count); #define BUFFER_NAME_RESOLVER_SIG(n) \ -void n(Application_Links *app, Buffer_Name_Conflict_Entry *conflicts, i32 conflict_count) +void n(Application_Links *app, Buffer_Name_Conflict_Entry *conflicts, \ + i32 conflict_count) typedef i32 Buffer_Hook_Function(Application_Links *app, Buffer_ID buffer_id); #define BUFFER_HOOK_SIG(name) i32 name(Application_Links *app, Buffer_ID buffer_id) typedef i32 Buffer_Edit_Range_Function(Application_Links *app, Buffer_ID buffer_id, - Range_i64 new_range, String_Const_u8 text); + Range_i64 new_range, umem original_size); #define BUFFER_EDIT_RANGE_SIG(name) \ i32 name(Application_Links *app, Buffer_ID buffer_id, \ -Interval_i64 new_range, String_Const_u8 text) + Interval_i64 new_range, umem original_size) typedef Vec2_f32 Delta_Rule_Function(Vec2_f32 pending, b32 is_new_target, f32 dt, void *data); #define DELTA_RULE_SIG(name) \ @@ -580,7 +581,8 @@ typedef void New_Clipboard_Contents_Function(Application_Links *app, String_Cons void name(Application_Links *app, String_Const_u8 contents) typedef void Render_Caller_Function(Application_Links *app, Frame_Info frame_info, View_ID view); -#define RENDER_CALLER_SIG(name) void name(Application_Links *app, Frame_Info frame_info, View_ID view) +#define RENDER_CALLER_SIG(name) \ +void name(Application_Links *app, Frame_Info frame_info, View_ID view) typedef i64 Command_Map_ID; diff --git a/custom/generated/command_metadata.h b/custom/generated/command_metadata.h index 94a84cc2..13ccb7f3 100644 --- a/custom/generated/command_metadata.h +++ b/custom/generated/command_metadata.h @@ -354,10 +354,10 @@ static Command_Metadata fcoder_metacmd_table[213] = { { PROC_LINKS(redo_all_buffers, 0), false, "redo_all_buffers", 16, "Advances forward through the undo history in the buffer containing the most recent regular edit.", 96, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1922 }, { PROC_LINKS(open_in_other, 0), false, "open_in_other", 13, "Interactively opens a file in the other panel.", 46, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 2023 }, { PROC_LINKS(default_file_externally_modified, 0), false, "default_file_externally_modified", 32, "Notes the external modification of attached files by printing a message.", 72, "w:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 2030 }, -{ PROC_LINKS(set_eol_mode_to_crlf, 0), false, "set_eol_mode_to_crlf", 20, "Puts the buffer in crlf line ending mode.", 41, "w:\\4ed\\code\\custom\\4coder_eol.cpp", 33, 82 }, -{ PROC_LINKS(set_eol_mode_to_lf, 0), false, "set_eol_mode_to_lf", 18, "Puts the buffer in lf line ending mode.", 39, "w:\\4ed\\code\\custom\\4coder_eol.cpp", 33, 93 }, -{ PROC_LINKS(set_eol_mode_to_binary, 0), false, "set_eol_mode_to_binary", 22, "Puts the buffer in bin line ending mode.", 40, "w:\\4ed\\code\\custom\\4coder_eol.cpp", 33, 104 }, -{ PROC_LINKS(set_eol_mode_from_contents, 0), false, "set_eol_mode_from_contents", 26, "Sets the buffer's line ending mode to match the contents of the buffer.", 71, "w:\\4ed\\code\\custom\\4coder_eol.cpp", 33, 115 }, +{ PROC_LINKS(set_eol_mode_to_crlf, 0), false, "set_eol_mode_to_crlf", 20, "Puts the buffer in crlf line ending mode.", 41, "w:\\4ed\\code\\custom\\4coder_eol.cpp", 33, 86 }, +{ PROC_LINKS(set_eol_mode_to_lf, 0), false, "set_eol_mode_to_lf", 18, "Puts the buffer in lf line ending mode.", 39, "w:\\4ed\\code\\custom\\4coder_eol.cpp", 33, 97 }, +{ PROC_LINKS(set_eol_mode_to_binary, 0), false, "set_eol_mode_to_binary", 22, "Puts the buffer in bin line ending mode.", 40, "w:\\4ed\\code\\custom\\4coder_eol.cpp", 33, 108 }, +{ PROC_LINKS(set_eol_mode_from_contents, 0), false, "set_eol_mode_from_contents", 26, "Sets the buffer's line ending mode to match the contents of the buffer.", 71, "w:\\4ed\\code\\custom\\4coder_eol.cpp", 33, 119 }, { PROC_LINKS(interactive_switch_buffer, 0), true, "interactive_switch_buffer", 25, "Interactively switch to an open buffer.", 39, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 416 }, { PROC_LINKS(interactive_kill_buffer, 0), true, "interactive_kill_buffer", 23, "Interactively kill an open buffer.", 34, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 426 }, { PROC_LINKS(interactive_open_or_new, 0), true, "interactive_open_or_new", 23, "Interactively open a file out of the file system.", 49, "w:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 474 },