Archive for August, 2013

M-x insert-c++-scope

Monday, August 12th, 2013

If you write C++ code like I do, when you add a new method to a class, you:

  1. type the function signature into the declaration in the header file;
  2. copy and paste it into the source file;
  3. either type in the name of the class by hand or hunt around looking for another instance of it to copy and paste in.

I finally got tired of step 3 and wrote a little Emacs Lisp code to semi-automate the process. It scans through the source file looking for things that look like scopes, presents you with a list of them to choose from (in descending order of frequency, so the one you’re most likely to want is first), and then inserts the one you choose.

Here it is:

(require 'ido)

;; Returns a list of all strings of the form "<x>::" in the current
;; buffer, sorted by decreasing frequency.
(defun all-c++-scopes-in-buffer ()
  (let ((scope-alist nil))
      (goto-char (point-min))
      (while (re-search-forward "\\w+::" nil t)
        (let* ((scope (match-string-no-properties 0))
               (ass (assoc scope scope-alist))
               (pair (if ass
                       (setq scope-alist (cons (cons scope 0) scope-alist))
                       (car scope-alist))))
          (setcdr pair (1+ (cdr pair)))))
      (mapcar 'car (sort scope-alist (lambda (x y) (> (cdr x) (cdr y))))))))

(defun insert-c++-scope ()
     (ido-completing-read "Insert scope: " (all-c++-scopes-in-buffer)))))

If you don’t use ido, then 1) you are nuts, and 2) you can just use completing-read instead of ido-completing-read.

Of course, I have this bound to a key rather than type M-x insert-c++-scope every time.

My Emacs Lisp is rusty, so I imagine that there’s a more idiomatic way to do this (no convenience function to look something up in an alist and automatically add a default pair to it if it’s not already there? really?), but it works, and makes the experience of writing C++ in Emacs a little more pleasant.