From 3ad0772662e9b66500950ff28ee9199bdba440e9 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Sat, 28 May 2016 23:12:12 -0400 Subject: [PATCH 01/34] win32 layer organization --- 4coder_default_bindings.cpp | 100 ++-------------- 4coder_default_view.cpp | 89 ++++++++++++++ 4ed_mem.cpp | 8 +- 4ed_system.h | 10 +- README.txt | 2 +- SUPERREADME.txt | 2 +- build_all.bat | 4 +- power/4coder_experiments.cpp | 7 +- win32_4ed.cpp | 225 ++++++++++++++++++++--------------- 9 files changed, 244 insertions(+), 203 deletions(-) create mode 100644 4coder_default_view.cpp diff --git a/4coder_default_bindings.cpp b/4coder_default_bindings.cpp index 0ca989ed..fb50d018 100644 --- a/4coder_default_bindings.cpp +++ b/4coder_default_bindings.cpp @@ -141,22 +141,24 @@ CUSTOM_COMMAND_SIG(open_my_files){ // any circumstance. push_parameter(app, par_name, literal("w:/4ed/data/test/basic.cpp")); exec_command(app, cmdid_interactive_open); - + +#if 0 exec_command(app, cmdid_change_active_panel); - + char my_file[256]; int my_file_len; - + my_file_len = sizeof("w:/4ed/data/test/basic.txt") - 1; for (int i = 0; i < my_file_len; ++i){ my_file[i] = ("w:/4ed/data/test/basic.txt")[i]; } - + // NOTE(allen|a3.1): null terminators are not needed for strings. push_parameter(app, par_name, my_file, my_file_len); exec_command(app, cmdid_interactive_open); - + exec_command(app, cmdid_change_active_panel); +#endif } CUSTOM_COMMAND_SIG(build_at_launch_location){ @@ -434,93 +436,7 @@ get_bindings(void *data, int size){ return(result); } -struct Custom_Vars{ - int initialized; - Partition part; -}; - -enum View_Mode{ - ViewMode_File, -}; - -struct View_Vars{ - int id; - View_Mode mode; - - GUI_Scroll_Vars scroll; - i32_Rect scroll_region; - - int buffer_id; -}; -inline View_Vars -view_vars_zero(){ - View_Vars vars = {0}; - return(vars); -} - -extern "C" void -view_routine(Application_Links *app, int view_id){ - Custom_Vars *vars = (Custom_Vars*)app->memory; - View_Vars view = {0}; - view.id = view_id; - - int show_scrollbar = 1; - - if (!vars->initialized){ - vars->initialized = 1; - vars->part = make_part(app->memory, app->memory_size); - push_struct(&vars->part, Custom_Vars); - } - - for(;;){ - Event_Message message = {0}; - message = app->get_event_message(app); - - switch (message.type){ - case EM_Open_View: - { - view = view_vars_zero(); - view.id = view_id; - }break; - - case EM_Frame: - { - GUI_Functions *guifn = app->get_gui_functions(app); - GUI *gui = app->get_gui(app, view_id); - - guifn->begin(gui); - guifn->top_bar(gui); - - switch (view.mode){ - case ViewMode_File: - // TODO(allen): Overlapped widget - GUI_id scroll_id; - scroll_id.id[1] = view.mode; - scroll_id.id[0] = view.buffer_id; - - guifn->get_scroll_vars(gui, scroll_id, &view.scroll, - &view.scroll_region); - guifn->begin_scrollable(gui, scroll_id, view.scroll, - 144.f, show_scrollbar); - guifn->file(gui, view.buffer_id); - guifn->end_scrollable(gui); - break; - } - - guifn->end(gui); - - // TODO(allen): Put this code in charge of dispatching - // to the command or command coroutine or whatever. - - // TODO(allen): Put this code in charge of when to process - // the GUI with input and retrieve new layout data. - }break; - - case EM_Close_View: - {}break; - } - } -} +#include "4coder_default_view.cpp" #endif diff --git a/4coder_default_view.cpp b/4coder_default_view.cpp new file mode 100644 index 00000000..122a2da3 --- /dev/null +++ b/4coder_default_view.cpp @@ -0,0 +1,89 @@ + +struct Custom_Vars{ + int initialized; + Partition part; +}; + +enum View_Mode{ + ViewMode_File, +}; + +struct View_Vars{ + int id; + View_Mode mode; + + GUI_Scroll_Vars scroll; + i32_Rect scroll_region; + + int buffer_id; +}; +inline View_Vars +view_vars_zero(){ + View_Vars vars = {0}; + return(vars); +} + +extern "C" void +view_routine(Application_Links *app, int view_id){ + Custom_Vars *vars = (Custom_Vars*)app->memory; + View_Vars view = {0}; + view.id = view_id; + + int show_scrollbar = 1; + + if (!vars->initialized){ + vars->initialized = 1; + vars->part = make_part(app->memory, app->memory_size); + push_struct(&vars->part, Custom_Vars); + } + + for(;;){ + Event_Message message = {0}; + message = app->get_event_message(app); + + switch (message.type){ + case EM_Open_View: + { + view = view_vars_zero(); + view.id = view_id; + }break; + + case EM_Frame: + { + GUI_Functions *guifn = app->get_gui_functions(app); + GUI *gui = app->get_gui(app, view_id); + + guifn->begin(gui); + guifn->top_bar(gui); + + switch (view.mode){ + case ViewMode_File: + // TODO(allen): Overlapped widget + GUI_id scroll_id; + scroll_id.id[1] = view.mode; + scroll_id.id[0] = view.buffer_id; + + guifn->get_scroll_vars(gui, scroll_id, &view.scroll, + &view.scroll_region); + guifn->begin_scrollable(gui, scroll_id, view.scroll, + 144.f, show_scrollbar); + guifn->file(gui, view.buffer_id); + guifn->end_scrollable(gui); + break; + } + + guifn->end(gui); + + // TODO(allen): Put this code in charge of dispatching + // to the command or command coroutine or whatever. + + // TODO(allen): Put this code in charge of when to process + // the GUI with input and retrieve new layout data. + }break; + + case EM_Close_View: + {}break; + } + } +} + diff --git a/4ed_mem.cpp b/4ed_mem.cpp index 535dbee8..72260d88 100644 --- a/4ed_mem.cpp +++ b/4ed_mem.cpp @@ -143,7 +143,9 @@ general_memory_attempt_merge(Bubble *left, Bubble *right){ internal void general_memory_free(General_Memory *general, void *memory){ Bubble *bubble = ((Bubble*)memory) - 1; - Assert((!FRED_INTERNAL) || (bubble->flags & MEM_BUBBLE_DEBUG_MASK) == MEM_BUBBLE_DEBUG); +#if FRED_INTERNAL + Assert((bubble->flags & MEM_BUBBLE_DEBUG_MASK) == MEM_BUBBLE_DEBUG); +#endif bubble->flags &= ~MEM_BUBBLE_USED; bubble->type = 0; Bubble *prev, *next; @@ -158,7 +160,9 @@ general_memory_reallocate(General_Memory *general, void *old, i32 old_size, i32 void *result = old; Bubble *bubble = ((Bubble*)old) - 1; bubble->type = type; - Assert((!FRED_INTERNAL) || (bubble->flags & MEM_BUBBLE_DEBUG_MASK) == MEM_BUBBLE_DEBUG); +#if FRED_INTERNAL + Assert((bubble->flags & MEM_BUBBLE_DEBUG_MASK) == MEM_BUBBLE_DEBUG); +#endif i32 additional_space = size - bubble->size; if (additional_space > 0){ Bubble *next = bubble->next; diff --git a/4ed_system.h b/4ed_system.h index 65e2dee7..a6ba628c 100644 --- a/4ed_system.h +++ b/4ed_system.h @@ -226,15 +226,15 @@ struct System_Functions{ System_File_Load_Begin *file_load_begin; System_File_Load_End *file_load_end; System_File_Save *file_save; - + // file system navigation (4coder_custom.h): 3 File_Exists_Function *file_exists; Directory_CD_Function *directory_cd; Get_4ed_Path_Function *get_4ed_path; - + // clipboard: 1 System_Post_Clipboard *post_clipboard; - + // time: 1 System_Time *time; @@ -249,14 +249,14 @@ struct System_Functions{ System_CLI_Begin_Update *cli_begin_update; System_CLI_Update_Step *cli_update_step; System_CLI_End_Update *cli_end_update; - + // threads: 5 System_Post_Job *post_job; System_Cancel_Job *cancel_job; System_Grow_Thread_Memory *grow_thread_memory; System_Acquire_Lock *acquire_lock; System_Release_Lock *release_lock; - + // debug: 3 INTERNAL_System_Sentinel *internal_sentinel; INTERNAL_System_Get_Thread_States *internal_get_thread_states; diff --git a/README.txt b/README.txt index 9d9b308d..5ca9b38e 100644 --- a/README.txt +++ b/README.txt @@ -1,4 +1,4 @@ -Distribution Date: 24.5.2016 (dd.mm.yyyy) +Distribution Date: 28.5.2016 (dd.mm.yyyy) Thank you for contributing to the 4coder project! diff --git a/SUPERREADME.txt b/SUPERREADME.txt index e25362cb..820ddefc 100644 --- a/SUPERREADME.txt +++ b/SUPERREADME.txt @@ -1,4 +1,4 @@ -Distribution Date: 24.5.2016 (dd.mm.yyyy) +Distribution Date: 28.5.2016 (dd.mm.yyyy) Thank you for contributing to the 4coder project! diff --git a/build_all.bat b/build_all.bat index bf8abcb0..a5873ee7 100644 --- a/build_all.bat +++ b/build_all.bat @@ -21,8 +21,8 @@ if %ERRORLEVEL% neq 0 (set FirstError=1) popd pushd ..\build -call "..\code\buildsuper.bat" ..\code\4coder_default_bindings.cpp -REM call "..\code\buildsuper.bat" ..\code\power\4coder_experiments.cpp +REM call "..\code\buildsuper.bat" ..\code\4coder_default_bindings.cpp +call "..\code\buildsuper.bat" ..\code\power\4coder_experiments.cpp REM call "..\code\buildsuper.bat" ..\code\power\4coder_casey.cpp if %ERRORLEVEL% neq 0 (set FirstError=1) diff --git a/power/4coder_experiments.cpp b/power/4coder_experiments.cpp index 81bb017e..0bbe9361 100644 --- a/power/4coder_experiments.cpp +++ b/power/4coder_experiments.cpp @@ -4,6 +4,8 @@ #define NO_BINDING #include "../4coder_default_bindings.cpp" +#include + CUSTOM_COMMAND_SIG(kill_rect){ View_Summary view = app->get_active_view(app); Buffer_Summary buffer = app->get_buffer(app, view.buffer_id); @@ -377,10 +379,7 @@ get_bindings(void *data, int size){ return(result); } -extern "C" void -view_routine(Application_Links *app, int view_id){ - app->get_user_input(app, 0, 0); -} +#include "..\4coder_default_view.cpp" // BOTTOM diff --git a/win32_4ed.cpp b/win32_4ed.cpp index 0710504c..3418f73e 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -200,7 +200,7 @@ Win32Ptr(void *h){ } // -// System Layer Memory +// Memory (not exposed to application, but needed in system_shared.cpp) // #if FRED_INTERNAL @@ -273,7 +273,7 @@ INTERNAL_system_debug_message(char *message){ #endif // -// Platform Layer File Services +// File // internal @@ -388,8 +388,7 @@ Sys_File_Save_Sig(system_file_save){ internal Sys_File_Time_Stamp_Sig(system_file_time_stamp){ - u64 result; - result = 0; + u64 result = 0; FILETIME last_write; WIN32_FILE_ATTRIBUTE_DATA data; @@ -539,6 +538,7 @@ Sys_File_Unique_Hash_Sig(system_file_unique_hash){ return(hash); } +// NOTE(allen): Exposed to the custom layer. internal FILE_EXISTS_SIG(system_file_exists){ char full_filename_space[1024]; @@ -571,6 +571,7 @@ b32 Win32DirectoryExists(char *path){ (attrib & FILE_ATTRIBUTE_DIRECTORY)); } +// NOTE(allen): Exposed to the custom layer. internal DIRECTORY_CD_SIG(system_directory_cd){ String directory = make_string(dir, *len, capacity); @@ -618,11 +619,16 @@ Sys_Get_Binary_Path_Sig(system_get_binary_path){ return(result); } +// NOTE(allen): Exposed to the custom layer. GET_4ED_PATH_SIG(system_get_4ed_path){ String str = make_string(out, 0, capacity); return(system_get_binary_path(&str)); } +// +// Clipboard +// + internal Sys_Post_Clipboard_Sig(system_post_clipboard){ if (OpenClipboard(win32vars.window_handle)){ @@ -640,6 +646,10 @@ Sys_Post_Clipboard_Sig(system_post_clipboard){ } } +// +// Multithreading +// + internal Sys_Acquire_Lock_Sig(system_acquire_lock){ WaitForSingleObject(win32vars.locks[id], INFINITE); @@ -650,38 +660,7 @@ Sys_Release_Lock_Sig(system_release_lock){ ReleaseSemaphore(win32vars.locks[id], 1, 0); } -internal void -Win32SetCursorFromUpdate(Application_Mouse_Cursor cursor){ - switch (cursor){ - case APP_MOUSE_CURSOR_ARROW: - SetCursor(win32vars.cursor_arrow); break; - - case APP_MOUSE_CURSOR_IBEAM: - SetCursor(win32vars.cursor_ibeam); break; - - case APP_MOUSE_CURSOR_LEFTRIGHT: - SetCursor(win32vars.cursor_leftright); break; - - case APP_MOUSE_CURSOR_UPDOWN: - SetCursor(win32vars.cursor_updown); break; - } -} - -internal void -Win32Resize(i32 width, i32 height){ - if (width > 0 && height > 0){ - glViewport(0, 0, width, height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, width, height, 0, -1, 1); - glScissor(0, 0, width, height); - - win32vars.target.width = width; - win32vars.target.height = height; - } -} - -internal DWORD WINAPI +internal DWORD JobThreadProc(LPVOID lpParameter){ Thread_Context *thread = (Thread_Context*)lpParameter; Work_Queue *queue = thread->queue; @@ -766,6 +745,8 @@ Sys_Post_Job_Sig(system_post_job){ return result; } +// TODO(allen): I would like to get rid of job canceling +// but I still don't know what exactly I would do without it. internal Sys_Cancel_Job_Sig(system_cancel_job){ Work_Queue *queue = exchange_vars.thread.queues + group_id; @@ -829,6 +810,10 @@ INTERNAL_get_thread_states(Thread_Group_ID id, bool8 *running, i32 *pending){ } #endif +// +// Coroutine +// + internal Win32_Coroutine* Win32AllocCoroutine(){ Win32_Coroutine *result = win32vars.coroutine_free; @@ -919,6 +904,10 @@ Sys_Yield_Coroutine_Sig(system_yield_coroutine){ SwitchToFiber(coroutine->yield_handle); } +// +// Command Line Exectuion +// + internal Sys_CLI_Call_Sig(system_cli_call){ char cmd[] = "c:\\windows\\system32\\cmd.exe"; @@ -1060,6 +1049,40 @@ Sys_CLI_End_Update_Sig(system_cli_end_update){ return close_me; } + +#include "system_shared.cpp" +#include "4ed_rendering.cpp" + +internal +Font_Load_Sig(system_draw_font_load){ + if (win32vars.font_part.base == 0){ + win32vars.font_part = Win32ScratchPartition(Mbytes(8)); + } + + i32 oversample = 2; + + for (b32 success = 0; success == 0;){ + success = draw_font_load(&win32vars.font_part, + font_out, + filename, + pt_size, + tab_width, + oversample); + + // TODO(allen): Make the growable partition something that can + // just be passed directly to font load and let it be grown there. + if (!success){ + Win32ScratchPartitionDouble(&win32vars.font_part); + } + } + + return(1); +} + +// +// Linkage to Custom and Application +// + internal b32 Win32LoadAppCode(){ b32 result = 0; @@ -1151,7 +1174,7 @@ Win32LoadSystemCode(){ win32vars.system->acquire_lock = system_acquire_lock; win32vars.system->release_lock = system_release_lock; -#ifdef FRED_INTERNAL +#if FRED_INTERNAL win32vars.system->internal_sentinel = INTERNAL_system_sentinel; win32vars.system->internal_get_thread_states = INTERNAL_get_thread_states; win32vars.system->internal_debug_message = INTERNAL_system_debug_message; @@ -1160,35 +1183,6 @@ Win32LoadSystemCode(){ win32vars.system->slash = '/'; } -#include "system_shared.cpp" -#include "4ed_rendering.cpp" - -internal -Font_Load_Sig(system_draw_font_load){ - if (win32vars.font_part.base == 0){ - win32vars.font_part = Win32ScratchPartition(Mbytes(8)); - } - - i32 oversample = 2; - - for (b32 success = 0; success == 0;){ - success = draw_font_load(&win32vars.font_part, - font_out, - filename, - pt_size, - tab_width, - oversample); - - // TODO(allen): Make the growable partition something that can - // just be passed directly to font load and let it be grown there. - if (!success){ - Win32ScratchPartitionDouble(&win32vars.font_part); - } - } - - return(1); -} - internal void Win32LoadRenderCode(){ win32vars.target.push_clip = draw_push_clip; @@ -1200,26 +1194,14 @@ Win32LoadRenderCode(){ win32vars.target.font_set.release_font = draw_release_font; } -internal void -Win32RedrawScreen(HDC hdc){ - launch_rendering(&win32vars.target); - glFlush(); - SwapBuffers(hdc); -} - -internal void -Win32RedrawFromUpdate(){ - PAINTSTRUCT ps; - HWND hwnd = win32vars.window_handle; - HDC hdc = BeginPaint(hwnd, &ps); - Win32RedrawScreen(hdc); - EndPaint(hwnd, &ps); -} +// +// Helpers +// globalvar u8 keycode_lookup_table[255]; internal void -keycode_init(){ +Win32KeycodeInit(){ keycode_lookup_table[VK_BACK] = key_back; keycode_lookup_table[VK_DELETE] = key_del; keycode_lookup_table[VK_UP] = key_up; @@ -1252,9 +1234,55 @@ keycode_init(){ keycode_lookup_table[VK_F16] = key_f16; } +internal void +Win32RedrawScreen(HDC hdc){ + launch_rendering(&win32vars.target); + glFlush(); + SwapBuffers(hdc); +} + +internal void +Win32RedrawFromUpdate(){ + PAINTSTRUCT ps; + HWND hwnd = win32vars.window_handle; + HDC hdc = BeginPaint(hwnd, &ps); + Win32RedrawScreen(hdc); + EndPaint(hwnd, &ps); +} + +internal void +Win32Resize(i32 width, i32 height){ + if (width > 0 && height > 0){ + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, width, height, 0, -1, 1); + glScissor(0, 0, width, height); + + win32vars.target.width = width; + win32vars.target.height = height; + } +} + +internal void +Win32SetCursorFromUpdate(Application_Mouse_Cursor cursor){ + switch (cursor){ + case APP_MOUSE_CURSOR_ARROW: + SetCursor(win32vars.cursor_arrow); break; + + case APP_MOUSE_CURSOR_IBEAM: + SetCursor(win32vars.cursor_ibeam); break; + + case APP_MOUSE_CURSOR_LEFTRIGHT: + SetCursor(win32vars.cursor_leftright); break; + + case APP_MOUSE_CURSOR_UPDOWN: + SetCursor(win32vars.cursor_updown); break; + } +} + internal LRESULT -Win32Callback(HWND hwnd, UINT uMsg, - WPARAM wParam, LPARAM lParam){ +Win32Callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ LRESULT result = {}; switch (uMsg){ case WM_MENUCHAR: @@ -1562,7 +1590,6 @@ OpenGLDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsi OutputDebugStringA("\n"); } -#if 1 int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, @@ -1572,12 +1599,6 @@ WinMain(HINSTANCE hInstance, int argc = __argc; char **argv = __argv; -#else -int main(int argc, char **argv){ - - HINSTANCE hInstance = GetModuleHandle(0); -#endif - HANDLE original_out = GetStdHandle(STD_OUTPUT_HANDLE); memset(&win32vars, 0, sizeof(win32vars)); @@ -1701,6 +1722,14 @@ int main(int argc, char **argv){ } #endif + if (win32vars.custom_api.get_bindings == 0){ + win32vars.custom_api.get_bindings = (Get_Binding_Data_Function*)get_bindings; + } + + if (win32vars.custom_api.view_routine == 0){ + win32vars.custom_api.view_routine = (View_Routine_Function*)view_routine; + } + FreeConsole(); sysshared_filter_real_files(files, file_count); @@ -1716,11 +1745,7 @@ int main(int argc, char **argv){ win32vars.start_time = ((u64)filetime.dwHighDateTime << 32) | (filetime.dwLowDateTime); win32vars.start_time /= 10; - keycode_init(); - - if (win32vars.custom_api.get_bindings == 0){ - win32vars.custom_api.get_bindings = (Get_Binding_Data_Function*)get_bindings; - } + Win32KeycodeInit(); Thread_Context background[4]; memset(background, 0, sizeof(background)); @@ -2074,6 +2099,14 @@ int main(int argc, char **argv){ return 0; } +#if 0 +// NOTE(allen): In case I want to switch back to a console +// application at some point. +int main(int argc, char **argv){ + HINSTANCE hInstance = GetModuleHandle(0); +} +#endif + // BOTTOM From 63eedecea23db444a2de9eaa655a0f80034540d4 Mon Sep 17 00:00:00 2001 From: insofaras Date: Sun, 29 May 2016 04:30:16 +0100 Subject: [PATCH 02/34] linux: fall back to default view_routine, clean up debug prints a bit --- linux_4ed.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/linux_4ed.cpp b/linux_4ed.cpp index 1b2cf801..42519140 100644 --- a/linux_4ed.cpp +++ b/linux_4ed.cpp @@ -278,8 +278,6 @@ LinuxGetMemory_(i32 size, i32 line_number, char *file_name){ pthread_mutex_unlock(&linuxvars.DEBUG_sysmem_lock); result = bubble + 1; - - fprintf(stderr, "new bubble: %p\n", result); #else size_t real_size = size + sizeof(size_t); result = mmap(0, real_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); @@ -299,8 +297,6 @@ internal void LinuxFreeMemory(void *block){ if (block){ #if FRED_INTERNAL - fprintf(stderr, "del bubble: %p\n", block); - Sys_Bubble *bubble = ((Sys_Bubble*)block) - 1; Assert((bubble->flags & MEM_BUBBLE_DEBUG_MASK) == MEM_BUBBLE_SYS_DEBUG); @@ -556,8 +552,6 @@ Sys_File_Load_End_Sig(system_file_load_end){ char* ptr = buffer; size_t size = loading.size; - LINUX_FN_DEBUG("%d %p %zu", fd, ptr, size); - if(!loading.exists || fd == -1) return 0; do { @@ -575,6 +569,8 @@ Sys_File_Load_End_Sig(system_file_load_end){ close(fd); + LINUX_FN_DEBUG("success == %d", (size == 0)); + return (size == 0); } @@ -1098,7 +1094,7 @@ Font_Load_Sig(system_draw_font_load){ b32 success = 0; i32 attempts = 0; - LINUX_FN_DEBUG("%p %s %d %d", font_out, filename, pt_size, tab_width); + LINUX_FN_DEBUG("%s, %dpt, tab_width: %d", filename, pt_size, tab_width); if (linuxvars.font_part.base == 0){ linuxvars.font_part = sysshared_scratch_partition(Mbytes(8)); @@ -2309,6 +2305,9 @@ main(int argc, char **argv) fprintf(stderr, "Successfully loaded 4coder_custom.so\n"); } } + } else { + const char* error = dlerror(); + fprintf(stderr, "*** Failed to load 4coder_custom.so: %s\n", error ? error : "dlopen failed."); } #endif @@ -2316,6 +2315,10 @@ main(int argc, char **argv) linuxvars.custom_api.get_bindings = get_bindings; } + if (linuxvars.custom_api.view_routine == 0){ + linuxvars.custom_api.view_routine = view_routine; + } + Thread_Context background[4] = {}; linuxvars.groups[BACKGROUND_THREADS].threads = background; linuxvars.groups[BACKGROUND_THREADS].count = ArrayCount(background); From 5c604d827355b71a14ce9b76e4ff63a4d1498d43 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Sun, 29 May 2016 13:07:24 -0400 Subject: [PATCH 03/34] switched to CRITICAL_SECTION, reorganized win32main --- 4coder_version.h | 2 +- win32_4ed.cpp | 525 ++++++++++++++++++++++++----------------------- 2 files changed, 270 insertions(+), 257 deletions(-) diff --git a/4coder_version.h b/4coder_version.h index a73750ef..1baec73c 100644 --- a/4coder_version.h +++ b/4coder_version.h @@ -1,6 +1,6 @@ #define MAJOR 4 #define MINOR 0 -#define PATCH 6 +#define PATCH 7 #define VN__(a,b,c) #a"."#b"."#c #define VN_(a,b,c) VN__(a,b,c) diff --git a/win32_4ed.cpp b/win32_4ed.cpp index 3418f73e..dd3fdf3f 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -115,7 +115,6 @@ struct Sys_Bubble : public Bubble{ struct Win32_Vars{ HWND window_handle; - HDC window_hdc; Render_Target target; Win32_Input_Chunk input_chunk; @@ -131,8 +130,8 @@ struct Win32_Vars{ DWORD clipboard_sequence; Thread_Group groups[THREAD_GROUP_COUNT]; - HANDLE locks[LOCK_COUNT]; - HANDLE DEBUG_sysmem_lock; + CRITICAL_SECTION locks[LOCK_COUNT]; + CRITICAL_SECTION DEBUG_sysmem_lock; Thread_Memory *thread_memory; @@ -203,56 +202,44 @@ Win32Ptr(void *h){ // Memory (not exposed to application, but needed in system_shared.cpp) // -#if FRED_INTERNAL - internal Sys_Get_Memory_Sig(system_get_memory_){ void *ptr = 0; if (size > 0){ + +#if FRED_INTERNAL ptr = VirtualAlloc(0, size + sizeof(Sys_Bubble), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); Sys_Bubble *bubble = (Sys_Bubble*)ptr; bubble->flags = MEM_BUBBLE_SYS_DEBUG; bubble->line_number = line_number; bubble->file_name = file_name; bubble->size = size; - WaitForSingleObject(win32vars.DEBUG_sysmem_lock, INFINITE); + EnterCriticalSection(&win32vars.DEBUG_sysmem_lock); insert_bubble(&win32vars.internal_bubble, bubble); - ReleaseSemaphore(win32vars.DEBUG_sysmem_lock, 1, 0); + LeaveCriticalSection(&win32vars.DEBUG_sysmem_lock); ptr = bubble + 1; +#else + ptr = VirtualAlloc(0, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); +#endif } return(ptr); } internal Sys_Free_Memory_Sig(system_free_memory){ if (block){ +#if FRED_INTERNAL Sys_Bubble *bubble = ((Sys_Bubble*)block) - 1; Assert((bubble->flags & MEM_BUBBLE_DEBUG_MASK) == MEM_BUBBLE_SYS_DEBUG); - WaitForSingleObject(win32vars.DEBUG_sysmem_lock, INFINITE); + EnterCriticalSection(&win32vars.DEBUG_sysmem_lock); remove_bubble(bubble); - ReleaseSemaphore(win32vars.DEBUG_sysmem_lock, 1, 0); + LeaveCriticalSection(&win32vars.DEBUG_sysmem_lock); VirtualFree(bubble, 0, MEM_RELEASE); - } -} - #else - -internal -Sys_Get_Memory_Sig(system_get_memory_){ - void *ptr = 0; - if (size > 0){ - ptr = VirtualAlloc(0, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - } - return(ptr); -} -internal -Sys_Free_Memory_Sig(system_free_memory){ - if (block){ VirtualFree(block, 0, MEM_RELEASE); +#endif } } -#endif - #define Win32GetMemory(size) system_get_memory_(size, __LINE__, __FILE__) #define Win32FreeMemory(ptr) system_free_memory(ptr) @@ -278,16 +265,16 @@ INTERNAL_system_debug_message(char *message){ internal Sys_File_Can_Be_Made_Sig(system_file_can_be_made){ - HANDLE file; - file = CreateFile((char*)filename, FILE_APPEND_DATA, 0, 0, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - - if (!file || file == INVALID_HANDLE_VALUE){ - return 0; - } - - CloseHandle(file); - + HANDLE file; + file = CreateFile((char*)filename, FILE_APPEND_DATA, 0, 0, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + + if (!file || file == INVALID_HANDLE_VALUE){ + return 0; + } + + CloseHandle(file); + return(1); } @@ -652,12 +639,12 @@ Sys_Post_Clipboard_Sig(system_post_clipboard){ internal Sys_Acquire_Lock_Sig(system_acquire_lock){ - WaitForSingleObject(win32vars.locks[id], INFINITE); + EnterCriticalSection(&win32vars.locks[id]); } internal Sys_Release_Lock_Sig(system_release_lock){ - ReleaseSemaphore(win32vars.locks[id], 1, 0); + LeaveCriticalSection(&win32vars.locks[id]); } internal DWORD @@ -1599,153 +1586,13 @@ WinMain(HINSTANCE hInstance, int argc = __argc; char **argv = __argv; - HANDLE original_out = GetStdHandle(STD_OUTPUT_HANDLE); - memset(&win32vars, 0, sizeof(win32vars)); memset(&exchange_vars, 0, sizeof(exchange_vars)); - -#if FRED_INTERNAL - win32vars.internal_bubble.next = &win32vars.internal_bubble; - win32vars.internal_bubble.prev = &win32vars.internal_bubble; - win32vars.internal_bubble.flags = MEM_BUBBLE_SYS_DEBUG; -#endif - - if (!Win32LoadAppCode()){ - // TODO(allen): Failed to load app code, serious problem. - return 99; - } - - System_Functions system_; - System_Functions *system = &system_; - win32vars.system = system; - Win32LoadSystemCode(); - - ConvertThreadToFiber(0); - win32vars.coroutine_free = win32vars.coroutine_data; - for (i32 i = 0; i+1 < ArrayCount(win32vars.coroutine_data); ++i){ - win32vars.coroutine_data[i].next = win32vars.coroutine_data + i + 1; - } - - LPVOID base; -#if FRED_INTERNAL - base = (LPVOID)Tbytes(1); -#else - base = (LPVOID)0; -#endif - - memory_vars.vars_memory_size = Mbytes(2); - memory_vars.vars_memory = VirtualAlloc(base, memory_vars.vars_memory_size, - MEM_COMMIT | MEM_RESERVE, - PAGE_READWRITE); - -#if FRED_INTERNAL - base = (LPVOID)Tbytes(2); -#else - base = (LPVOID)0; -#endif - memory_vars.target_memory_size = Mbytes(512); - memory_vars.target_memory = VirtualAlloc(base, memory_vars.target_memory_size, - MEM_COMMIT | MEM_RESERVE, - PAGE_READWRITE); - - base = (LPVOID)0; - memory_vars.user_memory_size = Mbytes(2); - memory_vars.user_memory = VirtualAlloc(base, memory_vars.target_memory_size, - MEM_COMMIT | MEM_RESERVE, - PAGE_READWRITE); + + + // + // Threads and Coroutines // - - if (!memory_vars.vars_memory){ - return 4; - } - - DWORD required = GetCurrentDirectory(0, 0); - required += 1; - required *= 4; - char *current_directory_mem = (char*)system_get_memory(required); - DWORD written = GetCurrentDirectory(required, current_directory_mem); - - String current_directory = make_string(current_directory_mem, written, required); - terminate_with_null(¤t_directory); - replace_char(current_directory, '\\', '/'); - - Command_Line_Parameters clparams; - clparams.argv = argv; - clparams.argc = argc; - - char **files; - i32 *file_count; - - files = 0; - file_count = 0; - - i32 output_size = - win32vars.app.read_command_line(system, - &memory_vars, - current_directory, - &win32vars.settings, - &files, &file_count, - clparams); - - if (output_size > 0){ - DWORD written; - WriteFile(original_out, memory_vars.target_memory, output_size, &written, 0); - } - if (output_size != 0) return 0; - -#ifdef FRED_SUPER - char *custom_file_default = "4coder_custom.dll"; - char *custom_file = 0; - if (win32vars.settings.custom_dll) custom_file = win32vars.settings.custom_dll; - else custom_file = custom_file_default; - - win32vars.custom = LoadLibraryA(custom_file); - if (!win32vars.custom && custom_file != custom_file_default){ - if (!win32vars.settings.custom_dll_is_strict){ - win32vars.custom = LoadLibraryA(custom_file_default); - } - } - - if (win32vars.custom){ - win32vars.custom_api.get_alpha_4coder_version = (_Get_Version_Function*) - GetProcAddress(win32vars.custom, "get_alpha_4coder_version"); - - if (win32vars.custom_api.get_alpha_4coder_version == 0 || - win32vars.custom_api.get_alpha_4coder_version(MAJOR, MINOR, PATCH) == 0){ - OutputDebugStringA("Error: application and custom version numbers don't match"); - return 22; - } - win32vars.custom_api.get_bindings = (Get_Binding_Data_Function*) - GetProcAddress(win32vars.custom, "get_bindings"); - win32vars.custom_api.view_routine = (View_Routine_Function*) - GetProcAddress(win32vars.custom, "view_routine"); - } -#endif - - if (win32vars.custom_api.get_bindings == 0){ - win32vars.custom_api.get_bindings = (Get_Binding_Data_Function*)get_bindings; - } - - if (win32vars.custom_api.view_routine == 0){ - win32vars.custom_api.view_routine = (View_Routine_Function*)view_routine; - } - - FreeConsole(); - - sysshared_filter_real_files(files, file_count); - - LARGE_INTEGER lpf; - QueryPerformanceFrequency(&lpf); - win32vars.performance_frequency = lpf.QuadPart; - QueryPerformanceCounter(&lpf); - win32vars.start_pcount = lpf.QuadPart; - - FILETIME filetime; - GetSystemTimeAsFileTime(&filetime); - win32vars.start_time = ((u64)filetime.dwHighDateTime << 32) | (filetime.dwLowDateTime); - win32vars.start_time /= 10; - - Win32KeycodeInit(); Thread_Context background[4]; memset(background, 0, sizeof(background)); @@ -1774,32 +1621,172 @@ WinMain(HINSTANCE hInstance, Assert(win32vars.locks); for (i32 i = 0; i < LOCK_COUNT; ++i){ - win32vars.locks[i] = CreateSemaphore(0, 1, 1, 0); + InitializeCriticalSection(&win32vars.locks[i]); + } + InitializeCriticalSection(&win32vars.DEBUG_sysmem_lock); + + ConvertThreadToFiber(0); + win32vars.coroutine_free = win32vars.coroutine_data; + for (i32 i = 0; i+1 < ArrayCount(win32vars.coroutine_data); ++i){ + win32vars.coroutine_data[i].next = win32vars.coroutine_data + i + 1; + } + + + // + // Memory Initialization + // + +#if FRED_INTERNAL + win32vars.internal_bubble.next = &win32vars.internal_bubble; + win32vars.internal_bubble.prev = &win32vars.internal_bubble; + win32vars.internal_bubble.flags = MEM_BUBBLE_SYS_DEBUG; +#endif + + LPVOID base; +#if FRED_INTERNAL + base = (LPVOID)Tbytes(1); +#else + base = (LPVOID)0; +#endif + + memory_vars.vars_memory_size = Mbytes(2); + memory_vars.vars_memory = VirtualAlloc(base, memory_vars.vars_memory_size, + MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE); + +#if FRED_INTERNAL + base = (LPVOID)Tbytes(2); +#else + base = (LPVOID)0; +#endif + memory_vars.target_memory_size = Mbytes(512); + memory_vars.target_memory = + VirtualAlloc(base, memory_vars.target_memory_size, + MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + + base = (LPVOID)0; + memory_vars.user_memory_size = Mbytes(2); + memory_vars.user_memory = + VirtualAlloc(base, memory_vars.target_memory_size, + MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + + if (!memory_vars.vars_memory){ + exit(1); } - win32vars.DEBUG_sysmem_lock = CreateSemaphore(0, 1, 1, 0); - Win32LoadRenderCode(); win32vars.target.max = Mbytes(1); win32vars.target.push_buffer = (byte*)system_get_memory(win32vars.target.max); - win32vars.cursor_ibeam = LoadCursor(NULL, IDC_IBEAM); - win32vars.cursor_arrow = LoadCursor(NULL, IDC_ARROW); - win32vars.cursor_leftright = LoadCursor(NULL, IDC_SIZEWE); - win32vars.cursor_updown = LoadCursor(NULL, IDC_SIZENS); + + // + // System and Application Layer Linkage + // + + if (!Win32LoadAppCode()){ + exit(1); + } + + System_Functions system_; + System_Functions *system = &system_; + win32vars.system = system; + Win32LoadSystemCode(); + + Win32LoadRenderCode(); + + + // + // Read Command Line + // + + DWORD required = GetCurrentDirectory(0, 0); + required += 1; + required *= 4; + char *current_directory_mem = (char*)system_get_memory(required); + DWORD written = GetCurrentDirectory(required, current_directory_mem); + + String current_directory = make_string(current_directory_mem, written, required); + terminate_with_null(¤t_directory); + replace_char(current_directory, '\\', '/'); + + Command_Line_Parameters clparams; + clparams.argv = argv; + clparams.argc = argc; + + char **files; + i32 *file_count; + + files = 0; + file_count = 0; + + win32vars.app.read_command_line(system, + &memory_vars, + current_directory, + &win32vars.settings, + &files, &file_count, + clparams); + + sysshared_filter_real_files(files, file_count); + + + // + // Custom Layer Linkage + // + +#ifdef FRED_SUPER + char *custom_file_default = "4coder_custom.dll"; + char *custom_file = 0; + if (win32vars.settings.custom_dll) custom_file = win32vars.settings.custom_dll; + else custom_file = custom_file_default; + + win32vars.custom = LoadLibraryA(custom_file); + if (!win32vars.custom && custom_file != custom_file_default){ + if (!win32vars.settings.custom_dll_is_strict){ + win32vars.custom = LoadLibraryA(custom_file_default); + } + } + + if (win32vars.custom){ + win32vars.custom_api.get_alpha_4coder_version = (_Get_Version_Function*) + GetProcAddress(win32vars.custom, "get_alpha_4coder_version"); + + if (win32vars.custom_api.get_alpha_4coder_version == 0 || + win32vars.custom_api.get_alpha_4coder_version(MAJOR, MINOR, PATCH) == 0){ + OutputDebugStringA("Error: application and custom version numbers don't match"); + exit(1); + } + win32vars.custom_api.get_bindings = (Get_Binding_Data_Function*) + GetProcAddress(win32vars.custom, "get_bindings"); + win32vars.custom_api.view_routine = (View_Routine_Function*) + GetProcAddress(win32vars.custom, "view_routine"); + } +#endif + + if (win32vars.custom_api.get_bindings == 0){ + win32vars.custom_api.get_bindings = (Get_Binding_Data_Function*)get_bindings; + } + + if (win32vars.custom_api.view_routine == 0){ + win32vars.custom_api.view_routine = (View_Routine_Function*)view_routine; + } + + + // + // Window and GL Initialization + // WNDCLASS window_class = {}; - window_class.style = CS_HREDRAW|CS_VREDRAW|CS_OWNDC; + window_class.style = CS_HREDRAW|CS_VREDRAW; window_class.lpfnWndProc = Win32Callback; window_class.hInstance = hInstance; window_class.lpszClassName = "4coder-win32-wndclass"; window_class.hIcon = LoadIcon(hInstance, "main"); if (!RegisterClass(&window_class)){ - return 1; + exit(1); } RECT window_rect = {}; - + if (win32vars.settings.set_window_size){ window_rect.right = win32vars.settings.window_w; window_rect.bottom = win32vars.settings.window_h; @@ -1808,17 +1795,17 @@ WinMain(HINSTANCE hInstance, window_rect.right = 800; window_rect.bottom = 600; } - + if (!AdjustWindowRect(&window_rect, WS_OVERLAPPEDWINDOW, false)){ // TODO(allen): non-fatal diagnostics } - + #define WINDOW_NAME "4coder-window: " VERSION - + i32 window_x; i32 window_y; i32 window_style; - + if (win32vars.settings.set_window_pos){ window_x = win32vars.settings.window_x; window_y = win32vars.settings.window_y; @@ -1827,35 +1814,30 @@ WinMain(HINSTANCE hInstance, window_x = CW_USEDEFAULT; window_y = CW_USEDEFAULT; } - + window_style = WS_OVERLAPPEDWINDOW | WS_VISIBLE; if (win32vars.settings.maximize_window){ window_style |= WS_MAXIMIZE; } - + + win32vars.window_handle = + CreateWindowA(window_class.lpszClassName, + WINDOW_NAME, window_style, + window_x, window_y, + window_rect.right - window_rect.left, + window_rect.bottom - window_rect.top, + 0, 0, hInstance, 0); + + if (win32vars.window_handle == 0){ + exit(1); + } + + // TODO(allen): not Windows XP compatible, do we care? // SetProcessDPIAware(); - - HWND window_handle = {}; - window_handle = CreateWindowA( - window_class.lpszClassName, - WINDOW_NAME, window_style, - window_x, window_y, - window_rect.right - window_rect.left, - window_rect.bottom - window_rect.top, - 0, 0, hInstance, 0); - - if (window_handle == 0){ - return 2; - } - - // TODO(allen): errors? - win32vars.window_handle = window_handle; - HDC hdc = GetDC(window_handle); - win32vars.window_hdc = hdc; - - GetClientRect(window_handle, &window_rect); - + + GetClientRect(win32vars.window_handle, &window_rect); + static PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), 1, @@ -1873,48 +1855,57 @@ WinMain(HINSTANCE hInstance, PFD_MAIN_PLANE, 0, 0, 0, 0 }; - - i32 pixel_format; - pixel_format = ChoosePixelFormat(hdc, &pfd); - SetPixelFormat(hdc, pixel_format, &pfd); - - win32vars.target.handle = hdc; - win32vars.target.context = wglCreateContext(hdc); - wglMakeCurrent(hdc, (HGLRC)win32vars.target.context); + + HDC hdc = GetDC(win32vars.window_handle); + { + i32 pixel_format; + pixel_format = ChoosePixelFormat(hdc, &pfd); + SetPixelFormat(hdc, pixel_format, &pfd); + + win32vars.target.handle = hdc; + win32vars.target.context = wglCreateContext(hdc); + wglMakeCurrent(hdc, (HGLRC)win32vars.target.context); + } + ReleaseDC(win32vars.window_handle, hdc); #if FRED_INTERNAL - // NOTE(casey): This slows down GL but puts error messages to the debug console immediately whenever you do something wrong - glDebugMessageCallback_type *glDebugMessageCallback = (glDebugMessageCallback_type *)wglGetProcAddress("glDebugMessageCallback"); - glDebugMessageControl_type *glDebugMessageControl = (glDebugMessageControl_type *)wglGetProcAddress("glDebugMessageControl"); - if(glDebugMessageCallback && glDebugMessageControl) - { - glDebugMessageCallback(OpenGLDebugCallback, 0); - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE); - glEnable(GL_DEBUG_OUTPUT); - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - } + // NOTE(casey): This slows down GL but puts error messages to the debug console immediately whenever you do something wrong + glDebugMessageCallback_type *glDebugMessageCallback = (glDebugMessageCallback_type *)wglGetProcAddress("glDebugMessageCallback"); + glDebugMessageControl_type *glDebugMessageControl = (glDebugMessageControl_type *)wglGetProcAddress("glDebugMessageControl"); + if(glDebugMessageCallback && glDebugMessageControl) + { + glDebugMessageCallback(OpenGLDebugCallback, 0); + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE); + glEnable(GL_DEBUG_OUTPUT); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + } #endif - + glEnable(GL_TEXTURE_2D); glEnable(GL_SCISSOR_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - + Win32Resize(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top); - + + + // + // Misc System Initializations + // + win32vars.clipboard_sequence = GetClipboardSequenceNumber(); - + if (win32vars.clipboard_sequence == 0){ system_post_clipboard(make_lit_string("")); - + win32vars.clipboard_sequence = GetClipboardSequenceNumber(); win32vars.next_clipboard_is_self = 0; - + if (win32vars.clipboard_sequence == 0){ // TODO(allen): diagnostics } } - + else{ if (IsClipboardFormatAvailable(CF_TEXT)){ if (OpenClipboard(win32vars.window_handle)){ @@ -1931,23 +1922,45 @@ WinMain(HINSTANCE hInstance, } } } - + + LARGE_INTEGER lpf; + QueryPerformanceFrequency(&lpf); + win32vars.performance_frequency = lpf.QuadPart; + QueryPerformanceCounter(&lpf); + win32vars.start_pcount = lpf.QuadPart; + + FILETIME filetime; + GetSystemTimeAsFileTime(&filetime); + win32vars.start_time = ((u64)filetime.dwHighDateTime << 32) | (filetime.dwLowDateTime); + win32vars.start_time /= 10; + + Win32KeycodeInit(); + + win32vars.cursor_ibeam = LoadCursor(NULL, IDC_IBEAM); + win32vars.cursor_arrow = LoadCursor(NULL, IDC_ARROW); + win32vars.cursor_leftright = LoadCursor(NULL, IDC_SIZEWE); + win32vars.cursor_updown = LoadCursor(NULL, IDC_SIZENS); + + + // + // Main Loop + // + win32vars.app.init(win32vars.system, &win32vars.target, - &memory_vars, &exchange_vars, - win32vars.clipboard_contents, current_directory, - win32vars.custom_api); - + &memory_vars, &exchange_vars, + win32vars.clipboard_contents, current_directory, + win32vars.custom_api); + system_free_memory(current_directory.str); - + win32vars.input_chunk.pers.keep_playing = 1; win32vars.first = 1; timeBeginPeriod(1); - + + SetForegroundWindow(win32vars.window_handle); + SetActiveWindow(win32vars.window_handle); + system_acquire_lock(FRAME_LOCK); - - SetForegroundWindow(window_handle); - SetActiveWindow(window_handle); - MSG msg; for (;win32vars.input_chunk.pers.keep_playing;){ // TODO(allen): Find a good way to wait on a pipe @@ -2096,7 +2109,7 @@ WinMain(HINSTANCE hInstance, } } - return 0; + return(0); } #if 0 From 319bae87990a365788a2ee4761f1a0c3fa69c20b Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Sun, 29 May 2016 13:49:38 -0400 Subject: [PATCH 04/34] temporarily remove view routines --- 4coder_default_bindings.cpp | 2 -- 4ed.cpp | 35 +++++++++---------- buildsuper.bat | 2 +- ...pp => not_shipping_4coder_default_view.cpp | 0 power/4coder_experiments.cpp | 2 -- win32_4ed.cpp | 11 +++++- 6 files changed, 28 insertions(+), 24 deletions(-) rename 4coder_default_view.cpp => not_shipping_4coder_default_view.cpp (100%) diff --git a/4coder_default_bindings.cpp b/4coder_default_bindings.cpp index fb50d018..2a18a793 100644 --- a/4coder_default_bindings.cpp +++ b/4coder_default_bindings.cpp @@ -436,8 +436,6 @@ get_bindings(void *data, int size){ return(result); } -#include "4coder_default_view.cpp" - #endif // BOTTOM diff --git a/4ed.cpp b/4ed.cpp index 931eb63b..cefcae7c 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -3255,7 +3255,7 @@ App_Init_Sig(app_init){ persistent->view_routine = models->config_api.view_routine; } } - + { Command_Map *global = 0; i32 wanted_size = 0; @@ -3834,6 +3834,8 @@ App_Step_Sig(app_step){ cmd->part = partition_sub_part(&models->mem.part, 16 << 10); if (first_step){ + +#if 0 { View *view = 0; View_Persistent *persistent = 0; @@ -3848,22 +3850,17 @@ App_Step_Sig(app_step){ persistent->coroutine = system->create_coroutine(view_caller); - models->command_coroutine = persistent->coroutine; - persistent->coroutine = app_launch_coroutine(system, &models->app_links, Co_View, - persistent->coroutine, - view, - 0); + persistent->coroutine, view, 0); if (!persistent->coroutine){ // TODO(allen): Error message and recover NotImplemented; } } - - models->command_coroutine = 0; } +#endif General_Memory *general = &models->mem.general; Editing_File *file = working_set_alloc_always(&models->working_set, general); @@ -3883,7 +3880,9 @@ App_Step_Sig(app_step){ i32 i; String file_name; Panel *panel = models->layout.used_sentinel.next; - for (i = 0; i < models->settings.init_files_count; ++i, panel = panel->next){ + for (i = 0; + i < models->settings.init_files_count; + ++i, panel = panel->next){ file_name = make_string_slowly(models->settings.init_files[i]); if (i < models->layout.panel_count){ @@ -3902,7 +3901,7 @@ App_Step_Sig(app_step){ } } - // NOTE(allen): try to abort the command corroutine if we are shutting down + // NOTE(allen): respond if the user is trying to kill the application if (app_result.trying_to_kill){ b32 there_is_unsaved = 0; app_result.animating = 1; @@ -3921,15 +3920,14 @@ App_Step_Sig(app_step){ Coroutine *command_coroutine = models->command_coroutine; View *view = cmd->view; i32 i = 0; - + while (command_coroutine){ User_Input user_in = {0}; user_in.abort = 1; command_coroutine = app_resume_coroutine(system, &models->app_links, Co_Command, - command_coroutine, - &user_in, + command_coroutine, &user_in, models->command_coroutine_flags); ++i; @@ -3941,15 +3939,16 @@ App_Step_Sig(app_step){ if (view != 0){ init_query_set(&view->query_set); } - + if (view == 0){ Panel *panel = models->layout.used_sentinel.next; view = panel->view; } - + view_show_interactive(system, view, &models->map_ui, - IAct_Sure_To_Close, IInt_Sure_To_Close, make_lit_string("Are you sure?")); - + IAct_Sure_To_Close, IInt_Sure_To_Close, + make_lit_string("Are you sure?")); + models->command_coroutine = command_coroutine; } else{ @@ -3959,7 +3958,7 @@ App_Step_Sig(app_step){ // NOTE(allen): process the command_coroutine if it is unfinished Available_Input available_input = init_available_input(&key_summary, mouse); - + // NOTE(allen): Keyboard input to command coroutine. if (models->command_coroutine != 0){ Coroutine *command_coroutine = models->command_coroutine; diff --git a/buildsuper.bat b/buildsuper.bat index 83f0802e..105a74b3 100644 --- a/buildsuper.bat +++ b/buildsuper.bat @@ -11,7 +11,7 @@ SET OPTS=/W4 /wd4310 /wd4100 /wd4201 /wd4505 /wd4996 /wd4127 /wd4510 /wd4512 /wd SET OPTS=%OPTS% /GR- /nologo SET DEBUG=/Zi set BUILD_DLL=/LD /link /INCREMENTAL:NO /OPT:REF -SET EXPORTS=/EXPORT:view_routine /EXPORT:get_bindings /EXPORT:get_alpha_4coder_version +SET EXPORTS=/EXPORT:get_bindings /EXPORT:get_alpha_4coder_version REM SET LINKS=user32.lib gdi32.lib SET LINKS= diff --git a/4coder_default_view.cpp b/not_shipping_4coder_default_view.cpp similarity index 100% rename from 4coder_default_view.cpp rename to not_shipping_4coder_default_view.cpp diff --git a/power/4coder_experiments.cpp b/power/4coder_experiments.cpp index 0bbe9361..e8ffa4ed 100644 --- a/power/4coder_experiments.cpp +++ b/power/4coder_experiments.cpp @@ -379,7 +379,5 @@ get_bindings(void *data, int size){ return(result); } -#include "..\4coder_default_view.cpp" - // BOTTOM diff --git a/win32_4ed.cpp b/win32_4ed.cpp index dd3fdf3f..88980612 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -1756,8 +1756,14 @@ WinMain(HINSTANCE hInstance, } win32vars.custom_api.get_bindings = (Get_Binding_Data_Function*) GetProcAddress(win32vars.custom, "get_bindings"); + + // NOTE(allen): I am temporarily taking the view routine + // back out, it will be back soon. +#if 0 win32vars.custom_api.view_routine = (View_Routine_Function*) GetProcAddress(win32vars.custom, "view_routine"); +#endif + } #endif @@ -1765,10 +1771,13 @@ WinMain(HINSTANCE hInstance, win32vars.custom_api.get_bindings = (Get_Binding_Data_Function*)get_bindings; } + win32vars.custom_api.view_routine = (View_Routine_Function*)0; +#if 0 if (win32vars.custom_api.view_routine == 0){ win32vars.custom_api.view_routine = (View_Routine_Function*)view_routine; } - +#endif + // // Window and GL Initialization From c56703cbc8bff844fb81fc3d8a8dc51ad45da473 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Sun, 29 May 2016 15:05:27 -0400 Subject: [PATCH 05/34] change rate limitting in win32 a bit, fixed up bad calls to BeginPaint, and got rid of OWNDC --- 4ed.cpp | 7 +- 4ed_file_view.cpp | 5 +- 4ed_system.h | 17 +- win32_4ed.cpp | 482 ++++++++++++++++++++++------------------------ 4 files changed, 247 insertions(+), 264 deletions(-) diff --git a/4ed.cpp b/4ed.cpp index cefcae7c..7ed77572 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -1148,7 +1148,6 @@ COMMAND_DECL(to_lowercase){ } COMMAND_DECL(clean_all_lines){ - USE_MODELS(models); REQ_OPEN_VIEW(view); REQ_FILE(file, view); @@ -1157,21 +1156,19 @@ COMMAND_DECL(clean_all_lines){ } COMMAND_DECL(eol_dosify){ - REQ_READABLE_VIEW(view); REQ_FILE(file, view); file->settings.dos_write_mode = 1; - file->state.last_4ed_edit_time = system->time(); + file->state.last_4ed_edit_time = system->now_time_stamp(); } COMMAND_DECL(eol_nixify){ - REQ_READABLE_VIEW(view); REQ_FILE(file, view); file->settings.dos_write_mode = 0; - file->state.last_4ed_edit_time = system->time(); + file->state.last_4ed_edit_time = system->now_time_stamp(); } COMMAND_DECL(auto_tab_range){ diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index 3f444030..50220485 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -1162,8 +1162,9 @@ file_post_redo(General_Memory *general, Editing_File *file, Edit_Step step){ inv_step.child_count = step.inverse_child_count; inv_step.inverse_child_count = step.child_count; - if (redo->edit_count == redo->edit_max) + if (redo->edit_count == redo->edit_max){ undo_stack_grow_edits(general, redo); + } redo->edits[redo->edit_count++] = inv_step; } } @@ -1805,7 +1806,7 @@ file_pre_edit_maintenance(System_Functions *system, file->state.swap_stack.tokens = 0; } } - file->state.last_4ed_edit_time = system->time(); + file->state.last_4ed_edit_time = system->now_time_stamp(); } struct Cursor_Fix_Descriptor{ diff --git a/4ed_system.h b/4ed_system.h index a6ba628c..32527d58 100644 --- a/4ed_system.h +++ b/4ed_system.h @@ -35,9 +35,16 @@ uhash_equal(Unique_Hash a, Unique_Hash b){ return(result); } +// NOTE(allen): These two time functions should return values +// in the same time space. There is no requirement about +// resolution but the higher the better. These functions +// should not be used for profiling purposes. #define Sys_File_Time_Stamp_Sig(name) u64 name(char *filename) typedef Sys_File_Time_Stamp_Sig(System_File_Time_Stamp); +#define Sys_Now_Time_Stamp_Sig(name) u64 name() +typedef Sys_Now_Time_Stamp_Sig(System_Now_Time_Stamp); + // TODO(allen): make directory a char* to signal that it must be null terminated #define Sys_Set_File_List_Sig(name) void name(File_List *file_list, String directory) typedef Sys_Set_File_List_Sig(System_Set_File_List); @@ -66,13 +73,9 @@ typedef Sys_File_Load_End_Sig(System_File_Load_End); #define Sys_File_Save_Sig(name) b32 name(char *filename, char *buffer, i32 size) typedef Sys_File_Save_Sig(System_File_Save); - #define Sys_Post_Clipboard_Sig(name) void name(String str) typedef Sys_Post_Clipboard_Sig(System_Post_Clipboard); -#define Sys_Time_Sig(name) u64 name() -typedef Sys_Time_Sig(System_Time); - // cli struct CLI_Handles{ Plat_Handle proc; @@ -217,8 +220,9 @@ typedef INTERNAL_Sys_Get_Thread_States_Sig(INTERNAL_System_Get_Thread_States); typedef INTERNAL_Sys_Debug_Message_Sig(INTERNAL_System_Debug_Message); struct System_Functions{ - // files: 6 + // files: 7 System_File_Time_Stamp *file_time_stamp; + System_Now_Time_Stamp *now_time_stamp; System_Set_File_List *set_file_list; System_File_Unique_Hash *file_unique_hash; System_File_Track *file_track; @@ -235,9 +239,6 @@ struct System_Functions{ // clipboard: 1 System_Post_Clipboard *post_clipboard; - // time: 1 - System_Time *time; - // coroutine: 4 System_Create_Coroutine *create_coroutine; System_Launch_Coroutine *launch_coroutine; diff --git a/win32_4ed.cpp b/win32_4ed.cpp index 88980612..a374ff13 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -114,31 +114,9 @@ struct Sys_Bubble : public Bubble{ #endif struct Win32_Vars{ - HWND window_handle; - Render_Target target; - - Win32_Input_Chunk input_chunk; - b32 lctrl_lalt_is_altgr; - b32 got_useful_event; - - HCURSOR cursor_ibeam; - HCURSOR cursor_arrow; - HCURSOR cursor_leftright; - HCURSOR cursor_updown; - String clipboard_contents; - b32 next_clipboard_is_self; - DWORD clipboard_sequence; - - Thread_Group groups[THREAD_GROUP_COUNT]; - CRITICAL_SECTION locks[LOCK_COUNT]; - CRITICAL_SECTION DEBUG_sysmem_lock; - - Thread_Memory *thread_memory; - - u64 performance_frequency; - u64 start_pcount; - u64 start_time; - + System_Functions system; + App_Functions app; + Custom_API custom_api; #if UseWinDll HMODULE app_code; HMODULE custom; @@ -147,22 +125,44 @@ struct Win32_Vars{ DLL_Loaded custom_dll; #endif + Plat_Settings settings; + + + Thread_Group groups[THREAD_GROUP_COUNT]; + CRITICAL_SECTION locks[LOCK_COUNT]; + CRITICAL_SECTION DEBUG_sysmem_lock; + Thread_Memory *thread_memory; + Win32_Coroutine coroutine_data[18]; + Win32_Coroutine *coroutine_free; + + + Win32_Input_Chunk input_chunk; + b32 lctrl_lalt_is_altgr; + b32 got_useful_event; + + + HCURSOR cursor_ibeam; + HCURSOR cursor_arrow; + HCURSOR cursor_leftright; + HCURSOR cursor_updown; + String clipboard_contents; + b32 next_clipboard_is_self; + DWORD clipboard_sequence; + + + HWND window_handle; + Render_Target target; Partition font_part; - Plat_Settings settings; - System_Functions *system; - App_Functions app; - Custom_API custom_api; + + u64 count_per_usecond; b32 first; + i32 running_cli; + #if FRED_INTERNAL Sys_Bubble internal_bubble; #endif - - Win32_Coroutine coroutine_data[18]; - Win32_Coroutine *coroutine_free; - - i32 running_cli; }; globalvar Win32_Vars win32vars; @@ -366,13 +366,6 @@ Sys_File_Save_Sig(system_file_save){ return(success); } -// TODO(allen): THIS system does not really work. -// I want to eliminate them both entirely and find a better -// way to track the dirty state of files. It shouldn't be too -// hard to get the * part right. The trick is how we will know -// when a file is updated... hmm... maybe we can keep the -// file_time_stamp part. - internal Sys_File_Time_Stamp_Sig(system_file_time_stamp){ u64 result = 0; @@ -383,21 +376,18 @@ Sys_File_Time_Stamp_Sig(system_file_time_stamp){ last_write = data.ftLastWriteTime; result = ((u64)last_write.dwHighDateTime << 32) | (last_write.dwLowDateTime); - result /= 10; } return(result); } internal -Sys_Time_Sig(system_time){ +Sys_Now_Time_Stamp_Sig(system_now_time_stamp){ u64 result = 0; - LARGE_INTEGER time; - if (QueryPerformanceCounter(&time)){ - result = (u64)(time.QuadPart - win32vars.start_pcount) * 1000000 / win32vars.performance_frequency; - result += win32vars.start_time; - } - return result; + FILETIME filetime; + GetSystemTimeAsFileTime(&filetime); + result = ((u64)filetime.dwHighDateTime << 32) | (filetime.dwLowDateTime); + return(result); } internal @@ -633,6 +623,29 @@ Sys_Post_Clipboard_Sig(system_post_clipboard){ } } +internal b32 +Win32ReadClipboardContents(){ + b32 result = 0; + + if (IsClipboardFormatAvailable(CF_TEXT)){ + result = 1; + if (OpenClipboard(win32vars.window_handle)){ + HANDLE clip_data; + clip_data = GetClipboardData(CF_TEXT); + if (clip_data){ + win32vars.clipboard_contents.str = (char*)GlobalLock(clip_data); + if (win32vars.clipboard_contents.str){ + win32vars.clipboard_contents.size = str_size((char*)win32vars.clipboard_contents.str); + GlobalUnlock(clip_data); + } + } + CloseClipboard(); + } + } + + return(result); +} + // // Multithreading // @@ -651,32 +664,32 @@ internal DWORD JobThreadProc(LPVOID lpParameter){ Thread_Context *thread = (Thread_Context*)lpParameter; Work_Queue *queue = thread->queue; - + for (;;){ u32 read_index = queue->read_position; u32 write_index = queue->write_position; - + if (read_index != write_index){ u32 next_read_index = (read_index + 1) % JOB_ID_WRAP; u32 safe_read_index = InterlockedCompareExchange(&queue->read_position, - next_read_index, read_index); - + next_read_index, read_index); + if (safe_read_index == read_index){ Full_Job_Data *full_job = queue->jobs + (safe_read_index % QUEUE_WRAP); // NOTE(allen): This is interlocked so that it plays nice // with the cancel job routine, which may try to cancel this job // at the same time that we try to run it - + i32 safe_running_thread = InterlockedCompareExchange(&full_job->running_thread, - thread->id, THREAD_NOT_ASSIGNED); - + thread->id, THREAD_NOT_ASSIGNED); + if (safe_running_thread == THREAD_NOT_ASSIGNED){ thread->job_id = full_job->id; thread->running = 1; Thread_Memory *thread_memory = 0; - + // TODO(allen): remove memory_request if (full_job->job.memory_request != 0){ thread_memory = win32vars.thread_memory + thread->id - 1; @@ -689,8 +702,8 @@ JobThreadProc(LPVOID lpParameter){ thread_memory->size = new_size; } } - full_job->job.callback(win32vars.system, thread, thread_memory, - &exchange_vars.thread, full_job->job.data); + full_job->job.callback(&win32vars.system, thread, thread_memory, + &exchange_vars.thread, full_job->job.data); PostMessage(win32vars.window_handle, WM_4coder_ANIMATE, 0, 0); full_job->running_thread = 0; thread->running = 0; @@ -1129,45 +1142,45 @@ Win32LoadAppCode(){ internal void Win32LoadSystemCode(){ - win32vars.system->file_time_stamp = system_file_time_stamp; - win32vars.system->file_unique_hash = system_file_unique_hash; - win32vars.system->set_file_list = system_set_file_list; - win32vars.system->file_track = system_file_track; - win32vars.system->file_untrack = system_file_untrack; - win32vars.system->file_load_begin = system_file_load_begin; - win32vars.system->file_load_end = system_file_load_end; - win32vars.system->file_save = system_file_save; + win32vars.system.file_time_stamp = system_file_time_stamp; + win32vars.system.now_time_stamp = system_now_time_stamp; + win32vars.system.file_unique_hash = system_file_unique_hash; + win32vars.system.set_file_list = system_set_file_list; + win32vars.system.file_track = system_file_track; + win32vars.system.file_untrack = system_file_untrack; + win32vars.system.file_load_begin = system_file_load_begin; + win32vars.system.file_load_end = system_file_load_end; + win32vars.system.file_save = system_file_save; - win32vars.system->file_exists = system_file_exists; - win32vars.system->directory_cd = system_directory_cd; - win32vars.system->get_4ed_path = system_get_4ed_path; + win32vars.system.file_exists = system_file_exists; + win32vars.system.directory_cd = system_directory_cd; + win32vars.system.get_4ed_path = system_get_4ed_path; - win32vars.system->post_clipboard = system_post_clipboard; - win32vars.system->time = system_time; + win32vars.system.post_clipboard = system_post_clipboard; - win32vars.system->create_coroutine = system_create_coroutine; - win32vars.system->launch_coroutine = system_launch_coroutine; - win32vars.system->resume_coroutine = system_resume_coroutine; - win32vars.system->yield_coroutine = system_yield_coroutine; + win32vars.system.create_coroutine = system_create_coroutine; + win32vars.system.launch_coroutine = system_launch_coroutine; + win32vars.system.resume_coroutine = system_resume_coroutine; + win32vars.system.yield_coroutine = system_yield_coroutine; - win32vars.system->cli_call = system_cli_call; - win32vars.system->cli_begin_update = system_cli_begin_update; - win32vars.system->cli_update_step = system_cli_update_step; - win32vars.system->cli_end_update = system_cli_end_update; + win32vars.system.cli_call = system_cli_call; + win32vars.system.cli_begin_update = system_cli_begin_update; + win32vars.system.cli_update_step = system_cli_update_step; + win32vars.system.cli_end_update = system_cli_end_update; - win32vars.system->post_job = system_post_job; - win32vars.system->cancel_job = system_cancel_job; - win32vars.system->grow_thread_memory = system_grow_thread_memory; - win32vars.system->acquire_lock = system_acquire_lock; - win32vars.system->release_lock = system_release_lock; + win32vars.system.post_job = system_post_job; + win32vars.system.cancel_job = system_cancel_job; + win32vars.system.grow_thread_memory = system_grow_thread_memory; + win32vars.system.acquire_lock = system_acquire_lock; + win32vars.system.release_lock = system_release_lock; #if FRED_INTERNAL - win32vars.system->internal_sentinel = INTERNAL_system_sentinel; - win32vars.system->internal_get_thread_states = INTERNAL_get_thread_states; - win32vars.system->internal_debug_message = INTERNAL_system_debug_message; + win32vars.system.internal_sentinel = INTERNAL_system_sentinel; + win32vars.system.internal_get_thread_states = INTERNAL_get_thread_states; + win32vars.system.internal_debug_message = INTERNAL_system_debug_message; #endif - win32vars.system->slash = '/'; + win32vars.system.slash = '/'; } internal void @@ -1228,15 +1241,6 @@ Win32RedrawScreen(HDC hdc){ SwapBuffers(hdc); } -internal void -Win32RedrawFromUpdate(){ - PAINTSTRUCT ps; - HWND hwnd = win32vars.window_handle; - HDC hdc = BeginPaint(hwnd, &ps); - Win32RedrawScreen(hdc); - EndPaint(hwnd, &ps); -} - internal void Win32Resize(i32 width, i32 height){ if (width > 0 && height > 0){ @@ -1268,6 +1272,18 @@ Win32SetCursorFromUpdate(Application_Mouse_Cursor cursor){ } } +internal u64 +Win32HighResolutionTime(){ + u64 result = 0; + LARGE_INTEGER t; + if (QueryPerformanceCounter(&t)){ + result = (u64)t.QuadPart / win32vars.count_per_usecond; + } + return(result); +} + + + internal LRESULT Win32Callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ LRESULT result = {}; @@ -1686,9 +1702,6 @@ WinMain(HINSTANCE hInstance, exit(1); } - System_Functions system_; - System_Functions *system = &system_; - win32vars.system = system; Win32LoadSystemCode(); Win32LoadRenderCode(); @@ -1698,9 +1711,7 @@ WinMain(HINSTANCE hInstance, // Read Command Line // - DWORD required = GetCurrentDirectory(0, 0); - required += 1; - required *= 4; + DWORD required = (GetCurrentDirectory(0, 0)*4) + 1; char *current_directory_mem = (char*)system_get_memory(required); DWORD written = GetCurrentDirectory(required, current_directory_mem); @@ -1712,13 +1723,10 @@ WinMain(HINSTANCE hInstance, clparams.argv = argv; clparams.argc = argc; - char **files; - i32 *file_count; + char **files = 0; + i32 *file_count = 0; - files = 0; - file_count = 0; - - win32vars.app.read_command_line(system, + win32vars.app.read_command_line(&win32vars.system, &memory_vars, current_directory, &win32vars.settings, @@ -1751,7 +1759,7 @@ WinMain(HINSTANCE hInstance, if (win32vars.custom_api.get_alpha_4coder_version == 0 || win32vars.custom_api.get_alpha_4coder_version(MAJOR, MINOR, PATCH) == 0){ - OutputDebugStringA("Error: application and custom version numbers don't match"); + OutputDebugStringA("Error: application and custom version numbers don't match\n"); exit(1); } win32vars.custom_api.get_bindings = (Get_Binding_Data_Function*) @@ -1903,7 +1911,6 @@ WinMain(HINSTANCE hInstance, // win32vars.clipboard_sequence = GetClipboardSequenceNumber(); - if (win32vars.clipboard_sequence == 0){ system_post_clipboard(make_lit_string("")); @@ -1911,38 +1918,13 @@ WinMain(HINSTANCE hInstance, win32vars.next_clipboard_is_self = 0; if (win32vars.clipboard_sequence == 0){ - // TODO(allen): diagnostics + OutputDebugStringA("Failure while initializing clipboard\n"); } } - else{ - if (IsClipboardFormatAvailable(CF_TEXT)){ - if (OpenClipboard(win32vars.window_handle)){ - HANDLE clip_data; - clip_data = GetClipboardData(CF_TEXT); - if (clip_data){ - win32vars.clipboard_contents.str = (char*)GlobalLock(clip_data); - if (win32vars.clipboard_contents.str){ - win32vars.clipboard_contents.size = str_size((char*)win32vars.clipboard_contents.str); - GlobalUnlock(clip_data); - } - } - CloseClipboard(); - } - } + Win32ReadClipboardContents(); } - LARGE_INTEGER lpf; - QueryPerformanceFrequency(&lpf); - win32vars.performance_frequency = lpf.QuadPart; - QueryPerformanceCounter(&lpf); - win32vars.start_pcount = lpf.QuadPart; - - FILETIME filetime; - GetSystemTimeAsFileTime(&filetime); - win32vars.start_time = ((u64)filetime.dwHighDateTime << 32) | (filetime.dwLowDateTime); - win32vars.start_time /= 10; - Win32KeycodeInit(); win32vars.cursor_ibeam = LoadCursor(NULL, IDC_IBEAM); @@ -1950,12 +1932,21 @@ WinMain(HINSTANCE hInstance, win32vars.cursor_leftright = LoadCursor(NULL, IDC_SIZEWE); win32vars.cursor_updown = LoadCursor(NULL, IDC_SIZENS); + LARGE_INTEGER f; + if (QueryPerformanceFrequency(&f)){ + win32vars.count_per_usecond = (u64)f.QuadPart / 1000000; + } + else{ + // NOTE(allen): Just guess. + win32vars.count_per_usecond = 1; + } + // // Main Loop // - win32vars.app.init(win32vars.system, &win32vars.target, + win32vars.app.init(&win32vars.system, &win32vars.target, &memory_vars, &exchange_vars, win32vars.clipboard_contents, current_directory, win32vars.custom_api); @@ -1966,9 +1957,11 @@ WinMain(HINSTANCE hInstance, win32vars.first = 1; timeBeginPeriod(1); + SetForegroundWindow(win32vars.window_handle); SetActiveWindow(win32vars.window_handle); + u64 timer_start = Win32HighResolutionTime(); system_acquire_lock(FRAME_LOCK); MSG msg; for (;win32vars.input_chunk.pers.keep_playing;){ @@ -1977,12 +1970,12 @@ WinMain(HINSTANCE hInstance, // Looks like we can ReadFile with a size of zero // in an IOCP for this effect. + system_release_lock(FRAME_LOCK); + if (win32vars.running_cli == 0){ win32vars.got_useful_event = 0; for (;win32vars.got_useful_event == 0;){ - system_release_lock(FRAME_LOCK); if (GetMessage(&msg, 0, 0, 0)){ - system_acquire_lock(FRAME_LOCK); if (msg.message == WM_QUIT){ win32vars.input_chunk.pers.keep_playing = 0; }else{ @@ -1990,9 +1983,6 @@ WinMain(HINSTANCE hInstance, DispatchMessage(&msg); } } - else{ - system_acquire_lock(FRAME_LOCK); - } } } @@ -2005,117 +1995,111 @@ WinMain(HINSTANCE hInstance, } } - { - i64 timer_start = system_time(); + system_acquire_lock(FRAME_LOCK); + + POINT mouse_point; + if (GetCursorPos(&mouse_point) && + ScreenToClient(win32vars.window_handle, &mouse_point)){ - POINT mouse_point; - if (GetCursorPos(&mouse_point) && ScreenToClient(win32vars.window_handle, &mouse_point)){ - if (!hit_check(mouse_point.x, mouse_point.y, - 0, 0, win32vars.target.width, win32vars.target.height)){ - win32vars.input_chunk.trans.out_of_window = 1; - } - win32vars.input_chunk.pers.mouse_x = mouse_point.x; - win32vars.input_chunk.pers.mouse_y = mouse_point.y; - } - else{ + i32_Rect screen = + i32R(0, 0, win32vars.target.width, win32vars.target.height); + + if (!hit_check(mouse_point.x, mouse_point.y, screen)){ win32vars.input_chunk.trans.out_of_window = 1; } - Win32_Input_Chunk input_chunk = win32vars.input_chunk; - win32vars.input_chunk.trans = win32_input_chunk_transient_zero(); - - input_chunk.pers.control_keys[MDFR_CAPS_INDEX] = GetKeyState(VK_CAPITAL) & 0x1; - - win32vars.clipboard_contents = string_zero(); - if (win32vars.clipboard_sequence != 0){ - DWORD new_number = GetClipboardSequenceNumber(); - if (new_number != win32vars.clipboard_sequence){ - win32vars.clipboard_sequence = new_number; - if (win32vars.next_clipboard_is_self){ - win32vars.next_clipboard_is_self = 0; - } - else if (IsClipboardFormatAvailable(CF_TEXT)){ - if (OpenClipboard(win32vars.window_handle)){ - HANDLE clip_data; - clip_data = GetClipboardData(CF_TEXT); - if (clip_data){ - win32vars.clipboard_contents.str = (char*)GlobalLock(clip_data); - if (win32vars.clipboard_contents.str){ - win32vars.clipboard_contents.size = str_size((char*)win32vars.clipboard_contents.str); - GlobalUnlock(clip_data); - } - } - CloseClipboard(); - } - } + win32vars.input_chunk.pers.mouse_x = mouse_point.x; + win32vars.input_chunk.pers.mouse_y = mouse_point.y; + } + else{ + win32vars.input_chunk.trans.out_of_window = 1; + } + + Win32_Input_Chunk input_chunk = win32vars.input_chunk; + win32vars.input_chunk.trans = win32_input_chunk_transient_zero(); + + input_chunk.pers.control_keys[MDFR_CAPS_INDEX] = GetKeyState(VK_CAPITAL) & 0x1; + + win32vars.clipboard_contents = string_zero(); + if (win32vars.clipboard_sequence != 0){ + DWORD new_number = GetClipboardSequenceNumber(); + if (new_number != win32vars.clipboard_sequence){ + win32vars.clipboard_sequence = new_number; + if (win32vars.next_clipboard_is_self){ + win32vars.next_clipboard_is_self = 0; + } + else{ + Win32ReadClipboardContents(); } } - - Key_Input_Data input_data; - Mouse_State mouse; - Application_Step_Result result; - - input_data = input_chunk.trans.key_data; - mouse.out_of_window = input_chunk.trans.out_of_window; - - mouse.l = input_chunk.pers.mouse_l; - mouse.press_l = input_chunk.trans.mouse_l_press; - mouse.release_l = input_chunk.trans.mouse_l_release; - - mouse.r = input_chunk.pers.mouse_r; - mouse.press_r = input_chunk.trans.mouse_r_press; - mouse.release_r = input_chunk.trans.mouse_r_release; - - mouse.wheel = input_chunk.trans.mouse_wheel; - - mouse.x = input_chunk.pers.mouse_x; - mouse.y = input_chunk.pers.mouse_y; - - result.mouse_cursor_type = APP_MOUSE_CURSOR_DEFAULT; - result.lctrl_lalt_is_altgr = win32vars.lctrl_lalt_is_altgr; - result.trying_to_kill = input_chunk.trans.trying_to_kill; - result.perform_kill = 0; - - // NOTE(allen): The expected dt given the frame limit in seconds. - f32 dt = frame_useconds / 1000000.f; - - win32vars.app.step(win32vars.system, - &input_data, - &mouse, - &win32vars.target, - &memory_vars, - &exchange_vars, - win32vars.clipboard_contents, - dt, win32vars.first, - &result); - - if (result.perform_kill){ - win32vars.input_chunk.pers.keep_playing = 0; - } - - Win32SetCursorFromUpdate(result.mouse_cursor_type); - win32vars.lctrl_lalt_is_altgr = result.lctrl_lalt_is_altgr; - - Win32RedrawFromUpdate(); - - win32vars.first = 0; - - i64 timer_end = system_time(); - i64 end_target = (timer_start + frame_useconds); - - system_release_lock(FRAME_LOCK); - while (timer_end < end_target){ - DWORD samount = (DWORD)((end_target - timer_end) / 1000); - if (samount > 0) Sleep(samount); - timer_end = system_time(); - } - system_acquire_lock(FRAME_LOCK); - timer_start = system_time(); - - if (result.animating){ - PostMessage(win32vars.window_handle, WM_4coder_ANIMATE, 0, 0); - } } + + Key_Input_Data input_data; + Mouse_State mouse; + Application_Step_Result result; + + input_data = input_chunk.trans.key_data; + mouse.out_of_window = input_chunk.trans.out_of_window; + + mouse.l = input_chunk.pers.mouse_l; + mouse.press_l = input_chunk.trans.mouse_l_press; + mouse.release_l = input_chunk.trans.mouse_l_release; + + mouse.r = input_chunk.pers.mouse_r; + mouse.press_r = input_chunk.trans.mouse_r_press; + mouse.release_r = input_chunk.trans.mouse_r_release; + + mouse.wheel = input_chunk.trans.mouse_wheel; + + mouse.x = input_chunk.pers.mouse_x; + mouse.y = input_chunk.pers.mouse_y; + + result.mouse_cursor_type = APP_MOUSE_CURSOR_DEFAULT; + result.lctrl_lalt_is_altgr = win32vars.lctrl_lalt_is_altgr; + result.trying_to_kill = input_chunk.trans.trying_to_kill; + result.perform_kill = 0; + + // NOTE(allen): The expected dt given the frame limit in seconds. + f32 dt = frame_useconds / 1000000.f; + + win32vars.app.step(&win32vars.system, + &input_data, + &mouse, + &win32vars.target, + &memory_vars, + &exchange_vars, + win32vars.clipboard_contents, + dt, win32vars.first, + &result); + + if (result.perform_kill){ + win32vars.input_chunk.pers.keep_playing = 0; + } + + Win32SetCursorFromUpdate(result.mouse_cursor_type); + win32vars.lctrl_lalt_is_altgr = result.lctrl_lalt_is_altgr; + + HDC hdc = GetDC(win32vars.window_handle); + Win32RedrawScreen(hdc); + ReleaseDC(win32vars.window_handle, hdc); + + win32vars.first = 0; + + if (result.animating){ + PostMessage(win32vars.window_handle, WM_4coder_ANIMATE, 0, 0); + } + + u64 timer_end = Win32HighResolutionTime(); + u64 end_target = timer_start + frame_useconds; + + system_release_lock(FRAME_LOCK); + while (timer_end < end_target){ + DWORD samount = (DWORD)((end_target - timer_end) / 1000); + if (samount > 0) Sleep(samount); + timer_end = Win32HighResolutionTime(); + } + system_acquire_lock(FRAME_LOCK); + timer_start = Win32HighResolutionTime(); } return(0); From 93a1d3931fb603342ac050ac5cb55feeeae72933 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Sun, 29 May 2016 15:28:29 -0400 Subject: [PATCH 06/34] switched app.step over to a big input struct so that the signature does not have to change if I want to pass in more parameters in the future --- 4ed.cpp | 82 +++---- 4ed.h | 28 ++- win32_4ed.cpp | 586 +++++++++++++++++++++++++------------------------- 3 files changed, 358 insertions(+), 338 deletions(-) diff --git a/4ed.cpp b/4ed.cpp index 7ed77572..5a6e16f0 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -3631,51 +3631,53 @@ consume_input(Available_Input *available, i32 input_type){ App_Step_Sig(app_step){ Application_Step_Result app_result = *result; app_result.animating = 0; - + App_Vars *vars = (App_Vars*)memory->vars_memory; Models *models = &vars->models; target->partition = &models->mem.part; - + // NOTE(allen): OS clipboard event handling + String clipboard = input->clipboard; + if (clipboard.str){ String *dest = working_set_next_clipboard_string(&models->mem.general, &models->working_set, clipboard.size); dest->size = eol_convert_in(dest->str, clipboard.str, clipboard.size); } - + // NOTE(allen): check files are up to date { File_Node *node, *used_nodes; Editing_File *file; u64 time_stamp; - + used_nodes = &models->working_set.used_sentinel; for (dll_items(node, used_nodes)){ file = (Editing_File*)node; - + time_stamp = system->file_time_stamp(make_c_str(file->name.source_path)); - + if (time_stamp > 0){ file->state.last_sys_write_time = time_stamp; } } } - + // NOTE(allen): reorganizing panels on screen { i32 prev_width = models->layout.full_width; i32 prev_height = models->layout.full_height; i32 current_width = target->width; i32 current_height = target->height; - + Panel *panel, *used_panels; View *view; - + models->layout.full_width = current_width; models->layout.full_height = current_height; - + if (prev_width != current_width || prev_height != current_height){ layout_refit(&models->layout, prev_width, prev_height); - + used_panels = &models->layout.used_sentinel; for (dll_items(panel, used_panels)){ view = panel->view; @@ -3689,18 +3691,18 @@ App_Step_Sig(app_step){ // NOTE(allen): prepare input information Key_Summary key_summary = {0}; - for (i32 i = 0; i < input->press_count; ++i){ - key_summary.keys[key_summary.count++] = input->press[i]; + for (i32 i = 0; i < input->keys.press_count; ++i){ + key_summary.keys[key_summary.count++] = input->keys.press[i]; } - for (i32 i = 0; i < input->hold_count; ++i){ - key_summary.keys[key_summary.count++] = input->hold[i]; + for (i32 i = 0; i < input->keys.hold_count; ++i){ + key_summary.keys[key_summary.count++] = input->keys.hold[i]; } - mouse->wheel = -mouse->wheel; + input->mouse.wheel = -input->mouse.wheel; // NOTE(allen): detect mouse hover status - i32 mx = mouse->x; - i32 my = mouse->y; + i32 mx = input->mouse.x; + i32 my = input->mouse.y; b32 mouse_in_edit_area = 0; b32 mouse_in_margin_area = 0; Panel *mouse_panel, *used_panels; @@ -3787,7 +3789,7 @@ App_Step_Sig(app_step){ } // NOTE(allen): update child processes - if (dt > 0){ + if (input->dt > 0){ Temp_Memory temp = begin_temp_memory(&models->mem.part); u32 max = Kbytes(32); char *dest = push_array(&models->mem.part, char, max); @@ -3830,7 +3832,7 @@ App_Step_Sig(app_step){ Temp_Memory param_stack_temp = begin_temp_memory(&models->mem.part); cmd->part = partition_sub_part(&models->mem.part, 16 << 10); - if (first_step){ + if (input->first_step){ #if 0 { @@ -3954,7 +3956,7 @@ App_Step_Sig(app_step){ } // NOTE(allen): process the command_coroutine if it is unfinished - Available_Input available_input = init_available_input(&key_summary, mouse); + Available_Input available_input = init_available_input(&key_summary, &input->mouse); // NOTE(allen): Keyboard input to command coroutine. if (models->command_coroutine != 0){ @@ -4029,7 +4031,7 @@ App_Step_Sig(app_step){ User_Input user_in; user_in.type = UserInputMouse; - user_in.mouse = *mouse; + user_in.mouse = input->mouse; user_in.command = 0; user_in.abort = 0; @@ -4041,7 +4043,7 @@ App_Step_Sig(app_step){ consume_input(&available_input, Input_MouseMove); } - if (mouse->press_l || mouse->release_l || mouse->l){ + if (input->mouse.press_l || input->mouse.release_l || input->mouse.l){ if (abort_flags & EventOnLeftButton){ user_in.abort = 1; } @@ -4051,7 +4053,7 @@ App_Step_Sig(app_step){ } } - if (mouse->press_r || mouse->release_r || mouse->r){ + if (input->mouse.press_r || input->mouse.release_r || input->mouse.r){ if (abort_flags & EventOnRightButton){ user_in.abort = 1; } @@ -4061,7 +4063,7 @@ App_Step_Sig(app_step){ } } - if (mouse->wheel != 0){ + if (input->mouse.wheel != 0){ if (abort_flags & EventOnWheel){ user_in.abort = 1; } @@ -4095,12 +4097,12 @@ App_Step_Sig(app_step){ // NOTE(allen): pass raw input to the panels Input_Summary dead_input = {}; - dead_input.mouse.x = mouse->x; - dead_input.mouse.y = mouse->y; + dead_input.mouse.x = input->mouse.x; + dead_input.mouse.y = input->mouse.y; Input_Summary active_input = {}; - active_input.mouse.x = mouse->x; - active_input.mouse.y = mouse->y; + active_input.mouse.x = input->mouse.x; + active_input.mouse.y = input->mouse.y; active_input.keys = get_key_data(&available_input); @@ -4110,7 +4112,7 @@ App_Step_Sig(app_step){ Panel *panel = 0, *used_panels = 0; View *view = 0, *active_view = 0; b32 active = 0; - Input_Summary input = {0}; + Input_Summary summary = {0}; Input_Process_Result result = {0}; active_view = cmd->panel->view; @@ -4118,8 +4120,8 @@ App_Step_Sig(app_step){ for (dll_items(panel, used_panels)){ view = panel->view; active = (panel == cmd->panel); - input = (active)?(active_input):(dead_input); - if (step_file_view(system, view, active_view, input)){ + summary = (active)?(active_input):(dead_input); + if (step_file_view(system, view, active_view, summary)){ app_result.animating = 1; } } @@ -4128,9 +4130,9 @@ App_Step_Sig(app_step){ view = panel->view; Assert(view->current_scroll); active = (panel == cmd->panel); - input = (active)?(active_input):(dead_input); - if (panel == mouse_panel && !mouse->out_of_window){ - input.mouse = mouse_state; + summary = (active)?(active_input):(dead_input); + if (panel == mouse_panel && !input->mouse.out_of_window){ + summary.mouse = mouse_state; } @@ -4138,7 +4140,7 @@ App_Step_Sig(app_step){ // TODO(allen): I feel like the scroll context should actually not // be allowed to change in here at all. result = do_input_file_view(system, exchange, view, panel->inner, active, - &input, *vars, view->scroll_region); + &summary, *vars, view->scroll_region); if (result.is_animating){ app_result.animating = 1; } @@ -4219,7 +4221,7 @@ App_Step_Sig(app_step){ update_command_data(vars, cmd); // NOTE(allen): initialize message - if (first_step){ + if (input->first_step){ String welcome = make_lit_string("Welcome to " VERSION "\n" "If you're new to 4coder there's no tutorial yet :(\n" @@ -4256,7 +4258,7 @@ App_Step_Sig(app_step){ switch (vars->state){ case APP_STATE_EDIT: { - if (mouse->press_l && mouse_on_divider){ + if (input->mouse.press_l && mouse_on_divider){ vars->state = APP_STATE_RESIZING; Divider_And_ID div = layout_get_divider(&models->layout, mouse_divider_id); vars->resizing.divider = div.divider; @@ -4323,7 +4325,7 @@ App_Step_Sig(app_step){ case APP_STATE_RESIZING: { - if (mouse->l){ + if (input->mouse.l){ Panel_Divider *divider = vars->resizing.divider; if (divider->v_divider){ divider->pos = mx; @@ -4347,7 +4349,7 @@ App_Step_Sig(app_step){ }break; } - if (mouse_in_edit_area && mouse_panel != 0 && mouse->press_l){ + if (mouse_in_edit_area && mouse_panel != 0 && input->mouse.press_l){ models->layout.active_panel = (i32)(mouse_panel - models->layout.panels); } diff --git a/4ed.h b/4ed.h index 33d14324..c9d27895 100644 --- a/4ed.h +++ b/4ed.h @@ -81,17 +81,19 @@ struct Plat_Settings{ typedef App_Read_Command_Line_Sig(App_Read_Command_Line); + #define App_Init_Sig(name) void \ name(System_Functions *system, \ - Render_Target *target, \ - Application_Memory *memory, \ - Exchange *exchange, \ - String clipboard, \ - String current_directory, \ - Custom_API api) + Render_Target *target, \ + Application_Memory *memory, \ + Exchange *exchange, \ + String clipboard, \ + String current_directory, \ + Custom_API api) typedef App_Init_Sig(App_Init); + enum Application_Mouse_Cursor{ APP_MOUSE_CURSOR_DEFAULT, APP_MOUSE_CURSOR_ARROW, @@ -110,19 +112,25 @@ struct Application_Step_Result{ b32 animating; }; +struct Application_Step_Input{ + b32 first_step; + f32 dt; + Key_Input_Data keys; + Mouse_State mouse; + String clipboard; +}; + #define App_Step_Sig(name) void \ name(System_Functions *system, \ - Key_Input_Data *input, \ - Mouse_State *mouse, \ Render_Target *target, \ Application_Memory *memory, \ Exchange *exchange, \ - String clipboard, \ - f32 dt, b32 first_step, \ + Application_Step_Input *input, \ Application_Step_Result *result) typedef App_Step_Sig(App_Step); + struct App_Functions{ App_Read_Command_Line *read_command_line; App_Init *init; diff --git a/win32_4ed.cpp b/win32_4ed.cpp index a374ff13..085e2305 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -89,8 +89,6 @@ struct Win32_Input_Chunk_Persistent{ i32 mouse_x, mouse_y; b8 mouse_l, mouse_r; - b8 keep_playing; - Control_Keys controls; b8 control_keys[MDFR_INDEX_COUNT]; }; @@ -124,13 +122,11 @@ struct Win32_Vars{ DLL_Loaded app_dll; DLL_Loaded custom_dll; #endif - Plat_Settings settings; Thread_Group groups[THREAD_GROUP_COUNT]; CRITICAL_SECTION locks[LOCK_COUNT]; - CRITICAL_SECTION DEBUG_sysmem_lock; Thread_Memory *thread_memory; Win32_Coroutine coroutine_data[18]; Win32_Coroutine *coroutine_free; @@ -161,6 +157,7 @@ struct Win32_Vars{ #if FRED_INTERNAL + CRITICAL_SECTION DEBUG_sysmem_lock; Sys_Bubble internal_bubble; #endif }; @@ -169,6 +166,11 @@ globalvar Win32_Vars win32vars; globalvar Application_Memory memory_vars; globalvar Exchange exchange_vars; + +// +// Helpers +// + internal HANDLE Win32Handle(Plat_Handle h){ HANDLE result; @@ -198,6 +200,7 @@ Win32Ptr(void *h){ return(result); } + // // Memory (not exposed to application, but needed in system_shared.cpp) // @@ -259,8 +262,269 @@ INTERNAL_system_debug_message(char *message){ } #endif + // -// File +// Multithreading +// + +internal +Sys_Acquire_Lock_Sig(system_acquire_lock){ + EnterCriticalSection(&win32vars.locks[id]); +} + +internal +Sys_Release_Lock_Sig(system_release_lock){ + LeaveCriticalSection(&win32vars.locks[id]); +} + +internal DWORD +JobThreadProc(LPVOID lpParameter){ + Thread_Context *thread = (Thread_Context*)lpParameter; + Work_Queue *queue = thread->queue; + + for (;;){ + u32 read_index = queue->read_position; + u32 write_index = queue->write_position; + + if (read_index != write_index){ + u32 next_read_index = (read_index + 1) % JOB_ID_WRAP; + u32 safe_read_index = + InterlockedCompareExchange(&queue->read_position, + next_read_index, read_index); + + if (safe_read_index == read_index){ + Full_Job_Data *full_job = queue->jobs + (safe_read_index % QUEUE_WRAP); + // NOTE(allen): This is interlocked so that it plays nice + // with the cancel job routine, which may try to cancel this job + // at the same time that we try to run it + + i32 safe_running_thread = + InterlockedCompareExchange(&full_job->running_thread, + thread->id, THREAD_NOT_ASSIGNED); + + if (safe_running_thread == THREAD_NOT_ASSIGNED){ + thread->job_id = full_job->id; + thread->running = 1; + Thread_Memory *thread_memory = 0; + + // TODO(allen): remove memory_request + if (full_job->job.memory_request != 0){ + thread_memory = win32vars.thread_memory + thread->id - 1; + if (thread_memory->size < full_job->job.memory_request){ + if (thread_memory->data){ + Win32FreeMemory(thread_memory->data); + } + i32 new_size = LargeRoundUp(full_job->job.memory_request, Kbytes(4)); + thread_memory->data = Win32GetMemory(new_size); + thread_memory->size = new_size; + } + } + full_job->job.callback(&win32vars.system, thread, thread_memory, + &exchange_vars.thread, full_job->job.data); + PostMessage(win32vars.window_handle, WM_4coder_ANIMATE, 0, 0); + full_job->running_thread = 0; + thread->running = 0; + } + } + } + else{ + WaitForSingleObject(Win32Handle(queue->semaphore), INFINITE); + } + } +} + +internal +Sys_Post_Job_Sig(system_post_job){ + Work_Queue *queue = exchange_vars.thread.queues + group_id; + + Assert((queue->write_position + 1) % QUEUE_WRAP != queue->read_position % QUEUE_WRAP); + + b32 success = 0; + u32 result = 0; + while (!success){ + u32 write_index = queue->write_position; + u32 next_write_index = (write_index + 1) % JOB_ID_WRAP; + u32 safe_write_index = + InterlockedCompareExchange(&queue->write_position, + next_write_index, write_index); + if (safe_write_index == write_index){ + result = write_index; + write_index = write_index % QUEUE_WRAP; + queue->jobs[write_index].job = job; + queue->jobs[write_index].running_thread = THREAD_NOT_ASSIGNED; + queue->jobs[write_index].id = result; + success = 1; + } + } + + ReleaseSemaphore(Win32Handle(queue->semaphore), 1, 0); + + return result; +} + +// TODO(allen): I would like to get rid of job canceling +// but I still don't know what exactly I would do without it. +internal +Sys_Cancel_Job_Sig(system_cancel_job){ + Work_Queue *queue = exchange_vars.thread.queues + group_id; + Thread_Group *group = win32vars.groups + group_id; + + u32 job_index; + u32 thread_id; + Full_Job_Data *full_job; + Thread_Context *thread; + + job_index = job_id % QUEUE_WRAP; + full_job = queue->jobs + job_index; + + Assert(full_job->id == job_id); + thread_id = + InterlockedCompareExchange(&full_job->running_thread, + 0, THREAD_NOT_ASSIGNED); + + if (thread_id != THREAD_NOT_ASSIGNED){ + system_acquire_lock(CANCEL_LOCK0 + thread_id - 1); + thread = group->threads + thread_id - 1; + TerminateThread(thread->handle, 0); + u32 creation_flag = 0; + thread->handle = CreateThread(0, 0, JobThreadProc, thread, creation_flag, (LPDWORD)&thread->windows_id); + system_release_lock(CANCEL_LOCK0 + thread_id - 1); + thread->running = 0; + } +} + +internal void +system_grow_thread_memory(Thread_Memory *memory){ + void *old_data; + i32 old_size, new_size; + + system_acquire_lock(CANCEL_LOCK0 + memory->id - 1); + old_data = memory->data; + old_size = memory->size; + new_size = LargeRoundUp(memory->size*2, Kbytes(4)); + memory->data = system_get_memory(new_size); + memory->size = new_size; + if (old_data){ + memcpy(memory->data, old_data, old_size); + system_free_memory(old_data); + } + system_release_lock(CANCEL_LOCK0 + memory->id - 1); +} + +#if FRED_INTERNAL +internal void +INTERNAL_get_thread_states(Thread_Group_ID id, bool8 *running, i32 *pending){ + Work_Queue *queue = exchange_vars.thread.queues + id; + u32 write = queue->write_position; + u32 read = queue->read_position; + if (write < read) write += JOB_ID_WRAP; + *pending = (i32)(write - read); + + Thread_Group *group = win32vars.groups + id; + for (i32 i = 0; i < group->count; ++i){ + running[i] = (group->threads[i].running != 0); + } +} +#endif + + +// +// Coroutines +// + +internal Win32_Coroutine* +Win32AllocCoroutine(){ + Win32_Coroutine *result = win32vars.coroutine_free; + Assert(result != 0); + win32vars.coroutine_free = result->next; + return(result); +} + +internal void +Win32FreeCoroutine(Win32_Coroutine *data){ + data->next = win32vars.coroutine_free; + win32vars.coroutine_free = data; +} + +internal void +Win32CoroutineMain(void *arg_){ + Win32_Coroutine *c = (Win32_Coroutine*)arg_; + c->coroutine.func(&c->coroutine); + c->done = 1; + Win32FreeCoroutine(c); + SwitchToFiber(c->coroutine.yield_handle); +} + +internal +Sys_Create_Coroutine_Sig(system_create_coroutine){ + Win32_Coroutine *c; + Coroutine *coroutine; + void *fiber; + + c = Win32AllocCoroutine(); + c->done = 0; + + coroutine = &c->coroutine; + + fiber = CreateFiber(0, Win32CoroutineMain, coroutine); + + coroutine->plat_handle = Win32Handle(fiber); + coroutine->func = func; + + return(coroutine); +} + +internal +Sys_Launch_Coroutine_Sig(system_launch_coroutine){ + Win32_Coroutine *c = (Win32_Coroutine*)coroutine; + void *fiber; + + fiber = Win32Handle(coroutine->plat_handle); + coroutine->yield_handle = GetCurrentFiber(); + coroutine->in = in; + coroutine->out = out; + + SwitchToFiber(fiber); + + if (c->done){ + DeleteFiber(fiber); + Win32FreeCoroutine(c); + coroutine = 0; + } + + return(coroutine); +} + +Sys_Resume_Coroutine_Sig(system_resume_coroutine){ + Win32_Coroutine *c = (Win32_Coroutine*)coroutine; + void *fiber; + + Assert(c->done == 0); + + coroutine->yield_handle = GetCurrentFiber(); + coroutine->in = in; + coroutine->out = out; + + fiber = Win32Ptr(coroutine->plat_handle); + + SwitchToFiber(fiber); + + if (c->done){ + DeleteFiber(fiber); + Win32FreeCoroutine(c); + coroutine = 0; + } + + return(coroutine); +} + +Sys_Yield_Coroutine_Sig(system_yield_coroutine){ + SwitchToFiber(coroutine->yield_handle); +} + + +// +// Files // internal @@ -602,6 +866,7 @@ GET_4ED_PATH_SIG(system_get_4ed_path){ return(system_get_binary_path(&str)); } + // // Clipboard // @@ -646,263 +911,6 @@ Win32ReadClipboardContents(){ return(result); } -// -// Multithreading -// - -internal -Sys_Acquire_Lock_Sig(system_acquire_lock){ - EnterCriticalSection(&win32vars.locks[id]); -} - -internal -Sys_Release_Lock_Sig(system_release_lock){ - LeaveCriticalSection(&win32vars.locks[id]); -} - -internal DWORD -JobThreadProc(LPVOID lpParameter){ - Thread_Context *thread = (Thread_Context*)lpParameter; - Work_Queue *queue = thread->queue; - - for (;;){ - u32 read_index = queue->read_position; - u32 write_index = queue->write_position; - - if (read_index != write_index){ - u32 next_read_index = (read_index + 1) % JOB_ID_WRAP; - u32 safe_read_index = - InterlockedCompareExchange(&queue->read_position, - next_read_index, read_index); - - if (safe_read_index == read_index){ - Full_Job_Data *full_job = queue->jobs + (safe_read_index % QUEUE_WRAP); - // NOTE(allen): This is interlocked so that it plays nice - // with the cancel job routine, which may try to cancel this job - // at the same time that we try to run it - - i32 safe_running_thread = - InterlockedCompareExchange(&full_job->running_thread, - thread->id, THREAD_NOT_ASSIGNED); - - if (safe_running_thread == THREAD_NOT_ASSIGNED){ - thread->job_id = full_job->id; - thread->running = 1; - Thread_Memory *thread_memory = 0; - - // TODO(allen): remove memory_request - if (full_job->job.memory_request != 0){ - thread_memory = win32vars.thread_memory + thread->id - 1; - if (thread_memory->size < full_job->job.memory_request){ - if (thread_memory->data){ - Win32FreeMemory(thread_memory->data); - } - i32 new_size = LargeRoundUp(full_job->job.memory_request, Kbytes(4)); - thread_memory->data = Win32GetMemory(new_size); - thread_memory->size = new_size; - } - } - full_job->job.callback(&win32vars.system, thread, thread_memory, - &exchange_vars.thread, full_job->job.data); - PostMessage(win32vars.window_handle, WM_4coder_ANIMATE, 0, 0); - full_job->running_thread = 0; - thread->running = 0; - } - } - } - else{ - WaitForSingleObject(Win32Handle(queue->semaphore), INFINITE); - } - } -} - -internal -Sys_Post_Job_Sig(system_post_job){ - Work_Queue *queue = exchange_vars.thread.queues + group_id; - - Assert((queue->write_position + 1) % QUEUE_WRAP != queue->read_position % QUEUE_WRAP); - - b32 success = 0; - u32 result = 0; - while (!success){ - u32 write_index = queue->write_position; - u32 next_write_index = (write_index + 1) % JOB_ID_WRAP; - u32 safe_write_index = - InterlockedCompareExchange(&queue->write_position, - next_write_index, write_index); - if (safe_write_index == write_index){ - result = write_index; - write_index = write_index % QUEUE_WRAP; - queue->jobs[write_index].job = job; - queue->jobs[write_index].running_thread = THREAD_NOT_ASSIGNED; - queue->jobs[write_index].id = result; - success = 1; - } - } - - ReleaseSemaphore(Win32Handle(queue->semaphore), 1, 0); - - return result; -} - -// TODO(allen): I would like to get rid of job canceling -// but I still don't know what exactly I would do without it. -internal -Sys_Cancel_Job_Sig(system_cancel_job){ - Work_Queue *queue = exchange_vars.thread.queues + group_id; - Thread_Group *group = win32vars.groups + group_id; - - u32 job_index; - u32 thread_id; - Full_Job_Data *full_job; - Thread_Context *thread; - - job_index = job_id % QUEUE_WRAP; - full_job = queue->jobs + job_index; - - Assert(full_job->id == job_id); - thread_id = - InterlockedCompareExchange(&full_job->running_thread, - 0, THREAD_NOT_ASSIGNED); - - if (thread_id != THREAD_NOT_ASSIGNED){ - system_acquire_lock(CANCEL_LOCK0 + thread_id - 1); - thread = group->threads + thread_id - 1; - TerminateThread(thread->handle, 0); - u32 creation_flag = 0; - thread->handle = CreateThread(0, 0, JobThreadProc, thread, creation_flag, (LPDWORD)&thread->windows_id); - system_release_lock(CANCEL_LOCK0 + thread_id - 1); - thread->running = 0; - } -} - -internal void -system_grow_thread_memory(Thread_Memory *memory){ - void *old_data; - i32 old_size, new_size; - - system_acquire_lock(CANCEL_LOCK0 + memory->id - 1); - old_data = memory->data; - old_size = memory->size; - new_size = LargeRoundUp(memory->size*2, Kbytes(4)); - memory->data = system_get_memory(new_size); - memory->size = new_size; - if (old_data){ - memcpy(memory->data, old_data, old_size); - system_free_memory(old_data); - } - system_release_lock(CANCEL_LOCK0 + memory->id - 1); -} - -#if FRED_INTERNAL -internal void -INTERNAL_get_thread_states(Thread_Group_ID id, bool8 *running, i32 *pending){ - Work_Queue *queue = exchange_vars.thread.queues + id; - u32 write = queue->write_position; - u32 read = queue->read_position; - if (write < read) write += JOB_ID_WRAP; - *pending = (i32)(write - read); - - Thread_Group *group = win32vars.groups + id; - for (i32 i = 0; i < group->count; ++i){ - running[i] = (group->threads[i].running != 0); - } -} -#endif - -// -// Coroutine -// - -internal Win32_Coroutine* -Win32AllocCoroutine(){ - Win32_Coroutine *result = win32vars.coroutine_free; - Assert(result != 0); - win32vars.coroutine_free = result->next; - return(result); -} - -internal void -Win32FreeCoroutine(Win32_Coroutine *data){ - data->next = win32vars.coroutine_free; - win32vars.coroutine_free = data; -} - -internal void -Win32CoroutineMain(void *arg_){ - Win32_Coroutine *c = (Win32_Coroutine*)arg_; - c->coroutine.func(&c->coroutine); - c->done = 1; - Win32FreeCoroutine(c); - SwitchToFiber(c->coroutine.yield_handle); -} - -internal -Sys_Create_Coroutine_Sig(system_create_coroutine){ - Win32_Coroutine *c; - Coroutine *coroutine; - void *fiber; - - c = Win32AllocCoroutine(); - c->done = 0; - - coroutine = &c->coroutine; - - fiber = CreateFiber(0, Win32CoroutineMain, coroutine); - - coroutine->plat_handle = Win32Handle(fiber); - coroutine->func = func; - - return(coroutine); -} - -internal -Sys_Launch_Coroutine_Sig(system_launch_coroutine){ - Win32_Coroutine *c = (Win32_Coroutine*)coroutine; - void *fiber; - - fiber = Win32Handle(coroutine->plat_handle); - coroutine->yield_handle = GetCurrentFiber(); - coroutine->in = in; - coroutine->out = out; - - SwitchToFiber(fiber); - - if (c->done){ - DeleteFiber(fiber); - Win32FreeCoroutine(c); - coroutine = 0; - } - - return(coroutine); -} - -Sys_Resume_Coroutine_Sig(system_resume_coroutine){ - Win32_Coroutine *c = (Win32_Coroutine*)coroutine; - void *fiber; - - Assert(c->done == 0); - - coroutine->yield_handle = GetCurrentFiber(); - coroutine->in = in; - coroutine->out = out; - - fiber = Win32Ptr(coroutine->plat_handle); - - SwitchToFiber(fiber); - - if (c->done){ - DeleteFiber(fiber); - Win32FreeCoroutine(c); - coroutine = 0; - } - - return(coroutine); -} - -Sys_Yield_Coroutine_Sig(system_yield_coroutine){ - SwitchToFiber(coroutine->yield_handle); -} // // Command Line Exectuion @@ -1780,6 +1788,7 @@ WinMain(HINSTANCE hInstance, } win32vars.custom_api.view_routine = (View_Routine_Function*)0; + #if 0 if (win32vars.custom_api.view_routine == 0){ win32vars.custom_api.view_routine = (View_Routine_Function*)view_routine; @@ -1953,7 +1962,7 @@ WinMain(HINSTANCE hInstance, system_free_memory(current_directory.str); - win32vars.input_chunk.pers.keep_playing = 1; + b32 keep_playing = 1; win32vars.first = 1; timeBeginPeriod(1); @@ -1964,7 +1973,7 @@ WinMain(HINSTANCE hInstance, u64 timer_start = Win32HighResolutionTime(); system_acquire_lock(FRAME_LOCK); MSG msg; - for (;win32vars.input_chunk.pers.keep_playing;){ + for (;keep_playing;){ // TODO(allen): Find a good way to wait on a pipe // without interfering with the reading process // Looks like we can ReadFile with a size of zero @@ -1977,7 +1986,7 @@ WinMain(HINSTANCE hInstance, for (;win32vars.got_useful_event == 0;){ if (GetMessage(&msg, 0, 0, 0)){ if (msg.message == WM_QUIT){ - win32vars.input_chunk.pers.keep_playing = 0; + keep_playing = 0; }else{ TranslateMessage(&msg); DispatchMessage(&msg); @@ -1988,7 +1997,7 @@ WinMain(HINSTANCE hInstance, while (PeekMessage(&msg, 0, 0, 0, 1)){ if (msg.message == WM_QUIT){ - win32vars.input_chunk.pers.keep_playing = 0; + keep_playing = 0; }else{ TranslateMessage(&msg); DispatchMessage(&msg); @@ -2034,46 +2043,47 @@ WinMain(HINSTANCE hInstance, } } - Key_Input_Data input_data; - Mouse_State mouse; - Application_Step_Result result; + Application_Step_Input input = {0}; - input_data = input_chunk.trans.key_data; - mouse.out_of_window = input_chunk.trans.out_of_window; + input.first_step = win32vars.first; - mouse.l = input_chunk.pers.mouse_l; - mouse.press_l = input_chunk.trans.mouse_l_press; - mouse.release_l = input_chunk.trans.mouse_l_release; + // NOTE(allen): The expected dt given the frame limit in seconds. + input.dt = frame_useconds / 1000000.f; - mouse.r = input_chunk.pers.mouse_r; - mouse.press_r = input_chunk.trans.mouse_r_press; - mouse.release_r = input_chunk.trans.mouse_r_release; + input.keys = input_chunk.trans.key_data; - mouse.wheel = input_chunk.trans.mouse_wheel; + input.mouse.out_of_window = input_chunk.trans.out_of_window; - mouse.x = input_chunk.pers.mouse_x; - mouse.y = input_chunk.pers.mouse_y; + input.mouse.l = input_chunk.pers.mouse_l; + input.mouse.press_l = input_chunk.trans.mouse_l_press; + input.mouse.release_l = input_chunk.trans.mouse_l_release; + input.mouse.r = input_chunk.pers.mouse_r; + input.mouse.press_r = input_chunk.trans.mouse_r_press; + input.mouse.release_r = input_chunk.trans.mouse_r_release; + + input.mouse.wheel = input_chunk.trans.mouse_wheel; + input.mouse.x = input_chunk.pers.mouse_x; + input.mouse.y = input_chunk.pers.mouse_y; + + input.clipboard = win32vars.clipboard_contents; + + + Application_Step_Result result = {(Application_Mouse_Cursor)0}; result.mouse_cursor_type = APP_MOUSE_CURSOR_DEFAULT; result.lctrl_lalt_is_altgr = win32vars.lctrl_lalt_is_altgr; result.trying_to_kill = input_chunk.trans.trying_to_kill; result.perform_kill = 0; - // NOTE(allen): The expected dt given the frame limit in seconds. - f32 dt = frame_useconds / 1000000.f; - win32vars.app.step(&win32vars.system, - &input_data, - &mouse, &win32vars.target, &memory_vars, &exchange_vars, - win32vars.clipboard_contents, - dt, win32vars.first, + &input, &result); if (result.perform_kill){ - win32vars.input_chunk.pers.keep_playing = 0; + keep_playing = 0; } Win32SetCursorFromUpdate(result.mouse_cursor_type); From d224d8cd7b206894186d2969d004e95bcdafb083 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Sun, 29 May 2016 15:54:20 -0400 Subject: [PATCH 07/34] removed save, save_as, and new from the dact system --- 4ed.cpp | 61 ++--- 4ed_delay.cpp | 6 - 4ed_file_view.cpp | 611 +++++++++++++++++++++++++--------------------- 4ed_metagen.cpp | 3 + 4 files changed, 349 insertions(+), 332 deletions(-) diff --git a/4ed.cpp b/4ed.cpp index 5a6e16f0..e886b4e0 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -931,8 +931,6 @@ COMMAND_DECL(save){ USE_VIEW(view); USE_FILE(file, view); - Delay *delay = &models->delay1; - char *filename = 0; int filename_len = 0; int buffer_id = -1; @@ -963,11 +961,12 @@ COMMAND_DECL(save){ if (filename){ name = make_string(filename, filename_len); } - + if (file){ if (name.str){ if (!file->state.is_dummy && file_is_ready(file)){ - delayed_save_as(delay, name, file); + view_save_file(system, &models->mem, &models->working_set, + file, 0, name, 1); } } else{ @@ -977,7 +976,7 @@ COMMAND_DECL(save){ } } else{ - String name = {}; + String name = {0}; if (filename){ name = make_string(filename, filename_len); } @@ -988,11 +987,13 @@ COMMAND_DECL(save){ if (name.size != 0){ if (file){ if (!file->state.is_dummy && file_is_ready(file)){ - delayed_save(delay, name, file); + view_save_file(system, &models->mem, &models->working_set, + file, 0, name, 0); } } else{ - delayed_save(delay, name); + view_save_file(system, &models->mem, &models->working_set, + 0, 0, name, 0); } } } @@ -4437,54 +4438,20 @@ App_Step_Sig(app_step){ } }break; +#if 0 case DACT_SAVE: case DACT_SAVE_AS: { - if (!file){ - if (panel){ - View *view = panel->view; - Assert(view); - file = view->file_data.file; - } - else{ - file = working_set_lookup_file(working_set, string); - } - } - if (file && buffer_get_sync(file) != SYNC_GOOD){ - if (file_save(system, mem, file, string.str)){ - if (act->type == DACT_SAVE_AS){ - file_set_name(working_set, file, string.str); - } - } - } }break; - +#endif + +#if 0 case DACT_NEW: { - Editing_File *file = working_set_alloc_always(working_set, general); - file_create_empty(system, models, file, string.str); - working_set_add(system, working_set, file, general); - - View *view = panel->view; - - view_set_file(view, file, models); - view_show_file(view); - view->map = get_map(models, file->settings.base_map_id); - - Hook_Function *new_file_fnc = models->hooks[hook_new_file]; - if (new_file_fnc){ - models->buffer_param_indices[models->buffer_param_count++] = file->id.id; - new_file_fnc(&models->app_links); - models->buffer_param_count = 0; - file->settings.is_initialized = 1; - } - -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - if (file->settings.tokens_exist) - file_first_lex_parallel(system, general, file); -#endif + }break; +#endif case DACT_SWITCH: { diff --git a/4ed_delay.cpp b/4ed_delay.cpp index 715a1550..44c4062d 100644 --- a/4ed_delay.cpp +++ b/4ed_delay.cpp @@ -2,9 +2,6 @@ enum Action_Type{ DACT_OPEN, DACT_OPEN_BACKGROUND, DACT_SET_LINE, - DACT_SAVE_AS, - DACT_SAVE, - DACT_NEW, DACT_SWITCH, DACT_TRY_KILL, DACT_KILL, @@ -130,9 +127,6 @@ delayed_action_repush(Delay *delay, Delayed_Action *act){ #define delayed_open(delay, ...) delayed_action_(delay, DACT_OPEN, ##__VA_ARGS__) #define delayed_open_background(delay, ...) delayed_action_(delay, DACT_OPEN_BACKGROUND, ##__VA_ARGS__) #define delayed_set_line(delay, ...) delayed_action_(delay, DACT_SET_LINE, ##__VA_ARGS__) -#define delayed_save_as(delay, ...) delayed_action_(delay, DACT_SAVE_AS, ##__VA_ARGS__) -#define delayed_save(delay, ...) delayed_action_(delay, DACT_SAVE, ##__VA_ARGS__) -#define delayed_new(delay, ...) delayed_action_(delay, DACT_NEW, ##__VA_ARGS__) #define delayed_switch(delay, ...) delayed_action_(delay, DACT_SWITCH, ##__VA_ARGS__) #define delayed_try_kill(delay, ...) delayed_action_(delay, DACT_TRY_KILL, ##__VA_ARGS__) #define delayed_kill(delay, ...) delayed_action_(delay, DACT_KILL, ##__VA_ARGS__) diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index 50220485..bc543671 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -452,7 +452,13 @@ file_save(System_Functions *system, Mem_Options *mem, Editing_File *file, char * } Temp_Memory temp = begin_temp_memory(&mem->part); - data = (char*)push_array(&mem->part, char, max); + char empty = 0; + if (max == 0){ + data = ∅ + } + else{ + data = (char*)push_array(&mem->part, char, max); + } Assert(data); if (dos_write_mode){ @@ -508,18 +514,18 @@ file_grow_starts_widths_as_needed(General_Memory *general, Buffer_Type *buffer, i32 count = buffer->line_count; i32 target_lines = count + additional_lines; Assert(max == buffer->widths_max); - + if (target_lines > max || max == 0){ max = LargeRoundUp(target_lines + max, Kbytes(1)); - + f32 *new_widths = (f32*)general_memory_reallocate( general, buffer->line_widths, sizeof(f32)*count, sizeof(f32)*max, BUBBLE_WIDTHS); - + i32 *new_lines = (i32*)general_memory_reallocate( general, buffer->line_starts, sizeof(i32)*count, sizeof(i32)*max, BUBBLE_STARTS); - + if (new_lines){ buffer->line_starts = new_lines; buffer->line_max = max; @@ -535,7 +541,7 @@ file_grow_starts_widths_as_needed(General_Memory *general, Buffer_Type *buffer, result = GROW_FAILED; } } - + return(result); } @@ -554,34 +560,34 @@ file_measure_starts_widths(System_Functions *system, General_Memory *general, TentativeAssert(buffer->line_starts); // TODO(allen): when unable to allocate? } - + Buffer_Measure_Starts state = {}; while (buffer_measure_starts_widths(&state, buffer, advance_data)){ i32 count = state.count; i32 max = buffer->line_max; max = ((max + 1) << 1); - + { i32 *new_lines = (i32*)general_memory_reallocate( general, buffer->line_starts, sizeof(i32)*count, sizeof(i32)*max, BUBBLE_STARTS); - + // TODO(allen): when unable to grow? TentativeAssert(new_lines); buffer->line_starts = new_lines; buffer->line_max = max; } - + { f32 *new_lines = (f32*) general_memory_reallocate(general, buffer->line_widths, sizeof(f32)*count, sizeof(f32)*max, BUBBLE_WIDTHS); - + // TODO(allen): when unable to grow? TentativeAssert(new_lines); buffer->line_widths = new_lines; buffer->widths_max = max; } - + } buffer->line_count = state.count; buffer->widths_count = state.count; @@ -619,7 +625,7 @@ view_compute_lowest_line(View *view){ f32 wrap_y = view->file_data.line_wrap_y[last_line]; lowest_line = FLOOR32(wrap_y / view->font_height); f32 max_width = view_file_width(view); - + Editing_File *file = view->file_data.file; Assert(!file->state.is_dummy); f32 width = file->state.buffer.line_widths[last_line]; @@ -633,10 +639,10 @@ view_compute_lowest_line(View *view){ internal void view_measure_wraps(General_Memory *general, View *view){ Buffer_Type *buffer; - + buffer = &view->file_data.file->state.buffer; i32 line_count = buffer->line_count; - + if (view->file_data.line_max < line_count){ i32 max = view->file_data.line_max = LargeRoundUp(line_count, Kbytes(1)); if (view->file_data.line_wrap_y){ @@ -648,27 +654,27 @@ view_measure_wraps(General_Memory *general, View *view){ general_memory_allocate(general, sizeof(f32)*max, BUBBLE_WRAPS); } } - + f32 line_height = (f32)view->font_height; f32 max_width = view_file_width(view); buffer_measure_wrap_y(buffer, view->file_data.line_wrap_y, line_height, max_width); - + view->file_data.line_count = line_count; } internal void file_create_from_string(System_Functions *system, Models *models, Editing_File *file, char *filename, String val, b8 read_only = 0){ - + Font_Set *font_set = models->font_set; Working_Set *working_set = &models->working_set; General_Memory *general = &models->mem.general; Partition *part = &models->mem.part; Buffer_Init_Type init; i32 page_size, scratch_size, init_success; - + file->state = editing_file_state_zero(); - + init = buffer_begin_init(&file->state.buffer, val.str, val.size); for (; buffer_init_need_more(&init); ){ page_size = buffer_init_page_size(&init); @@ -677,29 +683,29 @@ file_create_from_string(System_Functions *system, Models *models, void *data = general_memory_allocate(general, page_size, BUBBLE_BUFFER); buffer_init_provide_page(&init, data, page_size); } - + scratch_size = partition_remaining(part); Assert(scratch_size > 0); init_success = buffer_end_init(&init, part->base + part->pos, scratch_size); AllowLocal(init_success); Assert(init_success); - + if (buffer_size(&file->state.buffer) < val.size){ file->settings.dos_write_mode = 1; } - + file_init_strings(file); file_set_name(working_set, file, (char*)filename); - + file->state.font_id = models->global_font.font_id; - + file_synchronize_times(system, file, filename); - + Render_Font *font = get_font_info(font_set, file->state.font_id)->font; float *advance_data = 0; if (font) advance_data = font->advance_data; file_measure_starts_widths(system, general, &file->state.buffer, advance_data); - + file->settings.read_only = read_only; if (!read_only){ // TODO(allen): Redo undo system (if you don't mind the pun) @@ -708,27 +714,27 @@ file_create_from_string(System_Functions *system, Models *models, file->state.undo.undo.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); file->state.undo.undo.edit_max = request_size / sizeof(Edit_Step); file->state.undo.undo.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO); - + file->state.undo.redo.max = request_size; file->state.undo.redo.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); file->state.undo.redo.edit_max = request_size / sizeof(Edit_Step); file->state.undo.redo.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO); - + file->state.undo.history.max = request_size; file->state.undo.history.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); file->state.undo.history.edit_max = request_size / sizeof(Edit_Step); file->state.undo.history.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO); - + file->state.undo.children.max = request_size; file->state.undo.children.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); file->state.undo.children.edit_max = request_size / sizeof(Buffer_Edit); file->state.undo.children.edits = (Buffer_Edit*)general_memory_allocate(general, request_size, BUBBLE_UNDO); - + file->state.undo.history_block_count = 1; file->state.undo.history_head_block = 0; file->state.undo.current_block_normal = 1; } - + Hook_Function *open_hook = models->hooks[hook_open_file]; models->buffer_param_indices[models->buffer_param_count++] = file->id.id; open_hook(&models->app_links); @@ -762,24 +768,24 @@ file_close(System_Functions *system, General_Memory *general, Editing_File *file if (file->state.token_stack.tokens){ general_memory_free(general, file->state.token_stack.tokens); } - + Buffer_Type *buffer = &file->state.buffer; if (buffer->data){ general_memory_free(general, buffer->data); general_memory_free(general, buffer->line_starts); general_memory_free(general, buffer->line_widths); } - + if (file->state.undo.undo.edits){ general_memory_free(general, file->state.undo.undo.strings); general_memory_free(general, file->state.undo.undo.edits); - + general_memory_free(general, file->state.undo.redo.strings); general_memory_free(general, file->state.undo.redo.edits); - + general_memory_free(general, file->state.undo.history.strings); general_memory_free(general, file->state.undo.history.edits); - + general_memory_free(general, file->state.undo.children.strings); general_memory_free(general, file->state.undo.children.edits); } @@ -793,27 +799,27 @@ internal Job_Callback_Sig(job_full_lex){ Editing_File *file = (Editing_File*)data[0]; General_Memory *general = (General_Memory*)data[1]; - + Cpp_File cpp_file; cpp_file.data = file->state.buffer.data; cpp_file.size = file->state.buffer.size; - + Cpp_Token_Stack tokens; tokens.tokens = (Cpp_Token*)memory->data; tokens.max_count = memory->size / sizeof(Cpp_Token); tokens.count = 0; - + Cpp_Lex_Data status = cpp_lex_file_nonalloc(cpp_file, &tokens); - + while (!status.complete){ system->grow_thread_memory(memory); tokens.tokens = (Cpp_Token*)memory->data; tokens.max_count = memory->size / sizeof(Cpp_Token); status = cpp_lex_file_nonalloc(cpp_file, &tokens, status); } - + i32 new_max = LargeRoundUp(tokens.count+1, Kbytes(1)); - + system->acquire_lock(FRAME_LOCK); { Assert(file->state.swap_stack.tokens == 0); @@ -821,12 +827,12 @@ Job_Callback_Sig(job_full_lex){ general_memory_allocate(general, new_max*sizeof(Cpp_Token), BUBBLE_TOKENS); } system->release_lock(FRAME_LOCK); - + u8 *dest = (u8*)file->state.swap_stack.tokens; u8 *src = (u8*)tokens.tokens; - + memcpy(dest, src, tokens.count*sizeof(Cpp_Token)); - + system->acquire_lock(FRAME_LOCK); { file->state.token_stack.count = tokens.count; @@ -837,9 +843,9 @@ Job_Callback_Sig(job_full_lex){ file->state.swap_stack.tokens = 0; } system->release_lock(FRAME_LOCK); - + exchange->force_redraw = 1; - + // NOTE(allen): These are outside the locked section because I don't // think getting these out of order will cause critical bugs, and I // want to minimize what's done in locked sections. @@ -871,13 +877,13 @@ internal void file_first_lex_parallel(System_Functions *system, General_Memory *general, Editing_File *file){ file->settings.tokens_exist = 1; - + if (file->state.is_loading == 0 && file->state.still_lexing == 0){ Assert(file->state.token_stack.tokens == 0); - + file->state.tokens_complete = 0; file->state.still_lexing = 1; - + Job_Data job; job.callback = job_full_lex; job.data[0] = file; @@ -898,19 +904,19 @@ file_relex_parallel(System_Functions *system, file_first_lex_parallel(system, general, file); return; } - + b32 inline_lex = !file->state.still_lexing; if (inline_lex){ Cpp_File cpp_file; cpp_file.data = file->state.buffer.data; cpp_file.size = file->state.buffer.size; - + Cpp_Token_Stack *stack = &file->state.token_stack; - + Cpp_Relex_State state = cpp_relex_nonalloc_start(cpp_file, stack, start_i, end_i, amount, 100); - + Temp_Memory temp = begin_temp_memory(part); i32 relex_end; Cpp_Token_Stack relex_space; @@ -923,7 +929,7 @@ file_relex_parallel(System_Functions *system, else{ i32 delete_amount = relex_end - state.start_token_i; i32 shift_amount = relex_space.count - delete_amount; - + if (shift_amount != 0){ int new_count = stack->count + shift_amount; if (new_count > stack->max_count){ @@ -934,32 +940,32 @@ file_relex_parallel(System_Functions *system, new_max*sizeof(Cpp_Token), BUBBLE_TOKENS); stack->max_count = new_max; } - + int shift_size = stack->count - relex_end; if (shift_size > 0){ Cpp_Token *old_base = stack->tokens + relex_end; memmove(old_base + shift_amount, old_base, sizeof(Cpp_Token)*shift_size); } - + stack->count += shift_amount; } - + memcpy(state.stack->tokens + state.start_token_i, relex_space.tokens, sizeof(Cpp_Token)*relex_space.count); } - + end_temp_memory(temp); } - + if (!inline_lex){ Cpp_Token_Stack *stack = &file->state.token_stack; Cpp_Get_Token_Result get_token_result = cpp_get_token(stack, end_i); i32 end_token_i = get_token_result.token_index; - + if (end_token_i < 0) end_token_i = 0; else if (end_i > stack->tokens[end_token_i].start) ++end_token_i; - + cpp_shift_token_starts(stack, end_token_i, amount); --end_token_i; if (end_token_i >= 0){ @@ -968,9 +974,9 @@ file_relex_parallel(System_Functions *system, token->size += amount; } } - + file->state.still_lexing = 1; - + Job_Data job; job.callback = job_full_lex; job.data[0] = file; @@ -1030,22 +1036,22 @@ undo_children_push(General_Memory *general, Small_Edit_Stack *children, i32 result = children->edit_count; if (children->edit_count + edit_count > children->edit_max) child_stack_grow_edits(general, children, edit_count); - + if (children->size + string_size > children->max) child_stack_grow_string(general, 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; } @@ -1061,25 +1067,25 @@ file_post_undo(General_Memory *general, Editing_File *file, 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(general, 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.pre_pos = step.pre_pos; inv_step.post_pos = step.post_pos; 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]; @@ -1091,7 +1097,7 @@ file_post_undo(General_Memory *general, Editing_File *file, } } } - + if (did_merge){ result = undo->edits + (undo->edit_count-1); *result = inv_step; @@ -1099,7 +1105,7 @@ file_post_undo(General_Memory *general, Editing_File *file, else{ if (undo->edit_count == undo->edit_max) undo_stack_grow_edits(general, undo); - + result = undo->edits + (undo->edit_count++); *result = inv_step; } @@ -1112,7 +1118,7 @@ file_post_undo(General_Memory *general, Editing_File *file, 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(general, undo); result = undo->edits + (undo->edit_count++); @@ -1134,21 +1140,21 @@ undo_stack_pop(Edit_Stack *stack){ internal void file_post_redo(General_Memory *general, 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(general, 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.pre_pos = step.pre_pos; inv_step.post_pos = step.post_pos; inv_step.type = ED_REDO; - + if (redo->edit_count == redo->edit_max) undo_stack_grow_edits(general, redo); redo->edits[redo->edit_count++] = inv_step; @@ -1161,7 +1167,7 @@ file_post_redo(General_Memory *general, Editing_File *file, Edit_Step step){ 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(general, redo); } @@ -1173,7 +1179,7 @@ inline 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; @@ -1196,7 +1202,7 @@ file_post_history(General_Memory *general, Editing_File *file, Edit_Step step, b32 do_merge, b32 can_merge){ Edit_Stack *history = &file->state.undo.history; Edit_Step *result = 0; - + persist Edit_Type reverse_types[4]; if (reverse_types[ED_UNDO] == 0){ reverse_types[ED_NORMAL] = ED_REVERSE_NORMAL; @@ -1204,22 +1210,22 @@ file_post_history(General_Memory *general, Editing_File *file, 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(general, 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.pre_pos = step.pre_pos; inv_step.post_pos = step.post_pos; inv_step.can_merge = (b8)can_merge; inv_step.type = reverse_types[step.type]; - + bool32 did_merge = 0; if (do_merge && history->edit_count > 0){ Edit_Step prev = history->edits[history->edit_count-1]; @@ -1231,7 +1237,7 @@ file_post_history(General_Memory *general, Editing_File *file, } } } - + if (did_merge){ result = history->edits + (history->edit_count-1); } @@ -1240,7 +1246,7 @@ file_post_history(General_Memory *general, Editing_File *file, undo_stack_grow_edits(general, history); result = history->edits + (history->edit_count++); } - + *result = inv_step; } else{ @@ -1251,13 +1257,13 @@ file_post_history(General_Memory *general, Editing_File *file, 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(general, history); result = history->edits + (history->edit_count++); *result = inv_step; } - + return result; } @@ -1266,7 +1272,7 @@ view_compute_cursor_from_pos(View *view, i32 pos){ Editing_File *file = view->file_data.file; Models *models = view->persistent.models; Render_Font *font = get_font_info(models->font_set, models->global_font.font_id)->font; - + Full_Cursor result = {}; if (font){ f32 max_width = view_file_width(view); @@ -1281,14 +1287,14 @@ view_compute_cursor_from_unwrapped_xy(View *view, f32 seek_x, f32 seek_y, b32 ro Editing_File *file = view->file_data.file; Models *models = view->persistent.models; Render_Font *font = get_font_info(models->font_set, models->global_font.font_id)->font; - + Full_Cursor result = {}; if (font){ f32 max_width = view_file_width(view); result = buffer_cursor_from_unwrapped_xy(&file->state.buffer, seek_x, seek_y, round_down, view->file_data.line_wrap_y, max_width, (f32)view->font_height, font->advance_data); } - + return result; } @@ -1297,7 +1303,7 @@ view_compute_cursor_from_wrapped_xy(View *view, f32 seek_x, f32 seek_y, b32 roun Editing_File *file = view->file_data.file; Models *models = view->persistent.models; Render_Font *font = get_font_info(models->font_set, models->global_font.font_id)->font; - + Full_Cursor result = {}; if (font){ f32 max_width = view_file_width(view); @@ -1305,7 +1311,7 @@ view_compute_cursor_from_wrapped_xy(View *view, f32 seek_x, f32 seek_y, b32 roun round_down, view->file_data.line_wrap_y, max_width, (f32)view->font_height, font->advance_data); } - + return (result); } @@ -1314,39 +1320,39 @@ view_compute_cursor_from_line_pos(View *view, i32 line, i32 pos){ Editing_File *file = view->file_data.file; Models *models = view->persistent.models; Render_Font *font = get_font_info(models->font_set, models->global_font.font_id)->font; - + Full_Cursor result = {}; if (font){ f32 max_width = view_file_width(view); result = buffer_cursor_from_line_character(&file->state.buffer, line, pos, view->file_data.line_wrap_y, max_width, (f32)view->font_height, font->advance_data); } - + return (result); } inline Full_Cursor view_compute_cursor(View *view, Buffer_Seek seek){ Full_Cursor result = {}; - + switch(seek.type){ case buffer_seek_pos: result = view_compute_cursor_from_pos(view, seek.pos); break; - + case buffer_seek_wrapped_xy: result = view_compute_cursor_from_wrapped_xy(view, seek.x, seek.y); break; - + case buffer_seek_unwrapped_xy: result = view_compute_cursor_from_unwrapped_xy(view, seek.x, seek.y); break; - + case buffer_seek_line_char: result = view_compute_cursor_from_line_pos(view, seek.line, seek.character); break; } - + return (result); } @@ -1400,13 +1406,13 @@ inline f32 view_get_cursor_y(View *view){ Full_Cursor *cursor; f32 result; - + if (view->file_data.show_temp_highlight) cursor = &view->file_data.temp_highlight; else cursor = &view->recent->cursor; - + if (view->file_data.unwrapped_lines) result = cursor->unwrapped_y; else result = cursor->wrapped_y; - + return result; } @@ -1425,14 +1431,14 @@ view_move_cursor_to_view(View *view){ f32 target_y = view->recent->scroll.target_y; f32 cursor_max_y = CursorMaxY(view_file_height(view), line_height); f32 cursor_min_y = CursorMinY(min_target_y, line_height); - + if (cursor_y > target_y + cursor_max_y){ cursor_y = target_y + cursor_max_y; } if (target_y != 0 && cursor_y < target_y + cursor_min_y){ cursor_y = target_y + cursor_min_y; } - + if (cursor_y != old_cursor_y){ if (cursor_y > old_cursor_y){ cursor_y += line_height; @@ -1627,11 +1633,11 @@ inline i32_Rect view_widget_rect(View *view, i32 font_height){ Panel *panel = view->panel; i32_Rect result = panel->inner; - + if (view->file_data.file){ result.y0 = result.y0 + font_height + 2; } - + return(result); } @@ -1646,30 +1652,30 @@ file_update_history_before_edit(Mem_Options *mem, Editing_File *file, Edit_Step History_Mode history_mode){ if (!file->state.undo.undo.edits) return; General_Memory *general = &mem->general; - + 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(general, file, step, do_merge, can_merge); file_post_undo(general, file, step, do_merge, can_merge); }break; - + case ED_REVERSE_NORMAL: { if (history_mode != hist_forward) file_post_history(general, 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); @@ -1678,7 +1684,7 @@ file_update_history_before_edit(Mem_Options *mem, Editing_File *file, Edit_Step 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; @@ -1697,25 +1703,25 @@ file_update_history_before_edit(Mem_Options *mem, Editing_File *file, Edit_Step } --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(general, &file->state.undo.redo); - + if (file->state.undo.redo.size + strings_of_redo > file->state.undo.redo.max) undo_stack_grow_string(general, &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; @@ -1726,13 +1732,13 @@ file_update_history_before_edit(Mem_Options *mem, Editing_File *file, Edit_Step } 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); } } @@ -1741,13 +1747,13 @@ file_update_history_before_edit(Mem_Options *mem, Editing_File *file, Edit_Step } } 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) @@ -1755,20 +1761,20 @@ file_update_history_before_edit(Mem_Options *mem, Editing_File *file, Edit_Step file_post_redo(general, 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(general, file, step, do_merge, can_merge); - + file_post_undo(general, 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){ @@ -1789,7 +1795,7 @@ file_update_history_before_edit(Mem_Options *mem, Editing_File *file, Edit_Step 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; } @@ -1828,19 +1834,19 @@ file_edit_cursor_fix(System_Functions *system, Partition *part, General_Memory *general, Editing_File *file, Editing_Layout *layout, Cursor_Fix_Descriptor desc){ - + Full_Cursor temp_cursor; Temp_Memory cursor_temp = begin_temp_memory(part); i32 cursor_max = layout->panel_max_count * 2; Cursor_With_Index *cursors = push_array(part, Cursor_With_Index, cursor_max); - + f32 y_offset = 0, y_position = 0; i32 cursor_count = 0; - + View *view; Panel *panel, *used_panels; used_panels = &layout->used_sentinel; - + for (dll_items(panel, used_panels)){ view = panel->view; if (view->file_data.file == file){ @@ -1850,7 +1856,7 @@ file_edit_cursor_fix(System_Functions *system, write_cursor_with_index(cursors, &cursor_count, view->recent->scroll_i - 1); } } - + if (cursor_count > 0){ buffer_sort_cursors(cursors, cursor_count); if (desc.is_batch){ @@ -1863,14 +1869,14 @@ file_edit_cursor_fix(System_Functions *system, desc.shift_amount + (desc.end - desc.start)); } buffer_unsort_cursors(cursors, cursor_count); - + cursor_count = 0; for (dll_items(panel, used_panels)){ view = panel->view; if (view && view->file_data.file == file){ view_cursor_move(view, cursors[cursor_count++].pos); view->recent->preferred_x = view_get_cursor_x(view); - + view->recent->mark = cursors[cursor_count++].pos + 1; i32 new_scroll_i = cursors[cursor_count++].pos + 1; if (view->recent->scroll_i != new_scroll_i){ @@ -1892,7 +1898,7 @@ file_edit_cursor_fix(System_Functions *system, } } } - + end_temp_memory(cursor_temp); } @@ -1901,26 +1907,26 @@ file_do_single_edit(System_Functions *system, Models *models, Editing_File *file, Edit_Spec spec, History_Mode history_mode, b32 use_high_permission = 0){ if (!use_high_permission && file->settings.read_only) return; - + Mem_Options *mem = &models->mem; Editing_Layout *layout = &models->layout; - + // NOTE(allen): fixing stuff beforewards???? file_update_history_before_edit(mem, file, spec.step, spec.str, history_mode); file_pre_edit_maintenance(system, &mem->general, file); - + // NOTE(allen): actual text replacement i32 shift_amount = 0; General_Memory *general = &mem->general; Partition *part = &mem->part; - + 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 scratch_size = partition_remaining(part); - + Assert(scratch_size > 0); i32 request_amount = 0; Assert(end <= buffer_size(&file->state.buffer)); @@ -1933,42 +1939,42 @@ file_do_single_edit(System_Functions *system, void *old_data = buffer_edit_provide_memory(&file->state.buffer, new_data, request_amount); if (old_data) general_memory_free(general, old_data); } - + Buffer_Type *buffer = &file->state.buffer; i32 line_start = buffer_get_line_index(&file->state.buffer, start); i32 line_end = buffer_get_line_index(&file->state.buffer, end); i32 replaced_line_count = line_end - line_start; i32 new_line_count = buffer_count_newlines(&file->state.buffer, start, start+str_len); i32 line_shift = new_line_count - replaced_line_count; - + Render_Font *font = get_font_info(models->font_set, file->state.font_id)->font; - + file_grow_starts_widths_as_needed(general, buffer, line_shift); buffer_remeasure_starts(buffer, line_start, line_end, line_shift, shift_amount); buffer_remeasure_widths(buffer, font->advance_data, line_start, line_end, line_shift); - + // NOTE(allen): update the views looking at this file Panel *panel, *used_panels; used_panels = &layout->used_sentinel; - + for (dll_items(panel, used_panels)){ View *view = panel->view; if (view->file_data.file == file){ view_measure_wraps(general, view); } } - + #if BUFFER_EXPERIMENT_SCALPEL <= 0 // NOTE(allen): fixing stuff afterwards if (file->settings.tokens_exist) file_relex_parallel(system, mem, file, start, end, shift_amount); #endif - + Cursor_Fix_Descriptor desc = {}; desc.start = start; desc.end = end; desc.shift_amount = shift_amount; - + file_edit_cursor_fix(system, part, general, file, layout, desc); } @@ -1976,26 +1982,26 @@ internal void file_do_white_batch_edit(System_Functions *system, Models *models, Editing_File *file, Edit_Spec spec, History_Mode history_mode, b32 use_high_permission = 0){ if (!use_high_permission && file->settings.read_only) return; - + Mem_Options *mem = &models->mem; Editing_Layout *layout = &models->layout; - + // NOTE(allen): fixing stuff "beforewards"??? Assert(spec.str == 0); file_update_history_before_edit(mem, file, spec.step, 0, history_mode); file_pre_edit_maintenance(system, &mem->general, file); - + // NOTE(allen): actual text replacement General_Memory *general = &mem->general; Partition *part = &mem->part; - + 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); - + i32 scratch_size = partition_remaining(part); Buffer_Batch_State state = {}; i32 request_amount; @@ -2009,7 +2015,7 @@ file_do_white_batch_edit(System_Functions *system, Models *models, Editing_File void *old_data = buffer_edit_provide_memory(&file->state.buffer, new_data, request_amount); if (old_data) general_memory_free(general, old_data); } - + // NOTE(allen): meta data { Buffer_Measure_Starts state = {}; @@ -2018,17 +2024,17 @@ file_do_white_batch_edit(System_Functions *system, Models *models, Editing_File if (font) advance_data = font->advance_data; buffer_measure_starts_widths(&state, &file->state.buffer, advance_data); } - + // NOTE(allen): cursor fixing { Cursor_Fix_Descriptor desc = {}; desc.is_batch = 1; desc.batch = batch; desc.batch_size = batch_size; - + file_edit_cursor_fix(system, part, general, file, layout, desc); } - + // NOTE(allen): token fixing if (file->state.tokens_complete){ Cpp_Token_Stack tokens = file->state.token_stack; @@ -2066,7 +2072,7 @@ file_replace_range(System_Functions *system, Models *models, Editing_File *file, spec.step.type = ED_NORMAL; spec.step.edit.start = start; spec.step.edit.end = end; - + spec.step.edit.len = len; spec.step.pre_pos = file->state.cursor_pos; spec.step.post_pos = next_cursor; @@ -2088,7 +2094,7 @@ view_replace_range(System_Functions *system, Models *models, View *view, inline void view_post_paste_effect(View *view, i32 ticks, i32 start, i32 size, u32 color){ Editing_File *file = view->file_data.file; - + file->state.paste_effect.start = start; file->state.paste_effect.end = start + size; file->state.paste_effect.color = color; @@ -2111,25 +2117,25 @@ view_undo_redo(System_Functions *system, Models *models, View *view, Edit_Stack *stack, Edit_Type expected_type){ Editing_File *file = view->file_data.file; - + if (stack->edit_count > 0){ Edit_Step step = stack->edits[stack->edit_count-1]; - + Assert(step.type == expected_type); - + Edit_Spec spec = {}; spec.step = step; - + if (step.child_count == 0){ spec.step.edit.str_start = 0; spec.str = stack->strings + step.edit.str_start; - + file_do_single_edit(system, models, file, spec, hist_normal); - + if (expected_type == ED_UNDO) view_cursor_move(view, step.pre_pos); else view_cursor_move(view, step.post_pos); view->recent->mark = view->recent->cursor.pos; - + Style *style = main_style(models); view_post_paste_effect(view, 10, step.edit.start, step.edit.len, style->main.undo_color); @@ -2163,9 +2169,9 @@ write_data(u8 *ptr, void *x, i32 size){ internal void file_dump_history(System_Functions *system, Mem_Options *mem, Editing_File *file, char *filename){ if (!file->state.undo.undo.edits) return; - + i32 size = 0; - + size += sizeof(i32); size += file->state.undo.undo.edit_count*sizeof(Edit_Step); size += sizeof(i32); @@ -2174,7 +2180,7 @@ file_dump_history(System_Functions *system, Mem_Options *mem, Editing_File *file size += file->state.undo.history.edit_count*sizeof(Edit_Step); size += sizeof(i32); size += file->state.undo.children.edit_count*sizeof(Buffer_Edit); - + size += sizeof(i32); size += file->state.undo.undo.size; size += sizeof(i32); @@ -2183,7 +2189,7 @@ file_dump_history(System_Functions *system, Mem_Options *mem, Editing_File *file size += file->state.undo.history.size; size += sizeof(i32); size += file->state.undo.children.size; - + Partition *part = &mem->part; i32 remaining = partition_remaining(part); if (size < remaining){ @@ -2198,17 +2204,17 @@ file_dump_history(System_Functions *system, Mem_Options *mem, Editing_File *file curs = write_data(curs, &file->state.undo.redo.size, 4); curs = write_data(curs, &file->state.undo.history.size, 4); curs = write_data(curs, &file->state.undo.children.size, 4); - + curs = write_data(curs, file->state.undo.undo.edits, sizeof(Edit_Step)*file->state.undo.undo.edit_count); curs = write_data(curs, file->state.undo.redo.edits, sizeof(Edit_Step)*file->state.undo.redo.edit_count); curs = write_data(curs, file->state.undo.history.edits, sizeof(Edit_Step)*file->state.undo.history.edit_count); curs = write_data(curs, file->state.undo.children.edits, sizeof(Buffer_Edit)*file->state.undo.children.edit_count); - + curs = write_data(curs, file->state.undo.undo.strings, file->state.undo.undo.size); curs = write_data(curs, file->state.undo.redo.strings, file->state.undo.redo.size); curs = write_data(curs, file->state.undo.history.strings, file->state.undo.history.size); curs = write_data(curs, file->state.undo.children.strings, file->state.undo.children.size); - + Assert((i32)(curs - data) == size); system->save_file(filename, data, size); } @@ -2218,9 +2224,9 @@ file_dump_history(System_Functions *system, Mem_Options *mem, Editing_File *file internal void view_history_step(System_Functions *system, Models *models, View *view, History_Mode history_mode){ Assert(history_mode != hist_normal); - + Editing_File *file = view->file_data.file; - + b32 do_history_step = 0; Edit_Step step = {}; if (history_mode == hist_backward){ @@ -2238,23 +2244,23 @@ view_history_step(System_Functions *system, Models *models, View *view, History_ do_history_step = 1; } } - + if (do_history_step){ Edit_Spec spec; spec.step = step; - + if (spec.step.child_count == 0){ spec.step.edit.str_start = 0; spec.str = file->state.undo.history.strings + step.edit.str_start; - + file_do_single_edit(system, models, file, spec, history_mode); - + switch (spec.step.type){ case ED_NORMAL: case ED_REDO: view_cursor_move(view, step.post_pos); break; - + case ED_REVERSE_NORMAL: case ED_UNDO: view_cursor_move(view, step.pre_pos); @@ -2384,21 +2390,21 @@ file_compute_whitespace_edit(Mem_Options *mem, Editing_File *file, i32 cursor_po Buffer_Edit *inverse_array, char *inv_str, i32 inv_max, i32 edit_count){ General_Memory *general = &mem->general; - + 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)){ Assert(0); } - + i32 first_child = undo_children_push(general, &file->state.undo.children, edits, edit_count, (u8*)(str_base), str_size); i32 inverse_first_child = undo_children_push(general, &file->state.undo.children, inverse_array, edit_count, (u8*)(inv_str), inv_str_pos); - + Edit_Spec spec = {}; spec.step.type = ED_NORMAL; spec.step.first_child = first_child; @@ -2408,7 +2414,7 @@ file_compute_whitespace_edit(Mem_Options *mem, Editing_File *file, i32 cursor_po spec.step.inverse_child_count = edit_count; spec.step.pre_pos = cursor_pos; spec.step.post_pos = cursor_pos; - + return spec; } @@ -2416,26 +2422,26 @@ internal void view_clean_whitespace(System_Functions *system, Models *models, View *view){ Mem_Options *mem = &models->mem; Editing_File *file = view->file_data.file; - + Partition *part = &mem->part; i32 line_count = file->state.buffer.line_count; i32 edit_max = line_count * 2; i32 edit_count = 0; - + Assert(file && !file->state.is_dummy); - + Temp_Memory temp = begin_temp_memory(part); Buffer_Edit *edits = push_array(part, Buffer_Edit, edit_max); - + char *str_base = (char*)part->base + part->pos; i32 str_size = 0; for (i32 line_i = 0; line_i < line_count; ++line_i){ i32 start = file->state.buffer.line_starts[line_i]; Hard_Start_Result hard_start = buffer_find_hard_start(&file->state.buffer, start, 4); - + if (hard_start.all_whitespace) hard_start.indent_pos = 0; - + if ((hard_start.all_whitespace && hard_start.char_pos > start) || !hard_start.all_space){ Buffer_Edit new_edit; new_edit.str_start = str_size; @@ -2449,22 +2455,22 @@ view_clean_whitespace(System_Functions *system, Models *models, View *view){ } Assert(edit_count <= edit_max); } - + if (edit_count > 0){ Assert(buffer_batch_debug_sort_check(edits, edit_count)); - + // NOTE(allen): computing edit spec, doing batch edit Buffer_Edit *inverse_array = push_array(part, Buffer_Edit, edit_count); Assert(inverse_array); - + char *inv_str = (char*)part->base + part->pos; Edit_Spec spec = file_compute_whitespace_edit(mem, file, view->recent->cursor.pos, edits, str_base, str_size, inverse_array, inv_str, part->max - part->pos, edit_count); - + file_do_white_batch_edit(system, models, view->file_data.file, spec, hist_normal); } - + end_temp_memory(temp); } @@ -2477,7 +2483,7 @@ struct Indent_Options{ struct Make_Batch_Result{ char *str_base; i32 str_size; - + Buffer_Edit *edits; i32 edit_max; i32 edit_count; @@ -2488,12 +2494,12 @@ get_first_token_at_line(Buffer *buffer, Cpp_Token_Stack tokens, i32 line){ Cpp_Token *result = 0; i32 start_pos = 0; Cpp_Get_Token_Result get_token = {0}; - + start_pos = buffer->line_starts[line]; get_token = cpp_get_token(&tokens, start_pos); if (get_token.in_whitespace) get_token.token_index += 1; result = tokens.tokens + get_token.token_index; - + return(result); } @@ -2534,20 +2540,20 @@ struct Indent_Parse_State{ internal i32 compute_this_indent(Buffer *buffer, Indent_Parse_State indent, Cpp_Token T, Cpp_Token prev_token, i32 line_i, i32 tab_width){ - + i32 previous_indent = indent.previous_line_indent; i32 this_indent = 0; - + i32 this_line_start = buffer->line_starts[line_i]; i32 next_line_start = 0; - + if (line_i+1 < buffer->line_count){ next_line_start = buffer->line_starts[line_i+1]; } else{ next_line_start = buffer_size(buffer); } - + if ((prev_token.type == CPP_TOKEN_COMMENT || prev_token.type == CPP_TOKEN_STRING_CONSTANT) && prev_token.start <= this_line_start && prev_token.start + prev_token.size > this_line_start){ this_indent = previous_indent; @@ -2567,7 +2573,7 @@ compute_this_indent(Buffer *buffer, Indent_Parse_State indent, default: if (indent.current_indent > 0){ if (!(prev_token.flags & CPP_TFLAG_PP_BODY || - prev_token.flags & CPP_TFLAG_PP_DIRECTIVE)){ + prev_token.flags & CPP_TFLAG_PP_DIRECTIVE)){ switch (prev_token.type){ case CPP_TOKEN_BRACKET_OPEN: case CPP_TOKEN_BRACE_OPEN: case CPP_TOKEN_BRACE_CLOSE: @@ -2582,7 +2588,7 @@ compute_this_indent(Buffer *buffer, Indent_Parse_State indent, } if (this_indent < 0) this_indent = 0; } - + if (indent.paren_nesting > 0){ i32 level = indent.paren_nesting-1; if (level >= ArrayCount(indent.paren_anchor_indent)){ @@ -2595,7 +2601,7 @@ compute_this_indent(Buffer *buffer, Indent_Parse_State indent, internal i32* get_line_indentation_marks(Partition *part, Buffer *buffer, Cpp_Token_Stack tokens, - i32 line_start, i32 line_end, i32 tab_width){ + i32 line_start, i32 line_end, i32 tab_width){ i32 indent_mark_count = line_end - line_start; i32 *indent_marks = push_array(part, i32, indent_mark_count); @@ -2624,12 +2630,12 @@ get_line_indentation_marks(Partition *part, Buffer *buffer, Cpp_Token_Stack toke i32 line = buffer_get_line_index(buffer, token->start); i32 start = buffer->line_starts[line]; Hard_Start_Result hard_start = buffer_find_hard_start(buffer, start, tab_width); - + indent.current_indent = hard_start.indent_pos; - + Cpp_Token *start_token = get_first_token_at_line(buffer, tokens, line); Cpp_Token *brace_token = token; - + if (start_token->type == CPP_TOKEN_PARENTHESE_OPEN){ if (start_token == tokens.tokens){ found_safe_start_position = 1; @@ -2640,7 +2646,7 @@ get_line_indentation_marks(Partition *part, Buffer *buffer, Cpp_Token_Stack toke } else{ int close = 0; - + for (token = brace_token; token >= start_token; --token){ switch(token->type){ case CPP_TOKEN_PARENTHESE_CLOSE: @@ -2654,19 +2660,19 @@ get_line_indentation_marks(Partition *part, Buffer *buffer, Cpp_Token_Stack toke switch (close){ case 0: token = start_token; found_safe_start_position = 1; break; - + case CPP_TOKEN_PARENTHESE_CLOSE: token = seek_matching_token_backwards(tokens, token-1, CPP_TOKEN_PARENTHESE_OPEN, CPP_TOKEN_PARENTHESE_CLOSE); break; - + case CPP_TOKEN_BRACKET_CLOSE: token = seek_matching_token_backwards(tokens, token-1, CPP_TOKEN_BRACKET_OPEN, CPP_TOKEN_BRACKET_CLOSE); break; - + case CPP_TOKEN_BRACE_CLOSE: token = seek_matching_token_backwards(tokens, token-1, CPP_TOKEN_BRACE_OPEN, @@ -2675,7 +2681,7 @@ get_line_indentation_marks(Partition *part, Buffer *buffer, Cpp_Token_Stack toke } } } while(found_safe_start_position == 0); - + // NOTE(allen): Shift the array so that line_i can just operate in // it's natural value range. indent_marks -= line_start; @@ -2706,7 +2712,7 @@ get_line_indentation_marks(Partition *part, Buffer *buffer, Cpp_Token_Stack toke T.start = buffer_size(buffer); T.flags = 0; } - + for (; T.start >= next_line_start && line_i < line_end;){ if (line_i+1 < buffer->line_count){ next_line_start = buffer->line_starts[line_i+1]; @@ -2718,7 +2724,7 @@ get_line_indentation_marks(Partition *part, Buffer *buffer, Cpp_Token_Stack toke // TODO(allen): Since this is called in one place we can probably go back // to directly passing in next_line_start and this_line_start. i32 this_indent = compute_this_indent(buffer, indent, T, prev_token, line_i, tab_width); - + if (line_i >= line_start){ indent_marks[line_i] = this_indent; } @@ -2741,7 +2747,7 @@ get_line_indentation_marks(Partition *part, Buffer *buffer, Cpp_Token_Stack toke i32 char_pos = T.start - start; Hard_Start_Result hard_start = buffer_find_hard_start( - buffer, start, tab_width); + buffer, start, tab_width); i32 line_pos = hard_start.char_pos - start; @@ -2751,7 +2757,7 @@ get_line_indentation_marks(Partition *part, Buffer *buffer, Cpp_Token_Stack toke ++indent.paren_nesting; } break; - + case CPP_TOKEN_PARENTHESE_CLOSE: if (!(T.flags & CPP_TFLAG_PP_BODY)){ --indent.paren_nesting; @@ -2770,7 +2776,7 @@ get_line_indentation_marks(Partition *part, Buffer *buffer, Cpp_Token_Stack toke internal Make_Batch_Result make_batch_from_indent_marks(Partition *part, Buffer *buffer, i32 line_start, i32 line_end, - i32 *indent_marks, Indent_Options opts){ + i32 *indent_marks, Indent_Options opts){ Make_Batch_Result result = {0}; @@ -2790,13 +2796,13 @@ make_batch_from_indent_marks(Partition *part, Buffer *buffer, i32 line_start, i3 i32 start = buffer->line_starts[line_i]; Hard_Start_Result hard_start = buffer_find_hard_start(buffer, start, opts.tab_width); - + i32 correct_indentation = indent_marks[line_i]; if (hard_start.all_whitespace && opts.empty_blank_lines) correct_indentation = 0; if (correct_indentation == -1) correct_indentation = hard_start.indent_pos; - + if ((hard_start.all_whitespace && hard_start.char_pos > start) || - !hard_start.all_space || correct_indentation != hard_start.indent_pos){ + !hard_start.all_space || correct_indentation != hard_start.indent_pos){ Buffer_Edit new_edit; new_edit.str_start = str_size; str_size += correct_indentation; @@ -2815,7 +2821,7 @@ make_batch_from_indent_marks(Partition *part, Buffer *buffer, i32 line_start, i3 new_edit.end = hard_start.char_pos; edits[edit_count++] = new_edit; } - + Assert(edit_count <= edit_max); } @@ -2831,7 +2837,7 @@ make_batch_from_indent_marks(Partition *part, Buffer *buffer, i32 line_start, i3 internal void view_auto_tab_tokens(System_Functions *system, Models *models, - View *view, i32 start, i32 end, Indent_Options opts){ + View *view, i32 start, i32 end, Indent_Options opts){ #if BUFFER_EXPERIMENT_SCALPEL <= 0 Editing_File *file = view->file_data.file; Mem_Options *mem = &models->mem; @@ -2846,30 +2852,30 @@ view_auto_tab_tokens(System_Functions *system, Models *models, i32 line_end = buffer_get_line_index(buffer, end) + 1; Temp_Memory temp = begin_temp_memory(part); - + i32 *indent_marks = get_line_indentation_marks(part, buffer, tokens, line_start, line_end, opts.tab_width); - + Make_Batch_Result batch = make_batch_from_indent_marks(part, buffer, line_start, line_end, indent_marks, opts); - + if (batch.edit_count > 0){ Assert(buffer_batch_debug_sort_check(batch.edits, batch.edit_count)); - + // NOTE(allen): computing edit spec, doing batch edit Buffer_Edit *inverse_array = push_array(part, Buffer_Edit, batch.edit_count); Assert(inverse_array); - + char *inv_str = (char*)part->base + part->pos; Edit_Spec spec = file_compute_whitespace_edit(mem, file, view->recent->cursor.pos, - batch.edits, batch.str_base, batch.str_size, - inverse_array, inv_str, part->max - part->pos, batch.edit_count); - + batch.edits, batch.str_base, batch.str_size, + inverse_array, inv_str, part->max - part->pos, batch.edit_count); + file_do_white_batch_edit(system, models, view->file_data.file, spec, hist_normal); } end_temp_memory(temp); - + { i32 start = view->recent->cursor.pos; Hard_Start_Result hard_start = buffer_find_hard_start(buffer, start, 4); @@ -2903,27 +2909,27 @@ style_get_color(Style *style, Cpp_Token token){ case CPP_TOKEN_COMMENT: result = &style->main.comment_color; break; - + case CPP_TOKEN_STRING_CONSTANT: result = &style->main.str_constant_color; break; - + case CPP_TOKEN_CHARACTER_CONSTANT: result = &style->main.char_constant_color; break; - + case CPP_TOKEN_INTEGER_CONSTANT: result = &style->main.int_constant_color; break; - + case CPP_TOKEN_FLOATING_CONSTANT: result = &style->main.float_constant_color; break; - + case CPP_TOKEN_INCLUDE_FILE: result = &style->main.include_color; break; - + default: result = &style->main.default_color; break; @@ -2975,8 +2981,8 @@ view_show_config(View *view, Command_Map *gui_map){ inline void view_show_interactive(System_Functions *system, View *view, - Command_Map *gui_map, Interactive_Action action, - Interactive_Interaction interaction, String query){ + Command_Map *gui_map, Interactive_Action action, + Interactive_Interaction interaction, String query){ Models *models = view->persistent.models; @@ -3017,74 +3023,121 @@ view_show_file(View *view){ } internal void -interactive_view_complete(View *view, String dest, i32 user_action){ +view_save_file(System_Functions *system, Mem_Options *mem, Working_Set *working_set, + Editing_File *file, View *view, String filename, b32 save_as){ + if (!file){ + if (view){ + file = view->file_data.file; + } + else{ + file = working_set_lookup_file(working_set, filename); + } + } + + if (file && buffer_get_sync(file) != SYNC_GOOD){ + if (file_save(system, mem, file, filename.str)){ + if (save_as){ + file_set_name(working_set, file, filename.str); + } + } + } +} + +internal void +view_new_file(System_Functions *system, Models *models, + View *view, String string){ + Working_Set *working_set = &models->working_set; + General_Memory *general = &models->mem.general; + + Editing_File *file = working_set_alloc_always(working_set, general); + file_create_empty(system, models, file, string.str); + working_set_add(system, working_set, file, general); + + view_set_file(view, file, models); + view_show_file(view); + view->map = get_map(models, file->settings.base_map_id); + + Hook_Function *new_file_fnc = models->hooks[hook_new_file]; + if (new_file_fnc){ + models->buffer_param_indices[models->buffer_param_count++] = file->id.id; + new_file_fnc(&models->app_links); + models->buffer_param_count = 0; + file->settings.is_initialized = 1; + } + +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + if (file->settings.tokens_exist){ + file_first_lex_parallel(system, general, file); + } +#endif +} + +internal void +interactive_view_complete(System_Functions *system, View *view, String dest, i32 user_action){ Models *models = view->persistent.models; Panel *panel = view->panel; Editing_File *old_file = view->file_data.file; - + switch (view->action){ case IAct_Open: delayed_open(&models->delay1, dest, panel); delayed_touch_file(&models->delay1, old_file); break; - + case IAct_Save_As: - delayed_save_as(&models->delay1, dest, panel); + view_save_file(system, &models->mem, &models->working_set, + 0, view, dest, 1); break; - + case IAct_New: + // TODO(allen): The !char_is_slash part confuses me... let's investigate this soon. if (dest.size > 0 && - !char_is_slash(models->hot_directory.string.str[dest.size-1])){ - delayed_new(&models->delay1, dest, panel); + !char_is_slash(models->hot_directory.string.str[dest.size-1])){ + view_new_file(system, models, view, dest); }break; - + case IAct_Switch: delayed_switch(&models->delay1, dest, panel); delayed_touch_file(&models->delay1, old_file); break; - + case IAct_Kill: delayed_try_kill(&models->delay1, dest); break; - + case IAct_Sure_To_Close: switch (user_action){ case 0: delayed_close(&models->delay1); break; - + case 1: break; - + case 2: // TODO(allen): Save all. break; } break; - + case IAct_Sure_To_Kill: switch (user_action){ case 0: delayed_kill(&models->delay1, dest); break; - + case 1: break; - + case 2: - // TODO(allen): This is fishy! What if the save doesn't happen this time around? - // We need to ensure delayed acts happen in order I think... or better yet destroy delayed action entirely. - delayed_save(&models->delay1, dest); + view_save_file(system, &models->mem, &models->working_set, + 0, 0, dest, 0); delayed_kill(&models->delay1, dest); break; } break; } view_show_file(view); - - // TODO(allen): This is here to prevent the key press from being passed to the - // underlying file which is a giant pain. But I want a better system. - file_view_nullify_file(view); } #if 0 @@ -3269,7 +3322,7 @@ view_get_cursor_scroll_change_state(View *view){ internal void view_begin_cursor_scroll_updates(View *view){ - if (view->file_data.file == view->prev_context.file){ + if (view->file_data.file && view->file_data.file == view->prev_context.file){ Assert(view->prev_cursor_pos == view_get_cursor_pos(view)); } @@ -3948,7 +4001,7 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su do_new_directory = 1; } else if (use_item_in_list){ - interactive_view_complete(view, loop.full_path, 0); + interactive_view_complete(system, view, loop.full_path, 0); } } } @@ -3958,7 +4011,7 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su gui_end_list(target); if (activate_directly){ - interactive_view_complete(view, hdir->string, 0); + interactive_view_complete(system, view, hdir->string, 0); } if (do_new_directory){ @@ -4052,7 +4105,7 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su id.id[0] = (u64)(file); if (gui_do_file_option(target, id, file->name.live_name, 0, message)){ - interactive_view_complete(view, file->name.live_name, 0); + interactive_view_complete(system, view, file->name.live_name, 0); } } } @@ -4070,7 +4123,7 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su id.id[0] = (u64)(file); if (gui_do_file_option(target, id, file->name.live_name, 0, message)){ - interactive_view_complete(view, file->name.live_name, 0); + interactive_view_complete(system, view, file->name.live_name, 0); } } @@ -4104,7 +4157,7 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su } if (action != -1){ - interactive_view_complete(view, view->dest, action); + interactive_view_complete(system, view, view->dest, action); } }break; @@ -4136,7 +4189,7 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su } if (action != -1){ - interactive_view_complete(view, view->dest, action); + interactive_view_complete(system, view, view->dest, action); } }break; } diff --git a/4ed_metagen.cpp b/4ed_metagen.cpp index 8ed6c967..07f84b9f 100644 --- a/4ed_metagen.cpp +++ b/4ed_metagen.cpp @@ -149,9 +149,11 @@ char *daction_enum[] = { "OPEN", "OPEN_BACKGROUND", "SET_LINE", +#if 0 "SAVE_AS", "SAVE", "NEW", +#endif "SWITCH", "TRY_KILL", "KILL", @@ -456,6 +458,7 @@ char* generate_style(){ return(filename); } +////////////////////////////////////////////////////////////////////////////////////////////////// struct Function_Signature{ String name; String ret; From bc15f0ed3c783a094f7ff6b22ae778cbdc13f401 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Sun, 29 May 2016 16:12:53 -0400 Subject: [PATCH 08/34] removed open, and open_background from the dact system --- 4ed.cpp | 109 +++++----------------------------------------- 4ed_delay.cpp | 4 -- 4ed_file_view.cpp | 61 +++++++++++++++++++++++++- 4ed_metagen.cpp | 2 + 4 files changed, 72 insertions(+), 104 deletions(-) diff --git a/4ed.cpp b/4ed.cpp index e886b4e0..b7760547 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -801,13 +801,9 @@ COMMAND_DECL(interactive_new){ } COMMAND_DECL(interactive_open){ - USE_MODELS(models); - USE_PANEL(panel); USE_VIEW(view); - Delay *delay = &models->delay1; - char *filename = 0; int filename_len = 0; int do_in_background = 0; @@ -830,16 +826,10 @@ COMMAND_DECL(interactive_open){ if (filename){ String string = make_string(filename, filename_len); if (do_in_background){ - delayed_open_background(delay, string); + view_open_file(system, models, 0, string); } else{ - // TODO(allen): Change the behavior of all delayed_open/background - // calls so that they still allocate the buffer right away. This way - // it's still possible to get at the buffer if so wished in the API. - // The switch for this view doesn't need to happen until the file is ready. - // - // Alternatively... fuck all delayed actions. Please make them go away. - delayed_open(delay, string, panel); + view_open_file(system, models, view, string); } } else{ @@ -848,54 +838,6 @@ COMMAND_DECL(interactive_open){ } } -internal void -view_file_in_panel(Command_Data *cmd, Panel *panel, Editing_File *file){ - Models *models = cmd->models; - - Partition old_part; - Temp_Memory temp; - View *old_view; - Partition *part; - - old_view = cmd->view; - old_part = cmd->part; - - cmd->view = panel->view; - part = &models->mem.part; - temp = begin_temp_memory(part); - cmd->part = partition_sub_part(part, Kbytes(16)); - - View *view = panel->view; - view_set_file(view, file, models); - view_show_file(view); - - cmd->part = old_part; - end_temp_memory(temp); - cmd->view = old_view; - - panel->view->map = get_map(models, file->settings.base_map_id); -} - -internal void -init_normal_file(System_Functions *system, Models *models, Editing_File *file, - char *buffer, i32 size){ - - General_Memory *general = &models->mem.general; - - String val = make_string(buffer, size); - file_create_from_string(system, models, file, file->name.source_path.str, val); - - if (file->settings.tokens_exist){ - file_first_lex_parallel(system, general, file); - } - - for (View_Iter iter = file_view_iter_init(&models->layout, file, 0); - file_view_iter_good(iter); - iter = file_view_iter_next(iter)){ - view_measure_wraps(general, iter.view); - } -} - // TODO(allen): Improvements to reopen // - Preserve existing token stack // - Keep current version open and do some sort of diff to keep @@ -1601,10 +1543,8 @@ COMMAND_DECL(set_settings){ } COMMAND_DECL(command_line){ - USE_VARS(vars); USE_MODELS(models); - USE_PANEL(panel); USE_VIEW(view); Partition *part = &models->mem.part; @@ -1784,7 +1724,7 @@ COMMAND_DECL(command_line){ } if (bind_to_new_view){ - view_file_in_panel(command, panel, file); + view_set_file(view, file, models); } proc = procs + vars->cli_processes.count++; @@ -3878,26 +3818,26 @@ App_Step_Sig(app_step){ } i32 i; - String file_name; + String filename; Panel *panel = models->layout.used_sentinel.next; for (i = 0; i < models->settings.init_files_count; ++i, panel = panel->next){ - file_name = make_string_slowly(models->settings.init_files[i]); + filename = make_string_slowly(models->settings.init_files[i]); if (i < models->layout.panel_count){ - delayed_open(&models->delay1, file_name, panel); + view_open_file(system, models, panel->view, filename); if (i == 0){ delayed_set_line(&models->delay1, panel, models->settings.initial_line); } } else{ - delayed_open_background(&models->delay1, file_name); + view_open_file(system, models, 0, filename); } } if (i < models->layout.panel_count){ - view_file_in_panel(cmd, panel, models->message_buffer); + view_set_file(panel->view, models->message_buffer, models); } } @@ -4361,7 +4301,6 @@ App_Step_Sig(app_step){ Working_Set *working_set = &models->working_set; Mem_Options *mem = &models->mem; General_Memory *general = &mem->general; - Partition *part = &mem->part; i32 count = models->delay1.count; models->delay1.count = 0; @@ -4383,41 +4322,13 @@ App_Step_Sig(app_step){ } }break; +#if 0 case DACT_OPEN: case DACT_OPEN_BACKGROUND: { - String filename = string; - Editing_File *file = working_set_contains(system, working_set, filename); - if (file == 0){ - File_Loading loading = system->file_load_begin(filename.str); - - if (loading.exists){ - Temp_Memory temp = begin_temp_memory(part); - char *buffer = push_array(part, char, loading.size); - - if (system->file_load_end(loading, buffer)){ - file = working_set_alloc_always(working_set, general); - if (file){ - file_init_strings(file); - file_set_name(working_set, file, filename.str); - working_set_add(system, working_set, file, general); - - init_normal_file(system, models, file, - buffer, loading.size); - } - } - - end_temp_memory(temp); - } - } - - if (file){ - if (act->type == DACT_OPEN){ - view_file_in_panel(cmd, panel, file); - } - } }break; +#endif case DACT_SET_LINE: { diff --git a/4ed_delay.cpp b/4ed_delay.cpp index 44c4062d..ab4c8e13 100644 --- a/4ed_delay.cpp +++ b/4ed_delay.cpp @@ -1,6 +1,4 @@ enum Action_Type{ - DACT_OPEN, - DACT_OPEN_BACKGROUND, DACT_SET_LINE, DACT_SWITCH, DACT_TRY_KILL, @@ -124,8 +122,6 @@ delayed_action_repush(Delay *delay, Delayed_Action *act){ return(new_act); } -#define delayed_open(delay, ...) delayed_action_(delay, DACT_OPEN, ##__VA_ARGS__) -#define delayed_open_background(delay, ...) delayed_action_(delay, DACT_OPEN_BACKGROUND, ##__VA_ARGS__) #define delayed_set_line(delay, ...) delayed_action_(delay, DACT_SET_LINE, ##__VA_ARGS__) #define delayed_switch(delay, ...) delayed_action_(delay, DACT_SWITCH, ##__VA_ARGS__) #define delayed_try_kill(delay, ...) delayed_action_(delay, DACT_TRY_KILL, ##__VA_ARGS__) diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index bc543671..5dde1eb7 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -3072,6 +3072,65 @@ view_new_file(System_Functions *system, Models *models, #endif } +internal void +init_normal_file(System_Functions *system, Models *models, Editing_File *file, + char *buffer, i32 size){ + + General_Memory *general = &models->mem.general; + + String val = make_string(buffer, size); + file_create_from_string(system, models, file, file->name.source_path.str, val); + + if (file->settings.tokens_exist){ + file_first_lex_parallel(system, general, file); + } + + for (View_Iter iter = file_view_iter_init(&models->layout, file, 0); + file_view_iter_good(iter); + iter = file_view_iter_next(iter)){ + view_measure_wraps(general, iter.view); + } +} + +internal void +view_open_file(System_Functions *system, Models *models, + View *view, String filename){ + Working_Set *working_set = &models->working_set; + General_Memory *general = &models->mem.general; + Partition *part = &models->mem.part; + + Editing_File *file = working_set_contains(system, working_set, filename); + + if (file == 0){ + File_Loading loading = system->file_load_begin(filename.str); + + if (loading.exists){ + Temp_Memory temp = begin_temp_memory(part); + char *buffer = push_array(part, char, loading.size); + + if (system->file_load_end(loading, buffer)){ + file = working_set_alloc_always(working_set, general); + if (file){ + file_init_strings(file); + file_set_name(working_set, file, filename.str); + working_set_add(system, working_set, file, general); + + init_normal_file(system, models, file, + buffer, loading.size); + } + } + + end_temp_memory(temp); + } + } + + if (file){ + if (view){ + view_set_file(view, file, models); + } + } +} + internal void interactive_view_complete(System_Functions *system, View *view, String dest, i32 user_action){ Models *models = view->persistent.models; @@ -3080,7 +3139,7 @@ interactive_view_complete(System_Functions *system, View *view, String dest, i32 switch (view->action){ case IAct_Open: - delayed_open(&models->delay1, dest, panel); + view_open_file(system, models, view, dest); delayed_touch_file(&models->delay1, old_file); break; diff --git a/4ed_metagen.cpp b/4ed_metagen.cpp index 07f84b9f..65d6cc76 100644 --- a/4ed_metagen.cpp +++ b/4ed_metagen.cpp @@ -146,8 +146,10 @@ char* generate_keycode_enum(){ ////////////////////////////////////////////////////////////////////////////////////////////////// char daction_enum_name[] = "Action_Type"; char *daction_enum[] = { +#if 0 "OPEN", "OPEN_BACKGROUND", +#endif "SET_LINE", #if 0 "SAVE_AS", From 37e0b17e7c778f5ed6d2f6541ae9f50207eec18c Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Sun, 29 May 2016 16:41:51 -0400 Subject: [PATCH 09/34] removed kill from the dact system --- 4ed.cpp | 36 ++-- 4ed_delay.cpp | 2 - 4ed_file_view.cpp | 445 ++++++++++++++++++++++++---------------------- 4ed_metagen.cpp | 3 + 4 files changed, 244 insertions(+), 242 deletions(-) diff --git a/4ed.cpp b/4ed.cpp index b7760547..d890e813 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -907,8 +907,7 @@ COMMAND_DECL(save){ if (file){ if (name.str){ if (!file->state.is_dummy && file_is_ready(file)){ - view_save_file(system, &models->mem, &models->working_set, - file, 0, name, 1); + view_save_file(system, models, file, 0, name, 1); } } else{ @@ -929,13 +928,11 @@ COMMAND_DECL(save){ if (name.size != 0){ if (file){ if (!file->state.is_dummy && file_is_ready(file)){ - view_save_file(system, &models->mem, &models->working_set, - file, 0, name, 0); + view_save_file(system, models, file, 0, name, 0); } } else{ - view_save_file(system, &models->mem, &models->working_set, - 0, 0, name, 0); + view_save_file(system, models, 0, 0, name, 0); } } } @@ -992,7 +989,7 @@ COMMAND_DECL(kill_buffer){ if (buffer_id != 0){ file = working_set_get_active_file(&models->working_set, buffer_id); if (file){ - delayed_kill(delay, file); + kill_file(system, models, file, string_zero()); } } else if (file){ @@ -4381,21 +4378,13 @@ App_Step_Sig(app_step){ view->map = get_map(models, file->settings.base_map_id); } }break; - + +#if 0 case DACT_KILL: { - if (!file && string.str){ - file = working_set_lookup_file(working_set, string); - if (!file){ - file = working_set_contains(system, working_set, string); - } - } - - if (file && !file->settings.never_kill){ - working_set_remove(system, working_set, file->name.source_path); - kill_file(system, exchange, models, file); - } + }break; +#endif case DACT_TRY_KILL: { @@ -4413,16 +4402,17 @@ App_Step_Sig(app_step){ file = working_set_contains(system, working_set, string); } } - + if (file && !file->settings.never_kill){ if (buffer_needs_save(file)){ - copy(&view->dest, file->name.live_name); view_show_interactive(system, view, &models->map_ui, - IAct_Sure_To_Kill, IInt_Sure_To_Kill, make_lit_string("Are you sure?")); + IAct_Sure_To_Kill, IInt_Sure_To_Kill, + make_lit_string("Are you sure?")); + copy(&view->dest, file->name.live_name); } else{ working_set_remove(system, working_set, file->name.source_path); - kill_file(system, exchange, models, file); + kill_file(system, models, file, string_zero()); } } }break; diff --git a/4ed_delay.cpp b/4ed_delay.cpp index ab4c8e13..6964aa2b 100644 --- a/4ed_delay.cpp +++ b/4ed_delay.cpp @@ -2,7 +2,6 @@ enum Action_Type{ DACT_SET_LINE, DACT_SWITCH, DACT_TRY_KILL, - DACT_KILL, DACT_TOUCH_FILE, DACT_CLOSE, }; @@ -125,6 +124,5 @@ delayed_action_repush(Delay *delay, Delayed_Action *act){ #define delayed_set_line(delay, ...) delayed_action_(delay, DACT_SET_LINE, ##__VA_ARGS__) #define delayed_switch(delay, ...) delayed_action_(delay, DACT_SWITCH, ##__VA_ARGS__) #define delayed_try_kill(delay, ...) delayed_action_(delay, DACT_TRY_KILL, ##__VA_ARGS__) -#define delayed_kill(delay, ...) delayed_action_(delay, DACT_KILL, ##__VA_ARGS__) #define delayed_touch_file(delay, ...) delayed_action_(delay, DACT_TOUCH_FILE, ##__VA_ARGS__) #define delayed_close(delay, ...) delayed_action_(delay, DACT_CLOSE, ##__VA_ARGS__) diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index 5dde1eb7..56c5b527 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -3023,8 +3023,11 @@ view_show_file(View *view){ } internal void -view_save_file(System_Functions *system, Mem_Options *mem, Working_Set *working_set, +view_save_file(System_Functions *system, Models *models, Editing_File *file, View *view, String filename, b32 save_as){ + Mem_Options *mem = &models->mem; + Working_Set *working_set = &models->working_set; + if (!file){ if (view){ file = view->file_data.file; @@ -3131,6 +3134,41 @@ view_open_file(System_Functions *system, Models *models, } } +internal void +kill_file(System_Functions *system, Models *models, + Editing_File *file, String string){ + Working_Set *working_set = &models->working_set; + + if (!file && string.str){ + file = working_set_lookup_file(working_set, string); + if (!file){ + file = working_set_contains(system, working_set, string); + } + } + + if (file && !file->settings.never_kill){ + working_set_remove(system, working_set, file->name.source_path); + file_close(system, &models->mem.general, file); + working_set_free_file(&models->working_set, file); + + File_Node *used = &models->working_set.used_sentinel; + File_Node *node = used->next; + for (View_Iter iter = file_view_iter_init(&models->layout, file, 0); + file_view_iter_good(iter); + iter = file_view_iter_next(iter)){ + if (node != used){ + iter.view->file_data.file = 0; + view_set_file(iter.view, (Editing_File*)node, models); + node = node->next; + } + else{ + iter.view->file_data.file = 0; + view_set_file(iter.view, 0, models); + } + } + } +} + internal void interactive_view_complete(System_Functions *system, View *view, String dest, i32 user_action){ Models *models = view->persistent.models; @@ -3144,8 +3182,7 @@ interactive_view_complete(System_Functions *system, View *view, String dest, i32 break; case IAct_Save_As: - view_save_file(system, &models->mem, &models->working_set, - 0, view, dest, 1); + view_save_file(system, models, 0, view, dest, 1); break; case IAct_New: @@ -3182,16 +3219,15 @@ interactive_view_complete(System_Functions *system, View *view, String dest, i32 case IAct_Sure_To_Kill: switch (user_action){ case 0: - delayed_kill(&models->delay1, dest); + kill_file(system, models, 0, dest); break; case 1: break; case 2: - view_save_file(system, &models->mem, &models->working_set, - 0, 0, dest, 0); - delayed_kill(&models->delay1, dest); + view_save_file(system, models, 0, 0, dest, 0); + kill_file(system, models, 0, dest);; break; } break; @@ -5055,8 +5091,8 @@ draw_style_preview(GUI_Target *gui_target, Render_Target *target, View *view, i3 internal i32 do_render_file_view(System_Functions *system, Exchange *exchange, - View *view, View *active, i32_Rect rect, b32 is_active, - Render_Target *target, Input_Summary *user_input){ + View *view, View *active, i32_Rect rect, b32 is_active, + Render_Target *target, Input_Summary *user_input){ Editing_File *file = view->file_data.file; i32 result = 0; @@ -5067,233 +5103,208 @@ do_render_file_view(System_Functions *system, Exchange *exchange, GUI_Interpret_Result interpret_result = {0}; f32 v; - + if (gui_target->push.pos > 0){ - gui_session_init(&gui_session, gui_target, rect, view->font_height); - - v = view_get_scroll_y(view); - - i32_Rect clip_rect = rect; - draw_push_clip(target, clip_rect); - - for (h = (GUI_Header*)gui_target->push.base; - h->type; - h = NextHeader(h)){ - interpret_result = gui_interpret(gui_target, &gui_session, h, - *view->current_scroll, - view->scroll_region); + gui_session_init(&gui_session, gui_target, rect, view->font_height); - if (interpret_result.has_info){ - if (gui_session.clip_y > clip_rect.y0){ - clip_rect.y0 = gui_session.clip_y; - draw_change_clip(target, clip_rect); - } + v = view_get_scroll_y(view); + + i32_Rect clip_rect = rect; + draw_push_clip(target, clip_rect); + + for (h = (GUI_Header*)gui_target->push.base; + h->type; + h = NextHeader(h)){ + interpret_result = gui_interpret(gui_target, &gui_session, h, + *view->current_scroll, + view->scroll_region); - switch (h->type){ - case guicom_top_bar: - { - draw_file_bar(target, view, file, gui_session.rect); - }break; - - case guicom_file: - { - if (view->reinit_scrolling){ - view_reinit_scrolling(view); - } - if (file && file_is_ready(file)){ - result = draw_file_loaded(view, gui_session.rect, is_active, target); - } - }break; + if (interpret_result.has_info){ + if (gui_session.clip_y > clip_rect.y0){ + clip_rect.y0 = gui_session.clip_y; + draw_change_clip(target, clip_rect); + } - case guicom_text_field: - { - void *ptr = (h+1); - String p = gui_read_string(&ptr); - String t = gui_read_string(&ptr); - draw_text_field(target, view, gui_session.rect, p, t); - }break; - - case guicom_text_with_cursor: - { - void *ptr = (h+1); - String s = gui_read_string(&ptr); - i32 pos = gui_read_integer(&ptr); + switch (h->type){ + case guicom_top_bar: + { + draw_file_bar(target, view, file, gui_session.rect); + }break; - draw_text_with_cursor(target, view, gui_session.rect, s, pos); - }break; - - case guicom_color_button: - { - GUI_Interactive *b = (GUI_Interactive*)h; - void *ptr = (b + 1); - u32 fore = (u32)gui_read_integer(&ptr); - u32 back = (u32)gui_read_integer(&ptr); - String t = gui_read_string(&ptr); + case guicom_file: + { + if (view->reinit_scrolling){ + view_reinit_scrolling(view); + } + if (file && file_is_ready(file)){ + result = draw_file_loaded(view, gui_session.rect, is_active, target); + } + }break; - draw_color_button(gui_target, target, view, gui_session.rect, b->id, fore, back, t); - }break; - - case guicom_font_button: - { - GUI_Interactive *b = (GUI_Interactive*)h; - void *ptr = (b + 1); - i16 font_id = (i16)gui_read_integer(&ptr); - String t = gui_read_string(&ptr); + case guicom_text_field: + { + void *ptr = (h+1); + String p = gui_read_string(&ptr); + String t = gui_read_string(&ptr); + draw_text_field(target, view, gui_session.rect, p, t); + }break; - draw_font_button(gui_target, target, view, gui_session.rect, b->id, font_id, t); - }break; - - case guicom_file_option: - { - GUI_Interactive *b = (GUI_Interactive*)h; - void *ptr = (b + 1); - b32 folder = gui_read_integer(&ptr); - String f = gui_read_string(&ptr); - String m = gui_read_string(&ptr); + case guicom_text_with_cursor: + { + void *ptr = (h+1); + String s = gui_read_string(&ptr); + i32 pos = gui_read_integer(&ptr); + + draw_text_with_cursor(target, view, gui_session.rect, s, pos); + }break; - if (folder){ - append(&f, system->slash); - } + case guicom_color_button: + { + GUI_Interactive *b = (GUI_Interactive*)h; + void *ptr = (b + 1); + u32 fore = (u32)gui_read_integer(&ptr); + u32 back = (u32)gui_read_integer(&ptr); + String t = gui_read_string(&ptr); + + draw_color_button(gui_target, target, view, gui_session.rect, b->id, fore, back, t); + }break; - draw_fat_option_block(gui_target, target, view, gui_session.rect, b->id, f, m); - }break; - - case guicom_style_preview: - { - GUI_Interactive *b = (GUI_Interactive*)h; - i32 style_index = *(i32*)(b + 1); - Style *style = get_style(view->persistent.models, style_index); + case guicom_font_button: + { + GUI_Interactive *b = (GUI_Interactive*)h; + void *ptr = (b + 1); + i16 font_id = (i16)gui_read_integer(&ptr); + String t = gui_read_string(&ptr); + + draw_font_button(gui_target, target, view, gui_session.rect, b->id, font_id, t); + }break; - draw_style_preview(gui_target, target, view, gui_session.rect, b->id, style); - }break; - - case guicom_fixed_option: - case guicom_fixed_option_checkbox: - { - GUI_Interactive *b = (GUI_Interactive*)h; - void *ptr = (b + 1); - String f = gui_read_string(&ptr); - String m = {0}; - i8 status = -1; - if (h->type == guicom_fixed_option_checkbox){ - gui_read_byte(&ptr); - status = (i8)gui_read_byte(&ptr); - } + case guicom_file_option: + { + GUI_Interactive *b = (GUI_Interactive*)h; + void *ptr = (b + 1); + b32 folder = gui_read_integer(&ptr); + String f = gui_read_string(&ptr); + String m = gui_read_string(&ptr); + + if (folder){ + append(&f, system->slash); + } + + draw_fat_option_block(gui_target, target, view, gui_session.rect, b->id, f, m); + }break; - draw_fat_option_block(gui_target, target, view, gui_session.rect, b->id, f, m, status); - }break; - - case guicom_button: - { - GUI_Interactive *b = (GUI_Interactive*)h; - void *ptr = (b + 1); - String t = gui_read_string(&ptr); + case guicom_style_preview: + { + GUI_Interactive *b = (GUI_Interactive*)h; + i32 style_index = *(i32*)(b + 1); + Style *style = get_style(view->persistent.models, style_index); + + draw_style_preview(gui_target, target, view, gui_session.rect, b->id, style); + }break; - draw_button(gui_target, target, view, gui_session.rect, b->id, t); - }break; - - case guicom_scrollable_bar: - { - Models *models = view->persistent.models; - Style *style = main_style(models); + case guicom_fixed_option: + case guicom_fixed_option_checkbox: + { + GUI_Interactive *b = (GUI_Interactive*)h; + void *ptr = (b + 1); + String f = gui_read_string(&ptr); + String m = {0}; + i8 status = -1; + if (h->type == guicom_fixed_option_checkbox){ + gui_read_byte(&ptr); + status = (i8)gui_read_byte(&ptr); + } + + draw_fat_option_block(gui_target, target, view, gui_session.rect, b->id, f, m, status); + }break; - u32 back; - u32 outline; + case guicom_button: + { + GUI_Interactive *b = (GUI_Interactive*)h; + void *ptr = (b + 1); + String t = gui_read_string(&ptr); + + draw_button(gui_target, target, view, gui_session.rect, b->id, t); + }break; - i32_Rect bar = gui_session.rect; + case guicom_scrollable_bar: + { + Models *models = view->persistent.models; + Style *style = main_style(models); + + u32 back; + u32 outline; + + i32_Rect bar = gui_session.rect; + + back = style->main.back_color; + if (is_active){ + outline = style->main.margin_active_color; + } + else{ + outline = style->main.margin_color; + } + + draw_rectangle(target, bar, back); + draw_rectangle_outline(target, bar, outline); + }break; - back = style->main.back_color; - if (is_active){ - outline = style->main.margin_active_color; - } - else{ - outline = style->main.margin_color; - } + case guicom_scrollable_top: + case guicom_scrollable_slider: + case guicom_scrollable_bottom: + { + GUI_id id; + Models *models = view->persistent.models; + Style *style = main_style(models); + i32_Rect box = gui_session.rect; + + i32 active_level; + + u32 back; + u32 outline; + + switch (h->type){ + case guicom_scrollable_top: id = gui_id_scrollbar_top(); break; + case guicom_scrollable_bottom: id = gui_id_scrollbar_bottom(); break; + default: id = gui_id_scrollbar_slider(); break; + } + + active_level = gui_active_level(gui_target, id); + + switch (active_level){ + case 0: back = style->main.back_color; break; + case 1: back = style->main.margin_hover_color; break; + default: back = style->main.margin_active_color; break; + } + + if (is_active){ + outline = style->main.margin_active_color; + } + else{ + outline = style->main.margin_color; + } + + draw_rectangle(target, box, back); + draw_margin(target, box, get_inner_rect(box, 2), outline); + }break; - draw_rectangle(target, bar, back); - draw_rectangle_outline(target, bar, outline); - }break; - - case guicom_scrollable_top: - case guicom_scrollable_slider: - case guicom_scrollable_bottom: - { - GUI_id id; - Models *models = view->persistent.models; - Style *style = main_style(models); - i32_Rect box = gui_session.rect; + case guicom_begin_scrollable_section: + clip_rect.x1 = Min(gui_session.scroll_region.x1, clip_rect.x1); + draw_push_clip(target, clip_rect); + break; - i32 active_level; - - u32 back; - u32 outline; - - switch (h->type){ - case guicom_scrollable_top: id = gui_id_scrollbar_top(); break; - case guicom_scrollable_bottom: id = gui_id_scrollbar_bottom(); break; - default: id = gui_id_scrollbar_slider(); break; - } - - active_level = gui_active_level(gui_target, id); - - switch (active_level){ - case 0: back = style->main.back_color; break; - case 1: back = style->main.margin_hover_color; break; - default: back = style->main.margin_active_color; break; - } - - if (is_active){ - outline = style->main.margin_active_color; - } - else{ - outline = style->main.margin_color; - } - - draw_rectangle(target, box, back); - draw_margin(target, box, get_inner_rect(box, 2), outline); - }break; - - case guicom_begin_scrollable_section: - clip_rect.x1 = Min(gui_session.scroll_region.x1, clip_rect.x1); - draw_push_clip(target, clip_rect); - break; - - case guicom_end_scrollable_section: - clip_rect = draw_pop_clip(target); - break; - } - } - } - - draw_pop_clip(target); -} - - return(result); -} - -internal void -kill_file(System_Functions *system, Exchange *exchange, Models *models, Editing_File *file){ - File_Node *node, *used; - - file_close(system, &models->mem.general, file); - working_set_free_file(&models->working_set, file); - - used = &models->working_set.used_sentinel; - node = used->next; - - for (View_Iter iter = file_view_iter_init(&models->layout, file, 0); - file_view_iter_good(iter); - iter = file_view_iter_next(iter)){ - if (node != used){ - iter.view->file_data.file = 0; - view_set_file(iter.view, (Editing_File*)node, models); - node = node->next; - } - else{ - iter.view->file_data.file = 0; - view_set_file(iter.view, 0, models); + case guicom_end_scrollable_section: + clip_rect = draw_pop_clip(target); + break; + } + } } + + draw_pop_clip(target); } + + return(result); } inline void diff --git a/4ed_metagen.cpp b/4ed_metagen.cpp index 65d6cc76..93f707ec 100644 --- a/4ed_metagen.cpp +++ b/4ed_metagen.cpp @@ -158,8 +158,11 @@ char *daction_enum[] = { #endif "SWITCH", "TRY_KILL", +#if 0 "KILL", +#endif "TOUCH_FILE", + "CLOSE", }; From cd6614b21522985f22af5ca89c29014f0dfb99e2 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Sun, 29 May 2016 16:50:07 -0400 Subject: [PATCH 10/34] removed 'touch' from the dact system --- 4ed.cpp | 9 ++++----- 4ed_delay.cpp | 2 -- 4ed_file.cpp | 8 +++++--- 4ed_file_view.cpp | 4 ++-- 4ed_metagen.cpp | 2 +- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/4ed.cpp b/4ed.cpp index d890e813..231a95ad 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -4312,13 +4312,12 @@ App_Step_Sig(app_step){ // TODO(allen): Paramter checking in each DACT case. switch (act->type){ +#if 0 case DACT_TOUCH_FILE: { - if (file){ - touch_file(working_set, file); - } + }break; - +#endif #if 0 case DACT_OPEN: case DACT_OPEN_BACKGROUND: @@ -4326,7 +4325,7 @@ App_Step_Sig(app_step){ }break; #endif - + case DACT_SET_LINE: { // TODO(allen): deduplicate diff --git a/4ed_delay.cpp b/4ed_delay.cpp index 6964aa2b..11812a4a 100644 --- a/4ed_delay.cpp +++ b/4ed_delay.cpp @@ -2,7 +2,6 @@ enum Action_Type{ DACT_SET_LINE, DACT_SWITCH, DACT_TRY_KILL, - DACT_TOUCH_FILE, DACT_CLOSE, }; @@ -124,5 +123,4 @@ delayed_action_repush(Delay *delay, Delayed_Action *act){ #define delayed_set_line(delay, ...) delayed_action_(delay, DACT_SET_LINE, ##__VA_ARGS__) #define delayed_switch(delay, ...) delayed_action_(delay, DACT_SWITCH, ##__VA_ARGS__) #define delayed_try_kill(delay, ...) delayed_action_(delay, DACT_TRY_KILL, ##__VA_ARGS__) -#define delayed_touch_file(delay, ...) delayed_action_(delay, DACT_TOUCH_FILE, ##__VA_ARGS__) #define delayed_close(delay, ...) delayed_action_(delay, DACT_CLOSE, ##__VA_ARGS__) diff --git a/4ed_file.cpp b/4ed_file.cpp index 123ca46d..61e63c6e 100644 --- a/4ed_file.cpp +++ b/4ed_file.cpp @@ -488,9 +488,11 @@ working_set_lookup_file(Working_Set *working_set, String string){ internal void touch_file(Working_Set *working_set, Editing_File *file){ - Assert(!file->state.is_dummy); - dll_remove(&file->node); - dll_insert(&working_set->used_sentinel, &file->node); + if (file){ + Assert(!file->state.is_dummy); + dll_remove(&file->node); + dll_insert(&working_set->used_sentinel, &file->node); + } } // Hot Directory diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index 56c5b527..2f25d74c 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -3178,7 +3178,7 @@ interactive_view_complete(System_Functions *system, View *view, String dest, i32 switch (view->action){ case IAct_Open: view_open_file(system, models, view, dest); - delayed_touch_file(&models->delay1, old_file); + touch_file(&models->working_set, old_file); break; case IAct_Save_As: @@ -3194,7 +3194,7 @@ interactive_view_complete(System_Functions *system, View *view, String dest, i32 case IAct_Switch: delayed_switch(&models->delay1, dest, panel); - delayed_touch_file(&models->delay1, old_file); + touch_file(&models->working_set, old_file); break; case IAct_Kill: diff --git a/4ed_metagen.cpp b/4ed_metagen.cpp index 93f707ec..88107e8b 100644 --- a/4ed_metagen.cpp +++ b/4ed_metagen.cpp @@ -160,8 +160,8 @@ char *daction_enum[] = { "TRY_KILL", #if 0 "KILL", -#endif "TOUCH_FILE", +#endif "CLOSE", }; From 5138d565d8c564e3e86496d81fab2155aa8ce224 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Sun, 29 May 2016 17:02:03 -0400 Subject: [PATCH 11/34] removed switch from the dact system --- 4ed.cpp | 19 ++++--------------- 4ed_delay.cpp | 2 -- 4ed_file_view.cpp | 17 ++++++++++++++--- 4ed_metagen.cpp | 2 +- 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/4ed.cpp b/4ed.cpp index 231a95ad..6a709795 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -4359,25 +4359,14 @@ App_Step_Sig(app_step){ }break; #endif - + +#if 0 case DACT_SWITCH: { - if (!file && string.str){ - file = working_set_lookup_file(working_set, string); - if (!file){ - file = working_set_contains(system, working_set, string); - } - } - if (file){ - View *view = panel->view; - - view_set_file(view, file, models); - view_show_file(view); - view->map = get_map(models, file->settings.base_map_id); - } }break; - +#endif + #if 0 case DACT_KILL: { diff --git a/4ed_delay.cpp b/4ed_delay.cpp index 11812a4a..73a00831 100644 --- a/4ed_delay.cpp +++ b/4ed_delay.cpp @@ -1,6 +1,5 @@ enum Action_Type{ DACT_SET_LINE, - DACT_SWITCH, DACT_TRY_KILL, DACT_CLOSE, }; @@ -121,6 +120,5 @@ delayed_action_repush(Delay *delay, Delayed_Action *act){ } #define delayed_set_line(delay, ...) delayed_action_(delay, DACT_SET_LINE, ##__VA_ARGS__) -#define delayed_switch(delay, ...) delayed_action_(delay, DACT_SWITCH, ##__VA_ARGS__) #define delayed_try_kill(delay, ...) delayed_action_(delay, DACT_TRY_KILL, ##__VA_ARGS__) #define delayed_close(delay, ...) delayed_action_(delay, DACT_CLOSE, ##__VA_ARGS__) diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index 2f25d74c..c4ea7d47 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -3172,7 +3172,6 @@ kill_file(System_Functions *system, Models *models, internal void interactive_view_complete(System_Functions *system, View *view, String dest, i32 user_action){ Models *models = view->persistent.models; - Panel *panel = view->panel; Editing_File *old_file = view->file_data.file; switch (view->action){ @@ -3193,8 +3192,20 @@ interactive_view_complete(System_Functions *system, View *view, String dest, i32 }break; case IAct_Switch: - delayed_switch(&models->delay1, dest, panel); - touch_file(&models->working_set, old_file); + { + touch_file(&models->working_set, old_file); + + Editing_File *file = 0; + String string = dest; + + file = working_set_lookup_file(&models->working_set, string); + if (!file){ + file = working_set_contains(system, &models->working_set, string); + } + if (file){ + view_set_file(view, file, models); + } + } break; case IAct_Kill: diff --git a/4ed_metagen.cpp b/4ed_metagen.cpp index 88107e8b..4b3295e9 100644 --- a/4ed_metagen.cpp +++ b/4ed_metagen.cpp @@ -155,8 +155,8 @@ char *daction_enum[] = { "SAVE_AS", "SAVE", "NEW", -#endif "SWITCH", +#endif "TRY_KILL", #if 0 "KILL", From 5275ac58238d39b3cef10a4a44c574430b224cd8 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Sun, 29 May 2016 17:34:52 -0400 Subject: [PATCH 12/34] removed try_kill from the dact system --- 4ed.cpp | 44 ++++++++------------------- 4ed_app_models.h | 4 +-- 4ed_delay.cpp | 4 --- 4ed_file_view.cpp | 76 +++++++++++++++++++++++++++++++++++++++-------- 4ed_metagen.cpp | 5 +--- 5 files changed, 79 insertions(+), 54 deletions(-) diff --git a/4ed.cpp b/4ed.cpp index 6a709795..eb3fbc96 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -969,12 +969,10 @@ COMMAND_DECL(interactive_kill_buffer){ } COMMAND_DECL(kill_buffer){ - USE_MODELS(models); USE_VIEW(view); USE_FILE(file, view); - Delay *delay = &models->delay1; int buffer_id = 0; Command_Parameter *end = param_stack_end(&command->part); @@ -993,7 +991,8 @@ COMMAND_DECL(kill_buffer){ } } else if (file){ - delayed_try_kill(delay, file, view->panel); + try_kill_file(system, models, + file, view, string_zero()); } } @@ -3128,6 +3127,7 @@ App_Init_Sig(app_init){ vars = (App_Vars*)memory->vars_memory; models = &vars->models; + models->keep_playing = 1; app_links_init(system, &models->app_links, memory->user_memory, memory->user_memory_size); @@ -4374,41 +4374,21 @@ App_Step_Sig(app_step){ }break; #endif + +#if 0 case DACT_TRY_KILL: { - View *view = 0; - if (panel){ - view = panel->view; - } - else{ - view = (models->layout.panels + models->layout.active_panel)->view; - } - if (!file && string.str){ - file = working_set_lookup_file(working_set, string); - if (!file){ - file = working_set_contains(system, working_set, string); - } - } - - if (file && !file->settings.never_kill){ - if (buffer_needs_save(file)){ - view_show_interactive(system, view, &models->map_ui, - IAct_Sure_To_Kill, IInt_Sure_To_Kill, - make_lit_string("Are you sure?")); - copy(&view->dest, file->name.live_name); - } - else{ - working_set_remove(system, working_set, file->name.source_path); - kill_file(system, models, file, string_zero()); - } - } }break; - +#endif + +#if 0 case DACT_CLOSE: { - app_result.perform_kill = 1; + }break; +#endif + } if (string.str){ @@ -4538,6 +4518,8 @@ App_Step_Sig(app_step){ Assert(general_memory_check(&models->mem.general)); + app_result.perform_kill = models->keep_playing; + // end-of-app_step } diff --git a/4ed_app_models.h b/4ed_app_models.h index 35df15a6..ede2dd54 100644 --- a/4ed_app_models.h +++ b/4ed_app_models.h @@ -65,9 +65,7 @@ struct Models{ Custom_API config_api; Scroll_Rule_Function *scroll_rule; -#if 0 - File_Exchange files; -#endif + b32 keep_playing; }; // BOTTOM diff --git a/4ed_delay.cpp b/4ed_delay.cpp index 73a00831..a8ed2b84 100644 --- a/4ed_delay.cpp +++ b/4ed_delay.cpp @@ -1,7 +1,5 @@ enum Action_Type{ DACT_SET_LINE, - DACT_TRY_KILL, - DACT_CLOSE, }; struct Delayed_Action{ @@ -120,5 +118,3 @@ delayed_action_repush(Delay *delay, Delayed_Action *act){ } #define delayed_set_line(delay, ...) delayed_action_(delay, DACT_SET_LINE, ##__VA_ARGS__) -#define delayed_try_kill(delay, ...) delayed_action_(delay, DACT_TRY_KILL, ##__VA_ARGS__) -#define delayed_close(delay, ...) delayed_action_(delay, DACT_CLOSE, ##__VA_ARGS__) diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index c4ea7d47..2edc1150 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -3169,6 +3169,35 @@ kill_file(System_Functions *system, Models *models, } } +internal void +try_kill_file(System_Functions *system, Models *models, + Editing_File *file, View *view, String string){ + Working_Set *working_set = &models->working_set; + + if (!file && string.str){ + file = working_set_lookup_file(working_set, string); + if (!file){ + file = working_set_contains(system, working_set, string); + } + } + + if (file && !file->settings.never_kill){ + if (buffer_needs_save(file)){ + if (view == 0){ + view = models->layout.panels[models->layout.active_panel].view; + } + view_show_interactive(system, view, &models->map_ui, + IAct_Sure_To_Kill, IInt_Sure_To_Kill, + make_lit_string("Are you sure?")); + copy(&view->dest, file->name.live_name); + } + else{ + kill_file(system, models, file, string_zero()); + view_show_file(view); + } + } +} + internal void interactive_view_complete(System_Functions *system, View *view, String dest, i32 user_action){ Models *models = view->persistent.models; @@ -3178,10 +3207,12 @@ interactive_view_complete(System_Functions *system, View *view, String dest, i32 case IAct_Open: view_open_file(system, models, view, dest); touch_file(&models->working_set, old_file); + view_show_file(view); break; case IAct_Save_As: view_save_file(system, models, 0, view, dest, 1); + view_show_file(view); break; case IAct_New: @@ -3189,6 +3220,7 @@ interactive_view_complete(System_Functions *system, View *view, String dest, i32 if (dest.size > 0 && !char_is_slash(models->hot_directory.string.str[dest.size-1])){ view_new_file(system, models, view, dest); + view_show_file(view); }break; case IAct_Switch: @@ -3205,24 +3237,25 @@ interactive_view_complete(System_Functions *system, View *view, String dest, i32 if (file){ view_set_file(view, file, models); } + view_show_file(view); } break; case IAct_Kill: - delayed_try_kill(&models->delay1, dest); + try_kill_file(system, models, 0, 0, dest); break; case IAct_Sure_To_Close: switch (user_action){ case 0: - delayed_close(&models->delay1); + models->keep_playing = 0; break; case 1: break; case 2: - // TODO(allen): Save all. + // TODO(allen): Save all and close. break; } break; @@ -3231,6 +3264,7 @@ interactive_view_complete(System_Functions *system, View *view, String dest, i32 switch (user_action){ case 0: kill_file(system, models, 0, dest); + view_show_file(view); break; case 1: @@ -3238,12 +3272,12 @@ interactive_view_complete(System_Functions *system, View *view, String dest, i32 case 2: view_save_file(system, models, 0, 0, dest, 0); - kill_file(system, models, 0, dest);; + kill_file(system, models, 0, dest); + view_show_file(view); break; } break; } - view_show_file(view); } #if 0 @@ -4023,6 +4057,11 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su case VUI_Interactive: { + b32 complete = 0; + char comp_dest_space[1024]; + String comp_dest = make_fixed_width_string(comp_dest_space); + i32 comp_action = 0; + view->current_scroll = &view->gui_scroll; GUI_id id = {0}; @@ -4107,7 +4146,8 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su do_new_directory = 1; } else if (use_item_in_list){ - interactive_view_complete(system, view, loop.full_path, 0); + complete = 1; + copy(&comp_dest, loop.full_path); } } } @@ -4117,7 +4157,8 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su gui_end_list(target); if (activate_directly){ - interactive_view_complete(system, view, hdir->string, 0); + complete = 1; + copy(&comp_dest, hdir->string); } if (do_new_directory){ @@ -4211,7 +4252,8 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su id.id[0] = (u64)(file); if (gui_do_file_option(target, id, file->name.live_name, 0, message)){ - interactive_view_complete(system, view, file->name.live_name, 0); + complete = 1; + copy(&comp_dest, file->name.live_name); } } } @@ -4229,7 +4271,8 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su id.id[0] = (u64)(file); if (gui_do_file_option(target, id, file->name.live_name, 0, message)){ - interactive_view_complete(system, view, file->name.live_name, 0); + complete = 1; + copy(&comp_dest, file->name.live_name); } } @@ -4263,7 +4306,9 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su } if (action != -1){ - interactive_view_complete(system, view, view->dest, action); + complete = 1; + copy(&comp_dest, view->dest); + comp_action = action; } }break; @@ -4293,12 +4338,19 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su if (gui_do_fixed_option(target, id, message, 's')){ action = 2; } - + if (action != -1){ - interactive_view_complete(system, view, view->dest, action); + complete = 1; + copy(&comp_dest, view->dest); + comp_action = action; } }break; } + + if (complete){ + terminate_with_null(&comp_dest); + interactive_view_complete(system, view, comp_dest, comp_action); + } }break; } } diff --git a/4ed_metagen.cpp b/4ed_metagen.cpp index 4b3295e9..0c84a053 100644 --- a/4ed_metagen.cpp +++ b/4ed_metagen.cpp @@ -156,14 +156,11 @@ char *daction_enum[] = { "SAVE", "NEW", "SWITCH", -#endif "TRY_KILL", -#if 0 "KILL", "TOUCH_FILE", -#endif - "CLOSE", +#endif }; char str_alloc_copy[] = From 17dfa93c34c760f8816b36f2ca0fd08cdefcc5a3 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Sun, 29 May 2016 18:01:27 -0400 Subject: [PATCH 13/34] removed the delayed action system --- 4ed.cpp | 266 +++++++++++++-------------------------------- 4ed_app_models.h | 2 - 4ed_app_target.cpp | 1 - 4ed_delay.cpp | 120 -------------------- 4ed_file.cpp | 24 ++-- 4ed_file_view.cpp | 16 +-- 4ed_metagen.cpp | 185 ------------------------------- 7 files changed, 95 insertions(+), 519 deletions(-) delete mode 100644 4ed_delay.cpp diff --git a/4ed.cpp b/4ed.cpp index eb3fbc96..7b2441f5 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -906,7 +906,7 @@ COMMAND_DECL(save){ if (file){ if (name.str){ - if (!file->state.is_dummy && file_is_ready(file)){ + if (!file->is_dummy && file_is_ready(file)){ view_save_file(system, models, file, 0, name, 1); } } @@ -927,7 +927,7 @@ COMMAND_DECL(save){ if (name.size != 0){ if (file){ - if (!file->state.is_dummy && file_is_ready(file)){ + if (!file->is_dummy && file_is_ready(file)){ view_save_file(system, models, file, 0, name, 0); } } @@ -1751,7 +1751,7 @@ globalvar Command_Function command_table[cmdid_count]; internal void fill_buffer_summary(Buffer_Summary *buffer, Editing_File *file, Working_Set *working_set){ *buffer = buffer_summary_zero(); - if (!file->state.is_dummy){ + if (!file->is_dummy){ buffer->exists = 1; buffer->ready = file_is_ready(file); @@ -1952,7 +1952,7 @@ extern "C"{ Working_Set *working_set = &cmd->models->working_set; file = working_set_contains(cmd->system, working_set, make_string(filename, len)); - if (file && !file->state.is_dummy){ + if (file && !file->is_dummy){ fill_buffer_summary(&buffer, file, working_set); } @@ -2241,7 +2241,7 @@ extern "C"{ if (view_id >= 0 && view_id < live_set->max){ vptr = live_set->views + view_id; file = vptr->file_data.file; - if (file && !file->state.is_loading){ + if (file && !file->is_loading){ if (seek.type == buffer_seek_line_char && seek.character <= 0){ seek.character = 1; } @@ -2268,7 +2268,7 @@ extern "C"{ if (view_id >= 0 && view_id < live_set->max){ vptr = live_set->views + view_id; file = vptr->file_data.file; - if (file && !file->state.is_loading){ + if (file && !file->is_loading){ result = 1; if (seek.type == buffer_seek_line_char && seek.character <= 0){ seek.character = 1; @@ -2945,12 +2945,12 @@ init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, switch (arg[1]){ case 'u': action = CLAct_UserFile; strict = 0; break; case 'U': action = CLAct_UserFile; strict = 1; break; - + case 'd': action = CLAct_CustomDLL; strict = 0; break; case 'D': action = CLAct_CustomDLL; strict = 1; break; - + case 'i': action = CLAct_InitialFilePosition; break; - + case 'w': action = CLAct_WindowSize; break; case 'W': action = CLAct_WindowMaximize; break; case 'p': action = CLAct_WindowPosition; break; @@ -2965,7 +2965,7 @@ init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, } } }break; - + case CLAct_UserFile: { settings->user_file_is_strict = strict; @@ -2974,7 +2974,7 @@ init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, } action = CLAct_Nothing; }break; - + case CLAct_CustomDLL: { plat_settings->custom_dll_is_strict = strict; @@ -2983,7 +2983,7 @@ init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, } action = CLAct_Nothing; }break; - + case CLAct_InitialFilePosition: { if (i < clparams.argc){ @@ -2991,33 +2991,33 @@ init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, } action = CLAct_Nothing; }break; - + case CLAct_WindowSize: { if (i + 1 < clparams.argc){ plat_settings->set_window_size = 1; plat_settings->window_w = str_to_int(clparams.argv[i]); plat_settings->window_h = str_to_int(clparams.argv[i+1]); - + ++i; } action = CLAct_Nothing; }break; - + case CLAct_WindowMaximize: { --i; plat_settings->maximize_window = 1; action = CLAct_Nothing; }break; - + case CLAct_WindowPosition: { if (i + 1 < clparams.argc){ plat_settings->set_window_pos = 1; plat_settings->window_x = str_to_int(clparams.argv[i]); plat_settings->window_y = str_to_int(clparams.argv[i+1]); - + ++i; } action = CLAct_Nothing; @@ -3029,7 +3029,7 @@ init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, settings->font_size = str_to_int(clparams.argv[i]); } action = CLAct_Nothing; - }break; + }break; } } } @@ -3047,9 +3047,9 @@ app_setup_memory(Application_Memory *memory){ Assert(vars); *vars = app_vars_zero(); vars->models.mem.part = _partition; - + general_memory_open(&vars->models.mem.general, memory->target_memory, memory->target_memory_size); - + return(vars); } @@ -3079,13 +3079,13 @@ App_Read_Command_Line_Sig(app_read_command_line){ App_Vars *vars; App_Settings *settings; i32 out_size = 0; - + if (clparams.argc > 1 && match(clparams.argv[1], "-T")){ out_size = execute_special_tool(memory->target_memory, memory->target_memory_size, clparams); } else{ vars = app_setup_memory(memory); - + settings = &vars->models.settings; *settings = app_settings_zero(); settings->font_size = 16; @@ -3097,7 +3097,7 @@ App_Read_Command_Line_Sig(app_read_command_line){ *files = vars->models.settings.init_files; *file_count = &vars->models.settings.init_files_count; } - + return(out_size); } @@ -3190,7 +3190,7 @@ App_Init_Sig(app_init){ persistent->view_routine = models->config_api.view_routine; } } - + { Command_Map *global = 0; i32 wanted_size = 0; @@ -3415,17 +3415,6 @@ App_Init_Sig(app_init){ copy(dest, make_string((char*)clipboard.str, clipboard.size)); } - // NOTE(allen): delay setup - models->delay1.general = &models->mem.general; - models->delay1.max = 16; - models->delay1.acts = (Delayed_Action*)general_memory_allocate( - &models->mem.general, models->delay1.max*sizeof(Delayed_Action), 0); - - models->delay2.general = &models->mem.general; - models->delay2.max = 16; - models->delay2.acts = (Delayed_Action*)general_memory_allocate( - &models->mem.general, models->delay2.max*sizeof(Delayed_Action), 0); - // NOTE(allen): style setup app_hardcode_styles(models); @@ -3455,17 +3444,17 @@ App_Init_Sig(app_init){ internal i32 update_cli_handle_with_file(System_Functions *system, Models *models, - CLI_Handles *cli, Editing_File *file, char *dest, i32 max, b32 cursor_at_end){ + CLI_Handles *cli, Editing_File *file, char *dest, i32 max, b32 cursor_at_end){ i32 result = 0; u32 amount; for (system->cli_begin_update(cli); - system->cli_update_step(cli, dest, max, &amount);){ + system->cli_update_step(cli, dest, max, &amount);){ amount = eol_in_place_convert_in(dest, amount); output_file_append(system, models, file, make_string(dest, amount), cursor_at_end); result = 1; } - + if (system->cli_end_update(cli)){ char str_space[256]; String str = make_fixed_width_string(str_space); @@ -3474,16 +3463,16 @@ update_cli_handle_with_file(System_Functions *system, Models *models, output_file_append(system, models, file, str, cursor_at_end); result = -1; } - + i32 new_cursor = 0; if (cursor_at_end){ new_cursor = buffer_size(&file->state.buffer); } - + for (View_Iter iter = file_view_iter_init(&models->layout, file, 0); - file_view_iter_good(iter); - iter = file_view_iter_next(iter)){ + file_view_iter_good(iter); + iter = file_view_iter_next(iter)){ view_cursor_move(iter.view, new_cursor); } @@ -3656,16 +3645,16 @@ App_Step_Sig(app_step){ break; } } - + if (!(mouse_in_edit_area || mouse_in_margin_area)){ mouse_panel = 0; } - + b32 mouse_on_divider = 0; b32 mouse_divider_vertical = 0; i32 mouse_divider_id = 0; i32 mouse_divider_side = 0; - + if (mouse_in_margin_area){ Panel *panel = mouse_panel; if (mx >= panel->inner.x0 && mx < panel->inner.x1){ @@ -3686,20 +3675,20 @@ App_Step_Sig(app_step){ mouse_divider_side = 1; } } - + if (models->layout.panel_count > 1){ i32 which_child; mouse_divider_id = panel->parent; which_child = panel->which_child; for (;;){ Divider_And_ID div = layout_get_divider(&models->layout, mouse_divider_id); - + if (which_child == mouse_divider_side && - div.divider->v_divider == mouse_divider_vertical){ + div.divider->v_divider == mouse_divider_vertical){ mouse_on_divider = 1; break; } - + if (mouse_divider_id == models->layout.root){ break; } @@ -3752,16 +3741,16 @@ App_Step_Sig(app_step){ // NOTE(allen): prepare to start executing commands Command_Data *cmd = &vars->command_data; - + cmd->models = models; cmd->vars = vars; cmd->system = system; cmd->exchange = exchange; cmd->live_set = &vars->live_set; - + cmd->panel = models->layout.panels + models->layout.active_panel; cmd->view = cmd->panel->view; - + cmd->screen_width = target->width; cmd->screen_height = target->height; @@ -3813,7 +3802,7 @@ App_Step_Sig(app_step){ models->hooks[hook_start](&models->app_links); cmd->part.pos = 0; } - + i32 i; String filename; Panel *panel = models->layout.used_sentinel.next; @@ -3821,12 +3810,18 @@ App_Step_Sig(app_step){ i < models->settings.init_files_count; ++i, panel = panel->next){ filename = make_string_slowly(models->settings.init_files[i]); - + if (i < models->layout.panel_count){ view_open_file(system, models, panel->view, filename); +#if 0 if (i == 0){ - delayed_set_line(&models->delay1, panel, models->settings.initial_line); + if (panel->view->file_data.file){ + // TODO(allen): How to set the cursor of a file on the first frame? + view_compute_cursor_from_line_pos(panel->view, models->settings.initial_line, 1); + view_move_view_to_cursor(panel->view, &panel->view->recent->scroll); + } } +#endif } else{ view_open_file(system, models, 0, filename); @@ -3901,9 +3896,9 @@ App_Step_Sig(app_step){ Coroutine *command_coroutine = models->command_coroutine; u32 get_flags = models->command_coroutine_flags[0]; u32 abort_flags = models->command_coroutine_flags[1]; - + get_flags |= abort_flags; - + if ((get_flags & EventOnAnyKey) || (get_flags & EventOnEsc)){ Key_Summary key_data = get_key_data(&available_input); @@ -3912,25 +3907,25 @@ App_Step_Sig(app_step){ View *view = cmd->view; b32 pass_in = 0; cmd->key = key; - + Command_Map *map = 0; if (view) map = view->map; if (map == 0) map = &models->map_top; Command_Binding cmd_bind = map_extract_recursive(map, key); - + User_Input user_in; user_in.type = UserInputKey; user_in.key = key; user_in.command = (unsigned long long)cmd_bind.custom; user_in.abort = 0; - + if ((EventOnEsc & abort_flags) && key.keycode == key_esc){ user_in.abort = 1; } else if (EventOnAnyKey & abort_flags){ user_in.abort = 1; } - + if (EventOnAnyKey & get_flags){ pass_in = 1; consume_input(&available_input, Input_AnyKey); @@ -3941,7 +3936,7 @@ App_Step_Sig(app_step){ } consume_input(&available_input, Input_Esc); } - + if (pass_in){ models->command_coroutine = app_resume_coroutine(system, &models->app_links, Co_Command, @@ -3950,7 +3945,7 @@ App_Step_Sig(app_step){ models->command_coroutine_flags); app_result.animating = 1; - + // TOOD(allen): Deduplicate // TODO(allen): Should I somehow allow a view to clean up however it wants after a // command finishes, or after transfering to another view mid command? @@ -3961,18 +3956,18 @@ App_Step_Sig(app_step){ } } } - + // NOTE(allen): Mouse input to command coroutine if (models->command_coroutine != 0 && (get_flags & EventOnMouse)){ View *view = cmd->view; b32 pass_in = 0; - + User_Input user_in; user_in.type = UserInputMouse; user_in.mouse = input->mouse; user_in.command = 0; user_in.abort = 0; - + if (abort_flags & EventOnMouseMove){ user_in.abort = 1; } @@ -3980,7 +3975,7 @@ App_Step_Sig(app_step){ pass_in = 1; consume_input(&available_input, Input_MouseMove); } - + if (input->mouse.press_l || input->mouse.release_l || input->mouse.l){ if (abort_flags & EventOnLeftButton){ user_in.abort = 1; @@ -3990,7 +3985,7 @@ App_Step_Sig(app_step){ consume_input(&available_input, Input_MouseLeftButton); } } - + if (input->mouse.press_r || input->mouse.release_r || input->mouse.r){ if (abort_flags & EventOnRightButton){ user_in.abort = 1; @@ -4000,7 +3995,7 @@ App_Step_Sig(app_step){ consume_input(&available_input, Input_MouseRightButton); } } - + if (input->mouse.wheel != 0){ if (abort_flags & EventOnWheel){ user_in.abort = 1; @@ -4010,7 +4005,7 @@ App_Step_Sig(app_step){ consume_input(&available_input, Input_MouseWheel); } } - + if (pass_in){ models->command_coroutine = app_resume_coroutine(system, &models->app_links, Co_Command, @@ -4029,7 +4024,7 @@ App_Step_Sig(app_step){ } } } - + update_command_data(vars, cmd); // NOTE(allen): pass raw input to the panels @@ -4037,7 +4032,7 @@ App_Step_Sig(app_step){ Input_Summary dead_input = {}; dead_input.mouse.x = input->mouse.x; dead_input.mouse.y = input->mouse.y; - + Input_Summary active_input = {}; active_input.mouse.x = input->mouse.x; active_input.mouse.y = input->mouse.y; @@ -4086,7 +4081,7 @@ App_Step_Sig(app_step){ view->scroll_region = result.region; } } - + update_command_data(vars, cmd); // NOTE(allen): command execution @@ -4097,7 +4092,7 @@ App_Step_Sig(app_step){ for (i32 key_i = 0; key_i < key_data.count; ++key_i){ if (models->command_coroutine != 0) break; - + switch (vars->state){ case APP_STATE_EDIT: { @@ -4200,7 +4195,7 @@ App_Step_Sig(app_step){ vars->state = APP_STATE_RESIZING; Divider_And_ID div = layout_get_divider(&models->layout, mouse_divider_id); vars->resizing.divider = div.divider; - + i32 min, max; { i32 mid, MIN, MAX; @@ -4215,7 +4210,7 @@ App_Step_Sig(app_step){ } min = MIN; max = MAX; - + i32 divider_id = div.id; do{ Divider_And_ID other_div = layout_get_divider(&models->layout, divider_id); @@ -4229,12 +4224,12 @@ App_Step_Sig(app_step){ } divider_id = other_div.divider->parent; }while(divider_id != -1); - + Temp_Memory temp = begin_temp_memory(&models->mem.part); i32 *divider_stack = push_array(&models->mem.part, i32, models->layout.panel_count); i32 top = 0; divider_stack[top++] = div.id; - + while (top > 0){ Divider_And_ID other_div = layout_get_divider(&models->layout, divider_stack[--top]); b32 divider_match = (other_div.divider->v_divider == mouse_divider_vertical); @@ -4252,15 +4247,15 @@ App_Step_Sig(app_step){ divider_stack[top++] = other_div.divider->child2; } } - + end_temp_memory(temp); } - + vars->resizing.min = min; vars->resizing.max = max; } }break; - + case APP_STATE_RESIZING: { if (input->mouse.l){ @@ -4271,14 +4266,14 @@ App_Step_Sig(app_step){ else{ divider->pos = my; } - + if (divider->pos < vars->resizing.min){ divider->pos = vars->resizing.min; } else if (divider->pos > vars->resizing.max){ divider->pos = vars->resizing.max - 1; } - + layout_fix_all_panels(&models->layout); } else{ @@ -4293,111 +4288,6 @@ App_Step_Sig(app_step){ update_command_data(vars, cmd); - // NOTE(allen): process as many delayed actions as possible - if (models->delay1.count > 0){ - Working_Set *working_set = &models->working_set; - Mem_Options *mem = &models->mem; - General_Memory *general = &mem->general; - - i32 count = models->delay1.count; - models->delay1.count = 0; - models->delay2.count = 0; - - Delayed_Action *act = models->delay1.acts; - for (i32 i = 0; i < count; ++i, ++act){ - String string = act->string; - Panel *panel = act->panel; - Editing_File *file = act->file; - i32 integer = act->integer; - - // TODO(allen): Paramter checking in each DACT case. - switch (act->type){ -#if 0 - case DACT_TOUCH_FILE: - { - - }break; -#endif -#if 0 - case DACT_OPEN: - case DACT_OPEN_BACKGROUND: - { - - }break; -#endif - - case DACT_SET_LINE: - { - // TODO(allen): deduplicate - if (panel){ - file = panel->view->file_data.file; - } - else if (string.str && string.size > 0){ - file = working_set_lookup_file(working_set, string); - } - if (file){ - if (file->state.is_loading){ - file->preload.start_line = integer; - } - else{ - // TODO(allen): write this case - } - } - }break; - -#if 0 - case DACT_SAVE: - case DACT_SAVE_AS: - { - - }break; -#endif - -#if 0 - case DACT_NEW: - { - - }break; -#endif - -#if 0 - case DACT_SWITCH: - { - - }break; -#endif - -#if 0 - case DACT_KILL: - { - - }break; -#endif - - -#if 0 - case DACT_TRY_KILL: - { - - }break; -#endif - -#if 0 - case DACT_CLOSE: - { - - }break; -#endif - - } - - if (string.str){ - general_memory_free(general, string.str); - } - } - Swap(Delay, models->delay1, models->delay2); - } - end_temp_memory(param_stack_temp); // NOTE(allen): send resize messages to panels that have changed size diff --git a/4ed_app_models.h b/4ed_app_models.h index ede2dd54..0022ec49 100644 --- a/4ed_app_models.h +++ b/4ed_app_models.h @@ -58,8 +58,6 @@ struct Models{ char hot_dir_base_[256]; Hot_Directory hot_directory; - Delay delay1, delay2; - Panel *prev_mouse_panel; Custom_API config_api; diff --git a/4ed_app_target.cpp b/4ed_app_target.cpp index dd6e8d1d..1ec9a45b 100644 --- a/4ed_app_target.cpp +++ b/4ed_app_target.cpp @@ -44,7 +44,6 @@ #include "4ed_file.cpp" #include "4ed_gui.cpp" #include "4ed_layout.cpp" -#include "4ed_delay.cpp" #include "4ed_app_models.h" #include "4ed_file_view.cpp" #include "4ed.cpp" diff --git a/4ed_delay.cpp b/4ed_delay.cpp deleted file mode 100644 index a8ed2b84..00000000 --- a/4ed_delay.cpp +++ /dev/null @@ -1,120 +0,0 @@ -enum Action_Type{ - DACT_SET_LINE, -}; - -struct Delayed_Action{ - Action_Type type; - String string; - Panel* panel; - Editing_File* file; - i32 integer; -}; - -struct Delay{ - General_Memory* general; - Delayed_Action* acts; - i32 count; - i32 max; -}; - -internal String -str_alloc_copy(General_Memory *general, String str){ - String result; - result.memory_size = str.memory_size + 1; - result.size = str.size; - result.str = (char*)general_memory_allocate(general, result.memory_size, 0); - memcpy(result.str, str.str, str.size); - result.str[result.size] = 0; - return(result); -} - -inline Delayed_Action -delayed_action_zero(){ - Delayed_Action result = {(Action_Type)0}; - return(result); -} - -inline Delayed_Action* -delayed_action_(Delay *delay, Action_Type type){ - Delayed_Action *result; - if (delay->count == delay->max){ - delay->max *= 2; - delay->acts = (Delayed_Action*)general_memory_reallocate(delay->general, delay->acts, delay->count*sizeof(Delayed_Action), delay->max*sizeof(Delayed_Action), 0); - } - result = delay->acts + delay->count++; - *result = delayed_action_zero(); - result->type = type; - return(result); -} - -inline Delayed_Action* -delayed_action_(Delay *delay, Action_Type type, String string){ - Delayed_Action *result; - result = delayed_action_(delay, type); - result->string = str_alloc_copy(delay->general, string); - return(result); -} - -inline Delayed_Action* -delayed_action_(Delay *delay, Action_Type type, Panel* panel){ - Delayed_Action *result; - result = delayed_action_(delay, type); - result->panel = panel; - return(result); -} - -inline Delayed_Action* -delayed_action_(Delay *delay, Action_Type type, Editing_File* file){ - Delayed_Action *result; - result = delayed_action_(delay, type); - result->file = file; - return(result); -} - -inline Delayed_Action* -delayed_action_(Delay *delay, Action_Type type, Editing_File* file, Panel* panel){ - Delayed_Action *result; - result = delayed_action_(delay, type); - result->file = file; - result->panel = panel; - return(result); -} - -inline Delayed_Action* -delayed_action_(Delay *delay, Action_Type type, String string, Panel* panel){ - Delayed_Action *result; - result = delayed_action_(delay, type); - result->string = str_alloc_copy(delay->general, string); - result->panel = panel; - return(result); -} - -inline Delayed_Action* -delayed_action_(Delay *delay, Action_Type type, String string, Editing_File* file){ - Delayed_Action *result; - result = delayed_action_(delay, type); - result->string = str_alloc_copy(delay->general, string); - result->file = file; - return(result); -} - -inline Delayed_Action* -delayed_action_(Delay *delay, Action_Type type, Panel* panel, i32 integer){ - Delayed_Action *result; - result = delayed_action_(delay, type); - result->panel = panel; - result->integer = integer; - return(result); -} - -inline Delayed_Action* -delayed_action_repush(Delay *delay, Delayed_Action *act){ - Delayed_Action *new_act = delayed_action_(delay, (Action_Type)0); - *new_act = *act; - if (act->string.str){ - new_act->string = str_alloc_copy(delay->general, act->string); - } - return(new_act); -} - -#define delayed_set_line(delay, ...) delayed_action_(delay, DACT_SET_LINE, ##__VA_ARGS__) diff --git a/4ed_file.cpp b/4ed_file.cpp index 61e63c6e..51db66c0 100644 --- a/4ed_file.cpp +++ b/4ed_file.cpp @@ -111,9 +111,6 @@ struct Editing_File_Settings{ // NOTE(allen): This part of the Editing_File is cleared whenever // the contents of the file is set. struct Editing_File_State{ - b32 is_dummy; - b32 is_loading; - i16 font_id; Buffer_Type buffer; @@ -135,10 +132,6 @@ struct Editing_File_State{ u64 last_sys_write_time; }; -struct Editing_File_Preload{ - i32 start_line; -}; - struct Editing_File_Name{ char live_name_[256]; char source_path_[256]; @@ -168,9 +161,10 @@ struct Editing_File{ // NOTE(allen): node must be the first member of Editing_File! File_Node node; Editing_File_Settings settings; - union{ + struct{ + b32 is_loading; + b32 is_dummy; Editing_File_State state; - Editing_File_Preload preload; }; Editing_File_Name name; Buffer_Slot_ID id; @@ -317,7 +311,7 @@ working_set_alloc_always(Working_Set *working_set, General_Memory *general){ inline void working_set_free_file(Working_Set *working_set, Editing_File *file){ - file->state.is_dummy = 1; + file->is_dummy = 1; dll_remove(&file->node); dll_insert(&working_set->free_sentinel, &file->node); --working_set->file_count; @@ -349,7 +343,7 @@ inline Editing_File* working_set_get_active_file(Working_Set *working_set, Buffer_Slot_ID id){ Editing_File *result = 0; result = working_set_index(working_set, id); - if (result && result->state.is_dummy){ + if (result && result->is_dummy){ result = 0; } return(result); @@ -383,7 +377,7 @@ working_set_init(Working_Set *working_set, Partition *partition, General_Memory null_file = working_set_index(working_set, 0); dll_remove(&null_file->node); - null_file->state.is_dummy = 1; + null_file->is_dummy = 1; ++working_set->file_count; table_size = working_set->file_max; @@ -489,7 +483,7 @@ working_set_lookup_file(Working_Set *working_set, String string){ internal void touch_file(Working_Set *working_set, Editing_File *file){ if (file){ - Assert(!file->state.is_dummy); + Assert(!file->is_dummy); dll_remove(&file->node); dll_insert(&working_set->used_sentinel, &file->node); } @@ -650,7 +644,7 @@ buffer_needs_save(Editing_File *file){ inline b32 file_is_ready(Editing_File *file){ b32 result = 0; - if (file && file->state.is_loading == 0){ + if (file && file->is_loading == 0){ result = 1; } return(result); @@ -672,7 +666,7 @@ inline void file_set_to_loading(Editing_File *file){ file->state = editing_file_state_zero(); file->settings = editing_file_settings_zero(); - file->state.is_loading = 1; + file->is_loading = 1; } // BOTTOM diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index 2edc1150..c0925fab 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -627,7 +627,7 @@ view_compute_lowest_line(View *view){ f32 max_width = view_file_width(view); Editing_File *file = view->file_data.file; - Assert(!file->state.is_dummy); + Assert(!file->is_dummy); f32 width = file->state.buffer.line_widths[last_line]; i32 line_span = view_wrapped_line_span(width, max_width); lowest_line += line_span - 1; @@ -878,7 +878,7 @@ file_first_lex_parallel(System_Functions *system, General_Memory *general, Editing_File *file){ file->settings.tokens_exist = 1; - if (file->state.is_loading == 0 && file->state.still_lexing == 0){ + if (file->is_loading == 0 && file->state.still_lexing == 0){ Assert(file->state.token_stack.tokens == 0); file->state.tokens_complete = 0; @@ -2428,7 +2428,7 @@ view_clean_whitespace(System_Functions *system, Models *models, View *view){ i32 edit_max = line_count * 2; i32 edit_count = 0; - Assert(file && !file->state.is_dummy); + Assert(file && !file->is_dummy); Temp_Memory temp = begin_temp_memory(part); Buffer_Edit *edits = push_array(part, Buffer_Edit, edit_max); @@ -2844,7 +2844,7 @@ view_auto_tab_tokens(System_Functions *system, Models *models, Partition *part = &mem->part; Buffer *buffer = &file->state.buffer; - Assert(file && !file->state.is_dummy); + Assert(file && !file->is_dummy); Cpp_Token_Stack tokens = file->state.token_stack; Assert(tokens.tokens); @@ -3506,7 +3506,7 @@ internal b32 file_step(View *view, i32_Rect region, Input_Summary *user_input, b32 is_active){ i32 is_animating = 0; Editing_File *file = view->file_data.file; - if (file && !file->state.is_loading){ + if (file && !file->is_loading){ f32 max_visible_y = view_file_height(view); f32 max_x = view_file_width(view); @@ -4232,7 +4232,7 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su used_nodes = &working_set->used_sentinel; for (dll_items(node, used_nodes)){ file = (Editing_File*)node; - Assert(!file->state.is_dummy); + Assert(!file->is_dummy); if (filename_match(view->dest, &absolutes, file->name.live_name, 1)){ iter = file_view_iter_init(layout, file, 0); @@ -4687,7 +4687,7 @@ draw_file_loaded(View *view, i32_Rect rect, b32 is_active, Render_Target *target i32 max_x = rect.x1 - rect.x0; i32 max_y = rect.y1 - rect.y0 + line_height; - Assert(file && !file->state.is_dummy && buffer_good(&file->state.buffer)); + Assert(file && !file->is_dummy && buffer_good(&file->state.buffer)); b32 tokens_use = 0; Cpp_Token_Stack token_stack = {}; @@ -4941,7 +4941,7 @@ draw_file_bar(Render_Target *target, View *view, Editing_File *file, i32_Rect re intbar_draw_string(target, &bar, file->name.live_name, base_color); intbar_draw_string(target, &bar, make_lit_string(" -"), base_color); - if (file->state.is_loading){ + if (file->is_loading){ intbar_draw_string(target, &bar, make_lit_string(" loading"), base_color); } else{ diff --git a/4ed_metagen.cpp b/4ed_metagen.cpp index 0c84a053..3f790884 100644 --- a/4ed_metagen.cpp +++ b/4ed_metagen.cpp @@ -143,188 +143,6 @@ char* generate_keycode_enum(){ return(filename); } -////////////////////////////////////////////////////////////////////////////////////////////////// -char daction_enum_name[] = "Action_Type"; -char *daction_enum[] = { -#if 0 - "OPEN", - "OPEN_BACKGROUND", -#endif - "SET_LINE", -#if 0 - "SAVE_AS", - "SAVE", - "NEW", - "SWITCH", - "TRY_KILL", - "KILL", - "TOUCH_FILE", - "CLOSE", -#endif -}; - -char str_alloc_copy[] = -"internal String\n" -"str_alloc_copy(General_Memory *general, String str){\n" -" String result;\n" -" result.memory_size = str.memory_size + 1;\n" -" result.size = str.size;\n" -" result.str = (char*)general_memory_allocate(general, result.memory_size, 0);\n" -" memcpy(result.str, str.str, str.size);\n" -" result.str[result.size] = 0;\n" -" return(result);\n" -"}\n\n"; - -char delayed_action_zero[] = -"inline Delayed_Action\n" -"delayed_action_zero(){\n" -" Delayed_Action result = {(Action_Type)0};\n" -" return(result);\n" -"}\n\n" -; - -char daction_name[] = "Delayed_Action"; -Struct_Field daction_fields[] = { - {"Action_Type", "type"}, -}; -Struct_Field daction_fields_primary[] = { - {"String", "string"}, - {"Panel*", "panel"}, - {"Editing_File*", "file"}, - {"i32", "integer"}, -}; -enum Daction_Field_Handle{ - dfph_null, - dfph_string, - dfph_panel, - dfph_file, - dfph_integer, -}; -Daction_Field_Handle dact_param_sets[] = { - dfph_string, dfph_null, - dfph_panel, dfph_null, - dfph_file, dfph_null, - dfph_file, dfph_panel, dfph_null, - dfph_string, dfph_panel, dfph_null, - dfph_string, dfph_file, dfph_null, - dfph_panel, dfph_integer, dfph_null, -}; - -char delay_name[] = "Delay"; -Struct_Field delay_fields[] = { - {"General_Memory*", "general"}, - {"Delayed_Action*", "acts"}, - {"i32", "count"}, - {"i32", "max"}, -}; - -char delayed_action_function_top[] = -"inline Delayed_Action*\n" -"delayed_action_(Delay *delay, Action_Type type"; - -char delayed_action_function_bottom[] = -"){\n" -" Delayed_Action *result;\n" -" if (delay->count == delay->max){\n" -" delay->max *= 2;\n" -" delay->acts = (Delayed_Action*)general_memory_reallocate(" -"delay->general, delay->acts, delay->count*sizeof(Delayed_Action), delay->max*sizeof(Delayed_Action), 0);\n" -" }\n" -" result = delay->acts + delay->count++;\n" -" *result = delayed_action_zero();\n" -" result->type = type;\n" -" return(result);\n" -"}\n\n"; - -char delayed_action_special_param[] = ", %s %s"; - -char delayed_action_specialized_middle[] = -"){\n" -" Delayed_Action *result;\n" -" result = delayed_action_(delay, type);\n"; - -char delayed_action_special_line[] = -" result->%s = %s;\n"; - -char delayed_action_special_string_line[] = -" result->%s = str_alloc_copy(delay->general, %s);\n"; - -char delayed_action_specialized_bottom[] = -" return(result);\n" -"}\n\n"; - -char delayed_action_macro[] = -"#define delayed_%s(delay, ...) delayed_action_(delay, DACT_%s, ##__VA_ARGS__)\n"; - -char delayed_action_repush_function[] = -"inline Delayed_Action*\n" -"delayed_action_repush(Delay *delay, Delayed_Action *act){\n" -" Delayed_Action *new_act = delayed_action_(delay, (Action_Type)0);\n" -" *new_act = *act;\n" -" if (act->string.str){\n" -" new_act->string = str_alloc_copy(delay->general, act->string);\n" -" }\n" -" return(new_act);\n" -"}\n\n"; - -char* generate_delayed_action(){ - FILE *file; - char *filename = "4ed_delay.cpp"; - char scratch[256]; - int i,j; - - file = fopen(filename, "wb"); - - fprintf(file, "enum %s{\n", daction_enum_name); - for (i = 0; i < ArrayCount(daction_enum); ++i){ - fprintf(file, " DACT_%s,\n", daction_enum[i]); - } - fprintf(file, "};\n\n"); - - struct_begin(file, daction_name); - struct_fields(file, daction_fields, ArrayCount(daction_fields)); - struct_fields(file, daction_fields_primary, ArrayCount(daction_fields_primary)); - struct_end(file); - - struct_begin(file, delay_name); - struct_fields(file, delay_fields, ArrayCount(delay_fields)); - struct_end(file); - - fprintf(file, "%s", str_alloc_copy); - fprintf(file, "%s", delayed_action_zero); - fprintf(file, "%s%s", delayed_action_function_top, delayed_action_function_bottom); - - for (i = 0; i < ArrayCount(dact_param_sets); ++i){ - j = i; - fprintf(file, "%s", delayed_action_function_top); - for (; dact_param_sets[i] != dfph_null; ++i){ - Struct_Field field = daction_fields_primary[dact_param_sets[i] - 1]; - fprintf(file, delayed_action_special_param, field.type, field.name); - } - fprintf(file, "%s", delayed_action_specialized_middle); - for (; dact_param_sets[j] != dfph_null; ++j){ - int handle = (int)(dact_param_sets[j]); - Struct_Field field = daction_fields_primary[handle - 1]; - if (handle == dfph_string){ - fprintf(file, delayed_action_special_string_line, field.name, field.name); - } - else{ - fprintf(file, delayed_action_special_line, field.name, field.name); - } - } - fprintf(file, "%s", delayed_action_specialized_bottom); - } - - fprintf(file, "%s", delayed_action_repush_function); - - for (i = 0; i < ArrayCount(daction_enum); ++i){ - to_lower(daction_enum[i], scratch); - fprintf(file, delayed_action_macro, scratch, daction_enum[i]); - } - - return(filename); -} - ////////////////////////////////////////////////////////////////////////////////////////////////// char* bar_style_fields[] = { "bar", @@ -669,9 +487,6 @@ int main(){ filename = generate_keycode_enum(); printf("gen success: %s\n", filename); - filename = generate_delayed_action(); - printf("gen success: %s\n", filename); - filename = generate_style(); printf("gen success: %s\n", filename); From 4815ab86206afbe7e472f13a52585d306c7eeb93 Mon Sep 17 00:00:00 2001 From: insofaras Date: Mon, 30 May 2016 04:28:12 +0100 Subject: [PATCH 14/34] linux: update to match changes + do some spring cleaning --- linux_4ed.cpp | 770 +++++++++++++++++++++++++------------------------- 1 file changed, 385 insertions(+), 385 deletions(-) diff --git a/linux_4ed.cpp b/linux_4ed.cpp index 42519140..13b7393a 100644 --- a/linux_4ed.cpp +++ b/linux_4ed.cpp @@ -124,8 +124,7 @@ struct Linux_Vars{ XIMStyle input_style; XIC input_context; - Key_Input_Data key_data; - Mouse_State mouse_data; + Application_Step_Input input; String clipboard_contents; String clipboard_outgoing; @@ -133,10 +132,10 @@ struct Linux_Vars{ Atom atom_CLIPBOARD; Atom atom_UTF8_STRING; - Atom atom_NET_WM_STATE; - Atom atom_NET_WM_STATE_MAXIMIZED_HORZ; - Atom atom_NET_WM_STATE_MAXIMIZED_VERT; - Atom atom_NET_WM_PING; + Atom atom__NET_WM_STATE; + Atom atom__NET_WM_STATE_MAXIMIZED_HORZ; + Atom atom__NET_WM_STATE_MAXIMIZED_VERT; + Atom atom__NET_WM_PING; Atom atom_WM_DELETE_WINDOW; b32 has_xfixes; @@ -166,11 +165,9 @@ struct Linux_Vars{ Partition font_part; Plat_Settings settings; - System_Functions *system; + System_Functions system; App_Functions app; Custom_API custom_api; - b32 first; - b32 redraw; b32 vsync; #if FRED_INTERNAL @@ -381,6 +378,20 @@ Sys_File_Time_Stamp_Sig(system_file_time_stamp){ return(microsecond_timestamp); } +internal +Sys_Now_Time_Stamp_Sig(system_now_time_stamp){ + struct timespec spec; + u64 result; + + clock_gettime(CLOCK_REALTIME, &spec); + result = (spec.tv_sec * UINT64_C(1000000)) + (spec.tv_nsec / UINT64_C(1000)); + + //LINUX_FN_DEBUG("ts: %" PRIu64, result); + + return(result); +} + + internal Sys_Set_File_List_Sig(system_set_file_list){ DIR *d; @@ -681,23 +692,6 @@ Sys_Post_Clipboard_Sig(system_post_clipboard){ XSetSelectionOwner(linuxvars.XDisplay, linuxvars.atom_CLIPBOARD, linuxvars.XWindow, CurrentTime); } -// -// Time -// - -internal -Sys_Time_Sig(system_time){ - struct timespec spec; - u64 result; - - clock_gettime(CLOCK_REALTIME, &spec); - result = (spec.tv_sec * UINT64_C(1000000)) + (spec.tv_nsec / UINT64_C(1000)); - - //LINUX_FN_DEBUG("ts: %" PRIu64, result); - - return(result); -} - // // Coroutine // @@ -947,7 +941,7 @@ ThreadProc(void* arg){ thread_memory->size = new_size; } } - full_job->job.callback(linuxvars.system, thread, thread_memory, + full_job->job.callback(&linuxvars.system, thread, thread_memory, &exchange_vars.thread, full_job->job.data); full_job->running_thread = 0; thread->running = 0; @@ -1158,45 +1152,45 @@ LinuxLoadAppCode(String* base_dir){ internal void LinuxLoadSystemCode(){ - linuxvars.system->file_time_stamp = system_file_time_stamp; - linuxvars.system->file_unique_hash = system_file_unique_hash; - linuxvars.system->set_file_list = system_set_file_list; - linuxvars.system->file_track = system_file_track; - linuxvars.system->file_untrack = system_file_untrack; - linuxvars.system->file_load_begin = system_file_load_begin; - linuxvars.system->file_load_end = system_file_load_end; - linuxvars.system->file_save = system_file_save; + linuxvars.system.file_time_stamp = system_file_time_stamp; + linuxvars.system.file_unique_hash = system_file_unique_hash; + linuxvars.system.set_file_list = system_set_file_list; + linuxvars.system.file_track = system_file_track; + linuxvars.system.file_untrack = system_file_untrack; + linuxvars.system.file_load_begin = system_file_load_begin; + linuxvars.system.file_load_end = system_file_load_end; + linuxvars.system.file_save = system_file_save; - linuxvars.system->file_exists = system_file_exists; - linuxvars.system->directory_cd = system_directory_cd; - linuxvars.system->get_4ed_path = system_get_4ed_path; + linuxvars.system.file_exists = system_file_exists; + linuxvars.system.directory_cd = system_directory_cd; + linuxvars.system.get_4ed_path = system_get_4ed_path; - linuxvars.system->post_clipboard = system_post_clipboard; - linuxvars.system->time = system_time; + linuxvars.system.post_clipboard = system_post_clipboard; + linuxvars.system.now_time_stamp = system_now_time_stamp; - linuxvars.system->create_coroutine = system_create_coroutine; - linuxvars.system->launch_coroutine = system_launch_coroutine; - linuxvars.system->resume_coroutine = system_resume_coroutine; - linuxvars.system->yield_coroutine = system_yield_coroutine; + linuxvars.system.create_coroutine = system_create_coroutine; + linuxvars.system.launch_coroutine = system_launch_coroutine; + linuxvars.system.resume_coroutine = system_resume_coroutine; + linuxvars.system.yield_coroutine = system_yield_coroutine; - linuxvars.system->cli_call = system_cli_call; - linuxvars.system->cli_begin_update = system_cli_begin_update; - linuxvars.system->cli_update_step = system_cli_update_step; - linuxvars.system->cli_end_update = system_cli_end_update; + linuxvars.system.cli_call = system_cli_call; + linuxvars.system.cli_begin_update = system_cli_begin_update; + linuxvars.system.cli_update_step = system_cli_update_step; + linuxvars.system.cli_end_update = system_cli_end_update; - linuxvars.system->post_job = system_post_job; - linuxvars.system->cancel_job = system_cancel_job; - linuxvars.system->grow_thread_memory = system_grow_thread_memory; - linuxvars.system->acquire_lock = system_acquire_lock; - linuxvars.system->release_lock = system_release_lock; + linuxvars.system.post_job = system_post_job; + linuxvars.system.cancel_job = system_cancel_job; + linuxvars.system.grow_thread_memory = system_grow_thread_memory; + linuxvars.system.acquire_lock = system_acquire_lock; + linuxvars.system.release_lock = system_release_lock; #if FRED_INTERNAL - linuxvars.system->internal_sentinel = internal_sentinel; - linuxvars.system->internal_get_thread_states = internal_get_thread_states; - linuxvars.system->internal_debug_message = internal_debug_message; + linuxvars.system.internal_sentinel = internal_sentinel; + linuxvars.system.internal_get_thread_states = internal_get_thread_states; + linuxvars.system.internal_debug_message = internal_debug_message; #endif - linuxvars.system->slash = '/'; + linuxvars.system.slash = '/'; } internal void @@ -1232,7 +1226,6 @@ LinuxResizeTarget(i32 width, i32 height){ linuxvars.target.width = width; linuxvars.target.height = height; - linuxvars.redraw = 1; } } @@ -1542,9 +1535,8 @@ init_input_result_zero(){ return(result); } -// NOTE(inso): doesn't actually use XInput anymore, i should change the name... internal Init_Input_Result -InitializeXInput(Display *dpy, Window XWindow) +LinuxInputInit(Display *dpy, Window XWindow) { Init_Input_Result result = {}; XIMStyles *styles = 0; @@ -1711,11 +1703,11 @@ LinuxPushKey(u8 code, u8 chr, u8 chr_nocaps, b8 (*mods)[MDFR_INDEX_COUNT], b32 i Key_Event_Data *data; if(is_hold){ - count = &linuxvars.key_data.hold_count; - data = linuxvars.key_data.hold; + count = &linuxvars.input.keys.hold_count; + data = linuxvars.input.keys.hold; } else { - count = &linuxvars.key_data.press_count; - data = linuxvars.key_data.press; + count = &linuxvars.input.keys.press_count; + data = linuxvars.input.keys.press; } if(*count < KEY_INPUT_BUFFER_SIZE){ @@ -1771,7 +1763,7 @@ LinuxStringDup(String* str, void* data, size_t size){ internal void LinuxScheduleStep(void) { - u64 now = system_time(); + u64 now = system_now_time_stamp(); u64 diff = (now - linuxvars.last_step); if(diff > (u64)frame_useconds){ @@ -1802,12 +1794,12 @@ LinuxMaximizeWindow(Display* d, Window w, b32 maximize) XEvent e = {}; e.xany.type = ClientMessage; - e.xclient.message_type = linuxvars.atom_NET_WM_STATE; + e.xclient.message_type = linuxvars.atom__NET_WM_STATE; e.xclient.format = 32; e.xclient.window = w; e.xclient.data.l[0] = maximize ? STATE_ADD : STATE_REMOVE; - e.xclient.data.l[1] = linuxvars.atom_NET_WM_STATE_MAXIMIZED_VERT; - e.xclient.data.l[2] = linuxvars.atom_NET_WM_STATE_MAXIMIZED_HORZ; + e.xclient.data.l[1] = linuxvars.atom__NET_WM_STATE_MAXIMIZED_VERT; + e.xclient.data.l[2] = linuxvars.atom__NET_WM_STATE_MAXIMIZED_HORZ; e.xclient.data.l[3] = 0L; XSendEvent( @@ -1837,6 +1829,194 @@ LinuxSetIcon(Display* d, Window w) ); } +// +// X11 window init +// + +internal +b32 LinuxX11WindowInit(int argc, char** argv, int* WinWidth, int* WinHeight) +{ + // NOTE(allen): Here begins the linux screen setup stuff. + // Behold the true nature of this wonderful OS: + // (thanks again to Casey for providing this stuff) + + Colormap cmap; + XSetWindowAttributes swa; + b32 window_setup_success = 0; + + if (linuxvars.settings.set_window_size){ + *WinWidth = linuxvars.settings.window_w; + *WinHeight = linuxvars.settings.window_h; + } else { + *WinWidth = 800; + *WinHeight = 600; + } + + int XScreenCount = ScreenCount(linuxvars.XDisplay); + glx_config_result Config = {}; + + if(!GLXCanUseFBConfig(linuxvars.XDisplay)){ + fprintf(stderr, "Your GLX version is too old.\n"); + return false; + } + + // TODO(inso): maybe should try the default screen first? or only the default without iterating. + + for(int XScreenIndex = 0; + XScreenIndex < XScreenCount; + ++XScreenIndex) + { + Screen *XScreen = ScreenOfDisplay(linuxvars.XDisplay, XScreenIndex); + + i32 ScrnWidth, ScrnHeight; + ScrnWidth = WidthOfScreen(XScreen); + ScrnHeight = HeightOfScreen(XScreen); + + if (ScrnWidth + 50 < *WinWidth) *WinWidth = ScrnWidth + 50; + if (ScrnHeight + 50 < *WinHeight) *WinHeight = ScrnHeight + 50; + + Config = ChooseGLXConfig(linuxvars.XDisplay, XScreenIndex); + if(Config.Found) + { + swa.colormap = cmap = XCreateColormap(linuxvars.XDisplay, + RootWindow(linuxvars.XDisplay, Config.BestInfo.screen ), + Config.BestInfo.visual, AllocNone); + swa.background_pixmap = None; + swa.border_pixel = 0; + swa.event_mask = StructureNotifyMask; + + linuxvars.XWindow = + XCreateWindow(linuxvars.XDisplay, + RootWindow(linuxvars.XDisplay, Config.BestInfo.screen), + 0, 0, *WinWidth, *WinHeight, + 0, Config.BestInfo.depth, InputOutput, + Config.BestInfo.visual, + CWBorderPixel|CWColormap|CWEventMask, &swa); + + if(linuxvars.XWindow) + { + window_setup_success = 1; + break; + } + } + } + + if (!window_setup_success){ + fprintf(stderr, "Error creating window.\n"); + return false; + } + + //NOTE(inso): Set the window's type to normal + Atom _NET_WM_WINDOW_TYPE = XInternAtom(linuxvars.XDisplay, "_NET_WM_WINDOW_TYPE", False); + Atom _NET_WIN_TYPE_NORMAL = XInternAtom(linuxvars.XDisplay, "_NET_WM_WINDOW_TYPE_NORMAL", False); + XChangeProperty( + linuxvars.XDisplay, + linuxvars.XWindow, + _NET_WM_WINDOW_TYPE, + XA_ATOM, + 32, + PropModeReplace, + (unsigned char*)&_NET_WIN_TYPE_NORMAL, + 1 + ); + + //NOTE(inso): window managers want the PID as a window property for some reason. + Atom _NET_WM_PID = XInternAtom(linuxvars.XDisplay, "_NET_WM_PID", False); + pid_t pid = getpid(); + XChangeProperty( + linuxvars.XDisplay, + linuxvars.XWindow, + _NET_WM_PID, + XA_CARDINAL, + 32, + PropModeReplace, + (unsigned char*)&pid, + 1 + ); + +#define WINDOW_NAME "4coder 4linux: " VERSION + + //NOTE(inso): set wm properties + XStoreName(linuxvars.XDisplay, linuxvars.XWindow, WINDOW_NAME); + + char* win_name_list[] = { WINDOW_NAME }; + XTextProperty win_name; + + XStringListToTextProperty(win_name_list, 1, &win_name); + + XSizeHints *sz_hints = XAllocSizeHints(); + XWMHints *wm_hints = XAllocWMHints(); + XClassHint *cl_hints = XAllocClassHint(); + + if(linuxvars.settings.set_window_pos){ + sz_hints->flags |= USPosition; + sz_hints->x = linuxvars.settings.window_x; + sz_hints->y = linuxvars.settings.window_y; + } + + wm_hints->flags |= InputHint; + wm_hints->input = True; + + cl_hints->res_name = "4coder"; + cl_hints->res_class = "4coder"; + + XSetWMProperties( + linuxvars.XDisplay, + linuxvars.XWindow, + &win_name, + NULL, + argv, + argc, + sz_hints, + wm_hints, + cl_hints + ); + + XFree(sz_hints); + XFree(wm_hints); + XFree(cl_hints); + + XFree(win_name.value); + + LinuxSetIcon(linuxvars.XDisplay, linuxvars.XWindow); + + //NOTE(inso): make the window visible + XMapWindow(linuxvars.XDisplay, linuxvars.XWindow); + + b32 IsLegacy = false; + GLXContext GLContext = + InitializeOpenGLContext(linuxvars.XDisplay, linuxvars.XWindow, Config.BestConfig, IsLegacy); + + XWindowAttributes WinAttribs; + if(XGetWindowAttributes(linuxvars.XDisplay, linuxvars.XWindow, &WinAttribs)) + { + *WinWidth = WinAttribs.width; + *WinHeight = WinAttribs.height; + } + + XRaiseWindow(linuxvars.XDisplay, linuxvars.XWindow); + XSync(linuxvars.XDisplay, False); + + if (linuxvars.settings.set_window_pos){ + XMoveWindow( + linuxvars.XDisplay, + linuxvars.XWindow, + linuxvars.settings.window_x, + linuxvars.settings.window_y + ); + } + + if (linuxvars.settings.maximize_window){ + LinuxMaximizeWindow(linuxvars.XDisplay, linuxvars.XWindow, 1); + } + + Atom wm_protos[] = { + linuxvars.atom_WM_DELETE_WINDOW, + linuxvars.atom__NET_WM_PING + }; + + XSetWMProtocols(linuxvars.XDisplay, linuxvars.XWindow, wm_protos, 2); +} internal void LinuxHandleX11Events(void) @@ -1933,30 +2113,30 @@ LinuxHandleX11Events(void) case MotionNotify: { should_step = 1; - linuxvars.mouse_data.x = Event.xmotion.x; - linuxvars.mouse_data.y = Event.xmotion.y; + linuxvars.input.mouse.x = Event.xmotion.x; + linuxvars.input.mouse.y = Event.xmotion.y; }break; case ButtonPress: { should_step = 1; switch(Event.xbutton.button){ case Button1: { - linuxvars.mouse_data.press_l = 1; - linuxvars.mouse_data.l = 1; + linuxvars.input.mouse.press_l = 1; + linuxvars.input.mouse.l = 1; } break; case Button3: { - linuxvars.mouse_data.press_r = 1; - linuxvars.mouse_data.r = 1; + linuxvars.input.mouse.press_r = 1; + linuxvars.input.mouse.r = 1; } break; //NOTE(inso): scroll up case Button4: { - linuxvars.mouse_data.wheel = 1; + linuxvars.input.mouse.wheel = 1; }break; //NOTE(inso): scroll down case Button5: { - linuxvars.mouse_data.wheel = -1; + linuxvars.input.mouse.wheel = -1; }break; } }break; @@ -1965,31 +2145,31 @@ LinuxHandleX11Events(void) should_step = 1; switch(Event.xbutton.button){ case Button1: { - linuxvars.mouse_data.release_l = 1; - linuxvars.mouse_data.l = 0; + linuxvars.input.mouse.release_l = 1; + linuxvars.input.mouse.l = 0; } break; case Button3: { - linuxvars.mouse_data.release_r = 1; - linuxvars.mouse_data.r = 0; + linuxvars.input.mouse.release_r = 1; + linuxvars.input.mouse.r = 0; } break; } }break; case EnterNotify: { should_step = 1; - linuxvars.mouse_data.out_of_window = 0; + linuxvars.input.mouse.out_of_window = 0; }break; case LeaveNotify: { should_step = 1; - linuxvars.mouse_data.out_of_window = 1; + linuxvars.input.mouse.out_of_window = 1; }break; case FocusIn: case FocusOut: { should_step = 1; - linuxvars.mouse_data.l = 0; - linuxvars.mouse_data.r = 0; + linuxvars.input.mouse.l = 0; + linuxvars.input.mouse.r = 0; }break; case ConfigureNotify: { @@ -2013,7 +2193,7 @@ LinuxHandleX11Events(void) should_step = 1; linuxvars.keep_running = 0; } - else if ((Atom)Event.xclient.data.l[0] == linuxvars.atom_NET_WM_PING) { + else if ((Atom)Event.xclient.data.l[0] == linuxvars.atom__NET_WM_PING) { Event.xclient.window = DefaultRootWindow(linuxvars.XDisplay); XSendEvent( linuxvars.XDisplay, @@ -2111,7 +2291,6 @@ LinuxHandleX11Events(void) case Expose: case VisibilityNotify: { should_step = 1; - linuxvars.redraw = 1; }break; default: { @@ -2160,6 +2339,9 @@ LinuxHandleFileEvents() int main(int argc, char **argv) { + // + // System & Memory init + // #if FRED_INTERNAL linuxvars.internal_bubble.next = &linuxvars.internal_bubble; @@ -2169,68 +2351,38 @@ main(int argc, char **argv) pthread_mutex_init(&linuxvars.DEBUG_sysmem_lock, 0); #endif - linuxvars.first = 1; - char base_dir_mem[PATH_MAX]; String base_dir = make_fixed_width_string(base_dir_mem); if (!LinuxLoadAppCode(&base_dir)){ - // TODO(allen): Failed to load app code, serious problem. + fprintf(stderr, "Could not load 4ed_app.so! It should be in the same dir as 4ed.\n"); return 99; } - System_Functions system_; - System_Functions *system = &system_; - linuxvars.system = system; LinuxLoadSystemCode(); + LinuxLoadRenderCode(); - linuxvars.coroutine_free = linuxvars.coroutine_data; - for (i32 i = 0; i+1 < ArrayCount(linuxvars.coroutine_data); ++i){ - linuxvars.coroutine_data[i].next = linuxvars.coroutine_data + i + 1; - } - - const size_t stack_size = Mbytes(16); - for (i32 i = 0; i < ArrayCount(linuxvars.coroutine_data); ++i){ - linuxvars.coroutine_data[i].stack.ss_size = stack_size; - linuxvars.coroutine_data[i].stack.ss_sp = system_get_memory(stack_size); - } - - memory_vars.vars_memory_size = Mbytes(2); - memory_vars.vars_memory = system_get_memory(memory_vars.vars_memory_size); + memory_vars.vars_memory_size = Mbytes(2); + memory_vars.vars_memory = system_get_memory(memory_vars.vars_memory_size); memory_vars.target_memory_size = Mbytes(512); - memory_vars.target_memory = system_get_memory(memory_vars.target_memory_size); - memory_vars.user_memory_size = Mbytes(2); - memory_vars.user_memory = system_get_memory(memory_vars.user_memory_size); + memory_vars.target_memory = system_get_memory(memory_vars.target_memory_size); + memory_vars.user_memory_size = Mbytes(2); + memory_vars.user_memory = system_get_memory(memory_vars.user_memory_size); -#if 0 - memory_vars.vars_memory_size = Mbytes(2); - memory_vars.vars_memory = mmap(0, memory_vars.vars_memory_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - memory_vars.target_memory_size = Mbytes(512); - memory_vars.target_memory = mmap(0, memory_vars.target_memory_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - memory_vars.user_memory_size = Mbytes(2); - memory_vars.user_memory = mmap(0, memory_vars.user_memory_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); -#endif - - String current_directory; - i32 curdir_req, curdir_size; - char *curdir_mem; + linuxvars.target.max = Mbytes(1); + linuxvars.target.push_buffer = (byte*)system_get_memory(linuxvars.target.max); + + // + // Read command line + // - curdir_req = (1 << 9); - curdir_mem = (char*)system_get_memory(curdir_req); - for (; getcwd(curdir_mem, curdir_req) == 0 && curdir_req < (1 << 13);){ - system_free_memory(curdir_mem); - curdir_req *= 4; - curdir_mem = (char*)system_get_memory(curdir_req); + char* cwd = get_current_dir_name(); + if(!cwd){ + perror("get_current_dir_name"); + return 1; } - if (curdir_req >= (1 << 13)){ - // TODO(allen): bullshit string APIs makin' me pissed - return 57; - } - - for (curdir_size = 0; curdir_mem[curdir_size]; ++curdir_size); - - current_directory = make_string(curdir_mem, curdir_size, curdir_req); + String current_directory = make_string_slowly(cwd); Command_Line_Parameters clparams; clparams.argv = argv; @@ -2241,12 +2393,12 @@ main(int argc, char **argv) i32 output_size; output_size = - linuxvars.app.read_command_line(system, - &memory_vars, - current_directory, - &linuxvars.settings, - &files, &file_count, - clparams); + linuxvars.app.read_command_line(&linuxvars.system, + &memory_vars, + current_directory, + &linuxvars.settings, + &files, &file_count, + clparams); if (output_size > 0){ // TODO(allen): crt free version @@ -2256,16 +2408,12 @@ main(int argc, char **argv) sysshared_filter_real_files(files, file_count); - linuxvars.XDisplay = XOpenDisplay(0); - - if(!linuxvars.XDisplay){ - fprintf(stderr, "Can't open display!\n"); - return 1; - } - - LinuxKeycodeInit(linuxvars.XDisplay); + // + // Custom layer linkage + // #ifdef FRED_SUPER + char *custom_file_default = "4coder_custom.so"; sysshared_to_binary_path(&base_dir, custom_file_default); custom_file_default = base_dir.str; @@ -2309,15 +2457,33 @@ main(int argc, char **argv) const char* error = dlerror(); fprintf(stderr, "*** Failed to load 4coder_custom.so: %s\n", error ? error : "dlopen failed."); } + #endif if (linuxvars.custom_api.get_bindings == 0){ linuxvars.custom_api.get_bindings = get_bindings; } +#if 0 if (linuxvars.custom_api.view_routine == 0){ linuxvars.custom_api.view_routine = view_routine; } +#endif + + // + // Coroutine / Thread / Semaphore / Mutex init + // + + linuxvars.coroutine_free = linuxvars.coroutine_data; + for (i32 i = 0; i+1 < ArrayCount(linuxvars.coroutine_data); ++i){ + linuxvars.coroutine_data[i].next = linuxvars.coroutine_data + i + 1; + } + + const size_t stack_size = Mbytes(16); + for (i32 i = 0; i < ArrayCount(linuxvars.coroutine_data); ++i){ + linuxvars.coroutine_data[i].stack.ss_size = stack_size; + linuxvars.coroutine_data[i].stack.ss_sp = system_get_memory(stack_size); + } Thread_Context background[4] = {}; linuxvars.groups[BACKGROUND_THREADS].threads = background; @@ -2347,210 +2513,34 @@ main(int argc, char **argv) pthread_mutex_init(linuxvars.locks + i, NULL); } - LinuxLoadRenderCode(); - linuxvars.target.max = Mbytes(1); - linuxvars.target.push_buffer = (byte*)system_get_memory(linuxvars.target.max); + // + // X11 init + // + + linuxvars.XDisplay = XOpenDisplay(0); + if(!linuxvars.XDisplay){ + fprintf(stderr, "Can't open display!\n"); + return 1; + } + +#define LOAD_ATOM(x) linuxvars.atom_##x = XInternAtom(linuxvars.XDisplay, #x, False); - // NOTE(allen): Here begins the linux screen setup stuff. - // Behold the true nature of this wonderful OS: - // (thanks again to Casey for providing this stuff) + LOAD_ATOM(CLIPBOARD); + LOAD_ATOM(UTF8_STRING); + LOAD_ATOM(_NET_WM_STATE); + LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ); + LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT); + LOAD_ATOM(_NET_WM_PING); + LOAD_ATOM(WM_DELETE_WINDOW); + +#undef LOAD_ATOM - Colormap cmap; - XSetWindowAttributes swa; int WinWidth, WinHeight; - b32 window_setup_success = 0; - - if (linuxvars.settings.set_window_size){ - WinWidth = linuxvars.settings.window_w; - WinHeight = linuxvars.settings.window_h; - } else { - WinWidth = 800; - WinHeight = 600; - } - - int XScreenCount = ScreenCount(linuxvars.XDisplay); - glx_config_result Config = {}; - - if(!GLXCanUseFBConfig(linuxvars.XDisplay)){ - fprintf(stderr, "Your GLX version is too old.\n"); - exit(1); - } - - // TODO(inso): maybe should try the default screen first? or only the default without iterating. - - for(int XScreenIndex = 0; - XScreenIndex < XScreenCount; - ++XScreenIndex) - { - Screen *XScreen = ScreenOfDisplay(linuxvars.XDisplay, XScreenIndex); - - i32 ScrnWidth, ScrnHeight; - ScrnWidth = WidthOfScreen(XScreen); - ScrnHeight = HeightOfScreen(XScreen); - - if (ScrnWidth + 50 < WinWidth) WinWidth = ScrnWidth + 50; - if (ScrnHeight + 50 < WinHeight) WinHeight = ScrnHeight + 50; - - Config = ChooseGLXConfig(linuxvars.XDisplay, XScreenIndex); - if(Config.Found) - { - swa.colormap = cmap = XCreateColormap(linuxvars.XDisplay, - RootWindow(linuxvars.XDisplay, Config.BestInfo.screen ), - Config.BestInfo.visual, AllocNone); - swa.background_pixmap = None; - swa.border_pixel = 0; - swa.event_mask = StructureNotifyMask; - - linuxvars.XWindow = - XCreateWindow(linuxvars.XDisplay, - RootWindow(linuxvars.XDisplay, Config.BestInfo.screen), - 0, 0, WinWidth, WinHeight, - 0, Config.BestInfo.depth, InputOutput, - Config.BestInfo.visual, - CWBorderPixel|CWColormap|CWEventMask, &swa); - - if(linuxvars.XWindow) - { - window_setup_success = 1; - break; - } - } - } - - if (!window_setup_success){ - fprintf(stderr, "Error creating window.\n"); - exit(1); - } - - //NOTE(inso): Set the window's type to normal - Atom _NET_WM_WINDOW_TYPE = XInternAtom(linuxvars.XDisplay, "_NET_WM_WINDOW_TYPE", False); - Atom _NET_WIN_TYPE_NORMAL = XInternAtom(linuxvars.XDisplay, "_NET_WM_WINDOW_TYPE_NORMAL", False); - XChangeProperty( - linuxvars.XDisplay, - linuxvars.XWindow, - _NET_WM_WINDOW_TYPE, - XA_ATOM, - 32, - PropModeReplace, - (unsigned char*)&_NET_WIN_TYPE_NORMAL, - 1 - ); - - //NOTE(inso): window managers want the PID as a window property for some reason. - Atom _NET_WM_PID = XInternAtom(linuxvars.XDisplay, "_NET_WM_PID", False); - pid_t pid = getpid(); - XChangeProperty( - linuxvars.XDisplay, - linuxvars.XWindow, - _NET_WM_PID, - XA_CARDINAL, - 32, - PropModeReplace, - (unsigned char*)&pid, - 1 - ); - -#define WINDOW_NAME "4coder 4linux: " VERSION - - //NOTE(inso): set wm properties - XStoreName(linuxvars.XDisplay, linuxvars.XWindow, WINDOW_NAME); - - char* win_name_list[] = { WINDOW_NAME }; - XTextProperty win_name; - - XStringListToTextProperty(win_name_list, 1, &win_name); - - XSizeHints *sz_hints = XAllocSizeHints(); - XWMHints *wm_hints = XAllocWMHints(); - XClassHint *cl_hints = XAllocClassHint(); - - if(linuxvars.settings.set_window_pos){ - sz_hints->flags |= USPosition; - sz_hints->x = linuxvars.settings.window_x; - sz_hints->y = linuxvars.settings.window_y; - } - - wm_hints->flags |= InputHint; - wm_hints->input = True; - - cl_hints->res_name = "4coder"; - cl_hints->res_class = "4coder"; - - XSetWMProperties( - linuxvars.XDisplay, - linuxvars.XWindow, - &win_name, - NULL, - argv, - argc, - sz_hints, - wm_hints, - cl_hints - ); - - XFree(sz_hints); - XFree(wm_hints); - XFree(cl_hints); - - XFree(win_name.value); - - LinuxSetIcon(linuxvars.XDisplay, linuxvars.XWindow); - - //NOTE(inso): make the window visible - XMapWindow(linuxvars.XDisplay, linuxvars.XWindow); - - Init_Input_Result input_result = - InitializeXInput(linuxvars.XDisplay, linuxvars.XWindow); - - linuxvars.input_method = input_result.input_method; - linuxvars.input_style = input_result.best_style; - linuxvars.input_context = input_result.xic; - - b32 IsLegacy = false; - GLXContext GLContext = - InitializeOpenGLContext(linuxvars.XDisplay, linuxvars.XWindow, Config.BestConfig, IsLegacy); - - XWindowAttributes WinAttribs; - if(XGetWindowAttributes(linuxvars.XDisplay, linuxvars.XWindow, &WinAttribs)) - { - WinWidth = WinAttribs.width; - WinHeight = WinAttribs.height; - } - - XRaiseWindow(linuxvars.XDisplay, linuxvars.XWindow); - XSync(linuxvars.XDisplay, False); - - if (linuxvars.settings.set_window_pos){ - XMoveWindow( - linuxvars.XDisplay, - linuxvars.XWindow, - linuxvars.settings.window_x, - linuxvars.settings.window_y - ); - } - - Cursor xcursors[APP_MOUSE_CURSOR_COUNT] = { - None, - XCreateFontCursor(linuxvars.XDisplay, XC_arrow), - XCreateFontCursor(linuxvars.XDisplay, XC_xterm), - XCreateFontCursor(linuxvars.XDisplay, XC_sb_h_double_arrow), - XCreateFontCursor(linuxvars.XDisplay, XC_sb_v_double_arrow) - }; - - XSetICFocus(linuxvars.input_context); - - linuxvars.atom_CLIPBOARD = XInternAtom(linuxvars.XDisplay, "CLIPBOARD", False); - linuxvars.atom_UTF8_STRING = XInternAtom(linuxvars.XDisplay, "UTF8_STRING", False); - linuxvars.atom_NET_WM_STATE = XInternAtom(linuxvars.XDisplay, "_NET_WM_STATE", False); - linuxvars.atom_NET_WM_STATE_MAXIMIZED_HORZ = XInternAtom(linuxvars.XDisplay, "_NET_WM_STATE_MAXIMIZED_HORZ", False); - linuxvars.atom_NET_WM_STATE_MAXIMIZED_VERT = XInternAtom(linuxvars.XDisplay, "_NET_WM_STATE_MAXIMIZED_VERT", False); - - if (linuxvars.settings.maximize_window){ - LinuxMaximizeWindow(linuxvars.XDisplay, linuxvars.XWindow, 1); + if(!LinuxX11WindowInit(argc, argv, &WinWidth, &WinHeight)){ + return 1; } int xfixes_version_unused, xfixes_err_unused; - linuxvars.has_xfixes = XQueryExtension( linuxvars.XDisplay, "XFIXES", @@ -2568,20 +2558,26 @@ main(int argc, char **argv) ); } - linuxvars.atom_WM_DELETE_WINDOW = XInternAtom(linuxvars.XDisplay, "WM_DELETE_WINDOW", False); - linuxvars.atom_NET_WM_PING = XInternAtom(linuxvars.XDisplay, "_NET_WM_PING", False); + Init_Input_Result input_result = + LinuxInputInit(linuxvars.XDisplay, linuxvars.XWindow); - Atom wm_protos[] = { - linuxvars.atom_WM_DELETE_WINDOW, - linuxvars.atom_NET_WM_PING + linuxvars.input_method = input_result.input_method; + linuxvars.input_style = input_result.best_style; + linuxvars.input_context = input_result.xic; + + LinuxKeycodeInit(linuxvars.XDisplay); + + Cursor xcursors[APP_MOUSE_CURSOR_COUNT] = { + None, + XCreateFontCursor(linuxvars.XDisplay, XC_arrow), + XCreateFontCursor(linuxvars.XDisplay, XC_xterm), + XCreateFontCursor(linuxvars.XDisplay, XC_sb_h_double_arrow), + XCreateFontCursor(linuxvars.XDisplay, XC_sb_v_double_arrow) }; - XSetWMProtocols(linuxvars.XDisplay, linuxvars.XWindow, wm_protos, 2); - linuxvars.app.init(linuxvars.system, &linuxvars.target, &memory_vars, &exchange_vars, - linuxvars.clipboard_contents, current_directory, - linuxvars.custom_api); - - LinuxResizeTarget(WinWidth, WinHeight); + // + // Epoll init + // linuxvars.x11_fd = ConnectionNumber(linuxvars.XDisplay); linuxvars.inotify_fd = inotify_init1(IN_NONBLOCK); @@ -2606,9 +2602,26 @@ main(int argc, char **argv) e.data.u64 = LINUX_4ED_EVENT_STEP_TIMER; epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, linuxvars.step_timer_fd, &e); } + + // + // App init + // + + linuxvars.app.init(&linuxvars.system, &linuxvars.target, &memory_vars, &exchange_vars, + linuxvars.clipboard_contents, current_directory, + linuxvars.custom_api); + + LinuxResizeTarget(WinWidth, WinHeight); + + // + // Main loop + // LinuxScheduleStep(); + linuxvars.keep_running = 1; + linuxvars.input.first_step = 1; + linuxvars.input.dt = (frame_useconds / 1000000.f); while(1){ @@ -2665,12 +2678,9 @@ main(int argc, char **argv) } if(do_step){ - linuxvars.last_step = system_time(); + linuxvars.last_step = system_now_time_stamp(); - // TODO(inso): not all events should require a redraw? - linuxvars.redraw = 1; - - if(linuxvars.first || !linuxvars.has_xfixes){ + if(linuxvars.input.first_step || !linuxvars.has_xfixes){ XConvertSelection( linuxvars.XDisplay, linuxvars.atom_CLIPBOARD, @@ -2685,24 +2695,19 @@ main(int argc, char **argv) result.mouse_cursor_type = APP_MOUSE_CURSOR_DEFAULT; result.trying_to_kill = !linuxvars.keep_running; - String clipboard = {}; if(linuxvars.new_clipboard){ - clipboard = linuxvars.clipboard_contents; + linuxvars.input.clipboard = linuxvars.clipboard_contents; linuxvars.new_clipboard = 0; + } else { + linuxvars.input.clipboard = string_zero(); } - f32 dt = frame_useconds / 1000000.f; - linuxvars.app.step( - linuxvars.system, - &linuxvars.key_data, - &linuxvars.mouse_data, + &linuxvars.system, &linuxvars.target, &memory_vars, &exchange_vars, - clipboard, - dt, - linuxvars.first, + &linuxvars.input, &result ); @@ -2713,14 +2718,10 @@ main(int argc, char **argv) } if(result.animating){ - linuxvars.redraw = 1; LinuxScheduleStep(); } - if(linuxvars.redraw){ - LinuxRedrawTarget(); - linuxvars.redraw = 0; - } + LinuxRedrawTarget(); if(result.mouse_cursor_type != linuxvars.cursor){ Cursor c = xcursors[result.mouse_cursor_type]; @@ -2728,14 +2729,13 @@ main(int argc, char **argv) linuxvars.cursor = result.mouse_cursor_type; } - linuxvars.first = 0; - linuxvars.redraw = 0; - linuxvars.key_data = key_input_data_zero(); - linuxvars.mouse_data.press_l = 0; - linuxvars.mouse_data.release_l = 0; - linuxvars.mouse_data.press_r = 0; - linuxvars.mouse_data.release_r = 0; - linuxvars.mouse_data.wheel = 0; + linuxvars.input.first_step = 0; + linuxvars.input.keys = key_input_data_zero(); + linuxvars.input.mouse.press_l = 0; + linuxvars.input.mouse.release_l = 0; + linuxvars.input.mouse.press_r = 0; + linuxvars.input.mouse.release_r = 0; + linuxvars.input.mouse.wheel = 0; } system_release_lock(FRAME_LOCK); From ce27493fb350dc3bec3a8a7a7e1ee59369d28bca Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Mon, 30 May 2016 10:56:54 -0400 Subject: [PATCH 15/34] set up GUI to consume keys it uses --- 4ed.cpp | 20 ++++--- 4ed_file_view.cpp | 119 +++++++++++++++++++++++------------------ TODO.txt | 22 ++++---- power/4coder_casey.cpp | 6 +-- 4 files changed, 91 insertions(+), 76 deletions(-) diff --git a/4ed.cpp b/4ed.cpp index 7b2441f5..ea10980d 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -3884,14 +3884,13 @@ App_Step_Sig(app_step){ models->command_coroutine = command_coroutine; } else{ - app_result.perform_kill = 1; + models->keep_playing = 0; } } - // NOTE(allen): process the command_coroutine if it is unfinished + // NOTE(allen): Keyboard input to command coroutine. Available_Input available_input = init_available_input(&key_summary, &input->mouse); - // NOTE(allen): Keyboard input to command coroutine. if (models->command_coroutine != 0){ Coroutine *command_coroutine = models->command_coroutine; u32 get_flags = models->command_coroutine_flags[0]; @@ -4028,7 +4027,6 @@ App_Step_Sig(app_step){ update_command_data(vars, cmd); // NOTE(allen): pass raw input to the panels - Input_Summary dead_input = {}; dead_input.mouse.x = input->mouse.x; dead_input.mouse.y = input->mouse.y; @@ -4054,9 +4052,17 @@ App_Step_Sig(app_step){ view = panel->view; active = (panel == cmd->panel); summary = (active)?(active_input):(dead_input); - if (step_file_view(system, view, active_view, summary)){ + + View_Step_Result result = step_file_view(system, view, active_view, summary); + if (result.animating){ app_result.animating = 1; } + if (result.consume_keys){ + consume_input(&available_input, Input_AnyKey); + } + if (result.consume_keys || result.consume_esc){ + consume_input(&available_input, Input_Esc); + } } for (dll_items(panel, used_panels)){ @@ -4404,12 +4410,12 @@ App_Step_Sig(app_step){ models->prev_mouse_panel = mouse_panel; app_result.lctrl_lalt_is_altgr = models->settings.lctrl_lalt_is_altgr; + app_result.perform_kill = !models->keep_playing; + *result = app_result; Assert(general_memory_check(&models->mem.general)); - app_result.perform_kill = models->keep_playing; - // end-of-app_step } diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index c0925fab..6a5e55de 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -1811,6 +1811,7 @@ file_pre_edit_maintenance(System_Functions *system, general_memory_free(general, file->state.swap_stack.tokens); file->state.swap_stack.tokens = 0; } + file->state.still_lexing = 0; } file->state.last_4ed_edit_time = system->now_time_stamp(); } @@ -3216,9 +3217,7 @@ interactive_view_complete(System_Functions *system, View *view, String dest, i32 break; case IAct_New: - // TODO(allen): The !char_is_slash part confuses me... let's investigate this soon. - if (dest.size > 0 && - !char_is_slash(models->hot_directory.string.str[dest.size-1])){ + if (dest.size > 0 && !char_is_slash(dest.str[dest.size-1])){ view_new_file(system, models, view, dest); view_show_file(view); }break; @@ -3782,8 +3781,15 @@ app_single_number_input_step(System_Functions *system, Key_Event_Data key, Strin return result; } -internal b32 +struct View_Step_Result{ + b32 animating; + b32 consume_keys; + b32 consume_esc; +}; + +internal View_Step_Result step_file_view(System_Functions *system, View *view, View *active_view, Input_Summary input){ + View_Step_Result result = {0}; GUI_Target *target = &view->gui_target; Models *models = view->persistent.models; Key_Summary keys = input.keys; @@ -3792,6 +3798,25 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su view->current_scroll = 0; + if (view->showing_ui != VUI_None){ + b32 did_esc = 0; + Key_Event_Data key; + i32 i; + + for (i = 0; i < keys.count; ++i){ + key = get_single_key(&keys, i); + if (key.keycode == key_esc){ + did_esc = 1; + break; + } + } + + if (did_esc){ + view_show_file(view); + result.consume_esc = 1; + } + } + gui_begin_top_level(target, input); { gui_do_top_bar(target); @@ -3832,22 +3857,22 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su String empty_string = {0}; GUI_id id = {0}; id.id[1] = VUI_Menu; - + gui_do_text_field(target, message, empty_string); - + id.id[0] = 0; message = make_lit_string("Theme"); if (gui_do_fixed_option(target, id, message, 0)){ view_show_theme(view, view->map); } - + id.id[0] = 1; message = make_lit_string("Config"); if (gui_do_fixed_option(target, id, message, 0)){ view_show_config(view, view->map); } }break; - + case VUI_Config: { view->current_scroll = &view->gui_scroll; @@ -3856,16 +3881,16 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su String empty_string = {0}; GUI_id id = {0}; id.id[1] = VUI_Config; - + gui_do_text_field(target, message, empty_string); - + id.id[0] = 0; message = make_lit_string("Left Ctrl + Left Alt = AltGr"); if (gui_do_fixed_option_checkbox(target, id, message, 0, (b8)models->settings.lctrl_lalt_is_altgr)){ models->settings.lctrl_lalt_is_altgr = !models->settings.lctrl_lalt_is_altgr; } }break; - + case VUI_Theme: { view->current_scroll = &view->gui_scroll; @@ -3873,7 +3898,7 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su if (view != active_view){ view->hot_file_view = active_view; } - + String message = {0}; String empty_string = {0}; @@ -3995,47 +4020,50 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su next_color_editing = i; view->color_cursor = 0; } - + if (view->current_color_editing == i){ GUI_Item_Update update = {0}; char text_space[7]; String text = make_fixed_width_string(text_space); - + color_to_hexstr(*edit_color, &text); if (gui_do_text_with_cursor(target, view->color_cursor, text, &update)){ b32 r = 0; i32 j = 0; - + for (j = 0; j < keys.count; ++j){ i16 key = keys.keys[j].keycode; switch (key){ - case key_left: --view->color_cursor; r = 1; break; - case key_right: ++view->color_cursor; r = 1; break; - + case key_left: --view->color_cursor; r = 1; result.consume_keys = 1; break; + case key_right: ++view->color_cursor; r = 1; result.consume_keys = 1; break; + case key_up: if (next_color_editing > 0){ --next_color_editing; } + result.consume_keys = 1; break; - + case key_down: if (next_color_editing <= ArrayCount(colors_to_edit)-1){ ++next_color_editing; } + result.consume_keys = 1; break; - + default: if ((key >= '0' && key <= '9') || (key >= 'a' && key <= 'f') || (key >= 'A' && key <= 'F')){ text.str[view->color_cursor] = (char)key; r = 1; + result.consume_keys = 1; } break; } - + if (view->color_cursor < 0) view->color_cursor = 0; if (view->color_cursor >= 6) view->color_cursor = 5; } - + if (r){ hexstr_to_color(text, edit_color); gui_rollback(target, &update); @@ -4044,12 +4072,12 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su } } } - + if (view->current_color_editing != next_color_editing){ view->current_color_editing = next_color_editing; view->color_cursor = 0; } - + gui_end_scrollable(target); }break; } @@ -4107,9 +4135,11 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su &hdir->string, hdir, 1, 1, 0); if (step.made_a_change){ view->list_i = 0; + result.consume_keys = 1; } if (!use_item_in_list && (key.keycode == '\n' || key.keycode == '\t')){ activate_directly = 1; + result.consume_keys = 1; } } } @@ -4128,6 +4158,7 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su if (gui_begin_list(target, id, view->list_i, 0, snap_into_view, &update)){ + // TODO(allen): Allow me to handle key consumption correctly here! gui_standard_list(target, id, view->current_scroll, view->scroll_region, &keys, &view->list_i, &update); } @@ -4173,19 +4204,19 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su b32 snap_into_view = 0; persist String message_unsaved = make_lit_string(" *"); persist String message_unsynced = make_lit_string(" !"); - + String message = {0}; switch (view->action){ case IAct_Switch: message = make_lit_string("Switch: "); break; case IAct_Kill: message = make_lit_string("Kill: "); break; } - + Absolutes absolutes; Editing_File *file; Working_Set *working_set = &models->working_set; Editing_Layout *layout = &models->layout; GUI_Item_Update update = {0}; - + { Single_Line_Input_Step step; Key_Event_Data key; @@ -4195,14 +4226,15 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su step = app_single_line_input_step(system, key, &view->dest); if (step.made_a_change){ view->list_i = 0; + result.consume_keys = 1; } } } - + get_absolutes(view->dest, &absolutes, 1, 1); - + gui_do_text_field(target, message, view->dest); - + scroll_context.id[0] = (u64)(working_set); if (gui_get_scroll_vars(target, scroll_context, &view->gui_scroll, &view->scroll_region)){ @@ -4210,7 +4242,7 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su } gui_begin_scrollable(target, scroll_context, view->gui_scroll, 9.f * view->font_height, show_scrollbar); - + id.id[0] = (u64)(working_set) + 1; if (gui_begin_list(target, id, view->list_i, 0, snap_into_view, &update)){ @@ -4356,7 +4388,9 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su } } gui_end_top_level(target); - return(target->animating); + + result.animating = target->animating; + return(result); } internal f32 @@ -4651,27 +4685,6 @@ do_input_file_view(System_Functions *system, Exchange *exchange, result.vars = scroll_vars; } - - // TODO(allen): GET RID OF THIS!!! - { - Key_Summary *keys = &user_input->keys; - b32 did_esc = 0; - Key_Event_Data key; - i32 i, count; - - count = keys->count; - for (i = 0; i < count; ++i){ - key = get_single_key(keys, i); - if (key.keycode == key_esc){ - did_esc = 1; - break; - } - } - - if (did_esc && view->showing_ui != VUI_None){ - view_show_file(view); - } - } } return(result); diff --git a/TODO.txt b/TODO.txt index 8a8d85a7..1f78229b 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,7 +1,3 @@ - -; before shipping: -; [] make sure 4coder_handmade_hero.cpp works - ; Started this list on: (18.01.2016)(dd.mm.yyyy) ; This list is an informal todo list, it may very well miss items ; checked or unchecked, that I inted to do some day. It is included @@ -67,12 +63,15 @@ ; [X] chronal's map setting issue ; [X] linux save jankieness ; [X] bouncing when scrolling down +; [X] sometimes the main cursor is not the same width as the mark cursor in the same spot +; [X] tab character wrong width +; [X] miblo's off screen cursor thing +; [X] paste snaps the cursor back into view! +; [X] new file is messed up for code files, it never finishes parsing! ; [] indication on failure to save ; [] clean whitespace doesn't appear to be cleaning trailing whitespace anymore??? -; [] sometimes the main cursor is not the same width as the mark cursor in the same spot -; [] tab character wrong width -; [] miblo's off screen cursor thing ; +; [] key presses that should be consumed in the GUI are now passed to the file! ; ; TODOS @@ -117,14 +116,13 @@ ; [X] rewrite GUI ; [X] arrow navigation of GUIs ; [] GUI API -; [] text links -> arbitrary commands / callbacks? ; ; search related tech ; [X] replace word (incremental and/or in range) +; [X] caps insensitivety ; [] optimize search ; [] allow search wrap around beginning/end ; [] improved custom API for text "streams" -; [] caps insensitivety ; ; theme related business ; [] fix the versioning system for themes @@ -173,12 +171,11 @@ ; INTERNAL TODOS ; [X] switch building non-extensible version by statically linking to custom.cpp +; [X] pack fonts more squarely ; [] general parameter handling ; [] hashed string pool for clipboard/filenames/etc -; [] ask for clipboards to update by request, not on loop -; [] pack fonts more squarely -; [] setup tests through special tool ; [] new profiling/debugging system +; [] change job canceling to a polling based thing ; ; EASY TODOS @@ -199,6 +196,7 @@ ; [] fill screen right away ; [] how to get fast repaint (do I really need double buffering?) ; [] history breaks when heavily used (disk swaping?) +; [] window stops repainting bug on a handful of machines (Win 10? Driver?) ; ; PORTING TODOS diff --git a/power/4coder_casey.cpp b/power/4coder_casey.cpp index df8fbc20..bd2cb789 100644 --- a/power/4coder_casey.cpp +++ b/power/4coder_casey.cpp @@ -104,13 +104,11 @@ #include #include +#include +#include #include "../4coder_default_include.cpp" -enum maps{ - my_code_map -}; - #ifndef Assert #define internal static #define Assert assert From 16677d3f9002c2edb37bee5e7e7c8f6e84138b9a Mon Sep 17 00:00:00 2001 From: insofaras Date: Tue, 31 May 2016 00:30:06 +0100 Subject: [PATCH 16/34] linux: a few small improvements: * Add PropertyChangeMask to events, makes compiz redraw better with (un)maximizing * Create the window on the default screen instead of iterating through all of them * Set backing store hint, looks nicer when moving stuff over the 4ed window * Set some other WM hints like min/max/default size, gravity, etc since most other apps seem to set them --- linux_4ed.cpp | 150 +++++++++++++++++++++++--------------------------- 1 file changed, 69 insertions(+), 81 deletions(-) diff --git a/linux_4ed.cpp b/linux_4ed.cpp index 13b7393a..f2ac65d3 100644 --- a/linux_4ed.cpp +++ b/linux_4ed.cpp @@ -136,6 +136,9 @@ struct Linux_Vars{ Atom atom__NET_WM_STATE_MAXIMIZED_HORZ; Atom atom__NET_WM_STATE_MAXIMIZED_VERT; Atom atom__NET_WM_PING; + Atom atom__NET_WM_WINDOW_TYPE; + Atom atom__NET_WM_WINDOW_TYPE_NORMAL; + Atom atom__NET_WM_PID; Atom atom_WM_DELETE_WINDOW; b32 has_xfixes; @@ -1601,6 +1604,7 @@ LinuxInputInit(Display *dpy, Window XWindow) KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | + PropertyChangeMask | PointerMotionMask | FocusChangeMask | StructureNotifyMask | @@ -1840,93 +1844,66 @@ b32 LinuxX11WindowInit(int argc, char** argv, int* WinWidth, int* WinHeight) // Behold the true nature of this wonderful OS: // (thanks again to Casey for providing this stuff) - Colormap cmap; - XSetWindowAttributes swa; - b32 window_setup_success = 0; +#define BASE_W 800 +#define BASE_H 600 if (linuxvars.settings.set_window_size){ *WinWidth = linuxvars.settings.window_w; *WinHeight = linuxvars.settings.window_h; } else { - *WinWidth = 800; - *WinHeight = 600; + *WinWidth = BASE_W; + *WinHeight = BASE_H; } - int XScreenCount = ScreenCount(linuxvars.XDisplay); - glx_config_result Config = {}; - - if(!GLXCanUseFBConfig(linuxvars.XDisplay)){ + if (!GLXCanUseFBConfig(linuxvars.XDisplay)){ fprintf(stderr, "Your GLX version is too old.\n"); return false; } - // TODO(inso): maybe should try the default screen first? or only the default without iterating. - - for(int XScreenIndex = 0; - XScreenIndex < XScreenCount; - ++XScreenIndex) - { - Screen *XScreen = ScreenOfDisplay(linuxvars.XDisplay, XScreenIndex); - - i32 ScrnWidth, ScrnHeight; - ScrnWidth = WidthOfScreen(XScreen); - ScrnHeight = HeightOfScreen(XScreen); - - if (ScrnWidth + 50 < *WinWidth) *WinWidth = ScrnWidth + 50; - if (ScrnHeight + 50 < *WinHeight) *WinHeight = ScrnHeight + 50; - - Config = ChooseGLXConfig(linuxvars.XDisplay, XScreenIndex); - if(Config.Found) - { - swa.colormap = cmap = XCreateColormap(linuxvars.XDisplay, - RootWindow(linuxvars.XDisplay, Config.BestInfo.screen ), - Config.BestInfo.visual, AllocNone); - swa.background_pixmap = None; - swa.border_pixel = 0; - swa.event_mask = StructureNotifyMask; - - linuxvars.XWindow = - XCreateWindow(linuxvars.XDisplay, - RootWindow(linuxvars.XDisplay, Config.BestInfo.screen), - 0, 0, *WinWidth, *WinHeight, - 0, Config.BestInfo.depth, InputOutput, - Config.BestInfo.visual, - CWBorderPixel|CWColormap|CWEventMask, &swa); - - if(linuxvars.XWindow) - { - window_setup_success = 1; - break; - } - } + glx_config_result Config = ChooseGLXConfig(linuxvars.XDisplay, DefaultScreen(linuxvars.XDisplay)); + if (!Config.Found){ + fprintf(stderr, "Could not create GLX FBConfig.\n"); } - if (!window_setup_success){ + XSetWindowAttributes swa = {}; + swa.backing_store = WhenMapped; + swa.event_mask = StructureNotifyMask; + swa.bit_gravity = NorthWestGravity; + swa.colormap = XCreateColormap(linuxvars.XDisplay, + RootWindow(linuxvars.XDisplay, Config.BestInfo.screen), + Config.BestInfo.visual, AllocNone); + + linuxvars.XWindow = + XCreateWindow(linuxvars.XDisplay, + RootWindow(linuxvars.XDisplay, Config.BestInfo.screen), + 0, 0, *WinWidth, *WinHeight, + 0, Config.BestInfo.depth, InputOutput, + Config.BestInfo.visual, + CWBackingStore|CWBitGravity|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &swa); + + if (!linuxvars.XWindow){ fprintf(stderr, "Error creating window.\n"); return false; } //NOTE(inso): Set the window's type to normal - Atom _NET_WM_WINDOW_TYPE = XInternAtom(linuxvars.XDisplay, "_NET_WM_WINDOW_TYPE", False); - Atom _NET_WIN_TYPE_NORMAL = XInternAtom(linuxvars.XDisplay, "_NET_WM_WINDOW_TYPE_NORMAL", False); XChangeProperty( linuxvars.XDisplay, linuxvars.XWindow, - _NET_WM_WINDOW_TYPE, + linuxvars.atom__NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, - (unsigned char*)&_NET_WIN_TYPE_NORMAL, + (unsigned char*)&linuxvars.atom__NET_WM_WINDOW_TYPE_NORMAL, 1 ); //NOTE(inso): window managers want the PID as a window property for some reason. - Atom _NET_WM_PID = XInternAtom(linuxvars.XDisplay, "_NET_WM_PID", False); pid_t pid = getpid(); XChangeProperty( linuxvars.XDisplay, linuxvars.XWindow, - _NET_WM_PID, + linuxvars.atom__NET_WM_PID, XA_CARDINAL, 32, PropModeReplace, @@ -1939,45 +1916,53 @@ b32 LinuxX11WindowInit(int argc, char** argv, int* WinWidth, int* WinHeight) //NOTE(inso): set wm properties XStoreName(linuxvars.XDisplay, linuxvars.XWindow, WINDOW_NAME); - char* win_name_list[] = { WINDOW_NAME }; - XTextProperty win_name; - - XStringListToTextProperty(win_name_list, 1, &win_name); - XSizeHints *sz_hints = XAllocSizeHints(); XWMHints *wm_hints = XAllocWMHints(); XClassHint *cl_hints = XAllocClassHint(); - if(linuxvars.settings.set_window_pos){ + sz_hints->flags = PMinSize | PMaxSize | PBaseSize | PWinGravity; + + sz_hints->min_width = 50; + sz_hints->min_height = 50; + + sz_hints->max_width = sz_hints->max_height = (1UL << 16UL); + + sz_hints->base_width = BASE_W; + sz_hints->base_height = BASE_H; + + sz_hints->win_gravity = NorthWestGravity; + + if (linuxvars.settings.set_window_pos){ sz_hints->flags |= USPosition; sz_hints->x = linuxvars.settings.window_x; sz_hints->y = linuxvars.settings.window_y; } - wm_hints->flags |= InputHint; + wm_hints->flags |= InputHint | StateHint; wm_hints->input = True; + wm_hints->initial_state = NormalState; cl_hints->res_name = "4coder"; cl_hints->res_class = "4coder"; + char* win_name_list[] = { WINDOW_NAME }; + XTextProperty win_name; + XStringListToTextProperty(win_name_list, 1, &win_name); + XSetWMProperties( linuxvars.XDisplay, linuxvars.XWindow, - &win_name, - NULL, - argv, - argc, - sz_hints, - wm_hints, - cl_hints + &win_name, NULL, + argv, argc, + sz_hints, wm_hints, cl_hints ); + XFree(win_name.value); + XFree(sz_hints); XFree(wm_hints); XFree(cl_hints); - XFree(win_name.value); - LinuxSetIcon(linuxvars.XDisplay, linuxvars.XWindow); //NOTE(inso): make the window visible @@ -1987,15 +1972,7 @@ b32 LinuxX11WindowInit(int argc, char** argv, int* WinWidth, int* WinHeight) GLXContext GLContext = InitializeOpenGLContext(linuxvars.XDisplay, linuxvars.XWindow, Config.BestConfig, IsLegacy); - XWindowAttributes WinAttribs; - if(XGetWindowAttributes(linuxvars.XDisplay, linuxvars.XWindow, &WinAttribs)) - { - *WinWidth = WinAttribs.width; - *WinHeight = WinAttribs.height; - } - XRaiseWindow(linuxvars.XDisplay, linuxvars.XWindow); - XSync(linuxvars.XDisplay, False); if (linuxvars.settings.set_window_pos){ XMoveWindow( @@ -2009,6 +1986,14 @@ b32 LinuxX11WindowInit(int argc, char** argv, int* WinWidth, int* WinHeight) if (linuxvars.settings.maximize_window){ LinuxMaximizeWindow(linuxvars.XDisplay, linuxvars.XWindow, 1); } + XSync(linuxvars.XDisplay, False); + + XWindowAttributes WinAttribs; + if (XGetWindowAttributes(linuxvars.XDisplay, linuxvars.XWindow, &WinAttribs)) + { + *WinWidth = WinAttribs.width; + *WinHeight = WinAttribs.height; + } Atom wm_protos[] = { linuxvars.atom_WM_DELETE_WINDOW, @@ -2495,7 +2480,7 @@ main(int argc, char **argv) sem_init(&linuxvars.thread_semaphores[BACKGROUND_THREADS], 0, 0); exchange_vars.thread.queues[BACKGROUND_THREADS].semaphore = - LinuxSemToHandle(&linuxvars.thread_semaphores[BACKGROUND_THREADS]); + LinuxSemToHandle(&linuxvars.thread_semaphores[BACKGROUND_THREADS]); for(i32 i = 0; i < linuxvars.groups[BACKGROUND_THREADS].count; ++i){ Thread_Context *thread = linuxvars.groups[BACKGROUND_THREADS].threads + i; @@ -2522,7 +2507,7 @@ main(int argc, char **argv) fprintf(stderr, "Can't open display!\n"); return 1; } - + #define LOAD_ATOM(x) linuxvars.atom_##x = XInternAtom(linuxvars.XDisplay, #x, False); LOAD_ATOM(CLIPBOARD); @@ -2531,6 +2516,9 @@ main(int argc, char **argv) LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ); LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT); LOAD_ATOM(_NET_WM_PING); + LOAD_ATOM(_NET_WM_WINDOW_TYPE); + LOAD_ATOM(_NET_WM_WINDOW_TYPE_NORMAL); + LOAD_ATOM(_NET_WM_PID); LOAD_ATOM(WM_DELETE_WINDOW); #undef LOAD_ATOM From 9ac0727d08c2eef09fc946a5c6de79387d285908 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Mon, 30 May 2016 21:22:55 -0400 Subject: [PATCH 17/34] trimmed down custom api --- 4coder_custom_api.h | 12 -- 4coder_default_include.cpp | 64 ++++--- 4coder_helper.h | 358 +++++++++++++++++++++++++++++++++++ 4coder_string.h | 50 ++--- 4ed.cpp | 28 +-- 4ed_file.cpp | 4 +- 4ed_metagen.cpp | 18 ++ 4tech_table.cpp | 3 +- TODO.txt | 4 +- custom_api_spec.txt | 8 +- power/4coder_experiments.cpp | 99 +--------- 11 files changed, 454 insertions(+), 194 deletions(-) diff --git a/4coder_custom_api.h b/4coder_custom_api.h index 5903c3df..aa9a839c 100644 --- a/4coder_custom_api.h +++ b/4coder_custom_api.h @@ -11,12 +11,8 @@ #define GET_BUFFER_FIRST_SIG(n) Buffer_Summary n(Application_Links *app) #define GET_BUFFER_NEXT_SIG(n) void n(Application_Links *app, Buffer_Summary *buffer) #define GET_BUFFER_SIG(n) Buffer_Summary n(Application_Links *app, int index) -#define GET_ACTIVE_BUFFER_SIG(n) Buffer_Summary n(Application_Links *app) #define GET_PARAMETER_BUFFER_SIG(n) Buffer_Summary n(Application_Links *app, int param_index) #define GET_BUFFER_BY_NAME_SIG(n) Buffer_Summary n(Application_Links *app, char *filename, int len) -#define BUFFER_SEEK_DELIMITER_SIG(n) int n(Application_Links *app, Buffer_Summary *buffer, int start, char delim, int seek_forward, int *out) -#define BUFFER_SEEK_STRING_SIG(n) int n(Application_Links *app, Buffer_Summary *buffer, int start, char *str, int len, int seek_forward, int *out) -#define BUFFER_SEEK_STRING_INSENSITIVE_SIG(n) int n(Application_Links *app, Buffer_Summary *buffer, int start, char *str, int len, int seek_forward, int *out) #define REFRESH_BUFFER_SIG(n) int n(Application_Links *app, Buffer_Summary *buffer) #define BUFFER_READ_RANGE_SIG(n) int n(Application_Links *app, Buffer_Summary *buffer, int start, int end, char *out) #define BUFFER_REPLACE_RANGE_SIG(n) int n(Application_Links *app, Buffer_Summary *buffer, int start, int end, char *str, int len) @@ -56,12 +52,8 @@ extern "C"{ typedef GET_BUFFER_FIRST_SIG(Get_Buffer_First_Function); typedef GET_BUFFER_NEXT_SIG(Get_Buffer_Next_Function); typedef GET_BUFFER_SIG(Get_Buffer_Function); - typedef GET_ACTIVE_BUFFER_SIG(Get_Active_Buffer_Function); typedef GET_PARAMETER_BUFFER_SIG(Get_Parameter_Buffer_Function); typedef GET_BUFFER_BY_NAME_SIG(Get_Buffer_By_Name_Function); - typedef BUFFER_SEEK_DELIMITER_SIG(Buffer_Seek_Delimiter_Function); - typedef BUFFER_SEEK_STRING_SIG(Buffer_Seek_String_Function); - typedef BUFFER_SEEK_STRING_INSENSITIVE_SIG(Buffer_Seek_String_Insensitive_Function); typedef REFRESH_BUFFER_SIG(Refresh_Buffer_Function); typedef BUFFER_READ_RANGE_SIG(Buffer_Read_Range_Function); typedef BUFFER_REPLACE_RANGE_SIG(Buffer_Replace_Range_Function); @@ -104,12 +96,8 @@ struct Application_Links{ Get_Buffer_First_Function *get_buffer_first; Get_Buffer_Next_Function *get_buffer_next; Get_Buffer_Function *get_buffer; - Get_Active_Buffer_Function *get_active_buffer; Get_Parameter_Buffer_Function *get_parameter_buffer; Get_Buffer_By_Name_Function *get_buffer_by_name; - Buffer_Seek_Delimiter_Function *buffer_seek_delimiter; - Buffer_Seek_String_Function *buffer_seek_string; - Buffer_Seek_String_Insensitive_Function *buffer_seek_string_insensitive; Refresh_Buffer_Function *refresh_buffer; Buffer_Read_Range_Function *buffer_read_range; Buffer_Replace_Range_Function *buffer_replace_range; diff --git a/4coder_default_include.cpp b/4coder_default_include.cpp index 72efbe6c..da08c946 100644 --- a/4coder_default_include.cpp +++ b/4coder_default_include.cpp @@ -4,14 +4,13 @@ #define FCPP_STRING_IMPLEMENTATION #include "4coder_string.h" -#define UseInterfacesThatArePhasingOut 0 #include "4coder_helper.h" #include static void write_string(Application_Links *app, String string){ - Buffer_Summary buffer = app->get_active_buffer(app); + Buffer_Summary buffer = get_active_buffer(app); app->buffer_replace_range(app, &buffer, buffer.buffer_cursor_pos, buffer.buffer_cursor_pos, string.str, string.size); } @@ -92,7 +91,7 @@ CUSTOM_COMMAND_SIG(if0_off){ int pos; view = app->get_active_view(app); - buffer = app->get_active_buffer(app); + buffer = app->get_buffer(app, view.buffer_id); range = get_range(&view); pos = range.min; @@ -161,8 +160,8 @@ CUSTOM_COMMAND_SIG(open_file_in_quotes){ view = app->get_active_view(app); buffer = app->get_buffer(app, view.buffer_id); pos = view.cursor.pos; - app->buffer_seek_delimiter(app, &buffer, pos, '"', 1, &end); - app->buffer_seek_delimiter(app, &buffer, pos, '"', 0, &start); + buffer_seek_delimiter_forward(app, &buffer, pos, '"', &end); + buffer_seek_delimiter_backward(app, &buffer, pos, '"', &start); ++start; size = end - start; @@ -213,39 +212,39 @@ isearch(Application_Links *app, int start_reversed){ Buffer_Summary buffer; User_Input in; Query_Bar bar; - + view = app->get_active_view(app); buffer = app->get_buffer(app, view.locked_buffer_id); if (!buffer.exists) return; if (app->start_query_bar(app, &bar, 0) == 0) return; - + Range match; int reverse = start_reversed; int pos; pos = view.cursor.pos; match = make_range(pos, pos); - + char bar_string_space[256]; bar.string = make_fixed_width_string(bar_string_space); - + String isearch = make_lit_string("I-Search: "); String rsearch = make_lit_string("Reverse-I-Search: "); - + while (1){ // NOTE(allen): Change the bar's prompt to match the current direction. if (reverse) bar.prompt = rsearch; else bar.prompt = isearch; - + in = app->get_user_input(app, EventOnAnyKey, EventOnEsc | EventOnButton); if (in.abort) break; - + // NOTE(allen): If we're getting mouse events here it's a 4coder bug, because we // only asked to intercept key events. assert(in.type == UserInputKey); - + int made_change = 0; if (in.key.keycode == '\n' || in.key.keycode == '\t'){ break; @@ -260,15 +259,15 @@ isearch(Application_Links *app, int start_reversed){ made_change = 1; } } - + int step_forward = 0; int step_backward = 0; - + if (CommandEqual(in.command, search) || - in.key.keycode == key_page_down || in.key.keycode == key_down) step_forward = 1; + in.key.keycode == key_page_down || in.key.keycode == key_down) step_forward = 1; if (CommandEqual(in.command, reverse_search) || - in.key.keycode == key_page_up || in.key.keycode == key_up) step_backward = 1; - + in.key.keycode == key_page_up || in.key.keycode == key_up) step_backward = 1; + int start_pos = pos; if (step_forward && reverse){ start_pos = match.start + 1; @@ -282,17 +281,18 @@ isearch(Application_Links *app, int start_reversed){ reverse = 1; step_backward = 0; } - + if (in.key.keycode != key_back){ int new_pos; if (reverse){ - // TODO(allen): Need a good way to allow users to implement seeks for themselves. - app->buffer_seek_string_insensitive(app, &buffer, start_pos - 1, bar.string.str, bar.string.size, 0, &new_pos); + buffer_seek_string_insensitive_backward(app, &buffer, start_pos - 1, + bar.string.str, bar.string.size, &new_pos); if (new_pos >= 0){ if (step_backward){ pos = new_pos; start_pos = new_pos; - app->buffer_seek_string_insensitive(app, &buffer, start_pos - 1, bar.string.str, bar.string.size, 0, &new_pos); + buffer_seek_string_insensitive_backward(app, &buffer, start_pos - 1, + bar.string.str, bar.string.size, &new_pos); if (new_pos < 0) new_pos = start_pos; } match.start = new_pos; @@ -300,12 +300,14 @@ isearch(Application_Links *app, int start_reversed){ } } else{ - app->buffer_seek_string_insensitive(app, &buffer, start_pos + 1, bar.string.str, bar.string.size, 1, &new_pos); + buffer_seek_string_insensitive_forward(app, &buffer, start_pos + 1, + bar.string.str, bar.string.size, &new_pos); if (new_pos < buffer.size){ if (step_forward){ pos = new_pos; start_pos = new_pos; - app->buffer_seek_string_insensitive(app, &buffer, start_pos + 1, bar.string.str, bar.string.size, 1, &new_pos); + buffer_seek_string_insensitive_forward(app, &buffer, start_pos + 1, + bar.string.str, bar.string.size, &new_pos); if (new_pos >= buffer.size) new_pos = start_pos; } match.start = new_pos; @@ -318,12 +320,12 @@ isearch(Application_Links *app, int start_reversed){ match.end = match.start + bar.string.size; } } - + app->view_set_highlight(app, &view, match.start, match.end, 1); } app->view_set_highlight(app, &view, 0, 0, 0); if (in.abort) return; - + app->view_set_cursor(app, &view, seek_pos(match.min), 1); } @@ -365,14 +367,14 @@ CUSTOM_COMMAND_SIG(replace_in_range){ int pos, new_pos; pos = range.min; - app->buffer_seek_string(app, &buffer, pos, r.str, r.size, 1, &new_pos); + buffer_seek_string_forward(app, &buffer, pos, r.str, r.size, &new_pos); while (new_pos + r.size <= range.end){ app->buffer_replace_range(app, &buffer, new_pos, new_pos + r.size, w.str, w.size); app->refresh_view(app, &view); range = get_range(&view); pos = new_pos + w.size; - app->buffer_seek_string(app, &buffer, pos, r.str, r.size, 1, &new_pos); + buffer_seek_string_forward(app, &buffer, pos, r.str, r.size, &new_pos); } } @@ -410,7 +412,7 @@ CUSTOM_COMMAND_SIG(query_replace){ buffer = app->get_buffer(app, view.buffer_id); pos = view.cursor.pos; - app->buffer_seek_string(app, &buffer, pos, r.str, r.size, 1, &new_pos); + buffer_seek_string_forward(app, &buffer, pos, r.str, r.size, &new_pos); User_Input in = {0}; while (new_pos < buffer.size){ @@ -428,7 +430,7 @@ CUSTOM_COMMAND_SIG(query_replace){ pos = match.max; } - app->buffer_seek_string(app, &buffer, pos, r.str, r.size, 1, &new_pos); + buffer_seek_string_forward(app, &buffer, pos, r.str, r.size, &new_pos); } app->view_set_highlight(app, &view, 0, 0, 0); @@ -663,7 +665,7 @@ CUSTOM_COMMAND_SIG(auto_tab_line_at_cursor){ } CUSTOM_COMMAND_SIG(auto_tab_whole_file){ - Buffer_Summary buffer = app->get_active_buffer(app); + Buffer_Summary buffer = get_active_buffer(app); push_parameter(app, par_range_start, 0); push_parameter(app, par_range_end, buffer.size); exec_command(app, cmdid_auto_tab_range); diff --git a/4coder_helper.h b/4coder_helper.h index ce090629..54e7960a 100644 --- a/4coder_helper.h +++ b/4coder_helper.h @@ -386,3 +386,361 @@ query_user_number(Application_Links *app, Query_Bar *bar){ } inline String empty_string() {String Result = {}; return(Result);} + +inline Buffer_Summary +get_active_buffer(Application_Links *app){ + View_Summary view = app->get_active_view(app); + Buffer_Summary buffer = app->get_buffer(app, view.buffer_id); + return(buffer); +} + + +struct Stream_Chunk{ + Application_Links *app; + Buffer_Summary *buffer; + + char *base_data; + int start, end; + int data_size; + + char *data; +}; + +int +round_down(int x, int b){ + int r = 0; + if (x >= 0){ + r = x - (x % b); + } + return(r); +} + +int +round_up(int x, int b){ + int r = 0; + if (x >= 0){ + r = x - (x % b) + b; + } + return(r); +} + +int +init_stream_chunk(Stream_Chunk *chunk, + Application_Links *app, Buffer_Summary *buffer, + int pos, char *data, int size){ + int result = 0; + + app->refresh_buffer(app, buffer); + if (pos >= 0 && pos < buffer->size && size > 0){ + result = 1; + chunk->app = app; + chunk->buffer = buffer; + chunk->base_data = data; + chunk->data_size = size; + chunk->start = round_down(pos, size); + chunk->end = round_up(pos, size); + if (chunk->end > buffer->size){ + chunk->end = buffer->size; + } + app->buffer_read_range(app, buffer, chunk->start, chunk->end, chunk->base_data); + chunk->data = chunk->base_data - chunk->start; + } + return(result); +} + +int +forward_stream_chunk(Stream_Chunk *chunk){ + Application_Links *app = chunk->app; + Buffer_Summary *buffer = chunk->buffer; + int result = 0; + + app->refresh_buffer(app, buffer); + if (chunk->end < buffer->size){ + result = 1; + chunk->start = chunk->end; + chunk->end += chunk->data_size; + if (chunk->end > buffer->size){ + chunk->end = buffer->size; + } + app->buffer_read_range(app, buffer, chunk->start, chunk->end, chunk->base_data); + chunk->data = chunk->base_data - chunk->start; + } + return(result); +} + +int +backward_stream_chunk(Stream_Chunk *chunk){ + Application_Links *app = chunk->app; + Buffer_Summary *buffer = chunk->buffer; + int result = 0; + + app->refresh_buffer(app, buffer); + if (chunk->start > 0){ + result = 1; + chunk->end = chunk->start; + chunk->start -= chunk->data_size; + if (chunk->start < 0){ + chunk->start = 0; + } + app->buffer_read_range(app, buffer, chunk->start, chunk->end, chunk->base_data); + chunk->data = chunk->base_data - chunk->start; + } + return(result); +} + +void +buffer_seek_delimiter_forward(Application_Links *app, Buffer_Summary *buffer, + int pos, char delim, int *result){ + if (buffer->exists){ + char chunk[1024]; + int size = sizeof(chunk); + Stream_Chunk stream = {0}; + + if (init_stream_chunk(&stream, app, buffer, pos, chunk, size)){ + int still_looping = 1; + do{ + for(; pos < stream.end; ++pos){ + char at_pos = stream.data[pos]; + if (at_pos == delim){ + *result = pos; + goto finished; + } + } + still_looping = forward_stream_chunk(&stream); + }while (still_looping); + } + } + + *result = buffer->size; + + finished:; +} + +void +buffer_seek_delimiter_backward(Application_Links *app, Buffer_Summary *buffer, + int pos, char delim, int *result){ + if (buffer->exists){ + char chunk[1024]; + int size = sizeof(chunk); + Stream_Chunk stream = {0}; + + if (init_stream_chunk(&stream, app, buffer, pos, chunk, size)){ + int still_looping = 1; + do{ + for(; pos >= stream.start; --pos){ + char at_pos = stream.data[pos]; + if (at_pos == delim){ + *result = pos; + goto finished; + } + } + still_looping = backward_stream_chunk(&stream); + }while (still_looping); + } + } + + *result = 0; + + finished:; +} + +// TODO(allen): This duplication is driving me crazy... I've gotta +// upgrade the meta programming system another level. + +// NOTE(allen): This is limitted to a string size of 512. +// You can push it up or do something more clever by just +// replacing char read_buffer[512]; with more memory. +void +buffer_seek_string_forward(Application_Links *app, Buffer_Summary *buffer, + int pos, char *str, int size, int *result){ + char read_buffer[512]; + char chunk[1024]; + int chunk_size = sizeof(chunk); + Stream_Chunk stream = {0}; + + if (size <= 0){ + *result = pos; + } + else if (size > sizeof(read_buffer)){ + *result = pos; + } + else{ + if (buffer->exists){ + String read_str = make_fixed_width_string(read_buffer); + String needle_str = make_string(str, size); + char first_char = str[0]; + + read_str.size = size; + + if (init_stream_chunk(&stream, app, buffer, pos, chunk, chunk_size)){ + int still_looping = 1; + do{ + for(; pos < stream.end; ++pos){ + char at_pos = stream.data[pos]; + if (at_pos == first_char){ + app->buffer_read_range(app, buffer, pos, pos+size, read_buffer); + if (match(needle_str, read_str)){ + *result = pos; + goto finished; + } + } + } + still_looping = forward_stream_chunk(&stream); + }while (still_looping); + } + } + + *result = buffer->size; + + finished:; + } +} + +// NOTE(allen): This is limitted to a string size of 512. +// You can push it up or do something more clever by just +// replacing char read_buffer[512]; with more memory. +void +buffer_seek_string_backward(Application_Links *app, Buffer_Summary *buffer, + int pos, char *str, int size, int *result){ + char read_buffer[512]; + char chunk[1024]; + int chunk_size = sizeof(chunk); + Stream_Chunk stream = {0}; + + if (size <= 0){ + *result = 0; + } + else if (size > sizeof(read_buffer)){ + *result = 0; + } + else{ + if (buffer->exists){ + String read_str = make_fixed_width_string(read_buffer); + String needle_str = make_string(str, size); + char first_char = str[0]; + + read_str.size = size; + + if (init_stream_chunk(&stream, app, buffer, pos, chunk, chunk_size)){ + int still_looping = 1; + do{ + for(; pos >= stream.start; --pos){ + char at_pos = stream.data[pos]; + if (at_pos == first_char){ + app->buffer_read_range(app, buffer, pos, pos+size, read_buffer); + if (match(needle_str, read_str)){ + *result = pos; + goto finished; + } + } + } + still_looping = backward_stream_chunk(&stream); + }while (still_looping); + } + } + + *result = 0; + + finished:; + } +} + +// NOTE(allen): This is limitted to a string size of 512. +// You can push it up or do something more clever by just +// replacing char read_buffer[512]; with more memory. +void +buffer_seek_string_insensitive_forward(Application_Links *app, Buffer_Summary *buffer, + int pos, char *str, int size, int *result){ + char read_buffer[512]; + char chunk[1024]; + int chunk_size = sizeof(chunk); + Stream_Chunk stream = {0}; + + if (size <= 0){ + *result = pos; + } + else if (size > sizeof(read_buffer)){ + *result = pos; + } + else{ + if (buffer->exists){ + String read_str = make_fixed_width_string(read_buffer); + String needle_str = make_string(str, size); + char first_char = char_to_upper(str[0]); + + read_str.size = size; + + if (init_stream_chunk(&stream, app, buffer, pos, chunk, chunk_size)){ + int still_looping = 1; + do{ + for(; pos < stream.end; ++pos){ + char at_pos = char_to_upper(stream.data[pos]); + if (at_pos == first_char){ + app->buffer_read_range(app, buffer, pos, pos+size, read_buffer); + if (match_insensitive(needle_str, read_str)){ + *result = pos; + goto finished; + } + } + } + still_looping = forward_stream_chunk(&stream); + }while (still_looping); + } + } + + *result = buffer->size; + + finished:; + } +} + +// NOTE(allen): This is limitted to a string size of 512. +// You can push it up or do something more clever by just +// replacing char read_buffer[512]; with more memory. +void +buffer_seek_string_insensitive_backward(Application_Links *app, Buffer_Summary *buffer, + int pos, char *str, int size, int *result){ + char read_buffer[512]; + char chunk[1024]; + int chunk_size = sizeof(chunk); + Stream_Chunk stream = {0}; + + if (size <= 0){ + *result = -1; + } + else if (size > sizeof(read_buffer)){ + *result = -1; + } + else{ + if (buffer->exists){ + String read_str = make_fixed_width_string(read_buffer); + String needle_str = make_string(str, size); + char first_char = char_to_upper(str[0]); + + read_str.size = size; + + if (init_stream_chunk(&stream, app, buffer, pos, chunk, chunk_size)){ + int still_looping = 1; + do{ + for(; pos >= stream.start; --pos){ + char at_pos = char_to_upper(stream.data[pos]); + if (at_pos == first_char){ + app->buffer_read_range(app, buffer, pos, pos+size, read_buffer); + if (match_insensitive(needle_str, read_str)){ + *result = pos; + goto finished; + } + } + } + still_looping = backward_stream_chunk(&stream); + }while (still_looping); + } + } + + *result = -1; + + finished:; + } +} + + diff --git a/4coder_string.h b/4coder_string.h index c1958cc0..c51c82bc 100644 --- a/4coder_string.h +++ b/4coder_string.h @@ -102,17 +102,17 @@ FSTRING_INLINE bool match_part(String a, char *b) { int x; return match_part FSTRING_LINK bool match_part(char *a, String b); FSTRING_LINK bool match_part(String a, String b); -FSTRING_LINK bool match_unsensitive(char *a, char *b); -FSTRING_LINK bool match_unsensitive(String a, char *b); -FSTRING_INLINE bool match_unsensitive(char *a, String b) { return match_unsensitive(b,a); } -FSTRING_LINK bool match_unsensitive(String a, String b); +FSTRING_LINK bool match_insensitive(char *a, char *b); +FSTRING_LINK bool match_insensitive(String a, char *b); +FSTRING_INLINE bool match_insensitive(char *a, String b) { return match_insensitive(b,a); } +FSTRING_LINK bool match_insensitive(String a, String b); -FSTRING_LINK bool match_part_unsensitive(char *a, char *b, int *len); -FSTRING_LINK bool match_part_unsensitive(String a, char *b, int *len); -FSTRING_INLINE bool match_part_unsensitive(char *a, char *b) { int x; return match_part(a,b,&x); } -FSTRING_INLINE bool match_part_unsensitive(String a, char *b) { int x; return match_part(a,b,&x); } -FSTRING_LINK bool match_part_unsensitive(char *a, String b); -FSTRING_LINK bool match_part_unsensitive(String a, String b); +FSTRING_LINK bool match_part_insensitive(char *a, char *b, int *len); +FSTRING_LINK bool match_part_insensitive(String a, char *b, int *len); +FSTRING_INLINE bool match_part_insensitive(char *a, char *b) { int x; return match_part(a,b,&x); } +FSTRING_INLINE bool match_part_insensitive(String a, char *b) { int x; return match_part(a,b,&x); } +FSTRING_LINK bool match_part_insensitive(char *a, String b); +FSTRING_LINK bool match_part_insensitive(String a, String b); FSTRING_LINK int find(char *s, int start, char c); FSTRING_LINK int find(String s, int start, char c); @@ -123,14 +123,14 @@ FSTRING_LINK int find_substr(char *s, int start, String seek); FSTRING_LINK int find_substr(String s, int start, String seek); FSTRING_LINK int rfind_substr(String s, int start, String seek); -FSTRING_LINK int find_substr_unsensitive(char *s, int start, String seek); -FSTRING_LINK int find_substr_unsensitive(String s, int start, String seek); +FSTRING_LINK int find_substr_insensitive(char *s, int start, String seek); +FSTRING_LINK int find_substr_insensitive(String s, int start, String seek); FSTRING_INLINE bool has_substr(char *s, String seek) { return (s[find_substr(s, 0, seek)] != 0); } FSTRING_INLINE bool has_substr(String s, String seek) { return (find_substr(s, 0, seek) < s.size); } -FSTRING_INLINE bool has_substr_unsensitive(char *s, String seek) { return (s[find_substr_unsensitive(s, 0, seek)] != 0); } -FSTRING_INLINE bool has_substr_unsensitive(String s, String seek) { return (find_substr_unsensitive(s, 0, seek) < s.size); } +FSTRING_INLINE bool has_substr_insensitive(char *s, String seek) { return (s[find_substr_insensitive(s, 0, seek)] != 0); } +FSTRING_INLINE bool has_substr_insensitive(String s, String seek) { return (find_substr_insensitive(s, 0, seek) < s.size); } FSTRING_LINK int int_to_str_size(int x); FSTRING_LINK int int_to_str(int x, char *s_out); @@ -391,7 +391,7 @@ match_part(String a, String b){ } FSTRING_LINK bool -match_unsensitive(char *a, char *b){ +match_insensitive(char *a, char *b){ for (int i = 0;; ++i){ if (char_to_upper(a[i]) != char_to_upper(b[i])){ @@ -404,7 +404,7 @@ match_unsensitive(char *a, char *b){ } FSTRING_LINK bool -match_unsensitive(String a, char *b){ +match_insensitive(String a, char *b){ int i = 0; for (; i < a.size; ++i){ if (char_to_upper(a.str[i]) != @@ -419,7 +419,7 @@ match_unsensitive(String a, char *b){ } FSTRING_LINK bool -match_unsensitive(String a, String b){ +match_insensitive(String a, String b){ if (a.size != b.size){ return 0; } @@ -433,7 +433,7 @@ match_unsensitive(String a, String b){ } FSTRING_LINK bool -match_part_unsensitive(char *a, char *b, int *len){ +match_part_insensitive(char *a, char *b, int *len){ int i; for (i = 0; b[i] != 0; ++i){ if (char_to_upper(a[i]) != char_to_upper(b[i])){ @@ -445,7 +445,7 @@ match_part_unsensitive(char *a, char *b, int *len){ } FSTRING_LINK bool -match_part_unsensitive(String a, char *b, int *len){ +match_part_insensitive(String a, char *b, int *len){ int i; for (i = 0; b[i] != 0; ++i){ if (char_to_upper(a.str[i]) != char_to_upper(b[i]) || @@ -458,7 +458,7 @@ match_part_unsensitive(String a, char *b, int *len){ } FSTRING_LINK bool -match_part_unsensitive(char *a, String b){ +match_part_insensitive(char *a, String b){ for (int i = 0; i != b.size; ++i){ if (char_to_upper(a[i]) != char_to_upper(b.str[i])){ return 0; @@ -468,7 +468,7 @@ match_part_unsensitive(char *a, String b){ } FSTRING_LINK bool -match_part_unsensitive(String a, String b){ +match_part_insensitive(String a, String b){ if (a.size < b.size){ return 0; } @@ -602,7 +602,7 @@ rfind_substr(String str, int start, String seek){ } FSTRING_LINK int -find_substr_unsensitive(char *str, int start, String seek){ +find_substr_insensitive(char *str, int start, String seek){ int i, j, k; bool hit; char a_upper, b_upper; @@ -630,7 +630,7 @@ find_substr_unsensitive(char *str, int start, String seek){ } FSTRING_LINK int -find_substr_unsensitive(String str, int start, String seek){ +find_substr_insensitive(String str, int start, String seek){ int i, j, k; int stop_at; bool hit; @@ -1217,8 +1217,8 @@ wildcard_match(Absolutes *absolutes, char *x, int case_sensitive){ match_part_func = match_part; } else{ - match_func = match_unsensitive; - match_part_func = match_part_unsensitive; + match_func = match_insensitive; + match_part_func = match_part_insensitive; } if (absolutes->count == 1){ diff --git a/4ed.cpp b/4ed.cpp index ea10980d..2137b137 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -1917,22 +1917,6 @@ extern "C"{ return(buffer); } - GET_ACTIVE_BUFFER_SIG(external_get_active_buffer){ - Command_Data *cmd = (Command_Data*)app->cmd_context; - Buffer_Summary buffer = {}; - View *view = cmd->view; - Editing_File *file; - - if (view_lock_level(view) <= LockLevel_Open){ - file = view->file_data.file; - if (file){ - fill_buffer_summary(&buffer, file, &cmd->models->working_set); - } - } - - return(buffer); - } - GET_PARAMETER_BUFFER_SIG(external_get_parameter_buffer){ Command_Data *cmd = (Command_Data*)app->cmd_context; Models *models = cmd->models; @@ -1958,7 +1942,8 @@ extern "C"{ return(buffer); } - + +#if 0 BUFFER_SEEK_DELIMITER_SIG(external_buffer_seek_delimiter){ Command_Data *cmd = (Command_Data*)app->cmd_context; Editing_File *file; @@ -2071,7 +2056,8 @@ extern "C"{ return(result); } - +#endif + REFRESH_BUFFER_SIG(external_refresh_buffer){ int result; *buffer = external_get_buffer(app, buffer->buffer_id); @@ -2522,7 +2508,6 @@ internal void view_caller(Coroutine *coroutine){ View *view = (View*)coroutine->in; View_Persistent *persistent = &view->persistent; - persistent->view_routine(&persistent->models->app_links, persistent->id); } @@ -2547,14 +2532,17 @@ app_links_init(System_Functions *system, Application_Links *app_links, void *dat app_links->get_buffer_next = external_get_buffer_next; app_links->get_buffer = external_get_buffer; - app_links->get_active_buffer = external_get_active_buffer; app_links->get_parameter_buffer = external_get_parameter_buffer; app_links->get_buffer_by_name = external_get_buffer_by_name; app_links->refresh_buffer = external_refresh_buffer; + +#if 0 app_links->buffer_seek_delimiter = external_buffer_seek_delimiter; app_links->buffer_seek_string = external_buffer_seek_string; app_links->buffer_seek_string_insensitive = external_buffer_seek_string_insensitive; +#endif + app_links->buffer_read_range = external_buffer_read_range; app_links->buffer_replace_range = external_buffer_replace_range; diff --git a/4ed_file.cpp b/4ed_file.cpp index 51db66c0..0d03d2bc 100644 --- a/4ed_file.cpp +++ b/4ed_file.cpp @@ -582,6 +582,7 @@ filename_match(String query, Absolutes *absolutes, String filename, b32 case_sen return result; } +#if 0 internal Hot_Directory_Match hot_directory_first_match(Hot_Directory *hot_directory, String str, @@ -605,7 +606,7 @@ hot_directory_first_match(Hot_Directory *hot_directory, if (match(filename, str)) is_match = 1; } else{ - if (match_unsensitive(filename, str)) is_match = 1; + if (match_insensitive(filename, str)) is_match = 1; } } else{ @@ -621,6 +622,7 @@ hot_directory_first_match(Hot_Directory *hot_directory, return result; } +#endif inline File_Sync_State buffer_get_sync(Editing_File *file){ diff --git a/4ed_metagen.cpp b/4ed_metagen.cpp index 3f790884..d052ce25 100644 --- a/4ed_metagen.cpp +++ b/4ed_metagen.cpp @@ -476,6 +476,24 @@ generate_custom_headers(){ ); fprintf(file, "};\n"); + // TODO(allen): Generate app->function(app, ...) to function(app, ...) wrappers. + // Need to parse parameter names to do this. +#if 0 + for (int i = 0; i < sig_count; ++i){ + Function_Signature *sig = sigs + i; + + copy_fast_unsafe(name_buffer, sig->name); + name_buffer[sig->name.size] = 0; + to_lower(name_buffer, name_buffer); + + fprintf(file, + "inline %.*s\n" + "%s%.*s{ app->%s(", + sig->name.size, sig->name.str, + name_buffer); + } +#endif + fclose(file); return(filename); diff --git a/4tech_table.cpp b/4tech_table.cpp index 7c4144e5..77ba5a3e 100644 --- a/4tech_table.cpp +++ b/4tech_table.cpp @@ -88,12 +88,13 @@ table_add(Table *table, void *item, void *arg, Hash_Function *hash_func, Compare internal b32 table_find_pos(Table *table, void *search_key, void *arg, i32 *pos, i32 *index, Hash_Function *hash_func, Compare_Function *comp_func){ u32 hash, *inspect; - i32 i; + i32 i, start; Assert((table->count - 1) * 8 < table->max * 7); hash = (hash_func(search_key, arg) | TableHashMin); i = hash % table->max; + start = i; inspect = table->hash_array + i; while (*inspect != TableHashEmpty){ diff --git a/TODO.txt b/TODO.txt index 1f78229b..083fa665 100644 --- a/TODO.txt +++ b/TODO.txt @@ -66,12 +66,12 @@ ; [X] sometimes the main cursor is not the same width as the mark cursor in the same spot ; [X] tab character wrong width ; [X] miblo's off screen cursor thing -; [X] paste snaps the cursor back into view! ; [X] new file is messed up for code files, it never finishes parsing! +; [X] key presses that should be consumed in the GUI are now passed to the file! ; [] indication on failure to save ; [] clean whitespace doesn't appear to be cleaning trailing whitespace anymore??? ; -; [] key presses that should be consumed in the GUI are now passed to the file! +; [] paste snaps the cursor back into view! ; ; TODOS diff --git a/custom_api_spec.txt b/custom_api_spec.txt index 853b2bab..fd11836f 100644 --- a/custom_api_spec.txt +++ b/custom_api_spec.txt @@ -18,14 +18,12 @@ Buffer_Summary Get_Buffer_First(Application_Links *app) void Get_Buffer_Next(Application_Links *app, Buffer_Summary *buffer) Buffer_Summary Get_Buffer(Application_Links *app, int index) -Buffer_Summary Get_Active_Buffer(Application_Links *app) Buffer_Summary Get_Parameter_Buffer(Application_Links *app, int param_index) Buffer_Summary Get_Buffer_By_Name(Application_Links *app, char *filename, int len) -// TODO(allen): Need more flexible seek system somehow. Regex? Just expose the text stream to the user? -int Buffer_Seek_Delimiter(Application_Links *app, Buffer_Summary *buffer, int start, char delim, int seek_forward, int *out) -int Buffer_Seek_String(Application_Links *app, Buffer_Summary *buffer, int start, char *str, int len, int seek_forward, int *out) -int Buffer_Seek_String_Insensitive(Application_Links *app, Buffer_Summary *buffer, int start, char *str, int len, int seek_forward, int *out) +//int Buffer_Seek_Delimiter(Application_Links *app, Buffer_Summary *buffer, int start, char delim, int seek_forward, int *out) +//int Buffer_Seek_String(Application_Links *app, Buffer_Summary *buffer, int start, char *str, int len, int seek_forward, int *out) +//int Buffer_Seek_String_Insensitive(Application_Links *app, Buffer_Summary *buffer, int start, char *str, int len, int seek_forward, int *out) int Refresh_Buffer(Application_Links *app, Buffer_Summary *buffer) int Buffer_Read_Range(Application_Links *app, Buffer_Summary *buffer, int start, int end, char *out) diff --git a/power/4coder_experiments.cpp b/power/4coder_experiments.cpp index e8ffa4ed..06b77398 100644 --- a/power/4coder_experiments.cpp +++ b/power/4coder_experiments.cpp @@ -27,102 +27,6 @@ CUSTOM_COMMAND_SIG(kill_rect){ } } -// NOTE(allen): This stream stuff will be moved to helper if it looks -// like it will be helpful. So if you want to use it to build your own -// commands I suggest you move it there first. -struct Stream_Chunk{ - Application_Links *app; - Buffer_Summary *buffer; - - char *base_data; - int start, end; - int data_size; - - char *data; -}; - -int -round_down(int x, int b){ - int r = 0; - if (x >= 0){ - r = x - (x % b); - } - return(r); -} - -int -round_up(int x, int b){ - int r = 0; - if (x >= 0){ - r = x - (x % b) + b; - } - return(r); -} - -int -init_stream_chunk(Stream_Chunk *chunk, - Application_Links *app, Buffer_Summary *buffer, - int pos, char *data, int size){ - int result = 0; - - app->refresh_buffer(app, buffer); - if (pos >= 0 && pos < buffer->size && size > 0){ - result = 1; - chunk->app = app; - chunk->buffer = buffer; - chunk->base_data = data; - chunk->data_size = size; - chunk->start = round_down(pos, size); - chunk->end = round_up(pos, size); - if (chunk->end > buffer->size){ - chunk->end = buffer->size; - } - app->buffer_read_range(app, buffer, chunk->start, chunk->end, chunk->base_data); - chunk->data = chunk->base_data - chunk->start; - } - return(result); -} - -int -forward_stream_chunk(Stream_Chunk *chunk){ - Application_Links *app = chunk->app; - Buffer_Summary *buffer = chunk->buffer; - int result = 0; - - app->refresh_buffer(app, buffer); - if (chunk->end < buffer->size){ - result = 1; - chunk->start = chunk->end; - chunk->end += chunk->data_size; - if (chunk->end > buffer->size){ - chunk->end = buffer->size; - } - app->buffer_read_range(app, buffer, chunk->start, chunk->end, chunk->base_data); - chunk->data = chunk->base_data - chunk->start; - } - return(result); -} - -int -backward_stream_chunk(Stream_Chunk *chunk){ - Application_Links *app = chunk->app; - Buffer_Summary *buffer = chunk->buffer; - int result = 0; - - app->refresh_buffer(app, buffer); - if (chunk->start > 0){ - result = 1; - chunk->end = chunk->start; - chunk->start -= chunk->data_size; - if (chunk->start < 0){ - chunk->start = 0; - } - app->buffer_read_range(app, buffer, chunk->start, chunk->end, chunk->base_data); - chunk->data = chunk->base_data - chunk->start; - } - return(result); -} - // TODO(allen): Both of these brace related commands would work better // if the API exposed access to the tokens in a code file. CUSTOM_COMMAND_SIG(mark_matching_brace){ @@ -146,7 +50,8 @@ CUSTOM_COMMAND_SIG(mark_matching_brace){ int nesting_counter = 0; char at_cursor = 0; - if (init_stream_chunk(&chunk, app, &buffer, i, chunk_space, sizeof(chunk_space))){ + if (init_stream_chunk(&chunk, app, &buffer, i, + chunk_space, sizeof(chunk_space))){ // NOTE(allen): This is important! The data array is a pointer that is adjusted // so that indexing it with "i" will put it with the chunk that is actually loaded. From 22dc134db3f4029158277c2445a0daec30d240f2 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Mon, 30 May 2016 21:32:01 -0400 Subject: [PATCH 18/34] show file on 'no' action --- 4ed_file_view.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index 6a5e55de..f7fd5d17 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -3251,6 +3251,7 @@ interactive_view_complete(System_Functions *system, View *view, String dest, i32 break; case 1: + view_show_file(view); break; case 2: @@ -3267,6 +3268,7 @@ interactive_view_complete(System_Functions *system, View *view, String dest, i32 break; case 1: + view_show_file(view); break; case 2: From 0f3f7ce05b25856231c38403c5e30d950bb9e77d Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Tue, 31 May 2016 12:27:40 -0400 Subject: [PATCH 19/34] exchange is totally gone --- 4ed.cpp | 26 ++++++++------------------ 4ed.h | 2 -- 4ed_app_target.cpp | 1 - 4ed_exchange.cpp | 35 ----------------------------------- 4ed_file_view.cpp | 10 ++++------ 4ed_system.h | 17 +++++------------ README.txt | 2 +- SUPERREADME.txt | 2 +- TODO.txt | 3 ++- win32_4ed.cpp | 26 +++++++++++++------------- 10 files changed, 34 insertions(+), 90 deletions(-) delete mode 100644 4ed_exchange.cpp diff --git a/4ed.cpp b/4ed.cpp index 2137b137..19eee6a3 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -33,9 +33,6 @@ struct CLI_List{ i32 count, max; }; -#define SysAppCreateView 0x1 -#define SysAppCreateNewBuffer 0x2 - struct Complete_State{ Search_Set set; Search_Iter iter; @@ -49,7 +46,6 @@ struct Command_Data{ Models *models; struct App_Vars *vars; System_Functions *system; - Exchange *exchange; Live_Views *live_set; Panel *panel; @@ -167,7 +163,6 @@ do_feedback_message(System_Functions *system, Models *models, String value){ #define USE_PANEL(n) Panel *n = command->panel #define USE_VIEW(n) View *n = command->view #define USE_FILE(n,v) Editing_File *n = (v)->file_data.file -#define USE_EXCHANGE(n) Exchange *n = command->exchange #define REQ_OPEN_VIEW(n) View *n = command->panel->view; if (view_lock_level(n) > LockLevel_Open) return #define REQ_READABLE_VIEW(n) View *n = command->panel->view; if (view_lock_level(n) > LockLevel_NoWrite) return @@ -219,7 +214,7 @@ param_stack_end(Partition *part){ } internal View* -panel_make_empty(System_Functions *system, Exchange *exchange, App_Vars *vars, Panel *panel){ +panel_make_empty(System_Functions *system, App_Vars *vars, Panel *panel){ Models *models = &vars->models; View_And_ID new_view; @@ -1160,7 +1155,6 @@ COMMAND_DECL(open_panel_vsplit){ USE_VARS(vars); USE_MODELS(models); USE_PANEL(panel); - USE_EXCHANGE(exchange); if (models->layout.panel_count < models->layout.panel_max_count){ Split_Result split = layout_split_panel(&models->layout, panel, 1); @@ -1179,16 +1173,14 @@ COMMAND_DECL(open_panel_vsplit){ panel2->prev_inner = panel2->inner; models->layout.active_panel = (i32)(panel2 - models->layout.panels); - panel_make_empty(system, exchange, vars, panel2); + panel_make_empty(system, vars, panel2); } } COMMAND_DECL(open_panel_hsplit){ - USE_VARS(vars); USE_MODELS(models); USE_PANEL(panel); - USE_EXCHANGE(exchange); if (models->layout.panel_count < models->layout.panel_max_count){ Split_Result split = layout_split_panel(&models->layout, panel, 0); @@ -1207,16 +1199,14 @@ COMMAND_DECL(open_panel_hsplit){ panel2->prev_inner = panel2->inner; models->layout.active_panel = (i32)(panel2 - models->layout.panels); - panel_make_empty(system, exchange, vars, panel2); + panel_make_empty(system, vars, panel2); } } COMMAND_DECL(close_panel){ - USE_MODELS(models); USE_PANEL(panel); USE_VIEW(view); - USE_EXCHANGE(exchange); Panel *panel_ptr, *used_panels; Divider_And_ID div, parent_div, child_div; @@ -1226,7 +1216,7 @@ COMMAND_DECL(close_panel){ i32 active; if (models->layout.panel_count > 1){ - live_set_free_view(system, exchange, command->live_set, view); + live_set_free_view(system, command->live_set, view); panel->view = 0; div = layout_get_divider(&models->layout, panel->parent); @@ -3411,7 +3401,7 @@ App_Init_Sig(app_init){ // NOTE(allen): init first panel Panel_And_ID p = layout_alloc_panel(&models->layout); - panel_make_empty(system, exchange, vars, p.panel); + panel_make_empty(system, vars, p.panel); models->layout.active_panel = p.id; String hdbase = make_fixed_width_string(models->hot_dir_base_); @@ -3733,7 +3723,6 @@ App_Step_Sig(app_step){ cmd->models = models; cmd->vars = vars; cmd->system = system; - cmd->exchange = exchange; cmd->live_set = &vars->live_set; cmd->panel = models->layout.panels + models->layout.active_panel; @@ -4066,7 +4055,7 @@ App_Step_Sig(app_step){ GUI_Scroll_Vars *vars = view->current_scroll; // TODO(allen): I feel like the scroll context should actually not // be allowed to change in here at all. - result = do_input_file_view(system, exchange, view, panel->inner, active, + result = do_input_file_view(system, view, panel->inner, active, &summary, *vars, view->scroll_region); if (result.is_animating){ app_result.animating = 1; @@ -4356,7 +4345,8 @@ App_Step_Sig(app_step){ draw_rectangle(target, full, back_color); draw_push_clip(target, panel->inner); - do_render_file_view(system, exchange, view, cmd->view, panel->inner, active, target, &dead_input); + do_render_file_view(system, view, cmd->view, + panel->inner, active, target, &dead_input); draw_pop_clip(target); u32 margin_color; diff --git a/4ed.h b/4ed.h index c9d27895..47b66a5b 100644 --- a/4ed.h +++ b/4ed.h @@ -86,7 +86,6 @@ typedef App_Read_Command_Line_Sig(App_Read_Command_Line); name(System_Functions *system, \ Render_Target *target, \ Application_Memory *memory, \ - Exchange *exchange, \ String clipboard, \ String current_directory, \ Custom_API api) @@ -124,7 +123,6 @@ struct Application_Step_Input{ name(System_Functions *system, \ Render_Target *target, \ Application_Memory *memory, \ - Exchange *exchange, \ Application_Step_Input *input, \ Application_Step_Result *result) diff --git a/4ed_app_target.cpp b/4ed_app_target.cpp index 1ec9a45b..d3f4b609 100644 --- a/4ed_app_target.cpp +++ b/4ed_app_target.cpp @@ -39,7 +39,6 @@ #include "4ed_style.h" #include "4ed_style.cpp" -#include "4ed_exchange.cpp" #include "4ed_command.cpp" #include "4ed_file.cpp" #include "4ed_gui.cpp" diff --git a/4ed_exchange.cpp b/4ed_exchange.cpp deleted file mode 100644 index 24b1d9ae..00000000 --- a/4ed_exchange.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 9.12.2015 - * - * Exchange stuff - * - */ - -// TOP - -// NOTE(allen): Uhhh.... is it just me or did it get awkward -// in here when I deleted all the file exchange stuff? - -internal b32 -queue_job_is_pending(Work_Queue *queue, u32 job_id){ - b32 result; - u32 job_index; - Full_Job_Data *full_job; - - job_index = job_id % QUEUE_WRAP; - full_job = queue->jobs + job_index; - - Assert(full_job->id == job_id); - - result = 0; - if (full_job->running_thread != 0){ - result = 1; - } - - return(result); -} - -// BOTTOM - diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index f7fd5d17..d858b124 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -844,8 +844,6 @@ Job_Callback_Sig(job_full_lex){ } system->release_lock(FRAME_LOCK); - exchange->force_redraw = 1; - // NOTE(allen): These are outside the locked section because I don't // think getting these out of order will cause critical bugs, and I // want to minimize what's done in locked sections. @@ -4459,7 +4457,7 @@ struct Input_Process_Result{ }; internal Input_Process_Result -do_input_file_view(System_Functions *system, Exchange *exchange, +do_input_file_view(System_Functions *system, View *view, i32_Rect rect, b32 is_active, Input_Summary *user_input, GUI_Scroll_Vars vars, i32_Rect region){ @@ -5168,8 +5166,8 @@ draw_style_preview(GUI_Target *gui_target, Render_Target *target, View *view, i3 } internal i32 -do_render_file_view(System_Functions *system, Exchange *exchange, - View *view, View *active, i32_Rect rect, b32 is_active, +do_render_file_view(System_Functions *system, View *view, + View *active, i32_Rect rect, b32 is_active, Render_Target *target, Input_Summary *user_input){ Editing_File *file = view->file_data.file; @@ -5635,7 +5633,7 @@ live_set_alloc_view(Live_Views *live_set, Panel *panel, Models *models){ } inline void -live_set_free_view(System_Functions *system, Exchange *exchange, Live_Views *live_set, View *view){ +live_set_free_view(System_Functions *system, Live_Views *live_set, View *view){ Assert(live_set->count > 0); --live_set->count; file_view_free_buffers(view); diff --git a/4ed_system.h b/4ed_system.h index 32527d58..6597a83e 100644 --- a/4ed_system.h +++ b/4ed_system.h @@ -157,9 +157,11 @@ thread_memory_zero(){ struct Thread_Exchange; struct System_Functions; -#define Job_Callback_Sig(name) void name( \ - System_Functions *system, Thread_Context *thread, Thread_Memory *memory, \ - Thread_Exchange *exchange, void *data[2]) +#define Job_Callback_Sig(name) void name( \ + System_Functions *system, \ + Thread_Context *thread, \ + Thread_Memory *memory, \ + void *data[2]) typedef Job_Callback_Sig(Job_Callback); struct Job_Data{ @@ -189,11 +191,6 @@ struct Work_Queue{ #define JOB_ID_WRAP (ArrayCount(queue->jobs) * 4) #define QUEUE_WRAP (ArrayCount(queue->jobs)) -struct Thread_Exchange{ - Work_Queue queues[THREAD_GROUP_COUNT]; - volatile u32 force_redraw; -}; - #define Sys_Post_Job_Sig(name) u32 name(Thread_Group_ID group_id, Job_Data job) typedef Sys_Post_Job_Sig(System_Post_Job); @@ -267,9 +264,5 @@ struct System_Functions{ char slash; }; -struct Exchange{ - Thread_Exchange thread; -}; - // BOTTOM diff --git a/README.txt b/README.txt index 5ca9b38e..fb715b69 100644 --- a/README.txt +++ b/README.txt @@ -1,4 +1,4 @@ -Distribution Date: 28.5.2016 (dd.mm.yyyy) +Distribution Date: 31.5.2016 (dd.mm.yyyy) Thank you for contributing to the 4coder project! diff --git a/SUPERREADME.txt b/SUPERREADME.txt index 820ddefc..d7220460 100644 --- a/SUPERREADME.txt +++ b/SUPERREADME.txt @@ -1,4 +1,4 @@ -Distribution Date: 28.5.2016 (dd.mm.yyyy) +Distribution Date: 31.5.2016 (dd.mm.yyyy) Thank you for contributing to the 4coder project! diff --git a/TODO.txt b/TODO.txt index 083fa665..dae85159 100644 --- a/TODO.txt +++ b/TODO.txt @@ -68,10 +68,11 @@ ; [X] miblo's off screen cursor thing ; [X] new file is messed up for code files, it never finishes parsing! ; [X] key presses that should be consumed in the GUI are now passed to the file! +; [X] paste snaps the cursor back into view! +; ; [] indication on failure to save ; [] clean whitespace doesn't appear to be cleaning trailing whitespace anymore??? ; -; [] paste snaps the cursor back into view! ; ; TODOS diff --git a/win32_4ed.cpp b/win32_4ed.cpp index 085e2305..56ea7f54 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -125,6 +125,7 @@ struct Win32_Vars{ Plat_Settings settings; + Work_Queue queues[THREAD_GROUP_COUNT]; Thread_Group groups[THREAD_GROUP_COUNT]; CRITICAL_SECTION locks[LOCK_COUNT]; Thread_Memory *thread_memory; @@ -164,7 +165,6 @@ struct Win32_Vars{ globalvar Win32_Vars win32vars; globalvar Application_Memory memory_vars; -globalvar Exchange exchange_vars; // @@ -319,8 +319,8 @@ JobThreadProc(LPVOID lpParameter){ thread_memory->size = new_size; } } - full_job->job.callback(&win32vars.system, thread, thread_memory, - &exchange_vars.thread, full_job->job.data); + full_job->job.callback(&win32vars.system, + thread, thread_memory, full_job->job.data); PostMessage(win32vars.window_handle, WM_4coder_ANIMATE, 0, 0); full_job->running_thread = 0; thread->running = 0; @@ -335,7 +335,7 @@ JobThreadProc(LPVOID lpParameter){ internal Sys_Post_Job_Sig(system_post_job){ - Work_Queue *queue = exchange_vars.thread.queues + group_id; + Work_Queue *queue = win32vars.queues + group_id; Assert((queue->write_position + 1) % QUEUE_WRAP != queue->read_position % QUEUE_WRAP); @@ -366,7 +366,7 @@ Sys_Post_Job_Sig(system_post_job){ // but I still don't know what exactly I would do without it. internal Sys_Cancel_Job_Sig(system_cancel_job){ - Work_Queue *queue = exchange_vars.thread.queues + group_id; + Work_Queue *queue = win32vars.queues + group_id; Thread_Group *group = win32vars.groups + group_id; u32 job_index; @@ -414,7 +414,7 @@ system_grow_thread_memory(Thread_Memory *memory){ #if FRED_INTERNAL internal void INTERNAL_get_thread_states(Thread_Group_ID id, bool8 *running, i32 *pending){ - Work_Queue *queue = exchange_vars.thread.queues + id; + Work_Queue *queue = win32vars.queues + id; u32 write = queue->write_position; u32 read = queue->read_position; if (write < read) write += JOB_ID_WRAP; @@ -1611,7 +1611,6 @@ WinMain(HINSTANCE hInstance, char **argv = __argv; memset(&win32vars, 0, sizeof(win32vars)); - memset(&exchange_vars, 0, sizeof(exchange_vars)); // @@ -1626,7 +1625,7 @@ WinMain(HINSTANCE hInstance, Thread_Memory thread_memory[ArrayCount(background)]; win32vars.thread_memory = thread_memory; - exchange_vars.thread.queues[BACKGROUND_THREADS].semaphore = + win32vars.queues[BACKGROUND_THREADS].semaphore = Win32Handle(CreateSemaphore(0, 0, win32vars.groups[BACKGROUND_THREADS].count, 0)); @@ -1639,7 +1638,7 @@ WinMain(HINSTANCE hInstance, *memory = thread_memory_zero(); memory->id = thread->id; - thread->queue = &exchange_vars.thread.queues[BACKGROUND_THREADS]; + thread->queue = &win32vars.queues[BACKGROUND_THREADS]; thread->handle = CreateThread(0, 0, JobThreadProc, thread, creation_flag, (LPDWORD)&thread->windows_id); } @@ -1955,9 +1954,11 @@ WinMain(HINSTANCE hInstance, // Main Loop // - win32vars.app.init(&win32vars.system, &win32vars.target, - &memory_vars, &exchange_vars, - win32vars.clipboard_contents, current_directory, + win32vars.app.init(&win32vars.system, + &win32vars.target, + &memory_vars, + win32vars.clipboard_contents, + current_directory, win32vars.custom_api); system_free_memory(current_directory.str); @@ -2078,7 +2079,6 @@ WinMain(HINSTANCE hInstance, win32vars.app.step(&win32vars.system, &win32vars.target, &memory_vars, - &exchange_vars, &input, &result); From 43f65dd5efafb0570eb91218e8ec73fe58ab2e00 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Tue, 31 May 2016 13:07:31 -0400 Subject: [PATCH 20/34] remove overlapped sections, need floating sections instead --- 4coder_gui.h | 2 +- 4ed.cpp | 44 ++++++++++--------- 4ed_file_view.cpp | 105 +++++++++++++++++----------------------------- 4ed_gui.cpp | 67 ++++------------------------- 4ed_math.cpp | 16 ++++++- 5 files changed, 84 insertions(+), 150 deletions(-) diff --git a/4coder_gui.h b/4coder_gui.h index 2771b490..28ddc8ef 100644 --- a/4coder_gui.h +++ b/4coder_gui.h @@ -17,7 +17,7 @@ struct GUI_Scroll_Vars{ float scroll_y; float target_y; float prev_target_y; - float min_y, max_y; + float max_y; float scroll_x; float target_x; diff --git a/4ed.cpp b/4ed.cpp index 19eee6a3..b006f540 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -415,10 +415,9 @@ COMMAND_DECL(center_view){ else{ y = view->recent->cursor.wrapped_y; } - + h = view_file_height(view); - y -= h * .5f; - if (y < view->recent->scroll.min_y) y = view->recent->scroll.min_y; + y = clamp_bottom(0.f, y - h*.5f); view->recent->scroll.target_y = y; } @@ -1362,7 +1361,7 @@ COMMAND_DECL(move_down){ USE_MODELS(models); REQ_READABLE_VIEW(view); REQ_FILE(file, view); - + f32 font_height = (f32)get_font_info(models->font_set, models->global_font.font_id)->height; f32 cy = view_get_cursor_y(view)+font_height; f32 px = view->recent->preferred_x; @@ -1373,7 +1372,7 @@ COMMAND_DECL(move_down){ COMMAND_DECL(seek_end_of_line){ REQ_READABLE_VIEW(view); REQ_FILE(file, view); - + i32 pos = view_find_end_of_line(view, view->recent->cursor.pos); view_cursor_move(view, pos); } @@ -1381,48 +1380,47 @@ COMMAND_DECL(seek_end_of_line){ COMMAND_DECL(seek_beginning_of_line){ REQ_READABLE_VIEW(view); REQ_FILE(file, view); - + i32 pos = view_find_beginning_of_line(view, view->recent->cursor.pos); view_cursor_move(view, pos); } COMMAND_DECL(page_down){ REQ_READABLE_VIEW(view); - + f32 height = view_file_height(view); f32 max_target_y = view->recent->scroll.max_y; - - view->recent->scroll.target_y += height; - if (view->recent->scroll.target_y > max_target_y) view->recent->scroll.target_y = max_target_y; - - view->recent->cursor = view_compute_cursor_from_xy( - view, 0, view->recent->scroll.target_y + (height - view->font_height)*.5f); + + view->recent->scroll.target_y = + clamp_top(view->recent->scroll.target_y + height, max_target_y); + + view->recent->cursor = + view_compute_cursor_from_xy(view, 0, view->recent->scroll.target_y + (height - view->font_height)*.5f); } COMMAND_DECL(page_up){ REQ_READABLE_VIEW(view); - + f32 height = view_file_height(view); - f32 min_target_y = view->recent->scroll.min_y; - - view->recent->scroll.target_y -= height; - if (view->recent->scroll.target_y < min_target_y) view->recent->scroll.target_y = min_target_y; - - view->recent->cursor = view_compute_cursor_from_xy( - view, 0, view->recent->scroll.target_y + (height - view->font_height)*.5f); + + view->recent->scroll.target_y = + clamp_bottom(0.f, view->recent->scroll.target_y - height); + + view->recent->cursor = + view_compute_cursor_from_xy(view, 0, view->recent->scroll.target_y + (height - view->font_height)*.5f); } COMMAND_DECL(open_color_tweaker){ USE_VIEW(view); USE_MODELS(models); - + view_show_theme(view, &models->map_ui); } COMMAND_DECL(open_config){ USE_VIEW(view); USE_MODELS(models); - + view_show_config(view, &models->map_ui); } diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index d858b124..c8d98518 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -1422,7 +1422,7 @@ view_get_cursor_y(View *view){ internal void view_move_cursor_to_view(View *view){ - f32 min_target_y = view->recent->scroll.min_y; + f32 min_target_y = 0; i32 line_height = view->font_height; f32 old_cursor_y = view_get_cursor_y(view); f32 cursor_y = old_cursor_y; @@ -1465,7 +1465,7 @@ view_move_view_to_cursor(View *view, GUI_Scroll_Vars *scroll){ f32 target_x = scroll_vars.target_x; f32 cursor_max_y = CursorMaxY(max_visible_y, line_height); - f32 cursor_min_y = CursorMinY(scroll_vars.min_y, line_height); + f32 cursor_min_y = CursorMinY(0, line_height); if (cursor_y > target_y + cursor_max_y){ target_y = cursor_y - cursor_max_y + delta_y; @@ -1474,8 +1474,7 @@ view_move_view_to_cursor(View *view, GUI_Scroll_Vars *scroll){ target_y = cursor_y - delta_y - cursor_min_y; } - if (target_y > scroll_vars.max_y) target_y = scroll_vars.max_y; - if (target_y < scroll_vars.min_y) target_y = view->recent->scroll.min_y; + target_y = clamp(0.f, target_y, scroll_vars.max_y); if (cursor_x < target_x){ target_x = (f32)Max(0, cursor_x - max_x/2); @@ -1535,7 +1534,11 @@ view_set_file(View *view, Editing_File *file, Models *models){ if (file_is_ready(file)){ view_measure_wraps(&models->mem.general, view); view->recent->cursor = view_compute_cursor_from_pos(view, view->recent->cursor.pos); + +#if 0 view->recent->scroll.max_y = 1000000000.f; +#endif + view_move_view_to_cursor(view, &view->recent->scroll); } } @@ -1551,11 +1554,13 @@ view_set_file(View *view, Editing_File *file, Models *models){ if (file_is_ready(file)){ view_measure_wraps(&models->mem.general, view); view->recent->cursor = view_compute_cursor_from_pos(view, file->state.cursor_pos); + +#if 0 view->recent->scroll.max_y = 1000000000.f; +#endif + view_move_view_to_cursor(view, &view->recent->scroll); - if (!found_recent_entry){ - view->reinit_scrolling = 1; - } + view->reinit_scrolling = 1; } } } @@ -1564,7 +1569,6 @@ view_set_file(View *view, Editing_File *file, Models *models){ struct Relative_Scrolling{ f32 scroll_x, scroll_y; f32 target_x, target_y; - f32 scroll_min_limit; }; internal Relative_Scrolling @@ -1574,7 +1578,6 @@ view_get_relative_scrolling(View *view){ cursor_y = view_get_cursor_y(view); result.scroll_y = cursor_y - view->recent->scroll.scroll_y; result.target_y = cursor_y - view->recent->scroll.target_y; - result.scroll_min_limit = view->recent->scroll.min_y; return(result); } @@ -1583,10 +1586,8 @@ view_set_relative_scrolling(View *view, Relative_Scrolling scrolling){ f32 cursor_y; cursor_y = view_get_cursor_y(view); view->recent->scroll.scroll_y = cursor_y - scrolling.scroll_y; - view->recent->scroll.target_y = cursor_y - scrolling.target_y; - if (view->recent->scroll.target_y < scrolling.scroll_min_limit){ - view->recent->scroll.target_y = scrolling.scroll_min_limit; - } + view->recent->scroll.target_y = + clamp_bottom(0.f, cursor_y - scrolling.target_y); } inline void @@ -2940,7 +2941,7 @@ style_get_color(Style *style, Cpp_Token token){ inline f32 view_compute_max_target_y(i32 lowest_line, i32 line_height, f32 view_height){ f32 max_target_y = ((lowest_line+.5f)*line_height) - view_height*.5f; - if (max_target_y < 0) max_target_y = 0; + max_target_y = clamp_bottom(0.f, max_target_y); return(max_target_y); } @@ -3402,10 +3403,7 @@ view_reinit_scrolling(View *view){ target_x = (f32)(cursor_x - w*.5f); } - target_y = (f32)FLOOR32(cursor_y - h*.5f); - if (target_y < view->recent->scroll.min_y){ - target_y = view->recent->scroll.min_y; - } + target_y = clamp_bottom(0.f, (f32)FLOOR32(cursor_y - h*.5f)); } view->recent->scroll.target_y = target_y; @@ -3520,7 +3518,7 @@ file_step(View *view, i32_Rect region, Input_Summary *user_input, b32 is_active) f32 rx = (f32)(user_input->mouse.x - region.x0); f32 ry = (f32)(user_input->mouse.y - region.y0); - if (ry >= -view->recent->scroll.min_y){ + if (ry >= 0){ view_set_widget(view, FWIDG_NONE); if (rx >= 0 && rx < max_x && ry >= 0 && ry < max_visible_y){ view_cursor_move(view, rx + scroll_vars.scroll_x, ry + scroll_vars.scroll_y, 1); @@ -3539,14 +3537,10 @@ do_widget(View *view, GUI_Target *target){ Query_Slot *slot; Query_Bar *bar; - gui_begin_serial_section(target); - for (slot = view->query_set.used_slot; slot != 0; slot = slot->next){ bar = slot->query_bar; gui_do_text_field(target, bar->prompt, bar->string); } - - gui_end_serial_section(target); } struct Exhaustive_File_Loop{ @@ -3820,34 +3814,29 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su gui_begin_top_level(target, input); { gui_do_top_bar(target); + do_widget(view, target); if (view->showing_ui == VUI_None){ - gui_begin_overlap(target); + + gui_begin_serial_section(target); { - do_widget(view, target); + f32 delta = 9.f * view->font_height; + GUI_id scroll_context = {0}; + scroll_context.id[1] = view->showing_ui; + scroll_context.id[0] = (u64)(view->file_data.file); - gui_begin_serial_section(target); - { - f32 delta = 9.f * view->font_height; - GUI_id scroll_context = {0}; - scroll_context.id[1] = view->showing_ui; - scroll_context.id[0] = (u64)(view->file_data.file); - - view->current_scroll = &view->recent->scroll; - gui_get_scroll_vars(target, scroll_context, - &view->recent->scroll, &view->scroll_region); - - gui_begin_scrollable(target, scroll_context, view->recent->scroll, - delta, show_scrollbar); - gui_do_file(target); - gui_end_scrollable(target); - } - gui_end_serial_section(target); + view->current_scroll = &view->recent->scroll; + gui_get_scroll_vars(target, scroll_context, + &view->recent->scroll, &view->scroll_region); + + gui_begin_scrollable(target, scroll_context, view->recent->scroll, + delta, show_scrollbar); + gui_do_file(target); + gui_end_scrollable(target); } - gui_end_overlap(target); + gui_end_serial_section(target); } else{ - do_widget(view, target); switch (view->showing_ui){ case VUI_Menu: { @@ -4514,12 +4503,9 @@ do_input_file_view(System_Functions *system, case guicom_file: { - f32 new_min_y = -(f32)(gui_session_get_eclipsed_y(&gui_session) - - gui_session.rect.y0); f32 new_max_y = view_compute_max_target_y(view); view->file_region = gui_session.rect; - result.vars.min_y = new_min_y; result.vars.max_y = new_max_y; if (view->reinit_scrolling){ @@ -4596,10 +4582,8 @@ do_input_file_view(System_Functions *system, if (gui_id_eq(target->mouse_hot, id)){ v = unlerp(gui_session.scroll_top, (f32)my, gui_session.scroll_bottom); - if (v < 0) v = 0; - if (v > 1.f) v = 1.f; - result.vars.target_y = - lerp(result.vars.min_y, v, result.vars.max_y); + v = clamp(0.f, v, 1.f); + result.vars.target_y = lerp(0.f, v, result.vars.max_y); gui_activate_scrolling(target); result.is_animating = 1; @@ -4612,12 +4596,8 @@ do_input_file_view(System_Functions *system, if (user_input->mouse.wheel != 0){ result.vars.target_y += user_input->mouse.wheel*target->delta; - if (result.vars.target_y < result.vars.min_y){ - result.vars.target_y = result.vars.min_y; - } - if (result.vars.target_y > result.vars.max_y){ - result.vars.target_y = result.vars.max_y; - } + result.vars.target_y = + clamp(0.f, result.vars.target_y, result.vars.max_y); gui_activate_scrolling(target); result.is_animating = 1; } @@ -4629,9 +4609,7 @@ do_input_file_view(System_Functions *system, if (scroll_button_input(target, &gui_session, user_input, id, &result.is_animating)){ result.vars.target_y -= target->delta * 0.25f; - if (result.vars.target_y < result.vars.min_y){ - result.vars.target_y = result.vars.min_y; - } + result.vars.target_y = clamp_bottom(0.f, result.vars.target_y); } }break; @@ -4641,19 +4619,14 @@ do_input_file_view(System_Functions *system, if (scroll_button_input(target, &gui_session, user_input, id, &result.is_animating)){ result.vars.target_y += target->delta * 0.25f; - if (result.vars.target_y > result.vars.max_y){ - result.vars.target_y = result.vars.max_y; - } + result.vars.target_y = clamp_top(0.f, result.vars.max_y); } }break; case guicom_end_scrollable_section: { if (!is_file_scroll){ - f32 new_min_y = gui_session.suggested_min_y; f32 new_max_y = gui_session.suggested_max_y; - - result.vars.min_y = new_min_y; result.vars.max_y = new_max_y; } }break; diff --git a/4ed_gui.cpp b/4ed_gui.cpp index c43c5503..81ef53da 100644 --- a/4ed_gui.cpp +++ b/4ed_gui.cpp @@ -171,8 +171,6 @@ struct GUI_Edit{ enum GUI_Command_Type{ guicom_null, - guicom_begin_overlap, - guicom_end_overlap, guicom_begin_serial, guicom_end_serial, guicom_top_bar, @@ -371,16 +369,6 @@ gui_push_string(GUI_Target *target, GUI_Header *h, String s){ gui_push_string(target, h, s, 0); } -internal void -gui_begin_overlap(GUI_Target *target){ - gui_push_simple_command(target, guicom_begin_overlap); -} - -internal void -gui_end_overlap(GUI_Target *target){ - gui_push_simple_command(target, guicom_end_overlap); -} - internal void gui_begin_serial_section(GUI_Target *target){ gui_push_simple_command(target, guicom_begin_serial); @@ -661,10 +649,10 @@ gui_get_scroll_vars(GUI_Target *target, GUI_id scroll_context_id, GUI_Scroll_Var *vars_out = target->scroll_updated; *region_out = target->region_updated; - if (vars_out->target_y < vars_out->min_y) vars_out->target_y = vars_out->min_y; + if (vars_out->target_y < 0) vars_out->target_y = 0; if (vars_out->target_y > vars_out->max_y) vars_out->target_y = vars_out->max_y; - if (vars_out->scroll_y < vars_out->min_y) vars_out->scroll_y = vars_out->min_y; + if (vars_out->scroll_y < 0) vars_out->scroll_y = 0; if (vars_out->scroll_y > vars_out->max_y) vars_out->scroll_y = vars_out->max_y; if (gui_id_eq(target->active, gui_id_scrollbar())){ @@ -724,7 +712,6 @@ gui_activate_scrolling(GUI_Target *target){ } struct GUI_Section{ - b32 overlapped; i32 max_v, v, top_v; }; @@ -739,7 +726,6 @@ struct GUI_Session{ i32_Rect full_rect; i32_Rect rect; - f32 suggested_min_y; f32 suggested_max_y; i32 clip_y; @@ -759,17 +745,11 @@ struct GUI_Session{ #define GUIScrollbarWidth 16 +// TODO(allen): We can probably totally get rid of this now. internal i32 gui_session_get_eclipsed_y(GUI_Session *session){ - GUI_Section *section = session->sections; - i32 count = session->t + 1, i; - i32 max_v = 0; - for (i = 0; i < count; ++i, ++section){ - if (section->overlapped){ - max_v = Max(max_v, section->max_v); - } - } - max_v = Max(max_v, session->sections[count-1].top_v); + i32 count = session->t + 1; + i32 max_v = session->sections[count-1].top_v; return(max_v); } @@ -804,9 +784,7 @@ gui_session_init(GUI_Session *session, GUI_Target *target, internal void gui_section_end_item(GUI_Section *section, i32 v){ - if (!section->overlapped){ - section->v = v; - } + section->v = v; if (section->max_v < v){ section->max_v = v; } @@ -978,29 +956,10 @@ gui_interpret(GUI_Target *target, GUI_Session *session, GUI_Header *h, switch (h->type){ case guicom_null: Assert(0); break; - case guicom_begin_overlap: - ++session->t; - Assert(session->t < ArrayCount(session->sections)); - new_section = &session->sections[session->t]; - new_section->overlapped = 1; - new_section->v = y; - new_section->max_v = y; - new_section->top_v = y; - break; - - case guicom_end_overlap: - Assert(session->t > 0); - Assert(section->overlapped); - prev_section = &session->sections[--session->t]; - end_v = section->max_v; - end_section = prev_section; - break; - case guicom_begin_serial: ++session->t; Assert(session->t < ArrayCount(session->sections)); new_section = &session->sections[session->t]; - new_section->overlapped = 0; new_section->v = y; new_section->max_v = y; new_section->top_v = y; @@ -1008,7 +967,6 @@ gui_interpret(GUI_Target *target, GUI_Session *session, GUI_Header *h, case guicom_end_serial: Assert(session->t > 0); - Assert(!section->overlapped); prev_section = &session->sections[--session->t]; end_v = section->max_v; end_section = prev_section; @@ -1110,7 +1068,6 @@ gui_interpret(GUI_Target *target, GUI_Session *session, GUI_Header *h, case guicom_scrollable: Assert(session->is_scrollable == 0); - Assert(!section->overlapped); session->is_scrollable = 1; always_give_to_user = 1; @@ -1128,7 +1085,6 @@ gui_interpret(GUI_Target *target, GUI_Session *session, GUI_Header *h, case guicom_scrollable_bar: Assert(session->is_scrollable); - Assert(!section->overlapped); give_to_user = 1; rect.x1 = session->full_rect.x1; rect.x0 = rect.x1 - GUIScrollbarWidth; @@ -1151,7 +1107,6 @@ gui_interpret(GUI_Target *target, GUI_Session *session, GUI_Header *h, case guicom_scrollable_top: Assert(session->is_scrollable); - Assert(!section->overlapped); give_to_user = 1; gui_scrollbar_top(session->scroll_rect, &rect); scroll_v = 0; @@ -1159,29 +1114,26 @@ gui_interpret(GUI_Target *target, GUI_Session *session, GUI_Header *h, case guicom_scrollable_slider: Assert(session->is_scrollable); - Assert(!section->overlapped); give_to_user = 1; lerp_space_scroll_v = - unlerp((f32)target->scroll_original.min_y, + unlerp(0, (f32)target->scroll_original.target_y, (f32)target->scroll_original.max_y); gui_scrollbar_slider(session->scroll_rect, &rect, lerp_space_scroll_v, &session->scroll_top, &session->scroll_bottom, - target->scroll_original.min_y, target->scroll_original.max_y); + 0, target->scroll_original.max_y); scroll_v = 0; break; case guicom_scrollable_invisible: Assert(session->is_scrollable); - Assert(!section->overlapped); always_give_to_user = 1; break; case guicom_scrollable_bottom: Assert(session->is_scrollable); - Assert(!section->overlapped); give_to_user = 1; gui_scrollbar_bottom(session->scroll_rect, &rect); scroll_v = 0; @@ -1196,9 +1148,6 @@ gui_interpret(GUI_Target *target, GUI_Session *session, GUI_Header *h, case guicom_end_scrollable_section: always_give_to_user = 1; - session->suggested_min_y = - -(f32)(gui_session_get_eclipsed_y(session) - - gui_session_get_current_top(session)); session->suggested_max_y = (f32)(session->scrollable_items_bottom - session->full_rect.y1 * .5f); diff --git a/4ed_math.cpp b/4ed_math.cpp index cb49e7c0..de324c35 100644 --- a/4ed_math.cpp +++ b/4ed_math.cpp @@ -464,9 +464,23 @@ unlerp(f32 a, f32 x, f32 b){ return(r); } +inline f32 +clamp_bottom(f32 a, f32 n){ + if (n < a) n = a; + return (n); +} + +inline f32 +clamp_top(f32 n, f32 z){ + if (n > z) n = z; + return (n); +} + inline f32 clamp(f32 a, f32 n, f32 z){ - return (nz)?(z):n); + if (n < a) n = a; + else if (n > z) n = z; + return (n); } /* From a09851af122722b8ab3363c36c19fdf96d43addd Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Tue, 31 May 2016 14:32:58 -0400 Subject: [PATCH 21/34] switched to condition-variable based cancelation --- 4ed_file_view.cpp | 11266 ++++++++++++++++++++++---------------------- 4ed_system.h | 6 +- win32_4ed.cpp | 116 +- 3 files changed, 5754 insertions(+), 5634 deletions(-) diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index c8d98518..7fcf241c 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -1,5618 +1,5648 @@ -/* -* Mr. 4th Dimention - Allen Webster -* -* 19.08.2015 -* -* File editing view for 4coder -* -*/ - -// TOP - -internal i32 -get_or_add_map_index(Models *models, i32 mapid){ - i32 result; - i32 user_map_count = models->user_map_count; - i32 *map_id_table = models->map_id_table; - for (result = 0; result < user_map_count; ++result){ - if (map_id_table[result] == mapid) break; - if (map_id_table[result] == -1){ - map_id_table[result] = mapid; - break; - } - } - return result; -} - -internal i32 -get_map_index(Models *models, i32 mapid){ - i32 result; - i32 user_map_count = models->user_map_count; - i32 *map_id_table = models->map_id_table; - for (result = 0; result < user_map_count; ++result){ - if (map_id_table[result] == mapid) break; - if (map_id_table[result] == 0){ - result = user_map_count; - break; - } - } - return result; -} - -internal Command_Map* -get_map_base(Models *models, i32 mapid, b32 add){ - Command_Map *map = 0; - if (mapid < mapid_global){ - if (add){ - mapid = get_or_add_map_index(models, mapid); - } - else{ - mapid = get_map_index(models, mapid); - } - if (mapid < models->user_map_count){ - map = models->user_maps + mapid; - } - } - else if (mapid == mapid_global) map = &models->map_top; - else if (mapid == mapid_file) map = &models->map_file; - return(map); -} - -internal Command_Map* -get_or_add_map(Models *models, i32 mapid){ - Command_Map *map = get_map_base(models, mapid, 1); - return(map); -} - -internal Command_Map* -get_map(Models *models, i32 mapid){ - Command_Map *map = get_map_base(models, mapid, 0); - return(map); -} - -internal void -map_set_count(Models *models, i32 mapid, i32 count){ - Command_Map *map = get_or_add_map(models, mapid); - Assert(map->commands == 0); - map->count = count; - if (map->max < count){ - map->max = count; - } -} - -internal i32 -map_get_count(Models *models, i32 mapid){ - Command_Map *map = get_or_add_map(models, mapid); - i32 count = map->count; - Assert(map->commands == 0); - return(count); -} - -internal i32 -map_get_max_count(Models *models, i32 mapid){ - Command_Map *map = get_or_add_map(models, mapid); - i32 count = map->max; - return(count); -} - -enum Interactive_Action{ - IAct_Open, - IAct_Save_As, - IAct_New, - IAct_Switch, - IAct_Kill, - IAct_Sure_To_Kill, - IAct_Sure_To_Close -}; - -enum Interactive_Interaction{ - IInt_Sys_File_List, - IInt_Live_File_List, - IInt_Sure_To_Kill, - IInt_Sure_To_Close -}; - -struct View_Mode{ - i32 rewrite; -}; -inline View_Mode -view_mode_zero(){ - View_Mode mode={0}; - return(mode); -} - -enum View_Widget_Type{ - FWIDG_NONE, - FWIDG_TIMELINES, - // never below this - FWIDG_TYPE_COUNT -}; - -struct View_Widget{ - View_Widget_Type type; - i32 height_; - struct{ - b32 undo_line; - b32 history_line; - } timeline; -}; - -enum View_UI{ - VUI_None, - VUI_Theme, - VUI_Interactive, - VUI_Menu, - VUI_Config, -}; - -enum Color_View_Mode{ - CV_Mode_Library, - CV_Mode_Font, - CV_Mode_Adjusting -}; - -struct File_Viewing_Data{ - Editing_File *file; - - Full_Cursor temp_highlight; - i32 temp_highlight_end_pos; - b32 show_temp_highlight; - - b32 unwrapped_lines; - b32 show_whitespace; - b32 file_locked; - - i32 line_count, line_max; - f32 *line_wrap_y; -}; -inline File_Viewing_Data -file_viewing_data_zero(){ - File_Viewing_Data data={0}; - return(data); -} - -struct Recent_File_Data{ - u64 unique_buffer_id; - GUI_Scroll_Vars scroll; - - Full_Cursor cursor; - i32 mark; - f32 preferred_x; - i32 scroll_i; -}; -inline Recent_File_Data -recent_file_data_zero(){ - Recent_File_Data data = {0}; - return(data); -} - -struct Scroll_Context{ - Editing_File *file; - GUI_id scroll; - View_UI mode; -}; -inline b32 -context_eq(Scroll_Context a, Scroll_Context b){ - b32 result = 0; - if (gui_id_eq(a.scroll, b.scroll)){ - if (a.file == b.file){ - if (a.mode == b.mode){ - result = 1; - } - } - } - return(result); -} - -struct View_Persistent{ - i32 id; - - View_Routine_Function *view_routine; - Coroutine *coroutine; - Event_Message message_passing_slot; - - // TODO(allen): eliminate this models pointer: explicitly parameterize. - Models *models; -}; - -struct View{ - View_Persistent persistent; - - View *next, *prev; - Panel *panel; - b32 in_use; - Command_Map *map; - - File_Viewing_Data file_data; - i32 prev_cursor_pos; - Scroll_Context prev_context; - - i32_Rect file_region_prev; - i32_Rect file_region; - - i32_Rect scroll_region; - Recent_File_Data recent[16]; - - GUI_Scroll_Vars *current_scroll; - - View_UI showing_ui; - GUI_Target gui_target; - void *gui_mem; - GUI_Scroll_Vars gui_scroll; - i32 list_i; - - b32 hide_scrollbar; - - // interactive stuff - Interactive_Interaction interaction; - Interactive_Action action; - - char dest_[256]; - String dest; - - // theme stuff - View *hot_file_view; - u32 *palette; - i32 palette_size; - Color_View_Mode color_mode; - Super_Color color; - b32 p4c_only; - Style_Library inspecting_styles; - b8 import_export_check[64]; - i32 import_file_id; - i32 current_color_editing; - i32 color_cursor; - - i32 font_advance; - i32 font_height; - - View_Mode mode, next_mode; - View_Widget widget; - Query_Set query_set; - i32 scrub_max; - - b32 reinit_scrolling; -}; -inline void* -get_view_body(View *view){ - char *result = (char*)view; - result += sizeof(View_Persistent); - return(result); -} -inline i32 -get_view_size(){ - return(sizeof(View) - sizeof(View_Persistent)); -} - -struct View_And_ID{ - View *view; - i32 id; -}; - -#define LockLevel_Open 0 -#define LockLevel_NoWrite 1 -#define LockLevel_NoUpdate 2 - -inline i32 -view_lock_level(View *view){ - i32 result = LockLevel_Open; - File_Viewing_Data *data = &view->file_data; - if (view->showing_ui != VUI_None) result = LockLevel_NoUpdate; - else if (data->file_locked || (data->file && data->file->settings.read_only)) result = LockLevel_NoWrite; - return(result); -} - -inline f32 -view_file_width(View *view){ - i32_Rect file_rect = view->file_region; - f32 result = (f32)(file_rect.x1 - file_rect.x0); - return (result); -} - -inline f32 -view_file_height(View *view){ - i32_Rect file_rect = view->file_region; - f32 result = (f32)(file_rect.y1 - file_rect.y0); - return (result); -} - -struct View_Iter{ - View *view; - - Editing_File *file; - View *skip; - Panel *used_panels; - Panel *panel; -}; - -internal View_Iter -file_view_iter_next(View_Iter iter){ - View *view; - - for (iter.panel = iter.panel->next; iter.panel != iter.used_panels; iter.panel = iter.panel->next){ - view = iter.panel->view; - if (view != iter.skip && (view->file_data.file == iter.file || iter.file == 0)){ - iter.view = view; - break; - } - } - - return(iter); -} - -internal View_Iter -file_view_iter_init(Editing_Layout *layout, Editing_File *file, View *skip){ - View_Iter result; - result.used_panels = &layout->used_sentinel; - result.panel = result.used_panels; - result.file = file; - result.skip = skip; - - result = file_view_iter_next(result); - - return(result); -} - -internal b32 -file_view_iter_good(View_Iter iter){ - b32 result = (iter.panel != iter.used_panels); - return(result); -} - -inline b32 -starts_new_line(u8 character){ - return (character == '\n'); -} - -inline void -file_init_strings(Editing_File *file){ - file->name.source_path = make_fixed_width_string(file->name.source_path_); - file->name.live_name = make_fixed_width_string(file->name.live_name_); - file->name.extension = make_fixed_width_string(file->name.extension_); -} - -inline void -file_set_name(Working_Set *working_set, Editing_File *file, char *filename){ - String f, ext; - - Assert(file->name.live_name.str != 0); - - f = make_string_slowly(filename); - copy_checked(&file->name.source_path, f); - - file->name.live_name.size = 0; - get_front_of_directory(&file->name.live_name, f); - - if (file->name.source_path.size == file->name.live_name.size){ - file->name.extension.size = 0; - } - else{ - ext = file_extension(f); - copy(&file->name.extension, ext); - } - - { - File_Node *node, *used_nodes; - Editing_File *file_ptr; - i32 file_x, original_len; - b32 hit_conflict; - - used_nodes = &working_set->used_sentinel; - original_len = file->name.live_name.size; - hit_conflict = 1; - file_x = 0; - while (hit_conflict){ - hit_conflict = 0; - for (dll_items(node, used_nodes)){ - file_ptr = (Editing_File*)node; - if (file_ptr != file && file_is_ready(file_ptr)){ - if (match(file->name.live_name, file_ptr->name.live_name)){ - ++file_x; - hit_conflict = 1; - break; - } - } - } - - if (hit_conflict){ - file->name.live_name.size = original_len; - append(&file->name.live_name, " <"); - append_int_to_str(file_x, &file->name.live_name); - append(&file->name.live_name, ">"); - } - } - } -} - -inline void -file_synchronize_times(System_Functions *system, Editing_File *file, char *filename){ - u64 stamp = system->file_time_stamp(filename); - if (stamp > 0){ - file->state.last_4ed_write_time = stamp; - file->state.last_4ed_edit_time = stamp; - file->state.last_sys_write_time = stamp; - } - file->state.sync = buffer_get_sync(file); -} - -internal b32 -file_save(System_Functions *system, Mem_Options *mem, Editing_File *file, char *filename){ - b32 result = 0; - - i32 max, size; - b32 dos_write_mode = file->settings.dos_write_mode; - char *data; - Buffer_Type *buffer = &file->state.buffer; - - if (dos_write_mode){ - max = buffer_size(buffer) + buffer->line_count + 1; - } - else{ - max = buffer_size(buffer); - } - - Temp_Memory temp = begin_temp_memory(&mem->part); - char empty = 0; - if (max == 0){ - data = ∅ - } - else{ - data = (char*)push_array(&mem->part, char, max); - } - Assert(data); - - if (dos_write_mode){ - size = buffer_convert_out(buffer, data, max); - } - else{ - size = max; - buffer_stringify(buffer, 0, size, data); - } - - result = system->file_save(filename, data, size); - - file_synchronize_times(system, file, filename); - - end_temp_memory(temp); - - return(result); -} - -inline b32 -file_save_and_set_names(System_Functions *system, Mem_Options *mem, - Working_Set *working_set, Editing_File *file, - char *filename){ - b32 result = 0; - result = file_save(system, mem, file, filename); - if (result){ - file_set_name(working_set, file, filename); - } - return result; -} - -enum File_Bubble_Type{ - BUBBLE_BUFFER = 1, - BUBBLE_STARTS, - BUBBLE_WIDTHS, - BUBBLE_WRAPS, - BUBBLE_TOKENS, - BUBBLE_UNDO_STRING, - BUBBLE_UNDO, - BUBBLE_UNDO_CHILDREN, - // - FILE_BUBBLE_TYPE_END, -}; - -#define GROW_FAILED 0 -#define GROW_NOT_NEEDED 1 -#define GROW_SUCCESS 2 - -internal i32 -file_grow_starts_widths_as_needed(General_Memory *general, Buffer_Type *buffer, i32 additional_lines){ - b32 result = GROW_NOT_NEEDED; - i32 max = buffer->line_max; - i32 count = buffer->line_count; - i32 target_lines = count + additional_lines; - Assert(max == buffer->widths_max); - - if (target_lines > max || max == 0){ - max = LargeRoundUp(target_lines + max, Kbytes(1)); - - f32 *new_widths = (f32*)general_memory_reallocate( - general, buffer->line_widths, - sizeof(f32)*count, sizeof(f32)*max, BUBBLE_WIDTHS); - - i32 *new_lines = (i32*)general_memory_reallocate( - general, buffer->line_starts, - sizeof(i32)*count, sizeof(i32)*max, BUBBLE_STARTS); - - if (new_lines){ - buffer->line_starts = new_lines; - buffer->line_max = max; - } - if (new_widths){ - buffer->line_widths = new_widths; - buffer->widths_max = max; - } - if (new_lines && new_widths){ - result = GROW_SUCCESS; - } - else{ - result = GROW_FAILED; - } - } - - return(result); -} - -internal void -file_measure_starts_widths(System_Functions *system, General_Memory *general, - Buffer_Type *buffer, float *advance_data){ - if (!buffer->line_starts){ - i32 max = buffer->line_max = Kbytes(1); - buffer->line_starts = (i32*)general_memory_allocate(general, max*sizeof(i32), BUBBLE_STARTS); - TentativeAssert(buffer->line_starts); - // TODO(allen): when unable to allocate? - } - if (!buffer->line_widths){ - i32 max = buffer->widths_max = Kbytes(1); - buffer->line_widths = (f32*)general_memory_allocate(general, max*sizeof(f32), BUBBLE_WIDTHS); - TentativeAssert(buffer->line_starts); - // TODO(allen): when unable to allocate? - } - - Buffer_Measure_Starts state = {}; - while (buffer_measure_starts_widths(&state, buffer, advance_data)){ - i32 count = state.count; - i32 max = buffer->line_max; - max = ((max + 1) << 1); - - { - i32 *new_lines = (i32*)general_memory_reallocate( - general, buffer->line_starts, sizeof(i32)*count, sizeof(i32)*max, BUBBLE_STARTS); - - // TODO(allen): when unable to grow? - TentativeAssert(new_lines); - buffer->line_starts = new_lines; - buffer->line_max = max; - } - - { - f32 *new_lines = (f32*) - general_memory_reallocate(general, buffer->line_widths, - sizeof(f32)*count, sizeof(f32)*max, BUBBLE_WIDTHS); - - // TODO(allen): when unable to grow? - TentativeAssert(new_lines); - buffer->line_widths = new_lines; - buffer->widths_max = max; - } - - } - buffer->line_count = state.count; - buffer->widths_count = state.count; -} - -struct Opaque_Font_Advance{ - void *data; - int stride; -}; - -inline Opaque_Font_Advance -get_opaque_font_advance(Render_Font *font){ - Opaque_Font_Advance result; - result.data = (char*)font->chardata + OffsetOfPtr(font->chardata, xadvance); - result.stride = sizeof(*font->chardata); - return result; -} - -inline i32 -view_wrapped_line_span(f32 line_width, f32 max_width){ - i32 line_count = CEIL32(line_width / max_width); - if (line_count == 0) line_count = 1; - return line_count; -} - -internal i32 -view_compute_lowest_line(View *view){ - i32 lowest_line = 0; - i32 last_line = view->file_data.line_count - 1; - if (last_line > 0){ - if (view->file_data.unwrapped_lines){ - lowest_line = last_line; - } - else{ - f32 wrap_y = view->file_data.line_wrap_y[last_line]; - lowest_line = FLOOR32(wrap_y / view->font_height); - f32 max_width = view_file_width(view); - - Editing_File *file = view->file_data.file; - Assert(!file->is_dummy); - f32 width = file->state.buffer.line_widths[last_line]; - i32 line_span = view_wrapped_line_span(width, max_width); - lowest_line += line_span - 1; - } - } - return lowest_line; -} - -internal void -view_measure_wraps(General_Memory *general, View *view){ - Buffer_Type *buffer; - - buffer = &view->file_data.file->state.buffer; - i32 line_count = buffer->line_count; - - if (view->file_data.line_max < line_count){ - i32 max = view->file_data.line_max = LargeRoundUp(line_count, Kbytes(1)); - if (view->file_data.line_wrap_y){ - view->file_data.line_wrap_y = (f32*) - general_memory_reallocate_nocopy(general, view->file_data.line_wrap_y, sizeof(f32)*max, BUBBLE_WRAPS); - } - else{ - view->file_data.line_wrap_y = (f32*) - general_memory_allocate(general, sizeof(f32)*max, BUBBLE_WRAPS); - } - } - - f32 line_height = (f32)view->font_height; - f32 max_width = view_file_width(view); - buffer_measure_wrap_y(buffer, view->file_data.line_wrap_y, line_height, max_width); - - view->file_data.line_count = line_count; -} - -internal void -file_create_from_string(System_Functions *system, Models *models, - Editing_File *file, char *filename, String val, b8 read_only = 0){ - - Font_Set *font_set = models->font_set; - Working_Set *working_set = &models->working_set; - General_Memory *general = &models->mem.general; - Partition *part = &models->mem.part; - Buffer_Init_Type init; - i32 page_size, scratch_size, init_success; - - file->state = editing_file_state_zero(); - - init = buffer_begin_init(&file->state.buffer, val.str, val.size); - for (; buffer_init_need_more(&init); ){ - page_size = buffer_init_page_size(&init); - page_size = LargeRoundUp(page_size, Kbytes(4)); - if (page_size < Kbytes(4)) page_size = Kbytes(4); - void *data = general_memory_allocate(general, page_size, BUBBLE_BUFFER); - buffer_init_provide_page(&init, data, page_size); - } - - scratch_size = partition_remaining(part); - Assert(scratch_size > 0); - init_success = buffer_end_init(&init, part->base + part->pos, scratch_size); - AllowLocal(init_success); - Assert(init_success); - - if (buffer_size(&file->state.buffer) < val.size){ - file->settings.dos_write_mode = 1; - } - - file_init_strings(file); - file_set_name(working_set, file, (char*)filename); - - file->state.font_id = models->global_font.font_id; - - file_synchronize_times(system, file, filename); - - Render_Font *font = get_font_info(font_set, file->state.font_id)->font; - float *advance_data = 0; - if (font) advance_data = font->advance_data; - file_measure_starts_widths(system, general, &file->state.buffer, advance_data); - - file->settings.read_only = read_only; - if (!read_only){ - // TODO(allen): Redo undo system (if you don't mind the pun) - i32 request_size = Kbytes(64); - file->state.undo.undo.max = request_size; - file->state.undo.undo.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); - file->state.undo.undo.edit_max = request_size / sizeof(Edit_Step); - file->state.undo.undo.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO); - - file->state.undo.redo.max = request_size; - file->state.undo.redo.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); - file->state.undo.redo.edit_max = request_size / sizeof(Edit_Step); - file->state.undo.redo.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO); - - file->state.undo.history.max = request_size; - file->state.undo.history.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); - file->state.undo.history.edit_max = request_size / sizeof(Edit_Step); - file->state.undo.history.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO); - - file->state.undo.children.max = request_size; - file->state.undo.children.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); - file->state.undo.children.edit_max = request_size / sizeof(Buffer_Edit); - file->state.undo.children.edits = (Buffer_Edit*)general_memory_allocate(general, request_size, BUBBLE_UNDO); - - file->state.undo.history_block_count = 1; - file->state.undo.history_head_block = 0; - file->state.undo.current_block_normal = 1; - } - - Hook_Function *open_hook = models->hooks[hook_open_file]; - models->buffer_param_indices[models->buffer_param_count++] = file->id.id; - open_hook(&models->app_links); - models->buffer_param_count = 0; - file->settings.is_initialized = 1; -} - -internal b32 -file_create_empty(System_Functions *system, - Models *models, Editing_File *file, char *filename){ - file_create_from_string(system, models, file, filename, string_zero()); - return (1); -} - -internal b32 -file_create_read_only(System_Functions *system, - Models *models, Editing_File *file, char *filename){ - file_create_from_string(system, models, file, filename, string_zero(), 1); - return (1); -} - -internal void -file_close(System_Functions *system, General_Memory *general, Editing_File *file){ - if (file->state.still_lexing){ - system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); - if (file->state.swap_stack.tokens){ - general_memory_free(general, file->state.swap_stack.tokens); - file->state.swap_stack.tokens = 0; - } - } - if (file->state.token_stack.tokens){ - general_memory_free(general, file->state.token_stack.tokens); - } - - Buffer_Type *buffer = &file->state.buffer; - if (buffer->data){ - general_memory_free(general, buffer->data); - general_memory_free(general, buffer->line_starts); - general_memory_free(general, buffer->line_widths); - } - - if (file->state.undo.undo.edits){ - general_memory_free(general, file->state.undo.undo.strings); - general_memory_free(general, file->state.undo.undo.edits); - - general_memory_free(general, file->state.undo.redo.strings); - general_memory_free(general, file->state.undo.redo.edits); - - general_memory_free(general, file->state.undo.history.strings); - general_memory_free(general, file->state.undo.history.edits); - - general_memory_free(general, file->state.undo.children.strings); - general_memory_free(general, file->state.undo.children.edits); - } -} - -struct Shift_Information{ - i32 start, end, amount; -}; - -internal -Job_Callback_Sig(job_full_lex){ - Editing_File *file = (Editing_File*)data[0]; - General_Memory *general = (General_Memory*)data[1]; - - Cpp_File cpp_file; - cpp_file.data = file->state.buffer.data; - cpp_file.size = file->state.buffer.size; - - Cpp_Token_Stack tokens; - tokens.tokens = (Cpp_Token*)memory->data; - tokens.max_count = memory->size / sizeof(Cpp_Token); - tokens.count = 0; - - Cpp_Lex_Data status = cpp_lex_file_nonalloc(cpp_file, &tokens); - - while (!status.complete){ - system->grow_thread_memory(memory); - tokens.tokens = (Cpp_Token*)memory->data; - tokens.max_count = memory->size / sizeof(Cpp_Token); - status = cpp_lex_file_nonalloc(cpp_file, &tokens, status); - } - - i32 new_max = LargeRoundUp(tokens.count+1, Kbytes(1)); - - system->acquire_lock(FRAME_LOCK); - { - Assert(file->state.swap_stack.tokens == 0); - file->state.swap_stack.tokens = (Cpp_Token*) - general_memory_allocate(general, new_max*sizeof(Cpp_Token), BUBBLE_TOKENS); - } - system->release_lock(FRAME_LOCK); - - u8 *dest = (u8*)file->state.swap_stack.tokens; - u8 *src = (u8*)tokens.tokens; - - memcpy(dest, src, tokens.count*sizeof(Cpp_Token)); - - system->acquire_lock(FRAME_LOCK); - { - file->state.token_stack.count = tokens.count; - file->state.token_stack.max_count = new_max; - if (file->state.token_stack.tokens) - general_memory_free(general, file->state.token_stack.tokens); - file->state.token_stack.tokens = file->state.swap_stack.tokens; - file->state.swap_stack.tokens = 0; - } - system->release_lock(FRAME_LOCK); - - // NOTE(allen): These are outside the locked section because I don't - // think getting these out of order will cause critical bugs, and I - // want to minimize what's done in locked sections. - file->state.tokens_complete = 1; - file->state.still_lexing = 0; -} - - -internal void -file_kill_tokens(System_Functions *system, - General_Memory *general, Editing_File *file){ - file->settings.tokens_exist = 0; - if (file->state.still_lexing){ - system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); - if (file->state.swap_stack.tokens){ - general_memory_free(general, file->state.swap_stack.tokens); - file->state.swap_stack.tokens = 0; - } - } - if (file->state.token_stack.tokens){ - general_memory_free(general, file->state.token_stack.tokens); - } - file->state.tokens_complete = 0; - file->state.token_stack = cpp_token_stack_zero(); -} - -#if BUFFER_EXPERIMENT_SCALPEL <= 0 -internal void -file_first_lex_parallel(System_Functions *system, - General_Memory *general, Editing_File *file){ - file->settings.tokens_exist = 1; - - if (file->is_loading == 0 && file->state.still_lexing == 0){ - Assert(file->state.token_stack.tokens == 0); - - file->state.tokens_complete = 0; - file->state.still_lexing = 1; - - Job_Data job; - job.callback = job_full_lex; - job.data[0] = file; - job.data[1] = general; - job.memory_request = Kbytes(64); - file->state.lex_job = system->post_job(BACKGROUND_THREADS, job); - } -} -#endif - -internal void -file_relex_parallel(System_Functions *system, - Mem_Options *mem, Editing_File *file, - i32 start_i, i32 end_i, i32 amount){ - General_Memory *general = &mem->general; - Partition *part = &mem->part; - if (file->state.token_stack.tokens == 0){ - file_first_lex_parallel(system, general, file); - return; - } - - b32 inline_lex = !file->state.still_lexing; - if (inline_lex){ - Cpp_File cpp_file; - cpp_file.data = file->state.buffer.data; - cpp_file.size = file->state.buffer.size; - - Cpp_Token_Stack *stack = &file->state.token_stack; - - Cpp_Relex_State state = - cpp_relex_nonalloc_start(cpp_file, stack, - start_i, end_i, amount, 100); - - Temp_Memory temp = begin_temp_memory(part); - i32 relex_end; - Cpp_Token_Stack relex_space; - relex_space.count = 0; - relex_space.max_count = state.space_request; - relex_space.tokens = push_array(part, Cpp_Token, relex_space.max_count); - if (cpp_relex_nonalloc_main(&state, &relex_space, &relex_end)){ - inline_lex = 0; - } - else{ - i32 delete_amount = relex_end - state.start_token_i; - i32 shift_amount = relex_space.count - delete_amount; - - if (shift_amount != 0){ - int new_count = stack->count + shift_amount; - if (new_count > stack->max_count){ - int new_max = LargeRoundUp(new_count, Kbytes(1)); - stack->tokens = (Cpp_Token*) - general_memory_reallocate(general, stack->tokens, - stack->count*sizeof(Cpp_Token), - new_max*sizeof(Cpp_Token), BUBBLE_TOKENS); - stack->max_count = new_max; - } - - int shift_size = stack->count - relex_end; - if (shift_size > 0){ - Cpp_Token *old_base = stack->tokens + relex_end; - memmove(old_base + shift_amount, old_base, - sizeof(Cpp_Token)*shift_size); - } - - stack->count += shift_amount; - } - - memcpy(state.stack->tokens + state.start_token_i, relex_space.tokens, - sizeof(Cpp_Token)*relex_space.count); - } - - end_temp_memory(temp); - } - - if (!inline_lex){ - Cpp_Token_Stack *stack = &file->state.token_stack; - Cpp_Get_Token_Result get_token_result = cpp_get_token(stack, end_i); - i32 end_token_i = get_token_result.token_index; - - if (end_token_i < 0) end_token_i = 0; - else if (end_i > stack->tokens[end_token_i].start) ++end_token_i; - - cpp_shift_token_starts(stack, end_token_i, amount); - --end_token_i; - if (end_token_i >= 0){ - Cpp_Token *token = stack->tokens + end_token_i; - if (token->start < end_i && token->start + token->size > end_i){ - token->size += amount; - } - } - - file->state.still_lexing = 1; - - Job_Data job; - job.callback = job_full_lex; - job.data[0] = file; - job.data[1] = general; - job.memory_request = Kbytes(64); - file->state.lex_job = system->post_job(BACKGROUND_THREADS, job); - } -} - -internal void -undo_stack_grow_string(General_Memory *general, 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 = (u8*) - general_memory_reallocate(general, old_str, old_max, new_max); - stack->strings = new_str; - stack->max = new_max; -} - -internal void -undo_stack_grow_edits(General_Memory *general, 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 = (Edit_Step*) - general_memory_reallocate(general, old_eds, old_max*sizeof(Edit_Step), new_max*sizeof(Edit_Step)); - stack->edits = new_eds; - stack->edit_max = new_max; -} - -internal void -child_stack_grow_string(General_Memory *general, 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 = (u8*) - general_memory_reallocate(general, old_str, old_max, new_max); - stack->strings = new_str; - stack->max = new_max; -} - -internal void -child_stack_grow_edits(General_Memory *general, 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 = (Buffer_Edit*) - general_memory_reallocate(general, old_eds, old_max*sizeof(Buffer_Edit), new_max*sizeof(Buffer_Edit)); - stack->edits = new_eds; - stack->edit_max = new_max; -} - -internal i32 -undo_children_push(General_Memory *general, 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(general, children, edit_count); - - if (children->size + string_size > children->max) - child_stack_grow_string(general, 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; -} - -struct Edit_Spec{ - u8 *str; - Edit_Step step; -}; - -internal Edit_Step* -file_post_undo(General_Memory *general, 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(general, 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.pre_pos = step.pre_pos; - inv_step.post_pos = step.post_pos; - 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; - inv_step.pre_pos = prev.pre_pos; - } - } - } - - 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(general, 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(general, undo); - result = undo->edits + (undo->edit_count++); - *result = inv_step; - } - return result; -} - -inline 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(General_Memory *general, 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(general, 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.pre_pos = step.pre_pos; - inv_step.post_pos = step.post_pos; - inv_step.type = ED_REDO; - - if (redo->edit_count == redo->edit_max) - undo_stack_grow_edits(general, 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(general, redo); - } - redo->edits[redo->edit_count++] = inv_step; - } -} - -inline 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; -} - -inline 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(General_Memory *general, Editing_File *file, - Edit_Step step, b32 do_merge, b32 can_merge){ - Edit_Stack *history = &file->state.undo.history; - Edit_Step *result = 0; - - 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(general, 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.pre_pos = step.pre_pos; - inv_step.post_pos = step.post_pos; - inv_step.can_merge = (b8)can_merge; - inv_step.type = reverse_types[step.type]; - - bool32 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; - inv_step.pre_pos = prev.pre_pos; - } - } - } - - if (did_merge){ - result = history->edits + (history->edit_count-1); - } - else{ - if (history->edit_count == history->edit_max) - undo_stack_grow_edits(general, 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(general, history); - result = history->edits + (history->edit_count++); - *result = inv_step; - } - - return result; -} - -inline Full_Cursor -view_compute_cursor_from_pos(View *view, i32 pos){ - Editing_File *file = view->file_data.file; - Models *models = view->persistent.models; - Render_Font *font = get_font_info(models->font_set, models->global_font.font_id)->font; - - Full_Cursor result = {}; - if (font){ - f32 max_width = view_file_width(view); - result = buffer_cursor_from_pos(&file->state.buffer, pos, view->file_data.line_wrap_y, - max_width, (f32)view->font_height, font->advance_data); - } - return result; -} - -inline Full_Cursor -view_compute_cursor_from_unwrapped_xy(View *view, f32 seek_x, f32 seek_y, b32 round_down = 0){ - Editing_File *file = view->file_data.file; - Models *models = view->persistent.models; - Render_Font *font = get_font_info(models->font_set, models->global_font.font_id)->font; - - Full_Cursor result = {}; - if (font){ - f32 max_width = view_file_width(view); - result = buffer_cursor_from_unwrapped_xy(&file->state.buffer, seek_x, seek_y, - round_down, view->file_data.line_wrap_y, max_width, (f32)view->font_height, font->advance_data); - } - - return result; -} - -internal Full_Cursor -view_compute_cursor_from_wrapped_xy(View *view, f32 seek_x, f32 seek_y, b32 round_down = 0){ - Editing_File *file = view->file_data.file; - Models *models = view->persistent.models; - Render_Font *font = get_font_info(models->font_set, models->global_font.font_id)->font; - - Full_Cursor result = {}; - if (font){ - f32 max_width = view_file_width(view); - result = buffer_cursor_from_wrapped_xy(&file->state.buffer, seek_x, seek_y, - round_down, view->file_data.line_wrap_y, - max_width, (f32)view->font_height, font->advance_data); - } - - return (result); -} - -internal Full_Cursor -view_compute_cursor_from_line_pos(View *view, i32 line, i32 pos){ - Editing_File *file = view->file_data.file; - Models *models = view->persistent.models; - Render_Font *font = get_font_info(models->font_set, models->global_font.font_id)->font; - - Full_Cursor result = {}; - if (font){ - f32 max_width = view_file_width(view); - result = buffer_cursor_from_line_character(&file->state.buffer, line, pos, - view->file_data.line_wrap_y, max_width, (f32)view->font_height, font->advance_data); - } - - return (result); -} - -inline Full_Cursor -view_compute_cursor(View *view, Buffer_Seek seek){ - Full_Cursor result = {}; - - switch(seek.type){ - case buffer_seek_pos: - result = view_compute_cursor_from_pos(view, seek.pos); - break; - - case buffer_seek_wrapped_xy: - result = view_compute_cursor_from_wrapped_xy(view, seek.x, seek.y); - break; - - case buffer_seek_unwrapped_xy: - result = view_compute_cursor_from_unwrapped_xy(view, seek.x, seek.y); - break; - - case buffer_seek_line_char: - result = view_compute_cursor_from_line_pos(view, seek.line, seek.character); - break; - } - - return (result); -} - -inline Full_Cursor -view_compute_cursor_from_xy(View *view, f32 seek_x, f32 seek_y){ - Full_Cursor result; - if (view->file_data.unwrapped_lines) result = view_compute_cursor_from_unwrapped_xy(view, seek_x, seek_y); - else result = view_compute_cursor_from_wrapped_xy(view, seek_x, seek_y); - return result; -} - -inline void -view_set_temp_highlight(View *view, i32 pos, i32 end_pos){ - view->file_data.temp_highlight = view_compute_cursor_from_pos(view, pos); - view->file_data.temp_highlight_end_pos = end_pos; - view->file_data.show_temp_highlight = 1; -} - -inline i32 -view_get_cursor_pos(View *view){ - i32 result; - if (view->file_data.show_temp_highlight){ - result = view->file_data.temp_highlight.pos; - } - else{ - result = view->recent->cursor.pos; - } - return result; -} - -inline f32 -view_get_cursor_x(View *view){ - f32 result; - Full_Cursor *cursor; - if (view->file_data.show_temp_highlight){ - cursor = &view->file_data.temp_highlight; - } - else{ - cursor = &view->recent->cursor; - } - if (view->file_data.unwrapped_lines){ - result = cursor->unwrapped_x; - } - else{ - result = cursor->wrapped_x; - } - return result; -} - -inline f32 -view_get_cursor_y(View *view){ - Full_Cursor *cursor; - f32 result; - - if (view->file_data.show_temp_highlight) cursor = &view->file_data.temp_highlight; - else cursor = &view->recent->cursor; - - if (view->file_data.unwrapped_lines) result = cursor->unwrapped_y; - else result = cursor->wrapped_y; - - return result; -} - -#define CursorMaxY_(m,h) ((m) - (h)*3) -#define CursorMinY_(m,h) (-(m) + (h)*2) - -#define CursorMaxY(m,h) (CursorMaxY_(m,h) > 0)?(CursorMaxY_(m,h)):(0) -#define CursorMinY(m,h) (CursorMinY_(m,h) > 0)?(CursorMinY_(m,h)):(0) - -internal void -view_move_cursor_to_view(View *view){ - f32 min_target_y = 0; - i32 line_height = view->font_height; - f32 old_cursor_y = view_get_cursor_y(view); - f32 cursor_y = old_cursor_y; - f32 target_y = view->recent->scroll.target_y; - f32 cursor_max_y = CursorMaxY(view_file_height(view), line_height); - f32 cursor_min_y = CursorMinY(min_target_y, line_height); - - if (cursor_y > target_y + cursor_max_y){ - cursor_y = target_y + cursor_max_y; - } - if (target_y != 0 && cursor_y < target_y + cursor_min_y){ - cursor_y = target_y + cursor_min_y; - } - - if (cursor_y != old_cursor_y){ - if (cursor_y > old_cursor_y){ - cursor_y += line_height; - } - else{ - cursor_y -= line_height; - } - view->recent->cursor = - view_compute_cursor_from_xy(view, view->recent->preferred_x, cursor_y); - } -} - -internal void -view_move_view_to_cursor(View *view, GUI_Scroll_Vars *scroll){ - f32 line_height = (f32)view->font_height; - f32 delta_y = 3.f*line_height; - - f32 max_visible_y = view_file_height(view); - f32 max_x = view_file_width(view); - - f32 cursor_y = view_get_cursor_y(view); - f32 cursor_x = view_get_cursor_x(view); - - GUI_Scroll_Vars scroll_vars = *scroll; - f32 target_y = scroll_vars.target_y; - f32 target_x = scroll_vars.target_x; - - f32 cursor_max_y = CursorMaxY(max_visible_y, line_height); - f32 cursor_min_y = CursorMinY(0, line_height); - - if (cursor_y > target_y + cursor_max_y){ - target_y = cursor_y - cursor_max_y + delta_y; - } - if (cursor_y < target_y + cursor_min_y){ - target_y = cursor_y - delta_y - cursor_min_y; - } - - target_y = clamp(0.f, target_y, scroll_vars.max_y); - - if (cursor_x < target_x){ - target_x = (f32)Max(0, cursor_x - max_x/2); - } - else if (cursor_x >= target_x + max_x){ - target_x = (f32)(cursor_x - max_x/2); - } - - if (target_x != scroll_vars.target_x || target_y != scroll_vars.target_y){ - scroll->target_x = target_x; - scroll->target_y = target_y; - } -} - -inline void -file_view_nullify_file(View *view){ - General_Memory *general = &view->persistent.models->mem.general; - if (view->file_data.line_wrap_y){ - general_memory_free(general, view->file_data.line_wrap_y); - } - view->file_data = file_viewing_data_zero(); -} - -internal void -view_set_file(View *view, Editing_File *file, Models *models){ - Font_Info *fnt_info; - - // TODO(allen): This belongs somewhere else. - fnt_info = get_font_info(models->font_set, models->global_font.font_id); - view->font_advance = fnt_info->advance; - view->font_height = fnt_info->height; - - file_view_nullify_file(view); - view->file_data.file = file; - - if (file){ - u64 unique_buffer_id = file->unique_buffer_id; - Recent_File_Data *recent = view->recent; - Recent_File_Data temp_recent = {0}; - i32 i = 0; - i32 max = ArrayCount(view->recent)-1; - b32 found_recent_entry = 0; - - view->file_data.unwrapped_lines = file->settings.unwrapped_lines; - - for (; i < max; ++i, ++recent){ - if (recent->unique_buffer_id == unique_buffer_id){ - temp_recent = *recent; - memmove(view->recent+1, view->recent, sizeof(*recent)*i); - view->recent[0] = temp_recent; - found_recent_entry = 1; - break; - } - } - - if (found_recent_entry){ - if (file_is_ready(file)){ - view_measure_wraps(&models->mem.general, view); - view->recent->cursor = view_compute_cursor_from_pos(view, view->recent->cursor.pos); - -#if 0 - view->recent->scroll.max_y = 1000000000.f; -#endif - - view_move_view_to_cursor(view, &view->recent->scroll); - } - } - else{ - i = 15; - recent = view->recent + i; - memmove(view->recent+1, view->recent, sizeof(*recent)*i); - view->recent[0] = recent_file_data_zero(); - - recent = view->recent; - recent->unique_buffer_id = unique_buffer_id; - - if (file_is_ready(file)){ - view_measure_wraps(&models->mem.general, view); - view->recent->cursor = view_compute_cursor_from_pos(view, file->state.cursor_pos); - -#if 0 - view->recent->scroll.max_y = 1000000000.f; -#endif - - view_move_view_to_cursor(view, &view->recent->scroll); - view->reinit_scrolling = 1; - } - } - } -} - -struct Relative_Scrolling{ - f32 scroll_x, scroll_y; - f32 target_x, target_y; -}; - -internal Relative_Scrolling -view_get_relative_scrolling(View *view){ - Relative_Scrolling result; - f32 cursor_y; - cursor_y = view_get_cursor_y(view); - result.scroll_y = cursor_y - view->recent->scroll.scroll_y; - result.target_y = cursor_y - view->recent->scroll.target_y; - return(result); -} - -internal void -view_set_relative_scrolling(View *view, Relative_Scrolling scrolling){ - f32 cursor_y; - cursor_y = view_get_cursor_y(view); - view->recent->scroll.scroll_y = cursor_y - scrolling.scroll_y; - view->recent->scroll.target_y = - clamp_bottom(0.f, cursor_y - scrolling.target_y); -} - -inline void -view_cursor_move(View *view, Full_Cursor cursor){ - view->recent->cursor = cursor; - view->recent->preferred_x = view_get_cursor_x(view); - view->file_data.file->state.cursor_pos = view->recent->cursor.pos; - view->file_data.show_temp_highlight = 0; -} - -inline void -view_cursor_move(View *view, i32 pos){ - Full_Cursor cursor = view_compute_cursor_from_pos(view, pos); - view_cursor_move(view, cursor); -} - -inline void -view_cursor_move(View *view, f32 x, f32 y, b32 round_down = 0){ - Full_Cursor cursor; - if (view->file_data.unwrapped_lines){ - cursor = view_compute_cursor_from_unwrapped_xy(view, x, y, round_down); - } - else{ - cursor = view_compute_cursor_from_wrapped_xy(view, x, y, round_down); - } - view_cursor_move(view, cursor); -} - -inline void -view_cursor_move(View *view, i32 line, i32 pos){ - Full_Cursor cursor = view_compute_cursor_from_line_pos(view, line, pos); - view_cursor_move(view, cursor); -} - -inline void -view_set_widget(View *view, View_Widget_Type type){ - view->widget.type = type; -} - - -inline i32_Rect -view_widget_rect(View *view, i32 font_height){ - Panel *panel = view->panel; - i32_Rect result = panel->inner; - - if (view->file_data.file){ - result.y0 = result.y0 + font_height + 2; - } - - return(result); -} - -enum History_Mode{ - hist_normal, - hist_backward, - hist_forward -}; - -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; - General_Memory *general = &mem->general; - - 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(general, file, step, do_merge, can_merge); - - file_post_undo(general, file, step, do_merge, can_merge); - }break; - - case ED_REVERSE_NORMAL: - { - if (history_mode != hist_forward) - file_post_history(general, 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(general, &file->state.undo.redo); - - if (file->state.undo.redo.size + strings_of_redo > file->state.undo.redo.max) - undo_stack_grow_string(general, &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(general, file, step, do_merge, can_merge); - file_post_redo(general, 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(general, file, step, do_merge, can_merge); - - file_post_undo(general, 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; - } -} - -inline void -file_pre_edit_maintenance(System_Functions *system, - General_Memory *general, - Editing_File *file){ - if (file->state.still_lexing){ - system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); - if (file->state.swap_stack.tokens){ - general_memory_free(general, file->state.swap_stack.tokens); - file->state.swap_stack.tokens = 0; - } - file->state.still_lexing = 0; - } - file->state.last_4ed_edit_time = system->now_time_stamp(); -} - -struct Cursor_Fix_Descriptor{ - b32 is_batch; - union{ - struct{ - Buffer_Edit *batch; - i32 batch_size; - }; - struct{ - i32 start, end; - i32 shift_amount; - }; - }; -}; - -internal void -file_edit_cursor_fix(System_Functions *system, - Partition *part, General_Memory *general, - Editing_File *file, Editing_Layout *layout, - Cursor_Fix_Descriptor desc){ - - Full_Cursor temp_cursor; - Temp_Memory cursor_temp = begin_temp_memory(part); - i32 cursor_max = layout->panel_max_count * 2; - Cursor_With_Index *cursors = push_array(part, Cursor_With_Index, cursor_max); - - f32 y_offset = 0, y_position = 0; - i32 cursor_count = 0; - - View *view; - Panel *panel, *used_panels; - used_panels = &layout->used_sentinel; - - for (dll_items(panel, used_panels)){ - view = panel->view; - if (view->file_data.file == file){ - view_measure_wraps(general, view); - write_cursor_with_index(cursors, &cursor_count, view->recent->cursor.pos); - write_cursor_with_index(cursors, &cursor_count, view->recent->mark - 1); - write_cursor_with_index(cursors, &cursor_count, view->recent->scroll_i - 1); - } - } - - if (cursor_count > 0){ - buffer_sort_cursors(cursors, cursor_count); - if (desc.is_batch){ - buffer_batch_edit_update_cursors(cursors, cursor_count, - desc.batch, desc.batch_size); - } - else{ - buffer_update_cursors(cursors, cursor_count, - desc.start, desc.end, - desc.shift_amount + (desc.end - desc.start)); - } - buffer_unsort_cursors(cursors, cursor_count); - - cursor_count = 0; - for (dll_items(panel, used_panels)){ - view = panel->view; - if (view && view->file_data.file == file){ - view_cursor_move(view, cursors[cursor_count++].pos); - view->recent->preferred_x = view_get_cursor_x(view); - - view->recent->mark = cursors[cursor_count++].pos + 1; - i32 new_scroll_i = cursors[cursor_count++].pos + 1; - if (view->recent->scroll_i != new_scroll_i){ - view->recent->scroll_i = new_scroll_i; - temp_cursor = view_compute_cursor_from_pos(view, view->recent->scroll_i); - y_offset = MOD(view->recent->scroll.scroll_y, view->font_height); - - if (view->file_data.unwrapped_lines){ - y_position = temp_cursor.unwrapped_y + y_offset; - view->recent->scroll.target_y += (y_position - view->recent->scroll.scroll_y); - view->recent->scroll.scroll_y = y_position; - } - else{ - y_position = temp_cursor.wrapped_y + y_offset; - view->recent->scroll.target_y += (y_position - view->recent->scroll.scroll_y); - view->recent->scroll.scroll_y = y_position; - } - } - } - } - } - - end_temp_memory(cursor_temp); -} - -internal void -file_do_single_edit(System_Functions *system, - Models *models, Editing_File *file, - Edit_Spec spec, History_Mode history_mode, b32 use_high_permission = 0){ - if (!use_high_permission && file->settings.read_only) return; - - Mem_Options *mem = &models->mem; - Editing_Layout *layout = &models->layout; - - // NOTE(allen): fixing stuff beforewards???? - file_update_history_before_edit(mem, file, spec.step, spec.str, history_mode); - file_pre_edit_maintenance(system, &mem->general, file); - - // NOTE(allen): actual text replacement - i32 shift_amount = 0; - General_Memory *general = &mem->general; - Partition *part = &mem->part; - - 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 scratch_size = partition_remaining(part); - - Assert(scratch_size > 0); - i32 request_amount = 0; - Assert(end <= buffer_size(&file->state.buffer)); - while (buffer_replace_range(&file->state.buffer, start, end, str, str_len, &shift_amount, - part->base + part->pos, scratch_size, &request_amount)){ - void *new_data = 0; - if (request_amount > 0){ - new_data = general_memory_allocate(general, request_amount, BUBBLE_BUFFER); - } - void *old_data = buffer_edit_provide_memory(&file->state.buffer, new_data, request_amount); - if (old_data) general_memory_free(general, old_data); - } - - Buffer_Type *buffer = &file->state.buffer; - i32 line_start = buffer_get_line_index(&file->state.buffer, start); - i32 line_end = buffer_get_line_index(&file->state.buffer, end); - i32 replaced_line_count = line_end - line_start; - i32 new_line_count = buffer_count_newlines(&file->state.buffer, start, start+str_len); - i32 line_shift = new_line_count - replaced_line_count; - - Render_Font *font = get_font_info(models->font_set, file->state.font_id)->font; - - file_grow_starts_widths_as_needed(general, buffer, line_shift); - buffer_remeasure_starts(buffer, line_start, line_end, line_shift, shift_amount); - buffer_remeasure_widths(buffer, font->advance_data, line_start, line_end, line_shift); - - // NOTE(allen): update the views looking at this file - Panel *panel, *used_panels; - used_panels = &layout->used_sentinel; - - for (dll_items(panel, used_panels)){ - View *view = panel->view; - if (view->file_data.file == file){ - view_measure_wraps(general, view); - } - } - -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - // NOTE(allen): fixing stuff afterwards - if (file->settings.tokens_exist) - file_relex_parallel(system, mem, file, start, end, shift_amount); -#endif - - Cursor_Fix_Descriptor desc = {}; - desc.start = start; - desc.end = end; - desc.shift_amount = shift_amount; - - file_edit_cursor_fix(system, part, general, file, layout, desc); -} - -internal void -file_do_white_batch_edit(System_Functions *system, Models *models, Editing_File *file, - Edit_Spec spec, History_Mode history_mode, b32 use_high_permission = 0){ - if (!use_high_permission && file->settings.read_only) return; - - Mem_Options *mem = &models->mem; - Editing_Layout *layout = &models->layout; - - // NOTE(allen): fixing stuff "beforewards"??? - Assert(spec.str == 0); - file_update_history_before_edit(mem, file, spec.step, 0, history_mode); - file_pre_edit_maintenance(system, &mem->general, file); - - // NOTE(allen): actual text replacement - General_Memory *general = &mem->general; - Partition *part = &mem->part; - - 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); - - i32 scratch_size = partition_remaining(part); - Buffer_Batch_State state = {}; - i32 request_amount; - while (buffer_batch_edit_step(&state, &file->state.buffer, batch, - (char*)str_base, batch_size, part->base + part->pos, - scratch_size, &request_amount)){ - void *new_data = 0; - if (request_amount > 0){ - new_data = general_memory_allocate(general, request_amount, BUBBLE_BUFFER); - } - void *old_data = buffer_edit_provide_memory(&file->state.buffer, new_data, request_amount); - if (old_data) general_memory_free(general, old_data); - } - - // NOTE(allen): meta data - { - Buffer_Measure_Starts state = {}; - Render_Font *font = get_font_info(models->font_set, file->state.font_id)->font; - float *advance_data = 0; - if (font) advance_data = font->advance_data; - buffer_measure_starts_widths(&state, &file->state.buffer, advance_data); - } - - // NOTE(allen): cursor fixing - { - Cursor_Fix_Descriptor desc = {}; - desc.is_batch = 1; - desc.batch = batch; - desc.batch_size = batch_size; - - file_edit_cursor_fix(system, part, general, file, layout, desc); - } - - // NOTE(allen): token fixing - if (file->state.tokens_complete){ - Cpp_Token_Stack tokens = file->state.token_stack; - Cpp_Token *token = tokens.tokens; - Cpp_Token *end_token = tokens.tokens + tokens.count; - Cpp_Token original = {(Cpp_Token_Type)0}; - - Buffer_Edit *edit = batch; - Buffer_Edit *end_edit = batch + batch_size; - - 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)); - 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)); - } - token->size += local_shift; - shift_amount += local_shift; - } - } -} - -inline void -file_replace_range(System_Functions *system, Models *models, Editing_File *file, - i32 start, i32 end, char *str, i32 len, i32 next_cursor, b32 use_high_permission = 0){ - Edit_Spec spec = {}; - spec.step.type = ED_NORMAL; - spec.step.edit.start = start; - spec.step.edit.end = end; - - spec.step.edit.len = len; - spec.step.pre_pos = file->state.cursor_pos; - spec.step.post_pos = next_cursor; - spec.str = (u8*)str; - file_do_single_edit(system, models, file, spec, hist_normal, use_high_permission); -} - -inline void -file_clear(System_Functions *system, Models *models, Editing_File *file, b32 use_high_permission = 0){ - file_replace_range(system, models, file, 0, buffer_size(&file->state.buffer), 0, 0, 0, use_high_permission); -} - -inline void -view_replace_range(System_Functions *system, Models *models, View *view, - i32 start, i32 end, char *str, i32 len, i32 next_cursor){ - file_replace_range(system, models, view->file_data.file, start, end, str, len, next_cursor); -} - -inline void -view_post_paste_effect(View *view, i32 ticks, i32 start, i32 size, u32 color){ - Editing_File *file = view->file_data.file; - - file->state.paste_effect.start = start; - file->state.paste_effect.end = start + size; - file->state.paste_effect.color = color; - file->state.paste_effect.tick_down = ticks; - file->state.paste_effect.tick_max = ticks; -} - -internal Style* -get_style(Models *models, i32 i){ - return (&models->styles.styles[i]); -} - -internal Style* -main_style(Models *models){ - return (get_style(models, 0)); -} - -internal void -view_undo_redo(System_Functions *system, - Models *models, View *view, - Edit_Stack *stack, Edit_Type expected_type){ - Editing_File *file = view->file_data.file; - - if (stack->edit_count > 0){ - Edit_Step step = stack->edits[stack->edit_count-1]; - - Assert(step.type == expected_type); - - Edit_Spec spec = {}; - spec.step = step; - - if (step.child_count == 0){ - spec.step.edit.str_start = 0; - spec.str = stack->strings + step.edit.str_start; - - file_do_single_edit(system, models, file, spec, hist_normal); - - if (expected_type == ED_UNDO) view_cursor_move(view, step.pre_pos); - else view_cursor_move(view, step.post_pos); - view->recent->mark = view->recent->cursor.pos; - - Style *style = main_style(models); - view_post_paste_effect(view, 10, step.edit.start, step.edit.len, - style->main.undo_color); - } - else{ - TentativeAssert(spec.step.special_type == 1); - file_do_white_batch_edit(system, models, view->file_data.file, spec, hist_normal); - } - } -} - -inline void -view_undo(System_Functions *system, Models *models, View *view){ - view_undo_redo(system, models, view, &view->file_data.file->state.undo.undo, ED_UNDO); -} - -inline void -view_redo(System_Functions *system, Models *models, View *view){ - view_undo_redo(system, models, view, &view->file_data.file->state.undo.redo, ED_REDO); -} - -inline u8* -write_data(u8 *ptr, void *x, i32 size){ - memcpy(ptr, x, size); - return (ptr + size); -} - -#define UseFileHistoryDump 0 - -#if UseFileHistoryDump -internal void -file_dump_history(System_Functions *system, Mem_Options *mem, Editing_File *file, char *filename){ - if (!file->state.undo.undo.edits) return; - - i32 size = 0; - - size += sizeof(i32); - size += file->state.undo.undo.edit_count*sizeof(Edit_Step); - size += sizeof(i32); - size += file->state.undo.redo.edit_count*sizeof(Edit_Step); - size += sizeof(i32); - size += file->state.undo.history.edit_count*sizeof(Edit_Step); - size += sizeof(i32); - size += file->state.undo.children.edit_count*sizeof(Buffer_Edit); - - size += sizeof(i32); - size += file->state.undo.undo.size; - size += sizeof(i32); - size += file->state.undo.redo.size; - size += sizeof(i32); - size += file->state.undo.history.size; - size += sizeof(i32); - size += file->state.undo.children.size; - - Partition *part = &mem->part; - i32 remaining = partition_remaining(part); - if (size < remaining){ - u8 *data, *curs; - data = (u8*)part->base + part->pos; - curs = data; - curs = write_data(curs, &file->state.undo.undo.edit_count, 4); - curs = write_data(curs, &file->state.undo.redo.edit_count, 4); - curs = write_data(curs, &file->state.undo.history.edit_count, 4); - curs = write_data(curs, &file->state.undo.children.edit_count, 4); - curs = write_data(curs, &file->state.undo.undo.size, 4); - curs = write_data(curs, &file->state.undo.redo.size, 4); - curs = write_data(curs, &file->state.undo.history.size, 4); - curs = write_data(curs, &file->state.undo.children.size, 4); - - curs = write_data(curs, file->state.undo.undo.edits, sizeof(Edit_Step)*file->state.undo.undo.edit_count); - curs = write_data(curs, file->state.undo.redo.edits, sizeof(Edit_Step)*file->state.undo.redo.edit_count); - curs = write_data(curs, file->state.undo.history.edits, sizeof(Edit_Step)*file->state.undo.history.edit_count); - curs = write_data(curs, file->state.undo.children.edits, sizeof(Buffer_Edit)*file->state.undo.children.edit_count); - - curs = write_data(curs, file->state.undo.undo.strings, file->state.undo.undo.size); - curs = write_data(curs, file->state.undo.redo.strings, file->state.undo.redo.size); - curs = write_data(curs, file->state.undo.history.strings, file->state.undo.history.size); - curs = write_data(curs, file->state.undo.children.strings, file->state.undo.children.size); - - Assert((i32)(curs - data) == size); - system->save_file(filename, data, size); - } -} -#endif - -internal void -view_history_step(System_Functions *system, Models *models, View *view, History_Mode history_mode){ - Assert(history_mode != hist_normal); - - Editing_File *file = view->file_data.file; - - b32 do_history_step = 0; - Edit_Step step = {}; - if (history_mode == hist_backward){ - if (file->state.undo.edit_history_cursor > 0){ - do_history_step = 1; - step = file->state.undo.history.edits[--file->state.undo.edit_history_cursor]; - } - } - else{ - if (file->state.undo.edit_history_cursor < file->state.undo.history.edit_count){ - Assert(((file->state.undo.history.edit_count - file->state.undo.edit_history_cursor) & 1) == 0); - step = file->state.undo.history.edits[--file->state.undo.history.edit_count]; - file->state.undo.history.size -= step.edit.len; - ++file->state.undo.edit_history_cursor; - do_history_step = 1; - } - } - - if (do_history_step){ - Edit_Spec spec; - spec.step = step; - - if (spec.step.child_count == 0){ - spec.step.edit.str_start = 0; - spec.str = file->state.undo.history.strings + step.edit.str_start; - - file_do_single_edit(system, models, file, spec, history_mode); - - switch (spec.step.type){ - case ED_NORMAL: - case ED_REDO: - view_cursor_move(view, step.post_pos); - break; - - case ED_REVERSE_NORMAL: - case ED_UNDO: - view_cursor_move(view, step.pre_pos); - break; - } - view->recent->mark = view->recent->cursor.pos; - } - else{ - TentativeAssert(spec.step.special_type == 1); - file_do_white_batch_edit(system, models, view->file_data.file, spec, history_mode); - } - } -} - -// TODO(allen): write these as streamed operations -internal i32 -view_find_end_of_line(View *view, i32 pos){ -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - Editing_File *file = view->file_data.file; - char *data = file->state.buffer.data; - while (pos < file->state.buffer.size && data[pos] != '\n') ++pos; - if (pos > file->state.buffer.size) pos = file->state.buffer.size; -#endif - return pos; -} - -internal i32 -view_find_beginning_of_line(View *view, i32 pos){ -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - Editing_File *file = view->file_data.file; - char *data = file->state.buffer.data; - if (pos > 0){ - --pos; - while (pos > 0 && data[pos] != '\n') --pos; - if (pos != 0) ++pos; - } -#endif - return pos; -} - -internal i32 -view_find_beginning_of_next_line(View *view, i32 pos){ -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - Editing_File *file = view->file_data.file; - char *data = file->state.buffer.data; - while (pos < file->state.buffer.size && - !starts_new_line(data[pos])){ - ++pos; - } - if (pos < file->state.buffer.size){ - ++pos; - } -#endif - return pos; -} - -internal String* -working_set_next_clipboard_string(General_Memory *general, Working_Set *working, i32 str_size){ - String *result = 0; - i32 clipboard_current = working->clipboard_current; - if (working->clipboard_size == 0){ - clipboard_current = 0; - working->clipboard_size = 1; - } - else{ - ++clipboard_current; - if (clipboard_current >= working->clipboard_max_size){ - clipboard_current = 0; - } - else if (working->clipboard_size <= clipboard_current){ - working->clipboard_size = clipboard_current+1; - } - } - result = &working->clipboards[clipboard_current]; - working->clipboard_current = clipboard_current; - working->clipboard_rolling = clipboard_current; - char *new_str; - if (result->str){ - new_str = (char*)general_memory_reallocate(general, result->str, result->size, str_size); - } - else{ - new_str = (char*)general_memory_allocate(general, str_size+1); - } - // TODO(allen): What if new_str == 0? - *result = make_string(new_str, 0, str_size); - return result; -} - -internal String* -working_set_clipboard_head(Working_Set *working){ - String *result = 0; - if (working->clipboard_size > 0){ - i32 clipboard_index = working->clipboard_current; - working->clipboard_rolling = clipboard_index; - result = &working->clipboards[clipboard_index]; - } - return result; -} - -internal String* -working_set_clipboard_roll_down(Working_Set *working){ - String *result = 0; - if (working->clipboard_size > 0){ - i32 clipboard_index = working->clipboard_rolling; - --clipboard_index; - if (clipboard_index < 0){ - clipboard_index = working->clipboard_size-1; - } - working->clipboard_rolling = clipboard_index; - result = &working->clipboards[clipboard_index]; - } - return result; -} - -internal void -clipboard_copy(System_Functions *system, General_Memory *general, Working_Set *working, Range range, Editing_File *file){ - i32 size = range.end - range.start; - String *dest = working_set_next_clipboard_string(general, working, size); - buffer_stringify(&file->state.buffer, range.start, range.end, dest->str); - dest->size = size; - system->post_clipboard(*dest); -} - -internal Edit_Spec -file_compute_whitespace_edit(Mem_Options *mem, Editing_File *file, i32 cursor_pos, - Buffer_Edit *edits, char *str_base, i32 str_size, - Buffer_Edit *inverse_array, char *inv_str, i32 inv_max, - i32 edit_count){ - General_Memory *general = &mem->general; - - 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)){ - Assert(0); - } - - i32 first_child = - undo_children_push(general, &file->state.undo.children, - edits, edit_count, (u8*)(str_base), str_size); - i32 inverse_first_child = - undo_children_push(general, &file->state.undo.children, - inverse_array, edit_count, (u8*)(inv_str), inv_str_pos); - - Edit_Spec spec = {}; - spec.step.type = ED_NORMAL; - spec.step.first_child = first_child; - spec.step.inverse_first_child = inverse_first_child; - spec.step.special_type = 1; - spec.step.child_count = edit_count; - spec.step.inverse_child_count = edit_count; - spec.step.pre_pos = cursor_pos; - spec.step.post_pos = cursor_pos; - - return spec; -} - -internal void -view_clean_whitespace(System_Functions *system, Models *models, View *view){ - Mem_Options *mem = &models->mem; - Editing_File *file = view->file_data.file; - - Partition *part = &mem->part; - i32 line_count = file->state.buffer.line_count; - i32 edit_max = line_count * 2; - i32 edit_count = 0; - - Assert(file && !file->is_dummy); - - Temp_Memory temp = begin_temp_memory(part); - Buffer_Edit *edits = push_array(part, Buffer_Edit, edit_max); - - char *str_base = (char*)part->base + part->pos; - i32 str_size = 0; - for (i32 line_i = 0; line_i < line_count; ++line_i){ - i32 start = file->state.buffer.line_starts[line_i]; - Hard_Start_Result hard_start = - buffer_find_hard_start(&file->state.buffer, start, 4); - - if (hard_start.all_whitespace) hard_start.indent_pos = 0; - - if ((hard_start.all_whitespace && hard_start.char_pos > start) || !hard_start.all_space){ - Buffer_Edit new_edit; - new_edit.str_start = str_size; - str_size += hard_start.indent_pos; - char *str = push_array(part, char, hard_start.indent_pos); - for (i32 j = 0; j < hard_start.indent_pos; ++j) str[j] = ' '; - new_edit.len = hard_start.indent_pos; - new_edit.start = start; - new_edit.end = hard_start.char_pos; - edits[edit_count++] = new_edit; - } - Assert(edit_count <= edit_max); - } - - if (edit_count > 0){ - Assert(buffer_batch_debug_sort_check(edits, edit_count)); - - // NOTE(allen): computing edit spec, doing batch edit - Buffer_Edit *inverse_array = push_array(part, Buffer_Edit, edit_count); - Assert(inverse_array); - - char *inv_str = (char*)part->base + part->pos; - Edit_Spec spec = - file_compute_whitespace_edit(mem, file, view->recent->cursor.pos, edits, str_base, str_size, - inverse_array, inv_str, part->max - part->pos, edit_count); - - file_do_white_batch_edit(system, models, view->file_data.file, spec, hist_normal); - } - - end_temp_memory(temp); -} - -struct Indent_Options{ - b32 empty_blank_lines; - b32 use_tabs; - i32 tab_width; -}; - -struct Make_Batch_Result{ - char *str_base; - i32 str_size; - - Buffer_Edit *edits; - i32 edit_max; - i32 edit_count; -}; - -internal Cpp_Token* -get_first_token_at_line(Buffer *buffer, Cpp_Token_Stack tokens, i32 line){ - Cpp_Token *result = 0; - i32 start_pos = 0; - Cpp_Get_Token_Result get_token = {0}; - - start_pos = buffer->line_starts[line]; - get_token = cpp_get_token(&tokens, start_pos); - if (get_token.in_whitespace) get_token.token_index += 1; - result = tokens.tokens + get_token.token_index; - - return(result); -} - -internal Cpp_Token* -seek_matching_token_backwards(Cpp_Token_Stack tokens, Cpp_Token *token, - Cpp_Token_Type open_type, Cpp_Token_Type close_type){ - int nesting_level = 0; - if (token <= tokens.tokens){ - token = tokens.tokens; - } - else{ - for (; token > tokens.tokens; --token){ - if (!(token->flags & CPP_TFLAG_PP_BODY)){ - if (token->type == close_type){ - ++nesting_level; - } - else if (token->type == open_type){ - if (nesting_level == 0){ - break; - } - else{ - --nesting_level; - } - } - } - } - } - return(token); -} - -struct Indent_Parse_State{ - i32 current_indent; - i32 previous_line_indent; - i32 paren_nesting; - i32 paren_anchor_indent[16]; -}; - -internal i32 -compute_this_indent(Buffer *buffer, Indent_Parse_State indent, - Cpp_Token T, Cpp_Token prev_token, i32 line_i, i32 tab_width){ - - i32 previous_indent = indent.previous_line_indent; - i32 this_indent = 0; - - i32 this_line_start = buffer->line_starts[line_i]; - i32 next_line_start = 0; - - if (line_i+1 < buffer->line_count){ - next_line_start = buffer->line_starts[line_i+1]; - } - else{ - next_line_start = buffer_size(buffer); - } - - if ((prev_token.type == CPP_TOKEN_COMMENT || prev_token.type == CPP_TOKEN_STRING_CONSTANT) && - prev_token.start <= this_line_start && prev_token.start + prev_token.size > this_line_start){ - this_indent = previous_indent; - } - else{ - this_indent = indent.current_indent; - if (T.start < next_line_start){ - if (T.flags & CPP_TFLAG_PP_DIRECTIVE){ - this_indent = 0; - } - else{ - switch (T.type){ - case CPP_TOKEN_BRACKET_CLOSE: this_indent -= tab_width; break; - case CPP_TOKEN_BRACE_CLOSE: this_indent -= tab_width; break; - case CPP_TOKEN_BRACE_OPEN: break; - - default: - if (indent.current_indent > 0){ - if (!(prev_token.flags & CPP_TFLAG_PP_BODY || - prev_token.flags & CPP_TFLAG_PP_DIRECTIVE)){ - switch (prev_token.type){ - case CPP_TOKEN_BRACKET_OPEN: - case CPP_TOKEN_BRACE_OPEN: case CPP_TOKEN_BRACE_CLOSE: - case CPP_TOKEN_SEMICOLON: case CPP_TOKEN_COLON: - case CPP_TOKEN_COMMA: case CPP_TOKEN_COMMENT: break; - default: this_indent += tab_width; - } - } - } - } - } - } - if (this_indent < 0) this_indent = 0; - } - - if (indent.paren_nesting > 0){ - i32 level = indent.paren_nesting-1; - if (level >= ArrayCount(indent.paren_anchor_indent)){ - level = ArrayCount(indent.paren_anchor_indent)-1; - } - this_indent = indent.paren_anchor_indent[level]; - } - return(this_indent); -} - -internal i32* -get_line_indentation_marks(Partition *part, Buffer *buffer, Cpp_Token_Stack tokens, - i32 line_start, i32 line_end, i32 tab_width){ - - i32 indent_mark_count = line_end - line_start; - i32 *indent_marks = push_array(part, i32, indent_mark_count); - - Indent_Parse_State indent = {0}; - Cpp_Token *token = get_first_token_at_line(buffer, tokens, line_start); - - if (token != tokens.tokens){ - --token; - for (; token > tokens.tokens; --token){ - if (!(token->flags & CPP_TFLAG_PP_BODY)){ - switch(token->type){ - case CPP_TOKEN_BRACE_OPEN: - case CPP_TOKEN_BRACE_CLOSE: - goto out_of_loop; - } - } - } - out_of_loop:; - } - - // TODO(allen): This can maybe be it's own function now, so that we - // can do the decls in the order we want and avoid the extra binary search. - i32 found_safe_start_position = 0; - do{ - i32 line = buffer_get_line_index(buffer, token->start); - i32 start = buffer->line_starts[line]; - Hard_Start_Result hard_start = buffer_find_hard_start(buffer, start, tab_width); - - indent.current_indent = hard_start.indent_pos; - - Cpp_Token *start_token = get_first_token_at_line(buffer, tokens, line); - Cpp_Token *brace_token = token; - - if (start_token->type == CPP_TOKEN_PARENTHESE_OPEN){ - if (start_token == tokens.tokens){ - found_safe_start_position = 1; - } - else{ - token = start_token-1; - } - } - else{ - int close = 0; - - for (token = brace_token; token >= start_token; --token){ - switch(token->type){ - case CPP_TOKEN_PARENTHESE_CLOSE: - case CPP_TOKEN_BRACKET_CLOSE: - case CPP_TOKEN_BRACE_CLOSE: - close = token->type; - goto out_of_loop2; - } - } - out_of_loop2:; - - switch (close){ - case 0: token = start_token; found_safe_start_position = 1; break; - - case CPP_TOKEN_PARENTHESE_CLOSE: - token = seek_matching_token_backwards(tokens, token-1, - CPP_TOKEN_PARENTHESE_OPEN, - CPP_TOKEN_PARENTHESE_CLOSE); - break; - - case CPP_TOKEN_BRACKET_CLOSE: - token = seek_matching_token_backwards(tokens, token-1, - CPP_TOKEN_BRACKET_OPEN, - CPP_TOKEN_BRACKET_CLOSE); - break; - - case CPP_TOKEN_BRACE_CLOSE: - token = seek_matching_token_backwards(tokens, token-1, - CPP_TOKEN_BRACE_OPEN, - CPP_TOKEN_BRACE_CLOSE); - break; - } - } - } while(found_safe_start_position == 0); - - // NOTE(allen): Shift the array so that line_i can just operate in - // it's natural value range. - indent_marks -= line_start; - - i32 line_i = buffer_get_line_index(buffer, token->start); - - if (line_i > line_start){ - line_i = line_start; - } - - i32 next_line_start = buffer->line_starts[line_i+1]; - switch (token->type){ - case CPP_TOKEN_BRACKET_OPEN: indent.current_indent += tab_width; break; - case CPP_TOKEN_BRACE_OPEN: indent.current_indent += tab_width; break; - } - - indent.previous_line_indent = indent.current_indent; - Cpp_Token T; - Cpp_Token prev_token = *token; - ++token; - - for (; line_i < line_end; ++token){ - if (token < tokens.tokens + tokens.count){ - T = *token; - } - else{ - T.type = CPP_TOKEN_EOF; - T.start = buffer_size(buffer); - T.flags = 0; - } - - for (; T.start >= next_line_start && line_i < line_end;){ - if (line_i+1 < buffer->line_count){ - next_line_start = buffer->line_starts[line_i+1]; - } - else{ - next_line_start = buffer_size(buffer); - } - - // TODO(allen): Since this is called in one place we can probably go back - // to directly passing in next_line_start and this_line_start. - i32 this_indent = compute_this_indent(buffer, indent, T, prev_token, line_i, tab_width); - - if (line_i >= line_start){ - indent_marks[line_i] = this_indent; - } - ++line_i; - - indent.previous_line_indent = this_indent; - } - - switch (T.type){ - case CPP_TOKEN_BRACKET_OPEN: indent.current_indent += 4; break; - case CPP_TOKEN_BRACKET_CLOSE: indent.current_indent -= 4; break; - case CPP_TOKEN_BRACE_OPEN: indent.current_indent += 4; break; - case CPP_TOKEN_BRACE_CLOSE: indent.current_indent -= 4; break; - - case CPP_TOKEN_PARENTHESE_OPEN: - if (!(T.flags & CPP_TFLAG_PP_BODY)){ - if (indent.paren_nesting < ArrayCount(indent.paren_anchor_indent)){ - i32 line = buffer_get_line_index(buffer, T.start); - i32 start = buffer->line_starts[line]; - i32 char_pos = T.start - start; - - Hard_Start_Result hard_start = buffer_find_hard_start( - buffer, start, tab_width); - - i32 line_pos = hard_start.char_pos - start; - - indent.paren_anchor_indent[indent.paren_nesting] = - char_pos - line_pos + indent.previous_line_indent + 1; - } - ++indent.paren_nesting; - } - break; - - case CPP_TOKEN_PARENTHESE_CLOSE: - if (!(T.flags & CPP_TFLAG_PP_BODY)){ - --indent.paren_nesting; - } - break; - } - prev_token = T; - } - - // NOTE(allen): Unshift the indent_marks array so that the return value - // is the exact starting point of the array that was actually allocated. - indent_marks += line_start; - - return(indent_marks); -} - -internal Make_Batch_Result -make_batch_from_indent_marks(Partition *part, Buffer *buffer, i32 line_start, i32 line_end, - i32 *indent_marks, Indent_Options opts){ - - Make_Batch_Result result = {0}; - - i32 edit_max = line_end - line_start; - i32 edit_count = 0; - - Buffer_Edit *edits = push_array(part, Buffer_Edit, edit_max); - - char *str_base = (char*)part->base + part->pos; - i32 str_size = 0; - - // NOTE(allen): Shift the array so that line_i can just operate in - // it's natural value range. - indent_marks -= line_start; - - for (i32 line_i = line_start; line_i < line_end; ++line_i){ - i32 start = buffer->line_starts[line_i]; - Hard_Start_Result hard_start = - buffer_find_hard_start(buffer, start, opts.tab_width); - - i32 correct_indentation = indent_marks[line_i]; - if (hard_start.all_whitespace && opts.empty_blank_lines) correct_indentation = 0; - if (correct_indentation == -1) correct_indentation = hard_start.indent_pos; - - if ((hard_start.all_whitespace && hard_start.char_pos > start) || - !hard_start.all_space || correct_indentation != hard_start.indent_pos){ - Buffer_Edit new_edit; - new_edit.str_start = str_size; - str_size += correct_indentation; - char *str = push_array(part, char, correct_indentation); - i32 j = 0; - if (opts.use_tabs){ - i32 i = 0; - for (; i + opts.tab_width <= correct_indentation; i += opts.tab_width) str[j++] = '\t'; - for (; i < correct_indentation; ++i) str[j++] = ' '; - } - else{ - for (; j < correct_indentation; ++j) str[j] = ' '; - } - new_edit.len = j; - new_edit.start = start; - new_edit.end = hard_start.char_pos; - edits[edit_count++] = new_edit; - } - - Assert(edit_count <= edit_max); - } - - result.str_base = str_base; - result.str_size = str_size; - - result.edits = edits; - result.edit_max = edit_max; - result.edit_count = edit_count; - - return(result); -} - -internal void -view_auto_tab_tokens(System_Functions *system, Models *models, - View *view, i32 start, i32 end, Indent_Options opts){ -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - Editing_File *file = view->file_data.file; - Mem_Options *mem = &models->mem; - Partition *part = &mem->part; - Buffer *buffer = &file->state.buffer; - - Assert(file && !file->is_dummy); - Cpp_Token_Stack tokens = file->state.token_stack; - Assert(tokens.tokens); - - i32 line_start = buffer_get_line_index(buffer, start); - i32 line_end = buffer_get_line_index(buffer, end) + 1; - - Temp_Memory temp = begin_temp_memory(part); - - i32 *indent_marks = - get_line_indentation_marks(part, buffer, tokens, line_start, line_end, opts.tab_width); - - Make_Batch_Result batch = - make_batch_from_indent_marks(part, buffer, line_start, line_end, indent_marks, opts); - - if (batch.edit_count > 0){ - Assert(buffer_batch_debug_sort_check(batch.edits, batch.edit_count)); - - // NOTE(allen): computing edit spec, doing batch edit - Buffer_Edit *inverse_array = push_array(part, Buffer_Edit, batch.edit_count); - Assert(inverse_array); - - char *inv_str = (char*)part->base + part->pos; - Edit_Spec spec = - file_compute_whitespace_edit(mem, file, view->recent->cursor.pos, - batch.edits, batch.str_base, batch.str_size, - inverse_array, inv_str, part->max - part->pos, batch.edit_count); - - file_do_white_batch_edit(system, models, view->file_data.file, spec, hist_normal); - } - end_temp_memory(temp); - - { - i32 start = view->recent->cursor.pos; - Hard_Start_Result hard_start = buffer_find_hard_start(buffer, start, 4); - - view_cursor_move(view, hard_start.char_pos); - } -#endif -} - -struct Get_Link_Result{ - b32 in_link; - i32 index; -}; - -internal u32* -style_get_color(Style *style, Cpp_Token token){ - u32 *result; - if (token.flags & CPP_TFLAG_IS_KEYWORD){ - if (token.type == CPP_TOKEN_BOOLEAN_CONSTANT){ - result = &style->main.bool_constant_color; - } - else{ - result = &style->main.keyword_color; - } - } - else if(token.flags & CPP_TFLAG_PP_DIRECTIVE){ - result = &style->main.preproc_color; - } - else{ - switch (token.type){ - case CPP_TOKEN_COMMENT: - result = &style->main.comment_color; - break; - - case CPP_TOKEN_STRING_CONSTANT: - result = &style->main.str_constant_color; - break; - - case CPP_TOKEN_CHARACTER_CONSTANT: - result = &style->main.char_constant_color; - break; - - case CPP_TOKEN_INTEGER_CONSTANT: - result = &style->main.int_constant_color; - break; - - case CPP_TOKEN_FLOATING_CONSTANT: - result = &style->main.float_constant_color; - break; - - case CPP_TOKEN_INCLUDE_FILE: - result = &style->main.include_color; - break; - - default: - result = &style->main.default_color; - break; - } - } - return result; -} - -inline f32 -view_compute_max_target_y(i32 lowest_line, i32 line_height, f32 view_height){ - f32 max_target_y = ((lowest_line+.5f)*line_height) - view_height*.5f; - max_target_y = clamp_bottom(0.f, max_target_y); - return(max_target_y); -} - -internal f32 -view_compute_max_target_y(View *view){ - i32 lowest_line = view_compute_lowest_line(view); - i32 line_height = view->font_height; - f32 view_height = view_file_height(view); - f32 max_target_y = view_compute_max_target_y(lowest_line, line_height, view_height); - return(max_target_y); -} - -internal void -remeasure_file_view(System_Functions *system, View *view){ - if (file_is_ready(view->file_data.file)){ - Relative_Scrolling relative = view_get_relative_scrolling(view); - view_measure_wraps(&view->persistent.models->mem.general, view); - view_cursor_move(view, view->recent->cursor.pos); - view->recent->preferred_x = view_get_cursor_x(view); - view_set_relative_scrolling(view, relative); - } -} - -inline void -view_show_menu(View *view, Command_Map *gui_map){ - view->map = gui_map; - view->showing_ui = VUI_Menu; - view->current_scroll = &view->gui_scroll; -} - -inline void -view_show_config(View *view, Command_Map *gui_map){ - view->map = gui_map; - view->showing_ui = VUI_Config; - view->current_scroll = &view->gui_scroll; -} - -inline void -view_show_interactive(System_Functions *system, View *view, - Command_Map *gui_map, Interactive_Action action, - Interactive_Interaction interaction, String query){ - - Models *models = view->persistent.models; - - view->showing_ui = VUI_Interactive; - view->action = action; - view->interaction = interaction; - view->dest = make_fixed_width_string(view->dest_); - view->list_i = 0; - view->current_scroll = &view->gui_scroll; - - view->map = gui_map; - - hot_directory_clean_end(&models->hot_directory); - hot_directory_reload(system, &models->hot_directory, &models->working_set); -} - -inline void -view_show_theme(View *view, Command_Map *gui_map){ - view->map = gui_map; - view->showing_ui = VUI_Theme; - view->color_mode = CV_Mode_Library; - view->color = super_color_create(0xFF000000); - view->current_color_editing = 0; - view->current_scroll = &view->gui_scroll; -} - -inline void -view_show_file(View *view){ - Editing_File *file = view->file_data.file; - if (file){ - view->map = get_map(view->persistent.models, file->settings.base_map_id); - } - else{ - view->map = get_map(view->persistent.models, mapid_global); - } - view->showing_ui = VUI_None; - view->current_scroll = &view->recent->scroll; -} - -internal void -view_save_file(System_Functions *system, Models *models, - Editing_File *file, View *view, String filename, b32 save_as){ - Mem_Options *mem = &models->mem; - Working_Set *working_set = &models->working_set; - - if (!file){ - if (view){ - file = view->file_data.file; - } - else{ - file = working_set_lookup_file(working_set, filename); - } - } - - if (file && buffer_get_sync(file) != SYNC_GOOD){ - if (file_save(system, mem, file, filename.str)){ - if (save_as){ - file_set_name(working_set, file, filename.str); - } - } - } -} - -internal void -view_new_file(System_Functions *system, Models *models, - View *view, String string){ - Working_Set *working_set = &models->working_set; - General_Memory *general = &models->mem.general; - - Editing_File *file = working_set_alloc_always(working_set, general); - file_create_empty(system, models, file, string.str); - working_set_add(system, working_set, file, general); - - view_set_file(view, file, models); - view_show_file(view); - view->map = get_map(models, file->settings.base_map_id); - - Hook_Function *new_file_fnc = models->hooks[hook_new_file]; - if (new_file_fnc){ - models->buffer_param_indices[models->buffer_param_count++] = file->id.id; - new_file_fnc(&models->app_links); - models->buffer_param_count = 0; - file->settings.is_initialized = 1; - } - -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - if (file->settings.tokens_exist){ - file_first_lex_parallel(system, general, file); - } -#endif -} - -internal void -init_normal_file(System_Functions *system, Models *models, Editing_File *file, - char *buffer, i32 size){ - - General_Memory *general = &models->mem.general; - - String val = make_string(buffer, size); - file_create_from_string(system, models, file, file->name.source_path.str, val); - - if (file->settings.tokens_exist){ - file_first_lex_parallel(system, general, file); - } - - for (View_Iter iter = file_view_iter_init(&models->layout, file, 0); - file_view_iter_good(iter); - iter = file_view_iter_next(iter)){ - view_measure_wraps(general, iter.view); - } -} - -internal void -view_open_file(System_Functions *system, Models *models, - View *view, String filename){ - Working_Set *working_set = &models->working_set; - General_Memory *general = &models->mem.general; - Partition *part = &models->mem.part; - - Editing_File *file = working_set_contains(system, working_set, filename); - - if (file == 0){ - File_Loading loading = system->file_load_begin(filename.str); - - if (loading.exists){ - Temp_Memory temp = begin_temp_memory(part); - char *buffer = push_array(part, char, loading.size); - - if (system->file_load_end(loading, buffer)){ - file = working_set_alloc_always(working_set, general); - if (file){ - file_init_strings(file); - file_set_name(working_set, file, filename.str); - working_set_add(system, working_set, file, general); - - init_normal_file(system, models, file, - buffer, loading.size); - } - } - - end_temp_memory(temp); - } - } - - if (file){ - if (view){ - view_set_file(view, file, models); - } - } -} - -internal void -kill_file(System_Functions *system, Models *models, - Editing_File *file, String string){ - Working_Set *working_set = &models->working_set; - - if (!file && string.str){ - file = working_set_lookup_file(working_set, string); - if (!file){ - file = working_set_contains(system, working_set, string); - } - } - - if (file && !file->settings.never_kill){ - working_set_remove(system, working_set, file->name.source_path); - file_close(system, &models->mem.general, file); - working_set_free_file(&models->working_set, file); - - File_Node *used = &models->working_set.used_sentinel; - File_Node *node = used->next; - for (View_Iter iter = file_view_iter_init(&models->layout, file, 0); - file_view_iter_good(iter); - iter = file_view_iter_next(iter)){ - if (node != used){ - iter.view->file_data.file = 0; - view_set_file(iter.view, (Editing_File*)node, models); - node = node->next; - } - else{ - iter.view->file_data.file = 0; - view_set_file(iter.view, 0, models); - } - } - } -} - -internal void -try_kill_file(System_Functions *system, Models *models, - Editing_File *file, View *view, String string){ - Working_Set *working_set = &models->working_set; - - if (!file && string.str){ - file = working_set_lookup_file(working_set, string); - if (!file){ - file = working_set_contains(system, working_set, string); - } - } - - if (file && !file->settings.never_kill){ - if (buffer_needs_save(file)){ - if (view == 0){ - view = models->layout.panels[models->layout.active_panel].view; - } - view_show_interactive(system, view, &models->map_ui, - IAct_Sure_To_Kill, IInt_Sure_To_Kill, - make_lit_string("Are you sure?")); - copy(&view->dest, file->name.live_name); - } - else{ - kill_file(system, models, file, string_zero()); - view_show_file(view); - } - } -} - -internal void -interactive_view_complete(System_Functions *system, View *view, String dest, i32 user_action){ - Models *models = view->persistent.models; - Editing_File *old_file = view->file_data.file; - - switch (view->action){ - case IAct_Open: - view_open_file(system, models, view, dest); - touch_file(&models->working_set, old_file); - view_show_file(view); - break; - - case IAct_Save_As: - view_save_file(system, models, 0, view, dest, 1); - view_show_file(view); - break; - - case IAct_New: - if (dest.size > 0 && !char_is_slash(dest.str[dest.size-1])){ - view_new_file(system, models, view, dest); - view_show_file(view); - }break; - - case IAct_Switch: - { - touch_file(&models->working_set, old_file); - - Editing_File *file = 0; - String string = dest; - - file = working_set_lookup_file(&models->working_set, string); - if (!file){ - file = working_set_contains(system, &models->working_set, string); - } - if (file){ - view_set_file(view, file, models); - } - view_show_file(view); - } - break; - - case IAct_Kill: - try_kill_file(system, models, 0, 0, dest); - break; - - case IAct_Sure_To_Close: - switch (user_action){ - case 0: - models->keep_playing = 0; - break; - - case 1: - view_show_file(view); - break; - - case 2: - // TODO(allen): Save all and close. - break; - } - break; - - case IAct_Sure_To_Kill: - switch (user_action){ - case 0: - kill_file(system, models, 0, dest); - view_show_file(view); - break; - - case 1: - view_show_file(view); - break; - - case 2: - view_save_file(system, models, 0, 0, dest, 0); - kill_file(system, models, 0, dest); - view_show_file(view); - break; - } - break; - } -} - -#if 0 -internal void -update_highlighting(View *view){ - View *file_view = view->hot_file_view; - if (!file_view){ - view->highlight = {}; - return; - } - - Editing_File *file = file_view->file; - if (!file || !file_is_ready(file)){ - view->highlight = {}; - return; - } - - Models *models = view->persistent.models; - - Style *style = &models->style; - i32 pos = view_get_cursor_pos(file_view); - char c = buffer_get_char(&file->state.buffer, pos); - - if (c == '\r'){ - view->highlight.ids[0] = - raw_ptr_dif(&style->main.special_character_color, style); - } - - else if (file->state.tokens_complete){ - Cpp_Token_Stack *tokens = &file->state.token_stack; - Cpp_Get_Token_Result result = cpp_get_token(tokens, pos); - Cpp_Token token = tokens->tokens[result.token_index]; - if (!result.in_whitespace){ - u32 *color = style_get_color(style, token); - view->highlight.ids[0] = raw_ptr_dif(color, style); - if (token.type == CPP_TOKEN_JUNK){ - view->highlight.ids[1] = - raw_ptr_dif(&style->main.highlight_junk_color, style); - } - else if (char_is_whitespace(c)){ - view->highlight.ids[1] = - raw_ptr_dif(&style->main.highlight_white_color, style); - } - else{ - view->highlight.ids[1] = 0; - } - } - else{ - view->highlight.ids[0] = 0; - view->highlight.ids[1] = - raw_ptr_dif(&style->main.highlight_white_color, style); - } - } - - else{ - if (char_is_whitespace(c)){ - view->highlight.ids[0] = 0; - view->highlight.ids[1] = - raw_ptr_dif(&style->main.highlight_white_color, style); - } - else{ - view->highlight.ids[0] = - raw_ptr_dif(&style->main.default_color, style); - view->highlight.ids[1] = 0; - } - } - - if (file_view->show_temp_highlight){ - view->highlight.ids[2] = - raw_ptr_dif(&style->main.highlight_color, style); - view->highlight.ids[3] = - raw_ptr_dif(&style->main.at_highlight_color, style); - } - else if (file->state.paste_effect.tick_down > 0){ - view->highlight.ids[2] = - raw_ptr_dif(&style->main.paste_color, style); - view->highlight.ids[3] = 0; - } - else{ - view->highlight.ids[2] = 0; - view->highlight.ids[3] = 0; - } -} -#endif - -struct File_Bar{ - f32 pos_x, pos_y; - f32 text_shift_x, text_shift_y; - i32_Rect rect; - i16 font_id; -}; - -internal void -intbar_draw_string(Render_Target *target, File_Bar *bar, String str, u32 char_color){ - i16 font_id = bar->font_id; - draw_string(target, font_id, str, - (i32)(bar->pos_x + bar->text_shift_x), - (i32)(bar->pos_y + bar->text_shift_y), - char_color); - bar->pos_x += font_string_width(target, font_id, str); -} - -internal void -view_reinit_scrolling(View *view){ - Editing_File *file = view->file_data.file; - f32 w, h; - f32 cursor_x, cursor_y; - f32 target_x, target_y; - - view->reinit_scrolling = 0; - - target_x = 0; - target_y = 0; - - if (file && file_is_ready(file)){ - cursor_x = view_get_cursor_x(view); - cursor_y = view_get_cursor_y(view); - - w = view_file_width(view); - h = view_file_height(view); - - if (cursor_x >= target_x + w){ - target_x = (f32)(cursor_x - w*.5f); - } - - target_y = clamp_bottom(0.f, (f32)FLOOR32(cursor_y - h*.5f)); - } - - view->recent->scroll.target_y = target_y; - view->recent->scroll.scroll_y = target_y; - view->recent->scroll.prev_target_y = -1000.f; - - view->recent->scroll.target_x = target_x; - view->recent->scroll.scroll_x = target_x; - view->recent->scroll.prev_target_x = -1000.f; -} - -enum CursorScroll_State{ - CursorScroll_NoChange = 0x0, - CursorScroll_Cursor = 0x1, - CursorScroll_Scroll = 0x2, - CursorScroll_ContextChange = 0x4 -}; - -internal u32 -view_get_cursor_scroll_change_state(View *view){ - u32 result = 0; - i32 pos = 0; - Scroll_Context context = {0}; - - if (view->gui_target.did_file){ - pos = view_get_cursor_pos(view); - if ((view->prev_cursor_pos != pos)){ - result |= CursorScroll_Cursor; - } - } - - if (view->current_scroll){ - if (!gui_scroll_eq(view->current_scroll, &view->gui_target.scroll_original)){ - result |= CursorScroll_Scroll; - } - } - - if (context.mode == VUI_None){ - context.file = view->file_data.file; - } - else{ - context.file = view->prev_context.file; - } - context.scroll = view->gui_target.scroll_id; - context.mode = view->showing_ui; - - if (!context_eq(view->prev_context, context)){ - result |= CursorScroll_ContextChange; - } - - return(result); -} - -internal void -view_begin_cursor_scroll_updates(View *view){ - if (view->file_data.file && view->file_data.file == view->prev_context.file){ - Assert(view->prev_cursor_pos == view_get_cursor_pos(view)); - } - - view->prev_context.file = view->file_data.file; - view->prev_context.scroll = view->gui_target.scroll_id; - view->prev_context.mode = view->showing_ui; -} - -internal void -view_end_cursor_scroll_updates(View *view){ - i32 cursor_scroll_state = - view_get_cursor_scroll_change_state(view); - - switch (cursor_scroll_state){ - case CursorScroll_NoChange:break; - - case CursorScroll_Cursor: - case CursorScroll_Cursor|CursorScroll_Scroll: - view_move_view_to_cursor(view, view->current_scroll); - gui_post_scroll_vars(&view->gui_target, view->current_scroll, view->scroll_region); - break; - - case CursorScroll_Scroll: - view_move_cursor_to_view(view); - gui_post_scroll_vars(&view->gui_target, view->current_scroll, view->scroll_region); - break; - } - - if (cursor_scroll_state & CursorScroll_ContextChange){ - view->current_scroll->scroll_y = view->current_scroll->target_y; - view->current_scroll->scroll_x = view->current_scroll->target_x; - gui_post_scroll_vars(&view->gui_target, view->current_scroll, view->scroll_region); - } - - if (view->gui_target.did_file){ - view->prev_cursor_pos = view_get_cursor_pos(view); - } -} - -internal b32 -file_step(View *view, i32_Rect region, Input_Summary *user_input, b32 is_active){ - i32 is_animating = 0; - Editing_File *file = view->file_data.file; - if (file && !file->is_loading){ - f32 max_visible_y = view_file_height(view); - f32 max_x = view_file_width(view); - - GUI_Scroll_Vars scroll_vars = *view->current_scroll; - - if (file->state.paste_effect.tick_down > 0){ - --file->state.paste_effect.tick_down; - is_animating = 1; - } - - if (user_input->mouse.press_l && is_active){ - f32 rx = (f32)(user_input->mouse.x - region.x0); - f32 ry = (f32)(user_input->mouse.y - region.y0); - - if (ry >= 0){ - view_set_widget(view, FWIDG_NONE); - if (rx >= 0 && rx < max_x && ry >= 0 && ry < max_visible_y){ - view_cursor_move(view, rx + scroll_vars.scroll_x, ry + scroll_vars.scroll_y, 1); - view->mode = view_mode_zero(); - } - } - } - if (!is_active) view_set_widget(view, FWIDG_NONE); - } - - return(is_animating); -} - -internal void -do_widget(View *view, GUI_Target *target){ - Query_Slot *slot; - Query_Bar *bar; - - for (slot = view->query_set.used_slot; slot != 0; slot = slot->next){ - bar = slot->query_bar; - gui_do_text_field(target, bar->prompt, bar->string); - } -} - -struct Exhaustive_File_Loop{ - char front_name_[256]; - char full_path_[256]; - String front_name, full_path; - - Absolutes absolutes; - - File_Info *infos; - i32 count, r; -}; - -struct Exhaustive_File_Info{ - File_Info *info; - String message; - b8 is_folder; - b8 name_match; - b8 is_loaded; -}; - -internal void -begin_exhaustive_loop(Exhaustive_File_Loop *loop, Hot_Directory *hdir){ - loop->front_name = make_fixed_width_string(loop->front_name_); - loop->full_path = make_fixed_width_string(loop->full_path_); - - loop->infos = hdir->file_list.infos; - loop->count = hdir->file_list.count; - - get_front_of_directory(&loop->front_name, hdir->string); - get_absolutes(loop->front_name, &loop->absolutes, 1, 1); - get_path_of_directory(&loop->full_path, hdir->string); - loop->r = loop->full_path.size; -} - -internal Exhaustive_File_Info -get_exhaustive_info(System_Functions *system, Working_Set *working_set, Exhaustive_File_Loop *loop, i32 i){ - persist String message_loaded = make_lit_string(" LOADED"); - persist String message_unsaved = make_lit_string(" LOADED *"); - persist String message_unsynced = make_lit_string(" LOADED !"); - - Exhaustive_File_Info result = {0}; - Editing_File *file = 0; - - result.info = loop->infos + i; - loop->full_path.size = loop->r; - append(&loop->full_path, result.info->filename); - terminate_with_null(&loop->full_path); - file = working_set_contains(system, working_set, loop->full_path); - - result.is_folder = (result.info->folder != 0); - result.name_match = (filename_match(loop->front_name, &loop->absolutes, result.info->filename, 0) != 0); - result.is_loaded = (file != 0 && file_is_ready(file)); - - result.message = string_zero(); - if (result.is_loaded){ - switch (buffer_get_sync(file)){ - case SYNC_GOOD: result.message = message_loaded; break; - case SYNC_BEHIND_OS: result.message = message_unsynced; break; - case SYNC_UNSAVED: result.message = message_unsaved; break; - } - } - - return(result); -} - -struct Style_Color_Edit{ - Style_Tag target; - Style_Tag fore; - Style_Tag back; - String text; -}; - -static Style_Color_Edit colors_to_edit[] = { - {Stag_Back, Stag_Default, Stag_Back, make_lit_string("Background")}, - {Stag_Margin, Stag_Default, Stag_Margin, make_lit_string("Margin")}, - {Stag_Margin_Hover, Stag_Default, Stag_Margin_Hover, make_lit_string("Margin Hover")}, - {Stag_Margin_Active, Stag_Default, Stag_Margin_Active, make_lit_string("Margin Active")}, - - {Stag_Cursor, Stag_At_Cursor, Stag_Cursor, make_lit_string("Cursor")}, - {Stag_At_Cursor, Stag_At_Cursor, Stag_Cursor, make_lit_string("Text At Cursor")}, - {Stag_Mark, Stag_Mark, Stag_Back, make_lit_string("Mark")}, - - {Stag_Highlight, Stag_At_Highlight, Stag_Highlight, make_lit_string("Highlight")}, - {Stag_At_Highlight, Stag_At_Highlight, Stag_Highlight, make_lit_string("Text At Highlight")}, - - {Stag_Default, Stag_Default, Stag_Back, make_lit_string("Text Default")}, - {Stag_Comment, Stag_Comment, Stag_Back, make_lit_string("Comment")}, - {Stag_Keyword, Stag_Keyword, Stag_Back, make_lit_string("Keyword")}, - {Stag_Str_Constant, Stag_Str_Constant, Stag_Back, make_lit_string("String Constant")}, - {Stag_Char_Constant, Stag_Char_Constant, Stag_Back, make_lit_string("Character Constant")}, - {Stag_Int_Constant, Stag_Int_Constant, Stag_Back, make_lit_string("Integer Constant")}, - {Stag_Float_Constant, Stag_Float_Constant, Stag_Back, make_lit_string("Float Constant")}, - {Stag_Bool_Constant, Stag_Bool_Constant, Stag_Back, make_lit_string("Boolean Constant")}, - {Stag_Preproc, Stag_Preproc, Stag_Back, make_lit_string("Preprocessor")}, - {Stag_Special_Character, Stag_Special_Character, Stag_Back, make_lit_string("Special Character")}, - - {Stag_Highlight_Junk, Stag_Default, Stag_Highlight_Junk, make_lit_string("Junk Highlight")}, - {Stag_Highlight_White, Stag_Default, Stag_Highlight_White, make_lit_string("Whitespace Highlight")}, - - {Stag_Paste, Stag_Paste, Stag_Back, make_lit_string("Paste Color")}, - - {Stag_Bar, Stag_Base, Stag_Bar, make_lit_string("Bar")}, - {Stag_Base, Stag_Base, Stag_Bar, make_lit_string("Bar Text")}, - {Stag_Pop1, Stag_Pop1, Stag_Bar, make_lit_string("Bar Pop 1")}, - {Stag_Pop2, Stag_Pop2, Stag_Bar, make_lit_string("Bar Pop 2")}, -}; - -struct Single_Line_Input_Step{ - b8 hit_newline; - b8 hit_ctrl_newline; - b8 hit_a_character; - b8 hit_backspace; - b8 hit_esc; - b8 made_a_change; - b8 did_command; - b8 no_file_match; -}; - -enum Single_Line_Input_Type{ - SINGLE_LINE_STRING, - SINGLE_LINE_FILE -}; - -struct Single_Line_Mode{ - Single_Line_Input_Type type; - String *string; - Hot_Directory *hot_directory; - b32 fast_folder_select; - b32 try_to_match; - b32 case_sensitive; -}; - -internal Single_Line_Input_Step -app_single_line_input_core(System_Functions *system, Working_Set *working_set, - Key_Event_Data key, Single_Line_Mode mode){ - Single_Line_Input_Step result = {0}; - - if (key.keycode == key_back){ - result.hit_backspace = 1; - if (mode.string->size > 0){ - result.made_a_change = 1; - --mode.string->size; - switch (mode.type){ - case SINGLE_LINE_STRING: - { - mode.string->str[mode.string->size] = 0; - }break; - - case SINGLE_LINE_FILE: - { - char end_character = mode.string->str[mode.string->size]; - if (char_is_slash(end_character)){ - mode.string->size = reverse_seek_slash(*mode.string) + 1; - mode.string->str[mode.string->size] = 0; - hot_directory_set(system, mode.hot_directory, *mode.string, working_set); - } - else{ - mode.string->str[mode.string->size] = 0; - } - }break; - } - } - } - - else if (key.character == '\n' || key.character == '\t'){ - // NOTE(allen): do nothing! - } - - else if (key.keycode == key_esc){ - result.hit_esc = 1; - result.made_a_change = 1; - } - - else if (key.character){ - result.hit_a_character = 1; - if (!key.modifiers[MDFR_CONTROL_INDEX] && - !key.modifiers[MDFR_ALT_INDEX]){ - if (mode.string->size+1 < mode.string->memory_size){ - u8 new_character = (u8)key.character; - mode.string->str[mode.string->size] = new_character; - mode.string->size++; - mode.string->str[mode.string->size] = 0; - if (mode.type == SINGLE_LINE_FILE && char_is_slash(new_character)){ - hot_directory_set(system, mode.hot_directory, *mode.string, working_set); - } - result.made_a_change = 1; - } - } - else{ - result.did_command = 1; - result.made_a_change = 1; - } - } - - return result; -} - -inline Single_Line_Input_Step -app_single_line_input_step(System_Functions *system, Key_Event_Data key, String *string){ - Single_Line_Mode mode = {}; - mode.type = SINGLE_LINE_STRING; - mode.string = string; - return app_single_line_input_core(system, 0, key, mode); -} - -inline Single_Line_Input_Step -app_single_file_input_step(System_Functions *system, - Working_Set *working_set, Key_Event_Data key, - String *string, Hot_Directory *hot_directory, - b32 fast_folder_select, b32 try_to_match, b32 case_sensitive){ - Single_Line_Mode mode = {}; - mode.type = SINGLE_LINE_FILE; - mode.string = string; - mode.hot_directory = hot_directory; - mode.fast_folder_select = fast_folder_select; - mode.try_to_match = try_to_match; - mode.case_sensitive = case_sensitive; - return app_single_line_input_core(system, working_set, key, mode); -} - -inline Single_Line_Input_Step -app_single_number_input_step(System_Functions *system, Key_Event_Data key, String *string){ - Single_Line_Input_Step result = {}; - Single_Line_Mode mode = {}; - mode.type = SINGLE_LINE_STRING; - mode.string = string; - - char c = (char)key.character; - if (c == 0 || c == '\n' || char_is_numeric(c)) - result = app_single_line_input_core(system, 0, key, mode); - return result; -} - -struct View_Step_Result{ - b32 animating; - b32 consume_keys; - b32 consume_esc; -}; - -internal View_Step_Result -step_file_view(System_Functions *system, View *view, View *active_view, Input_Summary input){ - View_Step_Result result = {0}; - GUI_Target *target = &view->gui_target; - Models *models = view->persistent.models; - Key_Summary keys = input.keys; - - b32 show_scrollbar = !view->hide_scrollbar; - - view->current_scroll = 0; - - if (view->showing_ui != VUI_None){ - b32 did_esc = 0; - Key_Event_Data key; - i32 i; - - for (i = 0; i < keys.count; ++i){ - key = get_single_key(&keys, i); - if (key.keycode == key_esc){ - did_esc = 1; - break; - } - } - - if (did_esc){ - view_show_file(view); - result.consume_esc = 1; - } - } - - gui_begin_top_level(target, input); - { - gui_do_top_bar(target); - do_widget(view, target); - - if (view->showing_ui == VUI_None){ - - gui_begin_serial_section(target); - { - f32 delta = 9.f * view->font_height; - GUI_id scroll_context = {0}; - scroll_context.id[1] = view->showing_ui; - scroll_context.id[0] = (u64)(view->file_data.file); - - view->current_scroll = &view->recent->scroll; - gui_get_scroll_vars(target, scroll_context, - &view->recent->scroll, &view->scroll_region); - - gui_begin_scrollable(target, scroll_context, view->recent->scroll, - delta, show_scrollbar); - gui_do_file(target); - gui_end_scrollable(target); - } - gui_end_serial_section(target); - } - else{ - switch (view->showing_ui){ - case VUI_Menu: - { - view->current_scroll = &view->gui_scroll; - - String message = make_lit_string("Menu"); - String empty_string = {0}; - GUI_id id = {0}; - id.id[1] = VUI_Menu; - - gui_do_text_field(target, message, empty_string); - - id.id[0] = 0; - message = make_lit_string("Theme"); - if (gui_do_fixed_option(target, id, message, 0)){ - view_show_theme(view, view->map); - } - - id.id[0] = 1; - message = make_lit_string("Config"); - if (gui_do_fixed_option(target, id, message, 0)){ - view_show_config(view, view->map); - } - }break; - - case VUI_Config: - { - view->current_scroll = &view->gui_scroll; - - String message = make_lit_string("Config"); - String empty_string = {0}; - GUI_id id = {0}; - id.id[1] = VUI_Config; - - gui_do_text_field(target, message, empty_string); - - id.id[0] = 0; - message = make_lit_string("Left Ctrl + Left Alt = AltGr"); - if (gui_do_fixed_option_checkbox(target, id, message, 0, (b8)models->settings.lctrl_lalt_is_altgr)){ - models->settings.lctrl_lalt_is_altgr = !models->settings.lctrl_lalt_is_altgr; - } - }break; - - case VUI_Theme: - { - view->current_scroll = &view->gui_scroll; - - if (view != active_view){ - view->hot_file_view = active_view; - } - - String message = {0}; - String empty_string = {0}; - - GUI_id id = {0}; - id.id[1] = VUI_Theme + ((u64)view->color_mode << 32); - - GUI_id scroll_context = {0}; - scroll_context.id[0] = 0; - scroll_context.id[1] = VUI_Theme + ((u64)view->color_mode << 32); - - switch (view->color_mode){ - case CV_Mode_Library: - message = make_lit_string("Current Theme - Click to Edit"); - gui_do_text_field(target, message, empty_string); - - id.id[0] = (u64)(main_style(models)); - if (gui_do_style_preview(target, id, 0)){ - view->color_mode = CV_Mode_Adjusting; - } - - message = make_lit_string("Set Font"); - id.id[0] = (u64)(&models->global_font); - if (gui_do_button(target, id, message)){ - view->color_mode = CV_Mode_Font; - } - - message = make_lit_string("Theme Library - Click to Select"); - gui_do_text_field(target, message, empty_string); - - view->current_scroll = &view->gui_scroll; - gui_get_scroll_vars(target, scroll_context, &view->gui_scroll, &view->scroll_region); - gui_begin_scrollable(target, scroll_context, view->gui_scroll, - 9.f * view->font_height, show_scrollbar); - - { - i32 count = models->styles.count; - Style *style; - i32 i; - - for (i = 1; i < count; ++i, ++style){ - style = get_style(models, i); - id.id[0] = (u64)(style); - if (gui_do_style_preview(target, id, i)){ - style_copy(main_style(models), style); - } - } - } - - gui_end_scrollable(target); - break; - - case CV_Mode_Font: - { - Font_Set *font_set = models->font_set; - Font_Info *info = 0; - - i16 i = 1, count = (i16)models->font_set->count + 1; - i16 font_id = 0, new_font_id = 0; - - String message = make_lit_string("Back"); - - id.id[0] = 0; - if (gui_do_button(target, id, message)){ - view->color_mode = CV_Mode_Library; - } - - font_id = models->global_font.font_id; - new_font_id = font_id; - - for (i = 1; i < count; ++i){ - info = get_font_info(font_set, i); - id.id[0] = (u64)i; - if (i != font_id){ - if (gui_do_font_button(target, id, i, info->name)){ - new_font_id = i; - } - } - else{ - char message_space[256]; - message = make_fixed_width_string(message_space); - copy(&message, make_lit_string("currently selected: ")); - append(&message, info->name); - gui_do_font_button(target, id, i, message); - } - } - - models->global_font.font_id = (i16)(new_font_id); - }break; - - case CV_Mode_Adjusting: - { - Style *style = main_style(models); - u32 *edit_color = 0; - u32 *fore = 0, *back = 0; - i32 i = 0; - - String message = make_lit_string("Back"); - - id.id[0] = 0; - if (gui_do_button(target, id, message)){ - view->color_mode = CV_Mode_Library; - } - - view->current_scroll = &view->gui_scroll; - gui_get_scroll_vars(target, scroll_context, &view->gui_scroll, &view->scroll_region); - gui_begin_scrollable(target, scroll_context, view->gui_scroll, - 9.f * view->font_height, show_scrollbar); - - i32 next_color_editing = view->current_color_editing; - - for (i = 0; i < ArrayCount(colors_to_edit); ++i){ - edit_color = style_index_by_tag(&style->main, colors_to_edit[i].target); - id.id[0] = (u64)(edit_color); - - fore = style_index_by_tag(&style->main, colors_to_edit[i].fore); - back = style_index_by_tag(&style->main, colors_to_edit[i].back); - - if (gui_do_color_button(target, id, *fore, *back, colors_to_edit[i].text)){ - next_color_editing = i; - view->color_cursor = 0; - } - - if (view->current_color_editing == i){ - GUI_Item_Update update = {0}; - char text_space[7]; - String text = make_fixed_width_string(text_space); - - color_to_hexstr(*edit_color, &text); - if (gui_do_text_with_cursor(target, view->color_cursor, text, &update)){ - b32 r = 0; - i32 j = 0; - - for (j = 0; j < keys.count; ++j){ - i16 key = keys.keys[j].keycode; - switch (key){ - case key_left: --view->color_cursor; r = 1; result.consume_keys = 1; break; - case key_right: ++view->color_cursor; r = 1; result.consume_keys = 1; break; - - case key_up: - if (next_color_editing > 0){ - --next_color_editing; - } - result.consume_keys = 1; - break; - - case key_down: - if (next_color_editing <= ArrayCount(colors_to_edit)-1){ - ++next_color_editing; - } - result.consume_keys = 1; - break; - - default: - if ((key >= '0' && key <= '9') || (key >= 'a' && key <= 'f') || (key >= 'A' && key <= 'F')){ - text.str[view->color_cursor] = (char)key; - r = 1; - result.consume_keys = 1; - } - break; - } - - if (view->color_cursor < 0) view->color_cursor = 0; - if (view->color_cursor >= 6) view->color_cursor = 5; - } - - if (r){ - hexstr_to_color(text, edit_color); - gui_rollback(target, &update); - gui_do_text_with_cursor(target, view->color_cursor, text, 0); - } - } - } - } - - if (view->current_color_editing != next_color_editing){ - view->current_color_editing = next_color_editing; - view->color_cursor = 0; - } - - gui_end_scrollable(target); - }break; - } - }break; - - case VUI_Interactive: - { - b32 complete = 0; - char comp_dest_space[1024]; - String comp_dest = make_fixed_width_string(comp_dest_space); - i32 comp_action = 0; - - view->current_scroll = &view->gui_scroll; - - GUI_id id = {0}; - id.id[1] = VUI_Interactive + ((u64)view->interaction << 32); - - GUI_id scroll_context = {0}; - scroll_context.id[1] = VUI_Interactive + ((u64)view->interaction << 32); - - switch (view->interaction){ - case IInt_Sys_File_List: - { - b32 use_item_in_list = 1; - b32 activate_directly = 0; - - if (view->action == IAct_Save_As || view->action == IAct_New){ - use_item_in_list = 0; - } - - String message = {0}; - switch (view->action){ - case IAct_Open: message = make_lit_string("Open: "); break; - case IAct_Save_As: message = make_lit_string("Save As: "); break; - case IAct_New: message = make_lit_string("New: "); break; - } - - Exhaustive_File_Loop loop; - Exhaustive_File_Info file_info; - - GUI_Item_Update update = {0}; - Hot_Directory *hdir = &models->hot_directory; - b32 do_new_directory = 0; - b32 snap_into_view = 0; - i32 i = 0; - - { - Single_Line_Input_Step step = {0}; - Key_Event_Data key = {0}; - i32 i; - - for (i = 0; i < keys.count; ++i){ - key = get_single_key(&keys, i); - step = app_single_file_input_step(system, &models->working_set, key, - &hdir->string, hdir, 1, 1, 0); - if (step.made_a_change){ - view->list_i = 0; - result.consume_keys = 1; - } - if (!use_item_in_list && (key.keycode == '\n' || key.keycode == '\t')){ - activate_directly = 1; - result.consume_keys = 1; - } - } - } - - gui_do_text_field(target, message, hdir->string); - - scroll_context.id[0] = (u64)(hdir); - if (gui_get_scroll_vars(target, scroll_context, - &view->gui_scroll, &view->scroll_region)){ - snap_into_view = 1; - } - gui_begin_scrollable(target, scroll_context, view->gui_scroll, - 9.f * view->font_height, show_scrollbar); - - id.id[0] = (u64)(hdir) + 1; - - if (gui_begin_list(target, id, view->list_i, 0, - snap_into_view, &update)){ - // TODO(allen): Allow me to handle key consumption correctly here! - gui_standard_list(target, id, view->current_scroll, view->scroll_region, - &keys, &view->list_i, &update); - } - - { - begin_exhaustive_loop(&loop, hdir); - for (i = 0; i < loop.count; ++i){ - file_info = get_exhaustive_info(system, &models->working_set, &loop, i); - - if (file_info.name_match){ - id.id[0] = (u64)(file_info.info); - if (gui_do_file_option(target, id, file_info.info->filename, - file_info.is_folder, file_info.message)){ - if (file_info.is_folder){ - set_last_folder(&hdir->string, file_info.info->filename, '/'); - do_new_directory = 1; - } - else if (use_item_in_list){ - complete = 1; - copy(&comp_dest, loop.full_path); - } - } - } - } - } - - gui_end_list(target); - - if (activate_directly){ - complete = 1; - copy(&comp_dest, hdir->string); - } - - if (do_new_directory){ - hot_directory_reload(system, hdir, &models->working_set); - } - - gui_end_scrollable(target); - }break; - - case IInt_Live_File_List: - { - b32 snap_into_view = 0; - persist String message_unsaved = make_lit_string(" *"); - persist String message_unsynced = make_lit_string(" !"); - - String message = {0}; - switch (view->action){ - case IAct_Switch: message = make_lit_string("Switch: "); break; - case IAct_Kill: message = make_lit_string("Kill: "); break; - } - - Absolutes absolutes; - Editing_File *file; - Working_Set *working_set = &models->working_set; - Editing_Layout *layout = &models->layout; - GUI_Item_Update update = {0}; - - { - Single_Line_Input_Step step; - Key_Event_Data key; - i32 i; - for (i = 0; i < keys.count; ++i){ - key = get_single_key(&keys, i); - step = app_single_line_input_step(system, key, &view->dest); - if (step.made_a_change){ - view->list_i = 0; - result.consume_keys = 1; - } - } - } - - get_absolutes(view->dest, &absolutes, 1, 1); - - gui_do_text_field(target, message, view->dest); - - scroll_context.id[0] = (u64)(working_set); - if (gui_get_scroll_vars(target, scroll_context, - &view->gui_scroll, &view->scroll_region)){ - snap_into_view = 1; - } - gui_begin_scrollable(target, scroll_context, view->gui_scroll, - 9.f * view->font_height, show_scrollbar); - - id.id[0] = (u64)(working_set) + 1; - if (gui_begin_list(target, id, view->list_i, - 0, snap_into_view, &update)){ - gui_standard_list(target, id, view->current_scroll, view->scroll_region, - &keys, &view->list_i, &update); - } - - { - Partition *part = &models->mem.part; - Temp_Memory temp = begin_temp_memory(part); - File_Node *node = 0, *used_nodes = 0; - Editing_File **reserved_files = 0; - i32 reserved_top = 0, i = 0; - View_Iter iter = {0}; - - partition_align(part, sizeof(i32)); - reserved_files = (Editing_File**)partition_current(part); - - used_nodes = &working_set->used_sentinel; - for (dll_items(node, used_nodes)){ - file = (Editing_File*)node; - Assert(!file->is_dummy); - - if (filename_match(view->dest, &absolutes, file->name.live_name, 1)){ - iter = file_view_iter_init(layout, file, 0); - if (file_view_iter_good(iter)){ - reserved_files[reserved_top++] = file; - } - else{ - if (file->name.live_name.str[0] == '*'){ - reserved_files[reserved_top++] = file; - } - else{ - message = string_zero(); - switch (buffer_get_sync(file)){ - case SYNC_BEHIND_OS: message = message_unsynced; break; - case SYNC_UNSAVED: message = message_unsaved; break; - } - - id.id[0] = (u64)(file); - if (gui_do_file_option(target, id, file->name.live_name, 0, message)){ - complete = 1; - copy(&comp_dest, file->name.live_name); - } - } - } - } - } - - for (i = 0; i < reserved_top; ++i){ - file = reserved_files[i]; - - message = string_zero(); - switch (buffer_get_sync(file)){ - case SYNC_BEHIND_OS: message = message_unsynced; break; - case SYNC_UNSAVED: message = message_unsaved; break; - } - - id.id[0] = (u64)(file); - if (gui_do_file_option(target, id, file->name.live_name, 0, message)){ - complete = 1; - copy(&comp_dest, file->name.live_name); - } - } - - end_temp_memory(temp); - } - - gui_end_list(target); - - gui_end_scrollable(target); - }break; - - case IInt_Sure_To_Close: - { - i32 action = -1; - - String empty_str = {0}; - String message = make_lit_string("There is one or more files unsaved changes, close anyway?"); - - gui_do_text_field(target, message, empty_str); - - id.id[0] = (u64)('y'); - message = make_lit_string("(Y)es"); - if (gui_do_fixed_option(target, id, message, 'y')){ - action = 0; - } - - id.id[0] = (u64)('n'); - message = make_lit_string("(N)o"); - if (gui_do_fixed_option(target, id, message, 'n')){ - action = 1; - } - - if (action != -1){ - complete = 1; - copy(&comp_dest, view->dest); - comp_action = action; - } - }break; - - case IInt_Sure_To_Kill: - { - i32 action = -1; - - String empty_str = {0}; - String message = make_lit_string("There are unsaved changes, close anyway?"); - - gui_do_text_field(target, message, empty_str); - - id.id[0] = (u64)('y'); - message = make_lit_string("(Y)es"); - if (gui_do_fixed_option(target, id, message, 'y')){ - action = 0; - } - - id.id[0] = (u64)('n'); - message = make_lit_string("(N)o"); - if (gui_do_fixed_option(target, id, message, 'n')){ - action = 1; - } - - id.id[0] = (u64)('s'); - message = make_lit_string("(S)ave and kill"); - if (gui_do_fixed_option(target, id, message, 's')){ - action = 2; - } - - if (action != -1){ - complete = 1; - copy(&comp_dest, view->dest); - comp_action = action; - } - }break; - } - - if (complete){ - terminate_with_null(&comp_dest); - interactive_view_complete(system, view, comp_dest, comp_action); - } - }break; - } - } - } - gui_end_top_level(target); - - result.animating = target->animating; - return(result); -} - -internal f32 -view_get_scroll_y(View *view){ - f32 v; - if (view->showing_ui == VUI_None){ - v = view->recent->scroll.scroll_y; - } - else{ - v = view->gui_scroll.scroll_y; - } - return(v); -} - -internal void -click_button_input(GUI_Target *target, GUI_Session *session, Input_Summary *user_input, - GUI_Interactive *b, b32 *is_animating){ - i32 mx = user_input->mouse.x; - i32 my = user_input->mouse.y; - - if (hit_check(mx, my, session->rect)){ - target->hover = b->id; - if (user_input->mouse.press_l){ - target->mouse_hot = b->id; - *is_animating = 1; - } - if (user_input->mouse.release_l && gui_id_eq(target->mouse_hot, b->id)){ - target->active = b->id; - target->mouse_hot = gui_id_zero(); - *is_animating = 1; - } - } - else if (gui_id_eq(target->hover, b->id)){ - target->hover = gui_id_zero(); - } -} - -internal b32 -scroll_button_input(GUI_Target *target, GUI_Session *session, Input_Summary *user_input, - GUI_id id, b32 *is_animating){ - b32 result = 0; - i32 mx = user_input->mouse.x; - i32 my = user_input->mouse.y; - - if (hit_check(mx, my, session->rect)){ - target->hover = id; - if (user_input->mouse.l){ - target->mouse_hot = id; - gui_activate_scrolling(target); - *is_animating = 1; - result = 1; - } - } - else if (gui_id_eq(target->hover, id)){ - target->hover = gui_id_zero(); - } - return(result); -} - -struct Input_Process_Result{ - GUI_Scroll_Vars vars; - i32_Rect region; - b32 is_animating; -}; - -internal Input_Process_Result -do_input_file_view(System_Functions *system, - View *view, i32_Rect rect, b32 is_active, - Input_Summary *user_input, - GUI_Scroll_Vars vars, i32_Rect region){ - Input_Process_Result result = {0}; - b32 is_file_scroll = 0; - - GUI_Session gui_session = {0}; - GUI_Header *h = 0; - GUI_Target *target = &view->gui_target; - GUI_Interpret_Result interpret_result = {0}; - - result.vars = vars; - result.region = region; - - target->active = gui_id_zero(); - - if (target->push.pos > 0){ - gui_session_init(&gui_session, target, rect, view->font_height); - - for (h = (GUI_Header*)target->push.base; - h->type; - h = NextHeader(h)){ - interpret_result = gui_interpret(target, &gui_session, h, - result.vars, result.region); - - if (interpret_result.has_region){ - result.region = interpret_result.region; - } - - switch (h->type){ - case guicom_file_option: - case guicom_fixed_option: - case guicom_fixed_option_checkbox: - { - GUI_Interactive *b = (GUI_Interactive*)h; - - if (interpret_result.auto_activate){ - target->auto_hot = gui_id_zero(); - target->active = b->id; - result.is_animating = 1; - } - else if (interpret_result.auto_hot){ - if (!gui_id_eq(target->auto_hot, b->id)){ - target->auto_hot = b->id; - result.is_animating = 1; - } - } - }break; - } - - if (interpret_result.has_info){ - switch (h->type){ - case guicom_top_bar: break; - - case guicom_file: - { - f32 new_max_y = view_compute_max_target_y(view); - - view->file_region = gui_session.rect; - result.vars.max_y = new_max_y; - - if (view->reinit_scrolling){ - view_reinit_scrolling(view); - result.is_animating = 1; - } - if (file_step(view, gui_session.rect, user_input, is_active)){ - result.is_animating = 1; - } - is_file_scroll = 1; - }break; - - case guicom_color_button: - case guicom_font_button: - case guicom_button: - case guicom_file_option: - case guicom_style_preview: - { - GUI_Interactive *b = (GUI_Interactive*)h; - - click_button_input(target, &gui_session, user_input, b, &result.is_animating); - }break; - - case guicom_fixed_option: - case guicom_fixed_option_checkbox: - { - GUI_Interactive *b = (GUI_Interactive*)h; - - click_button_input(target, &gui_session, user_input, b, &result.is_animating); - - { - Key_Event_Data key; - Key_Summary *keys = &user_input->keys; - - void *ptr = (b + 1); - String string; - char activation_key; - - i32 i, count; - - string = gui_read_string(&ptr); - activation_key = *(char*)ptr; - - count = keys->count; - for (i = 0; i < count; ++i){ - key = get_single_key(keys, i); - if (char_to_upper(key.character) == char_to_upper(activation_key)){ - target->active = b->id; - result.is_animating = 1; - break; - } - } - } - }break; - - case guicom_scrollable_slider: - { - GUI_id id = gui_id_scrollbar_slider(); - i32 mx = user_input->mouse.x; - i32 my = user_input->mouse.y; - f32 v = 0; - - if (hit_check(mx, my, gui_session.rect)){ - target->hover = id; - if (user_input->mouse.press_l){ - target->mouse_hot = id; - result.is_animating = 1; - } - } - else if (gui_id_eq(target->hover, id)){ - target->hover = gui_id_zero(); - } - - if (gui_id_eq(target->mouse_hot, id)){ - v = unlerp(gui_session.scroll_top, (f32)my, - gui_session.scroll_bottom); - v = clamp(0.f, v, 1.f); - result.vars.target_y = lerp(0.f, v, result.vars.max_y); - - gui_activate_scrolling(target); - result.is_animating = 1; - } - } - // NOTE(allen): NO BREAK HERE!! - - case guicom_scrollable_invisible: - { - if (user_input->mouse.wheel != 0){ - result.vars.target_y += user_input->mouse.wheel*target->delta; - - result.vars.target_y = - clamp(0.f, result.vars.target_y, result.vars.max_y); - gui_activate_scrolling(target); - result.is_animating = 1; - } - }break; - - case guicom_scrollable_top: - { - GUI_id id = gui_id_scrollbar_top(); - - if (scroll_button_input(target, &gui_session, user_input, id, &result.is_animating)){ - result.vars.target_y -= target->delta * 0.25f; - result.vars.target_y = clamp_bottom(0.f, result.vars.target_y); - } - }break; - - case guicom_scrollable_bottom: - { - GUI_id id = gui_id_scrollbar_bottom(); - - if (scroll_button_input(target, &gui_session, user_input, id, &result.is_animating)){ - result.vars.target_y += target->delta * 0.25f; - result.vars.target_y = clamp_top(0.f, result.vars.max_y); - } - }break; - - case guicom_end_scrollable_section: - { - if (!is_file_scroll){ - f32 new_max_y = gui_session.suggested_max_y; - result.vars.max_y = new_max_y; - } - }break; - } - } - } - - if (!user_input->mouse.l){ - if (!gui_id_is_null(target->mouse_hot)){ - target->mouse_hot = gui_id_zero(); - result.is_animating = 1; - } - } - - { - GUI_Scroll_Vars scroll_vars = result.vars; - b32 is_new_target = 0; - if (scroll_vars.target_x != scroll_vars.prev_target_x) is_new_target = 1; - if (scroll_vars.target_y != scroll_vars.prev_target_y) is_new_target = 1; - - if (view->persistent.models->scroll_rule(scroll_vars.target_x, scroll_vars.target_y, - &scroll_vars.scroll_x, &scroll_vars.scroll_y, - (view->persistent.id) + 1, is_new_target)){ - result.is_animating = 1; - } - - scroll_vars.prev_target_x = scroll_vars.target_x; - scroll_vars.prev_target_y = scroll_vars.target_y; - - result.vars = scroll_vars; - } - } - - return(result); -} - -internal i32 -draw_file_loaded(View *view, i32_Rect rect, b32 is_active, Render_Target *target){ - Models *models = view->persistent.models; - Editing_File *file = view->file_data.file; - Style *style = main_style(models); - i32 line_height = view->font_height; - - i32 max_x = rect.x1 - rect.x0; - i32 max_y = rect.y1 - rect.y0 + line_height; - - Assert(file && !file->is_dummy && buffer_good(&file->state.buffer)); - - b32 tokens_use = 0; - Cpp_Token_Stack token_stack = {}; - if (file){ - tokens_use = file->state.tokens_complete && (file->state.token_stack.count > 0); - token_stack = file->state.token_stack; - } - - Partition *part = &models->mem.part; - - Temp_Memory temp = begin_temp_memory(part); - - partition_align(part, 4); - i32 max = partition_remaining(part) / sizeof(Buffer_Render_Item); - Buffer_Render_Item *items = push_array(part, Buffer_Render_Item, max); - - i16 font_id = models->global_font.font_id; - Render_Font *font = get_font_info(models->font_set, font_id)->font; - float *advance_data = 0; - if (font) advance_data = font->advance_data; - - i32 count; - Full_Cursor render_cursor; - Buffer_Render_Options opts = {}; - - f32 *wraps = view->file_data.line_wrap_y; - f32 scroll_x = view->recent->scroll.scroll_x; - f32 scroll_y = view->recent->scroll.scroll_y; - - { - render_cursor = buffer_get_start_cursor(&file->state.buffer, wraps, scroll_y, - !view->file_data.unwrapped_lines, (f32)max_x, advance_data, (f32)line_height); - - view->recent->scroll_i = render_cursor.pos; - - buffer_get_render_data(&file->state.buffer, items, max, &count, - (f32)rect.x0, (f32)rect.y0, - scroll_x, scroll_y, render_cursor, - !view->file_data.unwrapped_lines, - (f32)max_x, (f32)max_y, - advance_data, (f32)line_height, - opts); - } - - Assert(count > 0); - - i32 cursor_begin, cursor_end; - u32 cursor_color, at_cursor_color; - if (view->file_data.show_temp_highlight){ - cursor_begin = view->file_data.temp_highlight.pos; - cursor_end = view->file_data.temp_highlight_end_pos; - cursor_color = style->main.highlight_color; - at_cursor_color = style->main.at_highlight_color; - } - else{ - cursor_begin = view->recent->cursor.pos; - cursor_end = cursor_begin + 1; - cursor_color = style->main.cursor_color; - at_cursor_color = style->main.at_cursor_color; - } - - i32 token_i = 0; - u32 main_color = style->main.default_color; - u32 special_color = style->main.special_character_color; - if (tokens_use){ - Cpp_Get_Token_Result result = cpp_get_token(&token_stack, items->index); - main_color = *style_get_color(style, token_stack.tokens[result.token_index]); - token_i = result.token_index + 1; - } - - u32 mark_color = style->main.mark_color; - Buffer_Render_Item *item = items; - i32 prev_ind = -1; - u32 highlight_color = 0; - u32 highlight_this_color = 0; - - for (i32 i = 0; i < count; ++i, ++item){ - i32 ind = item->index; - highlight_this_color = 0; - if (tokens_use && ind != prev_ind){ - Cpp_Token current_token = token_stack.tokens[token_i-1]; - - if (token_i < token_stack.count){ - if (ind >= token_stack.tokens[token_i].start){ - main_color = - *style_get_color(style, token_stack.tokens[token_i]); - current_token = token_stack.tokens[token_i]; - ++token_i; - } - else if (ind >= current_token.start + current_token.size){ - main_color = 0xFFFFFFFF; - } - } - - if (current_token.type == CPP_TOKEN_JUNK && - i >= current_token.start && i < current_token.start + current_token.size){ - highlight_color = style->main.highlight_junk_color; - } - else{ - highlight_color = 0; - } - } - - u32 char_color = main_color; - if (item->flags & BRFlag_Special_Character) char_color = special_color; - - f32_Rect char_rect = f32R(item->x0, item->y0, item->x1, item->y1); - if (view->file_data.show_whitespace && highlight_color == 0 && - char_is_whitespace((char)item->glyphid)){ - highlight_this_color = style->main.highlight_white_color; - } - else{ - highlight_this_color = highlight_color; - } - - if (cursor_begin <= ind && ind < cursor_end && (ind != prev_ind || cursor_begin < ind)){ - if (is_active){ - draw_rectangle(target, char_rect, cursor_color); - char_color = at_cursor_color; - } - else{ - if (!view->file_data.show_temp_highlight){ - draw_rectangle_outline(target, char_rect, cursor_color); - } - } - } - else if (highlight_this_color){ - draw_rectangle(target, char_rect, highlight_this_color); - } - - u32 fade_color = 0xFFFF00FF; - f32 fade_amount = 0.f; - - if (file->state.paste_effect.tick_down > 0 && - file->state.paste_effect.start <= ind && - ind < file->state.paste_effect.end){ - fade_color = file->state.paste_effect.color; - fade_amount = (f32)(file->state.paste_effect.tick_down) / file->state.paste_effect.tick_max; - } - - char_color = color_blend(char_color, fade_amount, fade_color); - - if (ind == view->recent->mark && prev_ind != ind){ - draw_rectangle_outline(target, char_rect, mark_color); - } - if (item->glyphid != 0){ - font_draw_glyph(target, font_id, (u8)item->glyphid, - item->x0, item->y0, char_color); - } - prev_ind = ind; - } - - end_temp_memory(temp); - - return(0); -} - -internal void -draw_text_field(Render_Target *target, View *view, i32_Rect rect, String p, String t){ - Models *models = view->persistent.models; - Style *style = main_style(models); - - u32 back_color = style->main.margin_color; - u32 text1_color = style->main.default_color; - u32 text2_color = style->main.file_info_style.pop1_color; - - i32 x = rect.x0; - i32 y = rect.y0 + 2; - - i16 font_id = models->global_font.font_id; - - if (target){ - draw_rectangle(target, rect, back_color); - x = CEIL32(draw_string(target, font_id, p, x, y, text2_color)); - draw_string(target, font_id, t, x, y, text1_color); - } -} - -internal void -draw_text_with_cursor(Render_Target *target, View *view, i32_Rect rect, String s, i32 pos){ - Models *models = view->persistent.models; - Style *style = main_style(models); - - u32 back_color = style->main.margin_color; - u32 text_color = style->main.default_color; - u32 cursor_color = style->main.cursor_color; - u32 at_cursor_color = style->main.at_cursor_color; - - f32 x = (f32)rect.x0; - i32 y = rect.y0 + 2; - - i16 font_id = models->global_font.font_id; - - if (target){ - draw_rectangle(target, rect, back_color); - - if (pos >= 0 && pos < s.size){ - String part1, part2, part3; - i32_Rect cursor_rect; - Render_Font *font = get_font_info(models->font_set, font_id)->font; - - part1 = substr(s, 0, pos); - part2 = substr(s, pos, 1); - part3 = substr(s, pos+1, s.size-pos-1); - - - x = draw_string(target, font_id, part1, FLOOR32(x), y, text_color); - - cursor_rect.x0 = FLOOR32(x); - cursor_rect.x1 = FLOOR32(x) + CEIL32(font->advance_data[s.str[pos]]); - cursor_rect.y0 = y; - cursor_rect.y1 = y + view->font_height; - draw_rectangle(target, cursor_rect, cursor_color); - x = draw_string(target, font_id, part2, FLOOR32(x), y, at_cursor_color); - - draw_string(target, font_id, part3, FLOOR32(x), y, text_color); - } - else{ - draw_string(target, font_id, s, FLOOR32(x), y, text_color); - } - } -} - -internal void -draw_file_bar(Render_Target *target, View *view, Editing_File *file, i32_Rect rect){ - File_Bar bar; - Models *models = view->persistent.models; - Style_Font *font = &models->global_font; - Style *style = main_style(models); - Interactive_Style bar_style = style->main.file_info_style; - - u32 back_color = bar_style.bar_color; - u32 base_color = bar_style.base_color; - u32 pop1_color = bar_style.pop1_color; - u32 pop2_color = bar_style.pop2_color; - - bar.rect = rect; - - if (target){ - bar.font_id = font->font_id; - bar.pos_x = (f32)bar.rect.x0; - bar.pos_y = (f32)bar.rect.y0; - bar.text_shift_y = 2; - bar.text_shift_x = 0; - - draw_rectangle(target, bar.rect, back_color); - if (!file){ - intbar_draw_string(target, &bar, make_lit_string("*NULL*"), base_color); - } - else{ - intbar_draw_string(target, &bar, file->name.live_name, base_color); - intbar_draw_string(target, &bar, make_lit_string(" -"), base_color); - - if (file->is_loading){ - intbar_draw_string(target, &bar, make_lit_string(" loading"), base_color); - } - else{ - char line_number_space[30]; - String line_number = make_fixed_width_string(line_number_space); - append(&line_number, " L#"); - append_int_to_str(view->recent->cursor.line, &line_number); - append(&line_number, " C#"); - append_int_to_str(view->recent->cursor.character, &line_number); - - intbar_draw_string(target, &bar, line_number, base_color); - - intbar_draw_string(target, &bar, make_lit_string(" -"), base_color); - - if (file->settings.dos_write_mode){ - intbar_draw_string(target, &bar, make_lit_string(" dos"), base_color); - } - else{ - intbar_draw_string(target, &bar, make_lit_string(" nix"), base_color); - } - - if (file->state.still_lexing){ - intbar_draw_string(target, &bar, make_lit_string(" parsing"), pop1_color); - } - - if (!file->settings.unimportant){ - switch (buffer_get_sync(file)){ - case SYNC_BEHIND_OS: - { - persist String out_of_sync = make_lit_string(" !"); - intbar_draw_string(target, &bar, out_of_sync, pop2_color); - }break; - - case SYNC_UNSAVED: - { - persist String out_of_sync = make_lit_string(" *"); - intbar_draw_string(target, &bar, out_of_sync, pop2_color); - }break; - } - } - } - } - } -} - -u32 -get_margin_color(i32 active_level, Style *style){ - u32 margin = 0xFFFFFFFF; - - switch (active_level){ - default: - margin = style->main.margin_color; - break; - - case 1: case 2: - margin = style->main.margin_hover_color; - break; - - case 3: case 4: - margin = style->main.margin_active_color; - break; - } - - return(margin); -} - -internal void -draw_color_button(GUI_Target *gui_target, Render_Target *target, View *view, - i32_Rect rect, GUI_id id, u32 fore, u32 back, String text){ - Models *models = view->persistent.models; - - i32 active_level = gui_active_level(gui_target, id); - i16 font_id = models->global_font.font_id; - - if (active_level > 0){ - Swap(u32, back, fore); - } - - draw_rectangle(target, rect, back); - draw_string(target, font_id, text, rect.x0, rect.y0 + 1, fore); -} - -internal void -draw_font_button(GUI_Target *gui_target, Render_Target *target, View *view, - i32_Rect rect, GUI_id id, i16 font_id, String text){ - Models *models = view->persistent.models; - Style *style = main_style(models); - - i32 active_level = gui_active_level(gui_target, id); - - u32 margin = get_margin_color(active_level, style); - u32 back = style->main.back_color; - u32 text_color = style->main.default_color; - - draw_rectangle(target, rect, back); - draw_rectangle_outline(target, rect, margin); - draw_string(target, font_id, text, rect.x0, rect.y0 + 1, text_color); -} - -internal void -draw_fat_option_block(GUI_Target *gui_target, Render_Target *target, View *view, i32_Rect rect, GUI_id id, - String text, String pop, i8 checkbox = -1){ - Models *models = view->persistent.models; - Style *style = main_style(models); - - i32 active_level = gui_active_level(gui_target, id); - i16 font_id = models->global_font.font_id; - - i32_Rect inner = get_inner_rect(rect, 3); - - u32 margin = get_margin_color(active_level, style); - u32 back = style->main.back_color; - u32 text_color = style->main.default_color; - u32 pop_color = style->main.special_character_color; - - i32 h = view->font_height; - i32 x = inner.x0 + 3; - i32 y = inner.y0 + h/2 - 1; - - draw_rectangle(target, inner, back); - draw_margin(target, rect, inner, margin); - - if (checkbox != -1){ - u32 checkbox_color = style->main.margin_active_color; - i32_Rect checkbox_rect = get_inner_rect(inner, (inner.y1 - inner.y0 - h)/2); - checkbox_rect.x1 = checkbox_rect.x0 + (checkbox_rect.y1 - checkbox_rect.y0); - - if (checkbox == 0){ - draw_rectangle_outline(target, checkbox_rect, checkbox_color); - } - else{ - draw_rectangle(target, checkbox_rect, checkbox_color); - } - - x = checkbox_rect.x1 + 3; - } - - x = CEIL32(draw_string(target, font_id, text, x, y, text_color)); - draw_string(target, font_id, pop, x, y, pop_color); -} - -internal void -draw_button(GUI_Target *gui_target, Render_Target *target, View *view, i32_Rect rect, GUI_id id, String text){ - Models *models = view->persistent.models; - Style *style = main_style(models); - - i32 active_level = gui_active_level(gui_target, id); - i16 font_id = models->global_font.font_id; - - i32_Rect inner = get_inner_rect(rect, 3); - - u32 margin = style->main.default_color; - u32 back = get_margin_color(active_level, style); - u32 text_color = style->main.default_color; - - i32 h = view->font_height; - i32 y = inner.y0 + h/2 - 1; - - i32 w = (i32)font_string_width(target, font_id, text); - i32 x = (inner.x1 + inner.x0 - w)/2; - - draw_rectangle(target, inner, back); - draw_rectangle_outline(target, inner, margin); - - draw_string(target, font_id, text, x, y, text_color); -} - -internal void -draw_style_preview(GUI_Target *gui_target, Render_Target *target, View *view, i32_Rect rect, GUI_id id, Style *style){ - Models *models = view->persistent.models; - - i32 active_level = gui_active_level(gui_target, id); - i16 font_id = models->global_font.font_id; - Font_Info *info = get_font_info(models->font_set, font_id); - - i32_Rect inner = get_inner_rect(rect, 3); - - u32 margin_color = get_margin_color(active_level, style); - u32 back = style->main.back_color; - u32 text_color = style->main.default_color; - u32 keyword_color = style->main.keyword_color; - u32 int_constant_color = style->main.int_constant_color; - u32 comment_color = style->main.comment_color; - - draw_margin(target, rect, inner, margin_color); - draw_rectangle(target, inner, back); - - i32 y = inner.y0; - i32 x = inner.x0; - x = CEIL32(draw_string(target, font_id, style->name.str, x, y, text_color)); - i32 font_x = (i32)(inner.x1 - font_string_width(target, font_id, info->name.str)); - if (font_x > x + 10){ - draw_string(target, font_id, info->name.str, font_x, y, text_color); - } - - x = inner.x0; - y += info->height; - x = CEIL32(draw_string(target, font_id, "if", x, y, keyword_color)); - x = CEIL32(draw_string(target, font_id, "(x < ", x, y, text_color)); - x = CEIL32(draw_string(target, font_id, "0", x, y, int_constant_color)); - x = CEIL32(draw_string(target, font_id, ") { x = ", x, y, text_color)); - x = CEIL32(draw_string(target, font_id, "0", x, y, int_constant_color)); - x = CEIL32(draw_string(target, font_id, "; } ", x, y, text_color)); - x = CEIL32(draw_string(target, font_id, "// comment", x, y, comment_color)); - - x = inner.x0; - y += info->height; - draw_string(target, font_id, "[] () {}; * -> +-/ <>= ! && || % ^", x, y, text_color); -} - -internal i32 -do_render_file_view(System_Functions *system, View *view, - View *active, i32_Rect rect, b32 is_active, - Render_Target *target, Input_Summary *user_input){ - - Editing_File *file = view->file_data.file; - i32 result = 0; - - GUI_Session gui_session = {0}; - GUI_Header *h; - GUI_Target *gui_target = &view->gui_target; - GUI_Interpret_Result interpret_result = {0}; - - f32 v; - - if (gui_target->push.pos > 0){ - gui_session_init(&gui_session, gui_target, rect, view->font_height); - - v = view_get_scroll_y(view); - - i32_Rect clip_rect = rect; - draw_push_clip(target, clip_rect); - - for (h = (GUI_Header*)gui_target->push.base; - h->type; - h = NextHeader(h)){ - interpret_result = gui_interpret(gui_target, &gui_session, h, - *view->current_scroll, - view->scroll_region); - - if (interpret_result.has_info){ - if (gui_session.clip_y > clip_rect.y0){ - clip_rect.y0 = gui_session.clip_y; - draw_change_clip(target, clip_rect); - } - - switch (h->type){ - case guicom_top_bar: - { - draw_file_bar(target, view, file, gui_session.rect); - }break; - - case guicom_file: - { - if (view->reinit_scrolling){ - view_reinit_scrolling(view); - } - if (file && file_is_ready(file)){ - result = draw_file_loaded(view, gui_session.rect, is_active, target); - } - }break; - - case guicom_text_field: - { - void *ptr = (h+1); - String p = gui_read_string(&ptr); - String t = gui_read_string(&ptr); - draw_text_field(target, view, gui_session.rect, p, t); - }break; - - case guicom_text_with_cursor: - { - void *ptr = (h+1); - String s = gui_read_string(&ptr); - i32 pos = gui_read_integer(&ptr); - - draw_text_with_cursor(target, view, gui_session.rect, s, pos); - }break; - - case guicom_color_button: - { - GUI_Interactive *b = (GUI_Interactive*)h; - void *ptr = (b + 1); - u32 fore = (u32)gui_read_integer(&ptr); - u32 back = (u32)gui_read_integer(&ptr); - String t = gui_read_string(&ptr); - - draw_color_button(gui_target, target, view, gui_session.rect, b->id, fore, back, t); - }break; - - case guicom_font_button: - { - GUI_Interactive *b = (GUI_Interactive*)h; - void *ptr = (b + 1); - i16 font_id = (i16)gui_read_integer(&ptr); - String t = gui_read_string(&ptr); - - draw_font_button(gui_target, target, view, gui_session.rect, b->id, font_id, t); - }break; - - case guicom_file_option: - { - GUI_Interactive *b = (GUI_Interactive*)h; - void *ptr = (b + 1); - b32 folder = gui_read_integer(&ptr); - String f = gui_read_string(&ptr); - String m = gui_read_string(&ptr); - - if (folder){ - append(&f, system->slash); - } - - draw_fat_option_block(gui_target, target, view, gui_session.rect, b->id, f, m); - }break; - - case guicom_style_preview: - { - GUI_Interactive *b = (GUI_Interactive*)h; - i32 style_index = *(i32*)(b + 1); - Style *style = get_style(view->persistent.models, style_index); - - draw_style_preview(gui_target, target, view, gui_session.rect, b->id, style); - }break; - - case guicom_fixed_option: - case guicom_fixed_option_checkbox: - { - GUI_Interactive *b = (GUI_Interactive*)h; - void *ptr = (b + 1); - String f = gui_read_string(&ptr); - String m = {0}; - i8 status = -1; - if (h->type == guicom_fixed_option_checkbox){ - gui_read_byte(&ptr); - status = (i8)gui_read_byte(&ptr); - } - - draw_fat_option_block(gui_target, target, view, gui_session.rect, b->id, f, m, status); - }break; - - case guicom_button: - { - GUI_Interactive *b = (GUI_Interactive*)h; - void *ptr = (b + 1); - String t = gui_read_string(&ptr); - - draw_button(gui_target, target, view, gui_session.rect, b->id, t); - }break; - - case guicom_scrollable_bar: - { - Models *models = view->persistent.models; - Style *style = main_style(models); - - u32 back; - u32 outline; - - i32_Rect bar = gui_session.rect; - - back = style->main.back_color; - if (is_active){ - outline = style->main.margin_active_color; - } - else{ - outline = style->main.margin_color; - } - - draw_rectangle(target, bar, back); - draw_rectangle_outline(target, bar, outline); - }break; - - case guicom_scrollable_top: - case guicom_scrollable_slider: - case guicom_scrollable_bottom: - { - GUI_id id; - Models *models = view->persistent.models; - Style *style = main_style(models); - i32_Rect box = gui_session.rect; - - i32 active_level; - - u32 back; - u32 outline; - - switch (h->type){ - case guicom_scrollable_top: id = gui_id_scrollbar_top(); break; - case guicom_scrollable_bottom: id = gui_id_scrollbar_bottom(); break; - default: id = gui_id_scrollbar_slider(); break; - } - - active_level = gui_active_level(gui_target, id); - - switch (active_level){ - case 0: back = style->main.back_color; break; - case 1: back = style->main.margin_hover_color; break; - default: back = style->main.margin_active_color; break; - } - - if (is_active){ - outline = style->main.margin_active_color; - } - else{ - outline = style->main.margin_color; - } - - draw_rectangle(target, box, back); - draw_margin(target, box, get_inner_rect(box, 2), outline); - }break; - - case guicom_begin_scrollable_section: - clip_rect.x1 = Min(gui_session.scroll_region.x1, clip_rect.x1); - draw_push_clip(target, clip_rect); - break; - - case guicom_end_scrollable_section: - clip_rect = draw_pop_clip(target); - break; - } - } - } - - draw_pop_clip(target); - } - - return(result); -} - -inline void -file_view_free_buffers(View *view){ - General_Memory *general = &view->persistent.models->mem.general; - if (view->file_data.line_wrap_y){ - general_memory_free(general, view->file_data.line_wrap_y); - view->file_data.line_wrap_y = 0; - } - general_memory_free(general, view->gui_mem); - view->gui_mem = 0; -} - -struct Search_Range{ - Buffer_Type *buffer; - i32 start, size; -}; - -struct Search_Set{ - Search_Range *ranges; - i32 count, max; -}; - -struct Search_Iter{ - String word; - i32 pos; - i32 i; -}; - -struct Search_Match{ - Buffer_Type *buffer; - i32 start, end; - b32 found_match; -}; - -internal void -search_iter_init(General_Memory *general, Search_Iter *iter, i32 size){ - i32 str_max; - - if (iter->word.str == 0){ - str_max = size*2; - iter->word.str = (char*)general_memory_allocate(general, str_max, 0); - iter->word.memory_size = str_max; - } - else if (iter->word.memory_size < size){ - str_max = size*2; - iter->word.str = (char*)general_memory_reallocate_nocopy(general, iter->word.str, str_max, 0); - iter->word.memory_size = str_max; - } - - iter->i = 0; - iter->pos = 0; -} - -internal void -search_set_init(General_Memory *general, Search_Set *set, i32 set_count){ - i32 max; - - if (set->ranges == 0){ - max = set_count*2; - set->ranges = (Search_Range*)general_memory_allocate(general, sizeof(Search_Range)*max, 0); - set->max = max; - } - else if (set->max < set_count){ - max = set_count*2; - set->ranges = (Search_Range*)general_memory_reallocate_nocopy( - general, set->ranges, sizeof(Search_Range)*max, 0); - set->max = max; - } - - set->count = set_count; -} - -internal void -search_hits_table_alloc(General_Memory *general, Table *hits, i32 table_size){ - void *mem; - i32 mem_size; - - mem_size = table_required_mem_size(table_size, sizeof(Offset_String)); - if (hits->hash_array == 0){ - mem = general_memory_allocate(general, mem_size, 0); - } - else{ - mem = general_memory_reallocate_nocopy(general, hits->hash_array, mem_size, 0); - } - table_init_memory(hits, mem, table_size, sizeof(Offset_String)); -} - -internal void -search_hits_init(General_Memory *general, Table *hits, String_Space *str, i32 table_size, i32 str_size){ - void *mem; - i32 mem_size; - - if (hits->hash_array == 0){ - search_hits_table_alloc(general, hits, table_size); - } - else if (hits->max < table_size){ - mem_size = table_required_mem_size(table_size, sizeof(Offset_String)); - mem = general_memory_reallocate_nocopy(general, hits->hash_array, mem_size, 0); - table_init_memory(hits, mem, table_size, sizeof(Offset_String)); - } - - if (str->space == 0){ - str->space = (char*)general_memory_allocate(general, str_size, 0); - str->max = str_size; - } - else if (str->max < str_size){ - str->space = (char*)general_memory_reallocate_nocopy(general, str->space, str_size, 0); - str->max = str_size; - } - - str->pos = str->new_pos = 0; - table_clear(hits); -} - -internal b32 -search_hit_add(General_Memory *general, Table *hits, String_Space *space, char *str, i32 len){ - b32 result; - i32 new_size; - Offset_String ostring; - Table new_hits; - - Assert(len != 0); - - ostring = strspace_append(space, str, len); - if (ostring.size == 0){ - new_size = Max(space->max*2, space->max + len); - space->space = (char*)general_memory_reallocate(general, space->space, space->new_pos, new_size, 0); - ostring = strspace_append(space, str, len); - } - - Assert(ostring.size != 0); - - if (table_at_capacity(hits)){ - search_hits_table_alloc(general, &new_hits, hits->max*2); - table_clear(&new_hits); - table_rehash(hits, &new_hits, space->space, tbl_offset_string_hash, tbl_offset_string_compare); - general_memory_free(general, hits->hash_array); - *hits = new_hits; - } - - if (!table_add(hits, &ostring, space->space, tbl_offset_string_hash, tbl_offset_string_compare)){ - result = 1; - strspace_keep_prev(space); - } - else{ - result = 0; - strspace_discard_prev(space); - } - - return(result); -} - -internal Search_Match -search_next_match(Partition *part, Search_Set *set, Search_Iter *iter_){ - Search_Match result = {}; - Search_Iter iter = *iter_; - Search_Range *range; - Temp_Memory temp; - char *spare; - i32 start_pos, end_pos, count; - - temp = begin_temp_memory(part); - spare = push_array(part, char, iter.word.size); - - count = set->count; - for (; iter.i < count;){ - range = set->ranges + iter.i; - - end_pos = range->start + range->size; - - if (iter.pos + iter.word.size < end_pos){ - start_pos = Max(iter.pos, range->start); - result.start = buffer_find_string(range->buffer, start_pos, end_pos, iter.word.str, iter.word.size, spare); - - if (result.start < end_pos){ - iter.pos = result.start + 1; - if (result.start == 0 || !char_is_alpha_numeric(buffer_get_char(range->buffer, result.start - 1))){ - result.end = buffer_seek_word_right_assume_on_word(range->buffer, result.start); - if (result.end < end_pos){ - result.found_match = 1; - result.buffer = range->buffer; - iter.pos = result.end; - break; - } - } - } - else{ - ++iter.i, iter.pos = 0; - } - } - else{ - ++iter.i, iter.pos = 0; - } - } - end_temp_memory(temp); - - *iter_ = iter; - - return(result); -} - -inline void -view_change_size(General_Memory *general, View *view){ - if (view->file_data.file){ - view_measure_wraps(general, view); - view->recent->cursor = view_compute_cursor_from_pos(view, view->recent->cursor.pos); - } -} - -struct Live_Views{ - View *views; - View free_sentinel; - i32 count, max; -}; - -internal View_And_ID -live_set_alloc_view(Live_Views *live_set, Panel *panel, Models *models){ - View_And_ID result = {}; - - Assert(live_set->count < live_set->max); - ++live_set->count; - - result.view = live_set->free_sentinel.next; - result.id = (i32)(result.view - live_set->views); - Assert(result.id == result.view->persistent.id); - - dll_remove(result.view); - memset(get_view_body(result.view), 0, get_view_size()); - - result.view->in_use = 1; - panel->view = result.view; - result.view->panel = panel; - - result.view->persistent.models = models; - result.view->scrub_max = 1; - result.view->current_scroll = &result.view->recent->scroll; - - init_query_set(&result.view->query_set); - - { - i32 gui_mem_size = Kbytes(32); - void *gui_mem = general_memory_allocate(&models->mem.general, gui_mem_size + 8, 0); - result.view->gui_mem = gui_mem; - gui_mem = advance_to_alignment(gui_mem); - result.view->gui_target.push = make_part(gui_mem, gui_mem_size); - } - - return(result); -} - -inline void -live_set_free_view(System_Functions *system, Live_Views *live_set, View *view){ - Assert(live_set->count > 0); - --live_set->count; - file_view_free_buffers(view); - dll_insert(&live_set->free_sentinel, view); - view->in_use = 0; -} - -// BOTTOM - +/* +* Mr. 4th Dimention - Allen Webster +* +* 19.08.2015 +* +* File editing view for 4coder +* +*/ + +// TOP + +internal i32 +get_or_add_map_index(Models *models, i32 mapid){ + i32 result; + i32 user_map_count = models->user_map_count; + i32 *map_id_table = models->map_id_table; + for (result = 0; result < user_map_count; ++result){ + if (map_id_table[result] == mapid) break; + if (map_id_table[result] == -1){ + map_id_table[result] = mapid; + break; + } + } + return result; +} + +internal i32 +get_map_index(Models *models, i32 mapid){ + i32 result; + i32 user_map_count = models->user_map_count; + i32 *map_id_table = models->map_id_table; + for (result = 0; result < user_map_count; ++result){ + if (map_id_table[result] == mapid) break; + if (map_id_table[result] == 0){ + result = user_map_count; + break; + } + } + return result; +} + +internal Command_Map* +get_map_base(Models *models, i32 mapid, b32 add){ + Command_Map *map = 0; + if (mapid < mapid_global){ + if (add){ + mapid = get_or_add_map_index(models, mapid); + } + else{ + mapid = get_map_index(models, mapid); + } + if (mapid < models->user_map_count){ + map = models->user_maps + mapid; + } + } + else if (mapid == mapid_global) map = &models->map_top; + else if (mapid == mapid_file) map = &models->map_file; + return(map); +} + +internal Command_Map* +get_or_add_map(Models *models, i32 mapid){ + Command_Map *map = get_map_base(models, mapid, 1); + return(map); +} + +internal Command_Map* +get_map(Models *models, i32 mapid){ + Command_Map *map = get_map_base(models, mapid, 0); + return(map); +} + +internal void +map_set_count(Models *models, i32 mapid, i32 count){ + Command_Map *map = get_or_add_map(models, mapid); + Assert(map->commands == 0); + map->count = count; + if (map->max < count){ + map->max = count; + } +} + +internal i32 +map_get_count(Models *models, i32 mapid){ + Command_Map *map = get_or_add_map(models, mapid); + i32 count = map->count; + Assert(map->commands == 0); + return(count); +} + +internal i32 +map_get_max_count(Models *models, i32 mapid){ + Command_Map *map = get_or_add_map(models, mapid); + i32 count = map->max; + return(count); +} + +enum Interactive_Action{ + IAct_Open, + IAct_Save_As, + IAct_New, + IAct_Switch, + IAct_Kill, + IAct_Sure_To_Kill, + IAct_Sure_To_Close +}; + +enum Interactive_Interaction{ + IInt_Sys_File_List, + IInt_Live_File_List, + IInt_Sure_To_Kill, + IInt_Sure_To_Close +}; + +struct View_Mode{ + i32 rewrite; +}; +inline View_Mode +view_mode_zero(){ + View_Mode mode={0}; + return(mode); +} + +enum View_Widget_Type{ + FWIDG_NONE, + FWIDG_TIMELINES, + // never below this + FWIDG_TYPE_COUNT +}; + +struct View_Widget{ + View_Widget_Type type; + i32 height_; + struct{ + b32 undo_line; + b32 history_line; + } timeline; +}; + +enum View_UI{ + VUI_None, + VUI_Theme, + VUI_Interactive, + VUI_Menu, + VUI_Config, +}; + +enum Color_View_Mode{ + CV_Mode_Library, + CV_Mode_Font, + CV_Mode_Adjusting +}; + +struct File_Viewing_Data{ + Editing_File *file; + + Full_Cursor temp_highlight; + i32 temp_highlight_end_pos; + b32 show_temp_highlight; + + b32 unwrapped_lines; + b32 show_whitespace; + b32 file_locked; + + i32 line_count, line_max; + f32 *line_wrap_y; +}; +inline File_Viewing_Data +file_viewing_data_zero(){ + File_Viewing_Data data={0}; + return(data); +} + +struct Recent_File_Data{ + u64 unique_buffer_id; + GUI_Scroll_Vars scroll; + + Full_Cursor cursor; + i32 mark; + f32 preferred_x; + i32 scroll_i; +}; +inline Recent_File_Data +recent_file_data_zero(){ + Recent_File_Data data = {0}; + return(data); +} + +struct Scroll_Context{ + Editing_File *file; + GUI_id scroll; + View_UI mode; +}; +inline b32 +context_eq(Scroll_Context a, Scroll_Context b){ + b32 result = 0; + if (gui_id_eq(a.scroll, b.scroll)){ + if (a.file == b.file){ + if (a.mode == b.mode){ + result = 1; + } + } + } + return(result); +} + +struct View_Persistent{ + i32 id; + + View_Routine_Function *view_routine; + Coroutine *coroutine; + Event_Message message_passing_slot; + + // TODO(allen): eliminate this models pointer: explicitly parameterize. + Models *models; +}; + +struct View{ + View_Persistent persistent; + + View *next, *prev; + Panel *panel; + b32 in_use; + Command_Map *map; + + File_Viewing_Data file_data; + i32 prev_cursor_pos; + Scroll_Context prev_context; + + i32_Rect file_region_prev; + i32_Rect file_region; + + i32_Rect scroll_region; + Recent_File_Data recent[16]; + + GUI_Scroll_Vars *current_scroll; + + View_UI showing_ui; + GUI_Target gui_target; + void *gui_mem; + GUI_Scroll_Vars gui_scroll; + i32 list_i; + + b32 hide_scrollbar; + + // interactive stuff + Interactive_Interaction interaction; + Interactive_Action action; + + char dest_[256]; + String dest; + + // theme stuff + View *hot_file_view; + u32 *palette; + i32 palette_size; + Color_View_Mode color_mode; + Super_Color color; + b32 p4c_only; + Style_Library inspecting_styles; + b8 import_export_check[64]; + i32 import_file_id; + i32 current_color_editing; + i32 color_cursor; + + i32 font_advance; + i32 font_height; + + View_Mode mode, next_mode; + View_Widget widget; + Query_Set query_set; + i32 scrub_max; + + b32 reinit_scrolling; +}; +inline void* +get_view_body(View *view){ + char *result = (char*)view; + result += sizeof(View_Persistent); + return(result); +} +inline i32 +get_view_size(){ + return(sizeof(View) - sizeof(View_Persistent)); +} + +struct View_And_ID{ + View *view; + i32 id; +}; + +#define LockLevel_Open 0 +#define LockLevel_NoWrite 1 +#define LockLevel_NoUpdate 2 + +inline i32 +view_lock_level(View *view){ + i32 result = LockLevel_Open; + File_Viewing_Data *data = &view->file_data; + if (view->showing_ui != VUI_None) result = LockLevel_NoUpdate; + else if (data->file_locked || (data->file && data->file->settings.read_only)) result = LockLevel_NoWrite; + return(result); +} + +inline f32 +view_file_width(View *view){ + i32_Rect file_rect = view->file_region; + f32 result = (f32)(file_rect.x1 - file_rect.x0); + return (result); +} + +inline f32 +view_file_height(View *view){ + i32_Rect file_rect = view->file_region; + f32 result = (f32)(file_rect.y1 - file_rect.y0); + return (result); +} + +struct View_Iter{ + View *view; + + Editing_File *file; + View *skip; + Panel *used_panels; + Panel *panel; +}; + +internal View_Iter +file_view_iter_next(View_Iter iter){ + View *view; + + for (iter.panel = iter.panel->next; iter.panel != iter.used_panels; iter.panel = iter.panel->next){ + view = iter.panel->view; + if (view != iter.skip && (view->file_data.file == iter.file || iter.file == 0)){ + iter.view = view; + break; + } + } + + return(iter); +} + +internal View_Iter +file_view_iter_init(Editing_Layout *layout, Editing_File *file, View *skip){ + View_Iter result; + result.used_panels = &layout->used_sentinel; + result.panel = result.used_panels; + result.file = file; + result.skip = skip; + + result = file_view_iter_next(result); + + return(result); +} + +internal b32 +file_view_iter_good(View_Iter iter){ + b32 result = (iter.panel != iter.used_panels); + return(result); +} + +inline b32 +starts_new_line(u8 character){ + return (character == '\n'); +} + +inline void +file_init_strings(Editing_File *file){ + file->name.source_path = make_fixed_width_string(file->name.source_path_); + file->name.live_name = make_fixed_width_string(file->name.live_name_); + file->name.extension = make_fixed_width_string(file->name.extension_); +} + +inline void +file_set_name(Working_Set *working_set, Editing_File *file, char *filename){ + String f, ext; + + Assert(file->name.live_name.str != 0); + + f = make_string_slowly(filename); + copy_checked(&file->name.source_path, f); + + file->name.live_name.size = 0; + get_front_of_directory(&file->name.live_name, f); + + if (file->name.source_path.size == file->name.live_name.size){ + file->name.extension.size = 0; + } + else{ + ext = file_extension(f); + copy(&file->name.extension, ext); + } + + { + File_Node *node, *used_nodes; + Editing_File *file_ptr; + i32 file_x, original_len; + b32 hit_conflict; + + used_nodes = &working_set->used_sentinel; + original_len = file->name.live_name.size; + hit_conflict = 1; + file_x = 0; + while (hit_conflict){ + hit_conflict = 0; + for (dll_items(node, used_nodes)){ + file_ptr = (Editing_File*)node; + if (file_ptr != file && file_is_ready(file_ptr)){ + if (match(file->name.live_name, file_ptr->name.live_name)){ + ++file_x; + hit_conflict = 1; + break; + } + } + } + + if (hit_conflict){ + file->name.live_name.size = original_len; + append(&file->name.live_name, " <"); + append_int_to_str(file_x, &file->name.live_name); + append(&file->name.live_name, ">"); + } + } + } +} + +inline void +file_synchronize_times(System_Functions *system, Editing_File *file, char *filename){ + u64 stamp = system->file_time_stamp(filename); + if (stamp > 0){ + file->state.last_4ed_write_time = stamp; + file->state.last_4ed_edit_time = stamp; + file->state.last_sys_write_time = stamp; + } + file->state.sync = buffer_get_sync(file); +} + +internal b32 +file_save(System_Functions *system, Mem_Options *mem, Editing_File *file, char *filename){ + b32 result = 0; + + i32 max, size; + b32 dos_write_mode = file->settings.dos_write_mode; + char *data; + Buffer_Type *buffer = &file->state.buffer; + + if (dos_write_mode){ + max = buffer_size(buffer) + buffer->line_count + 1; + } + else{ + max = buffer_size(buffer); + } + + Temp_Memory temp = begin_temp_memory(&mem->part); + char empty = 0; + if (max == 0){ + data = ∅ + } + else{ + data = (char*)push_array(&mem->part, char, max); + } + Assert(data); + + if (dos_write_mode){ + size = buffer_convert_out(buffer, data, max); + } + else{ + size = max; + buffer_stringify(buffer, 0, size, data); + } + + result = system->file_save(filename, data, size); + + file_synchronize_times(system, file, filename); + + end_temp_memory(temp); + + return(result); +} + +inline b32 +file_save_and_set_names(System_Functions *system, Mem_Options *mem, + Working_Set *working_set, Editing_File *file, + char *filename){ + b32 result = 0; + result = file_save(system, mem, file, filename); + if (result){ + file_set_name(working_set, file, filename); + } + return result; +} + +enum File_Bubble_Type{ + BUBBLE_BUFFER = 1, + BUBBLE_STARTS, + BUBBLE_WIDTHS, + BUBBLE_WRAPS, + BUBBLE_TOKENS, + BUBBLE_UNDO_STRING, + BUBBLE_UNDO, + BUBBLE_UNDO_CHILDREN, + // + FILE_BUBBLE_TYPE_END, +}; + +#define GROW_FAILED 0 +#define GROW_NOT_NEEDED 1 +#define GROW_SUCCESS 2 + +internal i32 +file_grow_starts_widths_as_needed(General_Memory *general, Buffer_Type *buffer, i32 additional_lines){ + b32 result = GROW_NOT_NEEDED; + i32 max = buffer->line_max; + i32 count = buffer->line_count; + i32 target_lines = count + additional_lines; + Assert(max == buffer->widths_max); + + if (target_lines > max || max == 0){ + max = LargeRoundUp(target_lines + max, Kbytes(1)); + + f32 *new_widths = (f32*)general_memory_reallocate( + general, buffer->line_widths, + sizeof(f32)*count, sizeof(f32)*max, BUBBLE_WIDTHS); + + i32 *new_lines = (i32*)general_memory_reallocate( + general, buffer->line_starts, + sizeof(i32)*count, sizeof(i32)*max, BUBBLE_STARTS); + + if (new_lines){ + buffer->line_starts = new_lines; + buffer->line_max = max; + } + if (new_widths){ + buffer->line_widths = new_widths; + buffer->widths_max = max; + } + if (new_lines && new_widths){ + result = GROW_SUCCESS; + } + else{ + result = GROW_FAILED; + } + } + + return(result); +} + +internal void +file_measure_starts_widths(System_Functions *system, General_Memory *general, + Buffer_Type *buffer, float *advance_data){ + if (!buffer->line_starts){ + i32 max = buffer->line_max = Kbytes(1); + buffer->line_starts = (i32*)general_memory_allocate(general, max*sizeof(i32), BUBBLE_STARTS); + TentativeAssert(buffer->line_starts); + // TODO(allen): when unable to allocate? + } + if (!buffer->line_widths){ + i32 max = buffer->widths_max = Kbytes(1); + buffer->line_widths = (f32*)general_memory_allocate(general, max*sizeof(f32), BUBBLE_WIDTHS); + TentativeAssert(buffer->line_starts); + // TODO(allen): when unable to allocate? + } + + Buffer_Measure_Starts state = {}; + while (buffer_measure_starts_widths(&state, buffer, advance_data)){ + i32 count = state.count; + i32 max = buffer->line_max; + max = ((max + 1) << 1); + + { + i32 *new_lines = (i32*)general_memory_reallocate( + general, buffer->line_starts, sizeof(i32)*count, sizeof(i32)*max, BUBBLE_STARTS); + + // TODO(allen): when unable to grow? + TentativeAssert(new_lines); + buffer->line_starts = new_lines; + buffer->line_max = max; + } + + { + f32 *new_lines = (f32*) + general_memory_reallocate(general, buffer->line_widths, + sizeof(f32)*count, sizeof(f32)*max, BUBBLE_WIDTHS); + + // TODO(allen): when unable to grow? + TentativeAssert(new_lines); + buffer->line_widths = new_lines; + buffer->widths_max = max; + } + + } + buffer->line_count = state.count; + buffer->widths_count = state.count; +} + +struct Opaque_Font_Advance{ + void *data; + int stride; +}; + +inline Opaque_Font_Advance +get_opaque_font_advance(Render_Font *font){ + Opaque_Font_Advance result; + result.data = (char*)font->chardata + OffsetOfPtr(font->chardata, xadvance); + result.stride = sizeof(*font->chardata); + return result; +} + +inline i32 +view_wrapped_line_span(f32 line_width, f32 max_width){ + i32 line_count = CEIL32(line_width / max_width); + if (line_count == 0) line_count = 1; + return line_count; +} + +internal i32 +view_compute_lowest_line(View *view){ + i32 lowest_line = 0; + i32 last_line = view->file_data.line_count - 1; + if (last_line > 0){ + if (view->file_data.unwrapped_lines){ + lowest_line = last_line; + } + else{ + f32 wrap_y = view->file_data.line_wrap_y[last_line]; + lowest_line = FLOOR32(wrap_y / view->font_height); + f32 max_width = view_file_width(view); + + Editing_File *file = view->file_data.file; + Assert(!file->is_dummy); + f32 width = file->state.buffer.line_widths[last_line]; + i32 line_span = view_wrapped_line_span(width, max_width); + lowest_line += line_span - 1; + } + } + return lowest_line; +} + +internal void +view_measure_wraps(General_Memory *general, View *view){ + Buffer_Type *buffer; + + buffer = &view->file_data.file->state.buffer; + i32 line_count = buffer->line_count; + + if (view->file_data.line_max < line_count){ + i32 max = view->file_data.line_max = LargeRoundUp(line_count, Kbytes(1)); + if (view->file_data.line_wrap_y){ + view->file_data.line_wrap_y = (f32*) + general_memory_reallocate_nocopy(general, view->file_data.line_wrap_y, sizeof(f32)*max, BUBBLE_WRAPS); + } + else{ + view->file_data.line_wrap_y = (f32*) + general_memory_allocate(general, sizeof(f32)*max, BUBBLE_WRAPS); + } + } + + f32 line_height = (f32)view->font_height; + f32 max_width = view_file_width(view); + buffer_measure_wrap_y(buffer, view->file_data.line_wrap_y, line_height, max_width); + + view->file_data.line_count = line_count; +} + +internal void +file_create_from_string(System_Functions *system, Models *models, + Editing_File *file, char *filename, String val, b8 read_only = 0){ + + Font_Set *font_set = models->font_set; + Working_Set *working_set = &models->working_set; + General_Memory *general = &models->mem.general; + Partition *part = &models->mem.part; + Buffer_Init_Type init; + i32 page_size, scratch_size, init_success; + + file->state = editing_file_state_zero(); + + init = buffer_begin_init(&file->state.buffer, val.str, val.size); + for (; buffer_init_need_more(&init); ){ + page_size = buffer_init_page_size(&init); + page_size = LargeRoundUp(page_size, Kbytes(4)); + if (page_size < Kbytes(4)) page_size = Kbytes(4); + void *data = general_memory_allocate(general, page_size, BUBBLE_BUFFER); + buffer_init_provide_page(&init, data, page_size); + } + + scratch_size = partition_remaining(part); + Assert(scratch_size > 0); + init_success = buffer_end_init(&init, part->base + part->pos, scratch_size); + AllowLocal(init_success); + Assert(init_success); + + if (buffer_size(&file->state.buffer) < val.size){ + file->settings.dos_write_mode = 1; + } + + file_init_strings(file); + file_set_name(working_set, file, (char*)filename); + + file->state.font_id = models->global_font.font_id; + + file_synchronize_times(system, file, filename); + + Render_Font *font = get_font_info(font_set, file->state.font_id)->font; + float *advance_data = 0; + if (font) advance_data = font->advance_data; + file_measure_starts_widths(system, general, &file->state.buffer, advance_data); + + file->settings.read_only = read_only; + if (!read_only){ + // TODO(allen): Redo undo system (if you don't mind the pun) + i32 request_size = Kbytes(64); + file->state.undo.undo.max = request_size; + file->state.undo.undo.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); + file->state.undo.undo.edit_max = request_size / sizeof(Edit_Step); + file->state.undo.undo.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO); + + file->state.undo.redo.max = request_size; + file->state.undo.redo.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); + file->state.undo.redo.edit_max = request_size / sizeof(Edit_Step); + file->state.undo.redo.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO); + + file->state.undo.history.max = request_size; + file->state.undo.history.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); + file->state.undo.history.edit_max = request_size / sizeof(Edit_Step); + file->state.undo.history.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO); + + file->state.undo.children.max = request_size; + file->state.undo.children.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); + file->state.undo.children.edit_max = request_size / sizeof(Buffer_Edit); + file->state.undo.children.edits = (Buffer_Edit*)general_memory_allocate(general, request_size, BUBBLE_UNDO); + + file->state.undo.history_block_count = 1; + file->state.undo.history_head_block = 0; + file->state.undo.current_block_normal = 1; + } + + Hook_Function *open_hook = models->hooks[hook_open_file]; + models->buffer_param_indices[models->buffer_param_count++] = file->id.id; + open_hook(&models->app_links); + models->buffer_param_count = 0; + file->settings.is_initialized = 1; +} + +internal b32 +file_create_empty(System_Functions *system, + Models *models, Editing_File *file, char *filename){ + file_create_from_string(system, models, file, filename, string_zero()); + return (1); +} + +internal b32 +file_create_read_only(System_Functions *system, + Models *models, Editing_File *file, char *filename){ + file_create_from_string(system, models, file, filename, string_zero(), 1); + return (1); +} + +internal void +file_close(System_Functions *system, General_Memory *general, Editing_File *file){ + if (file->state.still_lexing){ + system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); + if (file->state.swap_stack.tokens){ + general_memory_free(general, file->state.swap_stack.tokens); + file->state.swap_stack.tokens = 0; + } + } + if (file->state.token_stack.tokens){ + general_memory_free(general, file->state.token_stack.tokens); + } + + Buffer_Type *buffer = &file->state.buffer; + if (buffer->data){ + general_memory_free(general, buffer->data); + general_memory_free(general, buffer->line_starts); + general_memory_free(general, buffer->line_widths); + } + + if (file->state.undo.undo.edits){ + general_memory_free(general, file->state.undo.undo.strings); + general_memory_free(general, file->state.undo.undo.edits); + + general_memory_free(general, file->state.undo.redo.strings); + general_memory_free(general, file->state.undo.redo.edits); + + general_memory_free(general, file->state.undo.history.strings); + general_memory_free(general, file->state.undo.history.edits); + + general_memory_free(general, file->state.undo.children.strings); + general_memory_free(general, file->state.undo.children.edits); + } +} + +struct Shift_Information{ + i32 start, end, amount; +}; + +internal +Job_Callback_Sig(job_full_lex){ + Editing_File *file = (Editing_File*)data[0]; + General_Memory *general = (General_Memory*)data[1]; + + Cpp_File cpp_file; + cpp_file.data = file->state.buffer.data; + cpp_file.size = file->state.buffer.size; + + Cpp_Token_Stack tokens; + tokens.tokens = (Cpp_Token*)memory->data; + tokens.max_count = memory->size / sizeof(Cpp_Token); + tokens.count = 0; + + Cpp_Lex_Data status = {}; + + do{ + for (i32 r = 2048; r > 0 && status.pos < cpp_file.size; --r){ + Cpp_Lex_Data prev_lex = status; + Cpp_Read_Result step_result = cpp_lex_step(cpp_file, &status); + + if (step_result.has_result){ + if (!cpp_push_token_nonalloc(&tokens, step_result.token)){ + status = prev_lex; + system->grow_thread_memory(memory); + tokens.tokens = (Cpp_Token*)memory->data; + tokens.max_count = memory->size / sizeof(Cpp_Token); + } + } + } + + if (status.pos >= cpp_file.size){ + status.complete = 1; + } + else{ + if (system->check_cancel(thread)){ + return; + } + } + } while(!status.complete); + + i32 new_max = LargeRoundUp(tokens.count+1, Kbytes(1)); + + system->acquire_lock(FRAME_LOCK); + { + Assert(file->state.swap_stack.tokens == 0); + file->state.swap_stack.tokens = (Cpp_Token*) + general_memory_allocate(general, new_max*sizeof(Cpp_Token), BUBBLE_TOKENS); + } + system->release_lock(FRAME_LOCK); + + u8 *dest = (u8*)file->state.swap_stack.tokens; + u8 *src = (u8*)tokens.tokens; + + memcpy(dest, src, tokens.count*sizeof(Cpp_Token)); + + system->acquire_lock(FRAME_LOCK); + { + Cpp_Token_Stack *file_stack = &file->state.token_stack; + file_stack->count = tokens.count; + file_stack->max_count = new_max; + if (file_stack->tokens){ + general_memory_free(general, file_stack->tokens); + } + file_stack->tokens = file->state.swap_stack.tokens; + file->state.swap_stack.tokens = 0; + } + system->release_lock(FRAME_LOCK); + + // NOTE(allen): These are outside the locked section because I don't + // think getting these out of order will cause critical bugs, and I + // want to minimize what's done in locked sections. + file->state.tokens_complete = 1; + file->state.still_lexing = 0; +} + + +internal void +file_kill_tokens(System_Functions *system, + General_Memory *general, Editing_File *file){ + file->settings.tokens_exist = 0; + if (file->state.still_lexing){ + system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); + if (file->state.swap_stack.tokens){ + general_memory_free(general, file->state.swap_stack.tokens); + file->state.swap_stack.tokens = 0; + } + } + if (file->state.token_stack.tokens){ + general_memory_free(general, file->state.token_stack.tokens); + } + file->state.tokens_complete = 0; + file->state.token_stack = cpp_token_stack_zero(); +} + +#if BUFFER_EXPERIMENT_SCALPEL <= 0 +internal void +file_first_lex_parallel(System_Functions *system, + General_Memory *general, Editing_File *file){ + file->settings.tokens_exist = 1; + + if (file->is_loading == 0 && file->state.still_lexing == 0){ + Assert(file->state.token_stack.tokens == 0); + + file->state.tokens_complete = 0; + file->state.still_lexing = 1; + + Job_Data job; + job.callback = job_full_lex; + job.data[0] = file; + job.data[1] = general; + job.memory_request = Kbytes(64); + file->state.lex_job = system->post_job(BACKGROUND_THREADS, job); + } +} +#endif + +internal void +file_relex_parallel(System_Functions *system, + Mem_Options *mem, Editing_File *file, + i32 start_i, i32 end_i, i32 amount){ + General_Memory *general = &mem->general; + Partition *part = &mem->part; + if (file->state.token_stack.tokens == 0){ + file_first_lex_parallel(system, general, file); + return; + } + + b32 inline_lex = !file->state.still_lexing; + if (inline_lex){ + Cpp_File cpp_file; + cpp_file.data = file->state.buffer.data; + cpp_file.size = file->state.buffer.size; + + Cpp_Token_Stack *stack = &file->state.token_stack; + + Cpp_Relex_State state = + cpp_relex_nonalloc_start(cpp_file, stack, + start_i, end_i, amount, 100); + + Temp_Memory temp = begin_temp_memory(part); + i32 relex_end; + Cpp_Token_Stack relex_space; + relex_space.count = 0; + relex_space.max_count = state.space_request; + relex_space.tokens = push_array(part, Cpp_Token, relex_space.max_count); + if (cpp_relex_nonalloc_main(&state, &relex_space, &relex_end)){ + inline_lex = 0; + } + else{ + i32 delete_amount = relex_end - state.start_token_i; + i32 shift_amount = relex_space.count - delete_amount; + + if (shift_amount != 0){ + int new_count = stack->count + shift_amount; + if (new_count > stack->max_count){ + int new_max = LargeRoundUp(new_count, Kbytes(1)); + stack->tokens = (Cpp_Token*) + general_memory_reallocate(general, stack->tokens, + stack->count*sizeof(Cpp_Token), + new_max*sizeof(Cpp_Token), BUBBLE_TOKENS); + stack->max_count = new_max; + } + + int shift_size = stack->count - relex_end; + if (shift_size > 0){ + Cpp_Token *old_base = stack->tokens + relex_end; + memmove(old_base + shift_amount, old_base, + sizeof(Cpp_Token)*shift_size); + } + + stack->count += shift_amount; + } + + memcpy(state.stack->tokens + state.start_token_i, relex_space.tokens, + sizeof(Cpp_Token)*relex_space.count); + } + + end_temp_memory(temp); + } + + if (!inline_lex){ + Cpp_Token_Stack *stack = &file->state.token_stack; + Cpp_Get_Token_Result get_token_result = cpp_get_token(stack, end_i); + i32 end_token_i = get_token_result.token_index; + + if (end_token_i < 0) end_token_i = 0; + else if (end_i > stack->tokens[end_token_i].start) ++end_token_i; + + cpp_shift_token_starts(stack, end_token_i, amount); + --end_token_i; + if (end_token_i >= 0){ + Cpp_Token *token = stack->tokens + end_token_i; + if (token->start < end_i && token->start + token->size > end_i){ + token->size += amount; + } + } + + file->state.still_lexing = 1; + + Job_Data job; + job.callback = job_full_lex; + job.data[0] = file; + job.data[1] = general; + job.memory_request = Kbytes(64); + file->state.lex_job = system->post_job(BACKGROUND_THREADS, job); + } +} + +internal void +undo_stack_grow_string(General_Memory *general, 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 = (u8*) + general_memory_reallocate(general, old_str, old_max, new_max); + stack->strings = new_str; + stack->max = new_max; +} + +internal void +undo_stack_grow_edits(General_Memory *general, 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 = (Edit_Step*) + general_memory_reallocate(general, old_eds, old_max*sizeof(Edit_Step), new_max*sizeof(Edit_Step)); + stack->edits = new_eds; + stack->edit_max = new_max; +} + +internal void +child_stack_grow_string(General_Memory *general, 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 = (u8*) + general_memory_reallocate(general, old_str, old_max, new_max); + stack->strings = new_str; + stack->max = new_max; +} + +internal void +child_stack_grow_edits(General_Memory *general, 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 = (Buffer_Edit*) + general_memory_reallocate(general, old_eds, old_max*sizeof(Buffer_Edit), new_max*sizeof(Buffer_Edit)); + stack->edits = new_eds; + stack->edit_max = new_max; +} + +internal i32 +undo_children_push(General_Memory *general, 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(general, children, edit_count); + + if (children->size + string_size > children->max) + child_stack_grow_string(general, 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; +} + +struct Edit_Spec{ + u8 *str; + Edit_Step step; +}; + +internal Edit_Step* +file_post_undo(General_Memory *general, 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(general, 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.pre_pos = step.pre_pos; + inv_step.post_pos = step.post_pos; + 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; + inv_step.pre_pos = prev.pre_pos; + } + } + } + + 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(general, 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(general, undo); + result = undo->edits + (undo->edit_count++); + *result = inv_step; + } + return result; +} + +inline 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(General_Memory *general, 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(general, 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.pre_pos = step.pre_pos; + inv_step.post_pos = step.post_pos; + inv_step.type = ED_REDO; + + if (redo->edit_count == redo->edit_max) + undo_stack_grow_edits(general, 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(general, redo); + } + redo->edits[redo->edit_count++] = inv_step; + } +} + +inline 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; +} + +inline 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(General_Memory *general, Editing_File *file, + Edit_Step step, b32 do_merge, b32 can_merge){ + Edit_Stack *history = &file->state.undo.history; + Edit_Step *result = 0; + + 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(general, 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.pre_pos = step.pre_pos; + inv_step.post_pos = step.post_pos; + inv_step.can_merge = (b8)can_merge; + inv_step.type = reverse_types[step.type]; + + bool32 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; + inv_step.pre_pos = prev.pre_pos; + } + } + } + + if (did_merge){ + result = history->edits + (history->edit_count-1); + } + else{ + if (history->edit_count == history->edit_max) + undo_stack_grow_edits(general, 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(general, history); + result = history->edits + (history->edit_count++); + *result = inv_step; + } + + return result; +} + +inline Full_Cursor +view_compute_cursor_from_pos(View *view, i32 pos){ + Editing_File *file = view->file_data.file; + Models *models = view->persistent.models; + Render_Font *font = get_font_info(models->font_set, models->global_font.font_id)->font; + + Full_Cursor result = {}; + if (font){ + f32 max_width = view_file_width(view); + result = buffer_cursor_from_pos(&file->state.buffer, pos, view->file_data.line_wrap_y, + max_width, (f32)view->font_height, font->advance_data); + } + return result; +} + +inline Full_Cursor +view_compute_cursor_from_unwrapped_xy(View *view, f32 seek_x, f32 seek_y, b32 round_down = 0){ + Editing_File *file = view->file_data.file; + Models *models = view->persistent.models; + Render_Font *font = get_font_info(models->font_set, models->global_font.font_id)->font; + + Full_Cursor result = {}; + if (font){ + f32 max_width = view_file_width(view); + result = buffer_cursor_from_unwrapped_xy(&file->state.buffer, seek_x, seek_y, + round_down, view->file_data.line_wrap_y, max_width, (f32)view->font_height, font->advance_data); + } + + return result; +} + +internal Full_Cursor +view_compute_cursor_from_wrapped_xy(View *view, f32 seek_x, f32 seek_y, b32 round_down = 0){ + Editing_File *file = view->file_data.file; + Models *models = view->persistent.models; + Render_Font *font = get_font_info(models->font_set, models->global_font.font_id)->font; + + Full_Cursor result = {}; + if (font){ + f32 max_width = view_file_width(view); + result = buffer_cursor_from_wrapped_xy(&file->state.buffer, seek_x, seek_y, + round_down, view->file_data.line_wrap_y, + max_width, (f32)view->font_height, font->advance_data); + } + + return (result); +} + +internal Full_Cursor +view_compute_cursor_from_line_pos(View *view, i32 line, i32 pos){ + Editing_File *file = view->file_data.file; + Models *models = view->persistent.models; + Render_Font *font = get_font_info(models->font_set, models->global_font.font_id)->font; + + Full_Cursor result = {}; + if (font){ + f32 max_width = view_file_width(view); + result = buffer_cursor_from_line_character(&file->state.buffer, line, pos, + view->file_data.line_wrap_y, max_width, (f32)view->font_height, font->advance_data); + } + + return (result); +} + +inline Full_Cursor +view_compute_cursor(View *view, Buffer_Seek seek){ + Full_Cursor result = {}; + + switch(seek.type){ + case buffer_seek_pos: + result = view_compute_cursor_from_pos(view, seek.pos); + break; + + case buffer_seek_wrapped_xy: + result = view_compute_cursor_from_wrapped_xy(view, seek.x, seek.y); + break; + + case buffer_seek_unwrapped_xy: + result = view_compute_cursor_from_unwrapped_xy(view, seek.x, seek.y); + break; + + case buffer_seek_line_char: + result = view_compute_cursor_from_line_pos(view, seek.line, seek.character); + break; + } + + return (result); +} + +inline Full_Cursor +view_compute_cursor_from_xy(View *view, f32 seek_x, f32 seek_y){ + Full_Cursor result; + if (view->file_data.unwrapped_lines) result = view_compute_cursor_from_unwrapped_xy(view, seek_x, seek_y); + else result = view_compute_cursor_from_wrapped_xy(view, seek_x, seek_y); + return result; +} + +inline void +view_set_temp_highlight(View *view, i32 pos, i32 end_pos){ + view->file_data.temp_highlight = view_compute_cursor_from_pos(view, pos); + view->file_data.temp_highlight_end_pos = end_pos; + view->file_data.show_temp_highlight = 1; +} + +inline i32 +view_get_cursor_pos(View *view){ + i32 result; + if (view->file_data.show_temp_highlight){ + result = view->file_data.temp_highlight.pos; + } + else{ + result = view->recent->cursor.pos; + } + return result; +} + +inline f32 +view_get_cursor_x(View *view){ + f32 result; + Full_Cursor *cursor; + if (view->file_data.show_temp_highlight){ + cursor = &view->file_data.temp_highlight; + } + else{ + cursor = &view->recent->cursor; + } + if (view->file_data.unwrapped_lines){ + result = cursor->unwrapped_x; + } + else{ + result = cursor->wrapped_x; + } + return result; +} + +inline f32 +view_get_cursor_y(View *view){ + Full_Cursor *cursor; + f32 result; + + if (view->file_data.show_temp_highlight) cursor = &view->file_data.temp_highlight; + else cursor = &view->recent->cursor; + + if (view->file_data.unwrapped_lines) result = cursor->unwrapped_y; + else result = cursor->wrapped_y; + + return result; +} + +#define CursorMaxY_(m,h) ((m) - (h)*3) +#define CursorMinY_(m,h) (-(m) + (h)*2) + +#define CursorMaxY(m,h) (CursorMaxY_(m,h) > 0)?(CursorMaxY_(m,h)):(0) +#define CursorMinY(m,h) (CursorMinY_(m,h) > 0)?(CursorMinY_(m,h)):(0) + +internal void +view_move_cursor_to_view(View *view){ + f32 min_target_y = 0; + i32 line_height = view->font_height; + f32 old_cursor_y = view_get_cursor_y(view); + f32 cursor_y = old_cursor_y; + f32 target_y = view->recent->scroll.target_y; + f32 cursor_max_y = CursorMaxY(view_file_height(view), line_height); + f32 cursor_min_y = CursorMinY(min_target_y, line_height); + + if (cursor_y > target_y + cursor_max_y){ + cursor_y = target_y + cursor_max_y; + } + if (target_y != 0 && cursor_y < target_y + cursor_min_y){ + cursor_y = target_y + cursor_min_y; + } + + if (cursor_y != old_cursor_y){ + if (cursor_y > old_cursor_y){ + cursor_y += line_height; + } + else{ + cursor_y -= line_height; + } + view->recent->cursor = + view_compute_cursor_from_xy(view, view->recent->preferred_x, cursor_y); + } +} + +internal void +view_move_view_to_cursor(View *view, GUI_Scroll_Vars *scroll){ + f32 line_height = (f32)view->font_height; + f32 delta_y = 3.f*line_height; + + f32 max_visible_y = view_file_height(view); + f32 max_x = view_file_width(view); + + f32 cursor_y = view_get_cursor_y(view); + f32 cursor_x = view_get_cursor_x(view); + + GUI_Scroll_Vars scroll_vars = *scroll; + f32 target_y = scroll_vars.target_y; + f32 target_x = scroll_vars.target_x; + + f32 cursor_max_y = CursorMaxY(max_visible_y, line_height); + f32 cursor_min_y = CursorMinY(0, line_height); + + if (cursor_y > target_y + cursor_max_y){ + target_y = cursor_y - cursor_max_y + delta_y; + } + if (cursor_y < target_y + cursor_min_y){ + target_y = cursor_y - delta_y - cursor_min_y; + } + + target_y = clamp(0.f, target_y, scroll_vars.max_y); + + if (cursor_x < target_x){ + target_x = (f32)Max(0, cursor_x - max_x/2); + } + else if (cursor_x >= target_x + max_x){ + target_x = (f32)(cursor_x - max_x/2); + } + + if (target_x != scroll_vars.target_x || target_y != scroll_vars.target_y){ + scroll->target_x = target_x; + scroll->target_y = target_y; + } +} + +inline void +file_view_nullify_file(View *view){ + General_Memory *general = &view->persistent.models->mem.general; + if (view->file_data.line_wrap_y){ + general_memory_free(general, view->file_data.line_wrap_y); + } + view->file_data = file_viewing_data_zero(); +} + +inline f32 +view_compute_max_target_y(i32 lowest_line, i32 line_height, f32 view_height){ + f32 max_target_y = ((lowest_line+.5f)*line_height) - view_height*.5f; + max_target_y = clamp_bottom(0.f, max_target_y); + return(max_target_y); +} + +internal f32 +view_compute_max_target_y(View *view){ + i32 lowest_line = view_compute_lowest_line(view); + i32 line_height = view->font_height; + f32 view_height = view_file_height(view); + f32 max_target_y = view_compute_max_target_y(lowest_line, line_height, view_height); + return(max_target_y); +} + +internal void +view_set_file(View *view, Editing_File *file, Models *models){ + Font_Info *fnt_info; + + // TODO(allen): This belongs somewhere else. + fnt_info = get_font_info(models->font_set, models->global_font.font_id); + view->font_advance = fnt_info->advance; + view->font_height = fnt_info->height; + + file_view_nullify_file(view); + view->file_data.file = file; + + if (file){ + u64 unique_buffer_id = file->unique_buffer_id; + Recent_File_Data *recent = view->recent; + Recent_File_Data temp_recent = {0}; + i32 i = 0; + i32 max = ArrayCount(view->recent)-1; + b32 found_recent_entry = 0; + + view->file_data.unwrapped_lines = file->settings.unwrapped_lines; + + for (; i < max; ++i, ++recent){ + if (recent->unique_buffer_id == unique_buffer_id){ + temp_recent = *recent; + memmove(view->recent+1, view->recent, sizeof(*recent)*i); + view->recent[0] = temp_recent; + found_recent_entry = 1; + break; + } + } + + if (found_recent_entry){ + if (file_is_ready(file)){ + view_measure_wraps(&models->mem.general, view); + view->recent->cursor = view_compute_cursor_from_pos(view, view->recent->cursor.pos); + view->recent->scroll.max_y = view_compute_max_target_y(view); + + view_move_view_to_cursor(view, &view->recent->scroll); + } + } + else{ + i = 15; + recent = view->recent + i; + memmove(view->recent+1, view->recent, sizeof(*recent)*i); + view->recent[0] = recent_file_data_zero(); + + recent = view->recent; + recent->unique_buffer_id = unique_buffer_id; + + if (file_is_ready(file)){ + view_measure_wraps(&models->mem.general, view); + view->recent->cursor = view_compute_cursor_from_pos(view, file->state.cursor_pos); + view->recent->scroll.max_y = view_compute_max_target_y(view); + + view_move_view_to_cursor(view, &view->recent->scroll); + view->reinit_scrolling = 1; + } + } + } +} + +struct Relative_Scrolling{ + f32 scroll_x, scroll_y; + f32 target_x, target_y; +}; + +internal Relative_Scrolling +view_get_relative_scrolling(View *view){ + Relative_Scrolling result; + f32 cursor_y; + cursor_y = view_get_cursor_y(view); + result.scroll_y = cursor_y - view->recent->scroll.scroll_y; + result.target_y = cursor_y - view->recent->scroll.target_y; + return(result); +} + +internal void +view_set_relative_scrolling(View *view, Relative_Scrolling scrolling){ + f32 cursor_y; + cursor_y = view_get_cursor_y(view); + view->recent->scroll.scroll_y = cursor_y - scrolling.scroll_y; + view->recent->scroll.target_y = + clamp_bottom(0.f, cursor_y - scrolling.target_y); +} + +inline void +view_cursor_move(View *view, Full_Cursor cursor){ + view->recent->cursor = cursor; + view->recent->preferred_x = view_get_cursor_x(view); + view->file_data.file->state.cursor_pos = view->recent->cursor.pos; + view->file_data.show_temp_highlight = 0; +} + +inline void +view_cursor_move(View *view, i32 pos){ + Full_Cursor cursor = view_compute_cursor_from_pos(view, pos); + view_cursor_move(view, cursor); +} + +inline void +view_cursor_move(View *view, f32 x, f32 y, b32 round_down = 0){ + Full_Cursor cursor; + if (view->file_data.unwrapped_lines){ + cursor = view_compute_cursor_from_unwrapped_xy(view, x, y, round_down); + } + else{ + cursor = view_compute_cursor_from_wrapped_xy(view, x, y, round_down); + } + view_cursor_move(view, cursor); +} + +inline void +view_cursor_move(View *view, i32 line, i32 pos){ + Full_Cursor cursor = view_compute_cursor_from_line_pos(view, line, pos); + view_cursor_move(view, cursor); +} + +inline void +view_set_widget(View *view, View_Widget_Type type){ + view->widget.type = type; +} + + +inline i32_Rect +view_widget_rect(View *view, i32 font_height){ + Panel *panel = view->panel; + i32_Rect result = panel->inner; + + if (view->file_data.file){ + result.y0 = result.y0 + font_height + 2; + } + + return(result); +} + +enum History_Mode{ + hist_normal, + hist_backward, + hist_forward +}; + +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; + General_Memory *general = &mem->general; + + 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(general, file, step, do_merge, can_merge); + + file_post_undo(general, file, step, do_merge, can_merge); + }break; + + case ED_REVERSE_NORMAL: + { + if (history_mode != hist_forward) + file_post_history(general, 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(general, &file->state.undo.redo); + + if (file->state.undo.redo.size + strings_of_redo > file->state.undo.redo.max) + undo_stack_grow_string(general, &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(general, file, step, do_merge, can_merge); + file_post_redo(general, 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(general, file, step, do_merge, can_merge); + + file_post_undo(general, 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; + } +} + +inline void +file_pre_edit_maintenance(System_Functions *system, + General_Memory *general, + Editing_File *file){ + if (file->state.still_lexing){ + system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); + if (file->state.swap_stack.tokens){ + general_memory_free(general, file->state.swap_stack.tokens); + file->state.swap_stack.tokens = 0; + } + file->state.still_lexing = 0; + } + file->state.last_4ed_edit_time = system->now_time_stamp(); +} + +struct Cursor_Fix_Descriptor{ + b32 is_batch; + union{ + struct{ + Buffer_Edit *batch; + i32 batch_size; + }; + struct{ + i32 start, end; + i32 shift_amount; + }; + }; +}; + +internal void +file_edit_cursor_fix(System_Functions *system, + Partition *part, General_Memory *general, + Editing_File *file, Editing_Layout *layout, + Cursor_Fix_Descriptor desc){ + + Full_Cursor temp_cursor; + Temp_Memory cursor_temp = begin_temp_memory(part); + i32 cursor_max = layout->panel_max_count * 2; + Cursor_With_Index *cursors = push_array(part, Cursor_With_Index, cursor_max); + + f32 y_offset = 0, y_position = 0; + i32 cursor_count = 0; + + View *view; + Panel *panel, *used_panels; + used_panels = &layout->used_sentinel; + + for (dll_items(panel, used_panels)){ + view = panel->view; + if (view->file_data.file == file){ + view_measure_wraps(general, view); + write_cursor_with_index(cursors, &cursor_count, view->recent->cursor.pos); + write_cursor_with_index(cursors, &cursor_count, view->recent->mark - 1); + write_cursor_with_index(cursors, &cursor_count, view->recent->scroll_i - 1); + } + } + + if (cursor_count > 0){ + buffer_sort_cursors(cursors, cursor_count); + if (desc.is_batch){ + buffer_batch_edit_update_cursors(cursors, cursor_count, + desc.batch, desc.batch_size); + } + else{ + buffer_update_cursors(cursors, cursor_count, + desc.start, desc.end, + desc.shift_amount + (desc.end - desc.start)); + } + buffer_unsort_cursors(cursors, cursor_count); + + cursor_count = 0; + for (dll_items(panel, used_panels)){ + view = panel->view; + if (view && view->file_data.file == file){ + view_cursor_move(view, cursors[cursor_count++].pos); + view->recent->preferred_x = view_get_cursor_x(view); + + view->recent->mark = cursors[cursor_count++].pos + 1; + i32 new_scroll_i = cursors[cursor_count++].pos + 1; + if (view->recent->scroll_i != new_scroll_i){ + view->recent->scroll_i = new_scroll_i; + temp_cursor = view_compute_cursor_from_pos(view, view->recent->scroll_i); + y_offset = MOD(view->recent->scroll.scroll_y, view->font_height); + + if (view->file_data.unwrapped_lines){ + y_position = temp_cursor.unwrapped_y + y_offset; + view->recent->scroll.target_y += (y_position - view->recent->scroll.scroll_y); + view->recent->scroll.scroll_y = y_position; + } + else{ + y_position = temp_cursor.wrapped_y + y_offset; + view->recent->scroll.target_y += (y_position - view->recent->scroll.scroll_y); + view->recent->scroll.scroll_y = y_position; + } + } + } + } + } + + end_temp_memory(cursor_temp); +} + +internal void +file_do_single_edit(System_Functions *system, + Models *models, Editing_File *file, + Edit_Spec spec, History_Mode history_mode, b32 use_high_permission = 0){ + if (!use_high_permission && file->settings.read_only) return; + + Mem_Options *mem = &models->mem; + Editing_Layout *layout = &models->layout; + + // NOTE(allen): fixing stuff beforewards???? + file_update_history_before_edit(mem, file, spec.step, spec.str, history_mode); + file_pre_edit_maintenance(system, &mem->general, file); + + // NOTE(allen): actual text replacement + i32 shift_amount = 0; + General_Memory *general = &mem->general; + Partition *part = &mem->part; + + 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 scratch_size = partition_remaining(part); + + Assert(scratch_size > 0); + i32 request_amount = 0; + Assert(end <= buffer_size(&file->state.buffer)); + while (buffer_replace_range(&file->state.buffer, start, end, str, str_len, &shift_amount, + part->base + part->pos, scratch_size, &request_amount)){ + void *new_data = 0; + if (request_amount > 0){ + new_data = general_memory_allocate(general, request_amount, BUBBLE_BUFFER); + } + void *old_data = buffer_edit_provide_memory(&file->state.buffer, new_data, request_amount); + if (old_data) general_memory_free(general, old_data); + } + + Buffer_Type *buffer = &file->state.buffer; + i32 line_start = buffer_get_line_index(&file->state.buffer, start); + i32 line_end = buffer_get_line_index(&file->state.buffer, end); + i32 replaced_line_count = line_end - line_start; + i32 new_line_count = buffer_count_newlines(&file->state.buffer, start, start+str_len); + i32 line_shift = new_line_count - replaced_line_count; + + Render_Font *font = get_font_info(models->font_set, file->state.font_id)->font; + + file_grow_starts_widths_as_needed(general, buffer, line_shift); + buffer_remeasure_starts(buffer, line_start, line_end, line_shift, shift_amount); + buffer_remeasure_widths(buffer, font->advance_data, line_start, line_end, line_shift); + + // NOTE(allen): update the views looking at this file + Panel *panel, *used_panels; + used_panels = &layout->used_sentinel; + + for (dll_items(panel, used_panels)){ + View *view = panel->view; + if (view->file_data.file == file){ + view_measure_wraps(general, view); + } + } + +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + // NOTE(allen): fixing stuff afterwards + if (file->settings.tokens_exist) + file_relex_parallel(system, mem, file, start, end, shift_amount); +#endif + + Cursor_Fix_Descriptor desc = {}; + desc.start = start; + desc.end = end; + desc.shift_amount = shift_amount; + + file_edit_cursor_fix(system, part, general, file, layout, desc); +} + +internal void +file_do_white_batch_edit(System_Functions *system, Models *models, Editing_File *file, + Edit_Spec spec, History_Mode history_mode, b32 use_high_permission = 0){ + if (!use_high_permission && file->settings.read_only) return; + + Mem_Options *mem = &models->mem; + Editing_Layout *layout = &models->layout; + + // NOTE(allen): fixing stuff "beforewards"??? + Assert(spec.str == 0); + file_update_history_before_edit(mem, file, spec.step, 0, history_mode); + file_pre_edit_maintenance(system, &mem->general, file); + + // NOTE(allen): actual text replacement + General_Memory *general = &mem->general; + Partition *part = &mem->part; + + 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); + + i32 scratch_size = partition_remaining(part); + Buffer_Batch_State state = {}; + i32 request_amount; + while (buffer_batch_edit_step(&state, &file->state.buffer, batch, + (char*)str_base, batch_size, part->base + part->pos, + scratch_size, &request_amount)){ + void *new_data = 0; + if (request_amount > 0){ + new_data = general_memory_allocate(general, request_amount, BUBBLE_BUFFER); + } + void *old_data = buffer_edit_provide_memory(&file->state.buffer, new_data, request_amount); + if (old_data) general_memory_free(general, old_data); + } + + // NOTE(allen): meta data + { + Buffer_Measure_Starts state = {}; + Render_Font *font = get_font_info(models->font_set, file->state.font_id)->font; + float *advance_data = 0; + if (font) advance_data = font->advance_data; + buffer_measure_starts_widths(&state, &file->state.buffer, advance_data); + } + + // NOTE(allen): cursor fixing + { + Cursor_Fix_Descriptor desc = {}; + desc.is_batch = 1; + desc.batch = batch; + desc.batch_size = batch_size; + + file_edit_cursor_fix(system, part, general, file, layout, desc); + } + + // NOTE(allen): token fixing + if (file->state.tokens_complete){ + Cpp_Token_Stack tokens = file->state.token_stack; + Cpp_Token *token = tokens.tokens; + Cpp_Token *end_token = tokens.tokens + tokens.count; + Cpp_Token original = {(Cpp_Token_Type)0}; + + Buffer_Edit *edit = batch; + Buffer_Edit *end_edit = batch + batch_size; + + 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)); + 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)); + } + token->size += local_shift; + shift_amount += local_shift; + } + } +} + +inline void +file_replace_range(System_Functions *system, Models *models, Editing_File *file, + i32 start, i32 end, char *str, i32 len, i32 next_cursor, b32 use_high_permission = 0){ + Edit_Spec spec = {}; + spec.step.type = ED_NORMAL; + spec.step.edit.start = start; + spec.step.edit.end = end; + + spec.step.edit.len = len; + spec.step.pre_pos = file->state.cursor_pos; + spec.step.post_pos = next_cursor; + spec.str = (u8*)str; + file_do_single_edit(system, models, file, spec, hist_normal, use_high_permission); +} + +inline void +file_clear(System_Functions *system, Models *models, Editing_File *file, b32 use_high_permission = 0){ + file_replace_range(system, models, file, 0, buffer_size(&file->state.buffer), 0, 0, 0, use_high_permission); +} + +inline void +view_replace_range(System_Functions *system, Models *models, View *view, + i32 start, i32 end, char *str, i32 len, i32 next_cursor){ + file_replace_range(system, models, view->file_data.file, start, end, str, len, next_cursor); +} + +inline void +view_post_paste_effect(View *view, i32 ticks, i32 start, i32 size, u32 color){ + Editing_File *file = view->file_data.file; + + file->state.paste_effect.start = start; + file->state.paste_effect.end = start + size; + file->state.paste_effect.color = color; + file->state.paste_effect.tick_down = ticks; + file->state.paste_effect.tick_max = ticks; +} + +internal Style* +get_style(Models *models, i32 i){ + return (&models->styles.styles[i]); +} + +internal Style* +main_style(Models *models){ + return (get_style(models, 0)); +} + +internal void +view_undo_redo(System_Functions *system, + Models *models, View *view, + Edit_Stack *stack, Edit_Type expected_type){ + Editing_File *file = view->file_data.file; + + if (stack->edit_count > 0){ + Edit_Step step = stack->edits[stack->edit_count-1]; + + Assert(step.type == expected_type); + + Edit_Spec spec = {}; + spec.step = step; + + if (step.child_count == 0){ + spec.step.edit.str_start = 0; + spec.str = stack->strings + step.edit.str_start; + + file_do_single_edit(system, models, file, spec, hist_normal); + + if (expected_type == ED_UNDO) view_cursor_move(view, step.pre_pos); + else view_cursor_move(view, step.post_pos); + view->recent->mark = view->recent->cursor.pos; + + Style *style = main_style(models); + view_post_paste_effect(view, 10, step.edit.start, step.edit.len, + style->main.undo_color); + } + else{ + TentativeAssert(spec.step.special_type == 1); + file_do_white_batch_edit(system, models, view->file_data.file, spec, hist_normal); + } + } +} + +inline void +view_undo(System_Functions *system, Models *models, View *view){ + view_undo_redo(system, models, view, &view->file_data.file->state.undo.undo, ED_UNDO); +} + +inline void +view_redo(System_Functions *system, Models *models, View *view){ + view_undo_redo(system, models, view, &view->file_data.file->state.undo.redo, ED_REDO); +} + +inline u8* +write_data(u8 *ptr, void *x, i32 size){ + memcpy(ptr, x, size); + return (ptr + size); +} + +#define UseFileHistoryDump 0 + +#if UseFileHistoryDump +internal void +file_dump_history(System_Functions *system, Mem_Options *mem, Editing_File *file, char *filename){ + if (!file->state.undo.undo.edits) return; + + i32 size = 0; + + size += sizeof(i32); + size += file->state.undo.undo.edit_count*sizeof(Edit_Step); + size += sizeof(i32); + size += file->state.undo.redo.edit_count*sizeof(Edit_Step); + size += sizeof(i32); + size += file->state.undo.history.edit_count*sizeof(Edit_Step); + size += sizeof(i32); + size += file->state.undo.children.edit_count*sizeof(Buffer_Edit); + + size += sizeof(i32); + size += file->state.undo.undo.size; + size += sizeof(i32); + size += file->state.undo.redo.size; + size += sizeof(i32); + size += file->state.undo.history.size; + size += sizeof(i32); + size += file->state.undo.children.size; + + Partition *part = &mem->part; + i32 remaining = partition_remaining(part); + if (size < remaining){ + u8 *data, *curs; + data = (u8*)part->base + part->pos; + curs = data; + curs = write_data(curs, &file->state.undo.undo.edit_count, 4); + curs = write_data(curs, &file->state.undo.redo.edit_count, 4); + curs = write_data(curs, &file->state.undo.history.edit_count, 4); + curs = write_data(curs, &file->state.undo.children.edit_count, 4); + curs = write_data(curs, &file->state.undo.undo.size, 4); + curs = write_data(curs, &file->state.undo.redo.size, 4); + curs = write_data(curs, &file->state.undo.history.size, 4); + curs = write_data(curs, &file->state.undo.children.size, 4); + + curs = write_data(curs, file->state.undo.undo.edits, sizeof(Edit_Step)*file->state.undo.undo.edit_count); + curs = write_data(curs, file->state.undo.redo.edits, sizeof(Edit_Step)*file->state.undo.redo.edit_count); + curs = write_data(curs, file->state.undo.history.edits, sizeof(Edit_Step)*file->state.undo.history.edit_count); + curs = write_data(curs, file->state.undo.children.edits, sizeof(Buffer_Edit)*file->state.undo.children.edit_count); + + curs = write_data(curs, file->state.undo.undo.strings, file->state.undo.undo.size); + curs = write_data(curs, file->state.undo.redo.strings, file->state.undo.redo.size); + curs = write_data(curs, file->state.undo.history.strings, file->state.undo.history.size); + curs = write_data(curs, file->state.undo.children.strings, file->state.undo.children.size); + + Assert((i32)(curs - data) == size); + system->save_file(filename, data, size); + } +} +#endif + +internal void +view_history_step(System_Functions *system, Models *models, View *view, History_Mode history_mode){ + Assert(history_mode != hist_normal); + + Editing_File *file = view->file_data.file; + + b32 do_history_step = 0; + Edit_Step step = {}; + if (history_mode == hist_backward){ + if (file->state.undo.edit_history_cursor > 0){ + do_history_step = 1; + step = file->state.undo.history.edits[--file->state.undo.edit_history_cursor]; + } + } + else{ + if (file->state.undo.edit_history_cursor < file->state.undo.history.edit_count){ + Assert(((file->state.undo.history.edit_count - file->state.undo.edit_history_cursor) & 1) == 0); + step = file->state.undo.history.edits[--file->state.undo.history.edit_count]; + file->state.undo.history.size -= step.edit.len; + ++file->state.undo.edit_history_cursor; + do_history_step = 1; + } + } + + if (do_history_step){ + Edit_Spec spec; + spec.step = step; + + if (spec.step.child_count == 0){ + spec.step.edit.str_start = 0; + spec.str = file->state.undo.history.strings + step.edit.str_start; + + file_do_single_edit(system, models, file, spec, history_mode); + + switch (spec.step.type){ + case ED_NORMAL: + case ED_REDO: + view_cursor_move(view, step.post_pos); + break; + + case ED_REVERSE_NORMAL: + case ED_UNDO: + view_cursor_move(view, step.pre_pos); + break; + } + view->recent->mark = view->recent->cursor.pos; + } + else{ + TentativeAssert(spec.step.special_type == 1); + file_do_white_batch_edit(system, models, view->file_data.file, spec, history_mode); + } + } +} + +// TODO(allen): write these as streamed operations +internal i32 +view_find_end_of_line(View *view, i32 pos){ +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + Editing_File *file = view->file_data.file; + char *data = file->state.buffer.data; + while (pos < file->state.buffer.size && data[pos] != '\n') ++pos; + if (pos > file->state.buffer.size) pos = file->state.buffer.size; +#endif + return pos; +} + +internal i32 +view_find_beginning_of_line(View *view, i32 pos){ +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + Editing_File *file = view->file_data.file; + char *data = file->state.buffer.data; + if (pos > 0){ + --pos; + while (pos > 0 && data[pos] != '\n') --pos; + if (pos != 0) ++pos; + } +#endif + return pos; +} + +internal i32 +view_find_beginning_of_next_line(View *view, i32 pos){ +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + Editing_File *file = view->file_data.file; + char *data = file->state.buffer.data; + while (pos < file->state.buffer.size && + !starts_new_line(data[pos])){ + ++pos; + } + if (pos < file->state.buffer.size){ + ++pos; + } +#endif + return pos; +} + +internal String* +working_set_next_clipboard_string(General_Memory *general, Working_Set *working, i32 str_size){ + String *result = 0; + i32 clipboard_current = working->clipboard_current; + if (working->clipboard_size == 0){ + clipboard_current = 0; + working->clipboard_size = 1; + } + else{ + ++clipboard_current; + if (clipboard_current >= working->clipboard_max_size){ + clipboard_current = 0; + } + else if (working->clipboard_size <= clipboard_current){ + working->clipboard_size = clipboard_current+1; + } + } + result = &working->clipboards[clipboard_current]; + working->clipboard_current = clipboard_current; + working->clipboard_rolling = clipboard_current; + char *new_str; + if (result->str){ + new_str = (char*)general_memory_reallocate(general, result->str, result->size, str_size); + } + else{ + new_str = (char*)general_memory_allocate(general, str_size+1); + } + // TODO(allen): What if new_str == 0? + *result = make_string(new_str, 0, str_size); + return result; +} + +internal String* +working_set_clipboard_head(Working_Set *working){ + String *result = 0; + if (working->clipboard_size > 0){ + i32 clipboard_index = working->clipboard_current; + working->clipboard_rolling = clipboard_index; + result = &working->clipboards[clipboard_index]; + } + return result; +} + +internal String* +working_set_clipboard_roll_down(Working_Set *working){ + String *result = 0; + if (working->clipboard_size > 0){ + i32 clipboard_index = working->clipboard_rolling; + --clipboard_index; + if (clipboard_index < 0){ + clipboard_index = working->clipboard_size-1; + } + working->clipboard_rolling = clipboard_index; + result = &working->clipboards[clipboard_index]; + } + return result; +} + +internal void +clipboard_copy(System_Functions *system, General_Memory *general, Working_Set *working, Range range, Editing_File *file){ + i32 size = range.end - range.start; + String *dest = working_set_next_clipboard_string(general, working, size); + buffer_stringify(&file->state.buffer, range.start, range.end, dest->str); + dest->size = size; + system->post_clipboard(*dest); +} + +internal Edit_Spec +file_compute_whitespace_edit(Mem_Options *mem, Editing_File *file, i32 cursor_pos, + Buffer_Edit *edits, char *str_base, i32 str_size, + Buffer_Edit *inverse_array, char *inv_str, i32 inv_max, + i32 edit_count){ + General_Memory *general = &mem->general; + + 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)){ + Assert(0); + } + + i32 first_child = + undo_children_push(general, &file->state.undo.children, + edits, edit_count, (u8*)(str_base), str_size); + i32 inverse_first_child = + undo_children_push(general, &file->state.undo.children, + inverse_array, edit_count, (u8*)(inv_str), inv_str_pos); + + Edit_Spec spec = {}; + spec.step.type = ED_NORMAL; + spec.step.first_child = first_child; + spec.step.inverse_first_child = inverse_first_child; + spec.step.special_type = 1; + spec.step.child_count = edit_count; + spec.step.inverse_child_count = edit_count; + spec.step.pre_pos = cursor_pos; + spec.step.post_pos = cursor_pos; + + return spec; +} + +internal void +view_clean_whitespace(System_Functions *system, Models *models, View *view){ + Mem_Options *mem = &models->mem; + Editing_File *file = view->file_data.file; + + Partition *part = &mem->part; + i32 line_count = file->state.buffer.line_count; + i32 edit_max = line_count * 2; + i32 edit_count = 0; + + Assert(file && !file->is_dummy); + + Temp_Memory temp = begin_temp_memory(part); + Buffer_Edit *edits = push_array(part, Buffer_Edit, edit_max); + + char *str_base = (char*)part->base + part->pos; + i32 str_size = 0; + for (i32 line_i = 0; line_i < line_count; ++line_i){ + i32 start = file->state.buffer.line_starts[line_i]; + Hard_Start_Result hard_start = + buffer_find_hard_start(&file->state.buffer, start, 4); + + if (hard_start.all_whitespace) hard_start.indent_pos = 0; + + if ((hard_start.all_whitespace && hard_start.char_pos > start) || !hard_start.all_space){ + Buffer_Edit new_edit; + new_edit.str_start = str_size; + str_size += hard_start.indent_pos; + char *str = push_array(part, char, hard_start.indent_pos); + for (i32 j = 0; j < hard_start.indent_pos; ++j) str[j] = ' '; + new_edit.len = hard_start.indent_pos; + new_edit.start = start; + new_edit.end = hard_start.char_pos; + edits[edit_count++] = new_edit; + } + Assert(edit_count <= edit_max); + } + + if (edit_count > 0){ + Assert(buffer_batch_debug_sort_check(edits, edit_count)); + + // NOTE(allen): computing edit spec, doing batch edit + Buffer_Edit *inverse_array = push_array(part, Buffer_Edit, edit_count); + Assert(inverse_array); + + char *inv_str = (char*)part->base + part->pos; + Edit_Spec spec = + file_compute_whitespace_edit(mem, file, view->recent->cursor.pos, edits, str_base, str_size, + inverse_array, inv_str, part->max - part->pos, edit_count); + + file_do_white_batch_edit(system, models, view->file_data.file, spec, hist_normal); + } + + end_temp_memory(temp); +} + +struct Indent_Options{ + b32 empty_blank_lines; + b32 use_tabs; + i32 tab_width; +}; + +struct Make_Batch_Result{ + char *str_base; + i32 str_size; + + Buffer_Edit *edits; + i32 edit_max; + i32 edit_count; +}; + +internal Cpp_Token* +get_first_token_at_line(Buffer *buffer, Cpp_Token_Stack tokens, i32 line){ + Cpp_Token *result = 0; + i32 start_pos = 0; + Cpp_Get_Token_Result get_token = {0}; + + start_pos = buffer->line_starts[line]; + get_token = cpp_get_token(&tokens, start_pos); + if (get_token.in_whitespace) get_token.token_index += 1; + result = tokens.tokens + get_token.token_index; + + return(result); +} + +internal Cpp_Token* +seek_matching_token_backwards(Cpp_Token_Stack tokens, Cpp_Token *token, + Cpp_Token_Type open_type, Cpp_Token_Type close_type){ + int nesting_level = 0; + if (token <= tokens.tokens){ + token = tokens.tokens; + } + else{ + for (; token > tokens.tokens; --token){ + if (!(token->flags & CPP_TFLAG_PP_BODY)){ + if (token->type == close_type){ + ++nesting_level; + } + else if (token->type == open_type){ + if (nesting_level == 0){ + break; + } + else{ + --nesting_level; + } + } + } + } + } + return(token); +} + +struct Indent_Parse_State{ + i32 current_indent; + i32 previous_line_indent; + i32 paren_nesting; + i32 paren_anchor_indent[16]; +}; + +internal i32 +compute_this_indent(Buffer *buffer, Indent_Parse_State indent, + Cpp_Token T, Cpp_Token prev_token, i32 line_i, i32 tab_width){ + + i32 previous_indent = indent.previous_line_indent; + i32 this_indent = 0; + + i32 this_line_start = buffer->line_starts[line_i]; + i32 next_line_start = 0; + + if (line_i+1 < buffer->line_count){ + next_line_start = buffer->line_starts[line_i+1]; + } + else{ + next_line_start = buffer_size(buffer); + } + + if ((prev_token.type == CPP_TOKEN_COMMENT || prev_token.type == CPP_TOKEN_STRING_CONSTANT) && + prev_token.start <= this_line_start && prev_token.start + prev_token.size > this_line_start){ + this_indent = previous_indent; + } + else{ + this_indent = indent.current_indent; + if (T.start < next_line_start){ + if (T.flags & CPP_TFLAG_PP_DIRECTIVE){ + this_indent = 0; + } + else{ + switch (T.type){ + case CPP_TOKEN_BRACKET_CLOSE: this_indent -= tab_width; break; + case CPP_TOKEN_BRACE_CLOSE: this_indent -= tab_width; break; + case CPP_TOKEN_BRACE_OPEN: break; + + default: + if (indent.current_indent > 0){ + if (!(prev_token.flags & CPP_TFLAG_PP_BODY || + prev_token.flags & CPP_TFLAG_PP_DIRECTIVE)){ + switch (prev_token.type){ + case CPP_TOKEN_BRACKET_OPEN: + case CPP_TOKEN_BRACE_OPEN: case CPP_TOKEN_BRACE_CLOSE: + case CPP_TOKEN_SEMICOLON: case CPP_TOKEN_COLON: + case CPP_TOKEN_COMMA: case CPP_TOKEN_COMMENT: break; + default: this_indent += tab_width; + } + } + } + } + } + } + if (this_indent < 0) this_indent = 0; + } + + if (indent.paren_nesting > 0){ + i32 level = indent.paren_nesting-1; + if (level >= ArrayCount(indent.paren_anchor_indent)){ + level = ArrayCount(indent.paren_anchor_indent)-1; + } + this_indent = indent.paren_anchor_indent[level]; + } + return(this_indent); +} + +internal i32* +get_line_indentation_marks(Partition *part, Buffer *buffer, Cpp_Token_Stack tokens, + i32 line_start, i32 line_end, i32 tab_width){ + + i32 indent_mark_count = line_end - line_start; + i32 *indent_marks = push_array(part, i32, indent_mark_count); + + Indent_Parse_State indent = {0}; + Cpp_Token *token = get_first_token_at_line(buffer, tokens, line_start); + + if (token != tokens.tokens){ + --token; + for (; token > tokens.tokens; --token){ + if (!(token->flags & CPP_TFLAG_PP_BODY)){ + switch(token->type){ + case CPP_TOKEN_BRACE_OPEN: + case CPP_TOKEN_BRACE_CLOSE: + goto out_of_loop; + } + } + } + out_of_loop:; + } + + // TODO(allen): This can maybe be it's own function now, so that we + // can do the decls in the order we want and avoid the extra binary search. + i32 found_safe_start_position = 0; + do{ + i32 line = buffer_get_line_index(buffer, token->start); + i32 start = buffer->line_starts[line]; + Hard_Start_Result hard_start = buffer_find_hard_start(buffer, start, tab_width); + + indent.current_indent = hard_start.indent_pos; + + Cpp_Token *start_token = get_first_token_at_line(buffer, tokens, line); + Cpp_Token *brace_token = token; + + if (start_token->type == CPP_TOKEN_PARENTHESE_OPEN){ + if (start_token == tokens.tokens){ + found_safe_start_position = 1; + } + else{ + token = start_token-1; + } + } + else{ + int close = 0; + + for (token = brace_token; token >= start_token; --token){ + switch(token->type){ + case CPP_TOKEN_PARENTHESE_CLOSE: + case CPP_TOKEN_BRACKET_CLOSE: + case CPP_TOKEN_BRACE_CLOSE: + close = token->type; + goto out_of_loop2; + } + } + out_of_loop2:; + + switch (close){ + case 0: token = start_token; found_safe_start_position = 1; break; + + case CPP_TOKEN_PARENTHESE_CLOSE: + token = seek_matching_token_backwards(tokens, token-1, + CPP_TOKEN_PARENTHESE_OPEN, + CPP_TOKEN_PARENTHESE_CLOSE); + break; + + case CPP_TOKEN_BRACKET_CLOSE: + token = seek_matching_token_backwards(tokens, token-1, + CPP_TOKEN_BRACKET_OPEN, + CPP_TOKEN_BRACKET_CLOSE); + break; + + case CPP_TOKEN_BRACE_CLOSE: + token = seek_matching_token_backwards(tokens, token-1, + CPP_TOKEN_BRACE_OPEN, + CPP_TOKEN_BRACE_CLOSE); + break; + } + } + } while(found_safe_start_position == 0); + + // NOTE(allen): Shift the array so that line_i can just operate in + // it's natural value range. + indent_marks -= line_start; + + i32 line_i = buffer_get_line_index(buffer, token->start); + + if (line_i > line_start){ + line_i = line_start; + } + + i32 next_line_start = buffer->line_starts[line_i+1]; + switch (token->type){ + case CPP_TOKEN_BRACKET_OPEN: indent.current_indent += tab_width; break; + case CPP_TOKEN_BRACE_OPEN: indent.current_indent += tab_width; break; + } + + indent.previous_line_indent = indent.current_indent; + Cpp_Token T; + Cpp_Token prev_token = *token; + ++token; + + for (; line_i < line_end; ++token){ + if (token < tokens.tokens + tokens.count){ + T = *token; + } + else{ + T.type = CPP_TOKEN_EOF; + T.start = buffer_size(buffer); + T.flags = 0; + } + + for (; T.start >= next_line_start && line_i < line_end;){ + if (line_i+1 < buffer->line_count){ + next_line_start = buffer->line_starts[line_i+1]; + } + else{ + next_line_start = buffer_size(buffer); + } + + // TODO(allen): Since this is called in one place we can probably go back + // to directly passing in next_line_start and this_line_start. + i32 this_indent = compute_this_indent(buffer, indent, T, prev_token, line_i, tab_width); + + if (line_i >= line_start){ + indent_marks[line_i] = this_indent; + } + ++line_i; + + indent.previous_line_indent = this_indent; + } + + switch (T.type){ + case CPP_TOKEN_BRACKET_OPEN: indent.current_indent += 4; break; + case CPP_TOKEN_BRACKET_CLOSE: indent.current_indent -= 4; break; + case CPP_TOKEN_BRACE_OPEN: indent.current_indent += 4; break; + case CPP_TOKEN_BRACE_CLOSE: indent.current_indent -= 4; break; + + case CPP_TOKEN_PARENTHESE_OPEN: + if (!(T.flags & CPP_TFLAG_PP_BODY)){ + if (indent.paren_nesting < ArrayCount(indent.paren_anchor_indent)){ + i32 line = buffer_get_line_index(buffer, T.start); + i32 start = buffer->line_starts[line]; + i32 char_pos = T.start - start; + + Hard_Start_Result hard_start = buffer_find_hard_start( + buffer, start, tab_width); + + i32 line_pos = hard_start.char_pos - start; + + indent.paren_anchor_indent[indent.paren_nesting] = + char_pos - line_pos + indent.previous_line_indent + 1; + } + ++indent.paren_nesting; + } + break; + + case CPP_TOKEN_PARENTHESE_CLOSE: + if (!(T.flags & CPP_TFLAG_PP_BODY)){ + --indent.paren_nesting; + } + break; + } + prev_token = T; + } + + // NOTE(allen): Unshift the indent_marks array so that the return value + // is the exact starting point of the array that was actually allocated. + indent_marks += line_start; + + return(indent_marks); +} + +internal Make_Batch_Result +make_batch_from_indent_marks(Partition *part, Buffer *buffer, i32 line_start, i32 line_end, + i32 *indent_marks, Indent_Options opts){ + + Make_Batch_Result result = {0}; + + i32 edit_max = line_end - line_start; + i32 edit_count = 0; + + Buffer_Edit *edits = push_array(part, Buffer_Edit, edit_max); + + char *str_base = (char*)part->base + part->pos; + i32 str_size = 0; + + // NOTE(allen): Shift the array so that line_i can just operate in + // it's natural value range. + indent_marks -= line_start; + + for (i32 line_i = line_start; line_i < line_end; ++line_i){ + i32 start = buffer->line_starts[line_i]; + Hard_Start_Result hard_start = + buffer_find_hard_start(buffer, start, opts.tab_width); + + i32 correct_indentation = indent_marks[line_i]; + if (hard_start.all_whitespace && opts.empty_blank_lines) correct_indentation = 0; + if (correct_indentation == -1) correct_indentation = hard_start.indent_pos; + + if ((hard_start.all_whitespace && hard_start.char_pos > start) || + !hard_start.all_space || correct_indentation != hard_start.indent_pos){ + Buffer_Edit new_edit; + new_edit.str_start = str_size; + str_size += correct_indentation; + char *str = push_array(part, char, correct_indentation); + i32 j = 0; + if (opts.use_tabs){ + i32 i = 0; + for (; i + opts.tab_width <= correct_indentation; i += opts.tab_width) str[j++] = '\t'; + for (; i < correct_indentation; ++i) str[j++] = ' '; + } + else{ + for (; j < correct_indentation; ++j) str[j] = ' '; + } + new_edit.len = j; + new_edit.start = start; + new_edit.end = hard_start.char_pos; + edits[edit_count++] = new_edit; + } + + Assert(edit_count <= edit_max); + } + + result.str_base = str_base; + result.str_size = str_size; + + result.edits = edits; + result.edit_max = edit_max; + result.edit_count = edit_count; + + return(result); +} + +internal void +view_auto_tab_tokens(System_Functions *system, Models *models, + View *view, i32 start, i32 end, Indent_Options opts){ +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + Editing_File *file = view->file_data.file; + Mem_Options *mem = &models->mem; + Partition *part = &mem->part; + Buffer *buffer = &file->state.buffer; + + Assert(file && !file->is_dummy); + Cpp_Token_Stack tokens = file->state.token_stack; + Assert(tokens.tokens); + + i32 line_start = buffer_get_line_index(buffer, start); + i32 line_end = buffer_get_line_index(buffer, end) + 1; + + Temp_Memory temp = begin_temp_memory(part); + + i32 *indent_marks = + get_line_indentation_marks(part, buffer, tokens, line_start, line_end, opts.tab_width); + + Make_Batch_Result batch = + make_batch_from_indent_marks(part, buffer, line_start, line_end, indent_marks, opts); + + if (batch.edit_count > 0){ + Assert(buffer_batch_debug_sort_check(batch.edits, batch.edit_count)); + + // NOTE(allen): computing edit spec, doing batch edit + Buffer_Edit *inverse_array = push_array(part, Buffer_Edit, batch.edit_count); + Assert(inverse_array); + + char *inv_str = (char*)part->base + part->pos; + Edit_Spec spec = + file_compute_whitespace_edit(mem, file, view->recent->cursor.pos, + batch.edits, batch.str_base, batch.str_size, + inverse_array, inv_str, part->max - part->pos, batch.edit_count); + + file_do_white_batch_edit(system, models, view->file_data.file, spec, hist_normal); + } + end_temp_memory(temp); + + { + i32 start = view->recent->cursor.pos; + Hard_Start_Result hard_start = buffer_find_hard_start(buffer, start, 4); + + view_cursor_move(view, hard_start.char_pos); + } +#endif +} + +struct Get_Link_Result{ + b32 in_link; + i32 index; +}; + +internal u32* +style_get_color(Style *style, Cpp_Token token){ + u32 *result; + if (token.flags & CPP_TFLAG_IS_KEYWORD){ + if (token.type == CPP_TOKEN_BOOLEAN_CONSTANT){ + result = &style->main.bool_constant_color; + } + else{ + result = &style->main.keyword_color; + } + } + else if(token.flags & CPP_TFLAG_PP_DIRECTIVE){ + result = &style->main.preproc_color; + } + else{ + switch (token.type){ + case CPP_TOKEN_COMMENT: + result = &style->main.comment_color; + break; + + case CPP_TOKEN_STRING_CONSTANT: + result = &style->main.str_constant_color; + break; + + case CPP_TOKEN_CHARACTER_CONSTANT: + result = &style->main.char_constant_color; + break; + + case CPP_TOKEN_INTEGER_CONSTANT: + result = &style->main.int_constant_color; + break; + + case CPP_TOKEN_FLOATING_CONSTANT: + result = &style->main.float_constant_color; + break; + + case CPP_TOKEN_INCLUDE_FILE: + result = &style->main.include_color; + break; + + default: + result = &style->main.default_color; + break; + } + } + return result; +} + +internal void +remeasure_file_view(System_Functions *system, View *view){ + if (file_is_ready(view->file_data.file)){ + Relative_Scrolling relative = view_get_relative_scrolling(view); + view_measure_wraps(&view->persistent.models->mem.general, view); + view_cursor_move(view, view->recent->cursor.pos); + view->recent->preferred_x = view_get_cursor_x(view); + view_set_relative_scrolling(view, relative); + } +} + +inline void +view_show_menu(View *view, Command_Map *gui_map){ + view->map = gui_map; + view->showing_ui = VUI_Menu; + view->current_scroll = &view->gui_scroll; +} + +inline void +view_show_config(View *view, Command_Map *gui_map){ + view->map = gui_map; + view->showing_ui = VUI_Config; + view->current_scroll = &view->gui_scroll; +} + +inline void +view_show_interactive(System_Functions *system, View *view, + Command_Map *gui_map, Interactive_Action action, + Interactive_Interaction interaction, String query){ + + Models *models = view->persistent.models; + + view->showing_ui = VUI_Interactive; + view->action = action; + view->interaction = interaction; + view->dest = make_fixed_width_string(view->dest_); + view->list_i = 0; + view->current_scroll = &view->gui_scroll; + + view->map = gui_map; + + hot_directory_clean_end(&models->hot_directory); + hot_directory_reload(system, &models->hot_directory, &models->working_set); +} + +inline void +view_show_theme(View *view, Command_Map *gui_map){ + view->map = gui_map; + view->showing_ui = VUI_Theme; + view->color_mode = CV_Mode_Library; + view->color = super_color_create(0xFF000000); + view->current_color_editing = 0; + view->current_scroll = &view->gui_scroll; +} + +inline void +view_show_file(View *view){ + Editing_File *file = view->file_data.file; + if (file){ + view->map = get_map(view->persistent.models, file->settings.base_map_id); + } + else{ + view->map = get_map(view->persistent.models, mapid_global); + } + view->showing_ui = VUI_None; + view->current_scroll = &view->recent->scroll; +} + +internal void +view_save_file(System_Functions *system, Models *models, + Editing_File *file, View *view, String filename, b32 save_as){ + Mem_Options *mem = &models->mem; + Working_Set *working_set = &models->working_set; + + if (!file){ + if (view){ + file = view->file_data.file; + } + else{ + file = working_set_lookup_file(working_set, filename); + } + } + + if (file && buffer_get_sync(file) != SYNC_GOOD){ + if (file_save(system, mem, file, filename.str)){ + if (save_as){ + file_set_name(working_set, file, filename.str); + } + } + } +} + +internal void +view_new_file(System_Functions *system, Models *models, + View *view, String string){ + Working_Set *working_set = &models->working_set; + General_Memory *general = &models->mem.general; + + Editing_File *file = working_set_alloc_always(working_set, general); + file_create_empty(system, models, file, string.str); + working_set_add(system, working_set, file, general); + + view_set_file(view, file, models); + view_show_file(view); + view->map = get_map(models, file->settings.base_map_id); + + Hook_Function *new_file_fnc = models->hooks[hook_new_file]; + if (new_file_fnc){ + models->buffer_param_indices[models->buffer_param_count++] = file->id.id; + new_file_fnc(&models->app_links); + models->buffer_param_count = 0; + file->settings.is_initialized = 1; + } + +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + if (file->settings.tokens_exist){ + file_first_lex_parallel(system, general, file); + } +#endif +} + +internal void +init_normal_file(System_Functions *system, Models *models, Editing_File *file, + char *buffer, i32 size){ + + General_Memory *general = &models->mem.general; + + String val = make_string(buffer, size); + file_create_from_string(system, models, file, file->name.source_path.str, val); + + if (file->settings.tokens_exist){ + file_first_lex_parallel(system, general, file); + } + + for (View_Iter iter = file_view_iter_init(&models->layout, file, 0); + file_view_iter_good(iter); + iter = file_view_iter_next(iter)){ + view_measure_wraps(general, iter.view); + } +} + +internal void +view_open_file(System_Functions *system, Models *models, + View *view, String filename){ + Working_Set *working_set = &models->working_set; + General_Memory *general = &models->mem.general; + Partition *part = &models->mem.part; + + Editing_File *file = working_set_contains(system, working_set, filename); + + if (file == 0){ + File_Loading loading = system->file_load_begin(filename.str); + + if (loading.exists){ + b32 in_general_mem = 0; + Temp_Memory temp = begin_temp_memory(part); + char *buffer = push_array(part, char, loading.size); + + // TODO(allen): How will we get temporary space for large + // buffers? The main partition isn't always big enough + // but getting a general block this large and copying it + // then freeing it is *super* dumb! + if (buffer == 0){ + buffer = (char*)general_memory_allocate(general, loading.size); + if (buffer != 0){ + in_general_mem = 1; + } + } + + if (system->file_load_end(loading, buffer)){ + file = working_set_alloc_always(working_set, general); + if (file){ + file_init_strings(file); + file_set_name(working_set, file, filename.str); + working_set_add(system, working_set, file, general); + + init_normal_file(system, models, file, + buffer, loading.size); + } + } + + if (in_general_mem){ + general_memory_free(general, buffer); + } + + end_temp_memory(temp); + } + } + + if (file){ + if (view){ + view_set_file(view, file, models); + } + } +} + +internal void +kill_file(System_Functions *system, Models *models, + Editing_File *file, String string){ + Working_Set *working_set = &models->working_set; + + if (!file && string.str){ + file = working_set_lookup_file(working_set, string); + if (!file){ + file = working_set_contains(system, working_set, string); + } + } + + if (file && !file->settings.never_kill){ + working_set_remove(system, working_set, file->name.source_path); + file_close(system, &models->mem.general, file); + working_set_free_file(&models->working_set, file); + + File_Node *used = &models->working_set.used_sentinel; + File_Node *node = used->next; + for (View_Iter iter = file_view_iter_init(&models->layout, file, 0); + file_view_iter_good(iter); + iter = file_view_iter_next(iter)){ + if (node != used){ + iter.view->file_data.file = 0; + view_set_file(iter.view, (Editing_File*)node, models); + node = node->next; + } + else{ + iter.view->file_data.file = 0; + view_set_file(iter.view, 0, models); + } + } + } +} + +internal void +try_kill_file(System_Functions *system, Models *models, + Editing_File *file, View *view, String string){ + Working_Set *working_set = &models->working_set; + + if (!file && string.str){ + file = working_set_lookup_file(working_set, string); + if (!file){ + file = working_set_contains(system, working_set, string); + } + } + + if (file && !file->settings.never_kill){ + if (buffer_needs_save(file)){ + if (view == 0){ + view = models->layout.panels[models->layout.active_panel].view; + } + view_show_interactive(system, view, &models->map_ui, + IAct_Sure_To_Kill, IInt_Sure_To_Kill, + make_lit_string("Are you sure?")); + copy(&view->dest, file->name.live_name); + } + else{ + kill_file(system, models, file, string_zero()); + view_show_file(view); + } + } +} + +internal void +interactive_view_complete(System_Functions *system, View *view, String dest, i32 user_action){ + Models *models = view->persistent.models; + Editing_File *old_file = view->file_data.file; + + switch (view->action){ + case IAct_Open: + view_open_file(system, models, view, dest); + touch_file(&models->working_set, old_file); + view_show_file(view); + break; + + case IAct_Save_As: + view_save_file(system, models, 0, view, dest, 1); + view_show_file(view); + break; + + case IAct_New: + if (dest.size > 0 && !char_is_slash(dest.str[dest.size-1])){ + view_new_file(system, models, view, dest); + view_show_file(view); + }break; + + case IAct_Switch: + { + touch_file(&models->working_set, old_file); + + Editing_File *file = 0; + String string = dest; + + file = working_set_lookup_file(&models->working_set, string); + if (!file){ + file = working_set_contains(system, &models->working_set, string); + } + if (file){ + view_set_file(view, file, models); + } + view_show_file(view); + } + break; + + case IAct_Kill: + try_kill_file(system, models, 0, 0, dest); + break; + + case IAct_Sure_To_Close: + switch (user_action){ + case 0: + models->keep_playing = 0; + break; + + case 1: + view_show_file(view); + break; + + case 2: + // TODO(allen): Save all and close. + break; + } + break; + + case IAct_Sure_To_Kill: + switch (user_action){ + case 0: + kill_file(system, models, 0, dest); + view_show_file(view); + break; + + case 1: + view_show_file(view); + break; + + case 2: + view_save_file(system, models, 0, 0, dest, 0); + kill_file(system, models, 0, dest); + view_show_file(view); + break; + } + break; + } +} + +#if 0 +internal void +update_highlighting(View *view){ + View *file_view = view->hot_file_view; + if (!file_view){ + view->highlight = {}; + return; + } + + Editing_File *file = file_view->file; + if (!file || !file_is_ready(file)){ + view->highlight = {}; + return; + } + + Models *models = view->persistent.models; + + Style *style = &models->style; + i32 pos = view_get_cursor_pos(file_view); + char c = buffer_get_char(&file->state.buffer, pos); + + if (c == '\r'){ + view->highlight.ids[0] = + raw_ptr_dif(&style->main.special_character_color, style); + } + + else if (file->state.tokens_complete){ + Cpp_Token_Stack *tokens = &file->state.token_stack; + Cpp_Get_Token_Result result = cpp_get_token(tokens, pos); + Cpp_Token token = tokens->tokens[result.token_index]; + if (!result.in_whitespace){ + u32 *color = style_get_color(style, token); + view->highlight.ids[0] = raw_ptr_dif(color, style); + if (token.type == CPP_TOKEN_JUNK){ + view->highlight.ids[1] = + raw_ptr_dif(&style->main.highlight_junk_color, style); + } + else if (char_is_whitespace(c)){ + view->highlight.ids[1] = + raw_ptr_dif(&style->main.highlight_white_color, style); + } + else{ + view->highlight.ids[1] = 0; + } + } + else{ + view->highlight.ids[0] = 0; + view->highlight.ids[1] = + raw_ptr_dif(&style->main.highlight_white_color, style); + } + } + + else{ + if (char_is_whitespace(c)){ + view->highlight.ids[0] = 0; + view->highlight.ids[1] = + raw_ptr_dif(&style->main.highlight_white_color, style); + } + else{ + view->highlight.ids[0] = + raw_ptr_dif(&style->main.default_color, style); + view->highlight.ids[1] = 0; + } + } + + if (file_view->show_temp_highlight){ + view->highlight.ids[2] = + raw_ptr_dif(&style->main.highlight_color, style); + view->highlight.ids[3] = + raw_ptr_dif(&style->main.at_highlight_color, style); + } + else if (file->state.paste_effect.tick_down > 0){ + view->highlight.ids[2] = + raw_ptr_dif(&style->main.paste_color, style); + view->highlight.ids[3] = 0; + } + else{ + view->highlight.ids[2] = 0; + view->highlight.ids[3] = 0; + } +} +#endif + +struct File_Bar{ + f32 pos_x, pos_y; + f32 text_shift_x, text_shift_y; + i32_Rect rect; + i16 font_id; +}; + +internal void +intbar_draw_string(Render_Target *target, File_Bar *bar, String str, u32 char_color){ + i16 font_id = bar->font_id; + draw_string(target, font_id, str, + (i32)(bar->pos_x + bar->text_shift_x), + (i32)(bar->pos_y + bar->text_shift_y), + char_color); + bar->pos_x += font_string_width(target, font_id, str); +} + +internal void +view_reinit_scrolling(View *view){ + Editing_File *file = view->file_data.file; + f32 w, h; + f32 cursor_x, cursor_y; + f32 target_x, target_y; + + view->reinit_scrolling = 0; + + target_x = 0; + target_y = 0; + + if (file && file_is_ready(file)){ + cursor_x = view_get_cursor_x(view); + cursor_y = view_get_cursor_y(view); + + w = view_file_width(view); + h = view_file_height(view); + + if (cursor_x >= target_x + w){ + target_x = (f32)(cursor_x - w*.5f); + } + + target_y = clamp_bottom(0.f, (f32)FLOOR32(cursor_y - h*.5f)); + } + + view->recent->scroll.target_y = target_y; + view->recent->scroll.scroll_y = target_y; + view->recent->scroll.prev_target_y = -1000.f; + + view->recent->scroll.target_x = target_x; + view->recent->scroll.scroll_x = target_x; + view->recent->scroll.prev_target_x = -1000.f; +} + +enum CursorScroll_State{ + CursorScroll_NoChange = 0x0, + CursorScroll_Cursor = 0x1, + CursorScroll_Scroll = 0x2, + CursorScroll_ContextChange = 0x4 +}; + +internal u32 +view_get_cursor_scroll_change_state(View *view){ + u32 result = 0; + i32 pos = 0; + Scroll_Context context = {0}; + + if (view->gui_target.did_file){ + pos = view_get_cursor_pos(view); + if ((view->prev_cursor_pos != pos)){ + result |= CursorScroll_Cursor; + } + } + + if (view->current_scroll){ + if (!gui_scroll_eq(view->current_scroll, &view->gui_target.scroll_original)){ + result |= CursorScroll_Scroll; + } + } + + if (context.mode == VUI_None){ + context.file = view->file_data.file; + } + else{ + context.file = view->prev_context.file; + } + context.scroll = view->gui_target.scroll_id; + context.mode = view->showing_ui; + + if (!context_eq(view->prev_context, context)){ + result |= CursorScroll_ContextChange; + } + + return(result); +} + +internal void +view_begin_cursor_scroll_updates(View *view){ + if (view->file_data.file && view->file_data.file == view->prev_context.file){ + Assert(view->prev_cursor_pos == view_get_cursor_pos(view)); + } + + view->prev_context.file = view->file_data.file; + view->prev_context.scroll = view->gui_target.scroll_id; + view->prev_context.mode = view->showing_ui; +} + +internal void +view_end_cursor_scroll_updates(View *view){ + i32 cursor_scroll_state = + view_get_cursor_scroll_change_state(view); + + switch (cursor_scroll_state){ + case CursorScroll_NoChange:break; + + case CursorScroll_Cursor: + case CursorScroll_Cursor|CursorScroll_Scroll: + view_move_view_to_cursor(view, view->current_scroll); + gui_post_scroll_vars(&view->gui_target, view->current_scroll, view->scroll_region); + break; + + case CursorScroll_Scroll: + view_move_cursor_to_view(view); + gui_post_scroll_vars(&view->gui_target, view->current_scroll, view->scroll_region); + break; + } + + if (cursor_scroll_state & CursorScroll_ContextChange){ + view->current_scroll->scroll_y = view->current_scroll->target_y; + view->current_scroll->scroll_x = view->current_scroll->target_x; + gui_post_scroll_vars(&view->gui_target, view->current_scroll, view->scroll_region); + } + + if (view->gui_target.did_file){ + view->prev_cursor_pos = view_get_cursor_pos(view); + } +} + +internal b32 +file_step(View *view, i32_Rect region, Input_Summary *user_input, b32 is_active){ + i32 is_animating = 0; + Editing_File *file = view->file_data.file; + if (file && !file->is_loading){ + f32 max_visible_y = view_file_height(view); + f32 max_x = view_file_width(view); + + GUI_Scroll_Vars scroll_vars = *view->current_scroll; + + if (file->state.paste_effect.tick_down > 0){ + --file->state.paste_effect.tick_down; + is_animating = 1; + } + + if (user_input->mouse.press_l && is_active){ + f32 rx = (f32)(user_input->mouse.x - region.x0); + f32 ry = (f32)(user_input->mouse.y - region.y0); + + if (ry >= 0){ + view_set_widget(view, FWIDG_NONE); + if (rx >= 0 && rx < max_x && ry >= 0 && ry < max_visible_y){ + view_cursor_move(view, rx + scroll_vars.scroll_x, ry + scroll_vars.scroll_y, 1); + view->mode = view_mode_zero(); + } + } + } + if (!is_active) view_set_widget(view, FWIDG_NONE); + } + + return(is_animating); +} + +internal void +do_widget(View *view, GUI_Target *target){ + Query_Slot *slot; + Query_Bar *bar; + + for (slot = view->query_set.used_slot; slot != 0; slot = slot->next){ + bar = slot->query_bar; + gui_do_text_field(target, bar->prompt, bar->string); + } +} + +struct Exhaustive_File_Loop{ + char front_name_[256]; + char full_path_[256]; + String front_name, full_path; + + Absolutes absolutes; + + File_Info *infos; + i32 count, r; +}; + +struct Exhaustive_File_Info{ + File_Info *info; + String message; + b8 is_folder; + b8 name_match; + b8 is_loaded; +}; + +internal void +begin_exhaustive_loop(Exhaustive_File_Loop *loop, Hot_Directory *hdir){ + loop->front_name = make_fixed_width_string(loop->front_name_); + loop->full_path = make_fixed_width_string(loop->full_path_); + + loop->infos = hdir->file_list.infos; + loop->count = hdir->file_list.count; + + get_front_of_directory(&loop->front_name, hdir->string); + get_absolutes(loop->front_name, &loop->absolutes, 1, 1); + get_path_of_directory(&loop->full_path, hdir->string); + loop->r = loop->full_path.size; +} + +internal Exhaustive_File_Info +get_exhaustive_info(System_Functions *system, Working_Set *working_set, Exhaustive_File_Loop *loop, i32 i){ + persist String message_loaded = make_lit_string(" LOADED"); + persist String message_unsaved = make_lit_string(" LOADED *"); + persist String message_unsynced = make_lit_string(" LOADED !"); + + Exhaustive_File_Info result = {0}; + Editing_File *file = 0; + + result.info = loop->infos + i; + loop->full_path.size = loop->r; + append(&loop->full_path, result.info->filename); + terminate_with_null(&loop->full_path); + file = working_set_contains(system, working_set, loop->full_path); + + result.is_folder = (result.info->folder != 0); + result.name_match = (filename_match(loop->front_name, &loop->absolutes, result.info->filename, 0) != 0); + result.is_loaded = (file != 0 && file_is_ready(file)); + + result.message = string_zero(); + if (result.is_loaded){ + switch (buffer_get_sync(file)){ + case SYNC_GOOD: result.message = message_loaded; break; + case SYNC_BEHIND_OS: result.message = message_unsynced; break; + case SYNC_UNSAVED: result.message = message_unsaved; break; + } + } + + return(result); +} + +struct Style_Color_Edit{ + Style_Tag target; + Style_Tag fore; + Style_Tag back; + String text; +}; + +static Style_Color_Edit colors_to_edit[] = { + {Stag_Back, Stag_Default, Stag_Back, make_lit_string("Background")}, + {Stag_Margin, Stag_Default, Stag_Margin, make_lit_string("Margin")}, + {Stag_Margin_Hover, Stag_Default, Stag_Margin_Hover, make_lit_string("Margin Hover")}, + {Stag_Margin_Active, Stag_Default, Stag_Margin_Active, make_lit_string("Margin Active")}, + + {Stag_Cursor, Stag_At_Cursor, Stag_Cursor, make_lit_string("Cursor")}, + {Stag_At_Cursor, Stag_At_Cursor, Stag_Cursor, make_lit_string("Text At Cursor")}, + {Stag_Mark, Stag_Mark, Stag_Back, make_lit_string("Mark")}, + + {Stag_Highlight, Stag_At_Highlight, Stag_Highlight, make_lit_string("Highlight")}, + {Stag_At_Highlight, Stag_At_Highlight, Stag_Highlight, make_lit_string("Text At Highlight")}, + + {Stag_Default, Stag_Default, Stag_Back, make_lit_string("Text Default")}, + {Stag_Comment, Stag_Comment, Stag_Back, make_lit_string("Comment")}, + {Stag_Keyword, Stag_Keyword, Stag_Back, make_lit_string("Keyword")}, + {Stag_Str_Constant, Stag_Str_Constant, Stag_Back, make_lit_string("String Constant")}, + {Stag_Char_Constant, Stag_Char_Constant, Stag_Back, make_lit_string("Character Constant")}, + {Stag_Int_Constant, Stag_Int_Constant, Stag_Back, make_lit_string("Integer Constant")}, + {Stag_Float_Constant, Stag_Float_Constant, Stag_Back, make_lit_string("Float Constant")}, + {Stag_Bool_Constant, Stag_Bool_Constant, Stag_Back, make_lit_string("Boolean Constant")}, + {Stag_Preproc, Stag_Preproc, Stag_Back, make_lit_string("Preprocessor")}, + {Stag_Special_Character, Stag_Special_Character, Stag_Back, make_lit_string("Special Character")}, + + {Stag_Highlight_Junk, Stag_Default, Stag_Highlight_Junk, make_lit_string("Junk Highlight")}, + {Stag_Highlight_White, Stag_Default, Stag_Highlight_White, make_lit_string("Whitespace Highlight")}, + + {Stag_Paste, Stag_Paste, Stag_Back, make_lit_string("Paste Color")}, + + {Stag_Bar, Stag_Base, Stag_Bar, make_lit_string("Bar")}, + {Stag_Base, Stag_Base, Stag_Bar, make_lit_string("Bar Text")}, + {Stag_Pop1, Stag_Pop1, Stag_Bar, make_lit_string("Bar Pop 1")}, + {Stag_Pop2, Stag_Pop2, Stag_Bar, make_lit_string("Bar Pop 2")}, +}; + +struct Single_Line_Input_Step{ + b8 hit_newline; + b8 hit_ctrl_newline; + b8 hit_a_character; + b8 hit_backspace; + b8 hit_esc; + b8 made_a_change; + b8 did_command; + b8 no_file_match; +}; + +enum Single_Line_Input_Type{ + SINGLE_LINE_STRING, + SINGLE_LINE_FILE +}; + +struct Single_Line_Mode{ + Single_Line_Input_Type type; + String *string; + Hot_Directory *hot_directory; + b32 fast_folder_select; + b32 try_to_match; + b32 case_sensitive; +}; + +internal Single_Line_Input_Step +app_single_line_input_core(System_Functions *system, Working_Set *working_set, + Key_Event_Data key, Single_Line_Mode mode){ + Single_Line_Input_Step result = {0}; + + if (key.keycode == key_back){ + result.hit_backspace = 1; + if (mode.string->size > 0){ + result.made_a_change = 1; + --mode.string->size; + switch (mode.type){ + case SINGLE_LINE_STRING: + { + mode.string->str[mode.string->size] = 0; + }break; + + case SINGLE_LINE_FILE: + { + char end_character = mode.string->str[mode.string->size]; + if (char_is_slash(end_character)){ + mode.string->size = reverse_seek_slash(*mode.string) + 1; + mode.string->str[mode.string->size] = 0; + hot_directory_set(system, mode.hot_directory, *mode.string, working_set); + } + else{ + mode.string->str[mode.string->size] = 0; + } + }break; + } + } + } + + else if (key.character == '\n' || key.character == '\t'){ + // NOTE(allen): do nothing! + } + + else if (key.keycode == key_esc){ + result.hit_esc = 1; + result.made_a_change = 1; + } + + else if (key.character){ + result.hit_a_character = 1; + if (!key.modifiers[MDFR_CONTROL_INDEX] && + !key.modifiers[MDFR_ALT_INDEX]){ + if (mode.string->size+1 < mode.string->memory_size){ + u8 new_character = (u8)key.character; + mode.string->str[mode.string->size] = new_character; + mode.string->size++; + mode.string->str[mode.string->size] = 0; + if (mode.type == SINGLE_LINE_FILE && char_is_slash(new_character)){ + hot_directory_set(system, mode.hot_directory, *mode.string, working_set); + } + result.made_a_change = 1; + } + } + else{ + result.did_command = 1; + result.made_a_change = 1; + } + } + + return result; +} + +inline Single_Line_Input_Step +app_single_line_input_step(System_Functions *system, Key_Event_Data key, String *string){ + Single_Line_Mode mode = {}; + mode.type = SINGLE_LINE_STRING; + mode.string = string; + return app_single_line_input_core(system, 0, key, mode); +} + +inline Single_Line_Input_Step +app_single_file_input_step(System_Functions *system, + Working_Set *working_set, Key_Event_Data key, + String *string, Hot_Directory *hot_directory, + b32 fast_folder_select, b32 try_to_match, b32 case_sensitive){ + Single_Line_Mode mode = {}; + mode.type = SINGLE_LINE_FILE; + mode.string = string; + mode.hot_directory = hot_directory; + mode.fast_folder_select = fast_folder_select; + mode.try_to_match = try_to_match; + mode.case_sensitive = case_sensitive; + return app_single_line_input_core(system, working_set, key, mode); +} + +inline Single_Line_Input_Step +app_single_number_input_step(System_Functions *system, Key_Event_Data key, String *string){ + Single_Line_Input_Step result = {}; + Single_Line_Mode mode = {}; + mode.type = SINGLE_LINE_STRING; + mode.string = string; + + char c = (char)key.character; + if (c == 0 || c == '\n' || char_is_numeric(c)) + result = app_single_line_input_core(system, 0, key, mode); + return result; +} + +struct View_Step_Result{ + b32 animating; + b32 consume_keys; + b32 consume_esc; +}; + +internal View_Step_Result +step_file_view(System_Functions *system, View *view, View *active_view, Input_Summary input){ + View_Step_Result result = {0}; + GUI_Target *target = &view->gui_target; + Models *models = view->persistent.models; + Key_Summary keys = input.keys; + + b32 show_scrollbar = !view->hide_scrollbar; + + view->current_scroll = 0; + + if (view->showing_ui != VUI_None){ + b32 did_esc = 0; + Key_Event_Data key; + i32 i; + + for (i = 0; i < keys.count; ++i){ + key = get_single_key(&keys, i); + if (key.keycode == key_esc){ + did_esc = 1; + break; + } + } + + if (did_esc){ + view_show_file(view); + result.consume_esc = 1; + } + } + + gui_begin_top_level(target, input); + { + gui_do_top_bar(target); + do_widget(view, target); + + if (view->showing_ui == VUI_None){ + + gui_begin_serial_section(target); + { + f32 delta = 9.f * view->font_height; + GUI_id scroll_context = {0}; + scroll_context.id[1] = view->showing_ui; + scroll_context.id[0] = (u64)(view->file_data.file); + + view->current_scroll = &view->recent->scroll; + gui_get_scroll_vars(target, scroll_context, + &view->recent->scroll, &view->scroll_region); + + gui_begin_scrollable(target, scroll_context, view->recent->scroll, + delta, show_scrollbar); + gui_do_file(target); + gui_end_scrollable(target); + } + gui_end_serial_section(target); + } + else{ + switch (view->showing_ui){ + case VUI_Menu: + { + view->current_scroll = &view->gui_scroll; + + String message = make_lit_string("Menu"); + String empty_string = {0}; + GUI_id id = {0}; + id.id[1] = VUI_Menu; + + gui_do_text_field(target, message, empty_string); + + id.id[0] = 0; + message = make_lit_string("Theme"); + if (gui_do_fixed_option(target, id, message, 0)){ + view_show_theme(view, view->map); + } + + id.id[0] = 1; + message = make_lit_string("Config"); + if (gui_do_fixed_option(target, id, message, 0)){ + view_show_config(view, view->map); + } + }break; + + case VUI_Config: + { + view->current_scroll = &view->gui_scroll; + + String message = make_lit_string("Config"); + String empty_string = {0}; + GUI_id id = {0}; + id.id[1] = VUI_Config; + + gui_do_text_field(target, message, empty_string); + + id.id[0] = 0; + message = make_lit_string("Left Ctrl + Left Alt = AltGr"); + if (gui_do_fixed_option_checkbox(target, id, message, 0, (b8)models->settings.lctrl_lalt_is_altgr)){ + models->settings.lctrl_lalt_is_altgr = !models->settings.lctrl_lalt_is_altgr; + } + }break; + + case VUI_Theme: + { + view->current_scroll = &view->gui_scroll; + + if (view != active_view){ + view->hot_file_view = active_view; + } + + String message = {0}; + String empty_string = {0}; + + GUI_id id = {0}; + id.id[1] = VUI_Theme + ((u64)view->color_mode << 32); + + GUI_id scroll_context = {0}; + scroll_context.id[0] = 0; + scroll_context.id[1] = VUI_Theme + ((u64)view->color_mode << 32); + + switch (view->color_mode){ + case CV_Mode_Library: + message = make_lit_string("Current Theme - Click to Edit"); + gui_do_text_field(target, message, empty_string); + + id.id[0] = (u64)(main_style(models)); + if (gui_do_style_preview(target, id, 0)){ + view->color_mode = CV_Mode_Adjusting; + } + + message = make_lit_string("Set Font"); + id.id[0] = (u64)(&models->global_font); + if (gui_do_button(target, id, message)){ + view->color_mode = CV_Mode_Font; + } + + message = make_lit_string("Theme Library - Click to Select"); + gui_do_text_field(target, message, empty_string); + + view->current_scroll = &view->gui_scroll; + gui_get_scroll_vars(target, scroll_context, &view->gui_scroll, &view->scroll_region); + gui_begin_scrollable(target, scroll_context, view->gui_scroll, + 9.f * view->font_height, show_scrollbar); + + { + i32 count = models->styles.count; + Style *style; + i32 i; + + for (i = 1; i < count; ++i, ++style){ + style = get_style(models, i); + id.id[0] = (u64)(style); + if (gui_do_style_preview(target, id, i)){ + style_copy(main_style(models), style); + } + } + } + + gui_end_scrollable(target); + break; + + case CV_Mode_Font: + { + Font_Set *font_set = models->font_set; + Font_Info *info = 0; + + i16 i = 1, count = (i16)models->font_set->count + 1; + i16 font_id = 0, new_font_id = 0; + + String message = make_lit_string("Back"); + + id.id[0] = 0; + if (gui_do_button(target, id, message)){ + view->color_mode = CV_Mode_Library; + } + + font_id = models->global_font.font_id; + new_font_id = font_id; + + for (i = 1; i < count; ++i){ + info = get_font_info(font_set, i); + id.id[0] = (u64)i; + if (i != font_id){ + if (gui_do_font_button(target, id, i, info->name)){ + new_font_id = i; + } + } + else{ + char message_space[256]; + message = make_fixed_width_string(message_space); + copy(&message, make_lit_string("currently selected: ")); + append(&message, info->name); + gui_do_font_button(target, id, i, message); + } + } + + models->global_font.font_id = (i16)(new_font_id); + }break; + + case CV_Mode_Adjusting: + { + Style *style = main_style(models); + u32 *edit_color = 0; + u32 *fore = 0, *back = 0; + i32 i = 0; + + String message = make_lit_string("Back"); + + id.id[0] = 0; + if (gui_do_button(target, id, message)){ + view->color_mode = CV_Mode_Library; + } + + view->current_scroll = &view->gui_scroll; + gui_get_scroll_vars(target, scroll_context, &view->gui_scroll, &view->scroll_region); + gui_begin_scrollable(target, scroll_context, view->gui_scroll, + 9.f * view->font_height, show_scrollbar); + + i32 next_color_editing = view->current_color_editing; + + for (i = 0; i < ArrayCount(colors_to_edit); ++i){ + edit_color = style_index_by_tag(&style->main, colors_to_edit[i].target); + id.id[0] = (u64)(edit_color); + + fore = style_index_by_tag(&style->main, colors_to_edit[i].fore); + back = style_index_by_tag(&style->main, colors_to_edit[i].back); + + if (gui_do_color_button(target, id, *fore, *back, colors_to_edit[i].text)){ + next_color_editing = i; + view->color_cursor = 0; + } + + if (view->current_color_editing == i){ + GUI_Item_Update update = {0}; + char text_space[7]; + String text = make_fixed_width_string(text_space); + + color_to_hexstr(*edit_color, &text); + if (gui_do_text_with_cursor(target, view->color_cursor, text, &update)){ + b32 r = 0; + i32 j = 0; + + for (j = 0; j < keys.count; ++j){ + i16 key = keys.keys[j].keycode; + switch (key){ + case key_left: --view->color_cursor; r = 1; result.consume_keys = 1; break; + case key_right: ++view->color_cursor; r = 1; result.consume_keys = 1; break; + + case key_up: + if (next_color_editing > 0){ + --next_color_editing; + } + result.consume_keys = 1; + break; + + case key_down: + if (next_color_editing <= ArrayCount(colors_to_edit)-1){ + ++next_color_editing; + } + result.consume_keys = 1; + break; + + default: + if ((key >= '0' && key <= '9') || (key >= 'a' && key <= 'f') || (key >= 'A' && key <= 'F')){ + text.str[view->color_cursor] = (char)key; + r = 1; + result.consume_keys = 1; + } + break; + } + + if (view->color_cursor < 0) view->color_cursor = 0; + if (view->color_cursor >= 6) view->color_cursor = 5; + } + + if (r){ + hexstr_to_color(text, edit_color); + gui_rollback(target, &update); + gui_do_text_with_cursor(target, view->color_cursor, text, 0); + } + } + } + } + + if (view->current_color_editing != next_color_editing){ + view->current_color_editing = next_color_editing; + view->color_cursor = 0; + } + + gui_end_scrollable(target); + }break; + } + }break; + + case VUI_Interactive: + { + b32 complete = 0; + char comp_dest_space[1024]; + String comp_dest = make_fixed_width_string(comp_dest_space); + i32 comp_action = 0; + + view->current_scroll = &view->gui_scroll; + + GUI_id id = {0}; + id.id[1] = VUI_Interactive + ((u64)view->interaction << 32); + + GUI_id scroll_context = {0}; + scroll_context.id[1] = VUI_Interactive + ((u64)view->interaction << 32); + + switch (view->interaction){ + case IInt_Sys_File_List: + { + b32 use_item_in_list = 1; + b32 activate_directly = 0; + + if (view->action == IAct_Save_As || view->action == IAct_New){ + use_item_in_list = 0; + } + + String message = {0}; + switch (view->action){ + case IAct_Open: message = make_lit_string("Open: "); break; + case IAct_Save_As: message = make_lit_string("Save As: "); break; + case IAct_New: message = make_lit_string("New: "); break; + } + + Exhaustive_File_Loop loop; + Exhaustive_File_Info file_info; + + GUI_Item_Update update = {0}; + Hot_Directory *hdir = &models->hot_directory; + b32 do_new_directory = 0; + b32 snap_into_view = 0; + i32 i = 0; + + { + Single_Line_Input_Step step = {0}; + Key_Event_Data key = {0}; + i32 i; + + for (i = 0; i < keys.count; ++i){ + key = get_single_key(&keys, i); + step = app_single_file_input_step(system, &models->working_set, key, + &hdir->string, hdir, 1, 1, 0); + if (step.made_a_change){ + view->list_i = 0; + result.consume_keys = 1; + } + if (!use_item_in_list && (key.keycode == '\n' || key.keycode == '\t')){ + activate_directly = 1; + result.consume_keys = 1; + } + } + } + + gui_do_text_field(target, message, hdir->string); + + scroll_context.id[0] = (u64)(hdir); + if (gui_get_scroll_vars(target, scroll_context, + &view->gui_scroll, &view->scroll_region)){ + snap_into_view = 1; + } + gui_begin_scrollable(target, scroll_context, view->gui_scroll, + 9.f * view->font_height, show_scrollbar); + + id.id[0] = (u64)(hdir) + 1; + + if (gui_begin_list(target, id, view->list_i, 0, + snap_into_view, &update)){ + // TODO(allen): Allow me to handle key consumption correctly here! + gui_standard_list(target, id, view->current_scroll, view->scroll_region, + &keys, &view->list_i, &update); + } + + { + begin_exhaustive_loop(&loop, hdir); + for (i = 0; i < loop.count; ++i){ + file_info = get_exhaustive_info(system, &models->working_set, &loop, i); + + if (file_info.name_match){ + id.id[0] = (u64)(file_info.info); + if (gui_do_file_option(target, id, file_info.info->filename, + file_info.is_folder, file_info.message)){ + if (file_info.is_folder){ + set_last_folder(&hdir->string, file_info.info->filename, '/'); + do_new_directory = 1; + } + else if (use_item_in_list){ + complete = 1; + copy(&comp_dest, loop.full_path); + } + } + } + } + } + + gui_end_list(target); + + if (activate_directly){ + complete = 1; + copy(&comp_dest, hdir->string); + } + + if (do_new_directory){ + hot_directory_reload(system, hdir, &models->working_set); + } + + gui_end_scrollable(target); + }break; + + case IInt_Live_File_List: + { + b32 snap_into_view = 0; + persist String message_unsaved = make_lit_string(" *"); + persist String message_unsynced = make_lit_string(" !"); + + String message = {0}; + switch (view->action){ + case IAct_Switch: message = make_lit_string("Switch: "); break; + case IAct_Kill: message = make_lit_string("Kill: "); break; + } + + Absolutes absolutes; + Editing_File *file; + Working_Set *working_set = &models->working_set; + Editing_Layout *layout = &models->layout; + GUI_Item_Update update = {0}; + + { + Single_Line_Input_Step step; + Key_Event_Data key; + i32 i; + for (i = 0; i < keys.count; ++i){ + key = get_single_key(&keys, i); + step = app_single_line_input_step(system, key, &view->dest); + if (step.made_a_change){ + view->list_i = 0; + result.consume_keys = 1; + } + } + } + + get_absolutes(view->dest, &absolutes, 1, 1); + + gui_do_text_field(target, message, view->dest); + + scroll_context.id[0] = (u64)(working_set); + if (gui_get_scroll_vars(target, scroll_context, + &view->gui_scroll, &view->scroll_region)){ + snap_into_view = 1; + } + gui_begin_scrollable(target, scroll_context, view->gui_scroll, + 9.f * view->font_height, show_scrollbar); + + id.id[0] = (u64)(working_set) + 1; + if (gui_begin_list(target, id, view->list_i, + 0, snap_into_view, &update)){ + gui_standard_list(target, id, view->current_scroll, view->scroll_region, + &keys, &view->list_i, &update); + } + + { + Partition *part = &models->mem.part; + Temp_Memory temp = begin_temp_memory(part); + File_Node *node = 0, *used_nodes = 0; + Editing_File **reserved_files = 0; + i32 reserved_top = 0, i = 0; + View_Iter iter = {0}; + + partition_align(part, sizeof(i32)); + reserved_files = (Editing_File**)partition_current(part); + + used_nodes = &working_set->used_sentinel; + for (dll_items(node, used_nodes)){ + file = (Editing_File*)node; + Assert(!file->is_dummy); + + if (filename_match(view->dest, &absolutes, file->name.live_name, 1)){ + iter = file_view_iter_init(layout, file, 0); + if (file_view_iter_good(iter)){ + reserved_files[reserved_top++] = file; + } + else{ + if (file->name.live_name.str[0] == '*'){ + reserved_files[reserved_top++] = file; + } + else{ + message = string_zero(); + switch (buffer_get_sync(file)){ + case SYNC_BEHIND_OS: message = message_unsynced; break; + case SYNC_UNSAVED: message = message_unsaved; break; + } + + id.id[0] = (u64)(file); + if (gui_do_file_option(target, id, file->name.live_name, 0, message)){ + complete = 1; + copy(&comp_dest, file->name.live_name); + } + } + } + } + } + + for (i = 0; i < reserved_top; ++i){ + file = reserved_files[i]; + + message = string_zero(); + switch (buffer_get_sync(file)){ + case SYNC_BEHIND_OS: message = message_unsynced; break; + case SYNC_UNSAVED: message = message_unsaved; break; + } + + id.id[0] = (u64)(file); + if (gui_do_file_option(target, id, file->name.live_name, 0, message)){ + complete = 1; + copy(&comp_dest, file->name.live_name); + } + } + + end_temp_memory(temp); + } + + gui_end_list(target); + + gui_end_scrollable(target); + }break; + + case IInt_Sure_To_Close: + { + i32 action = -1; + + String empty_str = {0}; + String message = make_lit_string("There is one or more files unsaved changes, close anyway?"); + + gui_do_text_field(target, message, empty_str); + + id.id[0] = (u64)('y'); + message = make_lit_string("(Y)es"); + if (gui_do_fixed_option(target, id, message, 'y')){ + action = 0; + } + + id.id[0] = (u64)('n'); + message = make_lit_string("(N)o"); + if (gui_do_fixed_option(target, id, message, 'n')){ + action = 1; + } + + if (action != -1){ + complete = 1; + copy(&comp_dest, view->dest); + comp_action = action; + } + }break; + + case IInt_Sure_To_Kill: + { + i32 action = -1; + + String empty_str = {0}; + String message = make_lit_string("There are unsaved changes, close anyway?"); + + gui_do_text_field(target, message, empty_str); + + id.id[0] = (u64)('y'); + message = make_lit_string("(Y)es"); + if (gui_do_fixed_option(target, id, message, 'y')){ + action = 0; + } + + id.id[0] = (u64)('n'); + message = make_lit_string("(N)o"); + if (gui_do_fixed_option(target, id, message, 'n')){ + action = 1; + } + + id.id[0] = (u64)('s'); + message = make_lit_string("(S)ave and kill"); + if (gui_do_fixed_option(target, id, message, 's')){ + action = 2; + } + + if (action != -1){ + complete = 1; + copy(&comp_dest, view->dest); + comp_action = action; + } + }break; + } + + if (complete){ + terminate_with_null(&comp_dest); + interactive_view_complete(system, view, comp_dest, comp_action); + } + }break; + } + } + } + gui_end_top_level(target); + + result.animating = target->animating; + return(result); +} + +internal f32 +view_get_scroll_y(View *view){ + f32 v; + if (view->showing_ui == VUI_None){ + v = view->recent->scroll.scroll_y; + } + else{ + v = view->gui_scroll.scroll_y; + } + return(v); +} + +internal void +click_button_input(GUI_Target *target, GUI_Session *session, Input_Summary *user_input, + GUI_Interactive *b, b32 *is_animating){ + i32 mx = user_input->mouse.x; + i32 my = user_input->mouse.y; + + if (hit_check(mx, my, session->rect)){ + target->hover = b->id; + if (user_input->mouse.press_l){ + target->mouse_hot = b->id; + *is_animating = 1; + } + if (user_input->mouse.release_l && gui_id_eq(target->mouse_hot, b->id)){ + target->active = b->id; + target->mouse_hot = gui_id_zero(); + *is_animating = 1; + } + } + else if (gui_id_eq(target->hover, b->id)){ + target->hover = gui_id_zero(); + } +} + +internal b32 +scroll_button_input(GUI_Target *target, GUI_Session *session, Input_Summary *user_input, + GUI_id id, b32 *is_animating){ + b32 result = 0; + i32 mx = user_input->mouse.x; + i32 my = user_input->mouse.y; + + if (hit_check(mx, my, session->rect)){ + target->hover = id; + if (user_input->mouse.l){ + target->mouse_hot = id; + gui_activate_scrolling(target); + *is_animating = 1; + result = 1; + } + } + else if (gui_id_eq(target->hover, id)){ + target->hover = gui_id_zero(); + } + return(result); +} + +struct Input_Process_Result{ + GUI_Scroll_Vars vars; + i32_Rect region; + b32 is_animating; +}; + +internal Input_Process_Result +do_input_file_view(System_Functions *system, + View *view, i32_Rect rect, b32 is_active, + Input_Summary *user_input, + GUI_Scroll_Vars vars, i32_Rect region){ + Input_Process_Result result = {0}; + b32 is_file_scroll = 0; + + GUI_Session gui_session = {0}; + GUI_Header *h = 0; + GUI_Target *target = &view->gui_target; + GUI_Interpret_Result interpret_result = {0}; + + result.vars = vars; + result.region = region; + + target->active = gui_id_zero(); + + if (target->push.pos > 0){ + gui_session_init(&gui_session, target, rect, view->font_height); + + for (h = (GUI_Header*)target->push.base; + h->type; + h = NextHeader(h)){ + interpret_result = gui_interpret(target, &gui_session, h, + result.vars, result.region); + + if (interpret_result.has_region){ + result.region = interpret_result.region; + } + + switch (h->type){ + case guicom_file_option: + case guicom_fixed_option: + case guicom_fixed_option_checkbox: + { + GUI_Interactive *b = (GUI_Interactive*)h; + + if (interpret_result.auto_activate){ + target->auto_hot = gui_id_zero(); + target->active = b->id; + result.is_animating = 1; + } + else if (interpret_result.auto_hot){ + if (!gui_id_eq(target->auto_hot, b->id)){ + target->auto_hot = b->id; + result.is_animating = 1; + } + } + }break; + } + + if (interpret_result.has_info){ + switch (h->type){ + case guicom_top_bar: break; + + case guicom_file: + { + f32 new_max_y = view_compute_max_target_y(view); + + view->file_region = gui_session.rect; + result.vars.max_y = new_max_y; + + if (view->reinit_scrolling){ + view_reinit_scrolling(view); + result.is_animating = 1; + } + if (file_step(view, gui_session.rect, user_input, is_active)){ + result.is_animating = 1; + } + is_file_scroll = 1; + }break; + + case guicom_color_button: + case guicom_font_button: + case guicom_button: + case guicom_file_option: + case guicom_style_preview: + { + GUI_Interactive *b = (GUI_Interactive*)h; + + click_button_input(target, &gui_session, user_input, b, &result.is_animating); + }break; + + case guicom_fixed_option: + case guicom_fixed_option_checkbox: + { + GUI_Interactive *b = (GUI_Interactive*)h; + + click_button_input(target, &gui_session, user_input, b, &result.is_animating); + + { + Key_Event_Data key; + Key_Summary *keys = &user_input->keys; + + void *ptr = (b + 1); + String string; + char activation_key; + + i32 i, count; + + string = gui_read_string(&ptr); + activation_key = *(char*)ptr; + + count = keys->count; + for (i = 0; i < count; ++i){ + key = get_single_key(keys, i); + if (char_to_upper(key.character) == char_to_upper(activation_key)){ + target->active = b->id; + result.is_animating = 1; + break; + } + } + } + }break; + + case guicom_scrollable_slider: + { + GUI_id id = gui_id_scrollbar_slider(); + i32 mx = user_input->mouse.x; + i32 my = user_input->mouse.y; + f32 v = 0; + + if (hit_check(mx, my, gui_session.rect)){ + target->hover = id; + if (user_input->mouse.press_l){ + target->mouse_hot = id; + result.is_animating = 1; + } + } + else if (gui_id_eq(target->hover, id)){ + target->hover = gui_id_zero(); + } + + if (gui_id_eq(target->mouse_hot, id)){ + v = unlerp(gui_session.scroll_top, (f32)my, + gui_session.scroll_bottom); + v = clamp(0.f, v, 1.f); + result.vars.target_y = lerp(0.f, v, result.vars.max_y); + + gui_activate_scrolling(target); + result.is_animating = 1; + } + } + // NOTE(allen): NO BREAK HERE!! + + case guicom_scrollable_invisible: + { + if (user_input->mouse.wheel != 0){ + result.vars.target_y += user_input->mouse.wheel*target->delta; + + result.vars.target_y = + clamp(0.f, result.vars.target_y, result.vars.max_y); + gui_activate_scrolling(target); + result.is_animating = 1; + } + }break; + + case guicom_scrollable_top: + { + GUI_id id = gui_id_scrollbar_top(); + + if (scroll_button_input(target, &gui_session, user_input, id, &result.is_animating)){ + result.vars.target_y -= target->delta * 0.25f; + result.vars.target_y = clamp_bottom(0.f, result.vars.target_y); + } + }break; + + case guicom_scrollable_bottom: + { + GUI_id id = gui_id_scrollbar_bottom(); + + if (scroll_button_input(target, &gui_session, user_input, id, &result.is_animating)){ + result.vars.target_y += target->delta * 0.25f; + result.vars.target_y = clamp_top(0.f, result.vars.max_y); + } + }break; + + case guicom_end_scrollable_section: + { + if (!is_file_scroll){ + f32 new_max_y = gui_session.suggested_max_y; + result.vars.max_y = new_max_y; + } + }break; + } + } + } + + if (!user_input->mouse.l){ + if (!gui_id_is_null(target->mouse_hot)){ + target->mouse_hot = gui_id_zero(); + result.is_animating = 1; + } + } + + { + GUI_Scroll_Vars scroll_vars = result.vars; + b32 is_new_target = 0; + if (scroll_vars.target_x != scroll_vars.prev_target_x) is_new_target = 1; + if (scroll_vars.target_y != scroll_vars.prev_target_y) is_new_target = 1; + + if (view->persistent.models->scroll_rule(scroll_vars.target_x, scroll_vars.target_y, + &scroll_vars.scroll_x, &scroll_vars.scroll_y, + (view->persistent.id) + 1, is_new_target)){ + result.is_animating = 1; + } + + scroll_vars.prev_target_x = scroll_vars.target_x; + scroll_vars.prev_target_y = scroll_vars.target_y; + + result.vars = scroll_vars; + } + } + + return(result); +} + +internal i32 +draw_file_loaded(View *view, i32_Rect rect, b32 is_active, Render_Target *target){ + Models *models = view->persistent.models; + Editing_File *file = view->file_data.file; + Style *style = main_style(models); + i32 line_height = view->font_height; + + i32 max_x = rect.x1 - rect.x0; + i32 max_y = rect.y1 - rect.y0 + line_height; + + Assert(file && !file->is_dummy && buffer_good(&file->state.buffer)); + + b32 tokens_use = 0; + Cpp_Token_Stack token_stack = {}; + if (file){ + tokens_use = file->state.tokens_complete && (file->state.token_stack.count > 0); + token_stack = file->state.token_stack; + } + + Partition *part = &models->mem.part; + + Temp_Memory temp = begin_temp_memory(part); + + partition_align(part, 4); + i32 max = partition_remaining(part) / sizeof(Buffer_Render_Item); + Buffer_Render_Item *items = push_array(part, Buffer_Render_Item, max); + + i16 font_id = models->global_font.font_id; + Render_Font *font = get_font_info(models->font_set, font_id)->font; + float *advance_data = 0; + if (font) advance_data = font->advance_data; + + i32 count; + Full_Cursor render_cursor; + Buffer_Render_Options opts = {}; + + f32 *wraps = view->file_data.line_wrap_y; + f32 scroll_x = view->recent->scroll.scroll_x; + f32 scroll_y = view->recent->scroll.scroll_y; + + { + render_cursor = buffer_get_start_cursor(&file->state.buffer, wraps, scroll_y, + !view->file_data.unwrapped_lines, (f32)max_x, advance_data, (f32)line_height); + + view->recent->scroll_i = render_cursor.pos; + + buffer_get_render_data(&file->state.buffer, items, max, &count, + (f32)rect.x0, (f32)rect.y0, + scroll_x, scroll_y, render_cursor, + !view->file_data.unwrapped_lines, + (f32)max_x, (f32)max_y, + advance_data, (f32)line_height, + opts); + } + + Assert(count > 0); + + i32 cursor_begin, cursor_end; + u32 cursor_color, at_cursor_color; + if (view->file_data.show_temp_highlight){ + cursor_begin = view->file_data.temp_highlight.pos; + cursor_end = view->file_data.temp_highlight_end_pos; + cursor_color = style->main.highlight_color; + at_cursor_color = style->main.at_highlight_color; + } + else{ + cursor_begin = view->recent->cursor.pos; + cursor_end = cursor_begin + 1; + cursor_color = style->main.cursor_color; + at_cursor_color = style->main.at_cursor_color; + } + + i32 token_i = 0; + u32 main_color = style->main.default_color; + u32 special_color = style->main.special_character_color; + if (tokens_use){ + Cpp_Get_Token_Result result = cpp_get_token(&token_stack, items->index); + main_color = *style_get_color(style, token_stack.tokens[result.token_index]); + token_i = result.token_index + 1; + } + + u32 mark_color = style->main.mark_color; + Buffer_Render_Item *item = items; + i32 prev_ind = -1; + u32 highlight_color = 0; + u32 highlight_this_color = 0; + + for (i32 i = 0; i < count; ++i, ++item){ + i32 ind = item->index; + highlight_this_color = 0; + if (tokens_use && ind != prev_ind){ + Cpp_Token current_token = token_stack.tokens[token_i-1]; + + if (token_i < token_stack.count){ + if (ind >= token_stack.tokens[token_i].start){ + main_color = + *style_get_color(style, token_stack.tokens[token_i]); + current_token = token_stack.tokens[token_i]; + ++token_i; + } + else if (ind >= current_token.start + current_token.size){ + main_color = 0xFFFFFFFF; + } + } + + if (current_token.type == CPP_TOKEN_JUNK && + i >= current_token.start && i < current_token.start + current_token.size){ + highlight_color = style->main.highlight_junk_color; + } + else{ + highlight_color = 0; + } + } + + u32 char_color = main_color; + if (item->flags & BRFlag_Special_Character) char_color = special_color; + + f32_Rect char_rect = f32R(item->x0, item->y0, item->x1, item->y1); + if (view->file_data.show_whitespace && highlight_color == 0 && + char_is_whitespace((char)item->glyphid)){ + highlight_this_color = style->main.highlight_white_color; + } + else{ + highlight_this_color = highlight_color; + } + + if (cursor_begin <= ind && ind < cursor_end && (ind != prev_ind || cursor_begin < ind)){ + if (is_active){ + draw_rectangle(target, char_rect, cursor_color); + char_color = at_cursor_color; + } + else{ + if (!view->file_data.show_temp_highlight){ + draw_rectangle_outline(target, char_rect, cursor_color); + } + } + } + else if (highlight_this_color){ + draw_rectangle(target, char_rect, highlight_this_color); + } + + u32 fade_color = 0xFFFF00FF; + f32 fade_amount = 0.f; + + if (file->state.paste_effect.tick_down > 0 && + file->state.paste_effect.start <= ind && + ind < file->state.paste_effect.end){ + fade_color = file->state.paste_effect.color; + fade_amount = (f32)(file->state.paste_effect.tick_down) / file->state.paste_effect.tick_max; + } + + char_color = color_blend(char_color, fade_amount, fade_color); + + if (ind == view->recent->mark && prev_ind != ind){ + draw_rectangle_outline(target, char_rect, mark_color); + } + if (item->glyphid != 0){ + font_draw_glyph(target, font_id, (u8)item->glyphid, + item->x0, item->y0, char_color); + } + prev_ind = ind; + } + + end_temp_memory(temp); + + return(0); +} + +internal void +draw_text_field(Render_Target *target, View *view, i32_Rect rect, String p, String t){ + Models *models = view->persistent.models; + Style *style = main_style(models); + + u32 back_color = style->main.margin_color; + u32 text1_color = style->main.default_color; + u32 text2_color = style->main.file_info_style.pop1_color; + + i32 x = rect.x0; + i32 y = rect.y0 + 2; + + i16 font_id = models->global_font.font_id; + + if (target){ + draw_rectangle(target, rect, back_color); + x = CEIL32(draw_string(target, font_id, p, x, y, text2_color)); + draw_string(target, font_id, t, x, y, text1_color); + } +} + +internal void +draw_text_with_cursor(Render_Target *target, View *view, i32_Rect rect, String s, i32 pos){ + Models *models = view->persistent.models; + Style *style = main_style(models); + + u32 back_color = style->main.margin_color; + u32 text_color = style->main.default_color; + u32 cursor_color = style->main.cursor_color; + u32 at_cursor_color = style->main.at_cursor_color; + + f32 x = (f32)rect.x0; + i32 y = rect.y0 + 2; + + i16 font_id = models->global_font.font_id; + + if (target){ + draw_rectangle(target, rect, back_color); + + if (pos >= 0 && pos < s.size){ + String part1, part2, part3; + i32_Rect cursor_rect; + Render_Font *font = get_font_info(models->font_set, font_id)->font; + + part1 = substr(s, 0, pos); + part2 = substr(s, pos, 1); + part3 = substr(s, pos+1, s.size-pos-1); + + + x = draw_string(target, font_id, part1, FLOOR32(x), y, text_color); + + cursor_rect.x0 = FLOOR32(x); + cursor_rect.x1 = FLOOR32(x) + CEIL32(font->advance_data[s.str[pos]]); + cursor_rect.y0 = y; + cursor_rect.y1 = y + view->font_height; + draw_rectangle(target, cursor_rect, cursor_color); + x = draw_string(target, font_id, part2, FLOOR32(x), y, at_cursor_color); + + draw_string(target, font_id, part3, FLOOR32(x), y, text_color); + } + else{ + draw_string(target, font_id, s, FLOOR32(x), y, text_color); + } + } +} + +internal void +draw_file_bar(Render_Target *target, View *view, Editing_File *file, i32_Rect rect){ + File_Bar bar; + Models *models = view->persistent.models; + Style_Font *font = &models->global_font; + Style *style = main_style(models); + Interactive_Style bar_style = style->main.file_info_style; + + u32 back_color = bar_style.bar_color; + u32 base_color = bar_style.base_color; + u32 pop1_color = bar_style.pop1_color; + u32 pop2_color = bar_style.pop2_color; + + bar.rect = rect; + + if (target){ + bar.font_id = font->font_id; + bar.pos_x = (f32)bar.rect.x0; + bar.pos_y = (f32)bar.rect.y0; + bar.text_shift_y = 2; + bar.text_shift_x = 0; + + draw_rectangle(target, bar.rect, back_color); + if (!file){ + intbar_draw_string(target, &bar, make_lit_string("*NULL*"), base_color); + } + else{ + intbar_draw_string(target, &bar, file->name.live_name, base_color); + intbar_draw_string(target, &bar, make_lit_string(" -"), base_color); + + if (file->is_loading){ + intbar_draw_string(target, &bar, make_lit_string(" loading"), base_color); + } + else{ + char line_number_space[30]; + String line_number = make_fixed_width_string(line_number_space); + append(&line_number, " L#"); + append_int_to_str(view->recent->cursor.line, &line_number); + append(&line_number, " C#"); + append_int_to_str(view->recent->cursor.character, &line_number); + + intbar_draw_string(target, &bar, line_number, base_color); + + intbar_draw_string(target, &bar, make_lit_string(" -"), base_color); + + if (file->settings.dos_write_mode){ + intbar_draw_string(target, &bar, make_lit_string(" dos"), base_color); + } + else{ + intbar_draw_string(target, &bar, make_lit_string(" nix"), base_color); + } + + if (file->state.still_lexing){ + intbar_draw_string(target, &bar, make_lit_string(" parsing"), pop1_color); + } + + if (!file->settings.unimportant){ + switch (buffer_get_sync(file)){ + case SYNC_BEHIND_OS: + { + persist String out_of_sync = make_lit_string(" !"); + intbar_draw_string(target, &bar, out_of_sync, pop2_color); + }break; + + case SYNC_UNSAVED: + { + persist String out_of_sync = make_lit_string(" *"); + intbar_draw_string(target, &bar, out_of_sync, pop2_color); + }break; + } + } + } + } + } +} + +u32 +get_margin_color(i32 active_level, Style *style){ + u32 margin = 0xFFFFFFFF; + + switch (active_level){ + default: + margin = style->main.margin_color; + break; + + case 1: case 2: + margin = style->main.margin_hover_color; + break; + + case 3: case 4: + margin = style->main.margin_active_color; + break; + } + + return(margin); +} + +internal void +draw_color_button(GUI_Target *gui_target, Render_Target *target, View *view, + i32_Rect rect, GUI_id id, u32 fore, u32 back, String text){ + Models *models = view->persistent.models; + + i32 active_level = gui_active_level(gui_target, id); + i16 font_id = models->global_font.font_id; + + if (active_level > 0){ + Swap(u32, back, fore); + } + + draw_rectangle(target, rect, back); + draw_string(target, font_id, text, rect.x0, rect.y0 + 1, fore); +} + +internal void +draw_font_button(GUI_Target *gui_target, Render_Target *target, View *view, + i32_Rect rect, GUI_id id, i16 font_id, String text){ + Models *models = view->persistent.models; + Style *style = main_style(models); + + i32 active_level = gui_active_level(gui_target, id); + + u32 margin = get_margin_color(active_level, style); + u32 back = style->main.back_color; + u32 text_color = style->main.default_color; + + draw_rectangle(target, rect, back); + draw_rectangle_outline(target, rect, margin); + draw_string(target, font_id, text, rect.x0, rect.y0 + 1, text_color); +} + +internal void +draw_fat_option_block(GUI_Target *gui_target, Render_Target *target, View *view, i32_Rect rect, GUI_id id, + String text, String pop, i8 checkbox = -1){ + Models *models = view->persistent.models; + Style *style = main_style(models); + + i32 active_level = gui_active_level(gui_target, id); + i16 font_id = models->global_font.font_id; + + i32_Rect inner = get_inner_rect(rect, 3); + + u32 margin = get_margin_color(active_level, style); + u32 back = style->main.back_color; + u32 text_color = style->main.default_color; + u32 pop_color = style->main.special_character_color; + + i32 h = view->font_height; + i32 x = inner.x0 + 3; + i32 y = inner.y0 + h/2 - 1; + + draw_rectangle(target, inner, back); + draw_margin(target, rect, inner, margin); + + if (checkbox != -1){ + u32 checkbox_color = style->main.margin_active_color; + i32_Rect checkbox_rect = get_inner_rect(inner, (inner.y1 - inner.y0 - h)/2); + checkbox_rect.x1 = checkbox_rect.x0 + (checkbox_rect.y1 - checkbox_rect.y0); + + if (checkbox == 0){ + draw_rectangle_outline(target, checkbox_rect, checkbox_color); + } + else{ + draw_rectangle(target, checkbox_rect, checkbox_color); + } + + x = checkbox_rect.x1 + 3; + } + + x = CEIL32(draw_string(target, font_id, text, x, y, text_color)); + draw_string(target, font_id, pop, x, y, pop_color); +} + +internal void +draw_button(GUI_Target *gui_target, Render_Target *target, View *view, i32_Rect rect, GUI_id id, String text){ + Models *models = view->persistent.models; + Style *style = main_style(models); + + i32 active_level = gui_active_level(gui_target, id); + i16 font_id = models->global_font.font_id; + + i32_Rect inner = get_inner_rect(rect, 3); + + u32 margin = style->main.default_color; + u32 back = get_margin_color(active_level, style); + u32 text_color = style->main.default_color; + + i32 h = view->font_height; + i32 y = inner.y0 + h/2 - 1; + + i32 w = (i32)font_string_width(target, font_id, text); + i32 x = (inner.x1 + inner.x0 - w)/2; + + draw_rectangle(target, inner, back); + draw_rectangle_outline(target, inner, margin); + + draw_string(target, font_id, text, x, y, text_color); +} + +internal void +draw_style_preview(GUI_Target *gui_target, Render_Target *target, View *view, i32_Rect rect, GUI_id id, Style *style){ + Models *models = view->persistent.models; + + i32 active_level = gui_active_level(gui_target, id); + i16 font_id = models->global_font.font_id; + Font_Info *info = get_font_info(models->font_set, font_id); + + i32_Rect inner = get_inner_rect(rect, 3); + + u32 margin_color = get_margin_color(active_level, style); + u32 back = style->main.back_color; + u32 text_color = style->main.default_color; + u32 keyword_color = style->main.keyword_color; + u32 int_constant_color = style->main.int_constant_color; + u32 comment_color = style->main.comment_color; + + draw_margin(target, rect, inner, margin_color); + draw_rectangle(target, inner, back); + + i32 y = inner.y0; + i32 x = inner.x0; + x = CEIL32(draw_string(target, font_id, style->name.str, x, y, text_color)); + i32 font_x = (i32)(inner.x1 - font_string_width(target, font_id, info->name.str)); + if (font_x > x + 10){ + draw_string(target, font_id, info->name.str, font_x, y, text_color); + } + + x = inner.x0; + y += info->height; + x = CEIL32(draw_string(target, font_id, "if", x, y, keyword_color)); + x = CEIL32(draw_string(target, font_id, "(x < ", x, y, text_color)); + x = CEIL32(draw_string(target, font_id, "0", x, y, int_constant_color)); + x = CEIL32(draw_string(target, font_id, ") { x = ", x, y, text_color)); + x = CEIL32(draw_string(target, font_id, "0", x, y, int_constant_color)); + x = CEIL32(draw_string(target, font_id, "; } ", x, y, text_color)); + x = CEIL32(draw_string(target, font_id, "// comment", x, y, comment_color)); + + x = inner.x0; + y += info->height; + draw_string(target, font_id, "[] () {}; * -> +-/ <>= ! && || % ^", x, y, text_color); +} + +internal i32 +do_render_file_view(System_Functions *system, View *view, + View *active, i32_Rect rect, b32 is_active, + Render_Target *target, Input_Summary *user_input){ + + Editing_File *file = view->file_data.file; + i32 result = 0; + + GUI_Session gui_session = {0}; + GUI_Header *h; + GUI_Target *gui_target = &view->gui_target; + GUI_Interpret_Result interpret_result = {0}; + + f32 v; + + if (gui_target->push.pos > 0){ + gui_session_init(&gui_session, gui_target, rect, view->font_height); + + v = view_get_scroll_y(view); + + i32_Rect clip_rect = rect; + draw_push_clip(target, clip_rect); + + for (h = (GUI_Header*)gui_target->push.base; + h->type; + h = NextHeader(h)){ + interpret_result = gui_interpret(gui_target, &gui_session, h, + *view->current_scroll, + view->scroll_region); + + if (interpret_result.has_info){ + if (gui_session.clip_y > clip_rect.y0){ + clip_rect.y0 = gui_session.clip_y; + draw_change_clip(target, clip_rect); + } + + switch (h->type){ + case guicom_top_bar: + { + draw_file_bar(target, view, file, gui_session.rect); + }break; + + case guicom_file: + { + if (view->reinit_scrolling){ + view_reinit_scrolling(view); + } + if (file && file_is_ready(file)){ + result = draw_file_loaded(view, gui_session.rect, is_active, target); + } + }break; + + case guicom_text_field: + { + void *ptr = (h+1); + String p = gui_read_string(&ptr); + String t = gui_read_string(&ptr); + draw_text_field(target, view, gui_session.rect, p, t); + }break; + + case guicom_text_with_cursor: + { + void *ptr = (h+1); + String s = gui_read_string(&ptr); + i32 pos = gui_read_integer(&ptr); + + draw_text_with_cursor(target, view, gui_session.rect, s, pos); + }break; + + case guicom_color_button: + { + GUI_Interactive *b = (GUI_Interactive*)h; + void *ptr = (b + 1); + u32 fore = (u32)gui_read_integer(&ptr); + u32 back = (u32)gui_read_integer(&ptr); + String t = gui_read_string(&ptr); + + draw_color_button(gui_target, target, view, gui_session.rect, b->id, fore, back, t); + }break; + + case guicom_font_button: + { + GUI_Interactive *b = (GUI_Interactive*)h; + void *ptr = (b + 1); + i16 font_id = (i16)gui_read_integer(&ptr); + String t = gui_read_string(&ptr); + + draw_font_button(gui_target, target, view, gui_session.rect, b->id, font_id, t); + }break; + + case guicom_file_option: + { + GUI_Interactive *b = (GUI_Interactive*)h; + void *ptr = (b + 1); + b32 folder = gui_read_integer(&ptr); + String f = gui_read_string(&ptr); + String m = gui_read_string(&ptr); + + if (folder){ + append(&f, system->slash); + } + + draw_fat_option_block(gui_target, target, view, gui_session.rect, b->id, f, m); + }break; + + case guicom_style_preview: + { + GUI_Interactive *b = (GUI_Interactive*)h; + i32 style_index = *(i32*)(b + 1); + Style *style = get_style(view->persistent.models, style_index); + + draw_style_preview(gui_target, target, view, gui_session.rect, b->id, style); + }break; + + case guicom_fixed_option: + case guicom_fixed_option_checkbox: + { + GUI_Interactive *b = (GUI_Interactive*)h; + void *ptr = (b + 1); + String f = gui_read_string(&ptr); + String m = {0}; + i8 status = -1; + if (h->type == guicom_fixed_option_checkbox){ + gui_read_byte(&ptr); + status = (i8)gui_read_byte(&ptr); + } + + draw_fat_option_block(gui_target, target, view, gui_session.rect, b->id, f, m, status); + }break; + + case guicom_button: + { + GUI_Interactive *b = (GUI_Interactive*)h; + void *ptr = (b + 1); + String t = gui_read_string(&ptr); + + draw_button(gui_target, target, view, gui_session.rect, b->id, t); + }break; + + case guicom_scrollable_bar: + { + Models *models = view->persistent.models; + Style *style = main_style(models); + + u32 back; + u32 outline; + + i32_Rect bar = gui_session.rect; + + back = style->main.back_color; + if (is_active){ + outline = style->main.margin_active_color; + } + else{ + outline = style->main.margin_color; + } + + draw_rectangle(target, bar, back); + draw_rectangle_outline(target, bar, outline); + }break; + + case guicom_scrollable_top: + case guicom_scrollable_slider: + case guicom_scrollable_bottom: + { + GUI_id id; + Models *models = view->persistent.models; + Style *style = main_style(models); + i32_Rect box = gui_session.rect; + + i32 active_level; + + u32 back; + u32 outline; + + switch (h->type){ + case guicom_scrollable_top: id = gui_id_scrollbar_top(); break; + case guicom_scrollable_bottom: id = gui_id_scrollbar_bottom(); break; + default: id = gui_id_scrollbar_slider(); break; + } + + active_level = gui_active_level(gui_target, id); + + switch (active_level){ + case 0: back = style->main.back_color; break; + case 1: back = style->main.margin_hover_color; break; + default: back = style->main.margin_active_color; break; + } + + if (is_active){ + outline = style->main.margin_active_color; + } + else{ + outline = style->main.margin_color; + } + + draw_rectangle(target, box, back); + draw_margin(target, box, get_inner_rect(box, 2), outline); + }break; + + case guicom_begin_scrollable_section: + clip_rect.x1 = Min(gui_session.scroll_region.x1, clip_rect.x1); + draw_push_clip(target, clip_rect); + break; + + case guicom_end_scrollable_section: + clip_rect = draw_pop_clip(target); + break; + } + } + } + + draw_pop_clip(target); + } + + return(result); +} + +inline void +file_view_free_buffers(View *view){ + General_Memory *general = &view->persistent.models->mem.general; + if (view->file_data.line_wrap_y){ + general_memory_free(general, view->file_data.line_wrap_y); + view->file_data.line_wrap_y = 0; + } + general_memory_free(general, view->gui_mem); + view->gui_mem = 0; +} + +struct Search_Range{ + Buffer_Type *buffer; + i32 start, size; +}; + +struct Search_Set{ + Search_Range *ranges; + i32 count, max; +}; + +struct Search_Iter{ + String word; + i32 pos; + i32 i; +}; + +struct Search_Match{ + Buffer_Type *buffer; + i32 start, end; + b32 found_match; +}; + +internal void +search_iter_init(General_Memory *general, Search_Iter *iter, i32 size){ + i32 str_max; + + if (iter->word.str == 0){ + str_max = size*2; + iter->word.str = (char*)general_memory_allocate(general, str_max, 0); + iter->word.memory_size = str_max; + } + else if (iter->word.memory_size < size){ + str_max = size*2; + iter->word.str = (char*)general_memory_reallocate_nocopy(general, iter->word.str, str_max, 0); + iter->word.memory_size = str_max; + } + + iter->i = 0; + iter->pos = 0; +} + +internal void +search_set_init(General_Memory *general, Search_Set *set, i32 set_count){ + i32 max; + + if (set->ranges == 0){ + max = set_count*2; + set->ranges = (Search_Range*)general_memory_allocate(general, sizeof(Search_Range)*max, 0); + set->max = max; + } + else if (set->max < set_count){ + max = set_count*2; + set->ranges = (Search_Range*)general_memory_reallocate_nocopy( + general, set->ranges, sizeof(Search_Range)*max, 0); + set->max = max; + } + + set->count = set_count; +} + +internal void +search_hits_table_alloc(General_Memory *general, Table *hits, i32 table_size){ + void *mem; + i32 mem_size; + + mem_size = table_required_mem_size(table_size, sizeof(Offset_String)); + if (hits->hash_array == 0){ + mem = general_memory_allocate(general, mem_size, 0); + } + else{ + mem = general_memory_reallocate_nocopy(general, hits->hash_array, mem_size, 0); + } + table_init_memory(hits, mem, table_size, sizeof(Offset_String)); +} + +internal void +search_hits_init(General_Memory *general, Table *hits, String_Space *str, i32 table_size, i32 str_size){ + void *mem; + i32 mem_size; + + if (hits->hash_array == 0){ + search_hits_table_alloc(general, hits, table_size); + } + else if (hits->max < table_size){ + mem_size = table_required_mem_size(table_size, sizeof(Offset_String)); + mem = general_memory_reallocate_nocopy(general, hits->hash_array, mem_size, 0); + table_init_memory(hits, mem, table_size, sizeof(Offset_String)); + } + + if (str->space == 0){ + str->space = (char*)general_memory_allocate(general, str_size, 0); + str->max = str_size; + } + else if (str->max < str_size){ + str->space = (char*)general_memory_reallocate_nocopy(general, str->space, str_size, 0); + str->max = str_size; + } + + str->pos = str->new_pos = 0; + table_clear(hits); +} + +internal b32 +search_hit_add(General_Memory *general, Table *hits, String_Space *space, char *str, i32 len){ + b32 result; + i32 new_size; + Offset_String ostring; + Table new_hits; + + Assert(len != 0); + + ostring = strspace_append(space, str, len); + if (ostring.size == 0){ + new_size = Max(space->max*2, space->max + len); + space->space = (char*)general_memory_reallocate(general, space->space, space->new_pos, new_size, 0); + ostring = strspace_append(space, str, len); + } + + Assert(ostring.size != 0); + + if (table_at_capacity(hits)){ + search_hits_table_alloc(general, &new_hits, hits->max*2); + table_clear(&new_hits); + table_rehash(hits, &new_hits, space->space, tbl_offset_string_hash, tbl_offset_string_compare); + general_memory_free(general, hits->hash_array); + *hits = new_hits; + } + + if (!table_add(hits, &ostring, space->space, tbl_offset_string_hash, tbl_offset_string_compare)){ + result = 1; + strspace_keep_prev(space); + } + else{ + result = 0; + strspace_discard_prev(space); + } + + return(result); +} + +internal Search_Match +search_next_match(Partition *part, Search_Set *set, Search_Iter *iter_){ + Search_Match result = {}; + Search_Iter iter = *iter_; + Search_Range *range; + Temp_Memory temp; + char *spare; + i32 start_pos, end_pos, count; + + temp = begin_temp_memory(part); + spare = push_array(part, char, iter.word.size); + + count = set->count; + for (; iter.i < count;){ + range = set->ranges + iter.i; + + end_pos = range->start + range->size; + + if (iter.pos + iter.word.size < end_pos){ + start_pos = Max(iter.pos, range->start); + result.start = buffer_find_string(range->buffer, start_pos, end_pos, iter.word.str, iter.word.size, spare); + + if (result.start < end_pos){ + iter.pos = result.start + 1; + if (result.start == 0 || !char_is_alpha_numeric(buffer_get_char(range->buffer, result.start - 1))){ + result.end = buffer_seek_word_right_assume_on_word(range->buffer, result.start); + if (result.end < end_pos){ + result.found_match = 1; + result.buffer = range->buffer; + iter.pos = result.end; + break; + } + } + } + else{ + ++iter.i, iter.pos = 0; + } + } + else{ + ++iter.i, iter.pos = 0; + } + } + end_temp_memory(temp); + + *iter_ = iter; + + return(result); +} + +inline void +view_change_size(General_Memory *general, View *view){ + if (view->file_data.file){ + view_measure_wraps(general, view); + view->recent->cursor = view_compute_cursor_from_pos(view, view->recent->cursor.pos); + } +} + +struct Live_Views{ + View *views; + View free_sentinel; + i32 count, max; +}; + +internal View_And_ID +live_set_alloc_view(Live_Views *live_set, Panel *panel, Models *models){ + View_And_ID result = {}; + + Assert(live_set->count < live_set->max); + ++live_set->count; + + result.view = live_set->free_sentinel.next; + result.id = (i32)(result.view - live_set->views); + Assert(result.id == result.view->persistent.id); + + dll_remove(result.view); + memset(get_view_body(result.view), 0, get_view_size()); + + result.view->in_use = 1; + panel->view = result.view; + result.view->panel = panel; + + result.view->persistent.models = models; + result.view->scrub_max = 1; + result.view->current_scroll = &result.view->recent->scroll; + + init_query_set(&result.view->query_set); + + { + i32 gui_mem_size = Kbytes(32); + void *gui_mem = general_memory_allocate(&models->mem.general, gui_mem_size + 8, 0); + result.view->gui_mem = gui_mem; + gui_mem = advance_to_alignment(gui_mem); + result.view->gui_target.push = make_part(gui_mem, gui_mem_size); + } + + return(result); +} + +inline void +live_set_free_view(System_Functions *system, Live_Views *live_set, View *view){ + Assert(live_set->count > 0); + --live_set->count; + file_view_free_buffers(view); + dll_insert(&live_set->free_sentinel, view); + view->in_use = 0; +} + +// BOTTOM + diff --git a/4ed_system.h b/4ed_system.h index 6597a83e..26867dcf 100644 --- a/4ed_system.h +++ b/4ed_system.h @@ -197,6 +197,9 @@ typedef Sys_Post_Job_Sig(System_Post_Job); #define Sys_Cancel_Job_Sig(name) void name(Thread_Group_ID group_id, u32 job_id) typedef Sys_Cancel_Job_Sig(System_Cancel_Job); +#define Sys_Check_Cancel_Sig(name) b32 name(Thread_Context *thread) +typedef Sys_Check_Cancel_Sig(System_Check_Cancel); + #define Sys_Grow_Thread_Memory_Sig(name) void name(Thread_Memory *memory) typedef Sys_Grow_Thread_Memory_Sig(System_Grow_Thread_Memory); @@ -248,9 +251,10 @@ struct System_Functions{ System_CLI_Update_Step *cli_update_step; System_CLI_End_Update *cli_end_update; - // threads: 5 + // threads: 7 System_Post_Job *post_job; System_Cancel_Job *cancel_job; + System_Check_Cancel *check_cancel; System_Grow_Thread_Memory *grow_thread_memory; System_Acquire_Lock *acquire_lock; System_Release_Lock *release_lock; diff --git a/win32_4ed.cpp b/win32_4ed.cpp index 56ea7f54..67612028 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -40,9 +40,11 @@ struct Thread_Context{ u32 job_id; b32 running; + b32 cancel; Work_Queue *queue; u32 id; + u32 group_id; u32 windows_id; HANDLE handle; }; @@ -50,6 +52,9 @@ struct Thread_Context{ struct Thread_Group{ Thread_Context *threads; i32 count; + + i32 cancel_lock0; + i32 cancel_cv0; }; #define UseWinDll 1 @@ -111,6 +116,18 @@ struct Sys_Bubble : public Bubble{ }; #endif +enum CV_ID{ + CANCEL_CV0, + CANCEL_CV1, + CANCEL_CV2, + CANCEL_CV3, + CANCEL_CV4, + CANCEL_CV5, + CANCEL_CV6, + CANCEL_CV7, + CV_COUNT +}; + struct Win32_Vars{ System_Functions system; App_Functions app; @@ -128,6 +145,7 @@ struct Win32_Vars{ Work_Queue queues[THREAD_GROUP_COUNT]; Thread_Group groups[THREAD_GROUP_COUNT]; CRITICAL_SECTION locks[LOCK_COUNT]; + CONDITION_VARIABLE condition_vars[CV_COUNT]; Thread_Memory *thread_memory; Win32_Coroutine coroutine_data[18]; Win32_Coroutine *coroutine_free; @@ -277,10 +295,29 @@ Sys_Release_Lock_Sig(system_release_lock){ LeaveCriticalSection(&win32vars.locks[id]); } +internal void +system_wait_cv(i32 crit_id, i32 cv_id){ + SleepConditionVariableCS(win32vars.condition_vars + cv_id, + win32vars.locks + crit_id, + INFINITE); +} + +internal void +system_signal_cv(i32 crit_id, i32 cv_id){ + AllowLocal(crit_id); + WakeConditionVariable(win32vars.condition_vars + cv_id); +} + internal DWORD JobThreadProc(LPVOID lpParameter){ Thread_Context *thread = (Thread_Context*)lpParameter; - Work_Queue *queue = thread->queue; + Work_Queue *queue = win32vars.queues + thread->group_id; + Thread_Group *group = win32vars.groups + thread->group_id; + + i32 thread_index = thread->id - 1; + + i32 cancel_lock = group->cancel_lock0 + thread_index; + i32 cancel_cv = group->cancel_cv0 + thread_index; for (;;){ u32 read_index = queue->read_position; @@ -324,6 +361,13 @@ JobThreadProc(LPVOID lpParameter){ PostMessage(win32vars.window_handle, WM_4coder_ANIMATE, 0, 0); full_job->running_thread = 0; thread->running = 0; + + system_acquire_lock(cancel_lock); + if (thread->cancel){ + thread->cancel = 0; + system_signal_cv(cancel_lock, cancel_cv); + } + system_release_lock(cancel_lock); } } } @@ -362,8 +406,18 @@ Sys_Post_Job_Sig(system_post_job){ return result; } -// TODO(allen): I would like to get rid of job canceling -// but I still don't know what exactly I would do without it. +// NOTE(allen): New job cancelling system: +// +// Jobs are expected to periodically check their cancelation +// state, especially if they are taking a while. +// +// When the main thread asks to cancel a job it sets the cancel +// state and does not resume until the thread running the job +// signals that it is okay. +// +// Don't hold the frame lock while sleeping, as this can dead-lock +// the job thread and the main thread, and since main is sleeping +// they won't collide anyway. internal Sys_Cancel_Job_Sig(system_cancel_job){ Work_Queue *queue = win32vars.queues + group_id; @@ -372,7 +426,6 @@ Sys_Cancel_Job_Sig(system_cancel_job){ u32 job_index; u32 thread_id; Full_Job_Data *full_job; - Thread_Context *thread; job_index = job_id % QUEUE_WRAP; full_job = queue->jobs + job_index; @@ -382,19 +435,47 @@ Sys_Cancel_Job_Sig(system_cancel_job){ InterlockedCompareExchange(&full_job->running_thread, 0, THREAD_NOT_ASSIGNED); - if (thread_id != THREAD_NOT_ASSIGNED){ - system_acquire_lock(CANCEL_LOCK0 + thread_id - 1); - thread = group->threads + thread_id - 1; - TerminateThread(thread->handle, 0); - u32 creation_flag = 0; - thread->handle = CreateThread(0, 0, JobThreadProc, thread, creation_flag, (LPDWORD)&thread->windows_id); - system_release_lock(CANCEL_LOCK0 + thread_id - 1); - thread->running = 0; + if (thread_id != THREAD_NOT_ASSIGNED && thread_id != 0){ + i32 thread_index = thread_id - 1; + + i32 cancel_lock = group->cancel_lock0 + thread_index; + i32 cancel_cv = group->cancel_cv0 + thread_index; + Thread_Context *thread = group->threads + thread_index; + + + system_acquire_lock(cancel_lock); + + thread->cancel = 1; + + system_release_lock(FRAME_LOCK); + do{ + system_wait_cv(cancel_lock, cancel_cv); + }while (thread->cancel == 1); + system_acquire_lock(FRAME_LOCK); + + system_release_lock(cancel_lock); } } -internal void -system_grow_thread_memory(Thread_Memory *memory){ +internal +Sys_Check_Cancel_Sig(system_check_cancel){ + b32 result = 0; + + Thread_Group *group = win32vars.groups + thread->group_id; + i32 thread_index = thread->id - 1; + i32 cancel_lock = group->cancel_lock0 + thread_index; + + system_acquire_lock(cancel_lock); + if (thread->cancel){ + result = 1; + } + system_release_lock(cancel_lock); + + return(result); +} + +internal +Sys_Grow_Thread_Memory_Sig(system_grow_thread_memory){ void *old_data; i32 old_size, new_size; @@ -1178,6 +1259,7 @@ Win32LoadSystemCode(){ win32vars.system.post_job = system_post_job; win32vars.system.cancel_job = system_cancel_job; + win32vars.system.check_cancel = system_check_cancel; win32vars.system.grow_thread_memory = system_grow_thread_memory; win32vars.system.acquire_lock = system_acquire_lock; win32vars.system.release_lock = system_release_lock; @@ -1621,18 +1703,22 @@ WinMain(HINSTANCE hInstance, memset(background, 0, sizeof(background)); win32vars.groups[BACKGROUND_THREADS].threads = background; win32vars.groups[BACKGROUND_THREADS].count = ArrayCount(background); + win32vars.groups[BACKGROUND_THREADS].cancel_lock0 = CANCEL_LOCK0; + win32vars.groups[BACKGROUND_THREADS].cancel_cv0 = CANCEL_CV0; Thread_Memory thread_memory[ArrayCount(background)]; win32vars.thread_memory = thread_memory; win32vars.queues[BACKGROUND_THREADS].semaphore = Win32Handle(CreateSemaphore(0, 0, - win32vars.groups[BACKGROUND_THREADS].count, 0)); + win32vars.groups[BACKGROUND_THREADS].count, + 0)); u32 creation_flag = 0; for (i32 i = 0; i < win32vars.groups[BACKGROUND_THREADS].count; ++i){ Thread_Context *thread = win32vars.groups[BACKGROUND_THREADS].threads + i; thread->id = i + 1; + thread->group_id = BACKGROUND_THREADS; Thread_Memory *memory = win32vars.thread_memory + i; *memory = thread_memory_zero(); From 2198dd9ec9828dbff49343235b03d64c23a36a1c Mon Sep 17 00:00:00 2001 From: insofaras Date: Tue, 31 May 2016 20:39:33 +0100 Subject: [PATCH 22/34] linux thread updates + improve x11/epoll interaction --- linux_4ed.cpp | 165 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 122 insertions(+), 43 deletions(-) diff --git a/linux_4ed.cpp b/linux_4ed.cpp index f2ac65d3..63109491 100644 --- a/linux_4ed.cpp +++ b/linux_4ed.cpp @@ -86,11 +86,12 @@ struct Sys_Bubble : public Bubble{ #endif enum { - LINUX_4ED_EVENT_X11, - LINUX_4ED_EVENT_FILE, - LINUX_4ED_EVENT_STEP, - LINUX_4ED_EVENT_STEP_TIMER, - LINUX_4ED_EVENT_CLI, + LINUX_4ED_EVENT_X11 = (UINT64_C(1) << 32), + LINUX_4ED_EVENT_X11_INTERNAL = (UINT64_C(1) << 33), + LINUX_4ED_EVENT_FILE = (UINT64_C(1) << 34), + LINUX_4ED_EVENT_STEP = (UINT64_C(1) << 35), + LINUX_4ED_EVENT_STEP_TIMER = (UINT64_C(1) << 36), + LINUX_4ED_EVENT_CLI = (UINT64_C(1) << 37), }; struct Linux_Coroutine { @@ -104,15 +105,20 @@ struct Linux_Coroutine { struct Thread_Context{ u32 job_id; b32 running; + b32 cancel; Work_Queue *queue; u32 id; + u32 group_id; pthread_t handle; }; struct Thread_Group{ Thread_Context *threads; i32 count; + + i32 cancel_lock0; + i32 cancel_cv0; }; struct Linux_Vars{ @@ -162,8 +168,10 @@ struct Linux_Vars{ Thread_Memory *thread_memory; Thread_Group groups[THREAD_GROUP_COUNT]; - sem_t thread_semaphores[THREAD_GROUP_COUNT]; + Work_Queue queues[THREAD_GROUP_COUNT]; pthread_mutex_t locks[LOCK_COUNT]; + pthread_cond_t conds[8]; + sem_t thread_semaphore; Partition font_part; @@ -216,7 +224,6 @@ struct Linux_Vars{ globalvar Linux_Vars linuxvars; globalvar Application_Memory memory_vars; -globalvar Exchange exchange_vars; // // Linux forward declarations @@ -905,8 +912,14 @@ Sys_CLI_End_Update_Sig(system_cli_end_update){ internal void* ThreadProc(void* arg){ Thread_Context *thread = (Thread_Context*)arg; - Work_Queue *queue = thread->queue; - + Work_Queue *queue = linuxvars.queues + thread->group_id; + Thread_Group* group = linuxvars.groups + thread->group_id; + + i32 thread_index = thread->id - 1; + + i32 cancel_lock = group->cancel_lock0 + thread_index; + i32 cancel_cv = group->cancel_cv0 + thread_index; + for (;;){ u32 read_index = queue->read_position; u32 write_index = queue->write_position; @@ -944,11 +957,17 @@ ThreadProc(void* arg){ thread_memory->size = new_size; } } - full_job->job.callback(&linuxvars.system, thread, thread_memory, - &exchange_vars.thread, full_job->job.data); + full_job->job.callback(&linuxvars.system, thread, thread_memory, full_job->job.data); full_job->running_thread = 0; thread->running = 0; + system_acquire_lock(cancel_lock); + if(thread->cancel){ + thread->cancel = 0; + pthread_cond_signal(linuxvars.conds + cancel_cv); + } + system_release_lock(cancel_lock); + LinuxScheduleStep(); } } @@ -961,7 +980,7 @@ ThreadProc(void* arg){ internal Sys_Post_Job_Sig(system_post_job){ - Work_Queue *queue = exchange_vars.thread.queues + group_id; + Work_Queue *queue = linuxvars.queues + group_id; Assert((queue->write_position + 1) % QUEUE_WRAP != queue->read_position % QUEUE_WRAP); @@ -990,13 +1009,12 @@ Sys_Post_Job_Sig(system_post_job){ internal Sys_Cancel_Job_Sig(system_cancel_job){ - Work_Queue *queue = exchange_vars.thread.queues + group_id; + Work_Queue *queue = linuxvars.queues + group_id; Thread_Group *group = linuxvars.groups + group_id; u32 job_index; u32 thread_id; Full_Job_Data *full_job; - Thread_Context *thread; job_index = job_id % QUEUE_WRAP; full_job = queue->jobs + job_index; @@ -1006,19 +1024,46 @@ Sys_Cancel_Job_Sig(system_cancel_job){ __sync_val_compare_and_swap(&full_job->running_thread, THREAD_NOT_ASSIGNED, 0); - if (thread_id != THREAD_NOT_ASSIGNED){ - system_acquire_lock(CANCEL_LOCK0 + thread_id - 1); - thread = group->threads + thread_id - 1; - pthread_kill(thread->handle, SIGINT); //NOTE(inso) SIGKILL if you really want it to die. - pthread_create(&thread->handle, NULL, &ThreadProc, thread); - system_release_lock(CANCEL_LOCK0 + thread_id - 1); - thread->running = 0; + if (thread_id != THREAD_NOT_ASSIGNED && thread_id != 0){ + i32 thread_index = thread_id - 1; + + i32 cancel_lock = group->cancel_lock0 + thread_index; + i32 cancel_cv = group->cancel_cv0 + thread_index; + Thread_Context *thread = group->threads + thread_index; + + system_acquire_lock(cancel_lock); + thread->cancel = 1; + + system_release_lock(FRAME_LOCK); + do { + pthread_cond_wait(linuxvars.conds + cancel_cv, linuxvars.locks + cancel_lock); + } while(thread->cancel == 1); + system_acquire_lock(FRAME_LOCK); + + system_release_lock(cancel_lock); LinuxScheduleStep(); } } +internal +Sys_Check_Cancel_Sig(system_check_cancel){ + b32 result = 0; + + Thread_Group* group = linuxvars.groups + thread->group_id; + i32 thread_index = thread->id - 1; + i32 cancel_lock = group->cancel_lock0 + thread_index; + + system_acquire_lock(cancel_lock); + if (thread->cancel){ + result = 1; + } + system_release_lock(cancel_lock); + + return (result); +} + internal Sys_Grow_Thread_Memory_Sig(system_grow_thread_memory){ void *old_data; @@ -1060,7 +1105,7 @@ INTERNAL_Sys_Sentinel_Sig(internal_sentinel){ internal INTERNAL_Sys_Get_Thread_States_Sig(internal_get_thread_states){ - Work_Queue *queue = exchange_vars.thread.queues + id; + Work_Queue *queue = linuxvars.queues + id; u32 write = queue->write_position; u32 read = queue->read_position; if (write < read) write += JOB_ID_WRAP; @@ -1183,6 +1228,7 @@ LinuxLoadSystemCode(){ linuxvars.system.post_job = system_post_job; linuxvars.system.cancel_job = system_cancel_job; + linuxvars.system.check_cancel = system_check_cancel; linuxvars.system.grow_thread_memory = system_grow_thread_memory; linuxvars.system.acquire_lock = system_acquire_lock; linuxvars.system.release_lock = system_release_lock; @@ -1604,7 +1650,6 @@ LinuxInputInit(Display *dpy, Window XWindow) KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | - PropertyChangeMask | PointerMotionMask | FocusChangeMask | StructureNotifyMask | @@ -1833,12 +1878,22 @@ LinuxSetIcon(Display* d, Window w) ); } +internal void +LinuxX11ConnectionWatch(Display* dpy, XPointer cdata, int fd, Bool opening, XPointer* wdata){ + struct epoll_event e = {}; + e.events = EPOLLIN | EPOLLET; + e.data.u64 = LINUX_4ED_EVENT_X11_INTERNAL | fd; + + int op = opening ? EPOLL_CTL_ADD : EPOLL_CTL_DEL; + epoll_ctl(linuxvars.epoll, op, fd, &e); +} + // // X11 window init // -internal -b32 LinuxX11WindowInit(int argc, char** argv, int* WinWidth, int* WinHeight) +internal b32 +LinuxX11WindowInit(int argc, char** argv, int* WinWidth, int* WinHeight) { // NOTE(allen): Here begins the linux screen setup stuff. // Behold the true nature of this wonderful OS: @@ -1920,16 +1975,17 @@ b32 LinuxX11WindowInit(int argc, char** argv, int* WinWidth, int* WinHeight) XWMHints *wm_hints = XAllocWMHints(); XClassHint *cl_hints = XAllocClassHint(); - sz_hints->flags = PMinSize | PMaxSize | PBaseSize | PWinGravity; + sz_hints->flags = PMinSize | PMaxSize | PWinGravity; sz_hints->min_width = 50; sz_hints->min_height = 50; sz_hints->max_width = sz_hints->max_height = (1UL << 16UL); +/* NOTE(inso): fluxbox thinks this is minimum, so don't set it sz_hints->base_width = BASE_W; sz_hints->base_height = BASE_H; - +*/ sz_hints->win_gravity = NorthWestGravity; if (linuxvars.settings.set_window_pos){ @@ -2473,24 +2529,25 @@ main(int argc, char **argv) Thread_Context background[4] = {}; linuxvars.groups[BACKGROUND_THREADS].threads = background; linuxvars.groups[BACKGROUND_THREADS].count = ArrayCount(background); + linuxvars.groups[BACKGROUND_THREADS].cancel_lock0 = CANCEL_LOCK0; + linuxvars.groups[BACKGROUND_THREADS].cancel_cv0 = 0; Thread_Memory thread_memory[ArrayCount(background)]; linuxvars.thread_memory = thread_memory; - sem_init(&linuxvars.thread_semaphores[BACKGROUND_THREADS], 0, 0); - - exchange_vars.thread.queues[BACKGROUND_THREADS].semaphore = - LinuxSemToHandle(&linuxvars.thread_semaphores[BACKGROUND_THREADS]); + sem_init(&linuxvars.thread_semaphore, 0, 0); + linuxvars.queues[BACKGROUND_THREADS].semaphore = LinuxSemToHandle(&linuxvars.thread_semaphore); for(i32 i = 0; i < linuxvars.groups[BACKGROUND_THREADS].count; ++i){ Thread_Context *thread = linuxvars.groups[BACKGROUND_THREADS].threads + i; thread->id = i + 1; + thread->group_id = BACKGROUND_THREADS; Thread_Memory *memory = linuxvars.thread_memory + i; *memory = thread_memory_zero(); memory->id = thread->id; - thread->queue = &exchange_vars.thread.queues[BACKGROUND_THREADS]; + thread->queue = &linuxvars.queues[BACKGROUND_THREADS]; pthread_create(&thread->handle, NULL, &ThreadProc, thread); } @@ -2498,10 +2555,14 @@ main(int argc, char **argv) pthread_mutex_init(linuxvars.locks + i, NULL); } + for(i32 i = 0; i < ArrayCount(linuxvars.conds); ++i){ + pthread_cond_init(linuxvars.conds + i, NULL); + } + // // X11 init // - + linuxvars.XDisplay = XOpenDisplay(0); if(!linuxvars.XDisplay){ fprintf(stderr, "Can't open display!\n"); @@ -2590,13 +2651,18 @@ main(int argc, char **argv) e.data.u64 = LINUX_4ED_EVENT_STEP_TIMER; epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, linuxvars.step_timer_fd, &e); } - + // // App init // - linuxvars.app.init(&linuxvars.system, &linuxvars.target, &memory_vars, &exchange_vars, - linuxvars.clipboard_contents, current_directory, + XAddConnectionWatch(linuxvars.XDisplay, &LinuxX11ConnectionWatch, NULL); + + linuxvars.app.init(&linuxvars.system, + &linuxvars.target, + &memory_vars, + linuxvars.clipboard_contents, + current_directory, linuxvars.custom_api); LinuxResizeTarget(WinWidth, WinHeight); @@ -2605,6 +2671,8 @@ main(int argc, char **argv) // Main loop // + system_acquire_lock(FRAME_LOCK); + LinuxScheduleStep(); linuxvars.keep_running = 1; @@ -2613,9 +2681,17 @@ main(int argc, char **argv) while(1){ + if(XEventsQueued(linuxvars.XDisplay, QueuedAlready)){ + LinuxHandleX11Events(); + } + + system_release_lock(FRAME_LOCK); + struct epoll_event events[16]; int num_events = epoll_wait(linuxvars.epoll, events, ArrayCount(events), -1); + system_acquire_lock(FRAME_LOCK); + if(num_events == -1){ if(errno != EINTR){ perror("epoll_wait"); @@ -2623,16 +2699,22 @@ main(int argc, char **argv) continue; } - system_acquire_lock(FRAME_LOCK); - b32 do_step = 0; for(int i = 0; i < num_events; ++i){ - switch(events[i].data.u64){ + + int fd = events[i].data.u64 & UINT32_MAX; + u64 type = events[i].data.u64 & ~fd; + + switch(type){ case LINUX_4ED_EVENT_X11: { LinuxHandleX11Events(); } break; + case LINUX_4ED_EVENT_X11_INTERNAL: { + XProcessInternalConnection(linuxvars.XDisplay, fd); + } break; + case LINUX_4ED_EVENT_FILE: { LinuxHandleFileEvents(); } break; @@ -2694,7 +2776,6 @@ main(int argc, char **argv) &linuxvars.system, &linuxvars.target, &memory_vars, - &exchange_vars, &linuxvars.input, &result ); @@ -2711,7 +2792,7 @@ main(int argc, char **argv) LinuxRedrawTarget(); - if(result.mouse_cursor_type != linuxvars.cursor){ + if(result.mouse_cursor_type != linuxvars.cursor && !linuxvars.input.mouse.l){ Cursor c = xcursors[result.mouse_cursor_type]; XDefineCursor(linuxvars.XDisplay, linuxvars.XWindow, c); linuxvars.cursor = result.mouse_cursor_type; @@ -2725,8 +2806,6 @@ main(int argc, char **argv) linuxvars.input.mouse.release_r = 0; linuxvars.input.mouse.wheel = 0; } - - system_release_lock(FRAME_LOCK); } return 0; From 2f572ee72b860a2f26a35831a8fbe31757725f1f Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Tue, 31 May 2016 16:01:25 -0400 Subject: [PATCH 23/34] another small indent rule improvement --- 4ed.cpp | 67 +- 4ed_file_view.cpp | 11311 ++++++++++++++++++++++---------------------- 4ed_system.h | 2 +- 4ed_template.cpp | 2 +- TODO.txt | 13 +- win32_4ed.cpp | 54 +- 6 files changed, 5737 insertions(+), 5712 deletions(-) diff --git a/4ed.cpp b/4ed.cpp index b006f540..34a3cac1 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -155,9 +155,6 @@ do_feedback_message(System_Functions *system, Models *models, String value){ // Commands -// TODO(allen): MOVE THIS TO models -//globalvar Application_Links app_links; - #define USE_MODELS(n) Models *n = command->models #define USE_VARS(n) App_Vars *n = command->vars #define USE_PANEL(n) Panel *n = command->panel @@ -428,52 +425,52 @@ COMMAND_DECL(word_complete){ USE_VARS(vars); REQ_OPEN_VIEW(view); REQ_FILE(file, view); - + Partition *part = &models->mem.part; General_Memory *general = &models->mem.general; Working_Set *working_set = &models->working_set; Complete_State *complete_state = &vars->complete_state; Search_Range *ranges; Search_Match match; - + Temp_Memory temp; - + Buffer_Type *buffer; Buffer_Backify_Type loop; char *data; i32 end; i32 size_of_buffer; - + i32 cursor_pos, word_start, word_end; char c; - + char *spare; i32 size; - + i32 match_size; b32 do_init = 0; - + buffer = &file->state.buffer; size_of_buffer = buffer_size(buffer); - + if (view->mode.rewrite != 2){ do_init = 1; } view->next_mode.rewrite = 2; - + if (complete_state->initialized == 0){ do_init = 1; } - + if (do_init){ word_end = view->recent->cursor.pos; word_start = word_end; cursor_pos = word_end - 1; - + // TODO(allen): macros for these buffer loops and some method of breaking out of them. for (loop = buffer_backify_loop(buffer, cursor_pos, 0); - buffer_backify_good(&loop); - buffer_backify_next(&loop)){ + buffer_backify_good(&loop); + buffer_backify_next(&loop)){ end = loop.absolute_pos; data = loop.data - loop.absolute_pos; for (; cursor_pos >= end; --cursor_pos){ @@ -487,35 +484,35 @@ COMMAND_DECL(word_complete){ } } double_break:; - + size = word_end - word_start; - + if (size == 0){ complete_state->initialized = 0; return; } - + complete_state->initialized = 1; search_iter_init(general, &complete_state->iter, size); buffer_stringify(buffer, word_start, word_end, complete_state->iter.word.str); complete_state->iter.word.size = size; - + { File_Node *node, *used_nodes; Editing_File *file_ptr; i32 buffer_count, j; - + buffer_count = working_set->file_count; search_set_init(general, &complete_state->set, buffer_count + 1); ranges = complete_state->set.ranges; ranges[0].buffer = buffer; ranges[0].start = 0; ranges[0].size = word_start; - + ranges[1].buffer = buffer; ranges[1].start = word_end; ranges[1].size = size_of_buffer - word_end; - + used_nodes = &working_set->used_sentinel; j = 2; for (dll_items(node, used_nodes)){ @@ -529,11 +526,11 @@ COMMAND_DECL(word_complete){ } complete_state->set.count = j; } - + search_hits_init(general, &complete_state->hits, &complete_state->str, 100, Kbytes(4)); search_hit_add(general, &complete_state->hits, &complete_state->str, - complete_state->iter.word.str, complete_state->iter.word.size); - + complete_state->iter.word.str, complete_state->iter.word.size); + complete_state->word_start = word_start; complete_state->word_end = word_end; } @@ -542,20 +539,20 @@ COMMAND_DECL(word_complete){ word_end = complete_state->word_end; size = complete_state->iter.word.size; } - + if (size > 0){ for (;;){ match = search_next_match(part, &complete_state->set, &complete_state->iter); - + if (match.found_match){ temp = begin_temp_memory(part); match_size = match.end - match.start; spare = (char*)push_array(part, char, match_size); buffer_stringify(match.buffer, match.start, match.end, spare); - + if (search_hit_add(general, &complete_state->hits, &complete_state->str, spare, match_size)){ view_replace_range(system, models, view, word_start, word_end, spare, match_size, word_end); - + complete_state->word_end = word_start + match_size; complete_state->set.ranges[1].start = word_start + match_size; break; @@ -565,15 +562,15 @@ COMMAND_DECL(word_complete){ else{ complete_state->iter.pos = 0; complete_state->iter.i = 0; - + search_hits_init(general, &complete_state->hits, &complete_state->str, 100, Kbytes(4)); search_hit_add(general, &complete_state->hits, &complete_state->str, - complete_state->iter.word.str, complete_state->iter.word.size); - + complete_state->iter.word.str, complete_state->iter.word.size); + match_size = complete_state->iter.word.size; view_replace_range(system, models, view, word_start, word_end, - complete_state->iter.word.str, match_size, word_end); - + complete_state->iter.word.str, match_size, word_end); + complete_state->word_end = word_start + match_size; complete_state->set.ranges[1].start = word_start + match_size; break; diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index 7fcf241c..33fed014 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -1,5648 +1,5663 @@ -/* -* Mr. 4th Dimention - Allen Webster -* -* 19.08.2015 -* -* File editing view for 4coder -* -*/ - -// TOP - -internal i32 -get_or_add_map_index(Models *models, i32 mapid){ - i32 result; - i32 user_map_count = models->user_map_count; - i32 *map_id_table = models->map_id_table; - for (result = 0; result < user_map_count; ++result){ - if (map_id_table[result] == mapid) break; - if (map_id_table[result] == -1){ - map_id_table[result] = mapid; - break; - } - } - return result; -} - -internal i32 -get_map_index(Models *models, i32 mapid){ - i32 result; - i32 user_map_count = models->user_map_count; - i32 *map_id_table = models->map_id_table; - for (result = 0; result < user_map_count; ++result){ - if (map_id_table[result] == mapid) break; - if (map_id_table[result] == 0){ - result = user_map_count; - break; - } - } - return result; -} - -internal Command_Map* -get_map_base(Models *models, i32 mapid, b32 add){ - Command_Map *map = 0; - if (mapid < mapid_global){ - if (add){ - mapid = get_or_add_map_index(models, mapid); - } - else{ - mapid = get_map_index(models, mapid); - } - if (mapid < models->user_map_count){ - map = models->user_maps + mapid; - } - } - else if (mapid == mapid_global) map = &models->map_top; - else if (mapid == mapid_file) map = &models->map_file; - return(map); -} - -internal Command_Map* -get_or_add_map(Models *models, i32 mapid){ - Command_Map *map = get_map_base(models, mapid, 1); - return(map); -} - -internal Command_Map* -get_map(Models *models, i32 mapid){ - Command_Map *map = get_map_base(models, mapid, 0); - return(map); -} - -internal void -map_set_count(Models *models, i32 mapid, i32 count){ - Command_Map *map = get_or_add_map(models, mapid); - Assert(map->commands == 0); - map->count = count; - if (map->max < count){ - map->max = count; - } -} - -internal i32 -map_get_count(Models *models, i32 mapid){ - Command_Map *map = get_or_add_map(models, mapid); - i32 count = map->count; - Assert(map->commands == 0); - return(count); -} - -internal i32 -map_get_max_count(Models *models, i32 mapid){ - Command_Map *map = get_or_add_map(models, mapid); - i32 count = map->max; - return(count); -} - -enum Interactive_Action{ - IAct_Open, - IAct_Save_As, - IAct_New, - IAct_Switch, - IAct_Kill, - IAct_Sure_To_Kill, - IAct_Sure_To_Close -}; - -enum Interactive_Interaction{ - IInt_Sys_File_List, - IInt_Live_File_List, - IInt_Sure_To_Kill, - IInt_Sure_To_Close -}; - -struct View_Mode{ - i32 rewrite; -}; -inline View_Mode -view_mode_zero(){ - View_Mode mode={0}; - return(mode); -} - -enum View_Widget_Type{ - FWIDG_NONE, - FWIDG_TIMELINES, - // never below this - FWIDG_TYPE_COUNT -}; - -struct View_Widget{ - View_Widget_Type type; - i32 height_; - struct{ - b32 undo_line; - b32 history_line; - } timeline; -}; - -enum View_UI{ - VUI_None, - VUI_Theme, - VUI_Interactive, - VUI_Menu, - VUI_Config, -}; - -enum Color_View_Mode{ - CV_Mode_Library, - CV_Mode_Font, - CV_Mode_Adjusting -}; - -struct File_Viewing_Data{ - Editing_File *file; - - Full_Cursor temp_highlight; - i32 temp_highlight_end_pos; - b32 show_temp_highlight; - - b32 unwrapped_lines; - b32 show_whitespace; - b32 file_locked; - - i32 line_count, line_max; - f32 *line_wrap_y; -}; -inline File_Viewing_Data -file_viewing_data_zero(){ - File_Viewing_Data data={0}; - return(data); -} - -struct Recent_File_Data{ - u64 unique_buffer_id; - GUI_Scroll_Vars scroll; - - Full_Cursor cursor; - i32 mark; - f32 preferred_x; - i32 scroll_i; -}; -inline Recent_File_Data -recent_file_data_zero(){ - Recent_File_Data data = {0}; - return(data); -} - -struct Scroll_Context{ - Editing_File *file; - GUI_id scroll; - View_UI mode; -}; -inline b32 -context_eq(Scroll_Context a, Scroll_Context b){ - b32 result = 0; - if (gui_id_eq(a.scroll, b.scroll)){ - if (a.file == b.file){ - if (a.mode == b.mode){ - result = 1; - } - } - } - return(result); -} - -struct View_Persistent{ - i32 id; - - View_Routine_Function *view_routine; - Coroutine *coroutine; - Event_Message message_passing_slot; - - // TODO(allen): eliminate this models pointer: explicitly parameterize. - Models *models; -}; - -struct View{ - View_Persistent persistent; - - View *next, *prev; - Panel *panel; - b32 in_use; - Command_Map *map; - - File_Viewing_Data file_data; - i32 prev_cursor_pos; - Scroll_Context prev_context; - - i32_Rect file_region_prev; - i32_Rect file_region; - - i32_Rect scroll_region; - Recent_File_Data recent[16]; - - GUI_Scroll_Vars *current_scroll; - - View_UI showing_ui; - GUI_Target gui_target; - void *gui_mem; - GUI_Scroll_Vars gui_scroll; - i32 list_i; - - b32 hide_scrollbar; - - // interactive stuff - Interactive_Interaction interaction; - Interactive_Action action; - - char dest_[256]; - String dest; - - // theme stuff - View *hot_file_view; - u32 *palette; - i32 palette_size; - Color_View_Mode color_mode; - Super_Color color; - b32 p4c_only; - Style_Library inspecting_styles; - b8 import_export_check[64]; - i32 import_file_id; - i32 current_color_editing; - i32 color_cursor; - - i32 font_advance; - i32 font_height; - - View_Mode mode, next_mode; - View_Widget widget; - Query_Set query_set; - i32 scrub_max; - - b32 reinit_scrolling; -}; -inline void* -get_view_body(View *view){ - char *result = (char*)view; - result += sizeof(View_Persistent); - return(result); -} -inline i32 -get_view_size(){ - return(sizeof(View) - sizeof(View_Persistent)); -} - -struct View_And_ID{ - View *view; - i32 id; -}; - -#define LockLevel_Open 0 -#define LockLevel_NoWrite 1 -#define LockLevel_NoUpdate 2 - -inline i32 -view_lock_level(View *view){ - i32 result = LockLevel_Open; - File_Viewing_Data *data = &view->file_data; - if (view->showing_ui != VUI_None) result = LockLevel_NoUpdate; - else if (data->file_locked || (data->file && data->file->settings.read_only)) result = LockLevel_NoWrite; - return(result); -} - -inline f32 -view_file_width(View *view){ - i32_Rect file_rect = view->file_region; - f32 result = (f32)(file_rect.x1 - file_rect.x0); - return (result); -} - -inline f32 -view_file_height(View *view){ - i32_Rect file_rect = view->file_region; - f32 result = (f32)(file_rect.y1 - file_rect.y0); - return (result); -} - -struct View_Iter{ - View *view; - - Editing_File *file; - View *skip; - Panel *used_panels; - Panel *panel; -}; - -internal View_Iter -file_view_iter_next(View_Iter iter){ - View *view; - - for (iter.panel = iter.panel->next; iter.panel != iter.used_panels; iter.panel = iter.panel->next){ - view = iter.panel->view; - if (view != iter.skip && (view->file_data.file == iter.file || iter.file == 0)){ - iter.view = view; - break; - } - } - - return(iter); -} - -internal View_Iter -file_view_iter_init(Editing_Layout *layout, Editing_File *file, View *skip){ - View_Iter result; - result.used_panels = &layout->used_sentinel; - result.panel = result.used_panels; - result.file = file; - result.skip = skip; - - result = file_view_iter_next(result); - - return(result); -} - -internal b32 -file_view_iter_good(View_Iter iter){ - b32 result = (iter.panel != iter.used_panels); - return(result); -} - -inline b32 -starts_new_line(u8 character){ - return (character == '\n'); -} - -inline void -file_init_strings(Editing_File *file){ - file->name.source_path = make_fixed_width_string(file->name.source_path_); - file->name.live_name = make_fixed_width_string(file->name.live_name_); - file->name.extension = make_fixed_width_string(file->name.extension_); -} - -inline void -file_set_name(Working_Set *working_set, Editing_File *file, char *filename){ - String f, ext; - - Assert(file->name.live_name.str != 0); - - f = make_string_slowly(filename); - copy_checked(&file->name.source_path, f); - - file->name.live_name.size = 0; - get_front_of_directory(&file->name.live_name, f); - - if (file->name.source_path.size == file->name.live_name.size){ - file->name.extension.size = 0; - } - else{ - ext = file_extension(f); - copy(&file->name.extension, ext); - } - - { - File_Node *node, *used_nodes; - Editing_File *file_ptr; - i32 file_x, original_len; - b32 hit_conflict; - - used_nodes = &working_set->used_sentinel; - original_len = file->name.live_name.size; - hit_conflict = 1; - file_x = 0; - while (hit_conflict){ - hit_conflict = 0; - for (dll_items(node, used_nodes)){ - file_ptr = (Editing_File*)node; - if (file_ptr != file && file_is_ready(file_ptr)){ - if (match(file->name.live_name, file_ptr->name.live_name)){ - ++file_x; - hit_conflict = 1; - break; - } - } - } - - if (hit_conflict){ - file->name.live_name.size = original_len; - append(&file->name.live_name, " <"); - append_int_to_str(file_x, &file->name.live_name); - append(&file->name.live_name, ">"); - } - } - } -} - -inline void -file_synchronize_times(System_Functions *system, Editing_File *file, char *filename){ - u64 stamp = system->file_time_stamp(filename); - if (stamp > 0){ - file->state.last_4ed_write_time = stamp; - file->state.last_4ed_edit_time = stamp; - file->state.last_sys_write_time = stamp; - } - file->state.sync = buffer_get_sync(file); -} - -internal b32 -file_save(System_Functions *system, Mem_Options *mem, Editing_File *file, char *filename){ - b32 result = 0; - - i32 max, size; - b32 dos_write_mode = file->settings.dos_write_mode; - char *data; - Buffer_Type *buffer = &file->state.buffer; - - if (dos_write_mode){ - max = buffer_size(buffer) + buffer->line_count + 1; - } - else{ - max = buffer_size(buffer); - } - - Temp_Memory temp = begin_temp_memory(&mem->part); - char empty = 0; - if (max == 0){ - data = ∅ - } - else{ - data = (char*)push_array(&mem->part, char, max); - } - Assert(data); - - if (dos_write_mode){ - size = buffer_convert_out(buffer, data, max); - } - else{ - size = max; - buffer_stringify(buffer, 0, size, data); - } - - result = system->file_save(filename, data, size); - - file_synchronize_times(system, file, filename); - - end_temp_memory(temp); - - return(result); -} - -inline b32 -file_save_and_set_names(System_Functions *system, Mem_Options *mem, - Working_Set *working_set, Editing_File *file, - char *filename){ - b32 result = 0; - result = file_save(system, mem, file, filename); - if (result){ - file_set_name(working_set, file, filename); - } - return result; -} - -enum File_Bubble_Type{ - BUBBLE_BUFFER = 1, - BUBBLE_STARTS, - BUBBLE_WIDTHS, - BUBBLE_WRAPS, - BUBBLE_TOKENS, - BUBBLE_UNDO_STRING, - BUBBLE_UNDO, - BUBBLE_UNDO_CHILDREN, - // - FILE_BUBBLE_TYPE_END, -}; - -#define GROW_FAILED 0 -#define GROW_NOT_NEEDED 1 -#define GROW_SUCCESS 2 - -internal i32 -file_grow_starts_widths_as_needed(General_Memory *general, Buffer_Type *buffer, i32 additional_lines){ - b32 result = GROW_NOT_NEEDED; - i32 max = buffer->line_max; - i32 count = buffer->line_count; - i32 target_lines = count + additional_lines; - Assert(max == buffer->widths_max); - - if (target_lines > max || max == 0){ - max = LargeRoundUp(target_lines + max, Kbytes(1)); - - f32 *new_widths = (f32*)general_memory_reallocate( - general, buffer->line_widths, - sizeof(f32)*count, sizeof(f32)*max, BUBBLE_WIDTHS); - - i32 *new_lines = (i32*)general_memory_reallocate( - general, buffer->line_starts, - sizeof(i32)*count, sizeof(i32)*max, BUBBLE_STARTS); - - if (new_lines){ - buffer->line_starts = new_lines; - buffer->line_max = max; - } - if (new_widths){ - buffer->line_widths = new_widths; - buffer->widths_max = max; - } - if (new_lines && new_widths){ - result = GROW_SUCCESS; - } - else{ - result = GROW_FAILED; - } - } - - return(result); -} - -internal void -file_measure_starts_widths(System_Functions *system, General_Memory *general, - Buffer_Type *buffer, float *advance_data){ - if (!buffer->line_starts){ - i32 max = buffer->line_max = Kbytes(1); - buffer->line_starts = (i32*)general_memory_allocate(general, max*sizeof(i32), BUBBLE_STARTS); - TentativeAssert(buffer->line_starts); - // TODO(allen): when unable to allocate? - } - if (!buffer->line_widths){ - i32 max = buffer->widths_max = Kbytes(1); - buffer->line_widths = (f32*)general_memory_allocate(general, max*sizeof(f32), BUBBLE_WIDTHS); - TentativeAssert(buffer->line_starts); - // TODO(allen): when unable to allocate? - } - - Buffer_Measure_Starts state = {}; - while (buffer_measure_starts_widths(&state, buffer, advance_data)){ - i32 count = state.count; - i32 max = buffer->line_max; - max = ((max + 1) << 1); - - { - i32 *new_lines = (i32*)general_memory_reallocate( - general, buffer->line_starts, sizeof(i32)*count, sizeof(i32)*max, BUBBLE_STARTS); - - // TODO(allen): when unable to grow? - TentativeAssert(new_lines); - buffer->line_starts = new_lines; - buffer->line_max = max; - } - - { - f32 *new_lines = (f32*) - general_memory_reallocate(general, buffer->line_widths, - sizeof(f32)*count, sizeof(f32)*max, BUBBLE_WIDTHS); - - // TODO(allen): when unable to grow? - TentativeAssert(new_lines); - buffer->line_widths = new_lines; - buffer->widths_max = max; - } - - } - buffer->line_count = state.count; - buffer->widths_count = state.count; -} - -struct Opaque_Font_Advance{ - void *data; - int stride; -}; - -inline Opaque_Font_Advance -get_opaque_font_advance(Render_Font *font){ - Opaque_Font_Advance result; - result.data = (char*)font->chardata + OffsetOfPtr(font->chardata, xadvance); - result.stride = sizeof(*font->chardata); - return result; -} - -inline i32 -view_wrapped_line_span(f32 line_width, f32 max_width){ - i32 line_count = CEIL32(line_width / max_width); - if (line_count == 0) line_count = 1; - return line_count; -} - -internal i32 -view_compute_lowest_line(View *view){ - i32 lowest_line = 0; - i32 last_line = view->file_data.line_count - 1; - if (last_line > 0){ - if (view->file_data.unwrapped_lines){ - lowest_line = last_line; - } - else{ - f32 wrap_y = view->file_data.line_wrap_y[last_line]; - lowest_line = FLOOR32(wrap_y / view->font_height); - f32 max_width = view_file_width(view); - - Editing_File *file = view->file_data.file; - Assert(!file->is_dummy); - f32 width = file->state.buffer.line_widths[last_line]; - i32 line_span = view_wrapped_line_span(width, max_width); - lowest_line += line_span - 1; - } - } - return lowest_line; -} - -internal void -view_measure_wraps(General_Memory *general, View *view){ - Buffer_Type *buffer; - - buffer = &view->file_data.file->state.buffer; - i32 line_count = buffer->line_count; - - if (view->file_data.line_max < line_count){ - i32 max = view->file_data.line_max = LargeRoundUp(line_count, Kbytes(1)); - if (view->file_data.line_wrap_y){ - view->file_data.line_wrap_y = (f32*) - general_memory_reallocate_nocopy(general, view->file_data.line_wrap_y, sizeof(f32)*max, BUBBLE_WRAPS); - } - else{ - view->file_data.line_wrap_y = (f32*) - general_memory_allocate(general, sizeof(f32)*max, BUBBLE_WRAPS); - } - } - - f32 line_height = (f32)view->font_height; - f32 max_width = view_file_width(view); - buffer_measure_wrap_y(buffer, view->file_data.line_wrap_y, line_height, max_width); - - view->file_data.line_count = line_count; -} - -internal void -file_create_from_string(System_Functions *system, Models *models, - Editing_File *file, char *filename, String val, b8 read_only = 0){ - - Font_Set *font_set = models->font_set; - Working_Set *working_set = &models->working_set; - General_Memory *general = &models->mem.general; - Partition *part = &models->mem.part; - Buffer_Init_Type init; - i32 page_size, scratch_size, init_success; - - file->state = editing_file_state_zero(); - - init = buffer_begin_init(&file->state.buffer, val.str, val.size); - for (; buffer_init_need_more(&init); ){ - page_size = buffer_init_page_size(&init); - page_size = LargeRoundUp(page_size, Kbytes(4)); - if (page_size < Kbytes(4)) page_size = Kbytes(4); - void *data = general_memory_allocate(general, page_size, BUBBLE_BUFFER); - buffer_init_provide_page(&init, data, page_size); - } - - scratch_size = partition_remaining(part); - Assert(scratch_size > 0); - init_success = buffer_end_init(&init, part->base + part->pos, scratch_size); - AllowLocal(init_success); - Assert(init_success); - - if (buffer_size(&file->state.buffer) < val.size){ - file->settings.dos_write_mode = 1; - } - - file_init_strings(file); - file_set_name(working_set, file, (char*)filename); - - file->state.font_id = models->global_font.font_id; - - file_synchronize_times(system, file, filename); - - Render_Font *font = get_font_info(font_set, file->state.font_id)->font; - float *advance_data = 0; - if (font) advance_data = font->advance_data; - file_measure_starts_widths(system, general, &file->state.buffer, advance_data); - - file->settings.read_only = read_only; - if (!read_only){ - // TODO(allen): Redo undo system (if you don't mind the pun) - i32 request_size = Kbytes(64); - file->state.undo.undo.max = request_size; - file->state.undo.undo.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); - file->state.undo.undo.edit_max = request_size / sizeof(Edit_Step); - file->state.undo.undo.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO); - - file->state.undo.redo.max = request_size; - file->state.undo.redo.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); - file->state.undo.redo.edit_max = request_size / sizeof(Edit_Step); - file->state.undo.redo.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO); - - file->state.undo.history.max = request_size; - file->state.undo.history.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); - file->state.undo.history.edit_max = request_size / sizeof(Edit_Step); - file->state.undo.history.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO); - - file->state.undo.children.max = request_size; - file->state.undo.children.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); - file->state.undo.children.edit_max = request_size / sizeof(Buffer_Edit); - file->state.undo.children.edits = (Buffer_Edit*)general_memory_allocate(general, request_size, BUBBLE_UNDO); - - file->state.undo.history_block_count = 1; - file->state.undo.history_head_block = 0; - file->state.undo.current_block_normal = 1; - } - - Hook_Function *open_hook = models->hooks[hook_open_file]; - models->buffer_param_indices[models->buffer_param_count++] = file->id.id; - open_hook(&models->app_links); - models->buffer_param_count = 0; - file->settings.is_initialized = 1; -} - -internal b32 -file_create_empty(System_Functions *system, - Models *models, Editing_File *file, char *filename){ - file_create_from_string(system, models, file, filename, string_zero()); - return (1); -} - -internal b32 -file_create_read_only(System_Functions *system, - Models *models, Editing_File *file, char *filename){ - file_create_from_string(system, models, file, filename, string_zero(), 1); - return (1); -} - -internal void -file_close(System_Functions *system, General_Memory *general, Editing_File *file){ - if (file->state.still_lexing){ - system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); - if (file->state.swap_stack.tokens){ - general_memory_free(general, file->state.swap_stack.tokens); - file->state.swap_stack.tokens = 0; - } - } - if (file->state.token_stack.tokens){ - general_memory_free(general, file->state.token_stack.tokens); - } - - Buffer_Type *buffer = &file->state.buffer; - if (buffer->data){ - general_memory_free(general, buffer->data); - general_memory_free(general, buffer->line_starts); - general_memory_free(general, buffer->line_widths); - } - - if (file->state.undo.undo.edits){ - general_memory_free(general, file->state.undo.undo.strings); - general_memory_free(general, file->state.undo.undo.edits); - - general_memory_free(general, file->state.undo.redo.strings); - general_memory_free(general, file->state.undo.redo.edits); - - general_memory_free(general, file->state.undo.history.strings); - general_memory_free(general, file->state.undo.history.edits); - - general_memory_free(general, file->state.undo.children.strings); - general_memory_free(general, file->state.undo.children.edits); - } -} - -struct Shift_Information{ - i32 start, end, amount; -}; - -internal -Job_Callback_Sig(job_full_lex){ - Editing_File *file = (Editing_File*)data[0]; - General_Memory *general = (General_Memory*)data[1]; - - Cpp_File cpp_file; - cpp_file.data = file->state.buffer.data; - cpp_file.size = file->state.buffer.size; - - Cpp_Token_Stack tokens; - tokens.tokens = (Cpp_Token*)memory->data; - tokens.max_count = memory->size / sizeof(Cpp_Token); - tokens.count = 0; - - Cpp_Lex_Data status = {}; - - do{ - for (i32 r = 2048; r > 0 && status.pos < cpp_file.size; --r){ - Cpp_Lex_Data prev_lex = status; - Cpp_Read_Result step_result = cpp_lex_step(cpp_file, &status); - - if (step_result.has_result){ - if (!cpp_push_token_nonalloc(&tokens, step_result.token)){ - status = prev_lex; - system->grow_thread_memory(memory); - tokens.tokens = (Cpp_Token*)memory->data; - tokens.max_count = memory->size / sizeof(Cpp_Token); - } - } - } - - if (status.pos >= cpp_file.size){ - status.complete = 1; - } - else{ - if (system->check_cancel(thread)){ - return; - } - } - } while(!status.complete); - - i32 new_max = LargeRoundUp(tokens.count+1, Kbytes(1)); - - system->acquire_lock(FRAME_LOCK); - { - Assert(file->state.swap_stack.tokens == 0); - file->state.swap_stack.tokens = (Cpp_Token*) - general_memory_allocate(general, new_max*sizeof(Cpp_Token), BUBBLE_TOKENS); - } - system->release_lock(FRAME_LOCK); - - u8 *dest = (u8*)file->state.swap_stack.tokens; - u8 *src = (u8*)tokens.tokens; - - memcpy(dest, src, tokens.count*sizeof(Cpp_Token)); - - system->acquire_lock(FRAME_LOCK); - { - Cpp_Token_Stack *file_stack = &file->state.token_stack; - file_stack->count = tokens.count; - file_stack->max_count = new_max; - if (file_stack->tokens){ - general_memory_free(general, file_stack->tokens); - } - file_stack->tokens = file->state.swap_stack.tokens; - file->state.swap_stack.tokens = 0; - } - system->release_lock(FRAME_LOCK); - - // NOTE(allen): These are outside the locked section because I don't - // think getting these out of order will cause critical bugs, and I - // want to minimize what's done in locked sections. - file->state.tokens_complete = 1; - file->state.still_lexing = 0; -} - - -internal void -file_kill_tokens(System_Functions *system, - General_Memory *general, Editing_File *file){ - file->settings.tokens_exist = 0; - if (file->state.still_lexing){ - system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); - if (file->state.swap_stack.tokens){ - general_memory_free(general, file->state.swap_stack.tokens); - file->state.swap_stack.tokens = 0; - } - } - if (file->state.token_stack.tokens){ - general_memory_free(general, file->state.token_stack.tokens); - } - file->state.tokens_complete = 0; - file->state.token_stack = cpp_token_stack_zero(); -} - -#if BUFFER_EXPERIMENT_SCALPEL <= 0 -internal void -file_first_lex_parallel(System_Functions *system, - General_Memory *general, Editing_File *file){ - file->settings.tokens_exist = 1; - - if (file->is_loading == 0 && file->state.still_lexing == 0){ - Assert(file->state.token_stack.tokens == 0); - - file->state.tokens_complete = 0; - file->state.still_lexing = 1; - - Job_Data job; - job.callback = job_full_lex; - job.data[0] = file; - job.data[1] = general; - job.memory_request = Kbytes(64); - file->state.lex_job = system->post_job(BACKGROUND_THREADS, job); - } -} -#endif - -internal void -file_relex_parallel(System_Functions *system, - Mem_Options *mem, Editing_File *file, - i32 start_i, i32 end_i, i32 amount){ - General_Memory *general = &mem->general; - Partition *part = &mem->part; - if (file->state.token_stack.tokens == 0){ - file_first_lex_parallel(system, general, file); - return; - } - - b32 inline_lex = !file->state.still_lexing; - if (inline_lex){ - Cpp_File cpp_file; - cpp_file.data = file->state.buffer.data; - cpp_file.size = file->state.buffer.size; - - Cpp_Token_Stack *stack = &file->state.token_stack; - - Cpp_Relex_State state = - cpp_relex_nonalloc_start(cpp_file, stack, - start_i, end_i, amount, 100); - - Temp_Memory temp = begin_temp_memory(part); - i32 relex_end; - Cpp_Token_Stack relex_space; - relex_space.count = 0; - relex_space.max_count = state.space_request; - relex_space.tokens = push_array(part, Cpp_Token, relex_space.max_count); - if (cpp_relex_nonalloc_main(&state, &relex_space, &relex_end)){ - inline_lex = 0; - } - else{ - i32 delete_amount = relex_end - state.start_token_i; - i32 shift_amount = relex_space.count - delete_amount; - - if (shift_amount != 0){ - int new_count = stack->count + shift_amount; - if (new_count > stack->max_count){ - int new_max = LargeRoundUp(new_count, Kbytes(1)); - stack->tokens = (Cpp_Token*) - general_memory_reallocate(general, stack->tokens, - stack->count*sizeof(Cpp_Token), - new_max*sizeof(Cpp_Token), BUBBLE_TOKENS); - stack->max_count = new_max; - } - - int shift_size = stack->count - relex_end; - if (shift_size > 0){ - Cpp_Token *old_base = stack->tokens + relex_end; - memmove(old_base + shift_amount, old_base, - sizeof(Cpp_Token)*shift_size); - } - - stack->count += shift_amount; - } - - memcpy(state.stack->tokens + state.start_token_i, relex_space.tokens, - sizeof(Cpp_Token)*relex_space.count); - } - - end_temp_memory(temp); - } - - if (!inline_lex){ - Cpp_Token_Stack *stack = &file->state.token_stack; - Cpp_Get_Token_Result get_token_result = cpp_get_token(stack, end_i); - i32 end_token_i = get_token_result.token_index; - - if (end_token_i < 0) end_token_i = 0; - else if (end_i > stack->tokens[end_token_i].start) ++end_token_i; - - cpp_shift_token_starts(stack, end_token_i, amount); - --end_token_i; - if (end_token_i >= 0){ - Cpp_Token *token = stack->tokens + end_token_i; - if (token->start < end_i && token->start + token->size > end_i){ - token->size += amount; - } - } - - file->state.still_lexing = 1; - - Job_Data job; - job.callback = job_full_lex; - job.data[0] = file; - job.data[1] = general; - job.memory_request = Kbytes(64); - file->state.lex_job = system->post_job(BACKGROUND_THREADS, job); - } -} - -internal void -undo_stack_grow_string(General_Memory *general, 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 = (u8*) - general_memory_reallocate(general, old_str, old_max, new_max); - stack->strings = new_str; - stack->max = new_max; -} - -internal void -undo_stack_grow_edits(General_Memory *general, 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 = (Edit_Step*) - general_memory_reallocate(general, old_eds, old_max*sizeof(Edit_Step), new_max*sizeof(Edit_Step)); - stack->edits = new_eds; - stack->edit_max = new_max; -} - -internal void -child_stack_grow_string(General_Memory *general, 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 = (u8*) - general_memory_reallocate(general, old_str, old_max, new_max); - stack->strings = new_str; - stack->max = new_max; -} - -internal void -child_stack_grow_edits(General_Memory *general, 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 = (Buffer_Edit*) - general_memory_reallocate(general, old_eds, old_max*sizeof(Buffer_Edit), new_max*sizeof(Buffer_Edit)); - stack->edits = new_eds; - stack->edit_max = new_max; -} - -internal i32 -undo_children_push(General_Memory *general, 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(general, children, edit_count); - - if (children->size + string_size > children->max) - child_stack_grow_string(general, 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; -} - -struct Edit_Spec{ - u8 *str; - Edit_Step step; -}; - -internal Edit_Step* -file_post_undo(General_Memory *general, 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(general, 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.pre_pos = step.pre_pos; - inv_step.post_pos = step.post_pos; - 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; - inv_step.pre_pos = prev.pre_pos; - } - } - } - - 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(general, 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(general, undo); - result = undo->edits + (undo->edit_count++); - *result = inv_step; - } - return result; -} - -inline 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(General_Memory *general, 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(general, 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.pre_pos = step.pre_pos; - inv_step.post_pos = step.post_pos; - inv_step.type = ED_REDO; - - if (redo->edit_count == redo->edit_max) - undo_stack_grow_edits(general, 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(general, redo); - } - redo->edits[redo->edit_count++] = inv_step; - } -} - -inline 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; -} - -inline 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(General_Memory *general, Editing_File *file, - Edit_Step step, b32 do_merge, b32 can_merge){ - Edit_Stack *history = &file->state.undo.history; - Edit_Step *result = 0; - - 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(general, 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.pre_pos = step.pre_pos; - inv_step.post_pos = step.post_pos; - inv_step.can_merge = (b8)can_merge; - inv_step.type = reverse_types[step.type]; - - bool32 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; - inv_step.pre_pos = prev.pre_pos; - } - } - } - - if (did_merge){ - result = history->edits + (history->edit_count-1); - } - else{ - if (history->edit_count == history->edit_max) - undo_stack_grow_edits(general, 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(general, history); - result = history->edits + (history->edit_count++); - *result = inv_step; - } - - return result; -} - -inline Full_Cursor -view_compute_cursor_from_pos(View *view, i32 pos){ - Editing_File *file = view->file_data.file; - Models *models = view->persistent.models; - Render_Font *font = get_font_info(models->font_set, models->global_font.font_id)->font; - - Full_Cursor result = {}; - if (font){ - f32 max_width = view_file_width(view); - result = buffer_cursor_from_pos(&file->state.buffer, pos, view->file_data.line_wrap_y, - max_width, (f32)view->font_height, font->advance_data); - } - return result; -} - -inline Full_Cursor -view_compute_cursor_from_unwrapped_xy(View *view, f32 seek_x, f32 seek_y, b32 round_down = 0){ - Editing_File *file = view->file_data.file; - Models *models = view->persistent.models; - Render_Font *font = get_font_info(models->font_set, models->global_font.font_id)->font; - - Full_Cursor result = {}; - if (font){ - f32 max_width = view_file_width(view); - result = buffer_cursor_from_unwrapped_xy(&file->state.buffer, seek_x, seek_y, - round_down, view->file_data.line_wrap_y, max_width, (f32)view->font_height, font->advance_data); - } - - return result; -} - -internal Full_Cursor -view_compute_cursor_from_wrapped_xy(View *view, f32 seek_x, f32 seek_y, b32 round_down = 0){ - Editing_File *file = view->file_data.file; - Models *models = view->persistent.models; - Render_Font *font = get_font_info(models->font_set, models->global_font.font_id)->font; - - Full_Cursor result = {}; - if (font){ - f32 max_width = view_file_width(view); - result = buffer_cursor_from_wrapped_xy(&file->state.buffer, seek_x, seek_y, - round_down, view->file_data.line_wrap_y, - max_width, (f32)view->font_height, font->advance_data); - } - - return (result); -} - -internal Full_Cursor -view_compute_cursor_from_line_pos(View *view, i32 line, i32 pos){ - Editing_File *file = view->file_data.file; - Models *models = view->persistent.models; - Render_Font *font = get_font_info(models->font_set, models->global_font.font_id)->font; - - Full_Cursor result = {}; - if (font){ - f32 max_width = view_file_width(view); - result = buffer_cursor_from_line_character(&file->state.buffer, line, pos, - view->file_data.line_wrap_y, max_width, (f32)view->font_height, font->advance_data); - } - - return (result); -} - -inline Full_Cursor -view_compute_cursor(View *view, Buffer_Seek seek){ - Full_Cursor result = {}; - - switch(seek.type){ - case buffer_seek_pos: - result = view_compute_cursor_from_pos(view, seek.pos); - break; - - case buffer_seek_wrapped_xy: - result = view_compute_cursor_from_wrapped_xy(view, seek.x, seek.y); - break; - - case buffer_seek_unwrapped_xy: - result = view_compute_cursor_from_unwrapped_xy(view, seek.x, seek.y); - break; - - case buffer_seek_line_char: - result = view_compute_cursor_from_line_pos(view, seek.line, seek.character); - break; - } - - return (result); -} - -inline Full_Cursor -view_compute_cursor_from_xy(View *view, f32 seek_x, f32 seek_y){ - Full_Cursor result; - if (view->file_data.unwrapped_lines) result = view_compute_cursor_from_unwrapped_xy(view, seek_x, seek_y); - else result = view_compute_cursor_from_wrapped_xy(view, seek_x, seek_y); - return result; -} - -inline void -view_set_temp_highlight(View *view, i32 pos, i32 end_pos){ - view->file_data.temp_highlight = view_compute_cursor_from_pos(view, pos); - view->file_data.temp_highlight_end_pos = end_pos; - view->file_data.show_temp_highlight = 1; -} - -inline i32 -view_get_cursor_pos(View *view){ - i32 result; - if (view->file_data.show_temp_highlight){ - result = view->file_data.temp_highlight.pos; - } - else{ - result = view->recent->cursor.pos; - } - return result; -} - -inline f32 -view_get_cursor_x(View *view){ - f32 result; - Full_Cursor *cursor; - if (view->file_data.show_temp_highlight){ - cursor = &view->file_data.temp_highlight; - } - else{ - cursor = &view->recent->cursor; - } - if (view->file_data.unwrapped_lines){ - result = cursor->unwrapped_x; - } - else{ - result = cursor->wrapped_x; - } - return result; -} - -inline f32 -view_get_cursor_y(View *view){ - Full_Cursor *cursor; - f32 result; - - if (view->file_data.show_temp_highlight) cursor = &view->file_data.temp_highlight; - else cursor = &view->recent->cursor; - - if (view->file_data.unwrapped_lines) result = cursor->unwrapped_y; - else result = cursor->wrapped_y; - - return result; -} - -#define CursorMaxY_(m,h) ((m) - (h)*3) -#define CursorMinY_(m,h) (-(m) + (h)*2) - -#define CursorMaxY(m,h) (CursorMaxY_(m,h) > 0)?(CursorMaxY_(m,h)):(0) -#define CursorMinY(m,h) (CursorMinY_(m,h) > 0)?(CursorMinY_(m,h)):(0) - -internal void -view_move_cursor_to_view(View *view){ - f32 min_target_y = 0; - i32 line_height = view->font_height; - f32 old_cursor_y = view_get_cursor_y(view); - f32 cursor_y = old_cursor_y; - f32 target_y = view->recent->scroll.target_y; - f32 cursor_max_y = CursorMaxY(view_file_height(view), line_height); - f32 cursor_min_y = CursorMinY(min_target_y, line_height); - - if (cursor_y > target_y + cursor_max_y){ - cursor_y = target_y + cursor_max_y; - } - if (target_y != 0 && cursor_y < target_y + cursor_min_y){ - cursor_y = target_y + cursor_min_y; - } - - if (cursor_y != old_cursor_y){ - if (cursor_y > old_cursor_y){ - cursor_y += line_height; - } - else{ - cursor_y -= line_height; - } - view->recent->cursor = - view_compute_cursor_from_xy(view, view->recent->preferred_x, cursor_y); - } -} - -internal void -view_move_view_to_cursor(View *view, GUI_Scroll_Vars *scroll){ - f32 line_height = (f32)view->font_height; - f32 delta_y = 3.f*line_height; - - f32 max_visible_y = view_file_height(view); - f32 max_x = view_file_width(view); - - f32 cursor_y = view_get_cursor_y(view); - f32 cursor_x = view_get_cursor_x(view); - - GUI_Scroll_Vars scroll_vars = *scroll; - f32 target_y = scroll_vars.target_y; - f32 target_x = scroll_vars.target_x; - - f32 cursor_max_y = CursorMaxY(max_visible_y, line_height); - f32 cursor_min_y = CursorMinY(0, line_height); - - if (cursor_y > target_y + cursor_max_y){ - target_y = cursor_y - cursor_max_y + delta_y; - } - if (cursor_y < target_y + cursor_min_y){ - target_y = cursor_y - delta_y - cursor_min_y; - } - - target_y = clamp(0.f, target_y, scroll_vars.max_y); - - if (cursor_x < target_x){ - target_x = (f32)Max(0, cursor_x - max_x/2); - } - else if (cursor_x >= target_x + max_x){ - target_x = (f32)(cursor_x - max_x/2); - } - - if (target_x != scroll_vars.target_x || target_y != scroll_vars.target_y){ - scroll->target_x = target_x; - scroll->target_y = target_y; - } -} - -inline void -file_view_nullify_file(View *view){ - General_Memory *general = &view->persistent.models->mem.general; - if (view->file_data.line_wrap_y){ - general_memory_free(general, view->file_data.line_wrap_y); - } - view->file_data = file_viewing_data_zero(); -} - -inline f32 -view_compute_max_target_y(i32 lowest_line, i32 line_height, f32 view_height){ - f32 max_target_y = ((lowest_line+.5f)*line_height) - view_height*.5f; - max_target_y = clamp_bottom(0.f, max_target_y); - return(max_target_y); -} - -internal f32 -view_compute_max_target_y(View *view){ - i32 lowest_line = view_compute_lowest_line(view); - i32 line_height = view->font_height; - f32 view_height = view_file_height(view); - f32 max_target_y = view_compute_max_target_y(lowest_line, line_height, view_height); - return(max_target_y); -} - -internal void -view_set_file(View *view, Editing_File *file, Models *models){ - Font_Info *fnt_info; - - // TODO(allen): This belongs somewhere else. - fnt_info = get_font_info(models->font_set, models->global_font.font_id); - view->font_advance = fnt_info->advance; - view->font_height = fnt_info->height; - - file_view_nullify_file(view); - view->file_data.file = file; - - if (file){ - u64 unique_buffer_id = file->unique_buffer_id; - Recent_File_Data *recent = view->recent; - Recent_File_Data temp_recent = {0}; - i32 i = 0; - i32 max = ArrayCount(view->recent)-1; - b32 found_recent_entry = 0; - - view->file_data.unwrapped_lines = file->settings.unwrapped_lines; - - for (; i < max; ++i, ++recent){ - if (recent->unique_buffer_id == unique_buffer_id){ - temp_recent = *recent; - memmove(view->recent+1, view->recent, sizeof(*recent)*i); - view->recent[0] = temp_recent; - found_recent_entry = 1; - break; - } - } - - if (found_recent_entry){ - if (file_is_ready(file)){ - view_measure_wraps(&models->mem.general, view); - view->recent->cursor = view_compute_cursor_from_pos(view, view->recent->cursor.pos); - view->recent->scroll.max_y = view_compute_max_target_y(view); - - view_move_view_to_cursor(view, &view->recent->scroll); - } - } - else{ - i = 15; - recent = view->recent + i; - memmove(view->recent+1, view->recent, sizeof(*recent)*i); - view->recent[0] = recent_file_data_zero(); - - recent = view->recent; - recent->unique_buffer_id = unique_buffer_id; - - if (file_is_ready(file)){ - view_measure_wraps(&models->mem.general, view); - view->recent->cursor = view_compute_cursor_from_pos(view, file->state.cursor_pos); - view->recent->scroll.max_y = view_compute_max_target_y(view); - - view_move_view_to_cursor(view, &view->recent->scroll); - view->reinit_scrolling = 1; - } - } - } -} - -struct Relative_Scrolling{ - f32 scroll_x, scroll_y; - f32 target_x, target_y; -}; - -internal Relative_Scrolling -view_get_relative_scrolling(View *view){ - Relative_Scrolling result; - f32 cursor_y; - cursor_y = view_get_cursor_y(view); - result.scroll_y = cursor_y - view->recent->scroll.scroll_y; - result.target_y = cursor_y - view->recent->scroll.target_y; - return(result); -} - -internal void -view_set_relative_scrolling(View *view, Relative_Scrolling scrolling){ - f32 cursor_y; - cursor_y = view_get_cursor_y(view); - view->recent->scroll.scroll_y = cursor_y - scrolling.scroll_y; - view->recent->scroll.target_y = - clamp_bottom(0.f, cursor_y - scrolling.target_y); -} - -inline void -view_cursor_move(View *view, Full_Cursor cursor){ - view->recent->cursor = cursor; - view->recent->preferred_x = view_get_cursor_x(view); - view->file_data.file->state.cursor_pos = view->recent->cursor.pos; - view->file_data.show_temp_highlight = 0; -} - -inline void -view_cursor_move(View *view, i32 pos){ - Full_Cursor cursor = view_compute_cursor_from_pos(view, pos); - view_cursor_move(view, cursor); -} - -inline void -view_cursor_move(View *view, f32 x, f32 y, b32 round_down = 0){ - Full_Cursor cursor; - if (view->file_data.unwrapped_lines){ - cursor = view_compute_cursor_from_unwrapped_xy(view, x, y, round_down); - } - else{ - cursor = view_compute_cursor_from_wrapped_xy(view, x, y, round_down); - } - view_cursor_move(view, cursor); -} - -inline void -view_cursor_move(View *view, i32 line, i32 pos){ - Full_Cursor cursor = view_compute_cursor_from_line_pos(view, line, pos); - view_cursor_move(view, cursor); -} - -inline void -view_set_widget(View *view, View_Widget_Type type){ - view->widget.type = type; -} - - -inline i32_Rect -view_widget_rect(View *view, i32 font_height){ - Panel *panel = view->panel; - i32_Rect result = panel->inner; - - if (view->file_data.file){ - result.y0 = result.y0 + font_height + 2; - } - - return(result); -} - -enum History_Mode{ - hist_normal, - hist_backward, - hist_forward -}; - -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; - General_Memory *general = &mem->general; - - 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(general, file, step, do_merge, can_merge); - - file_post_undo(general, file, step, do_merge, can_merge); - }break; - - case ED_REVERSE_NORMAL: - { - if (history_mode != hist_forward) - file_post_history(general, 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(general, &file->state.undo.redo); - - if (file->state.undo.redo.size + strings_of_redo > file->state.undo.redo.max) - undo_stack_grow_string(general, &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(general, file, step, do_merge, can_merge); - file_post_redo(general, 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(general, file, step, do_merge, can_merge); - - file_post_undo(general, 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; - } -} - -inline void -file_pre_edit_maintenance(System_Functions *system, - General_Memory *general, - Editing_File *file){ - if (file->state.still_lexing){ - system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); - if (file->state.swap_stack.tokens){ - general_memory_free(general, file->state.swap_stack.tokens); - file->state.swap_stack.tokens = 0; - } - file->state.still_lexing = 0; - } - file->state.last_4ed_edit_time = system->now_time_stamp(); -} - -struct Cursor_Fix_Descriptor{ - b32 is_batch; - union{ - struct{ - Buffer_Edit *batch; - i32 batch_size; - }; - struct{ - i32 start, end; - i32 shift_amount; - }; - }; -}; - -internal void -file_edit_cursor_fix(System_Functions *system, - Partition *part, General_Memory *general, - Editing_File *file, Editing_Layout *layout, - Cursor_Fix_Descriptor desc){ - - Full_Cursor temp_cursor; - Temp_Memory cursor_temp = begin_temp_memory(part); - i32 cursor_max = layout->panel_max_count * 2; - Cursor_With_Index *cursors = push_array(part, Cursor_With_Index, cursor_max); - - f32 y_offset = 0, y_position = 0; - i32 cursor_count = 0; - - View *view; - Panel *panel, *used_panels; - used_panels = &layout->used_sentinel; - - for (dll_items(panel, used_panels)){ - view = panel->view; - if (view->file_data.file == file){ - view_measure_wraps(general, view); - write_cursor_with_index(cursors, &cursor_count, view->recent->cursor.pos); - write_cursor_with_index(cursors, &cursor_count, view->recent->mark - 1); - write_cursor_with_index(cursors, &cursor_count, view->recent->scroll_i - 1); - } - } - - if (cursor_count > 0){ - buffer_sort_cursors(cursors, cursor_count); - if (desc.is_batch){ - buffer_batch_edit_update_cursors(cursors, cursor_count, - desc.batch, desc.batch_size); - } - else{ - buffer_update_cursors(cursors, cursor_count, - desc.start, desc.end, - desc.shift_amount + (desc.end - desc.start)); - } - buffer_unsort_cursors(cursors, cursor_count); - - cursor_count = 0; - for (dll_items(panel, used_panels)){ - view = panel->view; - if (view && view->file_data.file == file){ - view_cursor_move(view, cursors[cursor_count++].pos); - view->recent->preferred_x = view_get_cursor_x(view); - - view->recent->mark = cursors[cursor_count++].pos + 1; - i32 new_scroll_i = cursors[cursor_count++].pos + 1; - if (view->recent->scroll_i != new_scroll_i){ - view->recent->scroll_i = new_scroll_i; - temp_cursor = view_compute_cursor_from_pos(view, view->recent->scroll_i); - y_offset = MOD(view->recent->scroll.scroll_y, view->font_height); - - if (view->file_data.unwrapped_lines){ - y_position = temp_cursor.unwrapped_y + y_offset; - view->recent->scroll.target_y += (y_position - view->recent->scroll.scroll_y); - view->recent->scroll.scroll_y = y_position; - } - else{ - y_position = temp_cursor.wrapped_y + y_offset; - view->recent->scroll.target_y += (y_position - view->recent->scroll.scroll_y); - view->recent->scroll.scroll_y = y_position; - } - } - } - } - } - - end_temp_memory(cursor_temp); -} - -internal void -file_do_single_edit(System_Functions *system, - Models *models, Editing_File *file, - Edit_Spec spec, History_Mode history_mode, b32 use_high_permission = 0){ - if (!use_high_permission && file->settings.read_only) return; - - Mem_Options *mem = &models->mem; - Editing_Layout *layout = &models->layout; - - // NOTE(allen): fixing stuff beforewards???? - file_update_history_before_edit(mem, file, spec.step, spec.str, history_mode); - file_pre_edit_maintenance(system, &mem->general, file); - - // NOTE(allen): actual text replacement - i32 shift_amount = 0; - General_Memory *general = &mem->general; - Partition *part = &mem->part; - - 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 scratch_size = partition_remaining(part); - - Assert(scratch_size > 0); - i32 request_amount = 0; - Assert(end <= buffer_size(&file->state.buffer)); - while (buffer_replace_range(&file->state.buffer, start, end, str, str_len, &shift_amount, - part->base + part->pos, scratch_size, &request_amount)){ - void *new_data = 0; - if (request_amount > 0){ - new_data = general_memory_allocate(general, request_amount, BUBBLE_BUFFER); - } - void *old_data = buffer_edit_provide_memory(&file->state.buffer, new_data, request_amount); - if (old_data) general_memory_free(general, old_data); - } - - Buffer_Type *buffer = &file->state.buffer; - i32 line_start = buffer_get_line_index(&file->state.buffer, start); - i32 line_end = buffer_get_line_index(&file->state.buffer, end); - i32 replaced_line_count = line_end - line_start; - i32 new_line_count = buffer_count_newlines(&file->state.buffer, start, start+str_len); - i32 line_shift = new_line_count - replaced_line_count; - - Render_Font *font = get_font_info(models->font_set, file->state.font_id)->font; - - file_grow_starts_widths_as_needed(general, buffer, line_shift); - buffer_remeasure_starts(buffer, line_start, line_end, line_shift, shift_amount); - buffer_remeasure_widths(buffer, font->advance_data, line_start, line_end, line_shift); - - // NOTE(allen): update the views looking at this file - Panel *panel, *used_panels; - used_panels = &layout->used_sentinel; - - for (dll_items(panel, used_panels)){ - View *view = panel->view; - if (view->file_data.file == file){ - view_measure_wraps(general, view); - } - } - -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - // NOTE(allen): fixing stuff afterwards - if (file->settings.tokens_exist) - file_relex_parallel(system, mem, file, start, end, shift_amount); -#endif - - Cursor_Fix_Descriptor desc = {}; - desc.start = start; - desc.end = end; - desc.shift_amount = shift_amount; - - file_edit_cursor_fix(system, part, general, file, layout, desc); -} - -internal void -file_do_white_batch_edit(System_Functions *system, Models *models, Editing_File *file, - Edit_Spec spec, History_Mode history_mode, b32 use_high_permission = 0){ - if (!use_high_permission && file->settings.read_only) return; - - Mem_Options *mem = &models->mem; - Editing_Layout *layout = &models->layout; - - // NOTE(allen): fixing stuff "beforewards"??? - Assert(spec.str == 0); - file_update_history_before_edit(mem, file, spec.step, 0, history_mode); - file_pre_edit_maintenance(system, &mem->general, file); - - // NOTE(allen): actual text replacement - General_Memory *general = &mem->general; - Partition *part = &mem->part; - - 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); - - i32 scratch_size = partition_remaining(part); - Buffer_Batch_State state = {}; - i32 request_amount; - while (buffer_batch_edit_step(&state, &file->state.buffer, batch, - (char*)str_base, batch_size, part->base + part->pos, - scratch_size, &request_amount)){ - void *new_data = 0; - if (request_amount > 0){ - new_data = general_memory_allocate(general, request_amount, BUBBLE_BUFFER); - } - void *old_data = buffer_edit_provide_memory(&file->state.buffer, new_data, request_amount); - if (old_data) general_memory_free(general, old_data); - } - - // NOTE(allen): meta data - { - Buffer_Measure_Starts state = {}; - Render_Font *font = get_font_info(models->font_set, file->state.font_id)->font; - float *advance_data = 0; - if (font) advance_data = font->advance_data; - buffer_measure_starts_widths(&state, &file->state.buffer, advance_data); - } - - // NOTE(allen): cursor fixing - { - Cursor_Fix_Descriptor desc = {}; - desc.is_batch = 1; - desc.batch = batch; - desc.batch_size = batch_size; - - file_edit_cursor_fix(system, part, general, file, layout, desc); - } - - // NOTE(allen): token fixing - if (file->state.tokens_complete){ - Cpp_Token_Stack tokens = file->state.token_stack; - Cpp_Token *token = tokens.tokens; - Cpp_Token *end_token = tokens.tokens + tokens.count; - Cpp_Token original = {(Cpp_Token_Type)0}; - - Buffer_Edit *edit = batch; - Buffer_Edit *end_edit = batch + batch_size; - - 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)); - 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)); - } - token->size += local_shift; - shift_amount += local_shift; - } - } -} - -inline void -file_replace_range(System_Functions *system, Models *models, Editing_File *file, - i32 start, i32 end, char *str, i32 len, i32 next_cursor, b32 use_high_permission = 0){ - Edit_Spec spec = {}; - spec.step.type = ED_NORMAL; - spec.step.edit.start = start; - spec.step.edit.end = end; - - spec.step.edit.len = len; - spec.step.pre_pos = file->state.cursor_pos; - spec.step.post_pos = next_cursor; - spec.str = (u8*)str; - file_do_single_edit(system, models, file, spec, hist_normal, use_high_permission); -} - -inline void -file_clear(System_Functions *system, Models *models, Editing_File *file, b32 use_high_permission = 0){ - file_replace_range(system, models, file, 0, buffer_size(&file->state.buffer), 0, 0, 0, use_high_permission); -} - -inline void -view_replace_range(System_Functions *system, Models *models, View *view, - i32 start, i32 end, char *str, i32 len, i32 next_cursor){ - file_replace_range(system, models, view->file_data.file, start, end, str, len, next_cursor); -} - -inline void -view_post_paste_effect(View *view, i32 ticks, i32 start, i32 size, u32 color){ - Editing_File *file = view->file_data.file; - - file->state.paste_effect.start = start; - file->state.paste_effect.end = start + size; - file->state.paste_effect.color = color; - file->state.paste_effect.tick_down = ticks; - file->state.paste_effect.tick_max = ticks; -} - -internal Style* -get_style(Models *models, i32 i){ - return (&models->styles.styles[i]); -} - -internal Style* -main_style(Models *models){ - return (get_style(models, 0)); -} - -internal void -view_undo_redo(System_Functions *system, - Models *models, View *view, - Edit_Stack *stack, Edit_Type expected_type){ - Editing_File *file = view->file_data.file; - - if (stack->edit_count > 0){ - Edit_Step step = stack->edits[stack->edit_count-1]; - - Assert(step.type == expected_type); - - Edit_Spec spec = {}; - spec.step = step; - - if (step.child_count == 0){ - spec.step.edit.str_start = 0; - spec.str = stack->strings + step.edit.str_start; - - file_do_single_edit(system, models, file, spec, hist_normal); - - if (expected_type == ED_UNDO) view_cursor_move(view, step.pre_pos); - else view_cursor_move(view, step.post_pos); - view->recent->mark = view->recent->cursor.pos; - - Style *style = main_style(models); - view_post_paste_effect(view, 10, step.edit.start, step.edit.len, - style->main.undo_color); - } - else{ - TentativeAssert(spec.step.special_type == 1); - file_do_white_batch_edit(system, models, view->file_data.file, spec, hist_normal); - } - } -} - -inline void -view_undo(System_Functions *system, Models *models, View *view){ - view_undo_redo(system, models, view, &view->file_data.file->state.undo.undo, ED_UNDO); -} - -inline void -view_redo(System_Functions *system, Models *models, View *view){ - view_undo_redo(system, models, view, &view->file_data.file->state.undo.redo, ED_REDO); -} - -inline u8* -write_data(u8 *ptr, void *x, i32 size){ - memcpy(ptr, x, size); - return (ptr + size); -} - -#define UseFileHistoryDump 0 - -#if UseFileHistoryDump -internal void -file_dump_history(System_Functions *system, Mem_Options *mem, Editing_File *file, char *filename){ - if (!file->state.undo.undo.edits) return; - - i32 size = 0; - - size += sizeof(i32); - size += file->state.undo.undo.edit_count*sizeof(Edit_Step); - size += sizeof(i32); - size += file->state.undo.redo.edit_count*sizeof(Edit_Step); - size += sizeof(i32); - size += file->state.undo.history.edit_count*sizeof(Edit_Step); - size += sizeof(i32); - size += file->state.undo.children.edit_count*sizeof(Buffer_Edit); - - size += sizeof(i32); - size += file->state.undo.undo.size; - size += sizeof(i32); - size += file->state.undo.redo.size; - size += sizeof(i32); - size += file->state.undo.history.size; - size += sizeof(i32); - size += file->state.undo.children.size; - - Partition *part = &mem->part; - i32 remaining = partition_remaining(part); - if (size < remaining){ - u8 *data, *curs; - data = (u8*)part->base + part->pos; - curs = data; - curs = write_data(curs, &file->state.undo.undo.edit_count, 4); - curs = write_data(curs, &file->state.undo.redo.edit_count, 4); - curs = write_data(curs, &file->state.undo.history.edit_count, 4); - curs = write_data(curs, &file->state.undo.children.edit_count, 4); - curs = write_data(curs, &file->state.undo.undo.size, 4); - curs = write_data(curs, &file->state.undo.redo.size, 4); - curs = write_data(curs, &file->state.undo.history.size, 4); - curs = write_data(curs, &file->state.undo.children.size, 4); - - curs = write_data(curs, file->state.undo.undo.edits, sizeof(Edit_Step)*file->state.undo.undo.edit_count); - curs = write_data(curs, file->state.undo.redo.edits, sizeof(Edit_Step)*file->state.undo.redo.edit_count); - curs = write_data(curs, file->state.undo.history.edits, sizeof(Edit_Step)*file->state.undo.history.edit_count); - curs = write_data(curs, file->state.undo.children.edits, sizeof(Buffer_Edit)*file->state.undo.children.edit_count); - - curs = write_data(curs, file->state.undo.undo.strings, file->state.undo.undo.size); - curs = write_data(curs, file->state.undo.redo.strings, file->state.undo.redo.size); - curs = write_data(curs, file->state.undo.history.strings, file->state.undo.history.size); - curs = write_data(curs, file->state.undo.children.strings, file->state.undo.children.size); - - Assert((i32)(curs - data) == size); - system->save_file(filename, data, size); - } -} -#endif - -internal void -view_history_step(System_Functions *system, Models *models, View *view, History_Mode history_mode){ - Assert(history_mode != hist_normal); - - Editing_File *file = view->file_data.file; - - b32 do_history_step = 0; - Edit_Step step = {}; - if (history_mode == hist_backward){ - if (file->state.undo.edit_history_cursor > 0){ - do_history_step = 1; - step = file->state.undo.history.edits[--file->state.undo.edit_history_cursor]; - } - } - else{ - if (file->state.undo.edit_history_cursor < file->state.undo.history.edit_count){ - Assert(((file->state.undo.history.edit_count - file->state.undo.edit_history_cursor) & 1) == 0); - step = file->state.undo.history.edits[--file->state.undo.history.edit_count]; - file->state.undo.history.size -= step.edit.len; - ++file->state.undo.edit_history_cursor; - do_history_step = 1; - } - } - - if (do_history_step){ - Edit_Spec spec; - spec.step = step; - - if (spec.step.child_count == 0){ - spec.step.edit.str_start = 0; - spec.str = file->state.undo.history.strings + step.edit.str_start; - - file_do_single_edit(system, models, file, spec, history_mode); - - switch (spec.step.type){ - case ED_NORMAL: - case ED_REDO: - view_cursor_move(view, step.post_pos); - break; - - case ED_REVERSE_NORMAL: - case ED_UNDO: - view_cursor_move(view, step.pre_pos); - break; - } - view->recent->mark = view->recent->cursor.pos; - } - else{ - TentativeAssert(spec.step.special_type == 1); - file_do_white_batch_edit(system, models, view->file_data.file, spec, history_mode); - } - } -} - -// TODO(allen): write these as streamed operations -internal i32 -view_find_end_of_line(View *view, i32 pos){ -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - Editing_File *file = view->file_data.file; - char *data = file->state.buffer.data; - while (pos < file->state.buffer.size && data[pos] != '\n') ++pos; - if (pos > file->state.buffer.size) pos = file->state.buffer.size; -#endif - return pos; -} - -internal i32 -view_find_beginning_of_line(View *view, i32 pos){ -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - Editing_File *file = view->file_data.file; - char *data = file->state.buffer.data; - if (pos > 0){ - --pos; - while (pos > 0 && data[pos] != '\n') --pos; - if (pos != 0) ++pos; - } -#endif - return pos; -} - -internal i32 -view_find_beginning_of_next_line(View *view, i32 pos){ -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - Editing_File *file = view->file_data.file; - char *data = file->state.buffer.data; - while (pos < file->state.buffer.size && - !starts_new_line(data[pos])){ - ++pos; - } - if (pos < file->state.buffer.size){ - ++pos; - } -#endif - return pos; -} - -internal String* -working_set_next_clipboard_string(General_Memory *general, Working_Set *working, i32 str_size){ - String *result = 0; - i32 clipboard_current = working->clipboard_current; - if (working->clipboard_size == 0){ - clipboard_current = 0; - working->clipboard_size = 1; - } - else{ - ++clipboard_current; - if (clipboard_current >= working->clipboard_max_size){ - clipboard_current = 0; - } - else if (working->clipboard_size <= clipboard_current){ - working->clipboard_size = clipboard_current+1; - } - } - result = &working->clipboards[clipboard_current]; - working->clipboard_current = clipboard_current; - working->clipboard_rolling = clipboard_current; - char *new_str; - if (result->str){ - new_str = (char*)general_memory_reallocate(general, result->str, result->size, str_size); - } - else{ - new_str = (char*)general_memory_allocate(general, str_size+1); - } - // TODO(allen): What if new_str == 0? - *result = make_string(new_str, 0, str_size); - return result; -} - -internal String* -working_set_clipboard_head(Working_Set *working){ - String *result = 0; - if (working->clipboard_size > 0){ - i32 clipboard_index = working->clipboard_current; - working->clipboard_rolling = clipboard_index; - result = &working->clipboards[clipboard_index]; - } - return result; -} - -internal String* -working_set_clipboard_roll_down(Working_Set *working){ - String *result = 0; - if (working->clipboard_size > 0){ - i32 clipboard_index = working->clipboard_rolling; - --clipboard_index; - if (clipboard_index < 0){ - clipboard_index = working->clipboard_size-1; - } - working->clipboard_rolling = clipboard_index; - result = &working->clipboards[clipboard_index]; - } - return result; -} - -internal void -clipboard_copy(System_Functions *system, General_Memory *general, Working_Set *working, Range range, Editing_File *file){ - i32 size = range.end - range.start; - String *dest = working_set_next_clipboard_string(general, working, size); - buffer_stringify(&file->state.buffer, range.start, range.end, dest->str); - dest->size = size; - system->post_clipboard(*dest); -} - -internal Edit_Spec -file_compute_whitespace_edit(Mem_Options *mem, Editing_File *file, i32 cursor_pos, - Buffer_Edit *edits, char *str_base, i32 str_size, - Buffer_Edit *inverse_array, char *inv_str, i32 inv_max, - i32 edit_count){ - General_Memory *general = &mem->general; - - 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)){ - Assert(0); - } - - i32 first_child = - undo_children_push(general, &file->state.undo.children, - edits, edit_count, (u8*)(str_base), str_size); - i32 inverse_first_child = - undo_children_push(general, &file->state.undo.children, - inverse_array, edit_count, (u8*)(inv_str), inv_str_pos); - - Edit_Spec spec = {}; - spec.step.type = ED_NORMAL; - spec.step.first_child = first_child; - spec.step.inverse_first_child = inverse_first_child; - spec.step.special_type = 1; - spec.step.child_count = edit_count; - spec.step.inverse_child_count = edit_count; - spec.step.pre_pos = cursor_pos; - spec.step.post_pos = cursor_pos; - - return spec; -} - -internal void -view_clean_whitespace(System_Functions *system, Models *models, View *view){ - Mem_Options *mem = &models->mem; - Editing_File *file = view->file_data.file; - - Partition *part = &mem->part; - i32 line_count = file->state.buffer.line_count; - i32 edit_max = line_count * 2; - i32 edit_count = 0; - - Assert(file && !file->is_dummy); - - Temp_Memory temp = begin_temp_memory(part); - Buffer_Edit *edits = push_array(part, Buffer_Edit, edit_max); - - char *str_base = (char*)part->base + part->pos; - i32 str_size = 0; - for (i32 line_i = 0; line_i < line_count; ++line_i){ - i32 start = file->state.buffer.line_starts[line_i]; - Hard_Start_Result hard_start = - buffer_find_hard_start(&file->state.buffer, start, 4); - - if (hard_start.all_whitespace) hard_start.indent_pos = 0; - - if ((hard_start.all_whitespace && hard_start.char_pos > start) || !hard_start.all_space){ - Buffer_Edit new_edit; - new_edit.str_start = str_size; - str_size += hard_start.indent_pos; - char *str = push_array(part, char, hard_start.indent_pos); - for (i32 j = 0; j < hard_start.indent_pos; ++j) str[j] = ' '; - new_edit.len = hard_start.indent_pos; - new_edit.start = start; - new_edit.end = hard_start.char_pos; - edits[edit_count++] = new_edit; - } - Assert(edit_count <= edit_max); - } - - if (edit_count > 0){ - Assert(buffer_batch_debug_sort_check(edits, edit_count)); - - // NOTE(allen): computing edit spec, doing batch edit - Buffer_Edit *inverse_array = push_array(part, Buffer_Edit, edit_count); - Assert(inverse_array); - - char *inv_str = (char*)part->base + part->pos; - Edit_Spec spec = - file_compute_whitespace_edit(mem, file, view->recent->cursor.pos, edits, str_base, str_size, - inverse_array, inv_str, part->max - part->pos, edit_count); - - file_do_white_batch_edit(system, models, view->file_data.file, spec, hist_normal); - } - - end_temp_memory(temp); -} - -struct Indent_Options{ - b32 empty_blank_lines; - b32 use_tabs; - i32 tab_width; -}; - -struct Make_Batch_Result{ - char *str_base; - i32 str_size; - - Buffer_Edit *edits; - i32 edit_max; - i32 edit_count; -}; - -internal Cpp_Token* -get_first_token_at_line(Buffer *buffer, Cpp_Token_Stack tokens, i32 line){ - Cpp_Token *result = 0; - i32 start_pos = 0; - Cpp_Get_Token_Result get_token = {0}; - - start_pos = buffer->line_starts[line]; - get_token = cpp_get_token(&tokens, start_pos); - if (get_token.in_whitespace) get_token.token_index += 1; - result = tokens.tokens + get_token.token_index; - - return(result); -} - -internal Cpp_Token* -seek_matching_token_backwards(Cpp_Token_Stack tokens, Cpp_Token *token, - Cpp_Token_Type open_type, Cpp_Token_Type close_type){ - int nesting_level = 0; - if (token <= tokens.tokens){ - token = tokens.tokens; - } - else{ - for (; token > tokens.tokens; --token){ - if (!(token->flags & CPP_TFLAG_PP_BODY)){ - if (token->type == close_type){ - ++nesting_level; - } - else if (token->type == open_type){ - if (nesting_level == 0){ - break; - } - else{ - --nesting_level; - } - } - } - } - } - return(token); -} - -struct Indent_Parse_State{ - i32 current_indent; - i32 previous_line_indent; - i32 paren_nesting; - i32 paren_anchor_indent[16]; -}; - -internal i32 -compute_this_indent(Buffer *buffer, Indent_Parse_State indent, - Cpp_Token T, Cpp_Token prev_token, i32 line_i, i32 tab_width){ - - i32 previous_indent = indent.previous_line_indent; - i32 this_indent = 0; - - i32 this_line_start = buffer->line_starts[line_i]; - i32 next_line_start = 0; - - if (line_i+1 < buffer->line_count){ - next_line_start = buffer->line_starts[line_i+1]; - } - else{ - next_line_start = buffer_size(buffer); - } - - if ((prev_token.type == CPP_TOKEN_COMMENT || prev_token.type == CPP_TOKEN_STRING_CONSTANT) && - prev_token.start <= this_line_start && prev_token.start + prev_token.size > this_line_start){ - this_indent = previous_indent; - } - else{ - this_indent = indent.current_indent; - if (T.start < next_line_start){ - if (T.flags & CPP_TFLAG_PP_DIRECTIVE){ - this_indent = 0; - } - else{ - switch (T.type){ - case CPP_TOKEN_BRACKET_CLOSE: this_indent -= tab_width; break; - case CPP_TOKEN_BRACE_CLOSE: this_indent -= tab_width; break; - case CPP_TOKEN_BRACE_OPEN: break; - - default: - if (indent.current_indent > 0){ - if (!(prev_token.flags & CPP_TFLAG_PP_BODY || - prev_token.flags & CPP_TFLAG_PP_DIRECTIVE)){ - switch (prev_token.type){ - case CPP_TOKEN_BRACKET_OPEN: - case CPP_TOKEN_BRACE_OPEN: case CPP_TOKEN_BRACE_CLOSE: - case CPP_TOKEN_SEMICOLON: case CPP_TOKEN_COLON: - case CPP_TOKEN_COMMA: case CPP_TOKEN_COMMENT: break; - default: this_indent += tab_width; - } - } - } - } - } - } - if (this_indent < 0) this_indent = 0; - } - - if (indent.paren_nesting > 0){ - i32 level = indent.paren_nesting-1; - if (level >= ArrayCount(indent.paren_anchor_indent)){ - level = ArrayCount(indent.paren_anchor_indent)-1; - } - this_indent = indent.paren_anchor_indent[level]; - } - return(this_indent); -} - -internal i32* -get_line_indentation_marks(Partition *part, Buffer *buffer, Cpp_Token_Stack tokens, - i32 line_start, i32 line_end, i32 tab_width){ - - i32 indent_mark_count = line_end - line_start; - i32 *indent_marks = push_array(part, i32, indent_mark_count); - - Indent_Parse_State indent = {0}; - Cpp_Token *token = get_first_token_at_line(buffer, tokens, line_start); - - if (token != tokens.tokens){ - --token; - for (; token > tokens.tokens; --token){ - if (!(token->flags & CPP_TFLAG_PP_BODY)){ - switch(token->type){ - case CPP_TOKEN_BRACE_OPEN: - case CPP_TOKEN_BRACE_CLOSE: - goto out_of_loop; - } - } - } - out_of_loop:; - } - - // TODO(allen): This can maybe be it's own function now, so that we - // can do the decls in the order we want and avoid the extra binary search. - i32 found_safe_start_position = 0; - do{ - i32 line = buffer_get_line_index(buffer, token->start); - i32 start = buffer->line_starts[line]; - Hard_Start_Result hard_start = buffer_find_hard_start(buffer, start, tab_width); - - indent.current_indent = hard_start.indent_pos; - - Cpp_Token *start_token = get_first_token_at_line(buffer, tokens, line); - Cpp_Token *brace_token = token; - - if (start_token->type == CPP_TOKEN_PARENTHESE_OPEN){ - if (start_token == tokens.tokens){ - found_safe_start_position = 1; - } - else{ - token = start_token-1; - } - } - else{ - int close = 0; - - for (token = brace_token; token >= start_token; --token){ - switch(token->type){ - case CPP_TOKEN_PARENTHESE_CLOSE: - case CPP_TOKEN_BRACKET_CLOSE: - case CPP_TOKEN_BRACE_CLOSE: - close = token->type; - goto out_of_loop2; - } - } - out_of_loop2:; - - switch (close){ - case 0: token = start_token; found_safe_start_position = 1; break; - - case CPP_TOKEN_PARENTHESE_CLOSE: - token = seek_matching_token_backwards(tokens, token-1, - CPP_TOKEN_PARENTHESE_OPEN, - CPP_TOKEN_PARENTHESE_CLOSE); - break; - - case CPP_TOKEN_BRACKET_CLOSE: - token = seek_matching_token_backwards(tokens, token-1, - CPP_TOKEN_BRACKET_OPEN, - CPP_TOKEN_BRACKET_CLOSE); - break; - - case CPP_TOKEN_BRACE_CLOSE: - token = seek_matching_token_backwards(tokens, token-1, - CPP_TOKEN_BRACE_OPEN, - CPP_TOKEN_BRACE_CLOSE); - break; - } - } - } while(found_safe_start_position == 0); - - // NOTE(allen): Shift the array so that line_i can just operate in - // it's natural value range. - indent_marks -= line_start; - - i32 line_i = buffer_get_line_index(buffer, token->start); - - if (line_i > line_start){ - line_i = line_start; - } - - i32 next_line_start = buffer->line_starts[line_i+1]; - switch (token->type){ - case CPP_TOKEN_BRACKET_OPEN: indent.current_indent += tab_width; break; - case CPP_TOKEN_BRACE_OPEN: indent.current_indent += tab_width; break; - } - - indent.previous_line_indent = indent.current_indent; - Cpp_Token T; - Cpp_Token prev_token = *token; - ++token; - - for (; line_i < line_end; ++token){ - if (token < tokens.tokens + tokens.count){ - T = *token; - } - else{ - T.type = CPP_TOKEN_EOF; - T.start = buffer_size(buffer); - T.flags = 0; - } - - for (; T.start >= next_line_start && line_i < line_end;){ - if (line_i+1 < buffer->line_count){ - next_line_start = buffer->line_starts[line_i+1]; - } - else{ - next_line_start = buffer_size(buffer); - } - - // TODO(allen): Since this is called in one place we can probably go back - // to directly passing in next_line_start and this_line_start. - i32 this_indent = compute_this_indent(buffer, indent, T, prev_token, line_i, tab_width); - - if (line_i >= line_start){ - indent_marks[line_i] = this_indent; - } - ++line_i; - - indent.previous_line_indent = this_indent; - } - - switch (T.type){ - case CPP_TOKEN_BRACKET_OPEN: indent.current_indent += 4; break; - case CPP_TOKEN_BRACKET_CLOSE: indent.current_indent -= 4; break; - case CPP_TOKEN_BRACE_OPEN: indent.current_indent += 4; break; - case CPP_TOKEN_BRACE_CLOSE: indent.current_indent -= 4; break; - - case CPP_TOKEN_PARENTHESE_OPEN: - if (!(T.flags & CPP_TFLAG_PP_BODY)){ - if (indent.paren_nesting < ArrayCount(indent.paren_anchor_indent)){ - i32 line = buffer_get_line_index(buffer, T.start); - i32 start = buffer->line_starts[line]; - i32 char_pos = T.start - start; - - Hard_Start_Result hard_start = buffer_find_hard_start( - buffer, start, tab_width); - - i32 line_pos = hard_start.char_pos - start; - - indent.paren_anchor_indent[indent.paren_nesting] = - char_pos - line_pos + indent.previous_line_indent + 1; - } - ++indent.paren_nesting; - } - break; - - case CPP_TOKEN_PARENTHESE_CLOSE: - if (!(T.flags & CPP_TFLAG_PP_BODY)){ - --indent.paren_nesting; - } - break; - } - prev_token = T; - } - - // NOTE(allen): Unshift the indent_marks array so that the return value - // is the exact starting point of the array that was actually allocated. - indent_marks += line_start; - - return(indent_marks); -} - -internal Make_Batch_Result -make_batch_from_indent_marks(Partition *part, Buffer *buffer, i32 line_start, i32 line_end, - i32 *indent_marks, Indent_Options opts){ - - Make_Batch_Result result = {0}; - - i32 edit_max = line_end - line_start; - i32 edit_count = 0; - - Buffer_Edit *edits = push_array(part, Buffer_Edit, edit_max); - - char *str_base = (char*)part->base + part->pos; - i32 str_size = 0; - - // NOTE(allen): Shift the array so that line_i can just operate in - // it's natural value range. - indent_marks -= line_start; - - for (i32 line_i = line_start; line_i < line_end; ++line_i){ - i32 start = buffer->line_starts[line_i]; - Hard_Start_Result hard_start = - buffer_find_hard_start(buffer, start, opts.tab_width); - - i32 correct_indentation = indent_marks[line_i]; - if (hard_start.all_whitespace && opts.empty_blank_lines) correct_indentation = 0; - if (correct_indentation == -1) correct_indentation = hard_start.indent_pos; - - if ((hard_start.all_whitespace && hard_start.char_pos > start) || - !hard_start.all_space || correct_indentation != hard_start.indent_pos){ - Buffer_Edit new_edit; - new_edit.str_start = str_size; - str_size += correct_indentation; - char *str = push_array(part, char, correct_indentation); - i32 j = 0; - if (opts.use_tabs){ - i32 i = 0; - for (; i + opts.tab_width <= correct_indentation; i += opts.tab_width) str[j++] = '\t'; - for (; i < correct_indentation; ++i) str[j++] = ' '; - } - else{ - for (; j < correct_indentation; ++j) str[j] = ' '; - } - new_edit.len = j; - new_edit.start = start; - new_edit.end = hard_start.char_pos; - edits[edit_count++] = new_edit; - } - - Assert(edit_count <= edit_max); - } - - result.str_base = str_base; - result.str_size = str_size; - - result.edits = edits; - result.edit_max = edit_max; - result.edit_count = edit_count; - - return(result); -} - -internal void -view_auto_tab_tokens(System_Functions *system, Models *models, - View *view, i32 start, i32 end, Indent_Options opts){ -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - Editing_File *file = view->file_data.file; - Mem_Options *mem = &models->mem; - Partition *part = &mem->part; - Buffer *buffer = &file->state.buffer; - - Assert(file && !file->is_dummy); - Cpp_Token_Stack tokens = file->state.token_stack; - Assert(tokens.tokens); - - i32 line_start = buffer_get_line_index(buffer, start); - i32 line_end = buffer_get_line_index(buffer, end) + 1; - - Temp_Memory temp = begin_temp_memory(part); - - i32 *indent_marks = - get_line_indentation_marks(part, buffer, tokens, line_start, line_end, opts.tab_width); - - Make_Batch_Result batch = - make_batch_from_indent_marks(part, buffer, line_start, line_end, indent_marks, opts); - - if (batch.edit_count > 0){ - Assert(buffer_batch_debug_sort_check(batch.edits, batch.edit_count)); - - // NOTE(allen): computing edit spec, doing batch edit - Buffer_Edit *inverse_array = push_array(part, Buffer_Edit, batch.edit_count); - Assert(inverse_array); - - char *inv_str = (char*)part->base + part->pos; - Edit_Spec spec = - file_compute_whitespace_edit(mem, file, view->recent->cursor.pos, - batch.edits, batch.str_base, batch.str_size, - inverse_array, inv_str, part->max - part->pos, batch.edit_count); - - file_do_white_batch_edit(system, models, view->file_data.file, spec, hist_normal); - } - end_temp_memory(temp); - - { - i32 start = view->recent->cursor.pos; - Hard_Start_Result hard_start = buffer_find_hard_start(buffer, start, 4); - - view_cursor_move(view, hard_start.char_pos); - } -#endif -} - -struct Get_Link_Result{ - b32 in_link; - i32 index; -}; - -internal u32* -style_get_color(Style *style, Cpp_Token token){ - u32 *result; - if (token.flags & CPP_TFLAG_IS_KEYWORD){ - if (token.type == CPP_TOKEN_BOOLEAN_CONSTANT){ - result = &style->main.bool_constant_color; - } - else{ - result = &style->main.keyword_color; - } - } - else if(token.flags & CPP_TFLAG_PP_DIRECTIVE){ - result = &style->main.preproc_color; - } - else{ - switch (token.type){ - case CPP_TOKEN_COMMENT: - result = &style->main.comment_color; - break; - - case CPP_TOKEN_STRING_CONSTANT: - result = &style->main.str_constant_color; - break; - - case CPP_TOKEN_CHARACTER_CONSTANT: - result = &style->main.char_constant_color; - break; - - case CPP_TOKEN_INTEGER_CONSTANT: - result = &style->main.int_constant_color; - break; - - case CPP_TOKEN_FLOATING_CONSTANT: - result = &style->main.float_constant_color; - break; - - case CPP_TOKEN_INCLUDE_FILE: - result = &style->main.include_color; - break; - - default: - result = &style->main.default_color; - break; - } - } - return result; -} - -internal void -remeasure_file_view(System_Functions *system, View *view){ - if (file_is_ready(view->file_data.file)){ - Relative_Scrolling relative = view_get_relative_scrolling(view); - view_measure_wraps(&view->persistent.models->mem.general, view); - view_cursor_move(view, view->recent->cursor.pos); - view->recent->preferred_x = view_get_cursor_x(view); - view_set_relative_scrolling(view, relative); - } -} - -inline void -view_show_menu(View *view, Command_Map *gui_map){ - view->map = gui_map; - view->showing_ui = VUI_Menu; - view->current_scroll = &view->gui_scroll; -} - -inline void -view_show_config(View *view, Command_Map *gui_map){ - view->map = gui_map; - view->showing_ui = VUI_Config; - view->current_scroll = &view->gui_scroll; -} - -inline void -view_show_interactive(System_Functions *system, View *view, - Command_Map *gui_map, Interactive_Action action, - Interactive_Interaction interaction, String query){ - - Models *models = view->persistent.models; - - view->showing_ui = VUI_Interactive; - view->action = action; - view->interaction = interaction; - view->dest = make_fixed_width_string(view->dest_); - view->list_i = 0; - view->current_scroll = &view->gui_scroll; - - view->map = gui_map; - - hot_directory_clean_end(&models->hot_directory); - hot_directory_reload(system, &models->hot_directory, &models->working_set); -} - -inline void -view_show_theme(View *view, Command_Map *gui_map){ - view->map = gui_map; - view->showing_ui = VUI_Theme; - view->color_mode = CV_Mode_Library; - view->color = super_color_create(0xFF000000); - view->current_color_editing = 0; - view->current_scroll = &view->gui_scroll; -} - -inline void -view_show_file(View *view){ - Editing_File *file = view->file_data.file; - if (file){ - view->map = get_map(view->persistent.models, file->settings.base_map_id); - } - else{ - view->map = get_map(view->persistent.models, mapid_global); - } - view->showing_ui = VUI_None; - view->current_scroll = &view->recent->scroll; -} - -internal void -view_save_file(System_Functions *system, Models *models, - Editing_File *file, View *view, String filename, b32 save_as){ - Mem_Options *mem = &models->mem; - Working_Set *working_set = &models->working_set; - - if (!file){ - if (view){ - file = view->file_data.file; - } - else{ - file = working_set_lookup_file(working_set, filename); - } - } - - if (file && buffer_get_sync(file) != SYNC_GOOD){ - if (file_save(system, mem, file, filename.str)){ - if (save_as){ - file_set_name(working_set, file, filename.str); - } - } - } -} - -internal void -view_new_file(System_Functions *system, Models *models, - View *view, String string){ - Working_Set *working_set = &models->working_set; - General_Memory *general = &models->mem.general; - - Editing_File *file = working_set_alloc_always(working_set, general); - file_create_empty(system, models, file, string.str); - working_set_add(system, working_set, file, general); - - view_set_file(view, file, models); - view_show_file(view); - view->map = get_map(models, file->settings.base_map_id); - - Hook_Function *new_file_fnc = models->hooks[hook_new_file]; - if (new_file_fnc){ - models->buffer_param_indices[models->buffer_param_count++] = file->id.id; - new_file_fnc(&models->app_links); - models->buffer_param_count = 0; - file->settings.is_initialized = 1; - } - -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - if (file->settings.tokens_exist){ - file_first_lex_parallel(system, general, file); - } -#endif -} - -internal void -init_normal_file(System_Functions *system, Models *models, Editing_File *file, - char *buffer, i32 size){ - - General_Memory *general = &models->mem.general; - - String val = make_string(buffer, size); - file_create_from_string(system, models, file, file->name.source_path.str, val); - - if (file->settings.tokens_exist){ - file_first_lex_parallel(system, general, file); - } - - for (View_Iter iter = file_view_iter_init(&models->layout, file, 0); - file_view_iter_good(iter); - iter = file_view_iter_next(iter)){ - view_measure_wraps(general, iter.view); - } -} - -internal void -view_open_file(System_Functions *system, Models *models, - View *view, String filename){ - Working_Set *working_set = &models->working_set; - General_Memory *general = &models->mem.general; - Partition *part = &models->mem.part; - - Editing_File *file = working_set_contains(system, working_set, filename); - - if (file == 0){ - File_Loading loading = system->file_load_begin(filename.str); - - if (loading.exists){ - b32 in_general_mem = 0; - Temp_Memory temp = begin_temp_memory(part); - char *buffer = push_array(part, char, loading.size); - - // TODO(allen): How will we get temporary space for large - // buffers? The main partition isn't always big enough - // but getting a general block this large and copying it - // then freeing it is *super* dumb! - if (buffer == 0){ - buffer = (char*)general_memory_allocate(general, loading.size); - if (buffer != 0){ - in_general_mem = 1; - } - } - - if (system->file_load_end(loading, buffer)){ - file = working_set_alloc_always(working_set, general); - if (file){ - file_init_strings(file); - file_set_name(working_set, file, filename.str); - working_set_add(system, working_set, file, general); - - init_normal_file(system, models, file, - buffer, loading.size); - } - } - - if (in_general_mem){ - general_memory_free(general, buffer); - } - - end_temp_memory(temp); - } - } - - if (file){ - if (view){ - view_set_file(view, file, models); - } - } -} - -internal void -kill_file(System_Functions *system, Models *models, - Editing_File *file, String string){ - Working_Set *working_set = &models->working_set; - - if (!file && string.str){ - file = working_set_lookup_file(working_set, string); - if (!file){ - file = working_set_contains(system, working_set, string); - } - } - - if (file && !file->settings.never_kill){ - working_set_remove(system, working_set, file->name.source_path); - file_close(system, &models->mem.general, file); - working_set_free_file(&models->working_set, file); - - File_Node *used = &models->working_set.used_sentinel; - File_Node *node = used->next; - for (View_Iter iter = file_view_iter_init(&models->layout, file, 0); - file_view_iter_good(iter); - iter = file_view_iter_next(iter)){ - if (node != used){ - iter.view->file_data.file = 0; - view_set_file(iter.view, (Editing_File*)node, models); - node = node->next; - } - else{ - iter.view->file_data.file = 0; - view_set_file(iter.view, 0, models); - } - } - } -} - -internal void -try_kill_file(System_Functions *system, Models *models, - Editing_File *file, View *view, String string){ - Working_Set *working_set = &models->working_set; - - if (!file && string.str){ - file = working_set_lookup_file(working_set, string); - if (!file){ - file = working_set_contains(system, working_set, string); - } - } - - if (file && !file->settings.never_kill){ - if (buffer_needs_save(file)){ - if (view == 0){ - view = models->layout.panels[models->layout.active_panel].view; - } - view_show_interactive(system, view, &models->map_ui, - IAct_Sure_To_Kill, IInt_Sure_To_Kill, - make_lit_string("Are you sure?")); - copy(&view->dest, file->name.live_name); - } - else{ - kill_file(system, models, file, string_zero()); - view_show_file(view); - } - } -} - -internal void -interactive_view_complete(System_Functions *system, View *view, String dest, i32 user_action){ - Models *models = view->persistent.models; - Editing_File *old_file = view->file_data.file; - - switch (view->action){ - case IAct_Open: - view_open_file(system, models, view, dest); - touch_file(&models->working_set, old_file); - view_show_file(view); - break; - - case IAct_Save_As: - view_save_file(system, models, 0, view, dest, 1); - view_show_file(view); - break; - - case IAct_New: - if (dest.size > 0 && !char_is_slash(dest.str[dest.size-1])){ - view_new_file(system, models, view, dest); - view_show_file(view); - }break; - - case IAct_Switch: - { - touch_file(&models->working_set, old_file); - - Editing_File *file = 0; - String string = dest; - - file = working_set_lookup_file(&models->working_set, string); - if (!file){ - file = working_set_contains(system, &models->working_set, string); - } - if (file){ - view_set_file(view, file, models); - } - view_show_file(view); - } - break; - - case IAct_Kill: - try_kill_file(system, models, 0, 0, dest); - break; - - case IAct_Sure_To_Close: - switch (user_action){ - case 0: - models->keep_playing = 0; - break; - - case 1: - view_show_file(view); - break; - - case 2: - // TODO(allen): Save all and close. - break; - } - break; - - case IAct_Sure_To_Kill: - switch (user_action){ - case 0: - kill_file(system, models, 0, dest); - view_show_file(view); - break; - - case 1: - view_show_file(view); - break; - - case 2: - view_save_file(system, models, 0, 0, dest, 0); - kill_file(system, models, 0, dest); - view_show_file(view); - break; - } - break; - } -} - -#if 0 -internal void -update_highlighting(View *view){ - View *file_view = view->hot_file_view; - if (!file_view){ - view->highlight = {}; - return; - } - - Editing_File *file = file_view->file; - if (!file || !file_is_ready(file)){ - view->highlight = {}; - return; - } - - Models *models = view->persistent.models; - - Style *style = &models->style; - i32 pos = view_get_cursor_pos(file_view); - char c = buffer_get_char(&file->state.buffer, pos); - - if (c == '\r'){ - view->highlight.ids[0] = - raw_ptr_dif(&style->main.special_character_color, style); - } - - else if (file->state.tokens_complete){ - Cpp_Token_Stack *tokens = &file->state.token_stack; - Cpp_Get_Token_Result result = cpp_get_token(tokens, pos); - Cpp_Token token = tokens->tokens[result.token_index]; - if (!result.in_whitespace){ - u32 *color = style_get_color(style, token); - view->highlight.ids[0] = raw_ptr_dif(color, style); - if (token.type == CPP_TOKEN_JUNK){ - view->highlight.ids[1] = - raw_ptr_dif(&style->main.highlight_junk_color, style); - } - else if (char_is_whitespace(c)){ - view->highlight.ids[1] = - raw_ptr_dif(&style->main.highlight_white_color, style); - } - else{ - view->highlight.ids[1] = 0; - } - } - else{ - view->highlight.ids[0] = 0; - view->highlight.ids[1] = - raw_ptr_dif(&style->main.highlight_white_color, style); - } - } - - else{ - if (char_is_whitespace(c)){ - view->highlight.ids[0] = 0; - view->highlight.ids[1] = - raw_ptr_dif(&style->main.highlight_white_color, style); - } - else{ - view->highlight.ids[0] = - raw_ptr_dif(&style->main.default_color, style); - view->highlight.ids[1] = 0; - } - } - - if (file_view->show_temp_highlight){ - view->highlight.ids[2] = - raw_ptr_dif(&style->main.highlight_color, style); - view->highlight.ids[3] = - raw_ptr_dif(&style->main.at_highlight_color, style); - } - else if (file->state.paste_effect.tick_down > 0){ - view->highlight.ids[2] = - raw_ptr_dif(&style->main.paste_color, style); - view->highlight.ids[3] = 0; - } - else{ - view->highlight.ids[2] = 0; - view->highlight.ids[3] = 0; - } -} -#endif - -struct File_Bar{ - f32 pos_x, pos_y; - f32 text_shift_x, text_shift_y; - i32_Rect rect; - i16 font_id; -}; - -internal void -intbar_draw_string(Render_Target *target, File_Bar *bar, String str, u32 char_color){ - i16 font_id = bar->font_id; - draw_string(target, font_id, str, - (i32)(bar->pos_x + bar->text_shift_x), - (i32)(bar->pos_y + bar->text_shift_y), - char_color); - bar->pos_x += font_string_width(target, font_id, str); -} - -internal void -view_reinit_scrolling(View *view){ - Editing_File *file = view->file_data.file; - f32 w, h; - f32 cursor_x, cursor_y; - f32 target_x, target_y; - - view->reinit_scrolling = 0; - - target_x = 0; - target_y = 0; - - if (file && file_is_ready(file)){ - cursor_x = view_get_cursor_x(view); - cursor_y = view_get_cursor_y(view); - - w = view_file_width(view); - h = view_file_height(view); - - if (cursor_x >= target_x + w){ - target_x = (f32)(cursor_x - w*.5f); - } - - target_y = clamp_bottom(0.f, (f32)FLOOR32(cursor_y - h*.5f)); - } - - view->recent->scroll.target_y = target_y; - view->recent->scroll.scroll_y = target_y; - view->recent->scroll.prev_target_y = -1000.f; - - view->recent->scroll.target_x = target_x; - view->recent->scroll.scroll_x = target_x; - view->recent->scroll.prev_target_x = -1000.f; -} - -enum CursorScroll_State{ - CursorScroll_NoChange = 0x0, - CursorScroll_Cursor = 0x1, - CursorScroll_Scroll = 0x2, - CursorScroll_ContextChange = 0x4 -}; - -internal u32 -view_get_cursor_scroll_change_state(View *view){ - u32 result = 0; - i32 pos = 0; - Scroll_Context context = {0}; - - if (view->gui_target.did_file){ - pos = view_get_cursor_pos(view); - if ((view->prev_cursor_pos != pos)){ - result |= CursorScroll_Cursor; - } - } - - if (view->current_scroll){ - if (!gui_scroll_eq(view->current_scroll, &view->gui_target.scroll_original)){ - result |= CursorScroll_Scroll; - } - } - - if (context.mode == VUI_None){ - context.file = view->file_data.file; - } - else{ - context.file = view->prev_context.file; - } - context.scroll = view->gui_target.scroll_id; - context.mode = view->showing_ui; - - if (!context_eq(view->prev_context, context)){ - result |= CursorScroll_ContextChange; - } - - return(result); -} - -internal void -view_begin_cursor_scroll_updates(View *view){ - if (view->file_data.file && view->file_data.file == view->prev_context.file){ - Assert(view->prev_cursor_pos == view_get_cursor_pos(view)); - } - - view->prev_context.file = view->file_data.file; - view->prev_context.scroll = view->gui_target.scroll_id; - view->prev_context.mode = view->showing_ui; -} - -internal void -view_end_cursor_scroll_updates(View *view){ - i32 cursor_scroll_state = - view_get_cursor_scroll_change_state(view); - - switch (cursor_scroll_state){ - case CursorScroll_NoChange:break; - - case CursorScroll_Cursor: - case CursorScroll_Cursor|CursorScroll_Scroll: - view_move_view_to_cursor(view, view->current_scroll); - gui_post_scroll_vars(&view->gui_target, view->current_scroll, view->scroll_region); - break; - - case CursorScroll_Scroll: - view_move_cursor_to_view(view); - gui_post_scroll_vars(&view->gui_target, view->current_scroll, view->scroll_region); - break; - } - - if (cursor_scroll_state & CursorScroll_ContextChange){ - view->current_scroll->scroll_y = view->current_scroll->target_y; - view->current_scroll->scroll_x = view->current_scroll->target_x; - gui_post_scroll_vars(&view->gui_target, view->current_scroll, view->scroll_region); - } - - if (view->gui_target.did_file){ - view->prev_cursor_pos = view_get_cursor_pos(view); - } -} - -internal b32 -file_step(View *view, i32_Rect region, Input_Summary *user_input, b32 is_active){ - i32 is_animating = 0; - Editing_File *file = view->file_data.file; - if (file && !file->is_loading){ - f32 max_visible_y = view_file_height(view); - f32 max_x = view_file_width(view); - - GUI_Scroll_Vars scroll_vars = *view->current_scroll; - - if (file->state.paste_effect.tick_down > 0){ - --file->state.paste_effect.tick_down; - is_animating = 1; - } - - if (user_input->mouse.press_l && is_active){ - f32 rx = (f32)(user_input->mouse.x - region.x0); - f32 ry = (f32)(user_input->mouse.y - region.y0); - - if (ry >= 0){ - view_set_widget(view, FWIDG_NONE); - if (rx >= 0 && rx < max_x && ry >= 0 && ry < max_visible_y){ - view_cursor_move(view, rx + scroll_vars.scroll_x, ry + scroll_vars.scroll_y, 1); - view->mode = view_mode_zero(); - } - } - } - if (!is_active) view_set_widget(view, FWIDG_NONE); - } - - return(is_animating); -} - -internal void -do_widget(View *view, GUI_Target *target){ - Query_Slot *slot; - Query_Bar *bar; - - for (slot = view->query_set.used_slot; slot != 0; slot = slot->next){ - bar = slot->query_bar; - gui_do_text_field(target, bar->prompt, bar->string); - } -} - -struct Exhaustive_File_Loop{ - char front_name_[256]; - char full_path_[256]; - String front_name, full_path; - - Absolutes absolutes; - - File_Info *infos; - i32 count, r; -}; - -struct Exhaustive_File_Info{ - File_Info *info; - String message; - b8 is_folder; - b8 name_match; - b8 is_loaded; -}; - -internal void -begin_exhaustive_loop(Exhaustive_File_Loop *loop, Hot_Directory *hdir){ - loop->front_name = make_fixed_width_string(loop->front_name_); - loop->full_path = make_fixed_width_string(loop->full_path_); - - loop->infos = hdir->file_list.infos; - loop->count = hdir->file_list.count; - - get_front_of_directory(&loop->front_name, hdir->string); - get_absolutes(loop->front_name, &loop->absolutes, 1, 1); - get_path_of_directory(&loop->full_path, hdir->string); - loop->r = loop->full_path.size; -} - -internal Exhaustive_File_Info -get_exhaustive_info(System_Functions *system, Working_Set *working_set, Exhaustive_File_Loop *loop, i32 i){ - persist String message_loaded = make_lit_string(" LOADED"); - persist String message_unsaved = make_lit_string(" LOADED *"); - persist String message_unsynced = make_lit_string(" LOADED !"); - - Exhaustive_File_Info result = {0}; - Editing_File *file = 0; - - result.info = loop->infos + i; - loop->full_path.size = loop->r; - append(&loop->full_path, result.info->filename); - terminate_with_null(&loop->full_path); - file = working_set_contains(system, working_set, loop->full_path); - - result.is_folder = (result.info->folder != 0); - result.name_match = (filename_match(loop->front_name, &loop->absolutes, result.info->filename, 0) != 0); - result.is_loaded = (file != 0 && file_is_ready(file)); - - result.message = string_zero(); - if (result.is_loaded){ - switch (buffer_get_sync(file)){ - case SYNC_GOOD: result.message = message_loaded; break; - case SYNC_BEHIND_OS: result.message = message_unsynced; break; - case SYNC_UNSAVED: result.message = message_unsaved; break; - } - } - - return(result); -} - -struct Style_Color_Edit{ - Style_Tag target; - Style_Tag fore; - Style_Tag back; - String text; -}; - -static Style_Color_Edit colors_to_edit[] = { - {Stag_Back, Stag_Default, Stag_Back, make_lit_string("Background")}, - {Stag_Margin, Stag_Default, Stag_Margin, make_lit_string("Margin")}, - {Stag_Margin_Hover, Stag_Default, Stag_Margin_Hover, make_lit_string("Margin Hover")}, - {Stag_Margin_Active, Stag_Default, Stag_Margin_Active, make_lit_string("Margin Active")}, - - {Stag_Cursor, Stag_At_Cursor, Stag_Cursor, make_lit_string("Cursor")}, - {Stag_At_Cursor, Stag_At_Cursor, Stag_Cursor, make_lit_string("Text At Cursor")}, - {Stag_Mark, Stag_Mark, Stag_Back, make_lit_string("Mark")}, - - {Stag_Highlight, Stag_At_Highlight, Stag_Highlight, make_lit_string("Highlight")}, - {Stag_At_Highlight, Stag_At_Highlight, Stag_Highlight, make_lit_string("Text At Highlight")}, - - {Stag_Default, Stag_Default, Stag_Back, make_lit_string("Text Default")}, - {Stag_Comment, Stag_Comment, Stag_Back, make_lit_string("Comment")}, - {Stag_Keyword, Stag_Keyword, Stag_Back, make_lit_string("Keyword")}, - {Stag_Str_Constant, Stag_Str_Constant, Stag_Back, make_lit_string("String Constant")}, - {Stag_Char_Constant, Stag_Char_Constant, Stag_Back, make_lit_string("Character Constant")}, - {Stag_Int_Constant, Stag_Int_Constant, Stag_Back, make_lit_string("Integer Constant")}, - {Stag_Float_Constant, Stag_Float_Constant, Stag_Back, make_lit_string("Float Constant")}, - {Stag_Bool_Constant, Stag_Bool_Constant, Stag_Back, make_lit_string("Boolean Constant")}, - {Stag_Preproc, Stag_Preproc, Stag_Back, make_lit_string("Preprocessor")}, - {Stag_Special_Character, Stag_Special_Character, Stag_Back, make_lit_string("Special Character")}, - - {Stag_Highlight_Junk, Stag_Default, Stag_Highlight_Junk, make_lit_string("Junk Highlight")}, - {Stag_Highlight_White, Stag_Default, Stag_Highlight_White, make_lit_string("Whitespace Highlight")}, - - {Stag_Paste, Stag_Paste, Stag_Back, make_lit_string("Paste Color")}, - - {Stag_Bar, Stag_Base, Stag_Bar, make_lit_string("Bar")}, - {Stag_Base, Stag_Base, Stag_Bar, make_lit_string("Bar Text")}, - {Stag_Pop1, Stag_Pop1, Stag_Bar, make_lit_string("Bar Pop 1")}, - {Stag_Pop2, Stag_Pop2, Stag_Bar, make_lit_string("Bar Pop 2")}, -}; - -struct Single_Line_Input_Step{ - b8 hit_newline; - b8 hit_ctrl_newline; - b8 hit_a_character; - b8 hit_backspace; - b8 hit_esc; - b8 made_a_change; - b8 did_command; - b8 no_file_match; -}; - -enum Single_Line_Input_Type{ - SINGLE_LINE_STRING, - SINGLE_LINE_FILE -}; - -struct Single_Line_Mode{ - Single_Line_Input_Type type; - String *string; - Hot_Directory *hot_directory; - b32 fast_folder_select; - b32 try_to_match; - b32 case_sensitive; -}; - -internal Single_Line_Input_Step -app_single_line_input_core(System_Functions *system, Working_Set *working_set, - Key_Event_Data key, Single_Line_Mode mode){ - Single_Line_Input_Step result = {0}; - - if (key.keycode == key_back){ - result.hit_backspace = 1; - if (mode.string->size > 0){ - result.made_a_change = 1; - --mode.string->size; - switch (mode.type){ - case SINGLE_LINE_STRING: - { - mode.string->str[mode.string->size] = 0; - }break; - - case SINGLE_LINE_FILE: - { - char end_character = mode.string->str[mode.string->size]; - if (char_is_slash(end_character)){ - mode.string->size = reverse_seek_slash(*mode.string) + 1; - mode.string->str[mode.string->size] = 0; - hot_directory_set(system, mode.hot_directory, *mode.string, working_set); - } - else{ - mode.string->str[mode.string->size] = 0; - } - }break; - } - } - } - - else if (key.character == '\n' || key.character == '\t'){ - // NOTE(allen): do nothing! - } - - else if (key.keycode == key_esc){ - result.hit_esc = 1; - result.made_a_change = 1; - } - - else if (key.character){ - result.hit_a_character = 1; - if (!key.modifiers[MDFR_CONTROL_INDEX] && - !key.modifiers[MDFR_ALT_INDEX]){ - if (mode.string->size+1 < mode.string->memory_size){ - u8 new_character = (u8)key.character; - mode.string->str[mode.string->size] = new_character; - mode.string->size++; - mode.string->str[mode.string->size] = 0; - if (mode.type == SINGLE_LINE_FILE && char_is_slash(new_character)){ - hot_directory_set(system, mode.hot_directory, *mode.string, working_set); - } - result.made_a_change = 1; - } - } - else{ - result.did_command = 1; - result.made_a_change = 1; - } - } - - return result; -} - -inline Single_Line_Input_Step -app_single_line_input_step(System_Functions *system, Key_Event_Data key, String *string){ - Single_Line_Mode mode = {}; - mode.type = SINGLE_LINE_STRING; - mode.string = string; - return app_single_line_input_core(system, 0, key, mode); -} - -inline Single_Line_Input_Step -app_single_file_input_step(System_Functions *system, - Working_Set *working_set, Key_Event_Data key, - String *string, Hot_Directory *hot_directory, - b32 fast_folder_select, b32 try_to_match, b32 case_sensitive){ - Single_Line_Mode mode = {}; - mode.type = SINGLE_LINE_FILE; - mode.string = string; - mode.hot_directory = hot_directory; - mode.fast_folder_select = fast_folder_select; - mode.try_to_match = try_to_match; - mode.case_sensitive = case_sensitive; - return app_single_line_input_core(system, working_set, key, mode); -} - -inline Single_Line_Input_Step -app_single_number_input_step(System_Functions *system, Key_Event_Data key, String *string){ - Single_Line_Input_Step result = {}; - Single_Line_Mode mode = {}; - mode.type = SINGLE_LINE_STRING; - mode.string = string; - - char c = (char)key.character; - if (c == 0 || c == '\n' || char_is_numeric(c)) - result = app_single_line_input_core(system, 0, key, mode); - return result; -} - -struct View_Step_Result{ - b32 animating; - b32 consume_keys; - b32 consume_esc; -}; - -internal View_Step_Result -step_file_view(System_Functions *system, View *view, View *active_view, Input_Summary input){ - View_Step_Result result = {0}; - GUI_Target *target = &view->gui_target; - Models *models = view->persistent.models; - Key_Summary keys = input.keys; - - b32 show_scrollbar = !view->hide_scrollbar; - - view->current_scroll = 0; - - if (view->showing_ui != VUI_None){ - b32 did_esc = 0; - Key_Event_Data key; - i32 i; - - for (i = 0; i < keys.count; ++i){ - key = get_single_key(&keys, i); - if (key.keycode == key_esc){ - did_esc = 1; - break; - } - } - - if (did_esc){ - view_show_file(view); - result.consume_esc = 1; - } - } - - gui_begin_top_level(target, input); - { - gui_do_top_bar(target); - do_widget(view, target); - - if (view->showing_ui == VUI_None){ - - gui_begin_serial_section(target); - { - f32 delta = 9.f * view->font_height; - GUI_id scroll_context = {0}; - scroll_context.id[1] = view->showing_ui; - scroll_context.id[0] = (u64)(view->file_data.file); - - view->current_scroll = &view->recent->scroll; - gui_get_scroll_vars(target, scroll_context, - &view->recent->scroll, &view->scroll_region); - - gui_begin_scrollable(target, scroll_context, view->recent->scroll, - delta, show_scrollbar); - gui_do_file(target); - gui_end_scrollable(target); - } - gui_end_serial_section(target); - } - else{ - switch (view->showing_ui){ - case VUI_Menu: - { - view->current_scroll = &view->gui_scroll; - - String message = make_lit_string("Menu"); - String empty_string = {0}; - GUI_id id = {0}; - id.id[1] = VUI_Menu; - - gui_do_text_field(target, message, empty_string); - - id.id[0] = 0; - message = make_lit_string("Theme"); - if (gui_do_fixed_option(target, id, message, 0)){ - view_show_theme(view, view->map); - } - - id.id[0] = 1; - message = make_lit_string("Config"); - if (gui_do_fixed_option(target, id, message, 0)){ - view_show_config(view, view->map); - } - }break; - - case VUI_Config: - { - view->current_scroll = &view->gui_scroll; - - String message = make_lit_string("Config"); - String empty_string = {0}; - GUI_id id = {0}; - id.id[1] = VUI_Config; - - gui_do_text_field(target, message, empty_string); - - id.id[0] = 0; - message = make_lit_string("Left Ctrl + Left Alt = AltGr"); - if (gui_do_fixed_option_checkbox(target, id, message, 0, (b8)models->settings.lctrl_lalt_is_altgr)){ - models->settings.lctrl_lalt_is_altgr = !models->settings.lctrl_lalt_is_altgr; - } - }break; - - case VUI_Theme: - { - view->current_scroll = &view->gui_scroll; - - if (view != active_view){ - view->hot_file_view = active_view; - } - - String message = {0}; - String empty_string = {0}; - - GUI_id id = {0}; - id.id[1] = VUI_Theme + ((u64)view->color_mode << 32); - - GUI_id scroll_context = {0}; - scroll_context.id[0] = 0; - scroll_context.id[1] = VUI_Theme + ((u64)view->color_mode << 32); - - switch (view->color_mode){ - case CV_Mode_Library: - message = make_lit_string("Current Theme - Click to Edit"); - gui_do_text_field(target, message, empty_string); - - id.id[0] = (u64)(main_style(models)); - if (gui_do_style_preview(target, id, 0)){ - view->color_mode = CV_Mode_Adjusting; - } - - message = make_lit_string("Set Font"); - id.id[0] = (u64)(&models->global_font); - if (gui_do_button(target, id, message)){ - view->color_mode = CV_Mode_Font; - } - - message = make_lit_string("Theme Library - Click to Select"); - gui_do_text_field(target, message, empty_string); - - view->current_scroll = &view->gui_scroll; - gui_get_scroll_vars(target, scroll_context, &view->gui_scroll, &view->scroll_region); - gui_begin_scrollable(target, scroll_context, view->gui_scroll, - 9.f * view->font_height, show_scrollbar); - - { - i32 count = models->styles.count; - Style *style; - i32 i; - - for (i = 1; i < count; ++i, ++style){ - style = get_style(models, i); - id.id[0] = (u64)(style); - if (gui_do_style_preview(target, id, i)){ - style_copy(main_style(models), style); - } - } - } - - gui_end_scrollable(target); - break; - - case CV_Mode_Font: - { - Font_Set *font_set = models->font_set; - Font_Info *info = 0; - - i16 i = 1, count = (i16)models->font_set->count + 1; - i16 font_id = 0, new_font_id = 0; - - String message = make_lit_string("Back"); - - id.id[0] = 0; - if (gui_do_button(target, id, message)){ - view->color_mode = CV_Mode_Library; - } - - font_id = models->global_font.font_id; - new_font_id = font_id; - - for (i = 1; i < count; ++i){ - info = get_font_info(font_set, i); - id.id[0] = (u64)i; - if (i != font_id){ - if (gui_do_font_button(target, id, i, info->name)){ - new_font_id = i; - } - } - else{ - char message_space[256]; - message = make_fixed_width_string(message_space); - copy(&message, make_lit_string("currently selected: ")); - append(&message, info->name); - gui_do_font_button(target, id, i, message); - } - } - - models->global_font.font_id = (i16)(new_font_id); - }break; - - case CV_Mode_Adjusting: - { - Style *style = main_style(models); - u32 *edit_color = 0; - u32 *fore = 0, *back = 0; - i32 i = 0; - - String message = make_lit_string("Back"); - - id.id[0] = 0; - if (gui_do_button(target, id, message)){ - view->color_mode = CV_Mode_Library; - } - - view->current_scroll = &view->gui_scroll; - gui_get_scroll_vars(target, scroll_context, &view->gui_scroll, &view->scroll_region); - gui_begin_scrollable(target, scroll_context, view->gui_scroll, - 9.f * view->font_height, show_scrollbar); - - i32 next_color_editing = view->current_color_editing; - - for (i = 0; i < ArrayCount(colors_to_edit); ++i){ - edit_color = style_index_by_tag(&style->main, colors_to_edit[i].target); - id.id[0] = (u64)(edit_color); - - fore = style_index_by_tag(&style->main, colors_to_edit[i].fore); - back = style_index_by_tag(&style->main, colors_to_edit[i].back); - - if (gui_do_color_button(target, id, *fore, *back, colors_to_edit[i].text)){ - next_color_editing = i; - view->color_cursor = 0; - } - - if (view->current_color_editing == i){ - GUI_Item_Update update = {0}; - char text_space[7]; - String text = make_fixed_width_string(text_space); - - color_to_hexstr(*edit_color, &text); - if (gui_do_text_with_cursor(target, view->color_cursor, text, &update)){ - b32 r = 0; - i32 j = 0; - - for (j = 0; j < keys.count; ++j){ - i16 key = keys.keys[j].keycode; - switch (key){ - case key_left: --view->color_cursor; r = 1; result.consume_keys = 1; break; - case key_right: ++view->color_cursor; r = 1; result.consume_keys = 1; break; - - case key_up: - if (next_color_editing > 0){ - --next_color_editing; - } - result.consume_keys = 1; - break; - - case key_down: - if (next_color_editing <= ArrayCount(colors_to_edit)-1){ - ++next_color_editing; - } - result.consume_keys = 1; - break; - - default: - if ((key >= '0' && key <= '9') || (key >= 'a' && key <= 'f') || (key >= 'A' && key <= 'F')){ - text.str[view->color_cursor] = (char)key; - r = 1; - result.consume_keys = 1; - } - break; - } - - if (view->color_cursor < 0) view->color_cursor = 0; - if (view->color_cursor >= 6) view->color_cursor = 5; - } - - if (r){ - hexstr_to_color(text, edit_color); - gui_rollback(target, &update); - gui_do_text_with_cursor(target, view->color_cursor, text, 0); - } - } - } - } - - if (view->current_color_editing != next_color_editing){ - view->current_color_editing = next_color_editing; - view->color_cursor = 0; - } - - gui_end_scrollable(target); - }break; - } - }break; - - case VUI_Interactive: - { - b32 complete = 0; - char comp_dest_space[1024]; - String comp_dest = make_fixed_width_string(comp_dest_space); - i32 comp_action = 0; - - view->current_scroll = &view->gui_scroll; - - GUI_id id = {0}; - id.id[1] = VUI_Interactive + ((u64)view->interaction << 32); - - GUI_id scroll_context = {0}; - scroll_context.id[1] = VUI_Interactive + ((u64)view->interaction << 32); - - switch (view->interaction){ - case IInt_Sys_File_List: - { - b32 use_item_in_list = 1; - b32 activate_directly = 0; - - if (view->action == IAct_Save_As || view->action == IAct_New){ - use_item_in_list = 0; - } - - String message = {0}; - switch (view->action){ - case IAct_Open: message = make_lit_string("Open: "); break; - case IAct_Save_As: message = make_lit_string("Save As: "); break; - case IAct_New: message = make_lit_string("New: "); break; - } - - Exhaustive_File_Loop loop; - Exhaustive_File_Info file_info; - - GUI_Item_Update update = {0}; - Hot_Directory *hdir = &models->hot_directory; - b32 do_new_directory = 0; - b32 snap_into_view = 0; - i32 i = 0; - - { - Single_Line_Input_Step step = {0}; - Key_Event_Data key = {0}; - i32 i; - - for (i = 0; i < keys.count; ++i){ - key = get_single_key(&keys, i); - step = app_single_file_input_step(system, &models->working_set, key, - &hdir->string, hdir, 1, 1, 0); - if (step.made_a_change){ - view->list_i = 0; - result.consume_keys = 1; - } - if (!use_item_in_list && (key.keycode == '\n' || key.keycode == '\t')){ - activate_directly = 1; - result.consume_keys = 1; - } - } - } - - gui_do_text_field(target, message, hdir->string); - - scroll_context.id[0] = (u64)(hdir); - if (gui_get_scroll_vars(target, scroll_context, - &view->gui_scroll, &view->scroll_region)){ - snap_into_view = 1; - } - gui_begin_scrollable(target, scroll_context, view->gui_scroll, - 9.f * view->font_height, show_scrollbar); - - id.id[0] = (u64)(hdir) + 1; - - if (gui_begin_list(target, id, view->list_i, 0, - snap_into_view, &update)){ - // TODO(allen): Allow me to handle key consumption correctly here! - gui_standard_list(target, id, view->current_scroll, view->scroll_region, - &keys, &view->list_i, &update); - } - - { - begin_exhaustive_loop(&loop, hdir); - for (i = 0; i < loop.count; ++i){ - file_info = get_exhaustive_info(system, &models->working_set, &loop, i); - - if (file_info.name_match){ - id.id[0] = (u64)(file_info.info); - if (gui_do_file_option(target, id, file_info.info->filename, - file_info.is_folder, file_info.message)){ - if (file_info.is_folder){ - set_last_folder(&hdir->string, file_info.info->filename, '/'); - do_new_directory = 1; - } - else if (use_item_in_list){ - complete = 1; - copy(&comp_dest, loop.full_path); - } - } - } - } - } - - gui_end_list(target); - - if (activate_directly){ - complete = 1; - copy(&comp_dest, hdir->string); - } - - if (do_new_directory){ - hot_directory_reload(system, hdir, &models->working_set); - } - - gui_end_scrollable(target); - }break; - - case IInt_Live_File_List: - { - b32 snap_into_view = 0; - persist String message_unsaved = make_lit_string(" *"); - persist String message_unsynced = make_lit_string(" !"); - - String message = {0}; - switch (view->action){ - case IAct_Switch: message = make_lit_string("Switch: "); break; - case IAct_Kill: message = make_lit_string("Kill: "); break; - } - - Absolutes absolutes; - Editing_File *file; - Working_Set *working_set = &models->working_set; - Editing_Layout *layout = &models->layout; - GUI_Item_Update update = {0}; - - { - Single_Line_Input_Step step; - Key_Event_Data key; - i32 i; - for (i = 0; i < keys.count; ++i){ - key = get_single_key(&keys, i); - step = app_single_line_input_step(system, key, &view->dest); - if (step.made_a_change){ - view->list_i = 0; - result.consume_keys = 1; - } - } - } - - get_absolutes(view->dest, &absolutes, 1, 1); - - gui_do_text_field(target, message, view->dest); - - scroll_context.id[0] = (u64)(working_set); - if (gui_get_scroll_vars(target, scroll_context, - &view->gui_scroll, &view->scroll_region)){ - snap_into_view = 1; - } - gui_begin_scrollable(target, scroll_context, view->gui_scroll, - 9.f * view->font_height, show_scrollbar); - - id.id[0] = (u64)(working_set) + 1; - if (gui_begin_list(target, id, view->list_i, - 0, snap_into_view, &update)){ - gui_standard_list(target, id, view->current_scroll, view->scroll_region, - &keys, &view->list_i, &update); - } - - { - Partition *part = &models->mem.part; - Temp_Memory temp = begin_temp_memory(part); - File_Node *node = 0, *used_nodes = 0; - Editing_File **reserved_files = 0; - i32 reserved_top = 0, i = 0; - View_Iter iter = {0}; - - partition_align(part, sizeof(i32)); - reserved_files = (Editing_File**)partition_current(part); - - used_nodes = &working_set->used_sentinel; - for (dll_items(node, used_nodes)){ - file = (Editing_File*)node; - Assert(!file->is_dummy); - - if (filename_match(view->dest, &absolutes, file->name.live_name, 1)){ - iter = file_view_iter_init(layout, file, 0); - if (file_view_iter_good(iter)){ - reserved_files[reserved_top++] = file; - } - else{ - if (file->name.live_name.str[0] == '*'){ - reserved_files[reserved_top++] = file; - } - else{ - message = string_zero(); - switch (buffer_get_sync(file)){ - case SYNC_BEHIND_OS: message = message_unsynced; break; - case SYNC_UNSAVED: message = message_unsaved; break; - } - - id.id[0] = (u64)(file); - if (gui_do_file_option(target, id, file->name.live_name, 0, message)){ - complete = 1; - copy(&comp_dest, file->name.live_name); - } - } - } - } - } - - for (i = 0; i < reserved_top; ++i){ - file = reserved_files[i]; - - message = string_zero(); - switch (buffer_get_sync(file)){ - case SYNC_BEHIND_OS: message = message_unsynced; break; - case SYNC_UNSAVED: message = message_unsaved; break; - } - - id.id[0] = (u64)(file); - if (gui_do_file_option(target, id, file->name.live_name, 0, message)){ - complete = 1; - copy(&comp_dest, file->name.live_name); - } - } - - end_temp_memory(temp); - } - - gui_end_list(target); - - gui_end_scrollable(target); - }break; - - case IInt_Sure_To_Close: - { - i32 action = -1; - - String empty_str = {0}; - String message = make_lit_string("There is one or more files unsaved changes, close anyway?"); - - gui_do_text_field(target, message, empty_str); - - id.id[0] = (u64)('y'); - message = make_lit_string("(Y)es"); - if (gui_do_fixed_option(target, id, message, 'y')){ - action = 0; - } - - id.id[0] = (u64)('n'); - message = make_lit_string("(N)o"); - if (gui_do_fixed_option(target, id, message, 'n')){ - action = 1; - } - - if (action != -1){ - complete = 1; - copy(&comp_dest, view->dest); - comp_action = action; - } - }break; - - case IInt_Sure_To_Kill: - { - i32 action = -1; - - String empty_str = {0}; - String message = make_lit_string("There are unsaved changes, close anyway?"); - - gui_do_text_field(target, message, empty_str); - - id.id[0] = (u64)('y'); - message = make_lit_string("(Y)es"); - if (gui_do_fixed_option(target, id, message, 'y')){ - action = 0; - } - - id.id[0] = (u64)('n'); - message = make_lit_string("(N)o"); - if (gui_do_fixed_option(target, id, message, 'n')){ - action = 1; - } - - id.id[0] = (u64)('s'); - message = make_lit_string("(S)ave and kill"); - if (gui_do_fixed_option(target, id, message, 's')){ - action = 2; - } - - if (action != -1){ - complete = 1; - copy(&comp_dest, view->dest); - comp_action = action; - } - }break; - } - - if (complete){ - terminate_with_null(&comp_dest); - interactive_view_complete(system, view, comp_dest, comp_action); - } - }break; - } - } - } - gui_end_top_level(target); - - result.animating = target->animating; - return(result); -} - -internal f32 -view_get_scroll_y(View *view){ - f32 v; - if (view->showing_ui == VUI_None){ - v = view->recent->scroll.scroll_y; - } - else{ - v = view->gui_scroll.scroll_y; - } - return(v); -} - -internal void -click_button_input(GUI_Target *target, GUI_Session *session, Input_Summary *user_input, - GUI_Interactive *b, b32 *is_animating){ - i32 mx = user_input->mouse.x; - i32 my = user_input->mouse.y; - - if (hit_check(mx, my, session->rect)){ - target->hover = b->id; - if (user_input->mouse.press_l){ - target->mouse_hot = b->id; - *is_animating = 1; - } - if (user_input->mouse.release_l && gui_id_eq(target->mouse_hot, b->id)){ - target->active = b->id; - target->mouse_hot = gui_id_zero(); - *is_animating = 1; - } - } - else if (gui_id_eq(target->hover, b->id)){ - target->hover = gui_id_zero(); - } -} - -internal b32 -scroll_button_input(GUI_Target *target, GUI_Session *session, Input_Summary *user_input, - GUI_id id, b32 *is_animating){ - b32 result = 0; - i32 mx = user_input->mouse.x; - i32 my = user_input->mouse.y; - - if (hit_check(mx, my, session->rect)){ - target->hover = id; - if (user_input->mouse.l){ - target->mouse_hot = id; - gui_activate_scrolling(target); - *is_animating = 1; - result = 1; - } - } - else if (gui_id_eq(target->hover, id)){ - target->hover = gui_id_zero(); - } - return(result); -} - -struct Input_Process_Result{ - GUI_Scroll_Vars vars; - i32_Rect region; - b32 is_animating; -}; - -internal Input_Process_Result -do_input_file_view(System_Functions *system, - View *view, i32_Rect rect, b32 is_active, - Input_Summary *user_input, - GUI_Scroll_Vars vars, i32_Rect region){ - Input_Process_Result result = {0}; - b32 is_file_scroll = 0; - - GUI_Session gui_session = {0}; - GUI_Header *h = 0; - GUI_Target *target = &view->gui_target; - GUI_Interpret_Result interpret_result = {0}; - - result.vars = vars; - result.region = region; - - target->active = gui_id_zero(); - - if (target->push.pos > 0){ - gui_session_init(&gui_session, target, rect, view->font_height); - - for (h = (GUI_Header*)target->push.base; - h->type; - h = NextHeader(h)){ - interpret_result = gui_interpret(target, &gui_session, h, - result.vars, result.region); - - if (interpret_result.has_region){ - result.region = interpret_result.region; - } - - switch (h->type){ - case guicom_file_option: - case guicom_fixed_option: - case guicom_fixed_option_checkbox: - { - GUI_Interactive *b = (GUI_Interactive*)h; - - if (interpret_result.auto_activate){ - target->auto_hot = gui_id_zero(); - target->active = b->id; - result.is_animating = 1; - } - else if (interpret_result.auto_hot){ - if (!gui_id_eq(target->auto_hot, b->id)){ - target->auto_hot = b->id; - result.is_animating = 1; - } - } - }break; - } - - if (interpret_result.has_info){ - switch (h->type){ - case guicom_top_bar: break; - - case guicom_file: - { - f32 new_max_y = view_compute_max_target_y(view); - - view->file_region = gui_session.rect; - result.vars.max_y = new_max_y; - - if (view->reinit_scrolling){ - view_reinit_scrolling(view); - result.is_animating = 1; - } - if (file_step(view, gui_session.rect, user_input, is_active)){ - result.is_animating = 1; - } - is_file_scroll = 1; - }break; - - case guicom_color_button: - case guicom_font_button: - case guicom_button: - case guicom_file_option: - case guicom_style_preview: - { - GUI_Interactive *b = (GUI_Interactive*)h; - - click_button_input(target, &gui_session, user_input, b, &result.is_animating); - }break; - - case guicom_fixed_option: - case guicom_fixed_option_checkbox: - { - GUI_Interactive *b = (GUI_Interactive*)h; - - click_button_input(target, &gui_session, user_input, b, &result.is_animating); - - { - Key_Event_Data key; - Key_Summary *keys = &user_input->keys; - - void *ptr = (b + 1); - String string; - char activation_key; - - i32 i, count; - - string = gui_read_string(&ptr); - activation_key = *(char*)ptr; - - count = keys->count; - for (i = 0; i < count; ++i){ - key = get_single_key(keys, i); - if (char_to_upper(key.character) == char_to_upper(activation_key)){ - target->active = b->id; - result.is_animating = 1; - break; - } - } - } - }break; - - case guicom_scrollable_slider: - { - GUI_id id = gui_id_scrollbar_slider(); - i32 mx = user_input->mouse.x; - i32 my = user_input->mouse.y; - f32 v = 0; - - if (hit_check(mx, my, gui_session.rect)){ - target->hover = id; - if (user_input->mouse.press_l){ - target->mouse_hot = id; - result.is_animating = 1; - } - } - else if (gui_id_eq(target->hover, id)){ - target->hover = gui_id_zero(); - } - - if (gui_id_eq(target->mouse_hot, id)){ - v = unlerp(gui_session.scroll_top, (f32)my, - gui_session.scroll_bottom); - v = clamp(0.f, v, 1.f); - result.vars.target_y = lerp(0.f, v, result.vars.max_y); - - gui_activate_scrolling(target); - result.is_animating = 1; - } - } - // NOTE(allen): NO BREAK HERE!! - - case guicom_scrollable_invisible: - { - if (user_input->mouse.wheel != 0){ - result.vars.target_y += user_input->mouse.wheel*target->delta; - - result.vars.target_y = - clamp(0.f, result.vars.target_y, result.vars.max_y); - gui_activate_scrolling(target); - result.is_animating = 1; - } - }break; - - case guicom_scrollable_top: - { - GUI_id id = gui_id_scrollbar_top(); - - if (scroll_button_input(target, &gui_session, user_input, id, &result.is_animating)){ - result.vars.target_y -= target->delta * 0.25f; - result.vars.target_y = clamp_bottom(0.f, result.vars.target_y); - } - }break; - - case guicom_scrollable_bottom: - { - GUI_id id = gui_id_scrollbar_bottom(); - - if (scroll_button_input(target, &gui_session, user_input, id, &result.is_animating)){ - result.vars.target_y += target->delta * 0.25f; - result.vars.target_y = clamp_top(0.f, result.vars.max_y); - } - }break; - - case guicom_end_scrollable_section: - { - if (!is_file_scroll){ - f32 new_max_y = gui_session.suggested_max_y; - result.vars.max_y = new_max_y; - } - }break; - } - } - } - - if (!user_input->mouse.l){ - if (!gui_id_is_null(target->mouse_hot)){ - target->mouse_hot = gui_id_zero(); - result.is_animating = 1; - } - } - - { - GUI_Scroll_Vars scroll_vars = result.vars; - b32 is_new_target = 0; - if (scroll_vars.target_x != scroll_vars.prev_target_x) is_new_target = 1; - if (scroll_vars.target_y != scroll_vars.prev_target_y) is_new_target = 1; - - if (view->persistent.models->scroll_rule(scroll_vars.target_x, scroll_vars.target_y, - &scroll_vars.scroll_x, &scroll_vars.scroll_y, - (view->persistent.id) + 1, is_new_target)){ - result.is_animating = 1; - } - - scroll_vars.prev_target_x = scroll_vars.target_x; - scroll_vars.prev_target_y = scroll_vars.target_y; - - result.vars = scroll_vars; - } - } - - return(result); -} - -internal i32 -draw_file_loaded(View *view, i32_Rect rect, b32 is_active, Render_Target *target){ - Models *models = view->persistent.models; - Editing_File *file = view->file_data.file; - Style *style = main_style(models); - i32 line_height = view->font_height; - - i32 max_x = rect.x1 - rect.x0; - i32 max_y = rect.y1 - rect.y0 + line_height; - - Assert(file && !file->is_dummy && buffer_good(&file->state.buffer)); - - b32 tokens_use = 0; - Cpp_Token_Stack token_stack = {}; - if (file){ - tokens_use = file->state.tokens_complete && (file->state.token_stack.count > 0); - token_stack = file->state.token_stack; - } - - Partition *part = &models->mem.part; - - Temp_Memory temp = begin_temp_memory(part); - - partition_align(part, 4); - i32 max = partition_remaining(part) / sizeof(Buffer_Render_Item); - Buffer_Render_Item *items = push_array(part, Buffer_Render_Item, max); - - i16 font_id = models->global_font.font_id; - Render_Font *font = get_font_info(models->font_set, font_id)->font; - float *advance_data = 0; - if (font) advance_data = font->advance_data; - - i32 count; - Full_Cursor render_cursor; - Buffer_Render_Options opts = {}; - - f32 *wraps = view->file_data.line_wrap_y; - f32 scroll_x = view->recent->scroll.scroll_x; - f32 scroll_y = view->recent->scroll.scroll_y; - - { - render_cursor = buffer_get_start_cursor(&file->state.buffer, wraps, scroll_y, - !view->file_data.unwrapped_lines, (f32)max_x, advance_data, (f32)line_height); - - view->recent->scroll_i = render_cursor.pos; - - buffer_get_render_data(&file->state.buffer, items, max, &count, - (f32)rect.x0, (f32)rect.y0, - scroll_x, scroll_y, render_cursor, - !view->file_data.unwrapped_lines, - (f32)max_x, (f32)max_y, - advance_data, (f32)line_height, - opts); - } - - Assert(count > 0); - - i32 cursor_begin, cursor_end; - u32 cursor_color, at_cursor_color; - if (view->file_data.show_temp_highlight){ - cursor_begin = view->file_data.temp_highlight.pos; - cursor_end = view->file_data.temp_highlight_end_pos; - cursor_color = style->main.highlight_color; - at_cursor_color = style->main.at_highlight_color; - } - else{ - cursor_begin = view->recent->cursor.pos; - cursor_end = cursor_begin + 1; - cursor_color = style->main.cursor_color; - at_cursor_color = style->main.at_cursor_color; - } - - i32 token_i = 0; - u32 main_color = style->main.default_color; - u32 special_color = style->main.special_character_color; - if (tokens_use){ - Cpp_Get_Token_Result result = cpp_get_token(&token_stack, items->index); - main_color = *style_get_color(style, token_stack.tokens[result.token_index]); - token_i = result.token_index + 1; - } - - u32 mark_color = style->main.mark_color; - Buffer_Render_Item *item = items; - i32 prev_ind = -1; - u32 highlight_color = 0; - u32 highlight_this_color = 0; - - for (i32 i = 0; i < count; ++i, ++item){ - i32 ind = item->index; - highlight_this_color = 0; - if (tokens_use && ind != prev_ind){ - Cpp_Token current_token = token_stack.tokens[token_i-1]; - - if (token_i < token_stack.count){ - if (ind >= token_stack.tokens[token_i].start){ - main_color = - *style_get_color(style, token_stack.tokens[token_i]); - current_token = token_stack.tokens[token_i]; - ++token_i; - } - else if (ind >= current_token.start + current_token.size){ - main_color = 0xFFFFFFFF; - } - } - - if (current_token.type == CPP_TOKEN_JUNK && - i >= current_token.start && i < current_token.start + current_token.size){ - highlight_color = style->main.highlight_junk_color; - } - else{ - highlight_color = 0; - } - } - - u32 char_color = main_color; - if (item->flags & BRFlag_Special_Character) char_color = special_color; - - f32_Rect char_rect = f32R(item->x0, item->y0, item->x1, item->y1); - if (view->file_data.show_whitespace && highlight_color == 0 && - char_is_whitespace((char)item->glyphid)){ - highlight_this_color = style->main.highlight_white_color; - } - else{ - highlight_this_color = highlight_color; - } - - if (cursor_begin <= ind && ind < cursor_end && (ind != prev_ind || cursor_begin < ind)){ - if (is_active){ - draw_rectangle(target, char_rect, cursor_color); - char_color = at_cursor_color; - } - else{ - if (!view->file_data.show_temp_highlight){ - draw_rectangle_outline(target, char_rect, cursor_color); - } - } - } - else if (highlight_this_color){ - draw_rectangle(target, char_rect, highlight_this_color); - } - - u32 fade_color = 0xFFFF00FF; - f32 fade_amount = 0.f; - - if (file->state.paste_effect.tick_down > 0 && - file->state.paste_effect.start <= ind && - ind < file->state.paste_effect.end){ - fade_color = file->state.paste_effect.color; - fade_amount = (f32)(file->state.paste_effect.tick_down) / file->state.paste_effect.tick_max; - } - - char_color = color_blend(char_color, fade_amount, fade_color); - - if (ind == view->recent->mark && prev_ind != ind){ - draw_rectangle_outline(target, char_rect, mark_color); - } - if (item->glyphid != 0){ - font_draw_glyph(target, font_id, (u8)item->glyphid, - item->x0, item->y0, char_color); - } - prev_ind = ind; - } - - end_temp_memory(temp); - - return(0); -} - -internal void -draw_text_field(Render_Target *target, View *view, i32_Rect rect, String p, String t){ - Models *models = view->persistent.models; - Style *style = main_style(models); - - u32 back_color = style->main.margin_color; - u32 text1_color = style->main.default_color; - u32 text2_color = style->main.file_info_style.pop1_color; - - i32 x = rect.x0; - i32 y = rect.y0 + 2; - - i16 font_id = models->global_font.font_id; - - if (target){ - draw_rectangle(target, rect, back_color); - x = CEIL32(draw_string(target, font_id, p, x, y, text2_color)); - draw_string(target, font_id, t, x, y, text1_color); - } -} - -internal void -draw_text_with_cursor(Render_Target *target, View *view, i32_Rect rect, String s, i32 pos){ - Models *models = view->persistent.models; - Style *style = main_style(models); - - u32 back_color = style->main.margin_color; - u32 text_color = style->main.default_color; - u32 cursor_color = style->main.cursor_color; - u32 at_cursor_color = style->main.at_cursor_color; - - f32 x = (f32)rect.x0; - i32 y = rect.y0 + 2; - - i16 font_id = models->global_font.font_id; - - if (target){ - draw_rectangle(target, rect, back_color); - - if (pos >= 0 && pos < s.size){ - String part1, part2, part3; - i32_Rect cursor_rect; - Render_Font *font = get_font_info(models->font_set, font_id)->font; - - part1 = substr(s, 0, pos); - part2 = substr(s, pos, 1); - part3 = substr(s, pos+1, s.size-pos-1); - - - x = draw_string(target, font_id, part1, FLOOR32(x), y, text_color); - - cursor_rect.x0 = FLOOR32(x); - cursor_rect.x1 = FLOOR32(x) + CEIL32(font->advance_data[s.str[pos]]); - cursor_rect.y0 = y; - cursor_rect.y1 = y + view->font_height; - draw_rectangle(target, cursor_rect, cursor_color); - x = draw_string(target, font_id, part2, FLOOR32(x), y, at_cursor_color); - - draw_string(target, font_id, part3, FLOOR32(x), y, text_color); - } - else{ - draw_string(target, font_id, s, FLOOR32(x), y, text_color); - } - } -} - -internal void -draw_file_bar(Render_Target *target, View *view, Editing_File *file, i32_Rect rect){ - File_Bar bar; - Models *models = view->persistent.models; - Style_Font *font = &models->global_font; - Style *style = main_style(models); - Interactive_Style bar_style = style->main.file_info_style; - - u32 back_color = bar_style.bar_color; - u32 base_color = bar_style.base_color; - u32 pop1_color = bar_style.pop1_color; - u32 pop2_color = bar_style.pop2_color; - - bar.rect = rect; - - if (target){ - bar.font_id = font->font_id; - bar.pos_x = (f32)bar.rect.x0; - bar.pos_y = (f32)bar.rect.y0; - bar.text_shift_y = 2; - bar.text_shift_x = 0; - - draw_rectangle(target, bar.rect, back_color); - if (!file){ - intbar_draw_string(target, &bar, make_lit_string("*NULL*"), base_color); - } - else{ - intbar_draw_string(target, &bar, file->name.live_name, base_color); - intbar_draw_string(target, &bar, make_lit_string(" -"), base_color); - - if (file->is_loading){ - intbar_draw_string(target, &bar, make_lit_string(" loading"), base_color); - } - else{ - char line_number_space[30]; - String line_number = make_fixed_width_string(line_number_space); - append(&line_number, " L#"); - append_int_to_str(view->recent->cursor.line, &line_number); - append(&line_number, " C#"); - append_int_to_str(view->recent->cursor.character, &line_number); - - intbar_draw_string(target, &bar, line_number, base_color); - - intbar_draw_string(target, &bar, make_lit_string(" -"), base_color); - - if (file->settings.dos_write_mode){ - intbar_draw_string(target, &bar, make_lit_string(" dos"), base_color); - } - else{ - intbar_draw_string(target, &bar, make_lit_string(" nix"), base_color); - } - - if (file->state.still_lexing){ - intbar_draw_string(target, &bar, make_lit_string(" parsing"), pop1_color); - } - - if (!file->settings.unimportant){ - switch (buffer_get_sync(file)){ - case SYNC_BEHIND_OS: - { - persist String out_of_sync = make_lit_string(" !"); - intbar_draw_string(target, &bar, out_of_sync, pop2_color); - }break; - - case SYNC_UNSAVED: - { - persist String out_of_sync = make_lit_string(" *"); - intbar_draw_string(target, &bar, out_of_sync, pop2_color); - }break; - } - } - } - } - } -} - -u32 -get_margin_color(i32 active_level, Style *style){ - u32 margin = 0xFFFFFFFF; - - switch (active_level){ - default: - margin = style->main.margin_color; - break; - - case 1: case 2: - margin = style->main.margin_hover_color; - break; - - case 3: case 4: - margin = style->main.margin_active_color; - break; - } - - return(margin); -} - -internal void -draw_color_button(GUI_Target *gui_target, Render_Target *target, View *view, - i32_Rect rect, GUI_id id, u32 fore, u32 back, String text){ - Models *models = view->persistent.models; - - i32 active_level = gui_active_level(gui_target, id); - i16 font_id = models->global_font.font_id; - - if (active_level > 0){ - Swap(u32, back, fore); - } - - draw_rectangle(target, rect, back); - draw_string(target, font_id, text, rect.x0, rect.y0 + 1, fore); -} - -internal void -draw_font_button(GUI_Target *gui_target, Render_Target *target, View *view, - i32_Rect rect, GUI_id id, i16 font_id, String text){ - Models *models = view->persistent.models; - Style *style = main_style(models); - - i32 active_level = gui_active_level(gui_target, id); - - u32 margin = get_margin_color(active_level, style); - u32 back = style->main.back_color; - u32 text_color = style->main.default_color; - - draw_rectangle(target, rect, back); - draw_rectangle_outline(target, rect, margin); - draw_string(target, font_id, text, rect.x0, rect.y0 + 1, text_color); -} - -internal void -draw_fat_option_block(GUI_Target *gui_target, Render_Target *target, View *view, i32_Rect rect, GUI_id id, - String text, String pop, i8 checkbox = -1){ - Models *models = view->persistent.models; - Style *style = main_style(models); - - i32 active_level = gui_active_level(gui_target, id); - i16 font_id = models->global_font.font_id; - - i32_Rect inner = get_inner_rect(rect, 3); - - u32 margin = get_margin_color(active_level, style); - u32 back = style->main.back_color; - u32 text_color = style->main.default_color; - u32 pop_color = style->main.special_character_color; - - i32 h = view->font_height; - i32 x = inner.x0 + 3; - i32 y = inner.y0 + h/2 - 1; - - draw_rectangle(target, inner, back); - draw_margin(target, rect, inner, margin); - - if (checkbox != -1){ - u32 checkbox_color = style->main.margin_active_color; - i32_Rect checkbox_rect = get_inner_rect(inner, (inner.y1 - inner.y0 - h)/2); - checkbox_rect.x1 = checkbox_rect.x0 + (checkbox_rect.y1 - checkbox_rect.y0); - - if (checkbox == 0){ - draw_rectangle_outline(target, checkbox_rect, checkbox_color); - } - else{ - draw_rectangle(target, checkbox_rect, checkbox_color); - } - - x = checkbox_rect.x1 + 3; - } - - x = CEIL32(draw_string(target, font_id, text, x, y, text_color)); - draw_string(target, font_id, pop, x, y, pop_color); -} - -internal void -draw_button(GUI_Target *gui_target, Render_Target *target, View *view, i32_Rect rect, GUI_id id, String text){ - Models *models = view->persistent.models; - Style *style = main_style(models); - - i32 active_level = gui_active_level(gui_target, id); - i16 font_id = models->global_font.font_id; - - i32_Rect inner = get_inner_rect(rect, 3); - - u32 margin = style->main.default_color; - u32 back = get_margin_color(active_level, style); - u32 text_color = style->main.default_color; - - i32 h = view->font_height; - i32 y = inner.y0 + h/2 - 1; - - i32 w = (i32)font_string_width(target, font_id, text); - i32 x = (inner.x1 + inner.x0 - w)/2; - - draw_rectangle(target, inner, back); - draw_rectangle_outline(target, inner, margin); - - draw_string(target, font_id, text, x, y, text_color); -} - -internal void -draw_style_preview(GUI_Target *gui_target, Render_Target *target, View *view, i32_Rect rect, GUI_id id, Style *style){ - Models *models = view->persistent.models; - - i32 active_level = gui_active_level(gui_target, id); - i16 font_id = models->global_font.font_id; - Font_Info *info = get_font_info(models->font_set, font_id); - - i32_Rect inner = get_inner_rect(rect, 3); - - u32 margin_color = get_margin_color(active_level, style); - u32 back = style->main.back_color; - u32 text_color = style->main.default_color; - u32 keyword_color = style->main.keyword_color; - u32 int_constant_color = style->main.int_constant_color; - u32 comment_color = style->main.comment_color; - - draw_margin(target, rect, inner, margin_color); - draw_rectangle(target, inner, back); - - i32 y = inner.y0; - i32 x = inner.x0; - x = CEIL32(draw_string(target, font_id, style->name.str, x, y, text_color)); - i32 font_x = (i32)(inner.x1 - font_string_width(target, font_id, info->name.str)); - if (font_x > x + 10){ - draw_string(target, font_id, info->name.str, font_x, y, text_color); - } - - x = inner.x0; - y += info->height; - x = CEIL32(draw_string(target, font_id, "if", x, y, keyword_color)); - x = CEIL32(draw_string(target, font_id, "(x < ", x, y, text_color)); - x = CEIL32(draw_string(target, font_id, "0", x, y, int_constant_color)); - x = CEIL32(draw_string(target, font_id, ") { x = ", x, y, text_color)); - x = CEIL32(draw_string(target, font_id, "0", x, y, int_constant_color)); - x = CEIL32(draw_string(target, font_id, "; } ", x, y, text_color)); - x = CEIL32(draw_string(target, font_id, "// comment", x, y, comment_color)); - - x = inner.x0; - y += info->height; - draw_string(target, font_id, "[] () {}; * -> +-/ <>= ! && || % ^", x, y, text_color); -} - -internal i32 -do_render_file_view(System_Functions *system, View *view, - View *active, i32_Rect rect, b32 is_active, - Render_Target *target, Input_Summary *user_input){ - - Editing_File *file = view->file_data.file; - i32 result = 0; - - GUI_Session gui_session = {0}; - GUI_Header *h; - GUI_Target *gui_target = &view->gui_target; - GUI_Interpret_Result interpret_result = {0}; - - f32 v; - - if (gui_target->push.pos > 0){ - gui_session_init(&gui_session, gui_target, rect, view->font_height); - - v = view_get_scroll_y(view); - - i32_Rect clip_rect = rect; - draw_push_clip(target, clip_rect); - - for (h = (GUI_Header*)gui_target->push.base; - h->type; - h = NextHeader(h)){ - interpret_result = gui_interpret(gui_target, &gui_session, h, - *view->current_scroll, - view->scroll_region); - - if (interpret_result.has_info){ - if (gui_session.clip_y > clip_rect.y0){ - clip_rect.y0 = gui_session.clip_y; - draw_change_clip(target, clip_rect); - } - - switch (h->type){ - case guicom_top_bar: - { - draw_file_bar(target, view, file, gui_session.rect); - }break; - - case guicom_file: - { - if (view->reinit_scrolling){ - view_reinit_scrolling(view); - } - if (file && file_is_ready(file)){ - result = draw_file_loaded(view, gui_session.rect, is_active, target); - } - }break; - - case guicom_text_field: - { - void *ptr = (h+1); - String p = gui_read_string(&ptr); - String t = gui_read_string(&ptr); - draw_text_field(target, view, gui_session.rect, p, t); - }break; - - case guicom_text_with_cursor: - { - void *ptr = (h+1); - String s = gui_read_string(&ptr); - i32 pos = gui_read_integer(&ptr); - - draw_text_with_cursor(target, view, gui_session.rect, s, pos); - }break; - - case guicom_color_button: - { - GUI_Interactive *b = (GUI_Interactive*)h; - void *ptr = (b + 1); - u32 fore = (u32)gui_read_integer(&ptr); - u32 back = (u32)gui_read_integer(&ptr); - String t = gui_read_string(&ptr); - - draw_color_button(gui_target, target, view, gui_session.rect, b->id, fore, back, t); - }break; - - case guicom_font_button: - { - GUI_Interactive *b = (GUI_Interactive*)h; - void *ptr = (b + 1); - i16 font_id = (i16)gui_read_integer(&ptr); - String t = gui_read_string(&ptr); - - draw_font_button(gui_target, target, view, gui_session.rect, b->id, font_id, t); - }break; - - case guicom_file_option: - { - GUI_Interactive *b = (GUI_Interactive*)h; - void *ptr = (b + 1); - b32 folder = gui_read_integer(&ptr); - String f = gui_read_string(&ptr); - String m = gui_read_string(&ptr); - - if (folder){ - append(&f, system->slash); - } - - draw_fat_option_block(gui_target, target, view, gui_session.rect, b->id, f, m); - }break; - - case guicom_style_preview: - { - GUI_Interactive *b = (GUI_Interactive*)h; - i32 style_index = *(i32*)(b + 1); - Style *style = get_style(view->persistent.models, style_index); - - draw_style_preview(gui_target, target, view, gui_session.rect, b->id, style); - }break; - - case guicom_fixed_option: - case guicom_fixed_option_checkbox: - { - GUI_Interactive *b = (GUI_Interactive*)h; - void *ptr = (b + 1); - String f = gui_read_string(&ptr); - String m = {0}; - i8 status = -1; - if (h->type == guicom_fixed_option_checkbox){ - gui_read_byte(&ptr); - status = (i8)gui_read_byte(&ptr); - } - - draw_fat_option_block(gui_target, target, view, gui_session.rect, b->id, f, m, status); - }break; - - case guicom_button: - { - GUI_Interactive *b = (GUI_Interactive*)h; - void *ptr = (b + 1); - String t = gui_read_string(&ptr); - - draw_button(gui_target, target, view, gui_session.rect, b->id, t); - }break; - - case guicom_scrollable_bar: - { - Models *models = view->persistent.models; - Style *style = main_style(models); - - u32 back; - u32 outline; - - i32_Rect bar = gui_session.rect; - - back = style->main.back_color; - if (is_active){ - outline = style->main.margin_active_color; - } - else{ - outline = style->main.margin_color; - } - - draw_rectangle(target, bar, back); - draw_rectangle_outline(target, bar, outline); - }break; - - case guicom_scrollable_top: - case guicom_scrollable_slider: - case guicom_scrollable_bottom: - { - GUI_id id; - Models *models = view->persistent.models; - Style *style = main_style(models); - i32_Rect box = gui_session.rect; - - i32 active_level; - - u32 back; - u32 outline; - - switch (h->type){ - case guicom_scrollable_top: id = gui_id_scrollbar_top(); break; - case guicom_scrollable_bottom: id = gui_id_scrollbar_bottom(); break; - default: id = gui_id_scrollbar_slider(); break; - } - - active_level = gui_active_level(gui_target, id); - - switch (active_level){ - case 0: back = style->main.back_color; break; - case 1: back = style->main.margin_hover_color; break; - default: back = style->main.margin_active_color; break; - } - - if (is_active){ - outline = style->main.margin_active_color; - } - else{ - outline = style->main.margin_color; - } - - draw_rectangle(target, box, back); - draw_margin(target, box, get_inner_rect(box, 2), outline); - }break; - - case guicom_begin_scrollable_section: - clip_rect.x1 = Min(gui_session.scroll_region.x1, clip_rect.x1); - draw_push_clip(target, clip_rect); - break; - - case guicom_end_scrollable_section: - clip_rect = draw_pop_clip(target); - break; - } - } - } - - draw_pop_clip(target); - } - - return(result); -} - -inline void -file_view_free_buffers(View *view){ - General_Memory *general = &view->persistent.models->mem.general; - if (view->file_data.line_wrap_y){ - general_memory_free(general, view->file_data.line_wrap_y); - view->file_data.line_wrap_y = 0; - } - general_memory_free(general, view->gui_mem); - view->gui_mem = 0; -} - -struct Search_Range{ - Buffer_Type *buffer; - i32 start, size; -}; - -struct Search_Set{ - Search_Range *ranges; - i32 count, max; -}; - -struct Search_Iter{ - String word; - i32 pos; - i32 i; -}; - -struct Search_Match{ - Buffer_Type *buffer; - i32 start, end; - b32 found_match; -}; - -internal void -search_iter_init(General_Memory *general, Search_Iter *iter, i32 size){ - i32 str_max; - - if (iter->word.str == 0){ - str_max = size*2; - iter->word.str = (char*)general_memory_allocate(general, str_max, 0); - iter->word.memory_size = str_max; - } - else if (iter->word.memory_size < size){ - str_max = size*2; - iter->word.str = (char*)general_memory_reallocate_nocopy(general, iter->word.str, str_max, 0); - iter->word.memory_size = str_max; - } - - iter->i = 0; - iter->pos = 0; -} - -internal void -search_set_init(General_Memory *general, Search_Set *set, i32 set_count){ - i32 max; - - if (set->ranges == 0){ - max = set_count*2; - set->ranges = (Search_Range*)general_memory_allocate(general, sizeof(Search_Range)*max, 0); - set->max = max; - } - else if (set->max < set_count){ - max = set_count*2; - set->ranges = (Search_Range*)general_memory_reallocate_nocopy( - general, set->ranges, sizeof(Search_Range)*max, 0); - set->max = max; - } - - set->count = set_count; -} - -internal void -search_hits_table_alloc(General_Memory *general, Table *hits, i32 table_size){ - void *mem; - i32 mem_size; - - mem_size = table_required_mem_size(table_size, sizeof(Offset_String)); - if (hits->hash_array == 0){ - mem = general_memory_allocate(general, mem_size, 0); - } - else{ - mem = general_memory_reallocate_nocopy(general, hits->hash_array, mem_size, 0); - } - table_init_memory(hits, mem, table_size, sizeof(Offset_String)); -} - -internal void -search_hits_init(General_Memory *general, Table *hits, String_Space *str, i32 table_size, i32 str_size){ - void *mem; - i32 mem_size; - - if (hits->hash_array == 0){ - search_hits_table_alloc(general, hits, table_size); - } - else if (hits->max < table_size){ - mem_size = table_required_mem_size(table_size, sizeof(Offset_String)); - mem = general_memory_reallocate_nocopy(general, hits->hash_array, mem_size, 0); - table_init_memory(hits, mem, table_size, sizeof(Offset_String)); - } - - if (str->space == 0){ - str->space = (char*)general_memory_allocate(general, str_size, 0); - str->max = str_size; - } - else if (str->max < str_size){ - str->space = (char*)general_memory_reallocate_nocopy(general, str->space, str_size, 0); - str->max = str_size; - } - - str->pos = str->new_pos = 0; - table_clear(hits); -} - -internal b32 -search_hit_add(General_Memory *general, Table *hits, String_Space *space, char *str, i32 len){ - b32 result; - i32 new_size; - Offset_String ostring; - Table new_hits; - - Assert(len != 0); - - ostring = strspace_append(space, str, len); - if (ostring.size == 0){ - new_size = Max(space->max*2, space->max + len); - space->space = (char*)general_memory_reallocate(general, space->space, space->new_pos, new_size, 0); - ostring = strspace_append(space, str, len); - } - - Assert(ostring.size != 0); - - if (table_at_capacity(hits)){ - search_hits_table_alloc(general, &new_hits, hits->max*2); - table_clear(&new_hits); - table_rehash(hits, &new_hits, space->space, tbl_offset_string_hash, tbl_offset_string_compare); - general_memory_free(general, hits->hash_array); - *hits = new_hits; - } - - if (!table_add(hits, &ostring, space->space, tbl_offset_string_hash, tbl_offset_string_compare)){ - result = 1; - strspace_keep_prev(space); - } - else{ - result = 0; - strspace_discard_prev(space); - } - - return(result); -} - -internal Search_Match -search_next_match(Partition *part, Search_Set *set, Search_Iter *iter_){ - Search_Match result = {}; - Search_Iter iter = *iter_; - Search_Range *range; - Temp_Memory temp; - char *spare; - i32 start_pos, end_pos, count; - - temp = begin_temp_memory(part); - spare = push_array(part, char, iter.word.size); - - count = set->count; - for (; iter.i < count;){ - range = set->ranges + iter.i; - - end_pos = range->start + range->size; - - if (iter.pos + iter.word.size < end_pos){ - start_pos = Max(iter.pos, range->start); - result.start = buffer_find_string(range->buffer, start_pos, end_pos, iter.word.str, iter.word.size, spare); - - if (result.start < end_pos){ - iter.pos = result.start + 1; - if (result.start == 0 || !char_is_alpha_numeric(buffer_get_char(range->buffer, result.start - 1))){ - result.end = buffer_seek_word_right_assume_on_word(range->buffer, result.start); - if (result.end < end_pos){ - result.found_match = 1; - result.buffer = range->buffer; - iter.pos = result.end; - break; - } - } - } - else{ - ++iter.i, iter.pos = 0; - } - } - else{ - ++iter.i, iter.pos = 0; - } - } - end_temp_memory(temp); - - *iter_ = iter; - - return(result); -} - -inline void -view_change_size(General_Memory *general, View *view){ - if (view->file_data.file){ - view_measure_wraps(general, view); - view->recent->cursor = view_compute_cursor_from_pos(view, view->recent->cursor.pos); - } -} - -struct Live_Views{ - View *views; - View free_sentinel; - i32 count, max; -}; - -internal View_And_ID -live_set_alloc_view(Live_Views *live_set, Panel *panel, Models *models){ - View_And_ID result = {}; - - Assert(live_set->count < live_set->max); - ++live_set->count; - - result.view = live_set->free_sentinel.next; - result.id = (i32)(result.view - live_set->views); - Assert(result.id == result.view->persistent.id); - - dll_remove(result.view); - memset(get_view_body(result.view), 0, get_view_size()); - - result.view->in_use = 1; - panel->view = result.view; - result.view->panel = panel; - - result.view->persistent.models = models; - result.view->scrub_max = 1; - result.view->current_scroll = &result.view->recent->scroll; - - init_query_set(&result.view->query_set); - - { - i32 gui_mem_size = Kbytes(32); - void *gui_mem = general_memory_allocate(&models->mem.general, gui_mem_size + 8, 0); - result.view->gui_mem = gui_mem; - gui_mem = advance_to_alignment(gui_mem); - result.view->gui_target.push = make_part(gui_mem, gui_mem_size); - } - - return(result); -} - -inline void -live_set_free_view(System_Functions *system, Live_Views *live_set, View *view){ - Assert(live_set->count > 0); - --live_set->count; - file_view_free_buffers(view); - dll_insert(&live_set->free_sentinel, view); - view->in_use = 0; -} - -// BOTTOM - +/* +* Mr. 4th Dimention - Allen Webster +* +* 19.08.2015 +* +* File editing view for 4coder +* +*/ + +// TOP + +internal i32 +get_or_add_map_index(Models *models, i32 mapid){ + i32 result; + i32 user_map_count = models->user_map_count; + i32 *map_id_table = models->map_id_table; + for (result = 0; result < user_map_count; ++result){ + if (map_id_table[result] == mapid) break; + if (map_id_table[result] == -1){ + map_id_table[result] = mapid; + break; + } + } + return result; +} + +internal i32 +get_map_index(Models *models, i32 mapid){ + i32 result; + i32 user_map_count = models->user_map_count; + i32 *map_id_table = models->map_id_table; + for (result = 0; result < user_map_count; ++result){ + if (map_id_table[result] == mapid) break; + if (map_id_table[result] == 0){ + result = user_map_count; + break; + } + } + return result; +} + +internal Command_Map* +get_map_base(Models *models, i32 mapid, b32 add){ + Command_Map *map = 0; + if (mapid < mapid_global){ + if (add){ + mapid = get_or_add_map_index(models, mapid); + } + else{ + mapid = get_map_index(models, mapid); + } + if (mapid < models->user_map_count){ + map = models->user_maps + mapid; + } + } + else if (mapid == mapid_global) map = &models->map_top; + else if (mapid == mapid_file) map = &models->map_file; + return(map); +} + +internal Command_Map* +get_or_add_map(Models *models, i32 mapid){ + Command_Map *map = get_map_base(models, mapid, 1); + return(map); +} + +internal Command_Map* +get_map(Models *models, i32 mapid){ + Command_Map *map = get_map_base(models, mapid, 0); + return(map); +} + +internal void +map_set_count(Models *models, i32 mapid, i32 count){ + Command_Map *map = get_or_add_map(models, mapid); + Assert(map->commands == 0); + map->count = count; + if (map->max < count){ + map->max = count; + } +} + +internal i32 +map_get_count(Models *models, i32 mapid){ + Command_Map *map = get_or_add_map(models, mapid); + i32 count = map->count; + Assert(map->commands == 0); + return(count); +} + +internal i32 +map_get_max_count(Models *models, i32 mapid){ + Command_Map *map = get_or_add_map(models, mapid); + i32 count = map->max; + return(count); +} + +enum Interactive_Action{ + IAct_Open, + IAct_Save_As, + IAct_New, + IAct_Switch, + IAct_Kill, + IAct_Sure_To_Kill, + IAct_Sure_To_Close +}; + +enum Interactive_Interaction{ + IInt_Sys_File_List, + IInt_Live_File_List, + IInt_Sure_To_Kill, + IInt_Sure_To_Close +}; + +struct View_Mode{ + i32 rewrite; +}; +inline View_Mode +view_mode_zero(){ + View_Mode mode={0}; + return(mode); +} + +enum View_Widget_Type{ + FWIDG_NONE, + FWIDG_TIMELINES, + // never below this + FWIDG_TYPE_COUNT +}; + +struct View_Widget{ + View_Widget_Type type; + i32 height_; + struct{ + b32 undo_line; + b32 history_line; + } timeline; +}; + +enum View_UI{ + VUI_None, + VUI_Theme, + VUI_Interactive, + VUI_Menu, + VUI_Config, +}; + +enum Color_View_Mode{ + CV_Mode_Library, + CV_Mode_Font, + CV_Mode_Adjusting +}; + +struct File_Viewing_Data{ + Editing_File *file; + + Full_Cursor temp_highlight; + i32 temp_highlight_end_pos; + b32 show_temp_highlight; + + b32 unwrapped_lines; + b32 show_whitespace; + b32 file_locked; + + i32 line_count, line_max; + f32 *line_wrap_y; +}; +inline File_Viewing_Data +file_viewing_data_zero(){ + File_Viewing_Data data={0}; + return(data); +} + +struct Recent_File_Data{ + u64 unique_buffer_id; + GUI_Scroll_Vars scroll; + + Full_Cursor cursor; + i32 mark; + f32 preferred_x; + i32 scroll_i; +}; +inline Recent_File_Data +recent_file_data_zero(){ + Recent_File_Data data = {0}; + return(data); +} + +struct Scroll_Context{ + Editing_File *file; + GUI_id scroll; + View_UI mode; +}; +inline b32 +context_eq(Scroll_Context a, Scroll_Context b){ + b32 result = 0; + if (gui_id_eq(a.scroll, b.scroll)){ + if (a.file == b.file){ + if (a.mode == b.mode){ + result = 1; + } + } + } + return(result); +} + +struct View_Persistent{ + i32 id; + + View_Routine_Function *view_routine; + Coroutine *coroutine; + Event_Message message_passing_slot; + + // TODO(allen): eliminate this models pointer: explicitly parameterize. + Models *models; +}; + +struct View{ + View_Persistent persistent; + + View *next, *prev; + Panel *panel; + b32 in_use; + Command_Map *map; + + File_Viewing_Data file_data; + i32 prev_cursor_pos; + Scroll_Context prev_context; + + i32_Rect file_region_prev; + i32_Rect file_region; + + i32_Rect scroll_region; + Recent_File_Data recent[16]; + + GUI_Scroll_Vars *current_scroll; + + View_UI showing_ui; + GUI_Target gui_target; + void *gui_mem; + GUI_Scroll_Vars gui_scroll; + i32 list_i; + + b32 hide_scrollbar; + + // interactive stuff + Interactive_Interaction interaction; + Interactive_Action action; + + char dest_[256]; + String dest; + + // theme stuff + View *hot_file_view; + u32 *palette; + i32 palette_size; + Color_View_Mode color_mode; + Super_Color color; + b32 p4c_only; + Style_Library inspecting_styles; + b8 import_export_check[64]; + i32 import_file_id; + i32 current_color_editing; + i32 color_cursor; + + i32 font_advance; + i32 font_height; + + View_Mode mode, next_mode; + View_Widget widget; + Query_Set query_set; + i32 scrub_max; + + b32 reinit_scrolling; +}; +inline void* +get_view_body(View *view){ + char *result = (char*)view; + result += sizeof(View_Persistent); + return(result); +} +inline i32 +get_view_size(){ + return(sizeof(View) - sizeof(View_Persistent)); +} + +struct View_And_ID{ + View *view; + i32 id; +}; + +#define LockLevel_Open 0 +#define LockLevel_NoWrite 1 +#define LockLevel_NoUpdate 2 + +inline i32 +view_lock_level(View *view){ + i32 result = LockLevel_Open; + File_Viewing_Data *data = &view->file_data; + if (view->showing_ui != VUI_None) result = LockLevel_NoUpdate; + else if (data->file_locked || (data->file && data->file->settings.read_only)) result = LockLevel_NoWrite; + return(result); +} + +inline f32 +view_file_width(View *view){ + i32_Rect file_rect = view->file_region; + f32 result = (f32)(file_rect.x1 - file_rect.x0); + return (result); +} + +inline f32 +view_file_height(View *view){ + i32_Rect file_rect = view->file_region; + f32 result = (f32)(file_rect.y1 - file_rect.y0); + return (result); +} + +struct View_Iter{ + View *view; + + Editing_File *file; + View *skip; + Panel *used_panels; + Panel *panel; +}; + +internal View_Iter +file_view_iter_next(View_Iter iter){ + View *view; + + for (iter.panel = iter.panel->next; iter.panel != iter.used_panels; iter.panel = iter.panel->next){ + view = iter.panel->view; + if (view != iter.skip && (view->file_data.file == iter.file || iter.file == 0)){ + iter.view = view; + break; + } + } + + return(iter); +} + +internal View_Iter +file_view_iter_init(Editing_Layout *layout, Editing_File *file, View *skip){ + View_Iter result; + result.used_panels = &layout->used_sentinel; + result.panel = result.used_panels; + result.file = file; + result.skip = skip; + + result = file_view_iter_next(result); + + return(result); +} + +internal b32 +file_view_iter_good(View_Iter iter){ + b32 result = (iter.panel != iter.used_panels); + return(result); +} + +inline b32 +starts_new_line(u8 character){ + return (character == '\n'); +} + +inline void +file_init_strings(Editing_File *file){ + file->name.source_path = make_fixed_width_string(file->name.source_path_); + file->name.live_name = make_fixed_width_string(file->name.live_name_); + file->name.extension = make_fixed_width_string(file->name.extension_); +} + +inline void +file_set_name(Working_Set *working_set, Editing_File *file, char *filename){ + String f, ext; + + Assert(file->name.live_name.str != 0); + + f = make_string_slowly(filename); + copy_checked(&file->name.source_path, f); + + file->name.live_name.size = 0; + get_front_of_directory(&file->name.live_name, f); + + if (file->name.source_path.size == file->name.live_name.size){ + file->name.extension.size = 0; + } + else{ + ext = file_extension(f); + copy(&file->name.extension, ext); + } + + { + File_Node *node, *used_nodes; + Editing_File *file_ptr; + i32 file_x, original_len; + b32 hit_conflict; + + used_nodes = &working_set->used_sentinel; + original_len = file->name.live_name.size; + hit_conflict = 1; + file_x = 0; + while (hit_conflict){ + hit_conflict = 0; + for (dll_items(node, used_nodes)){ + file_ptr = (Editing_File*)node; + if (file_ptr != file && file_is_ready(file_ptr)){ + if (match(file->name.live_name, file_ptr->name.live_name)){ + ++file_x; + hit_conflict = 1; + break; + } + } + } + + if (hit_conflict){ + file->name.live_name.size = original_len; + append(&file->name.live_name, " <"); + append_int_to_str(file_x, &file->name.live_name); + append(&file->name.live_name, ">"); + } + } + } +} + +inline void +file_synchronize_times(System_Functions *system, Editing_File *file, char *filename){ + u64 stamp = system->file_time_stamp(filename); + if (stamp > 0){ + file->state.last_4ed_write_time = stamp; + file->state.last_4ed_edit_time = stamp; + file->state.last_sys_write_time = stamp; + } + file->state.sync = buffer_get_sync(file); +} + +internal b32 +file_save(System_Functions *system, Mem_Options *mem, Editing_File *file, char *filename){ + b32 result = 0; + + i32 max, size; + b32 dos_write_mode = file->settings.dos_write_mode; + char *data; + Buffer_Type *buffer = &file->state.buffer; + + if (dos_write_mode){ + max = buffer_size(buffer) + buffer->line_count + 1; + } + else{ + max = buffer_size(buffer); + } + + Temp_Memory temp = begin_temp_memory(&mem->part); + char empty = 0; + if (max == 0){ + data = ∅ + } + else{ + data = (char*)push_array(&mem->part, char, max); + } + Assert(data); + + if (dos_write_mode){ + size = buffer_convert_out(buffer, data, max); + } + else{ + size = max; + buffer_stringify(buffer, 0, size, data); + } + + result = system->file_save(filename, data, size); + + file_synchronize_times(system, file, filename); + + end_temp_memory(temp); + + return(result); +} + +inline b32 +file_save_and_set_names(System_Functions *system, Mem_Options *mem, + Working_Set *working_set, Editing_File *file, + char *filename){ + b32 result = 0; + result = file_save(system, mem, file, filename); + if (result){ + file_set_name(working_set, file, filename); + } + return result; +} + +enum File_Bubble_Type{ + BUBBLE_BUFFER = 1, + BUBBLE_STARTS, + BUBBLE_WIDTHS, + BUBBLE_WRAPS, + BUBBLE_TOKENS, + BUBBLE_UNDO_STRING, + BUBBLE_UNDO, + BUBBLE_UNDO_CHILDREN, + // + FILE_BUBBLE_TYPE_END, +}; + +#define GROW_FAILED 0 +#define GROW_NOT_NEEDED 1 +#define GROW_SUCCESS 2 + +internal i32 +file_grow_starts_widths_as_needed(General_Memory *general, Buffer_Type *buffer, i32 additional_lines){ + b32 result = GROW_NOT_NEEDED; + i32 max = buffer->line_max; + i32 count = buffer->line_count; + i32 target_lines = count + additional_lines; + Assert(max == buffer->widths_max); + + if (target_lines > max || max == 0){ + max = LargeRoundUp(target_lines + max, Kbytes(1)); + + f32 *new_widths = (f32*)general_memory_reallocate( + general, buffer->line_widths, + sizeof(f32)*count, sizeof(f32)*max, BUBBLE_WIDTHS); + + i32 *new_lines = (i32*)general_memory_reallocate( + general, buffer->line_starts, + sizeof(i32)*count, sizeof(i32)*max, BUBBLE_STARTS); + + if (new_lines){ + buffer->line_starts = new_lines; + buffer->line_max = max; + } + if (new_widths){ + buffer->line_widths = new_widths; + buffer->widths_max = max; + } + if (new_lines && new_widths){ + result = GROW_SUCCESS; + } + else{ + result = GROW_FAILED; + } + } + + return(result); +} + +internal void +file_measure_starts_widths(System_Functions *system, General_Memory *general, + Buffer_Type *buffer, float *advance_data){ + if (!buffer->line_starts){ + i32 max = buffer->line_max = Kbytes(1); + buffer->line_starts = (i32*)general_memory_allocate(general, max*sizeof(i32), BUBBLE_STARTS); + TentativeAssert(buffer->line_starts); + // TODO(allen): when unable to allocate? + } + if (!buffer->line_widths){ + i32 max = buffer->widths_max = Kbytes(1); + buffer->line_widths = (f32*)general_memory_allocate(general, max*sizeof(f32), BUBBLE_WIDTHS); + TentativeAssert(buffer->line_starts); + // TODO(allen): when unable to allocate? + } + + Buffer_Measure_Starts state = {}; + while (buffer_measure_starts_widths(&state, buffer, advance_data)){ + i32 count = state.count; + i32 max = buffer->line_max; + max = ((max + 1) << 1); + + { + i32 *new_lines = (i32*)general_memory_reallocate( + general, buffer->line_starts, sizeof(i32)*count, sizeof(i32)*max, BUBBLE_STARTS); + + // TODO(allen): when unable to grow? + TentativeAssert(new_lines); + buffer->line_starts = new_lines; + buffer->line_max = max; + } + + { + f32 *new_lines = (f32*) + general_memory_reallocate(general, buffer->line_widths, + sizeof(f32)*count, sizeof(f32)*max, BUBBLE_WIDTHS); + + // TODO(allen): when unable to grow? + TentativeAssert(new_lines); + buffer->line_widths = new_lines; + buffer->widths_max = max; + } + + } + buffer->line_count = state.count; + buffer->widths_count = state.count; +} + +struct Opaque_Font_Advance{ + void *data; + int stride; +}; + +inline Opaque_Font_Advance +get_opaque_font_advance(Render_Font *font){ + Opaque_Font_Advance result; + result.data = (char*)font->chardata + OffsetOfPtr(font->chardata, xadvance); + result.stride = sizeof(*font->chardata); + return result; +} + +inline i32 +view_wrapped_line_span(f32 line_width, f32 max_width){ + i32 line_count = CEIL32(line_width / max_width); + if (line_count == 0) line_count = 1; + return line_count; +} + +internal i32 +view_compute_lowest_line(View *view){ + i32 lowest_line = 0; + i32 last_line = view->file_data.line_count - 1; + if (last_line > 0){ + if (view->file_data.unwrapped_lines){ + lowest_line = last_line; + } + else{ + f32 wrap_y = view->file_data.line_wrap_y[last_line]; + lowest_line = FLOOR32(wrap_y / view->font_height); + f32 max_width = view_file_width(view); + + Editing_File *file = view->file_data.file; + Assert(!file->is_dummy); + f32 width = file->state.buffer.line_widths[last_line]; + i32 line_span = view_wrapped_line_span(width, max_width); + lowest_line += line_span - 1; + } + } + return lowest_line; +} + +internal void +view_measure_wraps(General_Memory *general, View *view){ + Buffer_Type *buffer; + + buffer = &view->file_data.file->state.buffer; + i32 line_count = buffer->line_count; + + if (view->file_data.line_max < line_count){ + i32 max = view->file_data.line_max = LargeRoundUp(line_count, Kbytes(1)); + if (view->file_data.line_wrap_y){ + view->file_data.line_wrap_y = (f32*) + general_memory_reallocate_nocopy(general, view->file_data.line_wrap_y, sizeof(f32)*max, BUBBLE_WRAPS); + } + else{ + view->file_data.line_wrap_y = (f32*) + general_memory_allocate(general, sizeof(f32)*max, BUBBLE_WRAPS); + } + } + + f32 line_height = (f32)view->font_height; + f32 max_width = view_file_width(view); + buffer_measure_wrap_y(buffer, view->file_data.line_wrap_y, line_height, max_width); + + view->file_data.line_count = line_count; +} + +internal void +file_create_from_string(System_Functions *system, Models *models, + Editing_File *file, char *filename, String val, b8 read_only = 0){ + + Font_Set *font_set = models->font_set; + Working_Set *working_set = &models->working_set; + General_Memory *general = &models->mem.general; + Partition *part = &models->mem.part; + Buffer_Init_Type init; + i32 page_size, scratch_size, init_success; + + file->state = editing_file_state_zero(); + + init = buffer_begin_init(&file->state.buffer, val.str, val.size); + for (; buffer_init_need_more(&init); ){ + page_size = buffer_init_page_size(&init); + page_size = LargeRoundUp(page_size, Kbytes(4)); + if (page_size < Kbytes(4)) page_size = Kbytes(4); + void *data = general_memory_allocate(general, page_size, BUBBLE_BUFFER); + buffer_init_provide_page(&init, data, page_size); + } + + scratch_size = partition_remaining(part); + Assert(scratch_size > 0); + init_success = buffer_end_init(&init, part->base + part->pos, scratch_size); + AllowLocal(init_success); + Assert(init_success); + + if (buffer_size(&file->state.buffer) < val.size){ + file->settings.dos_write_mode = 1; + } + + file_init_strings(file); + file_set_name(working_set, file, (char*)filename); + + file->state.font_id = models->global_font.font_id; + + file_synchronize_times(system, file, filename); + + Render_Font *font = get_font_info(font_set, file->state.font_id)->font; + float *advance_data = 0; + if (font) advance_data = font->advance_data; + file_measure_starts_widths(system, general, &file->state.buffer, advance_data); + + file->settings.read_only = read_only; + if (!read_only){ + // TODO(allen): Redo undo system (if you don't mind the pun) + i32 request_size = Kbytes(64); + file->state.undo.undo.max = request_size; + file->state.undo.undo.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); + file->state.undo.undo.edit_max = request_size / sizeof(Edit_Step); + file->state.undo.undo.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO); + + file->state.undo.redo.max = request_size; + file->state.undo.redo.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); + file->state.undo.redo.edit_max = request_size / sizeof(Edit_Step); + file->state.undo.redo.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO); + + file->state.undo.history.max = request_size; + file->state.undo.history.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); + file->state.undo.history.edit_max = request_size / sizeof(Edit_Step); + file->state.undo.history.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO); + + file->state.undo.children.max = request_size; + file->state.undo.children.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING); + file->state.undo.children.edit_max = request_size / sizeof(Buffer_Edit); + file->state.undo.children.edits = (Buffer_Edit*)general_memory_allocate(general, request_size, BUBBLE_UNDO); + + file->state.undo.history_block_count = 1; + file->state.undo.history_head_block = 0; + file->state.undo.current_block_normal = 1; + } + + Hook_Function *open_hook = models->hooks[hook_open_file]; + models->buffer_param_indices[models->buffer_param_count++] = file->id.id; + open_hook(&models->app_links); + models->buffer_param_count = 0; + file->settings.is_initialized = 1; +} + +internal b32 +file_create_empty(System_Functions *system, + Models *models, Editing_File *file, char *filename){ + file_create_from_string(system, models, file, filename, string_zero()); + return (1); +} + +internal b32 +file_create_read_only(System_Functions *system, + Models *models, Editing_File *file, char *filename){ + file_create_from_string(system, models, file, filename, string_zero(), 1); + return (1); +} + +internal void +file_close(System_Functions *system, General_Memory *general, Editing_File *file){ + if (file->state.still_lexing){ + system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); + if (file->state.swap_stack.tokens){ + general_memory_free(general, file->state.swap_stack.tokens); + file->state.swap_stack.tokens = 0; + } + } + if (file->state.token_stack.tokens){ + general_memory_free(general, file->state.token_stack.tokens); + } + + Buffer_Type *buffer = &file->state.buffer; + if (buffer->data){ + general_memory_free(general, buffer->data); + general_memory_free(general, buffer->line_starts); + general_memory_free(general, buffer->line_widths); + } + + if (file->state.undo.undo.edits){ + general_memory_free(general, file->state.undo.undo.strings); + general_memory_free(general, file->state.undo.undo.edits); + + general_memory_free(general, file->state.undo.redo.strings); + general_memory_free(general, file->state.undo.redo.edits); + + general_memory_free(general, file->state.undo.history.strings); + general_memory_free(general, file->state.undo.history.edits); + + general_memory_free(general, file->state.undo.children.strings); + general_memory_free(general, file->state.undo.children.edits); + } +} + +struct Shift_Information{ + i32 start, end, amount; +}; + +internal +Job_Callback_Sig(job_full_lex){ + Editing_File *file = (Editing_File*)data[0]; + General_Memory *general = (General_Memory*)data[1]; + + Cpp_File cpp_file; + cpp_file.data = file->state.buffer.data; + cpp_file.size = file->state.buffer.size; + + Cpp_Token_Stack tokens; + tokens.tokens = (Cpp_Token*)memory->data; + tokens.max_count = memory->size / sizeof(Cpp_Token); + tokens.count = 0; + + Cpp_Lex_Data status = {}; + + do{ + for (i32 r = 2048; r > 0 && status.pos < cpp_file.size; --r){ + Cpp_Lex_Data prev_lex = status; + Cpp_Read_Result step_result = cpp_lex_step(cpp_file, &status); + + if (step_result.has_result){ + if (!cpp_push_token_nonalloc(&tokens, step_result.token)){ + status = prev_lex; + system->grow_thread_memory(memory); + tokens.tokens = (Cpp_Token*)memory->data; + tokens.max_count = memory->size / sizeof(Cpp_Token); + } + } + } + + if (status.pos >= cpp_file.size){ + status.complete = 1; + } + else{ + if (system->check_cancel(thread)){ + return; + } + } + } while(!status.complete); + + i32 new_max = LargeRoundUp(tokens.count+1, Kbytes(1)); + + system->acquire_lock(FRAME_LOCK); + { + Assert(file->state.swap_stack.tokens == 0); + file->state.swap_stack.tokens = (Cpp_Token*) + general_memory_allocate(general, new_max*sizeof(Cpp_Token), BUBBLE_TOKENS); + } + system->release_lock(FRAME_LOCK); + + u8 *dest = (u8*)file->state.swap_stack.tokens; + u8 *src = (u8*)tokens.tokens; + + memcpy(dest, src, tokens.count*sizeof(Cpp_Token)); + + system->acquire_lock(FRAME_LOCK); + { + Cpp_Token_Stack *file_stack = &file->state.token_stack; + file_stack->count = tokens.count; + file_stack->max_count = new_max; + if (file_stack->tokens){ + general_memory_free(general, file_stack->tokens); + } + file_stack->tokens = file->state.swap_stack.tokens; + file->state.swap_stack.tokens = 0; + } + system->release_lock(FRAME_LOCK); + + // NOTE(allen): These are outside the locked section because I don't + // think getting these out of order will cause critical bugs, and I + // want to minimize what's done in locked sections. + file->state.tokens_complete = 1; + file->state.still_lexing = 0; +} + + +internal void +file_kill_tokens(System_Functions *system, + General_Memory *general, Editing_File *file){ + file->settings.tokens_exist = 0; + if (file->state.still_lexing){ + system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); + if (file->state.swap_stack.tokens){ + general_memory_free(general, file->state.swap_stack.tokens); + file->state.swap_stack.tokens = 0; + } + } + if (file->state.token_stack.tokens){ + general_memory_free(general, file->state.token_stack.tokens); + } + file->state.tokens_complete = 0; + file->state.token_stack = cpp_token_stack_zero(); +} + +#if BUFFER_EXPERIMENT_SCALPEL <= 0 +internal void +file_first_lex_parallel(System_Functions *system, + General_Memory *general, Editing_File *file){ + file->settings.tokens_exist = 1; + + if (file->is_loading == 0 && file->state.still_lexing == 0){ + Assert(file->state.token_stack.tokens == 0); + + file->state.tokens_complete = 0; + file->state.still_lexing = 1; + + Job_Data job; + job.callback = job_full_lex; + job.data[0] = file; + job.data[1] = general; + file->state.lex_job = system->post_job(BACKGROUND_THREADS, job); + } +} +#endif + +internal void +file_relex_parallel(System_Functions *system, + Mem_Options *mem, Editing_File *file, + i32 start_i, i32 end_i, i32 amount){ + General_Memory *general = &mem->general; + Partition *part = &mem->part; + if (file->state.token_stack.tokens == 0){ + file_first_lex_parallel(system, general, file); + return; + } + + b32 inline_lex = !file->state.still_lexing; + if (inline_lex){ + Cpp_File cpp_file; + cpp_file.data = file->state.buffer.data; + cpp_file.size = file->state.buffer.size; + + Cpp_Token_Stack *stack = &file->state.token_stack; + + Cpp_Relex_State state = + cpp_relex_nonalloc_start(cpp_file, stack, + start_i, end_i, amount, 100); + + Temp_Memory temp = begin_temp_memory(part); + i32 relex_end; + Cpp_Token_Stack relex_space; + relex_space.count = 0; + relex_space.max_count = state.space_request; + relex_space.tokens = push_array(part, Cpp_Token, relex_space.max_count); + if (cpp_relex_nonalloc_main(&state, &relex_space, &relex_end)){ + inline_lex = 0; + } + else{ + i32 delete_amount = relex_end - state.start_token_i; + i32 shift_amount = relex_space.count - delete_amount; + + if (shift_amount != 0){ + int new_count = stack->count + shift_amount; + if (new_count > stack->max_count){ + int new_max = LargeRoundUp(new_count, Kbytes(1)); + stack->tokens = (Cpp_Token*) + general_memory_reallocate(general, stack->tokens, + stack->count*sizeof(Cpp_Token), + new_max*sizeof(Cpp_Token), BUBBLE_TOKENS); + stack->max_count = new_max; + } + + int shift_size = stack->count - relex_end; + if (shift_size > 0){ + Cpp_Token *old_base = stack->tokens + relex_end; + memmove(old_base + shift_amount, old_base, + sizeof(Cpp_Token)*shift_size); + } + + stack->count += shift_amount; + } + + memcpy(state.stack->tokens + state.start_token_i, relex_space.tokens, + sizeof(Cpp_Token)*relex_space.count); + } + + end_temp_memory(temp); + } + + if (!inline_lex){ + Cpp_Token_Stack *stack = &file->state.token_stack; + Cpp_Get_Token_Result get_token_result = cpp_get_token(stack, end_i); + i32 end_token_i = get_token_result.token_index; + + if (end_token_i < 0) end_token_i = 0; + else if (end_i > stack->tokens[end_token_i].start) ++end_token_i; + + cpp_shift_token_starts(stack, end_token_i, amount); + --end_token_i; + if (end_token_i >= 0){ + Cpp_Token *token = stack->tokens + end_token_i; + if (token->start < end_i && token->start + token->size > end_i){ + token->size += amount; + } + } + + file->state.still_lexing = 1; + + Job_Data job; + job.callback = job_full_lex; + job.data[0] = file; + job.data[1] = general; + file->state.lex_job = system->post_job(BACKGROUND_THREADS, job); + } +} + +internal void +undo_stack_grow_string(General_Memory *general, 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 = (u8*) + general_memory_reallocate(general, old_str, old_max, new_max); + stack->strings = new_str; + stack->max = new_max; +} + +internal void +undo_stack_grow_edits(General_Memory *general, 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 = (Edit_Step*) + general_memory_reallocate(general, old_eds, old_max*sizeof(Edit_Step), new_max*sizeof(Edit_Step)); + stack->edits = new_eds; + stack->edit_max = new_max; +} + +internal void +child_stack_grow_string(General_Memory *general, 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 = (u8*) + general_memory_reallocate(general, old_str, old_max, new_max); + stack->strings = new_str; + stack->max = new_max; +} + +internal void +child_stack_grow_edits(General_Memory *general, 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 = (Buffer_Edit*) + general_memory_reallocate(general, old_eds, old_max*sizeof(Buffer_Edit), new_max*sizeof(Buffer_Edit)); + stack->edits = new_eds; + stack->edit_max = new_max; +} + +internal i32 +undo_children_push(General_Memory *general, 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(general, children, edit_count); + + if (children->size + string_size > children->max) + child_stack_grow_string(general, 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; +} + +struct Edit_Spec{ + u8 *str; + Edit_Step step; +}; + +internal Edit_Step* +file_post_undo(General_Memory *general, 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(general, 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.pre_pos = step.pre_pos; + inv_step.post_pos = step.post_pos; + 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; + inv_step.pre_pos = prev.pre_pos; + } + } + } + + 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(general, 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(general, undo); + result = undo->edits + (undo->edit_count++); + *result = inv_step; + } + return result; +} + +inline 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(General_Memory *general, 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(general, 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.pre_pos = step.pre_pos; + inv_step.post_pos = step.post_pos; + inv_step.type = ED_REDO; + + if (redo->edit_count == redo->edit_max) + undo_stack_grow_edits(general, 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(general, redo); + } + redo->edits[redo->edit_count++] = inv_step; + } +} + +inline 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; +} + +inline 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(General_Memory *general, Editing_File *file, + Edit_Step step, b32 do_merge, b32 can_merge){ + Edit_Stack *history = &file->state.undo.history; + Edit_Step *result = 0; + + 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(general, 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.pre_pos = step.pre_pos; + inv_step.post_pos = step.post_pos; + inv_step.can_merge = (b8)can_merge; + inv_step.type = reverse_types[step.type]; + + bool32 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; + inv_step.pre_pos = prev.pre_pos; + } + } + } + + if (did_merge){ + result = history->edits + (history->edit_count-1); + } + else{ + if (history->edit_count == history->edit_max) + undo_stack_grow_edits(general, 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(general, history); + result = history->edits + (history->edit_count++); + *result = inv_step; + } + + return result; +} + +inline Full_Cursor +view_compute_cursor_from_pos(View *view, i32 pos){ + Editing_File *file = view->file_data.file; + Models *models = view->persistent.models; + Render_Font *font = get_font_info(models->font_set, models->global_font.font_id)->font; + + Full_Cursor result = {}; + if (font){ + f32 max_width = view_file_width(view); + result = buffer_cursor_from_pos(&file->state.buffer, pos, view->file_data.line_wrap_y, + max_width, (f32)view->font_height, font->advance_data); + } + return result; +} + +inline Full_Cursor +view_compute_cursor_from_unwrapped_xy(View *view, f32 seek_x, f32 seek_y, b32 round_down = 0){ + Editing_File *file = view->file_data.file; + Models *models = view->persistent.models; + Render_Font *font = get_font_info(models->font_set, models->global_font.font_id)->font; + + Full_Cursor result = {}; + if (font){ + f32 max_width = view_file_width(view); + result = buffer_cursor_from_unwrapped_xy(&file->state.buffer, seek_x, seek_y, + round_down, view->file_data.line_wrap_y, max_width, (f32)view->font_height, font->advance_data); + } + + return result; +} + +internal Full_Cursor +view_compute_cursor_from_wrapped_xy(View *view, f32 seek_x, f32 seek_y, b32 round_down = 0){ + Editing_File *file = view->file_data.file; + Models *models = view->persistent.models; + Render_Font *font = get_font_info(models->font_set, models->global_font.font_id)->font; + + Full_Cursor result = {}; + if (font){ + f32 max_width = view_file_width(view); + result = buffer_cursor_from_wrapped_xy(&file->state.buffer, seek_x, seek_y, + round_down, view->file_data.line_wrap_y, + max_width, (f32)view->font_height, font->advance_data); + } + + return (result); +} + +internal Full_Cursor +view_compute_cursor_from_line_pos(View *view, i32 line, i32 pos){ + Editing_File *file = view->file_data.file; + Models *models = view->persistent.models; + Render_Font *font = get_font_info(models->font_set, models->global_font.font_id)->font; + + Full_Cursor result = {}; + if (font){ + f32 max_width = view_file_width(view); + result = buffer_cursor_from_line_character(&file->state.buffer, line, pos, + view->file_data.line_wrap_y, max_width, (f32)view->font_height, font->advance_data); + } + + return (result); +} + +inline Full_Cursor +view_compute_cursor(View *view, Buffer_Seek seek){ + Full_Cursor result = {}; + + switch(seek.type){ + case buffer_seek_pos: + result = view_compute_cursor_from_pos(view, seek.pos); + break; + + case buffer_seek_wrapped_xy: + result = view_compute_cursor_from_wrapped_xy(view, seek.x, seek.y); + break; + + case buffer_seek_unwrapped_xy: + result = view_compute_cursor_from_unwrapped_xy(view, seek.x, seek.y); + break; + + case buffer_seek_line_char: + result = view_compute_cursor_from_line_pos(view, seek.line, seek.character); + break; + } + + return (result); +} + +inline Full_Cursor +view_compute_cursor_from_xy(View *view, f32 seek_x, f32 seek_y){ + Full_Cursor result; + if (view->file_data.unwrapped_lines) result = view_compute_cursor_from_unwrapped_xy(view, seek_x, seek_y); + else result = view_compute_cursor_from_wrapped_xy(view, seek_x, seek_y); + return result; +} + +inline void +view_set_temp_highlight(View *view, i32 pos, i32 end_pos){ + view->file_data.temp_highlight = view_compute_cursor_from_pos(view, pos); + view->file_data.temp_highlight_end_pos = end_pos; + view->file_data.show_temp_highlight = 1; +} + +inline i32 +view_get_cursor_pos(View *view){ + i32 result; + if (view->file_data.show_temp_highlight){ + result = view->file_data.temp_highlight.pos; + } + else{ + result = view->recent->cursor.pos; + } + return result; +} + +inline f32 +view_get_cursor_x(View *view){ + f32 result; + Full_Cursor *cursor; + if (view->file_data.show_temp_highlight){ + cursor = &view->file_data.temp_highlight; + } + else{ + cursor = &view->recent->cursor; + } + if (view->file_data.unwrapped_lines){ + result = cursor->unwrapped_x; + } + else{ + result = cursor->wrapped_x; + } + return result; +} + +inline f32 +view_get_cursor_y(View *view){ + Full_Cursor *cursor; + f32 result; + + if (view->file_data.show_temp_highlight) cursor = &view->file_data.temp_highlight; + else cursor = &view->recent->cursor; + + if (view->file_data.unwrapped_lines) result = cursor->unwrapped_y; + else result = cursor->wrapped_y; + + return result; +} + +#define CursorMaxY_(m,h) ((m) - (h)*3) +#define CursorMinY_(m,h) (-(m) + (h)*2) + +#define CursorMaxY(m,h) (CursorMaxY_(m,h) > 0)?(CursorMaxY_(m,h)):(0) +#define CursorMinY(m,h) (CursorMinY_(m,h) > 0)?(CursorMinY_(m,h)):(0) + +internal void +view_move_cursor_to_view(View *view){ + f32 min_target_y = 0; + i32 line_height = view->font_height; + f32 old_cursor_y = view_get_cursor_y(view); + f32 cursor_y = old_cursor_y; + f32 target_y = view->recent->scroll.target_y; + f32 cursor_max_y = CursorMaxY(view_file_height(view), line_height); + f32 cursor_min_y = CursorMinY(min_target_y, line_height); + + if (cursor_y > target_y + cursor_max_y){ + cursor_y = target_y + cursor_max_y; + } + if (target_y != 0 && cursor_y < target_y + cursor_min_y){ + cursor_y = target_y + cursor_min_y; + } + + if (cursor_y != old_cursor_y){ + if (cursor_y > old_cursor_y){ + cursor_y += line_height; + } + else{ + cursor_y -= line_height; + } + view->recent->cursor = + view_compute_cursor_from_xy(view, view->recent->preferred_x, cursor_y); + } +} + +internal void +view_move_view_to_cursor(View *view, GUI_Scroll_Vars *scroll){ + f32 line_height = (f32)view->font_height; + f32 delta_y = 3.f*line_height; + + f32 max_visible_y = view_file_height(view); + f32 max_x = view_file_width(view); + + f32 cursor_y = view_get_cursor_y(view); + f32 cursor_x = view_get_cursor_x(view); + + GUI_Scroll_Vars scroll_vars = *scroll; + f32 target_y = scroll_vars.target_y; + f32 target_x = scroll_vars.target_x; + + f32 cursor_max_y = CursorMaxY(max_visible_y, line_height); + f32 cursor_min_y = CursorMinY(0, line_height); + + if (cursor_y > target_y + cursor_max_y){ + target_y = cursor_y - cursor_max_y + delta_y; + } + if (cursor_y < target_y + cursor_min_y){ + target_y = cursor_y - delta_y - cursor_min_y; + } + + target_y = clamp(0.f, target_y, scroll_vars.max_y); + + if (cursor_x < target_x){ + target_x = (f32)Max(0, cursor_x - max_x/2); + } + else if (cursor_x >= target_x + max_x){ + target_x = (f32)(cursor_x - max_x/2); + } + + if (target_x != scroll_vars.target_x || target_y != scroll_vars.target_y){ + scroll->target_x = target_x; + scroll->target_y = target_y; + } +} + +inline void +file_view_nullify_file(View *view){ + General_Memory *general = &view->persistent.models->mem.general; + if (view->file_data.line_wrap_y){ + general_memory_free(general, view->file_data.line_wrap_y); + } + view->file_data = file_viewing_data_zero(); +} + +inline f32 +view_compute_max_target_y(i32 lowest_line, i32 line_height, f32 view_height){ + f32 max_target_y = ((lowest_line+.5f)*line_height) - view_height*.5f; + max_target_y = clamp_bottom(0.f, max_target_y); + return(max_target_y); +} + +internal f32 +view_compute_max_target_y(View *view){ + i32 lowest_line = view_compute_lowest_line(view); + i32 line_height = view->font_height; + f32 view_height = view_file_height(view); + f32 max_target_y = view_compute_max_target_y(lowest_line, line_height, view_height); + return(max_target_y); +} + +internal void +view_set_file(View *view, Editing_File *file, Models *models){ + Font_Info *fnt_info; + + // TODO(allen): This belongs somewhere else. + fnt_info = get_font_info(models->font_set, models->global_font.font_id); + view->font_advance = fnt_info->advance; + view->font_height = fnt_info->height; + + file_view_nullify_file(view); + view->file_data.file = file; + + if (file){ + u64 unique_buffer_id = file->unique_buffer_id; + Recent_File_Data *recent = view->recent; + Recent_File_Data temp_recent = {0}; + i32 i = 0; + i32 max = ArrayCount(view->recent)-1; + b32 found_recent_entry = 0; + + view->file_data.unwrapped_lines = file->settings.unwrapped_lines; + + for (; i < max; ++i, ++recent){ + if (recent->unique_buffer_id == unique_buffer_id){ + temp_recent = *recent; + memmove(view->recent+1, view->recent, sizeof(*recent)*i); + view->recent[0] = temp_recent; + found_recent_entry = 1; + break; + } + } + + if (found_recent_entry){ + if (file_is_ready(file)){ + view_measure_wraps(&models->mem.general, view); + view->recent->cursor = view_compute_cursor_from_pos(view, view->recent->cursor.pos); + view->recent->scroll.max_y = view_compute_max_target_y(view); + + view_move_view_to_cursor(view, &view->recent->scroll); + } + } + else{ + i = 15; + recent = view->recent + i; + memmove(view->recent+1, view->recent, sizeof(*recent)*i); + view->recent[0] = recent_file_data_zero(); + + recent = view->recent; + recent->unique_buffer_id = unique_buffer_id; + + if (file_is_ready(file)){ + view_measure_wraps(&models->mem.general, view); + view->recent->cursor = view_compute_cursor_from_pos(view, file->state.cursor_pos); + view->recent->scroll.max_y = view_compute_max_target_y(view); + + view_move_view_to_cursor(view, &view->recent->scroll); + view->reinit_scrolling = 1; + } + } + } +} + +struct Relative_Scrolling{ + f32 scroll_x, scroll_y; + f32 target_x, target_y; +}; + +internal Relative_Scrolling +view_get_relative_scrolling(View *view){ + Relative_Scrolling result; + f32 cursor_y; + cursor_y = view_get_cursor_y(view); + result.scroll_y = cursor_y - view->recent->scroll.scroll_y; + result.target_y = cursor_y - view->recent->scroll.target_y; + return(result); +} + +internal void +view_set_relative_scrolling(View *view, Relative_Scrolling scrolling){ + f32 cursor_y; + cursor_y = view_get_cursor_y(view); + view->recent->scroll.scroll_y = cursor_y - scrolling.scroll_y; + view->recent->scroll.target_y = + clamp_bottom(0.f, cursor_y - scrolling.target_y); +} + +inline void +view_cursor_move(View *view, Full_Cursor cursor){ + view->recent->cursor = cursor; + view->recent->preferred_x = view_get_cursor_x(view); + view->file_data.file->state.cursor_pos = view->recent->cursor.pos; + view->file_data.show_temp_highlight = 0; +} + +inline void +view_cursor_move(View *view, i32 pos){ + Full_Cursor cursor = view_compute_cursor_from_pos(view, pos); + view_cursor_move(view, cursor); +} + +inline void +view_cursor_move(View *view, f32 x, f32 y, b32 round_down = 0){ + Full_Cursor cursor; + if (view->file_data.unwrapped_lines){ + cursor = view_compute_cursor_from_unwrapped_xy(view, x, y, round_down); + } + else{ + cursor = view_compute_cursor_from_wrapped_xy(view, x, y, round_down); + } + view_cursor_move(view, cursor); +} + +inline void +view_cursor_move(View *view, i32 line, i32 pos){ + Full_Cursor cursor = view_compute_cursor_from_line_pos(view, line, pos); + view_cursor_move(view, cursor); +} + +inline void +view_set_widget(View *view, View_Widget_Type type){ + view->widget.type = type; +} + + +inline i32_Rect +view_widget_rect(View *view, i32 font_height){ + Panel *panel = view->panel; + i32_Rect result = panel->inner; + + if (view->file_data.file){ + result.y0 = result.y0 + font_height + 2; + } + + return(result); +} + +enum History_Mode{ + hist_normal, + hist_backward, + hist_forward +}; + +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; + General_Memory *general = &mem->general; + + 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(general, file, step, do_merge, can_merge); + + file_post_undo(general, file, step, do_merge, can_merge); + }break; + + case ED_REVERSE_NORMAL: + { + if (history_mode != hist_forward) + file_post_history(general, 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(general, &file->state.undo.redo); + + if (file->state.undo.redo.size + strings_of_redo > file->state.undo.redo.max) + undo_stack_grow_string(general, &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(general, file, step, do_merge, can_merge); + file_post_redo(general, 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(general, file, step, do_merge, can_merge); + + file_post_undo(general, 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; + } +} + +inline void +file_pre_edit_maintenance(System_Functions *system, + General_Memory *general, + Editing_File *file){ + if (file->state.still_lexing){ + system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); + if (file->state.swap_stack.tokens){ + general_memory_free(general, file->state.swap_stack.tokens); + file->state.swap_stack.tokens = 0; + } + file->state.still_lexing = 0; + } + file->state.last_4ed_edit_time = system->now_time_stamp(); +} + +struct Cursor_Fix_Descriptor{ + b32 is_batch; + union{ + struct{ + Buffer_Edit *batch; + i32 batch_size; + }; + struct{ + i32 start, end; + i32 shift_amount; + }; + }; +}; + +internal void +file_edit_cursor_fix(System_Functions *system, + Partition *part, General_Memory *general, + Editing_File *file, Editing_Layout *layout, + Cursor_Fix_Descriptor desc){ + + Full_Cursor temp_cursor; + Temp_Memory cursor_temp = begin_temp_memory(part); + i32 cursor_max = layout->panel_max_count * 2; + Cursor_With_Index *cursors = push_array(part, Cursor_With_Index, cursor_max); + + f32 y_offset = 0, y_position = 0; + i32 cursor_count = 0; + + View *view; + Panel *panel, *used_panels; + used_panels = &layout->used_sentinel; + + for (dll_items(panel, used_panels)){ + view = panel->view; + if (view->file_data.file == file){ + view_measure_wraps(general, view); + write_cursor_with_index(cursors, &cursor_count, view->recent->cursor.pos); + write_cursor_with_index(cursors, &cursor_count, view->recent->mark - 1); + write_cursor_with_index(cursors, &cursor_count, view->recent->scroll_i - 1); + } + } + + if (cursor_count > 0){ + buffer_sort_cursors(cursors, cursor_count); + if (desc.is_batch){ + buffer_batch_edit_update_cursors(cursors, cursor_count, + desc.batch, desc.batch_size); + } + else{ + buffer_update_cursors(cursors, cursor_count, + desc.start, desc.end, + desc.shift_amount + (desc.end - desc.start)); + } + buffer_unsort_cursors(cursors, cursor_count); + + cursor_count = 0; + for (dll_items(panel, used_panels)){ + view = panel->view; + if (view && view->file_data.file == file){ + view_cursor_move(view, cursors[cursor_count++].pos); + view->recent->preferred_x = view_get_cursor_x(view); + + view->recent->mark = cursors[cursor_count++].pos + 1; + i32 new_scroll_i = cursors[cursor_count++].pos + 1; + if (view->recent->scroll_i != new_scroll_i){ + view->recent->scroll_i = new_scroll_i; + temp_cursor = view_compute_cursor_from_pos(view, view->recent->scroll_i); + y_offset = MOD(view->recent->scroll.scroll_y, view->font_height); + + if (view->file_data.unwrapped_lines){ + y_position = temp_cursor.unwrapped_y + y_offset; + view->recent->scroll.target_y += (y_position - view->recent->scroll.scroll_y); + view->recent->scroll.scroll_y = y_position; + } + else{ + y_position = temp_cursor.wrapped_y + y_offset; + view->recent->scroll.target_y += (y_position - view->recent->scroll.scroll_y); + view->recent->scroll.scroll_y = y_position; + } + } + } + } + } + + end_temp_memory(cursor_temp); +} + +internal void +file_do_single_edit(System_Functions *system, + Models *models, Editing_File *file, + Edit_Spec spec, History_Mode history_mode, b32 use_high_permission = 0){ + if (!use_high_permission && file->settings.read_only) return; + + Mem_Options *mem = &models->mem; + Editing_Layout *layout = &models->layout; + + // NOTE(allen): fixing stuff beforewards???? + file_update_history_before_edit(mem, file, spec.step, spec.str, history_mode); + file_pre_edit_maintenance(system, &mem->general, file); + + // NOTE(allen): actual text replacement + i32 shift_amount = 0; + General_Memory *general = &mem->general; + Partition *part = &mem->part; + + 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 scratch_size = partition_remaining(part); + + Assert(scratch_size > 0); + i32 request_amount = 0; + Assert(end <= buffer_size(&file->state.buffer)); + while (buffer_replace_range(&file->state.buffer, start, end, str, str_len, &shift_amount, + part->base + part->pos, scratch_size, &request_amount)){ + void *new_data = 0; + if (request_amount > 0){ + new_data = general_memory_allocate(general, request_amount, BUBBLE_BUFFER); + } + void *old_data = buffer_edit_provide_memory(&file->state.buffer, new_data, request_amount); + if (old_data) general_memory_free(general, old_data); + } + + Buffer_Type *buffer = &file->state.buffer; + i32 line_start = buffer_get_line_index(&file->state.buffer, start); + i32 line_end = buffer_get_line_index(&file->state.buffer, end); + i32 replaced_line_count = line_end - line_start; + i32 new_line_count = buffer_count_newlines(&file->state.buffer, start, start+str_len); + i32 line_shift = new_line_count - replaced_line_count; + + Render_Font *font = get_font_info(models->font_set, file->state.font_id)->font; + + file_grow_starts_widths_as_needed(general, buffer, line_shift); + buffer_remeasure_starts(buffer, line_start, line_end, line_shift, shift_amount); + buffer_remeasure_widths(buffer, font->advance_data, line_start, line_end, line_shift); + + // NOTE(allen): update the views looking at this file + Panel *panel, *used_panels; + used_panels = &layout->used_sentinel; + + for (dll_items(panel, used_panels)){ + View *view = panel->view; + if (view->file_data.file == file){ + view_measure_wraps(general, view); + } + } + +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + // NOTE(allen): fixing stuff afterwards + if (file->settings.tokens_exist) + file_relex_parallel(system, mem, file, start, end, shift_amount); +#endif + + Cursor_Fix_Descriptor desc = {}; + desc.start = start; + desc.end = end; + desc.shift_amount = shift_amount; + + file_edit_cursor_fix(system, part, general, file, layout, desc); +} + +internal void +file_do_white_batch_edit(System_Functions *system, Models *models, Editing_File *file, + Edit_Spec spec, History_Mode history_mode, b32 use_high_permission = 0){ + if (!use_high_permission && file->settings.read_only) return; + + Mem_Options *mem = &models->mem; + Editing_Layout *layout = &models->layout; + + // NOTE(allen): fixing stuff "beforewards"??? + Assert(spec.str == 0); + file_update_history_before_edit(mem, file, spec.step, 0, history_mode); + file_pre_edit_maintenance(system, &mem->general, file); + + // NOTE(allen): actual text replacement + General_Memory *general = &mem->general; + Partition *part = &mem->part; + + 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); + + i32 scratch_size = partition_remaining(part); + Buffer_Batch_State state = {}; + i32 request_amount; + while (buffer_batch_edit_step(&state, &file->state.buffer, batch, + (char*)str_base, batch_size, part->base + part->pos, + scratch_size, &request_amount)){ + void *new_data = 0; + if (request_amount > 0){ + new_data = general_memory_allocate(general, request_amount, BUBBLE_BUFFER); + } + void *old_data = buffer_edit_provide_memory(&file->state.buffer, new_data, request_amount); + if (old_data) general_memory_free(general, old_data); + } + + // NOTE(allen): meta data + { + Buffer_Measure_Starts state = {}; + Render_Font *font = get_font_info(models->font_set, file->state.font_id)->font; + float *advance_data = 0; + if (font) advance_data = font->advance_data; + buffer_measure_starts_widths(&state, &file->state.buffer, advance_data); + } + + // NOTE(allen): cursor fixing + { + Cursor_Fix_Descriptor desc = {}; + desc.is_batch = 1; + desc.batch = batch; + desc.batch_size = batch_size; + + file_edit_cursor_fix(system, part, general, file, layout, desc); + } + + // NOTE(allen): token fixing + if (file->state.tokens_complete){ + Cpp_Token_Stack tokens = file->state.token_stack; + Cpp_Token *token = tokens.tokens; + Cpp_Token *end_token = tokens.tokens + tokens.count; + Cpp_Token original = {(Cpp_Token_Type)0}; + + Buffer_Edit *edit = batch; + Buffer_Edit *end_edit = batch + batch_size; + + 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)); + 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)); + } + token->size += local_shift; + shift_amount += local_shift; + } + } +} + +inline void +file_replace_range(System_Functions *system, Models *models, Editing_File *file, + i32 start, i32 end, char *str, i32 len, i32 next_cursor, b32 use_high_permission = 0){ + Edit_Spec spec = {}; + spec.step.type = ED_NORMAL; + spec.step.edit.start = start; + spec.step.edit.end = end; + + spec.step.edit.len = len; + spec.step.pre_pos = file->state.cursor_pos; + spec.step.post_pos = next_cursor; + spec.str = (u8*)str; + file_do_single_edit(system, models, file, spec, hist_normal, use_high_permission); +} + +inline void +file_clear(System_Functions *system, Models *models, Editing_File *file, b32 use_high_permission = 0){ + file_replace_range(system, models, file, 0, buffer_size(&file->state.buffer), 0, 0, 0, use_high_permission); +} + +inline void +view_replace_range(System_Functions *system, Models *models, View *view, + i32 start, i32 end, char *str, i32 len, i32 next_cursor){ + file_replace_range(system, models, view->file_data.file, start, end, str, len, next_cursor); +} + +inline void +view_post_paste_effect(View *view, i32 ticks, i32 start, i32 size, u32 color){ + Editing_File *file = view->file_data.file; + + file->state.paste_effect.start = start; + file->state.paste_effect.end = start + size; + file->state.paste_effect.color = color; + file->state.paste_effect.tick_down = ticks; + file->state.paste_effect.tick_max = ticks; +} + +internal Style* +get_style(Models *models, i32 i){ + return (&models->styles.styles[i]); +} + +internal Style* +main_style(Models *models){ + return (get_style(models, 0)); +} + +internal void +view_undo_redo(System_Functions *system, + Models *models, View *view, + Edit_Stack *stack, Edit_Type expected_type){ + Editing_File *file = view->file_data.file; + + if (stack->edit_count > 0){ + Edit_Step step = stack->edits[stack->edit_count-1]; + + Assert(step.type == expected_type); + + Edit_Spec spec = {}; + spec.step = step; + + if (step.child_count == 0){ + spec.step.edit.str_start = 0; + spec.str = stack->strings + step.edit.str_start; + + file_do_single_edit(system, models, file, spec, hist_normal); + + if (expected_type == ED_UNDO) view_cursor_move(view, step.pre_pos); + else view_cursor_move(view, step.post_pos); + view->recent->mark = view->recent->cursor.pos; + + Style *style = main_style(models); + view_post_paste_effect(view, 10, step.edit.start, step.edit.len, + style->main.undo_color); + } + else{ + TentativeAssert(spec.step.special_type == 1); + file_do_white_batch_edit(system, models, view->file_data.file, spec, hist_normal); + } + } +} + +inline void +view_undo(System_Functions *system, Models *models, View *view){ + view_undo_redo(system, models, view, &view->file_data.file->state.undo.undo, ED_UNDO); +} + +inline void +view_redo(System_Functions *system, Models *models, View *view){ + view_undo_redo(system, models, view, &view->file_data.file->state.undo.redo, ED_REDO); +} + +inline u8* +write_data(u8 *ptr, void *x, i32 size){ + memcpy(ptr, x, size); + return (ptr + size); +} + +#define UseFileHistoryDump 0 + +#if UseFileHistoryDump +internal void +file_dump_history(System_Functions *system, Mem_Options *mem, Editing_File *file, char *filename){ + if (!file->state.undo.undo.edits) return; + + i32 size = 0; + + size += sizeof(i32); + size += file->state.undo.undo.edit_count*sizeof(Edit_Step); + size += sizeof(i32); + size += file->state.undo.redo.edit_count*sizeof(Edit_Step); + size += sizeof(i32); + size += file->state.undo.history.edit_count*sizeof(Edit_Step); + size += sizeof(i32); + size += file->state.undo.children.edit_count*sizeof(Buffer_Edit); + + size += sizeof(i32); + size += file->state.undo.undo.size; + size += sizeof(i32); + size += file->state.undo.redo.size; + size += sizeof(i32); + size += file->state.undo.history.size; + size += sizeof(i32); + size += file->state.undo.children.size; + + Partition *part = &mem->part; + i32 remaining = partition_remaining(part); + if (size < remaining){ + u8 *data, *curs; + data = (u8*)part->base + part->pos; + curs = data; + curs = write_data(curs, &file->state.undo.undo.edit_count, 4); + curs = write_data(curs, &file->state.undo.redo.edit_count, 4); + curs = write_data(curs, &file->state.undo.history.edit_count, 4); + curs = write_data(curs, &file->state.undo.children.edit_count, 4); + curs = write_data(curs, &file->state.undo.undo.size, 4); + curs = write_data(curs, &file->state.undo.redo.size, 4); + curs = write_data(curs, &file->state.undo.history.size, 4); + curs = write_data(curs, &file->state.undo.children.size, 4); + + curs = write_data(curs, file->state.undo.undo.edits, sizeof(Edit_Step)*file->state.undo.undo.edit_count); + curs = write_data(curs, file->state.undo.redo.edits, sizeof(Edit_Step)*file->state.undo.redo.edit_count); + curs = write_data(curs, file->state.undo.history.edits, sizeof(Edit_Step)*file->state.undo.history.edit_count); + curs = write_data(curs, file->state.undo.children.edits, sizeof(Buffer_Edit)*file->state.undo.children.edit_count); + + curs = write_data(curs, file->state.undo.undo.strings, file->state.undo.undo.size); + curs = write_data(curs, file->state.undo.redo.strings, file->state.undo.redo.size); + curs = write_data(curs, file->state.undo.history.strings, file->state.undo.history.size); + curs = write_data(curs, file->state.undo.children.strings, file->state.undo.children.size); + + Assert((i32)(curs - data) == size); + system->save_file(filename, data, size); + } +} +#endif + +internal void +view_history_step(System_Functions *system, Models *models, View *view, History_Mode history_mode){ + Assert(history_mode != hist_normal); + + Editing_File *file = view->file_data.file; + + b32 do_history_step = 0; + Edit_Step step = {}; + if (history_mode == hist_backward){ + if (file->state.undo.edit_history_cursor > 0){ + do_history_step = 1; + step = file->state.undo.history.edits[--file->state.undo.edit_history_cursor]; + } + } + else{ + if (file->state.undo.edit_history_cursor < file->state.undo.history.edit_count){ + Assert(((file->state.undo.history.edit_count - file->state.undo.edit_history_cursor) & 1) == 0); + step = file->state.undo.history.edits[--file->state.undo.history.edit_count]; + file->state.undo.history.size -= step.edit.len; + ++file->state.undo.edit_history_cursor; + do_history_step = 1; + } + } + + if (do_history_step){ + Edit_Spec spec; + spec.step = step; + + if (spec.step.child_count == 0){ + spec.step.edit.str_start = 0; + spec.str = file->state.undo.history.strings + step.edit.str_start; + + file_do_single_edit(system, models, file, spec, history_mode); + + switch (spec.step.type){ + case ED_NORMAL: + case ED_REDO: + view_cursor_move(view, step.post_pos); + break; + + case ED_REVERSE_NORMAL: + case ED_UNDO: + view_cursor_move(view, step.pre_pos); + break; + } + view->recent->mark = view->recent->cursor.pos; + } + else{ + TentativeAssert(spec.step.special_type == 1); + file_do_white_batch_edit(system, models, view->file_data.file, spec, history_mode); + } + } +} + +// TODO(allen): write these as streamed operations +internal i32 +view_find_end_of_line(View *view, i32 pos){ +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + Editing_File *file = view->file_data.file; + char *data = file->state.buffer.data; + while (pos < file->state.buffer.size && data[pos] != '\n') ++pos; + if (pos > file->state.buffer.size) pos = file->state.buffer.size; +#endif + return pos; +} + +internal i32 +view_find_beginning_of_line(View *view, i32 pos){ +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + Editing_File *file = view->file_data.file; + char *data = file->state.buffer.data; + if (pos > 0){ + --pos; + while (pos > 0 && data[pos] != '\n') --pos; + if (pos != 0) ++pos; + } +#endif + return pos; +} + +internal i32 +view_find_beginning_of_next_line(View *view, i32 pos){ +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + Editing_File *file = view->file_data.file; + char *data = file->state.buffer.data; + while (pos < file->state.buffer.size && + !starts_new_line(data[pos])){ + ++pos; + } + if (pos < file->state.buffer.size){ + ++pos; + } +#endif + return pos; +} + +internal String* +working_set_next_clipboard_string(General_Memory *general, Working_Set *working, i32 str_size){ + String *result = 0; + i32 clipboard_current = working->clipboard_current; + if (working->clipboard_size == 0){ + clipboard_current = 0; + working->clipboard_size = 1; + } + else{ + ++clipboard_current; + if (clipboard_current >= working->clipboard_max_size){ + clipboard_current = 0; + } + else if (working->clipboard_size <= clipboard_current){ + working->clipboard_size = clipboard_current+1; + } + } + result = &working->clipboards[clipboard_current]; + working->clipboard_current = clipboard_current; + working->clipboard_rolling = clipboard_current; + char *new_str; + if (result->str){ + new_str = (char*)general_memory_reallocate(general, result->str, result->size, str_size); + } + else{ + new_str = (char*)general_memory_allocate(general, str_size+1); + } + // TODO(allen): What if new_str == 0? + *result = make_string(new_str, 0, str_size); + return result; +} + +internal String* +working_set_clipboard_head(Working_Set *working){ + String *result = 0; + if (working->clipboard_size > 0){ + i32 clipboard_index = working->clipboard_current; + working->clipboard_rolling = clipboard_index; + result = &working->clipboards[clipboard_index]; + } + return result; +} + +internal String* +working_set_clipboard_roll_down(Working_Set *working){ + String *result = 0; + if (working->clipboard_size > 0){ + i32 clipboard_index = working->clipboard_rolling; + --clipboard_index; + if (clipboard_index < 0){ + clipboard_index = working->clipboard_size-1; + } + working->clipboard_rolling = clipboard_index; + result = &working->clipboards[clipboard_index]; + } + return result; +} + +internal void +clipboard_copy(System_Functions *system, General_Memory *general, Working_Set *working, Range range, Editing_File *file){ + i32 size = range.end - range.start; + String *dest = working_set_next_clipboard_string(general, working, size); + buffer_stringify(&file->state.buffer, range.start, range.end, dest->str); + dest->size = size; + system->post_clipboard(*dest); +} + +internal Edit_Spec +file_compute_whitespace_edit(Mem_Options *mem, Editing_File *file, i32 cursor_pos, + Buffer_Edit *edits, char *str_base, i32 str_size, + Buffer_Edit *inverse_array, char *inv_str, i32 inv_max, + i32 edit_count){ + General_Memory *general = &mem->general; + + 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)){ + Assert(0); + } + + i32 first_child = + undo_children_push(general, &file->state.undo.children, + edits, edit_count, (u8*)(str_base), str_size); + i32 inverse_first_child = + undo_children_push(general, &file->state.undo.children, + inverse_array, edit_count, (u8*)(inv_str), inv_str_pos); + + Edit_Spec spec = {}; + spec.step.type = ED_NORMAL; + spec.step.first_child = first_child; + spec.step.inverse_first_child = inverse_first_child; + spec.step.special_type = 1; + spec.step.child_count = edit_count; + spec.step.inverse_child_count = edit_count; + spec.step.pre_pos = cursor_pos; + spec.step.post_pos = cursor_pos; + + return spec; +} + +internal void +view_clean_whitespace(System_Functions *system, Models *models, View *view){ + Mem_Options *mem = &models->mem; + Editing_File *file = view->file_data.file; + + Partition *part = &mem->part; + i32 line_count = file->state.buffer.line_count; + i32 edit_max = line_count * 2; + i32 edit_count = 0; + + Assert(file && !file->is_dummy); + + Temp_Memory temp = begin_temp_memory(part); + Buffer_Edit *edits = push_array(part, Buffer_Edit, edit_max); + + char *str_base = (char*)part->base + part->pos; + i32 str_size = 0; + for (i32 line_i = 0; line_i < line_count; ++line_i){ + i32 start = file->state.buffer.line_starts[line_i]; + Hard_Start_Result hard_start = + buffer_find_hard_start(&file->state.buffer, start, 4); + + if (hard_start.all_whitespace) hard_start.indent_pos = 0; + + if ((hard_start.all_whitespace && hard_start.char_pos > start) || !hard_start.all_space){ + Buffer_Edit new_edit; + new_edit.str_start = str_size; + str_size += hard_start.indent_pos; + char *str = push_array(part, char, hard_start.indent_pos); + for (i32 j = 0; j < hard_start.indent_pos; ++j) str[j] = ' '; + new_edit.len = hard_start.indent_pos; + new_edit.start = start; + new_edit.end = hard_start.char_pos; + edits[edit_count++] = new_edit; + } + Assert(edit_count <= edit_max); + } + + if (edit_count > 0){ + Assert(buffer_batch_debug_sort_check(edits, edit_count)); + + // NOTE(allen): computing edit spec, doing batch edit + Buffer_Edit *inverse_array = push_array(part, Buffer_Edit, edit_count); + Assert(inverse_array); + + char *inv_str = (char*)part->base + part->pos; + Edit_Spec spec = + file_compute_whitespace_edit(mem, file, view->recent->cursor.pos, edits, str_base, str_size, + inverse_array, inv_str, part->max - part->pos, edit_count); + + file_do_white_batch_edit(system, models, view->file_data.file, spec, hist_normal); + } + + end_temp_memory(temp); +} + +struct Indent_Options{ + b32 empty_blank_lines; + b32 use_tabs; + i32 tab_width; +}; + +struct Make_Batch_Result{ + char *str_base; + i32 str_size; + + Buffer_Edit *edits; + i32 edit_max; + i32 edit_count; +}; + +internal Cpp_Token* +get_first_token_at_line(Buffer *buffer, Cpp_Token_Stack tokens, i32 line){ + Cpp_Token *result = 0; + i32 start_pos = 0; + Cpp_Get_Token_Result get_token = {0}; + + start_pos = buffer->line_starts[line]; + get_token = cpp_get_token(&tokens, start_pos); + if (get_token.in_whitespace) get_token.token_index += 1; + result = tokens.tokens + get_token.token_index; + + return(result); +} + +internal Cpp_Token* +seek_matching_token_backwards(Cpp_Token_Stack tokens, Cpp_Token *token, + Cpp_Token_Type open_type, Cpp_Token_Type close_type){ + int nesting_level = 0; + if (token <= tokens.tokens){ + token = tokens.tokens; + } + else{ + for (; token > tokens.tokens; --token){ + if (!(token->flags & CPP_TFLAG_PP_BODY)){ + if (token->type == close_type){ + ++nesting_level; + } + else if (token->type == open_type){ + if (nesting_level == 0){ + break; + } + else{ + --nesting_level; + } + } + } + } + } + return(token); +} + +struct Indent_Parse_State{ + i32 current_indent; + i32 previous_line_indent; + i32 paren_nesting; + i32 paren_anchor_indent[16]; +}; + +internal i32 +compute_this_indent(Buffer *buffer, Indent_Parse_State indent, + Cpp_Token T, Cpp_Token prev_token, i32 line_i, i32 tab_width){ + + i32 previous_indent = indent.previous_line_indent; + i32 this_indent = 0; + + i32 this_line_start = buffer->line_starts[line_i]; + i32 next_line_start = 0; + + if (line_i+1 < buffer->line_count){ + next_line_start = buffer->line_starts[line_i+1]; + } + else{ + next_line_start = buffer_size(buffer); + } + + if ((prev_token.type == CPP_TOKEN_COMMENT || + prev_token.type == CPP_TOKEN_STRING_CONSTANT) && + prev_token.start <= this_line_start && + prev_token.start + prev_token.size > this_line_start){ + this_indent = previous_indent; + } + else{ + this_indent = indent.current_indent; + if (T.start < next_line_start){ + if (T.flags & CPP_TFLAG_PP_DIRECTIVE){ + this_indent = 0; + } + else{ + switch (T.type){ + case CPP_TOKEN_BRACKET_CLOSE: this_indent -= tab_width; break; + case CPP_TOKEN_BRACE_CLOSE: this_indent -= tab_width; break; + case CPP_TOKEN_BRACE_OPEN: break; + + default: + if (indent.current_indent > 0){ + if (!(prev_token.flags & CPP_TFLAG_PP_BODY || + prev_token.flags & CPP_TFLAG_PP_DIRECTIVE)){ + switch (prev_token.type){ + case CPP_TOKEN_BRACKET_OPEN: + case CPP_TOKEN_BRACE_OPEN: case CPP_TOKEN_BRACE_CLOSE: + case CPP_TOKEN_SEMICOLON: case CPP_TOKEN_COLON: + case CPP_TOKEN_COMMA: case CPP_TOKEN_COMMENT: break; + default: this_indent += tab_width; + } + } + } + } + } + } + if (this_indent < 0) this_indent = 0; + } + + if (indent.paren_nesting > 0){ + if (prev_token.type != CPP_TOKEN_PARENTHESE_OPEN){ + i32 level = indent.paren_nesting-1; + if (level >= ArrayCount(indent.paren_anchor_indent)){ + level = ArrayCount(indent.paren_anchor_indent)-1; + } + this_indent = indent.paren_anchor_indent[level]; + } + } + return(this_indent); +} + +internal i32* +get_line_indentation_marks(Partition *part, Buffer *buffer, Cpp_Token_Stack tokens, + i32 line_start, i32 line_end, i32 tab_width){ + + i32 indent_mark_count = line_end - line_start; + i32 *indent_marks = push_array(part, i32, indent_mark_count); + + Indent_Parse_State indent = {0}; + Cpp_Token *token = get_first_token_at_line(buffer, tokens, line_start); + + if (token != tokens.tokens){ + --token; + for (; token > tokens.tokens; --token){ + if (!(token->flags & CPP_TFLAG_PP_BODY)){ + switch(token->type){ + case CPP_TOKEN_BRACE_OPEN: + case CPP_TOKEN_BRACE_CLOSE: + goto out_of_loop; + } + } + } + out_of_loop:; + } + + // TODO(allen): This can maybe be it's own function now, so that we + // can do the decls in the order we want and avoid the extra binary search. + i32 found_safe_start_position = 0; + do{ + i32 line = buffer_get_line_index(buffer, token->start); + i32 start = buffer->line_starts[line]; + Hard_Start_Result hard_start = buffer_find_hard_start(buffer, start, tab_width); + + indent.current_indent = hard_start.indent_pos; + + Cpp_Token *start_token = get_first_token_at_line(buffer, tokens, line); + Cpp_Token *brace_token = token; + + if (start_token->type == CPP_TOKEN_PARENTHESE_OPEN){ + if (start_token == tokens.tokens){ + found_safe_start_position = 1; + } + else{ + token = start_token-1; + } + } + else{ + int close = 0; + + for (token = brace_token; token >= start_token; --token){ + switch(token->type){ + case CPP_TOKEN_PARENTHESE_CLOSE: + case CPP_TOKEN_BRACKET_CLOSE: + case CPP_TOKEN_BRACE_CLOSE: + close = token->type; + goto out_of_loop2; + } + } + out_of_loop2:; + + switch (close){ + case 0: token = start_token; found_safe_start_position = 1; break; + + case CPP_TOKEN_PARENTHESE_CLOSE: + token = seek_matching_token_backwards(tokens, token-1, + CPP_TOKEN_PARENTHESE_OPEN, + CPP_TOKEN_PARENTHESE_CLOSE); + break; + + case CPP_TOKEN_BRACKET_CLOSE: + token = seek_matching_token_backwards(tokens, token-1, + CPP_TOKEN_BRACKET_OPEN, + CPP_TOKEN_BRACKET_CLOSE); + break; + + case CPP_TOKEN_BRACE_CLOSE: + token = seek_matching_token_backwards(tokens, token-1, + CPP_TOKEN_BRACE_OPEN, + CPP_TOKEN_BRACE_CLOSE); + break; + } + } + } while(found_safe_start_position == 0); + + // NOTE(allen): Shift the array so that line_i can just operate in + // it's natural value range. + indent_marks -= line_start; + + i32 line_i = buffer_get_line_index(buffer, token->start); + + if (line_i > line_start){ + line_i = line_start; + } + + i32 next_line_start = buffer->line_starts[line_i+1]; + switch (token->type){ + case CPP_TOKEN_BRACKET_OPEN: indent.current_indent += tab_width; break; + case CPP_TOKEN_BRACE_OPEN: indent.current_indent += tab_width; break; + case CPP_TOKEN_PARENTHESE_OPEN: indent.current_indent += tab_width; break; + } + + indent.previous_line_indent = indent.current_indent; + Cpp_Token T; + Cpp_Token prev_token = *token; + ++token; + + for (; line_i < line_end; ++token){ + if (token < tokens.tokens + tokens.count){ + T = *token; + } + else{ + T.type = CPP_TOKEN_EOF; + T.start = buffer_size(buffer); + T.flags = 0; + } + + for (; T.start >= next_line_start && line_i < line_end;){ + if (line_i+1 < buffer->line_count){ + next_line_start = buffer->line_starts[line_i+1]; + } + else{ + next_line_start = buffer_size(buffer); + } + + // TODO(allen): Since this is called in one place we can probably go back + // to directly passing in next_line_start and this_line_start. + i32 this_indent = compute_this_indent(buffer, indent, T, prev_token, line_i, tab_width); + + // NOTE(allen): Rebase the paren anchor if the first token + // after an open paren is on the next line. + if (indent.paren_nesting > 0){ + if (prev_token.type == CPP_TOKEN_PARENTHESE_OPEN){ + i32 level = indent.paren_nesting-1; + if (level >= ArrayCount(indent.paren_anchor_indent)){ + level = ArrayCount(indent.paren_anchor_indent)-1; + } + indent.paren_anchor_indent[level] = this_indent; + } + } + + if (line_i >= line_start){ + indent_marks[line_i] = this_indent; + } + ++line_i; + + indent.previous_line_indent = this_indent; + } + + switch (T.type){ + case CPP_TOKEN_BRACKET_OPEN: indent.current_indent += 4; break; + case CPP_TOKEN_BRACKET_CLOSE: indent.current_indent -= 4; break; + case CPP_TOKEN_BRACE_OPEN: indent.current_indent += 4; break; + case CPP_TOKEN_BRACE_CLOSE: indent.current_indent -= 4; break; + + case CPP_TOKEN_PARENTHESE_OPEN: + if (!(T.flags & CPP_TFLAG_PP_BODY)){ + if (indent.paren_nesting < ArrayCount(indent.paren_anchor_indent)){ + i32 line = buffer_get_line_index(buffer, T.start); + i32 start = buffer->line_starts[line]; + i32 char_pos = T.start - start; + + Hard_Start_Result hard_start = buffer_find_hard_start( + buffer, start, tab_width); + + i32 line_pos = hard_start.char_pos - start; + + indent.paren_anchor_indent[indent.paren_nesting] = + char_pos - line_pos + indent.previous_line_indent + 1; + } + ++indent.paren_nesting; + } + break; + + case CPP_TOKEN_PARENTHESE_CLOSE: + if (!(T.flags & CPP_TFLAG_PP_BODY)){ + --indent.paren_nesting; + } + break; + } + prev_token = T; + } + + // NOTE(allen): Unshift the indent_marks array so that the return value + // is the exact starting point of the array that was actually allocated. + indent_marks += line_start; + + return(indent_marks); +} + +internal Make_Batch_Result +make_batch_from_indent_marks(Partition *part, Buffer *buffer, i32 line_start, i32 line_end, + i32 *indent_marks, Indent_Options opts){ + + Make_Batch_Result result = {0}; + + i32 edit_max = line_end - line_start; + i32 edit_count = 0; + + Buffer_Edit *edits = push_array(part, Buffer_Edit, edit_max); + + char *str_base = (char*)part->base + part->pos; + i32 str_size = 0; + + // NOTE(allen): Shift the array so that line_i can just operate in + // it's natural value range. + indent_marks -= line_start; + + for (i32 line_i = line_start; line_i < line_end; ++line_i){ + i32 start = buffer->line_starts[line_i]; + Hard_Start_Result hard_start = + buffer_find_hard_start(buffer, start, opts.tab_width); + + i32 correct_indentation = indent_marks[line_i]; + if (hard_start.all_whitespace && opts.empty_blank_lines) correct_indentation = 0; + if (correct_indentation == -1) correct_indentation = hard_start.indent_pos; + + if ((hard_start.all_whitespace && hard_start.char_pos > start) || + !hard_start.all_space || correct_indentation != hard_start.indent_pos){ + Buffer_Edit new_edit; + new_edit.str_start = str_size; + str_size += correct_indentation; + char *str = push_array(part, char, correct_indentation); + i32 j = 0; + if (opts.use_tabs){ + i32 i = 0; + for (; i + opts.tab_width <= correct_indentation; i += opts.tab_width) str[j++] = '\t'; + for (; i < correct_indentation; ++i) str[j++] = ' '; + } + else{ + for (; j < correct_indentation; ++j) str[j] = ' '; + } + new_edit.len = j; + new_edit.start = start; + new_edit.end = hard_start.char_pos; + edits[edit_count++] = new_edit; + } + + Assert(edit_count <= edit_max); + } + + result.str_base = str_base; + result.str_size = str_size; + + result.edits = edits; + result.edit_max = edit_max; + result.edit_count = edit_count; + + return(result); +} + +internal void +view_auto_tab_tokens(System_Functions *system, Models *models, + View *view, i32 start, i32 end, Indent_Options opts){ +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + Editing_File *file = view->file_data.file; + Mem_Options *mem = &models->mem; + Partition *part = &mem->part; + Buffer *buffer = &file->state.buffer; + + Assert(file && !file->is_dummy); + Cpp_Token_Stack tokens = file->state.token_stack; + Assert(tokens.tokens); + + i32 line_start = buffer_get_line_index(buffer, start); + i32 line_end = buffer_get_line_index(buffer, end) + 1; + + Temp_Memory temp = begin_temp_memory(part); + + i32 *indent_marks = + get_line_indentation_marks(part, buffer, tokens, line_start, line_end, opts.tab_width); + + Make_Batch_Result batch = + make_batch_from_indent_marks(part, buffer, line_start, line_end, indent_marks, opts); + + if (batch.edit_count > 0){ + Assert(buffer_batch_debug_sort_check(batch.edits, batch.edit_count)); + + // NOTE(allen): computing edit spec, doing batch edit + Buffer_Edit *inverse_array = push_array(part, Buffer_Edit, batch.edit_count); + Assert(inverse_array); + + char *inv_str = (char*)part->base + part->pos; + Edit_Spec spec = + file_compute_whitespace_edit(mem, file, view->recent->cursor.pos, + batch.edits, batch.str_base, batch.str_size, + inverse_array, inv_str, part->max - part->pos, batch.edit_count); + + file_do_white_batch_edit(system, models, view->file_data.file, spec, hist_normal); + } + end_temp_memory(temp); + + { + i32 start = view->recent->cursor.pos; + Hard_Start_Result hard_start = buffer_find_hard_start(buffer, start, 4); + + view_cursor_move(view, hard_start.char_pos); + } +#endif +} + +struct Get_Link_Result{ + b32 in_link; + i32 index; +}; + +internal u32* +style_get_color(Style *style, Cpp_Token token){ + u32 *result; + if (token.flags & CPP_TFLAG_IS_KEYWORD){ + if (token.type == CPP_TOKEN_BOOLEAN_CONSTANT){ + result = &style->main.bool_constant_color; + } + else{ + result = &style->main.keyword_color; + } + } + else if(token.flags & CPP_TFLAG_PP_DIRECTIVE){ + result = &style->main.preproc_color; + } + else{ + switch (token.type){ + case CPP_TOKEN_COMMENT: + result = &style->main.comment_color; + break; + + case CPP_TOKEN_STRING_CONSTANT: + result = &style->main.str_constant_color; + break; + + case CPP_TOKEN_CHARACTER_CONSTANT: + result = &style->main.char_constant_color; + break; + + case CPP_TOKEN_INTEGER_CONSTANT: + result = &style->main.int_constant_color; + break; + + case CPP_TOKEN_FLOATING_CONSTANT: + result = &style->main.float_constant_color; + break; + + case CPP_TOKEN_INCLUDE_FILE: + result = &style->main.include_color; + break; + + default: + result = &style->main.default_color; + break; + } + } + return result; +} + +internal void +remeasure_file_view(System_Functions *system, View *view){ + if (file_is_ready(view->file_data.file)){ + Relative_Scrolling relative = view_get_relative_scrolling(view); + view_measure_wraps(&view->persistent.models->mem.general, view); + view_cursor_move(view, view->recent->cursor.pos); + view->recent->preferred_x = view_get_cursor_x(view); + view_set_relative_scrolling(view, relative); + } +} + +inline void +view_show_menu(View *view, Command_Map *gui_map){ + view->map = gui_map; + view->showing_ui = VUI_Menu; + view->current_scroll = &view->gui_scroll; +} + +inline void +view_show_config(View *view, Command_Map *gui_map){ + view->map = gui_map; + view->showing_ui = VUI_Config; + view->current_scroll = &view->gui_scroll; +} + +inline void +view_show_interactive(System_Functions *system, View *view, + Command_Map *gui_map, Interactive_Action action, + Interactive_Interaction interaction, String query){ + + Models *models = view->persistent.models; + + view->showing_ui = VUI_Interactive; + view->action = action; + view->interaction = interaction; + view->dest = make_fixed_width_string(view->dest_); + view->list_i = 0; + view->current_scroll = &view->gui_scroll; + + view->map = gui_map; + + hot_directory_clean_end(&models->hot_directory); + hot_directory_reload(system, &models->hot_directory, &models->working_set); +} + +inline void +view_show_theme(View *view, Command_Map *gui_map){ + view->map = gui_map; + view->showing_ui = VUI_Theme; + view->color_mode = CV_Mode_Library; + view->color = super_color_create(0xFF000000); + view->current_color_editing = 0; + view->current_scroll = &view->gui_scroll; +} + +inline void +view_show_file(View *view){ + Editing_File *file = view->file_data.file; + if (file){ + view->map = get_map(view->persistent.models, file->settings.base_map_id); + } + else{ + view->map = get_map(view->persistent.models, mapid_global); + } + view->showing_ui = VUI_None; + view->current_scroll = &view->recent->scroll; +} + +internal void +view_save_file(System_Functions *system, Models *models, + Editing_File *file, View *view, String filename, b32 save_as){ + Mem_Options *mem = &models->mem; + Working_Set *working_set = &models->working_set; + + if (!file){ + if (view){ + file = view->file_data.file; + } + else{ + file = working_set_lookup_file(working_set, filename); + } + } + + if (file && buffer_get_sync(file) != SYNC_GOOD){ + if (file_save(system, mem, file, filename.str)){ + if (save_as){ + file_set_name(working_set, file, filename.str); + } + } + } +} + +internal void +view_new_file(System_Functions *system, Models *models, + View *view, String string){ + Working_Set *working_set = &models->working_set; + General_Memory *general = &models->mem.general; + + Editing_File *file = working_set_alloc_always(working_set, general); + file_create_empty(system, models, file, string.str); + working_set_add(system, working_set, file, general); + + view_set_file(view, file, models); + view_show_file(view); + view->map = get_map(models, file->settings.base_map_id); + + Hook_Function *new_file_fnc = models->hooks[hook_new_file]; + if (new_file_fnc){ + models->buffer_param_indices[models->buffer_param_count++] = file->id.id; + new_file_fnc(&models->app_links); + models->buffer_param_count = 0; + file->settings.is_initialized = 1; + } + +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + if (file->settings.tokens_exist){ + file_first_lex_parallel(system, general, file); + } +#endif +} + +internal void +init_normal_file(System_Functions *system, Models *models, Editing_File *file, + char *buffer, i32 size){ + + General_Memory *general = &models->mem.general; + + String val = make_string(buffer, size); + file_create_from_string(system, models, file, file->name.source_path.str, val); + + if (file->settings.tokens_exist){ + file_first_lex_parallel(system, general, file); + } + + for (View_Iter iter = file_view_iter_init(&models->layout, file, 0); + file_view_iter_good(iter); + iter = file_view_iter_next(iter)){ + view_measure_wraps(general, iter.view); + } +} + +internal void +view_open_file(System_Functions *system, Models *models, + View *view, String filename){ + Working_Set *working_set = &models->working_set; + General_Memory *general = &models->mem.general; + Partition *part = &models->mem.part; + + Editing_File *file = working_set_contains(system, working_set, filename); + + if (file == 0){ + File_Loading loading = system->file_load_begin(filename.str); + + if (loading.exists){ + b32 in_general_mem = 0; + Temp_Memory temp = begin_temp_memory(part); + char *buffer = push_array(part, char, loading.size); + + // TODO(allen): How will we get temporary space for large + // buffers? The main partition isn't always big enough + // but getting a general block this large and copying it + // then freeing it is *super* dumb! + if (buffer == 0){ + buffer = (char*)general_memory_allocate(general, loading.size); + if (buffer != 0){ + in_general_mem = 1; + } + } + + if (system->file_load_end(loading, buffer)){ + file = working_set_alloc_always(working_set, general); + if (file){ + file_init_strings(file); + file_set_name(working_set, file, filename.str); + working_set_add(system, working_set, file, general); + + init_normal_file(system, models, file, + buffer, loading.size); + } + } + + if (in_general_mem){ + general_memory_free(general, buffer); + } + + end_temp_memory(temp); + } + } + + if (file){ + if (view){ + view_set_file(view, file, models); + } + } +} + +internal void +kill_file(System_Functions *system, Models *models, + Editing_File *file, String string){ + Working_Set *working_set = &models->working_set; + + if (!file && string.str){ + file = working_set_lookup_file(working_set, string); + if (!file){ + file = working_set_contains(system, working_set, string); + } + } + + if (file && !file->settings.never_kill){ + working_set_remove(system, working_set, file->name.source_path); + file_close(system, &models->mem.general, file); + working_set_free_file(&models->working_set, file); + + File_Node *used = &models->working_set.used_sentinel; + File_Node *node = used->next; + for (View_Iter iter = file_view_iter_init(&models->layout, file, 0); + file_view_iter_good(iter); + iter = file_view_iter_next(iter)){ + if (node != used){ + iter.view->file_data.file = 0; + view_set_file(iter.view, (Editing_File*)node, models); + node = node->next; + } + else{ + iter.view->file_data.file = 0; + view_set_file(iter.view, 0, models); + } + } + } +} + +internal void +try_kill_file(System_Functions *system, Models *models, + Editing_File *file, View *view, String string){ + Working_Set *working_set = &models->working_set; + + if (!file && string.str){ + file = working_set_lookup_file(working_set, string); + if (!file){ + file = working_set_contains(system, working_set, string); + } + } + + if (file && !file->settings.never_kill){ + if (buffer_needs_save(file)){ + if (view == 0){ + view = models->layout.panels[models->layout.active_panel].view; + } + view_show_interactive(system, view, &models->map_ui, + IAct_Sure_To_Kill, IInt_Sure_To_Kill, + make_lit_string("Are you sure?")); + copy(&view->dest, file->name.live_name); + } + else{ + kill_file(system, models, file, string_zero()); + view_show_file(view); + } + } +} + +internal void +interactive_view_complete(System_Functions *system, View *view, String dest, i32 user_action){ + Models *models = view->persistent.models; + Editing_File *old_file = view->file_data.file; + + switch (view->action){ + case IAct_Open: + view_open_file(system, models, view, dest); + touch_file(&models->working_set, old_file); + view_show_file(view); + break; + + case IAct_Save_As: + view_save_file(system, models, 0, view, dest, 1); + view_show_file(view); + break; + + case IAct_New: + if (dest.size > 0 && !char_is_slash(dest.str[dest.size-1])){ + view_new_file(system, models, view, dest); + view_show_file(view); + }break; + + case IAct_Switch: + { + touch_file(&models->working_set, old_file); + + Editing_File *file = 0; + String string = dest; + + file = working_set_lookup_file(&models->working_set, string); + if (!file){ + file = working_set_contains(system, &models->working_set, string); + } + if (file){ + view_set_file(view, file, models); + } + view_show_file(view); + } + break; + + case IAct_Kill: + try_kill_file(system, models, 0, 0, dest); + break; + + case IAct_Sure_To_Close: + switch (user_action){ + case 0: + models->keep_playing = 0; + break; + + case 1: + view_show_file(view); + break; + + case 2: + // TODO(allen): Save all and close. + break; + } + break; + + case IAct_Sure_To_Kill: + switch (user_action){ + case 0: + kill_file(system, models, 0, dest); + view_show_file(view); + break; + + case 1: + view_show_file(view); + break; + + case 2: + view_save_file(system, models, 0, 0, dest, 0); + kill_file(system, models, 0, dest); + view_show_file(view); + break; + } + break; + } +} + +#if 0 +internal void +update_highlighting(View *view){ + View *file_view = view->hot_file_view; + if (!file_view){ + view->highlight = {}; + return; + } + + Editing_File *file = file_view->file; + if (!file || !file_is_ready(file)){ + view->highlight = {}; + return; + } + + Models *models = view->persistent.models; + + Style *style = &models->style; + i32 pos = view_get_cursor_pos(file_view); + char c = buffer_get_char(&file->state.buffer, pos); + + if (c == '\r'){ + view->highlight.ids[0] = + raw_ptr_dif(&style->main.special_character_color, style); + } + + else if (file->state.tokens_complete){ + Cpp_Token_Stack *tokens = &file->state.token_stack; + Cpp_Get_Token_Result result = cpp_get_token(tokens, pos); + Cpp_Token token = tokens->tokens[result.token_index]; + if (!result.in_whitespace){ + u32 *color = style_get_color(style, token); + view->highlight.ids[0] = raw_ptr_dif(color, style); + if (token.type == CPP_TOKEN_JUNK){ + view->highlight.ids[1] = + raw_ptr_dif(&style->main.highlight_junk_color, style); + } + else if (char_is_whitespace(c)){ + view->highlight.ids[1] = + raw_ptr_dif(&style->main.highlight_white_color, style); + } + else{ + view->highlight.ids[1] = 0; + } + } + else{ + view->highlight.ids[0] = 0; + view->highlight.ids[1] = + raw_ptr_dif(&style->main.highlight_white_color, style); + } + } + + else{ + if (char_is_whitespace(c)){ + view->highlight.ids[0] = 0; + view->highlight.ids[1] = + raw_ptr_dif(&style->main.highlight_white_color, style); + } + else{ + view->highlight.ids[0] = + raw_ptr_dif(&style->main.default_color, style); + view->highlight.ids[1] = 0; + } + } + + if (file_view->show_temp_highlight){ + view->highlight.ids[2] = + raw_ptr_dif(&style->main.highlight_color, style); + view->highlight.ids[3] = + raw_ptr_dif(&style->main.at_highlight_color, style); + } + else if (file->state.paste_effect.tick_down > 0){ + view->highlight.ids[2] = + raw_ptr_dif(&style->main.paste_color, style); + view->highlight.ids[3] = 0; + } + else{ + view->highlight.ids[2] = 0; + view->highlight.ids[3] = 0; + } +} +#endif + +struct File_Bar{ + f32 pos_x, pos_y; + f32 text_shift_x, text_shift_y; + i32_Rect rect; + i16 font_id; +}; + +internal void +intbar_draw_string(Render_Target *target, File_Bar *bar, String str, u32 char_color){ + i16 font_id = bar->font_id; + draw_string(target, font_id, str, + (i32)(bar->pos_x + bar->text_shift_x), + (i32)(bar->pos_y + bar->text_shift_y), + char_color); + bar->pos_x += font_string_width(target, font_id, str); +} + +internal void +view_reinit_scrolling(View *view){ + Editing_File *file = view->file_data.file; + f32 w, h; + f32 cursor_x, cursor_y; + f32 target_x, target_y; + + view->reinit_scrolling = 0; + + target_x = 0; + target_y = 0; + + if (file && file_is_ready(file)){ + cursor_x = view_get_cursor_x(view); + cursor_y = view_get_cursor_y(view); + + w = view_file_width(view); + h = view_file_height(view); + + if (cursor_x >= target_x + w){ + target_x = (f32)(cursor_x - w*.5f); + } + + target_y = clamp_bottom(0.f, (f32)FLOOR32(cursor_y - h*.5f)); + } + + view->recent->scroll.target_y = target_y; + view->recent->scroll.scroll_y = target_y; + view->recent->scroll.prev_target_y = -1000.f; + + view->recent->scroll.target_x = target_x; + view->recent->scroll.scroll_x = target_x; + view->recent->scroll.prev_target_x = -1000.f; +} + +enum CursorScroll_State{ + CursorScroll_NoChange = 0x0, + CursorScroll_Cursor = 0x1, + CursorScroll_Scroll = 0x2, + CursorScroll_ContextChange = 0x4 +}; + +internal u32 +view_get_cursor_scroll_change_state(View *view){ + u32 result = 0; + i32 pos = 0; + Scroll_Context context = {0}; + + if (view->gui_target.did_file){ + pos = view_get_cursor_pos(view); + if ((view->prev_cursor_pos != pos)){ + result |= CursorScroll_Cursor; + } + } + + if (view->current_scroll){ + if (!gui_scroll_eq(view->current_scroll, &view->gui_target.scroll_original)){ + result |= CursorScroll_Scroll; + } + } + + if (context.mode == VUI_None){ + context.file = view->file_data.file; + } + else{ + context.file = view->prev_context.file; + } + context.scroll = view->gui_target.scroll_id; + context.mode = view->showing_ui; + + if (!context_eq(view->prev_context, context)){ + result |= CursorScroll_ContextChange; + } + + return(result); +} + +internal void +view_begin_cursor_scroll_updates(View *view){ + if (view->file_data.file && view->file_data.file == view->prev_context.file){ + Assert(view->prev_cursor_pos == view_get_cursor_pos(view)); + } + + view->prev_context.file = view->file_data.file; + view->prev_context.scroll = view->gui_target.scroll_id; + view->prev_context.mode = view->showing_ui; +} + +internal void +view_end_cursor_scroll_updates(View *view){ + i32 cursor_scroll_state = + view_get_cursor_scroll_change_state(view); + + switch (cursor_scroll_state){ + case CursorScroll_NoChange:break; + + case CursorScroll_Cursor: + case CursorScroll_Cursor|CursorScroll_Scroll: + view_move_view_to_cursor(view, view->current_scroll); + gui_post_scroll_vars(&view->gui_target, view->current_scroll, view->scroll_region); + break; + + case CursorScroll_Scroll: + view_move_cursor_to_view(view); + gui_post_scroll_vars(&view->gui_target, view->current_scroll, view->scroll_region); + break; + } + + if (cursor_scroll_state & CursorScroll_ContextChange){ + view->current_scroll->scroll_y = view->current_scroll->target_y; + view->current_scroll->scroll_x = view->current_scroll->target_x; + gui_post_scroll_vars(&view->gui_target, view->current_scroll, view->scroll_region); + } + + if (view->gui_target.did_file){ + view->prev_cursor_pos = view_get_cursor_pos(view); + } +} + +internal b32 +file_step(View *view, i32_Rect region, Input_Summary *user_input, b32 is_active){ + i32 is_animating = 0; + Editing_File *file = view->file_data.file; + if (file && !file->is_loading){ + f32 max_visible_y = view_file_height(view); + f32 max_x = view_file_width(view); + + GUI_Scroll_Vars scroll_vars = *view->current_scroll; + + if (file->state.paste_effect.tick_down > 0){ + --file->state.paste_effect.tick_down; + is_animating = 1; + } + + if (user_input->mouse.press_l && is_active){ + f32 rx = (f32)(user_input->mouse.x - region.x0); + f32 ry = (f32)(user_input->mouse.y - region.y0); + + if (ry >= 0){ + view_set_widget(view, FWIDG_NONE); + if (rx >= 0 && rx < max_x && ry >= 0 && ry < max_visible_y){ + view_cursor_move(view, rx + scroll_vars.scroll_x, ry + scroll_vars.scroll_y, 1); + view->mode = view_mode_zero(); + } + } + } + if (!is_active) view_set_widget(view, FWIDG_NONE); + } + + return(is_animating); +} + +internal void +do_widget(View *view, GUI_Target *target){ + Query_Slot *slot; + Query_Bar *bar; + + for (slot = view->query_set.used_slot; slot != 0; slot = slot->next){ + bar = slot->query_bar; + gui_do_text_field(target, bar->prompt, bar->string); + } +} + +struct Exhaustive_File_Loop{ + char front_name_[256]; + char full_path_[256]; + String front_name, full_path; + + Absolutes absolutes; + + File_Info *infos; + i32 count, r; +}; + +struct Exhaustive_File_Info{ + File_Info *info; + String message; + b8 is_folder; + b8 name_match; + b8 is_loaded; +}; + +internal void +begin_exhaustive_loop(Exhaustive_File_Loop *loop, Hot_Directory *hdir){ + loop->front_name = make_fixed_width_string(loop->front_name_); + loop->full_path = make_fixed_width_string(loop->full_path_); + + loop->infos = hdir->file_list.infos; + loop->count = hdir->file_list.count; + + get_front_of_directory(&loop->front_name, hdir->string); + get_absolutes(loop->front_name, &loop->absolutes, 1, 1); + get_path_of_directory(&loop->full_path, hdir->string); + loop->r = loop->full_path.size; +} + +internal Exhaustive_File_Info +get_exhaustive_info(System_Functions *system, Working_Set *working_set, Exhaustive_File_Loop *loop, i32 i){ + persist String message_loaded = make_lit_string(" LOADED"); + persist String message_unsaved = make_lit_string(" LOADED *"); + persist String message_unsynced = make_lit_string(" LOADED !"); + + Exhaustive_File_Info result = {0}; + Editing_File *file = 0; + + result.info = loop->infos + i; + loop->full_path.size = loop->r; + append(&loop->full_path, result.info->filename); + terminate_with_null(&loop->full_path); + file = working_set_contains(system, working_set, loop->full_path); + + result.is_folder = (result.info->folder != 0); + result.name_match = (filename_match(loop->front_name, &loop->absolutes, result.info->filename, 0) != 0); + result.is_loaded = (file != 0 && file_is_ready(file)); + + result.message = string_zero(); + if (result.is_loaded){ + switch (buffer_get_sync(file)){ + case SYNC_GOOD: result.message = message_loaded; break; + case SYNC_BEHIND_OS: result.message = message_unsynced; break; + case SYNC_UNSAVED: result.message = message_unsaved; break; + } + } + + return(result); +} + +struct Style_Color_Edit{ + Style_Tag target; + Style_Tag fore; + Style_Tag back; + String text; +}; + +static Style_Color_Edit colors_to_edit[] = { + {Stag_Back, Stag_Default, Stag_Back, make_lit_string("Background")}, + {Stag_Margin, Stag_Default, Stag_Margin, make_lit_string("Margin")}, + {Stag_Margin_Hover, Stag_Default, Stag_Margin_Hover, make_lit_string("Margin Hover")}, + {Stag_Margin_Active, Stag_Default, Stag_Margin_Active, make_lit_string("Margin Active")}, + + {Stag_Cursor, Stag_At_Cursor, Stag_Cursor, make_lit_string("Cursor")}, + {Stag_At_Cursor, Stag_At_Cursor, Stag_Cursor, make_lit_string("Text At Cursor")}, + {Stag_Mark, Stag_Mark, Stag_Back, make_lit_string("Mark")}, + + {Stag_Highlight, Stag_At_Highlight, Stag_Highlight, make_lit_string("Highlight")}, + {Stag_At_Highlight, Stag_At_Highlight, Stag_Highlight, make_lit_string("Text At Highlight")}, + + {Stag_Default, Stag_Default, Stag_Back, make_lit_string("Text Default")}, + {Stag_Comment, Stag_Comment, Stag_Back, make_lit_string("Comment")}, + {Stag_Keyword, Stag_Keyword, Stag_Back, make_lit_string("Keyword")}, + {Stag_Str_Constant, Stag_Str_Constant, Stag_Back, make_lit_string("String Constant")}, + {Stag_Char_Constant, Stag_Char_Constant, Stag_Back, make_lit_string("Character Constant")}, + {Stag_Int_Constant, Stag_Int_Constant, Stag_Back, make_lit_string("Integer Constant")}, + {Stag_Float_Constant, Stag_Float_Constant, Stag_Back, make_lit_string("Float Constant")}, + {Stag_Bool_Constant, Stag_Bool_Constant, Stag_Back, make_lit_string("Boolean Constant")}, + {Stag_Preproc, Stag_Preproc, Stag_Back, make_lit_string("Preprocessor")}, + {Stag_Special_Character, Stag_Special_Character, Stag_Back, make_lit_string("Special Character")}, + + {Stag_Highlight_Junk, Stag_Default, Stag_Highlight_Junk, make_lit_string("Junk Highlight")}, + {Stag_Highlight_White, Stag_Default, Stag_Highlight_White, make_lit_string("Whitespace Highlight")}, + + {Stag_Paste, Stag_Paste, Stag_Back, make_lit_string("Paste Color")}, + + {Stag_Bar, Stag_Base, Stag_Bar, make_lit_string("Bar")}, + {Stag_Base, Stag_Base, Stag_Bar, make_lit_string("Bar Text")}, + {Stag_Pop1, Stag_Pop1, Stag_Bar, make_lit_string("Bar Pop 1")}, + {Stag_Pop2, Stag_Pop2, Stag_Bar, make_lit_string("Bar Pop 2")}, +}; + +struct Single_Line_Input_Step{ + b8 hit_newline; + b8 hit_ctrl_newline; + b8 hit_a_character; + b8 hit_backspace; + b8 hit_esc; + b8 made_a_change; + b8 did_command; + b8 no_file_match; +}; + +enum Single_Line_Input_Type{ + SINGLE_LINE_STRING, + SINGLE_LINE_FILE +}; + +struct Single_Line_Mode{ + Single_Line_Input_Type type; + String *string; + Hot_Directory *hot_directory; + b32 fast_folder_select; + b32 try_to_match; + b32 case_sensitive; +}; + +internal Single_Line_Input_Step +app_single_line_input_core(System_Functions *system, Working_Set *working_set, + Key_Event_Data key, Single_Line_Mode mode){ + Single_Line_Input_Step result = {0}; + + if (key.keycode == key_back){ + result.hit_backspace = 1; + if (mode.string->size > 0){ + result.made_a_change = 1; + --mode.string->size; + switch (mode.type){ + case SINGLE_LINE_STRING: + { + mode.string->str[mode.string->size] = 0; + }break; + + case SINGLE_LINE_FILE: + { + char end_character = mode.string->str[mode.string->size]; + if (char_is_slash(end_character)){ + mode.string->size = reverse_seek_slash(*mode.string) + 1; + mode.string->str[mode.string->size] = 0; + hot_directory_set(system, mode.hot_directory, *mode.string, working_set); + } + else{ + mode.string->str[mode.string->size] = 0; + } + }break; + } + } + } + + else if (key.character == '\n' || key.character == '\t'){ + // NOTE(allen): do nothing! + } + + else if (key.keycode == key_esc){ + result.hit_esc = 1; + result.made_a_change = 1; + } + + else if (key.character){ + result.hit_a_character = 1; + if (!key.modifiers[MDFR_CONTROL_INDEX] && + !key.modifiers[MDFR_ALT_INDEX]){ + if (mode.string->size+1 < mode.string->memory_size){ + u8 new_character = (u8)key.character; + mode.string->str[mode.string->size] = new_character; + mode.string->size++; + mode.string->str[mode.string->size] = 0; + if (mode.type == SINGLE_LINE_FILE && char_is_slash(new_character)){ + hot_directory_set(system, mode.hot_directory, *mode.string, working_set); + } + result.made_a_change = 1; + } + } + else{ + result.did_command = 1; + result.made_a_change = 1; + } + } + + return result; +} + +inline Single_Line_Input_Step +app_single_line_input_step(System_Functions *system, Key_Event_Data key, String *string){ + Single_Line_Mode mode = {}; + mode.type = SINGLE_LINE_STRING; + mode.string = string; + return app_single_line_input_core(system, 0, key, mode); +} + +inline Single_Line_Input_Step +app_single_file_input_step(System_Functions *system, + Working_Set *working_set, Key_Event_Data key, + String *string, Hot_Directory *hot_directory, + b32 fast_folder_select, b32 try_to_match, b32 case_sensitive){ + Single_Line_Mode mode = {}; + mode.type = SINGLE_LINE_FILE; + mode.string = string; + mode.hot_directory = hot_directory; + mode.fast_folder_select = fast_folder_select; + mode.try_to_match = try_to_match; + mode.case_sensitive = case_sensitive; + return app_single_line_input_core(system, working_set, key, mode); +} + +inline Single_Line_Input_Step +app_single_number_input_step(System_Functions *system, Key_Event_Data key, String *string){ + Single_Line_Input_Step result = {}; + Single_Line_Mode mode = {}; + mode.type = SINGLE_LINE_STRING; + mode.string = string; + + char c = (char)key.character; + if (c == 0 || c == '\n' || char_is_numeric(c)) + result = app_single_line_input_core(system, 0, key, mode); + return result; +} + +struct View_Step_Result{ + b32 animating; + b32 consume_keys; + b32 consume_esc; +}; + +internal View_Step_Result +step_file_view(System_Functions *system, View *view, View *active_view, Input_Summary input){ + View_Step_Result result = {0}; + GUI_Target *target = &view->gui_target; + Models *models = view->persistent.models; + Key_Summary keys = input.keys; + + b32 show_scrollbar = !view->hide_scrollbar; + + view->current_scroll = 0; + + if (view->showing_ui != VUI_None){ + b32 did_esc = 0; + Key_Event_Data key; + i32 i; + + for (i = 0; i < keys.count; ++i){ + key = get_single_key(&keys, i); + if (key.keycode == key_esc){ + did_esc = 1; + break; + } + } + + if (did_esc){ + view_show_file(view); + result.consume_esc = 1; + } + } + + gui_begin_top_level(target, input); + { + gui_do_top_bar(target); + do_widget(view, target); + + if (view->showing_ui == VUI_None){ + + gui_begin_serial_section(target); + { + f32 delta = 9.f * view->font_height; + GUI_id scroll_context = {0}; + scroll_context.id[1] = view->showing_ui; + scroll_context.id[0] = (u64)(view->file_data.file); + + view->current_scroll = &view->recent->scroll; + gui_get_scroll_vars(target, scroll_context, + &view->recent->scroll, &view->scroll_region); + + gui_begin_scrollable(target, scroll_context, view->recent->scroll, + delta, show_scrollbar); + gui_do_file(target); + gui_end_scrollable(target); + } + gui_end_serial_section(target); + } + else{ + switch (view->showing_ui){ + case VUI_Menu: + { + view->current_scroll = &view->gui_scroll; + + String message = make_lit_string("Menu"); + String empty_string = {0}; + GUI_id id = {0}; + id.id[1] = VUI_Menu; + + gui_do_text_field(target, message, empty_string); + + id.id[0] = 0; + message = make_lit_string("Theme"); + if (gui_do_fixed_option(target, id, message, 0)){ + view_show_theme(view, view->map); + } + + id.id[0] = 1; + message = make_lit_string("Config"); + if (gui_do_fixed_option(target, id, message, 0)){ + view_show_config(view, view->map); + } + }break; + + case VUI_Config: + { + view->current_scroll = &view->gui_scroll; + + String message = make_lit_string("Config"); + String empty_string = {0}; + GUI_id id = {0}; + id.id[1] = VUI_Config; + + gui_do_text_field(target, message, empty_string); + + id.id[0] = 0; + message = make_lit_string("Left Ctrl + Left Alt = AltGr"); + if (gui_do_fixed_option_checkbox(target, id, message, 0, (b8)models->settings.lctrl_lalt_is_altgr)){ + models->settings.lctrl_lalt_is_altgr = !models->settings.lctrl_lalt_is_altgr; + } + }break; + + case VUI_Theme: + { + view->current_scroll = &view->gui_scroll; + + if (view != active_view){ + view->hot_file_view = active_view; + } + + String message = {0}; + String empty_string = {0}; + + GUI_id id = {0}; + id.id[1] = VUI_Theme + ((u64)view->color_mode << 32); + + GUI_id scroll_context = {0}; + scroll_context.id[0] = 0; + scroll_context.id[1] = VUI_Theme + ((u64)view->color_mode << 32); + + switch (view->color_mode){ + case CV_Mode_Library: + message = make_lit_string("Current Theme - Click to Edit"); + gui_do_text_field(target, message, empty_string); + + id.id[0] = (u64)(main_style(models)); + if (gui_do_style_preview(target, id, 0)){ + view->color_mode = CV_Mode_Adjusting; + } + + message = make_lit_string("Set Font"); + id.id[0] = (u64)(&models->global_font); + if (gui_do_button(target, id, message)){ + view->color_mode = CV_Mode_Font; + } + + message = make_lit_string("Theme Library - Click to Select"); + gui_do_text_field(target, message, empty_string); + + view->current_scroll = &view->gui_scroll; + gui_get_scroll_vars(target, scroll_context, &view->gui_scroll, &view->scroll_region); + gui_begin_scrollable(target, scroll_context, view->gui_scroll, + 9.f * view->font_height, show_scrollbar); + + { + i32 count = models->styles.count; + Style *style; + i32 i; + + for (i = 1; i < count; ++i, ++style){ + style = get_style(models, i); + id.id[0] = (u64)(style); + if (gui_do_style_preview(target, id, i)){ + style_copy(main_style(models), style); + } + } + } + + gui_end_scrollable(target); + break; + + case CV_Mode_Font: + { + Font_Set *font_set = models->font_set; + Font_Info *info = 0; + + i16 i = 1, count = (i16)models->font_set->count + 1; + i16 font_id = 0, new_font_id = 0; + + String message = make_lit_string("Back"); + + id.id[0] = 0; + if (gui_do_button(target, id, message)){ + view->color_mode = CV_Mode_Library; + } + + font_id = models->global_font.font_id; + new_font_id = font_id; + + for (i = 1; i < count; ++i){ + info = get_font_info(font_set, i); + id.id[0] = (u64)i; + if (i != font_id){ + if (gui_do_font_button(target, id, i, info->name)){ + new_font_id = i; + } + } + else{ + char message_space[256]; + message = make_fixed_width_string(message_space); + copy(&message, make_lit_string("currently selected: ")); + append(&message, info->name); + gui_do_font_button(target, id, i, message); + } + } + + models->global_font.font_id = (i16)(new_font_id); + }break; + + case CV_Mode_Adjusting: + { + Style *style = main_style(models); + u32 *edit_color = 0; + u32 *fore = 0, *back = 0; + i32 i = 0; + + String message = make_lit_string("Back"); + + id.id[0] = 0; + if (gui_do_button(target, id, message)){ + view->color_mode = CV_Mode_Library; + } + + view->current_scroll = &view->gui_scroll; + gui_get_scroll_vars(target, scroll_context, &view->gui_scroll, &view->scroll_region); + gui_begin_scrollable(target, scroll_context, view->gui_scroll, + 9.f * view->font_height, show_scrollbar); + + i32 next_color_editing = view->current_color_editing; + + for (i = 0; i < ArrayCount(colors_to_edit); ++i){ + edit_color = style_index_by_tag(&style->main, colors_to_edit[i].target); + id.id[0] = (u64)(edit_color); + + fore = style_index_by_tag(&style->main, colors_to_edit[i].fore); + back = style_index_by_tag(&style->main, colors_to_edit[i].back); + + if (gui_do_color_button(target, id, *fore, *back, colors_to_edit[i].text)){ + next_color_editing = i; + view->color_cursor = 0; + } + + if (view->current_color_editing == i){ + GUI_Item_Update update = {0}; + char text_space[7]; + String text = make_fixed_width_string(text_space); + + color_to_hexstr(*edit_color, &text); + if (gui_do_text_with_cursor(target, view->color_cursor, text, &update)){ + b32 r = 0; + i32 j = 0; + + for (j = 0; j < keys.count; ++j){ + i16 key = keys.keys[j].keycode; + switch (key){ + case key_left: --view->color_cursor; r = 1; result.consume_keys = 1; break; + case key_right: ++view->color_cursor; r = 1; result.consume_keys = 1; break; + + case key_up: + if (next_color_editing > 0){ + --next_color_editing; + } + result.consume_keys = 1; + break; + + case key_down: + if (next_color_editing <= ArrayCount(colors_to_edit)-1){ + ++next_color_editing; + } + result.consume_keys = 1; + break; + + default: + if ((key >= '0' && key <= '9') || (key >= 'a' && key <= 'f') || (key >= 'A' && key <= 'F')){ + text.str[view->color_cursor] = (char)key; + r = 1; + result.consume_keys = 1; + } + break; + } + + if (view->color_cursor < 0) view->color_cursor = 0; + if (view->color_cursor >= 6) view->color_cursor = 5; + } + + if (r){ + hexstr_to_color(text, edit_color); + gui_rollback(target, &update); + gui_do_text_with_cursor(target, view->color_cursor, text, 0); + } + } + } + } + + if (view->current_color_editing != next_color_editing){ + view->current_color_editing = next_color_editing; + view->color_cursor = 0; + } + + gui_end_scrollable(target); + }break; + } + }break; + + case VUI_Interactive: + { + b32 complete = 0; + char comp_dest_space[1024]; + String comp_dest = make_fixed_width_string(comp_dest_space); + i32 comp_action = 0; + + view->current_scroll = &view->gui_scroll; + + GUI_id id = {0}; + id.id[1] = VUI_Interactive + ((u64)view->interaction << 32); + + GUI_id scroll_context = {0}; + scroll_context.id[1] = VUI_Interactive + ((u64)view->interaction << 32); + + switch (view->interaction){ + case IInt_Sys_File_List: + { + b32 use_item_in_list = 1; + b32 activate_directly = 0; + + if (view->action == IAct_Save_As || view->action == IAct_New){ + use_item_in_list = 0; + } + + String message = {0}; + switch (view->action){ + case IAct_Open: message = make_lit_string("Open: "); break; + case IAct_Save_As: message = make_lit_string("Save As: "); break; + case IAct_New: message = make_lit_string("New: "); break; + } + + Exhaustive_File_Loop loop; + Exhaustive_File_Info file_info; + + GUI_Item_Update update = {0}; + Hot_Directory *hdir = &models->hot_directory; + b32 do_new_directory = 0; + b32 snap_into_view = 0; + i32 i = 0; + + { + Single_Line_Input_Step step = {0}; + Key_Event_Data key = {0}; + i32 i; + + for (i = 0; i < keys.count; ++i){ + key = get_single_key(&keys, i); + step = app_single_file_input_step(system, &models->working_set, key, + &hdir->string, hdir, 1, 1, 0); + if (step.made_a_change){ + view->list_i = 0; + result.consume_keys = 1; + } + if (!use_item_in_list && (key.keycode == '\n' || key.keycode == '\t')){ + activate_directly = 1; + result.consume_keys = 1; + } + } + } + + gui_do_text_field(target, message, hdir->string); + + scroll_context.id[0] = (u64)(hdir); + if (gui_get_scroll_vars(target, scroll_context, + &view->gui_scroll, &view->scroll_region)){ + snap_into_view = 1; + } + gui_begin_scrollable(target, scroll_context, view->gui_scroll, + 9.f * view->font_height, show_scrollbar); + + id.id[0] = (u64)(hdir) + 1; + + if (gui_begin_list(target, id, view->list_i, 0, + snap_into_view, &update)){ + // TODO(allen): Allow me to handle key consumption correctly here! + gui_standard_list(target, id, view->current_scroll, view->scroll_region, + &keys, &view->list_i, &update); + } + + { + begin_exhaustive_loop(&loop, hdir); + for (i = 0; i < loop.count; ++i){ + file_info = get_exhaustive_info(system, &models->working_set, &loop, i); + + if (file_info.name_match){ + id.id[0] = (u64)(file_info.info); + if (gui_do_file_option(target, id, file_info.info->filename, + file_info.is_folder, file_info.message)){ + if (file_info.is_folder){ + set_last_folder(&hdir->string, file_info.info->filename, '/'); + do_new_directory = 1; + } + else if (use_item_in_list){ + complete = 1; + copy(&comp_dest, loop.full_path); + } + } + } + } + } + + gui_end_list(target); + + if (activate_directly){ + complete = 1; + copy(&comp_dest, hdir->string); + } + + if (do_new_directory){ + hot_directory_reload(system, hdir, &models->working_set); + } + + gui_end_scrollable(target); + }break; + + case IInt_Live_File_List: + { + b32 snap_into_view = 0; + persist String message_unsaved = make_lit_string(" *"); + persist String message_unsynced = make_lit_string(" !"); + + String message = {0}; + switch (view->action){ + case IAct_Switch: message = make_lit_string("Switch: "); break; + case IAct_Kill: message = make_lit_string("Kill: "); break; + } + + Absolutes absolutes; + Editing_File *file; + Working_Set *working_set = &models->working_set; + Editing_Layout *layout = &models->layout; + GUI_Item_Update update = {0}; + + { + Single_Line_Input_Step step; + Key_Event_Data key; + i32 i; + for (i = 0; i < keys.count; ++i){ + key = get_single_key(&keys, i); + step = app_single_line_input_step(system, key, &view->dest); + if (step.made_a_change){ + view->list_i = 0; + result.consume_keys = 1; + } + } + } + + get_absolutes(view->dest, &absolutes, 1, 1); + + gui_do_text_field(target, message, view->dest); + + scroll_context.id[0] = (u64)(working_set); + if (gui_get_scroll_vars(target, scroll_context, + &view->gui_scroll, &view->scroll_region)){ + snap_into_view = 1; + } + gui_begin_scrollable(target, scroll_context, view->gui_scroll, + 9.f * view->font_height, show_scrollbar); + + id.id[0] = (u64)(working_set) + 1; + if (gui_begin_list(target, id, view->list_i, + 0, snap_into_view, &update)){ + gui_standard_list(target, id, view->current_scroll, view->scroll_region, + &keys, &view->list_i, &update); + } + + { + Partition *part = &models->mem.part; + Temp_Memory temp = begin_temp_memory(part); + File_Node *node = 0, *used_nodes = 0; + Editing_File **reserved_files = 0; + i32 reserved_top = 0, i = 0; + View_Iter iter = {0}; + + partition_align(part, sizeof(i32)); + reserved_files = (Editing_File**)partition_current(part); + + used_nodes = &working_set->used_sentinel; + for (dll_items(node, used_nodes)){ + file = (Editing_File*)node; + Assert(!file->is_dummy); + + if (filename_match(view->dest, &absolutes, file->name.live_name, 1)){ + iter = file_view_iter_init(layout, file, 0); + if (file_view_iter_good(iter)){ + reserved_files[reserved_top++] = file; + } + else{ + if (file->name.live_name.str[0] == '*'){ + reserved_files[reserved_top++] = file; + } + else{ + message = string_zero(); + switch (buffer_get_sync(file)){ + case SYNC_BEHIND_OS: message = message_unsynced; break; + case SYNC_UNSAVED: message = message_unsaved; break; + } + + id.id[0] = (u64)(file); + if (gui_do_file_option(target, id, file->name.live_name, 0, message)){ + complete = 1; + copy(&comp_dest, file->name.live_name); + } + } + } + } + } + + for (i = 0; i < reserved_top; ++i){ + file = reserved_files[i]; + + message = string_zero(); + switch (buffer_get_sync(file)){ + case SYNC_BEHIND_OS: message = message_unsynced; break; + case SYNC_UNSAVED: message = message_unsaved; break; + } + + id.id[0] = (u64)(file); + if (gui_do_file_option(target, id, file->name.live_name, 0, message)){ + complete = 1; + copy(&comp_dest, file->name.live_name); + } + } + + end_temp_memory(temp); + } + + gui_end_list(target); + + gui_end_scrollable(target); + }break; + + case IInt_Sure_To_Close: + { + i32 action = -1; + + String empty_str = {0}; + String message = make_lit_string("There is one or more files unsaved changes, close anyway?"); + + gui_do_text_field(target, message, empty_str); + + id.id[0] = (u64)('y'); + message = make_lit_string("(Y)es"); + if (gui_do_fixed_option(target, id, message, 'y')){ + action = 0; + } + + id.id[0] = (u64)('n'); + message = make_lit_string("(N)o"); + if (gui_do_fixed_option(target, id, message, 'n')){ + action = 1; + } + + if (action != -1){ + complete = 1; + copy(&comp_dest, view->dest); + comp_action = action; + } + }break; + + case IInt_Sure_To_Kill: + { + i32 action = -1; + + String empty_str = {0}; + String message = make_lit_string("There are unsaved changes, close anyway?"); + + gui_do_text_field(target, message, empty_str); + + id.id[0] = (u64)('y'); + message = make_lit_string("(Y)es"); + if (gui_do_fixed_option(target, id, message, 'y')){ + action = 0; + } + + id.id[0] = (u64)('n'); + message = make_lit_string("(N)o"); + if (gui_do_fixed_option(target, id, message, 'n')){ + action = 1; + } + + id.id[0] = (u64)('s'); + message = make_lit_string("(S)ave and kill"); + if (gui_do_fixed_option(target, id, message, 's')){ + action = 2; + } + + if (action != -1){ + complete = 1; + copy(&comp_dest, view->dest); + comp_action = action; + } + }break; + } + + if (complete){ + terminate_with_null(&comp_dest); + interactive_view_complete(system, view, comp_dest, comp_action); + } + }break; + } + } + } + gui_end_top_level(target); + + result.animating = target->animating; + return(result); +} + +internal f32 +view_get_scroll_y(View *view){ + f32 v; + if (view->showing_ui == VUI_None){ + v = view->recent->scroll.scroll_y; + } + else{ + v = view->gui_scroll.scroll_y; + } + return(v); +} + +internal void +click_button_input(GUI_Target *target, GUI_Session *session, Input_Summary *user_input, + GUI_Interactive *b, b32 *is_animating){ + i32 mx = user_input->mouse.x; + i32 my = user_input->mouse.y; + + if (hit_check(mx, my, session->rect)){ + target->hover = b->id; + if (user_input->mouse.press_l){ + target->mouse_hot = b->id; + *is_animating = 1; + } + if (user_input->mouse.release_l && gui_id_eq(target->mouse_hot, b->id)){ + target->active = b->id; + target->mouse_hot = gui_id_zero(); + *is_animating = 1; + } + } + else if (gui_id_eq(target->hover, b->id)){ + target->hover = gui_id_zero(); + } +} + +internal b32 +scroll_button_input(GUI_Target *target, GUI_Session *session, Input_Summary *user_input, + GUI_id id, b32 *is_animating){ + b32 result = 0; + i32 mx = user_input->mouse.x; + i32 my = user_input->mouse.y; + + if (hit_check(mx, my, session->rect)){ + target->hover = id; + if (user_input->mouse.l){ + target->mouse_hot = id; + gui_activate_scrolling(target); + *is_animating = 1; + result = 1; + } + } + else if (gui_id_eq(target->hover, id)){ + target->hover = gui_id_zero(); + } + return(result); +} + +struct Input_Process_Result{ + GUI_Scroll_Vars vars; + i32_Rect region; + b32 is_animating; +}; + +internal Input_Process_Result +do_input_file_view(System_Functions *system, + View *view, i32_Rect rect, b32 is_active, + Input_Summary *user_input, + GUI_Scroll_Vars vars, i32_Rect region){ + Input_Process_Result result = {0}; + b32 is_file_scroll = 0; + + GUI_Session gui_session = {0}; + GUI_Header *h = 0; + GUI_Target *target = &view->gui_target; + GUI_Interpret_Result interpret_result = {0}; + + result.vars = vars; + result.region = region; + + target->active = gui_id_zero(); + + if (target->push.pos > 0){ + gui_session_init(&gui_session, target, rect, view->font_height); + + for (h = (GUI_Header*)target->push.base; + h->type; + h = NextHeader(h)){ + interpret_result = gui_interpret(target, &gui_session, h, + result.vars, result.region); + + if (interpret_result.has_region){ + result.region = interpret_result.region; + } + + switch (h->type){ + case guicom_file_option: + case guicom_fixed_option: + case guicom_fixed_option_checkbox: + { + GUI_Interactive *b = (GUI_Interactive*)h; + + if (interpret_result.auto_activate){ + target->auto_hot = gui_id_zero(); + target->active = b->id; + result.is_animating = 1; + } + else if (interpret_result.auto_hot){ + if (!gui_id_eq(target->auto_hot, b->id)){ + target->auto_hot = b->id; + result.is_animating = 1; + } + } + }break; + } + + if (interpret_result.has_info){ + switch (h->type){ + case guicom_top_bar: break; + + case guicom_file: + { + f32 new_max_y = view_compute_max_target_y(view); + + view->file_region = gui_session.rect; + result.vars.max_y = new_max_y; + + if (view->reinit_scrolling){ + view_reinit_scrolling(view); + result.is_animating = 1; + } + if (file_step(view, gui_session.rect, user_input, is_active)){ + result.is_animating = 1; + } + is_file_scroll = 1; + }break; + + case guicom_color_button: + case guicom_font_button: + case guicom_button: + case guicom_file_option: + case guicom_style_preview: + { + GUI_Interactive *b = (GUI_Interactive*)h; + + click_button_input(target, &gui_session, user_input, b, &result.is_animating); + }break; + + case guicom_fixed_option: + case guicom_fixed_option_checkbox: + { + GUI_Interactive *b = (GUI_Interactive*)h; + + click_button_input(target, &gui_session, user_input, b, &result.is_animating); + + { + Key_Event_Data key; + Key_Summary *keys = &user_input->keys; + + void *ptr = (b + 1); + String string; + char activation_key; + + i32 i, count; + + string = gui_read_string(&ptr); + activation_key = *(char*)ptr; + + count = keys->count; + for (i = 0; i < count; ++i){ + key = get_single_key(keys, i); + if (char_to_upper(key.character) == char_to_upper(activation_key)){ + target->active = b->id; + result.is_animating = 1; + break; + } + } + } + }break; + + case guicom_scrollable_slider: + { + GUI_id id = gui_id_scrollbar_slider(); + i32 mx = user_input->mouse.x; + i32 my = user_input->mouse.y; + f32 v = 0; + + if (hit_check(mx, my, gui_session.rect)){ + target->hover = id; + if (user_input->mouse.press_l){ + target->mouse_hot = id; + result.is_animating = 1; + } + } + else if (gui_id_eq(target->hover, id)){ + target->hover = gui_id_zero(); + } + + if (gui_id_eq(target->mouse_hot, id)){ + v = unlerp(gui_session.scroll_top, (f32)my, + gui_session.scroll_bottom); + v = clamp(0.f, v, 1.f); + result.vars.target_y = lerp(0.f, v, result.vars.max_y); + + gui_activate_scrolling(target); + result.is_animating = 1; + } + } + // NOTE(allen): NO BREAK HERE!! + + case guicom_scrollable_invisible: + { + if (user_input->mouse.wheel != 0){ + result.vars.target_y += user_input->mouse.wheel*target->delta; + + result.vars.target_y = + clamp(0.f, result.vars.target_y, result.vars.max_y); + gui_activate_scrolling(target); + result.is_animating = 1; + } + }break; + + case guicom_scrollable_top: + { + GUI_id id = gui_id_scrollbar_top(); + + if (scroll_button_input(target, &gui_session, user_input, id, &result.is_animating)){ + result.vars.target_y -= target->delta * 0.25f; + result.vars.target_y = clamp_bottom(0.f, result.vars.target_y); + } + }break; + + case guicom_scrollable_bottom: + { + GUI_id id = gui_id_scrollbar_bottom(); + + if (scroll_button_input(target, &gui_session, user_input, id, &result.is_animating)){ + result.vars.target_y += target->delta * 0.25f; + result.vars.target_y = clamp_top(0.f, result.vars.max_y); + } + }break; + + case guicom_end_scrollable_section: + { + if (!is_file_scroll){ + f32 new_max_y = gui_session.suggested_max_y; + result.vars.max_y = new_max_y; + } + }break; + } + } + } + + if (!user_input->mouse.l){ + if (!gui_id_is_null(target->mouse_hot)){ + target->mouse_hot = gui_id_zero(); + result.is_animating = 1; + } + } + + { + GUI_Scroll_Vars scroll_vars = result.vars; + b32 is_new_target = 0; + if (scroll_vars.target_x != scroll_vars.prev_target_x) is_new_target = 1; + if (scroll_vars.target_y != scroll_vars.prev_target_y) is_new_target = 1; + + if (view->persistent.models->scroll_rule(scroll_vars.target_x, scroll_vars.target_y, + &scroll_vars.scroll_x, &scroll_vars.scroll_y, + (view->persistent.id) + 1, is_new_target)){ + result.is_animating = 1; + } + + scroll_vars.prev_target_x = scroll_vars.target_x; + scroll_vars.prev_target_y = scroll_vars.target_y; + + result.vars = scroll_vars; + } + } + + return(result); +} + +internal i32 +draw_file_loaded(View *view, i32_Rect rect, b32 is_active, Render_Target *target){ + Models *models = view->persistent.models; + Editing_File *file = view->file_data.file; + Style *style = main_style(models); + i32 line_height = view->font_height; + + i32 max_x = rect.x1 - rect.x0; + i32 max_y = rect.y1 - rect.y0 + line_height; + + Assert(file && !file->is_dummy && buffer_good(&file->state.buffer)); + + b32 tokens_use = 0; + Cpp_Token_Stack token_stack = {}; + if (file){ + tokens_use = file->state.tokens_complete && (file->state.token_stack.count > 0); + token_stack = file->state.token_stack; + } + + Partition *part = &models->mem.part; + + Temp_Memory temp = begin_temp_memory(part); + + partition_align(part, 4); + i32 max = partition_remaining(part) / sizeof(Buffer_Render_Item); + Buffer_Render_Item *items = push_array(part, Buffer_Render_Item, max); + + i16 font_id = models->global_font.font_id; + Render_Font *font = get_font_info(models->font_set, font_id)->font; + float *advance_data = 0; + if (font) advance_data = font->advance_data; + + i32 count; + Full_Cursor render_cursor; + Buffer_Render_Options opts = {}; + + f32 *wraps = view->file_data.line_wrap_y; + f32 scroll_x = view->recent->scroll.scroll_x; + f32 scroll_y = view->recent->scroll.scroll_y; + + { + render_cursor = buffer_get_start_cursor(&file->state.buffer, wraps, scroll_y, + !view->file_data.unwrapped_lines, (f32)max_x, advance_data, (f32)line_height); + + view->recent->scroll_i = render_cursor.pos; + + buffer_get_render_data(&file->state.buffer, items, max, &count, + (f32)rect.x0, (f32)rect.y0, + scroll_x, scroll_y, render_cursor, + !view->file_data.unwrapped_lines, + (f32)max_x, (f32)max_y, + advance_data, (f32)line_height, + opts); + } + + Assert(count > 0); + + i32 cursor_begin, cursor_end; + u32 cursor_color, at_cursor_color; + if (view->file_data.show_temp_highlight){ + cursor_begin = view->file_data.temp_highlight.pos; + cursor_end = view->file_data.temp_highlight_end_pos; + cursor_color = style->main.highlight_color; + at_cursor_color = style->main.at_highlight_color; + } + else{ + cursor_begin = view->recent->cursor.pos; + cursor_end = cursor_begin + 1; + cursor_color = style->main.cursor_color; + at_cursor_color = style->main.at_cursor_color; + } + + i32 token_i = 0; + u32 main_color = style->main.default_color; + u32 special_color = style->main.special_character_color; + if (tokens_use){ + Cpp_Get_Token_Result result = cpp_get_token(&token_stack, items->index); + main_color = *style_get_color(style, token_stack.tokens[result.token_index]); + token_i = result.token_index + 1; + } + + u32 mark_color = style->main.mark_color; + Buffer_Render_Item *item = items; + i32 prev_ind = -1; + u32 highlight_color = 0; + u32 highlight_this_color = 0; + + for (i32 i = 0; i < count; ++i, ++item){ + i32 ind = item->index; + highlight_this_color = 0; + if (tokens_use && ind != prev_ind){ + Cpp_Token current_token = token_stack.tokens[token_i-1]; + + if (token_i < token_stack.count){ + if (ind >= token_stack.tokens[token_i].start){ + main_color = + *style_get_color(style, token_stack.tokens[token_i]); + current_token = token_stack.tokens[token_i]; + ++token_i; + } + else if (ind >= current_token.start + current_token.size){ + main_color = 0xFFFFFFFF; + } + } + + if (current_token.type == CPP_TOKEN_JUNK && + i >= current_token.start && i < current_token.start + current_token.size){ + highlight_color = style->main.highlight_junk_color; + } + else{ + highlight_color = 0; + } + } + + u32 char_color = main_color; + if (item->flags & BRFlag_Special_Character) char_color = special_color; + + f32_Rect char_rect = f32R(item->x0, item->y0, item->x1, item->y1); + if (view->file_data.show_whitespace && highlight_color == 0 && + char_is_whitespace((char)item->glyphid)){ + highlight_this_color = style->main.highlight_white_color; + } + else{ + highlight_this_color = highlight_color; + } + + if (cursor_begin <= ind && ind < cursor_end && (ind != prev_ind || cursor_begin < ind)){ + if (is_active){ + draw_rectangle(target, char_rect, cursor_color); + char_color = at_cursor_color; + } + else{ + if (!view->file_data.show_temp_highlight){ + draw_rectangle_outline(target, char_rect, cursor_color); + } + } + } + else if (highlight_this_color){ + draw_rectangle(target, char_rect, highlight_this_color); + } + + u32 fade_color = 0xFFFF00FF; + f32 fade_amount = 0.f; + + if (file->state.paste_effect.tick_down > 0 && + file->state.paste_effect.start <= ind && + ind < file->state.paste_effect.end){ + fade_color = file->state.paste_effect.color; + fade_amount = (f32)(file->state.paste_effect.tick_down) / file->state.paste_effect.tick_max; + } + + char_color = color_blend(char_color, fade_amount, fade_color); + + if (ind == view->recent->mark && prev_ind != ind){ + draw_rectangle_outline(target, char_rect, mark_color); + } + if (item->glyphid != 0){ + font_draw_glyph(target, font_id, (u8)item->glyphid, + item->x0, item->y0, char_color); + } + prev_ind = ind; + } + + end_temp_memory(temp); + + return(0); +} + +internal void +draw_text_field(Render_Target *target, View *view, i32_Rect rect, String p, String t){ + Models *models = view->persistent.models; + Style *style = main_style(models); + + u32 back_color = style->main.margin_color; + u32 text1_color = style->main.default_color; + u32 text2_color = style->main.file_info_style.pop1_color; + + i32 x = rect.x0; + i32 y = rect.y0 + 2; + + i16 font_id = models->global_font.font_id; + + if (target){ + draw_rectangle(target, rect, back_color); + x = CEIL32(draw_string(target, font_id, p, x, y, text2_color)); + draw_string(target, font_id, t, x, y, text1_color); + } +} + +internal void +draw_text_with_cursor(Render_Target *target, View *view, i32_Rect rect, String s, i32 pos){ + Models *models = view->persistent.models; + Style *style = main_style(models); + + u32 back_color = style->main.margin_color; + u32 text_color = style->main.default_color; + u32 cursor_color = style->main.cursor_color; + u32 at_cursor_color = style->main.at_cursor_color; + + f32 x = (f32)rect.x0; + i32 y = rect.y0 + 2; + + i16 font_id = models->global_font.font_id; + + if (target){ + draw_rectangle(target, rect, back_color); + + if (pos >= 0 && pos < s.size){ + String part1, part2, part3; + i32_Rect cursor_rect; + Render_Font *font = get_font_info(models->font_set, font_id)->font; + + part1 = substr(s, 0, pos); + part2 = substr(s, pos, 1); + part3 = substr(s, pos+1, s.size-pos-1); + + + x = draw_string(target, font_id, part1, FLOOR32(x), y, text_color); + + cursor_rect.x0 = FLOOR32(x); + cursor_rect.x1 = FLOOR32(x) + CEIL32(font->advance_data[s.str[pos]]); + cursor_rect.y0 = y; + cursor_rect.y1 = y + view->font_height; + draw_rectangle(target, cursor_rect, cursor_color); + x = draw_string(target, font_id, part2, FLOOR32(x), y, at_cursor_color); + + draw_string(target, font_id, part3, FLOOR32(x), y, text_color); + } + else{ + draw_string(target, font_id, s, FLOOR32(x), y, text_color); + } + } +} + +internal void +draw_file_bar(Render_Target *target, View *view, Editing_File *file, i32_Rect rect){ + File_Bar bar; + Models *models = view->persistent.models; + Style_Font *font = &models->global_font; + Style *style = main_style(models); + Interactive_Style bar_style = style->main.file_info_style; + + u32 back_color = bar_style.bar_color; + u32 base_color = bar_style.base_color; + u32 pop1_color = bar_style.pop1_color; + u32 pop2_color = bar_style.pop2_color; + + bar.rect = rect; + + if (target){ + bar.font_id = font->font_id; + bar.pos_x = (f32)bar.rect.x0; + bar.pos_y = (f32)bar.rect.y0; + bar.text_shift_y = 2; + bar.text_shift_x = 0; + + draw_rectangle(target, bar.rect, back_color); + if (!file){ + intbar_draw_string(target, &bar, make_lit_string("*NULL*"), base_color); + } + else{ + intbar_draw_string(target, &bar, file->name.live_name, base_color); + intbar_draw_string(target, &bar, make_lit_string(" -"), base_color); + + if (file->is_loading){ + intbar_draw_string(target, &bar, make_lit_string(" loading"), base_color); + } + else{ + char line_number_space[30]; + String line_number = make_fixed_width_string(line_number_space); + append(&line_number, " L#"); + append_int_to_str(view->recent->cursor.line, &line_number); + append(&line_number, " C#"); + append_int_to_str(view->recent->cursor.character, &line_number); + + intbar_draw_string(target, &bar, line_number, base_color); + + intbar_draw_string(target, &bar, make_lit_string(" -"), base_color); + + if (file->settings.dos_write_mode){ + intbar_draw_string(target, &bar, make_lit_string(" dos"), base_color); + } + else{ + intbar_draw_string(target, &bar, make_lit_string(" nix"), base_color); + } + + if (file->state.still_lexing){ + intbar_draw_string(target, &bar, make_lit_string(" parsing"), pop1_color); + } + + if (!file->settings.unimportant){ + switch (buffer_get_sync(file)){ + case SYNC_BEHIND_OS: + { + persist String out_of_sync = make_lit_string(" !"); + intbar_draw_string(target, &bar, out_of_sync, pop2_color); + }break; + + case SYNC_UNSAVED: + { + persist String out_of_sync = make_lit_string(" *"); + intbar_draw_string(target, &bar, out_of_sync, pop2_color); + }break; + } + } + } + } + } +} + +u32 +get_margin_color(i32 active_level, Style *style){ + u32 margin = 0xFFFFFFFF; + + switch (active_level){ + default: + margin = style->main.margin_color; + break; + + case 1: case 2: + margin = style->main.margin_hover_color; + break; + + case 3: case 4: + margin = style->main.margin_active_color; + break; + } + + return(margin); +} + +internal void +draw_color_button(GUI_Target *gui_target, Render_Target *target, View *view, + i32_Rect rect, GUI_id id, u32 fore, u32 back, String text){ + Models *models = view->persistent.models; + + i32 active_level = gui_active_level(gui_target, id); + i16 font_id = models->global_font.font_id; + + if (active_level > 0){ + Swap(u32, back, fore); + } + + draw_rectangle(target, rect, back); + draw_string(target, font_id, text, rect.x0, rect.y0 + 1, fore); +} + +internal void +draw_font_button(GUI_Target *gui_target, Render_Target *target, View *view, + i32_Rect rect, GUI_id id, i16 font_id, String text){ + Models *models = view->persistent.models; + Style *style = main_style(models); + + i32 active_level = gui_active_level(gui_target, id); + + u32 margin = get_margin_color(active_level, style); + u32 back = style->main.back_color; + u32 text_color = style->main.default_color; + + draw_rectangle(target, rect, back); + draw_rectangle_outline(target, rect, margin); + draw_string(target, font_id, text, rect.x0, rect.y0 + 1, text_color); +} + +internal void +draw_fat_option_block(GUI_Target *gui_target, Render_Target *target, View *view, i32_Rect rect, GUI_id id, + String text, String pop, i8 checkbox = -1){ + Models *models = view->persistent.models; + Style *style = main_style(models); + + i32 active_level = gui_active_level(gui_target, id); + i16 font_id = models->global_font.font_id; + + i32_Rect inner = get_inner_rect(rect, 3); + + u32 margin = get_margin_color(active_level, style); + u32 back = style->main.back_color; + u32 text_color = style->main.default_color; + u32 pop_color = style->main.special_character_color; + + i32 h = view->font_height; + i32 x = inner.x0 + 3; + i32 y = inner.y0 + h/2 - 1; + + draw_rectangle(target, inner, back); + draw_margin(target, rect, inner, margin); + + if (checkbox != -1){ + u32 checkbox_color = style->main.margin_active_color; + i32_Rect checkbox_rect = get_inner_rect(inner, (inner.y1 - inner.y0 - h)/2); + checkbox_rect.x1 = checkbox_rect.x0 + (checkbox_rect.y1 - checkbox_rect.y0); + + if (checkbox == 0){ + draw_rectangle_outline(target, checkbox_rect, checkbox_color); + } + else{ + draw_rectangle(target, checkbox_rect, checkbox_color); + } + + x = checkbox_rect.x1 + 3; + } + + x = CEIL32(draw_string(target, font_id, text, x, y, text_color)); + draw_string(target, font_id, pop, x, y, pop_color); +} + +internal void +draw_button(GUI_Target *gui_target, Render_Target *target, View *view, i32_Rect rect, GUI_id id, String text){ + Models *models = view->persistent.models; + Style *style = main_style(models); + + i32 active_level = gui_active_level(gui_target, id); + i16 font_id = models->global_font.font_id; + + i32_Rect inner = get_inner_rect(rect, 3); + + u32 margin = style->main.default_color; + u32 back = get_margin_color(active_level, style); + u32 text_color = style->main.default_color; + + i32 h = view->font_height; + i32 y = inner.y0 + h/2 - 1; + + i32 w = (i32)font_string_width(target, font_id, text); + i32 x = (inner.x1 + inner.x0 - w)/2; + + draw_rectangle(target, inner, back); + draw_rectangle_outline(target, inner, margin); + + draw_string(target, font_id, text, x, y, text_color); +} + +internal void +draw_style_preview(GUI_Target *gui_target, Render_Target *target, View *view, i32_Rect rect, GUI_id id, Style *style){ + Models *models = view->persistent.models; + + i32 active_level = gui_active_level(gui_target, id); + i16 font_id = models->global_font.font_id; + Font_Info *info = get_font_info(models->font_set, font_id); + + i32_Rect inner = get_inner_rect(rect, 3); + + u32 margin_color = get_margin_color(active_level, style); + u32 back = style->main.back_color; + u32 text_color = style->main.default_color; + u32 keyword_color = style->main.keyword_color; + u32 int_constant_color = style->main.int_constant_color; + u32 comment_color = style->main.comment_color; + + draw_margin(target, rect, inner, margin_color); + draw_rectangle(target, inner, back); + + i32 y = inner.y0; + i32 x = inner.x0; + x = CEIL32(draw_string(target, font_id, style->name.str, x, y, text_color)); + i32 font_x = (i32)(inner.x1 - font_string_width(target, font_id, info->name.str)); + if (font_x > x + 10){ + draw_string(target, font_id, info->name.str, font_x, y, text_color); + } + + x = inner.x0; + y += info->height; + x = CEIL32(draw_string(target, font_id, "if", x, y, keyword_color)); + x = CEIL32(draw_string(target, font_id, "(x < ", x, y, text_color)); + x = CEIL32(draw_string(target, font_id, "0", x, y, int_constant_color)); + x = CEIL32(draw_string(target, font_id, ") { x = ", x, y, text_color)); + x = CEIL32(draw_string(target, font_id, "0", x, y, int_constant_color)); + x = CEIL32(draw_string(target, font_id, "; } ", x, y, text_color)); + x = CEIL32(draw_string(target, font_id, "// comment", x, y, comment_color)); + + x = inner.x0; + y += info->height; + draw_string(target, font_id, "[] () {}; * -> +-/ <>= ! && || % ^", x, y, text_color); +} + +internal i32 +do_render_file_view(System_Functions *system, View *view, + View *active, i32_Rect rect, b32 is_active, + Render_Target *target, Input_Summary *user_input){ + + Editing_File *file = view->file_data.file; + i32 result = 0; + + GUI_Session gui_session = {0}; + GUI_Header *h; + GUI_Target *gui_target = &view->gui_target; + GUI_Interpret_Result interpret_result = {0}; + + f32 v; + + if (gui_target->push.pos > 0){ + gui_session_init(&gui_session, gui_target, rect, view->font_height); + + v = view_get_scroll_y(view); + + i32_Rect clip_rect = rect; + draw_push_clip(target, clip_rect); + + for (h = (GUI_Header*)gui_target->push.base; + h->type; + h = NextHeader(h)){ + interpret_result = gui_interpret(gui_target, &gui_session, h, + *view->current_scroll, + view->scroll_region); + + if (interpret_result.has_info){ + if (gui_session.clip_y > clip_rect.y0){ + clip_rect.y0 = gui_session.clip_y; + draw_change_clip(target, clip_rect); + } + + switch (h->type){ + case guicom_top_bar: + { + draw_file_bar(target, view, file, gui_session.rect); + }break; + + case guicom_file: + { + if (view->reinit_scrolling){ + view_reinit_scrolling(view); + } + if (file && file_is_ready(file)){ + result = draw_file_loaded(view, gui_session.rect, is_active, target); + } + }break; + + case guicom_text_field: + { + void *ptr = (h+1); + String p = gui_read_string(&ptr); + String t = gui_read_string(&ptr); + draw_text_field(target, view, gui_session.rect, p, t); + }break; + + case guicom_text_with_cursor: + { + void *ptr = (h+1); + String s = gui_read_string(&ptr); + i32 pos = gui_read_integer(&ptr); + + draw_text_with_cursor(target, view, gui_session.rect, s, pos); + }break; + + case guicom_color_button: + { + GUI_Interactive *b = (GUI_Interactive*)h; + void *ptr = (b + 1); + u32 fore = (u32)gui_read_integer(&ptr); + u32 back = (u32)gui_read_integer(&ptr); + String t = gui_read_string(&ptr); + + draw_color_button(gui_target, target, view, gui_session.rect, b->id, fore, back, t); + }break; + + case guicom_font_button: + { + GUI_Interactive *b = (GUI_Interactive*)h; + void *ptr = (b + 1); + i16 font_id = (i16)gui_read_integer(&ptr); + String t = gui_read_string(&ptr); + + draw_font_button(gui_target, target, view, gui_session.rect, b->id, font_id, t); + }break; + + case guicom_file_option: + { + GUI_Interactive *b = (GUI_Interactive*)h; + void *ptr = (b + 1); + b32 folder = gui_read_integer(&ptr); + String f = gui_read_string(&ptr); + String m = gui_read_string(&ptr); + + if (folder){ + append(&f, system->slash); + } + + draw_fat_option_block(gui_target, target, view, gui_session.rect, b->id, f, m); + }break; + + case guicom_style_preview: + { + GUI_Interactive *b = (GUI_Interactive*)h; + i32 style_index = *(i32*)(b + 1); + Style *style = get_style(view->persistent.models, style_index); + + draw_style_preview(gui_target, target, view, gui_session.rect, b->id, style); + }break; + + case guicom_fixed_option: + case guicom_fixed_option_checkbox: + { + GUI_Interactive *b = (GUI_Interactive*)h; + void *ptr = (b + 1); + String f = gui_read_string(&ptr); + String m = {0}; + i8 status = -1; + if (h->type == guicom_fixed_option_checkbox){ + gui_read_byte(&ptr); + status = (i8)gui_read_byte(&ptr); + } + + draw_fat_option_block(gui_target, target, view, gui_session.rect, b->id, f, m, status); + }break; + + case guicom_button: + { + GUI_Interactive *b = (GUI_Interactive*)h; + void *ptr = (b + 1); + String t = gui_read_string(&ptr); + + draw_button(gui_target, target, view, gui_session.rect, b->id, t); + }break; + + case guicom_scrollable_bar: + { + Models *models = view->persistent.models; + Style *style = main_style(models); + + u32 back; + u32 outline; + + i32_Rect bar = gui_session.rect; + + back = style->main.back_color; + if (is_active){ + outline = style->main.margin_active_color; + } + else{ + outline = style->main.margin_color; + } + + draw_rectangle(target, bar, back); + draw_rectangle_outline(target, bar, outline); + }break; + + case guicom_scrollable_top: + case guicom_scrollable_slider: + case guicom_scrollable_bottom: + { + GUI_id id; + Models *models = view->persistent.models; + Style *style = main_style(models); + i32_Rect box = gui_session.rect; + + i32 active_level; + + u32 back; + u32 outline; + + switch (h->type){ + case guicom_scrollable_top: id = gui_id_scrollbar_top(); break; + case guicom_scrollable_bottom: id = gui_id_scrollbar_bottom(); break; + default: id = gui_id_scrollbar_slider(); break; + } + + active_level = gui_active_level(gui_target, id); + + switch (active_level){ + case 0: back = style->main.back_color; break; + case 1: back = style->main.margin_hover_color; break; + default: back = style->main.margin_active_color; break; + } + + if (is_active){ + outline = style->main.margin_active_color; + } + else{ + outline = style->main.margin_color; + } + + draw_rectangle(target, box, back); + draw_margin(target, box, get_inner_rect(box, 2), outline); + }break; + + case guicom_begin_scrollable_section: + clip_rect.x1 = Min(gui_session.scroll_region.x1, clip_rect.x1); + draw_push_clip(target, clip_rect); + break; + + case guicom_end_scrollable_section: + clip_rect = draw_pop_clip(target); + break; + } + } + } + + draw_pop_clip(target); + } + + return(result); +} + +inline void +file_view_free_buffers(View *view){ + General_Memory *general = &view->persistent.models->mem.general; + if (view->file_data.line_wrap_y){ + general_memory_free(general, view->file_data.line_wrap_y); + view->file_data.line_wrap_y = 0; + } + general_memory_free(general, view->gui_mem); + view->gui_mem = 0; +} + +struct Search_Range{ + Buffer_Type *buffer; + i32 start, size; +}; + +struct Search_Set{ + Search_Range *ranges; + i32 count, max; +}; + +struct Search_Iter{ + String word; + i32 pos; + i32 i; +}; + +struct Search_Match{ + Buffer_Type *buffer; + i32 start, end; + b32 found_match; +}; + +internal void +search_iter_init(General_Memory *general, Search_Iter *iter, i32 size){ + i32 str_max; + + if (iter->word.str == 0){ + str_max = size*2; + iter->word.str = (char*)general_memory_allocate(general, str_max, 0); + iter->word.memory_size = str_max; + } + else if (iter->word.memory_size < size){ + str_max = size*2; + iter->word.str = (char*)general_memory_reallocate_nocopy(general, iter->word.str, str_max, 0); + iter->word.memory_size = str_max; + } + + iter->i = 0; + iter->pos = 0; +} + +internal void +search_set_init(General_Memory *general, Search_Set *set, i32 set_count){ + i32 max; + + if (set->ranges == 0){ + max = set_count*2; + set->ranges = (Search_Range*)general_memory_allocate(general, sizeof(Search_Range)*max, 0); + set->max = max; + } + else if (set->max < set_count){ + max = set_count*2; + set->ranges = (Search_Range*)general_memory_reallocate_nocopy( + general, set->ranges, sizeof(Search_Range)*max, 0); + set->max = max; + } + + set->count = set_count; +} + +internal void +search_hits_table_alloc(General_Memory *general, Table *hits, i32 table_size){ + void *mem; + i32 mem_size; + + mem_size = table_required_mem_size(table_size, sizeof(Offset_String)); + if (hits->hash_array == 0){ + mem = general_memory_allocate(general, mem_size, 0); + } + else{ + mem = general_memory_reallocate_nocopy(general, hits->hash_array, mem_size, 0); + } + table_init_memory(hits, mem, table_size, sizeof(Offset_String)); +} + +internal void +search_hits_init(General_Memory *general, Table *hits, String_Space *str, i32 table_size, i32 str_size){ + void *mem; + i32 mem_size; + + if (hits->hash_array == 0){ + search_hits_table_alloc(general, hits, table_size); + } + else if (hits->max < table_size){ + mem_size = table_required_mem_size(table_size, sizeof(Offset_String)); + mem = general_memory_reallocate_nocopy(general, hits->hash_array, mem_size, 0); + table_init_memory(hits, mem, table_size, sizeof(Offset_String)); + } + + if (str->space == 0){ + str->space = (char*)general_memory_allocate(general, str_size, 0); + str->max = str_size; + } + else if (str->max < str_size){ + str->space = (char*)general_memory_reallocate_nocopy(general, str->space, str_size, 0); + str->max = str_size; + } + + str->pos = str->new_pos = 0; + table_clear(hits); +} + +internal b32 +search_hit_add(General_Memory *general, Table *hits, String_Space *space, char *str, i32 len){ + b32 result; + i32 new_size; + Offset_String ostring; + Table new_hits; + + Assert(len != 0); + + ostring = strspace_append(space, str, len); + if (ostring.size == 0){ + new_size = Max(space->max*2, space->max + len); + space->space = (char*)general_memory_reallocate(general, space->space, space->new_pos, new_size, 0); + ostring = strspace_append(space, str, len); + } + + Assert(ostring.size != 0); + + if (table_at_capacity(hits)){ + search_hits_table_alloc(general, &new_hits, hits->max*2); + table_clear(&new_hits); + table_rehash(hits, &new_hits, space->space, tbl_offset_string_hash, tbl_offset_string_compare); + general_memory_free(general, hits->hash_array); + *hits = new_hits; + } + + if (!table_add(hits, &ostring, space->space, tbl_offset_string_hash, tbl_offset_string_compare)){ + result = 1; + strspace_keep_prev(space); + } + else{ + result = 0; + strspace_discard_prev(space); + } + + return(result); +} + +internal Search_Match +search_next_match(Partition *part, Search_Set *set, Search_Iter *iter_){ + Search_Match result = {}; + Search_Iter iter = *iter_; + Search_Range *range; + Temp_Memory temp; + char *spare; + i32 start_pos, end_pos, count; + + temp = begin_temp_memory(part); + spare = push_array(part, char, iter.word.size); + + count = set->count; + for (; iter.i < count;){ + range = set->ranges + iter.i; + + end_pos = range->start + range->size; + + if (iter.pos + iter.word.size < end_pos){ + start_pos = Max(iter.pos, range->start); + result.start = buffer_find_string(range->buffer, start_pos, end_pos, iter.word.str, iter.word.size, spare); + + if (result.start < end_pos){ + iter.pos = result.start + 1; + if (result.start == 0 || !char_is_alpha_numeric(buffer_get_char(range->buffer, result.start - 1))){ + result.end = buffer_seek_word_right_assume_on_word(range->buffer, result.start); + if (result.end < end_pos){ + result.found_match = 1; + result.buffer = range->buffer; + iter.pos = result.end; + break; + } + } + } + else{ + ++iter.i, iter.pos = 0; + } + } + else{ + ++iter.i, iter.pos = 0; + } + } + end_temp_memory(temp); + + *iter_ = iter; + + return(result); +} + +inline void +view_change_size(General_Memory *general, View *view){ + if (view->file_data.file){ + view_measure_wraps(general, view); + view->recent->cursor = view_compute_cursor_from_pos(view, view->recent->cursor.pos); + } +} + +struct Live_Views{ + View *views; + View free_sentinel; + i32 count, max; +}; + +internal View_And_ID +live_set_alloc_view(Live_Views *live_set, Panel *panel, Models *models){ + View_And_ID result = {}; + + Assert(live_set->count < live_set->max); + ++live_set->count; + + result.view = live_set->free_sentinel.next; + result.id = (i32)(result.view - live_set->views); + Assert(result.id == result.view->persistent.id); + + dll_remove(result.view); + memset(get_view_body(result.view), 0, get_view_size()); + + result.view->in_use = 1; + panel->view = result.view; + result.view->panel = panel; + + result.view->persistent.models = models; + result.view->scrub_max = 1; + result.view->current_scroll = &result.view->recent->scroll; + + init_query_set(&result.view->query_set); + + { + i32 gui_mem_size = Kbytes(32); + void *gui_mem = general_memory_allocate(&models->mem.general, gui_mem_size + 8, 0); + result.view->gui_mem = gui_mem; + gui_mem = advance_to_alignment(gui_mem); + result.view->gui_target.push = make_part(gui_mem, gui_mem_size); + } + + return(result); +} + +inline void +live_set_free_view(System_Functions *system, Live_Views *live_set, View *view){ + Assert(live_set->count > 0); + --live_set->count; + file_view_free_buffers(view); + dll_insert(&live_set->free_sentinel, view); + view->in_use = 0; +} + +// BOTTOM + diff --git a/4ed_system.h b/4ed_system.h index 26867dcf..82f12bdd 100644 --- a/4ed_system.h +++ b/4ed_system.h @@ -167,7 +167,7 @@ typedef Job_Callback_Sig(Job_Callback); struct Job_Data{ Job_Callback *callback; void *data[2]; - i32 memory_request; + //i32 memory_request; }; struct Full_Job_Data{ diff --git a/4ed_template.cpp b/4ed_template.cpp index 22be5e61..fc1abfcf 100644 --- a/4ed_template.cpp +++ b/4ed_template.cpp @@ -12,7 +12,7 @@ // NOTE(allen): This is an experiment, BUT remember a lot of people shit on templates. // So if you start getting a wiff of stupidity from this back out immediately! // -// experience 1: no badness, haven't seen any anoying template errors +// experience 1: no badness, haven't seen any annoying template errors // ... template diff --git a/TODO.txt b/TODO.txt index dae85159..e86172d4 100644 --- a/TODO.txt +++ b/TODO.txt @@ -190,15 +190,24 @@ ; HARD BUGS ; [X] reduce cpu consumption -; [?] minimize and reopen problem (reported by two users now, still not reproduced here) ; [X] repainting too slow for resize looks really dumb ; [] fyoucon's segfaults with malloc on win10 ; [] handling cursor in non-client part of window so it doesn't spaz ; [] fill screen right away ; [] how to get fast repaint (do I really need double buffering?) ; [] history breaks when heavily used (disk swaping?) -; [] window stops repainting bug on a handful of machines (Win 10? Driver?) ; +; [] minimize and reopen problem (reported by two users now, still not reproduced here) +; + +; FANCY PANTS IDEAS +; [] pass messages to 'jobs' to try to avoid cancelling them +; if the job still thinks it should be cancelled it will say so +; but otherwise the job can try to incorporate the new info +; without throwing away the progress it has made so far. +; +; + ; PORTING TODOS ; [X] command line parameters diff --git a/win32_4ed.cpp b/win32_4ed.cpp index 67612028..7291f0cf 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -319,6 +319,14 @@ JobThreadProc(LPVOID lpParameter){ i32 cancel_lock = group->cancel_lock0 + thread_index; i32 cancel_cv = group->cancel_cv0 + thread_index; + Thread_Memory *thread_memory = win32vars.thread_memory + thread_index; + + if (thread_memory->size == 0){ + i32 new_size = Kbytes(64); + thread_memory->data = Win32GetMemory(new_size); + thread_memory->size = new_size; + } + for (;;){ u32 read_index = queue->read_position; u32 write_index = queue->write_position; @@ -342,20 +350,7 @@ JobThreadProc(LPVOID lpParameter){ if (safe_running_thread == THREAD_NOT_ASSIGNED){ thread->job_id = full_job->id; thread->running = 1; - Thread_Memory *thread_memory = 0; - // TODO(allen): remove memory_request - if (full_job->job.memory_request != 0){ - thread_memory = win32vars.thread_memory + thread->id - 1; - if (thread_memory->size < full_job->job.memory_request){ - if (thread_memory->data){ - Win32FreeMemory(thread_memory->data); - } - i32 new_size = LargeRoundUp(full_job->job.memory_request, Kbytes(4)); - thread_memory->data = Win32GetMemory(new_size); - thread_memory->size = new_size; - } - } full_job->job.callback(&win32vars.system, thread, thread_memory, full_job->job.data); PostMessage(win32vars.window_handle, WM_4coder_ANIMATE, 0, 0); @@ -1699,6 +1694,27 @@ WinMain(HINSTANCE hInstance, // Threads and Coroutines // + // NOTE(allen): These should come before threads are started! + // Threads now get memory right away and so they use + // the internal_bubble and DEBUG_sysmem_lock + +#if FRED_INTERNAL + win32vars.internal_bubble.next = &win32vars.internal_bubble; + win32vars.internal_bubble.prev = &win32vars.internal_bubble; + win32vars.internal_bubble.flags = MEM_BUBBLE_SYS_DEBUG; + + InitializeCriticalSection(&win32vars.DEBUG_sysmem_lock); +#endif + + for (i32 i = 0; i < LOCK_COUNT; ++i){ + InitializeCriticalSection(&win32vars.locks[i]); + } + + for (i32 i = 0; i < CV_COUNT; ++i){ + InitializeConditionVariable(&win32vars.condition_vars[i]); + } + + Thread_Context background[4]; memset(background, 0, sizeof(background)); win32vars.groups[BACKGROUND_THREADS].threads = background; @@ -1728,12 +1744,6 @@ WinMain(HINSTANCE hInstance, thread->handle = CreateThread(0, 0, JobThreadProc, thread, creation_flag, (LPDWORD)&thread->windows_id); } - Assert(win32vars.locks); - for (i32 i = 0; i < LOCK_COUNT; ++i){ - InitializeCriticalSection(&win32vars.locks[i]); - } - InitializeCriticalSection(&win32vars.DEBUG_sysmem_lock); - ConvertThreadToFiber(0); win32vars.coroutine_free = win32vars.coroutine_data; for (i32 i = 0; i+1 < ArrayCount(win32vars.coroutine_data); ++i){ @@ -1745,12 +1755,6 @@ WinMain(HINSTANCE hInstance, // Memory Initialization // -#if FRED_INTERNAL - win32vars.internal_bubble.next = &win32vars.internal_bubble; - win32vars.internal_bubble.prev = &win32vars.internal_bubble; - win32vars.internal_bubble.flags = MEM_BUBBLE_SYS_DEBUG; -#endif - LPVOID base; #if FRED_INTERNAL base = (LPVOID)Tbytes(1); From f1996a6f1f9e767e4760954f376b0b3d616b28e1 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Wed, 1 Jun 2016 12:03:45 -0400 Subject: [PATCH 24/34] added dpi aware back in --- 4tech_table.cpp | 7 +++++-- win32_4ed.cpp | 33 +++++++++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/4tech_table.cpp b/4tech_table.cpp index 77ba5a3e..fc4257c4 100644 --- a/4tech_table.cpp +++ b/4tech_table.cpp @@ -57,12 +57,13 @@ table_at_capacity(Table *table){ internal b32 table_add(Table *table, void *item, void *arg, Hash_Function *hash_func, Compare_Function *comp_func){ u32 hash, *inspect; - i32 i; + i32 i, start; Assert(table->count * 8 < table->max * 7); - + hash = (hash_func(item, arg) | TableHashMin); i = hash % table->max; + start = i; inspect = table->hash_array + i; while (*inspect >= TableHashMin){ @@ -77,6 +78,7 @@ table_add(Table *table, void *item, void *arg, Hash_Function *hash_func, Compare i = 0; inspect = table->hash_array; } + Assert(i != start); } *inspect = hash; memcpy(table->data_array + i*table->item_size, item, table->item_size); @@ -111,6 +113,7 @@ table_find_pos(Table *table, void *search_key, void *arg, i32 *pos, i32 *index, i = 0; inspect = table->hash_array; } + if (i == start) break; } return(0); diff --git a/win32_4ed.cpp b/win32_4ed.cpp index 7291f0cf..2ead9fd2 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -28,6 +28,8 @@ #include "system_shared.h" +#define SUPPORT_DPI 1 + #define FPS 60 #define frame_useconds (1000000 / FPS) @@ -168,7 +170,9 @@ struct Win32_Vars{ HWND window_handle; Render_Target target; Partition font_part; - +#if SUPPORT_DPI + i32 dpi_x, dpi_y; +#endif u64 count_per_usecond; b32 first; @@ -1137,6 +1141,15 @@ Sys_CLI_End_Update_Sig(system_cli_end_update){ #include "system_shared.cpp" #include "4ed_rendering.cpp" +internal f32 +size_change(i32 dpi_x, i32 dpi_y){ + // TODO(allen): We're just hoping dpi_x == dpi_y for now I guess. + f32 size_x = win32vars.dpi_x / 96.f; + f32 size_y = win32vars.dpi_y / 96.f; + f32 size_max = Max(size_x, size_y); + return(size_max); +} + internal Font_Load_Sig(system_draw_font_load){ if (win32vars.font_part.base == 0){ @@ -1145,6 +1158,10 @@ Font_Load_Sig(system_draw_font_load){ i32 oversample = 2; +#if SUPPORT_DPI + pt_size = ROUND32(pt_size * size_change(win32vars.dpi_x, win32vars.dpi_y)); +#endif + for (b32 success = 0; success == 0;){ success = draw_font_load(&win32vars.font_part, font_out, @@ -1947,9 +1964,18 @@ WinMain(HINSTANCE hInstance, exit(1); } + HDC hdc = GetDC(win32vars.window_handle); - // TODO(allen): not Windows XP compatible, do we care? - // SetProcessDPIAware(); +#if SUPPORT_DPI + // TODO(allen): not Windows XP compatible, how do I handle that? + SetProcessDPIAware(); + + win32vars.dpi_x = GetDeviceCaps(hdc, LOGPIXELSX); + win32vars.dpi_y = GetDeviceCaps(hdc, LOGPIXELSY); +#else + win32vars.dpi_x = 1; + win32vars.dpi_y = 1; +#endif GetClientRect(win32vars.window_handle, &window_rect); @@ -1971,7 +1997,6 @@ WinMain(HINSTANCE hInstance, 0, 0, 0, 0 }; - HDC hdc = GetDC(win32vars.window_handle); { i32 pixel_format; pixel_format = ChoosePixelFormat(hdc, &pfd); From 74a734fd4609c3e6d25d2b8470b32c31f4a5811a Mon Sep 17 00:00:00 2001 From: insofaras Date: Wed, 1 Jun 2016 17:58:57 +0100 Subject: [PATCH 25/34] linux: thread memory, dpi --- linux_4ed.cpp | 125 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 80 insertions(+), 45 deletions(-) diff --git a/linux_4ed.cpp b/linux_4ed.cpp index 63109491..e553c448 100644 --- a/linux_4ed.cpp +++ b/linux_4ed.cpp @@ -72,6 +72,36 @@ #include "system_shared.h" +// +// Linux macros +// + +#define LINUX_MAX_PASTE_CHARS 0x10000L +#define FPS 60L +#define frame_useconds (1000000UL / FPS) + +#define LinuxGetMemory(size) LinuxGetMemory_(size, __LINE__, __FILE__) + +#if FRED_INTERNAL + #define LINUX_FN_DEBUG(fmt, ...) do { \ + fprintf(stderr, "%s: " fmt "\n", __func__, ##__VA_ARGS__); \ + } while(0) +#else + #define LINUX_FN_DEBUG(fmt, ...) +#endif + +#if (__cplusplus <= 199711L) + #define static_assert(x, ...) +#endif + +#if defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || _POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700 + #define OLD_STAT_NANO_TIME 0 +#else + #define OLD_STAT_NANO_TIME 1 +#endif + +#define SUPPORT_DPI 1 + // // Linux structs / enums // @@ -175,6 +205,10 @@ struct Linux_Vars{ Partition font_part; +#if SUPPORT_DPI + i32 dpi_x, dpi_y; +#endif + Plat_Settings settings; System_Functions system; App_Functions app; @@ -190,34 +224,6 @@ struct Linux_Vars{ Linux_Coroutine *coroutine_free; }; -// -// Linux macros -// - -#define LINUX_MAX_PASTE_CHARS 0x10000L -#define FPS 60L -#define frame_useconds (1000000UL / FPS) - -#define LinuxGetMemory(size) LinuxGetMemory_(size, __LINE__, __FILE__) - -#if FRED_INTERNAL - #define LINUX_FN_DEBUG(fmt, ...) do { \ - fprintf(stderr, "%s: " fmt "\n", __func__, ##__VA_ARGS__); \ - } while(0) -#else - #define LINUX_FN_DEBUG(fmt, ...) -#endif - -#if (__cplusplus <= 199711L) - #define static_assert(x, ...) -#endif - -#if defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || _POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700 - #define OLD_STAT_NANO_TIME 0 -#else - #define OLD_STAT_NANO_TIME 1 -#endif - // // Linux globals // @@ -913,13 +919,21 @@ internal void* ThreadProc(void* arg){ Thread_Context *thread = (Thread_Context*)arg; Work_Queue *queue = linuxvars.queues + thread->group_id; - Thread_Group* group = linuxvars.groups + thread->group_id; + Thread_Group *group = linuxvars.groups + thread->group_id; i32 thread_index = thread->id - 1; i32 cancel_lock = group->cancel_lock0 + thread_index; i32 cancel_cv = group->cancel_cv0 + thread_index; + Thread_Memory *thread_memory = linuxvars.thread_memory + thread_index; + + if (thread_memory->size == 0){ + i32 new_size = Kbytes(64); + thread_memory->data = LinuxGetMemory(new_size); + thread_memory->size = new_size; + } + for (;;){ u32 read_index = queue->read_position; u32 write_index = queue->write_position; @@ -943,20 +957,7 @@ ThreadProc(void* arg){ if (safe_running_thread == THREAD_NOT_ASSIGNED){ thread->job_id = full_job->id; thread->running = 1; - Thread_Memory *thread_memory = 0; - // TODO(allen): remove memory_request - if (full_job->job.memory_request != 0){ - thread_memory = linuxvars.thread_memory + thread->id - 1; - if (thread_memory->size < full_job->job.memory_request){ - if (thread_memory->data){ - LinuxFreeMemory(thread_memory->data); - } - i32 new_size = LargeRoundUp(full_job->job.memory_request, Kbytes(4)); - thread_memory->data = LinuxGetMemory(new_size); - thread_memory->size = new_size; - } - } full_job->job.callback(&linuxvars.system, thread, thread_memory, full_job->job.data); full_job->running_thread = 0; thread->running = 0; @@ -1131,6 +1132,15 @@ INTERNAL_Sys_Debug_Message_Sig(internal_debug_message){ #include "system_shared.cpp" #include "4ed_rendering.cpp" +internal f32 +size_change(i32 dpi_x, i32 dpi_y){ + // TODO(allen): We're just hoping dpi_x == dpi_y for now I guess. + f32 size_x = linuxvars.dpi_x / 96.f; + f32 size_y = linuxvars.dpi_y / 96.f; + f32 size_max = Max(size_x, size_y); + return(size_max); +} + internal Font_Load_Sig(system_draw_font_load){ b32 success = 0; @@ -1144,6 +1154,10 @@ Font_Load_Sig(system_draw_font_load){ i32 oversample = 2; +#if SUPPORT_DPI + pt_size = ROUND32(pt_size * size_change(linuxvars.dpi_x, linuxvars.dpi_y)); +#endif + for(; attempts < 3; ++attempts){ success = draw_font_load( &linuxvars.font_part, @@ -2062,7 +2076,7 @@ LinuxX11WindowInit(int argc, char** argv, int* WinWidth, int* WinHeight) internal void LinuxHandleX11Events(void) { - XEvent PrevEvent = {}; + static XEvent PrevEvent = {}; b32 should_step = 0; while(XPending(linuxvars.XDisplay)) @@ -2412,7 +2426,7 @@ main(int argc, char **argv) linuxvars.target.max = Mbytes(1); linuxvars.target.push_buffer = (byte*)system_get_memory(linuxvars.target.max); - + // // Read command line // @@ -2520,7 +2534,7 @@ main(int argc, char **argv) linuxvars.coroutine_data[i].next = linuxvars.coroutine_data + i + 1; } - const size_t stack_size = Mbytes(16); + const size_t stack_size = Mbytes(2); for (i32 i = 0; i < ArrayCount(linuxvars.coroutine_data); ++i){ linuxvars.coroutine_data[i].stack.ss_size = stack_size; linuxvars.coroutine_data[i].stack.ss_sp = system_get_memory(stack_size); @@ -2624,6 +2638,27 @@ main(int argc, char **argv) XCreateFontCursor(linuxvars.XDisplay, XC_sb_v_double_arrow) }; + // + // DPI + // + +#if SUPPORT_DPI + { + int scr = DefaultScreen(linuxvars.XDisplay); + + int dw = DisplayWidth(linuxvars.XDisplay, scr); + int dh = DisplayHeight(linuxvars.XDisplay, scr); + + int dw_mm = DisplayWidthMM(linuxvars.XDisplay, scr); + int dh_mm = DisplayHeightMM(linuxvars.XDisplay, scr); + + linuxvars.dpi_x = dw_mm ? dw / (dw_mm / 25.4) : 96; + linuxvars.dpi_y = dh_mm ? dh / (dh_mm / 25.4) : 96; + + fprintf(stderr, "%dx%d - %dmmx%dmm DPI: %dx%d\n", dw, dh, dw_mm, dh_mm, linuxvars.dpi_x, linuxvars.dpi_y); + } +#endif + // // Epoll init // From 5e56483ec0c57e8b31400ac38a0790b69d9c82b0 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Wed, 1 Jun 2016 19:52:06 -0400 Subject: [PATCH 26/34] work on new lexer --- 4cpp_lexer.h | 18 +- 4cpp_lexer_types.h | 18 +- 4ed_file_view.cpp | 46 +- TODO.txt | 3 + test/4cpp_lexer_tables.c | 1429 +++++----------------------------- test/4cpp_new_lexer.h | 413 +++++++--- test/experiment.cpp | 172 ++-- test/fsm_table_generator.cpp | 127 --- 8 files changed, 658 insertions(+), 1568 deletions(-) diff --git a/4cpp_lexer.h b/4cpp_lexer.h index cfd3bf84..3f86a2ff 100644 --- a/4cpp_lexer.h +++ b/4cpp_lexer.h @@ -65,6 +65,19 @@ NOTES ON USE: #include "4cpp_lexer_types.h" +struct Cpp_Lex_Data{ + Cpp_Preprocessor_State pp_state; + int pos; + int complete; +}; + +struct Cpp_Read_Result{ + Cpp_Token token; + int pos; + char newline; + char has_result; +}; + Cpp_File data_as_cpp_file(Data data){ Cpp_File result; @@ -140,7 +153,6 @@ FCPP_LINK bool cpp_push_token_no_merge(Cpp_Token_Stack *stack, Cpp_Token token); FCPP_LINK bool cpp_push_token_nonalloc(Cpp_Token_Stack *stack, Cpp_Token token); inline Cpp_Lex_Data cpp_lex_data_zero() { Cpp_Lex_Data data = {(Cpp_Preprocessor_State)0}; return(data); } -inline Cpp_Token_Stack cpp_token_stack_zero() { Cpp_Token_Stack stack={0}; return(stack); } FCPP_LINK Cpp_Read_Result cpp_lex_step(Cpp_File file, Cpp_Lex_Data *lex); @@ -1266,10 +1278,10 @@ cpp_lex_step(Cpp_File file, Cpp_Lex_Data *lex_data){ } } } - + result.token.state_flags = state_flags; result.has_result = has_result; - + *lex_data = lex; return result; } diff --git a/4cpp_lexer_types.h b/4cpp_lexer_types.h index a33bd3c3..b25a6d1a 100644 --- a/4cpp_lexer_types.h +++ b/4cpp_lexer_types.h @@ -209,23 +209,15 @@ enum Cpp_Preprocessor_State{ CPP_LEX_PP_COUNT }; -struct Cpp_Lex_Data{ - Cpp_Preprocessor_State pp_state; - int pos; - int complete; -}; - -struct Cpp_Read_Result{ - Cpp_Token token; - int pos; - char newline; - char has_result; -}; - struct Cpp_Token_Stack{ Cpp_Token *tokens; int count, max_count; }; +inline Cpp_Token_Stack +cpp_token_stack_zero(){ + Cpp_Token_Stack stack={0}; + return(stack); +} struct Cpp_Token_Merge{ Cpp_Token new_token; diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index 33fed014..ca97d0f2 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -809,6 +809,40 @@ Job_Callback_Sig(job_full_lex){ tokens.max_count = memory->size / sizeof(Cpp_Token); tokens.count = 0; +#if 0 + + b32 still_lexing = 1; + + Lex_Data lex = {0}; + + do{ + i32 result = + cpp_lex_nonalloc(&lex, cpp_file.data, cpp_file.size, &tokens, 2048); + + switch (result){ + case LexNeedChunk: Assert(!"Invalid Path"); break; + + case LexNeedTokenMemory: + if (system->check_cancel(thread)){ + return; + } + system->grow_thread_memory(memory); + tokens.tokens = (Cpp_Token*)memory->data; + tokens.max_count = memory->size / sizeof(Cpp_Token); + break; + + case LexHitTokenLimit: + if (system->check_cancel(thread)){ + return; + } + break; + + case LexFinished: still_lexing = 0; break; + } + } while (still_lexing); + +#else + Cpp_Lex_Data status = {}; do{ @@ -836,6 +870,10 @@ Job_Callback_Sig(job_full_lex){ } } while(!status.complete); +#endif + + + i32 new_max = LargeRoundUp(tokens.count+1, Kbytes(1)); system->acquire_lock(FRAME_LOCK); @@ -948,9 +986,9 @@ file_relex_parallel(System_Functions *system, i32 shift_amount = relex_space.count - delete_amount; if (shift_amount != 0){ - int new_count = stack->count + shift_amount; + i32 new_count = stack->count + shift_amount; if (new_count > stack->max_count){ - int new_max = LargeRoundUp(new_count, Kbytes(1)); + i32 new_max = LargeRoundUp(new_count, Kbytes(1)); stack->tokens = (Cpp_Token*) general_memory_reallocate(general, stack->tokens, stack->count*sizeof(Cpp_Token), @@ -958,7 +996,7 @@ file_relex_parallel(System_Functions *system, stack->max_count = new_max; } - int shift_size = stack->count - relex_end; + i32 shift_size = stack->count - relex_end; if (shift_size > 0){ Cpp_Token *old_base = stack->tokens + relex_end; memmove(old_base + shift_amount, old_base, @@ -3238,7 +3276,6 @@ try_kill_file(System_Functions *system, Models *models, } else{ kill_file(system, models, file, string_zero()); - view_show_file(view); } } } @@ -3286,6 +3323,7 @@ interactive_view_complete(System_Functions *system, View *view, String dest, i32 case IAct_Kill: try_kill_file(system, models, 0, 0, dest); + view_show_file(view); break; case IAct_Sure_To_Close: diff --git a/TODO.txt b/TODO.txt index e86172d4..ed15ee12 100644 --- a/TODO.txt +++ b/TODO.txt @@ -99,6 +99,9 @@ ; [X] feedback messages ; [X] feedback message API ; [X] kill rect +; [X] add high DPI support +; +; [] OS font rendering ; ; [] file status in custom API ; [] user file bar string diff --git a/test/4cpp_lexer_tables.c b/test/4cpp_lexer_tables.c index a801c884..5b231e08 100644 --- a/test/4cpp_lexer_tables.c +++ b/test/4cpp_lexer_tables.c @@ -35,34 +35,34 @@ const int num_main_fsm_eq_classes = 29; unsigned char main_fsm_table[] = { 39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77, - 0, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 0, 1,41, 3, 4, 5, 5, 7, 8, 8,49,50,51,52,53,54,55,56,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 0, 1,41, 3, 4, 5, 6, 7, 8, 9,49,50,51,52,53,54,55,17,18,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -37, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 7, 1,41, 3, 4, 5, 4,46,47, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -42, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -39, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -34, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -29, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 4, 1,41, 3,43,44, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -33, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,19,17,17,20,20,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -31, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -27, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,14,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -21, 1,41, 3, 4, 5, 4, 7, 8, 7,12,12,51,52,53,54,55,17,17,19,19,22,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -16, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,17,17,17,19,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 0,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 0,40,41, 3, 4, 5, 5, 7, 8, 8,49,50,51,52,53,54,55,56,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 0,40,41, 3, 4, 5, 6, 7, 8, 9,49,50,51,52,53,54,55,17,18,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +37,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 7,40,41, 3, 4, 5, 4,46,47, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +42,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +39,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +34,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +29,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 4,40,41, 3,43,44, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +33,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,19,17,17,20,20,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +31,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +27,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,14,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +21,40,41, 3, 4, 5, 4, 7, 8, 7,12,12,51,52,53,54,55,17,17,19,19,22,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +16,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,17,17,17,19,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, 11, 1,41, 3, 4, 5, 4, 7, 8, 7,10,10,12,14,14,15,55,17,17,19,19,12,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, 10, 1,41, 3, 4, 5, 4, 7, 8, 7,10,10,12,14,14,15,55,17,17,19,19,12,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -32, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -23, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,24,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -36, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -25, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,26,65,28,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -39, 1,41, 3, 6, 6, 4, 9, 9, 7,49,50,51,52,53,54,55,18,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -35, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,13,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,15,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -30, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +32,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +23,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,24,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +36,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +25,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,26,65,28,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +39,40,41, 3, 6, 6, 4, 9, 9, 7,49,50,51,52,53,54,55,18,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +35,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,13,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,15,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +30,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, }; unsigned short pp_include_fsm_eq_classes[] = { @@ -88,34 +88,34 @@ const int num_pp_macro_fsm_eq_classes = 29; unsigned char pp_macro_fsm_table[] = { 39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77, - 0, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 0, 1,41, 3, 4, 5, 5, 7, 8, 8,49,50,51,52,53,54,55,56,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 0, 1,41, 3, 4, 5, 6, 7, 8, 9,49,50,51,52,53,54,55,17,18,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -37, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 7, 1,41, 3, 4, 5, 4,46,47, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 2, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -39, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -34, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -29, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 4, 1,41, 3,43,44, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -33, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,19,17,17,20,20,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -31, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -27, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,14,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -21, 1,41, 3, 4, 5, 4, 7, 8, 7,12,12,51,52,53,54,55,17,17,19,19,22,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -16, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,17,17,17,19,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 0,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 0,40,41, 3, 4, 5, 5, 7, 8, 8,49,50,51,52,53,54,55,56,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 0,40,41, 3, 4, 5, 6, 7, 8, 9,49,50,51,52,53,54,55,17,18,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +37,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 7,40,41, 3, 4, 5, 4,46,47, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 2,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +39,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +34,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +29,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 4,40,41, 3,43,44, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +33,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,19,17,17,20,20,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +31,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +27,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,14,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +21,40,41, 3, 4, 5, 4, 7, 8, 7,12,12,51,52,53,54,55,17,17,19,19,22,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +16,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,17,17,17,19,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, 11, 1,41, 3, 4, 5, 4, 7, 8, 7,10,10,12,14,14,15,55,17,17,19,19,12,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, 10, 1,41, 3, 4, 5, 4, 7, 8, 7,10,10,12,14,14,15,55,17,17,19,19,12,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -32, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -23, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,24,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -36, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -25, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,26,65,28,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -39, 1,41, 3, 6, 6, 4, 9, 9, 7,49,50,51,52,53,54,55,18,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -35, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,13,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,15,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -30, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +32,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +23,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,24,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +36,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +25,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,26,65,28,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +39,40,41, 3, 6, 6, 4, 9, 9, 7,49,50,51,52,53,54,55,18,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +35,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,13,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,15,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +30,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, }; unsigned short pp_identifier_fsm_eq_classes[] = { @@ -126,34 +126,34 @@ const int num_pp_identifier_fsm_eq_classes = 29; unsigned char pp_identifier_fsm_table[] = { 39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77, - 0, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 0, 1,41, 3, 4, 5, 5, 7, 8, 8,49,50,51,52,53,54,55,56,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 0, 1,41, 3, 4, 5, 6, 7, 8, 9,49,50,51,52,53,54,55,17,18,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -37, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 7, 1,41, 3, 4, 5, 4,46,47, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 2, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -39, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -34, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -29, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 4, 1,41, 3,43,44, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -33, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,19,17,17,20,20,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -31, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -27, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,14,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -21, 1,41, 3, 4, 5, 4, 7, 8, 7,12,12,51,52,53,54,55,17,17,19,19,22,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -16, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,17,17,17,19,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 0,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 0,40,41, 3, 4, 5, 5, 7, 8, 8,49,50,51,52,53,54,55,56,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 0,40,41, 3, 4, 5, 6, 7, 8, 9,49,50,51,52,53,54,55,17,18,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +37,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 7,40,41, 3, 4, 5, 4,46,47, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 2,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +39,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +34,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +29,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 4,40,41, 3,43,44, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +33,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,19,17,17,20,20,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +31,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +27,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,14,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +21,40,41, 3, 4, 5, 4, 7, 8, 7,12,12,51,52,53,54,55,17,17,19,19,22,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +16,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,17,17,17,19,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, 11, 1,41, 3, 4, 5, 4, 7, 8, 7,10,10,12,14,14,15,55,17,17,19,19,12,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, 10, 1,41, 3, 4, 5, 4, 7, 8, 7,10,10,12,14,14,15,55,17,17,19,19,12,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -32, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -23, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,24,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -36, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -25, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,26,65,28,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -39, 1,41, 3, 6, 6, 4, 9, 9, 7,49,50,51,52,53,54,55,18,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -35, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,13,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,15,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -30, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +32,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +23,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,24,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +36,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +25,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,26,65,28,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +39,40,41, 3, 6, 6, 4, 9, 9, 7,49,50,51,52,53,54,55,18,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +35,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,13,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,15,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +30,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, }; unsigned short pp_body_if_fsm_eq_classes[] = { @@ -164,34 +164,34 @@ const int num_pp_body_if_fsm_eq_classes = 29; unsigned char pp_body_if_fsm_table[] = { 39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77, - 0, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 0, 1,41, 3, 4, 5, 5, 7, 8, 8,49,50,51,52,53,54,55,56,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 0, 1,41, 3, 4, 5, 6, 7, 8, 9,49,50,51,52,53,54,55,17,18,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -37, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 7, 1,41, 3, 4, 5, 4,46,47, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 2, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -39, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -34, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -29, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 4, 1,41, 3,43,44, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -33, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,19,17,17,20,20,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -31, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -27, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,14,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -21, 1,41, 3, 4, 5, 4, 7, 8, 7,12,12,51,52,53,54,55,17,17,19,19,22,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -16, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,17,17,17,19,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 0,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 0,40,41, 3, 4, 5, 5, 7, 8, 8,49,50,51,52,53,54,55,56,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 0,40,41, 3, 4, 5, 6, 7, 8, 9,49,50,51,52,53,54,55,17,18,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +37,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 7,40,41, 3, 4, 5, 4,46,47, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 2,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +39,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +34,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +29,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 4,40,41, 3,43,44, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +33,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,19,17,17,20,20,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +31,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +27,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,14,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +21,40,41, 3, 4, 5, 4, 7, 8, 7,12,12,51,52,53,54,55,17,17,19,19,22,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +16,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,17,17,17,19,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, 11, 1,41, 3, 4, 5, 4, 7, 8, 7,10,10,12,14,14,15,55,17,17,19,19,12,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, 10, 1,41, 3, 4, 5, 4, 7, 8, 7,10,10,12,14,14,15,55,17,17,19,19,12,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -32, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -23, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,24,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -36, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -25, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,26,65,28,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -39, 1,41, 3, 6, 6, 4, 9, 9, 7,49,50,51,52,53,54,55,18,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -35, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,13,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,15,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -30, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +32,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +23,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,24,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +36,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +25,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,26,65,28,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +39,40,41, 3, 6, 6, 4, 9, 9, 7,49,50,51,52,53,54,55,18,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +35,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,13,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,15,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +30,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, }; unsigned short pp_body_fsm_eq_classes[] = { @@ -202,34 +202,34 @@ const int num_pp_body_fsm_eq_classes = 29; unsigned char pp_body_fsm_table[] = { 39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77, - 0, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 0, 1,41, 3, 4, 5, 5, 7, 8, 8,49,50,51,52,53,54,55,56,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 0, 1,41, 3, 4, 5, 6, 7, 8, 9,49,50,51,52,53,54,55,17,18,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -37, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 7, 1,41, 3, 4, 5, 4,46,47, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 2, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -39, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -34, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -29, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 4, 1,41, 3,43,44, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -33, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,19,17,17,20,20,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -31, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -27, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,14,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -21, 1,41, 3, 4, 5, 4, 7, 8, 7,12,12,51,52,53,54,55,17,17,19,19,22,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -16, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,17,17,17,19,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 0,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 0,40,41, 3, 4, 5, 5, 7, 8, 8,49,50,51,52,53,54,55,56,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 0,40,41, 3, 4, 5, 6, 7, 8, 9,49,50,51,52,53,54,55,17,18,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +37,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 7,40,41, 3, 4, 5, 4,46,47, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 2,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +39,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +34,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +29,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 4,40,41, 3,43,44, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +33,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,19,17,17,20,20,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +31,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +27,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,14,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +21,40,41, 3, 4, 5, 4, 7, 8, 7,12,12,51,52,53,54,55,17,17,19,19,22,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +16,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,17,17,17,19,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, 11, 1,41, 3, 4, 5, 4, 7, 8, 7,10,10,12,14,14,15,55,17,17,19,19,12,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, 10, 1,41, 3, 4, 5, 4, 7, 8, 7,10,10,12,14,14,15,55,17,17,19,19,12,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -32, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -23, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,24,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -36, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -25, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,26,65,28,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -39, 1,41, 3, 6, 6, 4, 9, 9, 7,49,50,51,52,53,54,55,18,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -35, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,13,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,15,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -30, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +32,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +23,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,24,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +36,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +25,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,26,65,28,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +39,40,41, 3, 6, 6, 4, 9, 9, 7,49,50,51,52,53,54,55,18,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +35,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,13,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,15,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +30,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, }; unsigned short pp_number_fsm_eq_classes[] = { @@ -240,34 +240,34 @@ const int num_pp_number_fsm_eq_classes = 29; unsigned char pp_number_fsm_table[] = { 39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77, - 0, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 0, 1,41, 3, 4, 5, 5, 7, 8, 8,49,50,51,52,53,54,55,56,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 0, 1,41, 3, 4, 5, 6, 7, 8, 9,49,50,51,52,53,54,55,17,18,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -37, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 7, 1,41, 3, 4, 5, 4,46,47, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 2, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -39, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -34, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -29, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 4, 1,41, 3,43,44, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -33, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,19,17,17,20,20,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -31, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -27, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,14,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -21, 1,41, 3, 4, 5, 4, 7, 8, 7,12,12,51,52,53,54,55,17,17,19,19,22,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -16, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,17,17,17,19,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 0,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 0,40,41, 3, 4, 5, 5, 7, 8, 8,49,50,51,52,53,54,55,56,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 0,40,41, 3, 4, 5, 6, 7, 8, 9,49,50,51,52,53,54,55,17,18,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +37,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 7,40,41, 3, 4, 5, 4,46,47, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 2,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +39,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +34,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +29,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 4,40,41, 3,43,44, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +33,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,19,17,17,20,20,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +31,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +27,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,14,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +21,40,41, 3, 4, 5, 4, 7, 8, 7,12,12,51,52,53,54,55,17,17,19,19,22,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +16,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,17,17,17,19,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, 11, 1,41, 3, 4, 5, 4, 7, 8, 7,10,10,12,14,14,15,55,17,17,19,19,12,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, 10, 1,41, 3, 4, 5, 4, 7, 8, 7,10,10,12,14,14,15,55,17,17,19,19,12,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -32, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -23, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,24,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -36, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -25, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,26,65,28,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -39, 1,41, 3, 6, 6, 4, 9, 9, 7,49,50,51,52,53,54,55,18,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -35, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,13,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,15,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -30, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +32,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +23,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,24,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +36,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +25,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,26,65,28,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +39,40,41, 3, 6, 6, 4, 9, 9, 7,49,50,51,52,53,54,55,18,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +35,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,13,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,15,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +30,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, }; unsigned short pp_error_fsm_eq_classes[] = { @@ -290,34 +290,34 @@ const int num_pp_junk_fsm_eq_classes = 29; unsigned char pp_junk_fsm_table[] = { 39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77, - 0, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 0, 1,41, 3, 4, 5, 5, 7, 8, 8,49,50,51,52,53,54,55,56,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 0, 1,41, 3, 4, 5, 6, 7, 8, 9,49,50,51,52,53,54,55,17,18,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -37, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 7, 1,41, 3, 4, 5, 4,46,47, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 2, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -39, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -34, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -29, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, - 4, 1,41, 3,43,44, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -33, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,19,17,17,20,20,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -31, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -27, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,14,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -21, 1,41, 3, 4, 5, 4, 7, 8, 7,12,12,51,52,53,54,55,17,17,19,19,22,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -16, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,17,17,17,19,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 0,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 0,40,41, 3, 4, 5, 5, 7, 8, 8,49,50,51,52,53,54,55,56,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 0,40,41, 3, 4, 5, 6, 7, 8, 9,49,50,51,52,53,54,55,17,18,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +37,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 7,40,41, 3, 4, 5, 4,46,47, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 2,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +39,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +34,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +29,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 4,40,41, 3,43,44, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +33,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,19,17,17,20,20,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +31,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +27,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,14,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +21,40,41, 3, 4, 5, 4, 7, 8, 7,12,12,51,52,53,54,55,17,17,19,19,22,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +16,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,17,17,17,19,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, 11, 1,41, 3, 4, 5, 4, 7, 8, 7,10,10,12,14,14,15,55,17,17,19,19,12,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, 10, 1,41, 3, 4, 5, 4, 7, 8, 7,10,10,12,14,14,15,55,17,17,19,19,12,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -32, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -23, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,24,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -36, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -25, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,26,65,28,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -39, 1,41, 3, 6, 6, 4, 9, 9, 7,49,50,51,52,53,54,55,18,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -35, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,13,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -40, 1,41, 3, 4, 5, 4, 7, 8, 7,49,15,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, -30, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +32,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +23,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,24,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +36,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +25,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,26,65,28,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +39,40,41, 3, 6, 6, 4, 9, 9, 7,49,50,51,52,53,54,55,18,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +35,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,50,13,52,53,15,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, + 1, 1,41, 3, 4, 5, 4, 7, 8, 7,49,15,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, +30,40,41, 3, 4, 5, 4, 7, 8, 7,49,50,51,52,53,54,55,17,17,19,19,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,38, }; unsigned short * get_eq_classes[] = { @@ -393,1068 +393,3 @@ unsigned char LSDIR_count = 119; unsigned char pp_directive_terminal_base = 200; -unsigned short keyword_part_0_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,20,40,60,80,100,120,140,160,180, 0, 0,200, 0,220,240,260, 0,280,300,320,340,360,380,400,420, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_0_table_eq_classes = 22; - -unsigned char keyword_part_0_table_table[] = { -75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, - 3,75,31,75,75,75,75,75,52,75,57,75,75,75,75,75,75,75,75,75, - 4,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, -10,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, - 7,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, -15,30,75,75,75,75,75,47,50,75,75,75,75,75,75,75,75,70,75,75, - 2,75,75,75,75,75,75,75,75,75,75,75,62,75,75,75,75,75,75,75, -16,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, -75,28,75,75,75,75,44,75,75,75,56,75,75,75,75,75,75,75,71,75, -12,75,75,75,38,75,43,75,75,75,75,60,75,75,75,75,75,75,75,75, -13,75,32,36,75,75,75,75,75,75,58,75,75,75,75,66,75,75,75,75, - 8,75,75,35,75,75,75,75,75,75,75,75,61,75,64,67,75,75,75,75, - 5,75,33,75,39,75,75,48,51,54,55,59,75,63,75,75,69,75,75,75, -19,75,75,75,75,42,75,75,75,75,75,75,75,75,75,75,75,75,75,75, -17,27,34,75,40,41,75,75,75,75,75,75,75,75,75,75,75,75,75,72, - 6,75,75,37,75,75,75,75,75,75,75,75,75,75,65,75,75,75,75,75, - 1,75,75,75,75,75,46,75,75,75,75,75,75,75,75,75,75,75,75,75, -14,75,75,75,75,75,75,75,53,75,75,75,75,75,75,75,75,75,75,73, -11,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, -18,75,75,75,75,75,45,75,75,75,75,75,75,75,75,75,75,75,75,75, - 9,75,75,75,75,75,75,75,75,75,75,75,75,75,75,68,75,75,75,75, -75,29,75,75,75,75,75,49,75,75,75,75,75,75,75,75,75,75,75,75, -}; - -/* -true -try -*/ -unsigned short keyword_part_1_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4, 0, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,12, 4, 4, 4,16, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_1_table_eq_classes = 5; - -unsigned char keyword_part_1_table_table[] = { -75,75,98,76, -75,75,75,75, -75, 3,75,75, - 1,75,75,75, - 2,75,75,75, -}; - -/* -throw -this -thread_local -*/ -unsigned short keyword_part_2_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,15,15,15,15,15,15,15,15,15,15, 0, 0, 0, 0, 0, 0, 0,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, 0, 0, 0, 0,30, 0,45,15,60,75,90,15,15,15,105,15,15,120,15,15,135,15,15,150,165,15,15,15,180,15,15,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_2_table_eq_classes = 13; - -unsigned char keyword_part_2_table_table[] = { -75,75,75,75,75,86,75,75,75,75,75,75,75,103,103, -75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, -75,75,75,75,75,75,75, 8,75,75,75,75,75,75,75, -75,75,75,75, 6,75,75,75,75,75,75,12,75,75,75, -75,75,75,75,75,75,75,75,75,75,11,75,75,75,75, -75,75,75,75,75,75, 7,75,75,75,75,75,75,75,75, -75, 4,75,75,75,75,75,75,75,75,75,75,75,75,75, - 2,75,75,75,75,75,75,75,75,75,75,75,75,75,75, -75,75,75,75,75,75,75,75, 9,75,75,75,13,75,75, -75, 3,75,75,75,75,75,75,75,10,75,75,75,75,75, - 1,75,75,75,75,75,75,75,75,75,75,75,75,75,75, -75,75,14,75,75,75,75,75,75,75,75,75,75,75,75, -75,75,75, 5,75,75,75,75,75,75,75,75,75,75,75, -}; - -/* -typeid -typedef -typename -*/ -unsigned short keyword_part_3_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,12,12,12,12,12,12,12,12,12,12, 0, 0, 0, 0, 0, 0, 0,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, 0, 0, 0, 0,12, 0,24,12,12,36,48,60,12,12,72,12,12,12,84,96,12,108,12,12,12,12,12,12,12,12,12,12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_3_table_eq_classes = 10; - -unsigned char keyword_part_3_table_table[] = { -75,75,75,75,75,75,93,75,100,75,75,100, -75,75,75,75,75,75,75,75,75,75,75,75, -75,75,75,75,75, 9,75,75,75,75,75,75, -75,75, 4, 6,75,75,75,75,75,75,75,75, -75, 2,75,75, 7,75,75,75,75,75,11,75, -75,75,75,75,75,75,75, 8,75,75,75,75, -75,75, 3,75,75,75,75,75,75,75,75,75, -75,75,75,75,75,75,75,75,75,10,75,75, -75,75, 5,75,75,75,75,75,75,75,75,75, - 1,75,75,75,75,75,75,75,75,75,75,75, -}; - -/* -template -*/ -unsigned short keyword_part_4_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 7, 0,14, 7, 7, 7,21, 7, 7, 7, 7, 7, 7,28,35, 7, 7,42, 7, 7, 7,49, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_4_table_eq_classes = 8; - -unsigned char keyword_part_4_table_table[] = { -75,75,75,75,75,75,100, -75,75,75,75,75,75,75, -75,75,75, 4,75,75,75, -75,75,75,75,75, 6,75, -75,75, 3,75,75,75,75, - 1,75,75,75,75,75,75, -75, 2,75,75,75,75,75, -75,75,75,75, 5,75,75, -}; - -/* -false -*/ -unsigned short keyword_part_5_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4, 0, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4,12, 4, 4, 4, 4, 4, 4,16, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_5_table_eq_classes = 5; - -unsigned char keyword_part_5_table_table[] = { -75,75,75,76, -75,75,75,75, -75,75, 3,75, - 1,75,75,75, -75, 2,75,75, -}; - -/* -float -*/ -unsigned short keyword_part_6_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4, 0, 8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,12, 4, 4, 4, 4,16, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_6_table_eq_classes = 5; - -unsigned char keyword_part_6_table_table[] = { -75,75,75,95, -75,75,75,75, -75, 2,75,75, - 1,75,75,75, -75,75, 3,75, -}; - -/* -for -*/ -unsigned short keyword_part_7_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_7_table_eq_classes = 3; - -unsigned char keyword_part_7_table_table[] = { -75,98, -75,75, - 1,75, -}; - -/* -friend -*/ -unsigned short keyword_part_8_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 5, 0, 5, 5, 5,10,15, 5, 5, 5,20, 5, 5, 5, 5,25, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_8_table_eq_classes = 6; - -unsigned char keyword_part_8_table_table[] = { -75,75,75,75,101, -75,75,75,75,75, -75,75,75, 4,75, -75, 2,75,75,75, - 1,75,75,75,75, -75,75, 3,75,75, -}; - -/* -and -and_eq -*/ -unsigned short keyword_part_9_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0,10, 0, 5, 5, 5,15,20, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,25, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_9_table_eq_classes = 6; - -unsigned char keyword_part_9_table_table[] = { -75,77,75,75,78, -75,75,75,75,75, -75, 2,75,75,75, - 1,75,75,75,75, -75,75, 3,75,75, -75,75,75, 4,75, -}; - -/* -alignof -alignas -*/ -unsigned short keyword_part_10_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 8, 0,16, 8, 8, 8, 8,24,32, 8,40, 8, 8, 8, 8,48,56, 8, 8, 8,64, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_10_table_eq_classes = 9; - -unsigned char keyword_part_10_table_table[] = { -75,75,75,75,75,75,84,103, -75,75,75,75,75,75,75,75, -75,75,75, 5,75,75,75,75, -75,75,75,75, 6,75,75,75, -75, 2,75,75,75,75,75,75, - 1,75,75,75,75,75,75,75, -75,75, 3,75,75,75,75,75, -75,75,75, 4,75,75,75,75, -75,75,75,75,75, 7,75,75, -}; - -/* -asm -*/ -unsigned short keyword_part_11_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_11_table_eq_classes = 3; - -unsigned char keyword_part_11_table_table[] = { -75,98, -75,75, - 1,75, -}; - -/* -bitand -bitor -*/ -unsigned short keyword_part_12_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 7, 0,14, 7, 7,21, 7, 7, 7, 7, 7, 7, 7, 7, 7,28,35, 7, 7,42, 7,49, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_12_table_eq_classes = 8; - -unsigned char keyword_part_12_table_table[] = { -75,75,75,75,75,79,80, -75,75,75,75,75,75,75, -75, 2,75,75,75,75,75, -75,75,75,75, 5,75,75, -75,75, 4,75,75,75,75, -75, 3,75,75,75,75,75, -75,75,75, 6,75,75,75, - 1,75,75,75,75,75,75, -}; - -/* -bool -*/ -unsigned short keyword_part_13_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 3, 3, 9, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_13_table_eq_classes = 4; - -unsigned char keyword_part_13_table_table[] = { -75,75,95, -75,75,75, -75, 2,75, - 1,75,75, -}; - -/* -break -*/ -unsigned short keyword_part_14_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4, 0, 8, 4, 4, 4,12, 4, 4, 4, 4, 4,16, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_14_table_eq_classes = 5; - -unsigned char keyword_part_14_table_table[] = { -75,75,75,98, -75,75,75,75, -75, 2,75,75, - 1,75,75,75, -75,75, 3,75, -}; - -/* -or -or_eq -*/ -unsigned short keyword_part_15_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 8, 0, 4, 4, 4, 4,12, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,16, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_15_table_eq_classes = 5; - -unsigned char keyword_part_15_table_table[] = { -81,75,75,82, -75,75,75,75, - 1,75,75,75, -75, 2,75,75, -75,75, 3,75, -}; - -/* -operator -*/ -unsigned short keyword_part_16_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 7, 0,14, 7, 7, 7,21, 7, 7, 7, 7, 7, 7, 7, 7, 7,28, 7, 7,35, 7,42, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_16_table_eq_classes = 7; - -unsigned char keyword_part_16_table_table[] = { -75,75,75,75,75,75,103, -75,75,75,75,75,75,75, -75,75, 3,75,75,75,75, - 1,75,75,75,75,75,75, -75,75,75,75, 5,75,75, -75, 2,75,75,75, 6,75, -75,75,75, 4,75,75,75, -}; - -/* -sizeof -*/ -unsigned short keyword_part_17_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 5, 0, 5, 5, 5, 5,10,15, 5, 5, 5, 5, 5, 5, 5, 5,20, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_17_table_eq_classes = 6; - -unsigned char keyword_part_17_table_table[] = { -75,75,75,75,83, -75,75,75,75,75, -75, 2,75,75,75, -75,75,75, 4,75, -75,75, 3,75,75, - 1,75,75,75,75, -}; - -/* -short -*/ -unsigned short keyword_part_18_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 4, 4,12, 4,16, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_18_table_eq_classes = 5; - -unsigned char keyword_part_18_table_table[] = { -75,75,75,96, -75,75,75,75, - 1,75,75,75, -75, 2,75,75, -75,75, 3,75, -}; - -/* -switch -*/ -unsigned short keyword_part_19_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 5, 0, 5, 5,10, 5, 5, 5, 5,15,20, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,25, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_19_table_eq_classes = 6; - -unsigned char keyword_part_19_table_table[] = { -75,75,75,75,98, -75,75,75,75,75, -75,75, 3,75,75, -75,75,75, 4,75, - 1,75,75,75,75, -75, 2,75,75,75, -}; - -/* -static_assert -static_cast -struct -static -*/ -unsigned short keyword_part_20_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,20,20,20,20,20,20,20,20,20,20, 0, 0, 0, 0, 0, 0, 0,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, 0, 0, 0, 0,40, 0,60,20,80,20,100,20,20,20,120,20,20,20,20,20,20,20,20,140,160,180,200,20,20,20,20,20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_20_table_eq_classes = 11; - -unsigned char keyword_part_20_table_table[] = { -75,75,75,75,75,102,75,75,75,75,75,75,75,98,75,75,99,75,75,100, -75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, -75,75,75,75,75, 6,75,75,75,75,75,75,75,75,75,75,75,75,75,75, - 1,75,75,75,75,75, 7,75,14,75,75,75,75,75,75,75,75,75,75,75, -75,75,75,75, 5,75, 8,75,75,75,75,75,75,75,75,75,75,18,75,75, -75,75,75,75,75,75,75,75,75,75,11,75,75,75,75,75,75,75,75,75, -75,75,75, 4,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, - 2,75,75,75,75,75,75,75,75,75,75,12,75,75,75,75,75,75,75,75, -75,75,75,75,75,75,75, 9,75,10,75,75,75,75,15,75,75,75,75,75, -75, 3,75,75,75,75,75,75,75,75,75,75,13,75,75,16,75,75,19,75, -75,75,17,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, -}; - -/* -decltype -delete -default -*/ -unsigned short keyword_part_21_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,16,16,16,16,16,16,16,16,16,16, 0, 0, 0, 0, 0, 0, 0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 0, 0, 0, 0,16, 0,32,16,48,16,64,80,16,16,16,16,16,96,16,16,16,112,16,16,16,128,144,16,16,16,160,16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_21_table_eq_classes = 11; - -unsigned char keyword_part_21_table_table[] = { -75,75,75,75,75,75,75,75,85,75,75,88,75,75,75,98, -75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, -75,75,75,12,75,75,75,75,75,75,75,75,75,75,75,75, - 1,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, -75,75, 9,75,75,75,75, 8,75,75,11,75,75,75,75,75, - 3,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, - 2, 4,75,75,75,75,75,75,75,75,75,75,75,14,75,75, -75,75,75,75,75,75, 7,75,75,75,75,75,75,75,75,75, -75,75,75,75, 5,75,75,75,75,10,75,75,75,75,15,75, -75,75,75,75,75,75,75,75,75,75,75,75,13,75,75,75, -75,75,75,75,75, 6,75,75,75,75,75,75,75,75,75,75, -}; - -/* -double -do -*/ -unsigned short keyword_part_22_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 5, 0, 5,10, 5, 5,15, 5, 5, 5, 5, 5, 5,20, 5, 5, 5, 5, 5, 5, 5, 5,25, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_22_table_eq_classes = 6; - -unsigned char keyword_part_22_table_table[] = { -98,75,75,75,95, -75,75,75,75,75, -75, 2,75,75,75, -75,75,75, 4,75, -75,75, 3,75,75, - 1,75,75,75,75, -}; - -/* -dynamic_cast -*/ -unsigned short keyword_part_23_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,11,11,11,11,11,11,11,11,11,11, 0, 0, 0, 0, 0, 0, 0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, 0, 0, 0, 0,22, 0,33,11,44,11,11,11,11,11,55,11,11,11,66,77,11,11,11,11,88,99,11,11,11,11,11,11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_23_table_eq_classes = 10; - -unsigned char keyword_part_23_table_table[] = { -75,75,75,75,75,75,75,75,75,75,99, -75,75,75,75,75,75,75,75,75,75,75, -75,75,75,75,75, 6,75,75,75,75,75, -75, 2,75,75,75,75,75, 8,75,75,75, -75,75,75,75, 5,75, 7,75,75,75,75, -75,75,75, 4,75,75,75,75,75,75,75, -75,75, 3,75,75,75,75,75,75,75,75, - 1,75,75,75,75,75,75,75,75,75,75, -75,75,75,75,75,75,75,75, 9,75,75, -75,75,75,75,75,75,75,75,75,10,75, -}; - -/* -new -*/ -unsigned short keyword_part_24_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_24_table_eq_classes = 3; - -unsigned char keyword_part_24_table_table[] = { -75,87, -75,75, - 1,75, -}; - -/* -not -not_eq -noexcept -*/ -unsigned short keyword_part_25_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,11,11,11,11,11,11,11,11,11,11, 0, 0, 0, 0, 0, 0, 0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, 0, 0, 0, 0,22, 0,11,11,33,11,44,11,11,11,11,11,11,11,11,11,11,55,66,11,11,77,11,11,11,88,11,11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_25_table_eq_classes = 9; - -unsigned char keyword_part_25_table_table[] = { -75,91,75,75,75,92,75,75,75,75,103, -75,75,75,75,75,75,75,75,75,75,75, -75, 3,75,75,75,75,75,75,75,75,75, -75,75,75,75,75,75, 7,75,75,75,75, - 2,75,75, 4,75,75,75, 8,75,75,75, -75,75,75,75,75,75,75,75, 9,75,75, -75,75,75,75, 5,75,75,75,75,75,75, - 1,75,75,75,75,75,75,75,75,10,75, -75,75, 6,75,75,75,75,75,75,75,75, -}; - -/* -namespace -*/ -unsigned short keyword_part_26_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 8, 0,16, 8,24, 8,32, 8, 8, 8, 8, 8, 8, 8,40, 8, 8,48, 8, 8,56, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_26_table_eq_classes = 8; - -unsigned char keyword_part_26_table_table[] = { -75,75,75,75,75,75,75,101, -75,75,75,75,75,75,75,75, -75,75,75,75, 5,75,75,75, -75,75,75,75,75, 6,75,75, -75, 2,75,75,75,75, 7,75, - 1,75,75,75,75,75,75,75, -75,75,75, 4,75,75,75,75, -75,75, 3,75,75,75,75,75, -}; - -/* -nullptr -*/ -unsigned short keyword_part_27_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 6, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,12, 6, 6, 6,18, 6,24, 6,30, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_27_table_eq_classes = 6; - -unsigned char keyword_part_27_table_table[] = { -75,75,75,75,75,103, -75,75,75,75,75,75, - 1, 2,75,75,75,75, -75,75, 3,75,75,75, -75,75,75,75, 5,75, -75,75,75, 4,75,75, -}; - -/* -xor -xor_eq -*/ -unsigned short keyword_part_28_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0,10, 0, 5, 5, 5, 5,15, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,20,25, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_28_table_eq_classes = 6; - -unsigned char keyword_part_28_table_table[] = { -75,89,75,75,90, -75,75,75,75,75, -75, 2,75,75,75, -75,75, 3,75,75, -75,75,75, 4,75, - 1,75,75,75,75, -}; - -/* -compl -const -continue -const_cast -*/ -unsigned short keyword_part_29_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,17,17,17,17,17,17,17,17,17,17, 0, 0, 0, 0, 0, 0, 0,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, 0, 0, 0, 0,34, 0,51,17,68,17,85,17,17,17,102,17,17,119,136,153,17,170,17,17,187,204,221,17,17,17,17,17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_29_table_eq_classes = 14; - -unsigned char keyword_part_29_table_table[] = { -75,75,75,75,94,75,75,97,75,75,75,75,99,75,75,75,98, -75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, -75,75,75,75,75,75,75, 8,75,75,75,75,75,75,75,75,75, -75,75,75,75,75,75,75,75,75,10,75,75,75,75,75,75,75, -75,75,75,75,75,75,75,75, 9,75,75,75,75,75,75,75,75, -75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,16,75, -75,75,75,75,75,75,13,75,75,75,75,75,75,75,75,75,75, -75,75,75, 4,75,75,75,75,75,75,75,75,75,75,75,75,75, - 1,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, - 2,75,75,75,75,75,75,75,75,75,75,75,75,14,75,75,75, -75, 3,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, -75,75, 5,75,75,75,75,75,75,75,11,75,75,75,75,75,75, -75,75, 6,75,75, 7,75,75,75,75,75,12,75,75,75,75,75, -75,75,75,75,75,75,75,75,75,75,75,75,75,75,15,75,75, -}; - -/* -char -*/ -unsigned short keyword_part_30_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 0, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 9, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_30_table_eq_classes = 4; - -unsigned char keyword_part_30_table_table[] = { -75,75,95, -75,75,75, - 1,75,75, -75, 2,75, -}; - -/* -case -catch -*/ -unsigned short keyword_part_31_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 6, 0, 6, 6,12, 6,18, 6, 6,24, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,30,36, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_31_table_eq_classes = 7; - -unsigned char keyword_part_31_table_table[] = { -75,75,75,98,75,98, -75,75,75,75,75,75, -75,75, 4,75,75,75, -75, 3,75,75,75,75, -75,75,75,75, 5,75, - 1,75,75,75,75,75, - 2,75,75,75,75,75, -}; - -/* -class -*/ -unsigned short keyword_part_32_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4, 0, 8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,12, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_32_table_eq_classes = 4; - -unsigned char keyword_part_32_table_table[] = { -75,75,75,100, -75,75,75,75, - 1,75,75,75, -75, 2, 3,75, -}; - -/* -void -volatile -*/ -unsigned short keyword_part_33_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 9, 0,18, 9, 9,27,36, 9, 9, 9,45, 9, 9,54, 9, 9, 9, 9, 9, 9, 9,63, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_33_table_eq_classes = 8; - -unsigned char keyword_part_33_table_table[] = { -75,75,75,95,75,75,75,75,97, -75,75,75,75,75,75,75,75,75, -75,75, 4,75,75,75,75,75,75, -75, 3,75,75,75,75,75,75,75, -75,75,75,75,75,75,75, 8,75, - 1,75,75,75,75, 6,75,75,75, - 2,75,75,75,75,75, 7,75,75, -75,75,75,75, 5,75,75,75,75, -}; - -/* -virtual -*/ -unsigned short keyword_part_34_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 6, 0,12, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,18, 6, 6, 6, 6, 6,24, 6,30,36, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_34_table_eq_classes = 7; - -unsigned char keyword_part_34_table_table[] = { -75,75,75,75,75,102, -75,75,75,75,75,75, -75,75,75, 4,75,75, -75,75,75,75, 5,75, - 1,75,75,75,75,75, -75, 2,75,75,75,75, -75,75, 3,75,75,75, -}; - -/* -int -inline -*/ -unsigned short keyword_part_35_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 6, 0, 6, 6, 6, 6,12, 6, 6, 6,18, 6, 6,24, 6,30, 6, 6, 6, 6, 6,36, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_35_table_eq_classes = 7; - -unsigned char keyword_part_35_table_table[] = { -75,95,75,75,75,102, -75,75,75,75,75,75, -75,75,75,75, 5,75, -75,75, 3,75,75,75, - 2,75,75,75,75,75, -75,75,75, 4,75,75, - 1,75,75,75,75,75, -}; - -/* -if -*/ -unsigned short keyword_part_36_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_36_table_eq_classes = 2; - -unsigned char keyword_part_36_table_table[] = { -98, -75, -}; - -/* -long -*/ -unsigned short keyword_part_37_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 0, 3, 3, 3, 3, 3, 3, 6, 3, 3, 3, 3, 3, 3, 9, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_37_table_eq_classes = 4; - -unsigned char keyword_part_37_table_table[] = { -75,75,96, -75,75,75, -75, 2,75, - 1,75,75, -}; - -/* -unsigned -union -*/ -unsigned short keyword_part_38_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10,10,10,10,10,10,10,10,10,10, 0, 0, 0, 0, 0, 0, 0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, 0, 0, 0, 0,10, 0,10,10,10,20,30,10,40,10,50,10,10,10,10,60,70,10,10,10,80,10,10,10,10,10,10,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_38_table_eq_classes = 9; - -unsigned char keyword_part_38_table_table[] = { -75,75,75,75,75,75,75,96,75,100, -75,75,75,75,75,75,75,75,75,75, -75,75,75,75,75,75, 7,75,75,75, -75,75,75,75,75, 6,75,75,75,75, -75,75,75, 4,75,75,75,75,75,75, - 2, 3,75,75,75,75,75,75,75,75, -75,75,75,75, 5,75,75,75, 9,75, -75,75, 8,75,75,75,75,75,75,75, - 1,75,75,75,75,75,75,75,75,75, -}; - -/* -using -*/ -unsigned short keyword_part_39_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4, 0, 4, 4, 4, 4, 4, 4, 8, 4,12, 4, 4, 4, 4,16, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_39_table_eq_classes = 5; - -unsigned char keyword_part_39_table_table[] = { -75,75,75,101, -75,75,75,75, -75,75, 3,75, - 1,75,75,75, -75, 2,75,75, -}; - -/* -else -*/ -unsigned short keyword_part_40_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 0, 3, 3, 3, 3, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 9, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_40_table_eq_classes = 4; - -unsigned char keyword_part_40_table_table[] = { -75,75,98, -75,75,75, -75, 2,75, - 1,75,75, -}; - -/* -enum -*/ -unsigned short keyword_part_41_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 3, 3, 3, 3, 3, 3, 3, 9, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_41_table_eq_classes = 4; - -unsigned char keyword_part_41_table_table[] = { -75,75,100, -75,75,75, -75, 2,75, - 1,75,75, -}; - -/* -extern -export -explicit -*/ -unsigned short keyword_part_42_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,14,14,14,14,14,14,14,14,14,14, 0, 0, 0, 0, 0, 0, 0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, 0, 0, 0, 0,14, 0,14,14,28,14,42,14,14,14,56,14,14,70,14,84,98,112,14,126,14,140,14,14,14,14,14,14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_42_table_eq_classes = 11; - -unsigned char keyword_part_42_table_table[] = { -75,75,75,75,75,102,75,75,75,102,75,75,75,103, -75,75,75,75,75,75,75,75,75,75,75,75,75,75, -75,75,75,75,75,75,75,75,75,75,11,75,75,75, -75, 3,75,75,75,75,75,75,75,75,75,75,75,75, -75,75,75,75,75,75,75,10,75,75,75,12,75,75, -75,75, 7,75,75,75,75,75,75,75,75,75,75,75, -75,75,75,75, 5,75,75,75,75,75,75,75,75,75, -75,75, 6,75,75,75,75,75,75,75,75,75,75,75, - 2,75,75,75,75,75,75,75,75,75,75,75,75,75, -75,75,75, 4,75,75, 8,75,75,75,75,75,75,75, - 1,75,75,75,75,75,75,75, 9,75,75,75,13,75, -}; - -/* -goto -*/ -unsigned short keyword_part_43_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 3, 3, 3, 3, 9, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_43_table_eq_classes = 4; - -unsigned char keyword_part_43_table_table[] = { -75,75,98, -75,75,75, -75, 2,75, - 1,75,75, -}; - -/* -return -reinterpret_cast -register -*/ -unsigned short keyword_part_44_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,22,22,22,22,22,22,22,22,22,22, 0, 0, 0, 0, 0, 0, 0,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, 0, 0, 0, 0,44, 0,66,22,88,22,110,22,132,22,154,22,22,22,22,176,22,198,22,220,242,264,286,22,22,22,22,22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_44_table_eq_classes = 14; - -unsigned char keyword_part_44_table_table[] = { -75,75,75,75,75,75,98,75,75,75,75,75,75,75,75,75,75,75,75,75,75,103, -75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, -75,75,75,75,75,75,75,75,75,75,75,75,75,75,15,75,75,75,75,75,75,75, -75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,74,75,75,75,75,75, -75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,16,75,75,75,75,75,75, -75,75,75,75,75,75,75,75, 9,75,75,75,13,75,75,75,75,75,75,20,75,75, - 3,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, - 2,75,75,17,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, -75,75, 7,75,75, 6,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, -75,75,75,75,75,75,75,75,75,75,11,75,75,75,75,75,75,75,75,75,75,75, -75,75,75,75, 5,75,75,75,75,10,75,12,75,75,75,75,75,75,75,75,21,75, -75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,18,75,75,75,75, - 1,75,75,75,75,75,75, 8,75,75,75,75,75,14,75,75,75,75,19,75,75,75, -75, 4,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, -}; - -/* -while -*/ -unsigned short keyword_part_45_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4, 0, 4, 4, 4, 4, 8, 4, 4, 4,12, 4, 4,16, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_45_table_eq_classes = 5; - -unsigned char keyword_part_45_table_table[] = { -75,75,75,98, -75,75,75,75, -75,75, 3,75, - 1,75,75,75, -75, 2,75,75, -}; - -/* -private -protected -*/ -unsigned short keyword_part_46_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,13,13,13,13,13,13,13,13,13,13, 0, 0, 0, 0, 0, 0, 0,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, 0, 0, 0, 0,13, 0,26,13,39,52,65,13,13,13,78,13,13,13,13,13,91,13,13,13,13,104,13,117,13,13,13,13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_46_table_eq_classes = 10; - -unsigned char keyword_part_46_table_table[] = { -75,75,75,75,75,75,101,75,75,75,75,75,101, -75,75,75,75,75,75,75,75,75,75,75,75,75, -75,75,75, 4,75,75,75,75,75,75,75,75,75, -75,75,75,75,75,75,75,75, 9,75,75,75,75, -75,75,75,75,75,75,75,75,75,75,75,12,75, -75,75,75,75,75, 6,75, 8,75,75,11,75,75, - 1,75,75,75,75,75,75,75,75,75,75,75,75, - 2,75,75,75,75,75,75,75,75,75,75,75,75, -75,75, 7,75, 5,75,75,75,75,10,75,75,75, -75, 3,75,75,75,75,75,75,75,75,75,75,75, -}; - -/* -public -*/ -unsigned short keyword_part_47_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 5, 0, 5,10,15, 5, 5, 5, 5, 5,20, 5, 5,25, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_47_table_eq_classes = 6; - -unsigned char keyword_part_47_table_table[] = { -75,75,75,75,101, -75,75,75,75,75, - 1,75,75,75,75, -75,75,75, 4,75, -75,75, 3,75,75, -75, 2,75,75,75, -}; - -/* -reinterpret_cast -*/ -unsigned short keyword_part_48_table_eq_classes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 9, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const int num_keyword_part_48_table_eq_classes = 4; - -unsigned char keyword_part_48_table_table[] = { -75,75,99, -75,75,75, - 1,75,75, -75, 2,75, -}; - -unsigned short * key_eq_class_tables[] = { -keyword_part_0_table_eq_classes, -keyword_part_1_table_eq_classes, -keyword_part_2_table_eq_classes, -keyword_part_3_table_eq_classes, -keyword_part_4_table_eq_classes, -keyword_part_5_table_eq_classes, -keyword_part_6_table_eq_classes, -keyword_part_7_table_eq_classes, -keyword_part_8_table_eq_classes, -keyword_part_9_table_eq_classes, -keyword_part_10_table_eq_classes, -keyword_part_11_table_eq_classes, -keyword_part_12_table_eq_classes, -keyword_part_13_table_eq_classes, -keyword_part_14_table_eq_classes, -keyword_part_15_table_eq_classes, -keyword_part_16_table_eq_classes, -keyword_part_17_table_eq_classes, -keyword_part_18_table_eq_classes, -keyword_part_19_table_eq_classes, -keyword_part_20_table_eq_classes, -keyword_part_21_table_eq_classes, -keyword_part_22_table_eq_classes, -keyword_part_23_table_eq_classes, -keyword_part_24_table_eq_classes, -keyword_part_25_table_eq_classes, -keyword_part_26_table_eq_classes, -keyword_part_27_table_eq_classes, -keyword_part_28_table_eq_classes, -keyword_part_29_table_eq_classes, -keyword_part_30_table_eq_classes, -keyword_part_31_table_eq_classes, -keyword_part_32_table_eq_classes, -keyword_part_33_table_eq_classes, -keyword_part_34_table_eq_classes, -keyword_part_35_table_eq_classes, -keyword_part_36_table_eq_classes, -keyword_part_37_table_eq_classes, -keyword_part_38_table_eq_classes, -keyword_part_39_table_eq_classes, -keyword_part_40_table_eq_classes, -keyword_part_41_table_eq_classes, -keyword_part_42_table_eq_classes, -keyword_part_43_table_eq_classes, -keyword_part_44_table_eq_classes, -keyword_part_45_table_eq_classes, -keyword_part_46_table_eq_classes, -keyword_part_47_table_eq_classes, -keyword_part_48_table_eq_classes, -}; - -unsigned char * key_tables[] = { -keyword_part_0_table_table, -keyword_part_1_table_table, -keyword_part_2_table_table, -keyword_part_3_table_table, -keyword_part_4_table_table, -keyword_part_5_table_table, -keyword_part_6_table_table, -keyword_part_7_table_table, -keyword_part_8_table_table, -keyword_part_9_table_table, -keyword_part_10_table_table, -keyword_part_11_table_table, -keyword_part_12_table_table, -keyword_part_13_table_table, -keyword_part_14_table_table, -keyword_part_15_table_table, -keyword_part_16_table_table, -keyword_part_17_table_table, -keyword_part_18_table_table, -keyword_part_19_table_table, -keyword_part_20_table_table, -keyword_part_21_table_table, -keyword_part_22_table_table, -keyword_part_23_table_table, -keyword_part_24_table_table, -keyword_part_25_table_table, -keyword_part_26_table_table, -keyword_part_27_table_table, -keyword_part_28_table_table, -keyword_part_29_table_table, -keyword_part_30_table_table, -keyword_part_31_table_table, -keyword_part_32_table_table, -keyword_part_33_table_table, -keyword_part_34_table_table, -keyword_part_35_table_table, -keyword_part_36_table_table, -keyword_part_37_table_table, -keyword_part_38_table_table, -keyword_part_39_table_table, -keyword_part_40_table_table, -keyword_part_41_table_table, -keyword_part_42_table_table, -keyword_part_43_table_table, -keyword_part_44_table_table, -keyword_part_45_table_table, -keyword_part_46_table_table, -keyword_part_47_table_table, -keyword_part_48_table_table, -}; - -#define LSKEY_table_transition 26 -#define LSKEY_totally_finished 75 diff --git a/test/4cpp_new_lexer.h b/test/4cpp_new_lexer.h index 0240294d..67861d54 100644 --- a/test/4cpp_new_lexer.h +++ b/test/4cpp_new_lexer.h @@ -4,6 +4,7 @@ #ifndef FCPP_NEW_LEXER_INC #define FCPP_NEW_LEXER_INC +#include "..\4cpp_lexer_types.h" #include "4cpp_lexer_fsms.h" #include "4cpp_lexer_tables.c" @@ -286,22 +287,35 @@ cpp_attempt_token_merge(Cpp_Token prev_token, Cpp_Token next_token){ return result; } -lexer_link void -cpp_push_token_nonalloc(Cpp_Token *out_tokens, int *token_i, Cpp_Token token){ +lexer_link int +cpp_place_token_nonalloc(Cpp_Token *out_tokens, int token_i, Cpp_Token token){ Cpp_Token_Merge merge = {(Cpp_Token_Type)0}; Cpp_Token prev_token = {(Cpp_Token_Type)0}; - if (*token_i > 0){ - prev_token = out_tokens[*token_i - 1]; + if (token_i > 0){ + prev_token = out_tokens[token_i - 1]; merge = new_lex::cpp_attempt_token_merge(prev_token, token); if (merge.did_merge){ - out_tokens[*token_i - 1] = merge.new_token; + out_tokens[token_i - 1] = merge.new_token; } } if (!merge.did_merge){ - out_tokens[(*token_i)++] = token; + out_tokens[token_i++] = token; } + + return(token_i); +} + +lexer_link bool +cpp_push_token_nonalloc(Cpp_Token_Stack *out_tokens, Cpp_Token token){ + bool result = 0; + if (out_tokens->count == out_tokens->max_count){ + out_tokens->count = + cpp_place_token_nonalloc(out_tokens->tokens, out_tokens->count, token); + result = 1; + } + return(result); } struct Lex_Data{ @@ -311,15 +325,13 @@ struct Lex_Data{ int pos; int pos_overide; + int chunk_pos; Lex_FSM fsm; Whitespace_FSM wfsm; unsigned char pp_state; unsigned char completed; - unsigned short *key_eq_classes; - unsigned char *key_table; - Cpp_Token token; int __pc__; @@ -335,20 +347,27 @@ struct Lex_Data{ token_stack_out->count = token_i;\ *S_ptr = S; S_ptr->__pc__ = -1; return(n); } +enum Lex_Result{ + LexFinished, + LexNeedChunk, + LexNeedTokenMemory, + LexHitTokenLimit +}; + lexer_link int cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_stack_out){ Lex_Data S = *S_ptr; - + Cpp_Token *out_tokens = token_stack_out->tokens; int token_i = token_stack_out->count; int max_token_i = token_stack_out->max_count; - + Pos_Update_Rule pos_update_rule = PUR_none; - + char c = 0; - - int end_pos = size + S.pos; - chunk -= S.pos; + + int end_pos = size + S.chunk_pos; + chunk -= S.chunk_pos; switch (S.__pc__){ DrCase(1); @@ -357,7 +376,6 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ DrCase(4); DrCase(5); DrCase(6); - DrCase(7); } for (;;){ @@ -372,7 +390,8 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ S.wfsm.white_done = (S.wfsm.pp_state >= LSPP_count); if (S.wfsm.white_done == 0){ - DrYield(4, 1); + S.chunk_pos += size; + DrYield(4, LexNeedChunk); } else break; } @@ -380,7 +399,7 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ S.pp_state = S.wfsm.pp_state; if (S.pp_state >= LSPP_count){ S.pp_state -= LSPP_count; - } + } S.token_start = S.pos; S.tb_pos = 0; @@ -388,19 +407,20 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ for(;;){ unsigned short *eq_classes = get_eq_classes[S.pp_state]; unsigned char *fsm_table = get_table[S.pp_state]; - + for (; S.fsm.state < LS_count && S.pos < end_pos;){ c = chunk[S.pos++]; S.tb[S.tb_pos++] = c; - + int i = S.fsm.state + eq_classes[c]; S.fsm.state = fsm_table[i]; S.fsm.multi_line |= multiline_state_table[S.fsm.state]; } S.fsm.emit_token = (S.fsm.state >= LS_count); - + if (S.fsm.emit_token == 0){ - DrYield(3, 1); + S.chunk_pos += size; + DrYield(3, LexNeedChunk); } else break; } @@ -413,13 +433,13 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ if (S.pp_state == LSPP_include){ switch (S.fsm.state){ case LSINC_default:break; - + case LSINC_quotes: case LSINC_pointy: S.token.type = CPP_TOKEN_INCLUDE_FILE; S.token.flags = 0; break; - + case LSINC_junk: S.token.type = CPP_TOKEN_JUNK; S.token.flags = 0; @@ -433,22 +453,22 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ #define OperCase(op,t) case op: S.token.type = t; break; OperCase('{', CPP_TOKEN_BRACE_OPEN); OperCase('}', CPP_TOKEN_BRACE_CLOSE); - + OperCase('[', CPP_TOKEN_BRACKET_OPEN); OperCase(']', CPP_TOKEN_BRACKET_CLOSE); - + OperCase('(', CPP_TOKEN_PARENTHESE_OPEN); OperCase(')', CPP_TOKEN_PARENTHESE_CLOSE); - + OperCase('~', CPP_TOKEN_TILDE); OperCase(',', CPP_TOKEN_COMMA); OperCase(';', CPP_TOKEN_SEMICOLON); OperCase('?', CPP_TOKEN_TERNARY_QMARK); - + OperCase('@', CPP_TOKEN_JUNK); OperCase('$', CPP_TOKEN_JUNK); #undef OperCase - + case '\\': if (S.pp_state == LSPP_default){ S.token.type = CPP_TOKEN_JUNK; @@ -461,13 +481,14 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ c = chunk[S.pos++]; if (!(c == ' ' || c == '\t' || c == '\r' || c == '\v' || c == '\f')) S.wfsm.white_done = 1; } - + if (S.wfsm.white_done == 0){ - DrYield(1, 1); + S.chunk_pos += size; + DrYield(1, LexNeedChunk); } else break; } - + if (c == '\n'){ S.fsm.emit_token = 0; S.pos_overide = 0; @@ -485,46 +506,10 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ case LS_identifier: { - S.fsm.state = 0; - S.fsm.emit_token = 0; - S.fsm.sub_machine = 0; - --S.pos; - for (;;){ - // TODO(allen): Need to drop down to the instructions to optimize - // this correctly I think. This looks like it will have more branches - // than it needs unless I am very careful. - for (; S.fsm.state < LSKEY_totally_finished && S.pos < end_pos;){ - // TODO(allen): Rebase these super tables so that we don't have - // to do a subtract on the state. - S.key_table = key_tables[S.fsm.sub_machine]; - S.key_eq_classes = key_eq_class_tables[S.fsm.sub_machine]; - for (; S.fsm.state < LSKEY_table_transition && S.pos < end_pos;){ - c = chunk[S.pos++]; - S.fsm.state = S.key_table[S.fsm.state + S.key_eq_classes[c]]; - } - if (S.fsm.state >= LSKEY_table_transition && S.fsm.state < LSKEY_totally_finished){ - S.fsm.sub_machine = S.fsm.state - LSKEY_table_transition; - S.fsm.state = 0; - } - } - S.fsm.emit_token = (S.fsm.int_state >= LSKEY_totally_finished); - - if (S.fsm.emit_token == 0){ - DrYield(7, 1); - } - else break; - } --S.pos; - // TODO(allen): do stuff regarding the actual type of the token - S.token.type = CPP_TOKEN_INTEGER_CONSTANT; - S.token.flags = 0; - -#if 0 - --S.pos; - int word_size = S.pos - S.token_start; - + if (S.pp_state == LSPP_body_if){ if (match(make_string(S.tb, word_size), make_lit_string("defined"))){ S.token.type = CPP_TOKEN_DEFINED; @@ -532,17 +517,17 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ break; } } - + Sub_Match_List_Result sub_match; sub_match = sub_match_list(S.tb, S.tb_pos, 0, bool_lits, word_size); - + if (sub_match.index != -1){ S.token.type = CPP_TOKEN_BOOLEAN_CONSTANT; S.token.flags = CPP_TFLAG_IS_KEYWORD; } else{ sub_match = sub_match_list(S.tb, S.tb_pos, 0, keywords, word_size); - + if (sub_match.index != -1){ String_And_Flag data = keywords.data[sub_match.index]; S.token.type = (Cpp_Token_Type)data.flags; @@ -553,10 +538,8 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ S.token.flags = 0; } } -#endif - }break; - + case LS_pound: S.token.flags = 0; switch (c){ @@ -567,7 +550,7 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ break; } break; - + case LS_pp: { S.fsm.directive_state = LSDIR_default; @@ -578,9 +561,10 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ S.fsm.directive_state = pp_directive_table[S.fsm.directive_state + pp_directive_eq_classes[c]]; } S.fsm.emit_token = (S.fsm.int_state >= LSDIR_count); - + if (S.fsm.emit_token == 0){ - DrYield(6, 1); + S.chunk_pos += size; + DrYield(6, LexNeedChunk); } else break; } @@ -590,13 +574,13 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ S.token.type = type; if (type == CPP_TOKEN_JUNK){ S.token.flags = 0; - } + } else{ S.token.flags = CPP_TFLAG_PP_DIRECTIVE; S.pp_state = (unsigned char)cpp_pp_directive_to_state(S.token.type); - } + } }break; - + case LS_number: case LS_number0: case LS_hex: @@ -609,18 +593,19 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ S.fsm.int_state = int_fsm_table[S.fsm.int_state + int_fsm_eq_classes[c]]; } S.fsm.emit_token = (S.fsm.int_state >= LSINT_count); - + if (S.fsm.emit_token == 0){ - DrYield(5, 1); + S.chunk_pos += size; + DrYield(5, LexNeedChunk); } else break; } --S.pos; - + S.token.type = CPP_TOKEN_INTEGER_CONSTANT; S.token.flags = 0; break; - + case LS_float: case LS_crazy_float0: case LS_crazy_float1: @@ -634,27 +619,27 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ break; } break; - + case LS_char: S.token.type = CPP_TOKEN_CHARACTER_CONSTANT; S.token.flags = 0; break; - + case LS_char_multiline: S.token.type = CPP_TOKEN_CHARACTER_CONSTANT; S.token.flags = CPP_TFLAG_MULTILINE; break; - + case LS_string: S.token.type = CPP_TOKEN_STRING_CONSTANT; S.token.flags = 0; break; - + case LS_string_multiline: S.token.type = CPP_TOKEN_STRING_CONSTANT; S.token.flags = CPP_TFLAG_MULTILINE; break; - + case LS_comment_pre: S.token.flags = CPP_TFLAG_IS_OPERATOR; switch (c){ @@ -665,19 +650,19 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ break; } break; - + case LS_comment: case LS_comment_block_ending: S.token.type = CPP_TOKEN_COMMENT; S.token.flags = 0; pos_update_rule = PUR_unget_whitespace; break; - + case LS_error_message: S.token.type = CPP_TOKEN_ERROR_MESSAGE; S.token.flags = 0; pos_update_rule = PUR_unget_whitespace; break; - + case LS_dot: S.token.flags = CPP_TFLAG_IS_OPERATOR; switch (c){ @@ -688,21 +673,21 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ break; } break; - + case LS_ellipsis: switch (c){ case '.': S.token.flags = CPP_TFLAG_IS_OPERATOR; S.token.type = CPP_TOKEN_ELLIPSIS; break; - + default: S.token.type = CPP_TOKEN_JUNK; pos_update_rule = PUR_back_one; break; } break; - + case LS_less: S.token.flags = CPP_TFLAG_IS_OPERATOR; switch (c){ @@ -713,7 +698,7 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ break; } break; - + case LS_less_less: S.token.flags = CPP_TFLAG_IS_OPERATOR; switch (c){ @@ -724,7 +709,7 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ break; } break; - + case LS_more: S.token.flags = CPP_TFLAG_IS_OPERATOR; switch (c){ @@ -735,7 +720,7 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ break; } break; - + case LS_more_more: S.token.flags = CPP_TFLAG_IS_OPERATOR; switch (c){ @@ -746,7 +731,7 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ break; } break; - + case LS_minus: S.token.flags = CPP_TFLAG_IS_OPERATOR; switch (c){ @@ -758,7 +743,7 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ break; } break; - + case LS_arrow: S.token.flags = CPP_TFLAG_IS_OPERATOR; switch (c){ @@ -769,7 +754,7 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ break; } break; - + case LS_and: S.token.flags = CPP_TFLAG_IS_OPERATOR; switch (c){ @@ -781,7 +766,7 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ break; } break; - + case LS_or: S.token.flags = CPP_TFLAG_IS_OPERATOR; switch (c){ @@ -793,7 +778,7 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ break; } break; - + case LS_plus: S.token.flags = CPP_TFLAG_IS_OPERATOR; switch (c){ @@ -805,7 +790,7 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ break; } break; - + case LS_colon: S.token.flags = CPP_TFLAG_IS_OPERATOR; switch (c){ @@ -816,7 +801,7 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ break; } break; - + case LS_star: S.token.flags = CPP_TFLAG_IS_OPERATOR; switch (c){ @@ -827,7 +812,7 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ break; } break; - + case LS_modulo: S.token.flags = CPP_TFLAG_IS_OPERATOR; switch (c){ @@ -838,7 +823,7 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ break; } break; - + case LS_caret: S.token.flags = CPP_TFLAG_IS_OPERATOR; switch (c){ @@ -849,7 +834,7 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ break; } break; - + case LS_eq: S.token.flags = CPP_TFLAG_IS_OPERATOR; switch (c){ @@ -860,7 +845,7 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ break; } break; - + case LS_bang: S.token.flags = CPP_TFLAG_IS_OPERATOR; switch (c){ @@ -872,12 +857,12 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ } break; } - + switch (pos_update_rule){ case PUR_back_one: --S.pos; break; - + case PUR_unget_whitespace: c = chunk[--S.pos]; while (c == ' ' || c == '\n' || c == '\t' || c == '\r' || c == '\v' || c == '\f'){ @@ -886,7 +871,7 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ ++S.pos; break; } - + if ((S.token.flags & CPP_TFLAG_PP_DIRECTIVE) == 0){ switch (S.pp_state){ case LSPP_include: @@ -895,7 +880,7 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ } S.pp_state = LSPP_junk; break; - + case LSPP_macro_identifier: if (S.fsm.state != LS_identifier){ S.token.type = CPP_TOKEN_JUNK; @@ -905,14 +890,14 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ S.pp_state = LSPP_body; } break; - + case LSPP_identifier: if (S.fsm.state != LS_identifier){ S.token.type = CPP_TOKEN_JUNK; } S.pp_state = LSPP_junk; break; - + case LSPP_number: if (S.token.type != CPP_TOKEN_INTEGER_CONSTANT){ S.token.type = CPP_TOKEN_JUNK; @@ -922,14 +907,14 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ S.pp_state = LSPP_include; } break; - + case LSPP_junk: S.token.type = CPP_TOKEN_JUNK; break; } } } - + if (S.fsm.emit_token){ S.token.start = S.token_start; if (S.pos_overide){ @@ -944,9 +929,9 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ } S.token.state_flags = S.pp_state; - cpp_push_token_nonalloc(out_tokens, &token_i, S.token); + token_i = cpp_place_token_nonalloc(out_tokens, token_i, S.token); if (token_i == max_token_i){ - DrYield(2, 2); + DrYield(2, LexNeedTokenMemory); } } } @@ -957,13 +942,199 @@ cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, Cpp_Token_Stack *token_ } } - DrReturn(0); + DrReturn(LexFinished); } #undef DrYield #undef DrReturn #undef DrCase +lexer_link int +cpp_lex_nonalloc(Lex_Data *S_ptr, char *chunk, int size, + Cpp_Token_Stack *token_stack_out, int max_tokens){ + Cpp_Token_Stack temp_stack = *token_stack_out; + if (temp_stack.max_count > temp_stack.count + max_tokens){ + temp_stack.max_count = temp_stack.count + max_tokens; + } + + int result = cpp_lex_nonalloc(S_ptr, chunk, size, &temp_stack); + + token_stack_out->count = temp_stack.count; + + if (result == LexNeedTokenMemory){ + if (token_stack_out->count < token_stack_out->max_count){ + result = LexHitTokenLimit; + } + } + + return(result); +} + +lexer_link int +cpp_lex_size_nonalloc(Lex_Data *S_ptr, char *chunk, int size, int full_size, + Cpp_Token_Stack *token_stack_out){ + int result = 0; + if (S_ptr->pos >= full_size){ + char end_null = 0; + result = cpp_lex_nonalloc(S_ptr, &end_null, 1, token_stack_out); + } + else{ + result = cpp_lex_nonalloc(S_ptr, chunk, size, token_stack_out); + if (result == LexNeedChunk){ + if (S_ptr->pos >= full_size){ + char end_null = 0; + result = cpp_lex_nonalloc(S_ptr, &end_null, 1, token_stack_out); + } + } + } + return(result); +} + +lexer_link int +cpp_lex_size_nonalloc(Lex_Data *S_ptr, char *chunk, int size, int full_size, + Cpp_Token_Stack *token_stack_out, int max_tokens){ + Cpp_Token_Stack temp_stack = *token_stack_out; + if (temp_stack.max_count > temp_stack.count + max_tokens){ + temp_stack.max_count = temp_stack.count + max_tokens; + } + + int result = cpp_lex_size_nonalloc(S_ptr, chunk, size, full_size, + &temp_stack); + + token_stack_out->count = temp_stack.count; + + if (result == LexNeedTokenMemory){ + if (token_stack_out->count < token_stack_out->max_count){ + result = LexHitTokenLimit; + } + } + + return(result); +} + +#if 0 +lexer_link Cpp_Relex_State +cpp_relex_nonalloc_start(Cpp_File file, Cpp_Token_Stack *stack, + int start, int end, int amount, int tolerance){ + Cpp_Relex_State state; + state.file = file; + state.stack = stack; + state.start = start; + state.end = end; + state.amount = amount; + state.tolerance = tolerance; + + Cpp_Get_Token_Result result = new_lex::cpp_get_token(stack, start); + if (result.token_index <= 0){ + state.start_token_i = 0; + } + else{ + state.start_token_i = result.token_index-1; + } + + result = new_lex::cpp_get_token(stack, end); + if (result.token_index < 0) result.token_index = 0; + else if (end > stack->tokens[result.token_index].start) ++result.token_index; + state.end_token_i = result.token_index; + + state.relex_start = stack->tokens[state.start_token_i].start; + if (start < state.relex_start) state.relex_start = start; + + state.space_request = state.end_token_i - state.start_token_i + tolerance + 1; + + return(state); +} + +// TODO(allen): Eliminate this once we actually store the EOF token +// in the token stack. +inline Cpp_Token +cpp__get_token(Cpp_Token_Stack *stack, Cpp_Token *tokens, int size, int index){ + Cpp_Token result; + if (index < stack->count){ + result = tokens[index]; + } + else{ + result.start = size; + result.size = 0; + result.type = CPP_TOKEN_EOF; + result.flags = 0; + result.state_flags = 0; + } + return result; +} + +FCPP_LINK bool +cpp_relex_nonalloc_main(Cpp_Relex_State *state, Cpp_Token_Stack *relex_stack, int *relex_end){ + Cpp_Token_Stack *stack = state->stack; + Cpp_Token *tokens = stack->tokens; + + new_lex::cpp_shift_token_starts(stack, state->end_token_i, state->amount); + + Lex_Data lex = {}; + lex.pp_state = cpp_token_get_pp_state(tokens[state->start_token_i].state_flags); + lex.pos = state->relex_start; + + int relex_end_i = state->end_token_i; + Cpp_Token match_token = cpp__get_token(stack, tokens, state->file.size, relex_end_i); + Cpp_Token end_token = match_token; + bool went_too_far = 0; + + for (;;){ + Cpp_Read_Result read = cpp_lex_step(state->file, &lex); + if (read.has_result){ + if (read.token.start == end_token.start && + read.token.size == end_token.size && + read.token.flags == end_token.flags && + read.token.state_flags == end_token.state_flags){ + break; + } + cpp_push_token_nonalloc(relex_stack, read.token); + + while (lex.pos > end_token.start && relex_end_i < stack->count){ + ++relex_end_i; + end_token = cpp__get_token(stack, tokens, state->file.size, relex_end_i); + } + if (relex_stack->count == relex_stack->max_count){ + went_too_far = 1; + break; + } + } + if (lex.pos >= state->file.size) break; + } + + if (!went_too_far){ + if (relex_stack->count > 0){ + if (state->start_token_i > 0){ + Cpp_Token_Merge merge = + cpp_attempt_token_merge(tokens[state->start_token_i - 1], + relex_stack->tokens[0]); + if (merge.did_merge){ + --state->start_token_i; + relex_stack->tokens[0] = merge.new_token; + } + } + + if (relex_end_i < state->stack->count){ + Cpp_Token_Merge merge = + cpp_attempt_token_merge(relex_stack->tokens[relex_stack->count-1], + tokens[relex_end_i]); + if (merge.did_merge){ + ++relex_end_i; + relex_stack->tokens[relex_stack->count-1] = merge.new_token; + } + } + } + + *relex_end = relex_end_i; + } + else{ + cpp_shift_token_starts(stack, state->end_token_i, -state->amount); + } + + return went_too_far; +} +#endif + #endif // BOTTOM diff --git a/test/experiment.cpp b/test/experiment.cpp index e7cd8ed9..9f9e260a 100644 --- a/test/experiment.cpp +++ b/test/experiment.cpp @@ -7,6 +7,9 @@ * */ +// TODO(allen): In what corner cases, such as invalid files +// does the new lexer suffer??? + // TOP #include "../4ed_meta.h" @@ -204,104 +207,166 @@ end_t(Times *t){ } static void -run_experiment(Experiment *exp, char *filename, int verbose, int chunks){ +run_experiment(Experiment *exp, char *filename, int verbose, + int chunks, int max_tokens){ String extension = {}; Data file_data; Cpp_File file_cpp; new_lex::Lex_Data ld = {0}; int pass; int k, chunk_size, is_last; - + extension = file_extension(make_string_slowly(filename)); - + if (match(extension, "cpp") || match(extension, "h")){ file_data = dump_file(filename); if (file_data.size < (100 << 10)){ pass = 1; if (verbose >= 0) printf("testing on file: %s\n", filename); exp->test_total++; - + exp->correct_stack.count = 0; exp->testing_stack.count = 0; - - memset(exp->correct_stack.tokens, TOKEN_ARRAY_SIZE, 0); - memset(exp->testing_stack.tokens, TOKEN_ARRAY_SIZE, 0); - + + memset(exp->correct_stack.tokens, 0, TOKEN_ARRAY_SIZE); + memset(exp->testing_stack.tokens, 0, TOKEN_ARRAY_SIZE); + file_cpp.data = (char*)file_data.data; file_cpp.size = file_data.size; - + ld.tb = (char*)malloc(file_data.size + 1); - + { i64 start; - + start = __rdtsc(); cpp_lex_file_nonalloc(file_cpp, &exp->correct_stack, lex_data); time.handcoded += (__rdtsc() - start); - - start = __rdtsc(); - if (chunks){ - int relevant_size = file_data.size + 1; - is_last = 0; - for (k = 0; k < relevant_size; k += chunks){ - chunk_size = chunks; - if (chunk_size + k >= relevant_size){ - chunk_size = relevant_size - k; - is_last = 1; + + if (max_tokens == 0){ + if (chunks){ + start = __rdtsc(); + int relevant_size = file_data.size + 1; + is_last = 0; + for (k = 0; k < relevant_size; k += chunks){ + chunk_size = chunks; + if (chunk_size + k >= relevant_size){ + chunk_size = relevant_size - k; + is_last = 1; + } + + int result = + new_lex::cpp_lex_nonalloc(&ld, + (char*)file_data.data + k, chunk_size, + &exp->testing_stack); + + if (result == new_lex::LexFinished || + result == new_lex::LexNeedTokenMemory) break; } - - int result = new_lex::cpp_lex_nonalloc(&ld, (char*)file_data.data + k, chunk_size, &exp->testing_stack); - if (result == 0 || result == 2) break; + time.fsm += (__rdtsc() - start); + } + else{ + start = __rdtsc(); + new_lex::cpp_lex_nonalloc(&ld, + (char*)file_data.data, file_data.size, + &exp->testing_stack); + time.fsm += (__rdtsc() - start); } } else{ - new_lex::cpp_lex_nonalloc(&ld, (char*)file_data.data, file_data.size, &exp->testing_stack); + if (chunks){ + start = __rdtsc(); + int relevant_size = file_data.size + 1; + is_last = 0; + for (k = 0; k < relevant_size; k += chunks){ + chunk_size = chunks; + if (chunk_size + k >= relevant_size){ + chunk_size = relevant_size - k; + is_last = 1; + } + + int result = 0; + int still_lexing = 1; + do{ + result = + new_lex::cpp_lex_size_nonalloc(&ld, + (char*)file_data.data + k, chunk_size, file_data.size, + &exp->testing_stack, + max_tokens); + if (result == new_lex::LexFinished || + result == new_lex::LexNeedTokenMemory || + result == new_lex::LexNeedChunk){ + still_lexing = 0; + } + } while(still_lexing); + + + if (result == new_lex::LexFinished || + result == new_lex::LexNeedTokenMemory) break; + } + time.fsm += (__rdtsc() - start); + } + else{ + start = __rdtsc(); + int still_lexing = 1; + do{ + int result = + new_lex::cpp_lex_size_nonalloc(&ld, + (char*)file_data.data, file_data.size, file_data.size, + &exp->testing_stack, + max_tokens); + if (result == new_lex::LexFinished || + result == new_lex::LexNeedTokenMemory){ + still_lexing = 0; + } + } while(still_lexing); + time.fsm += (__rdtsc() - start); + } } - time.fsm += (__rdtsc() - start); } - + free(ld.tb); - + if (exp->correct_stack.count != exp->testing_stack.count){ pass = 0; if (verbose >= 0){ printf("error: stack size mismatch %d original and %d testing\n", - exp->correct_stack.count, exp->testing_stack.count); + exp->correct_stack.count, exp->testing_stack.count); } } - + int min_count = exp->correct_stack.count; if (min_count > exp->testing_stack.count) min_count = exp->testing_stack.count; - + for (int j = 0; j < min_count; ++j){ Cpp_Token *correct, *testing; correct = exp->correct_stack.tokens + j; testing = exp->testing_stack.tokens + j; - + if (correct->type != testing->type){ pass = 0; if (verbose >= 1) printf("type mismatch at token %d\n", j); } - + if (correct->start != testing->start || correct->size != testing->size){ pass = 0; if (verbose >= 1){ printf("token range mismatch at token %d\n" - " %d:%d original %d:%d testing\n" - " %.*s original %.*s testing\n", - j, - correct->start, correct->size, testing->start, testing->size, - correct->size, file_cpp.data + correct->start, - testing->size, file_cpp.data + testing->start); + " %d:%d original %d:%d testing\n" + " %.*s original %.*s testing\n", + j, + correct->start, correct->size, testing->start, testing->size, + correct->size, file_cpp.data + correct->start, + testing->size, file_cpp.data + testing->start); } } - + if (correct->flags != testing->flags){ pass = 0; if (verbose >= 1) printf("token flag mismatch at token %d\n", j); } } - + if (pass){ exp->passed_total++; if (verbose >= 0) printf("test passed!\n\n"); @@ -310,7 +375,7 @@ run_experiment(Experiment *exp, char *filename, int verbose, int chunks){ if (verbose >= 0) printf("test failed, you failed, fix it now!\n\n"); } } - + free(file_data.data); } } @@ -338,12 +403,13 @@ show_time(Times t, int repeats, char *type){ int main(){ int repeats = 1; - int verbose_level = 1; - int chunk_start = 0; - int chunk_end = 0; + int verbose_level = 0; + int chunk_start = 32; + int chunk_end = 64; #define TEST_FILE "parser_test1.cpp" -#define SINGLE_ITEM 1 - +#define SINGLE_ITEM 0 + int token_limit = 2; + int chunks = (chunk_start > 0 && chunk_start <= chunk_end); int c = 0; @@ -371,14 +437,14 @@ int main(){ begin_t(&chunk_exp_t); printf("With chunks of %d\n", chunks); for (c = chunk_start; c <= chunk_end; ++c){ - run_experiment(&chunk_exp, BASE_DIR TEST_FILE, 1, c); + run_experiment(&chunk_exp, BASE_DIR TEST_FILE, 1, c, token_limit); } end_t(&chunk_exp_t); } begin_t(&exp_t); printf("Unchunked\n"); - run_experiment(&exp, BASE_DIR TEST_FILE, 1, 0); + run_experiment(&exp, BASE_DIR TEST_FILE, 1, 0, token_limit); end_t(&exp_t); #else @@ -391,19 +457,19 @@ int main(){ if (chunks){ begin_t(&chunk_exp_t); for (c = chunk_start; c <= chunk_end; ++c){ - run_experiment(&chunk_exp, all_files.infos[i].filename.str, verbose_level, c); + run_experiment(&chunk_exp, all_files.infos[i].filename.str, verbose_level, c, token_limit); } end_t(&chunk_exp_t); } - + begin_t(&exp_t); if (verbose_level == -1 && chunks){ for (c = chunk_start; c <= chunk_end; ++c){ - run_experiment(&exp, all_files.infos[i].filename.str, verbose_level, 0); + run_experiment(&exp, all_files.infos[i].filename.str, verbose_level, 0, token_limit); } } else{ - run_experiment(&exp, all_files.infos[i].filename.str, verbose_level, 0); + run_experiment(&exp, all_files.infos[i].filename.str, verbose_level, 0, token_limit); } end_t(&exp_t); } diff --git a/test/fsm_table_generator.cpp b/test/fsm_table_generator.cpp index ba8f5e8b..7fb97479 100644 --- a/test/fsm_table_generator.cpp +++ b/test/fsm_table_generator.cpp @@ -576,97 +576,6 @@ process_match_node(String_And_Flag *input, Match_Node *node, Match_Tree *tree, F } } -FSM_Stack -generate_keyword_fsms(){ - Terminal_Lookup_Table terminal_table; - Cpp_Token_Type type; - - Future_FSM_Stack unfinished_futures; - Match_Tree_Stack tree_stack; - FSM_Stack fsm_stack; - Match_Tree *tree; - FSM *fsm; - Future_FSM *future; - Match_Node *root_node; - FSM_State *root_state; - int i, j; - - memset(terminal_table.type_to_state, 0, sizeof(terminal_table.type_to_state)); - memset(terminal_table.state_to_type, 0, sizeof(terminal_table.state_to_type)); - - for (i = 0; i < ArrayCount(keyword_strings); ++i){ - type = (Cpp_Token_Type)keyword_strings[i].flags; - if (terminal_table.type_to_state[type] == 0){ - terminal_table.type_to_state[type] = terminal_table.state_count; - terminal_table.state_to_type[terminal_table.state_count] = type; - ++terminal_table.state_count; - } - } - - fsm_stack.max = 255; - fsm_stack.count = 0; - fsm_stack.fsms = (FSM*)malloc(sizeof(FSM)*fsm_stack.max); - fsm_stack.table_transition_state = 26; - - tree_stack.max = 255; - tree_stack.count = 0; - tree_stack.trees = (Match_Tree*)malloc(sizeof(Match_Tree)*tree_stack.max); - - unfinished_futures.max = 255; - unfinished_futures.count = 0; - unfinished_futures.futures = (Future_FSM*)malloc(sizeof(Future_FSM)*unfinished_futures.max); - - fsm = get_fsm(&fsm_stack); - tree = get_tree(&tree_stack); - - *fsm = fsm_init(200, fsm_stack.table_transition_state); - *tree = tree_init(200); - - root_state = fsm_get_state(fsm, RealTerminateBase); - root_node = match_get_node(tree); - match_init_node(root_node, ArrayCount(keyword_strings)); - for (i = 0; i < ArrayCount(keyword_strings); ++i){ - root_node->words[i] = i; - } - - root_node->count = ArrayCount(keyword_strings); - root_node->state = root_state; - root_node->index = -1; - - push_future_fsm(&unfinished_futures, root_node); - process_match_node(keyword_strings, root_node, tree, fsm, &terminal_table, 2, &unfinished_futures); - - for (i = 1; i < unfinished_futures.count; ++i){ - future = unfinished_futures.futures + i; - - fsm = get_fsm(&fsm_stack); - tree = get_tree(&tree_stack); - - assert((int)(fsm - fsm_stack.fsms) == i); - - *fsm = fsm_init(200, fsm_stack.table_transition_state); - *tree = tree_init(200); - - root_state = fsm_get_state(fsm, RealTerminateBase); - root_node = match_get_node(tree); - match_copy_init_node(root_node, future->source); - root_node->state = root_state; - - for (j = 0; j < root_node->count; ++j){ - char space[1024]; - sprintf(space, "%s\n", keyword_strings[root_node->words[j]].str); - fsm_add_comment(fsm, space); - } - - process_match_node(keyword_strings, root_node, tree, fsm, &terminal_table, 12, &unfinished_futures); - } - - assert(fsm_stack.count < 255); - fsm_stack.final_state = fsm_stack.table_transition_state + (unsigned char)fsm_stack.count; - - return(fsm_stack); -} - Whitespace_FSM whitespace_skip_fsm(Whitespace_FSM wfsm, char c){ if (wfsm.pp_state != LSPP_default){ @@ -781,7 +690,6 @@ main_fsm(Lex_FSM fsm, unsigned char pp_state, unsigned char c){ case LS_default: if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'){ fsm.state = LS_identifier; - fsm.emit_token = 1; } else if (c >= '1' && c <= '9'){ fsm.state = LS_number; @@ -849,13 +757,11 @@ main_fsm(Lex_FSM fsm, unsigned char pp_state, unsigned char c){ } break; -#if 0 case LS_identifier: if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_')){ fsm.emit_token = 1; } break; -#endif case LS_pound: switch (c){ @@ -1405,39 +1311,6 @@ main(){ render_variable(file, "unsigned char", "LSDIR_count", pp_directive_fsm.count); render_variable(file, "unsigned char", "pp_directive_terminal_base", pp_directive_fsm.terminal_base); - FSM_Stack keyword_fsms = generate_keyword_fsms(); - - char name[1024]; - for (int i = 0; i < keyword_fsms.count; ++i){ - FSM_Tables partial_keywords_table = - generate_table_from_abstract_fsm(keyword_fsms.fsms[i], keyword_fsms.final_state); - if (keyword_fsms.fsms[i].comment){ - render_comment(file, keyword_fsms.fsms[i].comment); - } - - sprintf(name, "keyword_part_%d_table", i); - render_fsm_table(file, partial_keywords_table, name); - } - - begin_ptr_table(file, "short", "key_eq_class_tables"); - for (int i = 0; i < keyword_fsms.count; ++i){ - sprintf(name, "keyword_part_%d_table_eq_classes", i); - do_table_item_direct(file, name, ""); - end_row(file); - } - end_table(file); - - begin_ptr_table(file, "char", "key_tables"); - for (int i = 0; i < keyword_fsms.count; ++i){ - sprintf(name, "keyword_part_%d_table_table", i); - do_table_item_direct(file, name, ""); - end_row(file); - } - end_table(file); - - fprintf(file, "#define LSKEY_table_transition %d\n", (int)(keyword_fsms.table_transition_state)); - fprintf(file, "#define LSKEY_totally_finished %d\n", (int)(keyword_fsms.final_state)); - fclose(file); return(0); } From 93ab33ee844993ae6487e83474d2d34ee0a93bea Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Thu, 2 Jun 2016 08:41:30 -0400 Subject: [PATCH 27/34] fixed EOF paste/scroll bugs - robust against render buffer overflows --- 4ed_file_view.cpp | 41 +++--- 4ed_rendering.cpp | 22 +++- buffer/4coder_buffer_abstract.cpp | 212 +++++++++++++++++++----------- buffer/4coder_shared.cpp | 30 ----- 4 files changed, 174 insertions(+), 131 deletions(-) diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index ca97d0f2..7b717eb8 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -636,6 +636,22 @@ view_compute_lowest_line(View *view){ return lowest_line; } +inline f32 +view_compute_max_target_y(i32 lowest_line, i32 line_height, f32 view_height){ + f32 max_target_y = ((lowest_line+.5f)*line_height) - view_height*.5f; + max_target_y = clamp_bottom(0.f, max_target_y); + return(max_target_y); +} + +inline f32 +view_compute_max_target_y(View *view){ + i32 lowest_line = view_compute_lowest_line(view); + i32 line_height = view->font_height; + f32 view_height = view_file_height(view); + f32 max_target_y = view_compute_max_target_y(lowest_line, line_height, view_height); + return(max_target_y); +} + internal void view_measure_wraps(General_Memory *general, View *view){ Buffer_Type *buffer; @@ -1477,12 +1493,12 @@ view_get_cursor_y(View *view){ #define CursorMinY(m,h) (CursorMinY_(m,h) > 0)?(CursorMinY_(m,h)):(0) internal void -view_move_cursor_to_view(View *view){ +view_move_cursor_to_view(View *view, GUI_Scroll_Vars scroll){ f32 min_target_y = 0; i32 line_height = view->font_height; f32 old_cursor_y = view_get_cursor_y(view); f32 cursor_y = old_cursor_y; - f32 target_y = view->recent->scroll.target_y; + f32 target_y = scroll.target_y; f32 cursor_max_y = CursorMaxY(view_file_height(view), line_height); f32 cursor_min_y = CursorMinY(min_target_y, line_height); @@ -1554,22 +1570,6 @@ file_view_nullify_file(View *view){ view->file_data = file_viewing_data_zero(); } -inline f32 -view_compute_max_target_y(i32 lowest_line, i32 line_height, f32 view_height){ - f32 max_target_y = ((lowest_line+.5f)*line_height) - view_height*.5f; - max_target_y = clamp_bottom(0.f, max_target_y); - return(max_target_y); -} - -internal f32 -view_compute_max_target_y(View *view){ - i32 lowest_line = view_compute_lowest_line(view); - i32 line_height = view->font_height; - f32 view_height = view_file_height(view); - f32 max_target_y = view_compute_max_target_y(lowest_line, line_height, view_height); - return(max_target_y); -} - internal void view_set_file(View *view, Editing_File *file, Models *models){ Font_Info *fnt_info; @@ -3561,12 +3561,15 @@ view_end_cursor_scroll_updates(View *view){ case CursorScroll_Cursor: case CursorScroll_Cursor|CursorScroll_Scroll: + if (view->gui_target.did_file){ + view->recent->scroll.max_y = view_compute_max_target_y(view); + } view_move_view_to_cursor(view, view->current_scroll); gui_post_scroll_vars(&view->gui_target, view->current_scroll, view->scroll_region); break; case CursorScroll_Scroll: - view_move_cursor_to_view(view); + view_move_cursor_to_view(view, view->recent->scroll); gui_post_scroll_vars(&view->gui_target, view->current_scroll, view->scroll_region); break; } diff --git a/4ed_rendering.cpp b/4ed_rendering.cpp index 8a13f632..26a210a8 100644 --- a/4ed_rendering.cpp +++ b/4ed_rendering.cpp @@ -34,28 +34,36 @@ draw_set_color(Render_Target *target, u32 color){ } } -#define PutStruct(s,x) *(s*)(target->push_buffer + target->size) = x; target->size += sizeof(s) +inline void +draw_safe_push(Render_Target *target, i32 size, void *x){ + if (size + target->size <= target->max){ + memcpy(target->push_buffer + target->size, x, size); + target->size += size; + } +} + +#define PutStruct(s,x) draw_safe_push(target, sizeof(s), &x) internal void draw_push_piece(Render_Target *target, Render_Piece_Combined piece){ PutStruct(Render_Piece_Header, piece.header); switch (piece.header.type){ - case piece_type_rectangle: - case piece_type_outline: + case piece_type_rectangle: + case piece_type_outline: PutStruct(Render_Piece_Rectangle, piece.rectangle); break; - case piece_type_gradient: + case piece_type_gradient: PutStruct(Render_Piece_Gradient, piece.gradient); break; - case piece_type_glyph: - case piece_type_mono_glyph: + case piece_type_glyph: + case piece_type_mono_glyph: PutStruct(Render_Piece_Glyph, piece.glyph); break; - case piece_type_mono_glyph_advance: + case piece_type_mono_glyph_advance: PutStruct(Render_Piece_Glyph_Advance, piece.glyph_advance); break; } diff --git a/buffer/4coder_buffer_abstract.cpp b/buffer/4coder_buffer_abstract.cpp index 32ab27f9..f7ec17a3 100644 --- a/buffer/4coder_buffer_abstract.cpp +++ b/buffer/4coder_buffer_abstract.cpp @@ -1313,6 +1313,42 @@ buffer_get_start_cursor(Buffer_Type *buffer, float *wraps, float scroll_y, return(result); } +#define BRFlag_Special_Character (1 << 0) + +typedef struct Buffer_Render_Item{ + int index; + unsigned short glyphid; + unsigned short flags; + float x0, y0; + float x1, y1; +} Buffer_Render_Item; + +inline_4tech void +write_render_item(Buffer_Render_Item *item, + int index, + unsigned short glyphid, + float x, float y, + float w, float h){ + item->index = index; + item->glyphid = glyphid; + item->x0 = x; + item->y0 = y; + item->x1 = x + w; + item->y1 = y + h; +} + +inline_4tech float +write_render_item_inline(Buffer_Render_Item *item, + int index, + unsigned short glyphid, + float x, float y, + float *advance_data, float h){ + float ch_width; + ch_width = measure_character(advance_data, (char)glyphid); + write_render_item(item, index, glyphid, x, y, ch_width, h); + return(ch_width); +} + internal_4tech void buffer_get_render_data(Buffer_Type *buffer, Buffer_Render_Item *items, int max, int *count, float port_x, float port_y, @@ -1324,6 +1360,7 @@ buffer_get_render_data(Buffer_Type *buffer, Buffer_Render_Item *items, int max, Buffer_Stringify_Type loop; Buffer_Render_Item *item; + Buffer_Render_Item *item_end; char *data; int size, end; float shift_x, shift_y; @@ -1343,116 +1380,141 @@ buffer_get_render_data(Buffer_Type *buffer, Buffer_Render_Item *items, int max, y = shift_y; item_i = 0; item = items + item_i; + item_end = items + max; + // TODO(allen): What's the plan for when there is not enough space to store + // more render items? It seems like we should be able to use the view_x + // to skip items that are not in view right? That way I think it would + // just always fit in the buffer. if (advance_data){ for (loop = buffer_stringify_loop(buffer, start_cursor.pos, size); - buffer_stringify_good(&loop); + buffer_stringify_good(&loop) && item < item_end; buffer_stringify_next(&loop)){ - + end = loop.size + loop.absolute_pos; data = loop.data - loop.absolute_pos; - + for (i = loop.absolute_pos; i < end; ++i){ ch = data[i]; ch_width = measure_character(advance_data, ch); - + if (ch_width + x > width + shift_x && wrapped && ch != '\n'){ x = shift_x; y += font_height; } if (y > height + shift_y) goto buffer_get_render_data_end; - - switch (ch){ - case '\n': - write_render_item_inline(item, i, ' ', x, y, advance_data, font_height); - item->flags = 0; - ++item_i; - ++item; - x = shift_x; - y += font_height; - break; - - case 0: - ch_width = write_render_item_inline(item, i, '\\', x, y, advance_data, font_height); - item->flags = BRFlag_Special_Character; - ++item_i; - ++item; - x += ch_width; - - ch_width = write_render_item_inline(item, i, '0', x, y, advance_data, font_height); - item->flags = BRFlag_Special_Character; - ++item_i; - ++item; - x += ch_width; - break; - - case '\r': - ch_width = write_render_item_inline(item, i, '\\', x, y, advance_data, font_height); - item->flags = BRFlag_Special_Character; - ++item_i; - ++item; - x += ch_width; - - ch_width = write_render_item_inline(item, i, 'r', x, y, advance_data, font_height); - item->flags = BRFlag_Special_Character; - ++item_i; - ++item; - x += ch_width; - break; - - case '\t': - if (opts.show_slash_t){ - ch_width_sub = write_render_item_inline(item, i, '\\', x, y, advance_data, font_height); - item->flags = BRFlag_Special_Character; - ++item_i; - ++item; - - write_render_item_inline(item, i, 't', x + ch_width_sub, y, advance_data, font_height); - item->flags = BRFlag_Special_Character; - ++item_i; - ++item; - } - else{ + switch (ch){ + case '\n': + if (item < item_end){ write_render_item_inline(item, i, ' ', x, y, advance_data, font_height); item->flags = 0; ++item_i; ++item; + + x = shift_x; + y += font_height; + } + break; + + case 0: + if (item < item_end){ + ch_width = write_render_item_inline(item, i, '\\', x, y, advance_data, font_height); + item->flags = BRFlag_Special_Character; + ++item_i; + ++item; + x += ch_width; + + if (item < item_end){ + ch_width = write_render_item_inline(item, i, '0', x, y, advance_data, font_height); + item->flags = BRFlag_Special_Character; + ++item_i; + ++item; + x += ch_width; + } + } + break; + + case '\r': + if (item < item_end){ + ch_width = write_render_item_inline(item, i, '\\', x, y, advance_data, font_height); + item->flags = BRFlag_Special_Character; + ++item_i; + ++item; + x += ch_width; + + if (item < item_end){ + ch_width = write_render_item_inline(item, i, 'r', x, y, advance_data, font_height); + item->flags = BRFlag_Special_Character; + ++item_i; + ++item; + x += ch_width; + } + } + break; + + case '\t': + if (opts.show_slash_t){ + if (item < item_end){ + ch_width_sub = write_render_item_inline(item, i, '\\', x, y, advance_data, font_height); + item->flags = BRFlag_Special_Character; + ++item_i; + ++item; + if (item < item_end){ + write_render_item_inline(item, i, 't', x + ch_width_sub, y, advance_data, font_height); + item->flags = BRFlag_Special_Character; + ++item_i; + ++item; + } + } + } + else{ + if (item < item_end){ + write_render_item_inline(item, i, ' ', x, y, advance_data, font_height); + item->flags = 0; + ++item_i; + ++item; + } } x += ch_width; break; - - default: - write_render_item(item, i, ch, x, y, ch_width, font_height); - item->flags = 0; - ++item_i; - ++item; - x += ch_width; - + + default: + if (item < item_end){ + write_render_item(item, i, ch, x, y, ch_width, font_height); + item->flags = 0; + ++item_i; + ++item; + x += ch_width; + } break; } if (y > height + shift_y) goto buffer_get_render_data_end; } } - -buffer_get_render_data_end: + + buffer_get_render_data_end: if (y <= height + shift_y || item == items){ + if (item < item_end){ + ch = 0; + ch_width = measure_character(advance_data, ' '); + write_render_item(item, size, ch, x, y, ch_width, font_height); + ++item_i; + ++item; + x += ch_width; + } + } + } + else{ + if (item < item_end){ ch = 0; - ch_width = measure_character(advance_data, ' '); + ch_width = 0; write_render_item(item, size, ch, x, y, ch_width, font_height); ++item_i; ++item; x += ch_width; } } - else{ - ch = 0; - ch_width = 0; - write_render_item(item, size, ch, x, y, ch_width, font_height); - ++item_i; - ++item; - x += ch_width; - } // TODO(allen): handle this with a control state assert_4tech(item_i <= max); diff --git a/buffer/4coder_shared.cpp b/buffer/4coder_shared.cpp index afb630be..8a70e3e1 100644 --- a/buffer/4coder_shared.cpp +++ b/buffer/4coder_shared.cpp @@ -88,36 +88,6 @@ typedef struct Buffer_Batch_State{ int shift_total; } Buffer_Batch_State; -#define BRFlag_Special_Character (1 << 0) - -typedef struct Buffer_Render_Item{ - int index; - unsigned short glyphid; - unsigned short flags; - float x0, y0; - float x1, y1; -} Buffer_Render_Item; - -inline_4tech void -write_render_item(Buffer_Render_Item *item, int index, unsigned short glyphid, - float x, float y, float w, float h){ - item->index = index; - item->glyphid = glyphid; - item->x0 = x; - item->y0 = y; - item->x1 = x + w; - item->y1 = y + h; -} - -inline_4tech float -write_render_item_inline(Buffer_Render_Item *item, int index, unsigned short glyphid, - float x, float y, float *advance_data, float h){ - float ch_width; - ch_width = measure_character(advance_data, (char)glyphid); - write_render_item(item, index, glyphid, x, y, ch_width, h); - return(ch_width); -} - inline_4tech Full_Cursor make_cursor_hint(int line_index, int *starts, float *wrap_ys, float font_height){ Full_Cursor hint; From 58a334190d015acd19624d77bc4d0d3560ab9062 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Thu, 2 Jun 2016 09:47:43 -0400 Subject: [PATCH 28/34] temporary fix for lack of floating sections --- 4ed.cpp | 39 +++++------ 4ed_file_view.cpp | 170 ++++++++++++++++++++++------------------------ 4ed_gui.cpp | 6 +- 3 files changed, 103 insertions(+), 112 deletions(-) diff --git a/4ed.cpp b/4ed.cpp index 34a3cac1..5f2a82d9 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -584,6 +584,7 @@ COMMAND_DECL(set_mark){ REQ_FILE(file, view); view->recent->mark = (i32)view->recent->cursor.pos; + view->recent->preferred_x = view_get_cursor_x(view); } COMMAND_DECL(copy){ @@ -996,7 +997,7 @@ COMMAND_DECL(toggle_line_wrap){ view->file_data.unwrapped_lines = 0; file->settings.unwrapped_lines = 0; view->recent->scroll.target_x = 0; - view->recent->cursor =view_compute_cursor_from_pos( + view->recent->cursor = view_compute_cursor_from_pos( view, view->recent->cursor.pos); view->recent->preferred_x = view->recent->cursor.wrapped_x; } @@ -1344,8 +1345,8 @@ COMMAND_DECL(move_up){ REQ_READABLE_VIEW(view); REQ_FILE(file, view); - f32 font_height = (f32)get_font_info(models->font_set, models->global_font.font_id)->height; - f32 cy = view_get_cursor_y(view)-font_height; + f32 line_height = (f32)get_font_info(models->font_set, models->global_font.font_id)->height; + f32 cy = view_get_cursor_y(view)-line_height; f32 px = view->recent->preferred_x; if (cy >= 0){ view->recent->cursor = view_compute_cursor_from_xy(view, px, cy); @@ -1359,8 +1360,8 @@ COMMAND_DECL(move_down){ REQ_READABLE_VIEW(view); REQ_FILE(file, view); - f32 font_height = (f32)get_font_info(models->font_set, models->global_font.font_id)->height; - f32 cy = view_get_cursor_y(view)+font_height; + f32 line_height = (f32)get_font_info(models->font_set, models->global_font.font_id)->height; + f32 cy = view_get_cursor_y(view)+line_height; f32 px = view->recent->preferred_x; view->recent->cursor = view_compute_cursor_from_xy(view, px, cy); file->state.cursor_pos = view->recent->cursor.pos; @@ -1392,7 +1393,7 @@ COMMAND_DECL(page_down){ clamp_top(view->recent->scroll.target_y + height, max_target_y); view->recent->cursor = - view_compute_cursor_from_xy(view, 0, view->recent->scroll.target_y + (height - view->font_height)*.5f); + view_compute_cursor_from_xy(view, 0, view->recent->scroll.target_y + (height - view->line_height)*.5f); } COMMAND_DECL(page_up){ @@ -1404,7 +1405,7 @@ COMMAND_DECL(page_up){ clamp_bottom(0.f, view->recent->scroll.target_y - height); view->recent->cursor = - view_compute_cursor_from_xy(view, 0, view->recent->scroll.target_y + (height - view->font_height)*.5f); + view_compute_cursor_from_xy(view, 0, view->recent->scroll.target_y + (height - view->line_height)*.5f); } COMMAND_DECL(open_color_tweaker){ @@ -1763,7 +1764,7 @@ fill_view_summary(View_Summary *view, View *vptr, Live_Views *live_set, Working_ if (vptr->in_use){ view->exists = 1; view->view_id = (int)(vptr - live_set->views) + 1; - view->line_height = vptr->font_height; + view->line_height = vptr->line_height; view->unwrapped_lines = vptr->file_data.unwrapped_lines; if (vptr->file_data.file){ @@ -3562,6 +3563,17 @@ App_Step_Sig(app_step){ } } + // NOTE(allen): begin allowing the cursors and scroll locations + // to move around. + { + Panel *panel = 0, *used_panels = 0; + used_panels = &models->layout.used_sentinel; + for (dll_items(panel, used_panels)){ + Assert(panel->view); + view_begin_cursor_scroll_updates(panel->view); + } + } + // NOTE(allen): reorganizing panels on screen { i32 prev_width = models->layout.full_width; @@ -3677,17 +3689,6 @@ App_Step_Sig(app_step){ } } - // NOTE(allen): begin allowing the cursors and scroll locations - // to move around. - { - Panel *panel = 0, *used_panels = 0; - used_panels = &models->layout.used_sentinel; - for (dll_items(panel, used_panels)){ - Assert(panel->view); - view_begin_cursor_scroll_updates(panel->view); - } - } - // NOTE(allen): update child processes if (input->dt > 0){ Temp_Memory temp = begin_temp_memory(&models->mem.part); diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index 7b717eb8..b08c3b73 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -121,22 +121,6 @@ view_mode_zero(){ return(mode); } -enum View_Widget_Type{ - FWIDG_NONE, - FWIDG_TIMELINES, - // never below this - FWIDG_TYPE_COUNT -}; - -struct View_Widget{ - View_Widget_Type type; - i32 height_; - struct{ - b32 undo_line; - b32 history_line; - } timeline; -}; - enum View_UI{ VUI_None, VUI_Theme, @@ -263,13 +247,13 @@ struct View{ i32 current_color_editing; i32 color_cursor; + // misc i32 font_advance; - i32 font_height; + i32 line_height; View_Mode mode, next_mode; - View_Widget widget; Query_Set query_set; - i32 scrub_max; + f32 widget_height; b32 reinit_scrolling; }; @@ -623,7 +607,7 @@ view_compute_lowest_line(View *view){ } else{ f32 wrap_y = view->file_data.line_wrap_y[last_line]; - lowest_line = FLOOR32(wrap_y / view->font_height); + lowest_line = FLOOR32(wrap_y / view->line_height); f32 max_width = view_file_width(view); Editing_File *file = view->file_data.file; @@ -646,7 +630,7 @@ view_compute_max_target_y(i32 lowest_line, i32 line_height, f32 view_height){ inline f32 view_compute_max_target_y(View *view){ i32 lowest_line = view_compute_lowest_line(view); - i32 line_height = view->font_height; + i32 line_height = view->line_height; f32 view_height = view_file_height(view); f32 max_target_y = view_compute_max_target_y(lowest_line, line_height, view_height); return(max_target_y); @@ -671,7 +655,7 @@ view_measure_wraps(General_Memory *general, View *view){ } } - f32 line_height = (f32)view->font_height; + f32 line_height = (f32)view->line_height; f32 max_width = view_file_width(view); buffer_measure_wrap_y(buffer, view->file_data.line_wrap_y, line_height, max_width); @@ -1347,7 +1331,7 @@ view_compute_cursor_from_pos(View *view, i32 pos){ if (font){ f32 max_width = view_file_width(view); result = buffer_cursor_from_pos(&file->state.buffer, pos, view->file_data.line_wrap_y, - max_width, (f32)view->font_height, font->advance_data); + max_width, (f32)view->line_height, font->advance_data); } return result; } @@ -1362,7 +1346,7 @@ view_compute_cursor_from_unwrapped_xy(View *view, f32 seek_x, f32 seek_y, b32 ro if (font){ f32 max_width = view_file_width(view); result = buffer_cursor_from_unwrapped_xy(&file->state.buffer, seek_x, seek_y, - round_down, view->file_data.line_wrap_y, max_width, (f32)view->font_height, font->advance_data); + round_down, view->file_data.line_wrap_y, max_width, (f32)view->line_height, font->advance_data); } return result; @@ -1379,7 +1363,7 @@ view_compute_cursor_from_wrapped_xy(View *view, f32 seek_x, f32 seek_y, b32 roun f32 max_width = view_file_width(view); result = buffer_cursor_from_wrapped_xy(&file->state.buffer, seek_x, seek_y, round_down, view->file_data.line_wrap_y, - max_width, (f32)view->font_height, font->advance_data); + max_width, (f32)view->line_height, font->advance_data); } return (result); @@ -1395,7 +1379,7 @@ view_compute_cursor_from_line_pos(View *view, i32 line, i32 pos){ if (font){ f32 max_width = view_file_width(view); result = buffer_cursor_from_line_character(&file->state.buffer, line, pos, - view->file_data.line_wrap_y, max_width, (f32)view->font_height, font->advance_data); + view->file_data.line_wrap_y, max_width, (f32)view->line_height, font->advance_data); } return (result); @@ -1495,7 +1479,7 @@ view_get_cursor_y(View *view){ internal void view_move_cursor_to_view(View *view, GUI_Scroll_Vars scroll){ f32 min_target_y = 0; - i32 line_height = view->font_height; + i32 line_height = view->line_height; f32 old_cursor_y = view_get_cursor_y(view); f32 cursor_y = old_cursor_y; f32 target_y = scroll.target_y; @@ -1523,7 +1507,7 @@ view_move_cursor_to_view(View *view, GUI_Scroll_Vars scroll){ internal void view_move_view_to_cursor(View *view, GUI_Scroll_Vars *scroll){ - f32 line_height = (f32)view->font_height; + f32 line_height = (f32)view->line_height; f32 delta_y = 3.f*line_height; f32 max_visible_y = view_file_height(view); @@ -1577,7 +1561,7 @@ view_set_file(View *view, Editing_File *file, Models *models){ // TODO(allen): This belongs somewhere else. fnt_info = get_font_info(models->font_set, models->global_font.font_id); view->font_advance = fnt_info->advance; - view->font_height = fnt_info->height; + view->line_height = fnt_info->height; file_view_nullify_file(view); view->file_data.file = file; @@ -1688,19 +1672,14 @@ view_cursor_move(View *view, i32 line, i32 pos){ view_cursor_move(view, cursor); } -inline void -view_set_widget(View *view, View_Widget_Type type){ - view->widget.type = type; -} - inline i32_Rect -view_widget_rect(View *view, i32 font_height){ +view_widget_rect(View *view, i32 line_height){ Panel *panel = view->panel; i32_Rect result = panel->inner; if (view->file_data.file){ - result.y0 = result.y0 + font_height + 2; + result.y0 = result.y0 + line_height + 2; } return(result); @@ -1948,7 +1927,7 @@ file_edit_cursor_fix(System_Functions *system, if (view->recent->scroll_i != new_scroll_i){ view->recent->scroll_i = new_scroll_i; temp_cursor = view_compute_cursor_from_pos(view, view->recent->scroll_i); - y_offset = MOD(view->recent->scroll.scroll_y, view->font_height); + y_offset = MOD(view->recent->scroll.scroll_y, view->line_height); if (view->file_data.unwrapped_lines){ y_position = temp_cursor.unwrapped_y + y_offset; @@ -3545,10 +3524,6 @@ view_begin_cursor_scroll_updates(View *view){ if (view->file_data.file && view->file_data.file == view->prev_context.file){ Assert(view->prev_cursor_pos == view_get_cursor_pos(view)); } - - view->prev_context.file = view->file_data.file; - view->prev_context.scroll = view->gui_target.scroll_id; - view->prev_context.mode = view->showing_ui; } internal void @@ -3580,9 +3555,11 @@ view_end_cursor_scroll_updates(View *view){ gui_post_scroll_vars(&view->gui_target, view->current_scroll, view->scroll_region); } - if (view->gui_target.did_file){ - view->prev_cursor_pos = view_get_cursor_pos(view); - } + view->prev_cursor_pos = view_get_cursor_pos(view); + + view->prev_context.file = view->file_data.file; + view->prev_context.scroll = view->gui_target.scroll_id; + view->prev_context.mode = view->showing_ui; } internal b32 @@ -3605,14 +3582,15 @@ file_step(View *view, i32_Rect region, Input_Summary *user_input, b32 is_active) f32 ry = (f32)(user_input->mouse.y - region.y0); if (ry >= 0){ - view_set_widget(view, FWIDG_NONE); if (rx >= 0 && rx < max_x && ry >= 0 && ry < max_visible_y){ - view_cursor_move(view, rx + scroll_vars.scroll_x, ry + scroll_vars.scroll_y, 1); + view_cursor_move(view, + rx + scroll_vars.scroll_x, + ry + scroll_vars.scroll_y, + 1); view->mode = view_mode_zero(); } } } - if (!is_active) view_set_widget(view, FWIDG_NONE); } return(is_animating); @@ -3623,10 +3601,20 @@ do_widget(View *view, GUI_Target *target){ Query_Slot *slot; Query_Bar *bar; + // NOTE(allen): A temporary measure... although in + // general we maybe want the user to be able to ask + // how large a particular section of the GUI turns + // out to be after layout? + f32 height = 0.f; + for (slot = view->query_set.used_slot; slot != 0; slot = slot->next){ bar = slot->query_bar; gui_do_text_field(target, bar->prompt, bar->string); + + height += view->line_height + 2; } + + view->widget_height = height; } struct Exhaustive_File_Loop{ @@ -3906,7 +3894,7 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su gui_begin_serial_section(target); { - f32 delta = 9.f * view->font_height; + f32 delta = 9.f * view->line_height; GUI_id scroll_context = {0}; scroll_context.id[1] = view->showing_ui; scroll_context.id[0] = (u64)(view->file_data.file); @@ -4006,7 +3994,7 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su view->current_scroll = &view->gui_scroll; gui_get_scroll_vars(target, scroll_context, &view->gui_scroll, &view->scroll_region); gui_begin_scrollable(target, scroll_context, view->gui_scroll, - 9.f * view->font_height, show_scrollbar); + 9.f * view->line_height, show_scrollbar); { i32 count = models->styles.count; @@ -4080,7 +4068,7 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su view->current_scroll = &view->gui_scroll; gui_get_scroll_vars(target, scroll_context, &view->gui_scroll, &view->scroll_region); gui_begin_scrollable(target, scroll_context, view->gui_scroll, - 9.f * view->font_height, show_scrollbar); + 9.f * view->line_height, show_scrollbar); i32 next_color_editing = view->current_color_editing; @@ -4227,7 +4215,7 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su snap_into_view = 1; } gui_begin_scrollable(target, scroll_context, view->gui_scroll, - 9.f * view->font_height, show_scrollbar); + 9.f * view->line_height, show_scrollbar); id.id[0] = (u64)(hdir) + 1; @@ -4316,7 +4304,7 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su snap_into_view = 1; } gui_begin_scrollable(target, scroll_context, view->gui_scroll, - 9.f * view->font_height, show_scrollbar); + 9.f * view->line_height, show_scrollbar); id.id[0] = (u64)(working_set) + 1; if (gui_begin_list(target, id, view->list_i, @@ -4550,7 +4538,7 @@ do_input_file_view(System_Functions *system, target->active = gui_id_zero(); if (target->push.pos > 0){ - gui_session_init(&gui_session, target, rect, view->font_height); + gui_session_init(&gui_session, target, rect, view->line_height); for (h = (GUI_Header*)target->push.base; h->type; @@ -4754,47 +4742,54 @@ draw_file_loaded(View *view, i32_Rect rect, b32 is_active, Render_Target *target Models *models = view->persistent.models; Editing_File *file = view->file_data.file; Style *style = main_style(models); - i32 line_height = view->font_height; - + i32 line_height = view->line_height; + i32 max_x = rect.x1 - rect.x0; i32 max_y = rect.y1 - rect.y0 + line_height; - + Assert(file && !file->is_dummy && buffer_good(&file->state.buffer)); - + b32 tokens_use = 0; Cpp_Token_Stack token_stack = {}; if (file){ tokens_use = file->state.tokens_complete && (file->state.token_stack.count > 0); token_stack = file->state.token_stack; } - + Partition *part = &models->mem.part; - + Temp_Memory temp = begin_temp_memory(part); - + partition_align(part, 4); i32 max = partition_remaining(part) / sizeof(Buffer_Render_Item); Buffer_Render_Item *items = push_array(part, Buffer_Render_Item, max); - + i16 font_id = models->global_font.font_id; Render_Font *font = get_font_info(models->font_set, font_id)->font; float *advance_data = 0; if (font) advance_data = font->advance_data; - + i32 count; Full_Cursor render_cursor; Buffer_Render_Options opts = {}; - + f32 *wraps = view->file_data.line_wrap_y; f32 scroll_x = view->recent->scroll.scroll_x; f32 scroll_y = view->recent->scroll.scroll_y; - + + // NOTE(allen): For now we will temporarily adjust scroll_y to try + // to prevent the view moving around until floating sections are added + // to the gui system. + scroll_y += view->widget_height; + { render_cursor = buffer_get_start_cursor(&file->state.buffer, wraps, scroll_y, - !view->file_data.unwrapped_lines, (f32)max_x, advance_data, (f32)line_height); - + !view->file_data.unwrapped_lines, + (f32)max_x, + advance_data, (f32)line_height); + view->recent->scroll_i = render_cursor.pos; - + buffer_get_render_data(&file->state.buffer, items, max, &count, (f32)rect.x0, (f32)rect.y0, scroll_x, scroll_y, render_cursor, @@ -4803,9 +4798,9 @@ draw_file_loaded(View *view, i32_Rect rect, b32 is_active, Render_Target *target advance_data, (f32)line_height, opts); } - + Assert(count > 0); - + i32 cursor_begin, cursor_end; u32 cursor_color, at_cursor_color; if (view->file_data.show_temp_highlight){ @@ -4820,7 +4815,7 @@ draw_file_loaded(View *view, i32_Rect rect, b32 is_active, Render_Target *target cursor_color = style->main.cursor_color; at_cursor_color = style->main.at_cursor_color; } - + i32 token_i = 0; u32 main_color = style->main.default_color; u32 special_color = style->main.special_character_color; @@ -4829,19 +4824,19 @@ draw_file_loaded(View *view, i32_Rect rect, b32 is_active, Render_Target *target main_color = *style_get_color(style, token_stack.tokens[result.token_index]); token_i = result.token_index + 1; } - + u32 mark_color = style->main.mark_color; Buffer_Render_Item *item = items; i32 prev_ind = -1; u32 highlight_color = 0; u32 highlight_this_color = 0; - + for (i32 i = 0; i < count; ++i, ++item){ i32 ind = item->index; highlight_this_color = 0; if (tokens_use && ind != prev_ind){ Cpp_Token current_token = token_stack.tokens[token_i-1]; - + if (token_i < token_stack.count){ if (ind >= token_stack.tokens[token_i].start){ main_color = @@ -4853,7 +4848,7 @@ draw_file_loaded(View *view, i32_Rect rect, b32 is_active, Render_Target *target main_color = 0xFFFFFFFF; } } - + if (current_token.type == CPP_TOKEN_JUNK && i >= current_token.start && i < current_token.start + current_token.size){ highlight_color = style->main.highlight_junk_color; @@ -4862,10 +4857,10 @@ draw_file_loaded(View *view, i32_Rect rect, b32 is_active, Render_Target *target highlight_color = 0; } } - + u32 char_color = main_color; if (item->flags & BRFlag_Special_Character) char_color = special_color; - + f32_Rect char_rect = f32R(item->x0, item->y0, item->x1, item->y1); if (view->file_data.show_whitespace && highlight_color == 0 && char_is_whitespace((char)item->glyphid)){ @@ -4874,7 +4869,7 @@ draw_file_loaded(View *view, i32_Rect rect, b32 is_active, Render_Target *target else{ highlight_this_color = highlight_color; } - + if (cursor_begin <= ind && ind < cursor_end && (ind != prev_ind || cursor_begin < ind)){ if (is_active){ draw_rectangle(target, char_rect, cursor_color); @@ -4889,19 +4884,19 @@ draw_file_loaded(View *view, i32_Rect rect, b32 is_active, Render_Target *target else if (highlight_this_color){ draw_rectangle(target, char_rect, highlight_this_color); } - + u32 fade_color = 0xFFFF00FF; f32 fade_amount = 0.f; - + if (file->state.paste_effect.tick_down > 0 && file->state.paste_effect.start <= ind && ind < file->state.paste_effect.end){ fade_color = file->state.paste_effect.color; fade_amount = (f32)(file->state.paste_effect.tick_down) / file->state.paste_effect.tick_max; } - + char_color = color_blend(char_color, fade_amount, fade_color); - + if (ind == view->recent->mark && prev_ind != ind){ draw_rectangle_outline(target, char_rect, mark_color); } @@ -4911,9 +4906,9 @@ draw_file_loaded(View *view, i32_Rect rect, b32 is_active, Render_Target *target } prev_ind = ind; } - + end_temp_memory(temp); - + return(0); } @@ -4971,7 +4966,7 @@ draw_text_with_cursor(Render_Target *target, View *view, i32_Rect rect, String s cursor_rect.x0 = FLOOR32(x); cursor_rect.x1 = FLOOR32(x) + CEIL32(font->advance_data[s.str[pos]]); cursor_rect.y0 = y; - cursor_rect.y1 = y + view->font_height; + cursor_rect.y1 = y + view->line_height; draw_rectangle(target, cursor_rect, cursor_color); x = draw_string(target, font_id, part2, FLOOR32(x), y, at_cursor_color); @@ -5129,7 +5124,7 @@ draw_fat_option_block(GUI_Target *gui_target, Render_Target *target, View *view, u32 text_color = style->main.default_color; u32 pop_color = style->main.special_character_color; - i32 h = view->font_height; + i32 h = view->line_height; i32 x = inner.x0 + 3; i32 y = inner.y0 + h/2 - 1; @@ -5169,7 +5164,7 @@ draw_button(GUI_Target *gui_target, Render_Target *target, View *view, i32_Rect u32 back = get_margin_color(active_level, style); u32 text_color = style->main.default_color; - i32 h = view->font_height; + i32 h = view->line_height; i32 y = inner.y0 + h/2 - 1; i32 w = (i32)font_string_width(target, font_id, text); @@ -5240,7 +5235,7 @@ do_render_file_view(System_Functions *system, View *view, f32 v; if (gui_target->push.pos > 0){ - gui_session_init(&gui_session, gui_target, rect, view->font_height); + gui_session_init(&gui_session, gui_target, rect, view->line_height); v = view_get_scroll_y(view); @@ -5675,7 +5670,6 @@ live_set_alloc_view(Live_Views *live_set, Panel *panel, Models *models){ result.view->panel = panel; result.view->persistent.models = models; - result.view->scrub_max = 1; result.view->current_scroll = &result.view->recent->scroll; init_query_set(&result.view->query_set); diff --git a/4ed_gui.cpp b/4ed_gui.cpp index 81ef53da..3ff05037 100644 --- a/4ed_gui.cpp +++ b/4ed_gui.cpp @@ -649,11 +649,7 @@ gui_get_scroll_vars(GUI_Target *target, GUI_id scroll_context_id, GUI_Scroll_Var *vars_out = target->scroll_updated; *region_out = target->region_updated; - if (vars_out->target_y < 0) vars_out->target_y = 0; - if (vars_out->target_y > vars_out->max_y) vars_out->target_y = vars_out->max_y; - - if (vars_out->scroll_y < 0) vars_out->scroll_y = 0; - if (vars_out->scroll_y > vars_out->max_y) vars_out->scroll_y = vars_out->max_y; + vars_out->target_y = clamp(0.f, vars_out->target_y, vars_out->max_y); if (gui_id_eq(target->active, gui_id_scrollbar())){ result = 1; From f3370cfc2eb900d5e10f4ac939a5a520c14892be Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Thu, 2 Jun 2016 10:45:06 -0400 Subject: [PATCH 29/34] fixed vertically small window crash issue --- 4ed_file_view.cpp | 66 +++++++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index b08c3b73..858b2e76 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -1470,27 +1470,54 @@ view_get_cursor_y(View *view){ return result; } -#define CursorMaxY_(m,h) ((m) - (h)*3) -#define CursorMinY_(m,h) (-(m) + (h)*2) +struct Cursor_Limits{ + f32 min, max; + f32 delta; +}; -#define CursorMaxY(m,h) (CursorMaxY_(m,h) > 0)?(CursorMaxY_(m,h)):(0) -#define CursorMinY(m,h) (CursorMinY_(m,h) > 0)?(CursorMinY_(m,h)):(0) +inline Cursor_Limits +view_cursor_limits(View *view){ + Cursor_Limits limits = {0}; + + f32 line_height = (f32)view->line_height; + f32 visible_height = view_file_height(view); + + limits.max = visible_height - line_height*3.f; + limits.min = line_height * 2; + + if (limits.max - limits.min <= line_height){ + if (visible_height >= line_height){ + limits.max = visible_height - line_height; + limits.min = -line_height; + } + else{ + limits.max = visible_height; + limits.min = -line_height; + } + } + + limits.max = (limits.max > 0)?(limits.max):(0); + limits.min = (limits.min > 0)?(limits.min):(0); + + limits.delta = clamp_top(line_height*3.f, (limits.max - limits.min)*.5f); + + return(limits); +} internal void view_move_cursor_to_view(View *view, GUI_Scroll_Vars scroll){ - f32 min_target_y = 0; i32 line_height = view->line_height; f32 old_cursor_y = view_get_cursor_y(view); f32 cursor_y = old_cursor_y; f32 target_y = scroll.target_y; - f32 cursor_max_y = CursorMaxY(view_file_height(view), line_height); - f32 cursor_min_y = CursorMinY(min_target_y, line_height); - if (cursor_y > target_y + cursor_max_y){ - cursor_y = target_y + cursor_max_y; + Cursor_Limits limits = view_cursor_limits(view); + + if (cursor_y > target_y + limits.max){ + cursor_y = target_y + limits.max; } - if (target_y != 0 && cursor_y < target_y + cursor_min_y){ - cursor_y = target_y + cursor_min_y; + if (target_y != 0 && cursor_y < target_y + limits.min){ + cursor_y = target_y + limits.min; } if (cursor_y != old_cursor_y){ @@ -1507,10 +1534,6 @@ view_move_cursor_to_view(View *view, GUI_Scroll_Vars scroll){ internal void view_move_view_to_cursor(View *view, GUI_Scroll_Vars *scroll){ - f32 line_height = (f32)view->line_height; - f32 delta_y = 3.f*line_height; - - f32 max_visible_y = view_file_height(view); f32 max_x = view_file_width(view); f32 cursor_y = view_get_cursor_y(view); @@ -1520,14 +1543,13 @@ view_move_view_to_cursor(View *view, GUI_Scroll_Vars *scroll){ f32 target_y = scroll_vars.target_y; f32 target_x = scroll_vars.target_x; - f32 cursor_max_y = CursorMaxY(max_visible_y, line_height); - f32 cursor_min_y = CursorMinY(0, line_height); + Cursor_Limits limits = view_cursor_limits(view); - if (cursor_y > target_y + cursor_max_y){ - target_y = cursor_y - cursor_max_y + delta_y; + if (cursor_y > target_y + limits.max){ + target_y = cursor_y - limits.max + limits.delta; } - if (cursor_y < target_y + cursor_min_y){ - target_y = cursor_y - delta_y - cursor_min_y; + if (cursor_y < target_y + limits.min){ + target_y = cursor_y - limits.delta - limits.min; } target_y = clamp(0.f, target_y, scroll_vars.max_y); @@ -4693,7 +4715,7 @@ do_input_file_view(System_Functions *system, if (scroll_button_input(target, &gui_session, user_input, id, &result.is_animating)){ result.vars.target_y += target->delta * 0.25f; - result.vars.target_y = clamp_top(0.f, result.vars.max_y); + result.vars.target_y = clamp_top(result.vars.target_y, result.vars.max_y); } }break; From 71b18c4064c69f4c1ee848f67f2d23e79ddba00c Mon Sep 17 00:00:00 2001 From: insofaras Date: Thu, 2 Jun 2016 19:05:44 +0100 Subject: [PATCH 30/34] linux x11 clipboard improvements --- linux_4ed.cpp | 61 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/linux_4ed.cpp b/linux_4ed.cpp index e553c448..4cfd6e54 100644 --- a/linux_4ed.cpp +++ b/linux_4ed.cpp @@ -166,6 +166,7 @@ struct Linux_Vars{ String clipboard_outgoing; b32 new_clipboard; + Atom atom_TARGETS; Atom atom_CLIPBOARD; Atom atom_UTF8_STRING; Atom atom__NET_WM_STATE; @@ -2272,27 +2273,57 @@ LinuxHandleX11Events(void) response.time = request.time; response.property = None; - //TODO(inso): handle TARGETS negotiation instead of requiring UTF8_STRING if ( linuxvars.clipboard_outgoing.size && - request.target == linuxvars.atom_UTF8_STRING && request.selection == linuxvars.atom_CLIPBOARD && request.property != None && request.display && request.requestor ){ - XChangeProperty( - request.display, - request.requestor, - request.property, - request.target, - 8, - PropModeReplace, - (unsigned char*)linuxvars.clipboard_outgoing.str, - linuxvars.clipboard_outgoing.size - ); + Atom atoms[] = { + XA_STRING, + linuxvars.atom_UTF8_STRING + }; - response.property = request.property; + if(request.target == linuxvars.atom_TARGETS){ + + XChangeProperty( + request.display, + request.requestor, + request.property, + XA_ATOM, + 32, + PropModeReplace, + (u8*)atoms, + ArrayCount(atoms) + ); + + response.property = request.property; + + } else { + b32 found = false; + for(int i = 0; i < ArrayCount(atoms); ++i){ + if(request.target == atoms[i]){ + found = true; + break; + } + } + + if(found){ + XChangeProperty( + request.display, + request.requestor, + request.property, + request.target, + 8, + PropModeReplace, + (u8*)linuxvars.clipboard_outgoing.str, + linuxvars.clipboard_outgoing.size + ); + + response.property = request.property; + } + } } XSendEvent(request.display, request.requestor, True, 0, (XEvent*)&response); @@ -2339,6 +2370,7 @@ LinuxHandleX11Events(void) should_step = 1; linuxvars.new_clipboard = 1; XFree(data); + XDeleteProperty(linuxvars.XDisplay, linuxvars.XWindow, linuxvars.atom_CLIPBOARD); } } }break; @@ -2585,6 +2617,7 @@ main(int argc, char **argv) #define LOAD_ATOM(x) linuxvars.atom_##x = XInternAtom(linuxvars.XDisplay, #x, False); + LOAD_ATOM(TARGETS); LOAD_ATOM(CLIPBOARD); LOAD_ATOM(UTF8_STRING); LOAD_ATOM(_NET_WM_STATE); @@ -2619,6 +2652,8 @@ main(int argc, char **argv) linuxvars.atom_CLIPBOARD, XFixesSetSelectionOwnerNotifyMask ); + } else { + fputs("Your X server doesn't support XFIXES, mention this fact if you report any clipboard-related issues.\n", stderr); } Init_Input_Result input_result = From 4dd5d1bfa0a300cf421f3e32d0d360da60fb3066 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Fri, 3 Jun 2016 09:40:05 -0400 Subject: [PATCH 31/34] fixed issue with scroll controling in GUI lists --- 4ed.cpp | 2 ++ 4ed_gui.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/4ed.cpp b/4ed.cpp index 5f2a82d9..3444ebb4 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -3786,6 +3786,7 @@ App_Step_Sig(app_step){ if (i < models->layout.panel_count){ view_open_file(system, models, panel->view, filename); + view_show_file(panel->view); #if 0 if (i == 0){ if (panel->view->file_data.file){ @@ -3803,6 +3804,7 @@ App_Step_Sig(app_step){ if (i < models->layout.panel_count){ view_set_file(panel->view, models->message_buffer, models); + view_show_file(panel->view); } } diff --git a/4ed_gui.cpp b/4ed_gui.cpp index 3ff05037..2492c2fe 100644 --- a/4ed_gui.cpp +++ b/4ed_gui.cpp @@ -655,7 +655,7 @@ gui_get_scroll_vars(GUI_Target *target, GUI_id scroll_context_id, GUI_Scroll_Var result = 1; target->animating = 1; } - } + } return(result); } @@ -1213,7 +1213,7 @@ internal GUI_View_Jump gui_compute_view_jump(i32_Rect scroll_region, i32_Rect position){ GUI_View_Jump jump = {0}; i32 region_h = scroll_region.y1 - scroll_region.y0; - jump.view_min = (f32)position.y1 - region_h - scroll_region.y0; + jump.view_min = (f32)position.y1 - scroll_region.y0 - region_h; jump.view_max = (f32)position.y0 - scroll_region.y0; return(jump); } @@ -1240,8 +1240,8 @@ gui_standard_list(GUI_Target *target, GUI_id id, GUI_Scroll_Vars *vars, i32_Rect if (update->has_index_position){ GUI_View_Jump jump = gui_compute_view_jump(scroll_region, update->index_position); - jump.view_min += 45.f; - jump.view_max -= 45.f; + jump.view_min = clamp_bottom(0.f, jump.view_min + 45.f); + jump.view_max = clamp_bottom(0.f, jump.view_max - 45.f); *vars = gui_do_jump(target, jump, *vars); } From 9bd09d1da24068a8d40245e06a706b4d5a17a54d Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Fri, 3 Jun 2016 12:20:45 -0400 Subject: [PATCH 32/34] moved a lot of basics to the custom side --- 4coder_custom.h | 44 +++-- 4coder_default_bindings.cpp | 109 ++++------- 4coder_default_include.cpp | 306 +++++++++++++++++++++++++++++- 4ed.cpp | 270 +++----------------------- 4ed_file_view.cpp | 10 +- 4ed_gui.cpp | 4 +- buffer/4coder_buffer_abstract.cpp | 3 + 7 files changed, 394 insertions(+), 352 deletions(-) diff --git a/4coder_custom.h b/4coder_custom.h index 84e1b96e..54fd2f4a 100644 --- a/4coder_custom.h +++ b/4coder_custom.h @@ -172,55 +172,57 @@ typedef struct File_List{ enum Command_ID{ cmdid_null, - cmdid_write_character, + cmdid_seek_left, cmdid_seek_right, - cmdid_seek_whitespace_up, - cmdid_seek_whitespace_down, + cmdid_center_view, + cmdid_word_complete, - cmdid_set_mark, + cmdid_copy, cmdid_cut, cmdid_paste, cmdid_paste_next, - cmdid_delete_range, + cmdid_undo, cmdid_redo, cmdid_history_backward, cmdid_history_forward, + cmdid_interactive_new, cmdid_interactive_open, cmdid_reopen, cmdid_save, - cmdid_change_active_panel, cmdid_interactive_switch_buffer, cmdid_interactive_kill_buffer, cmdid_kill_buffer, - cmdid_toggle_line_wrap, - cmdid_toggle_endline_mode, + + cmdid_change_active_panel, + cmdid_to_uppercase, cmdid_to_lowercase, + + cmdid_toggle_line_wrap, cmdid_toggle_show_whitespace, - cmdid_clean_all_lines, + cmdid_eol_dosify, cmdid_eol_nixify, + + cmdid_clean_all_lines, cmdid_auto_tab_range, + cmdid_open_panel_vsplit, cmdid_open_panel_hsplit, cmdid_close_panel, - cmdid_move_left, - cmdid_move_right, - cmdid_delete, - cmdid_backspace, - cmdid_move_up, - cmdid_move_down, + cmdid_seek_end_of_line, cmdid_seek_beginning_of_line, cmdid_page_up, cmdid_page_down, - cmdid_open_color_tweaker, cmdid_cursor_mark_swap, + + cmdid_open_color_tweaker, cmdid_open_menu, cmdid_hide_scrollbar, cmdid_show_scrollbar, @@ -240,6 +242,7 @@ enum Param_ID{ par_lex_as_cpp_file, par_wrap_lines, par_key_mapid, + par_show_whitespace, par_cli_path, par_cli_command, par_clear_blank_lines, @@ -270,9 +273,9 @@ enum Special_Hook_ID{ _hook_scroll_rule = hook_type_count, }; -// NOTE(allen): None of the members of *_Summary structs nor any of the -// data pointed to by the members should be modified, I would have made -// them all const... but that causes a lot problems for C++ reasons. +// None of the members of *_Summary structs nor any of the data pointed +// to by the members should be modified, I would have made them all +// const... but that causes a lot problems for C++ reasons. struct Buffer_Summary{ int exists; int ready; @@ -305,8 +308,9 @@ struct View_Summary{ Full_Cursor cursor; Full_Cursor mark; float preferred_x; - int line_height; + float line_height; int unwrapped_lines; + int show_whitespace; }; inline View_Summary view_summary_zero(){ diff --git a/4coder_default_bindings.cpp b/4coder_default_bindings.cpp index 2a18a793..da15c181 100644 --- a/4coder_default_bindings.cpp +++ b/4coder_default_bindings.cpp @@ -49,44 +49,6 @@ CUSTOM_COMMAND_SIG(switch_to_compilation){ app->view_set_buffer(app, &view, buffer.buffer_id); } -CUSTOM_COMMAND_SIG(move_up_10){ - View_Summary view; - float x, y; - - view = app->get_active_view(app); - x = view.preferred_x; - - if (view.unwrapped_lines){ - y = view.cursor.unwrapped_y; - } - else{ - y = view.cursor.wrapped_y; - } - - y -= 10*view.line_height; - - app->view_set_cursor(app, &view, seek_xy(x, y, 0, view.unwrapped_lines), 0); -} - -CUSTOM_COMMAND_SIG(move_down_10){ - View_Summary view; - float x, y; - - view = app->get_active_view(app); - x = view.preferred_x; - - if (view.unwrapped_lines){ - y = view.cursor.unwrapped_y; - } - else{ - y = view.cursor.wrapped_y; - } - - y += 10*view.line_height; - - app->view_set_cursor(app, &view, seek_xy(x, y, 0, view.unwrapped_lines), 0); -} - CUSTOM_COMMAND_SIG(rewrite_as_single_caps){ View_Summary view; Buffer_Summary buffer; @@ -264,7 +226,7 @@ HOOK_SIG(my_file_settings){ push_parameter(app, par_wrap_lines, wrap_lines); push_parameter(app, par_key_mapid, (treat_as_code)?((int)my_code_map):((int)mapid_file)); exec_command(app, cmdid_set_settings); - + // no meaning for return return(0); } @@ -272,7 +234,7 @@ HOOK_SIG(my_file_settings){ void default_keys(Bind_Helper *context){ begin_map(context, mapid_global); - + bind(context, 'p', MDFR_CTRL, cmdid_open_panel_vsplit); bind(context, '_', MDFR_CTRL, cmdid_open_panel_hsplit); bind(context, 'P', MDFR_CTRL, cmdid_close_panel); @@ -284,40 +246,40 @@ default_keys(Bind_Helper *context){ bind(context, 'c', MDFR_ALT, cmdid_open_color_tweaker); bind(context, 'o', MDFR_ALT, open_in_other); bind(context, 'w', MDFR_CTRL, save_as); - + bind(context, 'm', MDFR_ALT, build_search); bind(context, 'x', MDFR_ALT, execute_arbitrary_command); bind(context, 'z', MDFR_ALT, execute_any_cli); bind(context, 'Z', MDFR_ALT, execute_previous_cli); - + // NOTE(allen): These callbacks may not actually be useful to you, but // go look at them and see what they do. bind(context, 'M', MDFR_ALT | MDFR_CTRL, open_my_files); bind(context, 'M', MDFR_ALT, build_at_launch_location); - + end_map(context); begin_map(context, my_empty_map1); inherit_map(context, mapid_nomap); end_map(context); - + begin_map(context, my_empty_map2); inherit_map(context, mapid_nomap); end_map(context); - + begin_map(context, my_code_map); - + // NOTE(allen|a3.1): Set this map (my_code_map == mapid_user_custom) to // inherit from mapid_file. When searching if a key is bound // in this map, if it is not found here it will then search mapid_file. // // If this is not set, it defaults to mapid_global. inherit_map(context, mapid_file); - + // NOTE(allen|a3.1): Children can override parent's bindings. bind(context, key_right, MDFR_CTRL, seek_alphanumeric_or_camel_right); bind(context, key_left, MDFR_CTRL, seek_alphanumeric_or_camel_left); - + // NOTE(allen|a3.2): Specific keys can override vanilla keys, // and write character writes whichever character corresponds // to the key that triggered the command. @@ -327,11 +289,11 @@ default_keys(Bind_Helper *context){ bind(context, ']', MDFR_NONE, write_and_auto_tab); bind(context, ';', MDFR_NONE, write_and_auto_tab); bind(context, '#', MDFR_NONE, write_and_auto_tab); - + bind(context, '\t', MDFR_NONE, cmdid_word_complete); bind(context, '\t', MDFR_CTRL, cmdid_auto_tab_range); bind(context, '\t', MDFR_SHIFT, auto_tab_line_at_cursor); - + bind(context, '=', MDFR_CTRL, write_increment); bind(context, 't', MDFR_ALT, write_allen_todo); bind(context, 'n', MDFR_ALT, write_allen_note); @@ -341,54 +303,53 @@ default_keys(Bind_Helper *context){ bind(context, 'i', MDFR_ALT, if0_off); bind(context, '1', MDFR_ALT, open_file_in_quotes); bind(context, '0', MDFR_CTRL, write_zero_struct); - + end_map(context); - - + + begin_map(context, mapid_file); - + // NOTE(allen|a3.4.4): Binding this essentially binds // all key combos that would normally insert a character // into a buffer. If the code for the key is not an enum // value such as key_left or key_back then it is a vanilla key. // It is possible to override this binding for individual keys. - bind_vanilla_keys(context, cmdid_write_character); - - bind(context, key_left, MDFR_NONE, cmdid_move_left); - bind(context, key_right, MDFR_NONE, cmdid_move_right); - bind(context, key_del, MDFR_NONE, cmdid_delete); - bind(context, key_back, MDFR_NONE, cmdid_backspace); - bind(context, key_up, MDFR_NONE, cmdid_move_up); - bind(context, key_down, MDFR_NONE, cmdid_move_down); + bind_vanilla_keys(context, write_character); + + bind(context, key_left, MDFR_NONE, move_left); + bind(context, key_right, MDFR_NONE, move_right); + bind(context, key_del, MDFR_NONE, delete_char); + bind(context, key_back, MDFR_NONE, backspace_char); + bind(context, key_up, MDFR_NONE, move_up); + bind(context, key_down, MDFR_NONE, move_down); bind(context, key_end, MDFR_NONE, cmdid_seek_end_of_line); bind(context, key_home, MDFR_NONE, cmdid_seek_beginning_of_line); bind(context, key_page_up, MDFR_NONE, cmdid_page_up); bind(context, key_page_down, MDFR_NONE, cmdid_page_down); - + bind(context, key_right, MDFR_CTRL, seek_whitespace_right); bind(context, key_left, MDFR_CTRL, seek_whitespace_left); - bind(context, key_up, MDFR_CTRL, cmdid_seek_whitespace_up); - bind(context, key_down, MDFR_CTRL, cmdid_seek_whitespace_down); - + bind(context, key_up, MDFR_CTRL, seek_whitespace_up); + bind(context, key_down, MDFR_CTRL, seek_whitespace_down); + bind(context, key_up, MDFR_ALT, move_up_10); bind(context, key_down, MDFR_ALT, move_down_10); - + bind(context, key_back, MDFR_CTRL, backspace_word); bind(context, key_back, MDFR_ALT, snipe_token_or_word); - - bind(context, ' ', MDFR_CTRL, cmdid_set_mark); + + bind(context, ' ', MDFR_CTRL, set_mark); bind(context, 'a', MDFR_CTRL, replace_in_range); bind(context, 'c', MDFR_CTRL, cmdid_copy); - bind(context, 'd', MDFR_CTRL, cmdid_delete_range); + bind(context, 'd', MDFR_CTRL, delete_range); bind(context, 'e', MDFR_CTRL, cmdid_center_view); bind(context, 'f', MDFR_CTRL, search); bind(context, 'g', MDFR_CTRL, goto_line); bind(context, 'h', MDFR_CTRL, cmdid_history_backward); bind(context, 'H', MDFR_CTRL, cmdid_history_forward); - bind(context, 'l', MDFR_CTRL, cmdid_toggle_line_wrap); bind(context, 'j', MDFR_CTRL, cmdid_to_lowercase); bind(context, 'K', MDFR_CTRL, cmdid_kill_buffer); - bind(context, 'L', MDFR_CTRL, cmdid_toggle_endline_mode); + bind(context, 'l', MDFR_CTRL, cmdid_toggle_line_wrap); bind(context, 'm', MDFR_CTRL, cmdid_cursor_mark_swap); bind(context, 'O', MDFR_CTRL, cmdid_reopen); bind(context, 'q', MDFR_CTRL, query_replace); @@ -411,7 +372,7 @@ default_keys(Bind_Helper *context){ bind(context, '~', MDFR_CTRL, cmdid_clean_all_lines); bind(context, '!', MDFR_CTRL, cmdid_eol_nixify); bind(context, '\n', MDFR_SHIFT, write_and_auto_tab); - bind(context, ' ', MDFR_SHIFT, cmdid_write_character); + bind(context, ' ', MDFR_SHIFT, write_character); end_map(context); } @@ -427,7 +388,7 @@ get_bindings(void *data, int size){ // and once set they always apply, regardless of what map is active. set_hook(context, hook_start, my_start); set_hook(context, hook_open_file, my_file_settings); - + set_scroll_rule(context, smooth_scroll_rule); default_keys(context); diff --git a/4coder_default_include.cpp b/4coder_default_include.cpp index da08c946..a5f49440 100644 --- a/4coder_default_include.cpp +++ b/4coder_default_include.cpp @@ -8,14 +8,289 @@ #include -static void -write_string(Application_Links *app, String string){ - Buffer_Summary buffer = get_active_buffer(app); - app->buffer_replace_range(app, &buffer, buffer.buffer_cursor_pos, buffer.buffer_cursor_pos, string.str, string.size); +inline float +get_view_y(View_Summary view){ + float y; + if (view.unwrapped_lines){ + y = view.cursor.unwrapped_y; + } + else{ + y = view.cursor.wrapped_y; + } + return(y); } -CUSTOM_COMMAND_SIG(write_increment){ - write_string(app, make_lit_string("++")); +inline float +get_view_x(View_Summary view){ + float x; + if (view.unwrapped_lines){ + x = view.cursor.unwrapped_x; + } + else{ + x = view.cursor.wrapped_x; + } + return(x); +} + +// +// Fundamental Editing +// + +CUSTOM_COMMAND_SIG(write_character){ + View_Summary view = app->get_active_view(app); + + User_Input in = app->get_command_input(app); + char character = 0; + + if (in.type == UserInputKey){ + character = in.key.character; + } + + if (character != 0){ + Buffer_Summary buffer = app->get_buffer(app, view.buffer_id); + int pos = view.cursor.pos; + int next_pos = pos + 1; + app->buffer_replace_range(app, &buffer, + pos, pos, &character, 1); + app->view_set_cursor(app, &view, seek_pos(next_pos), true); + } +} + +CUSTOM_COMMAND_SIG(delete_char){ + View_Summary view = app->get_active_view(app); + Buffer_Summary buffer = app->get_buffer(app, view.buffer_id); + + int pos = view.cursor.pos; + if (0 < buffer.size && pos < buffer.size){ + app->buffer_replace_range(app, &buffer, + pos, pos+1, 0, 0); + } +} + +CUSTOM_COMMAND_SIG(backspace_char){ + View_Summary view = app->get_active_view(app); + Buffer_Summary buffer = app->get_buffer(app, view.buffer_id); + + int pos = view.cursor.pos; + if (0 < pos && pos <= buffer.size){ + app->buffer_replace_range(app, &buffer, + pos-1, pos, 0, 0); + + app->view_set_cursor(app, &view, seek_pos(pos-1), true); + } +} + +CUSTOM_COMMAND_SIG(set_mark){ + View_Summary view = app->get_active_view(app); + + app->view_set_mark(app, &view, seek_pos(view.cursor.pos)); +} + +CUSTOM_COMMAND_SIG(delete_range){ + View_Summary view = app->get_active_view(app); + Buffer_Summary buffer = app->get_buffer(app, view.buffer_id); + + Range range = get_range(&view); + + app->buffer_replace_range(app, &buffer, + range.min, range.max, + 0, 0); +} + +// +// Basic Navigation +// + +inline void +move_vertical(Application_Links *app, float line_multiplier){ + View_Summary view = app->get_active_view(app); + + float new_y = get_view_y(view) + line_multiplier*view.line_height; + float x = view.preferred_x; + + app->view_set_cursor(app, &view, + seek_xy(x, new_y, false, view.unwrapped_lines), + false); +} + +CUSTOM_COMMAND_SIG(move_up){ + move_vertical(app, -1.f); +} + +CUSTOM_COMMAND_SIG(move_down){ + move_vertical(app, 1.f); +} + +CUSTOM_COMMAND_SIG(move_up_10){ + move_vertical(app, -10.f); +} + +CUSTOM_COMMAND_SIG(move_down_10){ + move_vertical(app, 10.f); +} + + +CUSTOM_COMMAND_SIG(move_left){ + View_Summary view = app->get_active_view(app); + int new_pos = view.cursor.pos - 1; + app->view_set_cursor(app, &view, + seek_pos(new_pos), + true); +} + +CUSTOM_COMMAND_SIG(move_right){ + View_Summary view = app->get_active_view(app); + int new_pos = view.cursor.pos + 1; + app->view_set_cursor(app, &view, + seek_pos(new_pos), + true); +} + +// +// Various Forms of Seek +// + +static int +buffer_seek_whitespace_up(Application_Links *app, Buffer_Summary *buffer, int pos){ + char chunk[1024]; + int chunk_size = sizeof(chunk); + Stream_Chunk stream = {0}; + + int no_hard; + int still_looping; + char at_pos; + + --pos; + if (init_stream_chunk(&stream, app, buffer, pos, chunk, chunk_size)){ + // Step 1: Find the first non-whitespace character + // behind the current position. + still_looping = true; + do{ + for (; pos >= stream.start; --pos){ + at_pos = stream.data[pos]; + if (!char_is_whitespace(at_pos)){ + goto double_break_1; + } + } + still_looping = backward_stream_chunk(&stream); + } while(still_looping); + double_break_1:; + + // Step 2: Continue scanning backward, at each '\n' + // mark the beginning of another line by setting + // no_hard to true, set it back to false if a + // non-whitespace character is discovered before + // the next '\n' + no_hard = false; + while (still_looping){ + for (; pos >= stream.start; --pos){ + at_pos = stream.data[pos]; + if (at_pos == '\n'){ + if (no_hard){ + goto double_break_2; + } + else{ + no_hard = true; + } + } + else if (!char_is_whitespace(at_pos)){ + no_hard = false; + } + } + still_looping = backward_stream_chunk(&stream); + } + double_break_2:; + + if (pos != 0){ + ++pos; + } + } + + return(pos); +} + +static int +buffer_seek_whitespace_down(Application_Links *app, Buffer_Summary *buffer, int pos){ + char chunk[1024]; + int chunk_size = sizeof(chunk); + Stream_Chunk stream = {0}; + + int no_hard; + int prev_endline; + int still_looping; + char at_pos; + + if (init_stream_chunk(&stream, app, buffer, pos, chunk, chunk_size)){ + // Step 1: Find the first non-whitespace character + // ahead of the current position. + still_looping = true; + do{ + for (; pos < stream.end; ++pos){ + at_pos = stream.data[pos]; + if (!char_is_whitespace(at_pos)){ + goto double_break_1; + } + } + still_looping = forward_stream_chunk(&stream); + } while(still_looping); + double_break_1:; + + // Step 2: Continue scanning forward, at each '\n' + // mark it as the beginning of a new line by updating + // the prev_endline value. If another '\n' is found + // with non-whitespace then the previous line was + // all whitespace. + no_hard = false; + prev_endline = -1; + while(still_looping){ + for (; pos < stream.end; ++pos){ + at_pos = stream.data[pos]; + if (at_pos == '\n'){ + if (no_hard){ + goto double_break_2; + } + else{ + no_hard = true; + prev_endline = pos; + } + } + else if (!char_is_whitespace(at_pos)){ + no_hard = false; + } + } + still_looping = forward_stream_chunk(&stream); + } + double_break_2:; + + if (prev_endline == -1 || prev_endline+1 >= buffer->size){ + pos = buffer->size; + } + else{ + pos = prev_endline+1; + } + } + + return(pos); +} + +CUSTOM_COMMAND_SIG(seek_whitespace_up){ + View_Summary view = app->get_active_view(app); + Buffer_Summary buffer = app->get_buffer(app, view.locked_buffer_id); + + int new_pos = buffer_seek_whitespace_up(app, &buffer, view.cursor.pos); + app->view_set_cursor(app, &view, + seek_pos(new_pos), + true); +} + +CUSTOM_COMMAND_SIG(seek_whitespace_down){ + View_Summary view = app->get_active_view(app); + Buffer_Summary buffer = app->get_buffer(app, view.locked_buffer_id); + + int new_pos = buffer_seek_whitespace_down(app, &buffer, view.cursor.pos); + app->view_set_cursor(app, &view, + seek_pos(new_pos), + true); } static void @@ -38,6 +313,23 @@ SEEK_COMMAND(alphanumeric, left, BoundryAlphanumeric) SEEK_COMMAND(alphanumeric_or_camel, right, BoundryAlphanumeric | BoundryCamelCase) SEEK_COMMAND(alphanumeric_or_camel, left, BoundryAlphanumeric | BoundryCamelCase) + +// +// Special string writing commands +// + +static void +write_string(Application_Links *app, String string){ + Buffer_Summary buffer = get_active_buffer(app); + app->buffer_replace_range(app, &buffer, + buffer.buffer_cursor_pos, buffer.buffer_cursor_pos, + string.str, string.size); +} + +CUSTOM_COMMAND_SIG(write_increment){ + write_string(app, make_lit_string("++")); +} + static void long_braces(Application_Links *app, char *text, int size){ View_Summary view; @@ -672,7 +964,7 @@ CUSTOM_COMMAND_SIG(auto_tab_whole_file){ } CUSTOM_COMMAND_SIG(write_and_auto_tab){ - exec_command(app, cmdid_write_character); + exec_command(app, write_character); exec_command(app, auto_tab_line_at_cursor); } diff --git a/4ed.cpp b/4ed.cpp index 3444ebb4..6f83f9fe 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -227,24 +227,6 @@ COMMAND_DECL(null){ AllowLocal(command); } -COMMAND_DECL(write_character){ - - USE_MODELS(models); - REQ_OPEN_VIEW(view); - REQ_FILE(file, view); - - char character; - i32 pos, next_cursor_pos; - - character = command->key.character; - if (character != 0){ - pos = view->recent->cursor.pos; - next_cursor_pos = view->recent->cursor.pos + 1; - view_replace_range(system, models, view, pos, pos, &character, 1, next_cursor_pos); - view_cursor_move(view, next_cursor_pos); - } -} - internal i32 seek_token_left(Cpp_Token_Stack *tokens, i32 pos){ Cpp_Get_Token_Result get = cpp_get_token(tokens, pos); @@ -275,7 +257,6 @@ seek_token_right(Cpp_Token_Stack *tokens, i32 pos){ } COMMAND_DECL(seek_left){ - REQ_READABLE_VIEW(view); REQ_FILE(file, view); @@ -328,7 +309,6 @@ COMMAND_DECL(seek_left){ } COMMAND_DECL(seek_right){ - REQ_READABLE_VIEW(view); REQ_FILE(file, view); @@ -382,26 +362,7 @@ COMMAND_DECL(seek_right){ view_cursor_move(view, new_pos); } -COMMAND_DECL(seek_whitespace_up){ - - REQ_READABLE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = buffer_seek_whitespace_up(&file->state.buffer, view->recent->cursor.pos); - view_cursor_move(view, pos); -} - -COMMAND_DECL(seek_whitespace_down){ - - REQ_READABLE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = buffer_seek_whitespace_down(&file->state.buffer, view->recent->cursor.pos); - view_cursor_move(view, pos); -} - COMMAND_DECL(center_view){ - USE_VIEW(view); REQ_FILE(file, view); @@ -420,7 +381,6 @@ COMMAND_DECL(center_view){ } COMMAND_DECL(word_complete){ - USE_MODELS(models); USE_VARS(vars); REQ_OPEN_VIEW(view); @@ -579,14 +539,6 @@ COMMAND_DECL(word_complete){ } } -COMMAND_DECL(set_mark){ - REQ_READABLE_VIEW(view); - REQ_FILE(file, view); - - view->recent->mark = (i32)view->recent->cursor.pos; - view->recent->preferred_x = view_get_cursor_x(view); -} - COMMAND_DECL(copy){ USE_MODELS(models); REQ_READABLE_VIEW(view); @@ -729,24 +681,6 @@ COMMAND_DECL(paste_next){ } } -COMMAND_DECL(delete_range){ - USE_MODELS(models); - REQ_OPEN_VIEW(view); - REQ_FILE(file, view); - - Range range; - i32 next_cursor_pos; - - range = make_range(view->recent->cursor.pos, view->recent->mark); - if (range.start < range.end){ - next_cursor_pos = range.start; - Assert(range.end <= buffer_size(&file->state.buffer)); - view_replace_range(system, models, view, range.start, range.end, 0, 0, next_cursor_pos); - view_cursor_move(view, next_cursor_pos); - view->recent->mark = range.start; - } -} - COMMAND_DECL(undo){ USE_MODELS(models); REQ_OPEN_VIEW(view); @@ -755,7 +689,6 @@ COMMAND_DECL(undo){ view_undo(system, models, view); Assert(file->state.undo.undo.size >= 0); - } COMMAND_DECL(redo){ @@ -1279,6 +1212,7 @@ COMMAND_DECL(close_panel){ } } +#if 0 COMMAND_DECL(move_left){ REQ_READABLE_VIEW(view); @@ -1303,18 +1237,17 @@ COMMAND_DECL(delete){ USE_MODELS(models); REQ_OPEN_VIEW(view); REQ_FILE(file, view); - + i32 size = buffer_size(&file->state.buffer); i32 cursor_pos = view->recent->cursor.pos; if (0 < size && cursor_pos < size){ i32 start, end; start = cursor_pos; end = cursor_pos+1; - - Assert(end - start > 0); - + i32 next_cursor_pos = start; - view_replace_range(system, models, view, start, end, 0, 0, next_cursor_pos); + view_replace_range(system, models, view, + start, end, 0, 0, next_cursor_pos); view_cursor_move(view, next_cursor_pos); } } @@ -1331,41 +1264,12 @@ COMMAND_DECL(backspace){ end = cursor_pos; start = cursor_pos-1; - i32 shift = (end - start); - Assert(shift > 0); - - i32 next_cursor_pos = view->recent->cursor.pos - shift; + i32 next_cursor_pos = view->recent->cursor.pos - 1; view_replace_range(system, models, view, start, end, 0, 0, next_cursor_pos); view_cursor_move(view, next_cursor_pos); } } - -COMMAND_DECL(move_up){ - USE_MODELS(models); - REQ_READABLE_VIEW(view); - REQ_FILE(file, view); - - f32 line_height = (f32)get_font_info(models->font_set, models->global_font.font_id)->height; - f32 cy = view_get_cursor_y(view)-line_height; - f32 px = view->recent->preferred_x; - if (cy >= 0){ - view->recent->cursor = view_compute_cursor_from_xy(view, px, cy); - file->state.cursor_pos = view->recent->cursor.pos; - } -} - -COMMAND_DECL(move_down){ - - USE_MODELS(models); - REQ_READABLE_VIEW(view); - REQ_FILE(file, view); - - f32 line_height = (f32)get_font_info(models->font_set, models->global_font.font_id)->height; - f32 cy = view_get_cursor_y(view)+line_height; - f32 px = view->recent->preferred_x; - view->recent->cursor = view_compute_cursor_from_xy(view, px, cy); - file->state.cursor_pos = view->recent->cursor.pos; -} +#endif COMMAND_DECL(seek_end_of_line){ REQ_READABLE_VIEW(view); @@ -1463,6 +1367,8 @@ COMMAND_DECL(set_settings){ Editing_File *file = 0; b32 set_mapid = 0; i32 new_mapid = 0; + b32 set_show_whitespace = 0; + b32 show_whitespace = 0; Command_Parameter *end = param_stack_end(&command->part); Command_Parameter *param = param_stack_first(&command->part, end); @@ -1512,13 +1418,19 @@ COMMAND_DECL(set_settings){ } } }break; + + case par_show_whitespace: + { + set_show_whitespace = 1; + show_whitespace = dynamic_to_bool(¶m->param.value); + }break; } } if (set_mapid){ for (View_Iter iter = file_view_iter_init(&models->layout, file, 0); - file_view_iter_good(iter); - iter = file_view_iter_next(iter)){ + file_view_iter_good(iter); + iter = file_view_iter_next(iter)){ iter.view->map = get_map(models, file->settings.base_map_id); } } @@ -1760,12 +1672,14 @@ fill_view_summary(View_Summary *view, View *vptr, Live_Views *live_set, Working_ i32 lock_level; int buffer_id; *view = view_summary_zero(); - + if (vptr->in_use){ view->exists = 1; view->view_id = (int)(vptr - live_set->views) + 1; - view->line_height = vptr->line_height; + view->line_height = (float)(vptr->line_height); view->unwrapped_lines = vptr->file_data.unwrapped_lines; + view->show_whitespace = vptr->file_data.show_whitespace; + if (vptr->file_data.file){ lock_level = view_lock_level(vptr); @@ -1929,121 +1843,6 @@ extern "C"{ return(buffer); } -#if 0 - BUFFER_SEEK_DELIMITER_SIG(external_buffer_seek_delimiter){ - Command_Data *cmd = (Command_Data*)app->cmd_context; - Editing_File *file; - Working_Set *working_set; - int result = 0; - int size; - - if (buffer->exists){ - working_set = &cmd->models->working_set; - file = working_set_get_active_file(working_set, buffer->buffer_id); - if (file && file_is_ready(file)){ - size = buffer_size(&file->state.buffer); - result = 1; - - if (start < 0 && !seek_forward) *out = start; - else if (start >= size && seek_forward) *out = start; - else{ - if (seek_forward){ - *out = buffer_seek_delimiter(&file->state.buffer, start, delim); - } - else{ - *out = buffer_reverse_seek_delimiter(&file->state.buffer, start, delim); - } - } - - fill_buffer_summary(buffer, file, working_set); - } - } - - return(result); - } - - BUFFER_SEEK_STRING_SIG(external_buffer_seek_string){ - Command_Data *cmd = (Command_Data*)app->cmd_context; - Models *models; - Editing_File *file; - Working_Set *working_set; - Partition *part; - Temp_Memory temp; - char *spare; - int result = 0; - int size; - - if (buffer->exists){ - models = cmd->models; - working_set = &models->working_set; - file = working_set_get_active_file(working_set, buffer->buffer_id); - if (file && file_is_ready(file)){ - size = buffer_size(&file->state.buffer); - - if (start < 0 && !seek_forward) *out = start; - else if (start >= size && seek_forward) *out = start; - else{ - part = &models->mem.part; - temp = begin_temp_memory(part); - spare = push_array(part, char, len); - result = 1; - if (seek_forward){ - *out = buffer_find_string(&file->state.buffer, start, size, str, len, spare); - } - else{ - *out = buffer_rfind_string(&file->state.buffer, start, str, len, spare); - } - end_temp_memory(temp); - } - fill_buffer_summary(buffer, file, working_set); - } - } - - return(result); - } - - // TODO(allen): Reduce duplication between this and external_buffer_seek_string - BUFFER_SEEK_STRING_SIG(external_buffer_seek_string_insensitive){ - Command_Data *cmd = (Command_Data*)app->cmd_context; - Models *models; - Editing_File *file; - Working_Set *working_set; - Partition *part; - Temp_Memory temp; - char *spare; - int result = 0; - int size; - - if (buffer->exists){ - models = cmd->models; - working_set = &models->working_set; - file = working_set_get_active_file(working_set, buffer->buffer_id); - if (file && file_is_ready(file)){ - size = buffer_size(&file->state.buffer); - - if (start < 0 && !seek_forward) *out = start; - else if (start >= size && seek_forward) *out = start; - else{ - part = &models->mem.part; - temp = begin_temp_memory(part); - spare = push_array(part, char, len); - result = 1; - if (seek_forward){ - *out = buffer_find_string_insensitive(&file->state.buffer, start, size, str, len, spare); - } - else{ - *out = buffer_rfind_string_insensitive(&file->state.buffer, start, str, len, spare); - } - end_temp_memory(temp); - } - fill_buffer_summary(buffer, file, working_set); - } - } - - return(result); - } -#endif - REFRESH_BUFFER_SIG(external_refresh_buffer){ int result; *buffer = external_get_buffer(app, buffer->buffer_id); @@ -2523,12 +2322,6 @@ app_links_init(System_Functions *system, Application_Links *app_links, void *dat app_links->refresh_buffer = external_refresh_buffer; -#if 0 - app_links->buffer_seek_delimiter = external_buffer_seek_delimiter; - app_links->buffer_seek_string = external_buffer_seek_string; - app_links->buffer_seek_string_insensitive = external_buffer_seek_string_insensitive; -#endif - app_links->buffer_read_range = external_buffer_read_range; app_links->buffer_replace_range = external_buffer_replace_range; @@ -2598,21 +2391,15 @@ setup_top_commands(Command_Map *commands, Partition *part, Command_Map *parent){ internal void setup_command_table(){ #define SET(n) command_table[cmdid_##n] = command_##n - SET(null); - SET(write_character); SET(seek_left); SET(seek_right); - SET(seek_whitespace_up); - SET(seek_whitespace_down); SET(center_view); SET(word_complete); - SET(set_mark); SET(copy); SET(cut); SET(paste); SET(paste_next); - SET(delete_range); SET(undo); SET(redo); SET(history_backward); @@ -2621,14 +2408,13 @@ setup_command_table(){ SET(interactive_open); SET(reopen); SET(save); - //SET(interactive_save_as); SET(change_active_panel); SET(interactive_switch_buffer); SET(interactive_kill_buffer); SET(kill_buffer); - SET(toggle_line_wrap); SET(to_uppercase); SET(to_lowercase); + SET(toggle_line_wrap); SET(toggle_show_whitespace); SET(clean_all_lines); SET(eol_dosify); @@ -2637,12 +2423,7 @@ setup_command_table(){ SET(open_panel_vsplit); SET(open_panel_hsplit); SET(close_panel); - SET(move_left); - SET(move_right); - SET(delete); - SET(backspace); - SET(move_up); - SET(move_down); + SET(seek_end_of_line); SET(seek_beginning_of_line); SET(page_up); @@ -4049,12 +3830,11 @@ App_Step_Sig(app_step){ summary.mouse = mouse_state; } - GUI_Scroll_Vars *vars = view->current_scroll; // TODO(allen): I feel like the scroll context should actually not // be allowed to change in here at all. - result = do_input_file_view(system, view, panel->inner, active, - &summary, *vars, view->scroll_region); + result = do_step_file_view(system, view, panel->inner, active, + &summary, *vars, view->scroll_region); if (result.is_animating){ app_result.animating = 1; } diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index 858b2e76..5571cf0f 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -4542,10 +4542,10 @@ struct Input_Process_Result{ }; internal Input_Process_Result -do_input_file_view(System_Functions *system, - View *view, i32_Rect rect, b32 is_active, - Input_Summary *user_input, - GUI_Scroll_Vars vars, i32_Rect region){ +do_step_file_view(System_Functions *system, + View *view, i32_Rect rect, b32 is_active, + Input_Summary *user_input, + GUI_Scroll_Vars vars, i32_Rect region){ Input_Process_Result result = {0}; b32 is_file_scroll = 0; @@ -4554,6 +4554,8 @@ do_input_file_view(System_Functions *system, GUI_Target *target = &view->gui_target; GUI_Interpret_Result interpret_result = {0}; + vars.target_y = clamp(0.f, vars.target_y, vars.max_y); + result.vars = vars; result.region = region; diff --git a/4ed_gui.cpp b/4ed_gui.cpp index 2492c2fe..63f5995e 100644 --- a/4ed_gui.cpp +++ b/4ed_gui.cpp @@ -1240,8 +1240,8 @@ gui_standard_list(GUI_Target *target, GUI_id id, GUI_Scroll_Vars *vars, i32_Rect if (update->has_index_position){ GUI_View_Jump jump = gui_compute_view_jump(scroll_region, update->index_position); - jump.view_min = clamp_bottom(0.f, jump.view_min + 45.f); - jump.view_max = clamp_bottom(0.f, jump.view_max - 45.f); + jump.view_min = jump.view_min + 45.f; + jump.view_max = jump.view_max - 45.f; *vars = gui_do_jump(target, jump, *vars); } diff --git a/buffer/4coder_buffer_abstract.cpp b/buffer/4coder_buffer_abstract.cpp index f7ec17a3..7d8aacb4 100644 --- a/buffer/4coder_buffer_abstract.cpp +++ b/buffer/4coder_buffer_abstract.cpp @@ -128,6 +128,8 @@ buffer_reverse_seek_delimiter(Buffer_Type *buffer, int pos, char delim){ return(pos); } + +#if 0 internal_4tech int buffer_seek_whitespace_down(Buffer_Type *buffer, int pos){ Buffer_Stringify_Type loop; @@ -219,6 +221,7 @@ buffer_seek_whitespace_up_end: return pos; } +#endif internal_4tech int buffer_seek_whitespace_right(Buffer_Type *buffer, int pos){ From 91386e62d01b2cde8080844dd4d5b7e4f9eecf96 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Fri, 3 Jun 2016 14:45:51 -0400 Subject: [PATCH 33/34] combined font-info-load and font-load --- 4ed.cpp | 522 +++++++++++++++--------------- 4ed_font_set.cpp | 50 +-- 4ed_rendering.cpp | 219 ++++--------- 4ed_rendering.h | 13 +- buffer/4coder_buffer_abstract.cpp | 100 +----- win32_4ed.cpp | 19 +- win32_font.cpp | 25 ++ 7 files changed, 395 insertions(+), 553 deletions(-) create mode 100644 win32_font.cpp diff --git a/4ed.cpp b/4ed.cpp index 6f83f9fe..f6d36dd2 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -47,27 +47,27 @@ struct Command_Data{ struct App_Vars *vars; System_Functions *system; Live_Views *live_set; - + Panel *panel; View *view; - + i32 screen_width, screen_height; Key_Event_Data key; - + Partition part; }; struct App_Vars{ Models models; - + CLI_List cli_processes; - + Live_Views live_set; - + App_State state; App_State_Resizing resizing; Complete_State complete_state; - + Command_Data command_data; }; @@ -101,10 +101,7 @@ app_launch_coroutine(System_Functions *system, Application_Links *app, Coroutine app->current_coroutine = co; app->type_coroutine = type; - { - result = system->launch_coroutine(co, in, out); - } - + result = system->launch_coroutine(co, in, out); restore_state(app, prev_state); return(result); @@ -119,10 +116,7 @@ app_resume_coroutine(System_Functions *system, Application_Links *app, Coroutine app->current_coroutine = co; app->type_coroutine = type; - { - result = system->resume_coroutine(co, in, out); - } - + result = system->resume_coroutine(co, in, out); restore_state(app, prev_state); return(result); @@ -141,7 +135,7 @@ output_file_append(System_Functions *system, Models *models, Editing_File *file, inline void do_feedback_message(System_Functions *system, Models *models, String value){ Editing_File *file = models->message_buffer; - + if (file){ output_file_append(system, models, file, value, 1); i32 pos = buffer_size(&file->state.buffer); @@ -214,12 +208,12 @@ internal View* panel_make_empty(System_Functions *system, App_Vars *vars, Panel *panel){ Models *models = &vars->models; View_And_ID new_view; - + Assert(panel->view == 0); new_view = live_set_alloc_view(&vars->live_set, panel, models); view_set_file(new_view.view, 0, models); new_view.view->map = get_map(models, mapid_global); - + return(new_view.view); } @@ -233,12 +227,12 @@ seek_token_left(Cpp_Token_Stack *tokens, i32 pos){ if (get.token_index == -1){ get.token_index = 0; } - + Cpp_Token *token = tokens->tokens + get.token_index; if (token->start == pos && get.token_index > 0){ --token; } - + return token->start; } @@ -251,7 +245,7 @@ seek_token_right(Cpp_Token_Stack *tokens, i32 pos){ if (get.token_index >= tokens->count){ get.token_index = tokens->count-1; } - + Cpp_Token *token = tokens->tokens + get.token_index; return token->start + token->size; } @@ -259,9 +253,9 @@ seek_token_right(Cpp_Token_Stack *tokens, i32 pos){ COMMAND_DECL(seek_left){ REQ_READABLE_VIEW(view); REQ_FILE(file, view); - + u32 flags = BoundryWhitespace; - + Command_Parameter *end = param_stack_end(&command->part); Command_Parameter *param = param_stack_first(&command->part, end); for (; param < end; param = param_next(param, end)){ @@ -272,13 +266,13 @@ COMMAND_DECL(seek_left){ break; } } - + i32 pos[4] = {0}; - + if (flags & (1)){ pos[0] = buffer_seek_whitespace_left(&file->state.buffer, view->recent->cursor.pos); } - + if (flags & (1 << 1)){ if (file->state.tokens_complete){ pos[1] = seek_token_left(&file->state.token_stack, view->recent->cursor.pos); @@ -287,7 +281,7 @@ COMMAND_DECL(seek_left){ pos[1] = buffer_seek_whitespace_left(&file->state.buffer, view->recent->cursor.pos); } } - + if (flags & (1 << 2)){ pos[2] = buffer_seek_alphanumeric_left(&file->state.buffer, view->recent->cursor.pos); if (flags & (1 << 3)){ @@ -299,21 +293,21 @@ COMMAND_DECL(seek_left){ pos[3] = buffer_seek_alphanumeric_or_camel_left(&file->state.buffer, view->recent->cursor.pos); } } - + i32 new_pos = 0; for (i32 i = 0; i < ArrayCount(pos); ++i){ if (pos[i] > new_pos) new_pos = pos[i]; } - + view_cursor_move(view, new_pos); } COMMAND_DECL(seek_right){ REQ_READABLE_VIEW(view); REQ_FILE(file, view); - + u32 flags = BoundryWhitespace; - + Command_Parameter *end = param_stack_end(&command->part); Command_Parameter *param = param_stack_first(&command->part, end); for (; param < end; param = param_next(param, end)){ @@ -324,15 +318,15 @@ COMMAND_DECL(seek_right){ break; } } - + i32 size = buffer_size(&file->state.buffer); i32 pos[4]; for (i32 i = 0; i < ArrayCount(pos); ++i) pos[i] = size; - + if (flags & (1)){ pos[0] = buffer_seek_whitespace_right(&file->state.buffer, view->recent->cursor.pos); } - + if (flags & (1 << 1)){ if (file->state.tokens_complete){ pos[1] = seek_token_right(&file->state.token_stack, view->recent->cursor.pos); @@ -341,7 +335,7 @@ COMMAND_DECL(seek_right){ pos[1] = buffer_seek_whitespace_right(&file->state.buffer, view->recent->cursor.pos); } } - + if (flags & (1 << 2)){ pos[2] = buffer_seek_alphanumeric_right(&file->state.buffer, view->recent->cursor.pos); if (flags & (1 << 3)){ @@ -353,19 +347,19 @@ COMMAND_DECL(seek_right){ pos[3] = buffer_seek_alphanumeric_or_camel_right(&file->state.buffer, view->recent->cursor.pos); } } - + i32 new_pos = size; for (i32 i = 0; i < ArrayCount(pos); ++i){ if (pos[i] < new_pos) new_pos = pos[i]; } - + view_cursor_move(view, new_pos); } COMMAND_DECL(center_view){ - USE_VIEW(view); + REQ_READABLE_VIEW(view); REQ_FILE(file, view); - + f32 y, h; if (view->file_data.unwrapped_lines){ y = view->recent->cursor.unwrapped_y; @@ -376,7 +370,7 @@ COMMAND_DECL(center_view){ h = view_file_height(view); y = clamp_bottom(0.f, y - h*.5f); - + view->recent->scroll.target_y = y; } @@ -543,11 +537,11 @@ COMMAND_DECL(copy){ USE_MODELS(models); REQ_READABLE_VIEW(view); REQ_FILE(file, view); - + // TODO(allen): deduplicate int r_start = 0, r_end = 0; int start_set = 0, end_set = 0; - + Command_Parameter *end = param_stack_end(&command->part); Command_Parameter *param = param_stack_first(&command->part, end); for (; param < end; param = param_next(param, end)){ @@ -557,14 +551,14 @@ COMMAND_DECL(copy){ start_set = 1; r_start = dynamic_to_int(¶m->param.value); break; - + case par_range_end: end_set = 1; r_end = dynamic_to_int(¶m->param.value); break; } } - + Range range = make_range(view->recent->cursor.pos, view->recent->mark); if (start_set) range.start = r_start; if (end_set) range.end = r_end; @@ -577,11 +571,11 @@ COMMAND_DECL(cut){ USE_MODELS(models); REQ_OPEN_VIEW(view); REQ_FILE(file, view); - + // TODO(allen): deduplicate int r_start = 0, r_end = 0; int start_set = 0, end_set = 0; - + Command_Parameter *end = param_stack_end(&command->part); Command_Parameter *param = param_stack_first(&command->part, end); for (; param < end; param = param_next(param, end)){ @@ -591,23 +585,23 @@ COMMAND_DECL(cut){ start_set = 1; r_start = dynamic_to_int(¶m->param.value); break; - + case par_range_end: end_set = 1; r_end = dynamic_to_int(¶m->param.value); break; } } - + Range range = make_range(view->recent->cursor.pos, view->recent->mark); if (start_set) range.start = r_start; if (end_set) range.end = r_end; if (range.start < range.end){ i32 next_cursor_pos = range.start; - + clipboard_copy(system, &models->mem.general, &models->working_set, range, file); view_replace_range(system, models, view, range.start, range.end, 0, 0, next_cursor_pos); - + view->recent->mark = range.start; view_cursor_move(view, next_cursor_pos); } @@ -618,28 +612,28 @@ COMMAND_DECL(paste){ USE_MODELS(models); REQ_OPEN_VIEW(view); REQ_FILE(file, view); - + View_Iter iter; String *src; i32 pos_left, next_cursor_pos; - + if (models->working_set.clipboard_size > 0){ view->next_mode.rewrite = 1; - + src = working_set_clipboard_head(&models->working_set); pos_left = view->recent->cursor.pos; - + next_cursor_pos = pos_left+src->size; view_replace_range(system, models, view, pos_left, pos_left, src->str, src->size, next_cursor_pos); - + view_cursor_move(view, next_cursor_pos); view->recent->mark = pos_left; - + Style *style = main_style(models); u32 paste_color = style->main.paste_color; for (iter = file_view_iter_init(&models->layout, file, 0); - file_view_iter_good(iter); - iter = file_view_iter_next(iter)){ + file_view_iter_good(iter); + iter = file_view_iter_next(iter)){ view_post_paste_effect(iter.view, 20, pos_left, src->size, paste_color); } } @@ -649,30 +643,30 @@ COMMAND_DECL(paste_next){ USE_MODELS(models); REQ_OPEN_VIEW(view); REQ_FILE(file, view); - + View_Iter iter; Range range; String *src; i32 next_cursor_pos; - + if (models->working_set.clipboard_size > 0 && view->mode.rewrite == 1){ view->next_mode.rewrite = 1; - + range = make_range(view->recent->mark, view->recent->cursor.pos); src = working_set_clipboard_roll_down(&models->working_set); next_cursor_pos = range.start+src->size; view_replace_range(system, - models, view, range.start, range.end, - src->str, src->size, next_cursor_pos); - + models, view, range.start, range.end, + src->str, src->size, next_cursor_pos); + view_cursor_move(view, next_cursor_pos); view->recent->mark = range.start; - + Style *style = main_style(models); u32 paste_color = style->main.paste_color; for (iter = file_view_iter_init(&models->layout, file, 0); - file_view_iter_good(iter); - iter = file_view_iter_next(iter)){ + file_view_iter_good(iter); + iter = file_view_iter_next(iter)){ view_post_paste_effect(iter.view, 20, range.start, src->size, paste_color); } } @@ -685,7 +679,7 @@ COMMAND_DECL(undo){ USE_MODELS(models); REQ_OPEN_VIEW(view); REQ_FILE_HISTORY(file, view); - + view_undo(system, models, view); Assert(file->state.undo.undo.size >= 0); @@ -695,7 +689,7 @@ COMMAND_DECL(redo){ USE_MODELS(models); REQ_OPEN_VIEW(view); REQ_FILE_HISTORY(file, view); - + view_redo(system, models, view); Assert(file->state.undo.undo.size >= 0); @@ -705,7 +699,7 @@ COMMAND_DECL(history_backward){ USE_MODELS(models); REQ_OPEN_VIEW(view); REQ_FILE_HISTORY(file, view); - + view_history_step(system, models, view, hist_backward); } @@ -713,32 +707,32 @@ COMMAND_DECL(history_forward){ USE_MODELS(models); REQ_OPEN_VIEW(view); REQ_FILE_HISTORY(file, view); - + view_history_step(system, models, view, hist_backward); } COMMAND_DECL(interactive_new){ USE_MODELS(models); USE_VIEW(view); - + view_show_interactive(system, view, &models->map_ui, - IAct_New, IInt_Sys_File_List, make_lit_string("New: ")); + IAct_New, IInt_Sys_File_List, make_lit_string("New: ")); } COMMAND_DECL(interactive_open){ USE_MODELS(models); USE_VIEW(view); - + char *filename = 0; int filename_len = 0; int do_in_background = 0; - + Command_Parameter *end = param_stack_end(&command->part); Command_Parameter *param = param_stack_first(&command->part, end); for (; param < end; param = param_next(param, end)){ if (param->param.param.type == dynamic_type_int){ if (param->param.param.int_value == par_name && - param->param.value.type == dynamic_type_string){ + param->param.value.type == dynamic_type_string){ filename = param->param.value.str_value; filename_len = param->param.value.str_len; } @@ -747,7 +741,7 @@ COMMAND_DECL(interactive_open){ } } } - + if (filename){ String string = make_string(filename, filename_len); if (do_in_background){ @@ -759,7 +753,7 @@ COMMAND_DECL(interactive_open){ } else{ view_show_interactive(system, view, &models->map_ui, - IAct_Open, IInt_Sys_File_List, make_lit_string("Open: ")); + IAct_Open, IInt_Sys_File_List, make_lit_string("Open: ")); } } @@ -797,12 +791,12 @@ COMMAND_DECL(save){ USE_MODELS(models); USE_VIEW(view); USE_FILE(file, view); - + char *filename = 0; int filename_len = 0; int buffer_id = -1; int update_names = 0; - + Command_Parameter *end = param_stack_end(&command->part); Command_Parameter *param = param_stack_first(&command->part, end); for (; param < end; param = param_next(param, end)){ @@ -815,13 +809,13 @@ COMMAND_DECL(save){ buffer_id = dynamic_to_int(¶m->param.value); } else if (v == par_save_update_name){ - update_names = dynamic_to_bool(¶m->param.value); - } + update_names = dynamic_to_bool(¶m->param.value); + } } - + if (buffer_id != -1){ file = working_set_get_active_file(&models->working_set, buffer_id); - } + } if (update_names){ String name = {}; @@ -837,7 +831,7 @@ COMMAND_DECL(save){ } else{ view_show_interactive(system, view, &models->map_ui, - IAct_Save_As, IInt_Sys_File_List, make_lit_string("Save As: ")); + IAct_Save_As, IInt_Sys_File_List, make_lit_string("Save As: ")); } } } @@ -867,7 +861,7 @@ COMMAND_DECL(change_active_panel){ USE_MODELS(models); USE_PANEL(panel); - + panel = panel->next; if (panel == &models->layout.used_sentinel){ panel = panel->next; @@ -879,27 +873,27 @@ COMMAND_DECL(interactive_switch_buffer){ USE_VIEW(view); USE_MODELS(models); - + view_show_interactive(system, view, &models->map_ui, - IAct_Switch, IInt_Live_File_List, make_lit_string("Switch Buffer: ")); + IAct_Switch, IInt_Live_File_List, make_lit_string("Switch Buffer: ")); } COMMAND_DECL(interactive_kill_buffer){ USE_VIEW(view); USE_MODELS(models); - + view_show_interactive(system, view, &models->map_ui, - IAct_Kill, IInt_Live_File_List, make_lit_string("Kill Buffer: ")); + IAct_Kill, IInt_Live_File_List, make_lit_string("Kill Buffer: ")); } COMMAND_DECL(kill_buffer){ USE_MODELS(models); USE_VIEW(view); USE_FILE(file, view); - + int buffer_id = 0; - + Command_Parameter *end = param_stack_end(&command->part); Command_Parameter *param = param_stack_first(&command->part, end); for (; param < end; param = param_next(param, end)){ @@ -908,7 +902,7 @@ COMMAND_DECL(kill_buffer){ buffer_id = dynamic_to_int(¶m->param.value); } } - + if (buffer_id != 0){ file = working_set_get_active_file(&models->working_set, buffer_id); if (file){ @@ -924,14 +918,14 @@ COMMAND_DECL(kill_buffer){ COMMAND_DECL(toggle_line_wrap){ REQ_READABLE_VIEW(view); REQ_FILE(file, view); - + Relative_Scrolling scrolling = view_get_relative_scrolling(view); if (view->file_data.unwrapped_lines){ view->file_data.unwrapped_lines = 0; file->settings.unwrapped_lines = 0; view->recent->scroll.target_x = 0; view->recent->cursor = view_compute_cursor_from_pos( - view, view->recent->cursor.pos); + view, view->recent->cursor.pos); view->recent->preferred_x = view->recent->cursor.wrapped_x; } else{ @@ -954,7 +948,7 @@ COMMAND_DECL(toggle_tokens){ USE_MODELS(models); REQ_OPEN_VIEW(view); REQ_FILE(file, view); - + if (file->settings.tokens_exist){ file_kill_tokens(system, &models->mem.general, file); } @@ -966,8 +960,8 @@ COMMAND_DECL(toggle_tokens){ internal void case_change_range(System_Functions *system, - Mem_Options *mem, View *view, Editing_File *file, - u8 a, u8 z, u8 char_delta){ + Mem_Options *mem, View *view, Editing_File *file, + u8 a, u8 z, u8 char_delta){ #if BUFFER_EXPERIMENT_SCALPEL <= 0 Range range = make_range(view->recent->cursor.pos, view->recent->mark); if (range.start < range.end){ @@ -976,19 +970,19 @@ case_change_range(System_Functions *system, step.edit.start = range.start; step.edit.end = range.end; step.edit.len = range.end - range.start; - + if (file->state.still_lexing) system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); - + file_update_history_before_edit(mem, file, step, 0, hist_normal); - + u8 *data = (u8*)file->state.buffer.data; for (i32 i = range.start; i < range.end; ++i){ if (data[i] >= a && data[i] <= z){ data[i] += char_delta; } } - + if (file->state.token_stack.tokens) file_relex_parallel(system, mem, file, range.start, range.end, 0); } @@ -1015,14 +1009,14 @@ COMMAND_DECL(clean_all_lines){ USE_MODELS(models); REQ_OPEN_VIEW(view); REQ_FILE(file, view); - + view_clean_whitespace(system, models, view); } COMMAND_DECL(eol_dosify){ REQ_READABLE_VIEW(view); REQ_FILE(file, view); - + file->settings.dos_write_mode = 1; file->state.last_4ed_edit_time = system->now_time_stamp(); } @@ -1030,7 +1024,7 @@ COMMAND_DECL(eol_dosify){ COMMAND_DECL(eol_nixify){ REQ_READABLE_VIEW(view); REQ_FILE(file, view); - + file->settings.dos_write_mode = 0; file->state.last_4ed_edit_time = system->now_time_stamp(); } @@ -1039,14 +1033,14 @@ COMMAND_DECL(auto_tab_range){ USE_MODELS(models); REQ_OPEN_VIEW(view); REQ_FILE(file, view); - + int r_start = 0, r_end = 0; int start_set = 0, end_set = 0; Indent_Options opts; opts.empty_blank_lines = 0; opts.use_tabs = 0; opts.tab_width = 4; - + // TODO(allen): deduplicate Command_Parameter *end = param_stack_end(&command->part); Command_Parameter *param = param_stack_first(&command->part, end); @@ -1057,12 +1051,12 @@ COMMAND_DECL(auto_tab_range){ start_set = 1; r_start = dynamic_to_int(¶m->param.value); break; - + case par_range_end: end_set = 1; r_end = dynamic_to_int(¶m->param.value); break; - + case par_clear_blank_lines: opts.empty_blank_lines = dynamic_to_bool(¶m->param.value); break; @@ -1072,7 +1066,7 @@ COMMAND_DECL(auto_tab_range){ break; } } - + if (file->state.token_stack.tokens && file->state.tokens_complete && !file->state.still_lexing){ Range range = make_range(view->recent->cursor.pos, view->recent->mark); if (start_set) range.start = r_start; @@ -1085,23 +1079,23 @@ COMMAND_DECL(open_panel_vsplit){ USE_VARS(vars); USE_MODELS(models); USE_PANEL(panel); - + if (models->layout.panel_count < models->layout.panel_max_count){ Split_Result split = layout_split_panel(&models->layout, panel, 1); - + Panel *panel1 = panel; Panel *panel2 = split.panel; - + panel2->screen_region = panel1->screen_region; - + panel2->full.x0 = split.divider->pos; panel2->full.x1 = panel1->full.x1; panel1->full.x1 = split.divider->pos; - + panel_fix_internal_area(panel1); panel_fix_internal_area(panel2); panel2->prev_inner = panel2->inner; - + models->layout.active_panel = (i32)(panel2 - models->layout.panels); panel_make_empty(system, vars, panel2); } @@ -1111,23 +1105,23 @@ COMMAND_DECL(open_panel_hsplit){ USE_VARS(vars); USE_MODELS(models); USE_PANEL(panel); - + if (models->layout.panel_count < models->layout.panel_max_count){ Split_Result split = layout_split_panel(&models->layout, panel, 0); - + Panel *panel1 = panel; Panel *panel2 = split.panel; - + panel2->screen_region = panel1->screen_region; - + panel2->full.y0 = split.divider->pos; panel2->full.y1 = panel1->full.y1; panel1->full.y1 = split.divider->pos; - + panel_fix_internal_area(panel1); panel_fix_internal_area(panel2); panel2->prev_inner = panel2->inner; - + models->layout.active_panel = (i32)(panel2 - models->layout.panels); panel_make_empty(system, vars, panel2); } @@ -1137,30 +1131,30 @@ COMMAND_DECL(close_panel){ USE_MODELS(models); USE_PANEL(panel); USE_VIEW(view); - + Panel *panel_ptr, *used_panels; Divider_And_ID div, parent_div, child_div; i32 child; i32 parent; i32 which_child; i32 active; - + if (models->layout.panel_count > 1){ live_set_free_view(system, command->live_set, view); panel->view = 0; - + div = layout_get_divider(&models->layout, panel->parent); - + // This divider cannot have two child dividers. Assert(div.divider->child1 == -1 || div.divider->child2 == -1); - + // Get the child who needs to fill in this node's spot child = div.divider->child1; if (child == -1) child = div.divider->child2; - + parent = div.divider->parent; which_child = div.divider->which_child; - + // Fill the child in the slot this node use to hold if (parent == -1){ Assert(models->layout.root == div.id); @@ -1175,14 +1169,14 @@ COMMAND_DECL(close_panel){ parent_div.divider->child2 = child; } } - + // If there was a child divider, give it information about it's new parent. if (child != -1){ child_div = layout_get_divider(&models->layout, child); child_div.divider->parent = parent; child_div.divider->which_child = div.divider->which_child; } - + // What is the new active panel? active = -1; if (child == -1){ @@ -1202,10 +1196,10 @@ COMMAND_DECL(close_panel){ Assert(panel_ptr != panel); active = (i32)(panel_ptr - models->layout.panels); } - + Assert(active != -1 && panel != models->layout.panels + active); models->layout.active_panel = active; - + layout_free_divider(&models->layout, div.divider); layout_free_panel(&models->layout, panel); layout_fix_all_panels(&models->layout); @@ -1217,7 +1211,7 @@ COMMAND_DECL(move_left){ REQ_READABLE_VIEW(view); REQ_FILE(file, view); - + i32 pos = view->recent->cursor.pos; if (pos > 0) --pos; view_cursor_move(view, pos); @@ -1226,7 +1220,7 @@ COMMAND_DECL(move_left){ COMMAND_DECL(move_right){ REQ_READABLE_VIEW(view); REQ_FILE(file, view); - + i32 size = buffer_size(&file->state.buffer); i32 pos = view->recent->cursor.pos; if (pos < size) ++pos; @@ -1256,14 +1250,14 @@ COMMAND_DECL(backspace){ USE_MODELS(models); REQ_OPEN_VIEW(view); REQ_FILE(file, view); - + i32 size = buffer_size(&file->state.buffer); i32 cursor_pos = view->recent->cursor.pos; if (cursor_pos > 0 && cursor_pos <= size){ i32 start, end; end = cursor_pos; start = cursor_pos-1; - + i32 next_cursor_pos = view->recent->cursor.pos - 1; view_replace_range(system, models, view, start, end, 0, 0, next_cursor_pos); view_cursor_move(view, next_cursor_pos); @@ -1329,7 +1323,7 @@ COMMAND_DECL(open_config){ COMMAND_DECL(open_menu){ USE_VIEW(view); USE_MODELS(models); - + view_show_menu(view, &models->map_ui); } @@ -1340,7 +1334,7 @@ COMMAND_DECL(close_minor_view){ COMMAND_DECL(cursor_mark_swap){ REQ_READABLE_VIEW(view); - + i32 pos = view->recent->cursor.pos; view_cursor_move(view, view->recent->mark); view->recent->mark = pos; @@ -1403,7 +1397,7 @@ COMMAND_DECL(set_settings){ file->settings.unwrapped_lines = !v; } }break; - + case par_key_mapid: { if (file){ @@ -1440,13 +1434,13 @@ COMMAND_DECL(command_line){ USE_VARS(vars); USE_MODELS(models); USE_VIEW(view); - + Partition *part = &models->mem.part; - + char *buffer_name = 0; char *path = 0; char *script = 0; - + i32 buffer_id = 0; i32 buffer_name_len = 0; i32 path_len = 0; @@ -1456,7 +1450,7 @@ COMMAND_DECL(command_line){ char feedback_space[256]; String feedback_str = make_fixed_width_string(feedback_space); - + Command_Parameter *end = param_stack_end(&command->part); Command_Parameter *param = param_stack_first(&command->part, end); for (; param < end; param = param_next(param, end)){ @@ -1469,17 +1463,17 @@ COMMAND_DECL(command_line){ buffer_name = new_buffer_name; } }break; - + case par_buffer_id: { buffer_id = dynamic_to_int(¶m->param.value); }break; - + case par_do_in_background: { do_in_background = 1; }break; - + case par_cli_path: { char *new_cli_path = dynamic_to_string(¶m->param.value, &path_len); @@ -1487,7 +1481,7 @@ COMMAND_DECL(command_line){ path = new_cli_path; } }break; - + case par_cli_command: { char *new_command = dynamic_to_string(¶m->param.value, &script_len); @@ -1495,21 +1489,21 @@ COMMAND_DECL(command_line){ script = new_command; } }break; - + case par_flags: { flags = (u32)dynamic_to_int(¶m->param.value); }break; } } - + { Working_Set *working_set = &models->working_set; CLI_Process *procs = vars->cli_processes.procs, *proc = 0; Editing_File *file = 0; b32 bind_to_new_view = !do_in_background; General_Memory *general = &models->mem.general; - + if (vars->cli_processes.count < vars->cli_processes.max){ if (buffer_id){ file = working_set_get_active_file(working_set, buffer_id); @@ -1557,12 +1551,12 @@ COMMAND_DECL(command_line){ working_set_add(system, working_set, file, general); } } - + if (file){ i32 proc_count = vars->cli_processes.count; View_Iter iter; i32 i; - + for (i = 0; i < proc_count; ++i){ if (procs[i].out_file == file){ if (flags & CLI_OverlapWithConflict) @@ -1572,11 +1566,11 @@ COMMAND_DECL(command_line){ break; } } - + if (file){ file_clear(system, models, file, 1); file->settings.unimportant = 1; - + if (!(flags & CLI_AlwaysBindToView)){ iter = file_view_iter_init(&models->layout, file, 0); if (file_view_iter_good(iter)){ @@ -1590,18 +1584,18 @@ COMMAND_DECL(command_line){ return; } } - + if (!path){ path = models->hot_directory.string.str; terminate_with_null(&models->hot_directory.string); } - + { Temp_Memory temp; Range range; Editing_File *file2; i32 size; - + temp = begin_temp_memory(part); if (!script){ file2 = view->file_data.file; @@ -1616,14 +1610,14 @@ COMMAND_DECL(command_line){ script = " echo no script specified"; } } - + if (bind_to_new_view){ view_set_file(view, file, models); } - + proc = procs + vars->cli_processes.count++; proc->out_file = file; - + if (!system->cli_call(path, script, &proc->cli)){ --vars->cli_processes.count; } @@ -1652,17 +1646,17 @@ fill_buffer_summary(Buffer_Summary *buffer, Editing_File *file, Working_Set *wor if (!file->is_dummy){ buffer->exists = 1; buffer->ready = file_is_ready(file); - + buffer->is_lexed = file->settings.tokens_exist; buffer->buffer_id = file->id.id; buffer->size = file->state.buffer.size; buffer->buffer_cursor_pos = file->state.cursor_pos; - + buffer->file_name_len = file->name.source_path.size; buffer->buffer_name_len = file->name.live_name.size; buffer->file_name = file->name.source_path.str; buffer->buffer_name = file->name.live_name.str; - + buffer->map_id = file->settings.base_map_id; } } @@ -1680,32 +1674,32 @@ fill_view_summary(View_Summary *view, View *vptr, Live_Views *live_set, Working_ view->unwrapped_lines = vptr->file_data.unwrapped_lines; view->show_whitespace = vptr->file_data.show_whitespace; - + if (vptr->file_data.file){ lock_level = view_lock_level(vptr); buffer_id = vptr->file_data.file->id.id; - + if (lock_level <= 0){ view->buffer_id = buffer_id; } else{ view->buffer_id = 0; } - + if (lock_level <= 1){ view->locked_buffer_id = buffer_id; } else{ view->locked_buffer_id = 0; } - + if (lock_level <= 2){ view->hidden_buffer_id = buffer_id; } else{ view->hidden_buffer_id = 0; } - + view->mark = view_compute_cursor_from_pos(vptr, vptr->recent->mark); view->cursor = vptr->recent->cursor; view->preferred_x = vptr->recent->preferred_x; @@ -1720,10 +1714,10 @@ extern "C"{ Command_Binding binding = {}; binding.function = function; if (function) function(cmd->system, cmd, binding); - + update_command_data(cmd->vars, cmd); } - + PUSH_PARAMETER_SIG(external_push_parameter){ Command_Data *cmd = (Command_Data*)app->cmd_context; Partition *part = &cmd->part; @@ -1732,7 +1726,7 @@ extern "C"{ cmd_param->param.param = param; cmd_param->param.value = value; } - + PUSH_MEMORY_SIG(external_push_memory){ Command_Data *cmd = (Command_Data*)app->cmd_context; Partition *part = &cmd->part; @@ -1746,12 +1740,12 @@ extern "C"{ base->inline_string.len = len; return(result); } - + CLEAR_PARAMETERS_SIG(external_clear_parameters){ Command_Data *cmd = (Command_Data*)app->cmd_context; cmd->part.pos = 0; } - + DIRECTORY_GET_HOT_SIG(external_directory_get_hot){ Command_Data *cmd = (Command_Data*)app->cmd_context; Hot_Directory *hot = &cmd->models->hot_directory; @@ -1763,7 +1757,7 @@ extern "C"{ out[copy_max] = 0; return(hot->string.size); } - + GET_FILE_LIST_SIG(external_get_file_list){ Command_Data *cmd = (Command_Data*)app->cmd_context; System_Functions *system = cmd->system; @@ -1771,13 +1765,13 @@ extern "C"{ system->set_file_list(&result, make_string(dir, len)); return(result); } - + FREE_FILE_LIST_SIG(external_free_file_list){ Command_Data *cmd = (Command_Data*)app->cmd_context; System_Functions *system = cmd->system; system->set_file_list(&list, make_string(0, 0)); } - + GET_BUFFER_FIRST_SIG(external_get_buffer_first){ Command_Data *cmd = (Command_Data*)app->cmd_context; Working_Set *working_set = &cmd->models->working_set; @@ -1787,12 +1781,12 @@ extern "C"{ } return(result); } - + GET_BUFFER_NEXT_SIG(external_get_buffer_next){ Command_Data *cmd = (Command_Data*)app->cmd_context; Working_Set *working_set = &cmd->models->working_set; Editing_File *file; - + file = working_set_get_active_file(working_set, buffer->buffer_id); if (file){ file = (Editing_File*)file->node.next; @@ -1802,39 +1796,39 @@ extern "C"{ *buffer = buffer_summary_zero(); } } - + GET_BUFFER_SIG(external_get_buffer){ Command_Data *cmd = (Command_Data*)app->cmd_context; Working_Set *working_set = &cmd->models->working_set; Buffer_Summary buffer = {}; Editing_File *file; - + file = working_set_get_active_file(working_set, index); if (file){ fill_buffer_summary(&buffer, file, working_set); } - + return(buffer); } - + GET_PARAMETER_BUFFER_SIG(external_get_parameter_buffer){ Command_Data *cmd = (Command_Data*)app->cmd_context; Models *models = cmd->models; Buffer_Summary buffer = {}; - + if (param_index >= 0 && param_index < models->buffer_param_count){ buffer = external_get_buffer(app, models->buffer_param_indices[param_index]); } - + return(buffer); } - + GET_BUFFER_BY_NAME_SIG(external_get_buffer_by_name){ Command_Data *cmd = (Command_Data*)app->cmd_context; Buffer_Summary buffer = {}; Editing_File *file; Working_Set *working_set = &cmd->models->working_set; - + file = working_set_contains(cmd->system, working_set, make_string(filename, len)); if (file && !file->is_dummy){ fill_buffer_summary(&buffer, file, working_set); @@ -1849,14 +1843,14 @@ extern "C"{ result = buffer->exists; return(result); } - + BUFFER_READ_RANGE_SIG(external_buffer_read_range){ Command_Data *cmd = (Command_Data*)app->cmd_context; Editing_File *file; Working_Set *working_set; int result = 0; int size; - + if (buffer->exists){ working_set = &cmd->models->working_set; file = working_set_get_active_file(working_set, buffer->buffer_id); @@ -1869,21 +1863,21 @@ extern "C"{ fill_buffer_summary(buffer, file, working_set); } } - + return(result); } - + BUFFER_REPLACE_RANGE_SIG(external_buffer_replace_range){ Command_Data *cmd = (Command_Data*)app->cmd_context; Editing_File *file; Working_Set *working_set; - + Models *models; - + int result = 0; int size; int next_cursor, pos; - + if (buffer->exists){ models = cmd->models; working_set = &models->working_set; @@ -1892,29 +1886,29 @@ extern "C"{ size = buffer_size(&file->state.buffer); if (0 <= start && start <= end && end <= size){ result = 1; - + pos = file->state.cursor_pos; if (pos < start) next_cursor = pos; else if (pos < end) next_cursor = start; else next_cursor = pos + end - start - len; - + file_replace_range(cmd->system, models, file, start, end, str, len, next_cursor); } fill_buffer_summary(buffer, file, working_set); } } - + return(result); } - + BUFFER_SET_POS_SIG(external_buffer_set_pos){ Command_Data *cmd = (Command_Data*)app->cmd_context; Editing_File *file; Working_Set *working_set; - + int result = 0; int size; - + if (buffer->exists){ working_set = &cmd->models->working_set; file = working_set_get_active_file(working_set, buffer->buffer_id); @@ -1927,23 +1921,23 @@ extern "C"{ fill_buffer_summary(buffer, file, working_set); } } - + return(result); } - + GET_VIEW_FIRST_SIG(external_get_view_first){ Command_Data *cmd = (Command_Data*)app->cmd_context; Editing_Layout *layout = &cmd->models->layout; View_Summary view = {}; - + Panel *panel = layout->used_sentinel.next; - + Assert(panel != &layout->used_sentinel); fill_view_summary(&view, panel->view, &cmd->vars->live_set, &cmd->models->working_set); - + return(view); } - + GET_VIEW_NEXT_SIG(external_get_view_next){ Command_Data *cmd = (Command_Data*)app->cmd_context; Editing_Layout *layout = &cmd->models->layout; @@ -1951,7 +1945,7 @@ extern "C"{ View *vptr; Panel *panel; int index = view->view_id - 1; - + if (index >= 0 && index < live_set->max){ vptr = live_set->views + index; panel = vptr->panel; @@ -1967,30 +1961,30 @@ extern "C"{ *view = view_summary_zero(); } } - + GET_VIEW_SIG(external_get_view){ Command_Data *cmd = (Command_Data*)app->cmd_context; View_Summary view = {}; Live_Views *live_set = cmd->live_set; int max = live_set->max; View *vptr; - + index -= 1; if (index >= 0 && index < max){ vptr = live_set->views + index; fill_view_summary(&view, vptr, live_set, &cmd->models->working_set); } - + return(view); } - + GET_ACTIVE_VIEW_SIG(external_get_active_view){ Command_Data *cmd = (Command_Data*)app->cmd_context; View_Summary view = {}; fill_view_summary(&view, cmd->view, &cmd->vars->live_set, &cmd->models->working_set); return(view); } - + REFRESH_VIEW_SIG(external_refresh_view){ int result; *view = external_get_view(app, view->view_id); @@ -2032,7 +2026,7 @@ extern "C"{ Editing_File *file; int result = 0; int view_id; - + if (view->exists){ live_set = cmd->live_set; view_id = view->view_id - 1; @@ -2053,10 +2047,10 @@ extern "C"{ } } } - + return(result); } - + VIEW_SET_MARK_SIG(external_view_set_mark){ Command_Data *cmd = (Command_Data*)app->cmd_context; Live_Views *live_set; @@ -2064,7 +2058,7 @@ extern "C"{ Full_Cursor cursor; int result = 0; int view_id; - + if (view->exists){ live_set = cmd->live_set; view_id = view->view_id - 1; @@ -2081,7 +2075,7 @@ extern "C"{ fill_view_summary(view, vptr, live_set, &cmd->models->working_set); } } - + return(result); } @@ -2262,7 +2256,7 @@ extern "C"{ Theme_Color *theme_color; u32 *color; i32 i; - + theme_color = colors; for (i = 0; i < count; ++i, ++theme_color){ color = style_index_by_tag(&style->main, theme_color->tag); @@ -2281,7 +2275,7 @@ command_caller(Coroutine *coroutine){ Command_In *cmd_in = (Command_In*)coroutine->in; Command_Data *cmd = cmd_in->cmd; View *view = cmd->view; - + // TODO(allen): this isn't really super awesome, could have issues if // the file view get's change out under us. view->next_mode = view_mode_zero(); @@ -2359,9 +2353,9 @@ app_links_init(System_Functions *system, Application_Links *app_links, void *dat internal void setup_ui_commands(Command_Map *commands, Partition *part, Command_Map *parent){ map_init(commands, part, 32, parent); - + commands->vanilla_keyboard_default.function = command_null; - + // TODO(allen): This is hacky, when the new UI stuff happens, let's fix it, // and by that I mean actually fix it, don't just say you fixed it with // something stupid again. @@ -2435,7 +2429,7 @@ setup_command_table(){ SET(show_scrollbar); SET(set_settings); SET(command_line); - + #undef SET } @@ -2447,14 +2441,14 @@ app_hardcode_styles(Models *models){ Style *styles, *style; styles = models->styles.styles; style = styles + 1; - + i16 fonts = 1; models->global_font.font_id = fonts + 0; models->global_font.font_changed = 0; - + ///////////////// style_set_name(style, make_lit_string("4coder")); - + style->main.back_color = 0xFF0C0C0C; style->main.margin_color = 0xFF181818; style->main.margin_hover_color = 0xFF252525; @@ -2475,13 +2469,13 @@ app_hardcode_styles(Models *models){ style->main.include_color = style->main.str_constant_color; style->main.preproc_color = style->main.default_color; style->main.special_character_color = 0xFFFF0000; - + style->main.paste_color = 0xFFDDEE00; style->main.undo_color = 0xFF00DDEE; - + style->main.highlight_junk_color = 0xff3a0000; style->main.highlight_white_color = 0xff003a3a; - + file_info_style.bar_color = 0xFF888888; file_info_style.bar_active_color = 0xFF666666; file_info_style.base_color = 0xFF000000; @@ -2489,10 +2483,10 @@ app_hardcode_styles(Models *models){ file_info_style.pop2_color = 0xFFFF0000; style->main.file_info_style = file_info_style; ++style; - + ///////////////// style_set_name(style, make_lit_string("Handmade Hero")); - + style->main.back_color = 0xFF161616; style->main.margin_color = 0xFF262626; style->main.margin_hover_color = 0xFF333333; @@ -2513,13 +2507,13 @@ app_hardcode_styles(Models *models){ style->main.include_color = 0xFF6B8E23; style->main.preproc_color = 0xFFDAB98F; style->main.special_character_color = 0xFFFF0000; - + style->main.paste_color = 0xFFFFBB00; style->main.undo_color = 0xFF80005D; - + style->main.highlight_junk_color = 0xFF3A0000; style->main.highlight_white_color = 0xFF003A3A; - + file_info_style.bar_color = 0xFFCACACA; file_info_style.bar_active_color = 0xFFA8A8A8; file_info_style.base_color = 0xFF000000; @@ -2527,10 +2521,10 @@ app_hardcode_styles(Models *models){ file_info_style.pop2_color = 0xFFFF0000; style->main.file_info_style = file_info_style; ++style; - + ///////////////// style_set_name(style, make_lit_string("Twilight")); - + style->main.back_color = 0xFF090D12; style->main.margin_color = 0xFF1A2634; style->main.margin_hover_color = 0xFF2D415B; @@ -2551,13 +2545,13 @@ app_hardcode_styles(Models *models){ style->main.include_color = style->main.str_constant_color; style->main.preproc_color = style->main.default_color; style->main.special_character_color = 0xFFFF0000; - + style->main.paste_color = 0xFFDDEE00; style->main.undo_color = 0xFF00DDEE; - + style->main.highlight_junk_color = 0xff3a0000; style->main.highlight_white_color = 0xFF151F2A; - + file_info_style.bar_color = 0xFF315E68; file_info_style.bar_active_color = 0xFF0F3C46; file_info_style.base_color = 0xFF000000; @@ -2565,10 +2559,10 @@ app_hardcode_styles(Models *models){ file_info_style.pop2_color = 0xFFFF200D; style->main.file_info_style = file_info_style; ++style; - + ///////////////// style_set_name(style, make_lit_string("Wolverine")); - + style->main.back_color = 0xFF070711; style->main.margin_color = 0xFF111168; style->main.margin_hover_color = 0xFF191996; @@ -2589,13 +2583,13 @@ app_hardcode_styles(Models *models){ style->main.include_color = style->main.str_constant_color; style->main.preproc_color = style->main.default_color; style->main.special_character_color = 0xFFFF0000; - + style->main.paste_color = 0xFF900090; style->main.undo_color = 0xFF606090; - + style->main.highlight_junk_color = 0xff3a0000; style->main.highlight_white_color = 0xff003a3a; - + file_info_style.bar_color = 0xFF7082F9; file_info_style.bar_active_color = 0xFF4E60D7; file_info_style.base_color = 0xFF000000; @@ -2603,10 +2597,10 @@ app_hardcode_styles(Models *models){ file_info_style.pop2_color = 0xFFD20000; style->main.file_info_style = file_info_style; ++style; - + ///////////////// style_set_name(style, make_lit_string("stb")); - + style->main.back_color = 0xFFD6D6D6; style->main.margin_color = 0xFF9E9E9E; style->main.margin_hover_color = 0xFF7E7E7E; @@ -2627,13 +2621,13 @@ app_hardcode_styles(Models *models){ style->main.include_color = style->main.str_constant_color; style->main.preproc_color = style->main.default_color; style->main.special_character_color = 0xFF9A0000; - + style->main.paste_color = 0xFF00B8B8; style->main.undo_color = 0xFFB800B8; - + style->main.highlight_junk_color = 0xFFFF7878; style->main.highlight_white_color = 0xFFBCBCBC; - + file_info_style.bar_color = 0xFF606060; file_info_style.bar_active_color = 0xFF3E3E3E; file_info_style.base_color = 0xFF000000; @@ -2641,7 +2635,7 @@ app_hardcode_styles(Models *models){ file_info_style.pop2_color = 0xFFE80505; style->main.file_info_style = file_info_style; ++style; - + models->styles.count = (i32)(style - styles); models->styles.max = ArrayCount(models->styles.styles); style_copy(main_style(models), models->styles.styles + 1); @@ -2682,7 +2676,7 @@ enum Command_Line_Action{ void init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, - Command_Line_Parameters clparams){ + Command_Line_Parameters clparams){ char *arg; Command_Line_Action action = CLAct_Nothing; i32 i,index; @@ -3894,7 +3888,7 @@ App_Step_Sig(app_step){ app_result.animating = 1; } }break; - + case APP_STATE_RESIZING: { if (key_data.count > 0){ @@ -4070,19 +4064,19 @@ App_Step_Sig(app_step){ // NOTE(allen): send style change messages if the style has changed if (models->global_font.font_changed){ models->global_font.font_changed = 0; - + File_Node *node, *used_nodes; Editing_File *file; Render_Font *font = get_font_info(models->font_set, models->global_font.font_id)->font; float *advance_data = 0; if (font) advance_data = font->advance_data; - + used_nodes = &models->working_set.used_sentinel; for (dll_items(node, used_nodes)){ file = (Editing_File*)node; file_measure_starts_widths(system, &models->mem.general, &file->state.buffer, advance_data); } - + Panel *panel, *used_panels; used_panels = &models->layout.used_sentinel; for (dll_items(panel, used_panels)){ @@ -4104,29 +4098,29 @@ App_Step_Sig(app_step){ // NOTE(allen): rendering { begin_render_section(target, system); - + target->clip_top = -1; draw_push_clip(target, rect_from_target(target)); - + // NOTE(allen): render the panels Panel *panel, *used_panels; used_panels = &models->layout.used_sentinel; for (dll_items(panel, used_panels)){ i32_Rect full = panel->full; i32_Rect inner = panel->inner; - + View *view = panel->view; Style *style = main_style(models); - + b32 active = (panel == cmd->panel); u32 back_color = style->main.back_color; draw_rectangle(target, full, back_color); - + draw_push_clip(target, panel->inner); do_render_file_view(system, view, cmd->view, panel->inner, active, target, &dead_input); draw_pop_clip(target); - + u32 margin_color; if (active){ margin_color = style->main.margin_active_color; @@ -4142,13 +4136,13 @@ App_Step_Sig(app_step){ draw_rectangle(target, i32R(full.x0, inner.y0, inner.x0, inner.y1), margin_color); draw_rectangle(target, i32R(inner.x1, inner.y0, full.x1, inner.y1), margin_color); } - + end_render_section(target, system); } // NOTE(allen): get cursor type if (mouse_in_edit_area){ - app_result.mouse_cursor_type = APP_MOUSE_CURSOR_ARROW; + app_result.mouse_cursor_type = APP_MOUSE_CURSOR_ARROW; } else if (mouse_in_margin_area){ if (mouse_on_divider){ @@ -4177,11 +4171,11 @@ App_Step_Sig(app_step){ external App_Get_Functions_Sig(app_get_functions){ App_Functions result = {}; - + result.read_command_line = app_read_command_line; result.init = app_init; result.step = app_step; - + return(result); } diff --git a/4ed_font_set.cpp b/4ed_font_set.cpp index 3a3ee64c..ab107521 100644 --- a/4ed_font_set.cpp +++ b/4ed_font_set.cpp @@ -1,11 +1,11 @@ /* - * Mr. 4th Dimention - Allen Webster - * - * 18.12.2015 - * - * Font set for 4coder - * - */ +* Mr. 4th Dimention - Allen Webster +* +* 18.12.2015 +* +* Font set for 4coder +* +*/ // TOP @@ -40,9 +40,9 @@ font__remove(Font_Slot *slot){ n->prev = p; } -internal Font_Slot +inline Font_Slot font_slot_zero(){ - Font_Slot slot = {}; + Font_Slot slot = {0}; return(slot); } @@ -57,10 +57,10 @@ font_set_init(Font_Set *set, Partition *partition, i32 max, i16 live_max){ partition_align(partition, 8); set->font_block = push_block(partition, live_max*(sizeof(Render_Font) + sizeof(Font_Slot))); - + set->free_slots = font_slot_zero(); set->used_slots = font_slot_zero(); - + dll_init_sentinel(&set->free_slots); dll_init_sentinel(&set->used_slots); @@ -69,7 +69,7 @@ font_set_init(Font_Set *set, Partition *partition, i32 max, i16 live_max){ dll_insert(&set->free_slots, (Font_Slot*)ptr); ptr += sizeof(Font_Slot) + sizeof(Render_Font); } - + set->font_used_flags = push_array(partition, b8, max); set->live_max = live_max; } @@ -87,12 +87,12 @@ font_set_add_hash(Font_Set *set, String name, i16 font_id){ entry.hash = font_hash(name); entry.name = name; entry.font_id = font_id; - + u32 i, j; i = entry.hash % set->max; j = i - 1; if (i <= 1) j += set->max; - + for (; i != j; ++i){ if (i == set->max) i = 0; if (set->entries[i].font_id == 0){ @@ -100,7 +100,7 @@ font_set_add_hash(Font_Set *set, String name, i16 font_id){ break; } } - + Assert(i != j); } @@ -119,7 +119,7 @@ font_set_load(Partition *partition, Font_Set *set, i16 font_id){ font__insert(&set->used_slots, slot); Render_Font *font = (Render_Font*)(slot + 1); - set->font_load(font, info->filename.str, info->pt_size, 4); + set->font_load(font, info->filename.str, info->pt_size, 4, 1); info->font = font; slot->font_id = font_id; } @@ -145,7 +145,7 @@ internal void font_set_use(Partition *partition, Font_Set *set, i16 font_id){ b8 already_used; already_used = set->font_used_flags[font_id-1]; - + if (!already_used){ if (set->used_this_frame < set->live_max){ ++set->used_this_frame; @@ -153,7 +153,7 @@ font_set_use(Partition *partition, Font_Set *set, i16 font_id){ already_used = 1; } } - + if (already_used){ // TODO(allen): optimize if you don't mind!!!! Font_Info *info = get_font_info(set, font_id); @@ -165,7 +165,7 @@ font_set_use(Partition *partition, Font_Set *set, i16 font_id){ font_set_load(partition, set, font_id); } slot = ((Font_Slot*)info->font) - 1; - + font__remove(slot); font__insert(&set->used_slots, slot); } @@ -176,12 +176,16 @@ font_set_add(Partition *partition, Font_Set *set, String filename, String name, i32 pt_size){ b32 result = 0; if (font_set_can_add(set)){ + Render_Font dummy_font = {0}; i16 font_id = (i16)(++set->count); Font_Info *info = get_font_info(set, font_id); info->filename = filename; info->name = name; info->pt_size = pt_size; - set->font_info_load(partition, filename.str, pt_size, &info->height, &info->advance); + set->font_load(&dummy_font, info->filename.str, info->pt_size, 4, 0); + info->height = dummy_font.height; + info->advance = dummy_font.advance; + font_set_add_hash(set, name, font_id); if (font_set_can_load(set)){ @@ -201,7 +205,7 @@ font_set_find_pos(Font_Set *set, String name, u32 *position){ i = hash % set->max; j = i - 1; if (j <= 1) j += set->max; - + result = 0; Font_Table_Entry *entry; for (; i != j; ++i){ @@ -215,7 +219,7 @@ font_set_find_pos(Font_Set *set, String name, u32 *position){ } } } - + return(result); } @@ -228,7 +232,7 @@ font_set_extract(Font_Set *set, String name, i16 *font_id){ if (result){ *font_id = set->entries[position].font_id; } - + return(result); } diff --git a/4ed_rendering.cpp b/4ed_rendering.cpp index 26a210a8..d75d947f 100644 --- a/4ed_rendering.cpp +++ b/4ed_rendering.cpp @@ -305,101 +305,14 @@ launch_rendering(Render_Target *target){ #undef ExtractStruct -internal i32 -draw_font_info_load(Partition *partition, - char *filename_untranslated, - i32 pt_size, i32 *height, i32 *advance){ - - char space_[1024]; - String filename = make_fixed_width_string(space_); - b32 translate_success = sysshared_to_binary_path(&filename, filename_untranslated); - if (!translate_success) return 0; - - i32 result = 1; - File_Data file; - file = sysshared_load_file(filename.str); - - Temp_Memory temp = begin_temp_memory(partition); - stbtt_packedchar *chardata = push_array(partition, stbtt_packedchar, 256); - - i32 oversample = 2; - - i32 tex_width, tex_height; - tex_width = pt_size*128*oversample; - tex_height = pt_size*2*oversample; - void *block = push_block(partition, tex_width * tex_height); - - if (!file.data.data){ - result = 0; - } - else{ - stbtt_fontinfo font; - if (!stbtt_InitFont(&font, (u8*)file.data.data, 0)){ - result = 0; - } - else{ - i32 ascent, descent, line_gap; - f32 scale; - - stbtt_GetFontVMetrics(&font, &ascent, &descent, &line_gap); - scale = stbtt_ScaleForPixelHeight(&font, (f32)pt_size); - - f32 scaled_ascent, scaled_descent, scaled_line_gap; - - scaled_ascent = scale*ascent; - scaled_descent = scale*descent; - scaled_line_gap = scale*line_gap; - - i32 font_height = (i32)(scaled_ascent - scaled_descent + scaled_line_gap); - - stbtt_pack_context spc; - if (stbtt_PackBegin(&spc, (u8*)block, tex_width, tex_height, tex_width, 1, partition)){ - stbtt_PackSetOversampling(&spc, oversample, oversample); - if (stbtt_PackFontRange(&spc, (u8*)file.data.data, 0, - STBTT_POINT_SIZE((f32)pt_size), 0, 128, chardata)){ - // do nothing - } - else{ - result = 0; - } - - stbtt_PackEnd(&spc); - } - else{ - result = 0; - } - - if (result){ - i32 max_advance = 0; - for (u8 code_point = 0; code_point < 128; ++code_point){ - if (stbtt_FindGlyphIndex(&font, code_point) != 0){ - i32 adv = CEIL32(chardata[code_point].xadvance); - if (max_advance < adv){ - max_advance = adv; - } - } - } - - *height = font_height; - *advance = max_advance - 1; - } - } - - system_free_memory(file.data.data); - } - - end_temp_memory(temp); - - return(result); -} - internal i32 draw_font_load(Partition *part, Render_Font *font_out, char *filename_untranslated, i32 pt_size, i32 tab_width, - i32 oversample){ + i32 oversample, + b32 store_texture){ char space_[1024]; String filename = make_fixed_width_string(space_); @@ -410,12 +323,6 @@ draw_font_load(Partition *part, stbtt_packedchar *chardata = font_out->chardata; - Temp_Memory temp = begin_temp_memory(part); - - i32 tex_width = pt_size*16*oversample; - i32 tex_height = pt_size*16*oversample; - void *block = sysshared_push_block(part, tex_width * tex_height); - File_Data file = sysshared_load_file(filename.str); if (!file.data.data){ @@ -428,85 +335,89 @@ draw_font_load(Partition *part, result = 0; } else{ + memset(font_out, 0, sizeof(*font_out)); + i32 ascent, descent, line_gap; - f32 scale; - stbtt_GetFontVMetrics(&font, &ascent, &descent, &line_gap); - scale = stbtt_ScaleForPixelHeight(&font, (f32)pt_size); - f32 scaled_ascent, scaled_descent, scaled_line_gap; + f32 scale = stbtt_ScaleForPixelHeight(&font, (f32)pt_size); - scaled_ascent = scale*ascent; - scaled_descent = scale*descent; - scaled_line_gap = scale*line_gap; + f32 scaled_ascent = scale*ascent; + f32 scaled_descent = scale*descent; + f32 scaled_line_gap = scale*line_gap; font_out->height = (i32)(scaled_ascent - scaled_descent + scaled_line_gap); font_out->ascent = (i32)(scaled_ascent); font_out->descent = (i32)(scaled_descent); font_out->line_skip = (i32)(scaled_line_gap); - font_out->tex_width = tex_width; - font_out->tex_height = tex_height; - - stbtt_pack_context spc; - - // TODO(allen): If this fails we can just expand the partition here now - // rather than forcing the user to do it. - if (stbtt_PackBegin(&spc, (u8*)block, tex_width, tex_height, - tex_width, 1, part)){ - stbtt_PackSetOversampling(&spc, oversample, oversample); - if (!stbtt_PackFontRange(&spc, (u8*)file.data.data, 0, - STBTT_POINT_SIZE((f32)pt_size), - 0, 128, chardata)){ + if (store_texture){ + Temp_Memory temp = begin_temp_memory(part); + + i32 tex_width = pt_size*16*oversample; + i32 tex_height = pt_size*16*oversample; + void *block = sysshared_push_block(part, tex_width * tex_height); + + font_out->tex_width = tex_width; + font_out->tex_height = tex_height; + + stbtt_pack_context spc; + + if (stbtt_PackBegin(&spc, (u8*)block, tex_width, tex_height, + tex_width, 1, part)){ + stbtt_PackSetOversampling(&spc, oversample, oversample); + if (!stbtt_PackFontRange(&spc, (u8*)file.data.data, 0, + STBTT_POINT_SIZE((f32)pt_size), + 0, 128, chardata)){ + result = 0; + } + + stbtt_PackEnd(&spc); + } + else{ result = 0; } - stbtt_PackEnd(&spc); - } - else{ - result = 0; - } - - if (result){ - GLuint font_tex; - glGenTextures(1, &font_tex); - glBindTexture(GL_TEXTURE_2D, font_tex); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, tex_width, tex_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, block); - - font_out->tex = font_tex; - glBindTexture(GL_TEXTURE_2D, 0); - - font_out->chardata['\r'] = font_out->chardata[' ']; - font_out->chardata['\n'] = font_out->chardata[' ']; - font_out->chardata['\t'] = font_out->chardata[' ']; - font_out->chardata['\t'].xadvance *= tab_width; - - i32 max_advance = 0; - for (u8 code_point = 0; code_point < 128; ++code_point){ - if (stbtt_FindGlyphIndex(&font, code_point) != 0){ - font_out->glyphs[code_point].exists = 1; - i32 advance = CEIL32(font_out->chardata[code_point].xadvance); - if (max_advance < advance) max_advance = advance; - font_out->advance_data[code_point] = font_out->chardata[code_point].xadvance; - } - else if (code_point == '\r' || code_point == '\n' || code_point == '\t'){ - font_out->advance_data[code_point] = font_out->chardata[code_point].xadvance; + if (result){ + GLuint font_tex; + glGenTextures(1, &font_tex); + glBindTexture(GL_TEXTURE_2D, font_tex); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, tex_width, tex_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, block); + + font_out->tex = font_tex; + glBindTexture(GL_TEXTURE_2D, 0); + + font_out->chardata['\r'] = font_out->chardata[' ']; + font_out->chardata['\n'] = font_out->chardata[' ']; + font_out->chardata['\t'] = font_out->chardata[' ']; + font_out->chardata['\t'].xadvance *= tab_width; + + i32 max_advance = 0; + for (u8 code_point = 0; code_point < 128; ++code_point){ + if (stbtt_FindGlyphIndex(&font, code_point) != 0){ + font_out->glyphs[code_point].exists = 1; + i32 advance = CEIL32(font_out->chardata[code_point].xadvance); + if (max_advance < advance) max_advance = advance; + font_out->advance_data[code_point] = font_out->chardata[code_point].xadvance; + } + else if (code_point == '\r' || code_point == '\n' || code_point == '\t'){ + font_out->advance_data[code_point] = font_out->chardata[code_point].xadvance; + } } + font_out->advance = max_advance - 1; } - font_out->advance = max_advance - 1; + + end_temp_memory(temp); } - } system_free_memory(file.data.data); } - end_temp_memory(temp); - return(result); } diff --git a/4ed_rendering.h b/4ed_rendering.h index 961c50cb..0c2e8d4b 100644 --- a/4ed_rendering.h +++ b/4ed_rendering.h @@ -115,16 +115,11 @@ typedef Draw_Push_Piece_Sig(Draw_Push_Piece); Render_Font *font_out, \ char *filename, \ i32 pt_size, \ - i32 tab_width) + i32 tab_width, \ + b32 store_texture) typedef Font_Load_Sig(Font_Load); -#define Font_Info_Load_Sig(name) i32 name( \ - Partition *partition, \ - char *filename, \ - i32 pt_size, \ - i32 *height, \ - i32 *advance) -typedef Font_Info_Load_Sig(Font_Info_Load); + #define Release_Font_Sig(name) void name(Render_Font *font) typedef Release_Font_Sig(Release_Font); @@ -158,7 +153,7 @@ struct Font_Set{ Font_Slot free_slots; Font_Slot used_slots; - Font_Info_Load *font_info_load; + //Font_Info_Load *font_info_load; Font_Load *font_load; Release_Font *release_font; diff --git a/buffer/4coder_buffer_abstract.cpp b/buffer/4coder_buffer_abstract.cpp index 7d8aacb4..5a52c209 100644 --- a/buffer/4coder_buffer_abstract.cpp +++ b/buffer/4coder_buffer_abstract.cpp @@ -128,101 +128,6 @@ buffer_reverse_seek_delimiter(Buffer_Type *buffer, int pos, char delim){ return(pos); } - -#if 0 -internal_4tech int -buffer_seek_whitespace_down(Buffer_Type *buffer, int pos){ - Buffer_Stringify_Type loop; - char *data; - int end; - int size; - int no_hard; - int prev_endline; - - size = buffer_size(buffer); - loop = buffer_stringify_loop(buffer, pos, size); - - for (;buffer_stringify_good(&loop); - buffer_stringify_next(&loop)){ - end = loop.size + loop.absolute_pos; - data = loop.data - loop.absolute_pos; - for (;pos < end; ++pos){ - if (!is_whitespace(data[pos])) goto buffer_seek_whitespace_down_mid; - } - } - -buffer_seek_whitespace_down_mid: - no_hard = 0; - prev_endline = -1; - for (;buffer_stringify_good(&loop); - buffer_stringify_next(&loop)){ - end = loop.size + loop.absolute_pos; - data = loop.data - loop.absolute_pos; - for (; pos < end; ++pos){ - if (data[pos] == '\n'){ - if (no_hard) goto buffer_seek_whitespace_down_end; - else{ - no_hard = 1; - prev_endline = pos; - } - } - else if (!is_whitespace(data[pos])){ - no_hard = 0; - } - } - } - -buffer_seek_whitespace_down_end: - if (prev_endline == -1 || prev_endline+1 >= size) pos = size; - else pos = prev_endline+1; - - return pos; -} - -internal_4tech int -buffer_seek_whitespace_up(Buffer_Type *buffer, int pos){ - Buffer_Backify_Type loop; - char *data; - int end; - int size; - int no_hard; - - size = buffer_size(buffer); - loop = buffer_backify_loop(buffer, pos-1, 1); - - for (;buffer_backify_good(&loop); - buffer_backify_next(&loop)){ - end = loop.absolute_pos; - data = loop.data - loop.absolute_pos; - for (;pos >= end; --pos){ - if (!is_whitespace(data[pos])) goto buffer_seek_whitespace_up_mid; - } - } - -buffer_seek_whitespace_up_mid: - no_hard = 0; - for (;buffer_backify_good(&loop); - buffer_backify_next(&loop)){ - end = loop.absolute_pos; - data = loop.data - loop.absolute_pos; - for (; pos >= end; --pos){ - if (data[pos] == '\n'){ - if (no_hard) goto buffer_seek_whitespace_up_end; - else no_hard = 1; - } - else if (!is_whitespace(data[pos])){ - no_hard = 0; - } - } - } - -buffer_seek_whitespace_up_end: - if (pos != 0) ++pos; - - return pos; -} -#endif - internal_4tech int buffer_seek_whitespace_right(Buffer_Type *buffer, int pos){ Buffer_Stringify_Type loop; @@ -948,6 +853,8 @@ buffer_get_line_index_range(Buffer_Type *buffer, int pos, int l_bound, int u_bou lines = buffer->line_starts; + assert_4tech(lines != 0); + start = l_bound; end = u_bound; for (;;){ @@ -967,8 +874,7 @@ buffer_get_line_index_range(Buffer_Type *buffer, int pos, int l_bound, int u_bou inline_4tech int buffer_get_line_index(Buffer_Type *buffer, int pos){ - int result; - result = buffer_get_line_index_range(buffer, pos, 0, buffer->line_count); + int result = buffer_get_line_index_range(buffer, pos, 0, buffer->line_count); return(result); } diff --git a/win32_4ed.cpp b/win32_4ed.cpp index 2ead9fd2..35fa94cd 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -29,6 +29,7 @@ #include "system_shared.h" #define SUPPORT_DPI 1 +#define USE_WIN32_FONTS 1 #define FPS 60 #define frame_useconds (1000000 / FPS) @@ -1137,9 +1138,11 @@ Sys_CLI_End_Update_Sig(system_cli_end_update){ return close_me; } - #include "system_shared.cpp" #include "4ed_rendering.cpp" +#if USE_WIN32_FONTS +#include "win32_font.cpp" +#endif internal f32 size_change(i32 dpi_x, i32 dpi_y){ @@ -1168,10 +1171,12 @@ Font_Load_Sig(system_draw_font_load){ filename, pt_size, tab_width, - oversample); + oversample, + store_texture); - // TODO(allen): Make the growable partition something that can - // just be passed directly to font load and let it be grown there. + // TODO(allen): Make the growable partition something + // that can just be passed directly to font load and + // let it be grown there. if (!success){ Win32ScratchPartitionDouble(&win32vars.font_part); } @@ -1190,13 +1195,15 @@ Win32LoadAppCode(){ App_Get_Functions *get_funcs = 0; #if UseWinDll + win32vars.app_code = LoadLibraryA("4ed_app.dll"); if (win32vars.app_code){ get_funcs = (App_Get_Functions*) GetProcAddress(win32vars.app_code, "app_get_functions"); } - + #else + File_Data file = system_load_file("4ed_app.dll"); if (file.got_file){ @@ -1291,7 +1298,7 @@ Win32LoadRenderCode(){ win32vars.target.pop_clip = draw_pop_clip; win32vars.target.push_piece = draw_push_piece; - win32vars.target.font_set.font_info_load = draw_font_info_load; + //win32vars.target.font_set.font_info_load = draw_font_info_load; win32vars.target.font_set.font_load = system_draw_font_load; win32vars.target.font_set.release_font = draw_release_font; } diff --git a/win32_font.cpp b/win32_font.cpp new file mode 100644 index 00000000..901214ef --- /dev/null +++ b/win32_font.cpp @@ -0,0 +1,25 @@ +/* + * Mr. 4th Dimention - Allen Webster + * + * 12.12.2014 + * + * Win32 font rendering for nicer fonts + * + */ + +// TOP + +internal i32 +win32_draw_font_load(Partition *part, + Render_Font *font_out, + char *filename_untranslated, + i32 pt_size, + i32 tab_width, + i32 oversample){ + i32 result = 1; + return(result); +} + +// BOTTOM + + From c706bb9250ed19a6786f1cb540c00b008ea85fc4 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Fri, 3 Jun 2016 15:20:29 -0400 Subject: [PATCH 34/34] progress towards win32 fonts --- 4ed_rendering.cpp | 3 +++ win32_4ed.cpp | 14 +++++++++++++ win32_font.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/4ed_rendering.cpp b/4ed_rendering.cpp index d75d947f..45705544 100644 --- a/4ed_rendering.cpp +++ b/4ed_rendering.cpp @@ -305,6 +305,9 @@ launch_rendering(Render_Target *target){ #undef ExtractStruct +// TODO(allen): Put the burden of translation outside +// of this function (and other functions implementing +// the same interface). internal i32 draw_font_load(Partition *part, Render_Font *font_out, diff --git a/win32_4ed.cpp b/win32_4ed.cpp index 35fa94cd..4a96ceb2 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -1166,6 +1166,18 @@ Font_Load_Sig(system_draw_font_load){ #endif for (b32 success = 0; success == 0;){ +#if USE_WIN32_FONTS + + success = win32_draw_font_load(&win32vars.font_part, + font_out, + filename, + pt_size, + tab_width, + oversample, + store_texture); + +#else + success = draw_font_load(&win32vars.font_part, font_out, filename, @@ -1174,6 +1186,8 @@ Font_Load_Sig(system_draw_font_load){ oversample, store_texture); +#endif + // TODO(allen): Make the growable partition something // that can just be passed directly to font load and // let it be grown there. diff --git a/win32_font.cpp b/win32_font.cpp index 901214ef..97ef97b6 100644 --- a/win32_font.cpp +++ b/win32_font.cpp @@ -15,8 +15,55 @@ win32_draw_font_load(Partition *part, char *filename_untranslated, i32 pt_size, i32 tab_width, - i32 oversample){ - i32 result = 1; + i32 oversample, + b32 store_texture){ + + char space_[1024]; + String filename = make_fixed_width_string(space_); + b32 translate_success = sysshared_to_binary_path(&filename, filename_untranslated); + if (!translate_success) return 0; + + i32 result = 0; + + AddFontResourceEx(filename.str, FR_PRIVATE, 0); + + HFONT font_handle = + CreateFontA(pt_size, 0, 0, 0, + FW_NORMAL, // WEIGHT + FALSE, // ITALICS + FALSE, // UNDERLINE + FALSE, // STRIKE-OUT + ANSI_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + ANTIALIASED_QUALITY, + DEFAULT_PITCH|FF_DONTCARE, + filename.str); + + if (font_handle){ + HDC dc = CreateCompatibleDC(0); + + if (dc){ + // TODO(allen): Have to get metrics + + result = 1; + + if (store_texture){ + i32 tex_width = pt_size*16*oversample; + i32 tex_height = pt_size*16*oversample; + + HBITAMP bitmap = CreateCompatibleBitmap(dc, tex_width, tex_height); + + // TODO(allen): pack each glyph into a texture + // and generate the equivalent data output by stb + // in the stbtt_packedchar array. + + } + } + + DeleteObject(font_handle); + } + return(result); }