Some batch edit optimizations; next need to support batch cursor fixing
This commit is contained in:
parent
14b71b8172
commit
529ef3928e
116
4ed_edit.cpp
116
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,17 +812,27 @@ 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);
|
||||
|
||||
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,
|
||||
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);
|
||||
|
@ -830,12 +840,14 @@ BUFFER_EDIT_RANGE_SIG(default_buffer_edit_range){
|
|||
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);
|
||||
|
||||
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);
|
||||
|
@ -866,9 +878,15 @@ BUFFER_EDIT_RANGE_SIG(default_buffer_edit_range){
|
|||
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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,6 +76,7 @@ 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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 },
|
||||
|
|
Loading…
Reference in New Issue