[variables] added new 4coder variables system

master
Allen Webster 2020-10-22 14:57:28 -07:00
parent 05027b9ef0
commit 8915bcceba
10 changed files with 339 additions and 816 deletions

View File

@ -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);
}

View File

@ -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

View File

@ -1013,7 +1013,9 @@ function void
set_next_rewrite(Application_Links *app, View_ID view, Rewrite_Type rewrite){
Managed_Scope scope = view_get_managed_scope(app, view);
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

View File

@ -133,5 +133,19 @@ struct Fade_Range_List{
#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

View File

@ -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_DOC("Input consumption loop for default view behavior")
{
@ -72,12 +88,12 @@ CUSTOM_DOC("Input consumption loop for default view behavior")
continue;
}
// NOTE(allen): Get map_id
Command_Map_ID map_id = default_get_map_id(app, view);
// NOTE(allen): Get binding
Command_Binding binding = map_get_binding_recursive(&framework_mapping, map_id, &input.event);
if (binding.custom == 0){
if (implicit_map_function == 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);
continue;
}
@ -85,7 +101,7 @@ CUSTOM_DOC("Input consumption loop for default view behavior")
// NOTE(allen): Run the command and pre/post command stuff
default_pre_command(app, scope);
ProfileCloseNow(view_input_profile);
binding.custom(app);
map_result.command(app);
ProfileScope(app, "after view input");
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));
}
#if 0
// TODO(allen): Put in 4coder_draw.cpp
// 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);
}
}
#endif
}
else{
paint_text_color_fcolor(app, text_layout_id, visible_range, fcolor_id(defcolor_text_default));

View File

@ -27,6 +27,7 @@
#include "generated/command_metadata.h"
#endif
#include "4coder_variables.h"
#include "4coder_profile.h"
#include "4coder_async_tasks.h"
#include "4coder_token.h"
@ -126,6 +127,7 @@
#include "4coder_doc_content_types.cpp"
#include "4coder_doc_commands.cpp"
#include "4coder_docs.cpp"
#include "4coder_variables.cpp"
#include "4coder_examples.cpp"

237
custom/4coder_variables.cpp Normal file
View File

@ -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

51
custom/4coder_variables.h Normal file
View File

@ -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

View File

@ -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_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_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_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 },

View File

@ -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
+ 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