Added parse error log and parse recover to the config parser

master
Allen Webster 2018-05-19 21:44:20 -07:00
parent cb1273d4cb
commit 5566572269
9 changed files with 418 additions and 563 deletions

View File

@ -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 <stdio.h>
////////////////////////////////
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);
}

View File

@ -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 <stdio.h>
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;
};
////////////////////////////////

View File

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

View File

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

View File

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

View File

@ -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(&current_project, &project, sizeof(current_project));
set_current_project(Application_Links *app, Partition *scratch, Project *project, Config *parsed){
memcpy(&current_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)

View File

@ -31,7 +31,6 @@ struct Project{
Fkey_Command fkey_commands[16];
bool32 open_recursively;
bool32 loaded;
};

View File

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

View File

@ -34,11 +34,10 @@ The following bindings apply in all situations.
\ITEM \STYLE{code} <ctrl <> \END Change the currently active panel, moving to the panel with the next lowest view_id.
\ITEM \STYLE{code} <ctrl n> \END Interactively creates a new file.
\ITEM \STYLE{code} <ctrl o> \END Interactively opens or creates a new file.
\ITEM \STYLE{code} <alt o> \END Reads a filename from surrounding '"' characters and attempts to open the corresponding file, displaying it in the other view.
\ITEM \STYLE{code} <alt o> \END Switches to the next active panel and begins an open file dialogue.
\ITEM \STYLE{code} <ctrl k> \END Interactively kill an open buffer.
\ITEM \STYLE{code} <ctrl i> \END Interactively switch to an open buffer.
\ITEM \STYLE{code} <ctrl h> \END Changes 4coder's hot directory to the root directory of the currently loaded project. With no loaded project nothing hapepns.
\ITEM \STYLE{code} <ctrl H> \END If a project file has already been loaded, reloads the same file. Useful for when the project configuration is changed.
\ITEM \STYLE{code} <ctrl S> \END Saves all buffers marked dirty (showing the '*' indicator).
\ITEM \STYLE{code} <alt c> \END Opens the 4coder colors and fonts selector menu.
\ITEM \STYLE{code} <alt .> \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} <alt w> \END Sets the current view to hide it's scrollbar.
\ITEM \STYLE{code} <alt b> \END Toggles the visibility status of the current view's filebar.
\ITEM \STYLE{code} <alt @> \END Toggles the mouse suppression mode, see suppress_mouse and allow_mouse.
\ITEM \STYLE{code} <ctrl page up> \END Toggle fullscreen mode on or off. The change(s) do not take effect until the next frame.
\ITEM \STYLE{code} <alt E> \END Attempts to close 4coder.
\ITEM \STYLE{code} <ctrl +> \END Increase the size of the face used by the current buffer.
\ITEM \STYLE{code} <ctrl -> \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} <alt F> \END Queries the user for a string and lists all case-insensitive substring matches found in all open buffers.
\ITEM \STYLE{code} <ctrl g> \END Queries the user for a number, and jumps the cursor to the corresponding line.
\ITEM \STYLE{code} <ctrl G> \END Reads the string in the selected range and lists all exact case-sensitive mathces in all open buffers.
\ITEM \STYLE{code} <ctrl j> \END Converts all ascii text in the range between the cursor and the mark to lowercase.
\ITEM \STYLE{code} <ctrl K> \END Kills the current buffer.
\ITEM \STYLE{code} <ctrl l> \END Toggles the current buffer's line wrapping status.
\ITEM \STYLE{code} <ctrl L> \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} <alt s> \END Queries the user for a name and saves the contents of the current buffer, altering the buffer's name too.
\ITEM \STYLE{code} <ctrl t> \END Begins an incremental search down through the current buffer for the word or token under the cursor.
\ITEM \STYLE{code} <ctrl T> \END Reads a token or word under the cursor and lists all exact case-sensitive mathces in all open buffers.
\ITEM \STYLE{code} <ctrl u> \END Converts all ascii text in the range between the cursor and the mark to uppercase.
\ITEM \STYLE{code} <ctrl v> \END Paste from the top of clipboard and run auto-indent on the newly pasted text.
\ITEM \STYLE{code} <alt v> \END Toggles the current buffer's virtual whitespace status.
\ITEM \STYLE{code} <ctrl V> \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} <cmnd <> \END Change the currently active panel, moving to the panel with the next lowest view_id.
\ITEM \STYLE{code} <cmnd n> \END Interactively creates a new file.
\ITEM \STYLE{code} <cmnd o> \END Interactively opens or creates a new file.
\ITEM \STYLE{code} <ctrl o> \END Reads a filename from surrounding '"' characters and attempts to open the corresponding file, displaying it in the other view.
\ITEM \STYLE{code} <ctrl o> \END Switches to the next active panel and begins an open file dialogue.
\ITEM \STYLE{code} <cmnd k> \END Interactively kill an open buffer.
\ITEM \STYLE{code} <cmnd i> \END Interactively switch to an open buffer.
\ITEM \STYLE{code} <cmnd h> \END Changes 4coder's hot directory to the root directory of the currently loaded project. With no loaded project nothing hapepns.
\ITEM \STYLE{code} <cmnd H> \END If a project file has already been loaded, reloads the same file. Useful for when the project configuration is changed.
\ITEM \STYLE{code} <cmnd S> \END Saves all buffers marked dirty (showing the '*' indicator).
\ITEM \STYLE{code} <ctrl c> \END Opens the 4coder colors and fonts selector menu.
\ITEM \STYLE{code} <ctrl .> \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} <ctrl w> \END Sets the current view to hide it's scrollbar.
\ITEM \STYLE{code} <ctrl b> \END Toggles the visibility status of the current view's filebar.
\ITEM \STYLE{code} <ctrl @> \END Toggles the mouse suppression mode, see suppress_mouse and allow_mouse.
\ITEM \STYLE{code} <cmnd page up> \END Toggle fullscreen mode on or off. The change(s) do not take effect until the next frame.
\ITEM \STYLE{code} <ctrl E> \END Attempts to close 4coder.
\ITEM \STYLE{code} <ctrl +> \END Increase the size of the face used by the current buffer.
\ITEM \STYLE{code} <ctrl -> \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} <ctrl F> \END Queries the user for a string and lists all case-insensitive substring matches found in all open buffers.
\ITEM \STYLE{code} <cmnd g> \END Queries the user for a number, and jumps the cursor to the corresponding line.
\ITEM \STYLE{code} <cmnd G> \END Reads the string in the selected range and lists all exact case-sensitive mathces in all open buffers.
\ITEM \STYLE{code} <cmnd j> \END Converts all ascii text in the range between the cursor and the mark to lowercase.
\ITEM \STYLE{code} <cmnd K> \END Kills the current buffer.
\ITEM \STYLE{code} <cmnd l> \END Toggles the current buffer's line wrapping status.
\ITEM \STYLE{code} <cmnd L> \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} <ctrl s> \END Queries the user for a name and saves the contents of the current buffer, altering the buffer's name too.
\ITEM \STYLE{code} <cmnd t> \END Begins an incremental search down through the current buffer for the word or token under the cursor.
\ITEM \STYLE{code} <cmnd T> \END Reads a token or word under the cursor and lists all exact case-sensitive mathces in all open buffers.
\ITEM \STYLE{code} <cmnd u> \END Converts all ascii text in the range between the cursor and the mark to uppercase.
\ITEM \STYLE{code} <cmnd v> \END Paste from the top of clipboard and run auto-indent on the newly pasted text.
\ITEM \STYLE{code} <ctrl v> \END Toggles the current buffer's virtual whitespace status.
\ITEM \STYLE{code} <cmnd V> \END Paste the next item on the clipboard and run auto-indent on the newly pasted text.