diff --git a/4coder_base_commands.cpp b/4coder_base_commands.cpp index ba68152e..5047b984 100644 --- a/4coder_base_commands.cpp +++ b/4coder_base_commands.cpp @@ -37,7 +37,7 @@ CUSTOM_DOC("Inserts whatever character was used to trigger this command.") uint8_t character[4]; uint32_t length = to_writable_character(in, character); write_character_parameter(app, character, length); - } +} CUSTOM_COMMAND_SIG(write_underscore) CUSTOM_DOC("Inserts an underscore.") @@ -1463,7 +1463,7 @@ CUSTOM_DOC("Opens the 4coder colors and fonts selector menu.") //////////////////////////////// CUSTOM_COMMAND_SIG(open_in_other) -CUSTOM_DOC("Switches to the next active panel and begins an open file dialogue.") +CUSTOM_DOC("Interactively opens a file in the other panel.") { change_active_panel(app); interactive_open_or_new(app); diff --git a/4coder_config.cpp b/4coder_config.cpp index cdde045e..3eec4cdf 100644 --- a/4coder_config.cpp +++ b/4coder_config.cpp @@ -70,10 +70,10 @@ get_error_location(char *base, char *pos){ static String config_stringize_errors(Partition *arena, Config *parsed){ String result = {0}; - if (parsed->first_error != 0){ + if (parsed->errors.first != 0){ result.str = push_array(arena, char, 0); result.memory_size = partition_remaining(arena); - for (Config_Error *error = parsed->first_error; + for (Config_Error *error = parsed->errors.first; error != 0; error = error->next){ Error_Location location = get_error_location(parsed->data.str, error->pos); @@ -204,37 +204,48 @@ 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); -} - +// TODO(allen): Move to string library static String -config_parser__begin_string(Config_Parser *ctx){ +config_begin_string(Partition *arena){ String str; - str.str = push_array(ctx->arena, char, 0); + str.str = push_array(arena, char, 0); str.size = 0; - str.memory_size = ctx->arena->max - ctx->arena->pos; + str.memory_size = arena->max - arena->pos; return(str); } static void -config_parser__end_string(Config_Parser *ctx, String *str){ +config_end_string(Partition *arena, String *str){ str->memory_size = str->size; - push_array(ctx->arena, char, str->size); + push_array(arena, char, str->size); +} + +static Config_Error* +config_error_push(Partition *arena, Config_Error_List *list, String file_name, char *pos, char *error_text){ + Config_Error *error = push_array(arena, Config_Error, 1); + zdll_push_back(list->first, list->last, error); + list->count += 1; + error->file_name = file_name; + error->pos = pos; + error->text = config_begin_string(arena); + append(&error->text, error_text); + config_end_string(arena, &error->text); + return(error); +} + +static char* +config_parser__get_pos(Config_Parser *ctx){ + return(ctx->data.str + ctx->token->start); +} + +static void +config_parser__log_error_pos(Config_Parser *ctx, char *pos, char *error_text){ + config_error_push(ctx->arena, &ctx->errors, ctx->file_name, pos, error_text); } 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); + config_parser__log_error_pos(ctx, config_parser__get_pos(ctx), error_text); } static Config* @@ -258,9 +269,8 @@ 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->errors = ctx->errors; + config->file_name = ctx->file_name; config->data = ctx->data; return(config); } @@ -316,6 +326,8 @@ config_parser__version(Config_Parser *ctx){ static Config_Assignment* config_parser__assignment(Config_Parser *ctx){ + char *pos = config_parser__get_pos(ctx); + Config_LValue *l = config_parser__lvalue(ctx); if (l == 0){ config_parser__log_error(ctx, "expected an l-value; l-value formats: 'identifier', 'identifier[#]'"); @@ -349,6 +361,7 @@ config_parser__assignment(Config_Parser *ctx){ Config_Assignment *assignment = push_array(ctx->arena, Config_Assignment, 1); memset(assignment, 0, sizeof(*assignment)); + assignment->pos = pos; assignment->l = l; assignment->r = r; return(assignment); @@ -449,6 +462,22 @@ config_parser__rvalue(Config_Parser *ctx){ return(0); } +static void +config_parser__compound__check(Config_Parser *ctx, Config_Compound *compound){ + bool32 implicit_index_allowed = true; + for (Config_Compound_Element *node = compound->first; + node != 0; + node = node->next){ + if (node->l.type != ConfigLayoutType_Unset){ + implicit_index_allowed = false; + } + else if (!implicit_index_allowed){ + config_parser__log_error_pos(ctx, node->l.pos, + "encountered unlabeled member after one or more labeled members"); + } + } +} + static Config_Compound* config_parser__compound(Config_Parser *ctx){ Config_Compound_Element *first = 0; @@ -477,12 +506,14 @@ config_parser__compound(Config_Parser *ctx){ compound->first = first; compound->last = last; compound->count = count; + config_parser__compound__check(ctx, compound); return(compound); } static Config_Compound_Element* config_parser__element(Config_Parser *ctx){ Config_Layout layout = {0}; + layout.pos = config_parser__get_pos(ctx); if (config_parser__match_token(ctx, CPP_TOKEN_DOT)){ if (config_parser__recognize_token(ctx, CPP_TOKEN_IDENTIFIER)){ layout.type = ConfigLayoutType_Identifier; @@ -511,6 +542,13 @@ config_parser__element(Config_Parser *ctx){ //////////////////////////////// +static Config_Error* +config_add_error(Partition *arena, Config *config, char *pos, char *error_text){ + return(config_error_push(arena, &config->errors, config->file_name, pos, error_text)); +} + +//////////////////////////////// + static Config_Assignment* config_lookup_assignment(Config *config, String var_name, int32_t subscript){ Config_Assignment *assignment; @@ -540,6 +578,7 @@ config_evaluate_rvalue(Config *config, Config_Assignment *assignment, Config_RVa } else{ result.success = true; + result.pos = assignment->pos; result.type = r->type; switch (r->type){ case ConfigRValueType_Boolean: @@ -617,6 +656,7 @@ config_compound_member(Config *config, Config_Compound *compound, String var_nam } if (element_matches_query){ Config_Assignment dummy_assignment = {0}; + dummy_assignment.pos = element->l.pos; result = config_evaluate_rvalue(config, &dummy_assignment, element->r); break; } diff --git a/4coder_config.h b/4coder_config.h index b0313efa..abfa5209 100644 --- a/4coder_config.h +++ b/4coder_config.h @@ -24,6 +24,12 @@ struct Config_Error{ String text; }; +struct Config_Error_List{ + Config_Error *first; + Config_Error *last; + int32_t count; +}; + struct Config_Parser{ Cpp_Token *start; Cpp_Token *token; @@ -34,9 +40,7 @@ struct Config_Parser{ Partition *arena; - Config_Error *first_error; - Config_Error *last_error; - int32_t count_error; + Config_Error_List errors; }; struct Config_LValue{ @@ -95,6 +99,7 @@ enum{ }; struct Config_Layout{ Config_Layout_Type type; + char *pos; union{ String identifier; int32_t integer; @@ -113,6 +118,7 @@ struct Config_Assignment{ Config_Assignment *next; Config_Assignment *prev; + char *pos; Config_LValue *l; Config_RValue *r; @@ -125,10 +131,9 @@ struct Config{ Config_Assignment *last; int32_t count; - Config_Error *first_error; - Config_Error *last_error; - int32_t count_error; + Config_Error_List errors; + String file_name; String data; }; @@ -144,6 +149,7 @@ enum{ struct Config_Get_Result{ bool32 success; Config_RValue_Type type; + char *pos; union{ bool32 boolean; int32_t integer; diff --git a/4coder_generated/command_metadata.h b/4coder_generated/command_metadata.h index ad80a3dc..1f1800b7 100644 --- a/4coder_generated/command_metadata.h +++ b/4coder_generated/command_metadata.h @@ -232,7 +232,7 @@ static Command_Metadata fcoder_metacmd_table[196] = { { 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, 986 }, +{ 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, 1000 }, { 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 }, @@ -298,7 +298,7 @@ static Command_Metadata fcoder_metacmd_table[196] = { { 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, 1009 }, +{ 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, 1023 }, { 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 }, @@ -320,11 +320,11 @@ static Command_Metadata fcoder_metacmd_table[196] = { { 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, 993 }, -{ 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, 1000 }, +{ 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, 1007 }, +{ 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, 1014 }, { 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 }, +{ PROC_LINKS(open_in_other, 0), "open_in_other", 13, "Interactively opens a file in the other panel.", 46, "C:\\work\\4ed\\code\\4coder_base_commands.cpp", 45, 1465 }, { PROC_LINKS(open_long_braces, 0), "open_long_braces", 16, "At the cursor, insert a '{' and '}' separated by a blank line.", 62, "C:\\work\\4ed\\code\\4coder_combined_write_commands.cpp", 55, 58 }, { PROC_LINKS(open_long_braces_break, 0), "open_long_braces_break", 22, "At the cursor, insert a '{' and '}break;' separated by a blank line.", 68, "C:\\work\\4ed\\code\\4coder_combined_write_commands.cpp", 55, 74 }, { PROC_LINKS(open_long_braces_semicolon, 0), "open_long_braces_semicolon", 26, "At the cursor, insert a '{' and '};' separated by a blank line.", 63, "C:\\work\\4ed\\code\\4coder_combined_write_commands.cpp", 55, 66 }, @@ -338,8 +338,8 @@ static Command_Metadata fcoder_metacmd_table[196] = { { 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, 1016 }, -{ 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, 1041 }, +{ 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, 1030 }, +{ 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, 1055 }, { 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 }, @@ -381,10 +381,10 @@ static Command_Metadata fcoder_metacmd_table[196] = { { 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_build_bat, 0), "setup_build_bat", 15, "Queries the user for several configuration options and initializes a new build batch script.", 92, "C:\\work\\4ed\\code\\4coder_project_commands.cpp", 48, 1426 }, -{ PROC_LINKS(setup_build_bat_and_sh, 0), "setup_build_bat_and_sh", 22, "Queries the user for several configuration options and initializes a new build batch script.", 92, "C:\\work\\4ed\\code\\4coder_project_commands.cpp", 48, 1438 }, -{ PROC_LINKS(setup_build_sh, 0), "setup_build_sh", 14, "Queries the user for several configuration options and initializes a new build shell script.", 92, "C:\\work\\4ed\\code\\4coder_project_commands.cpp", 48, 1432 }, -{ 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, 1419 }, +{ PROC_LINKS(setup_build_bat, 0), "setup_build_bat", 15, "Queries the user for several configuration options and initializes a new build batch script.", 92, "C:\\work\\4ed\\code\\4coder_project_commands.cpp", 48, 1440 }, +{ PROC_LINKS(setup_build_bat_and_sh, 0), "setup_build_bat_and_sh", 22, "Queries the user for several configuration options and initializes a new build batch script.", 92, "C:\\work\\4ed\\code\\4coder_project_commands.cpp", 48, 1452 }, +{ PROC_LINKS(setup_build_sh, 0), "setup_build_sh", 14, "Queries the user for several configuration options and initializes a new build shell script.", 92, "C:\\work\\4ed\\code\\4coder_project_commands.cpp", 48, 1446 }, +{ 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, 1433 }, { 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 b0aec44f..60767cac 100644 --- a/4coder_project_commands.cpp +++ b/4coder_project_commands.cpp @@ -411,13 +411,16 @@ parse_project__config_data__version_1(Partition *arena, String root_dir, Config for (Config_Get_Result_Node *node = list.first; node != 0; node = node->next, ++dst){ + char *pos = node->result.pos; Config_Compound *src = node->result.compound; memset(dst, 0, sizeof(*dst)); bool32 can_emit_command = true; - Config_Compound *cmd_set = 0; String name = {0}; + Config_Get_Result cmd_result = {0}; + Config_Compound *cmd_set = 0; + char *cmd_pos = 0; String cmd_str = {0}; String out = {0}; bool32 footer_panel = false; @@ -426,11 +429,19 @@ parse_project__config_data__version_1(Partition *arena, String root_dir, Config if (!config_compound_string_member(parsed, src, "name", 0, &name)){ can_emit_command = false; + config_add_error(arena, parsed, pos, "a command must have a string type name member"); goto finish_command; } - if (!config_compound_compound_member(parsed, src, "cmd", 1, &cmd_set)){ + cmd_result = config_compound_member(parsed, src, + make_lit_string("cmd"), 1); + if (cmd_result.success){ + cmd_set = cmd_result.compound; + cmd_pos = cmd_result.pos; + } + else{ can_emit_command = false; + config_add_error(arena, parsed, pos, "a command must have an array type cmd member"); goto finish_command; } @@ -464,22 +475,25 @@ parse_project__config_data__version_1(Partition *arena, String root_dir, Config } } - if (can_emit_command){ - config_compound_string_member(parsed, src, "out", 2, &out); - config_compound_bool_member(parsed, src, "footer_panel", 3, &footer_panel); - config_compound_bool_member(parsed, src, "save_dirty_files", 4, - &save_dirty_files); - config_compound_bool_member(parsed, src, "cursor_at_end", 5, - &cursor_at_end); - - dst->name = push_string_copy(arena, name); - dst->cmd = push_string_copy(arena, cmd_str); - dst->out = push_string_copy(arena, out); - dst->footer_panel = footer_panel; - dst->save_dirty_files = save_dirty_files; - dst->cursor_at_end = cursor_at_end; + if (!can_emit_command){ + config_add_error(arena, parsed, cmd_pos, "no usable command strings found in cmd"); + goto finish_command; } + config_compound_string_member(parsed, src, "out", 2, &out); + config_compound_bool_member(parsed, src, "footer_panel", 3, &footer_panel); + config_compound_bool_member(parsed, src, "save_dirty_files", 4, + &save_dirty_files); + config_compound_bool_member(parsed, src, "cursor_at_end", 5, + &cursor_at_end); + + dst->name = push_string_copy(arena, name); + dst->cmd = push_string_copy(arena, cmd_str); + dst->out = push_string_copy(arena, out); + dst->footer_panel = footer_panel; + dst->save_dirty_files = save_dirty_files; + dst->cursor_at_end = cursor_at_end; + finish_command:; } } diff --git a/project.4coder b/project.4coder index 7983b281..d8c6beb7 100644 --- a/project.4coder +++ b/project.4coder @@ -15,9 +15,9 @@ blacklist_patterns = { }; load_paths_only = { {"."}, }; load_paths = { - {load_paths_only, .os = "win"}, - {load_paths_only, .os = "linux"}, - {load_paths_only, .os = "mac"}, + { load_paths_only, .os = "win" }, + { load_paths_only, .os = "linux"}, + { load_paths_only, .os = "mac" }, }; build_x86_win32 = "echo build: x86 & build.bat /DDEV_BUILD_X86";