Configuring projects in org mode, or defining variables in Lisp is strange
Org mode in GNU Emacs makes it somewhat easy to publish its files as a small static website. You define the files to publish, how to convert them, where to publish them, and so on. The bad news is that you need to manually write a big data structure in Emacs Lisp. Not what a Lisp newbie really wanted to hear (no customize page?) but I decided org mode was worth the pain. Speaking of pain, here's the data structure:
0: (set 1: (quote org-publish-project-alist) 2: ' 3: ( 4: ( 5: "tsn" 6: :base-directory "~/Documents/foog/tsn" 7: :base-extension "org" 8: :publishing-directory "/dev/null" 9: :publishing-function org-publish-org-to-html 10: ) 11: ) 12: )
All that work just to define a list of lists? I could just write it in Ruby as:
# pretend this function exists in Ruby
# def org_publish_to_html() end
org_publish_project_alist = [
[ "tsn",
:base_directory, "~/Documents/foog/tsn",
:base_extension, "org",
:publishing_directory, "~/Documents/foog/tsn_export",
:publishing_function, org_publish_to_html ]
];
The major difference is all this
And now, we plunge through the rabbit hole!
So, why call the
(symbolp 123) => nil ;; nil is false in Emacs Lisp (symbolp (quote 123)) => nil ;; 123 passes through... (symbolp (quote "abc")) => nil ;; abc passes through (symbolp (quote foo)) => t ;; but foo is a symbol.
Okay, so now we can distinguish between a value and a reference. The next step is assigning a value to a reference. This is where
(set foo 123) => Lisp error: (void-variable foo)
That silly Lisp interpreter, trying to get a value while we are in the middle of setting it. That's where
(set (quote foo) 123) => 123 ;; No one does this (set 'foo 456) => 456 ;; 'foo = (quote foo) (setq foo 789) => 789 ;; People do this one.
INTERMISSION
Now that variable assignment has been hashed out we can pick up speed a bit and finish this off:
- Line 1 specifies the symbol we want to use.
- Line 2 is just a macro for
, so the contents will be returned without being evaluated.(quote)
- Line 3 starts a list. To me this implies that the variable
will contain an array of ... well, not sure yet.org-publish-project-alist
- Line 4 starts a list. This list will be the first item in the list defined by
.org-publish-project-alist
- Line 5 is just a string. It is the first element in the list. Calling
on the list started at line 4 would return "tsn".(car)
- Line 6 contains the 2nd and 3rd items in the list.
is a keyword symbol (:base-directory). "~/Documents/foog/tsn" is the next element in the list.(symbolp :base-directory) => t
- Lines 7-9 define the remnant of the list started at line 4.
- The remaining lines are the obligatory closing parens.
Probably because I am very new to Lisp I don't understand why flat lists are used to store this data. Key value pairs are a great fit for hash maps or associative lists (the variable name ends with alist...). My first attempt to restructure the data would be:
(setq org-projects
'(
("tsn"
(:base-directory . "~/Documents/foog/tsn")
(:base-extension . "org")
(:publishing-directory . "~/Documents/foog/tsn_export")
(:publishing-function . org-publish-org-to-html))
("css"
(:base-directory . "~/Documents/foog/tsn/css")
(:base-extension . "css"))
("img"
(:base-directory . "~/Documents/foog/tsn/images")
(:base-extension . "jpg|png"))
))
The difference being that key value pairs are stored in an associative list. This lets you take advantage of built in functions for getting property values.
(mapcar
(lambda (elt)
(let
((project (car elt))
(properties (cdr elt)))
(print (format "Project %s has base extension %s"
project
(cdr (assoc :base-extension properties))))))
org-projects)
Output: ("Project tsn has base extension org" "Project css has base extension css" "Project img has base extension jpg|png")
Wow, look at all the rambling. At least now I understand how to manually configure org mode's projects.
Lisp is neat.


