Add MAX-OVERDUE feature.

This commit is contained in:
Dianne Skoll
2025-08-14 18:50:39 -04:00
parent 582f388500
commit a000a7f17e
9 changed files with 102 additions and 5 deletions

View File

@@ -114,7 +114,7 @@
"DURATION" "ELSE" "ENDIF" "ERRMSG" "EXIT" "EXPR" "FIRST"
"FLUSH" "FOURTH" "FRENAME" "FROM" "FSET" "FUNSET" "IF"
"IFTRIG" "IN" "INC" "INCLUDE" "INCLUDECMD" "INFO" "LAST"
"LASTDAY" "LASTWORKDAY" "MAYBE" "MAYBE-UNCOMPUTABLE" "MSF"
"LASTDAY" "LASTWORKDAY" "MAX-OVERDUE" "MAYBE" "MAYBE-UNCOMPUTABLE" "MSF"
"MSG" "NOQUEUE" "OMIT" "OMITFUNC" "ONCE" "POP"
"POP-OMIT-CONTEXT" "POP-FUNCS" "POP-VARS" "PRESERVE" "PRIORITY" "PS"
"PSFILE" "PUSH" "PUSH-FUNCS" "PUSH-VARS" "PUSH-OMIT-CONTEXT" "REM" "RETURN"

View File

@@ -668,6 +668,7 @@ Its syntax is:
[\fIdelta\fR]
[\fIrepeat\fR]
[\fBTODO\fR]
[\fBMAX-OVERDUE\fR \fIn\fR]
[\fBCOMPLETE-THROUGH\fR \fIcomplete_date\fR]
[\fBPRIORITY\fR \fIprio\fR]
[\fBSKIP\fR | \fBBEFORE\fR | \fBAFTER\fR]
@@ -1944,7 +1945,7 @@ which recurrences have been completed. For example:
Canadian income taxes must be filed every 30 April. The above command
will remind you to pay taxes in 2026. If you don't update the
COMPLETE-THROUGH date, then after 30 April 2026, \fBRemind\fR will
keep reminding you until the end of time that my taxes were due on 30
keep reminding you until the end of time that your taxes were due on 30
April 2026. To indicate that you've paid them, simply update the
COMPLETE-THROUGH date to 2026-04-30 and then \fBRemind\fR will start
reminding you of your 2027 taxes (starting 15 days before the due
@@ -1952,6 +1953,26 @@ date.)
.PP
It is an error to specify COMPLETE-THROUGH without also specifying TODO.
.PP
.SH LIMITING REMINDERS ABOUT OVERDUE TODOS
.PP
Although \fBRemind\fR is happy to keep reminding you about overdue
TODOs for hundreds of years, for some things this may be pointless.
If you want \fBRemind\fR to \fIstop\fR nagging you about an overdue
TODO after a certain number of days, use the MAX-OVERDUE \fIn\fR clause.
In this case, \fBRemind\fR stops reminding you of a TODO that is overdue
by more than \fIn\fR days. Here is an example.
.PP
.nf
REM TODO 2025-08-13 ++5 MAX-OVERDUE 5 MSG Task: %b.
.fi
.PP
\fBRemind\fR \fIstarts\fR reminding you of the task on 2025-08-08,
because of the ++5 back value. It keeps reminding you of the task
after the due date. However, the last time it will remind you
will be on 2025-08-18, because of the MAX-OVERDUE clause. Starting
on 2025-08-19, \fBRemind\fR will no longer remind you of the task
since it's probably pointless---it has passed the MAX-OVERDUE period.
.PP
.SH MORE DETAILS ABOUT TODOS
.PP
TODOs are treated specially only in Agenda Mode. In Calendar Mode,

View File

