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