Skip to content

Commit a82f8e3

Browse files
authored
Merge pull request #1426 from kareltucek/arg_template_validation_fixes
Arg template validation fixes
2 parents 49b6b87 + 2d67140 commit a82f8e3

14 files changed

Lines changed: 91 additions & 76 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ node_modules
33
.cache
44
build
55
.vscode/settings.json
6+
.jj
67
mcux_include.json

doc-dev/reference-manual.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ COMMAND = set battery.chargeLimit { full | optimizeHealth }
188188
COMMAND = set bluetooth.enabled BOOL
189189
COMMAND = set bluetooth.alwaysAdvertiseHid BOOL
190190
COMMAND = set modifierLayerTriggers.{shift|alt|super|ctrl} {left|right|both}
191+
COMMAND = &macroArg.<macro argument index (INT)>
191192
CONDITION = <condition>
192193
CONDITION = if (EXPRESSION)
193194
CONDITION = else
@@ -218,7 +219,6 @@ MODIFIER = postponeKeys
218219
MODIFIER = final
219220
MODIFIER = autoRepeat
220221
MODIFIER = oneShot
221-
TEMPLATE = $macroArg.<macro argument index (INT)>
222222
IFSHORTCUT_OPTIONS = noConsume | transitive | anyOrder | orGate | timeoutIn <time in ms (INT)> | cancelIn <time in ms(INT)>
223223
DIRECTION = {left|right|up|down}
224224
LAYERID = {fn|mouse|mod|base|fn2|fn3|fn4|fn5|alt|shift|super|ctrl}|last|previous|current
@@ -227,7 +227,7 @@ KEYMAPID = <short keymap abbreviation(IDENTIFIER)>|last|current
227227
MACROID = last | <single char slot identifier(CHAR)> | <single number slot identifier(INT)>
228228
OPERATOR = + | - | * | / | % | < | > | <= | >= | == | != | && | ||
229229
VARIABLE_EXPANSION = $<variable name(IDENTIFIER)> | $<config value name>
230-
VARIABLE_EXPANSION = $currentAddress | $currentTime | $thisKeyId | $queuedKeyId.<queue index (INT)> | $keyId.KEYID_ABBREV | $uhk.name
230+
VARIABLE_EXPANSION = $currentAddress | $currentTime | $thisKeyId | $queuedKeyId.<queue index (INT)> | $keyId.KEYID_ABBREV | $uhk.name | $macroArg.<macro argument index (INT)>
231231
EXPRESSION = <expression> | (EXPRESSION) | INT | BOOL | FLOAT | VARIABLE_EXPANSION | EXPRESSION OPERATOR EXPRESSION | !EXPRESSION | min(EXPRESSION [, EXPRESSION]+) | max(EXPRESSION [, EXPRESSION]+)
232232
EXPRESSION = STRING == STRING | STRING != STRING
233233
PARENTHESSED_EXPRESSION = (EXPRESSION)
@@ -583,6 +583,15 @@ Internally, values are saved in one of the following types, and types are automa
583583
- `BOOL` - 1 or 0 value
584584
- `STRING` - a string _reference_. These strings can use interpolation, but this interpolation is always applied at the expansion site / time.
585585

586+
### Argument expansion:
587+
588+
Key actions can be parametrized with macro arguments. These arguments can be expanded in two ways:
589+
590+
- `$macroArg.<idx>` - in which case they are parsed as a single value. This is the normal and safe variant that prevents context corruption.
591+
- `&macroArg.<idx>` - this variant substitutes the argument into current parser context. These allow substituing any string, including full commands or their parts. This is an experimental feature and might be unsafe in some contexts. Following limitations apply:
592+
- the argument bounds must correspond to token bounds in the fully expanded string
593+
- the argument cannot span multiple lines
594+
586595
### Configuration options:
587596

588597
- `set stickyModifiers {never|smart|always}` globally turns on or off sticky modifiers. This affects only standard scancode actions. Macro actions (both gui and command ones) are always nonsticky, unless `sticky` flag is included in `tapKey|holdKey|pressKey` commands. Default value is `smart`, which is the official behaviour - i.e., `<alt/ctrl/gui> + <tab/arrows>` are sticky.

