Jack Kamm <[email protected]> writes: >> Ihor Radchenko <[email protected]> writes: >> >> I strongly suspect that reusing ox.el may end up being easier compared >> to custom templating solutions. Most parts of ox.el are pretty generic >> and can be applied to non-Org AST. And yes, ox.el does have templates. > > I was interested in this idea so made a prototype which I attach as a > patch. It converts the attached test-ics2org.ics to the attached > test-ics2org.org.
Nice! I'm glad this turned out to be as straightforward as I'd hoped. A couple of comments from me inline: > From 898701a786a165a4ac35338d88b8ee3f6e131dcf Mon Sep 17 00:00:00 2001 > From: Jack Kamm <[email protected]> > Date: Fri, 13 Mar 2026 15:43:00 -0700 > Subject: [PATCH] Prototype of ox-ics2org > ... > +(defun org-ics2org--vevent (vevent _contents info) > + "Transcoder that exports VEVENT as Org entry." > + (let* ((inner (org-element-contents vevent))) > + (concat > + "\n* " > + (org-export-data (assq 'icalendar-summary inner) info) > + ":PROPERTIES:\n" > + (string-join (org-element-map > + (org-element-contents vevent) > + org-ics2org--properties > + (lambda (prop) (org-export-data prop info)))) > + ":END:\n" > + (let* ((dtstart-node (assq 'icalendar-dtstart inner)) > + ;; FIXME: This only handles date-time, not date You can use `cl-typep' and `cl-typecase' to handle these cases separately. There are also a bunch of utility functions in icalendar-utils.el that provide a type-agnostic interface for common date functions. E.g. you can use `icalendar-date/time-weekday' instead of `decoded-time-weekday' in the code below so that it works with both dates and date-times. > + (dtstart-time (org-element-property > + :value (org-element-property > + :value dtstart-node))) > + (dtend-node (assq 'icalendar-dtend inner)) > + (dtend-time (and dtend-node (org-element-property > + :value (org-element-property > + :value dtend-node)))) > + (dtend-same-day-p (and dtend-time > + (equal (decoded-time-weekday dtstart-time) > + (decoded-time-weekday dtend-time)))) > + (rrule-node (assq 'icalendar-rrule inner)) > + (rrule-alist (and rrule-node (org-element-property > + :value (org-element-property > + :value rrule-node))))) The `icalendar-with-*' macros are intended to simplify code like this. I would write the bindings you're making here like this: (icalendar-with-component vevent ; or `inner'? not sure ((icalendar-dtstart :value dtstart-time) (icalendar-dtend :value dtend-time) (icalendar-rrule :value rrule-alist)) ...) > + (concat "<" > + (format-time-string (org-time-stamp-format t 'no-brackets) > + (encode-time dtstart-time)) > + (when dtend-same-day-p > + (format-time-string "-%H:%M" (encode-time dtend-time))) > + (when rrule-alist > + (let ((byday (cadr (assoc 'BYDAY rrule-alist)))) > + (if (or (not byday) > + (equal byday (list (decoded-time-weekday > dtstart-time)))) > + (format > + " +%d%s" > + (or (cadr (assq 'INTERVAL rrule-alist)) 1) > + (downcase > + (string-limit > + (symbol-name (cadr (assq 'FREQ rrule-alist))) > + 1))) > + ;; FIXME > + nil))) You should use the various `icalendar-recur-*' accessors to get the data out of an rrule value; the representation may not always be an alist. So: (when rrule-alist (let ((byday (icalendar-recur-by* 'BYDAY rrule-alist))) (if (or (not byday) (equal byday (list (icalendar-date/time-weekday dtstart-time)))) (format " +%d%s" (icalendar-recur-interval-size rrule-alist) (downcase (string-limit (symbol-name (icalendar-recur-freq rrule-alist)) 1))) ;; FIXME nil))) I might need to change the names of these accessors to make them more discoverable, since `icalendar-recur-' is also the prefix used in icalendar-recur.el. What do you think about `icalendar-rrule-' or `icalendar-recval-' instead? -- Best, Richard
