NavigatingParentheses

A balanced expression is an expression starting with an opening delimiter, and ending with the matching closing delimiter, given by the syntax table. This syntax table depends on the mode currently activated. In lisp-mode, for example, parentheses () and brackets [] are delimiters, whereas braces {} are just symbol constituents. The EmacsSyntaxTable of the current mode can be displayed by typing C-h s or F1 s.

See ParenthesisMatching for details concerning the syntax table. You will find there how to add or remove pair of delimiters from the syntax table.

Such an expression is called a sexp. Strings, symbols and numbers are also often considered as sexp, depending on the current mode.

Navigating over balanced expressions

A balanced expression can be a parenthetical group, a number, a word or a symbol. The precise definition of a balanced expression may depend on the current mode. Here is how to move from a balanced expression to another:

Here are a number of shortcuts for dealing with sexp:

  C-M-n     forward-list  Move forward over a parenthetical group 
  C-M-p     backward-list  Move backward over a parenthetical group 
  C-M-f     forward-sexp Move forward over a balanced expression
  C-M-b     backward-sexp  Move backward over a balanced expression
  C-M-k     kill-sexp  Kill balanced expression forward
  C-M-SPC   mark-sexp  Put the mark at the end of the sexp.

Here is a short example; let us consider the following sexp in text mode:

    (with-current-buffer "foo.tex" (insert " \\emph{first chapter} "))

If the cursor is before the first parenthesis, C-M-f puts it right after the last parenthesis. With cursor on the word current, C-M-f puts it at the end of the word buffer. If cursor is on the first “ character, C-M-f puts it just in front of the . character. Indeed, “ is not an open delimiter, so the cursor only moves forward one word. The { character howewer is recognized as a delimiter and the cursor will jump just after the corresponding }.

Now if we want to remove the second parenthesized group, when the cursor is on the parenthesis at the beginning of this group, we just type C-M-k. If we want to put it in the kill ring without removing it, we first type C-M-SPC, followed by M-w. We can then yank it somewhere else with the usual command C-y.

These commands see nothing but parentheses (according to the syntax table; {} are considered as parentheses in text-mode for example).

Let us return to the example of the previous section. With cursor on the word current, C-M-f puts it at the end of the word buffer, because with-current-buffer is considered as an sexp in text-mode. On the other hand, C-M-n puts the cursor in front of the last parenthesis. That is, the cursor jumped over the next parenthesis group, given by (insert " \\emph{first chapter} ").

Emulation of the vi % command

This code from http://emacro.sourceforge.net/ gives a vi-like way of moving over parenthesis groups. I bind it to C-%, from vi heritage.

(defun goto-match-paren (arg)
  "Go to the matching parenthesis if on parenthesis, otherwise insert %.
vi style of % jumping to matching brace."
  (interactive "p")
  (cond ((looking-at "\\s\(") (forward-list 1) (backward-char 1))
        ((looking-at "\\s\)") (forward-char 1) (backward-list 1))
        (t (self-insert-command (or arg 1)))))

Alternative method with added flexibility

This modification of the above code works when the point is either right before or right after a parenthesis character, and also works with shift-selection. Note: when you are in a cluster of nested sexps, the default association is with the bracket that you are immediately outside of, to match the behavior of forward-sexp and backward-sexp.

(defun forward-or-backward-sexp (&optional arg)
  "Go to the matching parenthesis character if one is adjacent to point."
  (interactive "^p")
  (cond ((looking-at "\\s(") (forward-sexp arg))
        ((looking-back "\\s)" 1) (backward-sexp arg))
        ;; Now, try to succeed from inside of a bracket
        ((looking-at "\\s)") (forward-char) (backward-sexp arg))
        ((looking-back "\\s(" 1) (backward-char) (forward-sexp arg))))

Another method for vi emulation of the % command

You could also bind a modified version of the first command to the “%” key:

