2017-01-23 06:19:43 +00:00
|
|
|
/*
|
2018-05-10 08:12:47 +00:00
|
|
|
4coder_seek.cpp - Procedures and commands for jumping through code to useful stop boundaries.
|
|
|
|
*/
|
2017-01-23 06:19:43 +00:00
|
|
|
|
|
|
|
// TOP
|
|
|
|
|
2017-03-23 19:15:33 +00:00
|
|
|
void
|
2019-06-09 00:19:55 +00:00
|
|
|
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);
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
|
2019-06-09 00:19:55 +00:00
|
|
|
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);
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-06-01 23:58:28 +00:00
|
|
|
buffer_seek_string_forward(Application_Links *app, Buffer_ID buffer_id, i32 pos, i32 end, String_Const_u8 needle_string, i32 *result){
|
2019-04-01 02:41:39 +00:00
|
|
|
i32 buffer_size = 0;
|
|
|
|
buffer_get_size(app, buffer_id, &buffer_size);
|
|
|
|
if (buffer_size > end){
|
|
|
|
*result = buffer_size;
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
else{
|
|
|
|
*result = end;
|
|
|
|
}
|
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
Scratch_Block scratch(app);
|
|
|
|
if (0 < needle_string.size){
|
2019-04-01 02:41:39 +00:00
|
|
|
if (buffer_exists(app, buffer_id)){
|
2019-06-01 23:58:28 +00:00
|
|
|
u8 first_char = string_get_character(needle_string, 0);
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2019-06-01 23:58:28 +00:00
|
|
|
u8 *read_buffer = push_array(scratch, u8, needle_string.size);
|
|
|
|
String_Const_u8 read_str = SCu8(read_buffer, needle_string.size);
|
2017-01-23 06:19:43 +00:00
|
|
|
|
|
|
|
char chunk[1024];
|
2018-11-20 08:18:54 +00:00
|
|
|
Stream_Chunk stream = {};
|
2017-01-23 06:19:43 +00:00
|
|
|
stream.max_end = end;
|
|
|
|
|
2019-04-01 02:41:39 +00:00
|
|
|
if (init_stream_chunk(&stream, app, buffer_id, pos, chunk, sizeof(chunk))){
|
|
|
|
b32 still_looping = true;
|
2017-01-23 06:19:43 +00:00
|
|
|
do{
|
2017-03-23 19:15:33 +00:00
|
|
|
for(; pos < stream.end; ++pos){
|
2019-06-01 23:58:28 +00:00
|
|
|
u8 at_pos = stream.data[pos];
|
2017-01-23 06:19:43 +00:00
|
|
|
if (at_pos == first_char){
|
2019-06-01 23:58:28 +00:00
|
|
|
buffer_read_range(app, buffer_id, pos, (i32)(pos + needle_string.size), (char*)read_buffer);
|
|
|
|
if (string_match(needle_string, read_str)){
|
2017-01-23 06:19:43 +00:00
|
|
|
*result = pos;
|
|
|
|
goto finished;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
still_looping = forward_stream_chunk(&stream);
|
|
|
|
}while (still_looping);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (end == 0){
|
2019-04-01 02:41:39 +00:00
|
|
|
*result = buffer_size;
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
else{
|
|
|
|
*result = end;
|
|
|
|
}
|
|
|
|
|
|
|
|
finished:;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-06-01 23:58:28 +00:00
|
|
|
buffer_seek_string_backward(Application_Links *app, Buffer_ID buffer_id, i32 pos, i32 min, String_Const_u8 needle_string, i32 *result){
|
|
|
|
Scratch_Block scratch(app);
|
2019-04-01 02:41:39 +00:00
|
|
|
*result = min - 1;
|
2019-06-01 23:58:28 +00:00
|
|
|
if (0 < needle_string.size && buffer_exists(app, buffer_id)){
|
|
|
|
u8 first_char = string_get_character(needle_string, 0);
|
|
|
|
|
|
|
|
u8 *read_buffer = push_array(scratch, u8, needle_string.size);
|
|
|
|
String_Const_u8 read_str = SCu8(read_buffer, needle_string.size);
|
|
|
|
|
2019-04-01 02:41:39 +00:00
|
|
|
char chunk[1024];
|
|
|
|
Stream_Chunk stream = {};
|
|
|
|
stream.min_start = min;
|
2019-06-01 23:58:28 +00:00
|
|
|
|
2019-04-01 02:41:39 +00:00
|
|
|
if (init_stream_chunk(&stream, app, buffer_id, pos, chunk, sizeof(chunk))){
|
2019-06-01 23:58:28 +00:00
|
|
|
b32 still_looping = true;
|
2019-04-01 02:41:39 +00:00
|
|
|
do{
|
|
|
|
for(; pos >= stream.start; --pos){
|
2019-06-01 23:58:28 +00:00
|
|
|
u8 at_pos = stream.data[pos];
|
2019-04-01 02:41:39 +00:00
|
|
|
if (at_pos == first_char){
|
2019-06-01 23:58:28 +00:00
|
|
|
buffer_read_range(app, buffer_id, pos, (i32)(pos + needle_string.size), (char*)read_buffer);
|
|
|
|
if (string_match(needle_string, read_str)){
|
2019-04-01 02:41:39 +00:00
|
|
|
*result = pos;
|
|
|
|
goto finished;
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
}
|
2019-04-01 02:41:39 +00:00
|
|
|
}
|
|
|
|
still_looping = backward_stream_chunk(&stream);
|
|
|
|
}while (still_looping);
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
finished:;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-06-01 23:58:28 +00:00
|
|
|
buffer_seek_string_insensitive_forward(Application_Links *app, Buffer_ID buffer_id, i32 pos, i32 end, String_Const_u8 needle_string, i32 *result){
|
2019-04-01 02:41:39 +00:00
|
|
|
i32 buffer_size = 0;
|
|
|
|
buffer_get_size(app, buffer_id, &buffer_size);
|
|
|
|
if (buffer_size > end){
|
|
|
|
*result = buffer_size;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
*result = end;
|
|
|
|
}
|
2019-06-01 23:58:28 +00:00
|
|
|
|
|
|
|
Scratch_Block scratch(app);
|
|
|
|
if (0 < needle_string.size && buffer_exists(app, buffer_id)){
|
|
|
|
u8 first_char = character_to_upper(string_get_character(needle_string, 0));
|
|
|
|
|
|
|
|
u8 *read_buffer = push_array(scratch, u8, needle_string.size);
|
|
|
|
String_Const_u8 read_str = SCu8(read_buffer, needle_string.size);
|
|
|
|
|
|
|
|
char chunk[1024];
|
|
|
|
Stream_Chunk stream = {};
|
|
|
|
stream.max_end = end;
|
|
|
|
|
|
|
|
if (init_stream_chunk(&stream, app, buffer_id, pos, chunk, sizeof(chunk))){
|
|
|
|
b32 still_looping = true;
|
2019-04-01 02:41:39 +00:00
|
|
|
do{
|
|
|
|
for(; pos < stream.end; ++pos){
|
2019-06-01 23:58:28 +00:00
|
|
|
u8 at_pos = character_to_upper(stream.data[pos]);
|
2019-04-01 02:41:39 +00:00
|
|
|
if (at_pos == first_char){
|
2019-06-01 23:58:28 +00:00
|
|
|
buffer_read_range(app, buffer_id, pos, (i32)(pos + needle_string.size), (char*)read_buffer);
|
|
|
|
if (string_match_insensitive(needle_string, read_str)){
|
2019-04-01 02:41:39 +00:00
|
|
|
*result = pos;
|
|
|
|
goto finished;
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
}
|
2019-04-01 02:41:39 +00:00
|
|
|
}
|
|
|
|
still_looping = forward_stream_chunk(&stream);
|
|
|
|
}while (still_looping);
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
finished:;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-06-01 23:58:28 +00:00
|
|
|
buffer_seek_string_insensitive_backward(Application_Links *app, Buffer_ID buffer_id, i32 pos, i32 min, String_Const_u8 needle_string, i32 *result){
|
|
|
|
Scratch_Block scratch(app);
|
2019-04-01 02:41:39 +00:00
|
|
|
*result = min - 1;
|
2019-06-01 23:58:28 +00:00
|
|
|
if (0 < needle_string.size && buffer_exists(app, buffer_id)){
|
|
|
|
u8 first_char = character_to_upper(string_get_character(needle_string, 0));
|
|
|
|
|
|
|
|
u8 *read_buffer = push_array(scratch, u8, needle_string.size);
|
|
|
|
String_Const_u8 read_str = SCu8(read_buffer, needle_string.size);
|
|
|
|
|
|
|
|
char chunk[1024];
|
|
|
|
Stream_Chunk stream = {};
|
|
|
|
stream.min_start = min;
|
|
|
|
|
|
|
|
if (init_stream_chunk(&stream, app, buffer_id, pos, chunk, sizeof(chunk))){
|
|
|
|
b32 still_looping = true;
|
2019-04-01 02:41:39 +00:00
|
|
|
do{
|
|
|
|
for(; pos >= stream.start; --pos){
|
2019-06-01 23:58:28 +00:00
|
|
|
u8 at_pos = character_to_upper(stream.data[pos]);
|
2019-04-01 02:41:39 +00:00
|
|
|
if (at_pos == first_char){
|
2019-06-01 23:58:28 +00:00
|
|
|
buffer_read_range(app, buffer_id, pos, (i32)(pos + needle_string.size), (char*)read_buffer);
|
|
|
|
if (string_match_insensitive(needle_string, read_str)){
|
2019-04-01 02:41:39 +00:00
|
|
|
*result = pos;
|
|
|
|
goto finished;
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
}
|
2019-04-01 02:41:39 +00:00
|
|
|
}
|
|
|
|
still_looping = backward_stream_chunk(&stream);
|
|
|
|
}while (still_looping);
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
finished:;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-29 23:00:14 +00:00
|
|
|
static void
|
2019-06-01 23:58:28 +00:00
|
|
|
buffer_seek_string(Application_Links *app, Buffer_ID buffer_id, i32 pos, i32 end, i32 min, String_Const_u8 str, i32 *result, Buffer_Seek_String_Flags flags){
|
2017-11-29 23:00:14 +00:00
|
|
|
switch (flags & 3){
|
|
|
|
case 0:
|
|
|
|
{
|
2019-06-01 23:58:28 +00:00
|
|
|
buffer_seek_string_forward(app, buffer_id, pos, end, str, result);
|
2017-11-29 23:00:14 +00:00
|
|
|
}break;
|
|
|
|
|
|
|
|
case BufferSeekString_Backward:
|
|
|
|
{
|
2019-06-01 23:58:28 +00:00
|
|
|
buffer_seek_string_backward(app, buffer_id, pos, min, str, result);
|
2017-11-29 23:00:14 +00:00
|
|
|
}break;
|
|
|
|
|
|
|
|
case BufferSeekString_CaseInsensitive:
|
|
|
|
{
|
2019-06-01 23:58:28 +00:00
|
|
|
buffer_seek_string_insensitive_forward(app, buffer_id, pos, end, str, result);
|
2017-11-29 23:00:14 +00:00
|
|
|
}break;
|
|
|
|
|
|
|
|
case BufferSeekString_Backward|BufferSeekString_CaseInsensitive:
|
|
|
|
{
|
2019-06-01 23:58:28 +00:00
|
|
|
buffer_seek_string_insensitive_backward(app, buffer_id, pos, min, str, result);
|
2017-11-29 23:00:14 +00:00
|
|
|
}break;
|
|
|
|
}
|
|
|
|
}
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2018-05-10 08:12:47 +00:00
|
|
|
////////////////////////////////
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2019-06-05 23:04:35 +00:00
|
|
|
internal void
|
|
|
|
seek_pos_of_textual_line(Application_Links *app, Side side){
|
2019-04-06 21:13:49 +00:00
|
|
|
View_ID view = 0;
|
|
|
|
get_active_view(app, AccessProtected, &view);
|
2019-04-01 02:41:39 +00:00
|
|
|
Buffer_ID buffer_id = 0;
|
2019-04-06 21:13:49 +00:00
|
|
|
view_get_buffer(app, view, AccessProtected, &buffer_id);
|
|
|
|
i32 pos = 0;
|
|
|
|
view_get_cursor_pos(app, view, &pos);
|
2019-06-05 23:04:35 +00:00
|
|
|
i32 new_pos = get_line_side_pos_from_pos(app, buffer_id, pos, side);
|
2019-04-06 21:13:49 +00:00
|
|
|
view_set_cursor(app, view, seek_pos(new_pos), true);
|
|
|
|
no_mark_snap_to_cursor_if_shift(app, view);
|
2018-05-10 08:12:47 +00:00
|
|
|
}
|
|
|
|
|
2019-06-05 23:04:35 +00:00
|
|
|
internal void
|
|
|
|
seek_pos_of_visual_line(Application_Links *app, Side side){
|
2019-04-06 21:13:49 +00:00
|
|
|
View_ID view = 0;
|
|
|
|
get_active_view(app, AccessProtected, &view);
|
|
|
|
i32 pos = 0;
|
|
|
|
view_get_cursor_pos(app, view, &pos);
|
2019-06-05 23:04:35 +00:00
|
|
|
Full_Cursor cursor = {};
|
|
|
|
view_compute_cursor(app, view, seek_pos(pos), &cursor);
|
|
|
|
f32 y = cursor.wrapped_y;
|
|
|
|
f32 x = (side == Side_Min)?(0.f):(max_f32);
|
|
|
|
view_set_cursor(app, view, seek_wrapped_xy(x, y, true), true);
|
2019-04-06 21:13:49 +00:00
|
|
|
no_mark_snap_to_cursor_if_shift(app, view);
|
2018-05-10 08:12:47 +00:00
|
|
|
}
|
|
|
|
|
2019-06-05 23:04:35 +00:00
|
|
|
CUSTOM_COMMAND_SIG(seek_beginning_of_textual_line)
|
|
|
|
CUSTOM_DOC("Seeks the cursor to the beginning of the line across all text.")
|
|
|
|
{
|
|
|
|
seek_pos_of_textual_line(app, Side_Min);
|
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_COMMAND_SIG(seek_end_of_textual_line)
|
|
|
|
CUSTOM_DOC("Seeks the cursor to the end of the line across all text.")
|
|
|
|
{
|
|
|
|
seek_pos_of_textual_line(app, Side_Max);
|
|
|
|
}
|
|
|
|
|
2018-05-10 08:12:47 +00:00
|
|
|
CUSTOM_COMMAND_SIG(seek_beginning_of_line)
|
|
|
|
CUSTOM_DOC("Seeks the cursor to the beginning of the visual line.")
|
|
|
|
{
|
2019-06-05 23:04:35 +00:00
|
|
|
seek_pos_of_visual_line(app, Side_Min);
|
2018-05-10 08:12:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_COMMAND_SIG(seek_end_of_line)
|
|
|
|
CUSTOM_DOC("Seeks the cursor to the end of the visual line.")
|
|
|
|
{
|
2019-06-05 23:04:35 +00:00
|
|
|
seek_pos_of_visual_line(app, Side_Max);
|
2018-05-10 08:12:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_COMMAND_SIG(goto_beginning_of_file)
|
|
|
|
CUSTOM_DOC("Sets the cursor to the beginning of the file.")
|
|
|
|
{
|
2019-04-06 21:13:49 +00:00
|
|
|
View_ID view = 0;
|
|
|
|
get_active_view(app, AccessProtected, &view);
|
|
|
|
view_set_cursor(app, view, seek_pos(0), true);
|
|
|
|
no_mark_snap_to_cursor_if_shift(app, view);
|
2018-05-10 08:12:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_COMMAND_SIG(goto_end_of_file)
|
|
|
|
CUSTOM_DOC("Sets the cursor to the end of the file.")
|
|
|
|
{
|
2019-04-06 21:13:49 +00:00
|
|
|
View_ID view = 0;
|
|
|
|
get_active_view(app, AccessProtected, &view);
|
2019-04-02 20:06:49 +00:00
|
|
|
Buffer_ID buffer_id = 0;
|
2019-04-06 21:13:49 +00:00
|
|
|
view_get_buffer(app, view, AccessProtected, &buffer_id);
|
2019-04-02 20:06:49 +00:00
|
|
|
i32 size = 0;
|
|
|
|
buffer_get_size(app, buffer_id, &size);
|
2019-04-06 21:13:49 +00:00
|
|
|
view_set_cursor(app, view, seek_pos(size), true);
|
|
|
|
no_mark_snap_to_cursor_if_shift(app, view);
|
2018-05-10 08:12:47 +00:00
|
|
|
}
|
|
|
|
|
2019-02-21 04:43:25 +00:00
|
|
|
// BOTTOM
|
|
|
|
|