dialectic API for line wrap measurements
parent
3cfb743a12
commit
980cb9e477
|
@ -955,8 +955,40 @@ file_allocate_wraps_as_needed(General_Memory *general, Editing_File *file){
|
|||
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);
|
||||
|
||||
Buffer_Measure_Wrap_Params params;
|
||||
params.buffer = &file->state.buffer;
|
||||
params.wraps = file->state.wraps;
|
||||
params.font_height = font_height;
|
||||
params.adv = adv;
|
||||
params.width = (f32)file->settings.display_width;
|
||||
params.virtual_white = VWHITE;
|
||||
|
||||
Buffer_Measure_Wrap_State state = {0};
|
||||
Buffer_Layout_Stop stop = {0};
|
||||
|
||||
f32 edge_tolerance = 50.f;
|
||||
if (edge_tolerance > params.width){
|
||||
edge_tolerance = params.width;
|
||||
}
|
||||
|
||||
f32 line_shift = 0.f;
|
||||
do{
|
||||
f32 this_line_shift = line_shift;
|
||||
if (this_line_shift > params.width - edge_tolerance){
|
||||
this_line_shift = params.width - edge_tolerance;
|
||||
}
|
||||
|
||||
stop = buffer_measure_wrap_y(&state, params, this_line_shift);
|
||||
switch (stop.status){
|
||||
case BLStatus_NeedWrapLineShift:
|
||||
case BLStatus_NeedLineShift:
|
||||
line_shift = (stop.line_index%4)*9.f;
|
||||
break;
|
||||
}
|
||||
}while(stop.status != BLStatus_Finished);
|
||||
|
||||
buffer_measure_wrap_y(&state, params, 0.f);
|
||||
file_update_cursor_positions(models, file);
|
||||
}
|
||||
|
||||
|
@ -2065,15 +2097,19 @@ file_do_single_edit(System_Functions *system,
|
|||
file_grow_starts_as_needed(general, buffer, line_shift);
|
||||
buffer_remeasure_starts(buffer, line_start, line_end, line_shift, shift_amount);
|
||||
|
||||
// TODO(allen): write the remeasurement version
|
||||
file_allocate_character_starts_as_needed(general, file);
|
||||
buffer_remeasure_character_starts(buffer, line_start, line_end, line_shift,
|
||||
file->state.character_starts, 0, VWHITE);
|
||||
|
||||
// TODO(allen): Redo this as some sort of dialectic API
|
||||
#if 0
|
||||
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);
|
||||
#endif
|
||||
|
||||
file_measure_wraps(models, file, (f32)font->height, font->advance_data);
|
||||
|
||||
// NOTE(allen): cursor fixing
|
||||
Cursor_Fix_Descriptor desc = {};
|
||||
|
|
23
TODO.txt
23
TODO.txt
|
@ -86,6 +86,15 @@
|
|||
; [] view fails to follow cursor after deleting long line
|
||||
;
|
||||
|
||||
; BEFORE I SHIP
|
||||
;
|
||||
; [] ad hoc call for setting up/down keys for interactive screens
|
||||
; [] miblo's various number editors
|
||||
; [] API docs have duplicate ids?
|
||||
; [] query buffer font info
|
||||
; [] option to not open *messages* every startup
|
||||
;
|
||||
|
||||
; TODOS
|
||||
; [X] success message when compiler works
|
||||
; [X] auto-complete
|
||||
|
@ -132,6 +141,7 @@
|
|||
; [X] why are command line files not loading any more?
|
||||
; [X] use strange theme
|
||||
; [X] cuber's return to previous buffer idea
|
||||
; [X] find matches for current identifier
|
||||
|
||||
; Token related upgrades
|
||||
; [X] tokens in the custom API
|
||||
|
@ -155,7 +165,7 @@
|
|||
; [] word level wrapping
|
||||
; [] code level wrapping
|
||||
|
||||
; buffer behavior cleanup
|
||||
; Buffer behavior cleanup
|
||||
; [X] show all characters as \# if they can't be rendered
|
||||
; [X] get the navigation working correctly around multi-glyph characters
|
||||
; [] wrap remeasuring routine for local edits
|
||||
|
@ -165,21 +175,17 @@
|
|||
; [] unicode buffer mode
|
||||
; [] support full length unicode file names
|
||||
|
||||
; [] miblo's various number editors
|
||||
; [] user file bar string
|
||||
; [] API docs as text file
|
||||
; [] read only files
|
||||
; [] option to hide hidden files
|
||||
; [] control over how mouse effects panel focus
|
||||
; [] option to not open *messages* every startup
|
||||
;
|
||||
; [] query buffer font info
|
||||
|
||||
; [] option to break buffer name ties by adding parent directories instead of <#>
|
||||
; [] undo groups
|
||||
; [] cursor/scroll groups
|
||||
; [] double binding warnings
|
||||
;
|
||||
;
|
||||
|
||||
; [] the "main_4coder" experiment
|
||||
; [] real multi-line editing
|
||||
; [] multi-cursor editing
|
||||
|
@ -188,10 +194,8 @@
|
|||
|
||||
; [] simple text based project file
|
||||
; [] system commands bound to <ctrl #> in project file
|
||||
; [] find matches for current identifier
|
||||
; [] ability to save and reopen the window state
|
||||
|
||||
; [] API docs have duplicate ids?
|
||||
; [] introduce custom command line arguments
|
||||
; [] control the file opening/start hook relationship better
|
||||
; [] get keyboard state on launch
|
||||
|
@ -222,6 +226,7 @@
|
|||
; [X] wave search
|
||||
; [] optimize search
|
||||
; [] smarter isearch behavior
|
||||
; [] cleanup word complete so it may be case-insensitive
|
||||
;
|
||||
|
||||
; theme related business
|
||||
|
|
|
@ -130,7 +130,7 @@ buffer_measure_starts(Buffer_Measure_Starts *state, Buffer_Type *buffer){
|
|||
}
|
||||
|
||||
internal_4tech void
|
||||
buffer_measure_character_starts(Buffer_Type *buffer, i32 *character_starts, i32 mode, i32 virtual_whitespace){
|
||||
buffer_measure_character_starts(Buffer_Type *buffer, i32 *character_starts, i32 mode, i32 virtual_white){
|
||||
assert_4tech(mode == 0);
|
||||
|
||||
Buffer_Stream_Type stream = {0};
|
||||
|
@ -144,7 +144,7 @@ buffer_measure_character_starts(Buffer_Type *buffer, i32 *character_starts, i32
|
|||
|
||||
character_starts[line_index++] = character_index;
|
||||
|
||||
if (virtual_whitespace){
|
||||
if (virtual_white){
|
||||
skipping_whitespace = 1;
|
||||
}
|
||||
|
||||
|
@ -158,7 +158,7 @@ buffer_measure_character_starts(Buffer_Type *buffer, i32 *character_starts, i32
|
|||
if (ch == '\n'){
|
||||
++character_index;
|
||||
character_starts[line_index++] = character_index;
|
||||
if (virtual_whitespace){
|
||||
if (virtual_white){
|
||||
skipping_whitespace = 1;
|
||||
}
|
||||
}
|
||||
|
@ -179,50 +179,142 @@ buffer_measure_character_starts(Buffer_Type *buffer, i32 *character_starts, i32
|
|||
assert_4tech(line_index-1 == buffer->line_count);
|
||||
}
|
||||
|
||||
internal_4tech void
|
||||
buffer_measure_wrap_y(Buffer_Type *buffer, f32 *wraps, f32 font_height, f32 *adv, f32 max_width){
|
||||
Buffer_Stream_Type stream = {0};
|
||||
i32 i = 0;
|
||||
i32 size = buffer_size(buffer);
|
||||
struct Buffer_Measure_Wrap_Params{
|
||||
Buffer_Type *buffer;
|
||||
f32 *wraps;
|
||||
f32 font_height;
|
||||
f32 *adv;
|
||||
f32 width;
|
||||
b32 virtual_white;
|
||||
};
|
||||
|
||||
struct Buffer_Measure_Wrap_State{
|
||||
Buffer_Stream_Type stream;
|
||||
i32 i;
|
||||
i32 size;
|
||||
i32 wrap_index;
|
||||
|
||||
i32 wrap_index = 0;
|
||||
f32 current_wrap = 0.f;
|
||||
f32 current_wrap;
|
||||
f32 current_adv;
|
||||
f32 x;
|
||||
|
||||
f32 x = 0.f;
|
||||
b32 skipping_whitespace;
|
||||
|
||||
wraps[wrap_index++] = current_wrap;
|
||||
b32 still_looping;
|
||||
|
||||
if (buffer_stringify_loop(&stream, buffer, i, size)){
|
||||
b32 still_looping = 0;
|
||||
u8 ch;
|
||||
|
||||
i32 __pc__;
|
||||
};
|
||||
|
||||
// duff-routine defines
|
||||
#define DrCase(PC) case PC: goto resumespot_##PC
|
||||
#define DrYield(PC, n) { *S_ptr = S; S_ptr->__pc__ = PC; return(n); resumespot_##PC:; }
|
||||
#define DrReturn(n) { *S_ptr = S; S_ptr->__pc__ = -1; return(n); }
|
||||
|
||||
enum{
|
||||
BLStatus_Finished,
|
||||
BLStatus_NeedWrapLineShift,
|
||||
BLStatus_NeedLineShift
|
||||
};
|
||||
|
||||
struct Buffer_Layout_Stop{
|
||||
u32 status;
|
||||
i32 line_index;
|
||||
i32 pos;
|
||||
};
|
||||
|
||||
internal_4tech Buffer_Layout_Stop
|
||||
buffer_measure_wrap_y(Buffer_Measure_Wrap_State *S_ptr, Buffer_Measure_Wrap_Params params, f32 line_shift){
|
||||
Buffer_Measure_Wrap_State S = *S_ptr;
|
||||
Buffer_Layout_Stop S_stop;
|
||||
|
||||
S.size = buffer_size(params.buffer);
|
||||
|
||||
switch (S.__pc__){
|
||||
DrCase(1);
|
||||
DrCase(2);
|
||||
DrCase(3);
|
||||
}
|
||||
|
||||
if (params.virtual_white){
|
||||
S_stop.status = BLStatus_NeedLineShift;
|
||||
S_stop.line_index = S.wrap_index;
|
||||
S_stop.pos = S.i;
|
||||
DrYield(1, S_stop);
|
||||
}
|
||||
|
||||
S.x = line_shift;
|
||||
params.wraps[S.wrap_index++] = 0;
|
||||
|
||||
if (params.virtual_white){
|
||||
S.skipping_whitespace = 1;
|
||||
}
|
||||
|
||||
if (buffer_stringify_loop(&S.stream, params.buffer, S.i, S.size)){
|
||||
S.still_looping = 0;
|
||||
do{
|
||||
for (; i < stream.end; ++i){
|
||||
u8 ch = (u8)stream.data[i];
|
||||
if (ch == '\n'){
|
||||
current_wrap += font_height;
|
||||
wraps[wrap_index++] = current_wrap;
|
||||
x = 0.f;
|
||||
for (; S.i < S.stream.end; ++S.i){
|
||||
S.ch = (u8)S.stream.data[S.i];
|
||||
if (S.ch == '\n'){
|
||||
S.current_wrap += params.font_height;
|
||||
params.wraps[S.wrap_index++] = S.current_wrap;
|
||||
|
||||
if (params.virtual_white){
|
||||
S_stop.status = BLStatus_NeedLineShift;
|
||||
S_stop.line_index = S.wrap_index - 1;
|
||||
S_stop.pos = S.i+1;
|
||||
DrYield(2, S_stop);
|
||||
}
|
||||
|
||||
S.x = line_shift;
|
||||
|
||||
if (params.virtual_white){
|
||||
S.skipping_whitespace = 1;
|
||||
}
|
||||
}
|
||||
else{
|
||||
f32 current_adv = adv[ch];
|
||||
if (x + current_adv > max_width){
|
||||
current_wrap += font_height;
|
||||
x = current_adv;
|
||||
if (S.ch != ' ' && S.ch != '\t'){
|
||||
S.skipping_whitespace = 0;
|
||||
}
|
||||
else{
|
||||
x += current_adv;
|
||||
|
||||
if (!S.skipping_whitespace){
|
||||
S.current_adv = params.adv[S.ch];
|
||||
if (S.x + S.current_adv > params.width){
|
||||
S.current_wrap += params.font_height;
|
||||
|
||||
if (params.virtual_white){
|
||||
S_stop.status = BLStatus_NeedWrapLineShift;
|
||||
S_stop.line_index = S.wrap_index - 1;
|
||||
S_stop.pos = S.i;
|
||||
DrYield(3, S_stop);
|
||||
}
|
||||
|
||||
S.x = line_shift + S.current_adv;
|
||||
}
|
||||
else{
|
||||
S.x += S.current_adv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
still_looping = buffer_stringify_next(&stream);
|
||||
}while(still_looping);
|
||||
S.still_looping = buffer_stringify_next(&S.stream);
|
||||
}while(S.still_looping);
|
||||
}
|
||||
|
||||
current_wrap += font_height;
|
||||
wraps[wrap_index++] = current_wrap;
|
||||
S.current_wrap += params.font_height;
|
||||
params.wraps[S.wrap_index++] = S.current_wrap;
|
||||
|
||||
assert_4tech(wrap_index-1 == buffer->line_count);
|
||||
assert_4tech(S.wrap_index-1 == params.buffer->line_count);
|
||||
|
||||
S_stop.status = BLStatus_Finished;
|
||||
DrReturn(S_stop);
|
||||
}
|
||||
|
||||
#undef DrCase
|
||||
#undef DrYield
|
||||
#undef DrReturn
|
||||
|
||||
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;
|
||||
|
@ -628,6 +720,8 @@ struct Buffer_Cursor_Seek_State{
|
|||
i32 i;
|
||||
i32 size;
|
||||
b32 xy_seek;
|
||||
|
||||
f32 ch_width;
|
||||
u8 ch;
|
||||
|
||||
i32 __pc__;
|
||||
|
@ -638,18 +732,6 @@ struct Buffer_Cursor_Seek_State{
|
|||
#define DrYield(PC, n) { *S_ptr = S; S_ptr->__pc__ = PC; return(n); resumespot_##PC:; }
|
||||
#define DrReturn(n) { *S_ptr = S; S_ptr->__pc__ = -1; return(n); }
|
||||
|
||||
enum{
|
||||
BLStatus_Finished,
|
||||
BLStatus_NeedWrapLineShift,
|
||||
BLStatus_NeedLineShift
|
||||
};
|
||||
|
||||
struct Buffer_Layout_Stop{
|
||||
u32 status;
|
||||
i32 line_index;
|
||||
i32 pos;
|
||||
};
|
||||
|
||||
internal_4tech Buffer_Layout_Stop
|
||||
buffer_cursor_seek(Buffer_Cursor_Seek_State *S_ptr, Buffer_Cursor_Seek_Params params,
|
||||
f32 line_shift, Full_Cursor *cursor_out){
|
||||
|
@ -658,6 +740,8 @@ buffer_cursor_seek(Buffer_Cursor_Seek_State *S_ptr, Buffer_Cursor_Seek_Params pa
|
|||
|
||||
switch (S.__pc__){
|
||||
DrCase(1);
|
||||
DrCase(2);
|
||||
DrCase(3);
|
||||
}
|
||||
|
||||
S.xy_seek = (params.seek.type == buffer_seek_wrapped_xy || params.seek.type == buffer_seek_unwrapped_xy);
|
||||
|
@ -832,23 +916,39 @@ buffer_cursor_seek(Buffer_Cursor_Seek_State *S_ptr, Buffer_Cursor_Seek_Params pa
|
|||
S.cursor.wrapped_y += params.font_height;
|
||||
S.cursor.character = 1;
|
||||
S.cursor.unwrapped_x = 0;
|
||||
S.cursor.wrapped_x = 0;
|
||||
|
||||
if (params.virtual_white){
|
||||
S_stop.status = BLStatus_NeedLineShift;
|
||||
S_stop.line_index = S.cursor.line-1;
|
||||
S_stop.pos = S.cursor.pos+1;
|
||||
DrYield(2, S_stop);
|
||||
}
|
||||
|
||||
S.cursor.wrapped_x = line_shift;
|
||||
}break;
|
||||
|
||||
default:
|
||||
{
|
||||
f32 ch_width = params.adv[S.ch];
|
||||
S.ch_width = params.adv[S.ch];
|
||||
|
||||
if (S.cursor.wrapped_x + ch_width > params.width){
|
||||
if (S.cursor.wrapped_x + S.ch_width > params.width){
|
||||
S.cursor.wrapped_y += params.font_height;
|
||||
S.cursor.wrapped_x = 0;
|
||||
|
||||
if (params.virtual_white){
|
||||
S_stop.status = BLStatus_NeedWrapLineShift;
|
||||
S_stop.line_index = S.cursor.line-1;
|
||||
S_stop.pos = S.cursor.pos;
|
||||
DrYield(3, S_stop);
|
||||
}
|
||||
|
||||
S.cursor.wrapped_x = line_shift;
|
||||
S.prev_cursor = S.cursor;
|
||||
}
|
||||
|
||||
++S.cursor.character_pos;
|
||||
++S.cursor.character;
|
||||
S.cursor.unwrapped_x += ch_width;
|
||||
S.cursor.wrapped_x += ch_width;
|
||||
S.cursor.unwrapped_x += S.ch_width;
|
||||
S.cursor.wrapped_x += S.ch_width;
|
||||
}break;
|
||||
}
|
||||
|
||||
|
@ -930,9 +1030,9 @@ buffer_cursor_seek(Buffer_Cursor_Seek_State *S_ptr, Buffer_Cursor_Seek_Params pa
|
|||
DrReturn(S_stop);
|
||||
}
|
||||
|
||||
#undef DrCase
|
||||
#undef DrYield
|
||||
#undef DrReturn
|
||||
#undef DrCase
|
||||
|
||||
internal_4tech void
|
||||
buffer_invert_edit_shift(Buffer_Type *buffer, Buffer_Edit edit, Buffer_Edit *inverse, char *strings,
|
||||
|
|
Loading…
Reference in New Issue