From 223f722b1dc03677a9ba1b0646c684d747d75e43 Mon Sep 17 00:00:00 2001 From: Lars Henriksen Date: Fri, 29 May 2020 15:13:28 +0200 Subject: Allow repeat count input (for until) in interactive UI Shortened repetition type text. Avoid "duration" in until-contexts (reserve it for appointment duration): "duration" changed to "increment" in user texts as well as source. Signed-off-by: Lars Henriksen Signed-off-by: Lukas Fleischer --- src/calcurse.h | 2 +- src/ui-day.c | 42 ++++++++++++++++++++++++++++++++++++------ src/utils.c | 22 +++++++++++----------- 3 files changed, 48 insertions(+), 18 deletions(-) diff --git a/src/calcurse.h b/src/calcurse.h index edf40b6..74e667a 100644 --- a/src/calcurse.h +++ b/src/calcurse.h @@ -1246,7 +1246,7 @@ int check_sec(time_t *); int check_time(unsigned, unsigned); int parse_time(const char *, unsigned *, unsigned *); int parse_duration(const char *, unsigned *, time_t); -int parse_date_duration(const char *, unsigned *, time_t); +int parse_date_increment(const char *, unsigned *, time_t); int parse_datetime(const char *, time_t *, time_t); void file_close(FILE *, const char *); void psleep(unsigned); diff --git a/src/ui-day.c b/src/ui-day.c index 0d0e1fd..7b2ea0b 100644 --- a/src/ui-day.c +++ b/src/ui-day.c @@ -658,8 +658,9 @@ static int edit_ilist(llist_t *ilist, int_list_t list_type, int rule_type) static int update_rept(time_t start, long dur, struct rpt **rpt, llist_t *exc, int simple) { - int updated = 0; + int updated = 0, count; struct rpt nrpt; + time_t until; char *types = NULL; char *freqstr = NULL; char *timstr = NULL; @@ -745,16 +746,19 @@ static int update_rept(time_t start, long dur, struct rpt **rpt, llist_t *exc, /* Edit until date. */ const char *msg_until_1 = - _("Until date or duration ('?' for input formats):"); + _("Until date, increment or repeat count ('?' for input formats):"); const char *msg_help_1 = - _("Date: %s (year or month may be omitted). Endless duration: 0."); + _("Date: %s (year, month may be omitted, endless: 0)."); const char *msg_help_2 = - _("Duration in days: +dd. Duration in weeks and days: +??w??d."); + _("Increment: +?? (days) or: +??w??d (weeks). " + "Repeat count: #?? (number)."); const char *msg_inv_until = _("Invalid date: until date must come after start date (%s)."); const char *msg_inv_date = _("Invalid date."); + const char *msg_count = _("Repeat count is too big."); for (;;) { + count = 0; mem_free(timstr); if ((*rpt)->until) timstr = date_sec2date_str((*rpt)->until, DATEFMT(conf.input_datefmt)); @@ -776,7 +780,7 @@ static int update_rept(time_t start, long dur, struct rpt **rpt, llist_t *exc, } if (*timstr == '+') { unsigned days; - if (!parse_date_duration(timstr + 1, &days, start)) { + if (!parse_date_increment(timstr + 1, &days, start)) { status_mesg(msg_inv_date, msg_cont); keys_wgetch(win[KEY].p); continue; @@ -786,6 +790,20 @@ static int update_rept(time_t start, long dur, struct rpt **rpt, llist_t *exc, update_time_in_date(start, 0, 0), 0, days ); + } else if (*timstr == '#') { + char *eos; + count = strtol(timstr + 1, &eos, 10); + if (*eos || !(count > 0)) + continue; + nrpt.until = 0; + if (!recur_nth_occurrence(start, dur, &nrpt, exc, + count, &until)) { + status_mesg(msg_count, msg_cont); + keys_wgetch(win[KEY].p); + continue; + } + nrpt.until = update_time_in_date(until, 0, 0); + break; } else { int year, month, day; if (!parse_date(timstr, conf.input_datefmt, &year, @@ -857,6 +875,17 @@ static int update_rept(time_t start, long dur, struct rpt **rpt, llist_t *exc, goto cleanup; } + /* The new until may no longer be valid. */ + if (count) { + nrpt.until = 0; + if (!recur_nth_occurrence(start, dur, &nrpt, exc, + count, &until)) { + status_mesg(msg_count, msg_cont); + keys_wgetch(win[KEY].p); + goto cleanup; + } + nrpt.until = update_time_in_date(until, 0, 0); + } /* * Check whether the start occurrence matches the recurrence rule, in * other words, does it occur on the start day? This is required by @@ -864,7 +893,8 @@ static int update_rept(time_t start, long dur, struct rpt **rpt, llist_t *exc, * is an exception day). */ char *msg_match = - _("Repetition must begin on start day (%s); any change discarded."); + _("Repetition must begin on start day (%s); " + "any change discarded."); if (!recur_item_find_occurrence(start, dur, &nrpt, NULL, update_time_in_date(start, 0, 0), NULL)) { diff --git a/src/utils.c b/src/utils.c index 552c61e..4da7f79 100644 --- a/src/utils.c +++ b/src/utils.c @@ -990,11 +990,11 @@ parse_date_interactive(const char *datestr, int *year, int *month, int *day) } /* - * Convert a date duration string into a number of days. + * Convert a date increment string into a number of days. * If start is non-zero, the final end time is validated. * * Allowed formats in lenient BNF: - * ::= | + * ::= | * ::= [ w ][ d ] * Notes: * and are any integer >= 0. @@ -1002,7 +1002,7 @@ parse_date_interactive(const char *datestr, int *year, int *month, int *day) * * Returns 1 on success and 0 on failure. */ -int parse_date_duration(const char *string, unsigned *days, time_t start) +int parse_date_increment(const char *string, unsigned *days, time_t start) { enum { STATE_INITIAL, @@ -1012,7 +1012,7 @@ int parse_date_duration(const char *string, unsigned *days, time_t start) const char *p; unsigned in = 0, frac = 0, denom = 1; - unsigned dur = 0; + unsigned incr = 0; if (!string || *string == '\0') return 0; @@ -1033,10 +1033,10 @@ int parse_date_duration(const char *string, unsigned *days, time_t start) switch (state) { case STATE_INITIAL: if (*p == 'w') { - dur += in * WEEKINDAYS / denom; + incr += in * WEEKINDAYS / denom; state = STATE_WWDD_DD; } else if (*p == 'd') { - dur += in / denom; + incr += in / denom; state = STATE_DONE; } else { return 0; @@ -1044,7 +1044,7 @@ int parse_date_duration(const char *string, unsigned *days, time_t start) break; case STATE_WWDD_DD: if (*p == 'd') { - dur += in / denom; + incr += in / denom; state = STATE_DONE; } else { return 0; @@ -1060,18 +1060,18 @@ int parse_date_duration(const char *string, unsigned *days, time_t start) } if (state == STATE_DONE && in > 0) return 0; - dur += in; + incr += in; if (start) { - /* wanted: start = start + dur * DAYINSEC */ + /* wanted: start = start + incr * DAYINSEC */ long p; - if (overflow_mul(dur, DAYINSEC, &p)) + if (overflow_mul(incr, DAYINSEC, &p)) return 0; if (overflow_add(start, p, &start)) return 0; if (!check_sec(&start)) return 0; } - *days = dur; + *days = incr; return 1; } -- cgit v1.2.3-54-g00ecf