Elisp code for easily creating a new blog post

Nov 18, 2013

Another reason why I’ve been keeping off blogging is because each post needs to be in a certain format for poet to accept it. Here’s what this post looks like so far at my end:

    { { {
        "title": "Elisp code for easily creating a new blog post",
        "date": "11-17-2013",
        "time": "23:38:53",
        "tags": ["emacs", "elisp", "poet"]
    } } }
    Another reason why I've been keeping off blogging is because each post needs to be in a certain format for [poet](https://github.com/jsantell/poet) to accept it. Here's what this post looks like so far at my end:

As you can see, there’s a lot of “minutae” involved. I have to create a file in the posts folder, then enter all the fields in it, fill out the fields with proper values, figure out what the current date and time are.. Sure, it might not sound like much, but after spending an hour in the bus I really don’t feel like doing all this just to update my blog. So I set out to make things even easier, and came up with a couple of functions in elisp that will make my life easier. In particular, the only user-facing function at the moment is poet:new-post, to which I simply pass the title of the post in quotes, e.g. (poet:new-post "Elisp code for easily creating a new blog post"). And the the elisp function creates a new file in the correct folder (depending on whether I’m blogging from my office machine or my personal desktop), fills out the necessary fields, and positions the cursor at the point where I can start typing the content of the post. Really, really convenient. Next up will be using magit functions to add the new post to the current repo, make a new commit, and push the commit to my local staging server for testing and finally to my webserver.

Anyway, here are the functions I came up with. The poet:get-current-date function started off as a cond statement, but thankfully I remembered about assoc lists just in time.

(defvar poet-roots '("/home/amey/Developer/wirywolf/_posts"
               "/home/aparulekar/Developer/wirywolf/_posts"))

(defun poet:get-current-date ()
  (let ((months '(("Jan" . "1") ("Feb" . "2") ("Mar" . "3") ("Apr" . "4")
                  ("May" . "5") ("Jun" . "6") ("Jul" . "7") ("Aug" . "8")
                  ("Sep" . "9") ("Oct" . "10") ("Nov" . "11") ("Dec" . "12")))
    (month-string (substring (current-time-string) 4 7))
    (date-string (substring (current-time-string) 8 10))
    (year-string (substring (current-time-string) 20)))
    (format "%s-%s-%s" (cdr (assoc month-string months)) date-string year-string)))

(defun poet:get-current-time ()
  (substring (current-time-string) 11 19))

(defun poet:get-filename-from-title (title)
  (format "%s/%s.md"
      ;; The first lambda takes the second lambda as an argument, and then calls it
      ;; with the second lambda itself as the last argument.
      ;; The second lambda then uses this last argument for recursion.
      (funcall (lambda (get-poet-root paths) (funcall get-poet-root paths get-poet-root))
               (lambda (paths get-poet-root)
                 (cond ((not (car paths))
                        nil)
                       ((file-exists-p (car paths))
                        (car paths))
                       (t
                        (funcall get-poet-root (cdr paths) get-poet-root))))
               poet-roots)
      (replace-regexp-in-string "\-+$" ""
        (replace-regexp-in-string "^\-+" ""
          (replace-regexp-in-string "[^[:alpha:][:digit:]]" "-" (downcase title))))
  ))

(defun poet:new-post (title)
  (interactive)
  (let ((post-date (poet:get-current-date))
    (post-time (poet:get-current-time))
    (post-file (poet:get-filename-from-title title)))
    (with-current-buffer (find-file-noselect post-file)
      (switch-to-buffer (find-buffer-visiting post-file))
      (insert "{ { {\n")
      (insert (format "\t\"title\": \"%s\",\n" title))
      (insert (format "\t\"date\": \"%s\",\n" post-date))
      (insert (format "\t\"time\": \"%s\",\n" post-time))
      (insert (format "\t\"tags\": %s\n" "[]"))
      (insert "} } }\n\n")
      )))