(defun goto-match-paren (arg)
  "Go to the matching parenthesis if on parenthesis AND last command is a movement command, otherwise insert %.
vi style of % jumping to matching brace."
  (interactive "p")
  (message "%s" last-command)
  (if (not (memq last-command '(
                                set-mark
                                cua-set-mark
                                goto-match-paren
                                down-list
                                up-list
                                end-of-defun
                                beginning-of-defun
                                backward-sexp
                                forward-sexp
                                backward-up-list
                                forward-paragraph
                                backward-paragraph
                                end-of-buffer
                                beginning-of-buffer
                                backward-word
                                forward-word
                                mwheel-scroll
                                backward-word
                                forward-word
                                mouse-start-secondary
                                mouse-yank-secondary
                                mouse-secondary-save-then-kill
                                move-end-of-line
                                move-beginning-of-line
                                backward-char
                                forward-char
                                scroll-up
                                scroll-down
                                scroll-left
                                scroll-right
                                mouse-set-point
                                next-buffer
                                previous-buffer
                                )
                 ))
      (self-insert-command (or arg 1))
    (cond ((looking-at "\\s\(") (forward-list 1) (backward-char 1))
          ((looking-at "\\s\)") (forward-char 1) (backward-list 1))
          (t (self-insert-command (or arg 1))))))

When your last command is a movement command, and your cursor is at a parenthesis, then it emulates vi’s % command. Otherwise it just types the % in the current buffer.

 - MLF

Additional ways to match parentheses

