diff --git a/4coder_API/4coder_types.h b/4coder_API/4coder_types.h index 48bf6c23..e5bf320a 100644 --- a/4coder_API/4coder_types.h +++ b/4coder_API/4coder_types.h @@ -612,6 +612,8 @@ DOC_SEE(4coder_Buffer_Positioning_System) */ STRUCT Partial_Cursor{ /* DOC(This field contains the cursor's position in absolute byte index positioning.) */ i32 pos; + /* DOC(This field contains the cursor's position in apparent character index positioning.) */ + i32 character_pos; /* DOC(This field contains the number of the character from the beginninf of the line where the cursor is located. This field is one based.) */ i32 line; diff --git a/4coder_api_transition_30_31_helpers.cpp b/4coder_api_transition_30_31_helpers.cpp index 3ba86e0e..aa73b0b7 100644 --- a/4coder_api_transition_30_31_helpers.cpp +++ b/4coder_api_transition_30_31_helpers.cpp @@ -173,12 +173,12 @@ get_token_or_word_under_pos(Application_Links *app, Buffer_Summary *buffer, i32 static i32 seek_line_end(Application_Links *app, Buffer_Summary *buffer, i32 pos){ - return(buffer==0?0:seek_line_end(app, buffer->buffer_id, pos)); + return(buffer==0?0:get_line_end_pos_from_pos(app, buffer->buffer_id, pos)); } static i32 seek_line_beginning(Application_Links *app, Buffer_Summary *buffer, i32 pos){ - return(buffer==0?0:seek_line_beginning(app, buffer->buffer_id, pos)); + return(buffer==0?0:get_line_start_pos_from_pos(app, buffer->buffer_id, pos)); } static void @@ -188,12 +188,12 @@ move_past_lead_whitespace(Application_Links *app, View_Summary *view, Buffer_Sum static i32 buffer_seek_whitespace_up(Application_Links *app, Buffer_Summary *buffer, i32 pos){ - return(buffer==0?0:buffer_seek_whitespace_up(app, buffer->buffer_id, pos)); + return(buffer==0?0:get_pos_of_blank_line(app, buffer->buffer_id, Scan_Backward, pos)); } static i32 buffer_seek_whitespace_down(Application_Links *app, Buffer_Summary *buffer, i32 pos){ - return(buffer==0?0:buffer_seek_whitespace_down(app, buffer->buffer_id, pos)); + return(buffer==0?0:get_pos_of_blank_line(app, buffer->buffer_id, Scan_Forward, pos)); } static i32 @@ -316,7 +316,7 @@ buffer_seek_string(Application_Links *app, Buffer_Summary *buffer, i32 pos, i32 static b32 buffer_line_is_blank(Application_Links *app, Buffer_Summary *buffer, i32 line){ - return(buffer==0?0:buffer_line_is_blank(app, buffer->buffer_id, line)); + return(buffer==0?0:line_is_valid_and_blank(app, buffer->buffer_id, line)); } static String diff --git a/4coder_base_types.h b/4coder_base_types.h index 72b39387..f38eb892 100644 --- a/4coder_base_types.h +++ b/4coder_base_types.h @@ -1013,6 +1013,12 @@ enum{ Side_Max = 1, }; +typedef i32 Scan_Direction; +enum{ + Scan_Backward = -1, + Scan_Forward = 1, +}; + //////////////////////////////// #define Migrating__Arena diff --git a/4coder_generated/command_metadata.h b/4coder_generated/command_metadata.h index 87cbff93..69ce3aa5 100644 --- a/4coder_generated/command_metadata.h +++ b/4coder_generated/command_metadata.h @@ -256,30 +256,30 @@ int32_t line_number; }; static Command_Metadata fcoder_metacmd_table[234] = { { PROC_LINKS(replace_all_occurrences, 0), "replace_all_occurrences", 23, "Queries the user for two strings, and replaces all occurrences of the first string with the second string in all open buffers.", 126, "w:\\4ed\\code\\4coder_experiments.cpp", 34, 806 }, -{ PROC_LINKS(seek_whitespace_up, 0), "seek_whitespace_up", 18, "Seeks the cursor up to the next blank line.", 43, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1041 }, -{ PROC_LINKS(seek_whitespace_down, 0), "seek_whitespace_down", 20, "Seeks the cursor down to the next blank line.", 45, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1055 }, -{ PROC_LINKS(seek_beginning_of_textual_line, 0), "seek_beginning_of_textual_line", 30, "Seeks the cursor to the beginning of the line across all text.", 62, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1069 }, -{ PROC_LINKS(seek_end_of_textual_line, 0), "seek_end_of_textual_line", 24, "Seeks the cursor to the end of the line across all text.", 56, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1083 }, -{ PROC_LINKS(seek_beginning_of_line, 0), "seek_beginning_of_line", 22, "Seeks the cursor to the beginning of the visual line.", 53, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1097 }, -{ PROC_LINKS(seek_end_of_line, 0), "seek_end_of_line", 16, "Seeks the cursor to the end of the visual line.", 47, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1111 }, -{ PROC_LINKS(seek_whitespace_up_end_line, 0), "seek_whitespace_up_end_line", 27, "Seeks the cursor up to the next blank line and places it at the end of the line.", 80, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1125 }, -{ PROC_LINKS(seek_whitespace_down_end_line, 0), "seek_whitespace_down_end_line", 29, "Seeks the cursor down to the next blank line and places it at the end of the line.", 82, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1140 }, -{ PROC_LINKS(goto_beginning_of_file, 0), "goto_beginning_of_file", 22, "Sets the cursor to the beginning of the file.", 45, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1155 }, -{ PROC_LINKS(goto_end_of_file, 0), "goto_end_of_file", 16, "Sets the cursor to the end of the file.", 39, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1164 }, -{ PROC_LINKS(seek_whitespace_right, 0), "seek_whitespace_right", 21, "Seek right for the next boundary between whitespace and non-whitespace.", 71, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1179 }, -{ PROC_LINKS(seek_whitespace_left, 0), "seek_whitespace_left", 20, "Seek left for the next boundary between whitespace and non-whitespace.", 70, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1185 }, -{ PROC_LINKS(seek_token_right, 0), "seek_token_right", 16, "Seek right for the next end of a token.", 39, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1191 }, -{ PROC_LINKS(seek_token_left, 0), "seek_token_left", 15, "Seek left for the next beginning of a token.", 44, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1197 }, -{ PROC_LINKS(seek_white_or_token_right, 0), "seek_white_or_token_right", 25, "Seek right for the next end of a token or boundary between whitespace and non-whitespace.", 89, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1203 }, -{ PROC_LINKS(seek_white_or_token_left, 0), "seek_white_or_token_left", 24, "Seek left for the next end of a token or boundary between whitespace and non-whitespace.", 88, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1209 }, -{ PROC_LINKS(seek_alphanumeric_right, 0), "seek_alphanumeric_right", 23, "Seek right for boundary between alphanumeric characters and non-alphanumeric characters.", 88, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1215 }, -{ PROC_LINKS(seek_alphanumeric_left, 0), "seek_alphanumeric_left", 22, "Seek left for boundary between alphanumeric characters and non-alphanumeric characters.", 87, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1221 }, -{ PROC_LINKS(seek_alphanumeric_or_camel_right, 0), "seek_alphanumeric_or_camel_right", 32, "Seek right for boundary between alphanumeric characters or camel case word and non-alphanumeric characters.", 107, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1227 }, -{ PROC_LINKS(seek_alphanumeric_or_camel_left, 0), "seek_alphanumeric_or_camel_left", 31, "Seek left for boundary between alphanumeric characters or camel case word and non-alphanumeric characters.", 106, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1233 }, -{ PROC_LINKS(backspace_word, 0), "backspace_word", 14, "Delete characters between the cursor position and the first alphanumeric boundary to the left.", 94, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1241 }, -{ PROC_LINKS(delete_word, 0), "delete_word", 11, "Delete characters between the cursor position and the first alphanumeric boundary to the right.", 95, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1247 }, -{ PROC_LINKS(snipe_token_or_word, 0), "snipe_token_or_word", 19, "Delete a single, whole token on or to the left of the cursor and post it to the clipboard.", 90, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1253 }, -{ PROC_LINKS(snipe_token_or_word_right, 0), "snipe_token_or_word_right", 25, "Delete a single, whole token on or to the right of the cursor and post it to the clipboard.", 91, "w:\\4ed\\code\\4coder_seek.cpp", 27, 1259 }, +{ PROC_LINKS(seek_whitespace_up, 0), "seek_whitespace_up", 18, "Seeks the cursor up to the next blank line.", 43, "w:\\4ed\\code\\4coder_seek.cpp", 27, 833 }, +{ PROC_LINKS(seek_whitespace_down, 0), "seek_whitespace_down", 20, "Seeks the cursor down to the next blank line.", 45, "w:\\4ed\\code\\4coder_seek.cpp", 27, 839 }, +{ PROC_LINKS(seek_beginning_of_textual_line, 0), "seek_beginning_of_textual_line", 30, "Seeks the cursor to the beginning of the line across all text.", 62, "w:\\4ed\\code\\4coder_seek.cpp", 27, 845 }, +{ PROC_LINKS(seek_end_of_textual_line, 0), "seek_end_of_textual_line", 24, "Seeks the cursor to the end of the line across all text.", 56, "w:\\4ed\\code\\4coder_seek.cpp", 27, 851 }, +{ PROC_LINKS(seek_beginning_of_line, 0), "seek_beginning_of_line", 22, "Seeks the cursor to the beginning of the visual line.", 53, "w:\\4ed\\code\\4coder_seek.cpp", 27, 857 }, +{ PROC_LINKS(seek_end_of_line, 0), "seek_end_of_line", 16, "Seeks the cursor to the end of the visual line.", 47, "w:\\4ed\\code\\4coder_seek.cpp", 27, 863 }, +{ PROC_LINKS(seek_whitespace_up_end_line, 0), "seek_whitespace_up_end_line", 27, "Seeks the cursor up to the next blank line and places it at the end of the line.", 80, "w:\\4ed\\code\\4coder_seek.cpp", 27, 869 }, +{ PROC_LINKS(seek_whitespace_down_end_line, 0), "seek_whitespace_down_end_line", 29, "Seeks the cursor down to the next blank line and places it at the end of the line.", 82, "w:\\4ed\\code\\4coder_seek.cpp", 27, 875 }, +{ PROC_LINKS(goto_beginning_of_file, 0), "goto_beginning_of_file", 22, "Sets the cursor to the beginning of the file.", 45, "w:\\4ed\\code\\4coder_seek.cpp", 27, 881 }, +{ PROC_LINKS(goto_end_of_file, 0), "goto_end_of_file", 16, "Sets the cursor to the end of the file.", 39, "w:\\4ed\\code\\4coder_seek.cpp", 27, 890 }, +{ PROC_LINKS(seek_whitespace_right, 0), "seek_whitespace_right", 21, "Seek right for the next boundary between whitespace and non-whitespace.", 71, "w:\\4ed\\code\\4coder_seek.cpp", 27, 905 }, +{ PROC_LINKS(seek_whitespace_left, 0), "seek_whitespace_left", 20, "Seek left for the next boundary between whitespace and non-whitespace.", 70, "w:\\4ed\\code\\4coder_seek.cpp", 27, 911 }, +{ PROC_LINKS(seek_token_right, 0), "seek_token_right", 16, "Seek right for the next end of a token.", 39, "w:\\4ed\\code\\4coder_seek.cpp", 27, 917 }, +{ PROC_LINKS(seek_token_left, 0), "seek_token_left", 15, "Seek left for the next beginning of a token.", 44, "w:\\4ed\\code\\4coder_seek.cpp", 27, 923 }, +{ PROC_LINKS(seek_white_or_token_right, 0), "seek_white_or_token_right", 25, "Seek right for the next end of a token or boundary between whitespace and non-whitespace.", 89, "w:\\4ed\\code\\4coder_seek.cpp", 27, 929 }, +{ PROC_LINKS(seek_white_or_token_left, 0), "seek_white_or_token_left", 24, "Seek left for the next end of a token or boundary between whitespace and non-whitespace.", 88, "w:\\4ed\\code\\4coder_seek.cpp", 27, 935 }, +{ PROC_LINKS(seek_alphanumeric_right, 0), "seek_alphanumeric_right", 23, "Seek right for boundary between alphanumeric characters and non-alphanumeric characters.", 88, "w:\\4ed\\code\\4coder_seek.cpp", 27, 941 }, +{ PROC_LINKS(seek_alphanumeric_left, 0), "seek_alphanumeric_left", 22, "Seek left for boundary between alphanumeric characters and non-alphanumeric characters.", 87, "w:\\4ed\\code\\4coder_seek.cpp", 27, 947 }, +{ PROC_LINKS(seek_alphanumeric_or_camel_right, 0), "seek_alphanumeric_or_camel_right", 32, "Seek right for boundary between alphanumeric characters or camel case word and non-alphanumeric characters.", 107, "w:\\4ed\\code\\4coder_seek.cpp", 27, 953 }, +{ PROC_LINKS(seek_alphanumeric_or_camel_left, 0), "seek_alphanumeric_or_camel_left", 31, "Seek left for boundary between alphanumeric characters or camel case word and non-alphanumeric characters.", 106, "w:\\4ed\\code\\4coder_seek.cpp", 27, 959 }, +{ PROC_LINKS(backspace_word, 0), "backspace_word", 14, "Delete characters between the cursor position and the first alphanumeric boundary to the left.", 94, "w:\\4ed\\code\\4coder_seek.cpp", 27, 967 }, +{ PROC_LINKS(delete_word, 0), "delete_word", 11, "Delete characters between the cursor position and the first alphanumeric boundary to the right.", 95, "w:\\4ed\\code\\4coder_seek.cpp", 27, 973 }, +{ PROC_LINKS(snipe_token_or_word, 0), "snipe_token_or_word", 19, "Delete a single, whole token on or to the left of the cursor and post it to the clipboard.", 90, "w:\\4ed\\code\\4coder_seek.cpp", 27, 979 }, +{ PROC_LINKS(snipe_token_or_word_right, 0), "snipe_token_or_word_right", 25, "Delete a single, whole token on or to the right of the cursor and post it to the clipboard.", 91, "w:\\4ed\\code\\4coder_seek.cpp", 27, 985 }, { PROC_LINKS(change_active_panel, 0), "change_active_panel", 19, "Change the currently active panel, moving to the panel with the next highest view_id.", 85, "w:\\4ed\\code\\4coder_default_framework.cpp", 40, 206 }, { PROC_LINKS(change_active_panel_backwards, 0), "change_active_panel_backwards", 29, "Change the currently active panel, moving to the panel with the next lowest view_id.", 84, "w:\\4ed\\code\\4coder_default_framework.cpp", 40, 217 }, { PROC_LINKS(open_panel_vsplit, 0), "open_panel_vsplit", 17, "Create a new panel by vertically splitting the active panel.", 60, "w:\\4ed\\code\\4coder_default_framework.cpp", 40, 228 }, diff --git a/4coder_helper.cpp b/4coder_helper.cpp index ac69d755..73f76502 100644 --- a/4coder_helper.cpp +++ b/4coder_helper.cpp @@ -384,18 +384,18 @@ character_pos_to_pos_buffer(Application_Links *app, Buffer_ID buffer, i32 charac } static Partial_Cursor -get_line__book_end(Application_Links *app, Buffer_ID buffer, i32 line_number, i32 side){ +get_line_side(Application_Links *app, Buffer_ID buffer, i32 line_number, Side side){ Partial_Cursor result = {}; - if (!buffer_compute_cursor(app, buffer, seek_line_char(line_number, side), &result)){ + i32 character_index = (side == Side_Min)?(1):(-1); + if (!buffer_compute_cursor(app, buffer, seek_line_char(line_number, character_index), &result)){ block_zero_struct(&result); } return(result); } - static i32 -get_line__book_end_pos(Application_Links *app, Buffer_ID buffer, i32 line_number, i32 side){ +get_line_side_pos(Application_Links *app, Buffer_ID buffer, i32 line_number, Side side){ i32 pos = -1; - Partial_Cursor partial_cursor = get_line__book_end(app, buffer, line_number, side); + Partial_Cursor partial_cursor = get_line_side(app, buffer, line_number, side); if (partial_cursor.line != 0){ pos = partial_cursor.pos; } @@ -404,26 +404,33 @@ get_line__book_end_pos(Application_Links *app, Buffer_ID buffer, i32 line_number static Partial_Cursor get_line_start(Application_Links *app, Buffer_ID buffer, i32 line_number){ - return(get_line__book_end(app, buffer, line_number, 1)); + return(get_line_side(app, buffer, line_number, Side_Min)); +} +static i32 +get_line_start_pos(Application_Links *app, Buffer_ID buffer, i32 line_number){ + return(get_line_side_pos(app, buffer, line_number, Side_Min)); } // NOTE(allen): The position returned has the index of the terminating newline character, // not one past the newline character. static Partial_Cursor get_line_end(Application_Links *app, Buffer_ID buffer, i32 line_number){ - return(get_line__book_end(app, buffer, line_number, -1)); + return(get_line_side(app, buffer, line_number, Side_Max)); } - -static i32 -get_line_start_pos(Application_Links *app, Buffer_ID buffer, i32 line_number){ - return(get_line__book_end_pos(app, buffer, line_number, 1)); -} - -// NOTE(allen): The position returned has the index of the terminating newline character, -// not one past the newline character. static i32 get_line_end_pos(Application_Links *app, Buffer_ID buffer, i32 line_number){ - return(get_line__book_end_pos(app, buffer, line_number, -1)); + return(get_line_side_pos(app, buffer, line_number, Side_Max)); +} + +static i32 +get_line_pos(Application_Links *app, Buffer_ID buffer, i32 line_number, Side side){ + i32 result = 0; + if (side == Side_Min){ + result = get_line_start_pos(app, buffer, line_number); + } + else{ + result = get_line_start_pos(app, buffer, line_number); + } } // NOTE(allen): The range returned does not include the terminating newline character @@ -460,6 +467,20 @@ make_range_from_cursors(Range_Partial_Cursor range){ return(make_range(range.begin.pos, range.end.pos)); } +static i32 +get_line_side_pos_from_pos(Application_Links *app, Buffer_ID buffer, i32 pos, Side side){ + i32 line_number = get_line_number_from_pos(app, buffer, pos); + return(get_line_side_pos(app, buffer, line_number, side)); +} +static i32 +get_line_start_pos_from_pos(Application_Links *app, Buffer_ID buffer, i32 pos){ + return(get_line_side_pos_from_pos(app, buffer, pos, Side_Min)); +} +static i32 +get_line_end_pos_from_pos(Application_Links *app, Buffer_ID buffer, i32 pos){ + return(get_line_side_pos_from_pos(app, buffer, pos, Side_Max)); +} + static Cpp_Token* get_first_token_from_pos(Cpp_Token_Array tokens, i32 pos){ Cpp_Get_Token_Result get_token = cpp_get_token(tokens, pos); @@ -613,6 +634,107 @@ token_lexeme_string_match(Application_Links *app, Buffer_ID buffer, Cpp_Token to return(string_match(push_token_lexeme(app, scratch, buffer, token), b)); } +static b32 +line_is_valid_and_blank(Application_Links *app, Buffer_ID buffer, i32 line_number){ + b32 result = false; + if (is_valid_line(app, buffer, line_number)){ + Scratch_Block scratch(app); + String_Const_u8 line = push_buffer_line(app, scratch, buffer, line_number); + result = true; + for (umem i = 0; i < line.size; i += 1){ + if (!character_is_whitespace(line.str[i])){ + result = false; + break; + } + } + } + return(result); +} + +//////////////////////////////// + +static i32 +get_pos_past_lead_whitespace(Application_Links *app, Buffer_ID buffer, i32 pos){ + Scratch_Block scratch(app); + i32 line_number = get_line_number_from_pos(app, buffer, pos); + Range line_range = get_line_pos_range(app, buffer, line_number); + String_Const_u8 line = push_buffer_range(app, scratch, buffer, line_range); + i32 result = line_range.end; + for (umem i = 0; i < line.size; i += 1){ + if (!character_is_whitespace(line.str[i])){ + result = line_range.start + (i32)i; + break; + } + } + result = clamp_bot(result, pos); + return(result); +} + +static void +move_past_lead_whitespace(Application_Links *app, View_ID view, Buffer_ID buffer){ + i32 pos = 0; + view_get_cursor_pos(app, view, &pos); + i32 new_pos = get_pos_past_lead_whitespace(app, buffer, pos); + view_set_cursor(app, view, seek_pos(new_pos), true); +} + +static void +move_past_lead_whitespace(Application_Links *app, View_ID view){ + Buffer_ID buffer = 0; + view_get_buffer(app, view, AccessProtected, &buffer); + move_past_lead_whitespace(app, view, buffer); +} + +static i32 +get_line_number_of_blank_line(Application_Links *app, Buffer_ID buffer, Scan_Direction direction, i32 line_number_start){ + i32 line_count = 0; + buffer_get_line_count(app, buffer, &line_count); + i32 line_number = line_number_start + direction; + for (;1 <= line_number && line_number <= line_count; line_number += direction){ + Scratch_Block scratch(app); + String_Const_u8 line = push_buffer_line(app, scratch, buffer, line_number); + b32 is_blank = true; + for (umem i = 0; i < line.size; i += 1){ + if (!character_is_whitespace(line.str[i])){ + is_blank = false; + break; + } + } + if (is_blank){ + break; + } + } + line_number = clamp(1, line_number, line_count); + return(line_number); +} + +static i32 +get_pos_of_blank_line(Application_Links *app, Buffer_ID buffer, Scan_Direction direction, i32 pos_start){ + i32 line_number_start = get_line_number_from_pos(app, buffer, pos_start); + i32 blank_line = get_line_number_of_blank_line(app, buffer, direction, line_number_start); + i32 pos = get_line_start_pos(app, buffer, blank_line); + return(pos); +} + +//////////////////////////////// + +static Cpp_Token_Array +buffer_get_all_tokens(Application_Links *app, Arena *arena, Buffer_ID buffer_id){ + Cpp_Token_Array array = {}; + if (buffer_exists(app, buffer_id)){ + b32 is_lexed = false; + if (buffer_get_setting(app, buffer_id, BufferSetting_Lex, &is_lexed)){ + if (is_lexed){ + buffer_token_count(app, buffer_id, &array.count); + array.max_count = array.count; + array.tokens = push_array(arena, Cpp_Token, array.count); + buffer_read_tokens(app, buffer_id, 0, array.count, array.tokens); + } + } + } + return(array); +} + //////////////////////////////// static i32 diff --git a/4coder_scope_commands.cpp b/4coder_scope_commands.cpp index 8b469a1a..9d91addd 100644 --- a/4coder_scope_commands.cpp +++ b/4coder_scope_commands.cpp @@ -414,8 +414,8 @@ place_begin_and_end_on_own_lines(Application_Links *app, char *begin, char *end) Scratch_Block scratch(app); - b32 min_line_blank = buffer_line_is_blank(app, buffer, lines.min); - b32 max_line_blank = buffer_line_is_blank(app, buffer, lines.max); + b32 min_line_blank = line_is_valid_and_blank(app, buffer, lines.min); + b32 max_line_blank = line_is_valid_and_blank(app, buffer, lines.max); if ((lines.min < lines.max) || (!min_line_blank)){ String_Const_u8 begin_str = {}; diff --git a/4coder_seek.cpp b/4coder_seek.cpp index 528d322b..8274a00e 100644 --- a/4coder_seek.cpp +++ b/4coder_seek.cpp @@ -4,210 +4,6 @@ // TOP -// TODO(allen): This seems suspiciously, overkilling, redundant. -static i32 -seek_line_end(Application_Links *app, Buffer_ID buffer_id, i32 pos){ - i32 buffer_size = 0; - buffer_get_size(app, buffer_id, &buffer_size); - - char chunk[1024]; - i32 chunk_size = sizeof(chunk); - Stream_Chunk stream = {}; - if (init_stream_chunk(&stream, app, buffer_id, pos, chunk, chunk_size)){ - b32 still_looping = true; - do{ - for (; pos < stream.end; ++pos){ - char at_pos = stream.data[pos]; - if (at_pos == '\n'){ - goto double_break; - } - } - still_looping = forward_stream_chunk(&stream); - }while(still_looping); - double_break:; - if (pos > buffer_size){ - pos = buffer_size; - } - } - return(pos); -} - -// TODO(allen): This seems suspiciously, overkilling, redundant. -static i32 -seek_line_beginning(Application_Links *app, Buffer_ID buffer_id, i32 pos){ - char chunk[1024]; - i32 chunk_size = sizeof(chunk); - Stream_Chunk stream = {}; - --pos; - if (init_stream_chunk(&stream, app, buffer_id, pos, chunk, chunk_size)){ - b32 still_looping = true; - do{ - for (; pos >= stream.start; --pos){ - char at_pos = stream.data[pos]; - if (at_pos == '\n'){ - goto double_break; - } - } - still_looping = backward_stream_chunk(&stream); - }while(still_looping); - double_break:; - if (pos != 0){ - ++pos; - } - if (pos < 0){ - pos = 0; - } - } - return(pos); -} - -static void -move_past_lead_whitespace(Application_Links *app, View_ID view, Buffer_ID buffer_id){ - i32 pos = 0; - view_get_cursor_pos(app, view, &pos); - - i32 new_pos = seek_line_beginning(app, buffer_id, pos); - char space[1024]; - Stream_Chunk chunk = {}; - i32 still_looping = false; - - i32 i = new_pos; - if (init_stream_chunk(&chunk, app, buffer_id, i, space, sizeof(space))){ - do{ - for (; i < chunk.end; ++i){ - char at_pos = chunk.data[i]; - if (at_pos == '\n' || !character_is_whitespace(at_pos)){ - goto break2; - } - } - still_looping = forward_stream_chunk(&chunk); - }while(still_looping); - break2:; - - if (i > pos){ - view_set_cursor(app, view, seek_pos(i), true); - } - } -} - -static i32 -buffer_seek_whitespace_up(Application_Links *app, Buffer_ID buffer_id, i32 pos){ - char chunk[1024]; - i32 chunk_size = sizeof(chunk); - Stream_Chunk stream = {}; - - - --pos; - if (init_stream_chunk(&stream, app, buffer_id, pos, chunk, chunk_size)){ - // Step 1: Find the first non-whitespace character - // behind the current position. - b32 still_looping = true; - for (;still_looping;){ - for (; pos >= stream.start; --pos){ - char at_pos = stream.data[pos]; - if (!character_is_whitespace(at_pos)){ - goto double_break_1; - } - } - still_looping = backward_stream_chunk(&stream); - } - double_break_1:; - - // Step 2: Continue scanning backward, at each '\n' - // mark the beginning of another line by setting - // no_hard to true, set it back to false if a - // non-whitespace character is discovered before - // the next '\n' - i32 no_hard = false; - for (;still_looping;){ - for (; pos >= stream.start; --pos){ - char at_pos = stream.data[pos]; - if (at_pos == '\n'){ - if (no_hard){ - goto double_break_2; - } - else{ - no_hard = true; - } - } - else if (!character_is_whitespace(at_pos)){ - no_hard = false; - } - } - still_looping = backward_stream_chunk(&stream); - } - double_break_2:; - - if (pos != 0){ - ++pos; - } - } - - return(pos); -} - -static i32 -buffer_seek_whitespace_down(Application_Links *app, Buffer_ID buffer_id, i32 pos){ - i32 buffer_size = 0; - buffer_get_size(app, buffer_id, &buffer_size); - - char chunk[1024]; - i32 chunk_size = sizeof(chunk); - Stream_Chunk stream = {}; - - if (init_stream_chunk(&stream, app, buffer_id, pos, chunk, chunk_size)){ - // step 1: find the first non-whitespace character - // ahead of the current position. - b32 still_looping = true; - do{ - for (; pos < stream.end; ++pos){ - char at_pos = stream.data[pos]; - if (!character_is_whitespace(at_pos)){ - goto double_break_1; - } - } - still_looping = forward_stream_chunk(&stream); - } while(still_looping); - double_break_1:; - - // step 2: continue scanning forward, at each '\n' - // mark it as the beginning of a new line by updating - // the prev_endline value. if another '\n' is found - // with non-whitespace then the previous line was - // all whitespace. - b32 no_hard = false; - i32 prev_endline = -1; - while(still_looping){ - for (; pos < stream.end; ++pos){ - char at_pos = stream.data[pos]; - if (at_pos == '\n'){ - if (no_hard){ - goto double_break_2; - } - else{ - no_hard = true; - prev_endline = pos; - } - } - else if (!character_is_whitespace(at_pos)){ - no_hard = false; - } - } - still_looping = forward_stream_chunk(&stream); - } - double_break_2:; - - if (prev_endline == -1 || prev_endline + 1 >= buffer_size){ - pos = buffer_size; - } - else{ - pos = prev_endline + 1; - } - } - - return(pos); -} - static i32 buffer_seek_whitespace_right(Application_Links *app, Buffer_ID buffer_id, i32 pos){ i32 buffer_size = 0; @@ -525,23 +321,6 @@ seek_token_right(Cpp_Token_Array *tokens, i32 pos, i32 buffer_end){ return(result); } -static Cpp_Token_Array -buffer_get_all_tokens(Application_Links *app, Arena *arena, Buffer_ID buffer_id){ - Cpp_Token_Array array = {}; - if (buffer_exists(app, buffer_id)){ - b32 is_lexed = false; - if (buffer_get_setting(app, buffer_id, BufferSetting_Lex, &is_lexed)){ - if (is_lexed){ - buffer_token_count(app, buffer_id, &array.count); - array.max_count = array.count; - array.tokens = push_array(arena, Cpp_Token, array.count); - buffer_read_tokens(app, buffer_id, 0, array.count, array.tokens); - } - } - } - return(array); -} - static i32 buffer_boundary_seek(Application_Links *app, Buffer_ID buffer_id, Arena *scratch, i32 start_pos, b32 seek_forward, Seek_Boundary_Flag flags){ i32 result = 0; @@ -554,12 +333,7 @@ buffer_boundary_seek(Application_Links *app, Buffer_ID buffer_id, Arena *scratch i32 new_pos = 0; buffer_get_size(app, buffer_id, &size); - if (start_pos < 0){ - start_pos = 0; - } - else if (start_pos > size){ - start_pos = size; - } + start_pos = clamp(0, start_pos, size); if (seek_forward){ for (i32 i = 0; i < ArrayCount(pos); ++i){ @@ -885,42 +659,6 @@ buffer_seek_string(Application_Links *app, Buffer_ID buffer_id, i32 pos, i32 end //////////////////////////////// -static b32 -buffer_line_is_blank(Application_Links *app, Buffer_ID buffer_id, i32 line){ - Partial_Cursor start = {}; - Partial_Cursor end = {}; - b32 result = false; - i32 line_count = 0; - buffer_get_line_count(app, buffer_id, &line_count); - if (line <= line_count){ - buffer_compute_cursor(app, buffer_id, seek_line_char(line, 1), &start); - buffer_compute_cursor(app, buffer_id, seek_line_char(line, -1), &end); - - static const i32 chunk_size = 1024; - char chunk[chunk_size]; - Stream_Chunk stream = {}; - i32 i = start.pos; - stream.max_end = end.pos; - - result = true; - if (init_stream_chunk(&stream, app, buffer_id, i, chunk, chunk_size)){ - b32 still_looping = false; - do{ - for (;i < stream.end; ++i){ - char c = stream.data[i]; - if (!character_is_whitespace(c)){ - result = false; - goto double_break; - } - } - still_looping = forward_stream_chunk(&stream); - }while(still_looping); - } - double_break:; - } - return(result); -} - static String_Const_u8 read_identifier_at_pos(Application_Links *app, Arena *arena, Buffer_ID buffer_id, i32 pos, Range *range_out){ i32 start = buffer_seek_alphanumeric_or_underscore_left(app, buffer_id, pos); @@ -1038,118 +776,106 @@ current_view_snipe_delete(Application_Links *app, i32 dir, u32 flags){ //////////////////////////////// -CUSTOM_COMMAND_SIG(seek_whitespace_up) -CUSTOM_DOC("Seeks the cursor up to the next blank line.") -{ +internal void +seek_blank_line(Application_Links *app, Scan_Direction direction){ View_ID view = 0; get_active_view(app, AccessProtected, &view); Buffer_ID buffer_id = 0; view_get_buffer(app, view, AccessProtected, &buffer_id); i32 pos = 0; view_get_cursor_pos(app, view, &pos); - i32 new_pos = buffer_seek_whitespace_up(app, buffer_id, pos); + i32 new_pos = get_pos_of_blank_line(app, buffer_id, direction, pos); view_set_cursor(app, view, seek_pos(new_pos), true); no_mark_snap_to_cursor_if_shift(app, view); } +internal void +seek_blank_line_skip_leading_whitespace(Application_Links *app, Scan_Direction direction){ + View_ID view = 0; + get_active_view(app, AccessProtected, &view); + Buffer_ID buffer_id = 0; + view_get_buffer(app, view, AccessProtected, &buffer_id); + i32 pos = 0; + view_get_cursor_pos(app, view, &pos); + i32 new_pos = get_pos_of_blank_line(app, buffer_id, direction, pos); + new_pos = get_pos_past_lead_whitespace(app, buffer_id, new_pos); + view_set_cursor(app, view, seek_pos(new_pos), true); + no_mark_snap_to_cursor_if_shift(app, view); +} + +internal void +seek_pos_of_textual_line(Application_Links *app, Side side){ + View_ID view = 0; + get_active_view(app, AccessProtected, &view); + Buffer_ID buffer_id = 0; + view_get_buffer(app, view, AccessProtected, &buffer_id); + i32 pos = 0; + view_get_cursor_pos(app, view, &pos); + i32 new_pos = get_line_side_pos_from_pos(app, buffer_id, pos, side); + view_set_cursor(app, view, seek_pos(new_pos), true); + no_mark_snap_to_cursor_if_shift(app, view); +} + +internal void +seek_pos_of_visual_line(Application_Links *app, Side side){ + View_ID view = 0; + get_active_view(app, AccessProtected, &view); + i32 pos = 0; + view_get_cursor_pos(app, view, &pos); + 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); + no_mark_snap_to_cursor_if_shift(app, view); +} + +CUSTOM_COMMAND_SIG(seek_whitespace_up) +CUSTOM_DOC("Seeks the cursor up to the next blank line.") +{ + seek_blank_line(app, Scan_Backward); +} + CUSTOM_COMMAND_SIG(seek_whitespace_down) CUSTOM_DOC("Seeks the cursor down to the next blank line.") { - View_ID view = 0; - get_active_view(app, AccessProtected, &view); - Buffer_ID buffer_id = 0; - view_get_buffer(app, view, AccessProtected, &buffer_id); - i32 pos = 0; - view_get_cursor_pos(app, view, &pos); - i32 new_pos = buffer_seek_whitespace_down(app, buffer_id, pos); - view_set_cursor(app, view, seek_pos(new_pos), true); - no_mark_snap_to_cursor_if_shift(app, view); + seek_blank_line(app, Scan_Forward); } CUSTOM_COMMAND_SIG(seek_beginning_of_textual_line) CUSTOM_DOC("Seeks the cursor to the beginning of the line across all text.") { - View_ID view = 0; - get_active_view(app, AccessProtected, &view); - Buffer_ID buffer_id = 0; - view_get_buffer(app, view, AccessProtected, &buffer_id); - i32 pos = 0; - view_get_cursor_pos(app, view, &pos); - i32 new_pos = seek_line_beginning(app, buffer_id, pos); - view_set_cursor(app, view, seek_pos(new_pos), true); - no_mark_snap_to_cursor_if_shift(app, view); + 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.") { - View_ID view = 0; - get_active_view(app, AccessProtected, &view); - Buffer_ID buffer_id = 0; - view_get_buffer(app, view, AccessProtected, &buffer_id); - i32 pos = 0; - view_get_cursor_pos(app, view, &pos); - i32 new_pos = seek_line_end(app, buffer_id, pos); - view_set_cursor(app, view, seek_pos(new_pos), true); - no_mark_snap_to_cursor_if_shift(app, view); + seek_pos_of_textual_line(app, Side_Max); } CUSTOM_COMMAND_SIG(seek_beginning_of_line) CUSTOM_DOC("Seeks the cursor to the beginning of the visual line.") { - View_ID view = 0; - get_active_view(app, AccessProtected, &view); - i32 pos = 0; - view_get_cursor_pos(app, view, &pos); - Full_Cursor cursor = {}; - view_compute_cursor(app, view, seek_pos(pos), &cursor); - f32 y = cursor.wrapped_y; - view_set_cursor(app, view, seek_wrapped_xy(0.f, y, true), true); - no_mark_snap_to_cursor_if_shift(app, view); + seek_pos_of_visual_line(app, Side_Min); } CUSTOM_COMMAND_SIG(seek_end_of_line) CUSTOM_DOC("Seeks the cursor to the end of the visual line.") { - View_ID view = 0; - get_active_view(app, AccessProtected, &view); - i32 pos = 0; - view_get_cursor_pos(app, view, &pos); - Full_Cursor cursor = {}; - view_compute_cursor(app, view, seek_pos(pos), &cursor); - f32 y = cursor.wrapped_y; - view_set_cursor(app, view, seek_wrapped_xy(max_f32, y, true), true); - no_mark_snap_to_cursor_if_shift(app, view); + seek_pos_of_visual_line(app, Side_Max); } CUSTOM_COMMAND_SIG(seek_whitespace_up_end_line) CUSTOM_DOC("Seeks the cursor up to the next blank line and places it at the end of the line.") { - View_ID view = 0; - get_active_view(app, AccessProtected, &view); - Buffer_ID buffer_id = 0; - view_get_buffer(app, view, AccessProtected, &buffer_id); - i32 pos = 0; - view_get_cursor_pos(app, view, &pos); - i32 new_pos = buffer_seek_whitespace_up(app, buffer_id, pos); - new_pos = seek_line_end(app, buffer_id, new_pos); - view_set_cursor(app, view, seek_pos(new_pos), true); - no_mark_snap_to_cursor_if_shift(app, view); + seek_blank_line_skip_leading_whitespace(app, Scan_Backward); } CUSTOM_COMMAND_SIG(seek_whitespace_down_end_line) CUSTOM_DOC("Seeks the cursor down to the next blank line and places it at the end of the line.") { - View_ID view = 0; - get_active_view(app, AccessProtected, &view); - Buffer_ID buffer_id = 0; - view_get_buffer(app, view, AccessProtected, &buffer_id); - i32 pos = 0; - view_get_cursor_pos(app, view, &pos); - i32 new_pos = buffer_seek_whitespace_down(app, buffer_id, pos); - new_pos = seek_line_end(app, buffer_id, new_pos); - view_set_cursor(app, view, seek_pos(new_pos), true); - no_mark_snap_to_cursor_if_shift(app, view); + seek_blank_line_skip_leading_whitespace(app, Scan_Forward); } CUSTOM_COMMAND_SIG(goto_beginning_of_file) @@ -1264,4 +990,3 @@ CUSTOM_DOC("Delete a single, whole token on or to the right of the cursor and po // BOTTOM - diff --git a/4ed_buffer.cpp b/4ed_buffer.cpp index 3d9edb32..2e1c43b0 100644 --- a/4ed_buffer.cpp +++ b/4ed_buffer.cpp @@ -1167,16 +1167,11 @@ buffer_partial_from_pos(Gap_Buffer *buffer, i32 pos){ Partial_Cursor result = {}; i32 size = buffer_size(buffer); - if (pos > size){ - pos = size; - } - if (pos < 0){ - pos = 0; - } + pos = clamp(0, pos, size); i32 line_index = buffer_get_line_index_range(buffer, pos, 0, buffer->line_count); result.pos = pos; - result.line = line_index+1; + result.line = line_index + 1; result.character = pos - buffer->line_starts[line_index] + 1; return(result); @@ -1187,20 +1182,16 @@ buffer_partial_from_line_character(Gap_Buffer *buffer, i32 line, i32 character){ Partial_Cursor result = {}; i32 line_index = line - 1; - if (line_index >= buffer->line_count){ - line_index = buffer->line_count - 1; - } - if (line_index < 0){ - line_index = 0; - } + i32 last_line_index = buffer->line_count - 1; + line_index = clamp(0, line_index, last_line_index); i32 size = buffer_size(buffer); i32 this_start = buffer->line_starts[line_index]; - i32 max_character = (size-this_start) + 1; - if (line_index+1 < buffer->line_count){ - i32 next_start = buffer->line_starts[line_index+1]; - max_character = (next_start-this_start); + i32 max_character = (size - this_start) + 1; + if (line_index < last_line_index){ + i32 next_start = buffer->line_starts[line_index + 1]; + max_character = (next_start - this_start); } i32 adjusted_pos = 0;