Skip to content

Instantly share code, notes, and snippets.

@luis-reyes-a
Created August 15, 2020 23:18
Show Gist options
  • Save luis-reyes-a/2e779db1d01b75543eb523c6f0b11b1b to your computer and use it in GitHub Desktop.
Save luis-reyes-a/2e779db1d01b75543eb523c6f0b11b1b to your computer and use it in GitHub Desktop.
word complete with token identifiers in outermost scope
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