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)