@@ -293,6 +293,12 @@ int DoRem(ParsePtr p)
return E_COMPLETE_WITHOUT_TODO;
}
if (trig.max_overdue >= 0 && !trig.is_todo) {
PurgeEchoLine("%s\n", CurLine);
FreeTrig(&trig);
return E_MAX_OVERDUE_WITHOUT_TODO;
}
if (trig.typ == NO_TYPE) {
if (!Hush) {
PurgeEchoLine("%s\n", "#!P! Cannot parse next line");
@@ -668,6 +674,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
tim->duration = NO_TIME;
trig->need_wkday = 0;
trig->is_todo = 0;
trig->max_overdue = -1;
trig->complete_through = NO_DATE;
trig->adj_for_last = 0;
trig->infos = NULL;
@@ -758,6 +765,25 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
trig->skip = tok.val;
break;
case T_MaxOverdue:
if (trig->max_overdue >= 0) return E_MAX_OVERDUE_TWICE;
DBufFree(&buf);
r = ParseToken(s, &buf);
if (r) return r;
FindToken(DBufValue(&buf), &tok);
DBufFree(&buf);
if (tok.type == T_Illegal) {
return -tok.val;
}
if (tok.type != T_Day && tok.type != T_Year && tok.type != T_Number) {
return E_EXPECTING_NUMBER;
}
if (tok.val < 0) {
return E_2LOW;
}
trig->max_overdue = tok.val;
break;
case T_Priority:
DBufFree(&buf);
r=ParsePriority(s, trig);
@@ -1664,8 +1690,14 @@ int ShouldTriggerReminder(Trigger const *t, TimeTrig const *tim, int dse, int *e
}
/* DO trigger if has not been completed through trigger date */
if (t->complete_through == NO_DATE || t->complete_through < dse) {
/* Trigger date is in the past - overdue */
/* Trigger date is in the past - overdue, Trigger unless we're
more than max_overdue days late */
if (dse < DSEToday) {
if (t->max_overdue >= 0) {
if (dse + t->max_overdue < DSEToday) {
return 0;
}
}
return 1;
}
/* Trigger date in future - use normal Remind rules */
@@ -1961,8 +1993,14 @@ static int ShouldTriggerBasedOnWarn(Trigger const *t, int dse, int *err)
}
/* DO trigger if has not been completed through trigger date */
if (t->complete_through == NO_DATE || t->complete_through < dse) {
/* Trigger date is in the past - overdue */
/* Trigger date is in the past - overdue, Trigger unless we're
more than max_overdue days late */
if (dse < DSEToday) {
if (t->max_overdue >= 0) {
if (dse + t->max_overdue < DSEToday) {
return 0;
}
}
return 1;
}
/* Trigger date in future - use normal Remind rules */

View File

@@ -130,6 +130,8 @@
#define E_EXPR_DISABLED 106
#define E_TIME_EXCEEDED 107
#define E_COMPLETE_WITHOUT_TODO 108
#define E_MAX_OVERDUE_TWICE 109
#define E_MAX_OVERDUE_WITHOUT_TODO 110
#ifdef MK_GLOBALS
#undef EXTERN
@@ -257,6 +259,8 @@ EXTERN char *ErrMsg[]
/* 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",
/* E_MAX_OVERDUE_TWICE */ "MAX-OVERDUE specified twice",
/* E_MAX_OVERDUE_WITHOUT_TODO */ "MAX-OVERDUE specified without TODO",
}
#endif /* MK_GLOBALS */
;

View File

@@ -1149,10 +1149,18 @@ ProcessLongOption(char const *arg)
return;
}
if (!strcmp(arg, "only-todos")) {
if (TodoFilter == ONLY_EVENTS) {
fprintf(ErrFp, "remind: Cannot combine --only-todos and --only-events\n");
exit(1);
}
TodoFilter = ONLY_TODOS;
return;
}
if (!strcmp(arg, "only-events")) {
if (TodoFilter == ONLY_TODOS) {
fprintf(ErrFp, "remind: Cannot combine --only-todos and --only-events\n");
exit(1);
}
TodoFilter = ONLY_EVENTS;
return;
}

View File

@@ -80,6 +80,7 @@ Token TokArray[] = {
{ "lastday", 7, T_BackAdj, -1 },
{ "lastworkday", 11, T_BackAdj, 1 },
{ "march", 3, T_Month, 2 },
{ "max-overdue", 11, T_MaxOverdue, 0 },
{ "may", 3, T_Month, 4 },
{ "maybe-uncomputable", 5, T_MaybeUncomputable, 0},
{ "monday", 3, T_WkDay, 0 },

View File

@@ -145,6 +145,7 @@ typedef struct {
int maybe_uncomputable; /* Suppress "can't compute trigger" warnings */
int addomit; /* Add trigger date to global OMITs */
int noqueue; /* Don't queue even if timed */
int max_overdue; /* Stop warning if TODO is too far overdue */
char sched[VAR_NAME_LEN+1]; /* Scheduling function */
char warn[VAR_NAME_LEN+1]; /* Warning function */
char omitfunc[VAR_NAME_LEN+1]; /* OMITFUNC function */
@@ -234,7 +235,7 @@ enum TokTypes
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,
T_IncludeCmd, T_IncludeR, T_IncludeSys, T_Info, T_LastBack,
T_LongTime, T_MaybeUncomputable, T_Month, T_NoQueue, T_Number,
T_LongTime, T_MaxOverdue, T_MaybeUncomputable, T_Month, T_NoQueue, T_Number,
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,

View File

@@ -24430,6 +24430,7 @@ info
last
lastday
lastworkday
max-overdue
maybe
maybe-uncomputable
msf
@@ -24965,6 +24966,8 @@ TRANSLATE "Duplicate argument name" ""
TRANSLATE "Expression evaluation is disabled" ""
TRANSLATE "Time limit for expression evaluation exceeded" ""
TRANSLATE "COMPLETE-THROUGH specified without TODO" ""
TRANSLATE "MAX-OVERDUE specified twice" ""
TRANSLATE "MAX-OVERDUE specified without TODO" ""
# Other Messages
TRANSLATE "%s function `%s' defined at %s(%s) does not use its argument" ""
@@ -39553,6 +39556,10 @@ Fifth today
Sixth on 2025-08-06
Eighth on 2025-08-20
Ninth today
Yup today
Yup2 yesterday
Yup3 on 2025-08-11
Yup4 on 2025-08-10
Testing TODOS in calendar mode
2025/08/01 * * * * First
@@ -39562,9 +39569,14 @@ Testing TODOS in calendar mode
2025/08/06 * * * * Seventh
2025/08/06 * * * * Eighth
2025/08/06 * * * * Ninth
2025/08/09 * * * * Nope
2025/08/10 * * * * Yup4
2025/08/11 * * * * Yup3
2025/08/12 * * * * Yup2
2025/08/13 * * * * Fifth
2025/08/13 * * * * Eighth
2025/08/13 * * * * Ninth
2025/08/13 * * * * Yup
2025/08/20 * * * * Fourth
2025/08/20 * * * * Eighth
2025/08/20 * * * * Ninth
@@ -39576,8 +39588,13 @@ Testing TODOS in calendar mode with completed todos hidden
2025/08/01 * * * * Second
2025/08/01 * * * * Third
2025/08/06 * * * * Sixth
2025/08/09 * * * * Nope
2025/08/10 * * * * Yup4
2025/08/11 * * * * Yup3
2025/08/12 * * * * Yup2
2025/08/13 * * * * Fifth
2025/08/13 * * * * Ninth
2025/08/13 * * * * Yup
2025/08/20 * * * * Fourth
2025/08/20 * * * * Eighth
2025/08/20 * * * * Ninth

View File

@@ -10,3 +10,10 @@ REM TODO 6 Aug 2025 +7 MSG %"Sixth%" %l
REM TODO COMPLETE-THROUGH 2025-08-06 6 Aug 2025 +7 MSG %"Seventh%" %l
REM TODO Wed +7 COMPLETE-THROUGH 2025-08-13 MSG %"Eighth%" %l
REM TODO Wed +7 COMPLETE-THROUGH 2025-08-12 MSG %"Ninth%" %l
# Test MAX-OVERDUE
REM TODO 2025-08-13 MAX-OVERDUE 3 MSG %"Yup%" %l
REM TODO 2025-08-12 MAX-OVERDUE 3 MSG %"Yup2%" %l
REM TODO 2025-08-11 MAX-OVERDUE 3 MSG %"Yup3%" %l
REM TODO 2025-08-10 MAX-OVERDUE 3 MSG %"Yup4%" %l
REM TODO 2025-08-9 MAX-OVERDUE 3 MSG %"Nope%" %l