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

Reply via email to