Start working on TODO and COMPLETE-THROUGH. Still a WIP!!!

This commit is contained in:
Dianne Skoll
2025-08-11 16:29:34 -04:00
parent 59fdf70732
commit 814dd51270
6 changed files with 150 additions and 85 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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