From 3ad0772662e9b66500950ff28ee9199bdba440e9 Mon Sep 17 00:00:00 2001
From: Allen Webster <editor@4coder.net>
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 <string.h>
+
 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 <iaminsofaras@gmail.com>
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 <editor@4coder.net>
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(&current_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(&current_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 <editor@4coder.net>
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 <editor@4coder.net>
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 <editor@4coder.net>
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 <editor@4coder.net>
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 = &empty;
+    }
+    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 <editor@4coder.net>
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 <editor@4coder.net>
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 <editor@4coder.net>
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 <editor@4coder.net>
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 <editor@4coder.net>
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 <editor@4coder.net>
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 <iaminsofaras@gmail.com>
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 <editor@4coder.net>
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 <math.h>
 #include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
 
 #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 <iaminsofaras@gmail.com>
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 <editor@4coder.net>
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 <assert.h>
 
 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 <editor@4coder.net>
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 <editor@4coder.net>
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 <editor@4coder.net>
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 (n<a)?(a):((n>z)?(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 <editor@4coder.net>
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 = &empty;
-    }
-    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 = &empty;
+    }
+    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 <iaminsofaras@gmail.com>
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 <editor@4coder.net>
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 = &empty;
-    }
-    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 = &empty;
+    }
+    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<typename T>
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 <editor@4coder.net>
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 <iaminsofaras@gmail.com>
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 <editor@4coder.net>
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 <editor@4coder.net>
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 <editor@4coder.net>
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 <editor@4coder.net>
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 <iaminsofaras@gmail.com>
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 <editor@4coder.net>
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 <editor@4coder.net>
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 <assert.h>
 
-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(&param->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 <editor@4coder.net>
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(&param->param.value);
             break;
-
+            
             case par_range_end:
             end_set = 1;
             r_end = dynamic_to_int(&param->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(&param->param.value);
             break;
-
+            
             case par_range_end:
             end_set = 1;
             r_end = dynamic_to_int(&param->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(&param->param.value);
         }
         else if (v == par_save_update_name){
-			update_names = dynamic_to_bool(&param->param.value);
-		}
+            update_names = dynamic_to_bool(&param->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(&param->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(&param->param.value);
             break;
-
+            
             case par_range_end:
             end_set = 1;
             r_end = dynamic_to_int(&param->param.value);
             break;
-
+            
             case par_clear_blank_lines:
             opts.empty_blank_lines = dynamic_to_bool(&param->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(&param->param.value);
             }break;
-
+            
             case par_do_in_background:
             {
                 do_in_background = 1;
             }break;
-
+            
             case par_cli_path:
             {
                 char *new_cli_path = dynamic_to_string(&param->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(&param->param.value, &script_len);
@@ -1495,21 +1489,21 @@ COMMAND_DECL(command_line){
                     script = new_command;
                 }
             }break;
-
+            
             case par_flags:
             {
                 flags = (u32)dynamic_to_int(&param->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 <editor@4coder.net>
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);
 }