How I Wrote an Emacs Blog Client (And Lived to Tell the Tale)
As I hinted in my last post, I wrote it from within Emacs. This entry, too, is being composed in the text editor extrordinaire. This shouldn’t come as much of a surprise. There are clients out there for Blogger, Livejournal, the more generic Atom API, and probably others well.
What’s cool about it, though, is that my blog is neither hosted by a blog host, nor does it implement Atom. I had to write my blog-from-Emacs code from scratch. This is my story.
What first inspired me to write the Emacs-blog-poster was a snazzy Emacs Textile-mode which I happened across and installed. I write my blog posts in Textile, so the prospect of having them syntax-highlighted, not to mention not having to deal with Firefox’s text area UI1, was pretty cool.
For a while, I’d write my entries in Emacs, then copy them over to the textbox to preview them. Then I’d switch back to Emacs to make any edits I needed to, then copy it back to the webpage, over and over again.
This was okay, but it got tedious, and it was a pain to deal with the idiosyncrasies between Emacs’s and Gnome’s different copy-paste mechanisms. Emacs behaves in the traditional X window system manner: if you highlight or delete text, it’s added to the clipboard.
This doesn’t disrupt Gnome’s more Mac- and Windows-style Control+C schema, because they copy to different clipboards. Highlighting text won’t get rid of whatever you last C-c’d.
However, most of the time I wanted to replace the text in the blog post text area, so I could preview the new stuff. Normally, I’d select all then paste over it. Unfortunately, selecting all then added that to the same clipboard the blog post was on.
This got to be enough of a pain that I decided to be a good programmer and just automate the thing. “It shouldn’t be too hard,” thought I, “my blog is RESTful2 anyway. A few HTTP requests and I should be golden.”
Not being eager to write my own ELisp HTTP library, let alone having any idea how to do so, I looked around to see what already existed. Lo and behold, I found http-emacs. It wasn’t ideal, but all I really needed was the ability to shove data at a website, and this provided that.
The general interface for posting data was a function called http-post.
Keeping in mind that in Lisp syntax,
(foo bar baz) means “call the function foo with arguments bar and baz,”
let’s look at how it works:
(http-post URL PARAMETERS ENCODING)
PARAMETERS was an assoc list3 of parameters to send to the website,
the same sort you’d send if you submitted, say, an HTML form.
So to post the same data as my HTML form,
I just had to set the same parameter names4:
post[title] and post[content].
I came up with a very basic function
to post the text I’m currently editing to the server.
Since I didn’t want any tests I made actually showing up on the real blog,
I pointed it to http://localhost:3000/,
where I was running my local development copy of my blog.
(defun post-blog-entry () "Post an entry to my blog" (interactive) (http-post "http://localhost:3000/posts" (list (cons "post[title]" (read-from-minibuffer "Post title: ")) (cons "post[content]" (buffer-string))) 'utf-8))
Let’s walk through this.
I’m defining a function called post-blog-entry
that takes no arguments.
The first line is a docstring;
it’s a string documenting the function.
The ELisp runtime notices these
and associates them with the function,
so that one can look them up via C-h f5.
The next line, (interactive),
tells Emacs that this function should be callable by the user.
The user can type M-x FUNCTION-NAME to call any interactive function.
Then comes the call to http-post.
The URL is pretty straightforward.
When I post information to /posts,
my blog software knows to make it into a new post and save it.
All that stuff with list and cons is just constructing the assoc list.
The upshot of it is that we’re posting the post[title] and post[content] parameters.
The title is assigned to a value read from the minibuffer
(the one-line area down at the bottom of Emacs),
and the content is assigned to the current contents of the file being edited.
Presumably, this is the blog post.
That little 'utf-8 bit at the bottom might be a bit confusing to non-Lispers.
It’s just a symbol.
Lisp symbols are the same as those in Ruby,
except that they begin with an apostrophe instead of a colon.
I gave my newborn function a try and, as so often happens with just-written functions, it failed. The problem wasn’t actually my function; it was my stupidity. I had forgotten that in order to post to my blog, I needed proper credentials. The server needed to know I was who I said I was.
The way this is accomplished through the HTML interface is with a session cookie. When a browser first visits my blog, the blog sends a unique cookie that identifies that browser. This browser then notifies the server of the cookie every time it goes to a new page, and the server uses that to figure out which user the browser request is being made by6.
When I sign in, the server is able to remember me via cookies. Then, when I try to make a post, it thinks, “Oh, that cookie belongs to a guy who’s allowed to post” and doesn’t make a fuss.
I tried to get this working with http-emacs, but its cookie module was still experimental. Unfortunately, this appeared to mean that it flat-out didn’t work.
I decided the easiest thing to do would be to leave Lisp-world for a little
and modify the server code.
I decided I’d make it possible to do a one-time-only login
using additional parameters: admin[name] and admin[pass].
If the requester, in this case my Emacs function, didn’t have a cookie set,
the server would check for the presence of these parameters
and attempt to log the user in with those.
This ended up being pretty simple to implement; it ended up being six more meaningful lines of code. I then went and added these parameters to my function:
(defun blog-post-entry () "Post an entry to my blog" (interactive) (http-post "http://localhost:3000/posts" (list (cons "post[title]" (read-from-minibuffer "Post title: ")) (cons "post[content]" (buffer-string)) (cons "admin[pass]" (read-passwd "Password: ")) (cons "admin[name]" "Nathan")) 'utf-8))
I didn’t want my password sitting around in a plaintext configuration file,
so I used read-passwd to read it from the user.
read-passwd works just like read-from-minibuffer,
except that it replaces all characters with periods.
After that, the function finally worked;
I was able to post my blog entries from Emacs.
After trying it out, I decided to switch the name around from
post-blog-entry to blog-post-entry.
This was partly because it’s better ELisp style to have a “namespace” word first,
but mostly because more functions began with “pos” than with “blo”,
so tab completion worked better this way.
I actually spent a fair amount of time polishing the function after I got the bare bones working; I made it more user-friendly, had it open the new post in Firefox, and even managed to get it to preview the rendered document (that one was quite tricky).
However, it’s 1:00 AM here in Seattle, and I’m tired, so I’m gonna call it a post and use my snazzy function to send it off to the blog. Let me know in the comments if you enjoyed this; if so, I could definitely continue it in a future post.
1 Don’t get me wrong, the text area UI is great for what it is. But lacking all my special Emacs keybindings just sucks for writing long blocks of text, such as blog posts.
2 For those of you who don’t know and don’t care what REST is, it pretty much just means that it’s easy to get information from and send information to a website using only normal URLs. For those of you who do care, I unfortunately don’t know any good introductions to REST. I’ll try to write one up at some point.
3 An assoc list is a list of pairs of data.
It’s used to link together keys and values,
in a similarly to a Ruby hash or a Python dict.
They’re represented as ((key1 . value1) (key2 . value2)).
4 A nifty thing about Rails:
parameters of the form foo[bar]
are automatically converted into hashes.
So if you submit foo[bar] as “Grumblesnakes,”
the parameters hash will be
{"foo" => {"bar" => "Grumblesnakes"}}.
5 I’m here using the Emacs style of denoting shortcut keys. C stands for Control; M stands for Meta, or Alt on modern keyboards. C-h f means Control+H followed by F.
6 Thankfully, Rails handles this almost entirely behind the scenes.
About Me
Feed
Why I Use Antimacs



For the record: Edward O’Connor posted a comment suggesting I check out the
urlpackage, as it’s included in the main distribution as of Emacs 22. I replied saying that I would check it out, and that I was dissatisfied withhttp-emacs’ UI.Then I accidentally deleted the comments while futzing around with spam without making backups. Clever me.
Set x-select-enable-clipboard to make Emacs copy to the clipboard.
If you use firefox, there is an extension, It’s All Text! https://addons.mozilla.org/en-US/firefox/addon/4125 quote: “Edit textareas using an external editor”
So, when you save content in emacs buffer, it appears in textareas soon without copy-and-paste.
Daniel: Then all my Emacs selections end up in the clipboard. Ideally I’d have something separate from normal deleting-and-yanking that copies to and pastes from the clipboard. I’m sure this is possible (I think cua-mode does something similar), I just haven’t gotten around to figuring it all out.
Liang: Cool! I’ll have to check that out. I think I still prefer my client, though, just because it allows me to seamlessly move from whatever I was doing in Emacs before to writing a blog entry without mucking about in a browser.
Nathan, you got it. You can find these commands with M-x apropos RET clipboard RET.
Sweet! Off to edit my
.emacs...For those curious, here are my modifications:
I defined my own yank function because the built-in one,
x-clipboard-yank, yanks from Emacs’ kill ring if something had been killed after the most recent copy. I wanted it to only yank from the X clipboard.I bound them to
C-vandC-zbecause I use the arrows and such for navigation (I know, I know), and because I hate it minimizing when I missC-xso I didn’t haveC-zbound anyway.Arent you transmitting the password as plaintext over the line? I believe using “read-passwd” only solved half the problem. I’m not an expert on this topic, but wouldnt using https rather than http solve this insecurity?
Yes, that’s true. SSL is kind of a pain to set up on the server side, so I haven’t gotten around to it. Also, I don’t think
http-emacssupports SSL, so I’d also have to switch over tourl.el. Since I’m lazy and I have diverse passwords, I haven’t really worried about it much.Yes! I’m trying to figure out a good way to deal with blog posts, and while textmate does a decent job of it, I’d really like to have emacs do the trick. Definitely post your full implementation, especially once you have url.el working for secure password transmission. (That was my first thought too!)
Also: have you thought about being able to pull down and re-edit? Not even sure how to do this, likely something with xmlrpc but I don’t know it well enough. I’m also using wordpress, so perhaps none of this will work.
Thanks for the notes!
Kai: I’ll be sure to post the new version when I get around to making it. Pulling down entries should be trivial if I expose a JSON-formatted document or something, and pushing them up already works with the current RESTful API. Wordpress is probably different, though.
I’m also trying to make Emacs interface with a RESTful blog, but I’m using url.el. I’m having trouble with the Lisp, though. From url.el:
I think I can help you just from general Elisp experience.
callbackprobably wants a function that will be called when the URL is retrieved. Since Emacs has separate variable and function namespaces, if you wanted to pass a functionfoo, you’d call it like(url-retrieve url 'foo)passing the function name as a symbol.I finally got it using http-post-simple.el
Here’s my code:(require 'http-post-simple) (require 'url-auth) (defun blog-post () (interactive) (url-auth-user-prompt "http://blogurl.com/admin/" "") (http-post-simple "http://blogurl.com/admin/posts" (append(get-parms)))) (defun get-parms () (list (cons 'post%5Bbody%5D (buffer-string)) (cons 'post%5Btitle%5D (read-from-minibuffer "Post title: "))))Thanks for the help :)