I am trying to find an easy and efficient way to modify the behaviour of forward-sexp to handle balanced pairs of characters not normally supported by it, such as balanced < and > and balanced << and >>.

My specific case is to enhance the support of Erlang but I believe it could apply to a lot of scenarios.

The implementation of forward-sexp allows the use of a forward-sexp-function which means I could implement such a function. I am also aware of the SMIE library and will look into it.

However I was hoping to find a variable that the C-implemented scan-sexp could use to define the matching pair but have not succeeded so far. It would seem the easiest and most efficient way of implementing such handling of balanced pair would be done there.

Is there a variable one can use to augment or modify the behaviour of scan-sexp?

  • Did you have a look at electric-pair-text-pairs?
    – aadcg
    Commented Sep 27, 2021 at 16:18
  • Have you tried Erlang mode? I don't know anything, either about Erlang or Erlang mode, but that's where I would start if I had to use it.
    – NickD
    Commented Sep 27, 2021 at 16:30
  • @aadcg I did not know electric-pair-text-pairs. I will look into it. Thanks
    – PRouleau
    Commented Sep 27, 2021 at 16:53
  • @NickD . Yes I am using erlang-mode from erlang.el. That's what I'm trying to enhance.
    – PRouleau
    Commented Sep 27, 2021 at 17:09
  • I tried adding the '(?< . ?>) pair to electric-pair-pairs and to electric-pair-text-pairs. What it does is add the automatic insertion of the matched pair character when the minor mode electric-pair-mode is activated. It does not seem to help navigation though. Although this electric-pair-mode is useful, I find that the smartparens-mode has more features. For Erlang I am using erlang.el and smartparens, but some navigation and matching are sill lacking, therefore my question. Here's what my code supports.
    – PRouleau
    Commented Sep 27, 2021 at 17:17

1 Answer 1


I have been able to get forward-sexp to recognize the < and > pair by modifying the syntax table the erlang-mode uses:

The erlang.el file has a function that sets the syntax table when the erlang-mode takes effect. It does the following:

(modify-syntax-entry ?< "." table)
(modify-syntax-entry ?> "." table)

but it should be this instead:

(modify-syntax-entry ?< "(>" table)
(modify-syntax-entry ?> ")<" table)

Since I can't modify erlang.el, a hook has to be used to modify the erlang.el syntax table variable: erlang-mode-syntax-table somewhere in initialization code I used something like this:

 (with-eval-after-load 'erlang

  (defvar erlang-mode-syntax-table) ; prevent byte compiler warning

  (add-hook 'erlang-mode-hook 
            (lambda () 
              "Add < > pair matching."
               (modify-syntax-entry ?< "(>" erlang-mode-syntax-table)
               (modify-syntax-entry ?> ")<" erlang-mode-syntax-table)))

The defvar is there to prevent byte-compiler warnings only. The with-eval-after-load 'erlang delays execution of the code after erlang.el has loaded to ensure the hook is not over-written.

Alternative (but more complex)

An alternative, which also works but requires much more code would have been to write a function my-erlang-forward-sexp that handles the pairing it self and behaves as a replacement for forward-sexp, and then place the following inside the hook function instead:

(setq-local forward-sexp-function (function my-erlang-forward-sexp))

It would set forward-sexp-function to my-erlang-forward-sexp only in buffers using the erlang-mode and would not modify the behaviour of other major modes.

However writing that function is more complex. Modifying the syntax table is much simpler to do and takes less code.

  • 1
    Thanks to @aadcg for suggesting I ask on gnu emacs mailing list and to Thibaut Verron who spotted a typo in my syntax table change that prevented the change to work.
    – PRouleau
    Commented Sep 28, 2021 at 12:14
  • sets-local is a typo, right? I presume the syntax-table mod works with << and >> as well? If erlang-mode sets the hook to nil or some non-nil value, then depending on when it is loaded, you might find your customization to be AWOL. It may be safer to use with-eval-after-load instead of the defvar.
    – NickD
    Commented Sep 28, 2021 at 17:20
  • @NickD, Thanks: I fixed the typo (caused by me not looking at what was autocorrected...): it should have read setq-local. And yes the syntax table mods make << match the >> pair. It's also working with er/expand-region. As for your last comment I'm not sure I understand.
    – PRouleau
    Commented Sep 28, 2021 at 17:58
  • If you don't have a problem with your current setup, you can ignore my last comment. If you do encounter a problem (you check the hook and it does not contain your function), then we can worry about it :-)
    – NickD
    Commented Sep 28, 2021 at 18:13
  • @NickD, what would be the sequence where the hook would not contain the function I added to go in the hook? The function is added to the hook before the erlang-mode is defined, which is when erlang.el is loaded. I know I had a similar problem in the past but can't remember what it was.
    – PRouleau
    Commented Sep 28, 2021 at 18:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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