Command-line and Emacs Calendar Client
1open Cmdliner
2open Caledonia_lib
3open Event_args
4
5let run ~summary ~start_date ~start_time ~end_date ~end_time ~location
6 ~description ~recur ~collection ?timezone ?end_timezone ~fs calendar_dir =
7 let ( let* ) = Result.bind in
8 let* start = parse_start ~start_date ~start_time ~timezone in
9 let* start =
10 match start with
11 | Some s -> Ok s
12 | None -> Error (`Msg "Start date required")
13 in
14 let* end_ = parse_end ~end_date ~end_time ~timezone ~end_timezone in
15 let* recurrence =
16 match recur with
17 | Some r ->
18 let* p = parse_recurrence r in
19 Ok (Some p)
20 | None -> Ok None
21 in
22 let collection = Collection.Col collection in
23 let event =
24 Event.create ~fs
25 ~calendar_dir_path:(Calendar_dir.get_path calendar_dir)
26 ~summary ~start ?end_ ?location ?description ?recurrence collection
27 in
28 let* _ = Calendar_dir.add_event ~fs calendar_dir event in
29 Printf.printf "Event created with ID: %s\n" (Event.get_id event);
30 Ok ()
31
32let cmd ~fs calendar_dir =
33 let run summary start_date start_time end_date end_time location description
34 recur collection timezone end_timezone =
35 match
36 run ~summary ~start_date ~start_time ~end_date ~end_time ~location
37 ~description ~recur ~collection ?timezone ?end_timezone ~fs calendar_dir
38 with
39 | Error (`Msg msg) ->
40 Printf.eprintf "Error: %s\n%!" msg;
41 1
42 | Ok () -> 0
43 in
44 let term =
45 Term.(
46 const run $ required_summary_arg $ start_date_arg $ start_time_arg
47 $ end_date_arg $ end_time_arg $ location_arg $ description_arg $ recur_arg
48 $ collection_arg $ timezone_arg $ end_time_arg)
49 in
50 let doc = "Add a new calendar event" in
51 let man =
52 [
53 `S Manpage.s_description;
54 `P "Add a new event to your calendar.";
55 `P
56 "Specify the event summary (title) as the first argument, and use \
57 options to set other details.";
58 `S Manpage.s_options;
59 ]
60 @ date_format_manpage_entries
61 @ [
62 `S Manpage.s_examples;
63 `I
64 ( "Add a event for today:",
65 "caled add \"Meeting\" --date today --time 14:00" );
66 `I
67 ( "Add an event with a specific date and time:",
68 "caled add \"Dentist Appointment\" --date 2025-04-15 --time 10:30"
69 );
70 `I
71 ( "Add an event with an end time:",
72 "caled add \"Conference\" --date 2025-05-20 --time 09:00 \
73 --end-date 2025-05-22 --end-time 17:00" );
74 `I
75 ( "Add an event with location and description:",
76 "caled add \"Lunch with Bob\" --date 2025-04-02 --time 12:30 \
77 --location \"Pasta Restaurant\" --description \"Discuss project \
78 plans\"" );
79 `I
80 ( "Add an event to a specific calendar:",
81 "caled add \"Work Meeting\" --date 2025-04-03 --time 15:00 \
82 --calendar work" );
83 `S "RECURRENCE";
84 `P
85 "Recurrence rule in iCalendar RFC5545 format. The FREQ part is \
86 required.";
87 `I ("FREQ=<frequency>", "DAILY, WEEKLY, MONTHLY, or YEARLY (required)");
88 `I
89 ( "COUNT=<number>",
90 "Limit to this many occurrences (optional, cannot be used with \
91 UNTIL)" );
92 `I
93 ( "UNTIL=<date>",
94 "Repeat until this date (optional, cannot be used with COUNT)" );
95 `I
96 ( "INTERVAL=<number>",
97 "Interval between occurrences, e.g., 2 for every other (optional)"
98 );
99 `I
100 ( "BYDAY=<dayspec>",
101 "Specific days, e.g., MO,WE,FR or 1MO (first Monday) (optional)" );
102 `I
103 ( "BYMONTHDAY=<daynum>",
104 "Day of month, e.g., 1,15 or -1 (last day) (optional)" );
105 `I
106 ( "BYMONTH=<monthnum>",
107 "Month number, e.g., 1,6,12 for Jan,Jun,Dec (optional)" );
108 `P "Examples:";
109 `I ("FREQ=DAILY;COUNT=5", "Daily for 5 occurrences");
110 `I ("FREQ=WEEKLY;INTERVAL=2", "Every other week indefinitely");
111 `I ("FREQ=WEEKLY;BYDAY=MO,WE,FR", "Every Monday, Wednesday, Friday");
112 `I ("FREQ=MONTHLY;BYDAY=1MO", "First Monday of every month");
113 `I
114 ( "FREQ=YEARLY;BYMONTH=1;BYMONTHDAY=1",
115 "Every January 1st (New Year's Day)" );
116 `I ("FREQ=MONTHLY;BYMONTHDAY=-1", "Last day of every month");
117 ]
118 in
119 let info = Cmd.info "add" ~doc ~man in
120 Cmd.v info term