null program

Emacs UUIDs

Yesterday Luke pointed out an interesting idea by Jeff Atwood: mark code snippets you post online with a UUID. That way it's easy to find other places where code snippets have been used, and it's easier to find updates. It's a neat idea that I might start using.

So, the next problem is where to get a UUID. One place to get one is createguid.com, which will serve you up a fresh version 4 UUID each visit. But I don't like relying on the Internet for something when I don't need to. This is why I sometimes make wget backups of my favorite sites, in case they ever disappear. By design it's easy to generate your own UUIDs, and you have 5 algorithms to choose from, so I'll make my own.

Since I'll always be in Emacs when I need one, I'll just have Emacs do it. However, it's a bit tricky to do in Emacs. The pseudo-random number generator isn't very good. It's always initialized to the same seed when it starts, so it's up to the user to reseed somewhere. There's no direct way to read from /dev/urandom, instead relying on an external process to feed it in. Relying on /dev/urandom is also not portable. There's also no simple, portable way to find out hardware information about the machine, such as MAC address, required by some versions of the UUID algorithms. Elisp integers are a few bits smaller than native integers (29-bits on 32-bit systems), so the UUID has to be handled in very small pieces.

I was beginning to work on my own when I found this great solution by Martin Blais (mirror). Specifically the uuid-simple function, which takes an MD5 hash of unique data in Emacs and uses it for the UUID. I believe this may count as a version 3 UUID (or at least close enough that I don't care). I modified it slightly, adding more unique data and a version number.

;; ID: 90aebf38-b33a-314b-1198-c9bffea2f2a2
(defun uuid-create ()
  "Return a newly generated UUID. This uses a simple hashing of variable data."
  (let ((s (md5 (format "%s%s%s%s%s%s%s%s%s%s"
                        (user-uid)
                        (emacs-pid)
                        (system-name)
                        (user-full-name)
                        user-mail-address
                        (current-time)
                        (emacs-uptime)
                        (garbage-collect)
                        (random)
                        (recent-keys)))))
    (format "%s-%s-3%s-%s-%s"
            (substring s 0 8)
            (substring s 8 12)
            (substring s 13 16)
            (substring s 16 20)
            (substring s 20 32))))

This returns a string containing the UUID. Next, make an interactive function to wrap it,

(defun uuid-insert ()
  "Inserts a new UUID at the point."
  (interactive)
  (insert (uuid-create)))

I bound this to "C-x !", which wasn't yet bound to anything.

(global-set-key <span class="string">"\C-x!"</span> 'uuid-insert)

Instant UUIDs in Emacs.

tags: [ emacs lisp ]
blog comments powered by Disqus
Fork me on GitHub