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 Answers3

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")))
nanny
  • 5,704
  • 18
  • 38
  • 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? – thirtythreeforty Nov 13 '15 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.

waymondo
  • 1,384
  • 11
  • 16
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)))
edam
  • 311
  • 1
  • 6