3

Here is the function spec: (defun jump-to-matched (open-char closed-char) )

say the content of current buffer is "a([b]c()d)".

If I move the cursor over the first "(" and run (jump-to-matched "(" ")"), I expect the function return 9 which is the position of ")" at the end of the buffer.

If I move the cursor over the "[" at the position 2 and run (jump-to-matched "[" "]"), I expect the function return 4 which is the position of "]".

My question is how to implement such function?

  • I wrote a plugin evil-matchit (github.com/redguardtoo/evil-matchit). It's a emulation of matchit in vim. I'm investigating some tech solution to replace the evil API evil-jump-item I'm using. So my "spec" exactly specify what I need, nothing more. – chen bin Jun 19 '15 at 2:33
5

If you want to write your own use the contents of (syntax-ppss (point)) which you give you the positions of matching pairs in the current context amongst other data. Read the docs for syntax-ppss for more info.

But you don't need to implement the function, you can use forward-sexp and backward-sexp to jump between matching pairs. bound by default to C-M-f and C-M-b. These commands are also extremely useful for intelligently moving about code.

  • 1
    thanks, I will try it asap. It's great if I can avoid writing the code. – chen bin Jun 17 '15 at 3:31
  • I'll have to edit the question, syntax-ppss will help you go backward to the left matching pair but on won't give you the position of the right matching pair. – Jordon Biondo Jun 17 '15 at 3:34
  • 1
    You do not need to jump around just to get the position of the matching delimiter. You can also use scan-sexps. – Tobias Jun 17 '15 at 9:58
  • @Tobias never knew about that function, you should write up an answer for it. – Jordon Biondo Jun 17 '15 at 11:51
  • thanks @Tobias, I think both of you answered my questions correctly because forward-sexp actually calls the scan-sexps. – chen bin Jun 19 '15 at 2:29
2

An implementation of this command was provided around 20 years ago, unfortunately forgot the source.

Here a basic approach:

(defun ar-simple-match-paren ()
  "Jump between matching paren. "
  (interactive)
  (cond ((eq 4 (car (syntax-after (point))))
     (forward-sexp)
     (forward-char -1))
    ((eq 5 (car (syntax-after (point))))
     (forward-char 1)
     (backward-sexp))
    (t (message "%s" "Don't see a matching paren"))))

Here with historical key "%":

(defun ar-match-paren (&optional arg)
  "Go to the matching brace, bracket or parenthesis if on its counterpart.

Otherwise insert the character, the key is assigned to, here `%'.
With \\[universal argument] insert a `%'. "
  (interactive "P")
  (if arg
      (self-insert-command (if (numberp arg) arg 1))
    (cond ((eq 4 (car (syntax-after (point))))
       (forward-sexp)
       (forward-char -1))
      ((eq 5 (car (syntax-after (point))))
       (forward-char 1)
       (backward-sexp))
      (t (self-insert-command 1)))))

(global-set-key [(%)] 'ar-match-paren)

Errors are mine...

0

I used this :

(defun px-match-paren (arg)
  "Go to the matching paren if on a paren; otherwise insert <key>."
  (interactive "p")
  (cond
   ((char-equal 41 (char-before)) (backward-list 1))
   ((char-equal 125 (char-before)) (backward-list 1))
   ((and
     (char-equal 123 (char-before))
     (char-equal 10 (char-after)))
    (backward-char 1) (forward-list 1))
   ((looking-at "\\s\(") (forward-list 1))
   ((looking-at "\\s\)") (backward-list 1))
   (t (self-insert-command (or arg 1)))))

Until I learned about forward and backward-sexp (C-M-left and C-M-right) :)

0

How about the following?

(defun jump-to-matched ()
  (ignore-errors
    (save-excursion
      (forward-sexp)
      (1- (point)))))

You will get nil as an answer in case there is no match.

  • The above gives 10, as opposed to 9, in your first example, but I believe 10 is the correct answer since buffer positions start at 1. – Ruy Oct 26 '17 at 19:56
  • The use of "condition-case" is to avoid an error in case there is no matching bracket, which in turn will break @Andreas answer. – Ruy Oct 26 '17 at 20:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.