Emacs Calendar Extension – Information Unity (Part 3)
Ok, this post should wrap up the series – finally. Sorry it’s taken me a while, but got caught up in life for a bit…
To summarize what we’ve covered so far, I figured out how to get a iCal file imported into Emacs calendaring system, remove duplicates, and do a little post-processing in order to get it looking the way I wanted.
Up to this point, it’s all been manual calls with
eval-region and that just won’t cut it! We need an Emacsian way of both a) Automatically running this code on start up (which the provided functions can already handle, and b) Being able to manually re-execute at any time via Emacsian means.
The running on start up, as I’ve said, is already handled via normal elisp code execution. We really just need to enable that same functionality through manual Emacs interaction.
Looking through documentation and many blog posts I discovered how to interact with the Emacs system – and it’s actually pretty simple. You only have to do a couple of things, actually:
defuna standard lisp method.
- Include the
interactiveform (of which there are varying arguments it takes based on the required functionality.
- From within this form make calls out to the forms that we already created for importing an iCal
The interactive form args accepts a ton of different values, but for the purposes of this discussion, I’m only going to cover what we’re using. Feel free to check out the docs for more information.
The following code gives us the functionality that we’re looking for – and is actually straightforward (even if it doesn’t look like it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
(defun manual-import-remote-ical (url-key) "Imports an ICS calendar from a URL into the diary" (interactive (list (completing-read "Choose pre-configured calendar: " (mapcar 'car my-ical-calendars-alist)))) (setq url-key (car(assoc url-key my-ical-calendars-alist))) (setq url-val (car(cdr(assoc url-key my-ical-calendars-alist)))) (if (boundp 'diary-file) (progn (message "Calendar to import: %s from %s" url-key url-val) (import-remote-ical url-val diary-file) ) (message "my-diary-file is not defined - aborting import for: %s" url-key) ) )
Now for some explanation: The
interactive form, in essence – in this instance – accepts a list, from which it will allow the user to choose – via Emacs’ minibuffer – a value from a predefined list of values.
completing-read form takes a string used for a display prompt, and a list of values. As you can see we’re using our trusty
mapcar form in order to pull all the keys from our alist, my-ical-calendars-alist, which is supplied to completing-read. The
manual-import-remote-ical‘s argument, url-key, is populated with the key chosen via interactive – which we then use in the ensuing code.
Nice! Now we can simply choose from the minibuffer which calendar to import without all the URL entering fuss.
We then use an Emacs form for printing a message to the user and then call our non-interactive calendar import method, import-remote-ical, with it’s required arguments – no muss, no fuss!
That takes care of the interactive, manual calendar loading. Now all we need to do is have Emacs do all this automatically on start up.
This is all very simple – we already have an alist of calendars – we just need to add more calendars to it. Once that is complete, we just need to cycle over the alist and call import-remote-ical on each. The following code is pretty self explanatory and does just that:
1 2 3 4 5 6 7 8 9 10
(defun import-all-remote-ical (my-ical-alist my-diary-file) "Imports all ical urls defined in ical-alist into my-diary-file, removing duplicates" (message (car(car my-ical-calendars-alist ))) (dolist (url-list-item my-ical-calendars-alist) (progn (message "Importing %s from %s" (car url-list-item) (car(cdr url-list-item))) (import-remote-ical (car(cdr url-list-item)) my-diary-file) ) ) )
Simple, simple. And that’s basically that.
This is a good example of how I learn new languages. I find a fairly simple problem that I want to solve and search for ways to solve it in my new language of choice.
In case you haven’t realized it, this little project has taught us a ton of Lisp and ELisp concepts – lists, alists, getting objects from lists, calling interactive methods in Emacs, standard means of iterating lists, running a function over every element of a list, creating functions, etc, etc, etc. It’s truly incredible how much you can learn when trying to do something so simple!