feat(cli): add output control flags, sort order, and verbose mode

- Add `--verbose`/`-v` flag; gate all diagnostic stderr output behind it
- Add `--no-uuid`, `--no-source`, `--no-location`, `--no-description`,
  `--no-conference-url` flags to suppress individual INFO lines
- Add `--sort` option (`asc`, `desc`, `original`) replacing hardcoded
  descending sort
- Add `--source` option to override calendar name (single-file only)
- Introduce `Config` module with global `ref` flags set at startup from
  CLI args
- Add `Utils.warn` helper that writes to stderr only when
  `Config.verbose` is set
- Normalise all diagnostic messages to a consistent format (`Warning:
  ... (UID: ...)`)
- Remove `debug_print_of_recurrence_and_skip`; inline skip at each call
  site
- Fix `add_common_part` to always emit a trailing `\\\n    `
  continuation line
This commit is contained in:
2026-05-24 12:25:22 +02:00
parent 7c645cbd7a
commit ea0a7e64be
7 changed files with 150 additions and 55 deletions

View File

@@ -52,7 +52,8 @@ let collect_start_end_duration rem ev : (Remind.rem, error) result =
begin match ev.dtend_or_duration with
| None -> { rem with Remind.date = day_start } |> Result.ok
| Some (`Dtend (_, `Datetime _)) ->
skip (* Start is a date, end is a datetime: invalid case for all-day event *)
Utils.warn "Warning: DTSTART is DATE but DTEND is DATETIME, skipping (UID: %s)\n" rem.Remind.original_uuid;
skip
| Some (`Dtend (_, `Date (year, month, day))) ->
begin match Timedesc.Date.Ymd.make ~year ~month ~day with
| Error e -> invalid_date "DTEND" e
@@ -96,7 +97,7 @@ let collect_start_end_duration rem ev : (Remind.rem, error) result =
Ok rem
end
| `Date (_year, _month, _day) ->
(* Start is a datetime, end is a date: invalid case for timed event *)
Utils.warn "Warning: DTSTART is DATETIME but DTEND is DATE, skipping (UID: %s)\n" rem.Remind.original_uuid;
skip
end
| Some (`Duration (_, duration)) ->
@@ -121,20 +122,15 @@ let yearly_simple_date rem ev : (Remind.rem, error) result =
| Some _ -> Ok rem
| None -> Ok rem
let debug_print_of_recurrence_and_skip ev recurs =
let uid = Utils.get_uid ev in
Printf.eprintf "RRULE: %s\t\t\tUID: %s\n" (Icalendar.show_recurrence recurs) uid;
skip
let simple_recurrence rem ev : (Remind.rem, error) result =
match ev.rrule with
| Some (_, (`Yearly, None, None, [])) -> Ok rem (* handled in yearly_simple_date *)
| Some (_, ((`Weekly as freq), count_or_until, interval, recurs))
| Some (_, ((`Daily as freq), count_or_until, interval, recurs)) ->
begin if List.length rem.recurring > 0 then (
Printf.eprintf "Warning: skipping complex recurrence with EXDATE/RDATE/overrides, not supported\t\t\tUID: %s\n"
Utils.warn "Warning: complex recurrence with EXDATE/RDATE/overrides not supported, skipping (UID: %s)\n"
(Utils.get_uid ev);
debug_print_of_recurrence_and_skip ev (freq, count_or_until, interval, recurs))
skip)
else
let days =
ListLabels.filter_map recurs ~f:(function
@@ -162,8 +158,8 @@ let simple_recurrence rem ev : (Remind.rem, error) result =
| Some (_, (`Monthly, count_or_until, interval, recurs)) ->
begin match interval with
| Some n when n > 1 ->
Printf.eprintf "Warning: MONTHLY INTERVAL=%d not supported\t\t\tUID: %s\n" n (Utils.get_uid ev);
debug_print_of_recurrence_and_skip ev (`Monthly, count_or_until, interval, recurs)
Utils.warn "Warning: MONTHLY INTERVAL=%d not supported, skipping (UID: %s)\n" n (Utils.get_uid ev);
skip
| _ -> (
let bymonthday =
List.find_map
@@ -187,11 +183,13 @@ let simple_recurrence rem ev : (Remind.rem, error) result =
in
match pattern with
| None ->
Printf.eprintf "Warning: MONTHLY with unsupported BYDAY\t\t\tUID: %s\n" (Utils.get_uid ev);
debug_print_of_recurrence_and_skip ev (`Monthly, count_or_until, interval, recurs)
Utils.warn "Warning: MONTHLY with unsupported BYDAY, skipping (UID: %s)\n" (Utils.get_uid ev);
skip
| Some p -> Ok { rem with Remind.monthly = Some { count_or_until; interval; pattern = p } })
end
| Some (_, recurs) -> debug_print_of_recurrence_and_skip ev recurs
| Some (_, recurs) ->
Utils.warn "Warning: unsupported recurrence rule, skipping (UID: %s)\n" (Utils.get_uid ev);
skip
| None -> Ok rem
let is_cancelled (ev : Icalendar.event) : bool =
@@ -219,7 +217,8 @@ let collect_overrides rem _ev : (Remind.rem, error) result =
let exdates =
match recur_id_opt with
| None ->
Printf.eprintf "Warning: override event has no RECURRENCE-ID\t\t\tUID: %s\n" (Utils.get_uid override_ev);
Utils.warn "Warning: override event has no RECURRENCE-ID, skipping (UID: %s)\n"
(Utils.get_uid override_ev);
exdates
| Some date_or_dt -> date_or_dt :: exdates
in
@@ -228,7 +227,7 @@ let collect_overrides rem _ev : (Remind.rem, error) result =
else
match build_override_rem rem.Remind.source override_ev with
| Error _ ->
Printf.eprintf "Warning: could not build override REM\t\t\tUID: %s\n" (Utils.get_uid override_ev);
Utils.warn "Warning: could not build override REM, skipping (UID: %s)\n" (Utils.get_uid override_ev);
overrides
| Ok override_rem -> override_rem :: overrides
in