Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can you modify two matching delimiters at once with Emacs?

Tags:

emacs

tex

elisp

While this question concerns the formatting of LaTeX within Emacs (and maybe Auctex), I believe this can be applied to more general situations in Emacs concerning delimiters like parentheses, brackets, and braces.

I am looking to be able to do the following with Emacs (and elisp), and don't know where to begin. Say I have:

(This is in parentheses)

With some keybinding in Emacs, I want Emacs to find the matching delimiter to whichever one is by my cursor (something I know Emacs can do since it can highlight matching delimiters in various modes) and be able to change both of them to

\left( This is in parentheses \right)

The delimiters I would like this to work with are: (...), [...], \lvert ... \rvert, \langle ... \rangle, \{ ... \}. What elisp would I need to accomplish this task?

More general ways to handle matching delimiters are welcome.

like image 984
qgp07 Avatar asked Dec 16 '11 18:12

qgp07


1 Answers

Evaluate the command below in Emacs. After reloading you can put the point (text cursor) immediately after a closing paren. Then do M-x replace-matching-parens to replace the closing ) with \right) and the matching start paren ( with \left(.

(defun replace-matching-parens ()
  (interactive)
  (save-excursion
    (let ((end-point (point)))
      (backward-list)
      (let ((start-point (point)))
        (goto-char end-point)
        (re-search-backward ")" nil t)
        (replace-match " \\\\right)" nil nil)

        (goto-char start-point)
        (re-search-forward "(" nil t)
        (replace-match "\\\\left( " nil nil)))))

The interactive bit indicates that I want a "command", so it can be executed using M-x. To avoid the cursor ending up in a strange place after execution I'm wrapping the logic in save-excursion. The point jumps back to the opening paren using backward-list and holds on to the start and end positions of the paren-matched region. Lastly, starting at the end and working backwards I replace the strings. By replacing backwards rather than forwards I avoid invalidating end-point before I need it.

Generalizing this to handle different kinds of delimiters shouldn't be too bad. backward-list ought to work with any pair of strings emacs recognizes as analogues of ( and ). To add more parenthesis-like string pairs, check out set-syntax-table in this Parenthesis Matching article.

Use global-set-key to setup a key binding to replace-matching-parens.

Fair warning: replace-matching-parens is the first elisp command I've implemented, so it may not align with best practices. To all the gurus out there, I'm open to constructive criticism.

like image 78
Sage Mitchell Avatar answered Oct 15 '22 17:10

Sage Mitchell