435 lines
9.2 KiB
C++
435 lines
9.2 KiB
C++
|
/*
|
||
|
* Mr. 4th Dimention - Allen Webster
|
||
|
*
|
||
|
* 03.01.2017
|
||
|
*
|
||
|
* File layer for 4coder
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
// TOP
|
||
|
|
||
|
//
|
||
|
// Edit Position Basics
|
||
|
//
|
||
|
|
||
|
enum Edit_Pos_Set_Type{
|
||
|
EditPos_None,
|
||
|
EditPos_CursorSet,
|
||
|
EditPos_ScrollSet
|
||
|
};
|
||
|
struct File_Edit_Positions{
|
||
|
GUI_Scroll_Vars scroll;
|
||
|
Full_Cursor cursor;
|
||
|
i32 mark;
|
||
|
f32 preferred_x;
|
||
|
i32 scroll_i;
|
||
|
i32 last_set_type;
|
||
|
b32 in_view;
|
||
|
};
|
||
|
static File_Edit_Positions null_edit_pos = {0};
|
||
|
|
||
|
internal void
|
||
|
edit_pos_set_cursor(File_Edit_Positions *edit_pos, Full_Cursor cursor, b32 set_preferred_x, b32 unwrapped_lines){
|
||
|
edit_pos->cursor = cursor;
|
||
|
if (set_preferred_x){
|
||
|
edit_pos->preferred_x = cursor.wrapped_x;
|
||
|
if (unwrapped_lines){
|
||
|
edit_pos->preferred_x = cursor.unwrapped_x;
|
||
|
}
|
||
|
}
|
||
|
edit_pos->last_set_type = EditPos_CursorSet;
|
||
|
}
|
||
|
|
||
|
internal void
|
||
|
edit_pos_set_scroll(File_Edit_Positions *edit_pos, GUI_Scroll_Vars scroll){
|
||
|
edit_pos->scroll = scroll;
|
||
|
edit_pos->last_set_type = EditPos_ScrollSet;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Undo Basics
|
||
|
//
|
||
|
|
||
|
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, max;
|
||
|
|
||
|
Edit_Step *edits;
|
||
|
i32 edit_count, edit_max;
|
||
|
};
|
||
|
|
||
|
struct Small_Edit_Stack{
|
||
|
u8 *strings;
|
||
|
i32 size, max;
|
||
|
|
||
|
Buffer_Edit *edits;
|
||
|
i32 edit_count, edit_max;
|
||
|
};
|
||
|
|
||
|
struct Undo_Data{
|
||
|
Edit_Stack undo;
|
||
|
Edit_Stack redo;
|
||
|
Edit_Stack history;
|
||
|
Small_Edit_Stack children;
|
||
|
|
||
|
i32 history_block_count, history_head_block;
|
||
|
i32 edit_history_cursor;
|
||
|
b32 current_block_normal;
|
||
|
};
|
||
|
|
||
|
|
||
|
//
|
||
|
// Highlighting Information
|
||
|
//
|
||
|
|
||
|
struct Text_Effect{
|
||
|
i32 start, end;
|
||
|
u32 color;
|
||
|
f32 seconds_down, seconds_max;
|
||
|
};
|
||
|
|
||
|
|
||
|
//
|
||
|
// Editing_File
|
||
|
//
|
||
|
|
||
|
struct Editing_File_Settings{
|
||
|
i32 base_map_id;
|
||
|
i32 display_width;
|
||
|
i32 minimum_base_display_width;
|
||
|
i32 wrap_indicator;
|
||
|
b32 dos_write_mode;
|
||
|
b32 virtual_white;
|
||
|
i16 font_id;
|
||
|
b8 unwrapped_lines;
|
||
|
b8 tokens_exist;
|
||
|
b8 is_initialized;
|
||
|
b8 unimportant;
|
||
|
b8 read_only;
|
||
|
b8 never_kill;
|
||
|
};
|
||
|
static Editing_File_Settings null_editing_file_settings = {0};
|
||
|
|
||
|
struct Editing_File_State{
|
||
|
Buffer_Type buffer;
|
||
|
|
||
|
i32 *wrap_line_index;
|
||
|
i32 wrap_max;
|
||
|
|
||
|
i32 *character_starts;
|
||
|
i32 character_start_max;
|
||
|
|
||
|
f32 *line_indents;
|
||
|
i32 line_indent_max;
|
||
|
|
||
|
i32 wrap_line_count;
|
||
|
|
||
|
i32 *wrap_positions;
|
||
|
i32 wrap_position_count;
|
||
|
i32 wrap_position_max;
|
||
|
|
||
|
Undo_Data undo;
|
||
|
|
||
|
Cpp_Token_Array token_array;
|
||
|
Cpp_Token_Array swap_array;
|
||
|
u32 lex_job;
|
||
|
b32 tokens_complete;
|
||
|
b32 still_lexing;
|
||
|
|
||
|
Text_Effect paste_effect;
|
||
|
|
||
|
Dirty_State dirty;
|
||
|
u32 ignore_behind_os;
|
||
|
|
||
|
File_Edit_Positions edit_pos_space[16];
|
||
|
File_Edit_Positions *edit_poss[16];
|
||
|
i32 edit_poss_count;
|
||
|
};
|
||
|
static Editing_File_State null_editing_file_state = {0};
|
||
|
|
||
|
struct Editing_File_Name{
|
||
|
char live_name_[256];
|
||
|
char source_path_[256];
|
||
|
char extension_[16];
|
||
|
String live_name;
|
||
|
String source_path;
|
||
|
String extension;
|
||
|
};
|
||
|
|
||
|
struct Editing_File_Canon_Name{
|
||
|
char name_[256];
|
||
|
String name;
|
||
|
};
|
||
|
|
||
|
struct File_Node{
|
||
|
File_Node *next, *prev;
|
||
|
};
|
||
|
|
||
|
union Buffer_Slot_ID{
|
||
|
i32 id;
|
||
|
i16 part[2];
|
||
|
};
|
||
|
|
||
|
inline Buffer_Slot_ID
|
||
|
to_file_id(i32 id){
|
||
|
Buffer_Slot_ID result;
|
||
|
result.id = id;
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
struct Editing_File{
|
||
|
// NOTE(allen): node must be the first member of Editing_File!
|
||
|
File_Node node;
|
||
|
Editing_File_Settings settings;
|
||
|
struct{
|
||
|
b32 is_loading;
|
||
|
b32 is_dummy;
|
||
|
Editing_File_State state;
|
||
|
};
|
||
|
Editing_File_Name name;
|
||
|
Editing_File_Canon_Name canon;
|
||
|
Buffer_Slot_ID id;
|
||
|
u64 unique_buffer_id;
|
||
|
};
|
||
|
static Editing_File null_editing_file = {0};
|
||
|
|
||
|
|
||
|
//
|
||
|
// Manipulating a file's Edit_Pos array
|
||
|
//
|
||
|
|
||
|
internal i32
|
||
|
edit_pos_get_index(Editing_File *file, File_Edit_Positions *edit_pos){
|
||
|
i32 edit_pos_index = -1;
|
||
|
|
||
|
i32 count = file->state.edit_poss_count;
|
||
|
File_Edit_Positions **edit_poss = file->state.edit_poss;
|
||
|
for (i32 i = 0; i < count; ++i){
|
||
|
if (edit_poss[i] == edit_pos){
|
||
|
edit_pos_index = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(edit_pos_index);
|
||
|
}
|
||
|
|
||
|
internal b32
|
||
|
edit_pos_move_to_front(Editing_File *file, File_Edit_Positions *edit_pos){
|
||
|
b32 result = false;
|
||
|
|
||
|
if (file && edit_pos){
|
||
|
i32 edit_pos_index = edit_pos_get_index(file, edit_pos);
|
||
|
Assert(edit_pos_index != -1);
|
||
|
|
||
|
File_Edit_Positions **edit_poss = file->state.edit_poss;
|
||
|
|
||
|
memmove(edit_poss + 1, edit_poss, edit_pos_index*sizeof(*edit_poss));
|
||
|
|
||
|
edit_poss[0] = edit_pos;
|
||
|
result = true;
|
||
|
}
|
||
|
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal b32
|
||
|
edit_pos_unset(Editing_File *file, File_Edit_Positions *edit_pos){
|
||
|
b32 result = false;
|
||
|
|
||
|
if (file && edit_pos){
|
||
|
i32 edit_pos_index = edit_pos_get_index(file, edit_pos);
|
||
|
Assert(edit_pos_index != -1);
|
||
|
|
||
|
i32 count = file->state.edit_poss_count;
|
||
|
File_Edit_Positions **edit_poss = file->state.edit_poss;
|
||
|
|
||
|
memmove(edit_poss + edit_pos_index,
|
||
|
edit_poss + edit_pos_index + 1,
|
||
|
(count - edit_pos_index - 1)*sizeof(*edit_poss));
|
||
|
|
||
|
edit_pos->in_view = false;
|
||
|
|
||
|
if (file->state.edit_poss_count > 1){
|
||
|
file->state.edit_poss_count -= 1;
|
||
|
}
|
||
|
result = true;
|
||
|
}
|
||
|
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
internal File_Edit_Positions*
|
||
|
edit_pos_get_new(Editing_File *file, i32 index){
|
||
|
File_Edit_Positions *result = 0;
|
||
|
|
||
|
if (file && 0 <= index && index < 16){
|
||
|
result = file->state.edit_pos_space + index;
|
||
|
i32 edit_pos_index = edit_pos_get_index(file, result);
|
||
|
|
||
|
if (edit_pos_index == -1){
|
||
|
File_Edit_Positions **edit_poss = file->state.edit_poss;
|
||
|
i32 count = file->state.edit_poss_count;
|
||
|
|
||
|
if (count > 0){
|
||
|
if (edit_poss[0]->in_view){
|
||
|
memcpy(result, edit_poss[0], sizeof(*result));
|
||
|
memmove(edit_poss+1, edit_poss, sizeof(*edit_poss)*count);
|
||
|
file->state.edit_poss_count = count + 1;
|
||
|
}
|
||
|
else{
|
||
|
Assert(count == 1);
|
||
|
memcpy(result, edit_poss[0], sizeof(*result));
|
||
|
}
|
||
|
}
|
||
|
else{
|
||
|
memset(result, 0, sizeof(*result));
|
||
|
file->state.edit_poss_count = 1;
|
||
|
}
|
||
|
|
||
|
edit_poss[0] = result;
|
||
|
}
|
||
|
|
||
|
result->in_view = true;
|
||
|
}
|
||
|
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Cursor Seeking
|
||
|
//
|
||
|
|
||
|
inline Partial_Cursor
|
||
|
file_compute_cursor_from_pos(Editing_File *file, i32 pos){
|
||
|
Partial_Cursor result = buffer_partial_from_pos(&file->state.buffer, pos);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
inline Partial_Cursor
|
||
|
file_compute_cursor_from_line_character(Editing_File *file, i32 line, i32 character){
|
||
|
Partial_Cursor result = buffer_partial_from_line_character(&file->state.buffer, line, character);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
inline b32
|
||
|
file_compute_partial_cursor(Editing_File *file, Buffer_Seek seek, Partial_Cursor *cursor){
|
||
|
b32 result = 1;
|
||
|
switch (seek.type){
|
||
|
case buffer_seek_pos:
|
||
|
{
|
||
|
*cursor = file_compute_cursor_from_pos(file, seek.pos);
|
||
|
}break;
|
||
|
|
||
|
case buffer_seek_line_char:
|
||
|
{
|
||
|
*cursor = file_compute_cursor_from_line_character(file, seek.line, seek.character);
|
||
|
}break;
|
||
|
|
||
|
default:
|
||
|
{
|
||
|
result = 0;
|
||
|
}break;
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Dirty Flags
|
||
|
//
|
||
|
|
||
|
inline b32
|
||
|
buffer_needs_save(Editing_File *file){
|
||
|
b32 result = 0;
|
||
|
if (!file->settings.unimportant){
|
||
|
if (file->state.dirty == DirtyState_UnsavedChanges){
|
||
|
result = 1;
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
inline b32
|
||
|
buffer_can_save(Editing_File *file){
|
||
|
b32 result = 0;
|
||
|
if (!file->settings.unimportant){
|
||
|
if (file->state.dirty == DirtyState_UnsavedChanges ||
|
||
|
file->state.dirty == DirtyState_UnloadedChanges){
|
||
|
result = 1;
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
inline b32
|
||
|
file_is_ready(Editing_File *file){
|
||
|
b32 result = 0;
|
||
|
if (file && file->is_loading == 0){
|
||
|
result = 1;
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
inline void
|
||
|
file_set_to_loading(Editing_File *file){
|
||
|
file->state = null_editing_file_state;
|
||
|
file->settings = null_editing_file_settings;
|
||
|
file->is_loading = 1;
|
||
|
}
|
||
|
|
||
|
inline void
|
||
|
file_mark_clean(Editing_File *file){
|
||
|
if (file->state.dirty != DirtyState_UnloadedChanges){
|
||
|
file->state.dirty = DirtyState_UpToDate;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline void
|
||
|
file_mark_dirty(Editing_File *file){
|
||
|
if (file->state.dirty != DirtyState_UnloadedChanges){
|
||
|
file->state.dirty = DirtyState_UnsavedChanges;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline void
|
||
|
file_mark_behind_os(Editing_File *file){
|
||
|
file->state.dirty = DirtyState_UnloadedChanges;
|
||
|
}
|
||
|
|
||
|
inline Dirty_State
|
||
|
file_get_sync(Editing_File *file){
|
||
|
return (file->state.dirty);
|
||
|
}
|
||
|
|
||
|
|
||
|
// BOTTOM
|