Basics of new history system working:

master
Allen Webster 2019-02-08 02:03:48 -08:00
parent d0eb652ab1
commit 0482cd05fe
25 changed files with 1062 additions and 806 deletions

View File

@ -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);

View File

@ -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);
}
}
////////////////////////////////

View File

@ -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));}

View File

@ -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 },

View File

@ -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));

View File

@ -75,6 +75,11 @@ struct Temp_Memory_Arena{
i32_4tech pos;
};
struct Temp_Memory_Arena_Light{
Partition_Chained *part;
i32_4tech pos;
};
#endif
#endif

12
4ed.cpp
View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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"

View File

@ -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 = {};

View File

@ -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);

View File

@ -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;

View File

@ -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;
}
}

34
4ed_edit.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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;

262
4ed_history.cpp Normal file
View File

@ -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

66
4ed_history.h Normal file
View File

@ -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

View File

@ -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)){

54
4ed_memory_bank.cpp Normal file
View File

@ -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

29
4ed_memory_bank.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;