From 0ac38fa47864b7afb1e4b41a230b22e7dfae26ac Mon Sep 17 00:00:00 2001 From: Karel Tucek Date: Fri, 30 Jan 2026 12:09:38 +0100 Subject: [PATCH] Validate all macros in general context Previously, macros were only validated in their binding site contexts, meaning macros that weren't bound to any key were never validated. Now Macros_ValidateAllMacros() also loops through all macros and validates them with argumentOffset=0 (general context). Commands containing "macroArg" are skipped during general context validation since they require binding-specific arguments. Added StrContains() utility function to str_utils for substring search. Co-Authored-By: Claude Opus 4.5 --- right/src/macros/core.c | 26 +++++++++++++++++++++----- right/src/str_utils.c | 24 ++++++++++++++++++++++++ right/src/str_utils.h | 1 + 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/right/src/macros/core.c b/right/src/macros/core.c index cf64b5ccc..b30d4c763 100644 --- a/right/src/macros/core.c +++ b/right/src/macros/core.c @@ -510,9 +510,16 @@ void Macros_ValidateMacro(uint8_t macroIndex, uint16_t argumentOffset, uint8_t m bool macroHasNotEnded = AllMacros[macroIndex].macroActionsCount; while (macroHasNotEnded) { if (S->ms.currentMacroAction.type == MacroActionType_Command) { - processCurrentMacroAction(); - wasValid &= !Macros_ParserError; - Macros_ParserError = false; + // Skip validation of commands containing macroArg when no argument context is available + const char* cmdText = S->ms.currentMacroAction.cmd.text; + const char* cmdEnd = cmdText + S->ms.currentMacroAction.cmd.textLen; + bool skipCommand = argumentOffset == 0 && StrContains(cmdText, cmdEnd, "macroArg"); + + if (!skipCommand) { + processCurrentMacroAction(); + wasValid &= !Macros_ParserError; + Macros_ParserError = false; + } } macroHasNotEnded = loadNextCommand() || loadNextAction(); @@ -535,7 +542,6 @@ void Macros_ValidateMacro(uint8_t macroIndex, uint16_t argumentOffset, uint8_t m /** * Current known limitations: - * - We check only actions that have arguments, therefore we don't catch missing arguments. * - The validation takes hundreds of milliseconds, causing a short freeze when config is saved. */ void Macros_ValidateAllMacros() @@ -543,13 +549,23 @@ void Macros_ValidateAllMacros() macro_state_t* oldS = S; scheduler_state_t schedulerState = Macros_SchedulerState; memset(&Macros_SchedulerState, 0, sizeof Macros_SchedulerState); - LogU("Validating macros with arguments...\n"); Macros_DryRun = true; Macros_ValidationInProgress = true; uint32_t t1 = Timer_GetCurrentTime(); + + // Validate macros in binding site contexts (with arguments) + LogU("Validating macros with arguments...\n"); for (uint8_t keymapIndex = 0; keymapIndex < AllKeymapsCount; keymapIndex++) { DryParseKeymap(keymapIndex); } + + // Validate all macros in general context (without arguments) + // Commands containing macroArg are skipped when argumentOffset == 0 + LogU("Validating macros in general context...\n"); + for (uint8_t macroIndex = 0; macroIndex < AllMacrosCount; macroIndex++) { + Macros_ValidateMacro(macroIndex, 0, 255, 255, 255, 255); + } + uint32_t t2 = Timer_GetCurrentTime(); LogU("Validation completed in %d ms!\n", t2 - t1); Macros_ValidationInProgress = false; diff --git a/right/src/str_utils.c b/right/src/str_utils.c index 48213b282..0beb9f5ef 100644 --- a/right/src/str_utils.c +++ b/right/src/str_utils.c @@ -94,6 +94,30 @@ const char* FindChar(char c, const char* str, const char* strEnd) return strEnd; } +bool StrContains(const char* str, const char* strEnd, const char* needle) +{ + uint8_t needleLen = strlen(needle); + uint16_t strLen = strEnd - str; + + if (strLen < needleLen) { + return false; + } + + for (uint16_t i = 0; i <= strLen - needleLen; i++) { + bool match = true; + for (uint8_t j = 0; j < needleLen; j++) { + if (str[i + j] != needle[j]) { + match = false; + break; + } + } + if (match) { + return true; + } + } + return false; +} + static bool isEnd(parser_context_t* ctx) { if (ctx->at < ctx->end) { return false; diff --git a/right/src/str_utils.h b/right/src/str_utils.h index 82614f432..bc5f97bbc 100644 --- a/right/src/str_utils.h +++ b/right/src/str_utils.h @@ -61,6 +61,7 @@ bool StrLessOrEqual(const char* a, const char* aEnd, const char* b, const char* bEnd); bool StrEqual(const char* a, const char* aEnd, const char* b, const char* bEnd); const char* FindChar(char c, const char* str, const char* strEnd); + bool StrContains(const char* str, const char* strEnd, const char* needle); bool ConsumeToken(parser_context_t* ctx, const char *b); void ConsumeAnyToken(parser_context_t* ctx); void ConsumeCommentsAsWhite(bool consume);