From 60dab2731c12969c105affb99253a98f1acc3f02 Mon Sep 17 00:00:00 2001
From: Allen Webster <yoyo4thdimention@gmail.com>
Date: Mon, 2 Nov 2015 19:43:36 -0500
Subject: [PATCH] work on mugab edits

---
 4coder_custom.cpp                  |   2 +-
 4coder_custom.h                    |   2 +-
 4ed.cpp                            | 159 +++++----
 4ed_file_view.cpp                  | 540 ++++++++++++++++++-----------
 4ed_style.cpp                      |  16 +-
 buffer/4coder_buffer_abstract.cpp  |  54 ++-
 buffer/4coder_gap_buffer.cpp       |  38 +-
 buffer/4coder_golden_array.cpp     |  28 +-
 buffer/4coder_multi_gap_buffer.cpp | 336 +++++++++++++++---
 buffer/4coder_shared.cpp           |   2 +
 win32_4ed.cpp                      |   2 +-
 11 files changed, 797 insertions(+), 382 deletions(-)

diff --git a/4coder_custom.cpp b/4coder_custom.cpp
index 986af21e..49d504e6 100644
--- a/4coder_custom.cpp
+++ b/4coder_custom.cpp
@@ -236,7 +236,7 @@ extern "C" GET_BINDING_DATA(get_bindings){
     bind(context, codes->down, MDFR_ALT, cmdid_stop_rewind_fastforward);
     bind(context, 'h', MDFR_CTRL, cmdid_history_backward);
     bind(context, 'H', MDFR_CTRL, cmdid_history_forward);
-    bind(context, 'd', MDFR_CTRL, cmdid_delete_chunk);
+    bind(context, 'd', MDFR_CTRL, cmdid_delete_range);
     bind(context, 'l', MDFR_CTRL, cmdid_toggle_line_wrap);
     bind(context, 'L', MDFR_CTRL, cmdid_toggle_endline_mode);
     bind(context, 'u', MDFR_CTRL, cmdid_to_uppercase);
diff --git a/4coder_custom.h b/4coder_custom.h
index 833a6109..bf56a768 100644
--- a/4coder_custom.h
+++ b/4coder_custom.h
@@ -69,7 +69,7 @@ enum Command_ID{
     cmdid_cut,
     cmdid_paste,
     cmdid_paste_next,
-    cmdid_delete_chunk,
+    cmdid_delete_range,
     cmdid_timeline_scrub,
     cmdid_undo,
     cmdid_redo,
diff --git a/4ed.cpp b/4ed.cpp
index 3a6707ca..9a8015f0 100644
--- a/4ed.cpp
+++ b/4ed.cpp
@@ -135,6 +135,8 @@ globalvar Application_Links app_links;
 
 #define REQ_VIEW(n) View *n = command->view; if (!n) return
 #define REQ_FILE_VIEW(n) File_View *n = view_to_file_view(command->view); if (!n) return
+#define REQ_OPEN_FILE_VIEW(n) File_View *n = view_to_file_view(command->view); if (!n || n->locked) return
+#define REQ_FILE_HISTORY(n,v) Editing_File *n = (v)->file; if (!n || !buffer_good(&n->buffer) || n->is_dummy || !n->undo.undo.edits) return
 #define REQ_FILE(n,v) Editing_File *n = (v)->file; if (!n || !buffer_good(&n->buffer) || n->is_dummy) return
 #define REQ_COLOR_VIEW(n) Color_View *n = view_to_color_view(command->view); if (!n) return
 #define REQ_DBG_VIEW(n) Debug_View *n = view_to_debug_view(command->view); if (!n) return
@@ -206,7 +208,7 @@ COMMAND_DECL(null){
 
 COMMAND_DECL(write_character){
     ProfileMomentFunction();
-    REQ_FILE_VIEW(view);
+    REQ_OPEN_FILE_VIEW(view);
     REQ_FILE(file, view);
     USE_LAYOUT(layout);
     USE_MEM(mem);
@@ -223,7 +225,7 @@ COMMAND_DECL(write_character){
     view_replace_range(mem, view, layout, pos, pos, (u8*)string.str, string.size, next_cursor_pos);
     view_cursor_move(view, next_cursor_pos);
     if (view->mark >= pos) view->mark += string.size;
-    view->file->cursor_pos = view->cursor.pos;
+    file->cursor_pos = view->cursor.pos;
 }
 
 COMMAND_DECL(seek_whitespace_right){
@@ -233,7 +235,6 @@ COMMAND_DECL(seek_whitespace_right){
     REQ_FILE(file, view);
     
     i32 pos = buffer_seek_whitespace_right(&file->buffer, view->cursor.pos);
-    
     view_cursor_move(view, pos);
 #endif
 }
@@ -245,7 +246,6 @@ COMMAND_DECL(seek_whitespace_left){
     REQ_FILE(file, view);
     
     i32 pos = buffer_seek_whitespace_left(&file->buffer, view->cursor.pos);
-    
     view_cursor_move(view, pos);
 #endif
 }
@@ -356,7 +356,7 @@ COMMAND_DECL(seek_white_or_token_left){
 }
 
 COMMAND_DECL(seek_alphanumeric_right){
-#if BUFFER_EXPERIMENT_SCALPEL <= 1
+#if BUFFER_EXPERIMENT_SCALPEL <= 2
     ProfileMomentFunction();
     REQ_FILE_VIEW(view);
     REQ_FILE(file, view);
@@ -367,7 +367,7 @@ COMMAND_DECL(seek_alphanumeric_right){
 }
 
 COMMAND_DECL(seek_alphanumeric_left){
-#if BUFFER_EXPERIMENT_SCALPEL <= 1
+#if BUFFER_EXPERIMENT_SCALPEL <= 2
     ProfileMomentFunction();
     REQ_FILE_VIEW(view);
     REQ_FILE(file, view);
@@ -378,7 +378,7 @@ COMMAND_DECL(seek_alphanumeric_left){
 }
 
 COMMAND_DECL(seek_alphanumeric_or_camel_right){
-#if BUFFER_EXPERIMENT_SCALPEL <= 1
+#if BUFFER_EXPERIMENT_SCALPEL <= 2
     ProfileMomentFunction();
     REQ_FILE_VIEW(view);
     REQ_FILE(file, view);
@@ -390,7 +390,7 @@ COMMAND_DECL(seek_alphanumeric_or_camel_right){
 }
 
 COMMAND_DECL(seek_alphanumeric_or_camel_left){
-#if BUFFER_EXPERIMENT_SCALPEL <= 1
+#if BUFFER_EXPERIMENT_SCALPEL <= 2
     ProfileMomentFunction();
     REQ_FILE_VIEW(view);
     REQ_FILE(file, view);
@@ -404,7 +404,7 @@ COMMAND_DECL(seek_alphanumeric_or_camel_left){
 COMMAND_DECL(search){
     ProfileMomentFunction();
     REQ_FILE_VIEW(view);
-    REQ_FILE(file, view);
+    REQ_FILE(fixed, view);
     USE_VARS(vars);
     
     view_set_widget(view, FWIDG_SEARCH);
@@ -416,7 +416,7 @@ COMMAND_DECL(search){
 COMMAND_DECL(rsearch){
     ProfileMomentFunction();
     REQ_FILE_VIEW(view);
-    REQ_FILE(file, view);
+    REQ_FILE(fixed, view);
     USE_VARS(vars);
     
     view_set_widget(view, FWIDG_SEARCH);
@@ -428,7 +428,7 @@ COMMAND_DECL(rsearch){
 COMMAND_DECL(goto_line){
     ProfileMomentFunction();
     REQ_FILE_VIEW(view);
-    REQ_FILE(file, view);
+    REQ_FILE(fixed, view);
     USE_VARS(vars);
     
     view_set_widget(view, FWIDG_GOTO_LINE);
@@ -460,7 +460,7 @@ COMMAND_DECL(copy){
 
 COMMAND_DECL(cut){
     ProfileMomentFunction();
-    REQ_FILE_VIEW(view);
+    REQ_OPEN_FILE_VIEW(view);
     REQ_FILE(file, view);
     USE_WORKING_SET(working_set);
     USE_LAYOUT(layout);
@@ -481,7 +481,7 @@ COMMAND_DECL(cut){
 
 COMMAND_DECL(paste){
     ProfileMomentFunction();
-    REQ_FILE_VIEW(view);
+    REQ_OPEN_FILE_VIEW(view);
     REQ_FILE(file, view);
     USE_WORKING_SET(working_set);
     USE_LAYOUT(layout);
@@ -516,7 +516,7 @@ COMMAND_DECL(paste){
 
 COMMAND_DECL(paste_next){
     ProfileMomentFunction();
-    REQ_FILE_VIEW(view);
+    REQ_OPEN_FILE_VIEW(view);
     REQ_FILE(file, view);
     USE_WORKING_SET(working_set);
     USE_LAYOUT(layout);
@@ -552,9 +552,9 @@ COMMAND_DECL(paste_next){
     }
 }
 
-COMMAND_DECL(delete_chunk){
+COMMAND_DECL(delete_range){
     ProfileMomentFunction();
-    REQ_FILE_VIEW(view);
+    REQ_OPEN_FILE_VIEW(view);
     REQ_FILE(file, view);
     USE_LAYOUT(layout);
     USE_MEM(mem);
@@ -572,7 +572,7 @@ COMMAND_DECL(delete_chunk){
 COMMAND_DECL(timeline_scrub){
     ProfileMomentFunction();
     REQ_FILE_VIEW(view);
-    REQ_FILE(file, view);
+    REQ_FILE_HISTORY(file, view);
     
     view_set_widget(view, FWIDG_TIMELINES);
     view->widget.timeline.undo_line = 1;
@@ -582,6 +582,7 @@ COMMAND_DECL(timeline_scrub){
 COMMAND_DECL(undo){
     ProfileMomentFunction();
     REQ_FILE_VIEW(view);
+    REQ_FILE_HISTORY(file, view);
     USE_LAYOUT(layout);
     USE_MEM(mem);
     
@@ -591,6 +592,7 @@ COMMAND_DECL(undo){
 COMMAND_DECL(redo){
     ProfileMomentFunction();
     REQ_FILE_VIEW(view);
+    REQ_FILE_HISTORY(file, view);
     USE_LAYOUT(layout);
     USE_MEM(mem);
     
@@ -600,6 +602,7 @@ COMMAND_DECL(redo){
 COMMAND_DECL(increase_rewind_speed){
     ProfileMomentFunction();
     REQ_FILE_VIEW(view);
+    REQ_FILE_HISTORY(file, view);
 
     i32 rewind_speed = ROUND32(view->rewind_speed * 4.f);
     if (rewind_speed > 1) rewind_speed >>= 1;
@@ -613,6 +616,7 @@ COMMAND_DECL(increase_rewind_speed){
 COMMAND_DECL(increase_fastforward_speed){
     ProfileMomentFunction();
     REQ_FILE_VIEW(view);
+    REQ_FILE_HISTORY(file, view);
     
     i32 neg_rewind_speed = -ROUND32(view->rewind_speed * 4.f);
     if (neg_rewind_speed > 1) neg_rewind_speed >>= 1;
@@ -626,6 +630,7 @@ COMMAND_DECL(increase_fastforward_speed){
 COMMAND_DECL(stop_rewind_fastforward){
     ProfileMomentFunction();
     REQ_FILE_VIEW(view);
+    REQ_FILE_HISTORY(file, view);
     
     view->rewind_speed = 0;
 }
@@ -633,7 +638,7 @@ COMMAND_DECL(stop_rewind_fastforward){
 COMMAND_DECL(history_backward){
     ProfileMomentFunction();
     REQ_FILE_VIEW(view);
-    REQ_FILE(file, view);
+    REQ_FILE_HISTORY(file, view);
     USE_LAYOUT(layout);
     USE_MEM(mem);
     
@@ -643,7 +648,7 @@ COMMAND_DECL(history_backward){
 COMMAND_DECL(history_forward){
     ProfileMomentFunction();
     REQ_FILE_VIEW(view);
-    REQ_FILE(file, view);
+    REQ_FILE_HISTORY(file, view);
     USE_LAYOUT(layout);
     USE_MEM(mem);
     
@@ -698,7 +703,7 @@ app_open_file(App_Vars *vars, General_Memory *general, Panel *panel,
         
         view_replace_major(new_view, panel, live_set);
         
-        File_View *file_view = file_view_init(new_view, &vars->delay, &vars->layout);
+        File_View *file_view = file_view_init(new_view, &vars->layout);
         result = file_view;
         
         View *old_view = command_data->view;
@@ -830,7 +835,7 @@ COMMAND_DECL(save){
     
     String *file_path = &file->source_path;
     if (file_path->size > 0){
-        file_save(&mem->part, file, (u8*)file_path->str);
+        file_save(&mem->part, file, file_path->str);
     }
 }
 
@@ -1219,7 +1224,6 @@ COMMAND_DECL(move_left){
     
     i32 pos = view->cursor.pos;
     if (pos > 0) --pos;
-    
     view_cursor_move(view, pos);
 }
 
@@ -1231,13 +1235,12 @@ COMMAND_DECL(move_right){
     i32 size = buffer_size(&file->buffer);
     i32 pos = view->cursor.pos;
     if (pos < size) ++pos;
-    
     view_cursor_move(view, pos);
 }
 
 COMMAND_DECL(delete){
     ProfileMomentFunction();
-    REQ_FILE_VIEW(view);
+    REQ_OPEN_FILE_VIEW(view);
     REQ_FILE(file, view);
     USE_LAYOUT(layout);
     USE_MEM(mem);
@@ -1261,7 +1264,7 @@ COMMAND_DECL(delete){
 
 COMMAND_DECL(backspace){
     ProfileMomentFunction();
-    REQ_FILE_VIEW(view);
+    REQ_OPEN_FILE_VIEW(view);
     REQ_FILE(file, view);
     USE_LAYOUT(layout);
     USE_MEM(mem);
@@ -1292,7 +1295,7 @@ COMMAND_DECL(move_up){
     real32 px = view->preferred_x;
     if (cy >= 0){
         view->cursor = view_compute_cursor_from_xy(view, px, cy);
-        view->file->cursor_pos = view->cursor.pos;
+        file->cursor_pos = view->cursor.pos;
     }
 }
 
@@ -1304,7 +1307,7 @@ COMMAND_DECL(move_down){
     real32 cy = view_get_cursor_y(view)+view->style->font->height;
     real32 px = view->preferred_x;
     view->cursor = view_compute_cursor_from_xy(view, px, cy);
-    view->file->cursor_pos = view->cursor.pos;
+    file->cursor_pos = view->cursor.pos;
 }
 
 COMMAND_DECL(seek_end_of_line){
@@ -1539,27 +1542,47 @@ COMMAND_DECL(build){
     USE_LIVE_SET(live_set);
     USE_PANEL(panel);
     
+    char *buffer_name = "*cli process*";
+    char *path = "..\\misc";
+    char *script = "test";
+    
     if (vars->cli_processes.count < vars->cli_processes.max){
-        Get_File_Result file = working_set_get_available_file(working_set);
-        if (file.file){
-            file_create_empty(&mem->general, file.file, (u8*)"*cli process*", style->font);
-            table_add(&working_set->table, file.file->source_path, file.index);
+        Editing_File *file = working_set_contains(working_set, make_string_slowly(buffer_name));
+        i32 index;
+
+        if (!file){
+            Get_File_Result get_file = working_set_get_available_file(working_set);
+            file = get_file.file;
+            index = get_file.index;
+        }
+        else{
+            i32 proc_count = vars->cli_processes.count;
+            for (i32 i = 0; i < proc_count; ++i){
+                if (vars->cli_processes.procs[i].out_file == file){
+                    vars->cli_processes.procs[i].out_file = 0;
+                }
+            }
+            index = (int)(file - vars->working_set.files);
+        }
+        
+        if (file){
+            file_create_super_locked(&mem->general, file, (u8*)buffer_name, style->font);
+            table_add(&working_set->table, file->live_name, index);
             
             View *new_view = live_set_alloc_view(live_set, mem);
             view_replace_major(new_view, panel, live_set);
             
-            File_View *file_view = file_view_init(new_view, &vars->delay, &vars->layout);
-            view_set_file(file_view, file.file, style,
+            File_View *file_view = file_view_init(new_view, &vars->layout);
+            view_set_file(file_view, file, style,
                           vars->hooks[hook_open_file], command, app_links);
-            file.file->tokens_exist = 0;
-            new_view->map = app_get_map(vars, file.file->base_map_id);
+            new_view->map = app_get_map(vars, file->base_map_id);
             
             i32 i = vars->cli_processes.count++;
             CLI_Process *proc = vars->cli_processes.procs + i;
-            if (!system_cli_call("..\\misc", "build_all_test", &proc->cli)){
+            if (!system_cli_call(path, script, &proc->cli)){
                 --vars->cli_processes.count;
             }
-            proc->out_file = file.file;
+            proc->out_file = file;
         }
         else{
             // TODO(allen): feedback message - no available file
@@ -1608,25 +1631,6 @@ extern "C"{
         if (function) function(cmd, binding);
 
         update_command_data(cmd->vars, cmd);
-#if 0
-        App_Vars *vars = cmd->vars;
-        Command_Data command_data;
-        command_data.vars = vars;
-        command_data.mem = &vars->mem;
-        command_data.working_set = &vars->working_set;
-        command_data.layout = &vars->layout;
-        command_data.panel = command_data.layout->panels + command_data.layout->active_panel;
-        command_data.view = command_data.panel->view;
-        command_data.live_set = &vars->live_set;
-        command_data.style = &vars->style;
-        command_data.delay = &vars->delay;
-        command_data.screen_width = cmd->screen_width;
-        command_data.screen_height = cmd->screen_height;
-        command_data.key = cmd->key;
-        command_data.part = cmd->part;
-        
-        *cmd = command_data;
-#endif
     }
     
     PUSH_PARAMETER_SIG(external_push_parameter){
@@ -1755,7 +1759,7 @@ setup_file_commands(Command_Map *commands, Partition *part, Key_Codes *codes, Co
     map_add(commands, codes->down, MDFR_ALT, command_stop_rewind_fastforward);
     map_add(commands, 'h', MDFR_CTRL, command_history_backward);
     map_add(commands, 'H', MDFR_CTRL, command_history_forward);
-    map_add(commands, 'd', MDFR_CTRL, command_delete_chunk);
+    map_add(commands, 'd', MDFR_CTRL, command_delete_range);
     map_add(commands, 'l', MDFR_CTRL, command_toggle_line_wrap);
     map_add(commands, '?', MDFR_CTRL, command_toggle_show_whitespace);
     map_add(commands, '|', MDFR_CTRL, command_toggle_tokens);
@@ -1830,7 +1834,7 @@ setup_command_table(){
     SET(cut);
     SET(paste);
     SET(paste_next);
-    SET(delete_chunk);
+    SET(delete_range);
     SET(timeline_scrub);
     SET(undo);
     SET(redo);
@@ -1998,7 +2002,6 @@ app_hardcode_styles(App_Vars *vars){
     
     style->main.paste_color = 0xFFDDEE00;
     style->main.undo_color = 0xFF00DDEE;
-    style->main.next_undo_color = 0xFF006E77;
     
     style->main.highlight_junk_color = 0xff3a0000;
     style->main.highlight_white_color = 0xff003a3a;
@@ -2086,7 +2089,6 @@ app_hardcode_styles(App_Vars *vars){
     
     style->main.paste_color = 0xFFDDEE00;
     style->main.undo_color = 0xFF00DDEE;
-    style->main.next_undo_color = 0xFF006E77;
     
     style->main.highlight_junk_color = 0xff3a0000;
     style->main.highlight_white_color = 0xFF151F2A;
@@ -2127,7 +2129,6 @@ app_hardcode_styles(App_Vars *vars){
     
     style->main.paste_color = 0xFF900090;
     style->main.undo_color = 0xFF606090;
-    style->main.next_undo_color = 0xFF404070;
     
     style->main.highlight_junk_color = 0xff3a0000;
     style->main.highlight_white_color = 0xff003a3a;
@@ -2168,7 +2169,6 @@ app_hardcode_styles(App_Vars *vars){
     
     style->main.paste_color = 0xFF00B8B8;
     style->main.undo_color = 0xFFB800B8;
-    style->main.next_undo_color = 0xFF5C005C;
     
     style->main.highlight_junk_color = 0xFFFF7878;
     style->main.highlight_white_color = 0xFFBCBCBC;
@@ -2592,7 +2592,7 @@ app_step(Thread_Context *thread, Key_Codes *codes,
     }
     
     // NOTE(allen): update child processes
-    {
+    if (time_step){
         Temp_Memory temp = begin_temp_memory(&vars->mem.part);
         u32 max = Kbytes(32);
         char *dest = push_array(&vars->mem.part, char, max);
@@ -2610,7 +2610,7 @@ app_step(Thread_Context *thread, Key_Codes *codes,
                     amount = eol_in_place_convert_in(dest, amount);
                     Edit_Spec spec = {};
                     spec.step.type = ED_NORMAL;
-                    spec.step.edit.start =  buffer_size(&out_file->buffer);
+                    spec.step.edit.start = buffer_size(&out_file->buffer);
                     spec.step.edit.end = spec.step.edit.start;
                     spec.step.edit.len = amount;
                     spec.step.pre_pos = new_cursor;
@@ -2622,11 +2622,22 @@ app_step(Thread_Context *thread, Key_Codes *codes,
                     new_cursor = spec.step.post_pos;
                 }
             }
-
+            
             if (system_cli_end_update(&proc->cli)){
                 *proc = vars->cli_processes.procs[--count];
                 --i;
             }
+            
+            Panel *panel = vars->layout.panels;
+            i32 panel_count = vars->layout.panel_count;
+            for (i32 i = 0; i < panel_count; ++i, ++panel){
+                View *view = panel->view;
+                if (view && view->is_minor) view = view->major;
+                File_View *fview = view_to_file_view(view);
+                if (fview){
+                    view_cursor_move(fview, new_cursor);
+                }
+            }
         }
         
         vars->cli_processes.count = count;
@@ -3043,7 +3054,7 @@ app_step(Thread_Context *thread, Key_Codes *codes,
                 if (fview){
                     Editing_File *file = fview->file;
                     if (file && !file->is_dummy){
-                        file_save_and_set_names(&vars->mem.part, file, (u8*)string->str);
+                        file_save_and_set_names(&vars->mem.part, file, string->str);
                     }
                 }
             }break;
@@ -3051,8 +3062,8 @@ app_step(Thread_Context *thread, Key_Codes *codes,
             case DACT_SAVE:
             {
                 Editing_File *file = working_set_lookup_file(working_set, *string);
-                if (file && !file->is_dummy){
-                    file_save(&vars->mem.part, file, (u8*)file->source_path.str);
+                if (!file->is_dummy){
+                    file_save(&vars->mem.part, file, file->source_path.str);
                 }
             }break;
             
@@ -3065,7 +3076,7 @@ app_step(Thread_Context *thread, Key_Codes *codes,
                 View *new_view = live_set_alloc_view(live_set, mem);
                 view_replace_major(new_view, panel, live_set);
                 
-                File_View *file_view = file_view_init(new_view, &vars->delay, &vars->layout);
+                File_View *file_view = file_view_init(new_view, &vars->layout);
                 command_data.view = (View*)file_view;
                 view_set_file(file_view, file.file, style,
                               vars->hooks[hook_open_file], &command_data, app_links);
@@ -3082,10 +3093,12 @@ app_step(Thread_Context *thread, Key_Codes *codes,
                     View *new_view = live_set_alloc_view(live_set, mem);
                     view_replace_major(new_view, panel, live_set);
                     
-                    File_View *file_view = file_view_init(new_view, &vars->delay, &vars->layout);
+                    File_View *file_view = file_view_init(new_view, &vars->layout);
                     command_data.view = (View*)file_view;
+                    
                     view_set_file(file_view, file, style,
                                   vars->hooks[hook_open_file], &command_data, app_links);
+                    
                     new_view->map = app_get_map(vars, file->base_map_id);
                 }
             }break;
@@ -3095,7 +3108,7 @@ app_step(Thread_Context *thread, Key_Codes *codes,
                 Editing_File *file = working_set_lookup_file(working_set, *string);
                 if (file){
                     table_remove(&working_set->table, file->source_path);
-                    kill_buffer(general, file, live_set, &vars->layout);
+                    kill_file(general, file, live_set, &vars->layout);
                 }
             }break;
             
@@ -3108,7 +3121,7 @@ app_step(Thread_Context *thread, Key_Codes *codes,
                     case SYNC_GOOD:
                     {
                         table_remove(&working_set->table, file->source_path);
-                        kill_buffer(general, file, live_set, &vars->layout);
+                        kill_file(general, file, live_set, &vars->layout);
                         view_remove_minor(panel, live_set);
                     }break;
                     
@@ -3186,7 +3199,7 @@ app_step(Thread_Context *thread, Key_Codes *codes,
         Editing_File *file = vars->working_set.files;
         for (i32 i = vars->working_set.file_index_count; i > 0; --i, ++file){
             if (buffer_good(&file->buffer) && !file->is_dummy){
-                file_measure_widths(&vars->mem.general, file, vars->style.font);
+                file_measure_widths(&vars->mem.general, &file->buffer, vars->style.font);
             }
         }
         
diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp
index ad089218..2eca2df5 100644
--- a/4ed_file_view.cpp
+++ b/4ed_file_view.cpp
@@ -84,28 +84,28 @@ struct Undo_Data{
 
 struct Editing_File{
     Buffer_Type buffer;
-    
-    Undo_Data undo;
-    
     Font *font;
     
     i32 cursor_pos;
     b32 is_dummy;
+    char live_name_[256];
+    String live_name;
+    
+    i32 base_map_id;
     
     char source_path_[256];
-    char live_name_[256];
     char extension_[16];
     String source_path;
-    String live_name;
     String extension;
     
+    Undo_Data undo;
+    b32 super_locked;
+    
     Cpp_Token_Stack token_stack;
     b32 tokens_complete;
     b32 tokens_exist;
     b32 still_lexing;
     u32 lex_job;
-    
-    i32 base_map_id;
     i32 dos_write_mode;
     
     u64 last_4ed_write_time;
@@ -116,7 +116,7 @@ struct Editing_File{
 struct File_Table_Entry{
     String name;
     u32 hash;
-    i32 index;
+    i32 id;
 };
 
 struct File_Table{
@@ -136,15 +136,15 @@ get_file_hash(String name){
     return x;
 }
 
-internal bool32
-table_add(File_Table *table, String name, i32 index){
+internal b32
+table_add(File_Table *table, String name, i32 id){
     Assert(table->count * 3 < table->max * 2);
     
     File_Table_Entry entry, e;
     i32 i;
     
     entry.name = name;
-    entry.index = index;
+    entry.id = id;
     entry.hash = get_file_hash(name);
     i = entry.hash % table->max;
     while ((e = table->table[i]).name.str){
@@ -178,18 +178,18 @@ table_find_pos(File_Table *table, String name, i32 *index){
     return 0;
 }
 
-inline bool32
-table_find(File_Table *table, String name, i32 *index){
+inline b32
+table_find(File_Table *table, String name, i32 *id){
     i32 pos;
-    bool32 r = table_find_pos(table, name, &pos);
-    if (r) *index = table->table[pos].index;
+    b32 r = table_find_pos(table, name, &pos);
+    if (r) *id = table->table[pos].id;
     return r;
 }
 
-inline bool32
+inline b32
 table_remove(File_Table *table, String name){
     i32 pos;
-    bool32 r = table_find_pos(table, name, &pos);
+    b32 r = table_find_pos(table, name, &pos);
     if (r){
         table->table[pos].name.str = 0;
         --table->count;
@@ -1021,23 +1021,37 @@ struct File_View_Widget{
     } timeline;
 };
 
+enum Link_Type{
+    link_result,
+    link_related,
+    link_error,
+    link_warning,
+    // never below this
+    link_type_count
+};
+
+struct Hyper_Link{
+    char *file_name;
+    i32 line_number;
+    i32 start, end;
+    Link_Type link_type;
+};
+
 struct File_View{
     View view_base;
-    
-    Delay *delay;
-    Editing_Layout *layout;
-    
+
     Editing_File *file;
     Style *style;
+    Editing_Layout *layout;
     
     i32 font_advance;
     i32 font_height;
-    
+
     Full_Cursor cursor;
     i32 mark;
-    real32 scroll_y, target_y, vel_y;
-    real32 scroll_x, target_x, vel_x;
-    real32 preferred_x;
+    f32 scroll_y, target_y, vel_y;
+    f32 scroll_x, target_x, vel_x;
+    f32 preferred_x;
     Full_Cursor scroll_y_cursor;
     union{
         Incremental_Search isearch;
@@ -1048,19 +1062,23 @@ struct File_View{
     
     Full_Cursor temp_highlight;
     i32 temp_highlight_end_pos;
-    bool32 show_temp_highlight;
+    b32 show_temp_highlight;
     
     File_View_Mode mode, next_mode;
     File_View_Widget widget;
-    real32 rewind_amount, rewind_speed;
+    f32 rewind_amount, rewind_speed;
     i32 rewind_max, scrub_max;
-    bool32 unwrapped_lines;
-    bool32 show_whitespace;
+    b32 unwrapped_lines;
+    b32 show_whitespace;
+    b32 locked;
     
     i32 line_count, line_max;
-    real32 *line_wrap_y;
+    f32 *line_wrap_y;
     
     Text_Effect paste_effect;
+    
+    Hyper_Link *links;
+    i32 link_count, link_max;
 };
 
 inline File_View*
@@ -1099,14 +1117,19 @@ file_init_strings(Editing_File *file){
 }
 
 inline void
-file_set_name(Editing_File *file, u8 *filename){
-    String f, ext;
-    f = make_string_slowly((char*)filename);
-    copy_checked(&file->source_path, f);
+file_set_name(Editing_File *file, char *filename){
     file->live_name = make_fixed_width_string(file->live_name_);
-    get_front_of_directory(&file->live_name, f);
-    ext = file_extension(f);
-    copy(&file->extension, ext);
+    if (filename[0] == '*'){
+        copy(&file->live_name, filename);
+    }
+    else{
+        String f, ext;
+        f = make_string_slowly(filename);
+        copy_checked(&file->source_path, f);
+        get_front_of_directory(&file->live_name, f);
+        ext = file_extension(f);
+        copy(&file->extension, ext);
+    }
 }
 
 inline void
@@ -1119,32 +1142,32 @@ file_synchronize_times(Editing_File *file, u8 *filename){
     }
 }
 
-internal bool32
-file_save(Partition *part, Editing_File *file, u8 *filename){
-	bool32 result = 0;
-#if BUFFER_EXPERIMENT_SCALPEL <= 1
+internal b32
+file_save(Partition *part, Editing_File *file, char *filename){
+	b32 result = 0;
+#if BUFFER_EXPERIMENT_SCALPEL <= 2
     Temp_Memory temp = begin_temp_memory(part);
     i32 max = partition_remaining(part);
     if (file->dos_write_mode){
         char *data = push_array(part, char, max);
         i32 size = buffer_convert_out(&file->buffer, data, max);
-        result = system_save_file(filename, data, size);
+        result = system_save_file((u8*)filename, data, size);
     }
     else{
         char *data = push_array(part, char, max);
         i32 size = buffer_size(&file->buffer);
         Assert(size <= max);
         buffer_stringify(&file->buffer, 0, size, data);
-        result = system_save_file(filename, data, size);
+        result = system_save_file((u8*)filename, data, size);
     }
     end_temp_memory(temp);
-    file_synchronize_times(file, filename);
+    file_synchronize_times(file, (u8*)filename);
 #endif
     return result;
 }
 
 inline bool32
-file_save_and_set_names(Partition *part, Editing_File *file, u8 *filename){
+file_save_and_set_names(Partition *part, Editing_File *file, char *filename){
 	bool32 result = 0;
 	if (file_save(part, file, filename)){
 		result = 1;
@@ -1153,16 +1176,6 @@ file_save_and_set_names(Partition *part, Editing_File *file, u8 *filename){
 	return result;
 }
 
-inline i32
-file_count_newlines(Editing_File *file, i32 start, i32 end){
-#if BUFFER_EXPERIMENT_SCALPEL <= 2
-    i32 count = buffer_count_newlines(&file->buffer, start, end);
-#else
-    i32 count = 0;
-#endif
-    return count;
-}
-
 enum File_Bubble_Type{
     BUBBLE_BUFFER = 1,
     BUBBLE_STARTS,
@@ -1181,20 +1194,20 @@ enum File_Bubble_Type{
 #define GROW_SUCCESS 2
 
 internal i32
-file_grow_starts_as_needed(General_Memory *general, Editing_File *file, i32 additional_lines){
+file_grow_starts_as_needed(General_Memory *general, Buffer_Type *buffer, i32 additional_lines){
     bool32 result = GROW_NOT_NEEDED;
 #if BUFFER_EXPERIMENT_SCALPEL <= 2
-    i32 max = file->buffer.line_max;
-    i32 count = file->buffer.line_count;
+    i32 max = buffer->line_max;
+    i32 count = buffer->line_count;
     i32 target_lines = count + additional_lines;
     if (target_lines > max || max == 0){
         max = LargeRoundUp(target_lines + max, Kbytes(1));
         i32 *new_lines = (i32*)
-            general_memory_reallocate(general, file->buffer.line_starts,
+            general_memory_reallocate(general, buffer->line_starts,
                                       sizeof(i32)*count, sizeof(i32)*max, BUBBLE_STARTS);
         if (new_lines){
-            file->buffer.line_starts = new_lines;
-            file->buffer.line_max = max;
+            buffer->line_starts = new_lines;
+            buffer->line_max = max;
             result = GROW_SUCCESS;
         }
         else{
@@ -1206,47 +1219,45 @@ file_grow_starts_as_needed(General_Memory *general, Editing_File *file, i32 addi
 }
 
 internal void
-file_measure_starts(General_Memory *general, Editing_File *file){
+file_measure_starts(General_Memory *general, Buffer_Type *buffer){
 #if BUFFER_EXPERIMENT_SCALPEL <= 2
     ProfileMomentFunction();
-    if (!file->buffer.line_starts){
-        i32 max = file->buffer.line_max = Kbytes(1);
-        file->buffer.line_starts = (i32*)general_memory_allocate(general, max*sizeof(i32), BUBBLE_STARTS);
-        TentativeAssert(file->buffer.line_starts);
+    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?
     }
     
     Buffer_Measure_Starts state = {};
-    while (buffer_measure_starts(&state, &file->buffer)){
-        i32 max = file->buffer.line_max;
+    while (buffer_measure_starts(&state, buffer)){
+        i32 max = buffer->line_max;
         i32 count = state.count;
         i32 target_lines = count + 1;
         
         max = (target_lines << 1);
         i32 *new_lines = (i32*)
-            general_memory_reallocate(general, file->buffer.line_starts,
+            general_memory_reallocate(general, buffer->line_starts,
                                       sizeof(i32)*count, sizeof(i32)*max, BUBBLE_STARTS);
         
         // TODO(allen): when unable to grow?
         TentativeAssert(new_lines);
-        file->buffer.line_starts = new_lines;
-        file->buffer.line_max = max;
+        buffer->line_starts = new_lines;
+        buffer->line_max = max;
     }
-    file->buffer.line_count = state.count;
+    buffer->line_count = state.count;
 #endif
 }
 
 internal void
-file_remeasure_starts(General_Memory *general, Editing_File *file,
+file_remeasure_starts(General_Memory *general, Buffer_Type *buffer,
                       i32 line_start, i32 line_end, i32 line_shift,
                       i32 character_shift){
 #if BUFFER_EXPERIMENT_SCALPEL <= 2
     ProfileMomentFunction();
-    
-    Assert(file->buffer.line_starts);
-    file_grow_starts_as_needed(general, file, line_shift);
-    
-    buffer_remeasure_starts(&file->buffer, line_start, line_end, line_shift, character_shift);
+    Assert(buffer->line_starts);
+    file_grow_starts_as_needed(general, buffer, line_shift);
+    buffer_remeasure_starts(buffer, line_start, line_end, line_shift, character_shift);
 #endif
 }
 
@@ -1264,47 +1275,44 @@ get_opaque_font_advance(Font *font){
 }
 
 internal void
-file_grow_widths_as_needed(General_Memory *general, Editing_File *file){
+file_grow_widths_as_needed(General_Memory *general, Buffer_Type *buffer){
 #if BUFFER_EXPERIMENT_SCALPEL <= 2
-    i32 line_count = file->buffer.line_count;
-    if (line_count > file->buffer.widths_max || file->buffer.widths_max == 0){
+    i32 line_count = buffer->line_count;
+    if (line_count > buffer->widths_max || buffer->widths_max == 0){
         i32 new_max = LargeRoundUp(line_count, Kbytes(1));
         if (new_max < Kbytes(1)) new_max = Kbytes(1);
-        if (file->buffer.line_widths){
-            file->buffer.line_widths = (f32*)
-                general_memory_reallocate(general, file->buffer.line_widths,
-                                          sizeof(f32)*file->buffer.widths_count, sizeof(f32)*new_max, BUBBLE_WIDTHS);
+        if (buffer->line_widths){
+            buffer->line_widths = (f32*)
+                general_memory_reallocate(general, buffer->line_widths,
+                                          sizeof(f32)*buffer->widths_count, sizeof(f32)*new_max, BUBBLE_WIDTHS);
         }
         else{
-            file->buffer.line_widths = (f32*)
+            buffer->line_widths = (f32*)
                 general_memory_allocate(general, sizeof(f32)*new_max, BUBBLE_WIDTHS);
         }
-        file->buffer.widths_max = new_max;
+        buffer->widths_max = new_max;
     }
 #endif
 }
 
 internal void
-file_measure_widths(General_Memory *general, Editing_File *file, Font *font){
+file_measure_widths(General_Memory *general, Buffer_Type *buffer, Font *font){
 #if BUFFER_EXPERIMENT_SCALPEL <= 2
     ProfileMomentFunction();
-    
-    file_grow_widths_as_needed(general, file);
+    file_grow_widths_as_needed(general, buffer);
     Opaque_Font_Advance opad = get_opaque_font_advance(font);
-    buffer_measure_widths(&file->buffer, opad.data, opad.stride);
+    buffer_measure_widths(buffer, opad.data, opad.stride);
 #endif
 }
 
 internal void
-file_remeasure_widths(General_Memory *general, Editing_File *file, Font *font,
+file_remeasure_widths(General_Memory *general, Buffer_Type *buffer, Font *font,
                       i32 line_start, i32 line_end, i32 line_shift){
 #if BUFFER_EXPERIMENT_SCALPEL <= 2
     ProfileMomentFunction();
-    
-    file_grow_widths_as_needed(general, file);
+    file_grow_widths_as_needed(general, buffer);
     Opaque_Font_Advance opad = get_opaque_font_advance(font);
-    buffer_remeasure_widths(&file->buffer, opad.data, opad.stride,
-                            line_start, line_end, line_shift);
+    buffer_remeasure_widths(buffer, opad.data, opad.stride, line_start, line_end, line_shift);
 #endif
 }
 
@@ -1325,15 +1333,15 @@ view_compute_lowest_line(File_View *view){
             lowest_line = last_line;
         }
         else{
-            real32 wrap_y = view->line_wrap_y[last_line];
-            Editing_File *file = view->file;
-            Assert(!file->is_dummy);
             Style *style = view->style;
             Font *font = style->font;
+            real32 wrap_y = view->line_wrap_y[last_line];
             lowest_line = FLOOR32(wrap_y / font->height);
-            
-            real32 width = file->buffer.line_widths[last_line];
-            real32 max_width = view_compute_width(view);
+            f32 max_width = view_compute_width(view);
+
+            Editing_File *file = view->file;
+            Assert(!file->is_dummy);
+            f32 width = file->buffer.line_widths[last_line];
             i32 line_span = view_wrapped_line_span(width, max_width);
             lowest_line += line_span - 1;
         }
@@ -1346,8 +1354,10 @@ internal void
 view_measure_wraps(General_Memory *general, File_View *view){
 #if BUFFER_EXPERIMENT_SCALPEL <= 2
     ProfileMomentFunction();
-    Editing_File *file = view->file;
-    i32 line_count = file->buffer.line_count;
+    Buffer_Type *buffer;
+
+    buffer = &view->file->buffer;
+    i32 line_count = buffer->line_count;
     
     if (view->line_max < line_count){
         i32 max = view->line_max = LargeRoundUp(line_count, Kbytes(1));
@@ -1364,7 +1374,7 @@ view_measure_wraps(General_Memory *general, File_View *view){
     Font *font = view->style->font;
     real32 line_height = (real32)font->height;
     real32 max_width = view_compute_width(view);
-    buffer_measure_wrap_y(&file->buffer, view->line_wrap_y, line_height, max_width);
+    buffer_measure_wrap_y(buffer, view->line_wrap_y, line_height, max_width);
     
     view->line_count = line_count;
 #endif
@@ -1378,7 +1388,7 @@ alloc_for_buffer(void *context, int *size){
 }
 
 internal void
-file_create_from_string(General_Memory *general, Editing_File *file, u8 *filename, Font *font, String val){
+file_create_from_string(General_Memory *general, Editing_File *file, u8 *filename, Font *font, String val, b32 super_locked = 0){
     *file = {};
 #if BUFFER_EXPERIMENT_SCALPEL <= 2
     Buffer_Init_Type init = buffer_begin_init(&file->buffer, val.str, val.size);
@@ -1393,40 +1403,44 @@ file_create_from_string(General_Memory *general, Editing_File *file, u8 *filenam
     Assert(init_success);
 #endif
     
-    file_synchronize_times(file, filename);
     file_init_strings(file);
-    file_set_name(file, filename);
+    file_set_name(file, (char*)filename);
     
     file->base_map_id = mapid_file;
-    
-    file_measure_starts(general, file);
-    file_measure_widths(general, file, font);
     file->font = font;
+    
+    file_synchronize_times(file, filename);
+        
+    file_measure_starts(general, &file->buffer);
+    file_measure_widths(general, &file->buffer, font);
 
-    i32 request_size = Kbytes(64);
-    file->undo.undo.max = request_size;
-    file->undo.undo.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING);
-    file->undo.undo.edit_max = request_size / sizeof(Edit_Step);
-    file->undo.undo.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO);
+    file->super_locked = super_locked;
+    if (!super_locked){
+        i32 request_size = Kbytes(64);
+        file->undo.undo.max = request_size;
+        file->undo.undo.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING);
+        file->undo.undo.edit_max = request_size / sizeof(Edit_Step);
+        file->undo.undo.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO);
     
-    file->undo.redo.max = request_size;
-    file->undo.redo.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING);
-    file->undo.redo.edit_max = request_size / sizeof(Edit_Step);
-    file->undo.redo.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO);
+        file->undo.redo.max = request_size;
+        file->undo.redo.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING);
+        file->undo.redo.edit_max = request_size / sizeof(Edit_Step);
+        file->undo.redo.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO);
     
-    file->undo.history.max = request_size;
-    file->undo.history.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING);
-    file->undo.history.edit_max = request_size / sizeof(Edit_Step);
-    file->undo.history.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO);
+        file->undo.history.max = request_size;
+        file->undo.history.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING);
+        file->undo.history.edit_max = request_size / sizeof(Edit_Step);
+        file->undo.history.edits = (Edit_Step*)general_memory_allocate(general, request_size, BUBBLE_UNDO);
     
-    file->undo.children.max = request_size;
-    file->undo.children.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING);
-    file->undo.children.edit_max = request_size / sizeof(Buffer_Edit);
-    file->undo.children.edits = (Buffer_Edit*)general_memory_allocate(general, request_size, BUBBLE_UNDO);
+        file->undo.children.max = request_size;
+        file->undo.children.strings = (u8*)general_memory_allocate(general, request_size, BUBBLE_UNDO_STRING);
+        file->undo.children.edit_max = request_size / sizeof(Buffer_Edit);
+        file->undo.children.edits = (Buffer_Edit*)general_memory_allocate(general, request_size, BUBBLE_UNDO);
     
-    file->undo.history_block_count = 1;
-    file->undo.history_head_block = 0;
-    file->undo.current_block_normal = 1;
+        file->undo.history_block_count = 1;
+        file->undo.history_head_block = 0;
+        file->undo.current_block_normal = 1;
+    }
 }
 
 internal bool32
@@ -1444,13 +1458,19 @@ file_create(General_Memory *general, Editing_File *file, u8 *filename, Font *fon
     return result;
 }
 
-internal bool32
+internal b32
 file_create_empty(General_Memory *general, Editing_File *file, u8 *filename, Font *font){
-    bool32 result = 1;
-    
+    b32 result = 1;
     String empty_str = {};
     file_create_from_string(general, file, filename, font, empty_str);
-    
+    return result;
+}
+
+internal b32
+file_create_super_locked(General_Memory *general, Editing_File *file, u8 *filename, Font *font){
+    b32 result = 1;
+    String empty_str = {};
+    file_create_from_string(general, file, filename, font, empty_str, 1);
     return result;
 }
 
@@ -1487,25 +1507,31 @@ file_close(General_Memory *general, Editing_File *file){
     if (file->token_stack.tokens){
         general_memory_free(general, file->token_stack.tokens);
     }
+    
 #if BUFFER_EXPERIMENT_SCALPEL <= 1
-    general_memory_free(general, file->buffer.data);
-    general_memory_free(general, file->buffer.line_starts);
-    general_memory_free(general, file->buffer.line_widths);
+    Buffer_Type *buffer = &file->buffer;
+    if (buffer->data){
+        general_memory_free(general, buffer->data);
+        general_memory_free(general, buffer->line_starts);
+        general_memory_free(general, buffer->line_widths);
+    }
 #elif BUFFER_EXPERIMENT_SCALPEL == 2
     // TODO
 #endif
+
+    if (file->undo.undo.edits){
+        general_memory_free(general, file->undo.undo.strings);
+        general_memory_free(general, file->undo.undo.edits);
     
-    general_memory_free(general, file->undo.undo.strings);
-    general_memory_free(general, file->undo.undo.edits);
+        general_memory_free(general, file->undo.redo.strings);
+        general_memory_free(general, file->undo.redo.edits);
     
-    general_memory_free(general, file->undo.redo.strings);
-    general_memory_free(general, file->undo.redo.edits);
-    
-    general_memory_free(general, file->undo.history.strings);
-    general_memory_free(general, file->undo.history.edits);
+        general_memory_free(general, file->undo.history.strings);
+        general_memory_free(general, file->undo.history.edits);
+    }
 }
 
-internal void
+inline void
 file_get_dummy(Editing_File *file){
 	*file = {};
 	file->is_dummy = 1;
@@ -2101,9 +2127,9 @@ view_set_file(File_View *view, Editing_File *file, Style *style,
               Custom_Command_Function *open_hook, void *cmd_context, Application_Links app){
     Panel *panel = view->view_base.panel;
     view->file = file;
+    view->locked = file->super_locked;
     
     General_Memory *general = &view->view_base.mem->general;
-    AllowLocal(general);
     Font *font = style->font;
     view->style = style;
     view->font_advance = font->advance;
@@ -2114,25 +2140,25 @@ view_set_file(File_View *view, Editing_File *file, Style *style,
     view->cursor = {};
     view->cursor = view_compute_cursor_from_pos(view, file->cursor_pos);
     
-    real32 cursor_x, cursor_y;
-    real32 w, h;
-    real32 target_x, target_y;
+    f32 cursor_x, cursor_y;
+    f32 w, h;
+    f32 target_x, target_y;
     
     cursor_x = view_get_cursor_x(view);
     cursor_y = view_get_cursor_y(view);
     
-    w = (real32)(panel->inner.x1 - panel->inner.x0);
-    h = (real32)(panel->inner.y1 - panel->inner.y0);
+    w = (f32)(panel->inner.x1 - panel->inner.x0);
+    h = (f32)(panel->inner.y1 - panel->inner.y0);
     
     target_x = 0;
     if (cursor_x < target_x){
-        target_x = (real32)Max(0, cursor_x - w*.5f);
+        target_x = (f32)Max(0, cursor_x - w*.5f);
     }
     else if (cursor_x >= target_x + w){
-        target_x = (real32)(cursor_x - w*.5f);
+        target_x = (f32)(cursor_x - w*.5f);
     }
     
-    target_y = (real32)FLOOR32(cursor_y - h*.5f);
+    target_y = (f32)FLOOR32(cursor_y - h*.5f);
     if (target_y < 0) target_y = 0;
     
     view->target_x = target_x;
@@ -2257,6 +2283,7 @@ enum History_Mode{
 internal void
 file_update_history_before_edit(Mem_Options *mem, Editing_File *file, Edit_Step step, u8 *str,
                                 History_Mode history_mode){
+    if (!file->undo.undo.edits) return;
 #if BUFFER_EXPERIMENT_SCALPEL <= 1
     General_Memory *general = &mem->general;
     
@@ -2443,30 +2470,28 @@ inline void
 file_pre_edit_maintenance(Editing_File *file){
     if (file->still_lexing)
         system_cancel_job(BACKGROUND_THREADS, file->lex_job);
-    
     file->last_4ed_edit_time = system_get_now();
 }
 
 internal void
 file_do_single_edit(Mem_Options *mem, Editing_File *file,
                     Editing_Layout *layout, Edit_Spec spec, History_Mode history_mode){
-    Assert(file);
     ProfileMomentFunction();
     
     // NOTE(allen): fixing stuff beforewards????
     file_update_history_before_edit(mem, file, spec.step, spec.str, history_mode);
     file_pre_edit_maintenance(file);
 
-#if BUFFER_EXPERIMENT_SCALPEL <= 1    
     // NOTE(allen): actual text replacement
+#if BUFFER_EXPERIMENT_SCALPEL <= 2
+    i32 shift_amount = 0;
     General_Memory *general = &mem->general;
 
+    char *str = (char*)spec.str;
     i32 start = spec.step.edit.start;
     i32 end = spec.step.edit.end;
-    char *str = (char*)spec.str;
     i32 str_len = spec.step.edit.len;
 
-    i32 shift_amount = 0;
     i32 request_amount = 0;
     while (buffer_replace_range(&file->buffer, start, end, str, str_len, &shift_amount, &request_amount)){
         void *new_data = 0;
@@ -2476,22 +2501,20 @@ file_do_single_edit(Mem_Options *mem, Editing_File *file,
         void *old_data = buffer_edit_provide_memory(&file->buffer, new_data, request_amount);
         if (old_data) general_memory_free(general, old_data);
     }
-    
-#if BUFFER_EXPERIMENT_SCALPEL <= 0
-    // NOTE(allen): fixing stuff afterwards
-    if (file->tokens_exist)
-        file_relex_parallel(mem, file, start, end, shift_amount);
+
+#if BUFFER_EXPERIMENT_SCALPEL == 2
+    buffer_mugab_check(&file->buffer);
 #endif
     
     i32 line_start = buffer_get_line_index(&file->buffer, start);
     i32 line_end = buffer_get_line_index(&file->buffer, end);
     i32 replaced_line_count = line_end - line_start;
-    i32 new_line_count = file_count_newlines(file, start, start+str_len);
+    i32 new_line_count = buffer_count_newlines(&file->buffer, start, start+str_len);
     i32 line_shift =  new_line_count - replaced_line_count;
     
-    file_remeasure_starts(general, file, line_start, line_end, line_shift, shift_amount);
-    file_remeasure_widths(general, file, file->font, line_start, line_end, line_shift);
-
+    file_remeasure_starts(general, &file->buffer, line_start, line_end, line_shift, shift_amount);
+    file_remeasure_widths(general, &file->buffer, file->font, line_start, line_end, line_shift);
+        
     i32 panel_count = layout->panel_count;
     Panel *current_panel = layout->panels;
     for (i32 i = 0; i < panel_count; ++i, ++current_panel){
@@ -2500,7 +2523,15 @@ file_do_single_edit(Mem_Options *mem, Editing_File *file,
             view_measure_wraps(general, current_view);
         }
     }
+#endif
+    
+#if BUFFER_EXPERIMENT_SCALPEL <= 0
+    // NOTE(allen): fixing stuff afterwards
+    if (file->tokens_exist)
+        file_relex_parallel(mem, file, start, end, shift_amount);
+#endif
 
+#if BUFFER_EXPERIMENT_SCALPEL <= 1
     Temp_Memory cursor_temp = begin_temp_memory(&mem->part);
     i32 cursor_max = layout->panel_max_count * 2;
     Cursor_With_Index *cursors = push_array(&mem->part, Cursor_With_Index, cursor_max);
@@ -2541,6 +2572,7 @@ file_do_single_edit(Mem_Options *mem, Editing_File *file,
 internal void
 view_do_white_batch_edit(Mem_Options *mem, File_View *view, Editing_File *file,
                          Editing_Layout *layout, Edit_Spec spec, History_Mode history_mode){
+    if (view->locked) return;
 #if BUFFER_EXPERIMENT_SCALPEL <= 1
     Assert(file);
     ProfileMomentFunction();
@@ -2652,6 +2684,7 @@ view_do_white_batch_edit(Mem_Options *mem, File_View *view, Editing_File *file,
 inline void
 view_replace_range(Mem_Options *mem, File_View *view, Editing_Layout *layout,
                    i32 start, i32 end, u8 *str, i32 len, i32 next_cursor){
+    if (view->locked) return;
     Edit_Spec spec = {};
     spec.step.type = ED_NORMAL;
     spec.step.edit.start =  start;
@@ -2663,7 +2696,7 @@ view_replace_range(Mem_Options *mem, File_View *view, Editing_Layout *layout,
     file_do_single_edit(mem, view->file, layout, spec, hist_normal);
 }
 
-internal void
+inline void
 view_post_paste_effect(File_View *view, i32 ticks, i32 start, i32 size, u32 color){
     view->paste_effect.start = start;
     view->paste_effect.end = start + size;
@@ -2675,6 +2708,7 @@ view_post_paste_effect(File_View *view, i32 ticks, i32 start, i32 size, u32 colo
 internal void
 view_undo_redo(Mem_Options *mem, Editing_Layout *layout, File_View *view, Editing_File *file,
                Edit_Stack *stack, Edit_Type expected_type){
+    if (view->locked) return;
     if (file && stack->edit_count > 0){
         Edit_Step step = stack->edits[stack->edit_count-1];
         
@@ -2717,9 +2751,11 @@ view_redo(Mem_Options *mem, Editing_Layout *layout, File_View *view){
 
 internal void
 view_history_step(Mem_Options *mem, Editing_Layout *layout, File_View *view, History_Mode history_mode){
+    if (view->locked) return;
     Assert(history_mode != hist_normal);
     
     Editing_File *file = view->file;
+    
     bool32 do_history_step = 0;
     Edit_Step step = {};
     if (history_mode == hist_backward){
@@ -2768,7 +2804,7 @@ view_history_step(Mem_Options *mem, Editing_Layout *layout, File_View *view, His
     }
 }
 
-// TODO(allen): should these still be view operations?
+// TODO(allen): write these as streamed operations
 internal i32
 view_find_end_of_line(File_View *view, i32 pos){
 #if BUFFER_EXPERIMENT_SCALPEL <= 0
@@ -2871,9 +2907,11 @@ working_set_clipboard_roll_down(Working_Set *working){
 inline Editing_File*
 working_set_contains(Working_Set *working, String filename){
     Editing_File *result = 0;
-    i32 index;
-    if (table_find(&working->table, filename, &index)){
-        result = working->files + index;
+    i32 id;
+    if (table_find(&working->table, filename, &id)){
+        if (id < working->file_max_count){
+            result = working->files + id;
+        }
     }
     return result;
 }
@@ -2894,7 +2932,7 @@ working_set_lookup_file(Working_Set *working_set, String string){
 		}
         if (file_i == end) file = 0;
 	}
-	
+    
 	return file;
 }
 
@@ -3194,6 +3232,44 @@ view_auto_tab_tokens(Mem_Options *mem, File_View *view, Editing_Layout *layout,
 #endif
 }
 
+struct Get_Link_Result{
+    b32 in_link;
+    i32 index;
+};
+
+internal Get_Link_Result
+get_link(Hyper_Link *links, i32 link_count, i32 pos){
+    Get_Link_Result result = {};
+    // TODO TODO TODO TODO TODO TODO TODO TODO
+    return result;
+}
+
+internal u32*
+style_get_link_color(Style *style, Link_Type type){
+	u32 *result;
+    switch (type){
+    case link_result:
+        result = &style->main.result_link_color;
+        break;
+        
+    case link_related:
+        result = &style->main.related_link_color;
+        break;
+
+    case link_error:
+        result = &style->main.error_link_color;
+        break;
+        
+    case link_warning:
+        result = &style->main.warning_link_color;
+        break;
+        
+    default:
+        result = &style->main.default_color;
+    }
+    return result;
+}
+
 internal u32*
 style_get_color(Style *style, Cpp_Token token){
 	u32 *result;
@@ -3503,16 +3579,16 @@ step_file_view(Thread_Context *thread, View *view_, i32_Rect rect,
     Style *style = view->style;
     Font *font = style->font;
     
-    real32 line_height = (real32)font->height;
-    real32 cursor_y = view_get_cursor_y(view);
-    real32 target_y = view->target_y;
-    real32 max_y = view_compute_height(view) - line_height*2;
+    f32 line_height = (f32)font->height;
+    f32 cursor_y = view_get_cursor_y(view);
+    f32 target_y = view->target_y;
+    f32 max_y = view_compute_height(view) - line_height*2;
     i32 lowest_line = view_compute_lowest_line(view);
-    real32 max_target_y = view_compute_max_target_y(lowest_line, font->height, max_y);
-    real32 delta_y = 3.f*line_height;
-    real32 extra_top = 0.f;
+    f32 max_target_y = view_compute_max_target_y(lowest_line, font->height, max_y);
+    f32 delta_y = 3.f*line_height;
+    f32 extra_top = 0.f;
     extra_top += view_widget_height(view, font);
-    real32 taken_top_space = line_height + extra_top;
+    f32 taken_top_space = line_height + extra_top;
     
     if (user_input->mouse.my < rect.y0 + taken_top_space){
         view_->mouse_cursor_type = APP_MOUSE_CURSOR_ARROW;
@@ -3595,7 +3671,7 @@ step_file_view(Thread_Context *thread, View *view_, i32_Rect rect,
     if (!is_active) view_set_widget(view, FWIDG_NONE);
 
     // NOTE(allen): framely undo stuff
-    {
+    if (file){
         i32 scrub_max = view->scrub_max;
         i32 undo_count, redo_count, total_count;
         undo_count = file->undo.undo.edit_count;
@@ -3740,12 +3816,27 @@ draw_file_view(Thread_Context *thread, View *view_, i32_Rect rect, bool32 is_act
     i32 max_x = rect.x1 - rect.x0;
     i32 max_y = rect.y1 - rect.y0 + font->height;
     
-    Assert(file && buffer_good(&file->buffer) && !file->is_dummy);
+    Assert(file && !file->is_dummy && buffer_good(&file->buffer));
 
     Opaque_Font_Advance opad = get_opaque_font_advance(font);
-    b32 tokens_use = file->tokens_complete && (file->token_stack.count > 0);
-    Cpp_Token_Stack token_stack = file->token_stack;
-
+    b32 tokens_use = 0;
+    Cpp_Token_Stack token_stack = {};
+    if (file){
+        tokens_use = file->tokens_complete && (file->token_stack.count > 0);
+        token_stack = file->token_stack;
+    }
+    
+    b32 links_use = 0;
+    Hyper_Link *links = 0;
+    i32 link_count = 0;
+    if (view->links){
+        if (view->link_count > 0){
+            links_use = 1;
+            links = view->links;
+            link_count = view->link_count;
+        }
+    }
+    
     Partition *part = &view_->mem->part;
     Temp_Memory temp = begin_temp_memory(part);
     
@@ -3775,17 +3866,38 @@ draw_file_view(Thread_Context *thread, View *view_, i32_Rect rect, bool32 is_act
     }
     
     i32 token_i = 0;
+    i32 link_i = 0;
     u32 main_color = style->main.default_color;
+    u32 link_color = 0;
     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;
     }
+    if (links_use){
+        Get_Link_Result result = get_link(links, link_count, items->index);
+        if (result.in_link){
+            link_color = *style_get_link_color(style, links[result.index].link_type);
+        }
+        link_i = result.index;
+    }
     
     u32 mark_color = style->main.mark_color;
     Buffer_Render_Item *item = items;
     i32 prev_ind = -1;
-    u32 highlight_color = 0; AllowLocal(highlight_color);
+    u32 highlight_color = 0;
+    
+    u32 chunk_highlights[] = {
+        0x22FF0000,
+        0x22FFFF00,
+        0x2200FF00,
+        0x2200FFFF,
+        0x220000FF,
+        0x22FF00FF
+    };
+
+    i32 current_chunk = item->chunk_i;
+    u32 chunk_highlight = chunk_highlights[current_chunk % ArrayCount(chunk_highlights)];
     for (i32 i = 0; i < count; ++i, ++item){
         i32 ind = item->index;
         if (tokens_use && ind != prev_ind){
@@ -3810,11 +3922,22 @@ draw_file_view(Thread_Context *thread, View *view_, i32_Rect rect, bool32 is_act
         }
         u32 char_color = main_color;
         
+        if (item->chunk_i > current_chunk){
+            current_chunk = item->chunk_i;
+            chunk_highlight = chunk_highlights[current_chunk % ArrayCount(chunk_highlights)];
+        }
+        
         if (cursor_begin <= ind && ind < cursor_end && (ind != prev_ind || cursor_begin < ind)){
             if (is_active) draw_rectangle(target, f32R(item->x0, item->y0, item->x1, item->y1), cursor_color);
             else draw_rectangle_outline(target, f32R(item->x0, item->y0, item->x1, item->y1), cursor_color);
             char_color = at_cursor_color;
         }
+        else if (highlight_color){
+            draw_rectangle(target, f32R(item->x0, item->y0, item->x1, item->y1), highlight_color);
+        }
+        else if  (chunk_highlight){
+            draw_rectangle(target, f32R(item->x0, item->y0, item->x1, item->y1), chunk_highlight);
+        }
         
         u32 fade_color = 0xFFFF00FF;
         f32 fade_amount = 0.f;
@@ -3859,6 +3982,7 @@ draw_file_view(Thread_Context *thread, View *view_, i32_Rect rect, bool32 is_act
         switch (view->widget.type){
         case FWIDG_TIMELINES:
         {
+            Assert(file);
             if (view->widget.timeline.undo_line){
                 do_button(1, &state, &layout, "- Undo", 1);
                 
@@ -3925,18 +4049,20 @@ draw_file_view(Thread_Context *thread, View *view_, i32_Rect rect, bool32 is_act
         
         intbar_draw_string(target, &bar, line_number, base_color);
 
-        switch (buffer_get_sync(file)){
-        case SYNC_BEHIND_OS:
-        {
-            persist String out_of_sync = make_lit_string(" BEHIND OS");
-            intbar_draw_string(target, &bar, out_of_sync, bar.style.pop2_color);
-        }break;
+        if (file){
+            switch (buffer_get_sync(file)){
+            case SYNC_BEHIND_OS:
+            {
+                persist String out_of_sync = make_lit_string(" BEHIND OS");
+                intbar_draw_string(target, &bar, out_of_sync, bar.style.pop2_color);
+            }break;
         
-        case SYNC_UNSAVED:
-        {
-            persist String out_of_sync = make_lit_string(" *");
-            intbar_draw_string(target, &bar, out_of_sync, bar.style.pop2_color);
-        }break;
+            case SYNC_UNSAVED:
+            {
+                persist String out_of_sync = make_lit_string(" *");
+                intbar_draw_string(target, &bar, out_of_sync, bar.style.pop2_color);
+            }break;
+            }
         }
     }
     
@@ -3944,7 +4070,7 @@ draw_file_view(Thread_Context *thread, View *view_, i32_Rect rect, bool32 is_act
 }
 
 internal void
-kill_buffer(General_Memory *general, Editing_File *file, Live_Views *live_set, Editing_Layout *layout){
+kill_file(General_Memory *general, Editing_File *file, Live_Views *live_set, Editing_Layout *layout){
     i32 panel_count = layout->panel_count;
     Panel *panels = layout->panels, *panel;
     panel = panels;
@@ -3963,7 +4089,6 @@ kill_buffer(General_Memory *general, Editing_File *file, Live_Views *live_set, E
         }
         ++panel;
     }
-    
     file_close(general, file);
     file_get_dummy(file);
 }
@@ -4098,9 +4223,11 @@ HANDLE_COMMAND_SIG(handle_command_file_view){
 }
 
 inline void
-free_file_view(View *view_){
-    File_View *view = (File_View*)view_;
-    general_memory_free(&view_->mem->general, view->line_wrap_y);
+free_file_view(View *view){
+    File_View *fview = (File_View*)view;
+    general_memory_free(&view->mem->general, fview->line_wrap_y);
+    if (fview->links)
+        general_memory_free(&view->mem->general, fview->links);
 }
 
 internal
@@ -4129,13 +4256,12 @@ DO_VIEW_SIG(do_file_view){
 }
 
 internal File_View*
-file_view_init(View *view, Delay *delay, Editing_Layout *layout){
+file_view_init(View *view, Editing_Layout *layout){
     view->type = VIEW_TYPE_FILE;
     view->do_view = do_file_view;
     view->handle_command = handle_command_file_view;
     
     File_View *result = (File_View*)view;
-    result->delay = delay;
     result->layout = layout;
     result->rewind_max = 4;
     result->scrub_max = 1;
diff --git a/4ed_style.cpp b/4ed_style.cpp
index 0f818a59..8097f94c 100644
--- a/4ed_style.cpp
+++ b/4ed_style.cpp
@@ -143,7 +143,10 @@ struct Style_Main_Data{
 	u32 highlight_white_color;
     u32 paste_color;
     u32 undo_color;
-    u32 next_undo_color;
+    u32 result_link_color;
+    u32 related_link_color;
+    u32 error_link_color;
+    u32 warning_link_color;
     Interactive_Style file_info_style;
 };
 
@@ -186,6 +189,10 @@ enum Style_Color_Tag{
     STAG_PASTE_COLOR,
     STAG_UNDO_COLOR,
     STAG_NEXT_UNDO_COLOR,
+    STAG_RESULT_LINK_COLOR,
+    STAG_RELATED_LINK_COLOR,
+    STAG_ERROR_LINK_COLOR,
+    STAG_WARNING_LINK_COLOR,
     // never below this
     STAG_COUNT
 };
@@ -350,7 +357,6 @@ style_form_convert(Style_File_Format_v4 *o, Style_File_Format_v3 *i){
     o->main.highlight_white_color = i->main.highlight_white_color;
     o->main.paste_color = i->main.paste_color;
     o->main.undo_color = i->main.paste_color ^ 0x00FFFFFF;
-    o->main.next_undo_color = i->main.paste_color ^ 0x00FFFFFF;
     o->main.file_info_style = i->main.file_info_style;
     o->main.file_info_style.bar_active_color = i->main.file_info_style.bar_color;
 }
@@ -395,7 +401,11 @@ style_index_by_tag(Style *s, u32 tag){
         
     case STAG_PASTE_COLOR: result = &s->main.paste_color; break;
     case STAG_UNDO_COLOR: result = &s->main.undo_color; break;
-    case STAG_NEXT_UNDO_COLOR: result = &s->main.next_undo_color; break;
+        
+    case STAG_RESULT_LINK_COLOR: result = &s->main.result_link_color; break;
+    case STAG_RELATED_LINK_COLOR: result = &s->main.related_link_color; break;
+    case STAG_ERROR_LINK_COLOR: result = &s->main.error_link_color; break;
+    case STAG_WARNING_LINK_COLOR: result = &s->main.warning_link_color; break;
     }
     return result;
 }
diff --git a/buffer/4coder_buffer_abstract.cpp b/buffer/4coder_buffer_abstract.cpp
index aa38cc86..2e92ea39 100644
--- a/buffer/4coder_buffer_abstract.cpp
+++ b/buffer/4coder_buffer_abstract.cpp
@@ -131,7 +131,7 @@ buffer_seek_whitespace_up(Buffer_Type *buffer, int pos){
     int no_hard;
     
     size = buffer_size(buffer);
-    loop = buffer_backify_loop(buffer, pos, 1);
+    loop = buffer_backify_loop(buffer, pos-1, 1);
     
     for (;buffer_backify_good(&loop);
          buffer_backify_next(&loop)){
@@ -245,18 +245,22 @@ buffer_seek_alphanumeric_right(Buffer_Type *buffer, int pos){
          buffer_stringify_next(&loop)){
         end = loop.size + loop.absolute_pos;
         data = loop.data - loop.absolute_pos;
-        for (; pos < end && is_alphanumeric_true(data[pos]); ++pos);
-        if (!is_alphanumeric_true(data[pos])) break;
+        for (; pos < end; ++pos){
+            if (!is_alphanumeric_true(data[pos])) goto buffer_seek_alphanumeric_right_mid;
+        }
     }
     
+buffer_seek_alphanumeric_right_mid:
     for (;buffer_stringify_good(&loop);
          buffer_stringify_next(&loop)){
         end = loop.size + loop.absolute_pos;
         data = loop.data - loop.absolute_pos;
-        for (; pos < end && !is_alphanumeric_true(data[pos]); ++pos);
-        if (is_alphanumeric_true(data[pos])) break;
+        for (; pos < end; ++pos){
+            if (is_alphanumeric_true(data[pos])) goto buffer_seek_alphanumeric_right_end;
+        }
     }
     
+buffer_seek_alphanumeric_right_end:
     return(pos);
 }
 
@@ -276,16 +280,19 @@ buffer_seek_alphanumeric_left(Buffer_Type *buffer, int pos){
              buffer_backify_next(&loop)){
             end = loop.absolute_pos;
             data = loop.data - end;
-            for (; pos >= end && !is_alphanumeric_true(data[pos]); --pos);
-            if (is_alphanumeric_true(data[pos])) break;
+            for (; pos >= end; --pos){
+                if (is_alphanumeric_true(data[pos])) goto buffer_seek_alphanumeric_left_mid;
+            }
         }
         
+buffer_seek_alphanumeric_left_mid:
         for (;buffer_backify_good(&loop);
              buffer_backify_next(&loop)){
             end = loop.absolute_pos;
             data = loop.data - end;
-            for (; pos >= end && is_alphanumeric_true(data[pos]); --pos);
-            if (!is_alphanumeric_true(data[pos])) break;
+            for (; pos >= end; --pos){
+                if (!is_alphanumeric_true(data[pos])) goto buffer_seek_alphanumeric_left_end;
+            }
         }
         
         ++pos;
@@ -294,6 +301,7 @@ buffer_seek_alphanumeric_left(Buffer_Type *buffer, int pos){
         pos = 0;
     }
     
+buffer_seek_alphanumeric_left_end:
     return(pos);
 }
 
@@ -1069,6 +1077,9 @@ buffer_get_render_data(Buffer_Type *buffer, float *wraps, Buffer_Render_Item *it
             switch (ch){
             case '\n':
                 write_render_item_inline(item, i, ' ', x, y, advance_data, stride, font_height);
+#if BUFFER_EXPERIMENT_SCALPEL == 2
+                item->chunk_i = loop.chunk_i*2 + ((loop.pos >= buffer->gaps[loop.chunk_i].size1)?1:0);
+#endif
                 ++item_i;
                 ++item;
                 
@@ -1078,11 +1089,17 @@ buffer_get_render_data(Buffer_Type *buffer, float *wraps, Buffer_Render_Item *it
 
             case 0:
                 ch_width = write_render_item_inline(item, i, '\\', x, y, advance_data, stride, font_height);
+#if BUFFER_EXPERIMENT_SCALPEL == 2
+                item->chunk_i = loop.chunk_i*2 + ((loop.pos >= buffer->gaps[loop.chunk_i].size1)?1:0);
+#endif
                 ++item_i;
                 ++item;
                 x += ch_width;
 
                 ch_width = write_render_item_inline(item, i, '0', x, y, advance_data, stride, font_height);
+#if BUFFER_EXPERIMENT_SCALPEL == 2
+                item->chunk_i = loop.chunk_i*2 + ((loop.pos >= buffer->gaps[loop.chunk_i].size1)?1:0);
+#endif
                 ++item_i;
                 ++item;
                 x += ch_width;
@@ -1090,11 +1107,17 @@ buffer_get_render_data(Buffer_Type *buffer, float *wraps, Buffer_Render_Item *it
 
             case '\r':
                 ch_width = write_render_item_inline(item, i, '\\', x, y, advance_data, stride, font_height);
+#if BUFFER_EXPERIMENT_SCALPEL == 2
+                item->chunk_i = loop.chunk_i*2 + ((loop.pos >= buffer->gaps[loop.chunk_i].size1)?1:0);
+#endif
                 ++item_i;
                 ++item;
                 x += ch_width;
 
                 ch_width = write_render_item_inline(item, i, 'r', x, y, advance_data, stride, font_height);
+#if BUFFER_EXPERIMENT_SCALPEL == 2
+                item->chunk_i = loop.chunk_i*2 + ((loop.pos >= buffer->gaps[loop.chunk_i].size1)?1:0);
+#endif
                 ++item_i;
                 ++item;
                 x += ch_width;
@@ -1102,10 +1125,16 @@ buffer_get_render_data(Buffer_Type *buffer, float *wraps, Buffer_Render_Item *it
 
             case '\t':
                 ch_width_sub = write_render_item_inline(item, i, '\\', x, y, advance_data, stride, font_height);
+#if BUFFER_EXPERIMENT_SCALPEL == 2
+                item->chunk_i = loop.chunk_i*2 + ((loop.pos >= buffer->gaps[loop.chunk_i].size1)?1:0);
+#endif
                 ++item_i;
                 ++item;
 
                 write_render_item_inline(item, i, 't', x + ch_width_sub, y, advance_data, stride, font_height);
+#if BUFFER_EXPERIMENT_SCALPEL == 2
+                item->chunk_i = loop.chunk_i*2 + ((loop.pos >= buffer->gaps[loop.chunk_i].size1)?1:0);
+#endif
                 ++item_i;
                 ++item;
                 x += ch_width;
@@ -1113,9 +1142,13 @@ buffer_get_render_data(Buffer_Type *buffer, float *wraps, Buffer_Render_Item *it
 
             default:
                 write_render_item(item, i, ch, x, y, ch_width, font_height);
+#if BUFFER_EXPERIMENT_SCALPEL == 2
+                item->chunk_i = loop.chunk_i*2 + ((loop.pos >= buffer->gaps[loop.chunk_i].size1)?1:0);
+#endif
                 ++item_i;
                 ++item;
                 x += ch_width;
+                
                 break;
             }
             if (y > height + shift_y) goto buffer_get_render_data_end;
@@ -1127,6 +1160,9 @@ buffer_get_render_data_end:
         ch = 0;
         ch_width = measure_character(advance_data, stride, ' ');
         write_render_item(item, size, ch, x, y, ch_width, font_height);
+#if BUFFER_EXPERIMENT_SCALPEL == 2
+        item->chunk_i = -1;
+#endif
         ++item_i;
         ++item;
         x += ch_width;
diff --git a/buffer/4coder_gap_buffer.cpp b/buffer/4coder_gap_buffer.cpp
index 58d49f58..654399c5 100644
--- a/buffer/4coder_gap_buffer.cpp
+++ b/buffer/4coder_gap_buffer.cpp
@@ -110,25 +110,6 @@ buffer_end_init(Gap_Buffer_Init *init){
     return(result);
 }
 
-internal_4tech void*
-buffer_edit_provide_memory(Gap_Buffer *buffer, void *new_data, int new_max){
-    void *result;
-    int new_gap_size;
-    
-    assert_4tech(new_max >= buffer_size(buffer));
-    
-    result = buffer->data;
-    new_gap_size = new_max - buffer_size(buffer);
-    memcpy_4tech(new_data, buffer->data, buffer->size1);
-    memcpy_4tech((char*)new_data + buffer->size1 + new_gap_size, buffer->data + buffer->size1 + buffer->gap_size, buffer->size2);
-    
-    buffer->data = (char*)new_data;
-    buffer->gap_size = new_gap_size;
-    buffer->max = new_max;
-    
-    return(result);
-}
-
 typedef struct{
     Gap_Buffer *buffer;
     char *data, *base;
@@ -334,5 +315,24 @@ buffer_batch_edit_step(Buffer_Batch_State *state, Gap_Buffer *buffer, Buffer_Edi
     return(result);
 }
 
+internal_4tech void*
+buffer_edit_provide_memory(Gap_Buffer *buffer, void *new_data, int new_max){
+    void *result;
+    int new_gap_size;
+    
+    assert_4tech(new_max >= buffer_size(buffer));
+    
+    result = buffer->data;
+    new_gap_size = new_max - buffer_size(buffer);
+    memcpy_4tech(new_data, buffer->data, buffer->size1);
+    memcpy_4tech((char*)new_data + buffer->size1 + new_gap_size, buffer->data + buffer->size1 + buffer->gap_size, buffer->size2);
+    
+    buffer->data = (char*)new_data;
+    buffer->gap_size = new_gap_size;
+    buffer->max = new_max;
+    
+    return(result);
+}
+
 // BOTTOM
 
diff --git a/buffer/4coder_golden_array.cpp b/buffer/4coder_golden_array.cpp
index 6d893f7f..2e7592eb 100644
--- a/buffer/4coder_golden_array.cpp
+++ b/buffer/4coder_golden_array.cpp
@@ -92,20 +92,6 @@ buffer_end_init(Buffer_Init *init){
     return(result);
 }
 
-internal_4tech void*
-buffer_edit_provide_memory(Buffer *buffer, void *new_data, int new_max){
-    void *result;
-    
-    assert_4tech(new_max >= buffer->size);
-    
-    result = buffer->data;
-    memcpy_4tech(new_data, buffer->data, buffer->size);
-    buffer->data = (char*)new_data;
-    buffer->max = new_max;
-    
-    return(result);
-}
-
 typedef struct{
     Buffer *buffer;
     char *data, *end;
@@ -226,5 +212,19 @@ buffer_batch_edit_step(Buffer_Batch_State *state, Buffer *buffer, Buffer_Edit *s
     return(result);
 }
 
+internal_4tech void*
+buffer_edit_provide_memory(Buffer *buffer, void *new_data, int new_max){
+    void *result;
+    
+    assert_4tech(new_max >= buffer->size);
+    
+    result = buffer->data;
+    memcpy_4tech(new_data, buffer->data, buffer->size);
+    buffer->data = (char*)new_data;
+    buffer->max = new_max;
+    
+    return(result);
+}
+
 // BOTTOM
 
diff --git a/buffer/4coder_multi_gap_buffer.cpp b/buffer/4coder_multi_gap_buffer.cpp
index 62abc9b7..25ad00d1 100644
--- a/buffer/4coder_multi_gap_buffer.cpp
+++ b/buffer/4coder_multi_gap_buffer.cpp
@@ -28,6 +28,7 @@ typedef struct{
 typedef struct{
     Fixed_Width_Gap_Buffer *gaps;
     int chunk_count;
+    int chunk_alloced;
     int chunk_max;
     int size;
     
@@ -37,6 +38,9 @@ typedef struct{
     int widths_count;
     int line_max;
     int widths_max;
+    
+    int grow_gaps;
+    int edit_stage;
 } Multi_Gap_Buffer;
 
 inline_4tech int
@@ -59,9 +63,9 @@ typedef struct{
     int size;
     int chunk_i;
     int chunk_count;
+    int chunk_alloc;
 } Multi_Gap_Buffer_Init;
 
-
 internal_4tech Multi_Gap_Buffer_Init
 buffer_begin_init(Multi_Gap_Buffer *buffer, char *data, int size){
     Multi_Gap_Buffer_Init init;
@@ -69,7 +73,9 @@ buffer_begin_init(Multi_Gap_Buffer *buffer, char *data, int size){
     init.data = data;
     init.size = size;
     init.chunk_i = 0;
-    init.chunk_count = div_ceil_4tech(size, fixed_width_buffer_half_size);
+    init.chunk_alloc = div_ceil_4tech(size, fixed_width_buffer_half_size);
+    init.chunk_count = init.chunk_alloc;
+    if (init.chunk_alloc < 4) init.chunk_alloc = 4;
     return(init);
 }
 
@@ -77,7 +83,7 @@ internal_4tech int
 buffer_init_need_more(Multi_Gap_Buffer_Init *init){
     int result;
     result = 1;
-    if (init->buffer->gaps && init->chunk_i == init->chunk_count)
+    if (init->buffer->gaps && init->chunk_i == init->chunk_alloc)
         result = 0;
     return(result);
 }
@@ -88,7 +94,7 @@ buffer_init_page_size(Multi_Gap_Buffer_Init *init){
     int result;
     buffer = init->buffer;
     if (buffer->gaps) result = fixed_width_buffer_size;
-    else result = init->chunk_count * 2 * sizeof(*buffer->gaps);
+    else result = init->chunk_alloc * 2 * sizeof(*buffer->gaps);
     return(result);
 }
 
@@ -123,12 +129,14 @@ buffer_end_init(Multi_Gap_Buffer_Init *init){
     if (buffer->gaps){
         if (buffer->chunk_max >= div_ceil_4tech(init->size, fixed_width_buffer_half_size)){
             buffer->chunk_count = init->chunk_count;
+            if (buffer->chunk_count == 0) buffer->chunk_count = 1;
+            buffer->chunk_alloced = init->chunk_alloc;
             result = 1;
             
             data = init->data;
             total_size = init->size;
             gap = buffer->gaps;
-            count = init->chunk_count;
+            count = buffer->chunk_count;
             size = fixed_width_buffer_half_size;
             pos = 0;
             start_pos = 0;
@@ -151,7 +159,7 @@ buffer_end_init(Multi_Gap_Buffer_Init *init){
                     gap->size2 = size2;
                     gap->gap_size = fixed_width_buffer_size - size1 - size2;
                     memmove_4tech(gap->data + size1 + gap->gap_size, gap->data + size1, size2);
-
+                    
                     gap->start_pos = start_pos;
                     start_pos += size1 + size2;
                 }
@@ -171,25 +179,24 @@ internal_4tech int
 buffer_find_chunk(Multi_Gap_Buffer *buffer, int pos){
     Fixed_Width_Gap_Buffer *gaps;
     int start, end, m, this_pos;
-
-    if (pos == buffer_size(buffer)){
-        m = buffer->chunk_count;
-    }
-    else{
-        gaps = buffer->gaps;
-        start = 0;
-        end = buffer->chunk_count;
-        for(;;){
-            m = (start + end) / 2;
-            this_pos = gaps[m].start_pos;
-            if (this_pos < pos) start = m;
-            else if (this_pos > pos) end = m;
-            else break;
-            if (start+1 == end){
-                m = start; break;
-            }
-            assert_4tech(start < end);
+    
+    gaps = buffer->gaps;
+    start = 0;
+    end = buffer->chunk_count;
+    for(;;){
+        m = (start + end) / 2;
+        this_pos = gaps[m].start_pos;
+        if (this_pos < pos) start = m;
+        else if (this_pos > pos) end = m;
+        else{
+            --m;
+            if (m < 0) m = 0;
+            break;
         }
+        if (start+1 == end){
+            m = start; break;
+        }
+        assert_4tech(start < end);
     }
     
     return(m);
@@ -222,7 +229,7 @@ buffer_stringify_loop(Multi_Gap_Buffer *buffer, int start, int end){
         
         gap = result.gaps + result.chunk_end;
         end -= gap->start_pos;
-        if (end < gap->size1) result.end = end;
+        if (end <= gap->size1) result.end = end;
         else result.end = end + gap->gap_size;
         
         gap = result.gaps + result.chunk_i;
@@ -272,6 +279,10 @@ buffer_stringify_next(Multi_Gap_Buffer_Stringify_Loop *loop){
             loop->pos = 0;
             loop->absolute_pos = gap->start_pos;
             temp_end = gap->size1;
+            if (gap->size1 == 0){
+                loop->pos = gap->gap_size;
+                temp_end = fixed_width_buffer_size;
+            }
         }
         if (loop->chunk_i == loop->chunk_end && temp_end > loop->end) temp_end = loop->end;
         loop->size = temp_end - loop->pos;
@@ -301,7 +312,7 @@ buffer_backify_loop(Multi_Gap_Buffer *buffer, int start, int end){
         result.buffer = buffer;
         result.gaps = buffer->gaps;
         
-        result.chunk_i = buffer_find_chunk(buffer, start);
+        result.chunk_i = buffer_find_chunk(buffer, start-1);
         result.chunk_end = buffer_find_chunk(buffer, end);
         
         gap = result.gaps + result.chunk_end;
@@ -369,12 +380,20 @@ buffer_backify_next(Multi_Gap_Buffer_Backify_Loop *loop){
 
 internal_4tech int
 buffer_replace_range(Multi_Gap_Buffer *buffer, int start, int end, char *str, int len, int *shift_amount_out, int *request_amount){
-    Fixed_Width_Gap_Buffer *gaps, *gap;
+    Fixed_Width_Gap_Buffer *gaps, *gap, *dgap;
+    char *data;
+    int move_size;
     int gap_start, gap_end;
     int result;
     int size;
     int local_end;
     int shift_amount;
+    int required_empty_buffers;
+    int supplanted_gaps;
+    int dpos;
+    int head_size, middle_size, tail_size;
+    int mem_pos, local_start_pos;
+    debug_4tech(int osize);
     
     size = buffer_size(buffer);
     assert_4tech(0 <= start);
@@ -386,35 +405,58 @@ buffer_replace_range(Multi_Gap_Buffer *buffer, int start, int end, char *str, in
     gaps = buffer->gaps;
     gap_start = buffer_find_chunk(buffer, start);
     gap_end = buffer_find_chunk(buffer, end);
-
-    gap = gaps + gap_start;
-    if (gap_start < gap_end){
-        memmove_4tech(gap + 1, gaps + gap_end, sizeof(*gaps)*(buffer->chunk_count - gap_end));
-        buffer->chunk_count -= (gap_end - gap_start + 1);
-        ++gap;
-        
-        local_end = end - gap->start_pos;
-        
-        if (gap->size1 >= local_end){
-            gap->size2 -= (local_end - gap->size1);
-            gap->size1 = 0;
+    
+    if (buffer->edit_stage == 0){
+        buffer->size += *shift_amount_out;
+        for (gap = gaps + gap_end + 1;
+             gap < gaps + buffer->chunk_count;
+             ++gap){
+            gap->start_pos += *shift_amount_out;
         }
-        else{
-            memmove_4tech(gap->data, gap->data + local_end, gap->size1 - local_end);
-            gap->size1 -= local_end;
-        }
-
-        --gap;
+        buffer->edit_stage = 1;
+    }
+    
+    gap = gaps + gap_start;
+    if (buffer->edit_stage == 1){
+        if (gap_start < gap_end && gap_start+1 < buffer->chunk_count){
+            supplanted_gaps = gap_end - gap_start + 1;
+            if (buffer->chunk_max - buffer->chunk_alloced >= supplanted_gaps){
+                ++gap;
+                memcpy_4tech(gaps + buffer->chunk_alloced, gap, sizeof(*gaps)*supplanted_gaps);
+                memmove_4tech(gap, gaps + gap_end, sizeof(*gaps)*(buffer->chunk_alloced - gap_start - 1));
+                buffer->chunk_count -= (gap_end - gap_start + 1);
+        
+                local_end = end - gap->start_pos;
+        
+                if (gap->size1 >= local_end){
+                    gap->size2 -= (local_end - gap->size1);
+                    gap->size1 = 0;
+                }
+                else{
+                    memmove_4tech(gap->data, gap->data + local_end, gap->size1 - local_end);
+                    gap->size1 -= local_end;
+                }
+        
+                --gap;
+            }
+            else{
+                buffer->grow_gaps = 1;
+                *request_amount = round_up_4tech(sizeof(*gaps)*(supplanted_gaps+buffer->chunk_max*2), 4<<10);
+                result = 1;
+                goto mugab_replace_range_end;
+            }
+        }
+        buffer->edit_stage = 2;
     }
-    if (end > gap->size1 + gap->size2) end = gap->size1 + gap->size2;
     
     shift_amount = (len - (end - start));
+    start -= gap->start_pos;
+    end -= gap->start_pos;
+    if (end > gap->size1 + gap->size2) end = gap->size1 + gap->size2;
     
     if (shift_amount + gap->size1 + gap->size2 <= fixed_width_buffer_size){
-        start -= gap->start_pos;
-        end -= gap->start_pos;
-        
         data = gap->data;
+        debug_4tech(osize = gap->size1 + gap->size2);
         if (end < gap->size1){
             move_size = gap->size1 - end;
             memmove_4tech(data + gap->size1 + gap->gap_size - move_size, data + end, move_size);
@@ -429,20 +471,206 @@ buffer_replace_range(Multi_Gap_Buffer *buffer, int start, int end, char *str, in
         }
         
         memcpy_4tech(data + start, str, len);
-        gap->size2 = size - end;
+        gap->size2 = fixed_width_buffer_size - (end + gap->gap_size);
         gap->size1 = start + len;
         gap->gap_size -= shift_amount;
         
-        assert_4tech(gap->size1 + gap->size2 == size + shift_amount);
-        assert_4tech(gap->size1 + gap->gap_size + gap->size2 == gap->max);
+        assert_4tech(gap->size1 + gap->size2 == osize + shift_amount);
+        assert_4tech(gap->size1 + gap->gap_size + gap->size2 == fixed_width_buffer_size);
         
         result = 0;
+        buffer->edit_stage = 0;
+
+        if (gap_start < gap_end){
+            ++gap;
+            gap->start_pos += shift_amount;
+        }
     }
     else{
-        div_ceil_4tech(shift_amount, fixed_width_buffer_half_size);
-        result = 1;
+        required_empty_buffers = div_ceil_4tech(shift_amount, fixed_width_buffer_half_size);
+        if (buffer->chunk_alloced - buffer->chunk_count >= required_empty_buffers){
+            if (buffer->chunk_max - buffer->chunk_alloced >= required_empty_buffers){
+                memcpy_4tech(gaps + buffer->chunk_alloced, gaps + buffer->chunk_count, sizeof(*gaps)*required_empty_buffers);
+                memmove_4tech(gap + required_empty_buffers + 1, gap + 1, sizeof(*gaps)*(buffer->chunk_count - gap_start - 1));
+                memcpy_4tech(gap + 1, gaps + buffer->chunk_alloced, sizeof(*gaps)*required_empty_buffers);
+                
+                data = gap->data;
+                if (end < gap->size1){
+                    move_size = gap->size1 - end;
+                    memmove_4tech(data + gap->size1 + gap->gap_size - move_size, data + end, move_size);
+                    gap->size1 -= move_size + (end - start);
+                    gap->size2 += move_size;
+                }
+                else if (start > gap->size1){
+                    move_size = start - gap->size1;
+                    memmove_4tech(data + gap->size1, data + gap->size1 + gap->gap_size, move_size);
+                    gap->size1 += move_size;
+                    gap->size2 -= move_size + (end - start);
+                }
+                else{
+                    if (end > gap->size1){
+                        gap->size2 -= (end - gap->size1);
+                    }
+                    gap->size1 = start;
+                }
+                
+                if (gap->size1 > fixed_width_buffer_half_size){
+                    move_size = gap->size1 - fixed_width_buffer_half_size;
+                    memmove_4tech(data + gap->size1 + gap->gap_size - move_size, data + end, move_size);
+                    gap->size1 -= move_size + (end - start);
+                    gap->size2 += move_size;
+                }
+                else if (gap->size2 > fixed_width_buffer_half_size){
+                    move_size = gap->size2 - fixed_width_buffer_half_size;
+                    memmove_4tech(data + gap->size1, data + gap->size1 + gap->gap_size, move_size);
+                    gap->size1 += move_size;
+                    gap->size2 -= move_size + (end - start);
+                }                
+                
+                dgap = gap + required_empty_buffers;
+                dpos = gap->size1 + gap->gap_size;
+                memcpy_4tech(dgap->data + dpos, data + dpos, gap->size2);
+                dgap->size2 = gap->size2;
+                gap->size2 = 0;
+                
+                middle_size = div_ceil_4tech(len, (required_empty_buffers * 2));
+                
+                head_size = middle_size;
+                tail_size = middle_size;
+                
+                if (head_size + gap->size1 + 256 > fixed_width_buffer_size){
+                    head_size = fixed_width_buffer_size - gap->size1 - 256;
+                    if (head_size < 0) head_size = 0;
+                }
+                
+                if (tail_size + dgap->size2 + 256 > fixed_width_buffer_size){
+                    tail_size = fixed_width_buffer_size - dgap->size2 - 256;
+                    if (tail_size < 0) tail_size = 0;
+                }
+
+                if (required_empty_buffers-1 > 0)
+                    middle_size = div_ceil_4tech(len - head_size - tail_size, (required_empty_buffers-1)*2);
+                else
+                    middle_size = 0;
+
+                mem_pos = 0;
+                if (head_size > len - mem_pos) head_size = len - mem_pos;
+                
+                gap->size2 = head_size;
+                gap->gap_size = fixed_width_buffer_size - gap->size1 - gap->size2;
+                memcpy_4tech(gap->data + fixed_width_buffer_size - head_size, str + mem_pos, head_size);
+                mem_pos += head_size;
+                local_start_pos = gap->start_pos + gap->size1 + gap->size2;
+                
+                ++gap;
+                for (;gap < dgap; ++gap){
+                    gap->start_pos = local_start_pos;
+                    
+                    if (middle_size > len - mem_pos) middle_size = len - mem_pos;
+                    gap->size1 = middle_size;
+                    memcpy_4tech(gap->data, str + mem_pos, middle_size);
+                    mem_pos += middle_size;
+                    
+                    if (middle_size > len - mem_pos) middle_size = len - mem_pos;
+                    gap->size2 = middle_size;
+                    memcpy_4tech(gap->data + fixed_width_buffer_size - middle_size, str + mem_pos, middle_size);
+                    mem_pos += middle_size;
+                    
+                    gap->gap_size = fixed_width_buffer_size - (gap->size1 + gap->size2);
+                    local_start_pos += gap->size1 + gap->size2;
+                    ++gap;
+                }
+                
+                if (tail_size > len - mem_pos) tail_size = len - mem_pos;
+                gap->start_pos = local_start_pos;
+                gap->size1 = tail_size;
+                gap->gap_size = fixed_width_buffer_size - gap->size1 - gap->size2;
+                memcpy_4tech(gap->data, str + mem_pos, tail_size);
+                mem_pos += tail_size;
+                assert_4tech(mem_pos == len);
+
+                buffer->chunk_count += required_empty_buffers;
+
+                result = 0;
+                buffer->edit_stage = 0;
+            }
+            else{
+                buffer->grow_gaps = 1;
+                *request_amount = round_up_4tech(sizeof(*gaps)*(required_empty_buffers+buffer->chunk_max*2), 4<<10);
+                result = 1;
+                goto mugab_replace_range_end;
+            }
+        }
+        else{
+            if (buffer->chunk_alloced < buffer->chunk_max){
+                *request_amount = fixed_width_buffer_size;
+                result = 1;
+            }
+            else{
+                buffer->grow_gaps = 1;
+                *request_amount = round_up_4tech(sizeof(*gaps)*(1+buffer->chunk_max*2), 4<<10);
+                result = 1;
+            }
+        }
+    }
+
+mugab_replace_range_end:
+    return(result);
+}
+
+internal_4tech void*
+buffer_edit_provide_memory(Multi_Gap_Buffer *buffer, void *new_data, int size){
+    void *result;
+    Fixed_Width_Gap_Buffer *gap;
+
+    if (buffer->grow_gaps){
+        assert_4tech(size >= buffer->chunk_max*sizeof(*buffer->gaps));
+        
+        result = buffer->gaps;
+        memcpy_4tech(new_data, buffer->gaps, buffer->chunk_alloced*sizeof(*buffer->gaps));
+        buffer->gaps = (Fixed_Width_Gap_Buffer*)new_data;
+        buffer->chunk_max = size / sizeof(*buffer->gaps);
+        buffer->grow_gaps = 0;
     }
     
+    else{
+        assert_4tech(buffer->chunk_max > buffer->chunk_alloced);
+        assert_4tech(size >= fixed_width_buffer_size);
+        
+        gap = &buffer->gaps[buffer->chunk_alloced++];
+        *gap = {};
+        gap->data = (char*)new_data;
+        result = 0;
+    }
+    
+    return(result);
+}
+
+internal_4tech int
+buffer_mugab_check(Multi_Gap_Buffer *buffer){
+    Fixed_Width_Gap_Buffer *gap;
+    int result;
+    int total_size;
+    int i, count;
+    
+    assert_4tech(buffer->chunk_count <= buffer->chunk_alloced);
+    assert_4tech(buffer->chunk_alloced <= buffer->chunk_max);
+    
+    count = buffer->chunk_count;
+    
+    total_size = 0;
+    gap = buffer->gaps;
+    for (i = 0; i < count; ++i, ++gap){
+        assert_4tech(gap->size1 + gap->size2 + gap->gap_size == fixed_width_buffer_size);
+        assert_4tech(gap->start_pos == total_size);
+        total_size += gap->size1 + gap->size2;
+    }
+    assert_4tech(total_size == buffer->size);
+    
+    assert_4tech(buffer->edit_stage == 0);
+    assert_4tech(buffer->grow_gaps == 0);
+    
+    result = 1;
     return(result);
 }
 
diff --git a/buffer/4coder_shared.cpp b/buffer/4coder_shared.cpp
index b103d464..bb8e0019 100644
--- a/buffer/4coder_shared.cpp
+++ b/buffer/4coder_shared.cpp
@@ -157,6 +157,8 @@ typedef struct{
     int glyphid;
     float x0, y0;
     float x1, y1;
+    
+    int chunk_i;
 } Buffer_Render_Item;
 
 inline_4tech void
diff --git a/win32_4ed.cpp b/win32_4ed.cpp
index 01f488e1..2eb405d6 100644
--- a/win32_4ed.cpp
+++ b/win32_4ed.cpp
@@ -58,7 +58,7 @@
 #define FPS 30
 #define FRAME_TIME (1000000 / FPS)
 
-#define BUFFER_EXPERIMENT_SCALPEL 0
+#define BUFFER_EXPERIMENT_SCALPEL 1
 
 #include "4ed_meta.h"