right/src/config_parser/parse_keymap.c

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,6 @@ static parser_error_t parseKeyActions(uint8_t targetLayer, config_buffer_t *buff
307307
uint8_t noneBlockUntil = 0;
308308
rgb_t noneBlockColor = {0, 0, 0};
309309
uint8_t actionIdx = 0;
310-
key_action_t currentAction = {};
311-
bool currentActionHasArguments = false;
312310
for (uint8_t i = 0; i < actionCount; i++) {
313311
bool isNoneActionInNoneBlock = actionIdx < noneBlockUntil;
314312

@@ -347,26 +345,13 @@ static parser_error_t parseKeyActions(uint8_t targetLayer, config_buffer_t *buff
347345
}
348346

349347
if (wasAction) {
350-
// validate previous action
351-
if (currentAction.type == KeyActionType_PlayMacro && currentActionHasArguments && Macros_ValidationInProgress) {
352-
//validate it
353-
Macros_ValidateMacro(currentAction.playMacro.macroId, currentAction.playMacro.offset, currentActionHasArguments, moduleId, actionIdx-1, keymapIdx);
348+
if (keyAction->type == KeyActionType_PlayMacro && Macros_ValidationInProgress) {
349+
Macros_ValidateMacro(keyAction->playMacro.macroId, keyAction->playMacro.offset, moduleId, actionIdx, keymapIdx, targetLayer);
354350
}
355351

356352
actionIdx++;
357-
358-
// cache current action
359-
currentAction = *keyAction;
360-
currentActionHasArguments = false;
361-
} else {
362-
currentActionHasArguments = true;
363353
}
364354
}
365-
// validate previous action
366-
if (currentAction.type == KeyActionType_PlayMacro && currentActionHasArguments && Macros_ValidationInProgress) {
367-
//validate it
368-
Macros_ValidateMacro(currentAction.playMacro.macroId, currentAction.playMacro.offset, currentActionHasArguments, moduleId, actionIdx-1, keymapIdx);
369-
}
370355

371356
/* default second touchpad action to right button */
372357
if (parseMode != ParseMode_DryRun && moduleId == ModuleId_TouchpadRight) {

right/src/debug.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
#define DEBUG_BATTERY_TESTING true
2424
#define DEBUG_UHK60_SLEEPS false
2525

26-
#define DEBUG_ROLL_STATUS_BUFFER true
26+
#define DEBUG_ROLL_STATUS_BUFFER false
2727

2828
#ifdef __ZEPHYR__
2929
#include "logger.h"

right/src/macro_events.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ void MacroEvent_TriggerGenericEvent(generic_macro_event_t eventId)
218218
void MacroEvent_OnError() {
219219
static uint32_t last = 0;
220220

221-
if (Timer_GetCurrentTime() - last > 1000) {
221+
if (Timer_GetCurrentTime() - last > 1000 && Macros_ValidationInProgress == false) {
222222
last = Timer_GetCurrentTime();
223223
MacroEvent_TriggerGenericEvent(GenericMacroEvent_OnError);
224224
}

right/src/macros/core.c

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ uint8_t Macros_StartMacro(uint8_t index, key_state_t *keyState, uint16_t argumen
482482
return slotIndex;
483483
}
484484

485-
void Macros_ValidateMacro(uint8_t macroIndex, uint16_t argumentOffset, bool hasArgs, uint8_t moduleId, uint8_t keyIdx, uint8_t keymapIdx) {
485+
void Macros_ValidateMacro(uint8_t macroIndex, uint16_t argumentOffset, uint8_t moduleId, uint8_t keyIdx, uint8_t keymapIdx, uint8_t layerIdx) {
486486
bool wasValid = true;
487487
uint8_t slotIndex = initMacro(macroIndex, NULL, argumentOffset, 255, 255);
488488

@@ -493,6 +493,7 @@ void Macros_ValidateMacro(uint8_t macroIndex, uint16_t argumentOffset, bool hasA
493493

494494
scheduleSlot(slotIndex);
495495

496+
Macros_ParserError = false;
496497
bool macroHasNotEnded = AllMacros[macroIndex].macroActionsCount;
497498
while (macroHasNotEnded) {
498499
if (S->ms.currentMacroAction.type == MacroActionType_Command) {
@@ -506,14 +507,17 @@ void Macros_ValidateMacro(uint8_t macroIndex, uint16_t argumentOffset, bool hasA
506507
endMacro();
507508
S = NULL;
508509

509-
if (!wasValid && hasArgs && moduleId != 255 && keyIdx != 255 && keymapIdx != 255) {
510+
if (!wasValid && moduleId != 255 && keyIdx != 255 && keymapIdx != 255) {
511+
const char *name, *nameEnd;
512+
FindMacroName(&AllMacros[macroIndex], &name, &nameEnd);
510513
uint8_t keyId = Utils_KeyCoordinatesToKeyId(ModuleIdToSlotId(moduleId), keyIdx);
511514
const char* keyAbbrev = MacroKeyIdParser_KeyIdToAbbreviation(keyId);
512515
const char* keymapAbbrev = AllKeymaps[keymapIdx].abbreviation;
513516
uint8_t keymapAbbrevLen = AllKeymaps[keymapIdx].abbreviationLen;
514517
const char* moduleName = ModuleIdToStr(moduleId);
515-
Macros_ReportErrorPrintf(NULL, "> Bound at %.*s/%s/%s.\n", keymapAbbrevLen, keymapAbbrev, moduleName, keyAbbrev);
518+
Macros_ReportErrorPrintf(NULL, "> '%.*s' bound at %.*s/%s/%s/%s.\n", nameEnd - name, name, keymapAbbrevLen, keymapAbbrev, LayerNames[layerIdx], moduleName, keyAbbrev);
516519
}
520+
Macros_ParserError = false;
517521
}
518522

519523
/**
@@ -526,16 +530,10 @@ void Macros_ValidateAllMacros()
526530
macro_state_t* oldS = S;
527531
scheduler_state_t schedulerState = Macros_SchedulerState;
528532
memset(&Macros_SchedulerState, 0, sizeof Macros_SchedulerState);
533+
LogU("Validating macros with arguments...\n");
529534
Macros_DryRun = true;
530535
Macros_ValidationInProgress = true;
531-
// Validate macros without arguments
532536
uint32_t t1 = Timer_GetCurrentTime();
533-
LogU("Validating macros without arguments...\n");
534-
for (uint8_t macroIndex = 0; macroIndex < AllMacrosCount; macroIndex++) {
535-
Macros_ValidateMacro(macroIndex, 0, false, 255, 255, 255);
536-
}
537-
LogU("Validating macros with arguments...\n");
538-
// Validate macros that have arguments
539537
for (uint8_t keymapIndex = 0; keymapIndex < AllKeymapsCount; keymapIndex++) {
540538
DryParseKeymap(keymapIndex);
541539
}

right/src/macros/core.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@
282282
void Macros_SignalInterrupt(void);
283283
void Macros_SignalUsbReportsChange();
284284
void Macros_ValidateAllMacros();
285-
void Macros_ValidateMacro(uint8_t macroIndex, uint16_t argumentOffset, bool hasArgs, uint8_t moduleId, uint8_t keyIdx, uint8_t keymapIdx);
285+
void Macros_ValidateMacro(uint8_t macroIndex, uint16_t argumentOffset, uint8_t moduleId, uint8_t keyIdx, uint8_t keymapIdx, uint8_t layerIdx);
286286
void Macros_WakeBecauseOfKeystateChange();
287287

288288
#endif

right/src/macros/set_command.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ static macro_variable_t allowUnsecuredConnections(parser_context_t* ctx, set_com
349349
{
350350
ASSIGN_BOOL(Cfg.Bt_AllowUnsecuredConnections);
351351
if (Cfg.Bt_AllowUnsecuredConnections) {
352-
Macros_PrintfWithPos(ctx->at, "Warning: insecure connections were allowed. This may allow eavesdropping on your keyboard input!");
352+
Macros_PrintfWithPos(ctx, "Warning: insecure connections were allowed. This may allow eavesdropping on your keyboard input!");
353353
}
354354

355355
return noneVar();

right/src/macros/status_buffer.c

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -262,9 +262,12 @@ static void reportErrorHeader(const char* status, uint16_t pos)
262262
}
263263
}
264264

265-
static void reportCommandLocation(uint16_t line, uint16_t pos, const char* begin, const char* end, bool markPosition)
265+
static void reportCommandLocation(uint16_t line, uint16_t pos, const char* begin, const char* end, bool markPosition, uint8_t indent)
266266
{
267267
Macros_SetStatusString("> ", NULL);
268+
for (uint8_t i = 0; i < indent; i++) {
269+
Macros_SetStatusString(" ", NULL);
270+
}
268271
uint16_t l = Buf.len;
269272
Macros_SetStatusNumSpaced(line, false);
270273
l = Buf.len - l;
@@ -273,7 +276,7 @@ static void reportCommandLocation(uint16_t line, uint16_t pos, const char* begin
273276
Macros_SetStatusString("\n", NULL);
274277
if (markPosition) {
275278
Macros_SetStatusString("> ", NULL);
276-
for (uint8_t i = 0; i < l; i++) {
279+
for (uint8_t i = 0; i < l + indent; i++) {
277280
Macros_SetStatusString(" ", NULL);
278281
}
279282
Macros_SetStatusString(" | ", NULL);
@@ -285,21 +288,23 @@ static void reportCommandLocation(uint16_t line, uint16_t pos, const char* begin
285288
}
286289
}
287290

288-
static void reportLocationStackLevel(const parser_context_t* ctx, uint16_t line) {
291+
static void reportLocationStackLevel(const parser_context_t* ctx, uint16_t line, uint8_t indent) {
289292
uint16_t pos = ctx->at - ctx->begin;
290293
bool positionIsValid = ctx->begin <= ctx->at && ctx->at <= ctx->end;
291294
if (positionIsValid) {
292-
reportCommandLocation(line, pos, ctx->begin, ctx->end, positionIsValid);
295+
reportCommandLocation(line, pos, ctx->begin, ctx->end, positionIsValid, indent);
293296
} else {
294297
Macros_SetStatusString("> Position not available here.\n", NULL);
295298
}
296299
}
297300

298301
static void reportLocationStack(parser_context_t* ctx, uint16_t line) {
302+
uint8_t indent = 0;
299303
for (uint8_t level = 0; level < ctx->nestingLevel; level++) {
300-
reportLocationStackLevel(ViewContext(level), line);
304+
reportLocationStackLevel(ViewContext(level), line, indent);
305+
indent = 0;
301306
}
302-
reportLocationStackLevel(ctx, line);
307+
reportLocationStackLevel(ctx, line, indent);
303308
}
304309

305310
static void reportError(
@@ -321,7 +326,7 @@ static void reportError(
321326
const char* endOfLine = S->ms.currentMacroAction.cmd.text + S->ls->ms.commandEnd;
322327
uint16_t line = findCurrentCommandLine();
323328
if (startOfLine <= arg && arg <= endOfLine) {
324-
reportCommandLocation(line, arg - startOfLine, startOfLine, endOfLine, argIsCommand);
329+
reportCommandLocation(line, arg - startOfLine, startOfLine, endOfLine, argIsCommand, 0);
325330
} else if (ctx != NULL) {
326331
reportLocationStack(ctx, line);
327332
} else {
@@ -376,7 +381,7 @@ void Macros_ReportWarn(const char* err, const char* arg, const char *argEnd)
376381
reportError(err, arg, argEnd, NULL);
377382
}
378383

379-
void Macros_PrintfWithPos(const char* pos, const char *fmt, ...)
384+
void Macros_PrintfWithPos(parser_context_t* ctx, const char *fmt, ...)
380385
{
381386
REENTRANCY_GUARD_BEGIN;
382387
va_list myargs;
@@ -385,9 +390,10 @@ void Macros_PrintfWithPos(const char* pos, const char *fmt, ...)
385390
vsprintf(buffer, fmt, myargs);
386391

387392
indicateOut();
388-
if (pos != NULL) {
389-
reportErrorHeader("Out", findPosition(pos));
390-
reportError(buffer, pos, pos, NULL);
393+
if (ctx != NULL) {
394+
reportErrorHeader("Out", findPositionCtx(ctx));
395+
reportError(buffer, NULL, NULL, ctx);
396+
391397
} else {
392398
Macros_SetStatusString(buffer, NULL);
393399
}

right/src/macros/status_buffer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
void Macros_ReportErrorNum(const char* err, int32_t num, const char* pos);
3838
void Macros_ReportErrorFloat(const char* err, float num, const char* pos);
3939
void Macros_ReportWarn(const char* err, const char* arg, const char *argEnd);
40-
void Macros_PrintfWithPos(const char* pos, const char *fmt, ...);
40+
void Macros_PrintfWithPos(parser_context_t* ctx, const char *fmt, ...);
4141
void Macros_SanitizedPut(const char* text, const char *textEnd);
4242

4343
void MacroStatusBuffer_Validate(void);

0 commit comments

Comments
 (0)