Command-line and Emacs Calendar Client
1type format = [ `Text | `Json | `Csv | `Ics | `Table | `Sexp ] 2 3let format_date date = 4 let y, m, d = Ptime.to_date date in 5 let cal_date = CalendarLib.Date.make y m d in 6 let weekday = 7 match CalendarLib.Date.day_of_week cal_date with 8 | CalendarLib.Date.Mon -> "Mon" 9 | CalendarLib.Date.Tue -> "Tue" 10 | CalendarLib.Date.Wed -> "Wed" 11 | CalendarLib.Date.Thu -> "Thu" 12 | CalendarLib.Date.Fri -> "Fri" 13 | CalendarLib.Date.Sat -> "Sat" 14 | CalendarLib.Date.Sun -> "Sun" 15 in 16 Printf.sprintf "%04d-%02d-%02d %s" y m d weekday 17 18let format_time date = 19 let _, ((h, m, _), _) = Ptime.to_date_time date in 20 Printf.sprintf "%02d:%02d" h m 21 22let format_datetime date = 23 Printf.sprintf "%s %s" (format_date date) (format_time date) 24 25let format_event ?(format = `Text) event = 26 let open Event in 27 match format with 28 | `Text -> 29 let summary = get_summary event in 30 let date = format_date (get_start event) in 31 let time = format_time (get_start event) in 32 let end_time_str = 33 match get_end event with 34 | Some e -> Printf.sprintf "-%s" (format_time e) 35 | None -> "" 36 in 37 let location_str = 38 match get_location event with 39 | Some loc when loc <> "" -> Printf.sprintf " @ %s" loc 40 | _ -> "" 41 in 42 let recur_str = 43 match get_recurrence event with 44 | Some _ -> Printf.sprintf " (recurring)" 45 | None -> "" 46 in 47 Printf.sprintf "%s %s%s %s%s%s" date time end_time_str summary 48 location_str recur_str 49 | `Json -> 50 let open Yojson.Safe in 51 let json = 52 `Assoc 53 [ 54 ("id", `String (get_id event)); 55 ("summary", `String (get_summary event)); 56 ("start", `String (format_datetime (get_start event))); 57 ( "end", 58 match get_end event with 59 | Some e -> `String (format_datetime e) 60 | None -> `Null ); 61 ( "location", 62 match get_location event with 63 | Some loc -> `String loc 64 | None -> `Null ); 65 ( "description", 66 match get_description event with 67 | Some desc -> `String desc 68 | None -> `Null ); 69 ( "calendar", 70 match get_collection event with 71 | Some (Calendar_dir.Collection cal) -> `String cal 72 | None -> `Null ); 73 ] 74 in 75 to_string json 76 | `Csv -> 77 let summary = get_summary event in 78 let start = format_datetime (get_start event) in 79 let end_str = 80 match get_end event with Some e -> format_datetime e | None -> "" 81 in 82 let location = 83 match get_location event with Some loc -> loc | None -> "" 84 in 85 let cal_id = 86 match get_collection event with 87 | Some (Calendar_dir.Collection cal) -> cal 88 | None -> "" 89 in 90 Printf.sprintf "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"" summary start end_str 91 location cal_id 92 | `Ics -> 93 let cal_props = [] in 94 let event_ical = Event.to_icalendar event in 95 Icalendar.to_ics (cal_props, [ `Event event_ical ]) 96 | `Table -> 97 let width = 80 in 98 let hr = String.make width '-' in 99 let summary = get_summary event in 100 let start = format_datetime (get_start event) in 101 let end_str = 102 match get_end event with Some e -> format_datetime e | None -> "" 103 in 104 let location = 105 match get_location event with Some loc -> loc | None -> "" 106 in 107 Printf.sprintf 108 "%s\n\ 109 | %-20s | %-30s |\n\ 110 | %-20s | %-30s |\n\ 111 | %-20s | %-30s |\n\ 112 | %-20s | %-30s |\n\ 113 %s" 114 hr "Summary" summary "Start" start "End" end_str "Location" location hr 115 | `Sexp -> 116 let summary = get_summary event in 117 let start_date, start_time = 118 let date = get_start event in 119 let y, m, d = Ptime.to_date date in 120 let _, ((h, min, s), _) = Ptime.to_date_time date in 121 let cal_date = CalendarLib.Date.make y m d in 122 let dow = 123 match CalendarLib.Date.day_of_week cal_date with 124 | CalendarLib.Date.Mon -> "monday" 125 | CalendarLib.Date.Tue -> "tuesday" 126 | CalendarLib.Date.Wed -> "wednesday" 127 | CalendarLib.Date.Thu -> "thursday" 128 | CalendarLib.Date.Fri -> "friday" 129 | CalendarLib.Date.Sat -> "saturday" 130 | CalendarLib.Date.Sun -> "sunday" 131 in 132 ( Printf.sprintf "(%04d %02d %02d %s)" y m d dow, 133 Printf.sprintf "(%02d %02d %02d)" h min s ) 134 in 135 let end_str = 136 match get_end event with 137 | Some end_date -> 138 let y, m, d = Ptime.to_date end_date in 139 let _, ((h, min, s), _) = Ptime.to_date_time end_date in 140 let cal_date = CalendarLib.Date.make y m d in 141 let dow = 142 match CalendarLib.Date.day_of_week cal_date with 143 | CalendarLib.Date.Mon -> "monday" 144 | CalendarLib.Date.Tue -> "tuesday" 145 | CalendarLib.Date.Wed -> "wednesday" 146 | CalendarLib.Date.Thu -> "thursday" 147 | CalendarLib.Date.Fri -> "friday" 148 | CalendarLib.Date.Sat -> "saturday" 149 | CalendarLib.Date.Sun -> "sunday" 150 in 151 Printf.sprintf "((%04d %02d %02d %s) (%02d %02d %02d))" y m d dow h 152 min s 153 | None -> "nil" 154 in 155 let location = 156 match get_location event with 157 | Some loc -> Printf.sprintf "\"%s\"" (String.escaped loc) 158 | None -> "nil" 159 in 160 let description = 161 match get_description event with 162 | Some desc -> Printf.sprintf "\"%s\"" (String.escaped desc) 163 | None -> "nil" 164 in 165 let calendar = 166 match get_collection event with 167 | Some (Calendar_dir.Collection cal) -> 168 Printf.sprintf "\"%s\"" (String.escaped cal) 169 | None -> "nil" 170 in 171 let id = get_id event in 172 Printf.sprintf 173 "((:id \"%s\" :summary \"%s\" :start (%s %s) :end %s :location %s \ 174 :description %s :calendar %s))" 175 (String.escaped id) (String.escaped summary) start_date start_time 176 end_str location description calendar 177 178let format_instance ?(format = `Text) instance = 179 match format with 180 | `Text -> 181 let summary = Event.get_summary instance.Recur.event in 182 let date = format_date instance.Recur.start in 183 let time = format_time instance.Recur.start in 184 let end_time_str = 185 match instance.Recur.end_ with 186 | Some e -> Printf.sprintf "-%s" (format_time e) 187 | None -> "" 188 in 189 let location_str = 190 match Event.get_location instance.Recur.event with 191 | Some loc when loc <> "" -> Printf.sprintf " @ %s" loc 192 | _ -> "" 193 in 194 Printf.sprintf "%s %s%s %s%s" date time end_time_str summary location_str 195 | format -> format_event ~format instance.Recur.event 196 197let format_events ?(format = `Text) events = 198 match format with 199 | `Json -> 200 let json_events = 201 List.map 202 (fun e -> Yojson.Safe.from_string (format_event ~format:`Json e)) 203 events 204 in 205 Yojson.Safe.to_string (`List json_events) 206 | `Csv -> 207 "\"Summary\",\"Start\",\"End\",\"Location\",\"Calendar\"\n" 208 ^ String.concat "\n" 209 (List.map 210 (fun e -> 211 let summary = Event.get_summary e in 212 let start = format_datetime (Event.get_start e) in 213 let end_str = 214 match Event.get_end e with 215 | Some end_ -> format_datetime end_ 216 | None -> "" 217 in 218 let location = 219 match Event.get_location e with Some loc -> loc | None -> "" 220 in 221 let cal_id = 222 match Event.get_collection e with 223 | Some (Calendar_dir.Collection cal) -> cal 224 | None -> "" 225 in 226 Printf.sprintf "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"" summary start 227 end_str location cal_id) 228 events) 229 | `Sexp -> 230 (* For S-expressions, we want a list of event S-expressions *) 231 "(" 232 ^ String.concat "\n " 233 (List.map (fun e -> format_event ~format:`Sexp e) events) 234 ^ ")" 235 | _ -> String.concat "\n" (List.map (fun e -> format_event ~format e) events) 236 237let format_instances ?(format = `Text) instances = 238 match format with 239 | `Json -> 240 let json_instances = 241 List.map 242 (fun i -> 243 let e = i.Recur.event in 244 let json = Yojson.Safe.from_string (format_event ~format:`Json e) in 245 match json with 246 | `Assoc fields -> 247 `Assoc 248 (("start", `String (format_datetime i.Recur.start)) 249 :: ( "end", 250 match i.Recur.end_ with 251 | Some e -> `String (format_datetime e) 252 | None -> `Null ) 253 :: List.filter 254 (fun (k, _) -> k <> "start" && k <> "end") 255 fields) 256 | _ -> json) 257 instances 258 in 259 Yojson.Safe.to_string (`List json_instances) 260 | `Csv -> 261 "\"Summary\",\"Start\",\"End\",\"Location\",\"Calendar\"\n" 262 ^ String.concat "\n" 263 (List.map 264 (fun i -> 265 let e = i.Recur.event in 266 let summary = Event.get_summary e in 267 let start = format_datetime i.Recur.start in 268 let end_str = 269 match i.Recur.end_ with 270 | Some end_ -> format_datetime end_ 271 | None -> "" 272 in 273 let location = 274 match Event.get_location e with Some loc -> loc | None -> "" 275 in 276 let cal_id = 277 match Event.get_collection e with 278 | Some (Calendar_dir.Collection cal) -> cal 279 | None -> "" 280 in 281 Printf.sprintf "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"" summary start 282 end_str location cal_id) 283 instances) 284 | `Sexp -> 285 (* Create a list of instance S-expressions *) 286 let format_instance_sexp i = 287 let e = i.Recur.event in 288 let summary = Event.get_summary e in 289 let start_date, start_time = 290 let date = i.Recur.start in 291 let y, m, d = Ptime.to_date date in 292 let _, ((h, min, s), _) = Ptime.to_date_time date in 293 let cal_date = CalendarLib.Date.make y m d in 294 let dow = 295 match CalendarLib.Date.day_of_week cal_date with 296 | CalendarLib.Date.Mon -> "monday" 297 | CalendarLib.Date.Tue -> "tuesday" 298 | CalendarLib.Date.Wed -> "wednesday" 299 | CalendarLib.Date.Thu -> "thursday" 300 | CalendarLib.Date.Fri -> "friday" 301 | CalendarLib.Date.Sat -> "saturday" 302 | CalendarLib.Date.Sun -> "sunday" 303 in 304 ( Printf.sprintf "(%04d %02d %02d %s)" y m d dow, 305 Printf.sprintf "(%02d %02d %02d)" h min s ) 306 in 307 let end_str = 308 match i.Recur.end_ with 309 | Some end_date -> 310 let y, m, d = Ptime.to_date end_date in 311 let _, ((h, min, s), _) = Ptime.to_date_time end_date in 312 let cal_date = CalendarLib.Date.make y m d in 313 let dow = 314 match CalendarLib.Date.day_of_week cal_date with 315 | CalendarLib.Date.Mon -> "monday" 316 | CalendarLib.Date.Tue -> "tuesday" 317 | CalendarLib.Date.Wed -> "wednesday" 318 | CalendarLib.Date.Thu -> "thursday" 319 | CalendarLib.Date.Fri -> "friday" 320 | CalendarLib.Date.Sat -> "saturday" 321 | CalendarLib.Date.Sun -> "sunday" 322 in 323 Printf.sprintf "((%04d %02d %02d %s) (%02d %02d %02d))" y m d dow 324 h min s 325 | None -> "nil" 326 in 327 let location = 328 match Event.get_location e with 329 | Some loc -> Printf.sprintf "\"%s\"" (String.escaped loc) 330 | None -> "nil" 331 in 332 let description = 333 match Event.get_description e with 334 | Some desc -> Printf.sprintf "\"%s\"" (String.escaped desc) 335 | None -> "nil" 336 in 337 let calendar = 338 match Event.get_collection e with 339 | Some (Calendar_dir.Collection cal) -> 340 Printf.sprintf "\"%s\"" (String.escaped cal) 341 | None -> "nil" 342 in 343 let id = Event.get_id e in 344 Printf.sprintf 345 "((:id \"%s\" :summary \"%s\" :start (%s %s) :end %s :location %s \ 346 :description %s :calendar %s))" 347 (String.escaped id) (String.escaped summary) start_date start_time 348 end_str location description calendar 349 in 350 "(" ^ String.concat "\n " (List.map format_instance_sexp instances) ^ ")" 351 | _ -> 352 String.concat "\n" 353 (List.map (fun i -> format_instance ~format i) instances)