From 556657226917790f3a0f0a5c7864d6ba08cc98cc Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Sat, 19 May 2018 21:44:20 -0700 Subject: [PATCH] Added parse error log and parse recover to the config parser --- 4coder_config.cpp | 789 +++++++++++--------------- 4coder_config.h | 27 + 4coder_config_grammar.txt | 2 +- 4coder_default_framework.h | 31 - 4coder_generated/command_metadata.h | 14 +- 4coder_project_commands.cpp | 55 +- 4coder_project_commands.h | 1 - project.4coder | 50 +- site/source_material/binding_list.txt | 12 +- 9 files changed, 418 insertions(+), 563 deletions(-) diff --git a/4coder_config.cpp b/4coder_config.cpp index 55aaa488..5b0a8cd1 100644 --- a/4coder_config.cpp +++ b/4coder_config.cpp @@ -4,12 +4,6 @@ // TOP -// TODO(allen): Stop handling files this way! My own API should be able to do this!!?!?!?!!?!?!!!!? -// NOTE(allen): Actually need binary buffers for some stuff to work, but not this parsing thing here. -#include - -//////////////////////////////// - static CString_Array get_code_extensions(Extension_List *list){ CString_Array array = {0}; @@ -54,6 +48,50 @@ parse_extension_line_to_extension_list(String str, Extension_List *list){ //////////////////////////////// +static Error_Location +get_error_location(char *base, char *pos){ + Error_Location location = {0}; + location.line_number = 1; + location.column_number = 1; + for (char *ptr = base; + ptr < pos; + ptr += 1){ + if (*ptr == '\n'){ + location.line_number += 1; + location.column_number = 1; + } + else{ + location.column_number += 1; + } + } + return(location); +} + +static String +config_stringize_errors(Partition *arena, Config *parsed){ + String result = {0}; + result.str = push_array(arena, char, 0); + result.memory_size = partition_remaining(arena); + for (Config_Error *error = parsed->first_error; + error != 0; + error = error->next){ + Error_Location location = get_error_location(parsed->data.str, error->pos); + append(&result, error->file_name); + append(&result, ":"); + append_int_to_str(&result, location.line_number); + append(&result, ":"); + append_int_to_str(&result, location.column_number); + append(&result, ": "); + append(&result, error->text); + append(&result, "\n"); + } + result.memory_size = result.size; + push_array(arena, char, result.size); + return(result); +} + +//////////////////////////////// + static void config_parser__advance_to_next(Config_Parser *ctx){ Cpp_Token *t = ctx->token; @@ -145,13 +183,13 @@ config_parser__match_text(Config_Parser *ctx, String text){ return(result); } -static Config *config_parser__config(Config_Parser *ctx); -static int32_t *config_parser__version(Config_Parser *ctx); +static Config *config_parser__config (Config_Parser *ctx); +static int32_t *config_parser__version (Config_Parser *ctx); static Config_Assignment *config_parser__assignment(Config_Parser *ctx); -static Config_LValue *config_parser__lvalue(Config_Parser *ctx); -static Config_RValue *config_parser__rvalue(Config_Parser *ctx); -static Config_Compound *config_parser__compound(Config_Parser *ctx); -static Config_Compound_Element *config_parser__element(Config_Parser *ctx); +static Config_LValue *config_parser__lvalue (Config_Parser *ctx); +static Config_RValue *config_parser__rvalue (Config_Parser *ctx); +static Config_Compound *config_parser__compound (Config_Parser *ctx); +static Config_Compound_Element *config_parser__element (Config_Parser *ctx); static Config* text_data_and_token_array_to_parse_data(Partition *arena, String file_name, String data, Cpp_Token_Array array){ @@ -164,6 +202,39 @@ text_data_and_token_array_to_parse_data(Partition *arena, String file_name, Stri return(config); } +static Config_Error* +config_parser__push_error(Config_Parser *ctx){ + Config_Error *error = push_array(ctx->arena, Config_Error, 1); + zdll_push_back(ctx->first_error, ctx->last_error, error); + error->file_name = ctx->file_name; + error->pos = ctx->data.str + ctx->token->start; + ctx->count_error += 1; + return(error); +} + +static String +config_parser__begin_string(Config_Parser *ctx){ + String str; + str.str = push_array(ctx->arena, char, 0); + str.size = 0; + str.memory_size = ctx->arena->max - ctx->arena->pos; + return(str); +} + +static void +config_parser__end_string(Config_Parser *ctx, String *str){ + str->memory_size = str->size; + push_array(ctx->arena, char, str->size); +} + +static void +config_parser__log_error(Config_Parser *ctx, char *error_text){ + Config_Error *error = config_parser__push_error(ctx); + error->text = config_parser__begin_string(ctx); + append(&error->text, error_text); + config_parser__end_string(ctx, &error->text); +} + static Config* config_parser__config(Config_Parser *ctx){ int32_t *version = config_parser__version(ctx); @@ -173,9 +244,10 @@ config_parser__config(Config_Parser *ctx){ int32_t count = 0; for (;!config_parser__recognize_token(ctx, CPP_TOKEN_EOF);){ Config_Assignment *assignment = config_parser__assignment(ctx); - require(assignment != 0); - zdll_push_back(first, last, assignment); - count += 1; + if (assignment != 0){ + zdll_push_back(first, last, assignment); + count += 1; + } } Config *config = push_array(ctx->arena, Config, 1); @@ -184,17 +256,57 @@ config_parser__config(Config_Parser *ctx){ config->first = first; config->last = last; config->count = count; + config->first_error = ctx->first_error; + config->last_error = ctx->last_error; + config->count_error = ctx->count_error; + config->data = ctx->data; return(config); } +static void +config_parser__recover_parse(Config_Parser *ctx){ + for (;;){ + if (config_parser__match_token(ctx, CPP_TOKEN_SEMICOLON)){ + break; + } + if (config_parser__recognize_token(ctx, CPP_TOKEN_EOF)){ + break; + } + config_parser__advance_to_next(ctx); + } +} + static int32_t* config_parser__version(Config_Parser *ctx){ require(config_parser__match_text(ctx, make_lit_string("version"))); - require(config_parser__match_token(ctx, CPP_TOKEN_PARENTHESE_OPEN)); - require(config_parser__recognize_token(ctx, CPP_TOKEN_INTEGER_CONSTANT)); + + if (!config_parser__match_token(ctx, CPP_TOKEN_PARENTHESE_OPEN)){ + config_parser__log_error(ctx, "expected token '(' for version specifier: 'version(#)'"); + config_parser__recover_parse(ctx); + return(0); + } + + if (!config_parser__recognize_token(ctx, CPP_TOKEN_INTEGER_CONSTANT)){ + config_parser__log_error(ctx, "expected an integer constant for version specifier: 'version(#)'"); + config_parser__recover_parse(ctx); + return(0); + } + Config_Integer value = config_parser__get_int(ctx); config_parser__advance_to_next(ctx); - require(config_parser__match_token(ctx, CPP_TOKEN_PARENTHESE_CLOSE)); + + if (!config_parser__match_token(ctx, CPP_TOKEN_PARENTHESE_CLOSE)){ + config_parser__log_error(ctx, "expected token ')' for version specifier: 'version(#)'"); + config_parser__recover_parse(ctx); + return(0); + } + + if (!config_parser__match_token(ctx, CPP_TOKEN_SEMICOLON)){ + config_parser__log_error(ctx, "expected token ';' for version specifier: 'version(#)'"); + config_parser__recover_parse(ctx); + return(0); + } + int32_t *ptr = push_array(ctx->arena, int32_t, 1); *ptr = value.integer; return(ptr); @@ -203,11 +315,35 @@ config_parser__version(Config_Parser *ctx){ static Config_Assignment* config_parser__assignment(Config_Parser *ctx){ Config_LValue *l = config_parser__lvalue(ctx); - require(l != 0); - require(config_parser__match_token(ctx, CPP_TOKEN_EQ)); + if (l == 0){ + config_parser__log_error(ctx, "expected an l-value; l-value formats: 'identifier', 'identifier[#]'"); + config_parser__recover_parse(ctx); + return(0); + } + + if (!config_parser__match_token(ctx, CPP_TOKEN_EQ)){ + config_parser__log_error(ctx, "expected token '=' for assignment: 'l-value = r-value;'"); + config_parser__recover_parse(ctx); + return(0); + } + Config_RValue *r = config_parser__rvalue(ctx); - require(r != 0); - require(config_parser__match_token(ctx, CPP_TOKEN_SEMICOLON)); + if (r == 0){ + config_parser__log_error(ctx, "expected an r-value; r-value formats:\n" + "\tconstants (true, false, integers, hexadecimal integers, strings, characters)\n" + "\tany l-value that is set in the file\n" + "\tcompound: '{ compound-element, compound-element, compound-element ...}'\n" + "\ta compound-element is an r-value, and can have a layout specifier\n" + "\tcompound-element with layout specifier: .name = r-value, .integer = r-value"); + config_parser__recover_parse(ctx); + return(0); + } + + if (!config_parser__match_token(ctx, CPP_TOKEN_SEMICOLON)){ + config_parser__log_error(ctx, "expected token ';' for assignment: 'l-value = r-value;'"); + config_parser__recover_parse(ctx); + return(0); + } Config_Assignment *assignment = push_array(ctx->arena, Config_Assignment, 1); memset(assignment, 0, sizeof(*assignment)); @@ -276,7 +412,7 @@ config_parser__rvalue(Config_Parser *ctx){ rvalue->type = ConfigRValueType_Integer; if (value.is_signed){ rvalue->integer = value.integer; -} + } else{ rvalue->uinteger = value.uinteger; } @@ -395,42 +531,42 @@ config_evaluate_rvalue(Config *config, Config_Assignment *assignment, Config_RVa Config_RValue_Type type, void *out){ bool32 success = false; if (r != 0 && !assignment->visited){ - if (r->type == ConfigRValueType_LValue){ - assignment->visited = true; - Config_LValue *l = r->lvalue; - success = config_var(config, l->identifier, l->index, type, out); - assignment->visited = false; - } - else if (r->type == type){ - success = true; - switch (type){ - case ConfigRValueType_Boolean: - { - *(bool32*)out = r->boolean; - }break; - - case ConfigRValueType_Integer: - { - *(int32_t*)out = r->integer; - }break; - - case ConfigRValueType_String: - { - *(String*)out = r->string; - }break; - - case ConfigRValueType_Character: - { - *(char*)out = r->character; - }break; - - case ConfigRValueType_Compound: - { - *(Config_Compound**)out = r->compound; - }break; + if (r->type == ConfigRValueType_LValue){ + assignment->visited = true; + Config_LValue *l = r->lvalue; + success = config_var(config, l->identifier, l->index, type, out); + assignment->visited = false; + } + else if (r->type == type){ + success = true; + switch (type){ + case ConfigRValueType_Boolean: + { + *(bool32*)out = r->boolean; + }break; + + case ConfigRValueType_Integer: + { + *(int32_t*)out = r->integer; + }break; + + case ConfigRValueType_String: + { + *(String*)out = r->string; + }break; + + case ConfigRValueType_Character: + { + *(char*)out = r->character; + }break; + + case ConfigRValueType_Compound: + { + *(Config_Compound**)out = r->compound; + }break; + } } } -} return(success); } @@ -484,6 +620,27 @@ config_string_var(Config *config, char *var_name, int32_t subscript, String *var return(config_var(config, make_string_slowly(var_name), subscript, ConfigRValueType_String, var_out)); } +static bool32 +config_placed_string_var(Config *config, String var_name, int32_t subscript, + String *var_out, char *space, int32_t space_size){ + *var_out = make_string_cap(space, 0, space_size); + String str = {0}; + bool32 result = config_string_var(config, var_name, subscript, &str); + if (result){ + copy(var_out, str); + } + return(result); +} + +static bool32 +config_placed_string_var(Config *config, char *var_name, int32_t subscript, + String *var_out, char *space, int32_t space_size){ + return(config_placed_string_var(config, make_string_slowly(var_name), subscript, + var_out, space, space_size)); +} + +#define config_fixed_string_var(c,v,s,o,a) config_placed_string_var((c),(v),(s),(o),(a),sizeof(a)) + static bool32 config_char_var(Config *config, String var_name, int32_t subscript, char *var_out){ return(config_var(config, var_name, subscript, ConfigRValueType_Character, var_out)); @@ -525,10 +682,10 @@ config_compound_member(Config *config, Config_Compound *compound, String var_nam case ConfigLayoutType_Identifier: { implicit_index_is_valid = false; - if (match(element->l.identifier, var_name)){ + if (match(element->l.identifier, var_name)){ element_matches_query = true; } - }break; + }break; case ConfigLayoutType_Integer: { @@ -620,307 +777,6 @@ config_compound_compound_member(Config *config, Config_Compound *compound, //////////////////////////////// -static Cpp_Token -read_config_token(Cpp_Token_Array array, int32_t *i_ptr){ - Cpp_Token token = {0}; - int32_t i = *i_ptr; - for (; i < array.count; ++i){ - Cpp_Token comment_token = array.tokens[i]; - if (comment_token.type != CPP_TOKEN_COMMENT){ - break; - } - } - if (i < array.count){ - token = array.tokens[i]; - } - *i_ptr = i; - return(token); -} - -static Config_Line -read_config_line(Cpp_Token_Array array, int32_t *i_ptr, char *text){ - Config_Line config_line = {0}; - - int32_t i = *i_ptr; - config_line.id_token = read_config_token(array, &i); - int32_t text_index_start = config_line.id_token.start; - if (config_line.id_token.type == CPP_TOKEN_IDENTIFIER){ - ++i; - if (i < array.count){ - Cpp_Token token = read_config_token(array, &i); - - bool32 lvalue_success = true; - if (token.type == CPP_TOKEN_BRACKET_OPEN){ - lvalue_success = false; - ++i; - if (i < array.count){ - config_line.subscript_token = read_config_token(array, &i); - if (config_line.subscript_token.type == CPP_TOKEN_INTEGER_CONSTANT){ - ++i; - if (i < array.count){ - token = read_config_token(array, &i); - if (token.type == CPP_TOKEN_BRACKET_CLOSE){ - ++i; - if (i < array.count){ - token = read_config_token(array, &i); - lvalue_success = true; - } - } - } - } - } - } - - if (lvalue_success){ - if (token.type == CPP_TOKEN_EQ){ - config_line.eq_token = read_config_token(array, &i); - ++i; - if (i < array.count){ - Cpp_Token val_token = read_config_token(array, &i); - - bool32 rvalue_success = true; - if (val_token.type == CPP_TOKEN_BRACE_OPEN){ - rvalue_success = false; - ++i; - if (i < array.count){ - config_line.val_array_start = i; - - bool32 expecting_array_item = 1; - for (; i < array.count; ++i){ - Cpp_Token array_token = read_config_token(array, &i); - if (array_token.size == 0){ - break; - } - if (array_token.type == CPP_TOKEN_BRACE_CLOSE){ - config_line.val_array_end = i; - rvalue_success = true; - break; - } - else{ - if (array_token.type == CPP_TOKEN_COMMA){ - if (!expecting_array_item){ - expecting_array_item = true; - } - else{ - break; - } - } - else{ - if (expecting_array_item){ - expecting_array_item = false; - ++config_line.val_array_count; - } - } - } - } - } - } - - if (rvalue_success){ - config_line.val_token = val_token; - ++i; - if (i < array.count){ - Cpp_Token semicolon_token = read_config_token(array, &i); - if (semicolon_token.type == CPP_TOKEN_SEMICOLON){ - config_line.read_success = true; - } - } - } - } - } - } - } - } - - if (!config_line.read_success){ - Cpp_Token token = {0}; - if (i < array.count){ - token = array.tokens[i]; - } - int32_t text_index_current = token.start + token.size; - if (text_index_current <= text_index_start){ - if (array.count > 0){ - token = array.tokens[array.count - 1]; - text_index_current = token.start + token.size; - } - } - - if (text_index_current > text_index_start){ - config_line.error_str = make_string(text + text_index_start, text_index_current - text_index_start); - } - - for (; i < array.count; ++i){ - Cpp_Token skip_token = read_config_token(array, &i); - if (skip_token.type == CPP_TOKEN_SEMICOLON){ - break; - } - } - } - - *i_ptr = i; - - return(config_line); -} - -static Config_Item -get_config_item(Config_Line line, char *mem, Cpp_Token_Array array){ - Config_Item item = {0}; - item.line = line; - item.array = array; - item.mem = mem; - if (line.id_token.size != 0){ - item.id = make_string(mem + line.id_token.start, line.id_token.size); - } - - if (line.subscript_token.size != 0){ - String subscript_str = make_string(mem + line.subscript_token.start,line.subscript_token.size); - item.subscript_index = str_to_int_s(subscript_str); - item.has_subscript = 1; - } - - return(item); -} - -static bool32 -config_var(Config_Item item, char *var_name, int32_t *subscript, uint32_t token_type, void *var_out){ - bool32 result = false; - bool32 subscript_success = true; - if (item.line.val_token.type == token_type){ - if ((var_name == 0 && item.id.size == 0) || match(item.id, var_name)){ - if (subscript){ - if (item.has_subscript){ - *subscript = item.subscript_index; - } - else{ - subscript_success = false; - } - } - - if (subscript_success){ - if (var_out){ - switch (token_type){ - case CPP_TOKEN_BOOLEAN_CONSTANT: - { - *(bool32*)var_out = (item.mem[item.line.val_token.start] == 't'); - }break; - - case CPP_TOKEN_INTEGER_CONSTANT: - { - if (match(make_string(item.mem + item.line.val_token.start, 2), "0x")){ - // Hex Integer - String val = make_string(item.mem + item.line.val_token.start + 2, item.line.val_token.size - 2); - *(uint32_t*)var_out = hexstr_to_int(val); - } - else{ - // Integer - String val = make_string(item.mem + item.line.val_token.start, item.line.val_token.size); - *(int32_t*)var_out = str_to_int(val); - } - }break; - - case CPP_TOKEN_STRING_CONSTANT: - { - String str = make_string(item.mem + item.line.val_token.start + 1,item.line.val_token.size - 2); - copy((String*)var_out, str); - }break; - - case CPP_TOKEN_IDENTIFIER: - { - String str = make_string(item.mem + item.line.val_token.start,item.line.val_token.size); - copy((String*)var_out, str); - }break; - - case CPP_TOKEN_BRACE_OPEN: - { - Config_Array_Reader *array_reader = (Config_Array_Reader*)var_out; - array_reader->array = item.array; - array_reader->mem = item.mem; - array_reader->i = item.line.val_array_start; - array_reader->val_array_end = item.line.val_array_end; - array_reader->good = 1; - }break; - } - } - result = true; - } - } - } - return(result); -} - -static bool32 -config_bool_var(Config_Item item, char *var_name, int32_t *subscript, bool32 *var_out){ - return(config_var(item, var_name, subscript, CPP_TOKEN_BOOLEAN_CONSTANT, var_out)); -} - -static bool32 -config_int_var(Config_Item item, char *var_name, int32_t *subscript, int32_t *var_out){ - return(config_var(item, var_name, subscript, CPP_TOKEN_INTEGER_CONSTANT, var_out)); -} - -static bool32 -config_uint_var(Config_Item item, char *var_name, int32_t *subscript, uint32_t *var_out){ - return(config_var(item, var_name, subscript, CPP_TOKEN_INTEGER_CONSTANT, var_out)); -} - -static bool32 -config_string_var(Config_Item item, char *var_name, int32_t *subscript, String *var_out){ - return(config_var(item, var_name, subscript, CPP_TOKEN_STRING_CONSTANT, var_out)); -} - -static bool32 -config_identifier_var(Config_Item item, char *var_name, int32_t *subscript, String *var_out){ - return(config_var(item, var_name, subscript, CPP_TOKEN_IDENTIFIER, var_out)); -} - -static bool32 -config_array_var(Config_Item item, char *var_name, int32_t *subscript, Config_Array_Reader *array_reader){ - return(config_var(item, var_name, subscript, CPP_TOKEN_BRACE_OPEN, array_reader)); -} - -static bool32 -config_array_next_item(Config_Array_Reader *array_reader, Config_Item *item){ - bool32 result = false; - - for (;array_reader->i < array_reader->val_array_end; - ++array_reader->i){ - Cpp_Token array_token = read_config_token(array_reader->array, &array_reader->i); - if (array_token.size == 0 || array_reader->i >= array_reader->val_array_end){ - break; - } - - if (array_token.type == CPP_TOKEN_BRACE_CLOSE){ - break; - } - - switch (array_token.type){ - case CPP_TOKEN_BOOLEAN_CONSTANT: - case CPP_TOKEN_INTEGER_CONSTANT: - case CPP_TOKEN_STRING_CONSTANT: - { - Config_Line line = {0}; - line.val_token = array_token; - line.read_success = 1; - *item = get_config_item(line, array_reader->mem, array_reader->array); - result = true; - ++array_reader->i; - goto doublebreak; - }break; - } - } - doublebreak:; - - array_reader->good = result; - return(result); -} - -static bool32 -config_array_good(Config_Array_Reader *array_reader){ - return(array_reader->good); -} - -//////////////////////////////// - static void change_mapping(Application_Links *app, String mapping){ bool32 did_remap = false; @@ -956,7 +812,7 @@ text_data_to_token_array(Partition *arena, String data){ success = true; } } - } + } if (!success){ memset(&array, 0, sizeof(array)); end_temp_memory(restore_point); @@ -971,11 +827,11 @@ text_data_to_parsed_data(Partition *arena, String file_name, String data){ Cpp_Token_Array array = text_data_to_token_array(arena, data); if (array.tokens != 0){ parsed = text_data_and_token_array_to_parse_data(arena, file_name, data, array); -if (parsed == 0){ - end_temp_memory(restore_point); + if (parsed == 0){ + end_temp_memory(restore_point); + } } -} - return(parsed); + return(parsed); } //////////////////////////////// @@ -1019,85 +875,91 @@ config_init_default(Config_Data *config){ memset(&config->code_exts, 0, sizeof(config->code_exts)); } -static void -config_parse__data(Partition *scratch, String file_name, String data, Config_Data *config){ +static Config* +config_parse__data(Partition *arena, String file_name, String data, Config_Data *config){ config_init_default(config); bool32 success = false; - Temp_Memory temp = begin_temp_memory(scratch); - Config *parsed = text_data_to_parsed_data(scratch, file_name, data); - if (parsed != 0){ - success = true; - - config_bool_var(parsed, "enable_code_wrapping", 0, &config->enable_code_wrapping); - config_bool_var(parsed, "automatically_adjust_wrapping", 0, &config->automatically_adjust_wrapping); - config_bool_var(parsed, "automatically_indent_text_on_save", 0, &config->automatically_indent_text_on_save); - config_bool_var(parsed, "automatically_save_changes_on_build", 0, &config->automatically_save_changes_on_build); - - config_int_var(parsed, "default_wrap_width", 0, &config->default_wrap_width); - config_int_var(parsed, "default_min_base_width", 0, &config->default_min_base_width); - - config_string_var(parsed, "default_theme_name", 0, &config->default_theme_name); - config_string_var(parsed, "default_font_name", 0, &config->default_font_name); - config_string_var(parsed, "user_name", 0, &config->user_name); - - config_string_var(parsed, "default_compiler_bat", 0, &config->default_compiler_bat); - config_string_var(parsed, "default_flags_bat", 0, &config->default_flags_bat); - config_string_var(parsed, "default_compiler_sh", 0, &config->default_compiler_sh); - config_string_var(parsed, "default_flags_sh", 0, &config->default_flags_sh); - - config_string_var(parsed, "mapping", 0, &config->current_mapping); - - char space[512]; - String str = make_fixed_width_string(space); - if (config_string_var(parsed, "treat_as_code", 0, &str)){ - parse_extension_line_to_extension_list(str, &config->code_exts); - } - - config_bool_var(parsed, "automatically_load_project", 0, &config->automatically_load_project); - config_bool_var(parsed, "lalt_lctrl_is_altgr", 0, &config->lalt_lctrl_is_altgr); - } - - end_temp_memory(temp); + Config *parsed = text_data_to_parsed_data(arena, file_name, data); + if (parsed != 0){ + success = true; + + config_bool_var(parsed, "enable_code_wrapping", 0, &config->enable_code_wrapping); + config_bool_var(parsed, "automatically_adjust_wrapping", 0, &config->automatically_adjust_wrapping); + config_bool_var(parsed, "automatically_indent_text_on_save", 0, &config->automatically_indent_text_on_save); + config_bool_var(parsed, "automatically_save_changes_on_build", 0, &config->automatically_save_changes_on_build); + + config_int_var(parsed, "default_wrap_width", 0, &config->default_wrap_width); + config_int_var(parsed, "default_min_base_width", 0, &config->default_min_base_width); + + config_fixed_string_var(parsed, "default_theme_name", 0, + &config->default_theme_name, config->default_theme_name_space); + config_fixed_string_var(parsed, "default_font_name", 0, + &config->default_font_name, config->default_font_name_space); + config_fixed_string_var(parsed, "user_name", 0, + &config->user_name, config->user_name_space); + + config_fixed_string_var(parsed, "default_compiler_bat", 0, + &config->default_compiler_bat, config->default_compiler_bat_space); + config_fixed_string_var(parsed, "default_flags_bat", 0, + &config->default_flags_bat, config->default_flags_bat_space); + config_fixed_string_var(parsed, "default_compiler_sh", 0, + &config->default_compiler_sh, config->default_compiler_sh_space); + config_fixed_string_var(parsed, "default_flags_sh", 0, + &config->default_flags_sh, config->default_flags_sh_space); + + config_fixed_string_var(parsed, "mapping", 0, + &config->current_mapping, config->current_mapping_space); + + String str; + if (config_string_var(parsed, "treat_as_code", 0, &str)){ + parse_extension_line_to_extension_list(str, &config->code_exts); + } + + config_bool_var(parsed, "automatically_load_project", 0, &config->automatically_load_project); + config_bool_var(parsed, "lalt_lctrl_is_altgr", 0, &config->lalt_lctrl_is_altgr); + } if (!success){ config_init_default(config); } + + return(parsed); } -static void -config_parse__file_handle(Partition *scratch, - String file_name, FILE *file, Config_Data *config){ - Temp_Memory temp = begin_temp_memory(scratch); - String data = dump_file_handle(scratch, file); +static Config* +config_parse__file_handle(Partition *arena, + String file_name, FILE *file, Config_Data *config){ + Config *parsed = 0; + String data = dump_file_handle(arena, file); if (data.str != 0){ - config_parse__data(scratch, file_name, data, config); + parsed = config_parse__data(arena, file_name, data, config); } else{ config_init_default(config); } - end_temp_memory(temp); + return(parsed); } -static void -config_parse__file_name(Application_Links *app, Partition *scratch, +static Config* +config_parse__file_name(Application_Links *app, Partition *arena, char *file_name, Config_Data *config){ + Config *parsed = 0; bool32 success = false; FILE *file = open_file_try_current_path_then_binary_path(app, file_name); if (file != 0){ - Temp_Memory temp = begin_temp_memory(scratch); - String data = dump_file_handle(scratch, file); + String data = dump_file_handle(arena, file); fclose(file); - if (data.str != 0){ - config_parse__data(scratch, make_string_slowly(file_name), data, config); + if (data.str != 0){ + parsed = config_parse__data(arena, make_string_slowly(file_name), data, config); + success = true; } - end_temp_memory(temp); - } - + } if (!success){ config_init_default(config); } + return(parsed); } static void @@ -1107,64 +969,50 @@ init_theme_zero(Theme *theme){ } } -static bool32 -theme_parse__data(Partition *scratch, String file_name, String data, Theme_Data *theme){ +static Config* +theme_parse__data(Partition *arena, String file_name, String data, Theme_Data *theme){ theme->name = make_fixed_width_string(theme->space); copy(&theme->name, "unnamed"); init_theme_zero(&theme->theme); - bool32 success = false; - Temp_Memory temp = begin_temp_memory(scratch); - - Config *parsed = text_data_to_parsed_data(scratch, file_name, data); - if (parsed != 0){ - success = true; - - String theme_name = {0}; - if (config_string_var(parsed, "name", 0, &theme_name)){ - copy(&theme->name, theme_name); - } - - for (int32_t i = 0; i < Stag_COUNT; ++i){ - char *name = style_tag_names[i]; - uint32_t color = 0; - if (!config_uint_var(parsed, name, 0, &color)){ - color = 0xFFFF00FF; - } - theme->theme.colors[i] = color; - } + Config *parsed = text_data_to_parsed_data(arena, file_name, data); + if (parsed != 0){ + config_fixed_string_var(parsed, "name", 0, &theme->name, theme->space); + + for (int32_t i = 0; i < Stag_COUNT; ++i){ + char *name = style_tag_names[i]; + uint32_t color = 0; + if (!config_uint_var(parsed, name, 0, &color)){ + color = 0xFFFF00FF; } - - end_temp_memory(temp); - - return(success); -} - -static bool32 -theme_parse__file_handle(Partition *scratch, String file_name, FILE *file, Theme_Data *theme){ - Temp_Memory temp = begin_temp_memory(scratch); - String data = dump_file_handle(scratch, file); - bool32 success = false; - if (data.str != 0){ - success = theme_parse__data(scratch, file_name, data, theme); + theme->theme.colors[i] = color; + } } - end_temp_memory(temp); - return(success); + + return(parsed); } -static bool32 -theme_parse__file_name(Application_Links *app, Partition *scratch, +static Config* +theme_parse__file_handle(Partition *arena, String file_name, FILE *file, Theme_Data *theme){ + String data = dump_file_handle(arena, file); + Config *parsed = 0; + if (data.str != 0){ + parsed = theme_parse__data(arena, file_name, data, theme); + } + return(parsed); +} + +static Config* +theme_parse__file_name(Application_Links *app, Partition *arena, char *file_name, Theme_Data *theme){ - bool32 success = false; + Config *parsed = 0; FILE *file = open_file_try_current_path_then_binary_path(app, file_name); if (file != 0){ - Temp_Memory temp = begin_temp_memory(scratch); - String data = dump_file_handle(scratch, file); + String data = dump_file_handle(arena, file); fclose(file); - success = theme_parse__data(scratch, make_string_slowly(file_name), data, theme); - end_temp_memory(temp); + parsed = theme_parse__data(arena, make_string_slowly(file_name), data, theme); } - if (!success){ + if (parsed == 0){ char space[256]; String str = make_fixed_width_string(space); append(&str, "Did not find "); @@ -1172,14 +1020,19 @@ theme_parse__file_name(Application_Links *app, Partition *scratch, append(&str, ", color scheme not loaded"); print_message(app, str.str, str.size); } - return(success); + return(parsed); } //////////////////////////////// static void load_config_and_apply(Application_Links *app, Partition *scratch, Config_Data *config){ - config_parse__file_name(app, scratch, "config.4coder", config); + Temp_Memory temp = begin_temp_memory(scratch); + Config *parsed = config_parse__file_name(app, scratch, "config.4coder", config); + String error_text = config_stringize_errors(scratch, parsed); + print_message(app, error_text.str, error_text.size); + end_temp_memory(temp); + change_mapping(app, config->current_mapping); adjust_all_buffer_wrap_widths(app, config->default_wrap_width, config->default_min_base_width); global_set_setting(app, GlobalSetting_LAltLCtrlIsAltGr, config->lalt_lctrl_is_altgr); @@ -1187,8 +1040,12 @@ load_config_and_apply(Application_Links *app, Partition *scratch, Config_Data *c static void load_theme_file_into_live_set(Application_Links *app, Partition *scratch, char *file_name){ + Temp_Memory temp = begin_temp_memory(scratch); Theme_Data theme = {0}; - theme_parse__file_name(app, scratch, file_name, &theme); + Config *config = theme_parse__file_name(app, scratch, file_name, &theme); + String error_text = config_stringize_errors(scratch, config); + print_message(app, error_text.str, error_text.size); + end_temp_memory(temp); create_theme(app, &theme.theme, theme.name.str, theme.name.size); } diff --git a/4coder_config.h b/4coder_config.h index 545b420e..11293310 100644 --- a/4coder_config.h +++ b/4coder_config.h @@ -7,6 +7,23 @@ #if !defined(FCODER_CONFIG_H) #define FCODER_CONFIG_H +// TODO(allen): Stop handling files this way! My own API should be able to do this!!?!?!?!!?!?!!!!? +// NOTE(allen): Actually need binary buffers for some stuff to work, but not this parsing thing here. +#include + +struct Error_Location{ + int32_t line_number; + int32_t column_number; +}; + +struct Config_Error{ + Config_Error *next; + Config_Error *prev; + String file_name; + char *pos; + String text; +}; + struct Config_Parser{ Cpp_Token *start; Cpp_Token *token; @@ -16,6 +33,10 @@ Cpp_Token *end; String data; Partition *arena; + + Config_Error *first_error; + Config_Error *last_error; + int32_t count_error; }; struct Config_LValue{ @@ -100,6 +121,12 @@ struct Config{ Config_Assignment *first; Config_Assignment *last; int32_t count; + + Config_Error *first_error; + Config_Error *last_error; + int32_t count_error; + + String data; }; //////////////////////////////// diff --git a/4coder_config_grammar.txt b/4coder_config_grammar.txt index 731630e9..77e99cc4 100644 --- a/4coder_config_grammar.txt +++ b/4coder_config_grammar.txt @@ -1,6 +1,6 @@ config := [version] {assignment} -version := "version" "(" INTEGER ")" +version := "version" "(" INTEGER ")" ";" assignment := lvalue "=" rvalue ";" lvalue := IDENTIFIER [ "[" INTEGER "]" ] rvalue := lvalue | BOOLEAN | INTEGER | STRING | CHARACTER | "{" compound_body diff --git a/4coder_default_framework.h b/4coder_default_framework.h index d9a33928..f6bbec24 100644 --- a/4coder_default_framework.h +++ b/4coder_default_framework.h @@ -36,37 +36,6 @@ struct ID_Based_Jump_Location{ //////////////////////////////// -struct Config_Line{ - Cpp_Token id_token; - Cpp_Token subscript_token; - Cpp_Token eq_token; - Cpp_Token val_token; - int32_t val_array_start; - int32_t val_array_end; - int32_t val_array_count; - String error_str; - bool32 read_success; -}; - -struct Config_Item{ - Config_Line line; - Cpp_Token_Array array; - char *mem; - String id; - int32_t subscript_index; - bool32 has_subscript; -}; - -struct Config_Array_Reader{ - Cpp_Token_Array array; - char *mem; - int32_t i; - int32_t val_array_end; - bool32 good; -}; - -//////////////////////////////// - struct Named_Mapping{ String name; Custom_Command_Function *remap_command; diff --git a/4coder_generated/command_metadata.h b/4coder_generated/command_metadata.h index 0a331b42..f6357e7e 100644 --- a/4coder_generated/command_metadata.h +++ b/4coder_generated/command_metadata.h @@ -229,7 +229,7 @@ static Command_Metadata fcoder_metacmd_table[193] = { { PROC_LINKS(clean_all_lines, 0), "clean_all_lines", 15, "Removes trailing whitespace from all lines in the current buffer.", 65, "C:\\work\\4ed\\code\\4coder_base_commands.cpp", 45, 368 }, { PROC_LINKS(click_set_cursor, 0), "click_set_cursor", 16, "Sets the cursor position to the mouse position.", 47, "C:\\work\\4ed\\code\\4coder_base_commands.cpp", 45, 174 }, { PROC_LINKS(click_set_mark, 0), "click_set_mark", 14, "Sets the mark position to the mouse position.", 45, "C:\\work\\4ed\\code\\4coder_base_commands.cpp", 45, 187 }, -{ PROC_LINKS(close_all_code, 0), "close_all_code", 14, "Closes any buffer with a filename ending with an extension configured to be recognized as a code file type.", 107, "C:\\work\\4ed\\code\\4coder_project_commands.cpp", 48, 373 }, +{ PROC_LINKS(close_all_code, 0), "close_all_code", 14, "Closes any buffer with a filename ending with an extension configured to be recognized as a code file type.", 107, "C:\\work\\4ed\\code\\4coder_project_commands.cpp", 48, 380 }, { PROC_LINKS(close_build_panel, 0), "close_build_panel", 17, "If the special build panel is open, closes it.", 46, "C:\\work\\4ed\\code\\4coder_build_commands.cpp", 46, 205 }, { PROC_LINKS(close_panel, 0), "close_panel", 11, "Closes the currently active panel if it is not the only panel open.", 67, "C:\\work\\4ed\\code\\4coder_base_commands.cpp", 45, 441 }, { PROC_LINKS(copy, 0), "copy", 4, "Copy the text in the range from the cursor to the mark onto the clipboard.", 74, "C:\\work\\4ed\\code\\4coder_clipboard.cpp", 41, 26 }, @@ -295,7 +295,7 @@ static Command_Metadata fcoder_metacmd_table[193] = { { PROC_LINKS(list_all_locations_of_type_definition_of_identifier, 0), "list_all_locations_of_type_definition_of_identifier", 51, "Reads a token or word under the cursor and lists all locations of strings that appear to define a type whose name matches it.", 125, "C:\\work\\4ed\\code\\4coder_search.cpp", 38, 800 }, { PROC_LINKS(list_all_substring_locations, 0), "list_all_substring_locations", 28, "Queries the user for a string and lists all case-sensitive substring matches found in all open buffers.", 103, "C:\\work\\4ed\\code\\4coder_search.cpp", 38, 747 }, { PROC_LINKS(list_all_substring_locations_case_insensitive, 0), "list_all_substring_locations_case_insensitive", 45, "Queries the user for a string and lists all case-insensitive substring matches found in all open buffers.", 105, "C:\\work\\4ed\\code\\4coder_search.cpp", 38, 759 }, -{ PROC_LINKS(load_project, 0), "load_project", 12, "Looks for a project.4coder file in the current directory and tries to load it. Looks in parent directories until a project file is found or there are no more parents.", 167, "C:\\work\\4ed\\code\\4coder_project_commands.cpp", 48, 396 }, +{ PROC_LINKS(load_project, 0), "load_project", 12, "Looks for a project.4coder file in the current directory and tries to load it. Looks in parent directories until a project file is found or there are no more parents.", 167, "C:\\work\\4ed\\code\\4coder_project_commands.cpp", 48, 403 }, { PROC_LINKS(make_directory_query, 0), "make_directory_query", 20, "Queries the user for a name and creates a new directory with the given name.", 76, "C:\\work\\4ed\\code\\4coder_base_commands.cpp", 45, 1101 }, { PROC_LINKS(miblo_decrement_basic, 0), "miblo_decrement_basic", 21, "Decrement an integer under the cursor by one.", 45, "C:\\work\\4ed\\code\\4coder_miblo_numbers.cpp", 45, 110 }, { PROC_LINKS(miblo_decrement_time_stamp, 0), "miblo_decrement_time_stamp", 26, "Decrement a time stamp under the cursor by one second. (format [m]m:ss or h:mm:ss", 81, "C:\\work\\4ed\\code\\4coder_miblo_numbers.cpp", 45, 383 }, @@ -317,8 +317,8 @@ static Command_Metadata fcoder_metacmd_table[193] = { { PROC_LINKS(newline_or_goto_position_same_panel_direct, 0), "newline_or_goto_position_same_panel_direct", 42, "If the buffer in the active view is writable, inserts a character, otherwise performs goto_jump_at_cursor_same_panel.", 117, "C:\\work\\4ed\\code\\4coder_jump_direct.cpp", 43, 116 }, { PROC_LINKS(newline_or_goto_position_same_panel_sticky, 0), "newline_or_goto_position_same_panel_sticky", 42, "If the buffer in the active view is writable, inserts a character, otherwise performs goto_jump_at_cursor_same_panel.", 117, "C:\\work\\4ed\\code\\4coder_jump_sticky.cpp", 43, 571 }, { PROC_LINKS(newline_or_goto_position_sticky, 0), "newline_or_goto_position_sticky", 31, "If the buffer in the active view is writable, inserts a character, otherwise performs goto_jump_at_cursor.", 106, "C:\\work\\4ed\\code\\4coder_jump_sticky.cpp", 43, 556 }, -{ PROC_LINKS(open_all_code, 0), "open_all_code", 13, "Open all code in the current directory. File types are determined by extensions. An extension is considered code based on the extensions specified in 4coder.config.", 164, "C:\\work\\4ed\\code\\4coder_project_commands.cpp", 48, 380 }, -{ PROC_LINKS(open_all_code_recursive, 0), "open_all_code_recursive", 23, "Works as open_all_code but also runs in all subdirectories.", 59, "C:\\work\\4ed\\code\\4coder_project_commands.cpp", 48, 387 }, +{ PROC_LINKS(open_all_code, 0), "open_all_code", 13, "Open all code in the current directory. File types are determined by extensions. An extension is considered code based on the extensions specified in 4coder.config.", 164, "C:\\work\\4ed\\code\\4coder_project_commands.cpp", 48, 387 }, +{ PROC_LINKS(open_all_code_recursive, 0), "open_all_code_recursive", 23, "Works as open_all_code but also runs in all subdirectories.", 59, "C:\\work\\4ed\\code\\4coder_project_commands.cpp", 48, 394 }, { PROC_LINKS(open_color_tweaker, 0), "open_color_tweaker", 18, "Opens the 4coder colors and fonts selector menu.", 48, "C:\\work\\4ed\\code\\4coder_base_commands.cpp", 45, 1457 }, { PROC_LINKS(open_file_in_quotes, 0), "open_file_in_quotes", 19, "Reads a filename from surrounding '\"' characters and attempts to open the corresponding file.", 94, "C:\\work\\4ed\\code\\4coder_base_commands.cpp", 45, 1320 }, { PROC_LINKS(open_in_other, 0), "open_in_other", 13, "Switches to the next active panel and begins an open file dialogue.", 67, "C:\\work\\4ed\\code\\4coder_base_commands.cpp", 45, 1465 }, @@ -335,8 +335,8 @@ static Command_Metadata fcoder_metacmd_table[193] = { { PROC_LINKS(paste_next, 0), "paste_next", 10, "If the previous command was paste or paste_next, replaces the paste range with the next text down on the clipboard, otherwise operates as the paste command.", 156, "C:\\work\\4ed\\code\\4coder_clipboard.cpp", 41, 84 }, { PROC_LINKS(paste_next_and_indent, 0), "paste_next_and_indent", 21, "Paste the next item on the clipboard and run auto-indent on the newly pasted text.", 82, "C:\\work\\4ed\\code\\4coder_clipboard.cpp", 41, 135 }, { PROC_LINKS(place_in_scope, 0), "place_in_scope", 14, "Wraps the code contained in the range between cursor and mark with a new curly brace scope.", 91, "C:\\work\\4ed\\code\\4coder_scope_commands.cpp", 46, 481 }, -{ PROC_LINKS(project_fkey_command, 0), "project_fkey_command", 20, "Run an 'fkey command' configured in a project.4coder file. Determines the index of the 'fkey command' by which function key or numeric key was pressed to trigger the command.", 175, "C:\\work\\4ed\\code\\4coder_project_commands.cpp", 48, 403 }, -{ PROC_LINKS(project_go_to_root_directory, 0), "project_go_to_root_directory", 28, "Changes 4coder's hot directory to the root directory of the currently loaded project. With no loaded project nothing hapepns.", 125, "C:\\work\\4ed\\code\\4coder_project_commands.cpp", 48, 428 }, +{ PROC_LINKS(project_fkey_command, 0), "project_fkey_command", 20, "Run an 'fkey command' configured in a project.4coder file. Determines the index of the 'fkey command' by which function key or numeric key was pressed to trigger the command.", 175, "C:\\work\\4ed\\code\\4coder_project_commands.cpp", 48, 410 }, +{ PROC_LINKS(project_go_to_root_directory, 0), "project_go_to_root_directory", 28, "Changes 4coder's hot directory to the root directory of the currently loaded project. With no loaded project nothing hapepns.", 125, "C:\\work\\4ed\\code\\4coder_project_commands.cpp", 48, 435 }, { PROC_LINKS(query_replace, 0), "query_replace", 13, "Queries the user for two strings, and incrementally replaces every occurence of the first string with the second string.", 120, "C:\\work\\4ed\\code\\4coder_base_commands.cpp", 45, 893 }, { PROC_LINKS(query_replace_identifier, 0), "query_replace_identifier", 24, "Queries the user for a string, and incrementally replace every occurence of the word or token found at the cursor with the specified string.", 140, "C:\\work\\4ed\\code\\4coder_base_commands.cpp", 45, 913 }, { PROC_LINKS(query_replace_selection, 0), "query_replace_selection", 23, "Queries the user for a string, and incrementally replace every occurence of the string found in the selected range with the specified string.", 141, "C:\\work\\4ed\\code\\4coder_base_commands.cpp", 45, 931 }, @@ -378,7 +378,7 @@ static Command_Metadata fcoder_metacmd_table[193] = { { PROC_LINKS(set_bindings_default, 0), "set_bindings_default", 20, "Remap keybindings using the 'default' mapping rule.", 51, "C:\\work\\4ed\\code\\4coder_remapping_commands.cpp", 50, 61 }, { PROC_LINKS(set_bindings_mac_default, 0), "set_bindings_mac_default", 24, "Remap keybindings using the 'mac-default' mapping rule.", 55, "C:\\work\\4ed\\code\\4coder_remapping_commands.cpp", 50, 75 }, { PROC_LINKS(set_mark, 0), "set_mark", 8, "Sets the mark to the current position of the cursor.", 52, "C:\\work\\4ed\\code\\4coder_base_commands.cpp", 45, 86 }, -{ PROC_LINKS(setup_new_project, 0), "setup_new_project", 17, "Queries the user for several configuration options and initializes a new 4coder project with build scripts for every OS.", 120, "C:\\work\\4ed\\code\\4coder_project_commands.cpp", 48, 475 }, +{ PROC_LINKS(setup_new_project, 0), "setup_new_project", 17, "Queries the user for several configuration options and initializes a new 4coder project with build scripts for every OS.", 120, "C:\\work\\4ed\\code\\4coder_project_commands.cpp", 48, 482 }, { PROC_LINKS(show_filebar, 0), "show_filebar", 12, "Sets the current view to show it's filebar.", 43, "C:\\work\\4ed\\code\\4coder_base_commands.cpp", 45, 464 }, { PROC_LINKS(show_scrollbar, 0), "show_scrollbar", 14, "Sets the current view to show it's scrollbar.", 45, "C:\\work\\4ed\\code\\4coder_base_commands.cpp", 45, 450 }, { PROC_LINKS(snipe_token_or_word, 0), "snipe_token_or_word", 19, "Delete a single, whole token on or to the left of the cursor and post it to the clipboard.", 90, "C:\\work\\4ed\\code\\4coder_seek.cpp", 36, 1259 }, diff --git a/4coder_project_commands.cpp b/4coder_project_commands.cpp index 6e794111..81b077eb 100644 --- a/4coder_project_commands.cpp +++ b/4coder_project_commands.cpp @@ -144,17 +144,17 @@ open_all_files_in_hot_with_extension(Application_Links *app, Partition *scratch, /////////////////////////////// -static bool32 +static Config* parse_project__data(Partition *scratch, String file_name, String data, String file_dir, Project *project){ - bool32 success = false; + Config *parsed = 0; Cpp_Token_Array array = text_data_to_token_array(scratch, data); if (array.tokens != 0){ - Config *parsed = text_data_and_token_array_to_parse_data(scratch, file_name, data, array); + parsed = text_data_and_token_array_to_parse_data(scratch, file_name, data, array); if (parsed != 0){ - success = true; memset(project, 0, sizeof(*project)); + project->loaded = true; // Set new project directory { @@ -223,32 +223,32 @@ parse_project__data(Partition *scratch, String file_name, String data, String fi } } - return(success); + return(parsed); } -static bool32 -parse_project__nearest_file(Application_Links *app, Partition *arena, Project *project){ - bool32 success = false; +static Config* +parse_project__nearest_file(Application_Links *app, Partition *scratch, Project *project){ + Config *parsed = 0; String project_path = {0}; - Temp_Memory temp = begin_temp_memory(arena); + Temp_Memory temp = begin_temp_memory(scratch); int32_t size = 32 << 10; - char *space = push_array(arena, char, size); + char *space = push_array(scratch, char, size); if (space != 0){ project_path = make_string_cap(space, 0, size); project_path.size = directory_get_hot(app, project_path.str, project_path.memory_size); end_temp_memory(temp); - push_array(arena, char, project_path.size); + push_array(scratch, char, project_path.size); project_path.memory_size = project_path.size; if (project_path.size == 0){ print_message(app, literal("The hot directory is empty, cannot search for a project.\n")); } else{ - File_Name_Path_Data dump = dump_file_search_up_path(arena, project_path, make_lit_string("project.4coder")); + File_Name_Path_Data dump = dump_file_search_up_path(scratch, project_path, make_lit_string("project.4coder")); if (dump.data.str != 0){ String project_root = dump.path; remove_last_folder(&project_root); - success = parse_project__data(arena, dump.file_name, dump.data, project_root, project); + parsed = parse_project__data(scratch, dump.file_name, dump.data, project_root, project); } else{ char message_space[512]; @@ -268,14 +268,15 @@ parse_project__nearest_file(Application_Links *app, Partition *arena, Project *p } end_temp_memory(temp); - return(success); + return(parsed); } static void -set_current_project(Application_Links *app, Partition *scratch, Project *project){ - memcpy(¤t_project, &project, sizeof(current_project)); +set_current_project(Application_Links *app, Partition *scratch, Project *project, Config *parsed){ + memcpy(¤t_project, project, sizeof(current_project)); + current_project.dir = current_project.dir_space; - String file_dir = make_string(project->dir_space, project->dir_len); + String file_dir = make_string(current_project.dir_space, current_project.dir_len); // Open all project files uint32_t flags = 0; @@ -292,6 +293,11 @@ set_current_project(Application_Links *app, Partition *scratch, Project *project append(&builder, file_dir); terminate_with_null(&builder); set_window_title(app, builder.str); + + Temp_Memory temp = begin_temp_memory(scratch); + String error_text = config_stringize_errors(scratch, parsed); + print_message(app, error_text.str, error_text.size); + end_temp_memory(temp); } static void @@ -299,19 +305,20 @@ set_current_project_from_data(Application_Links *app, Partition *scratch, String file_name, String data, String file_dir){ Temp_Memory temp = begin_temp_memory(scratch); Project project = {0}; - if (parse_project__data(scratch, file_name, data, file_dir, - &project)){ - set_current_project(app, scratch, &project); + Config *parsed = parse_project__data(scratch, file_name, data, file_dir, &project); + if (parsed != 0){ + set_current_project(app, scratch, &project, parsed); } end_temp_memory(temp); } static void -set_project_from_nearest_project_file(Application_Links *app, Partition *scratch){ +set_current_project_from_nearest_project_file(Application_Links *app, Partition *scratch){ Temp_Memory temp = begin_temp_memory(scratch); Project project = {0}; - if (parse_project__nearest_file(app, scratch, &project)){ - set_current_project(app, scratch, &project); + Config *parsed = parse_project__nearest_file(app, scratch, &project); + if (parsed != 0){ + set_current_project(app, scratch, &project, parsed); } end_temp_memory(temp); } @@ -397,7 +404,7 @@ CUSTOM_COMMAND_SIG(load_project) CUSTOM_DOC("Looks for a project.4coder file in the current directory and tries to load it. Looks in parent directories until a project file is found or there are no more parents.") { save_all_dirty_buffers(app); - set_project_from_nearest_project_file(app, &global_part); + set_current_project_from_nearest_project_file(app, &global_part); } CUSTOM_COMMAND_SIG(project_fkey_command) diff --git a/4coder_project_commands.h b/4coder_project_commands.h index 3b486110..31300316 100644 --- a/4coder_project_commands.h +++ b/4coder_project_commands.h @@ -31,7 +31,6 @@ struct Project{ Fkey_Command fkey_commands[16]; bool32 open_recursively; - bool32 loaded; }; diff --git a/project.4coder b/project.4coder index aa4091ef..d20d8866 100644 --- a/project.4coder +++ b/project.4coder @@ -1,30 +1,34 @@ extensions = ".c.cpp.h.m.bat.sh.4coder.txt"; open_recursively = true; -fkey_command_win[1] = {"build_tests.bat" , "*compilation*" , true , true }; -fkey_command_win[2] = {"generate_tests.bat" , "*compilation*" , true , true }; -fkey_command_win[3] = {"run_regression_tests.bat" , "*test*" , false, true }; +build_x86_win32 = "echo build: x86 & build.bat /DDEV_BUILD_X86"; +build_x86_linux = "echo build: x86 & ./build.sh -DDEV_BUILD_X86"; +build_x86_mac = "echo build: x86 & ./build.sh -DDEV_BUILD_X86"; -fkey_command_win[1] = {"echo build: x64 & build.bat", "*compilation*" , true , true }; -fkey_command_win[2] = {"build_site.bat" , "*site*" , false, true }; -fkey_command_win[3] = {"build_string.bat" , "*compilation*" , true , true }; -fkey_command_win[4] = {"echo build: x86 & build.bat /DDEV_BUILD_X86" , "*compilation*", true, true }; -fkey_command_win[5] = {"build_metadata.bat" , "*compilation*" , true , true }; -fkey_command_win[6] = {"run_regression_tests.bat" , "*test*" , false, true }; -fkey_command_win[7] = {"build_tests.bat" , "*compilation*" , true , true }; -fkey_command_win[8] = {"generate_tests.bat" , "*compilation*" , true , true }; -fkey_command_win[12] = {"package.bat" , "*package*" , false, true }; +fkey_command_win[1] = {"echo build: x64 & build.bat", "*compilation*" , .footer_panel = true , .save_dirty_files = true }; +fkey_command_win[2] = {"build_site.bat" , "*site*" , .footer_panel = false, .save_dirty_files = true }; +fkey_command_win[3] = {"build_string.bat" , "*compilation*" , .footer_panel = true , .save_dirty_files = true }; +fkey_command_win[4] = {build_x86_win32 , "*compilation*" , .footer_panel = true, .save_dirty_files = true }; +fkey_command_win[5] = {"build_metadata.bat" , "*compilation*" , .footer_panel = true , .save_dirty_files = true }; +fkey_command_win[6] = {"run_regression_tests.bat" , "*test*" , .footer_panel = false, .save_dirty_files = true }; +fkey_command_win[7] = {"build_tests.bat" , "*compilation*" , .footer_panel = true , .save_dirty_files = true }; +fkey_command_win[8] = {"generate_tests.bat" , "*compilation*" , .footer_panel = true , .save_dirty_files = true }; +fkey_command_win[12] = {"package.bat" , "*package*" , .footer_panel = false, .save_dirty_files = true }; -fkey_command_linux[1] = {"echo build: x64 & ./build.sh", "*compilation*" , true , true }; -fkey_command_linux[2] = {"build_site.sh" , "*site*" , false, true }; -fkey_command_linux[3] = {"build_string.sh" , "*compilation*" , true , true }; -fkey_command_linux[4] = {"echo build: x86 & ./build.sh -DDEV_BUILD_X86" , "*compilation*", true, true }; -fkey_command_linux[5] = {"./build_metadata.sh" , "*compilation*" , true , true }; -fkey_command_linux[12] = {"./package.sh" , "*package*" , false, true }; +fkey_command_win[1] = {"build_tests.bat" , "*compilation*" , .footer_panel = true , .save_dirty_files = true }; +fkey_command_win[2] = {"generate_tests.bat" , "*compilation*" , .footer_panel = true , .save_dirty_files = true }; +fkey_command_win[3] = {"run_regression_tests.bat" , "*test*" , .footer_panel = false, .save_dirty_files = true }; -fkey_command_mac[1] = {"echo build: x64 & ./build.sh", "*compilation*" , true , true }; -fkey_command_mac[2] = {"build_site.sh" , "*site*" , false, true }; -fkey_command_mac[3] = {"build_string.sh" , "*compilation*" , true , true }; -fkey_command_mac[4] = {"echo build: x86 & ./build.sh -DDEV_BUILD_X86" , "*compilation*", true, true }; -fkey_command_mac[10] = {"./package.sh" , "*package*" , false, true }; +fkey_command_linux[1] = {"echo build: x64 & ./build.sh", "*compilation*" , .footer_panel = true , .save_dirty_files = true }; +fkey_command_linux[2] = {"build_site.sh" , "*site*" , .footer_panel = false, .save_dirty_files = true }; +fkey_command_linux[3] = {"build_string.sh" , "*compilation*" , .footer_panel = true , .save_dirty_files = true }; +fkey_command_linux[4] = {build_x86_linux , "*compilation*" , .footer_panel = true , .save_dirty_files = true }; +fkey_command_linux[5] = {"./build_metadata.sh" , "*compilation*" , .footer_panel = true , .save_dirty_files = true }; +fkey_command_linux[12] = {"./package.sh" , "*package*" , .footer_panel = false, .save_dirty_files = true }; + +fkey_command_mac[1] = {"echo build: x64 & ./build.sh", "*compilation*" , .footer_panel = true , .save_dirty_files = true }; +fkey_command_mac[2] = {"build_site.sh" , "*site*" , .footer_panel = false, .save_dirty_files = true }; +fkey_command_mac[3] = {"build_string.sh" , "*compilation*" , .footer_panel = true , .save_dirty_files = true }; +fkey_command_mac[4] = {build_x86_mac , "*compilation*" , .footer_panel = true , .save_dirty_files = true }; +fkey_command_mac[10] = {"./package.sh" , "*package*" , .footer_panel = false, .save_dirty_files = true }; diff --git a/site/source_material/binding_list.txt b/site/source_material/binding_list.txt index a9a2b102..c65bcc34 100644 --- a/site/source_material/binding_list.txt +++ b/site/source_material/binding_list.txt @@ -34,11 +34,10 @@ The following bindings apply in all situations. \ITEM \STYLE{code} \END Change the currently active panel, moving to the panel with the next lowest view_id. \ITEM \STYLE{code} \END Interactively creates a new file. \ITEM \STYLE{code} \END Interactively opens or creates a new file. -\ITEM \STYLE{code} \END Reads a filename from surrounding '"' characters and attempts to open the corresponding file, displaying it in the other view. +\ITEM \STYLE{code} \END Switches to the next active panel and begins an open file dialogue. \ITEM \STYLE{code} \END Interactively kill an open buffer. \ITEM \STYLE{code} \END Interactively switch to an open buffer. \ITEM \STYLE{code} \END Changes 4coder's hot directory to the root directory of the currently loaded project. With no loaded project nothing hapepns. -\ITEM \STYLE{code} \END If a project file has already been loaded, reloads the same file. Useful for when the project configuration is changed. \ITEM \STYLE{code} \END Saves all buffers marked dirty (showing the '*' indicator). \ITEM \STYLE{code} \END Opens the 4coder colors and fonts selector menu. \ITEM \STYLE{code} \END If the special build panel is open, makes the build panel the active panel. @@ -54,7 +53,6 @@ The following bindings apply in all situations. \ITEM \STYLE{code} \END Sets the current view to hide it's scrollbar. \ITEM \STYLE{code} \END Toggles the visibility status of the current view's filebar. \ITEM \STYLE{code} \END Toggles the mouse suppression mode, see suppress_mouse and allow_mouse. -\ITEM \STYLE{code} \END Toggle fullscreen mode on or off. The change(s) do not take effect until the next frame. \ITEM \STYLE{code} \END Attempts to close 4coder. \ITEM \STYLE{code} \END Increase the size of the face used by the current buffer. \ITEM \STYLE{code} \END Decrease the size of the face used by the current buffer. @@ -119,7 +117,6 @@ The following bindings apply in general text files and most apply in code files, \ITEM \STYLE{code} \END Queries the user for a string and lists all case-insensitive substring matches found in all open buffers. \ITEM \STYLE{code} \END Queries the user for a number, and jumps the cursor to the corresponding line. \ITEM \STYLE{code} \END Reads the string in the selected range and lists all exact case-sensitive mathces in all open buffers. -\ITEM \STYLE{code} \END Converts all ascii text in the range between the cursor and the mark to lowercase. \ITEM \STYLE{code} \END Kills the current buffer. \ITEM \STYLE{code} \END Toggles the current buffer's line wrapping status. \ITEM \STYLE{code} \END Create a copy of the line on which the cursor sits. @@ -133,7 +130,6 @@ The following bindings apply in general text files and most apply in code files, \ITEM \STYLE{code} \END Queries the user for a name and saves the contents of the current buffer, altering the buffer's name too. \ITEM \STYLE{code} \END Begins an incremental search down through the current buffer for the word or token under the cursor. \ITEM \STYLE{code} \END Reads a token or word under the cursor and lists all exact case-sensitive mathces in all open buffers. -\ITEM \STYLE{code} \END Converts all ascii text in the range between the cursor and the mark to uppercase. \ITEM \STYLE{code} \END Paste from the top of clipboard and run auto-indent on the newly pasted text. \ITEM \STYLE{code} \END Toggles the current buffer's virtual whitespace status. \ITEM \STYLE{code} \END Paste the next item on the clipboard and run auto-indent on the newly pasted text. @@ -198,11 +194,10 @@ The following bindings apply in all situations. \ITEM \STYLE{code} \END Change the currently active panel, moving to the panel with the next lowest view_id. \ITEM \STYLE{code} \END Interactively creates a new file. \ITEM \STYLE{code} \END Interactively opens or creates a new file. -\ITEM \STYLE{code} \END Reads a filename from surrounding '"' characters and attempts to open the corresponding file, displaying it in the other view. +\ITEM \STYLE{code} \END Switches to the next active panel and begins an open file dialogue. \ITEM \STYLE{code} \END Interactively kill an open buffer. \ITEM \STYLE{code} \END Interactively switch to an open buffer. \ITEM \STYLE{code} \END Changes 4coder's hot directory to the root directory of the currently loaded project. With no loaded project nothing hapepns. -\ITEM \STYLE{code} \END If a project file has already been loaded, reloads the same file. Useful for when the project configuration is changed. \ITEM \STYLE{code} \END Saves all buffers marked dirty (showing the '*' indicator). \ITEM \STYLE{code} \END Opens the 4coder colors and fonts selector menu. \ITEM \STYLE{code} \END If the special build panel is open, makes the build panel the active panel. @@ -218,7 +213,6 @@ The following bindings apply in all situations. \ITEM \STYLE{code} \END Sets the current view to hide it's scrollbar. \ITEM \STYLE{code} \END Toggles the visibility status of the current view's filebar. \ITEM \STYLE{code} \END Toggles the mouse suppression mode, see suppress_mouse and allow_mouse. -\ITEM \STYLE{code} \END Toggle fullscreen mode on or off. The change(s) do not take effect until the next frame. \ITEM \STYLE{code} \END Attempts to close 4coder. \ITEM \STYLE{code} \END Increase the size of the face used by the current buffer. \ITEM \STYLE{code} \END Decrease the size of the face used by the current buffer. @@ -282,7 +276,6 @@ The following bindings apply in general text files and most apply in code files, \ITEM \STYLE{code} \END Queries the user for a string and lists all case-insensitive substring matches found in all open buffers. \ITEM \STYLE{code} \END Queries the user for a number, and jumps the cursor to the corresponding line. \ITEM \STYLE{code} \END Reads the string in the selected range and lists all exact case-sensitive mathces in all open buffers. -\ITEM \STYLE{code} \END Converts all ascii text in the range between the cursor and the mark to lowercase. \ITEM \STYLE{code} \END Kills the current buffer. \ITEM \STYLE{code} \END Toggles the current buffer's line wrapping status. \ITEM \STYLE{code} \END Create a copy of the line on which the cursor sits. @@ -295,7 +288,6 @@ The following bindings apply in general text files and most apply in code files, \ITEM \STYLE{code} \END Queries the user for a name and saves the contents of the current buffer, altering the buffer's name too. \ITEM \STYLE{code} \END Begins an incremental search down through the current buffer for the word or token under the cursor. \ITEM \STYLE{code} \END Reads a token or word under the cursor and lists all exact case-sensitive mathces in all open buffers. -\ITEM \STYLE{code} \END Converts all ascii text in the range between the cursor and the mark to uppercase. \ITEM \STYLE{code} \END Paste from the top of clipboard and run auto-indent on the newly pasted text. \ITEM \STYLE{code} \END Toggles the current buffer's virtual whitespace status. \ITEM \STYLE{code} \END Paste the next item on the clipboard and run auto-indent on the newly pasted text.