2017-01-23 06:19:43 +00:00
|
|
|
/*
|
|
|
|
4coder_search.cpp - Commands that search accross buffers including word complete,
|
|
|
|
and list all locations.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// TOP
|
|
|
|
|
|
|
|
//
|
|
|
|
// Search Iteration Systems
|
|
|
|
//
|
|
|
|
|
2019-07-13 03:19:24 +00:00
|
|
|
global String_Const_u8 search_name = string_u8_litexpr("*search*");
|
|
|
|
|
|
|
|
internal void
|
|
|
|
print_string_match_list_to_buffer(Application_Links *app, Buffer_ID out_buffer_id, String_Match_List matches){
|
|
|
|
Scratch_Block scratch(app);
|
|
|
|
clear_buffer(app, out_buffer_id);
|
|
|
|
Buffer_Insertion out = begin_buffer_insertion_at_buffered(app, out_buffer_id, 0, scratch, KB(64));
|
|
|
|
buffer_set_setting(app, out_buffer_id, BufferSetting_ReadOnly, true);
|
|
|
|
buffer_set_setting(app, out_buffer_id, BufferSetting_RecordsHistory, false);
|
|
|
|
|
|
|
|
Temp_Memory buffer_name_restore_point = begin_temp(scratch);
|
|
|
|
String_Const_u8 current_file_name = {};
|
|
|
|
Buffer_ID current_buffer = 0;
|
|
|
|
|
2019-07-27 02:31:01 +00:00
|
|
|
if (matches.first != 0){
|
|
|
|
for (String_Match *node = matches.first;
|
|
|
|
node != 0;
|
|
|
|
node = node->next){
|
|
|
|
if (node->buffer != out_buffer_id){
|
|
|
|
if (current_buffer != 0 && current_buffer != node->buffer){
|
|
|
|
insertc(&out, '\n');
|
2019-07-13 03:19:24 +00:00
|
|
|
}
|
2019-07-27 02:31:01 +00:00
|
|
|
if (current_buffer != node->buffer){
|
|
|
|
end_temp(buffer_name_restore_point);
|
|
|
|
current_buffer = node->buffer;
|
|
|
|
current_file_name = push_buffer_file_name(app, scratch, current_buffer);
|
|
|
|
if (current_file_name.size == 0){
|
|
|
|
current_file_name = push_buffer_unique_name(app, scratch, current_buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-02 18:59:36 +00:00
|
|
|
Buffer_Cursor cursor = buffer_compute_cursor(app, current_buffer, seek_pos(node->range.first));
|
2019-07-27 02:31:01 +00:00
|
|
|
Temp_Memory line_temp = begin_temp(scratch);
|
2019-09-02 18:59:36 +00:00
|
|
|
String_Const_u8 full_line_str = push_buffer_line(app, scratch, current_buffer, cursor.line);
|
2019-07-27 02:31:01 +00:00
|
|
|
String_Const_u8 line_str = string_skip_chop_whitespace(full_line_str);
|
2019-09-02 18:59:36 +00:00
|
|
|
insertf(&out, "%.*s:%d:%d: %.*s\n",
|
|
|
|
string_expand(current_file_name), cursor.line, cursor.col,
|
|
|
|
string_expand(line_str));
|
2019-07-27 02:31:01 +00:00
|
|
|
end_temp(line_temp);
|
2019-07-13 03:19:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-07-27 02:31:01 +00:00
|
|
|
else{
|
|
|
|
insertf(&out, "no matches");
|
|
|
|
}
|
2019-07-13 03:19:24 +00:00
|
|
|
|
|
|
|
end_buffer_insertion(&out);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void
|
|
|
|
print_all_matches_all_buffers(Application_Links *app, String_Const_u8_Array match_patterns, String_Match_Flag must_have_flags, String_Match_Flag must_not_have_flags, Buffer_ID out_buffer_id){
|
|
|
|
Scratch_Block scratch(app);
|
|
|
|
String_Match_List matches = find_all_matches_all_buffers(app, scratch, match_patterns, must_have_flags, must_not_have_flags);
|
|
|
|
string_match_list_filter_remove_buffer(&matches, out_buffer_id);
|
2019-07-31 20:43:27 +00:00
|
|
|
string_match_list_filter_remove_buffer_predicate(app, &matches, buffer_has_name_with_star);
|
2019-07-13 03:19:24 +00:00
|
|
|
print_string_match_list_to_buffer(app, out_buffer_id, matches);
|
|
|
|
}
|
2019-07-13 00:43:17 +00:00
|
|
|
|
2019-07-13 03:19:24 +00:00
|
|
|
internal void
|
|
|
|
print_all_matches_all_buffers(Application_Links *app, String_Const_u8 pattern, String_Match_Flag must_have_flags, String_Match_Flag must_not_have_flags, Buffer_ID out_buffer_id){
|
|
|
|
String_Const_u8_Array array = {&pattern, 1};
|
|
|
|
print_all_matches_all_buffers(app, array, must_have_flags, must_not_have_flags, out_buffer_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void
|
|
|
|
print_all_matches_all_buffers_to_search(Application_Links *app, String_Const_u8_Array match_patterns, String_Match_Flag must_have_flags, String_Match_Flag must_not_have_flags, View_ID default_target_view){
|
|
|
|
Buffer_ID search_buffer = create_or_switch_to_buffer_and_clear_by_name(app, search_name, default_target_view);
|
|
|
|
print_all_matches_all_buffers(app, match_patterns, must_have_flags, must_not_have_flags, search_buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void
|
|
|
|
print_all_matches_all_buffers_to_search(Application_Links *app, String_Const_u8 pattern, String_Match_Flag must_have_flags, String_Match_Flag must_not_have_flags, View_ID default_target_view){
|
|
|
|
String_Const_u8_Array array = {&pattern, 1};
|
|
|
|
print_all_matches_all_buffers_to_search(app, array, must_have_flags, must_not_have_flags, default_target_view);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal String_Const_u8
|
|
|
|
query_user_list_needle(Application_Links *app, Arena *arena){
|
|
|
|
u8 *space = push_array(arena, u8, KB(1));
|
|
|
|
return(get_query_string(app, "List Locations For: ", space, KB(1)));
|
|
|
|
}
|
|
|
|
|
|
|
|
internal String_Const_u8_Array
|
|
|
|
user_list_definition_array(Application_Links *app, Arena *arena, String_Const_u8 base_needle){
|
|
|
|
String_Const_u8_Array result = {};
|
|
|
|
if (base_needle.size > 0){
|
|
|
|
result.count = 9;
|
|
|
|
result.vals = push_array(arena, String_Const_u8, result.count);
|
|
|
|
i32 i = 0;
|
|
|
|
result.vals[i++] = (push_u8_stringf(arena, "struct %.*s{" , string_expand(base_needle)));
|
|
|
|
result.vals[i++] = (push_u8_stringf(arena, "struct %.*s\n{", string_expand(base_needle)));
|
|
|
|
result.vals[i++] = (push_u8_stringf(arena, "struct %.*s {" , string_expand(base_needle)));
|
|
|
|
result.vals[i++] = (push_u8_stringf(arena, "union %.*s{" , string_expand(base_needle)));
|
|
|
|
result.vals[i++] = (push_u8_stringf(arena, "union %.*s\n{" , string_expand(base_needle)));
|
|
|
|
result.vals[i++] = (push_u8_stringf(arena, "union %.*s {" , string_expand(base_needle)));
|
|
|
|
result.vals[i++] = (push_u8_stringf(arena, "enum %.*s{" , string_expand(base_needle)));
|
|
|
|
result.vals[i++] = (push_u8_stringf(arena, "enum %.*s\n{" , string_expand(base_needle)));
|
|
|
|
result.vals[i++] = (push_u8_stringf(arena, "enum %.*s {" , string_expand(base_needle)));
|
|
|
|
Assert(i == result.count);
|
|
|
|
}
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal String_Const_u8_Array
|
|
|
|
query_user_list_definition_needle(Application_Links *app, Arena *arena){
|
|
|
|
u8 *space = push_array(arena, u8, KB(1));
|
|
|
|
String_Const_u8 base_needle = get_query_string(app, "List Definitions For: ", space, KB(1));
|
|
|
|
return(user_list_definition_array(app, arena, base_needle));
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void
|
|
|
|
list_all_locations__generic(Application_Links *app, String_Const_u8_Array needle, List_All_Locations_Flag flags){
|
|
|
|
if (needle.count > 0){
|
2019-10-18 02:54:02 +00:00
|
|
|
View_ID target_view = get_next_view_after_active(app, Access_Always);
|
2019-07-13 03:19:24 +00:00
|
|
|
String_Match_Flag must_have_flags = 0;
|
|
|
|
String_Match_Flag must_not_have_flags = 0;
|
|
|
|
if (HasFlag(flags, ListAllLocationsFlag_CaseSensitive)){
|
|
|
|
AddFlag(must_have_flags, StringMatch_CaseSensitive);
|
|
|
|
}
|
|
|
|
if (!HasFlag(flags, ListAllLocationsFlag_MatchSubstring)){
|
|
|
|
AddFlag(must_not_have_flags, StringMatch_LeftSideSloppy);
|
|
|
|
AddFlag(must_not_have_flags, StringMatch_RightSideSloppy);
|
|
|
|
}
|
|
|
|
print_all_matches_all_buffers_to_search(app, needle, must_have_flags, must_not_have_flags, target_view);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void
|
|
|
|
list_all_locations__generic(Application_Links *app, String_Const_u8 needle, List_All_Locations_Flag flags){
|
|
|
|
String_Const_u8_Array array = {&needle, 1};
|
|
|
|
list_all_locations__generic(app, array, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void
|
|
|
|
list_all_locations__generic_query(Application_Links *app, List_All_Locations_Flag flags){
|
|
|
|
Scratch_Block scratch(app);
|
|
|
|
String_Const_u8 needle = query_user_list_needle(app, scratch);
|
|
|
|
list_all_locations__generic(app, needle, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void
|
|
|
|
list_all_locations__generic_identifier(Application_Links *app, List_All_Locations_Flag flags){
|
|
|
|
Scratch_Block scratch(app);
|
|
|
|
String_Const_u8 needle = push_token_or_word_under_active_cursor(app, scratch);
|
|
|
|
list_all_locations__generic(app, needle, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void
|
|
|
|
list_all_locations__generic_view_range(Application_Links *app, List_All_Locations_Flag flags){
|
|
|
|
Scratch_Block scratch(app);
|
|
|
|
String_Const_u8 needle = push_view_range_string(app, scratch);
|
|
|
|
list_all_locations__generic(app, needle, flags);
|
|
|
|
}
|
|
|
|
|
2019-07-13 00:43:17 +00:00
|
|
|
CUSTOM_COMMAND_SIG(list_all_locations)
|
|
|
|
CUSTOM_DOC("Queries the user for a string and lists all exact case-sensitive matches found in all open buffers.")
|
|
|
|
{
|
2019-07-13 03:19:24 +00:00
|
|
|
list_all_locations__generic_query(app, ListAllLocationsFlag_CaseSensitive);
|
2019-07-13 00:43:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_COMMAND_SIG(list_all_substring_locations)
|
|
|
|
CUSTOM_DOC("Queries the user for a string and lists all case-sensitive substring matches found in all open buffers.")
|
|
|
|
{
|
2019-07-13 03:19:24 +00:00
|
|
|
list_all_locations__generic_query(app, ListAllLocationsFlag_CaseSensitive|ListAllLocationsFlag_MatchSubstring);
|
2019-07-13 00:43:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_COMMAND_SIG(list_all_locations_case_insensitive)
|
|
|
|
CUSTOM_DOC("Queries the user for a string and lists all exact case-insensitive matches found in all open buffers.")
|
|
|
|
{
|
2019-07-13 03:19:24 +00:00
|
|
|
list_all_locations__generic_query(app, 0);
|
2019-07-13 00:43:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_COMMAND_SIG(list_all_substring_locations_case_insensitive)
|
|
|
|
CUSTOM_DOC("Queries the user for a string and lists all case-insensitive substring matches found in all open buffers.")
|
|
|
|
{
|
2019-07-13 03:19:24 +00:00
|
|
|
list_all_locations__generic_query(app, ListAllLocationsFlag_MatchSubstring);
|
2019-07-13 00:43:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_COMMAND_SIG(list_all_locations_of_identifier)
|
|
|
|
CUSTOM_DOC("Reads a token or word under the cursor and lists all exact case-sensitive mathces in all open buffers.")
|
|
|
|
{
|
2019-07-13 03:19:24 +00:00
|
|
|
list_all_locations__generic_identifier(app, ListAllLocationsFlag_CaseSensitive);
|
2019-07-13 00:43:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_COMMAND_SIG(list_all_locations_of_identifier_case_insensitive)
|
|
|
|
CUSTOM_DOC("Reads a token or word under the cursor and lists all exact case-insensitive mathces in all open buffers.")
|
|
|
|
{
|
2019-07-13 03:19:24 +00:00
|
|
|
list_all_locations__generic_identifier(app, ListAllLocationsFlag_CaseSensitive|ListAllLocationsFlag_MatchSubstring);
|
2019-07-13 00:43:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_COMMAND_SIG(list_all_locations_of_selection)
|
|
|
|
CUSTOM_DOC("Reads the string in the selected range and lists all exact case-sensitive mathces in all open buffers.")
|
|
|
|
{
|
2019-07-13 03:19:24 +00:00
|
|
|
list_all_locations__generic_view_range(app, ListAllLocationsFlag_CaseSensitive);
|
2019-07-13 00:43:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_COMMAND_SIG(list_all_locations_of_selection_case_insensitive)
|
|
|
|
CUSTOM_DOC("Reads the string in the selected range and lists all exact case-insensitive mathces in all open buffers.")
|
|
|
|
{
|
2019-07-13 03:19:24 +00:00
|
|
|
list_all_locations__generic_view_range(app, 0);
|
2019-07-13 00:43:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_COMMAND_SIG(list_all_locations_of_type_definition)
|
|
|
|
CUSTOM_DOC("Queries user for string, lists all locations of strings that appear to define a type whose name matches the input string.")
|
|
|
|
{
|
2019-07-13 03:19:24 +00:00
|
|
|
Scratch_Block scratch(app);
|
|
|
|
String_Const_u8_Array array = query_user_list_definition_needle(app, scratch);
|
|
|
|
list_all_locations__generic(app, array, ListAllLocationsFlag_CaseSensitive|ListAllLocationsFlag_MatchSubstring);
|
2019-07-13 00:43:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_COMMAND_SIG(list_all_locations_of_type_definition_of_identifier)
|
|
|
|
CUSTOM_DOC("Reads a token or word under the cursor and lists all locations of strings that appear to define a type whose name matches it.")
|
|
|
|
{
|
2019-07-13 03:19:24 +00:00
|
|
|
Scratch_Block scratch(app);
|
|
|
|
String_Const_u8 base_needle = push_token_or_word_under_active_cursor(app, scratch);
|
|
|
|
String_Const_u8_Array array = user_list_definition_array(app, scratch, base_needle);
|
|
|
|
list_all_locations__generic(app, array, ListAllLocationsFlag_CaseSensitive|ListAllLocationsFlag_MatchSubstring);
|
2019-07-13 00:43:17 +00:00
|
|
|
}
|
|
|
|
|
2019-07-14 22:18:59 +00:00
|
|
|
internal Range_i64
|
|
|
|
get_word_complete_needle_range(Application_Links *app, Buffer_ID buffer, i64 pos){
|
|
|
|
Range_i64 needle_range = {};
|
|
|
|
needle_range.max = pos;
|
|
|
|
needle_range.min = scan(app, boundary_alpha_numeric_underscore_utf8, buffer, Scan_Backward, pos);
|
|
|
|
i64 e = scan(app, boundary_alpha_numeric_underscore_utf8, buffer, Scan_Forward, needle_range.min);
|
|
|
|
if (needle_range.max > e){
|
2019-10-06 06:59:35 +00:00
|
|
|
needle_range = Ii64(pos);
|
2017-11-29 23:00:14 +00:00
|
|
|
}
|
2019-07-14 22:18:59 +00:00
|
|
|
return(needle_range);
|
2017-11-29 23:00:14 +00:00
|
|
|
}
|
|
|
|
|
2019-07-14 22:18:59 +00:00
|
|
|
internal void
|
2019-10-18 03:18:15 +00:00
|
|
|
string_match_list_enclose_all(Application_Links *app, String_Match_List list,
|
|
|
|
Enclose_Function *enclose){
|
2019-07-14 22:18:59 +00:00
|
|
|
for (String_Match *node = list.first;
|
|
|
|
node != 0;
|
|
|
|
node = node->next){
|
|
|
|
node->range = enclose(app, node->buffer, node->range);
|
2016-07-12 18:20:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-19 18:55:56 +00:00
|
|
|
global String_Match_Flag complete_must = (StringMatch_CaseSensitive|
|
|
|
|
StringMatch_RightSideSloppy);
|
|
|
|
global String_Match_Flag complete_must_not = StringMatch_LeftSideSloppy;
|
|
|
|
|
|
|
|
internal String_Match_List
|
|
|
|
get_complete_list_raw(Application_Links *app, Arena *arena, Buffer_ID buffer,
|
|
|
|
Range_i64 needle_range, String_Const_u8 needle){
|
|
|
|
local_persist Character_Predicate *pred =
|
|
|
|
&character_predicate_alpha_numeric_underscore_utf8;
|
|
|
|
|
|
|
|
String_Match_List result = {};
|
|
|
|
i64 size = buffer_get_size(app, buffer);
|
|
|
|
if (range_size(needle_range) > 0){
|
|
|
|
String_Match_List up = buffer_find_all_matches(app, arena, buffer, 0,
|
|
|
|
Ii64(0, needle_range.min),
|
|
|
|
needle, pred, Scan_Backward);
|
|
|
|
String_Match_List down = buffer_find_all_matches(app, arena, buffer, 0,
|
|
|
|
Ii64(needle_range.max, size),
|
|
|
|
needle, pred, Scan_Forward);
|
|
|
|
string_match_list_filter_flags(&up, complete_must, complete_must_not);
|
|
|
|
string_match_list_filter_flags(&down, complete_must, complete_must_not);
|
|
|
|
result = string_match_list_merge_nearest(&up, &down, needle_range);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
result = buffer_find_all_matches(app, arena, buffer, 0,
|
|
|
|
Ii64(0, size), needle, pred, Scan_Forward);
|
|
|
|
string_match_list_filter_flags(&result, complete_must, complete_must_not);
|
2016-07-12 18:20:06 +00:00
|
|
|
}
|
2019-10-19 18:55:56 +00:00
|
|
|
|
|
|
|
string_match_list_enclose_all(app, result,
|
|
|
|
right_enclose_alpha_numeric_underscore_utf8);
|
|
|
|
return(result);
|
2016-07-12 18:20:06 +00:00
|
|
|
}
|
|
|
|
|
2019-10-19 18:55:56 +00:00
|
|
|
function void
|
|
|
|
word_complete_list_extend_from_raw(Application_Links *app, Arena *arena,
|
|
|
|
String_Match_List *matches,
|
|
|
|
List_String_Const_u8 *list,
|
|
|
|
Table_Data_u64 *used_table){
|
|
|
|
Scratch_Block scratch(app);
|
|
|
|
for (String_Match *node = matches->first;
|
2019-07-14 22:18:59 +00:00
|
|
|
node != 0;
|
2019-10-19 18:55:56 +00:00
|
|
|
node = node->next){
|
|
|
|
String_Const_u8 s = push_buffer_range(app, scratch, node->buffer, node->range);
|
|
|
|
Data data = make_data(s.str, s.size);
|
|
|
|
Table_Lookup lookup = table_lookup(used_table, data);
|
|
|
|
if (!lookup.found_match){
|
|
|
|
data = push_data_copy(arena, data);
|
|
|
|
table_insert(used_table, data, 1);
|
|
|
|
string_list_push(arena, list, SCu8(data.data, data.size));
|
2016-07-12 18:20:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-19 18:55:56 +00:00
|
|
|
internal Word_Complete_Iterator
|
|
|
|
get_word_complete_it(Application_Links *app, Arena *arena,
|
|
|
|
Buffer_ID buffer, Range_i64 range){
|
|
|
|
Base_Allocator *allocator = get_base_allocator_system();
|
2018-09-07 22:39:33 +00:00
|
|
|
|
2019-10-19 18:55:56 +00:00
|
|
|
Scratch_Block scratch(app);
|
|
|
|
String_Const_u8 needle = push_buffer_range(app, arena, buffer, range);
|
|
|
|
String_Match_List list = get_complete_list_raw(app, scratch, buffer, range, needle);
|
2019-02-22 12:43:12 +00:00
|
|
|
|
2019-10-19 18:55:56 +00:00
|
|
|
Word_Complete_Iterator it = {};
|
|
|
|
it.app = app;
|
|
|
|
it.arena = arena;
|
|
|
|
it.arena_restore = begin_temp(arena);
|
|
|
|
it.first_buffer = buffer;
|
|
|
|
it.current_buffer = buffer;
|
|
|
|
it.needle = needle;
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2019-10-19 18:55:56 +00:00
|
|
|
it.already_used_table = make_table_Data_u64(allocator, 100);
|
|
|
|
word_complete_list_extend_from_raw(app, arena,
|
|
|
|
&list, &it.list, &it.already_used_table);
|
|
|
|
return(it);
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
|
2019-10-19 18:55:56 +00:00
|
|
|
function void
|
|
|
|
word_complete_it_release(Word_Complete_Iterator *it){
|
|
|
|
if (it->arena != 0){
|
|
|
|
end_temp(it->arena_restore);
|
|
|
|
table_clear(&it->already_used_table);
|
|
|
|
}
|
|
|
|
block_zero_struct(it);
|
2018-05-11 20:46:26 +00:00
|
|
|
}
|
|
|
|
|
2019-10-19 18:55:56 +00:00
|
|
|
function Word_Complete_State
|
|
|
|
get_word_complete_state(Application_Links *app, Arena *arena,
|
|
|
|
Buffer_ID buffer, Range_i64 needle_range){
|
2019-07-14 22:18:59 +00:00
|
|
|
Word_Complete_State state = {};
|
|
|
|
state.initialized = true;
|
|
|
|
state.range = needle_range;
|
2019-10-19 18:55:56 +00:00
|
|
|
state.it = get_word_complete_it(app, arena, buffer, needle_range);
|
2019-07-14 22:18:59 +00:00
|
|
|
return(state);
|
2017-11-29 23:00:14 +00:00
|
|
|
}
|
|
|
|
|
2019-10-19 18:55:56 +00:00
|
|
|
function void
|
|
|
|
word_complete_it_next(Word_Complete_Iterator *it){
|
|
|
|
for (;;){
|
|
|
|
if (it->node == 0){
|
|
|
|
it->node = it->list.first;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
it->node = it->node->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (it->node != 0){
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
Application_Links *app = it->app;
|
|
|
|
Buffer_ID next = get_buffer_next_looped(app, it->current_buffer, Access_Read);
|
|
|
|
if (next == it->first_buffer){
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
it->node = it->list.last;
|
|
|
|
it->current_buffer = next;
|
|
|
|
Scratch_Block scratch(app);
|
|
|
|
String_Match_List list = get_complete_list_raw(app, scratch,
|
|
|
|
next, Ii64(), it->needle);
|
|
|
|
word_complete_list_extend_from_raw(app, it->arena, &list,
|
|
|
|
&it->list, &it->already_used_table);
|
|
|
|
}
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
|
2019-10-19 18:55:56 +00:00
|
|
|
function String_Const_u8
|
|
|
|
word_complete_it_read(Word_Complete_Iterator *it){
|
|
|
|
String_Const_u8 result = {};
|
|
|
|
if (it->node == 0){
|
|
|
|
result = it->needle;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
result = it->node->string;
|
|
|
|
}
|
|
|
|
return(result);
|
2017-11-21 18:25:19 +00:00
|
|
|
}
|
|
|
|
|
2019-06-21 02:31:22 +00:00
|
|
|
CUSTOM_COMMAND_SIG(word_complete)
|
|
|
|
CUSTOM_DOC("Iteratively tries completing the word to the left of the cursor with other words in open buffers that have the same prefix string.")
|
|
|
|
{
|
2019-10-18 02:54:02 +00:00
|
|
|
View_ID view = get_active_view(app, Access_ReadWriteVisible);
|
|
|
|
Buffer_ID buffer = view_get_buffer(app, view, Access_ReadWriteVisible);
|
2019-06-21 02:31:22 +00:00
|
|
|
if (buffer != 0){
|
2019-06-20 04:45:58 +00:00
|
|
|
Managed_Scope scope = view_get_managed_scope(app, view);
|
2018-08-11 00:42:15 +00:00
|
|
|
|
2019-07-14 22:18:59 +00:00
|
|
|
b32 first_completion = false;
|
2019-09-04 05:31:35 +00:00
|
|
|
Rewrite_Type *rewrite = scope_attachment(app, scope, view_rewrite_loc, Rewrite_Type);
|
|
|
|
if (*rewrite != Rewrite_WordComplete){
|
2019-07-14 22:18:59 +00:00
|
|
|
first_completion = true;
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
2019-10-01 23:10:25 +00:00
|
|
|
|
|
|
|
Rewrite_Type *next_rewrite = scope_attachment(app, scope, view_next_rewrite_loc, Rewrite_Type);
|
|
|
|
*next_rewrite = Rewrite_WordComplete;
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2019-10-01 02:06:21 +00:00
|
|
|
local_persist Arena *completion_arena = {};
|
|
|
|
if (completion_arena == 0){
|
|
|
|
completion_arena = reserve_arena(app);
|
2019-07-14 22:18:59 +00:00
|
|
|
}
|
|
|
|
local_persist Word_Complete_State state = {};
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2019-07-14 22:18:59 +00:00
|
|
|
if (first_completion || !state.initialized){
|
2019-10-19 18:55:56 +00:00
|
|
|
word_complete_it_release(&state.it);
|
2017-01-23 06:19:43 +00:00
|
|
|
|
2019-07-14 22:18:59 +00:00
|
|
|
i64 pos = view_get_cursor_pos(app, view);
|
2019-10-18 20:54:45 +00:00
|
|
|
|
2019-07-14 22:18:59 +00:00
|
|
|
Range_i64 needle_range = get_word_complete_needle_range(app, buffer, pos);
|
2019-10-18 20:54:45 +00:00
|
|
|
|
2019-07-14 22:18:59 +00:00
|
|
|
if (range_size(needle_range) > 0){
|
2019-10-18 20:54:45 +00:00
|
|
|
state = get_word_complete_state(app, completion_arena, buffer,
|
|
|
|
needle_range);
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
2019-07-14 22:18:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (state.initialized){
|
2019-10-19 18:55:56 +00:00
|
|
|
word_complete_it_next(&state.it);
|
|
|
|
String_Const_u8 str = word_complete_it_read(&state.it);
|
2019-07-14 22:18:59 +00:00
|
|
|
|
|
|
|
buffer_replace_range(app, buffer, state.range, str);
|
2019-10-19 19:16:31 +00:00
|
|
|
|
2019-07-14 22:18:59 +00:00
|
|
|
state.range.max = state.range.min + str.size;
|
2019-09-02 21:32:52 +00:00
|
|
|
view_set_cursor_and_preferred_x(app, view, seek_pos(state.range.max));
|
2017-01-23 06:19:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-07-13 00:43:17 +00:00
|
|
|
|
2017-01-23 06:19:43 +00:00
|
|
|
// BOTTOM
|
|
|
|
|