Emacs: jump to matching paren/beginning of block

Christian Kruse

One thing I always wanted for Emacs was a „jump to matching paren” button. And when I began to program Ruby, I also wanted a button to jump to the matching keyword when on end or to matching end when on a keyword. Well, lets first have a look at the „jump to matching paren” problem. This is relatively easy to solve since Emacs already has a function for that, so we only need a little bit of boilerplate:

(defun goto-match-paren (arg)  "Go to the matching  if on (){}[], similar to vi style of % "  (interactive "p")  ;; first, check for "outside of bracket" positions expected by forward-sexp, etc  (cond ((looking-at "[\[\(\{]") (forward-sexp))        ((looking-back "[\]\)\}]" 1) (backward-sexp))        ;; now, try to succeed from inside of a bracket        ((looking-at "[\]\)\}]") (forward-char) (backward-sexp))        ((looking-back "[\[\(\{]" 1) (backward-char) (forward-sexp))        (t nil)        )  )  

We basically check if we are on or behind a paren and jump to the matching one. Next: jump to matching keyword/end. This is also relatively easy to solve, since ruby-mode has the functions (ruby-beginning-of-block) and (ruby-end-of-block):

(defun goto-matching-ruby-block (arg)  (cond   ;; are we at an end keyword?   ((equal (current-word) "end")    (ruby-beginning-of-block))   ;; or are we at a keyword itself?   ((string-match (current-word) "\\(for\\|while\\|until\\|if\\|class\\|module\\|case\\|unless\\|def\\|begin\\|do\\)")    (ruby-end-of-block)    )   )  )  

Now, since we want to use the same hotkey for both functions we need a dispatching function:

(defun dispatch-goto-matching (arg)  (interactive "p")  (if (or       (looking-at "[\[\(\{]")       (looking-at "[\]\)\}]")       (looking-back "[\[\(\{]" 1)       (looking-back "[\]\)\}]" 1))      (goto-match-paren arg)    (when (eq major-mode 'ruby-mode)      (goto-matching-ruby-block arg)      )    )  )  

This function basically just looks if we are at a paren and calls (goto-matching-paren). If not and we're in ruby-mode, it calls (goto-matching-ruby-block). Now we bind this function to a key and tada! we can navigate very easily to the beginning or end of the block:

(global-set-key "\M--" 'dispatch-goto-matching)  

I must say, the more LISP I write the more I like it.