diff --git a/4coder_API/4coder_types.h b/4coder_API/4coder_types.h index 71a67217..bd8042f3 100644 --- a/4coder_API/4coder_types.h +++ b/4coder_API/4coder_types.h @@ -561,18 +561,6 @@ STRUCT Partial_Cursor{ int32_t character; }; -/* DOC(Buffer_Edit describes a range of a buffer and string to replace that range. A Buffer_Edit has to be paired with a string that contains the actual text that will be replaced into the buffer.) */ -STRUCT Buffer_Edit{ - /* DOC(The str_start field specifies the first character in the accompanying string that corresponds with this edit.) */ - int32_t str_start; - /* DOC(The len field specifies the length of the string being written into the buffer.) */ - int32_t len; - /* DOC(The start field specifies the start of the range in the buffer to replace in absolute position.) */ - int32_t start; - /* DOC(The end field specifies one past the end of the range in the buffer to replace in absolute position.) */ - int32_t end; -}; - /* DOC(Buffer_Summary acts as a handle to a buffer and describes the state of the buffer.) DOC_SEE(Access_Flag) DOC_SEE(Dirty_State) */ @@ -981,8 +969,22 @@ ENUM(int32_t, Buffer_Batch_Edit_Type){ BatchEdit_PreserveTokens }; +/* DOC(Buffer_Edit describes a range of a buffer and string to replace that range. A Buffer_Edit has to be paired with a string that contains the actual +text that will be replaced into the buffer.) */ +STRUCT Buffer_Edit{ + /* DOC(The str_start field specifies the first character in the accompanying string that corresponds with this edit.) */ + int32_t str_start; + /* DOC(The len field specifies the length of the string being written into the buffer.) */ + int32_t len; + /* DOC(The start field specifies the start of the range in the buffer to replace in absolute position.) */ + int32_t start; + /* DOC(The end field specifies one past the end of the range in the buffer to replace in absolute position.) */ + int32_t end; +}; + /* DOC(This struct is used to bundle the parameters of the buffer_batch_edit function. It is convenient for a few functions that return a batch edit to the user.) +DOC_SEE(Buffer_Edit) DOC_SEE(buffer_batch_edit) */ STRUCT Buffer_Batch_Edit{ @@ -997,6 +999,17 @@ STRUCT Buffer_Batch_Edit{ int32_t edit_count; }; +ENUM(int32_t, Record_Kind){ + RecordKind_Single, + RecordKind_Batch, + RecordKind_Group, +}; + +TYPEDEF int32_t History_Record_Index; + +STRUCT Record_Data{ + +}; /* DOC(Custom_Command_Function is a function type which matches the signature used for commands. To declare a command use CUSTOM_COMMAND_SIG.) DOC_SEE(CUSTOM_COMMAND_SIG) */ TYPEDEF void Custom_Command_Function(struct Application_Links *app); diff --git a/4coder_base_commands.cpp b/4coder_base_commands.cpp index e2cc6b1b..113cd8c3 100644 --- a/4coder_base_commands.cpp +++ b/4coder_base_commands.cpp @@ -1582,23 +1582,26 @@ CUSTOM_DOC("Reopen the current buffer from the hard drive.") CUSTOM_COMMAND_SIG(undo) CUSTOM_DOC("Advances backwards through the undo history.") { - // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): - // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): - // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): - // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): - // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): - // re-implement undo + View_Summary view = get_active_view(app, AccessOpen); + Buffer_Summary buffer = get_buffer(app, view.buffer_id, AccessOpen); + History_Record_Index current = buffer_history_get_current_state_index(app, &buffer); + if (current > 0){ + current -= 1; + buffer_history_set_current_state_index(app, &buffer, current); + } } CUSTOM_COMMAND_SIG(redo) -CUSTOM_DOC("Advances forewards through the undo history.") +CUSTOM_DOC("Advances forwards through the undo history.") { - // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): - // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): - // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): - // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): - // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): // TODO(allen): - // re-implement redo + View_Summary view = get_active_view(app, AccessOpen); + Buffer_Summary buffer = get_buffer(app, view.buffer_id, AccessOpen); + History_Record_Index current = buffer_history_get_current_state_index(app, &buffer); + History_Record_Index max_index = buffer_history_newest_record_index(app, &buffer); + if (current < max_index){ + current += 1; + buffer_history_set_current_state_index(app, &buffer, current); + } } //////////////////////////////// diff --git a/4coder_generated/app_functions.h b/4coder_generated/app_functions.h index 22dbb815..38e5472c 100644 --- a/4coder_generated/app_functions.h +++ b/4coder_generated/app_functions.h @@ -95,6 +95,16 @@ struct Application_Links; #define GET_LARGEST_FACE_ID_SIG(n) Face_ID n(Application_Links *app) #define SET_GLOBAL_FACE_SIG(n) bool32 n(Application_Links *app, Face_ID id, bool32 apply_to_all_buffers) #define BUFFER_SET_FACE_SIG(n) bool32 n(Application_Links *app, Buffer_Summary *buffer, Face_ID id) +#define BUFFER_HISTORY_NEWEST_RECORD_INDEX_SIG(n) History_Record_Index n(Application_Links *app, Buffer_Summary *buffer) +#define BUFFER_HISTORY_GET_RECORD_SIG(n) Record_Data n(Application_Links *app, Buffer_Summary *buffer, History_Record_Index record) +#define BUFFER_HISTORY_GET_CURRENT_STATE_INDEX_SIG(n) History_Record_Index n(Application_Links *app, Buffer_Summary *buffer) +#define BUFFER_HISTORY_SET_CURRENT_STATE_INDEX_SIG(n) bool32 n(Application_Links *app, Buffer_Summary *buffer, History_Record_Index index) +#define BUFFER_HISTORY_MERGE_RECORDS_BETWEEN_STATES_SIG(n) bool32 n(Application_Links *app, Buffer_Summary *buffer, History_Record_Index first_index, History_Record_Index last_index) +#define BUFFER_HISTORY_SPLIT_GROUP_RECORD_SIG(n) bool32 n(Application_Links *app, Buffer_Summary *buffer, History_Record_Index record_index, int32_t sub_record_index) +#define BUFFER_HISTORY_SPLIT_SINGLE_RECORD_SIG(n) bool32 n(Application_Links *app, Buffer_Summary *buffer, History_Record_Index record_index, int32_t forward_str_split, int32_t backward_str_split) +#define BUFFER_HISTORY_CLEAR_AFTER_UNDO_POSITION_SIG(n) bool32 n(Application_Links *app, Buffer_Summary *buffer) +#define GLOBAL_HISTORY_EDIT_GROUP_BEGIN_SIG(n) void n(Application_Links *app) +#define GLOBAL_HISTORY_EDIT_GROUP_END_SIG(n) void n(Application_Links *app) #define GET_FACE_DESCRIPTION_SIG(n) Face_Description n(Application_Links *app, Face_ID id) #define GET_FACE_ID_SIG(n) Face_ID n(Application_Links *app, Buffer_Summary *buffer) #define TRY_CREATE_NEW_FACE_SIG(n) Face_ID n(Application_Links *app, Face_Description *description) @@ -222,6 +232,16 @@ typedef CHANGE_THEME_BY_INDEX_SIG(Change_Theme_By_Index_Function); typedef GET_LARGEST_FACE_ID_SIG(Get_Largest_Face_ID_Function); typedef SET_GLOBAL_FACE_SIG(Set_Global_Face_Function); typedef BUFFER_SET_FACE_SIG(Buffer_Set_Face_Function); +typedef BUFFER_HISTORY_NEWEST_RECORD_INDEX_SIG(Buffer_History_Newest_Record_Index_Function); +typedef BUFFER_HISTORY_GET_RECORD_SIG(Buffer_History_Get_Record_Function); +typedef BUFFER_HISTORY_GET_CURRENT_STATE_INDEX_SIG(Buffer_History_Get_Current_State_Index_Function); +typedef BUFFER_HISTORY_SET_CURRENT_STATE_INDEX_SIG(Buffer_History_Set_Current_State_Index_Function); +typedef BUFFER_HISTORY_MERGE_RECORDS_BETWEEN_STATES_SIG(Buffer_History_Merge_Records_Between_States_Function); +typedef BUFFER_HISTORY_SPLIT_GROUP_RECORD_SIG(Buffer_History_Split_Group_Record_Function); +typedef BUFFER_HISTORY_SPLIT_SINGLE_RECORD_SIG(Buffer_History_Split_Single_Record_Function); +typedef BUFFER_HISTORY_CLEAR_AFTER_UNDO_POSITION_SIG(Buffer_History_Clear_After_Undo_Position_Function); +typedef GLOBAL_HISTORY_EDIT_GROUP_BEGIN_SIG(Global_History_Edit_Group_Begin_Function); +typedef GLOBAL_HISTORY_EDIT_GROUP_END_SIG(Global_History_Edit_Group_End_Function); typedef GET_FACE_DESCRIPTION_SIG(Get_Face_Description_Function); typedef GET_FACE_ID_SIG(Get_Face_ID_Function); typedef TRY_CREATE_NEW_FACE_SIG(Try_Create_New_Face_Function); @@ -351,6 +371,16 @@ Change_Theme_By_Index_Function *change_theme_by_index; Get_Largest_Face_ID_Function *get_largest_face_id; Set_Global_Face_Function *set_global_face; Buffer_Set_Face_Function *buffer_set_face; +Buffer_History_Newest_Record_Index_Function *buffer_history_newest_record_index; +Buffer_History_Get_Record_Function *buffer_history_get_record; +Buffer_History_Get_Current_State_Index_Function *buffer_history_get_current_state_index; +Buffer_History_Set_Current_State_Index_Function *buffer_history_set_current_state_index; +Buffer_History_Merge_Records_Between_States_Function *buffer_history_merge_records_between_states; +Buffer_History_Split_Group_Record_Function *buffer_history_split_group_record; +Buffer_History_Split_Single_Record_Function *buffer_history_split_single_record; +Buffer_History_Clear_After_Undo_Position_Function *buffer_history_clear_after_undo_position; +Global_History_Edit_Group_Begin_Function *global_history_edit_group_begin; +Global_History_Edit_Group_End_Function *global_history_edit_group_end; Get_Face_Description_Function *get_face_description; Get_Face_ID_Function *get_face_id; Try_Create_New_Face_Function *try_create_new_face; @@ -479,6 +509,16 @@ Change_Theme_By_Index_Function *change_theme_by_index_; Get_Largest_Face_ID_Function *get_largest_face_id_; Set_Global_Face_Function *set_global_face_; Buffer_Set_Face_Function *buffer_set_face_; +Buffer_History_Newest_Record_Index_Function *buffer_history_newest_record_index_; +Buffer_History_Get_Record_Function *buffer_history_get_record_; +Buffer_History_Get_Current_State_Index_Function *buffer_history_get_current_state_index_; +Buffer_History_Set_Current_State_Index_Function *buffer_history_set_current_state_index_; +Buffer_History_Merge_Records_Between_States_Function *buffer_history_merge_records_between_states_; +Buffer_History_Split_Group_Record_Function *buffer_history_split_group_record_; +Buffer_History_Split_Single_Record_Function *buffer_history_split_single_record_; +Buffer_History_Clear_After_Undo_Position_Function *buffer_history_clear_after_undo_position_; +Global_History_Edit_Group_Begin_Function *global_history_edit_group_begin_; +Global_History_Edit_Group_End_Function *global_history_edit_group_end_; Get_Face_Description_Function *get_face_description_; Get_Face_ID_Function *get_face_id_; Try_Create_New_Face_Function *try_create_new_face_; @@ -615,6 +655,16 @@ app_links->change_theme_by_index_ = Change_Theme_By_Index;\ app_links->get_largest_face_id_ = Get_Largest_Face_ID;\ app_links->set_global_face_ = Set_Global_Face;\ app_links->buffer_set_face_ = Buffer_Set_Face;\ +app_links->buffer_history_newest_record_index_ = Buffer_History_Newest_Record_Index;\ +app_links->buffer_history_get_record_ = Buffer_History_Get_Record;\ +app_links->buffer_history_get_current_state_index_ = Buffer_History_Get_Current_State_Index;\ +app_links->buffer_history_set_current_state_index_ = Buffer_History_Set_Current_State_Index;\ +app_links->buffer_history_merge_records_between_states_ = Buffer_History_Merge_Records_Between_States;\ +app_links->buffer_history_split_group_record_ = Buffer_History_Split_Group_Record;\ +app_links->buffer_history_split_single_record_ = Buffer_History_Split_Single_Record;\ +app_links->buffer_history_clear_after_undo_position_ = Buffer_History_Clear_After_Undo_Position;\ +app_links->global_history_edit_group_begin_ = Global_History_Edit_Group_Begin;\ +app_links->global_history_edit_group_end_ = Global_History_Edit_Group_End;\ app_links->get_face_description_ = Get_Face_Description;\ app_links->get_face_id_ = Get_Face_ID;\ app_links->try_create_new_face_ = Try_Create_New_Face;\ @@ -743,6 +793,16 @@ static bool32 change_theme_by_index(Application_Links *app, int32_t index){retur static Face_ID get_largest_face_id(Application_Links *app){return(app->get_largest_face_id(app));} static bool32 set_global_face(Application_Links *app, Face_ID id, bool32 apply_to_all_buffers){return(app->set_global_face(app, id, apply_to_all_buffers));} static bool32 buffer_set_face(Application_Links *app, Buffer_Summary *buffer, Face_ID id){return(app->buffer_set_face(app, buffer, id));} +static History_Record_Index buffer_history_newest_record_index(Application_Links *app, Buffer_Summary *buffer){return(app->buffer_history_newest_record_index(app, buffer));} +static Record_Data buffer_history_get_record(Application_Links *app, Buffer_Summary *buffer, History_Record_Index record){return(app->buffer_history_get_record(app, buffer, record));} +static History_Record_Index buffer_history_get_current_state_index(Application_Links *app, Buffer_Summary *buffer){return(app->buffer_history_get_current_state_index(app, buffer));} +static bool32 buffer_history_set_current_state_index(Application_Links *app, Buffer_Summary *buffer, History_Record_Index index){return(app->buffer_history_set_current_state_index(app, buffer, index));} +static bool32 buffer_history_merge_records_between_states(Application_Links *app, Buffer_Summary *buffer, History_Record_Index first_index, History_Record_Index last_index){return(app->buffer_history_merge_records_between_states(app, buffer, first_index, last_index));} +static bool32 buffer_history_split_group_record(Application_Links *app, Buffer_Summary *buffer, History_Record_Index record_index, int32_t sub_record_index){return(app->buffer_history_split_group_record(app, buffer, record_index, sub_record_index));} +static bool32 buffer_history_split_single_record(Application_Links *app, Buffer_Summary *buffer, History_Record_Index record_index, int32_t forward_str_split, int32_t backward_str_split){return(app->buffer_history_split_single_record(app, buffer, record_index, forward_str_split, backward_str_split));} +static bool32 buffer_history_clear_after_undo_position(Application_Links *app, Buffer_Summary *buffer){return(app->buffer_history_clear_after_undo_position(app, buffer));} +static void global_history_edit_group_begin(Application_Links *app){(app->global_history_edit_group_begin(app));} +static void global_history_edit_group_end(Application_Links *app){(app->global_history_edit_group_end(app));} static Face_Description get_face_description(Application_Links *app, Face_ID id){return(app->get_face_description(app, id));} static Face_ID get_face_id(Application_Links *app, Buffer_Summary *buffer){return(app->get_face_id(app, buffer));} static Face_ID try_create_new_face(Application_Links *app, Face_Description *description){return(app->try_create_new_face(app, description));} @@ -871,6 +931,16 @@ static bool32 change_theme_by_index(Application_Links *app, int32_t index){retur static Face_ID get_largest_face_id(Application_Links *app){return(app->get_largest_face_id_(app));} static bool32 set_global_face(Application_Links *app, Face_ID id, bool32 apply_to_all_buffers){return(app->set_global_face_(app, id, apply_to_all_buffers));} static bool32 buffer_set_face(Application_Links *app, Buffer_Summary *buffer, Face_ID id){return(app->buffer_set_face_(app, buffer, id));} +static History_Record_Index buffer_history_newest_record_index(Application_Links *app, Buffer_Summary *buffer){return(app->buffer_history_newest_record_index_(app, buffer));} +static Record_Data buffer_history_get_record(Application_Links *app, Buffer_Summary *buffer, History_Record_Index record){return(app->buffer_history_get_record_(app, buffer, record));} +static History_Record_Index buffer_history_get_current_state_index(Application_Links *app, Buffer_Summary *buffer){return(app->buffer_history_get_current_state_index_(app, buffer));} +static bool32 buffer_history_set_current_state_index(Application_Links *app, Buffer_Summary *buffer, History_Record_Index index){return(app->buffer_history_set_current_state_index_(app, buffer, index));} +static bool32 buffer_history_merge_records_between_states(Application_Links *app, Buffer_Summary *buffer, History_Record_Index first_index, History_Record_Index last_index){return(app->buffer_history_merge_records_between_states_(app, buffer, first_index, last_index));} +static bool32 buffer_history_split_group_record(Application_Links *app, Buffer_Summary *buffer, History_Record_Index record_index, int32_t sub_record_index){return(app->buffer_history_split_group_record_(app, buffer, record_index, sub_record_index));} +static bool32 buffer_history_split_single_record(Application_Links *app, Buffer_Summary *buffer, History_Record_Index record_index, int32_t forward_str_split, int32_t backward_str_split){return(app->buffer_history_split_single_record_(app, buffer, record_index, forward_str_split, backward_str_split));} +static bool32 buffer_history_clear_after_undo_position(Application_Links *app, Buffer_Summary *buffer){return(app->buffer_history_clear_after_undo_position_(app, buffer));} +static void global_history_edit_group_begin(Application_Links *app){(app->global_history_edit_group_begin_(app));} +static void global_history_edit_group_end(Application_Links *app){(app->global_history_edit_group_end_(app));} static Face_Description get_face_description(Application_Links *app, Face_ID id){return(app->get_face_description_(app, id));} static Face_ID get_face_id(Application_Links *app, Buffer_Summary *buffer){return(app->get_face_id_(app, buffer));} static Face_ID try_create_new_face(Application_Links *app, Face_Description *description){return(app->try_create_new_face_(app, description));} diff --git a/4coder_generated/command_metadata.h b/4coder_generated/command_metadata.h index bdadbebe..7c3ba84d 100644 --- a/4coder_generated/command_metadata.h +++ b/4coder_generated/command_metadata.h @@ -364,7 +364,7 @@ static Command_Metadata fcoder_metacmd_table[220] = { { PROC_LINKS(open_all_code_recursive, 0), "open_all_code_recursive", 23, "Works as open_all_code but also runs in all subdirectories.", 59, "w:\\4ed\\code\\4coder_project_commands.cpp", 39, 1074 }, { PROC_LINKS(open_color_tweaker, 0), "open_color_tweaker", 18, "Opens the 4coder theme selector list.", 37, "w:\\4ed\\code\\4coder_lists.cpp", 28, 938 }, { PROC_LINKS(open_file_in_quotes, 0), "open_file_in_quotes", 19, "Reads a filename from surrounding '\"' characters and attempts to open the corresponding file.", 94, "w:\\4ed\\code\\4coder_base_commands.cpp", 36, 1464 }, -{ PROC_LINKS(open_in_other, 0), "open_in_other", 13, "Interactively opens a file in the other panel.", 46, "w:\\4ed\\code\\4coder_base_commands.cpp", 36, 1629 }, +{ PROC_LINKS(open_in_other, 0), "open_in_other", 13, "Interactively opens a file in the other panel.", 46, "w:\\4ed\\code\\4coder_base_commands.cpp", 36, 1632 }, { PROC_LINKS(open_long_braces, 0), "open_long_braces", 16, "At the cursor, insert a '{' and '}' separated by a blank line.", 62, "w:\\4ed\\code\\4coder_combined_write_commands.cpp", 46, 55 }, { PROC_LINKS(open_long_braces_break, 0), "open_long_braces_break", 22, "At the cursor, insert a '{' and '}break;' separated by a blank line.", 68, "w:\\4ed\\code\\4coder_combined_write_commands.cpp", 46, 71 }, { PROC_LINKS(open_long_braces_semicolon, 0), "open_long_braces_semicolon", 26, "At the cursor, insert a '{' and '};' separated by a blank line.", 63, "w:\\4ed\\code\\4coder_combined_write_commands.cpp", 46, 63 }, @@ -384,8 +384,8 @@ static Command_Metadata fcoder_metacmd_table[220] = { { PROC_LINKS(query_replace, 0), "query_replace", 13, "Queries the user for two strings, and incrementally replaces every occurence of the first string with the second string.", 120, "w:\\4ed\\code\\4coder_base_commands.cpp", 36, 1019 }, { PROC_LINKS(query_replace_identifier, 0), "query_replace_identifier", 24, "Queries the user for a string, and incrementally replace every occurence of the word or token found at the cursor with the specified string.", 140, "w:\\4ed\\code\\4coder_base_commands.cpp", 36, 1043 }, { PROC_LINKS(query_replace_selection, 0), "query_replace_selection", 23, "Queries the user for a string, and incrementally replace every occurence of the string found in the selected range with the specified string.", 141, "w:\\4ed\\code\\4coder_base_commands.cpp", 36, 1061 }, -{ PROC_LINKS(redo, 0), "redo", 4, "Advances forewards through the undo history.", 44, "w:\\4ed\\code\\4coder_base_commands.cpp", 36, 1593 }, -{ PROC_LINKS(reload_themes, 0), "reload_themes", 13, "Loads all the theme files in the theme folder, replacing duplicates with the new theme data.", 92, "w:\\4ed\\code\\4coder_base_commands.cpp", 36, 1606 }, +{ PROC_LINKS(redo, 0), "redo", 4, "Advances forwards through the undo history.", 43, "w:\\4ed\\code\\4coder_base_commands.cpp", 36, 1594 }, +{ PROC_LINKS(reload_themes, 0), "reload_themes", 13, "Loads all the theme files in the theme folder, replacing duplicates with the new theme data.", 92, "w:\\4ed\\code\\4coder_base_commands.cpp", 36, 1609 }, { PROC_LINKS(remap_interactive, 0), "remap_interactive", 17, "Switch to a named key binding map.", 34, "w:\\4ed\\code\\4coder_default_framework.cpp", 40, 290 }, { PROC_LINKS(rename_file_query, 0), "rename_file_query", 17, "Queries the user for a new name and renames the file of the current buffer, altering the buffer's name too.", 107, "w:\\4ed\\code\\4coder_base_commands.cpp", 36, 1201 }, { PROC_LINKS(reopen, 0), "reopen", 6, "Reopen the current buffer from the hard drive.", 46, "w:\\4ed\\code\\4coder_base_commands.cpp", 36, 1572 }, diff --git a/4coder_lib/4coder_arena.cpp b/4coder_lib/4coder_arena.cpp index 0b94c02f..aea1b09c 100644 --- a/4coder_lib/4coder_arena.cpp +++ b/4coder_lib/4coder_arena.cpp @@ -236,6 +236,23 @@ end_temp_memory(Temp_Memory_Arena temp){ } } +static Temp_Memory_Arena_Light +temp_memory_light(Temp_Memory_Arena temp){ + Temp_Memory_Arena_Light light = {}; + light.part = temp.part; + light.pos = temp.pos; + return(light); +} + +static void +end_temp_memory(Arena *arena, Temp_Memory_Arena_Light temp){ + Temp_Memory_Arena full_temp = {}; + full_temp.arena = arena; + full_temp.part = temp.part; + full_temp.pos = temp.pos; + end_temp_memory(full_temp); +} + static void* push_allocator_allocate(Arena *arena, i32_4tech size){ return(arena_allocate(arena, size)); diff --git a/4coder_lib/4coder_arena.h b/4coder_lib/4coder_arena.h index 2d5e7994..36ba5791 100644 --- a/4coder_lib/4coder_arena.h +++ b/4coder_lib/4coder_arena.h @@ -75,6 +75,11 @@ struct Temp_Memory_Arena{ i32_4tech pos; }; +struct Temp_Memory_Arena_Light{ + Partition_Chained *part; + i32_4tech pos; +}; + #endif #endif diff --git a/4ed.cpp b/4ed.cpp index 34537231..260da0df 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -58,7 +58,14 @@ internal void output_file_append(System_Functions *system, Models *models, Editing_File *file, String value){ if (!file->is_dummy){ i32 end = buffer_size(&file->state.buffer); - edit_single(system, models, file, end, end, value.str, value.size); + Edit edit = {}; + edit.str = value.str; + edit.length = value.size; + edit.range.first = end; + edit.range.one_past_last = end; + + Edit_Behaviors behaviors = {}; + edit_single(system, models, file, edit, behaviors); } } @@ -834,6 +841,9 @@ App_Init_Sig(app_init){ models->working_set.default_display_width = DEFAULT_DISPLAY_WIDTH; models->working_set.default_minimum_base_display_width = DEFAULT_MINIMUM_BASE_DISPLAY_WIDTH; + // NOTE(allen): history setup + global_history_init(&models->global_history); + // NOTE(allen): clipboard setup models->working_set.clipboard_max_size = ArrayCount(models->working_set.clipboards); models->working_set.clipboard_size = 0; diff --git a/4ed_api_implementation.cpp b/4ed_api_implementation.cpp index 0fcdbd6c..15b17472 100644 --- a/4ed_api_implementation.cpp +++ b/4ed_api_implementation.cpp @@ -646,8 +646,14 @@ DOC_SEE(4coder_Buffer_Positioning_System) if (file != 0){ size = buffer_size(&file->state.buffer); if (0 <= start && start <= end && end <= size){ + Edit edit = {}; + edit.str = str; + edit.length = len; + edit.range.first = start; + edit.range.one_past_last = end; + Edit_Behaviors behaviors = {}; + edit_single(models->system, models, file, edit, behaviors); result = true; - edit_single(models->system, models, file, start, end, str, len); } fill_buffer_summary(buffer, file, &models->working_set); } @@ -704,13 +710,22 @@ DOC_SEE(Buffer_Batch_Edit_Type) if (file != 0){ if (edit_count > 0){ Temp_Memory temp = begin_temp_memory(part); - Buffer_Edit *inverse_edits = push_array(part, Buffer_Edit, edit_count); - Assert(inverse_edits != 0); - char *inv_str = (char*)part->base + part->pos; - int32_t inv_str_max = part->max - part->pos; - Edit_Spec spec = edit_compute_batch_spec(&mem->heap, file, edits, str, str_len, - inverse_edits, inv_str, inv_str_max, edit_count, type); - edit_batch(system, models, file, spec, hist_normal, type); + Edit_Array real_edits = {}; + real_edits.vals = push_array(part, Edit, edit_count); + real_edits.count = edit_count; + Edit *edit_out = real_edits.vals; + Buffer_Edit *edit_in = edits; + Edit *one_past_last_edit_out = real_edits.vals + edit_count; + for (;edit_out < one_past_last_edit_out; + edit_out += 1, edit_in += 1){ + edit_out->str = str + edit_in->str_start; + edit_out->length = edit_in->len; + edit_out->range.first = edit_in->start; + edit_out->range.one_past_last = edit_in->end; + } + Edit_Behaviors behaviors = {}; + behaviors.batch_type = type; + edit_batch(system, models, file, real_edits, behaviors); end_temp_memory(temp); } result = true; @@ -1224,7 +1239,10 @@ DOC_SEE(Buffer_Create_Flag) if (file != 0 && (flags & BufferCreate_AlwaysNew) != 0){ i32 size = buffer_size(&file->state.buffer); if (size > 0){ - edit_single(system, models, file, 0, size, 0, 0); + Edit edit = {}; + edit.range.one_past_last = size; + Edit_Behaviors behaviors = {}; + edit_single(system, models, file, edit, behaviors); if (has_canon_name){ buffer_is_for_new_file = true; } @@ -1315,7 +1333,7 @@ DOC_SEE(Buffer_Identifier) if (file->canon.name.size != 0){ buffer_unbind_file(system, working_set, file); } - file_free(system, &models->app_links, &models->mem.heap, &models->lifetime_allocator, file); + file_free(system, &models->mem.heap, &models->lifetime_allocator, file); working_set_free_file(&models->mem.heap, working_set, file); Layout *layout = &models->layout; @@ -1397,7 +1415,7 @@ Reopen_Buffer(Application_Links *app, Buffer_Summary *buffer, Buffer_Reopen_Flag ++vptr_count; } - file_free(system, &models->app_links, &models->mem.heap, &models->lifetime_allocator, file); + file_free(system, &models->mem.heap, &models->lifetime_allocator, file); working_set_file_default_settings(&models->working_set, file); init_normal_file(system, models, file_memory, size, file); @@ -2526,7 +2544,7 @@ DOC(Managed objects allocate memory that is tied to the scope. When the scope i Managed_Object result = 0; if (workspace != 0){ int32_t size = count*item_size; - void *ptr = dynamic_memory_bank_allocate(heap, &workspace->mem_bank, size + sizeof(Managed_Memory_Header)); + void *ptr = memory_bank_allocate(heap, &workspace->mem_bank, size + sizeof(Managed_Memory_Header)); Managed_Memory_Header *header = (Managed_Memory_Header*)ptr; header->std_header.type = ManagedObjectType_Memory; header->std_header.item_size = item_size; @@ -2563,7 +2581,7 @@ DOC_SEE(Marker) Managed_Object result = 0; if (workspace != 0){ i32 size = count*sizeof(Marker); - void *ptr = dynamic_memory_bank_allocate(heap, &workspace->mem_bank, size + sizeof(Managed_Buffer_Markers_Header)); + void *ptr = memory_bank_allocate(heap, &workspace->mem_bank, size + sizeof(Managed_Buffer_Markers_Header)); Managed_Buffer_Markers_Header *header = (Managed_Buffer_Markers_Header*)ptr; header->std_header.type = ManagedObjectType_Markers; header->std_header.item_size = sizeof(Marker); @@ -2907,7 +2925,7 @@ DOC(Permanently frees the specified object. Not only does this free up the memo workspace->buffer_markers_list.count -= 1; } dynamic_workspace_erase_pointer(workspace, lo_id); - dynamic_memory_bank_free(&workspace->mem_bank, object_ptr); + memory_bank_free(&workspace->mem_bank, object_ptr); return(true); } } @@ -3291,6 +3309,84 @@ DOC_RETURN(Returns true if the given id was a valid face and the change was made return(did_change); } +API_EXPORT History_Record_Index +Buffer_History_Newest_Record_Index(Application_Links *app, Buffer_Summary *buffer){ + Models *models = (Models*)app->cmd_context; + Editing_File *file = imp_get_file(models, buffer); + History_Record_Index result = 0; + if (file != 0){ + result = history_get_record_count(&file->state.history); + } + return(result); +} + +API_EXPORT Record_Data +Buffer_History_Get_Record(Application_Links *app, Buffer_Summary *buffer, History_Record_Index record){ + Record_Data result = {}; + return(result); +} + +API_EXPORT History_Record_Index +Buffer_History_Get_Current_State_Index(Application_Links *app, Buffer_Summary *buffer){ + Models *models = (Models*)app->cmd_context; + Editing_File *file = imp_get_file(models, buffer); + History_Record_Index result = 0; + if (file != 0){ + result = file_get_current_record_index(file); + } + return(result); +} + +API_EXPORT bool32 +Buffer_History_Set_Current_State_Index(Application_Links *app, Buffer_Summary *buffer, History_Record_Index index){ + Models *models = (Models*)app->cmd_context; + Editing_File *file = imp_get_file(models, buffer); + bool32 result = false; + if (file != 0){ + i32 max_index = history_get_record_count(&file->state.history); + if (0 <= index && index <= max_index){ + System_Functions *system = models->system; + edit_change_current_history_state(system, models, file, index); + result = true; + } + } + return(result); +} + +API_EXPORT bool32 +Buffer_History_Merge_Records_Between_States(Application_Links *app, Buffer_Summary *buffer, History_Record_Index first_index, History_Record_Index last_index){ + bool32 result = false; + return(result); +} + +API_EXPORT bool32 +Buffer_History_Split_Group_Record(Application_Links *app, Buffer_Summary *buffer, History_Record_Index record_index, int32_t sub_record_index){ + bool32 result = false; + return(result); +} + +API_EXPORT bool32 +Buffer_History_Split_Single_Record(Application_Links *app, Buffer_Summary *buffer, History_Record_Index record_index, int32_t forward_str_split, int32_t backward_str_split){ + bool32 result = false; + return(result); +} + +API_EXPORT bool32 +Buffer_History_Clear_After_Undo_Position(Application_Links *app, Buffer_Summary *buffer){ + bool32 result = false; + return(result); +} + +API_EXPORT void +Global_History_Edit_Group_Begin(Application_Links *app){ + +} + +API_EXPORT void +Global_History_Edit_Group_End(Application_Links *app){ + +} + internal void font_pointers_to_face_description(Font_Pointers font, Face_Description *description){ Font_Metrics *metrics = font.metrics; diff --git a/4ed_app_models.h b/4ed_app_models.h index 11ae43f8..28d45fb9 100644 --- a/4ed_app_models.h +++ b/4ed_app_models.h @@ -68,6 +68,7 @@ struct Models{ Working_Set working_set; Live_Views live_set; Parse_Context_Memory parse_context_memory; + Global_History global_history; Dynamic_Variable_Layout variable_layout; Dynamic_Workspace dynamic_workspace; diff --git a/4ed_app_target.cpp b/4ed_app_target.cpp index f4e93397..3cfba91a 100644 --- a/4ed_app_target.cpp +++ b/4ed_app_target.cpp @@ -44,13 +44,14 @@ struct Mem_Options{ #include "4ed_linked_node_macros.h" #include "4ed_log.h" #include "4ed_ptr_check.h" +#include "4ed_memory_bank.h" #include "4ed_dynamic_variables.h" #include "4ed_buffer_model.h" #include "4ed_translation.h" #include "4ed_command.h" #include "4ed_buffer.h" -#include "4ed_undo.h" +#include "4ed_history.h" #include "4ed_file.h" #include "4ed_code_wrap.h" @@ -62,11 +63,13 @@ struct Mem_Options{ #include "4ed_gui.h" #include "4ed_layout.h" #include "4ed_view.h" +#include "4ed_edit.h" #include "4ed_app_models.h" #include "4ed_mem.cpp" #include "4ed_hash_functions.cpp" #include "4ed_ptr_check.cpp" +#include "4ed_memory_bank.cpp" #include "4ed_dynamic_variables.cpp" #include "4ed_parse_context.cpp" #include "4ed_font.cpp" @@ -75,7 +78,7 @@ struct Mem_Options{ #include "4ed_render_format.cpp" #include "4ed_command.cpp" #include "4ed_buffer.cpp" -#include "4ed_undo.cpp" +#include "4ed_history.cpp" #include "4ed_file_lex.cpp" #include "4ed_file.cpp" #include "4ed_code_wrap.cpp" diff --git a/4ed_buffer.cpp b/4ed_buffer.cpp index afba93e6..e3296504 100644 --- a/4ed_buffer.cpp +++ b/4ed_buffer.cpp @@ -112,22 +112,73 @@ buffer_batch_debug_sort_check(Buffer_Edit *sorted_edits, i32 edit_count){ return(result); } +// TODO(allen): This now relies on Edit and Edit_Array from 4ed_edit.h even though we sort of think of that +// as cheating... gotta rethink the separation of buffer from everything else moving forward or something. + internal i32 -buffer_batch_edit_max_shift(Buffer_Edit *sorted_edits, i32 edit_count){ - i32 i = 0; - i32 shift_total = 0, shift_max = 0; +buffer_batch_edit_update_cursors(Cursor_With_Index *sorted_positions, i32 count, Edit_Array sorted_edits, b32 lean_right){ + Cursor_With_Index *position = sorted_positions; + Cursor_With_Index *one_past_last_position = sorted_positions + count; + Edit *edit = sorted_edits.vals; + Edit *one_past_last_edit = sorted_edits.vals + sorted_edits.count; - Buffer_Edit *edit = sorted_edits; - for (i = 0; i < edit_count; ++i, ++edit){ - shift_total += (edit->len - (edit->end - edit->start)); - if (shift_total > shift_max){ - shift_max = shift_total; + i32 shift_amount = 0; + if (lean_right){ + for (;edit < one_past_last_edit && position < one_past_last_position; + ++edit){ + i32 start = edit->range.first; + i32 end = edit->range.one_past_last; + + for (;position->pos < start && position < one_past_last_position; + ++position){ + position->pos += shift_amount; + } + + i32 new_end = start + edit->length + shift_amount; + for (;position->pos <= end && position < one_past_last_position; + ++position){ + position->pos = new_end; + } + + shift_amount += (edit->length - (end - start)); + } + } + else{ + for (;edit < one_past_last_edit && position < one_past_last_position; + ++edit){ + i32 start = edit->range.first; + i32 end = edit->range.one_past_last; + + for (;position->pos < start && position < one_past_last_position; + ++position){ + position->pos += shift_amount; + } + + i32 new_end = start + shift_amount; + for (;position->pos <= end && position < one_past_last_position; + ++position){ + position->pos = new_end; + } + + shift_amount += (edit->length - (end - start)); } } - return(shift_max); + for (;position < one_past_last_position; + ++position){ + position->pos += shift_amount; + } + + for (;edit < one_past_last_edit; + ++edit){ + shift_amount += (edit->length - (edit->range.one_past_last - edit->range.first)); + } + + return(shift_amount); } +#if 0 + internal i32 buffer_batch_edit_update_cursors(Cursor_With_Index *sorted_positions, i32 count, Buffer_Edit *sorted_edits, i32 edit_count, b32 lean_right){ Cursor_With_Index *position = sorted_positions; @@ -181,6 +232,7 @@ buffer_batch_edit_update_cursors(Cursor_With_Index *sorted_positions, i32 count, return(shift_amount); } +#endif ////////////////////////////////////// @@ -471,6 +523,38 @@ buffer_replace_range(Gap_Buffer *buffer, i32 start, i32 end, char *str, i32 len, // TODO(allen): do(optimize Gap_Buffer batch edit) // Now that we are just using Gap_Buffer we could afford to improve // this for the Gap_Buffer's behavior. + +// TODO(allen): This now relies on Edit and Edit_Array from 4ed_edit.h even though we sort of think of that +// as cheating... gotta rethink the separation of buffer from everything else moving forward or something. + +internal b32 +buffer_batch_edit_step(Buffer_Batch_State *state, Gap_Buffer *buffer, Edit_Array sorted_edits, void *scratch, i32 scratch_size, i32 *request_amount){ + b32 result = false; + + i32 shift_total = state->shift_total; + i32 i = state->i; + + Edit *edit = sorted_edits.vals + i; + for (; i < sorted_edits.count; ++i, ++edit){ + char *str = edit->str; + i32 length = edit->length; + i32 start = edit->range.first + shift_total; + i32 end = edit->range.one_past_last + shift_total; + i32 shift_amount = buffer_replace_range_compute_shift(start, end, length); + result = buffer_replace_range(buffer, start, end, str, length, shift_amount, scratch, scratch_size, request_amount); + if (result){ + break; + } + shift_total += shift_amount; + } + + state->shift_total = shift_total; + state->i = i; + + return(result); +} + +#if 0 internal i32 buffer_batch_edit_step(Buffer_Batch_State *state, Gap_Buffer *buffer, Buffer_Edit *sorted_edits, char *strings, i32 edit_count, void *scratch, i32 scratch_size, i32 *request_amount){ @@ -497,6 +581,7 @@ buffer_batch_edit_step(Buffer_Batch_State *state, Gap_Buffer *buffer, Buffer_Edi return(result); } +#endif internal void* buffer_edit_provide_memory(Gap_Buffer *buffer, void *new_data, i32 new_max){ @@ -553,6 +638,11 @@ buffer_stringify(Gap_Buffer *buffer, i32 start, i32 end, char *out){ } } +internal void +buffer_stringify_range(Gap_Buffer *buffer, Range range, char *out){ + buffer_stringify(buffer, range.first, range.one_past_last, out); +} + internal i32 buffer_convert_out(Gap_Buffer *buffer, char *dest, i32 max){ Gap_Buffer_Stream stream = {}; diff --git a/4ed_dynamic_variables.cpp b/4ed_dynamic_variables.cpp index e9babdb1..576badc8 100644 --- a/4ed_dynamic_variables.cpp +++ b/4ed_dynamic_variables.cpp @@ -66,49 +66,6 @@ dynamic_variables_create(Heap *heap, Dynamic_Variable_Layout *layout, String nam //////////////////////////////// -internal void -dynamic_memory_bank_init(Heap *heap, Dynamic_Memory_Bank *mem_bank){ - heap_init(&mem_bank->heap); - mem_bank->first = 0; - mem_bank->last = 0; - mem_bank->total_memory_size = 0; -} - -internal void* -dynamic_memory_bank_allocate(Heap *heap, Dynamic_Memory_Bank *mem_bank, i32 size){ - void *ptr = heap_allocate(&mem_bank->heap, size); - if (ptr == 0){ - i32 alloc_size = clamp_bottom(4096, size*4 + sizeof(Dynamic_Memory_Header)); - void *new_block = heap_allocate(heap, alloc_size); - if (new_block != 0){ - Dynamic_Memory_Header *header = (Dynamic_Memory_Header*)new_block; - sll_push(mem_bank->first, mem_bank->last, header); - mem_bank->total_memory_size += alloc_size; - heap_extend(&mem_bank->heap, header + 1, alloc_size - sizeof(*header)); - ptr = heap_allocate(&mem_bank->heap, size); - } - } - return(ptr); -} - -internal void -dynamic_memory_bank_free(Dynamic_Memory_Bank *mem_bank, void *ptr){ - heap_free(&mem_bank->heap, ptr); -} - -internal void -dynamic_memory_bank_free_all(Heap *heap, Dynamic_Memory_Bank *mem_bank){ - for (Dynamic_Memory_Header *header = mem_bank->first, *next = 0; - header != 0; - header = next){ - next = header->next; - heap_free(heap, header); - } - mem_bank->total_memory_size = 0; -} - -//////////////////////////////// - internal void dynamic_variables_block_init(Dynamic_Variable_Block *block){ block->val_array = 0; @@ -117,12 +74,12 @@ dynamic_variables_block_init(Dynamic_Variable_Block *block){ } internal void -dynamic_variables_block_grow_max_to(Heap *heap, Dynamic_Memory_Bank *mem_bank, i32 new_max, Dynamic_Variable_Block *block){ +dynamic_variables_block_grow_max_to(Heap *heap, Memory_Bank *mem_bank, i32 new_max, Dynamic_Variable_Block *block){ i32 new_size = new_max*sizeof(u64); - u64 *new_array = (u64*)dynamic_memory_bank_allocate(heap, mem_bank, new_size); + u64 *new_array = (u64*)memory_bank_allocate(heap, mem_bank, new_size); if (block->val_array != 0){ memcpy(new_array, block->val_array, sizeof(u64)*block->count); - dynamic_memory_bank_free(mem_bank, block->val_array); + memory_bank_free(mem_bank, block->val_array); } block->val_array = new_array; } @@ -142,7 +99,7 @@ dynamic_variables_block_fill_unset_values(Dynamic_Variable_Layout *layout, Dynam } internal b32 -dynamic_variables_get_ptr(Heap *heap, Dynamic_Memory_Bank *mem_bank, +dynamic_variables_get_ptr(Heap *heap, Memory_Bank *mem_bank, Dynamic_Variable_Layout *layout, Dynamic_Variable_Block *block, i32 location, u64 **ptr_out){ b32 result = false; @@ -164,17 +121,17 @@ dynamic_variables_get_ptr(Heap *heap, Dynamic_Memory_Bank *mem_bank, //////////////////////////////// internal void -insert_u32_Ptr_table(Heap *heap, Dynamic_Memory_Bank *mem_bank, u32_Ptr_Table *table, u32 key, void* val){ +insert_u32_Ptr_table(Heap *heap, Memory_Bank *mem_bank, u32_Ptr_Table *table, u32 key, void* val){ if (at_max_u32_Ptr_table(table)){ i32 new_max = (table->max + 1)*2; i32 new_mem_size = max_to_memsize_u32_Ptr_table(new_max); - void *new_mem = dynamic_memory_bank_allocate(heap, mem_bank, new_mem_size); + void *new_mem = memory_bank_allocate(heap, mem_bank, new_mem_size); u32_Ptr_Table new_table = make_u32_Ptr_table(new_mem, new_mem_size); if (table->mem != 0){ b32 result = move_u32_Ptr_table(&new_table, table); Assert(result); AllowLocal(result); - dynamic_memory_bank_free(mem_bank, table->mem); + memory_bank_free(mem_bank, table->mem); } *table = new_table; } @@ -191,12 +148,12 @@ marker_visual_allocator_init(Marker_Visual_Allocator *allocator){ } internal Marker_Visual_Data* -dynamic_workspace_alloc_visual(Heap *heap, Dynamic_Memory_Bank *mem_bank, Dynamic_Workspace *workspace){ +dynamic_workspace_alloc_visual(Heap *heap, Memory_Bank *mem_bank, Dynamic_Workspace *workspace){ Marker_Visual_Allocator *allocator = &workspace->visual_allocator; if (allocator->free_count == 0){ i32 new_slots_count = clamp_bottom(16, allocator->total_visual_count); i32 memsize = new_slots_count*sizeof(Marker_Visual_Data); - void *new_slots_memory = dynamic_memory_bank_allocate(heap, mem_bank, memsize); + void *new_slots_memory = memory_bank_allocate(heap, mem_bank, memsize); memset(new_slots_memory, 0, memsize); Marker_Visual_Data *new_slot = (Marker_Visual_Data*)new_slots_memory; allocator->free_count += new_slots_count; @@ -254,7 +211,7 @@ marker_visual_defaults(Marker_Visual_Data *data){ internal void dynamic_workspace_init(Heap *heap, Lifetime_Allocator *lifetime_allocator, i32 user_type, void *user_back_ptr, Dynamic_Workspace *workspace){ memset(workspace, 0, sizeof(*workspace)); - dynamic_memory_bank_init(heap, &workspace->mem_bank); + memory_bank_init(&workspace->mem_bank); dynamic_variables_block_init(&workspace->var_block); marker_visual_allocator_init(&workspace->visual_allocator); if (lifetime_allocator->scope_id_counter == 0){ @@ -269,13 +226,13 @@ dynamic_workspace_init(Heap *heap, Lifetime_Allocator *lifetime_allocator, i32 u internal void dynamic_workspace_free(Heap *heap, Lifetime_Allocator *lifetime_allocator, Dynamic_Workspace *workspace){ erase_u32_Ptr_table(&lifetime_allocator->scope_id_to_scope_ptr_table, workspace->scope_id); - dynamic_memory_bank_free_all(heap, &workspace->mem_bank); + memory_bank_free_all(heap, &workspace->mem_bank); } internal void dynamic_workspace_clear_contents(Heap *heap, Dynamic_Workspace *workspace){ - dynamic_memory_bank_free_all(heap, &workspace->mem_bank); - dynamic_memory_bank_init(heap, &workspace->mem_bank); + memory_bank_free_all(heap, &workspace->mem_bank); + memory_bank_init(&workspace->mem_bank); dynamic_variables_block_init(&workspace->var_block); marker_visual_allocator_init(&workspace->visual_allocator); diff --git a/4ed_dynamic_variables.h b/4ed_dynamic_variables.h index d864c2e8..7f85d732 100644 --- a/4ed_dynamic_variables.h +++ b/4ed_dynamic_variables.h @@ -98,22 +98,9 @@ struct Dynamic_Variable_Block{ //////////////////////////////// -struct Dynamic_Memory_Header{ - Dynamic_Memory_Header *next; -}; - -struct Dynamic_Memory_Bank{ - Heap heap; - Dynamic_Memory_Header *first; - Dynamic_Memory_Header *last; - umem total_memory_size; -}; - -//////////////////////////////// - struct Dynamic_Workspace{ Dynamic_Variable_Block var_block; - Dynamic_Memory_Bank mem_bank; + Memory_Bank mem_bank; Marker_Visual_Allocator visual_allocator; u32_Ptr_Table object_id_to_object_ptr; u32 object_id_counter; diff --git a/4ed_edit.cpp b/4ed_edit.cpp index 8020e168..660dbd42 100644 --- a/4ed_edit.cpp +++ b/4ed_edit.cpp @@ -70,8 +70,11 @@ edit_fix_markers__read_workspace_markers(Dynamic_Workspace *workspace, Buffer_ID } internal void -edit_fix_markers(System_Functions *system, Models *models, Editing_File *file, Layout *layout, Cursor_Fix_Descriptor desc){ +edit_fix_markers(System_Functions *system, Models *models, Editing_File *file, Edit_Array edits){ Partition *part = &models->mem.part; + Layout *layout = &models->layout; + + Assert(edits.count > 0); Temp_Memory cursor_temp = begin_temp_memory(part); @@ -136,6 +139,7 @@ edit_fix_markers(System_Functions *system, Models *models, Editing_File *file, L if (cursor_count > 0 || r_cursor_count > 0){ buffer_sort_cursors(cursors, cursor_count); +#if 0 if (desc.is_batch){ buffer_batch_edit_update_cursors(cursors, cursor_count, desc.batch, desc.batch_size, false); buffer_batch_edit_update_cursors(r_cursors, r_cursor_count, desc.batch, desc.batch_size, true); @@ -144,6 +148,18 @@ edit_fix_markers(System_Functions *system, Models *models, Editing_File *file, L buffer_update_cursors(cursors, cursor_count, desc.start, desc.end, desc.shift_amount + (desc.end - desc.start), false); buffer_update_cursors(r_cursors, r_cursor_count, desc.start, desc.end, desc.shift_amount + (desc.end - desc.start), true); } +#endif + + if (edits.count > 1){ + buffer_batch_edit_update_cursors( cursors, cursor_count, edits, false); + buffer_batch_edit_update_cursors(r_cursors, r_cursor_count, edits, true); + } + else{ + Edit edit = edits.vals[0]; + buffer_update_cursors( cursors, cursor_count, edit.range.first, edit.range.one_past_last, edit.length, false); + buffer_update_cursors(r_cursors, r_cursor_count, edit.range.first, edit.range.one_past_last, edit.length, true); + } + buffer_unsort_cursors(cursors, cursor_count); cursor_count = 0; @@ -200,45 +216,58 @@ edit_fix_markers(System_Functions *system, Models *models, Editing_File *file, L } internal void -edit_single__inner(System_Functions *system, Models *models, Editing_File *file, Edit_Spec spec, History_Mode history_mode){ +edit_fix_markers(System_Functions *system, Models *models, Editing_File *file, Edit edit){ + Edit_Array edits = {}; + edits.vals = &edit; + edits.count = 1; + edit_fix_markers(system, models, file, edits); +} + +internal void +edit_single(System_Functions *system, Models *models, Editing_File *file, Edit edit, Edit_Behaviors behaviors){ Mem_Options *mem = &models->mem; - Layout *layout = &models->layout; Heap *heap = &mem->heap; Partition *part = &mem->part; + Gap_Buffer *buffer = &file->state.buffer; + Assert(0 <= edit.range.first); + Assert(edit.range.first <= edit.range.one_past_last); + Assert(edit.range.one_past_last <= buffer_size(buffer)); + + // 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(heap, &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???? - file_update_history_before_edit(mem, file, spec.step, spec.str, history_mode); edit_pre_state_change(system, &mem->heap, models, file); // NOTE(allen): expand spec, compute shift - char *str = (char*)spec.str; - i32 start = spec.step.edit.start; - i32 end = spec.step.edit.end; - i32 str_len = spec.step.edit.len; - i32 shift_amount = buffer_replace_range_compute_shift(start, end, str_len); + i32 shift_amount = buffer_replace_range_compute_shift(edit.range.first, edit.range.one_past_last, edit.length); // NOTE(allen): actual text replacement i32 scratch_size = part_remaining(part); Assert(scratch_size > 0); i32 request_amount = 0; - Assert(end <= buffer_size(&file->state.buffer)); - for (;buffer_replace_range(&file->state.buffer, start, end, str, str_len, shift_amount, part->base + part->pos, scratch_size, &request_amount);){ + for (;buffer_replace_range(buffer, edit.range.first, edit.range.one_past_last, edit.str, edit.length, + shift_amount, part->base + part->pos, scratch_size, &request_amount);){ void *new_data = 0; if (request_amount > 0){ new_data = heap_allocate(heap, request_amount); } - void *old_data = buffer_edit_provide_memory(&file->state.buffer, new_data, request_amount); + void *old_data = buffer_edit_provide_memory(buffer, new_data, request_amount); if (old_data){ heap_free(heap, old_data); } } // NOTE(allen): line meta data - Gap_Buffer *buffer = &file->state.buffer; - i32 line_start = buffer_get_line_number(&file->state.buffer, start); - i32 line_end = buffer_get_line_number(&file->state.buffer, end); + i32 line_start = buffer_get_line_number(buffer, edit.range.first); + i32 line_end = buffer_get_line_number(buffer, edit.range.one_past_last); i32 replaced_line_count = line_end - line_start; - i32 new_line_count = buffer_count_newlines(&file->state.buffer, start, start+str_len); + i32 new_line_count = buffer_count_newlines(buffer, edit.range.first, edit.range.first + edit.length); i32 line_shift = new_line_count - replaced_line_count; Font_Pointers font = system->font.get_pointers_by_id(file->settings.font_id); @@ -252,18 +281,14 @@ edit_single__inner(System_Functions *system, Models *models, Editing_File *file, // NOTE(allen): token fixing if (file->settings.tokens_exist){ - file_relex(system, models, file, start, end, shift_amount); + file_relex(system, models, file, edit.range.first, edit.range.one_past_last, shift_amount); } // NOTE(allen): wrap meta data file_measure_wraps(system, &models->mem, file, font); // NOTE(allen): cursor fixing - Cursor_Fix_Descriptor desc = {}; - desc.start = start; - desc.end = end; - desc.shift_amount = shift_amount; - edit_fix_markers(system, models, file, layout, desc); + edit_fix_markers(system, models, file, edit); // NOTE(allen): mark edit finished if (file->settings.tokens_exist){ @@ -276,28 +301,14 @@ edit_single__inner(System_Functions *system, Models *models, Editing_File *file, } } -internal void -edit_single(System_Functions *system, Models *models, Editing_File *file, - i32 start, i32 end, char *str, i32 len){ - Edit_Spec spec = {}; - spec.step.type = ED_NORMAL; - spec.step.edit.start = start; - spec.step.edit.end = end; - spec.step.edit.len = len; - spec.str = (u8*)str; - edit_single__inner(system, models, file, spec, hist_normal); -} - +#if 0 internal Edit_Spec -edit_compute_batch_spec(Heap *heap, - Editing_File *file, - Buffer_Edit *edits, char *str_base, i32 str_size, +edit_compute_batch_spec(Heap *heap, Editing_File *file, Buffer_Edit *edits, char *str_base, i32 str_size, Buffer_Edit *inverse_array, char *inv_str, i32 inv_max, i32 edit_count, i32 batch_type){ i32 inv_str_pos = 0; Buffer_Invert_Batch state = {}; - if (buffer_invert_batch(&state, &file->state.buffer, edits, edit_count, - inverse_array, inv_str, &inv_str_pos, inv_max)){ + if (buffer_invert_batch(&state, &file->state.buffer, edits, edit_count, inverse_array, inv_str, &inv_str_pos, inv_max)){ InvalidCodePath; } @@ -313,31 +324,33 @@ edit_compute_batch_spec(Heap *heap, spec.step.inverse_child_count = edit_count; return(spec); } +#endif internal void -edit_batch(System_Functions *system, Models *models, Editing_File *file, Edit_Spec spec, History_Mode history_mode, Buffer_Batch_Edit_Type batch_type){ +edit_batch(System_Functions *system, Models *models, Editing_File *file, Edit_Array edits, Edit_Behaviors behaviors){ Mem_Options *mem = &models->mem; Heap *heap = &mem->heap; Partition *part = &mem->part; - Layout *layout = &models->layout; + + Gap_Buffer *buffer = &file->state.buffer; + Assert(edits.count > 0); + + // 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(heap, &models->global_history, &file->state.history, buffer, edits, behaviors.batch_type); + file->state.current_record_index = history_get_record_count(&file->state.history); + } // NOTE(allen): fixing stuff "beforewards"??? - Assert(spec.str == 0); - file_update_history_before_edit(mem, file, spec.step, 0, history_mode); edit_pre_state_change(system, &mem->heap, models, file); - // NOTE(allen): expand spec - u8 *str_base = file->state.undo.children.strings; - i32 batch_size = spec.step.child_count; - Buffer_Edit *batch = file->state.undo.children.edits + spec.step.first_child; - Assert(spec.step.first_child < file->state.undo.children.edit_count); - Assert(batch_size >= 0); - // NOTE(allen): actual text replacement + void *scratch = push_array(part, u8, 0); i32 scratch_size = part_remaining(part); Buffer_Batch_State state = {}; i32 request_amount = 0; - for (;buffer_batch_edit_step(&state, &file->state.buffer, batch, (char*)str_base, batch_size, part->base + part->pos, scratch_size, &request_amount);){ + for (;buffer_batch_edit_step(&state, buffer, edits, scratch, scratch_size, &request_amount);){ void *new_data = 0; if (request_amount > 0){ new_data = heap_allocate(heap, request_amount); @@ -360,14 +373,14 @@ edit_batch(System_Functions *system, Models *models, Editing_File *file, Edit_Sp buffer_measure_character_starts(system, font, &file->state.buffer, file->state.character_starts, 0, file->settings.virtual_white); // NOTE(allen): token fixing - switch (batch_type){ + switch (behaviors.batch_type){ case BatchEdit_Normal: { if (file->settings.tokens_exist){ // TODO(allen): Write a smart fast one here someday. - Buffer_Edit *first_edit = batch; - Buffer_Edit *last_edit = batch + batch_size - 1; - file_relex(system, models, file, first_edit->start, last_edit->end, shift_total); + i32 start = edits.vals[0].range.first; + i32 end = edits.vals[edits.count - 1].range.one_past_last; + file_relex(system, models, file, start, end, shift_total); } else{ file_mark_edit_finished(&models->working_set, file); @@ -382,22 +395,25 @@ edit_batch(System_Functions *system, Models *models, Editing_File *file, Edit_Sp Cpp_Token *end_token = tokens.tokens + tokens.count; Cpp_Token original = {}; - Buffer_Edit *edit = batch; - Buffer_Edit *end_edit = batch + batch_size; + Edit *edit = edits.vals; + Edit *one_past_last_edit = edits.vals + edits.count; i32 shift_amount = 0; i32 local_shift = 0; for (;token < end_token; ++token){ original = *token; - for (; edit < end_edit && edit->start <= original.start; ++edit){ - local_shift = (edit->len - (edit->end - edit->start)); + for (;edit < one_past_last_edit && edit->range.first <= original.start; + ++edit){ + local_shift = (edit->length - (edit->range.one_past_last - edit->range.first)); shift_amount += local_shift; } token->start += shift_amount; local_shift = 0; - for (; edit < end_edit && edit->start < original.start + original.size; ++edit){ - local_shift += (edit->len - (edit->end - edit->start)); + i32 original_end = original.start + original.size; + for (;edit < one_past_last_edit && edit->range.first < original_end; + ++edit){ + local_shift += (edit->length - (edit->range.one_past_last - edit->range.first)); } token->size += local_shift; shift_amount += local_shift; @@ -411,11 +427,7 @@ edit_batch(System_Functions *system, Models *models, Editing_File *file, Edit_Sp file_measure_wraps(system, &models->mem, file, font); // NOTE(allen): cursor fixing - Cursor_Fix_Descriptor desc = {}; - desc.is_batch = true; - desc.batch = batch; - desc.batch_size = batch_size; - edit_fix_markers(system, models, file, layout, desc); + edit_fix_markers(system, models, file, edits); // NOTE(allen): mark edit finished if (file->settings.tokens_exist){ @@ -466,31 +478,162 @@ edit_clear(System_Functions *system, Models *models, Editing_File *file){ file->state.edit_pos_stack_top = -1; } - edit_single(system, models, file, 0, buffer_size(&file->state.buffer), 0, 0); + Edit edit = {}; + edit.range.one_past_last = buffer_size(&file->state.buffer); + + Edit_Behaviors behaviors = {}; + edit_single(system, models, file, edit, behaviors); } internal void -edit_historical(System_Functions *system, Models *models, Editing_File *file, View *view, Edit_Stack *stack, - Edit_Step step, History_Mode history_mode){ - Edit_Spec spec = {}; - spec.step = step; +edit__apply_record_forward(System_Functions *system, Models *models, Editing_File *file, Record *record, Edit_Behaviors behaviors_prototype){ + // NOTE(allen): // NOTE(allen): // NOTE(allen): // NOTE(allen): // NOTE(allen): + // Whenever you change this also change the backward version! - if (step.child_count == 0){ - spec.step.edit.str_start = 0; - spec.str = stack->strings + step.edit.str_start; + switch (record->kind){ + case RecordKind_Single: + { + Edit edit = {}; + edit.str = record->single.str_forward; + edit.length = record->single.length_forward; + edit.range.first = record->single.first; + edit.range.one_past_last = edit.range.first + record->single.length_backward; + edit_single(system, models, file, edit, behaviors_prototype); + }break; - edit_single__inner(system, models, file, spec, history_mode); - - if (view != 0){ - view_cursor_move(system, view, step.edit.start + step.edit.len); - view->transient.edit_pos.mark = view->transient.edit_pos.cursor.pos; + case RecordKind_Batch: + { + Partition *scratch = &models->mem.part; + Temp_Memory temp = begin_temp_memory(scratch); - Style *style = &models->styles.styles[0]; - view_post_paste_effect(view, 0.333f, step.edit.start, step.edit.len, style->theme.colors[Stag_Undo]); - } + i32 count = record->batch.count; + Edit_Array edits = {}; + edits.vals = push_array(scratch, Edit, count); + edits.count = count; + + Edit *edit = edits.vals; + Record_Batch_Slot *batch_slot = record->batch.batch_records; + char *str_base_forward = record->batch.str_base_forward; + for (i32 i = 0; i < count; i += 1, edit += 1, batch_slot += 1){ + edit->str = str_base_forward; + edit->length = batch_slot->length_forward; + edit->range.first = batch_slot->first; + edit->range.one_past_last = edit->range.first + batch_slot->length_backward; + str_base_forward += batch_slot->length_forward; + } + + Edit_Behaviors behaviors = behaviors_prototype; + behaviors.batch_type = record->batch.type; + edit_batch(system, models, file, edits, behaviors); + + end_temp_memory(temp); + }break; + + case RecordKind_Group: + { + Node *sentinel = &record->group.children; + for (Node *node = sentinel->next; + node != sentinel; + node = node->next){ + Record *record = CastFromMember(Record, node, node); + edit__apply_record_forward(system, models, file, record, behaviors_prototype); + } + }break; } - else{ - edit_batch(system, models, view->transient.file_data.file, spec, hist_normal, spec.step.special_type); +} + +internal void +edit__apply_record_backward(System_Functions *system, Models *models, Editing_File *file, Record *record, Edit_Behaviors behaviors_prototype){ + // NOTE(allen): // NOTE(allen): // NOTE(allen): // NOTE(allen): // NOTE(allen): + // Whenever you change this also change the forward version! + + switch (record->kind){ + case RecordKind_Single: + { + Edit edit = {}; + edit.str = record->single.str_backward; + edit.length = record->single.length_backward; + edit.range.first = record->single.first; + edit.range.one_past_last = edit.range.first + record->single.length_forward; + edit_single(system, models, file, edit, behaviors_prototype); + }break; + + case RecordKind_Batch: + { + Partition *scratch = &models->mem.part; + Temp_Memory temp = begin_temp_memory(scratch); + + i32 count = record->batch.count; + Edit_Array edits = {}; + edits.vals = push_array(scratch, Edit, count); + edits.count = count; + + i32 shift_amount = 0; + + Edit *edit = edits.vals; + Record_Batch_Slot *batch_slot = record->batch.batch_records; + char *str_base_backward = record->batch.str_base_backward; + for (i32 i = 0; i < count; i += 1, edit += 1, batch_slot += 1){ + edit->str = str_base_backward; + edit->length = batch_slot->length_backward; + edit->range.first = batch_slot->first + shift_amount; + edit->range.one_past_last = edit->range.first + batch_slot->length_forward; + str_base_backward += batch_slot->length_backward; + shift_amount += batch_slot->length_forward - batch_slot->length_backward; + } + + Edit_Behaviors behaviors = behaviors_prototype; + behaviors.batch_type = record->batch.type; + edit_batch(system, models, file, edits, behaviors); + + end_temp_memory(temp); + }break; + + case RecordKind_Group: + { + Node *sentinel = &record->group.children; + for (Node *node = sentinel->prev; + node != sentinel; + node = node->prev){ + Record *record = CastFromMember(Record, node, node); + edit__apply_record_backward(system, models, file, record, behaviors_prototype); + } + }break; + } +} + +internal void +edit_change_current_history_state(System_Functions *system, Models *models, Editing_File *file, i32 target_index){ + History *history = &file->state.history; + if (history->activated && file->state.current_record_index != target_index){ + Assert(0 <= target_index && target_index <= history->record_count); + + i32 current = file->state.current_record_index; + Record *record = history_get_record(history, current); + Assert(record != 0); + Record *dummy_record = history_get_dummy_record(history); + + Edit_Behaviors behaviors_prototype = {}; + behaviors_prototype.do_not_post_to_history = true; + + if (current < target_index){ + do{ + current += 1; + record = CastFromMember(Record, node, record->node.next); + Assert(record != dummy_record); + edit__apply_record_forward(system, models, file, record, behaviors_prototype); + } while (current != target_index); + } + else{ + do{ + Assert(record != dummy_record); + edit__apply_record_backward(system, models, file, record, behaviors_prototype); + current -= 1; + record = CastFromMember(Record, node, record->node.prev); + } while (current != target_index); + } + + file->state.current_record_index = current; } } diff --git a/4ed_edit.h b/4ed_edit.h new file mode 100644 index 00000000..c20b8d92 --- /dev/null +++ b/4ed_edit.h @@ -0,0 +1,34 @@ +/* + * Mr. 4th Dimention - Allen Webster + * + * 07.02.2019 + * + * Types used for edit operations + * + */ + +// TOP + +#if !defined(FRED_EDIT_H) +#define FRED_EDIT_H + +struct Edit{ + char *str; + i32 length; + Range range; +}; + +struct Edit_Array{ + Edit *vals; + i32 count; +}; + +struct Edit_Behaviors{ + Buffer_Batch_Edit_Type batch_type; + b32 do_not_post_to_history; +}; + +#endif + +// BOTTOM + diff --git a/4ed_file.cpp b/4ed_file.cpp index 4f4721aa..929e2459 100644 --- a/4ed_file.cpp +++ b/4ed_file.cpp @@ -441,31 +441,7 @@ file_create_from_string(System_Functions *system, Models *models, Editing_File * file->settings.read_only = ((flags & FileCreateFlag_ReadOnly) != 0); if (!file->settings.read_only){ - // TODO(allen): Redo undo system (if you don't mind the pun) - i32 request_size = KB(64); - file->state.undo.undo.max = request_size; - file->state.undo.undo.strings = (u8*)heap_allocate(heap, request_size); - file->state.undo.undo.edit_max = request_size/sizeof(Edit_Step); - file->state.undo.undo.edits = (Edit_Step*)heap_allocate(heap, request_size); - - file->state.undo.redo.max = request_size; - file->state.undo.redo.strings = (u8*)heap_allocate(heap, request_size); - file->state.undo.redo.edit_max = request_size/sizeof(Edit_Step); - file->state.undo.redo.edits = (Edit_Step*)heap_allocate(heap, request_size); - - file->state.undo.history.max = request_size; - file->state.undo.history.strings = (u8*)heap_allocate(heap, request_size); - file->state.undo.history.edit_max = request_size/sizeof(Edit_Step); - file->state.undo.history.edits = (Edit_Step*)heap_allocate(heap, request_size); - - file->state.undo.children.max = request_size; - file->state.undo.children.strings = (u8*)heap_allocate(heap, request_size); - file->state.undo.children.edit_max = request_size/sizeof(Buffer_Edit); - file->state.undo.children.edits = (Buffer_Edit*)heap_allocate(heap, request_size); - - file->state.undo.history_block_count = 1; - file->state.undo.history_head_block = 0; - file->state.undo.current_block_normal = 1; + history_init(&models->app_links, &file->state.history); } // TODO(allen): do(cleanup the create and settings dance) @@ -491,8 +467,7 @@ file_create_from_string(System_Functions *system, Models *models, Editing_File * } internal void -file_free(System_Functions *system, Application_Links *app, Heap *heap, Lifetime_Allocator *lifetime_allocator, - Editing_File *file){ +file_free(System_Functions *system, Heap *heap, Lifetime_Allocator *lifetime_allocator, Editing_File *file){ if (file->state.still_lexing){ system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); if (file->state.swap_array.tokens){ @@ -516,19 +491,7 @@ file_free(System_Functions *system, Application_Links *app, Heap *heap, Lifetime heap_free(heap, file->state.character_starts); heap_free(heap, file->state.line_indents); - if (file->state.undo.undo.edits){ - heap_free(heap, file->state.undo.undo.strings); - heap_free(heap, file->state.undo.undo.edits); - - heap_free(heap, file->state.undo.redo.strings); - heap_free(heap, file->state.undo.redo.edits); - - heap_free(heap, file->state.undo.history.strings); - heap_free(heap, file->state.undo.history.edits); - - heap_free(heap, file->state.undo.children.strings); - heap_free(heap, file->state.undo.children.edits); - } + history_free(heap, &file->state.history); } internal void @@ -543,5 +506,12 @@ init_read_only_file(System_Functions *system, Models *models, Editing_File *file file_create_from_string(system, models, file, val, FileCreateFlag_ReadOnly); } +//////////////////////////////// + +internal i32 +file_get_current_record_index(Editing_File *file){ + return(file->state.current_record_index); +} + // BOTTOM diff --git a/4ed_file.h b/4ed_file.h index eed00522..48adddf6 100644 --- a/4ed_file.h +++ b/4ed_file.h @@ -75,7 +75,8 @@ struct Editing_File_State{ i32 wrap_position_count; i32 wrap_position_max; - Undo_Data undo; + History history; + i32 current_record_index; Cpp_Token_Array token_array; Cpp_Token_Array swap_array; diff --git a/4ed_history.cpp b/4ed_history.cpp new file mode 100644 index 00000000..ce874563 --- /dev/null +++ b/4ed_history.cpp @@ -0,0 +1,262 @@ +/* + * Mr. 4th Dimention - Allen Webster + * + * 24.03.2018 + * + * History + */ + +// TOP + +// TODO(allen): do(make an index <-> node acceleration structure for history) + +internal i32 +history__to_index(History *history, Node *node){ + i32 result = -1; + i32 counter = 0; + Node *sentinel = &history->records; + Node *it = sentinel; + do{ + if (it == node){ + result = counter; + break; + } + counter += 1; + it = it->next; + } while (it != sentinel); + return(result); +} + +internal Node* +history__to_node(History *history, int32_t index){ + Node *result = 0; + if (0 <= index && index <= history->record_count){ + i32 counter = 0; + Node *sentinel = &history->records; + Node *it = sentinel; + do{ + if (counter == index){ + result = it; + break; + } + counter += 1; + it = it->next; + } while (it != sentinel); + } + return(result); +} + +internal Record* +history__allocate_record(Heap *heap, History *history){ + Node *sentinel = &history->free_records; + Node *new_node = sentinel->next; + if (new_node == sentinel){ + i32 new_record_count = 1024; + void *memory = memory_bank_allocate(heap, &history->bank, sizeof(Record)*new_record_count); + + Record *new_record = (Record*)memory; + sentinel->next = &new_record->node; + new_record->node.prev = sentinel; + for (i32 i = 1; i < new_record_count; i += 1, new_record += 1){ + new_record[0].node.next = &new_record[1].node; + new_record[1].node.prev = &new_record[0].node; + } + new_record[0].node.next = sentinel; + sentinel->prev = &new_record[0].node; + + new_node = &((Record*)memory)->node; + } + dll_remove(new_node); + Record *record = CastFromMember(Record, node, new_node); + block_zero_struct(record); + return(record); +} + +internal void +global_history_init(Global_History *global_history){ + global_history->edit_number_counter = 0; + global_history->edit_grouping_counter = 0; +} + +internal i32 +global_history_get_edit_number(Global_History *global_history){ + i32 result = global_history->edit_number_counter; + if (global_history->edit_grouping_counter == 0){ + global_history->edit_number_counter += 1; + } + return(result); +} + +internal void +global_history_adjust_edit_grouping_counter(Global_History *global_history, i32 adjustment){ + global_history->edit_grouping_counter += adjustment; +} + +internal void +history_init(Application_Links *app, History *history){ + history->activated = true; + history->arena = make_arena(app, KB(32)); + memory_bank_init(&history->bank); + dll_init_sentinel(&history->free_records); + dll_init_sentinel(&history->records); + history->record_count = 0; +} + +internal void +history_free(Heap *heap, History *history){ + if (history->activated){ + arena_release_all(&history->arena); + memory_bank_free_all(heap, &history->bank); + } +} + +internal i32 +history_get_record_count(History *history){ + return(history->record_count); +} + +internal Record* +history_get_record(History *history, i32 index){ + Record *record = 0; + Node *node = history__to_node(history, index); + if (node != 0){ + record = CastFromMember(Record, node, node); + } + return(record); +} + +internal Record* +history_get_dummy_record(History *history){ + return(CastFromMember(Record, node, &history->records)); +} + +internal void +history__stash_record(History *history, Record *new_record){ + dll_insert_back(&history->records, &new_record->node); + history->record_count += 1; +} + +internal void +history__free_nodes(History *history, i32 first_index, Node *first_node, Node *last_node){ + if (first_node == last_node){ + dll_remove(first_node); + dll_insert(&history->free_records, first_node); + } + else{ + { + Node *left = first_node->prev; + Node *right = last_node->next; + left->next = right; + right->prev = left; + } + + { + Node *left = &history->free_records; + Node *right = left->next; + left->next = first_node; + first_node->prev = left; + right->prev = last_node; + last_node->next = right; + } + } + Assert(first_index != 0); + history->record_count = first_index - 1; +} + +internal void +history_record_edit(Heap *heap, Global_History *global_history, History *history, Gap_Buffer *buffer, Edit edit){ + if (history->activated){ + Record *new_record = history__allocate_record(heap, history); + history__stash_record(history, new_record); + + new_record->restore_point = temp_memory_light(begin_temp_memory(&history->arena)); + new_record->edit_number = global_history_get_edit_number(global_history); + + new_record->kind = RecordKind_Single; + + i32 length_forward = edit.length; + i32 length_backward = edit.range.one_past_last - edit.range.first; + + new_record->single.str_forward = push_array(&history->arena, char, length_forward); + new_record->single.str_backward = push_array(&history->arena, char, length_backward); + new_record->single.length_forward = length_forward; + new_record->single.length_backward = length_backward; + new_record->single.first = edit.range.first; + + block_copy(new_record->single.str_forward, edit.str, length_forward); + buffer_stringify_range(buffer, edit.range, new_record->single.str_backward); + } +} + +internal void +history_record_edit(Heap *heap, Global_History *global_history, History *history, Gap_Buffer *buffer, Edit_Array edits, Buffer_Batch_Edit_Type batch_type){ + if (history->activated){ + Record *new_record = history__allocate_record(heap, history); + history__stash_record(history, new_record); + + new_record->restore_point = temp_memory_light(begin_temp_memory(&history->arena)); + new_record->edit_number = global_history_get_edit_number(global_history); + + new_record->kind = RecordKind_Batch; + + i32 length_forward = 0; + i32 length_backward = 0; + + for (i32 i = 0; i < edits.count; i += 1){ + length_forward += edits.vals[i].length; + length_backward += edits.vals[i].range.one_past_last - edits.vals[i].range.first; + } + + new_record->batch.type = batch_type; + new_record->batch.count = edits.count; + new_record->batch.str_base_forward = push_array(&history->arena, char, length_forward); + new_record->batch.str_base_backward = push_array(&history->arena, char, length_backward); + new_record->batch.batch_records = push_array(&history->arena, Record_Batch_Slot, edits.count); + + char *str_base_forward = new_record->batch.str_base_forward; + char *cursor_forward = str_base_forward; + char *str_base_backward = new_record->batch.str_base_backward; + char *cursor_backward = str_base_backward; + + Record_Batch_Slot *batch_slot = new_record->batch.batch_records; + Edit *edit = edits.vals; + + for (i32 i = 0; i < edits.count; i += 1, batch_slot += 1, edit += 1){ + i32 first = edit->range.first; + i32 length_forward = edit->length; + i32 length_backward = edit->range.one_past_last - first; + + batch_slot->length_forward = length_forward ; + batch_slot->length_backward = length_backward; + batch_slot->first = first; + + block_copy(cursor_forward , edit->str, length_forward); + buffer_stringify_range(buffer, edit->range, cursor_backward); + + cursor_forward += length_forward ; + cursor_backward += length_backward; + } + } +} + +internal void +history_dump_records_after_index(History *history, i32 index){ + Assert(0 <= index && index <= history->record_count); + if (index < history->record_count){ + Node *node = history__to_node(history, index); + Node *first_node_to_clear = node->next; + + Node *sentinel = &history->records; + Assert(first_node_to_clear != sentinel); + + Record *first_record_to_clear = CastFromMember(Record, node, first_node_to_clear); + end_temp_memory(&history->arena, first_record_to_clear->restore_point); + + Node *last_node_to_clear = sentinel->prev; + + history__free_nodes(history, index + 1, first_node_to_clear, last_node_to_clear); + } +} + +// BOTTOM + diff --git a/4ed_history.h b/4ed_history.h new file mode 100644 index 00000000..f811f7b1 --- /dev/null +++ b/4ed_history.h @@ -0,0 +1,66 @@ +/* + * Mr. 4th Dimention - Allen Webster + * + * 24.03.2018 + * + * History + * + */ + +// TOP + +#if !defined(FRED_HISTORY_H) +#define FRED_HISTORY_H + +struct Record_Batch_Slot{ + i32 length_forward; + i32 length_backward; + i32 first; +}; + +struct Record{ + Node node; + Temp_Memory_Arena_Light restore_point; + i32 edit_number; + Record_Kind kind; + union{ + struct{ + char *str_forward; + char *str_backward; + i32 length_forward; + i32 length_backward; + i32 first; + } single; + + struct{ + Buffer_Batch_Edit_Type type; + i32 count; + char *str_base_forward; + char *str_base_backward; + Record_Batch_Slot *batch_records; + } batch; + + struct{ + Node children; + i32 count; + } group; + }; +}; + +struct History{ + b32 activated; + Arena arena; + Memory_Bank bank; + Node free_records; + Node records; + i32 record_count; +}; + +struct Global_History{ + i32 edit_number_counter; + i32 edit_grouping_counter; +}; + +#endif + +// BOTTOM diff --git a/4ed_math.h b/4ed_math.h index 555d1f13..87d20fc5 100644 --- a/4ed_math.h +++ b/4ed_math.h @@ -838,7 +838,7 @@ fits_inside(i32_Rect rect, i32_Rect outer){ return(rect.x0 >= outer.x0 && rect.x1 <= outer.x1 && rect.y0 >= outer.y0 && rect.y1 <= outer.y1); } -static int32_t +internal int32_t interval_overlap(float a0, float a1, float b0, float b1){ if ((a0 <= b0 && b0 < a1) || (b0 <= a0 && a0 < b1)){ return(true); @@ -846,7 +846,7 @@ interval_overlap(float a0, float a1, float b0, float b1){ return(false); } -static int32_t +internal int32_t rect_opverlap(f32_Rect a, f32_Rect b){ if (interval_overlap(a.x0, a.x1, b.x0, b.x1) && interval_overlap(a.y0, a.y1, b.y0, b.y1)){ diff --git a/4ed_memory_bank.cpp b/4ed_memory_bank.cpp new file mode 100644 index 00000000..4f0c3d14 --- /dev/null +++ b/4ed_memory_bank.cpp @@ -0,0 +1,54 @@ +/* +* Mr. 4th Dimention - Allen Webster +* +* 07.02.2019 +* +* Memory bank wrapper for heap +* +*/ + +// TOP + +internal void +memory_bank_init(Memory_Bank *mem_bank){ + heap_init(&mem_bank->heap); + mem_bank->first = 0; + mem_bank->last = 0; + mem_bank->total_memory_size = 0; +} + +internal void* +memory_bank_allocate(Heap *heap, Memory_Bank *mem_bank, i32 size){ + void *ptr = heap_allocate(&mem_bank->heap, size); + if (ptr == 0){ + i32 alloc_size = clamp_bottom(4096, size*4 + sizeof(Memory_Header)); + void *new_block = heap_allocate(heap, alloc_size); + if (new_block != 0){ + Memory_Header *header = (Memory_Header*)new_block; + sll_push(mem_bank->first, mem_bank->last, header); + mem_bank->total_memory_size += alloc_size; + heap_extend(&mem_bank->heap, header + 1, alloc_size - sizeof(*header)); + ptr = heap_allocate(&mem_bank->heap, size); + } + } + return(ptr); +} + +internal void +memory_bank_free(Memory_Bank *mem_bank, void *ptr){ + heap_free(&mem_bank->heap, ptr); +} + +internal void +memory_bank_free_all(Heap *heap, Memory_Bank *mem_bank){ + for (Memory_Header *header = mem_bank->first, *next = 0; + header != 0; + header = next){ + next = header->next; + heap_free(heap, header); + } + mem_bank->total_memory_size = 0; +} + +// BOTTOM + diff --git a/4ed_memory_bank.h b/4ed_memory_bank.h new file mode 100644 index 00000000..728e1d76 --- /dev/null +++ b/4ed_memory_bank.h @@ -0,0 +1,29 @@ +/* +* Mr. 4th Dimention - Allen Webster +* +* 07.02.2019 +* +* Memory bank wrapper for heap +* +*/ + +// TOP + +#if !defined(FRED_MEMORY_BANK_H) +#define FRED_MEMORY_BANK_H + +struct Memory_Header{ + Memory_Header *next; +}; + +struct Memory_Bank{ + Heap heap; + Memory_Header *first; + Memory_Header *last; + umem total_memory_size; +}; + +#endif + +// BOTTOM + diff --git a/4ed_undo.cpp b/4ed_undo.cpp deleted file mode 100644 index 4435cdb9..00000000 --- a/4ed_undo.cpp +++ /dev/null @@ -1,456 +0,0 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 24.03.2018 - * - * Undo - * - */ - -// TOP - -internal void -undo_stack_grow_string(Heap *heap, Edit_Stack *stack, i32 extra_size){ - i32 old_max = stack->max; - u8 *old_str = stack->strings; - i32 new_max = old_max*2 + extra_size; - u8 *new_str = heap_array(heap, u8, new_max); - memcpy(new_str, old_str, sizeof(*new_str)*old_max); - heap_free(heap, old_str); - stack->strings = new_str; - stack->max = new_max; -} - -internal void -undo_stack_grow_edits(Heap *heap, Edit_Stack *stack){ - i32 old_max = stack->edit_max; - Edit_Step *old_eds = stack->edits; - i32 new_max = old_max*2 + 2; - Edit_Step *new_eds = heap_array(heap, Edit_Step, new_max); - memcpy(new_eds, old_eds, sizeof(*new_eds)*old_max); - heap_free(heap, old_eds); - stack->edits = new_eds; - stack->edit_max = new_max; -} - -internal void -child_stack_grow_string(Heap *heap, Small_Edit_Stack *stack, i32 extra_size){ - i32 old_max = stack->max; - u8 *old_str = stack->strings; - i32 new_max = old_max*2 + extra_size; - u8 *new_str = heap_array(heap, u8, new_max); - memcpy(new_str, old_str, sizeof(*new_str)*old_max); - heap_free(heap, old_str); - stack->strings = new_str; - stack->max = new_max; -} - -internal void -child_stack_grow_edits(Heap *heap, Small_Edit_Stack *stack, i32 amount){ - i32 old_max = stack->edit_max; - Buffer_Edit *old_eds = stack->edits; - i32 new_max = old_max*2 + amount; - Buffer_Edit *new_eds = heap_array(heap, Buffer_Edit, new_max); - memcpy(new_eds, old_eds, sizeof(*new_eds)*new_max); - heap_free(heap, old_eds); - stack->edits = new_eds; - stack->edit_max = new_max; -} - -internal i32 -undo_children_push(Heap *heap, Small_Edit_Stack *children, Buffer_Edit *edits, i32 edit_count, u8 *strings, i32 string_size){ - i32 result = children->edit_count; - if (children->edit_count + edit_count > children->edit_max){ - child_stack_grow_edits(heap, children, edit_count); - } - - if (children->size + string_size > children->max){ - child_stack_grow_string(heap, children, string_size); - } - - memcpy(children->edits + children->edit_count, edits, edit_count*sizeof(Buffer_Edit)); - memcpy(children->strings + children->size, strings, string_size); - - Buffer_Edit *edit = children->edits + children->edit_count; - i32 start_pos = children->size; - for (i32 i = 0; i < edit_count; ++i, ++edit){ - edit->str_start += start_pos; - } - - children->edit_count += edit_count; - children->size += string_size; - - return result; -} - -internal Edit_Step* -file_post_undo(Heap *heap, Editing_File *file, Edit_Step step, b32 do_merge, b32 can_merge){ - if (step.type == ED_NORMAL){ - file->state.undo.redo.size = 0; - file->state.undo.redo.edit_count = 0; - } - - Edit_Stack *undo = &file->state.undo.undo; - Edit_Step *result = 0; - - if (step.child_count == 0){ - if (step.edit.end - step.edit.start + undo->size > undo->max){ - undo_stack_grow_string(heap, undo, step.edit.end - step.edit.start); - } - - Buffer_Edit inv; - buffer_invert_edit(&file->state.buffer, step.edit, &inv, (char*)undo->strings, &undo->size, undo->max); - - Edit_Step inv_step = {}; - inv_step.edit = inv; - inv_step.can_merge = (b8)can_merge; - inv_step.type = ED_UNDO; - - b32 did_merge = 0; - if (do_merge && undo->edit_count > 0){ - Edit_Step prev = undo->edits[undo->edit_count-1]; - if (prev.can_merge && inv_step.edit.len == 0 && prev.edit.len == 0){ - if (prev.edit.end == inv_step.edit.start){ - did_merge = 1; - inv_step.edit.start = prev.edit.start; - } - } - } - - if (did_merge){ - result = undo->edits + (undo->edit_count-1); - *result = inv_step; - } - else{ - if (undo->edit_count == undo->edit_max){ - undo_stack_grow_edits(heap, undo); - } - - result = undo->edits + (undo->edit_count++); - *result = inv_step; - } - } - else{ - Edit_Step inv_step = {}; - inv_step.type = ED_UNDO; - inv_step.first_child = step.inverse_first_child; - inv_step.inverse_first_child = step.first_child; - inv_step.special_type = step.special_type; - inv_step.child_count = step.inverse_child_count; - inv_step.inverse_child_count = step.child_count; - - if (undo->edit_count == undo->edit_max){ - undo_stack_grow_edits(heap, undo); - } - result = undo->edits + (undo->edit_count++); - *result = inv_step; - } - return result; -} - -internal void -undo_stack_pop(Edit_Stack *stack){ - if (stack->edit_count > 0){ - Edit_Step *edit = stack->edits + (--stack->edit_count); - if (edit->child_count == 0){ - stack->size -= edit->edit.len; - } - } -} - -internal void -file_post_redo(Heap *heap, Editing_File *file, Edit_Step step){ - Edit_Stack *redo = &file->state.undo.redo; - - if (step.child_count == 0){ - if (step.edit.end - step.edit.start + redo->size > redo->max){ - undo_stack_grow_string(heap, redo, step.edit.end - step.edit.start); - } - - Buffer_Edit inv; - buffer_invert_edit(&file->state.buffer, step.edit, &inv, (char*)redo->strings, &redo->size, redo->max); - - Edit_Step inv_step = {}; - inv_step.edit = inv; - inv_step.type = ED_REDO; - - if (redo->edit_count == redo->edit_max){ - undo_stack_grow_edits(heap, redo); - } - redo->edits[redo->edit_count++] = inv_step; - } - else{ - Edit_Step inv_step = {}; - inv_step.type = ED_REDO; - inv_step.first_child = step.inverse_first_child; - inv_step.inverse_first_child = step.first_child; - inv_step.special_type = step.special_type; - inv_step.child_count = step.inverse_child_count; - inv_step.inverse_child_count = step.child_count; - - if (redo->edit_count == redo->edit_max){ - undo_stack_grow_edits(heap, redo); - } - redo->edits[redo->edit_count++] = inv_step; - } -} - -internal void -file_post_history_block(Editing_File *file, i32 pos){ - Assert(file->state.undo.history_head_block < pos); - Assert(pos < file->state.undo.history.edit_count); - - Edit_Step *history = file->state.undo.history.edits; - Edit_Step *step = history + file->state.undo.history_head_block; - step->next_block = pos; - step = history + pos; - step->prev_block = file->state.undo.history_head_block; - file->state.undo.history_head_block = pos; - ++file->state.undo.history_block_count; -} - -internal void -file_unpost_history_block(Editing_File *file){ - Assert(file->state.undo.history_block_count > 1); - --file->state.undo.history_block_count; - Edit_Step *old_head = file->state.undo.history.edits + file->state.undo.history_head_block; - file->state.undo.history_head_block = old_head->prev_block; -} - -internal Edit_Step* -file_post_history(Heap *heap, Editing_File *file, Edit_Step step, b32 do_merge, b32 can_merge){ - Edit_Stack *history = &file->state.undo.history; - Edit_Step *result = 0; - - local_persist Edit_Type reverse_types[4]; - if (reverse_types[ED_UNDO] == 0){ - reverse_types[ED_NORMAL] = ED_REVERSE_NORMAL; - reverse_types[ED_REVERSE_NORMAL] = ED_NORMAL; - reverse_types[ED_UNDO] = ED_REDO; - reverse_types[ED_REDO] = ED_UNDO; - } - - if (step.child_count == 0){ - if (step.edit.end - step.edit.start + history->size > history->max){ - undo_stack_grow_string(heap, history, step.edit.end - step.edit.start); - } - - Buffer_Edit inv; - buffer_invert_edit(&file->state.buffer, step.edit, &inv, - (char*)history->strings, &history->size, history->max); - - Edit_Step inv_step = {}; - inv_step.edit = inv; - inv_step.can_merge = (b8)can_merge; - inv_step.type = reverse_types[step.type]; - - b32 did_merge = 0; - if (do_merge && history->edit_count > 0){ - Edit_Step prev = history->edits[history->edit_count-1]; - if (prev.can_merge && inv_step.edit.len == 0 && prev.edit.len == 0){ - if (prev.edit.end == inv_step.edit.start){ - did_merge = 1; - inv_step.edit.start = prev.edit.start; - } - } - } - - if (did_merge){ - result = history->edits + (history->edit_count-1); - } - else{ - if (history->edit_count == history->edit_max){ - undo_stack_grow_edits(heap, history); - } - result = history->edits + (history->edit_count++); - } - - *result = inv_step; - } - else{ - Edit_Step inv_step = {}; - inv_step.type = reverse_types[step.type]; - inv_step.first_child = step.inverse_first_child; - inv_step.inverse_first_child = step.first_child; - inv_step.special_type = step.special_type; - inv_step.inverse_child_count = step.child_count; - inv_step.child_count = step.inverse_child_count; - - if (history->edit_count == history->edit_max){ - undo_stack_grow_edits(heap, history); - } - result = history->edits + (history->edit_count++); - *result = inv_step; - } - - return(result); -} - -internal void -file_update_history_before_edit(Mem_Options *mem, Editing_File *file, Edit_Step step, u8 *str, History_Mode history_mode){ - if (!file->state.undo.undo.edits) return; - Heap *heap = &mem->heap; - - b32 can_merge = 0, do_merge = 0; - switch (step.type){ - case ED_NORMAL: - { - if (step.edit.len == 1 && str && char_is_alpha_numeric(*str)){ - can_merge = 1; - } - if (step.edit.len == 1 && str && (can_merge || char_is_whitespace(*str))){ - do_merge = 1; - } - - if (history_mode != hist_forward){ - file_post_history(heap, file, step, do_merge, can_merge); - } - - file_post_undo(heap, file, step, do_merge, can_merge); - }break; - - case ED_REVERSE_NORMAL: - { - if (history_mode != hist_forward){ - file_post_history(heap, file, step, do_merge, can_merge); - } - - undo_stack_pop(&file->state.undo.undo); - - b32 restore_redos = 0; - Edit_Step *redo_end = 0; - - if (history_mode == hist_backward && file->state.undo.edit_history_cursor > 0){ - restore_redos = 1; - redo_end = file->state.undo.history.edits + (file->state.undo.edit_history_cursor - 1); - } - else if (history_mode == hist_forward && file->state.undo.history.edit_count > 0){ - restore_redos = 1; - redo_end = file->state.undo.history.edits + (file->state.undo.history.edit_count - 1); - } - - if (restore_redos){ - Edit_Step *redo_start = redo_end; - i32 steps_of_redo = 0; - i32 strings_of_redo = 0; - { - i32 undo_count = 0; - while (redo_start->type == ED_REDO || redo_start->type == ED_UNDO){ - if (redo_start->type == ED_REDO){ - if (undo_count > 0){ - --undo_count; - } - else{ - ++steps_of_redo; - strings_of_redo += redo_start->edit.len; - } - } - else{ - ++undo_count; - } - --redo_start; - } - } - - if (redo_start < redo_end){ - ++redo_start; - ++redo_end; - - if (file->state.undo.redo.edit_count + steps_of_redo > file->state.undo.redo.edit_max) - undo_stack_grow_edits(heap, &file->state.undo.redo); - - if (file->state.undo.redo.size + strings_of_redo > file->state.undo.redo.max) - undo_stack_grow_string(heap, &file->state.undo.redo, strings_of_redo); - - u8 *str_src = file->state.undo.history.strings + redo_end->edit.str_start; - u8 *str_dest_base = file->state.undo.redo.strings; - i32 str_redo_pos = file->state.undo.redo.size + strings_of_redo; - - Edit_Step *edit_src = redo_end; - Edit_Step *edit_dest = file->state.undo.redo.edits + file->state.undo.redo.edit_count + steps_of_redo; - - { - i32 undo_count = 0; - for (i32 i = 0; i < steps_of_redo;){ - --edit_src; - str_src -= edit_src->edit.len; - if (edit_src->type == ED_REDO){ - if (undo_count > 0){ - --undo_count; - } - else{ - ++i; - - --edit_dest; - *edit_dest = *edit_src; - - str_redo_pos -= edit_dest->edit.len; - edit_dest->edit.str_start = str_redo_pos; - - memcpy(str_dest_base + str_redo_pos, str_src, edit_dest->edit.len); - } - } - else{ - ++undo_count; - } - } - Assert(undo_count == 0); - } - - file->state.undo.redo.size += strings_of_redo; - file->state.undo.redo.edit_count += steps_of_redo; - } - } - }break; - - case ED_UNDO: - { - if (history_mode != hist_forward){ - file_post_history(heap, file, step, do_merge, can_merge); - } - file_post_redo(heap, file, step); - undo_stack_pop(&file->state.undo.undo); - }break; - - case ED_REDO: - { - if (step.edit.len == 1 && str && char_is_alpha_numeric(*str)) can_merge = 1; - if (step.edit.len == 1 && str && (can_merge || char_is_whitespace(*str))) do_merge = 1; - - if (history_mode != hist_forward){ - file_post_history(heap, file, step, do_merge, can_merge); - } - - file_post_undo(heap, file, step, do_merge, can_merge); - undo_stack_pop(&file->state.undo.redo); - }break; - } - - if (history_mode != hist_forward){ - if (step.type == ED_UNDO || step.type == ED_REDO){ - if (file->state.undo.current_block_normal){ - file_post_history_block(file, file->state.undo.history.edit_count - 1); - file->state.undo.current_block_normal = 0; - } - } - else{ - if (!file->state.undo.current_block_normal){ - file_post_history_block(file, file->state.undo.history.edit_count - 1); - file->state.undo.current_block_normal = 1; - } - } - } - else{ - if (file->state.undo.history_head_block == file->state.undo.history.edit_count){ - file_unpost_history_block(file); - file->state.undo.current_block_normal = !file->state.undo.current_block_normal; - } - } - - if (history_mode == hist_normal){ - file->state.undo.edit_history_cursor = file->state.undo.history.edit_count; - } -} - -// BOTTOM - diff --git a/4ed_undo.h b/4ed_undo.h deleted file mode 100644 index 9f7fc81e..00000000 --- a/4ed_undo.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 24.01.2018 - * - * Buffer types - * - */ - -// TOP - -#if !defined(FRED_UNDO_H) -#define FRED_UNDO_H - -enum Edit_Type{ - ED_NORMAL, - ED_REVERSE_NORMAL, - ED_UNDO, - ED_REDO, -}; - -struct Edit_Step{ - Edit_Type type; - union{ - struct{ - b32 can_merge; - Buffer_Edit edit; - i32 next_block; - i32 prev_block; - }; - struct{ - i32 first_child; - i32 inverse_first_child; - i32 inverse_child_count; - i32 special_type; - }; - }; - i32 child_count; -}; - -struct Edit_Stack{ - u8 *strings; - i32 size; - i32 max; - Edit_Step *edits; - i32 edit_count; - i32 edit_max; -}; - -struct Small_Edit_Stack{ - u8 *strings; - i32 size; - i32 max; - Buffer_Edit *edits; - i32 edit_count; - i32 edit_max; -}; - -struct Undo_Data{ - Edit_Stack undo; - Edit_Stack redo; - Edit_Stack history; - Small_Edit_Stack children; - - i32 history_block_count; - i32 history_head_block; - i32 edit_history_cursor; - b32 current_block_normal; -}; - -#endif - -// BOTTOM diff --git a/4ed_view.h b/4ed_view.h index ec2dd255..0b2707b0 100644 --- a/4ed_view.h +++ b/4ed_view.h @@ -114,11 +114,6 @@ struct Shift_Information{ i32 amount; }; -struct Edit_Spec{ - u8 *str; - Edit_Step step; -}; - struct Relative_Scrolling{ f32 scroll_x; f32 scroll_y; @@ -126,20 +121,6 @@ struct Relative_Scrolling{ f32 target_y; }; -struct Cursor_Fix_Descriptor{ - b32 is_batch; - union{ - struct{ - Buffer_Edit *batch; - i32 batch_size; - }; - struct{ - i32 start, end; - i32 shift_amount; - }; - }; -}; - struct File_Bar{ f32 pos_x; f32 pos_y; @@ -196,13 +177,6 @@ enum{ FileCreateFlag_ReadOnly = 1, }; -typedef i32 History_Mode; -enum{ - hist_normal, - hist_backward, - hist_forward -}; - struct Render_Marker{ Marker_Visual_Type type; u32 color;