Fixed bugs in string seek, fixed bug in insertf

master
Allen Webster 2019-06-19 20:43:02 -07:00
parent cf6c92fcbd
commit 5010d6e14f
7 changed files with 63 additions and 62 deletions

View File

@ -1151,7 +1151,7 @@ STRUCT String_Match{
Buffer_ID buffer;
i32 string_id;
String_Match_Flag flags;
Range_u64 range;
Range_i64 range;
};
STRUCT String_Match_List{

View File

@ -20,8 +20,8 @@ struct Application_Links;
#define BUFFER_READ_RANGE_SIG(n) b32 n(Application_Links *app, Buffer_ID buffer_id, i32 start, i32 one_past_last, char *out)
#define BUFFER_REPLACE_RANGE_SIG(n) b32 n(Application_Links *app, Buffer_ID buffer_id, Range range, String_Const_u8 string)
#define BUFFER_BATCH_EDIT_SIG(n) b32 n(Application_Links *app, Buffer_ID buffer_id, char *str, Buffer_Edit *edits, i32 edit_count)
#define BUFFER_SEEK_STRING_SIG(n) String_Match n(Application_Links *app, Buffer_ID buffer, String_Const_u8 needle, Scan_Direction direction, i32 start_pos)
#define BUFFER_SEEK_CHARACTER_CLASS_SIG(n) b32 n(Application_Links *app, Buffer_ID buffer_id, Character_Predicate *predicate, Scan_Direction direction, i32 start_pos, i32 *pos_out)
#define BUFFER_SEEK_STRING_SIG(n) String_Match n(Application_Links *app, Buffer_ID buffer, String_Const_u8 needle, Scan_Direction direction, i64 start_pos)
#define BUFFER_SEEK_CHARACTER_CLASS_SIG(n) String_Match n(Application_Links *app, Buffer_ID buffer, Character_Predicate *predicate, Scan_Direction direction, i64 start_pos)
#define BUFFER_COMPUTE_CURSOR_SIG(n) Partial_Cursor n(Application_Links *app, Buffer_ID buffer_id, Buffer_Seek seek)
#define BUFFER_EXISTS_SIG(n) b32 n(Application_Links *app, Buffer_ID buffer_id)
#define BUFFER_READY_SIG(n) b32 n(Application_Links *app, Buffer_ID buffer_id)
@ -178,7 +178,7 @@ struct Application_Links;
#define DRAW_RENDER_LAYOUT_SIG(n) void n(Application_Links *app, View_ID view_id)
#define OPEN_COLOR_PICKER_SIG(n) void n(Application_Links *app, Color_Picker *picker)
#define ANIMATE_IN_N_MILLISECONDS_SIG(n) void n(Application_Links *app, u32 n)
#define FIND_ALL_MATCHES_BUFFER_RANGE_SIG(n) String_Match_List n(Application_Links *app, Arena *arena, Buffer_ID buffer, i32 string_id, Range range, String_Const_u8 needle, Character_Predicate *predicate, Scan_Direction direction)
#define BUFFER_FIND_ALL_MATCHES_SIG(n) String_Match_List n(Application_Links *app, Arena *arena, Buffer_ID buffer, i32 string_id, Range_i64 range, String_Const_u8 needle, Character_Predicate *predicate, Scan_Direction direction)
#define GET_VIEW_VISIBLE_RANGE_SIG(n) Range n(Application_Links *app, View_ID view_id)
typedef GLOBAL_SET_SETTING_SIG(Global_Set_Setting_Function);
typedef GLOBAL_SET_MAPPING_SIG(Global_Set_Mapping_Function);
@ -359,7 +359,7 @@ typedef COMPUTE_RENDER_LAYOUT_SIG(Compute_Render_Layout_Function);
typedef DRAW_RENDER_LAYOUT_SIG(Draw_Render_Layout_Function);
typedef OPEN_COLOR_PICKER_SIG(Open_Color_Picker_Function);
typedef ANIMATE_IN_N_MILLISECONDS_SIG(Animate_In_N_Milliseconds_Function);
typedef FIND_ALL_MATCHES_BUFFER_RANGE_SIG(Find_All_Matches_Buffer_Range_Function);
typedef BUFFER_FIND_ALL_MATCHES_SIG(Buffer_Find_All_Matches_Function);
typedef GET_VIEW_VISIBLE_RANGE_SIG(Get_View_Visible_Range_Function);
struct Application_Links{
#if defined(ALLOW_DEP_4CODER)
@ -542,7 +542,7 @@ Compute_Render_Layout_Function *compute_render_layout;
Draw_Render_Layout_Function *draw_render_layout;
Open_Color_Picker_Function *open_color_picker;
Animate_In_N_Milliseconds_Function *animate_in_n_milliseconds;
Find_All_Matches_Buffer_Range_Function *find_all_matches_buffer_range;
Buffer_Find_All_Matches_Function *buffer_find_all_matches;
Get_View_Visible_Range_Function *get_view_visible_range;
#else
Global_Set_Setting_Function *global_set_setting_;
@ -724,7 +724,7 @@ Compute_Render_Layout_Function *compute_render_layout_;
Draw_Render_Layout_Function *draw_render_layout_;
Open_Color_Picker_Function *open_color_picker_;
Animate_In_N_Milliseconds_Function *animate_in_n_milliseconds_;
Find_All_Matches_Buffer_Range_Function *find_all_matches_buffer_range_;
Buffer_Find_All_Matches_Function *buffer_find_all_matches_;
Get_View_Visible_Range_Function *get_view_visible_range_;
#endif
void *memory;
@ -914,7 +914,7 @@ app_links->compute_render_layout_ = Compute_Render_Layout;\
app_links->draw_render_layout_ = Draw_Render_Layout;\
app_links->open_color_picker_ = Open_Color_Picker;\
app_links->animate_in_n_milliseconds_ = Animate_In_N_Milliseconds;\
app_links->find_all_matches_buffer_range_ = Find_All_Matches_Buffer_Range;\
app_links->buffer_find_all_matches_ = Buffer_Find_All_Matches;\
app_links->get_view_visible_range_ = Get_View_Visible_Range;} while(false)
#if defined(ALLOW_DEP_4CODER)
static b32 global_set_setting(Application_Links *app, Global_Setting_ID setting, i32 value){return(app->global_set_setting(app, setting, value));}
@ -938,8 +938,8 @@ static Buffer_ID get_buffer_by_file_name(Application_Links *app, String_Const_u8
static b32 buffer_read_range(Application_Links *app, Buffer_ID buffer_id, i32 start, i32 one_past_last, char *out){return(app->buffer_read_range(app, buffer_id, start, one_past_last, out));}
static b32 buffer_replace_range(Application_Links *app, Buffer_ID buffer_id, Range range, String_Const_u8 string){return(app->buffer_replace_range(app, buffer_id, range, string));}
static b32 buffer_batch_edit(Application_Links *app, Buffer_ID buffer_id, char *str, Buffer_Edit *edits, i32 edit_count){return(app->buffer_batch_edit(app, buffer_id, str, edits, edit_count));}
static String_Match buffer_seek_string(Application_Links *app, Buffer_ID buffer, String_Const_u8 needle, Scan_Direction direction, i32 start_pos){return(app->buffer_seek_string(app, buffer, needle, direction, start_pos));}
static b32 buffer_seek_character_class(Application_Links *app, Buffer_ID buffer_id, Character_Predicate *predicate, Scan_Direction direction, i32 start_pos, i32 *pos_out){return(app->buffer_seek_character_class(app, buffer_id, predicate, direction, start_pos, pos_out));}
static String_Match buffer_seek_string(Application_Links *app, Buffer_ID buffer, String_Const_u8 needle, Scan_Direction direction, i64 start_pos){return(app->buffer_seek_string(app, buffer, needle, direction, start_pos));}
static String_Match buffer_seek_character_class(Application_Links *app, Buffer_ID buffer, Character_Predicate *predicate, Scan_Direction direction, i64 start_pos){return(app->buffer_seek_character_class(app, buffer, predicate, direction, start_pos));}
static Partial_Cursor buffer_compute_cursor(Application_Links *app, Buffer_ID buffer_id, Buffer_Seek seek){return(app->buffer_compute_cursor(app, buffer_id, seek));}
static b32 buffer_exists(Application_Links *app, Buffer_ID buffer_id){return(app->buffer_exists(app, buffer_id));}
static b32 buffer_ready(Application_Links *app, Buffer_ID buffer_id){return(app->buffer_ready(app, buffer_id));}
@ -1096,7 +1096,7 @@ static b32 compute_render_layout(Application_Links *app, View_ID view_id, Buffer
static void draw_render_layout(Application_Links *app, View_ID view_id){(app->draw_render_layout(app, view_id));}
static void open_color_picker(Application_Links *app, Color_Picker *picker){(app->open_color_picker(app, picker));}
static void animate_in_n_milliseconds(Application_Links *app, u32 n){(app->animate_in_n_milliseconds(app, n));}
static String_Match_List find_all_matches_buffer_range(Application_Links *app, Arena *arena, Buffer_ID buffer, i32 string_id, Range range, String_Const_u8 needle, Character_Predicate *predicate, Scan_Direction direction){return(app->find_all_matches_buffer_range(app, arena, buffer, string_id, range, needle, predicate, direction));}
static String_Match_List buffer_find_all_matches(Application_Links *app, Arena *arena, Buffer_ID buffer, i32 string_id, Range_i64 range, String_Const_u8 needle, Character_Predicate *predicate, Scan_Direction direction){return(app->buffer_find_all_matches(app, arena, buffer, string_id, range, needle, predicate, direction));}
static Range get_view_visible_range(Application_Links *app, View_ID view_id){return(app->get_view_visible_range(app, view_id));}
#else
static b32 global_set_setting(Application_Links *app, Global_Setting_ID setting, i32 value){return(app->global_set_setting_(app, setting, value));}
@ -1120,8 +1120,8 @@ static Buffer_ID get_buffer_by_file_name(Application_Links *app, String_Const_u8
static b32 buffer_read_range(Application_Links *app, Buffer_ID buffer_id, i32 start, i32 one_past_last, char *out){return(app->buffer_read_range_(app, buffer_id, start, one_past_last, out));}
static b32 buffer_replace_range(Application_Links *app, Buffer_ID buffer_id, Range range, String_Const_u8 string){return(app->buffer_replace_range_(app, buffer_id, range, string));}
static b32 buffer_batch_edit(Application_Links *app, Buffer_ID buffer_id, char *str, Buffer_Edit *edits, i32 edit_count){return(app->buffer_batch_edit_(app, buffer_id, str, edits, edit_count));}
static String_Match buffer_seek_string(Application_Links *app, Buffer_ID buffer, String_Const_u8 needle, Scan_Direction direction, i32 start_pos){return(app->buffer_seek_string_(app, buffer, needle, direction, start_pos));}
static b32 buffer_seek_character_class(Application_Links *app, Buffer_ID buffer_id, Character_Predicate *predicate, Scan_Direction direction, i32 start_pos, i32 *pos_out){return(app->buffer_seek_character_class_(app, buffer_id, predicate, direction, start_pos, pos_out));}
static String_Match buffer_seek_string(Application_Links *app, Buffer_ID buffer, String_Const_u8 needle, Scan_Direction direction, i64 start_pos){return(app->buffer_seek_string_(app, buffer, needle, direction, start_pos));}
static String_Match buffer_seek_character_class(Application_Links *app, Buffer_ID buffer, Character_Predicate *predicate, Scan_Direction direction, i64 start_pos){return(app->buffer_seek_character_class_(app, buffer, predicate, direction, start_pos));}
static Partial_Cursor buffer_compute_cursor(Application_Links *app, Buffer_ID buffer_id, Buffer_Seek seek){return(app->buffer_compute_cursor_(app, buffer_id, seek));}
static b32 buffer_exists(Application_Links *app, Buffer_ID buffer_id){return(app->buffer_exists_(app, buffer_id));}
static b32 buffer_ready(Application_Links *app, Buffer_ID buffer_id){return(app->buffer_ready_(app, buffer_id));}
@ -1278,6 +1278,6 @@ static b32 compute_render_layout(Application_Links *app, View_ID view_id, Buffer
static void draw_render_layout(Application_Links *app, View_ID view_id){(app->draw_render_layout_(app, view_id));}
static void open_color_picker(Application_Links *app, Color_Picker *picker){(app->open_color_picker_(app, picker));}
static void animate_in_n_milliseconds(Application_Links *app, u32 n){(app->animate_in_n_milliseconds_(app, n));}
static String_Match_List find_all_matches_buffer_range(Application_Links *app, Arena *arena, Buffer_ID buffer, i32 string_id, Range range, String_Const_u8 needle, Character_Predicate *predicate, Scan_Direction direction){return(app->find_all_matches_buffer_range_(app, arena, buffer, string_id, range, needle, predicate, direction));}
static String_Match_List buffer_find_all_matches(Application_Links *app, Arena *arena, Buffer_ID buffer, i32 string_id, Range_i64 range, String_Const_u8 needle, Character_Predicate *predicate, Scan_Direction direction){return(app->buffer_find_all_matches_(app, arena, buffer, string_id, range, needle, predicate, direction));}
static Range get_view_visible_range(Application_Links *app, View_ID view_id){return(app->get_view_visible_range_(app, view_id));}
#endif

View File

@ -367,17 +367,19 @@ buffer_seek_character_class_change__inner(Application_Links *app, Buffer_ID buff
switch (direction){
case Scan_Backward:
{
b32 s1 = buffer_seek_character_class(app, buffer, negative, direction, pos, &pos);
b32 s2 = buffer_seek_character_class(app, buffer, positive, direction, pos, &pos);
if (s1 && s2){
String_Match m1 = buffer_seek_character_class(app, buffer, negative, direction, pos);
String_Match m2 = buffer_seek_character_class(app, buffer, positive, direction, m1.range.min);
pos = (i32)m2.range.min;
if (m1.buffer == buffer && m2.buffer == buffer){
pos += 1;
}
}break;
case Scan_Forward:
{
pos -= 1;
buffer_seek_character_class(app, buffer, positive, direction, pos, &pos);
buffer_seek_character_class(app, buffer, negative, direction, pos, &pos);
String_Match m1 = buffer_seek_character_class(app, buffer, positive, direction, pos);
String_Match m2 = buffer_seek_character_class(app, buffer, negative, direction, m1.range.min);
pos = (i32)m2.range.min;
}break;
}
return(pos);
@ -714,23 +716,24 @@ boundary_alpha_numeric_underscore(Application_Links *app, Buffer_ID buffer, Side
static i32
boundary_alpha_numeric_camel(Application_Links *app, Buffer_ID buffer, Side side, Scan_Direction direction, i32 pos){
i32 an_pos = boundary_alpha_numeric(app, buffer, side, direction, pos);
i32 cap_pos = 0;
buffer_seek_character_class(app, buffer, &character_predicate_uppercase,
direction, pos, &cap_pos);
String_Match m = buffer_seek_character_class(app, buffer, &character_predicate_uppercase,
direction, pos);
u64 cap_pos = m.range.min;
if (side == Side_Max){
i32 an_left_pos = boundary_alpha_numeric(app, buffer, flip_side(side),
flip_direction(direction), an_pos);
if (cap_pos == an_left_pos){
buffer_seek_character_class(app, buffer, &character_predicate_uppercase,
direction, cap_pos, &cap_pos);
m = buffer_seek_character_class(app, buffer, &character_predicate_uppercase,
direction, cap_pos);
cap_pos = m.range.min;
}
}
i32 result = 0;
if (direction == Scan_Backward){
result = Max(an_pos, cap_pos);
result = Max(an_pos, (i32)cap_pos);
}
else{
result = Min(an_pos, cap_pos);
result = Min(an_pos, (i32)cap_pos);
}
return(result);
}
@ -856,13 +859,15 @@ boundary_line(Application_Links *app, Buffer_ID buffer, Side side, Scan_Directio
void
buffer_seek_delimiter_forward(Application_Links *app, Buffer_ID buffer, i32 pos, char delim, i32 *result){
Character_Predicate predicate = character_predicate_from_character((u8)delim);
buffer_seek_character_class(app, buffer, &predicate, Scan_Forward, pos, result);
String_Match m = buffer_seek_character_class(app, buffer, &predicate, Scan_Forward, pos);
*result = (i32)m.range.min;
}
void
buffer_seek_delimiter_backward(Application_Links *app, Buffer_ID buffer, i32 pos, char delim, i32 *result){
Character_Predicate predicate = character_predicate_from_character((u8)delim);
buffer_seek_character_class(app, buffer, &predicate, Scan_Backward, pos, result);
String_Match m = buffer_seek_character_class(app, buffer, &predicate, Scan_Backward, pos);
*result = (i32)m.range.min;
}
// TODO(allen): these need a little more rewrite
@ -895,7 +900,7 @@ buffer_seek_string_backward(Application_Links *app, Buffer_ID buffer, i32 pos, i
if (HasFlag(match.flags, StringMatch_CaseSensitive) ||
match.buffer != buffer || match.range.first < min) break;
}
if (match.range.first >= min && match.buffer != buffer){
if (match.range.first >= min && match.buffer == buffer){
*result = (i32)match.range.first;
}
else{
@ -920,7 +925,7 @@ buffer_seek_string_insensitive_forward(Application_Links *app, Buffer_ID buffer,
static void
buffer_seek_string_insensitive_backward(Application_Links *app, Buffer_ID buffer, i32 pos, i32 min, String_Const_u8 needle, i32 *result){
String_Match match = buffer_seek_string(app, buffer, needle, Scan_Backward, pos);
if (match.range.first >= min && match.buffer != buffer){
if (match.range.first >= min && match.buffer == buffer){
*result = (i32)match.range.first;
}
else{

View File

@ -85,7 +85,7 @@ insertf(Buffer_Insertion *insertion, char *format, ...){
Temp_Memory temp = begin_temp(scratch);
va_list args;
va_start(args, format);
String_Const_u8 string = push_u8_stringf(scratch, format, args);
String_Const_u8 string = push_u8_stringfv(scratch, format, args);
va_end(args);
insert_string(insertion, string);
end_temp(temp);

View File

@ -11,7 +11,7 @@
internal void
string_match_list_push(Arena *arena, String_Match_List *list,
Buffer_ID buffer, i32 string_id, String_Match_Flag flags, Range_u64 range){
Buffer_ID buffer, i32 string_id, String_Match_Flag flags, Range_i64 range){
String_Match *match = push_array(arena, String_Match, 1);
sll_queue_push(list->first, list->last, match);
list->count += 1;
@ -23,9 +23,9 @@ string_match_list_push(Arena *arena, String_Match_List *list,
internal void
string_match_list_push(Arena *arena, String_Match_List *list,
Buffer_ID buffer, i32 string_id, String_Match_Flag flags, u64 start, u64 length){
Buffer_ID buffer, i32 string_id, String_Match_Flag flags, i64 start, i64 length){
string_match_list_push(arena, list, buffer, string_id, flags,
make_range_u64(start, start + length));
make_range_i64(start, start + length));
}
internal void

View File

@ -394,14 +394,14 @@ DOC_SEE(Buffer_Batch_Edit_Type)
}
API_EXPORT String_Match
Buffer_Seek_String(Application_Links *app, Buffer_ID buffer, String_Const_u8 needle, Scan_Direction direction, i32 start_pos){
Buffer_Seek_String(Application_Links *app, Buffer_ID buffer, String_Const_u8 needle, Scan_Direction direction, i64 start_pos){
Models *models = (Models*)app->cmd_context;
Editing_File *file = imp_get_file(models, buffer);
String_Match result = {};
if (api_check_buffer(file)){
if (needle.size == 0){
result.flags = StringMatch_CaseSensitive;
result.range = make_range_u64(start_pos);
result.range = make_range_i64(start_pos);
}
else{
Scratch_Block scratch(app);
@ -410,16 +410,16 @@ Buffer_Seek_String(Application_Links *app, Buffer_ID buffer, String_Const_u8 nee
String_Const_u8 space[3];
Cursor cursor = make_cursor(space, sizeof(space));
String_Const_u8_Array chunks = buffer_get_chunks(&cursor, gap_buffer);
Range range = {};
Range_i64 range = {};
if (direction == Scan_Forward){
i32 adjusted_pos = start_pos + 1;
i64 adjusted_pos = start_pos + 1;
start_pos = clamp_top(adjusted_pos, size);
range = make_range(adjusted_pos, size);
range = make_range_i64(adjusted_pos, size);
}
else{
i32 adjusted_pos = start_pos - 1;
i64 adjusted_pos = start_pos - 1;
start_pos = clamp_bot(0, adjusted_pos);
range = make_range(0, adjusted_pos);
range = make_range_i64(0, adjusted_pos);
}
chunks = buffer_chunks_clamp(chunks, range);
if (chunks.count > 0){
@ -427,24 +427,24 @@ Buffer_Seek_String(Application_Links *app, Buffer_ID buffer, String_Const_u8 nee
Character_Predicate dummy = {};
String_Match_List list = find_all_matches(scratch, 1,
chunks, needle, jump_table, &dummy, direction,
range.min, 0, 0);
range.min, buffer, 0);
if (list.count == 1){
result = *list.first;
}
}
else{
result.range = make_range_u64(start_pos);
result.range = Ii64(start_pos);
}
}
}
return(result);
}
API_EXPORT b32
Buffer_Seek_Character_Class(Application_Links *app, Buffer_ID buffer_id, Character_Predicate *predicate, Scan_Direction direction, i32 start_pos, i32 *pos_out){
API_EXPORT String_Match
Buffer_Seek_Character_Class(Application_Links *app, Buffer_ID buffer, Character_Predicate *predicate, Scan_Direction direction, i64 start_pos){
Models *models = (Models*)app->cmd_context;
Editing_File *file = imp_get_file(models, buffer_id);
b32 result = false;
Editing_File *file = imp_get_file(models, buffer);
String_Match result = {};
if (api_check_buffer(file)){
String_Const_u8 chunks_space[2];
Cursor chunks_cursor = make_cursor(chunks_space, sizeof(chunks_space));
@ -452,31 +452,27 @@ Buffer_Seek_Character_Class(Application_Links *app, Buffer_ID buffer_id, Charact
String_Const_u8_Array chunks = buffer_get_chunks(&chunks_cursor, gap_buffer, BufferGetChunk_Basic);
if (chunks.count > 0){
// TODO(allen): rewrite as loop-in-loop for better iteration performance
i32 size = buffer_size(gap_buffer);
start_pos = clamp(-1, start_pos, size);
Buffer_Chunk_Position pos = buffer_get_chunk_position(chunks, size, start_pos);
// TODO(allen): rewrite as loop-in-loop for better iteration performance
Buffer_Chunk_Position pos = buffer_get_chunk_position(chunks, size, (i32)start_pos);
for (;;){
i32 past_end = buffer_chunk_position_iterate(chunks, &pos, direction);
if (past_end == -1){
*pos_out = 0;
break;
}
else if (past_end == 1){
*pos_out = size;
result.range = make_range_i64(size);
break;
}
u8 v = chunks.vals[pos.chunk_index].str[pos.chunk_pos];
if (character_predicate_check_character(*predicate, v)){
result = true;
*pos_out = pos.real_pos;
result.buffer = buffer;
result.range = make_range_i64(pos.real_pos, pos.real_pos + 1);
break;
}
}
}
else{
*pos_out = 0;
}
}
return(result);
}
@ -4093,7 +4089,7 @@ Animate_In_N_Milliseconds(Application_Links *app, u32 n)
}
API_EXPORT String_Match_List
Find_All_Matches_Buffer_Range(Application_Links *app, Arena *arena, Buffer_ID buffer, i32 string_id, Range range, String_Const_u8 needle, Character_Predicate *predicate, Scan_Direction direction)
Buffer_Find_All_Matches(Application_Links *app, Arena *arena, Buffer_ID buffer, i32 string_id, Range_i64 range, String_Const_u8 needle, Character_Predicate *predicate, Scan_Direction direction)
{
Models *models = (Models*)app->cmd_context;
Editing_File *file = imp_get_file(models, buffer);

View File

@ -536,12 +536,12 @@ buffer_get_chunks(Cursor *cursor, Gap_Buffer *buffer){
}
internal String_Const_u8_Array
buffer_chunks_clamp(String_Const_u8_Array chunks, Range range){
i32 real_position = 0;
buffer_chunks_clamp(String_Const_u8_Array chunks, Range_i64 range){
i64 real_position = 0;
for (i32 i = 0; i < chunks.count; i += 1){
Range chunk_range = make_range(real_position, real_position + (i32)chunks.strings[i].size);
Range clamped_range = make_range(clamp(range.min, chunk_range.min, range.max),
clamp(range.min, chunk_range.max, range.max));
Range_i64 chunk_range = Ii64(real_position, real_position + chunks.strings[i].size);
Range_i64 clamped_range = Ii64(clamp(range.min, chunk_range.min, range.max),
clamp(range.min, chunk_range.max, range.max));
chunks.strings[i].str += clamped_range.min - chunk_range.min;
chunks.strings[i].size = range_size(clamped_range);
real_position += range_size(chunk_range);