From 814dd512702cc2c8d0921d167f500893417d1221 Mon Sep 17 00:00:00 2001 From: Dianne Skoll Date: Mon, 11 Aug 2025 16:29:34 -0400 Subject: [PATCH] Start working on TODO and COMPLETE-THROUGH. Still a WIP!!! --- contrib/remind-conf-mode/remind-conf-mode.el | 4 +- src/dorem.c | 206 ++++++++++++------- src/err.h | 10 +- src/token.c | 4 +- src/types.h | 6 +- tests/test.cmp | 5 + 6 files changed, 150 insertions(+), 85 deletions(-) diff --git a/contrib/remind-conf-mode/remind-conf-mode.el b/contrib/remind-conf-mode/remind-conf-mode.el index b4fbb8f6..30ecdfd9 100644 --- a/contrib/remind-conf-mode/remind-conf-mode.el +++ b/contrib/remind-conf-mode/remind-conf-mode.el @@ -110,7 +110,7 @@ (defconst remind-keywords (sort (list "ADDOMIT" "AFTER" "AT" "BAN" "BANNER" "BEFORE" "CAL" "CLEAR" - "CLEAR-OMIT-CONTEXT" "DEBUG" "DO" "DUMP" "DUMPVARS" + "CLEAR-OMIT-CONTEXT" "COMPLETE-THROUGH" "DEBUG" "DO" "DUMP" "DUMPVARS" "DURATION" "ELSE" "ENDIF" "ERRMSG" "EXIT" "EXPR" "FIRST" "FLUSH" "FOURTH" "FRENAME" "FROM" "FSET" "FUNSET" "IF" "IFTRIG" "IN" "INC" "INCLUDE" "INCLUDECMD" "INFO" "LAST" @@ -119,7 +119,7 @@ "POP-OMIT-CONTEXT" "POP-FUNCS" "POP-VARS" "PRESERVE" "PRIORITY" "PS" "PSFILE" "PUSH" "PUSH-FUNCS" "PUSH-VARS" "PUSH-OMIT-CONTEXT" "REM" "RETURN" "RUN" "SATISFY" "SCAN" "SCANFROM" "SCHED" "SECOND" "SET" - "SKIP" "SPECIAL" "SYSINCLUDE" "TAG" "THIRD" "THROUGH" + "SKIP" "SPECIAL" "SYSINCLUDE" "TAG" "THIRD" "THROUGH" "TODO" "TRANSLATE" "TRANS" "UNSET" "UNTIL" "WARN") #'(lambda (a b) (> (length a) (length b))))) diff --git a/src/dorem.c b/src/dorem.c index b96c5d4d..4944e7f6 100644 --- a/src/dorem.c +++ b/src/dorem.c @@ -213,6 +213,12 @@ int DoRem(ParsePtr p) return r; } + if (trig.complete_through != NO_DATE && !trig.is_todo) { + PurgeEchoLine("%s\n", CurLine); + FreeTrig(&trig); + return E_COMPLETE_WITHOUT_TODO; + } + if (trig.typ == NO_TYPE) { if (!Hush) { PurgeEchoLine("%s\n", "#!P! Cannot parse next line"); @@ -369,6 +375,107 @@ int DoRem(ParsePtr p) return r; } +/***************************************************************/ +/* */ +/* GetFullDate - get a full date, either YYYY-MM-DD or */ +/* YEAR MON DAY */ +/* */ +/* Returns OK on success or an error code on failure. Sets */ +/* *dse on success. */ +/* */ +/***************************************************************/ +static int GetFullDate(ParsePtr s, char const *prefix, int *dse) +{ + Token tok; + DynamicBuffer buf; + int y = NO_YR, m = NO_MON, d = NO_DAY; + int r; + *dse = NO_DATE; + + DBufInit(&buf); + + while(1) { + r = ParseToken(s, &buf); + if (r) return r; + FindToken(DBufValue(&buf), &tok); + switch(tok.type) { + case T_Year: + DBufFree(&buf); + if (y != NO_YR) { + Eprint("%s: %s", prefix, GetErr(E_YR_TWICE)); + return E_YR_TWICE; + } + y = tok.val; + break; + + case T_Month: + DBufFree(&buf); + if (m != NO_MON) { + Eprint("%s: %s", prefix, GetErr(E_MON_TWICE)); + return E_MON_TWICE; + } + m = tok.val; + break; + + case T_Day: + DBufFree(&buf); + if (d != NO_DAY) { + Eprint("%s: %s", prefix, GetErr(E_DAY_TWICE)); + return E_DAY_TWICE; + } + d = tok.val; + break; + + case T_Date: + DBufFree(&buf); + if (y != NO_YR) { + Eprint("%s: %s", prefix, GetErr(E_YR_TWICE)); + return E_YR_TWICE; + } + if (m != NO_MON) { + Eprint("%s: %s", prefix, GetErr(E_MON_TWICE)); + return E_MON_TWICE; + } + if (d != NO_DAY) { + Eprint("%s: %s", prefix, GetErr(E_DAY_TWICE)); + return E_DAY_TWICE; + } + if (*dse != NO_DATE) { + return E_DAY_TWICE; + } + *dse = tok.val; + /* Prevent further parsing of date */ + FromDSE(*dse, &y, &m, &d); + break; + + default: + if (tok.type == T_Illegal && tok.val < 0) { + Eprint("%s: `%s'", GetErr(-tok.val), DBufValue(&buf)); + DBufFree(&buf); + return -tok.val; + } + if (*dse == NO_DATE && (y == NO_YR || m == NO_MON || d == NO_DAY)) { + Eprint("%s: %s", prefix, GetErr(E_INCOMPLETE)); + DBufFree(&buf); + return E_INCOMPLETE; + } + if (*dse != NO_DATE) { + PushToken(DBufValue(&buf), s); + DBufFree(&buf); + return OK; + } + if (!DateOK(y, m, d)) { + DBufFree(&buf); + return E_BAD_DATE; + } + *dse = DSE(y, m, d); + PushToken(DBufValue(&buf), s); + DBufFree(&buf); + return OK; + } + } +} + /***************************************************************/ /* */ /* ParseRem */ @@ -383,6 +490,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim) DynamicBuffer buf; Token tok; int y, m, d; + int dse; int seen_delta = 0; DBufInit(&buf); @@ -418,6 +526,8 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim) tim->rep = NO_REP; tim->duration = NO_TIME; trig->need_wkday = 0; + trig->is_todo = 0; + trig->complete_through = NO_DATE; trig->adj_for_last = 0; trig->infos = NULL; @@ -430,6 +540,11 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim) /* Figure out what we've got */ FindToken(DBufValue(&buf), &tok); switch(tok.type) { + case T_Todo: + if (trig->is_todo) return E_TODO_TWICE; + trig->is_todo = 1; + break; + case T_In: /* Completely ignored */ DBufFree(&buf); @@ -556,6 +671,13 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim) if (r) return r; break; + case T_CompleteThrough: + if (trig->complete_through != NO_DATE) return E_COMPLETE_THROUGH_TWICE; + r = GetFullDate(s, "COMPLETE-THROUGH", &dse); + if (r != OK) return r; + trig->complete_through = dse; + break; + case T_Until: DBufFree(&buf); r=ParseUntil(s, trig, tok.type); @@ -884,93 +1006,25 @@ static int ParseLocalOmit(ParsePtr s, Trigger *t) /***************************************************************/ static int ParseUntil(ParsePtr s, Trigger *t, int type) { - int y = NO_YR, - m = NO_MON, - d = NO_DAY; char const *which; + int dse; + if (type == T_Until) { which = "UNTIL"; } else { which = "THROUGH"; } - Token tok; - int r; - DynamicBuffer buf; - DBufInit(&buf); if (t->until != NO_UNTIL) return E_UNTIL_TWICE; - while(1) { - r = ParseToken(s, &buf); - if (r) return r; - FindToken(DBufValue(&buf), &tok); - switch(tok.type) { - case T_Year: - DBufFree(&buf); - if (y != NO_YR) { - Eprint("%s: %s", which, GetErr(E_YR_TWICE)); - return E_YR_TWICE; - } - y = tok.val; - break; - - case T_Month: - DBufFree(&buf); - if (m != NO_MON) { - Eprint("%s: %s", which, GetErr(E_MON_TWICE)); - return E_MON_TWICE; - } - m = tok.val; - break; - - case T_Day: - DBufFree(&buf); - if (d != NO_DAY) { - Eprint("%s: %s", which, GetErr(E_DAY_TWICE)); - return E_DAY_TWICE; - } - d = tok.val; - break; - - case T_Date: - DBufFree(&buf); - if (y != NO_YR) { - Eprint("%s: %s", which, GetErr(E_YR_TWICE)); - return E_YR_TWICE; - } - if (m != NO_MON) { - Eprint("%s: %s", which, GetErr(E_MON_TWICE)); - return E_MON_TWICE; - } - if (d != NO_DAY) { - Eprint("%s: %s", which, GetErr(E_DAY_TWICE)); - return E_DAY_TWICE; - } - FromDSE(tok.val, &y, &m, &d); - break; - - default: - if (tok.type == T_Illegal && tok.val < 0) { - Eprint("%s: `%s'", GetErr(-tok.val), DBufValue(&buf)); - DBufFree(&buf); - return -tok.val; - } - if (y == NO_YR || m == NO_MON || d == NO_DAY) { - Eprint("%s: %s", which, GetErr(E_INCOMPLETE)); - DBufFree(&buf); - return E_INCOMPLETE; - } - if (!DateOK(y, m, d)) { - DBufFree(&buf); - return E_BAD_DATE; - } - t->until = DSE(y, m, d); - PushToken(DBufValue(&buf), s); - DBufFree(&buf); - return OK; - } + int r = GetFullDate(s, which, &dse); + if (r != OK) { + return r; } + + t->until = dse; + return OK; } /***************************************************************/ diff --git a/src/err.h b/src/err.h index 503b133e..fc811722 100644 --- a/src/err.h +++ b/src/err.h @@ -76,7 +76,7 @@ #define E_DAY_TWICE 52 #define E_UNKNOWN_TOKEN 53 #define E_SPEC_MON 54 -/* #define E_2MANY_PART 55 */ +#define E_TODO_TWICE 55 #define E_2MANY_FULL 56 #define E_PUSH_NOPOP 57 #define E_ERR_READING 58 @@ -114,7 +114,7 @@ #define E_MISS_EQ 90 #define E_MISS_VAR 91 #define E_MISS_EXPR 92 -/* #define M_CANTSET_ACCESS 93 */ +#define E_COMPLETE_THROUGH_TWICE 93 #define M_I_OPTION 94 #define E_NOREMINDERS 95 #define M_QUEUED 96 @@ -129,6 +129,7 @@ #define E_REPEATED_ARG 105 #define E_EXPR_DISABLED 106 #define E_TIME_EXCEEDED 107 +#define E_COMPLETE_WITHOUT_TODO 108 #ifdef MK_GLOBALS #undef EXTERN @@ -202,7 +203,7 @@ EXTERN char *ErrMsg[] /* E_DAY_TWICE */ "Day specified twice", /* E_UNKNOWN_TOKEN */ "Unknown token", /* E_SPEC_MON */ "Must specify month in OMIT command", -/* E_2MANY_PART */ "", +/* E_TODO_TWICE */ "TODO specified twice", /* E_2MANY_FULL */ "Too many full OMITs (max. " STR(MAX_FULL_OMITS) ")", /* E_PUSH_NOPOP */ "Warning: PUSH-OMIT-CONTEXT without matching POP-OMIT-CONTEXT", /* E_ERR_READING */ "Error reading", @@ -240,7 +241,7 @@ EXTERN char *ErrMsg[] /* E_MISS_EQ */ "Missing '=' sign", /* E_MISS_VAR */ "Missing variable name", /* E_MISS_EXPR */ "Missing expression", -/* M_CANTSET_ACCESS */ "", +/* E_COMPLETE_THROUGH_TWICE */ "COMPLETE-THROUGH specified twice", /* M_I_OPTION */ "Remind: '-i' option: %s", /* E_NOREMINDERS */ "No reminders.", /* M_QUEUED */ "%d reminder(s) queued for later today.", @@ -255,6 +256,7 @@ EXTERN char *ErrMsg[] /* E_REPEATED_ARG */ "Duplicate argument name", /* E_EXPR_DISABLED */ "Expression evaluation is disabled", /* E_TIME_EXCEEDED */ "Time limit for expression evaluation exceeded", +/* E_COMPLETE_WITHOUT_TODO */ "COMPLETE-THROUGH specified without TODO", } #endif /* MK_GLOBALS */ ; diff --git a/src/token.c b/src/token.c index b24df872..15fb73b9 100644 --- a/src/token.c +++ b/src/token.c @@ -46,7 +46,8 @@ Token TokArray[] = { { "banner", 3, T_Banner, 0 }, { "before", 6, T_Skip, BEFORE_SKIP }, { "cal", 3, T_RemType, CAL_TYPE }, - { "clear-omit-context", 5, T_Clr, 0 }, + { "clear-omit-context", 5, T_Clr, 0 }, + { "complete-through", 16, T_CompleteThrough, 0 }, { "debug", 5, T_Debug, 0 }, { "december", 3, T_Month, 11 }, { "do", 2, T_IncludeR, 0 }, @@ -118,6 +119,7 @@ Token TokArray[] = { { "third", 5, T_Ordinal, 2 }, { "through", 7, T_Through, 0 }, { "thursday", 3, T_WkDay, 3 }, + { "todo", 4, T_Todo, 0 }, { "translate", 5, T_Translate, 0 }, { "tuesday", 3, T_WkDay, 1 }, { "unset", 5, T_UnSet, 0 }, diff --git a/src/types.h b/src/types.h index 00b1e674..f68a7cd7 100644 --- a/src/types.h +++ b/src/types.h @@ -136,6 +136,8 @@ typedef struct { int from; int adj_for_last; /* Adjust month/year for use of LAST */ int need_wkday; /* Set if we *need* a weekday */ + int is_todo; /* This is a TODO reminder */ + int complete_through; /* DSE of complete-through date */ int priority; int duration_days; /* Duration converted to days to search */ int eventstart; /* Original event start (datetime) */ @@ -226,7 +228,7 @@ typedef Parser *ParsePtr; /* Pointer to parser structure */ /* Enumeration of the tokens */ enum TokTypes { T_Illegal, - T_AddOmit, T_At, T_Back, T_BackAdj, T_Banner, T_Clr, T_Comment, + T_AddOmit, T_At, T_Back, T_BackAdj, T_Banner, T_Clr, T_Comment, T_CompleteThrough, T_Date, T_DateTime, T_Day, T_Debug, T_Delta, T_Dumpvars, T_Duration, T_Else, T_Empty, T_EndIf, T_ErrMsg, T_Exit, T_Expr, T_Flush, T_Frename, T_Fset, T_Funset, T_If, T_IfTrig, T_In, T_Include, @@ -235,7 +237,7 @@ enum TokTypes T_Omit, T_OmitFunc, T_Once, T_Ordinal, T_Pop, T_PopFuncs, T_PopVars, T_Preserve, T_Priority, T_Push, T_PushFuncs, T_PushVars, T_Rem, T_RemType, T_Rep, T_Return, T_Scanfrom, T_Sched, T_Set, T_Skip, T_Tag, - T_Through, T_Time, T_Translate, T_UnSet, T_Until, T_Warn, T_WkDay, + T_Through, T_Time, T_Todo, T_Translate, T_UnSet, T_Until, T_Warn, T_WkDay, T_Year }; diff --git a/tests/test.cmp b/tests/test.cmp index a8e937ff..3e97f323 100644 --- a/tests/test.cmp +++ b/tests/test.cmp @@ -24402,6 +24402,7 @@ before cal clear clear-omit-context +complete-through debug do dump @@ -24464,6 +24465,7 @@ sysinclude tag third through +todo trans translate unset @@ -24906,6 +24908,7 @@ TRANSLATE "Month specified twice" "" TRANSLATE "Day specified twice" "" TRANSLATE "Unknown token" "" TRANSLATE "Must specify month in OMIT command" "" +TRANSLATE "TODO specified twice" "" TRANSLATE "Too many full OMITs (max. 1000)" "" TRANSLATE "Warning: PUSH-OMIT-CONTEXT without matching POP-OMIT-CONTEXT" "" TRANSLATE "Error reading" "" @@ -24943,6 +24946,7 @@ TRANSLATE "Out of memory for environment" "" TRANSLATE "Missing '=' sign" "" TRANSLATE "Missing variable name" "" TRANSLATE "Missing expression" "" +TRANSLATE "COMPLETE-THROUGH specified twice" "" TRANSLATE "Remind: '-i' option: %s" "" TRANSLATE "No reminders." "" TRANSLATE "%d reminder(s) queued for later today." "" @@ -24957,6 +24961,7 @@ TRANSLATE "Expecting weekday name" "" TRANSLATE "Duplicate argument name" "" TRANSLATE "Expression evaluation is disabled" "" TRANSLATE "Time limit for expression evaluation exceeded" "" +TRANSLATE "COMPLETE-THROUGH specified without TODO" "" # Other Messages TRANSLATE "%s function `%s' defined at %s(%s) does not use its argument" ""