From 93d738240bb2b45932ec2d94d6e12d3610dae835 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Thu, 22 Sep 2016 17:25:52 -0400 Subject: [PATCH] implemented standard wrap remeasuring rule --- 4ed.cpp | 31 ++-- 4ed_file_view.cpp | 90 +++++++---- buffer/4coder_buffer_abstract.cpp | 255 +++++++++++++++++++++--------- 3 files changed, 253 insertions(+), 123 deletions(-) diff --git a/4ed.cpp b/4ed.cpp index 766c0ecc..501a3a7e 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -1459,11 +1459,11 @@ App_Init_Sig(app_init){ user_map_count = unit->header.user_map_count; models->map_id_table = push_array( - &models->mem.part, i32, user_map_count); + &models->mem.part, i32, user_map_count); memset(models->map_id_table, -1, user_map_count*sizeof(i32)); models->user_maps = push_array( - &models->mem.part, Command_Map, user_map_count); + &models->mem.part, Command_Map, user_map_count); models->user_map_count = user_map_count; @@ -1694,26 +1694,33 @@ App_Init_Sig(app_init){ General_Memory *general = &models->mem.general; - String init_files[] = { - make_lit_string("*messages*"), - make_lit_string("*scratch*"), + struct File_Init{ + String name; + Editing_File **ptr; + i32 type; }; - Editing_File **init_file_ptrs[] = { - &models->message_buffer, - &models->scratch_buffer, + File_Init init_files[] = { + { make_lit_string("*messages*"), &models->message_buffer, 1, }, + { make_lit_string("*scratch*"), &models->scratch_buffer, 0, } }; for (i32 i = 0; i < ArrayCount(init_files); ++i){ - String name = init_files[i]; Editing_File *file = working_set_alloc_always(&models->working_set, general); - buffer_bind_name(general, &models->working_set, file, name); - init_read_only_file(system, models, file); + buffer_bind_name(general, &models->working_set, file, init_files[i].name); + + switch (init_files[i].type){ + case 0: init_normal_file(system, models, file, 0, 0); break; + case 1: init_read_only_file(system, models, file); break; + } + file->settings.never_kill = 1; file->settings.unimportant = 1; file->settings.unwrapped_lines = 1; - *init_file_ptrs[i] = file; + if (init_files[i].ptr){ + *init_files[i].ptr = file; + } } Panel_And_ID p = layout_alloc_panel(&models->layout); diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index 7242c679..7db81438 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -675,6 +675,16 @@ view_set_cursor_and_scroll(View *view, } } +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; + + view_set_cursor(view, view->file_data.temp_highlight, + 0, view->file_data.file->settings.unwrapped_lines); +} + struct View_And_ID{ View *view; i32 id; @@ -909,21 +919,30 @@ file_grow_starts_as_needed(General_Memory *general, Buffer_Type *buffer, i32 add 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; - - view_set_cursor(view, view->file_data.temp_highlight, - 0, view->file_data.file->settings.unwrapped_lines); +internal void +file_update_cursor_positions(Models *models, Editing_File *file){ + Editing_Layout *layout = &models->layout; + for (View_Iter iter = file_view_iter_init(layout, file, 0); + file_view_iter_good(iter); + iter = file_view_iter_next(iter)){ + i32 pos = view_get_cursor_pos(iter.view); + + if (!iter.view->file_data.show_temp_highlight){ + Full_Cursor cursor = view_compute_cursor_from_pos(iter.view, pos); + view_set_cursor(iter.view, cursor, 1, iter.view->file_data.file->settings.unwrapped_lines); + } + else{ + view_set_temp_highlight(iter.view, pos, iter.view->file_data.temp_highlight_end_pos); + } + } } +// NOTE(allen): This call assumes that the buffer's line starts are already correct, +// and that the buffer's line_count is correct. internal void -file_measure_wraps(Models *models, Editing_File *file, f32 font_height, f32 *adv){ +file_allocate_wraps_as_needed(General_Memory *general, Editing_File *file){ Buffer_Type *buffer = &file->state.buffer; - General_Memory *general = &models->mem.general; if (file->state.wraps == 0){ i32 max = ((buffer->line_count+1)*2); max = (max+(0x1FF))&(~(0x1FF)); @@ -942,25 +961,20 @@ file_measure_wraps(Models *models, Editing_File *file, f32 font_height, f32 *adv file->state.wraps = new_wraps; file->state.wrap_max = max; } - - buffer_measure_wrap_y(buffer, file->state.wraps, font_height, adv, (f32)file->settings.display_width); - - Editing_Layout *layout = &models->layout; - for (View_Iter iter = file_view_iter_init(layout, file, 0); - file_view_iter_good(iter); - iter = file_view_iter_next(iter)){ - i32 pos = view_get_cursor_pos(iter.view); - - if (!iter.view->file_data.show_temp_highlight){ - Full_Cursor cursor = view_compute_cursor_from_pos(iter.view, pos); - view_set_cursor(iter.view, cursor, 1, iter.view->file_data.file->settings.unwrapped_lines); - } - else{ - view_set_temp_highlight(iter.view, pos, iter.view->file_data.temp_highlight_end_pos); - } - } } +// NOTE(allen): This call assumes that the buffer's line starts are already correct, +// and that the buffer's line_count is correct. +internal void +file_measure_wraps(Models *models, Editing_File *file, f32 font_height, f32 *adv){ + file_allocate_wraps_as_needed(&models->mem.general, file); + buffer_measure_wrap_y(&file->state.buffer, file->state.wraps, + font_height, adv, (f32)file->settings.display_width); + file_update_cursor_positions(models, file); +} + +// NOTE(allen): This call assumes that the buffer's line starts are already correct, +// and that the buffer's line_count is correct. internal void file_set_display_width(Models *models, Editing_File *file, i32 display_width, f32 font_height, f32 *adv){ file->settings.display_width = display_width; @@ -2054,11 +2068,15 @@ file_do_single_edit(System_Functions *system, 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->settings.font_id)->font; file_grow_starts_as_needed(general, buffer, line_shift); buffer_remeasure_starts(buffer, line_start, line_end, line_shift, shift_amount); - Render_Font *font = get_font_info(models->font_set, file->settings.font_id)->font; - file_measure_wraps(models, file, (f32)font->height, font->advance_data); + file_allocate_wraps_as_needed(general, file); + buffer_remeasure_wrap_y(buffer, line_start, line_end, line_shift, + file->state.wraps, (f32)font->height, font->advance_data, + (f32)file->settings.display_width); // NOTE(allen): cursor fixing Cursor_Fix_Descriptor desc = {}; @@ -2079,6 +2097,8 @@ file_do_batch_edit(System_Functions *system, Models *models, Editing_File *file, Edit_Spec spec, History_Mode history_mode, i32 batch_type){ Mem_Options *mem = &models->mem; + General_Memory *general = &mem->general; + Partition *part = &mem->part; Editing_Layout *layout = &models->layout; // NOTE(allen): fixing stuff "beforewards"??? @@ -2087,9 +2107,6 @@ file_do_batch_edit(System_Functions *system, Models *models, Editing_File *file, 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; @@ -2113,10 +2130,18 @@ file_do_batch_edit(System_Functions *system, Models *models, Editing_File *file, } } + // TODO(allen): Let's try to switch to remeasuring here moron! + // We'll need to get the total shift from the actual batch edit state + // instead of from the cursor fixing. The only reason we're getting + // it from cursor fixing is because you're a lazy asshole. + // NOTE(allen): meta data Buffer_Measure_Starts measure_state = {}; buffer_measure_starts(&measure_state, &file->state.buffer); + Render_Font *font = get_font_info(models->font_set, file->settings.font_id)->font; + file_measure_wraps(models, file, (f32)font->height, font->advance_data); + // NOTE(allen): cursor fixing i32 shift_total = 0; { @@ -2124,7 +2149,6 @@ file_do_batch_edit(System_Functions *system, Models *models, Editing_File *file, desc.is_batch = 1; desc.batch = batch; desc.batch_size = batch_size; - file_edit_cursor_fix(system, models, file, layout, desc, &shift_total); } diff --git a/buffer/4coder_buffer_abstract.cpp b/buffer/4coder_buffer_abstract.cpp index a4bc7d6d..094fd115 100644 --- a/buffer/4coder_buffer_abstract.cpp +++ b/buffer/4coder_buffer_abstract.cpp @@ -73,6 +73,8 @@ typedef struct Buffer_Measure_Starts{ } Buffer_Measure_Starts; // TODO(allen): Rewrite this with a duff routine +// Also make it so that the array goes one past the end +// and stores the size in the extra spot. internal_4tech i32 buffer_measure_starts(Buffer_Measure_Starts *state, Buffer_Type *buffer){ Buffer_Stringify_Type loop = {0}; @@ -119,81 +121,19 @@ buffer_measure_starts(Buffer_Measure_Starts *state, Buffer_Type *buffer){ return(result); } -internal_4tech void -buffer_remeasure_starts(Buffer_Type *buffer, i32 line_start, i32 line_end, i32 line_shift, i32 text_shift){ - Buffer_Stringify_Type loop; - i32 *starts = buffer->line_starts; - i32 line_count = buffer->line_count; - char *data = 0; - i32 size = 0, end = 0; - i32 line_i = 0, char_i = 0, start = 0; - - assert_4tech(0 <= line_start); - assert_4tech(line_start <= line_end); - assert_4tech(line_end < line_count); - assert_4tech(line_count + line_shift <= buffer->line_max); - - ++line_end; - if (text_shift != 0){ - line_i = line_end; - starts += line_i; - for (; line_i < line_count; ++line_i, ++starts){ - *starts += text_shift; - } - starts = buffer->line_starts; - } - - if (line_shift != 0){ - memmove_4tech(starts + line_end + line_shift, starts + line_end, - sizeof(i32)*(line_count - line_end)); - line_count += line_shift; - } - - line_end += line_shift; - size = buffer_size(buffer); - char_i = starts[line_start]; - line_i = line_start; - start = char_i; - - for (loop = buffer_stringify_loop(buffer, char_i, size); - buffer_stringify_good(&loop); - buffer_stringify_next(&loop)){ - end = loop.size + loop.absolute_pos; - data = loop.data - loop.absolute_pos; - for (; char_i < end; ++char_i){ - if (data[char_i] == '\n'){ - starts[line_i++] = start; - start = char_i + 1; - if (line_i >= line_end && start == starts[line_i]) goto buffer_remeasure_starts_end; - } - } - } - - if (char_i == size){ - starts[line_i++] = start; - } - - buffer_remeasure_starts_end: - assert_4tech(line_count >= 1); - buffer->line_count = line_count; -} - internal_4tech void buffer_measure_wrap_y(Buffer_Type *buffer, f32 *wraps, f32 font_height, f32 *adv, f32 max_width){ Buffer_Stringify_Type loop = {0}; - i32 size = buffer_size(buffer); char *data = 0; i32 end = 0; i32 i = 0; + i32 size = buffer_size(buffer); i32 wrap_index = 0; f32 last_wrap = 0.f; f32 current_wrap = 0.f; f32 x = 0.f; - f32 current_adv = 0.f; - - u8 ch = 0; for (loop = buffer_stringify_loop(buffer, i, size); buffer_stringify_good(&loop); @@ -201,7 +141,7 @@ buffer_measure_wrap_y(Buffer_Type *buffer, f32 *wraps, f32 font_height, f32 *adv end = loop.size + loop.absolute_pos; data = loop.data - loop.absolute_pos; for (; i < end; ++i){ - ch = (u8)data[i]; + u8 ch = (u8)data[i]; if (ch == '\n'){ wraps[wrap_index++] = last_wrap; current_wrap += font_height; @@ -209,7 +149,7 @@ buffer_measure_wrap_y(Buffer_Type *buffer, f32 *wraps, f32 font_height, f32 *adv x = 0.f; } else{ - current_adv = adv[ch]; + f32 current_adv = adv[ch]; if (x + current_adv > max_width){ current_wrap += font_height; x = current_adv; @@ -227,6 +167,165 @@ buffer_measure_wrap_y(Buffer_Type *buffer, f32 *wraps, f32 font_height, f32 *adv assert_4tech(wrap_index-1 == buffer->line_count); } +internal_4tech void +buffer_remeasure_starts(Buffer_Type *buffer, i32 line_start, i32 line_end, i32 line_shift, i32 text_shift){ + i32 *starts = buffer->line_starts; + i32 line_count = buffer->line_count; + + assert_4tech(0 <= line_start); + assert_4tech(line_start <= line_end); + assert_4tech(line_end < line_count); + assert_4tech(line_count + line_shift <= buffer->line_max); + + ++line_end; + + // Adjust + if (text_shift != 0){ + i32 line_i = line_end; + starts += line_i; + for (; line_i < line_count; ++line_i, ++starts){ + *starts += text_shift; + } + starts = buffer->line_starts; + } + + // Shift + i32 new_line_count = line_count; + i32 new_line_end = line_end; + if (line_shift != 0){ + memmove_4tech(starts + line_end + line_shift, starts + line_end, + sizeof(i32)*(line_count - line_end)); + + new_line_count += line_shift; + new_line_end += line_shift; + } + + // Iteration data (yikes! Need better loop system) + Buffer_Stringify_Type loop = {0}; + i32 end = 0; + char *data = 0; + i32 size = buffer_size(buffer); + i32 char_i = starts[line_start]; + i32 line_i = line_start; + + // Line start measurement + i32 start = char_i; + + for (loop = buffer_stringify_loop(buffer, char_i, size); + buffer_stringify_good(&loop); + buffer_stringify_next(&loop)){ + end = loop.size + loop.absolute_pos; + data = loop.data - loop.absolute_pos; + for (; char_i < end; ++char_i){ + u8 ch = (u8)data[char_i]; + + if (ch == '\n'){ + starts[line_i] = start; + ++line_i; + start = char_i + 1; + + // TODO(allen): I would like to know that I am not guessing here, + // so let's try to turn the && into an Assert. + if (line_i >= new_line_end && (line_i >= new_line_count || start == starts[line_i])){ + goto buffer_remeasure_starts_end; + } + } + } + } + + // TODO(allen): I suspect this can just go away. + if (char_i == size){ + starts[line_i++] = start; + } + + buffer_remeasure_starts_end:; + assert_4tech(line_count >= 1); + buffer->line_count = new_line_count; +} + +internal_4tech void +buffer_remeasure_wrap_y(Buffer_Type *buffer, i32 line_start, i32 line_end, i32 line_shift, + f32 *wraps, f32 font_height, f32 *adv, f32 max_width){ + i32 new_line_count = buffer->line_count; + + assert_4tech(0 <= line_start); + assert_4tech(line_start <= line_end); + assert_4tech(line_end < new_line_count - line_shift); + + ++line_end; + + // Shift + i32 line_count = new_line_count; + i32 new_line_end = line_end; + if (line_shift != 0){ + memmove_4tech(wraps + line_end + line_shift, wraps + line_end, + sizeof(i32)*(line_count - line_end)); + + line_count -= line_shift; + new_line_end += line_shift; + } + + // Iteration data (yikes! Need better loop system) + Buffer_Stringify_Type loop = {0}; + i32 end = 0; + char *data = 0; + i32 size = buffer_size(buffer); + i32 char_i = buffer->line_starts[line_start]; + i32 line_i = line_start; + + // Line wrap measurement + f32 last_wrap = wraps[line_i]; + f32 current_wrap = last_wrap; + f32 x = 0.f; + + for (loop = buffer_stringify_loop(buffer, char_i, size); + buffer_stringify_good(&loop); + buffer_stringify_next(&loop)){ + end = loop.size + loop.absolute_pos; + data = loop.data - loop.absolute_pos; + for (; char_i < end; ++char_i){ + u8 ch = (u8)data[char_i]; + + if (ch == '\n'){ + wraps[line_i] = last_wrap; + ++line_i; + current_wrap += font_height; + last_wrap = current_wrap; + x = 0.f; + + // TODO(allen): I would like to know that I am not guessing here. + if (line_i >= new_line_end){ + goto buffer_remeasure_wraps_end; + } + } + else{ + f32 current_adv = adv[ch]; + if (x + current_adv > max_width){ + current_wrap += font_height; + x = current_adv; + } + else{ + x += current_adv; + } + } + } + } + + wraps[line_i++] = last_wrap; + + buffer_remeasure_wraps_end:; + + f32 y_shift = current_wrap - wraps[line_i]; + + // Adjust + if (y_shift != 0){ + wraps += line_i; + for (; line_i <= new_line_count; ++line_i, ++wraps){ + *wraps += y_shift; + } + } +} + internal_4tech i32 buffer_get_line_index_range(Buffer_Type *buffer, i32 pos, i32 l_bound, i32 u_bound){ i32 *lines = buffer->line_starts; @@ -297,7 +396,6 @@ cursor_seek_step(Seek_State *state, Buffer_Seek seek, i32 xy_seek, f32 max_width f32 font_height, f32 *adv, i32 size, uint8_t ch){ Full_Cursor cursor = state->cursor; Full_Cursor prev_cursor = cursor; - f32 ch_width; i32 result = 1; f32 x, px, y; @@ -312,18 +410,19 @@ cursor_seek_step(Seek_State *state, Buffer_Seek seek, i32 xy_seek, f32 max_width break; default: - ++cursor.character; - ch_width = adv[ch]; - - if (cursor.wrapped_x + ch_width >= max_width){ - cursor.wrapped_y += font_height; - cursor.wrapped_x = 0; - prev_cursor = cursor; - } - - cursor.unwrapped_x += ch_width; - cursor.wrapped_x += ch_width; - break; + { + f32 ch_width = adv[ch]; + + if (cursor.wrapped_x + ch_width > max_width){ + cursor.wrapped_y += font_height; + cursor.wrapped_x = 0; + prev_cursor = cursor; + } + + ++cursor.character; + cursor.unwrapped_x += ch_width; + cursor.wrapped_x += ch_width; + }break; } ++cursor.pos;