A popular approach is to use a single function button to bounce between parentheses. Here is a self-explanatory excerpt from my .emacs:

   (defun match-parenthesis (arg)
     "Match the current character according to the syntax table.
   Based on the freely available match-paren.el by Kayvan Sylvan.
   I merged code from goto-matching-paren-or-insert and match-it.
   You can define new \"parentheses\" (matching pairs).
   Example: angle brackets. Add the following to your .emacs file:
   	(modify-syntax-entry ?< \"(>\" )
   	(modify-syntax-entry ?> \")<\" )
   You can set hot keys to perform matching with one keystroke.
   Example: f6 and Control-C 6.
   	(global-set-key \"\\C-c6\" 'match-parenthesis)
   	(global-set-key [f6] 'match-parenthesis)
   Simon Hawkin <cema@cs.umd.edu> 03/14/1998"
     (interactive "p")
     (let
         ((syntax (char-syntax (following-char))))
     (cond
      ((= syntax ?\()
       (forward-sexp 1) (backward-char))
      ((= syntax ?\))
       (forward-char) (backward-sexp 1))
      (t (message "No match"))
      )
     ))

Discussion in [1]

I use a modified version. If triggered between parentheses it will bounce back to the opening parenthesis instead of triggering an error and it will jump to one char after the closing parenthesis and thus match the highlighting of show-paren-mode. ( [1 [x y] cursor 3] ? cursor[1 [x y] 3] ? [1 [x y] 3]cursor )

   (defun goto-match-paren (arg)
     "Go to the matching parenthesis if on parenthesis. Else go to the
   opening parenthesis one level up."
     (interactive "p")
     (cond ((looking-at "\\s\(") (forward-list 1))
           (t
            (backward-char 1)
            (cond ((looking-at "\\s\)")
                   (forward-char 1) (backward-list 1))
                  (t
                   (while (not (looking-at "\\s("))
                     (backward-char 1)
                     (cond ((looking-at "\\s\)")
                            (message "->> )")
                            (forward-char 1)
                            (backward-list 1)
                            (backward-char 1)))
                     ))))))

Strict parenthesis matching

It should be noted that the syntax-table makes all delimiters “even”. That means that a beginning parenthesis ( may match a closing bracket ] if the delimiters are not balanced as a whole. Try C-M-f on the following expression:

     (  [   )  ]

Here is a short piece of Lisp code in which such a situation occurs:

  (while
     (re-search-forward "\\(\\[[0-9]\\),\\([0-9]\\]\\)" nil t)
     (replace-match (concat (match-string 1) "." (match-string 2))))

This code replaces, e.g. [4,5] by [4.5]. Now, in the regular expression between quotes " ", the first opening bracket [ matches the first closing parenthesis ), whereas the last opening parenthesis ( matches the last closing bracket ]. This is a bit surprising at first sight.

Some people consider such behaviour as uncorrect, and have devised new matching commands to ensure that a starting ( is always matched by a closing ). The following code comes from the gnu-emacs-help archive [2] and provides a new definition for the forward-sexp command, which is bound by default to C-M-f. Note that these commands do not rely on the syntax table, which may be seen as a limitation.

  (defun skip-string-forward (&optional limit)
     (if (eq (char-after) ?\")
         (catch 'done
           (forward-char 1)
           (while t
             (skip-chars-forward "^\\\\\"" limit)
             (cond ((eq (point) limit)
                   (throw 'done nil) )
                   ((eq (char-after) ?\")
                   (forward-char 1)
                   (throw 'done nil) )
                   (t
                   (forward-char 1)
                   (if (eq (point) limit)
                        (throw 'done nil)
                      (forward-char 1) ) ) ) ) ) ) )
   
   (defun skip-string-backward (&optional limit)
     (if (eq (char-before) ?\")
         (catch 'done
           (forward-char -1)
           (while t
             (skip-chars-backward "^\"" limit)
             (if (eq (point) limit)
                 (throw 'done nil) )
             (forward-char -1)
             (if (eq (point) limit)
                 (throw 'done nil) )
             (if (not (eq (char-before) ?\\))
                 (throw 'done nil) ) ) ) ) )
   
   (defun forward-pexp (&optional arg)
     (interactive "p")
     (or arg (setq arg 1))
     (let (open close next notstrc notstro notstre depth pair)
       (catch 'done
         (cond ((> arg 0)
                (skip-chars-forward " \t\n")
                (if (not (memq (char-after) '(?\( ?\[ ?\{ ?\<)))
                   (goto-char (or (scan-sexps (point) arg) (buffer-end arg)))
                  (skip-chars-forward "^([{<\"")
                  (while (eq (char-after) ?\")
                   (skip-string-forward)
                   (skip-chars-forward "^([{<\"") )
                  (setq open (char-after))
                  (if (setq close (cadr (assq open '( (?\( ?\))
                                                      (?\[ ?\])
                                                      (?\{ ?\})
                                                      (?\< ?\>) ) ) ) )
                      (progn
                        (setq notstro (string ?^ open ?\")
                              notstre (string ?^ open close ?\") )
                        (while (and (> arg 0) (not (eobp)))
                          (skip-chars-forward notstro)
                          (while (eq (char-after) ?\")
                           (if (eq (char-before) ?\\)
                                (forward-char 1)
                              (skip-string-forward) )
                           (skip-chars-forward notstro) )
                          (forward-char 1)
                          (setq depth 1)
                          (while (and (> depth 0) (not (eobp)))
                           (skip-chars-forward notstre)
                           (while (eq (char-after) ?\")
                              (if (eq (char-before) ?\\)
                                  (forward-char 1)
                                (skip-string-forward) )
                              (skip-chars-forward notstre) )
                           (setq next (char-after))
                           (cond ((eq next open)
                                   (setq depth (1+ depth)) )
                                  ((eq next close)
                                   (setq depth (1- depth)) )
                                  (t
                                   (throw 'done nil) ) )
                           (forward-char 1) )
                          (setq arg (1- arg) ) ) ) ) ) )
               ((< arg 0)
                (skip-chars-backward " \t\t")
                (if (not (memq (char-before) '(?\) ?\] ?\} ?\>)))
                   (progn
                      (goto-char (or (scan-sexps (point) arg) (buffer-end arg)))
                      (backward-prefix-chars) )
                  (skip-chars-backward "^)]}>\"")
                  (while (eq (char-before) ?\")
                   (skip-string-backward)
                   (skip-chars-backward "^)]}>\"") )
                  (setq close (char-before))
                  (if (setq open (cadr (assq close '( (?\) ?\()
                                                      (?\] ?\[)
                                                      (?\} ?\{)
                                                      (?\> ?\<) ) ) ) )
                      (progn
                        (setq notstrc (string ?^ close ?\")
                              notstre (string ?^ close open ?\") )
                        (while (and (< arg 0) (not (bobp)))
                          (skip-chars-backward notstrc)
                          (while (eq (char-before) ?\")
                           (if (eq (char-before (1- (point))) ?\\)
                                (forward-char -1)
                              (skip-string-backward) )
                           (skip-chars-backward notstrc) )
                          (forward-char -1)
                          (setq depth 1)
                          (while (and (> depth 0) (not (bobp)))
                           (skip-chars-backward notstre)
                           (while (eq (char-before) ?\")
                              (if (eq (char-before (1- (point))) ?\\)
                                  (forward-char -1)
                                (skip-string-backward) )
                              (skip-chars-backward notstre) )
                           (setq next (char-before))
                           (cond ((eq next close)
                                   (setq depth (1+ depth)) )
                                  ((eq next open)
                                   (setq depth (1- depth)) )
                                  (t
                                   (throw 'done nil) ) )
                           (forward-char -1) )
                          (setq arg (1+ arg)) ) ) ) ) ) ) ) ))
   
   (setq forward-sexp-function 'forward-pexp)

Smartparens

Smartparens package provides additional functions for navigating and manipulating strictly balanced expressions. Here’s a short list of some mentioned on this page, all of them (and the rest) are described in the readme file on github page.

  • sp-forward-sexp (&optional arg) ;; C-M-f
  • sp-backward-sexp (&optional arg) ;; C-M-b
  • sp-down-sexp (&optional arg) ;; C-M-d
  • sp-backward-down-sexp (&optional arg) ;; C-M-a
  • sp-up-sexp (&optional arg) ;; C-M-e
  • sp-backward-up-sexp (&optional arg) ;; C-M-u
  • sp-next-sexp (&optional arg) ;; C-M-n
  • sp-previous-sexp (&optional arg) ;; C-M-p

Besides working on strictly balanced expressions, they also work on arbitrarily complex user-defined pairs. They also never signal the “scan error” as the built-in functions but instead perform a “natural” operation like jumping out of the list one level up (with sp-forward-sexp) etc.

How to find next delimiter

You can match delimiters with the help of regular expressions. Recall that C-M-s is the shortcut for incremental search based on regular expression. The following is available in regular expressions.

  \s(    matches an open delimiter
  \s)    matches a closing delimiter
  
  \S(    matches anything but an open delimiter
  \S(    matches anything but a closing delimiter

So, C-M-s RET \s( will highlight all opening delimiters. You can then hit C-M-s repeatedly to jump from one delimiter to the next.

A reminder: double escape is needed when using these expressions in Lisp code, e.g. \\s(

Other ways to handle parentheses and delimiters

Several other means have been devised to jump from parentheses to parentheses. Some are described below. Other can be found in ParenthesisMatching.

I made it by myself. Now I got it. :-)

      (defun move-forward-paren (&optional arg)
       "Move forward parenthesis"
        (interactive "P")
        (if (looking-at ")") (forward-char 1))
        (while (not (looking-at ")")) (forward-char 1))
      ) 
      
      (defun move-backward-paren (&optional arg)
       "Move backward parenthesis"
        (interactive "P")
        (if (looking-at "(") (forward-char -1))
        (while (not (looking-at "(")) (backward-char 1))
      ) 
      
      (defun move-forward-sqrParen (&optional arg)
       "Move forward square brackets"
        (interactive "P")
        (if (looking-at "]") (forward-char 1))
        (while (not (looking-at "]")) (forward-char 1))
      ) 
      
      (defun move-backward-sqrParen (&optional arg)
       "Move backward square brackets"
        (interactive "P")
        (if (looking-at "[[]") (forward-char -1))
        (while (not (looking-at "[[]")) (backward-char 1))
      ) 
      
      (defun move-forward-curlyParen (&optional arg)
       "Move forward curly brackets"
        (interactive "P")
        (if (looking-at "}") (forward-char 1))
        (while (not (looking-at "}")) (forward-char 1))
      ) 
      
      (defun move-backward-curlyParen (&optional arg)
       "Move backward curly brackets"
        (interactive "P")
        (if (looking-at "{") (forward-char -1))
        (while (not (looking-at "{")) (backward-char 1))
      ) 

These are my key bindings for these functions

       (global-set-key (kbd "M-)")           (quote move-forward-paren))
       (global-set-key (kbd "M-(")           (quote move-backward-paren))
      
       (global-set-key (kbd "M-]")           (quote move-forward-sqrParen))
       (global-set-key (kbd "M-[")           (quote move-backward-sqrParen))
      
       (global-set-key (kbd "M-}")           (quote move-forward-curlyParen))
       (global-set-key (kbd "M-{")           (quote move-backward-curlyParen))
  

I modified my global key binding. Replaced Ctrl with Meta here because C-[ will make Emacs behave quite strangely. Although some default key bindings are overrided, but it’s OK to me

DoveYoung

Answer: In some environments, C-[ is equivalent to Esc, just like C-i is equivalent to TAB. To distinguish between them, I once used this code:

 ;; This explicitly creates a separate binding for <tab>, so it doesn't conflict with C-i.
 (global-set-key [tab] (or (key-binding [tab]) (key-binding "\C-i")))

Also look here: http://stackoverflow.com/questions/1792326/how-do-i-bind-a-command-to-c-i-without-changing-tab

RaffaeleRicciardi


CategoryParentheses