Some batch edit optimizations; next need to support batch cursor fixing

This commit is contained in:
Allen Webster 2019-10-25 17:27:47 -07:00
parent 14b71b8172
commit 529ef3928e
6 changed files with 167 additions and 98 deletions

View File

@ -10,10 +10,30 @@
// TOP // TOP
internal void 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); 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 internal void
edit_fix_markers__write_workspace_markers(Dynamic_Workspace *workspace, Buffer_ID buffer_id, edit_fix_markers__write_workspace_markers(Dynamic_Workspace *workspace, Buffer_ID buffer_id,
Cursor_With_Index *cursors, Cursor_With_Index *r_cursors, 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){ if (cursor_count > 0 || r_cursor_count > 0){
buffer_sort_cursors( cursors, cursor_count); buffer_sort_cursors( cursors, cursor_count);
buffer_sort_cursors(r_cursors, r_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( cursors, cursor_count);
buffer_unsort_cursors(r_cursors, r_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 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){ Interval_i64 range, String_Const_u8 string, Edit_Behaviors behaviors){
Edit edit = {}; Edit edit = {};
edit.text = string; edit.text = string;
@ -193,21 +232,13 @@ edit_single(Thread_Context *tctx, Models *models, Editing_File *file,
// NOTE(allen): history update // NOTE(allen): history update
if (!behaviors.do_not_post_to_history){ 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,
history_record_edit(&models->global_history, &file->state.history, buffer, edit); edit);
file->state.current_record_index = history_get_record_count(&file->state.history); file->state.current_record_index =
history_get_record_count(&file->state.history);
} }
// NOTE(allen): fixing stuff beforewards???? // NOTE(allen): compute shift
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
i64 shift_amount = replace_range_shift(edit.range, (i64)edit.text.size); i64 shift_amount = replace_range_shift(edit.range, (i64)edit.text.size);
// NOTE(allen): actual text replacement // NOTE(allen): actual text replacement
@ -225,28 +256,18 @@ edit_single(Thread_Context *tctx, Models *models, Editing_File *file,
// NOTE(allen): cursor fixing // NOTE(allen): cursor fixing
edit_fix_markers(tctx, models, file, edit); 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 internal void
file_end_file(Thread_Context *tctx, Models *models, Editing_File *file){ edit_single(Thread_Context *tctx, Models *models, Editing_File *file,
if (models->end_buffer != 0){ Range_i64 range, String_Const_u8 string, Edit_Behaviors behaviors){
Application_Links app = {}; pre_edit_state_change(models, file);
app.tctx = tctx; pre_edit_history_prep(file, behaviors);
app.cmd_context = models;
models->end_buffer(&app, file->id); edit__apply(tctx, models, file, range, string, behaviors);
}
Lifetime_Allocator *lifetime_allocator = &models->lifetime_allocator; post_edit_call_hook(tctx, models, file,
lifetime_free_object(lifetime_allocator, file->lifetime_object); Ii64_size(range.first, string.size), range_size(range));
file->lifetime_object = lifetime_alloc_object(lifetime_allocator, DynamicWorkspace_Buffer, file);
} }
internal void internal void
@ -395,25 +416,41 @@ internal b32
edit_batch(Thread_Context *tctx, Models *models, Editing_File *file, edit_batch(Thread_Context *tctx, Models *models, Editing_File *file,
Batch_Edit *batch, Edit_Behaviors behaviors){ Batch_Edit *batch, Edit_Behaviors behaviors){
b32 result = true; b32 result = true;
if (batch != 0){ if (batch != 0){
pre_edit_state_change(models, file);
pre_edit_history_prep(file, behaviors);
History_Record_Index start_index = 0; History_Record_Index start_index = 0;
if (history_is_activated(&file->state.history)){ if (history_is_activated(&file->state.history)){
start_index = file->state.current_record_index; start_index = file->state.current_record_index;
} }
Range_i64 old_range = Ii64_neg_inf;
Range_i64 new_range = Ii64_neg_inf;
i64 shift = 0; i64 shift = 0;
for (Batch_Edit *edit = batch; for (Batch_Edit *edit = batch;
edit != 0; edit != 0;
edit = edit->next){ edit = edit->next){
String_Const_u8 insert_string = edit->edit.text; 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.first += shift;
edit_range.one_past_last += 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); i64 size = buffer_size(&file->state.buffer);
if (0 <= edit_range.first && if (0 <= edit_range.first &&
edit_range.first <= edit_range.one_past_last && edit_range.first <= edit_range.one_past_last &&
edit_range.one_past_last <= size){ 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); shift += replace_range_shift(edit_range, insert_string.size);
} }
else{ 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); 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); return(result);
} }

View File

@ -1797,6 +1797,11 @@ If32(){
return(interval); 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 internal b32
operator==(Interval_i32 a, Interval_i32 b){ operator==(Interval_i32 a, Interval_i32 b){
return(a.min == b.min && a.max == b.max); return(a.min == b.min && a.max == b.max);

View File

@ -794,10 +794,10 @@ BUFFER_HOOK_SIG(default_file_save){
} }
BUFFER_EDIT_RANGE_SIG(default_buffer_edit_range){ BUFFER_EDIT_RANGE_SIG(default_buffer_edit_range){
// buffer_id, new_range, text // buffer_id, new_range, original_size
ProfileScope(app, "default edit range"); 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 insert_size = range_size(new_range);
i64 text_shift = replace_range_shift(old_range, insert_size); i64 text_shift = replace_range_shift(old_range, insert_size);
@ -812,17 +812,27 @@ BUFFER_EDIT_RANGE_SIG(default_buffer_edit_range){
else{ else{
Token_Array *ptr = scope_attachment(app, scope, attachment_tokens, Token_Array); Token_Array *ptr = scope_attachment(app, scope, attachment_tokens, Token_Array);
if (ptr != 0 && ptr->tokens != 0){ 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_first = token_relex_first(ptr, old_range.first, 1);
i64 token_index_resync_guess = i64 token_index_resync_guess =
token_relex_resync(ptr, old_range.one_past_last, 16); token_relex_resync(ptr, old_range.one_past_last, 16);
if (token_index_resync_guess - token_index_first >= 4000){
do_full_relex = true;
}
else{
Token *token_first = ptr->tokens + token_index_first; Token *token_first = ptr->tokens + token_index_first;
Token *token_resync = ptr->tokens + token_index_resync_guess; Token *token_resync = ptr->tokens + token_index_resync_guess;
Range_i64 relex_range = Range_i64 relex_range =
Ii64(token_first->pos, Ii64(token_first->pos,
token_resync->pos + token_resync->size + text_shift); token_resync->pos + token_resync->size + text_shift);
String_Const_u8 partial_text = push_buffer_range(app, scratch, buffer_id, String_Const_u8 partial_text = push_buffer_range(app, scratch,
buffer_id,
relex_range); relex_range);
Token_List relex_list = lex_full_input_cpp(scratch, partial_text); Token_List relex_list = lex_full_input_cpp(scratch, partial_text);
@ -830,12 +840,14 @@ BUFFER_EDIT_RANGE_SIG(default_buffer_edit_range){
token_drop_eof(&relex_list); 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, Token_Relex relex = token_relex(relex_list, relex_range.first - text_shift,
ptr->tokens, token_index_first, token_index_resync_guess); ptr->tokens, token_index_first, token_index_resync_guess);
profile_attempt_resync.close_now();
if (relex.successful_resync){ if (relex.successful_resync){
ProfileBlock(app, "apply resync");
i64 token_index_resync = relex.first_resync_index; i64 token_index_resync = relex.first_resync_index;
Interval_i64 head = Ii64(0, token_index_first); Interval_i64 head = Ii64(0, token_index_first);
@ -866,9 +878,15 @@ BUFFER_EDIT_RANGE_SIG(default_buffer_edit_range){
ptr->max = new_tokens_count; ptr->max = new_tokens_count;
} }
else{ else{
do_full_relex = true;
}
}
if (do_full_relex){
base_free(allocator, ptr->tokens); base_free(allocator, ptr->tokens);
block_zero_struct(ptr); 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)); make_data_struct(&buffer_id));
} }
} }

View File

@ -14,6 +14,7 @@ rewrite_lines_to_crlf(Application_Links *app, Buffer_ID buffer){
Batch_Edit *first = 0; Batch_Edit *first = 0;
Batch_Edit *last = 0; Batch_Edit *last = 0;
ProfileBlockNamed(app, "build batch edit", profile_batch);
i64 pos = -1; i64 pos = -1;
Character_Predicate pred_cr = character_predicate_from_character('\r'); Character_Predicate pred_cr = character_predicate_from_character('\r');
Character_Predicate pred_lf = character_predicate_from_character('\n'); 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); edit->edit.range = Ii64(pos);
} }
} }
profile_batch.close_now();
buffer_batch_edit(app, buffer, first); 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 *first = 0;
Batch_Edit *last = 0; Batch_Edit *last = 0;
ProfileBlockNamed(app, "build batch edit", profile_batch);
i64 pos = -1; i64 pos = -1;
Character_Predicate pred = character_predicate_from_character('\r'); Character_Predicate pred = character_predicate_from_character('\r');
for (;;){ for (;;){
@ -73,6 +76,7 @@ rewrite_lines_to_lf(Application_Links *app, Buffer_ID buffer){
edit->edit.text = string_u8_litexpr(""); edit->edit.text = string_u8_litexpr("");
edit->edit.range = match.range; edit->edit.range = match.range;
} }
profile_batch.close_now();
buffer_batch_edit(app, buffer, first); buffer_batch_edit(app, buffer, first);
} }

View File

@ -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); typedef void Buffer_Name_Resolver_Function(Application_Links *app, Buffer_Name_Conflict_Entry *conflicts, i32 conflict_count);
#define BUFFER_NAME_RESOLVER_SIG(n) \ #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); 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) #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, 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) \ #define BUFFER_EDIT_RANGE_SIG(name) \
i32 name(Application_Links *app, Buffer_ID buffer_id, \ 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); typedef Vec2_f32 Delta_Rule_Function(Vec2_f32 pending, b32 is_new_target, f32 dt, void *data);
#define DELTA_RULE_SIG(name) \ #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) void name(Application_Links *app, String_Const_u8 contents)
typedef void Render_Caller_Function(Application_Links *app, Frame_Info frame_info, View_ID view); 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; typedef i64 Command_Map_ID;

View File

@ -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(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(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(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_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, 93 }, { 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, 104 }, { 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, 115 }, { 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_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_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 }, { 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 },