feat: initial implementation of iCalendar to Remind converter

- Add project scaffolding (dune, dune-project, opam, .ocamlformat)
- Implement basic parsing and handling of iCalendar events
- Add event predicates for common event types (all-day, timed,
  recurrence, exceptions)
- Add transformation logic to map iCalendar events to Remind format
  (stub implementation)
- Provide utilities for extracting event details and converting
  dates/times
- Set up executable entrypoint and command-line interface using Cmdliner
- Include Remind event type definitions and helpers
This commit is contained in:
2025-11-30 19:33:35 +01:00
parent d79471cc62
commit 83dfd0dfa9
12 changed files with 2645 additions and 0 deletions

119
bin/remind.ml Normal file
View File

@@ -0,0 +1,119 @@
(* Alias esplicito per chiarezza *)
type date = Ptime.date
let pp_date fmt (y, m, d) = Format.fprintf fmt "%04d-%02d-%02d" y m d
let show_date (d : date) : string =
let y, m, day = d in
Printf.sprintf "%04d-%02d-%02d" y m day
type tod = Ptime.Span.t (* secondi da mezzanotte locale *)
let pp_tod = Ptime.Span.pp
let span_min (m : int) : tod = Ptime.Span.of_int_s (m * 60)
let span_hm ~(h : int) ~(m : int) : tod = Ptime.Span.of_int_s ((h * 3600) + (m * 60))
let hm_of_tod (t : tod) : int * int =
match Ptime.Span.to_int_s t with
| None -> invalid_arg "tod out of range"
| Some s -> (s / 3600, s mod 3600 / 60)
type weekday =
| Mon
| Tue
| Wed
| Thu
| Fri
| Sat
| Sun
type time_spec =
| All_day
| Timed of {
at : tod;
duration : Ptime.Span.t option;
}
type range = {
from_ : date;
until : date option;
}
(* UNTIL inclusivo *)
type recurrence =
| No_recur
| Daily of {
interval : int;
span : range;
}
| Weekly of {
interval : int;
days : weekday list;
span : range;
}
| Monthly_dom of {
interval : int;
day : int;
span : range;
}
| Monthly_nth_weekday of {
interval : int;
n : int;
wday : weekday;
span : range;
}
| Yearly of {
month : int;
day : int;
}
type alarm = { warn_before : Ptime.Span.t }
type meta = {
location : string option;
url : string option;
categories : string list;
attendees : string list;
}
type instance_override = {
on : date;
cancel : bool;
summary : string option;
time_spec : time_spec option;
notes : string option;
alarm : alarm option;
meta : meta option;
}
type series = {
summary : string;
start : date; (* DTSTART locale *)
time_spec : time_spec;
recur : recurrence;
exdates : date list;
overrides : instance_override list;
alarm : alarm option;
notes : string option;
meta : meta;
}
type info_header = string [@@deriving show]
type info_value = string [@@deriving show]
type event =
| Rem of {
date_expr : string;
at : tod option;
duration : Ptime.Span.t option;
warn : Ptime.Span.t option;
msg : string;
exdates : date list;
infos : (info_header * info_value) list;
}
| Omit of date
[@@deriving show]
let string_of_date (d : date) : string =
let y, m, day = d in
Printf.sprintf "%04d-%02d-%02d" y m day