Created
August 15, 2020 23:18
-
-
Save luis-reyes-a/2e779db1d01b75543eb523c6f0b11b1b to your computer and use it in GitHub Desktop.
word complete with token identifiers in outermost scope
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
internal b32 | |
my_strings_match_so_far(String_Const_u8 a, String_Const_u8 b, u64 count) | |
{ | |
b32 match = true; | |
if((a.size >= count) && (b.size >= count)) | |
{ | |
for(i32 i = 0; i < count; i += 1) | |
{ | |
if(a.str[i] != b.str[i]) | |
{ | |
match = false; | |
break; | |
} | |
} | |
} | |
else match = false; | |
return match; | |
} | |
struct My_Token_Complete_Entry | |
{ | |
String_Const_u8 string; | |
i64 pos; | |
}; | |
struct My_Token_Complete_State | |
{ | |
b32 initialized; | |
My_Token_Complete_Entry sample; | |
My_Token_Complete_Entry entries[16]; | |
i32 entry_count; | |
i32 active; | |
Arena arena; | |
}; | |
internal void | |
my_complete_active_token(Application_Links *app, Buffer_ID buffer_id, | |
My_Token_Complete_State *state, Range_i64 sample_range) | |
{ | |
Assert(state->active >= 0 && state->active < state->entry_count); | |
String_Const_u8 string = state->entries[state->active].string; | |
buffer_replace_range(app, buffer_id, sample_range, string); | |
view_set_cursor_and_preferred_x(app, get_active_view(app, Access_Always), seek_pos(sample_range.min + string.size)); | |
} | |
internal i64 | |
get_distance_from_sample_pos(My_Token_Complete_State *state, My_Token_Complete_Entry *entry) | |
{ | |
i64 delta = entry->pos - state->sample.pos; | |
return (delta < 0) ? -delta : delta; | |
} | |
internal void | |
remove_entry(My_Token_Complete_State *state, i32 index) | |
{ | |
Assert(index > -1 && index < state->entry_count); | |
for(index; index < (state->entry_count - 1); index += 1) | |
{ | |
state->entries[index] = state->entries[index + 1]; | |
} | |
state->entries[--state->entry_count] = {}; | |
} | |
internal void | |
insert_entry(My_Token_Complete_State *state, My_Token_Complete_Entry *entry, i32 insertion_index) | |
{ | |
Assert(insertion_index > -1 && insertion_index <= state->entry_count); | |
if(insertion_index == state->entry_count && | |
state->entry_count < array_count(state->entries)) | |
{ | |
state->entries[state->entry_count++] = *entry; | |
} | |
else | |
{ | |
My_Token_Complete_Entry last_one = state->entries[state->entry_count - 1]; | |
//shift everything from insertion_index a slot to the right | |
for(i32 index = state->entry_count - 1; index > insertion_index; index -= 1) | |
{ | |
state->entries[index] = state->entries[index - 1]; | |
} | |
state->entries[insertion_index] = *entry; | |
//if room to save the very last one, do so | |
if(state->entry_count < array_count(state->entries)) | |
{ | |
state->entries[state->entry_count++] = last_one; | |
} | |
} | |
} | |
CUSTOM_COMMAND_SIG(my_token_complete_in_topmost_scope) | |
CUSTOM_DOC("token complete within outermost scope") | |
{ | |
static My_Token_Complete_State state = {}; | |
if(state.initialized == false) | |
{ | |
state.initialized = true; | |
state.arena = make_arena_system(); | |
} | |
View_ID view = get_active_view(app, Access_ReadWriteVisible); | |
Buffer_ID buffer_id = view_get_buffer(app, view, Access_Always); | |
if(buffer_id == 0) return; | |
Scratch_Block scratch(app); | |
i64 cursor_pos = view_get_cursor_pos(app, view); | |
Range_i64 sample_range = get_word_complete_needle_range(app, buffer_id, cursor_pos); | |
My_Token_Complete_Entry sample = {}; | |
sample.string = push_buffer_range(app, scratch, buffer_id, sample_range); | |
sample.pos = sample_range.min; | |
if(sample.string.size == 0) return; | |
if(state.entry_count && | |
(state.sample.pos == sample_range.min) && | |
my_strings_match_so_far(sample.string, state.sample.string, state.sample.string.size)) //cycle another token | |
{ | |
state.active += 1; | |
if(state.active >= state.entry_count) state.active = 0; | |
my_complete_active_token(app, buffer_id, &state, sample_range); | |
} | |
else //else we are looking for new tokens now | |
{ | |
//@TODO how do I clear the arena? | |
linalloc_clear(&state.arena); | |
state.active = 0; | |
state.entry_count = 0; | |
state.sample.pos = sample.pos; | |
state.sample.string = push_string_copy(&state.arena, sample.string); | |
String_Const_u8 file_name = push_buffer_file_name(app, scratch, buffer_id); | |
String_Const_u8 ext = string_file_extension(file_name); | |
if(!(string_match(ext, SCu8("cpp")) || | |
string_match(ext, SCu8("h")) || | |
string_match(ext, SCu8("c")))) return; | |
Range_i64 range = {}; | |
range.min = cursor_pos; | |
if (find_surrounding_nest(app, buffer_id, range.min, FindNest_Scope, &range)){ | |
for (;;){ | |
if (!find_surrounding_nest(app, buffer_id, range.min, FindNest_Scope, &range)){ | |
break; | |
} | |
} | |
} | |
//this is to include function parameters and return value tokens in search | |
i64 line_min = get_line_number_from_pos(app, buffer_id, range.min) - 2; | |
range.min = get_line_start_pos(app, buffer_id, line_min); | |
Managed_Scope scope = buffer_get_managed_scope(app, buffer_id); | |
Token_Array *tokens = scope_attachment(app, scope, attachment_tokens, Token_Array); | |
for(i64 token_index = 0; token_index < tokens->count; token_index += 1) | |
{ | |
token_index | |
Token *token = tokens->tokens + token_index; | |
if(token->pos < range.min) continue; | |
else if(token->pos > range.max) break; | |
if(token->kind != TokenBaseKind_Identifier) continue; | |
My_Token_Complete_Entry entry = {}; | |
entry.pos = token->pos; | |
//should probably temp memory this | |
entry.string = push_token_lexeme(app, scratch, buffer_id, token); | |
if(entry.string.size > sample.string.size && | |
my_strings_match_so_far(entry.string, sample.string, sample.string.size)) | |
{ | |
i32 stored_entry_index = -1; | |
for(i32 i = 0; i < state.entry_count; i += 1) | |
{ | |
if(string_match(state.entries[i].string, entry.string)) | |
{ | |
stored_entry_index = i; | |
break; | |
} | |
} | |
i64 entry_delta = get_distance_from_sample_pos(&state, &entry); | |
if(stored_entry_index > -1) | |
{ | |
//if stored already, let's see if the pos is closer to the sample pos | |
//if so we will update with the closer pos for filtering | |
if(entry_delta < get_distance_from_sample_pos(&state, | |
state.entries + | |
stored_entry_index)) | |
{ | |
//just use the same allocated string | |
entry.string = state.entries[stored_entry_index].string; | |
remove_entry(&state, stored_entry_index); | |
i32 insertion_index = 0; | |
for(insertion_index; | |
insertion_index < state.entry_count; | |
insertion_index += 1) | |
{ | |
i64 delta = get_distance_from_sample_pos(&state, | |
state.entries + | |
insertion_index); | |
if(entry_delta < delta) break; | |
} | |
insert_entry(&state, &entry, insertion_index); | |
} | |
} | |
else | |
{ | |
entry.string = push_string_copy(&state.arena, entry.string); | |
i32 insertion_index = 0; | |
for(insertion_index; | |
insertion_index < state.entry_count; | |
insertion_index += 1) | |
{ | |
i64 delta = get_distance_from_sample_pos(&state, | |
state.entries + insertion_index); | |
if(entry_delta < delta) break; | |
} | |
insert_entry(&state, &entry, insertion_index); | |
} | |
} | |
if(state.entry_count >= array_count(state.entries)) break; | |
} | |
if(state.entry_count) | |
{ | |
my_complete_active_token(app, buffer_id, &state, sample_range); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment