From 2d856aa1cf73b350c600c95e0533daead26ba155 Mon Sep 17 00:00:00 2001 From: Paolo Donadeo Date: Mon, 18 May 2026 14:36:54 +0200 Subject: [PATCH] feat: add location and description fields to reminders --- bin/eventPredicates.ml | 14 +++++++++++++ bin/remind.ml | 46 +++++++++++++++++++++++++++++++++++------- bin/utils.ml | 16 +++++++++++++++ 3 files changed, 69 insertions(+), 7 deletions(-) diff --git a/bin/eventPredicates.ml b/bin/eventPredicates.ml index bd89832..9ea9877 100644 --- a/bin/eventPredicates.ml +++ b/bin/eventPredicates.ml @@ -170,6 +170,18 @@ let collect_summary rem ev : (Remind.rem, error) result = | Some s -> Ok { rem with Remind.summary = s } | None -> Ok { rem with Remind.summary = "" } +let collect_location rem ev : (Remind.rem, error) result = + let location_opt = Utils.get_location ev in + match location_opt with + | Some loc -> Ok { rem with Remind.location = Some loc } + | None -> Ok rem + +let collect_description rem ev : (Remind.rem, error) result = + let description_opt = Utils.get_description ev in + match description_opt with + | Some desc -> Ok { rem with Remind.description = Some desc } + | None -> Ok rem + let collect_start_end_duration rem ev : (Remind.rem, error) result = let _, dtstart = ev.dtstart in match dtstart with @@ -417,6 +429,8 @@ let all_collectors : collector list = [ collect_uuid; collect_summary; + collect_location; + collect_description; collect_start_end_duration; collect_exdates; collect_overrides; diff --git a/bin/remind.ml b/bin/remind.ml index 00b8811..8407d24 100644 --- a/bin/remind.ml +++ b/bin/remind.ml @@ -32,6 +32,8 @@ type rem = { source : string; (** Source file or identifier for the reminder *) original_uuid : string; (** Original UID from the iCalendar event *) summary : string; (** Summary or title of the reminder *) + location : string option; (** Optional location of the event *) + description : string option; (** Optional description of the event *) date : Timedesc.Date.t; (** Date specification (day, month, year) *) end_date : Timedesc.Date.t option; (** Optional end date for a date range *) time : Timedesc.Time.t option; (** Optional time specification (hour, minute) *) @@ -54,6 +56,8 @@ let empty = source = ""; original_uuid = ""; summary = ""; + location = None; + description = None; date = Timedesc.Date.Ymd.make_exn ~year:1970 ~month:1 ~day:1; end_date = None; time = None; @@ -71,8 +75,8 @@ let empty = (* ── buffer primitives ────────────────────────────────────────── *) let add_rem b = Buffer.add_string b "REM " -let add_info b uuid = Buffer.add_string b (spf "INFO \"UID: %s\" " uuid) -let add_source b source = Buffer.add_string b (spf "INFO \"Calendar: %s\" " (String.uppercase_ascii source)) +let add_uid b uuid = Buffer.add_string b (spf "\\\n INFO \"UID: %s\" " uuid) +let add_source b source = Buffer.add_string b (spf "\\\n INFO \"Calendar: %s\" " (String.uppercase_ascii source)) let add_date b date = Buffer.add_string b (Timedesc.Date.to_rfc3339 date) let add_weekday b wd = Buffer.add_string b (spf "%s " (string_of_weekday wd)) @@ -164,6 +168,9 @@ let escape_msg s = let buf = Buffer.create (String.length s) in String.iter (function + | '\n' -> Buffer.add_string buf "\\n" + | '\t' -> () + | '"' -> Buffer.add_string buf "\\\"" | '%' -> Buffer.add_string buf "%%" | '[' -> Buffer.add_string buf {|["["]|} | c -> Buffer.add_char buf c) @@ -172,6 +179,21 @@ let escape_msg s = let add_msg b summary = Buffer.add_string b (spf " MSG %s\n" (escape_msg summary)) +let add_location b loc = + match loc with + | Some loc -> begin + let loc = String.trim loc in + Buffer.add_string b (spf "\\\n INFO \"Location: %s\" " (escape_msg loc)) + end + | None -> () + +let add_description b desc = + match desc with + | Some desc -> + let desc = String.trim desc in + Buffer.add_string b (spf "\\\n INFO \"Description: %s\" " (escape_msg desc)) + | None -> () + let date_of_date_or_datetime (d : Icalendar.date_or_datetime) : Timedesc.Date.t = match d with | `Date (year, month, day) -> Timedesc.Date.Ymd.make_exn ~year ~month ~day @@ -199,8 +221,10 @@ let render_daily rem (d : simple_daily) = let b = Buffer.create 256 in add_omit_context b rem.exdate; add_rem b; - add_info b rem.original_uuid; + add_uid b rem.original_uuid; add_source b rem.source; + add_location b rem.location; + add_description b rem.description; add_date b rem.date; Buffer.add_char b ' '; add_interval_daily b d; @@ -218,8 +242,10 @@ let render_weekly rem (w : simple_weekly) = List.iter (fun wd -> add_rem b; - add_info b rem.original_uuid; + add_uid b rem.original_uuid; add_source b rem.source; + add_location b rem.location; + add_description b rem.description; add_weekday b wd; add_date b rem.date; Buffer.add_char b ' '; @@ -237,8 +263,10 @@ let render_monthly rem (m : simple_monthly) = let b = Buffer.create 256 in add_omit_context b rem.exdate; add_rem b; - add_info b rem.original_uuid; + add_uid b rem.original_uuid; add_source b rem.source; + add_location b rem.location; + add_description b rem.description; (match m.pattern with | By_month_day day -> Buffer.add_string b (spf "%d " day) | By_nth_weekday (n, wd) when n > 0 -> @@ -261,8 +289,10 @@ let render_monthly rem (m : simple_monthly) = let render_single rem = let b = Buffer.create 256 in add_rem b; - add_info b rem.original_uuid; + add_uid b rem.original_uuid; add_source b rem.source; + add_location b rem.location; + add_description b rem.description; add_date b rem.date; add_at b rem.time; add_duration b rem.duration; @@ -273,8 +303,10 @@ let render_single rem = let render_yearly rem month day = let b = Buffer.create 64 in add_rem b; - add_info b rem.original_uuid; + add_uid b rem.original_uuid; add_source b rem.source; + add_location b rem.location; + add_description b rem.description; Buffer.add_string b (spf "%s %d" (month_of_int month |> string_of_month) day); add_msg b rem.summary; Buffer.contents b diff --git a/bin/utils.ml b/bin/utils.ml index 27ca2a2..b7c6100 100644 --- a/bin/utils.ml +++ b/bin/utils.ml @@ -190,6 +190,22 @@ let get_recurrence_id ev = | _ -> None) ev.props +let get_location ev = + List.find_map + (fun prop -> + match prop with + | `Location (_, loc) -> Some loc + | _ -> None) + ev.props + +let get_description ev = + List.find_map + (fun prop -> + match prop with + | `Description (_, desc) -> Some desc + | _ -> None) + ev.props + let separate_master_and_recurrence (events : Icalendar.event list) : Icalendar.event * Icalendar.event list = (* List.iteri (fun i e -> Printf.eprintf "%02d: %s\n" (i + 1) (Icalendar.show_component (`Event e))) events; *) let recur_ids = List.map (fun ev -> (ev, get_recurrence_id ev)) events in