Optimized batch edits remeasurement
parent
f2097ac6bc
commit
cd24295e8e
|
@ -68,6 +68,7 @@
|
|||
#include "4coder_app_links_allocator.cpp"
|
||||
#include "4coder_system_allocator.cpp"
|
||||
#include "4coder_profile.cpp"
|
||||
#include "4coder_profile_static_enable.cpp"
|
||||
#include "4coder_hash_functions.cpp"
|
||||
#include "4coder_table.cpp"
|
||||
#include "4coder_log.cpp"
|
||||
|
|
192
4ed_buffer.cpp
192
4ed_buffer.cpp
|
@ -424,6 +424,7 @@ buffer_eol_convert_out(Arena *arena, Gap_Buffer *buffer, Interval_i64 range){
|
|||
return(SCu8(memory, ptr));
|
||||
}
|
||||
|
||||
#if 0
|
||||
internal i64
|
||||
buffer_count_newlines(Arena *scratch, Gap_Buffer *buffer, i64 start, i64 end){
|
||||
Temp_Memory temp = begin_temp(scratch);
|
||||
|
@ -447,6 +448,7 @@ buffer_count_newlines(Arena *scratch, Gap_Buffer *buffer, i64 start, i64 end){
|
|||
|
||||
return(count);
|
||||
}
|
||||
#endif
|
||||
|
||||
internal void
|
||||
buffer_starts__ensure_max_size(Gap_Buffer *buffer, i64 max_size){
|
||||
|
@ -491,15 +493,172 @@ buffer_measure_starts(Arena *scratch, Gap_Buffer *buffer){
|
|||
end_temp(temp);
|
||||
}
|
||||
|
||||
internal i64
|
||||
buffer_get_line_index(Gap_Buffer *buffer, i64 pos){
|
||||
i64 i = 0;
|
||||
if (buffer->line_start_count > 2){
|
||||
i64 start = 0;
|
||||
i64 one_past_last = buffer->line_start_count - 1;
|
||||
i64 *array = buffer->line_starts;
|
||||
pos = clamp_bot(0, pos);
|
||||
for (;;){
|
||||
i = (start + one_past_last) >> 1;
|
||||
if (array[i] < pos){
|
||||
start = i;
|
||||
}
|
||||
else if (array[i] > pos){
|
||||
one_past_last = i;
|
||||
}
|
||||
else{
|
||||
break;
|
||||
}
|
||||
if (start + 1 >= one_past_last){
|
||||
i = start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(i);
|
||||
}
|
||||
|
||||
Line_Move*
|
||||
push_line_move(Arena *arena, Line_Move *moves, i64 new_line_first,
|
||||
i64 old_line_first, i64 old_line_opl, i64 text_shift){
|
||||
Line_Move *move = push_array(arena, Line_Move, 1);
|
||||
move->next = moves;
|
||||
move->kind = LineMove_ShiftOldValues;
|
||||
move->new_line_first = new_line_first;
|
||||
move->old_line_first = old_line_first;
|
||||
move->old_line_opl = old_line_opl;
|
||||
move->text_shift = text_shift;
|
||||
return(move);
|
||||
}
|
||||
|
||||
Line_Move*
|
||||
push_line_move(Arena *arena, Line_Move *moves, i64 new_line_first,
|
||||
String_Const_u8 string, i64 text_base){
|
||||
Line_Move *move = push_array(arena, Line_Move, 1);
|
||||
move->next = moves;
|
||||
move->kind = LineMove_MeasureString;
|
||||
move->new_line_first = new_line_first;
|
||||
move->string = string;
|
||||
move->text_base = text_base;
|
||||
return(move);
|
||||
}
|
||||
|
||||
function i64
|
||||
count_lines(String_Const_u8 string){
|
||||
i64 result = 0;
|
||||
for (umem i = 0; i < string.size; i += 1){
|
||||
if (string.str[i] == '\n'){
|
||||
result += 1;
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
function void
|
||||
fill_line_starts(i64 *lines_starts, String_Const_u8 string, i64 text_base){
|
||||
i64 *ptr = lines_starts;
|
||||
for (umem i = 0; i < string.size; i += 1){
|
||||
if (string.str[i] == '\n'){
|
||||
*ptr = text_base + i + 1;
|
||||
ptr += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function void
|
||||
buffer_remeasure_starts(Thread_Context *tctx, Gap_Buffer *buffer, Batch_Edit *batch){
|
||||
Scratch_Block scratch(tctx);
|
||||
|
||||
i64 line_start_count = buffer_line_count(buffer) + 1;
|
||||
|
||||
Line_Move *moves = 0;
|
||||
i64 current_line = 0;
|
||||
i64 text_shift = 0;
|
||||
i64 line_shift = 0;
|
||||
for (Batch_Edit *node = batch;
|
||||
node != 0;
|
||||
node = node->next){
|
||||
i64 first_line = buffer_get_line_index(buffer, node->edit.range.first);
|
||||
i64 opl_line = buffer_get_line_index(buffer, node->edit.range.one_past_last);
|
||||
i64 new_line_count = count_lines(node->edit.text);
|
||||
i64 deleted_line_count = opl_line - first_line;
|
||||
|
||||
Assert(first_line <= opl_line);
|
||||
Assert(opl_line <= line_start_count);
|
||||
|
||||
if (current_line <= first_line &&
|
||||
(text_shift != 0 || line_shift != 0)){
|
||||
moves = push_line_move(scratch, moves, current_line + line_shift,
|
||||
current_line, first_line + 1, text_shift);
|
||||
}
|
||||
|
||||
if (new_line_count != 0){
|
||||
moves = push_line_move(scratch, moves, first_line + 1 + line_shift,
|
||||
node->edit.text, node->edit.range.first + text_shift);
|
||||
}
|
||||
|
||||
text_shift += node->edit.text.size - range_size(node->edit.range);
|
||||
line_shift += new_line_count - deleted_line_count;
|
||||
current_line = opl_line + 1;
|
||||
}
|
||||
|
||||
moves = push_line_move(scratch, moves, current_line + line_shift,
|
||||
current_line, line_start_count, text_shift);
|
||||
line_start_count = line_start_count + line_shift;
|
||||
|
||||
buffer_starts__ensure_max_size(buffer, line_start_count + 1);
|
||||
buffer->line_start_count = line_start_count;
|
||||
|
||||
i64 *array = buffer->line_starts;
|
||||
|
||||
for (Line_Move *node = moves;
|
||||
node != 0;
|
||||
node = node->next){
|
||||
if (node->kind == LineMove_ShiftOldValues){
|
||||
i64 line_index_shift = node->new_line_first - node->old_line_first;
|
||||
i64 move_text_shift = node->text_shift;
|
||||
if (line_index_shift > 0){
|
||||
for (i64 i = node->old_line_opl - 1;
|
||||
i >= node->old_line_first;
|
||||
i -= 1){
|
||||
array[i + line_index_shift] = array[i] + move_text_shift;
|
||||
}
|
||||
}
|
||||
else{
|
||||
for (i64 i = node->old_line_first;
|
||||
i < node->old_line_opl;
|
||||
i += 1){
|
||||
array[i + line_index_shift] = array[i] + move_text_shift;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Line_Move *node = moves;
|
||||
node != 0;
|
||||
node = node->next){
|
||||
if (node->kind == LineMove_MeasureString){
|
||||
fill_line_starts(array + node->new_line_first, node->string, node->text_base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
internal void
|
||||
buffer_remeasure_starts(Arena *scratch, Gap_Buffer *buffer, Interval_i64 old_line_indexes, i64 line_shift, i64 text_shift){
|
||||
buffer_remeasure_starts(Arena *scratch, Gap_Buffer *buffer,
|
||||
Range_i64 old_line_indexes, i64 line_shift, i64 text_shift){
|
||||
Temp_Memory temp = begin_temp(scratch);
|
||||
buffer_starts__ensure_max_size(buffer, buffer->line_start_count + line_shift);
|
||||
|
||||
i64 new_line_indexes_opl = old_line_indexes.one_past_last + line_shift;
|
||||
i64 old_line_start_count = buffer->line_start_count;
|
||||
i64 *line_start_ptr = buffer->line_starts + old_line_indexes.one_past_last;
|
||||
for (i64 i = old_line_indexes.one_past_last; i < old_line_start_count; i += 1, line_start_ptr += 1){
|
||||
for (i64 i = old_line_indexes.one_past_last;
|
||||
i < old_line_start_count;
|
||||
i += 1, line_start_ptr += 1){
|
||||
*line_start_ptr += text_shift;
|
||||
}
|
||||
block_copy_dynamic_array(buffer->line_starts + new_line_indexes_opl,
|
||||
|
@ -532,34 +691,7 @@ buffer_remeasure_starts(Arena *scratch, Gap_Buffer *buffer, Interval_i64 old_lin
|
|||
buffer->line_start_count += line_shift;
|
||||
end_temp(temp);
|
||||
}
|
||||
|
||||
internal i64
|
||||
buffer_get_line_index(Gap_Buffer *buffer, i64 pos){
|
||||
i64 i = 0;
|
||||
if (buffer->line_start_count > 2){
|
||||
i64 start = 0;
|
||||
i64 one_past_last = buffer->line_start_count - 1;
|
||||
i64 *array = buffer->line_starts;
|
||||
pos = clamp_bot(0, pos);
|
||||
for (;;){
|
||||
i = (start + one_past_last) >> 1;
|
||||
if (array[i] < pos){
|
||||
start = i;
|
||||
}
|
||||
else if (array[i] > pos){
|
||||
one_past_last = i;
|
||||
}
|
||||
else{
|
||||
break;
|
||||
}
|
||||
if (start + 1 >= one_past_last){
|
||||
i = start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(i);
|
||||
}
|
||||
#endif
|
||||
|
||||
internal Interval_i64
|
||||
buffer_get_pos_range_from_line_number(Gap_Buffer *buffer, i64 line_number){
|
||||
|
|
22
4ed_buffer.h
22
4ed_buffer.h
|
@ -41,6 +41,28 @@ struct Buffer_Chunk_Position{
|
|||
i64 chunk_index;
|
||||
};
|
||||
|
||||
typedef i32 Line_Move_Kind;
|
||||
enum{
|
||||
LineMove_ShiftOldValues,
|
||||
LineMove_MeasureString,
|
||||
};
|
||||
struct Line_Move{
|
||||
Line_Move *next;
|
||||
Line_Move_Kind kind;
|
||||
i64 new_line_first;
|
||||
union{
|
||||
struct{
|
||||
i64 old_line_first;
|
||||
i64 old_line_opl;
|
||||
i64 text_shift;
|
||||
};
|
||||
struct{
|
||||
String_Const_u8 string;
|
||||
i64 text_base;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
typedef u32 Buffer_Layout_Flag;
|
||||
enum{
|
||||
BRFlag_Special_Character = (1 << 0),
|
||||
|
|
44
4ed_edit.cpp
44
4ed_edit.cpp
|
@ -225,33 +225,20 @@ edit__apply(Thread_Context *tctx, Models *models, Editing_File *file,
|
|||
Assert(edit.range.first <= edit.range.one_past_last);
|
||||
Assert(edit.range.one_past_last <= buffer_size(buffer));
|
||||
|
||||
Scratch_Block scratch(tctx, Scratch_Share);
|
||||
|
||||
// NOTE(allen): history update
|
||||
if (!behaviors.do_not_post_to_history){
|
||||
ProfileTLBlock(tctx, &models->profile_list, "edit apply 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): compute shift
|
||||
i64 shift_amount = replace_range_shift(edit.range, (i64)edit.text.size);
|
||||
|
||||
// NOTE(allen): actual text replacement
|
||||
buffer_replace_range(buffer, edit.range, edit.text, shift_amount);
|
||||
|
||||
// NOTE(allen): line meta data
|
||||
i64 line_start = buffer_get_line_index(buffer, edit.range.first);
|
||||
i64 line_end = buffer_get_line_index(buffer, edit.range.one_past_last);
|
||||
i64 replaced_line_count = line_end - line_start;
|
||||
i64 new_line_count = buffer_count_newlines(scratch, buffer, edit.range.first,
|
||||
edit.range.first + edit.text.size);
|
||||
i64 line_shift = new_line_count - replaced_line_count;
|
||||
|
||||
file_clear_layout_cache(file);
|
||||
buffer_remeasure_starts(scratch, buffer, Ii64(line_start, line_end + 1),
|
||||
line_shift, shift_amount);
|
||||
{
|
||||
ProfileTLBlock(tctx, &models->profile_list, "edit apply replace range");
|
||||
i64 shift_amount = replace_range_shift(edit.range, (i64)edit.text.size);
|
||||
buffer_replace_range(buffer, edit.range, edit.text, shift_amount);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
|
@ -262,11 +249,14 @@ edit_single(Thread_Context *tctx, Models *models, Editing_File *file,
|
|||
|
||||
edit__apply(tctx, models, file, range, string, behaviors);
|
||||
|
||||
file_clear_layout_cache(file);
|
||||
|
||||
Batch_Edit batch = {};
|
||||
batch.edit.text = string;
|
||||
batch.edit.range = range;
|
||||
edit_fix_markers(tctx, models, file, &batch);
|
||||
|
||||
buffer_remeasure_starts(tctx, &file->state.buffer, &batch);
|
||||
edit_fix_markers(tctx, models, file, &batch);
|
||||
post_edit_call_hook(tctx, models, file,
|
||||
Ii64_size(range.first, string.size), range_size(range));
|
||||
}
|
||||
|
@ -413,8 +403,6 @@ edit_merge_history_range(Thread_Context *tctx, Models *models, Editing_File *fil
|
|||
return(result);
|
||||
}
|
||||
|
||||
#include "4coder_profile_static_enable.cpp"
|
||||
|
||||
function b32
|
||||
edit_batch_check(Thread_Context *tctx, Profile_Global_List *list, Batch_Edit *batch){
|
||||
ProfileTLScope(tctx, list, "batch check");
|
||||
|
@ -453,7 +441,10 @@ edit_batch(Thread_Context *tctx, Models *models, Editing_File *file,
|
|||
Range_i64 old_range = Ii64_neg_inf;
|
||||
Range_i64 new_range = Ii64_neg_inf;
|
||||
|
||||
ProfileTLBlockNamed(tctx, &models->profile_list, "batch text edits", profile_edits);
|
||||
Gap_Buffer *buffer = &file->state.buffer;
|
||||
|
||||
ProfileTLBlockNamed(tctx, &models->profile_list, "batch text edits",
|
||||
profile_edits);
|
||||
i32 batch_count = 0;
|
||||
i64 shift = 0;
|
||||
for (Batch_Edit *edit = batch;
|
||||
|
@ -472,7 +463,7 @@ edit_batch(Thread_Context *tctx, Models *models, Editing_File *file,
|
|||
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(buffer);
|
||||
if (0 <= edit_range.first &&
|
||||
edit_range.first <= edit_range.one_past_last &&
|
||||
edit_range.one_past_last <= size){
|
||||
|
@ -497,6 +488,9 @@ edit_batch(Thread_Context *tctx, Models *models, Editing_File *file,
|
|||
}
|
||||
}
|
||||
|
||||
file_clear_layout_cache(file);
|
||||
|
||||
buffer_remeasure_starts(tctx, buffer, batch);
|
||||
edit_fix_markers(tctx, models, file, batch);
|
||||
|
||||
post_edit_call_hook(tctx, models, file, new_range, range_size(old_range));
|
||||
|
@ -506,8 +500,6 @@ edit_batch(Thread_Context *tctx, Models *models, Editing_File *file,
|
|||
return(result);
|
||||
}
|
||||
|
||||
#include "4coder_profile_static_disable.cpp"
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal Editing_File*
|
||||
|
|
|
@ -637,9 +637,19 @@ run_lister(Application_Links *app, Lister *lister){
|
|||
if (!handled){
|
||||
Mapping *mapping = lister->mapping;
|
||||
Command_Map *map = lister->map;
|
||||
if (ui_fallback_command_dispatch(app, view, mapping, map, &in)){
|
||||
|
||||
Fallback_Dispatch_Result disp_result =
|
||||
fallback_command_dispatch(app, mapping, map, &in);
|
||||
if (disp_result.code == FallbackDispatch_DelayedUICall){
|
||||
call_after_ctx_shutdown(app, view, disp_result.func);
|
||||
break;
|
||||
}
|
||||
if (disp_result.code == FallbackDispatch_Unhandled){
|
||||
leave_current_input_unhandled(app);
|
||||
}
|
||||
else{
|
||||
lister_call_refresh_handler(app, lister);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -469,6 +469,9 @@ profile_draw_node(Application_Links *app, View_ID view, Face_ID face_id,
|
|||
draw_rectangle_outline(app, box, 6.f, 3.f, margin);
|
||||
|
||||
y_pos = y.max;
|
||||
if (y_pos >= info_box.y1){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -445,7 +445,7 @@ static Command_Metadata fcoder_metacmd_table[213] = {
|
|||
{ PROC_LINKS(miblo_decrement_time_stamp, 0), false, "miblo_decrement_time_stamp", 26, "Decrement a time stamp under the cursor by one second. (format [m]m:ss or h:mm:ss", 81, "w:\\4ed\\code\\custom\\4coder_miblo_numbers.cpp", 43, 237 },
|
||||
{ PROC_LINKS(miblo_increment_time_stamp_minute, 0), false, "miblo_increment_time_stamp_minute", 33, "Increment a time stamp under the cursor by one minute. (format [m]m:ss or h:mm:ss", 81, "w:\\4ed\\code\\custom\\4coder_miblo_numbers.cpp", 43, 243 },
|
||||
{ PROC_LINKS(miblo_decrement_time_stamp_minute, 0), false, "miblo_decrement_time_stamp_minute", 33, "Decrement a time stamp under the cursor by one minute. (format [m]m:ss or h:mm:ss", 81, "w:\\4ed\\code\\custom\\4coder_miblo_numbers.cpp", 43, 249 },
|
||||
{ PROC_LINKS(profile_inspect, 0), true, "profile_inspect", 15, "Inspect all currently collected profiling information in 4coder's self profiler.", 80, "w:\\4ed\\code\\custom\\4coder_profile_inspect.cpp", 45, 776 },
|
||||
{ PROC_LINKS(profile_inspect, 0), true, "profile_inspect", 15, "Inspect all currently collected profiling information in 4coder's self profiler.", 80, "w:\\4ed\\code\\custom\\4coder_profile_inspect.cpp", 45, 779 },
|
||||
{ PROC_LINKS(default_startup, 0), false, "default_startup", 15, "Default command for responding to a startup event", 49, "w:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 7 },
|
||||
{ PROC_LINKS(default_try_exit, 0), false, "default_try_exit", 16, "Default command for responding to a try-exit event", 50, "w:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 22 },
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue