3

In c-mode, rust-mode, and similar major language modes, I frequently type something such as the following Rust:

if some_bool { Some(foo) } else { None }

As I enter this (| represents my cursor), electric-pair mode inserts matching brackets:

if some_bool { |}

Is there a setting that allows Emacs to insert matching space on the other side of the cursor following an opening character of a pair, so the above example would look like the following?

if some_bool { | }

I would expect it to behave exactly like additional parens had been inserted, and backspacing at this point should produce

if some_bool {|}

again.

3 Answers 3

1

With smartparens, you can add a :post-handler, like this:

(sp-pair "{" nil :post-handlers '(("| " "SPC")))

I use an additional handler for pressing return:

(sp-pair "{" nil :post-handlers '(("||\n[i]" "RET")
                                  ("| " "SPC")))
1
  • 1
    This almost works, but it doesn't handle pressing backspace. (Although it does still delete the matching close brace when I delete the opening one. Is there an extra rule I can use to accomplish that? Nov 13, 2015 at 17:46
0

Check out electric-spacing or electric-operator. You might need to configure it a bit for your use case, but it aims to automatically pad certain characters with spaces.

0

I don't think electric-pair-mode will be of much help to you here. You could add (?\s . ?\s) to electric-pair-pairs (its alist of characters to automatically double-insert), but that would affect every space you type (there is no way to add conditions as to when it will/won't insert a pair) and will probably play havoc with skipping over whitespace. Also, w.r.t. automatically deleting a matching space, electric-pair-mode doesn't do anything magical. It simply scans its list of characters to insert as pairs and removes the next character if it finds a match with the one you've deleted. Again, adding (?\s . ?\s) to electric-pair-pairs would be a poor solution.

So, I solved this by adding my own functions for the purpose...

(defun my/c-mode-insert-space (arg)
  (interactive "*P")
  (let ((prev (char-before))
        (next (char-after)))
    (self-insert-command (prefix-numeric-value arg))
    (if (and prev next
             (string-match-p "[[({]" (string prev))
             (string-match-p "[])}]" (string next)))
        (save-excursion (self-insert-command 1)))))

(defun my/c-mode-delete-space (arg &optional killp)
  (interactive "*p\nP")
  (let ((prev (char-before))
        (next (char-after))
        (pprev (char-before (- (point) 1))))
    (if (and prev next pprev
             (char-equal prev ?\s) (char-equal next ?\s)
             (string-match "[[({]" (string pprev)))
        (delete-char 1))
    (backward-delete-char-untabify arg killp)))

You can bind them in c-mode (and its derivatives) like this:

(add-hook 'c-mode-common-hook
          (lambda ()
            (local-set-key " " 'my/c-mode-insert-space)
            (local-set-key "\177" 'my/c-mode-delete-space)))

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.