[variables] added new 4coder variables system
This commit is contained in:
parent
05027b9ef0
commit
8915bcceba
|
@ -1,708 +0,0 @@
|
||||||
static Content_Index *global_content_index = 0;
|
|
||||||
|
|
||||||
internal String get_name_of_index_type(Indexed_Content_Element_Type content_type)
|
|
||||||
{
|
|
||||||
String result = {};
|
|
||||||
|
|
||||||
switch(content_type)
|
|
||||||
{
|
|
||||||
case ContentType_Unspecified: {result = make_lit_string("Unspecified");} break;
|
|
||||||
|
|
||||||
case ContentType_Function: {result = make_lit_string("Function");} break;
|
|
||||||
case ContentType_Type: {result = make_lit_string("Type");} break;
|
|
||||||
case ContentType_Macro: {result = make_lit_string("Macro");} break;
|
|
||||||
case ContentType_EnumValue: {result = make_lit_string("Enum Value");} break;
|
|
||||||
case ContentType_ForwardDeclaration: {result = make_lit_string("Forward Declaration");} break;
|
|
||||||
|
|
||||||
case ContentType_TODO: {result = make_lit_string("TODO");} break;
|
|
||||||
case ContentType_NOTE: {result = make_lit_string("Note");} break;
|
|
||||||
case ContentType_IMPORTANT: {result = make_lit_string("Important");} break;
|
|
||||||
case ContentType_STUDY: {result = make_lit_string("Study");} break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Content_Index *
|
|
||||||
create_content_index(Application_Links *app)
|
|
||||||
{
|
|
||||||
// TODO(casey): I really just want this to be its own allocating arena, but I can't find anything like that in 4coder?
|
|
||||||
// All arenas seem to be fixed size and they can't get more memory if they run out :(
|
|
||||||
Content_Index *index = (Content_Index *)malloc(sizeof(Content_Index));
|
|
||||||
|
|
||||||
memset(index, 0, sizeof(*index));
|
|
||||||
|
|
||||||
return(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Indexed_Content_Element **
|
|
||||||
get_element_slot_for_name(Content_Index *index, String name)
|
|
||||||
{
|
|
||||||
Indexed_Content_Element **slot = &index->name_hash[table_hash_u8((uint8_t *)name.str, name.size) % ArrayCount(index->name_hash)];
|
|
||||||
return(slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Indexed_Buffer *
|
|
||||||
get_or_create_indexed_buffer(Content_Index *index, Buffer_ID buffer_id)
|
|
||||||
{
|
|
||||||
Indexed_Buffer *result = 0;
|
|
||||||
|
|
||||||
Indexed_Buffer **slot = &index->buffer_hash[buffer_id % ArrayCount(index->buffer_hash)];
|
|
||||||
for(Indexed_Buffer *search = *slot;
|
|
||||||
search;
|
|
||||||
search = search->next_in_hash)
|
|
||||||
{
|
|
||||||
if(search->buffer_id == buffer_id)
|
|
||||||
{
|
|
||||||
result = search;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!result)
|
|
||||||
{
|
|
||||||
result = (Indexed_Buffer *)malloc(sizeof(Indexed_Buffer));
|
|
||||||
result->buffer_id = buffer_id;
|
|
||||||
result->first_tag = 0;
|
|
||||||
result->next_in_hash = *slot;
|
|
||||||
*slot = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
static color_pair
|
|
||||||
get_color_pair_for(Indexed_Content_Element_Type type)
|
|
||||||
{
|
|
||||||
color_pair result = {};
|
|
||||||
|
|
||||||
switch(type)
|
|
||||||
{
|
|
||||||
case ContentType_Function:
|
|
||||||
{
|
|
||||||
result.fore = CC_Function;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case ContentType_Type:
|
|
||||||
{
|
|
||||||
result.fore = CC_Type;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case ContentType_Macro:
|
|
||||||
{
|
|
||||||
result.fore = CC_Macro;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case ContentType_EnumValue:
|
|
||||||
{
|
|
||||||
result.fore = CC_EnumValue;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case ContentType_ForwardDeclaration:
|
|
||||||
{
|
|
||||||
result.fore = CC_ForwardDeclaration;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case ContentType_TODO:
|
|
||||||
{
|
|
||||||
result.fore = CC_TODO;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case ContentType_NOTE:
|
|
||||||
{
|
|
||||||
result.fore = CC_NOTE;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case ContentType_IMPORTANT:
|
|
||||||
{
|
|
||||||
result.fore = CC_IMPORTANT;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case ContentType_STUDY:
|
|
||||||
{
|
|
||||||
result.fore = CC_STUDY;
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Indexed_Content_Element *
|
|
||||||
begin_element_in_index(Content_Index *index, Indexed_Content_Element_Type type, Buffer_ID buffer_id, int32_t location,
|
|
||||||
int32_t name_size, int32_t content_size)
|
|
||||||
{
|
|
||||||
Indexed_Content_Element *elem = 0;
|
|
||||||
|
|
||||||
// TODO(casey): I really just want this to be its own allocating arena, but I can't find anything like that in 4coder?
|
|
||||||
// All arenas seem to be fixed size and they can't get more memory if they run out :(
|
|
||||||
uint8_t *mem = (uint8_t *)malloc(sizeof(Indexed_Content_Element) + name_size + content_size);
|
|
||||||
if(mem)
|
|
||||||
{
|
|
||||||
elem = (Indexed_Content_Element *)mem;
|
|
||||||
|
|
||||||
elem->next_in_hash = 0;
|
|
||||||
elem->type = type;
|
|
||||||
elem->name.memory_size = elem->name.size = name_size;
|
|
||||||
elem->name.str = (char *)(elem + 1);
|
|
||||||
elem->content.memory_size = elem->content.size = content_size;
|
|
||||||
elem->content.str = elem->name.str + name_size;
|
|
||||||
|
|
||||||
elem->color = get_color_pair_for(type);
|
|
||||||
|
|
||||||
elem->buffer_id = buffer_id;
|
|
||||||
elem->last_known_location = location;
|
|
||||||
|
|
||||||
index->total_string_space += name_size + content_size;
|
|
||||||
++index->element_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
return(elem);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
end_element_in_index(Content_Index *index, Indexed_Content_Element *elem, u32 flags)
|
|
||||||
{
|
|
||||||
if(elem)
|
|
||||||
{
|
|
||||||
// NOTE(casey): By convention, we make content into a single line, and remove leading/trailing whitespace
|
|
||||||
condense_whitespace(&elem->name);
|
|
||||||
condense_whitespace(&elem->content);
|
|
||||||
|
|
||||||
Indexed_Content_Element **slot = &index->unhashed;
|
|
||||||
if(!(flags & IndexFlag_NoNameLookup))
|
|
||||||
{
|
|
||||||
slot = get_element_slot_for_name(index, elem->name);
|
|
||||||
}
|
|
||||||
elem->next_in_hash = *slot;
|
|
||||||
*slot = elem;
|
|
||||||
|
|
||||||
Indexed_Buffer *buffer = get_or_create_indexed_buffer(index, elem->buffer_id);
|
|
||||||
++buffer->element_type_counts[elem->type];
|
|
||||||
++index->element_type_counts[elem->type];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Indexed_Content_Element *
|
|
||||||
add_element_to_index(Application_Links *app, Content_Index *index, Indexed_Content_Element_Type type, Buffer_Summary *buffer, int32_t location,
|
|
||||||
int32_t name_start, int32_t name_end,
|
|
||||||
int32_t content_start, int32_t content_end,
|
|
||||||
u32 flags = 0)
|
|
||||||
{
|
|
||||||
Indexed_Content_Element *elem = 0;
|
|
||||||
if((name_start <= name_end) &&
|
|
||||||
(content_start <= content_end))
|
|
||||||
{
|
|
||||||
elem = begin_element_in_index(index, type, buffer->buffer_id, location, name_end - name_start, content_end - content_start);
|
|
||||||
if(elem)
|
|
||||||
{
|
|
||||||
buffer_read_range(app, buffer, name_start, name_end, elem->name.str);
|
|
||||||
buffer_read_range(app, buffer, content_start, content_end, elem->content.str);
|
|
||||||
end_element_in_index(index, elem, flags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return(elem);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Indexed_Content_Element *
|
|
||||||
add_element_to_index(Content_Index *index, Indexed_Content_Element_Type type, Buffer_ID buffer_id, int32_t location, String name, String content,
|
|
||||||
u32 flags = 0)
|
|
||||||
{
|
|
||||||
Indexed_Content_Element *elem = begin_element_in_index(index, type, buffer_id, location, name.size, content.size);
|
|
||||||
if(elem)
|
|
||||||
{
|
|
||||||
copy_ss(&elem->name, name);
|
|
||||||
copy_ss(&elem->content, content);
|
|
||||||
end_element_in_index(index, elem, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
return(elem);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Indexed_Content_Tag *
|
|
||||||
add_tag_to_index(Content_Index *index, Buffer_Summary *buffer, uint32_t type, int32_t start, int32_t end, String content)
|
|
||||||
{
|
|
||||||
Indexed_Content_Tag *tag = 0;
|
|
||||||
|
|
||||||
if(start <= end)
|
|
||||||
{
|
|
||||||
Indexed_Buffer *index_buffer = get_or_create_indexed_buffer(index, buffer->buffer_id);
|
|
||||||
// TODO(casey): I really just want this to be its own allocating arena, but I can't find anything like that in 4coder?
|
|
||||||
// All arenas seem to be fixed size and they can't get more memory if they run out :(
|
|
||||||
uint8_t *mem = (uint8_t *)malloc(sizeof(Indexed_Content_Tag) + content.size);
|
|
||||||
if(mem)
|
|
||||||
{
|
|
||||||
tag = (Indexed_Content_Tag *)mem;
|
|
||||||
tag->content.size = tag->content.memory_size = content.size;
|
|
||||||
tag->content.str = (char *)(tag + 1);
|
|
||||||
copy_ss(&tag->content, content);
|
|
||||||
tag->type = type;
|
|
||||||
tag->start = start;
|
|
||||||
tag->end = end;
|
|
||||||
tag->next_in_buffer = index_buffer->first_tag;
|
|
||||||
index_buffer->first_tag = tag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Indexed_Content_Element *
|
|
||||||
get_element_by_name(Content_Index *index, String name)
|
|
||||||
{
|
|
||||||
Indexed_Content_Element *result = 0;
|
|
||||||
|
|
||||||
if(index)
|
|
||||||
{
|
|
||||||
for(Indexed_Content_Element *elem = *get_element_slot_for_name(index, name);
|
|
||||||
elem;
|
|
||||||
elem = elem->next_in_hash)
|
|
||||||
{
|
|
||||||
if(compare_ss(elem->name, name) == 0)
|
|
||||||
{
|
|
||||||
result = elem;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
remove_buffer_from_index(Application_Links *app, Content_Index *index, Buffer_ID buffer_id)
|
|
||||||
{
|
|
||||||
for(int hash_index = 0;
|
|
||||||
hash_index <= ArrayCount(index->name_hash);
|
|
||||||
++hash_index)
|
|
||||||
{
|
|
||||||
for(Indexed_Content_Element **elem_ptr = &index->name_hash[hash_index];
|
|
||||||
*elem_ptr;
|
|
||||||
)
|
|
||||||
{
|
|
||||||
Indexed_Content_Element *elem = *elem_ptr;
|
|
||||||
if(elem->buffer_id == buffer_id)
|
|
||||||
{
|
|
||||||
*elem_ptr = elem->next_in_hash;
|
|
||||||
free(elem);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
elem_ptr = &elem->next_in_hash;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Indexed_Buffer *index_buffer = get_or_create_indexed_buffer(index, buffer_id);
|
|
||||||
while(index_buffer->first_tag)
|
|
||||||
{
|
|
||||||
Indexed_Content_Tag *tag = index_buffer->first_tag;
|
|
||||||
index_buffer->first_tag = tag->next_in_buffer;
|
|
||||||
free(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(u32 type_index = 0;
|
|
||||||
type_index < ContentType_Count;
|
|
||||||
++type_index)
|
|
||||||
{
|
|
||||||
index->element_type_counts[type_index] -= index_buffer->element_type_counts[type_index];
|
|
||||||
index_buffer->element_type_counts[type_index] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
add_buffer_to_index(Application_Links *app, Content_Index *index, Buffer_Summary *buffer)
|
|
||||||
{
|
|
||||||
++index->buffer_count;
|
|
||||||
|
|
||||||
Token_Iterator iter = iterate_tokens(app, buffer, 0);
|
|
||||||
|
|
||||||
int32_t paren_level = 0;
|
|
||||||
int32_t brace_level = 0;
|
|
||||||
|
|
||||||
while(iter.valid)
|
|
||||||
{
|
|
||||||
Cpp_Token token = get_next_token(app, &iter);
|
|
||||||
|
|
||||||
if(token.flags & CPP_TFLAG_PP_BODY)
|
|
||||||
{
|
|
||||||
// TODO(casey): Do we need to pick up macros here?
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch(token.type)
|
|
||||||
{
|
|
||||||
case CPP_TOKEN_COMMENT:
|
|
||||||
{
|
|
||||||
// NOTE(casey): Comments can contain special operations that we want to perform, so we thunk to a special parser to handle those
|
|
||||||
parse_comment(app, index, buffer, token);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case CPP_PP_DEFINE:
|
|
||||||
{
|
|
||||||
int32_t content_start = token.start;
|
|
||||||
token = get_next_token(app, &iter);
|
|
||||||
|
|
||||||
// TODO(casey): Allen, how do I scan for the next "not continued newline"?
|
|
||||||
int32_t content_end = token.start + token.size;
|
|
||||||
|
|
||||||
add_element_to_index(app, index, ContentType_Macro, buffer, token.start,
|
|
||||||
token.start, token.start + token.size,
|
|
||||||
content_start, content_end);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case CPP_TOKEN_KEY_TYPE_DECLARATION:
|
|
||||||
{
|
|
||||||
bool32 forward_declaration = true;
|
|
||||||
int32_t content_start = token.start;
|
|
||||||
Cpp_Token element_name = {};
|
|
||||||
Cpp_Token last_identifier = {};
|
|
||||||
|
|
||||||
String typedef_keyword = make_lit_string("typedef");
|
|
||||||
if(token_text_is(app, buffer, token, typedef_keyword))
|
|
||||||
{
|
|
||||||
// NOTE(casey): Typedefs can't be "forward declared", so we always record their location.
|
|
||||||
forward_declaration = false;
|
|
||||||
|
|
||||||
// NOTE(casey): This is a simple "usually works" parser for typedefs. It is well-known that C grammar
|
|
||||||
// doesn't actually allow you to parse typedefs properly without actually knowing the declared types
|
|
||||||
// at the time, which of course we cannot do since we parse per-file, and don't even know things we
|
|
||||||
// would need (like -D switches, etc.)
|
|
||||||
|
|
||||||
// TODO(casey): If eventually this were upgraded to a more thoughtful parser, struct/union/enum defs
|
|
||||||
// would be parsed from brace to brace, so they could be handled recursively inside of a typedef for
|
|
||||||
// the pattern "typedef struct {} foo;", which currently we do not handle (we ignore the foo).
|
|
||||||
int typedef_paren_level = 0;
|
|
||||||
while(iter.valid)
|
|
||||||
{
|
|
||||||
token = get_next_token(app, &iter);
|
|
||||||
if(token.type == CPP_TOKEN_IDENTIFIER)
|
|
||||||
{
|
|
||||||
last_identifier = token;
|
|
||||||
}
|
|
||||||
else if(token.type == CPP_TOKEN_PARENTHESE_OPEN)
|
|
||||||
{
|
|
||||||
if(typedef_paren_level == 0)
|
|
||||||
{
|
|
||||||
// NOTE(casey): If we are going back into a parenthetical, it means that whatever the last
|
|
||||||
// identifier we saw is our best candidate.
|
|
||||||
element_name = last_identifier;
|
|
||||||
}
|
|
||||||
++typedef_paren_level;
|
|
||||||
}
|
|
||||||
else if(token.type == CPP_TOKEN_PARENTHESE_CLOSE)
|
|
||||||
{
|
|
||||||
--typedef_paren_level;
|
|
||||||
}
|
|
||||||
else if(token.type == CPP_TOKEN_KEY_TYPE_DECLARATION)
|
|
||||||
{
|
|
||||||
// TODO(casey): If we _really_ wanted to, we could parse the type here recursively,
|
|
||||||
// and then we could capture things that were named differently a la "typedef struct foo {...} bar;"
|
|
||||||
// but I think that should wait until the 4coder parser is more structural, because I don't
|
|
||||||
// know how much parsing we _really_ want to do here.
|
|
||||||
forward_declaration = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if(token.type == CPP_TOKEN_SEMICOLON)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(element_name.size == 0)
|
|
||||||
{
|
|
||||||
element_name = last_identifier;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!element_name.size)
|
|
||||||
{
|
|
||||||
while(iter.valid)
|
|
||||||
{
|
|
||||||
token = peek_token(app, &iter);
|
|
||||||
if(token.type == CPP_TOKEN_IDENTIFIER)
|
|
||||||
{
|
|
||||||
element_name = token;
|
|
||||||
get_next_token(app, &iter);
|
|
||||||
}
|
|
||||||
else if((token.type == CPP_TOKEN_KEY_MODIFIER) ||
|
|
||||||
(token.type == CPP_TOKEN_KEY_QUALIFIER) ||
|
|
||||||
(token.type == CPP_TOKEN_KEY_ACCESS) ||
|
|
||||||
(token.type == CPP_TOKEN_KEY_LINKAGE))
|
|
||||||
{
|
|
||||||
// NOTE(casey): Let it go.
|
|
||||||
get_next_token(app, &iter);
|
|
||||||
}
|
|
||||||
else if(token.type == CPP_TOKEN_BRACE_OPEN)
|
|
||||||
{
|
|
||||||
// NOTE(casey): It's probably type definition
|
|
||||||
forward_declaration = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// NOTE(casey): It's probably a forward declaration
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t content_end = token.start;
|
|
||||||
|
|
||||||
if(element_name.size)
|
|
||||||
{
|
|
||||||
Indexed_Content_Element_Type type = ContentType_Type;
|
|
||||||
if(forward_declaration)
|
|
||||||
{
|
|
||||||
type = ContentType_ForwardDeclaration;
|
|
||||||
}
|
|
||||||
|
|
||||||
add_element_to_index(app, index, type, buffer, element_name.start,
|
|
||||||
element_name.start, element_name.start + element_name.size,
|
|
||||||
content_start, content_end);
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case CPP_TOKEN_PARENTHESE_OPEN:
|
|
||||||
{
|
|
||||||
++paren_level;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case CPP_TOKEN_PARENTHESE_CLOSE:
|
|
||||||
{
|
|
||||||
--paren_level;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case CPP_TOKEN_BRACE_OPEN:
|
|
||||||
{
|
|
||||||
if((paren_level == 0) &&
|
|
||||||
(brace_level == 0))
|
|
||||||
{
|
|
||||||
// NOTE(casey): This is presumably a function, see if we can find it's name.
|
|
||||||
int32_t content_end = token.start;
|
|
||||||
int32_t content_start = content_end;
|
|
||||||
int32_t name_start = 0;
|
|
||||||
int32_t name_end = 0;
|
|
||||||
|
|
||||||
Token_Iterator back = iter;
|
|
||||||
get_prev_token(app, &back);
|
|
||||||
get_prev_token(app, &back);
|
|
||||||
Cpp_Token comment_pass = get_prev_token(app, &back);
|
|
||||||
while(comment_pass.type == CPP_TOKEN_COMMENT)
|
|
||||||
{
|
|
||||||
comment_pass = get_prev_token(app, &back);
|
|
||||||
}
|
|
||||||
if(comment_pass.type == CPP_TOKEN_PARENTHESE_CLOSE)
|
|
||||||
{
|
|
||||||
paren_level = -1;
|
|
||||||
while(back.valid)
|
|
||||||
{
|
|
||||||
if(token.type != CPP_TOKEN_COMMENT)
|
|
||||||
{
|
|
||||||
content_start = token.start;
|
|
||||||
}
|
|
||||||
token = get_prev_token(app, &back);
|
|
||||||
if((paren_level == 0) &&
|
|
||||||
(brace_level == 0) &&
|
|
||||||
((token.flags & CPP_TFLAG_PP_BODY) ||
|
|
||||||
(token.type == CPP_TOKEN_BRACE_CLOSE) ||
|
|
||||||
(token.type == CPP_TOKEN_SEMICOLON) ||
|
|
||||||
(token.type == CPP_TOKEN_EOF)))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch(token.type)
|
|
||||||
{
|
|
||||||
case CPP_TOKEN_PARENTHESE_OPEN:
|
|
||||||
{
|
|
||||||
++paren_level;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case CPP_TOKEN_PARENTHESE_CLOSE:
|
|
||||||
{
|
|
||||||
--paren_level;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case CPP_TOKEN_BRACE_OPEN:
|
|
||||||
{
|
|
||||||
++brace_level;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case CPP_TOKEN_BRACE_CLOSE:
|
|
||||||
{
|
|
||||||
--brace_level;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case CPP_TOKEN_IDENTIFIER:
|
|
||||||
{
|
|
||||||
if((paren_level == 0) &&
|
|
||||||
(brace_level == 0) &&
|
|
||||||
(name_start == 0))
|
|
||||||
{
|
|
||||||
name_start = token.start;
|
|
||||||
name_end = token.start + token.size;
|
|
||||||
Token_Iterator probe = back;
|
|
||||||
get_next_token(app, &probe);
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
Cpp_Token test = get_next_token(app, &probe);
|
|
||||||
if((test.type == 0) ||
|
|
||||||
(test.type == CPP_TOKEN_EOF) ||
|
|
||||||
(test.type == CPP_TOKEN_PARENTHESE_CLOSE) ||
|
|
||||||
(test.type == CPP_TOKEN_PARENTHESE_OPEN))
|
|
||||||
{
|
|
||||||
name_end = test.start;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(name_start < name_end)
|
|
||||||
{
|
|
||||||
Indexed_Content_Element_Type type = ContentType_Function;
|
|
||||||
add_element_to_index(app, index, type, buffer, name_start,
|
|
||||||
name_start, name_end,
|
|
||||||
content_start, content_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
brace_level = 0;
|
|
||||||
paren_level = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
++brace_level;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case CPP_TOKEN_BRACE_CLOSE:
|
|
||||||
{
|
|
||||||
--brace_level;
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
add_all_buffers_to_index(Application_Links *app, Content_Index *index)
|
|
||||||
{
|
|
||||||
for(Buffer_Summary buffer = get_buffer_first(app, AccessAll);
|
|
||||||
buffer.exists;
|
|
||||||
get_buffer_next(app, &buffer, AccessAll))
|
|
||||||
{
|
|
||||||
int32_t Unimportant = true;
|
|
||||||
buffer_get_setting(app, &buffer, BufferSetting_Unimportant, &Unimportant);
|
|
||||||
|
|
||||||
if(buffer.tokens_are_ready && !Unimportant)
|
|
||||||
{
|
|
||||||
add_buffer_to_index(app, index, &buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
update_index_for_buffer(Application_Links *app, Content_Index *index, Buffer_Summary *buffer)
|
|
||||||
{
|
|
||||||
remove_buffer_from_index(app, index, buffer->buffer_id);
|
|
||||||
add_buffer_to_index(app, index, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Content_Index *
|
|
||||||
get_global_content_index(Application_Links *app)
|
|
||||||
{
|
|
||||||
Content_Index *result = global_content_index;
|
|
||||||
if(!result)
|
|
||||||
{
|
|
||||||
global_content_index = create_content_index(app);
|
|
||||||
add_all_buffers_to_index(app, global_content_index);
|
|
||||||
result = global_content_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
jump_to_element(Application_Links *app, View_Summary *view, Indexed_Content_Element *elem)
|
|
||||||
{
|
|
||||||
if (view->buffer_id != elem->buffer_id)
|
|
||||||
{
|
|
||||||
view_set_buffer(app, view, elem->buffer_id, 0);
|
|
||||||
}
|
|
||||||
Buffer_Seek seek;
|
|
||||||
seek.type = buffer_seek_pos;
|
|
||||||
seek.pos = elem->last_known_location;;
|
|
||||||
view_set_cursor(app, view, seek, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
jump_to_element_activate(Application_Links *app, Partition *scratch, Heap *heap,
|
|
||||||
View_Summary *view, Lister_State *state,
|
|
||||||
String text_field, void *user_data, bool32 activated_by_mouse)
|
|
||||||
{
|
|
||||||
lister_default(app, scratch, heap, view, state, ListerActivation_Finished);
|
|
||||||
if(user_data)
|
|
||||||
{
|
|
||||||
jump_to_element(app, view, (Indexed_Content_Element *)user_data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef bool32 element_type_predicate(Application_Links *app, Content_Index *index, Indexed_Content_Element *elem, void *user_data);
|
|
||||||
|
|
||||||
static bool32
|
|
||||||
element_is_definition(Application_Links *app, Content_Index *index, Indexed_Content_Element *elem, void *user_data)
|
|
||||||
{
|
|
||||||
bool32 result = ((elem->type == ContentType_Function) ||
|
|
||||||
(elem->type == ContentType_Type) ||
|
|
||||||
(elem->type == ContentType_Macro) ||
|
|
||||||
(elem->type == ContentType_EnumValue));
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool32
|
|
||||||
element_type_equals(Application_Links *app, Content_Index *index, Indexed_Content_Element *elem, void *user_data)
|
|
||||||
{
|
|
||||||
bool32 result = (elem->type == (uint64_t)user_data);
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
jump_to_element_lister(Application_Links *app, char *Label, element_type_predicate *predicate, void *user_data = 0)
|
|
||||||
{
|
|
||||||
Partition *arena = &global_part;
|
|
||||||
|
|
||||||
View_Summary view = get_active_view(app, AccessAll);
|
|
||||||
view_end_ui_mode(app, &view);
|
|
||||||
Temp_Memory temp = begin_temp_memory(arena);
|
|
||||||
|
|
||||||
Content_Index *index = get_global_content_index(app);
|
|
||||||
|
|
||||||
Lister_Option *options = push_array(arena, Lister_Option, index->element_count);
|
|
||||||
int32_t option_index = 0;
|
|
||||||
for(int hash_index = 0;
|
|
||||||
hash_index <= ArrayCount(index->name_hash);
|
|
||||||
++hash_index)
|
|
||||||
{
|
|
||||||
for(Indexed_Content_Element *elem = index->name_hash[hash_index];
|
|
||||||
elem;
|
|
||||||
elem = elem->next_in_hash)
|
|
||||||
{
|
|
||||||
if(predicate(app, index, elem, user_data))
|
|
||||||
{
|
|
||||||
options[option_index].text_color = get_color(elem->color.fore);
|
|
||||||
options[option_index].pop_color = get_color(CC_DefaultText);
|
|
||||||
options[option_index].back_color = get_color(elem->color.back);
|
|
||||||
options[option_index].string = elem->name;
|
|
||||||
options[option_index].status = elem->content;
|
|
||||||
options[option_index].user_data = elem;
|
|
||||||
++option_index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
begin_integrated_lister__basic_list(app, Label, jump_to_element_activate, 0, 0, options, option_index, index->total_string_space, &view);
|
|
||||||
end_temp_memory(temp);
|
|
||||||
}
|
|
|
@ -1,100 +0,0 @@
|
||||||
/* date = October 18th 2020 3:41 pm */
|
|
||||||
|
|
||||||
#ifndef FCODER_CASEY_INDEX_H
|
|
||||||
#define FCODER_CASEY_INDEX_H
|
|
||||||
|
|
||||||
struct color_pair
|
|
||||||
{
|
|
||||||
casey_color_id fore;
|
|
||||||
casey_color_id back;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Indexed_Content_Element_Type
|
|
||||||
{
|
|
||||||
ContentType_Unspecified,
|
|
||||||
|
|
||||||
ContentType_Function,
|
|
||||||
ContentType_Type,
|
|
||||||
ContentType_Macro,
|
|
||||||
ContentType_EnumValue,
|
|
||||||
ContentType_ForwardDeclaration,
|
|
||||||
|
|
||||||
ContentType_TODO,
|
|
||||||
ContentType_NOTE,
|
|
||||||
ContentType_IMPORTANT,
|
|
||||||
ContentType_STUDY,
|
|
||||||
|
|
||||||
ContentType_Count,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Indexed_Content_Element
|
|
||||||
{
|
|
||||||
Indexed_Content_Element *next_in_hash;
|
|
||||||
uint32_t type;
|
|
||||||
|
|
||||||
String name;
|
|
||||||
String content;
|
|
||||||
|
|
||||||
color_pair color;
|
|
||||||
|
|
||||||
Buffer_ID buffer_id;
|
|
||||||
int32_t last_known_location;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Indexed_Content_Flag
|
|
||||||
{
|
|
||||||
IndexFlag_NoNameLookup = 0x1,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Indexed_Content_Tag_Type
|
|
||||||
{
|
|
||||||
TagType_Unspecified ,
|
|
||||||
|
|
||||||
TagType_Label,
|
|
||||||
TagType_Scope,
|
|
||||||
TagType_Highlight,
|
|
||||||
};
|
|
||||||
struct Indexed_Content_Tag
|
|
||||||
{
|
|
||||||
Indexed_Content_Tag *next_in_buffer;
|
|
||||||
String content;
|
|
||||||
|
|
||||||
uint32_t type;
|
|
||||||
int32_t start;
|
|
||||||
int32_t end;
|
|
||||||
|
|
||||||
color_pair color;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Indexed_Buffer
|
|
||||||
{
|
|
||||||
Indexed_Buffer *next_in_hash;
|
|
||||||
Buffer_ID buffer_id;
|
|
||||||
|
|
||||||
int32_t element_type_counts[ContentType_Count];
|
|
||||||
|
|
||||||
// TODO(casey): I really want a growable arena here, so I don't have to manage this memory. Everything
|
|
||||||
// gets cleared by buffer.
|
|
||||||
|
|
||||||
// TODO(casey): This should be a spatial query so it is more scalable
|
|
||||||
Indexed_Content_Tag *first_tag;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Content_Index
|
|
||||||
{
|
|
||||||
int32_t buffer_count;
|
|
||||||
int32_t element_count;
|
|
||||||
int32_t total_string_space;
|
|
||||||
|
|
||||||
int32_t element_type_counts[ContentType_Count];
|
|
||||||
|
|
||||||
Indexed_Buffer *buffer_hash[257];
|
|
||||||
|
|
||||||
// NOTE(casey): unhashed _must_ come immediately aftter name_hash, as they are treated as contiguous
|
|
||||||
// {
|
|
||||||
Indexed_Content_Element *name_hash[4099];
|
|
||||||
Indexed_Content_Element *unhashed;
|
|
||||||
// }
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //4CODER_CASEY_INDEX_H
|
|
|
@ -1013,7 +1013,9 @@ function void
|
||||||
set_next_rewrite(Application_Links *app, View_ID view, Rewrite_Type rewrite){
|
set_next_rewrite(Application_Links *app, View_ID view, Rewrite_Type rewrite){
|
||||||
Managed_Scope scope = view_get_managed_scope(app, view);
|
Managed_Scope scope = view_get_managed_scope(app, view);
|
||||||
Rewrite_Type *next_rewrite = scope_attachment(app, scope, view_next_rewrite_loc, Rewrite_Type);
|
Rewrite_Type *next_rewrite = scope_attachment(app, scope, view_next_rewrite_loc, Rewrite_Type);
|
||||||
*next_rewrite = rewrite;
|
if (next_rewrite != 0){
|
||||||
|
*next_rewrite = rewrite;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function void
|
function void
|
||||||
|
|
|
@ -133,5 +133,19 @@ struct Fade_Range_List{
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
|
||||||
|
struct Implicit_Map_Result{
|
||||||
|
String_ID map;
|
||||||
|
Custom_Command_Function *command;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Implicit_Map_Result Implicit_Map_Function(Application_Links *app,
|
||||||
|
String_ID buffer_language,
|
||||||
|
String_ID global_mode,
|
||||||
|
Input_Event *event);
|
||||||
|
|
||||||
|
global Implicit_Map_Function *implicit_map_function = 0;
|
||||||
|
|
||||||
// BOTTOM
|
// BOTTOM
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,22 @@ CUSTOM_DOC("Default command for responding to a try-exit event")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Implicit_Map_Result
|
||||||
|
default_implicit_map(Application_Links *app, String_ID lang, String_ID mode, Input_Event *event){
|
||||||
|
Implicit_Map_Result result = {};
|
||||||
|
|
||||||
|
View_ID view = get_this_ctx_view(app, Access_Always);
|
||||||
|
|
||||||
|
Command_Map_ID map_id = default_get_map_id(app, view);
|
||||||
|
Command_Binding binding = map_get_binding_recursive(&framework_mapping, map_id, event);
|
||||||
|
|
||||||
|
// TODO(allen): map_id <-> map name?
|
||||||
|
result.map = 0;
|
||||||
|
result.command = binding.custom;
|
||||||
|
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
CUSTOM_COMMAND_SIG(default_view_input_handler)
|
CUSTOM_COMMAND_SIG(default_view_input_handler)
|
||||||
CUSTOM_DOC("Input consumption loop for default view behavior")
|
CUSTOM_DOC("Input consumption loop for default view behavior")
|
||||||
{
|
{
|
||||||
|
@ -72,12 +88,12 @@ CUSTOM_DOC("Input consumption loop for default view behavior")
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(allen): Get map_id
|
|
||||||
Command_Map_ID map_id = default_get_map_id(app, view);
|
|
||||||
|
|
||||||
// NOTE(allen): Get binding
|
// NOTE(allen): Get binding
|
||||||
Command_Binding binding = map_get_binding_recursive(&framework_mapping, map_id, &input.event);
|
if (implicit_map_function == 0){
|
||||||
if (binding.custom == 0){
|
implicit_map_function = default_implicit_map;
|
||||||
|
}
|
||||||
|
Implicit_Map_Result map_result = implicit_map_function(app, 0, 0, &input.event);
|
||||||
|
if (map_result.command == 0){
|
||||||
leave_current_input_unhandled(app);
|
leave_current_input_unhandled(app);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -85,7 +101,7 @@ CUSTOM_DOC("Input consumption loop for default view behavior")
|
||||||
// NOTE(allen): Run the command and pre/post command stuff
|
// NOTE(allen): Run the command and pre/post command stuff
|
||||||
default_pre_command(app, scope);
|
default_pre_command(app, scope);
|
||||||
ProfileCloseNow(view_input_profile);
|
ProfileCloseNow(view_input_profile);
|
||||||
binding.custom(app);
|
map_result.command(app);
|
||||||
ProfileScope(app, "after view input");
|
ProfileScope(app, "after view input");
|
||||||
default_post_command(app, scope);
|
default_post_command(app, scope);
|
||||||
}
|
}
|
||||||
|
@ -250,6 +266,7 @@ default_render_buffer(Application_Links *app, View_ID view_id, Face_ID face_id,
|
||||||
&token_array, pairs, ArrayCount(pairs));
|
&token_array, pairs, ArrayCount(pairs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
// TODO(allen): Put in 4coder_draw.cpp
|
// TODO(allen): Put in 4coder_draw.cpp
|
||||||
// NOTE(allen): Color functions
|
// NOTE(allen): Color functions
|
||||||
|
|
||||||
|
@ -268,6 +285,7 @@ default_render_buffer(Application_Links *app, View_ID view_id, Face_ID face_id,
|
||||||
paint_text_color(app, text_layout_id, Ii64_size(token->pos, token->size), argb);
|
paint_text_color(app, text_layout_id, Ii64_size(token->pos, token->size), argb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
paint_text_color_fcolor(app, text_layout_id, visible_range, fcolor_id(defcolor_text_default));
|
paint_text_color_fcolor(app, text_layout_id, visible_range, fcolor_id(defcolor_text_default));
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "generated/command_metadata.h"
|
#include "generated/command_metadata.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "4coder_variables.h"
|
||||||
#include "4coder_profile.h"
|
#include "4coder_profile.h"
|
||||||
#include "4coder_async_tasks.h"
|
#include "4coder_async_tasks.h"
|
||||||
#include "4coder_token.h"
|
#include "4coder_token.h"
|
||||||
|
@ -126,6 +127,7 @@
|
||||||
#include "4coder_doc_content_types.cpp"
|
#include "4coder_doc_content_types.cpp"
|
||||||
#include "4coder_doc_commands.cpp"
|
#include "4coder_doc_commands.cpp"
|
||||||
#include "4coder_docs.cpp"
|
#include "4coder_docs.cpp"
|
||||||
|
#include "4coder_variables.cpp"
|
||||||
|
|
||||||
#include "4coder_examples.cpp"
|
#include "4coder_examples.cpp"
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,237 @@
|
||||||
|
/*
|
||||||
|
4coder_variables.cpp - Variables system
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TOP
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// NOTE(allen): String hashing
|
||||||
|
|
||||||
|
global Arena vars_arena = {};
|
||||||
|
global Table_Data_u64 vars_string_to_id = {};
|
||||||
|
global Table_u64_Data vars_id_to_string = {};
|
||||||
|
global String_ID vars_string_id_counter = 0;
|
||||||
|
|
||||||
|
function void
|
||||||
|
_vars_init(void){
|
||||||
|
local_persist b32 did_init = false;
|
||||||
|
if (!did_init)
|
||||||
|
{
|
||||||
|
did_init = true;
|
||||||
|
Base_Allocator *base = get_base_allocator_system();
|
||||||
|
vars_arena = make_arena(base);
|
||||||
|
vars_string_to_id = make_table_Data_u64(base, 100);
|
||||||
|
vars_id_to_string = make_table_u64_Data(base, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function String_ID
|
||||||
|
vars_save_string(String_Const_u8 string){
|
||||||
|
_vars_init();
|
||||||
|
|
||||||
|
String_ID result = 0;
|
||||||
|
Data string_data = make_data(string.str, string.size);
|
||||||
|
Table_Lookup location = table_lookup(&vars_string_to_id, string_data);
|
||||||
|
if (location.found_match){
|
||||||
|
table_read(&vars_string_to_id, location, &result);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
vars_string_id_counter += 1;
|
||||||
|
result = vars_string_id_counter;
|
||||||
|
string_data = push_data_copy(&vars_arena, string_data);
|
||||||
|
table_insert(&vars_string_to_id, string_data, result);
|
||||||
|
table_insert(&vars_id_to_string, result, string_data);
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
function String_Const_u8
|
||||||
|
vars_read_string(Arena *arena, String_ID id){
|
||||||
|
_vars_init();
|
||||||
|
|
||||||
|
String_Const_u8 result = {};
|
||||||
|
Table_Lookup location = table_lookup(&vars_id_to_string, id);
|
||||||
|
if (location.found_match){
|
||||||
|
Data data = {};
|
||||||
|
table_read(&vars_id_to_string, location, &data);
|
||||||
|
result.str = push_array(arena, u8 , data.size);
|
||||||
|
block_copy(result.str, data.data, data.size);
|
||||||
|
result.size = data.size;
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// NOTE(allen): Variable structure
|
||||||
|
|
||||||
|
global Variable vars_global_root = {};
|
||||||
|
global Variable vars_nil = {};
|
||||||
|
global Variable *vars_free_variables = 0;
|
||||||
|
|
||||||
|
function Variable_Handle
|
||||||
|
vars_get_root(void){
|
||||||
|
Variable_Handle handle = {&vars_global_root};
|
||||||
|
return(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Variable_Handle
|
||||||
|
vars_get_nil(void){
|
||||||
|
Variable_Handle handle = {&vars_nil};
|
||||||
|
return(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
function b32
|
||||||
|
vars_is_nil(Variable_Handle var){
|
||||||
|
return(var.ptr == &vars_nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
function b32
|
||||||
|
vars_match(Variable_Handle a, Variable_Handle b){
|
||||||
|
return(a.ptr == b.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function String_ID
|
||||||
|
vars_string_id_from_var(Variable_Handle var){
|
||||||
|
return(var.ptr->string);
|
||||||
|
}
|
||||||
|
|
||||||
|
function String_Const_u8
|
||||||
|
vars_string_from_var(Arena *arena, Variable_Handle var){
|
||||||
|
String_ID id = vars_string_id_from_var(var);
|
||||||
|
String_Const_u8 result = vars_read_string(arena, id);
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Variable_Handle
|
||||||
|
vars_read_key(Variable_Handle var, String_ID key){
|
||||||
|
Variable_Handle result = vars_get_nil();
|
||||||
|
for (Variable *node = var.ptr->first;
|
||||||
|
node != 0;
|
||||||
|
node = node->next){
|
||||||
|
if (node->key == key){
|
||||||
|
result.ptr = node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Variable_Handle
|
||||||
|
vars_read_key(Variable_Handle var, String_Const_u8 key){
|
||||||
|
String_ID id = vars_save_string(key);
|
||||||
|
Variable_Handle result = vars_read_key(var, id);
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
function void
|
||||||
|
vars_set_string(Variable_Handle var, String_ID string){
|
||||||
|
if (var.ptr != &vars_nil){
|
||||||
|
var.ptr->string = string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function void
|
||||||
|
vars_set_string(Variable_Handle var, String_Const_u8 string){
|
||||||
|
String_ID id = vars_save_string(string);
|
||||||
|
vars_set_string(var, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function void
|
||||||
|
_vars_free_variable_children(Variable *var){
|
||||||
|
for (Variable *node = var->first;
|
||||||
|
node != 0;
|
||||||
|
node = node->next){
|
||||||
|
_vars_free_variable_children(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (var->last != 0){
|
||||||
|
var->last->next = vars_free_variables;
|
||||||
|
}
|
||||||
|
if (var->first != 0){
|
||||||
|
vars_free_variables = var->first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function void
|
||||||
|
vars_erase(Variable_Handle var, String_ID key){
|
||||||
|
if (var.ptr != &vars_nil){
|
||||||
|
Variable *prev = 0;
|
||||||
|
Variable *node = var.ptr->first;
|
||||||
|
for (; node != 0;
|
||||||
|
node = node->next){
|
||||||
|
if (node->key == key){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prev = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node != 0){
|
||||||
|
_vars_free_variable_children(node);
|
||||||
|
if (prev != 0){
|
||||||
|
prev->next = node->next;
|
||||||
|
}
|
||||||
|
if (var.ptr->first == node){
|
||||||
|
var.ptr->first = node->next;
|
||||||
|
}
|
||||||
|
if (var.ptr->last == node){
|
||||||
|
var.ptr->last = prev;
|
||||||
|
}
|
||||||
|
sll_stack_push(vars_free_variables, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Variable_Handle
|
||||||
|
vars_new_variable(Variable_Handle var, String_ID key){
|
||||||
|
Variable_Handle handle = vars_get_nil();
|
||||||
|
if (var.ptr != &vars_nil){
|
||||||
|
Variable *prev = 0;
|
||||||
|
Variable *node = var.ptr->first;
|
||||||
|
for (; node != 0;
|
||||||
|
node = node->next){
|
||||||
|
if (node->key == key){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prev = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node != 0){
|
||||||
|
handle.ptr = node;
|
||||||
|
_vars_free_variable_children(node);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
handle.ptr = vars_free_variables;
|
||||||
|
if (handle.ptr == 0){
|
||||||
|
sll_stack_pop(vars_free_variables);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
handle.ptr = push_array(&vars_arena, Variable, 1);
|
||||||
|
}
|
||||||
|
sll_queue_push(var.ptr->first, var.ptr->last, handle.ptr);
|
||||||
|
handle.ptr->key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle.ptr->string = 0;
|
||||||
|
handle.ptr->first = 0;
|
||||||
|
handle.ptr->last = 0;
|
||||||
|
}
|
||||||
|
return(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Variable_Handle
|
||||||
|
vars_new_variable(Variable_Handle var, String_ID key, String_ID string){
|
||||||
|
Variable_Handle result = vars_new_variable(var, key);
|
||||||
|
vars_set_string(var, string);
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
function void
|
||||||
|
vars_clear_keys(Variable_Handle var){
|
||||||
|
if (var.ptr != &vars_nil){
|
||||||
|
_vars_free_variable_children(var.ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BOTTOM
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
4coder_variables.h - Variables system
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TOP
|
||||||
|
|
||||||
|
#if !defined(FCODER_VARIABLES_H)
|
||||||
|
#define FCODER_VARIABLES_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// NOTE(allen): Types
|
||||||
|
|
||||||
|
typedef u64 String_ID;
|
||||||
|
|
||||||
|
struct Variable{
|
||||||
|
Variable *next;
|
||||||
|
String_ID key;
|
||||||
|
String_ID string;
|
||||||
|
Variable *first;
|
||||||
|
Variable *last;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Variable_Handle{
|
||||||
|
Variable *ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// NOTE(allen): Functions
|
||||||
|
|
||||||
|
function String_ID vars_save_string(String_Const_u8 string);
|
||||||
|
#define vars_save_string_lit(S) vars_save_string(string_u8_litexpr(S))
|
||||||
|
function String_Const_u8 vars_read_string(Arena *arena, String_ID id);
|
||||||
|
|
||||||
|
function Variable_Handle vars_get_root(void);
|
||||||
|
function Variable_Handle vars_get_nil(void);
|
||||||
|
function b32 vars_is_nil(Variable_Handle var);
|
||||||
|
function b32 vars_match(Variable_Handle a, Variable_Handle b);
|
||||||
|
|
||||||
|
function Variable_Handle vars_read_key(Variable_Handle var, String_ID key);
|
||||||
|
function String_ID vars_string_id_from_var(Variable_Handle var);
|
||||||
|
function String_Const_u8 vars_string_from_var(Arena *arena, Variable_Handle var);
|
||||||
|
|
||||||
|
function void vars_set_string(Variable_Handle var, String_ID string);
|
||||||
|
function void vars_erase(Variable_Handle var, String_ID key);
|
||||||
|
function Variable_Handle vars_new_variable(Variable_Handle var, String_ID key);
|
||||||
|
function Variable_Handle vars_new_variable(Variable_Handle var, String_ID key, String_ID string);
|
||||||
|
function void vars_clear_keys(Variable_Handle var);
|
||||||
|
|
||||||
|
#endif //4CODER_VARIABLES_H
|
||||||
|
|
||||||
|
// BOTTOM
|
|
@ -308,7 +308,7 @@ static Command_Metadata fcoder_metacmd_table[248] = {
|
||||||
{ PROC_LINKS(default_file_externally_modified, 0), false, "default_file_externally_modified", 32, "Notes the external modification of attached files by printing a message.", 72, "W:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 2055 },
|
{ PROC_LINKS(default_file_externally_modified, 0), false, "default_file_externally_modified", 32, "Notes the external modification of attached files by printing a message.", 72, "W:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 2055 },
|
||||||
{ PROC_LINKS(default_startup, 0), false, "default_startup", 15, "Default command for responding to a startup event", 49, "W:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 7 },
|
{ PROC_LINKS(default_startup, 0), false, "default_startup", 15, "Default command for responding to a startup event", 49, "W:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 7 },
|
||||||
{ PROC_LINKS(default_try_exit, 0), false, "default_try_exit", 16, "Default command for responding to a try-exit event", 50, "W:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 23 },
|
{ PROC_LINKS(default_try_exit, 0), false, "default_try_exit", 16, "Default command for responding to a try-exit event", 50, "W:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 23 },
|
||||||
{ PROC_LINKS(default_view_input_handler, 0), false, "default_view_input_handler", 26, "Input consumption loop for default view behavior", 48, "W:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 51 },
|
{ PROC_LINKS(default_view_input_handler, 0), false, "default_view_input_handler", 26, "Input consumption loop for default view behavior", 48, "W:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 67 },
|
||||||
{ PROC_LINKS(delete_alpha_numeric_boundary, 0), false, "delete_alpha_numeric_boundary", 29, "Delete characters between the cursor position and the first alphanumeric boundary to the right.", 95, "W:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 161 },
|
{ PROC_LINKS(delete_alpha_numeric_boundary, 0), false, "delete_alpha_numeric_boundary", 29, "Delete characters between the cursor position and the first alphanumeric boundary to the right.", 95, "W:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 161 },
|
||||||
{ PROC_LINKS(delete_char, 0), false, "delete_char", 11, "Deletes the character to the right of the cursor.", 49, "W:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 79 },
|
{ PROC_LINKS(delete_char, 0), false, "delete_char", 11, "Deletes the character to the right of the cursor.", 49, "W:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 79 },
|
||||||
{ PROC_LINKS(delete_current_scope, 0), false, "delete_current_scope", 20, "Deletes the braces surrounding the currently selected scope. Leaves the contents within the scope.", 99, "W:\\4ed\\code\\custom\\4coder_scope_commands.cpp", 44, 112 },
|
{ PROC_LINKS(delete_current_scope, 0), false, "delete_current_scope", 20, "Deletes the braces surrounding the currently selected scope. Leaves the contents within the scope.", 99, "W:\\4ed\\code\\custom\\4coder_scope_commands.cpp", 44, 112 },
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
|
|
||||||
|
4.1.7
|
||||||
|
+ Core string hash features "save_string" "read_string"
|
||||||
|
+ Added lookup acceleration to code index data
|
||||||
|
+ Added highlighting for functions, types, and macros in code index
|
||||||
|
+ Default input is now dispatched through an "implicit map" callback
|
||||||
|
+ Fix: crash when pasting in read only buffer
|
||||||
|
|
||||||
4.1.6
|
4.1.6
|
||||||
+ In config.4coder "bind_by_physical_key" uses a key-layout that does not change with language
|
+ In config.4coder "bind_by_physical_key" uses a key-layout that does not change with language
|
||||||
+ Deprecated GlyphFlag_Rotate90, rotation of immediate mode text is entirely derived from the delta vector
|
+ Deprecated GlyphFlag_Rotate90, rotation of immediate mode text is entirely derived from the delta vector
|
||||||
|
|
Loading…
Reference in New Issue