First, I apologise in advance (to all 3 of you subscribed) if you got an avalanche of old new posts in your RSS feed. I’ve just gone through and tagged a lot of posts.
What’s most interesting, at least for me, was that I did it en-masse via Emacs. This blog is a set of static files generated by Jekyll Bootstrap, as I have written about previously. A post is simply a file with a bit of YAML meta-data up the top, optionally including tags applying to that post:
--- layout: post title: "Sample yaml front-matter" tags: [SomeTag,AnotherTag] --- Body of the post...
To simplify the repetitive work involved I wrote some elisp to take a bunch of files, query for the relevant tags, and add them to the front matter:
(defun mh/tag-posts (tags) "Apply tags (specified interactively) to the files marked in dired, merging with existing tags. Assumes the use of jekyll-bootstrap, ie with the `---' delimited yaml front-matter at the beginning." (interactive (list (read-from-minibuffer "Tag(s), comma-separated: "))) (let ((tags (split-string tags "[, ]+"))) (labels ((do-tags (f) (with-current-buffer (find-file-noselect f) (save-excursion (goto-char 0) (if (re-search-forward "^tags: \\[\\([[:alnum:], ]*\\)\\]" nil t) (let* ((existing-tags (split-string (match-string 1) "[, ]+")) (combined (union existing-tags tags)) (new-tags (mapconcat 'identity combined ","))) ;; replace-match wasn't working for some reason: (goto-char (match-beginning 1)) (delete-region (match-beginning 1) (match-end 1)) (insert new-tags)) (progn (goto-char 0) (forward-line 1) (re-search-forward "^---" nil t) ; find second occurence, assuming first is on line 1 (goto-char (match-beginning 0)) (insert (format "tags: [%s]\n" (mapconcat 'identity tags ",")))))) (save-buffer)))) (mapcar #'do-tags (dired-get-marked-files)))))
The guts are in the last line: I mark files using
in Emacs, then invoke
mh/tag-posts, which applies a function to
every marked file. This function then just has to take care of a few
corner cases such as the tag already being included (by using
cl common lisp emulation library to avoid repetition), and
when there’s no
tags:  entry at all, in which case it must add