How to get reliable indentation in elisp

2019-07-21 16:13发布

问题:

I'm new to Emacs.

I'm trying to write an elisp function that works across all modes. Specifically, I want to write a function that inserts braces (a bit like insert-parentheses) in the same way the following key sequence does for a dumb editor that only supports auto-indent:

"{" <ret> "}" <up-arrow> <end> <ret> <tab>

This key sequence works for both Java and C# (bsd) style indentation. I need it to work in all brace-y emacs modes, and also in plain text files - I have other formats that have no emacs modes but still use braces.

Here's my 12th attempt or so:

(defun insert-braces-macro ()
  (interactive)
  (insert "{")
  (newline)
  (indent-relative t)
  (insert "}")
  (forward-line -1)
  (end-of-line)
  (newline)
  (indent-relative t)
  (indent-relative nil))

Unfortunately, this doesn't work quite right. I don't think indent-relative is the right function, because it doesn't indent correctly in Java-style:

f |

expands into:

f {
  |
}

and in C mode:

somelongword another |

expands to:

somelongword another {
             |
}

But indent-according-to-mode isn't right either, because it will indent too much in C-ish modes (the trailing '}' is indented) and not at all in Fundamental mode.

What's the right way to handle this?

回答1:

indent-according-to-mode is the right answer, I think, but you need to remember that it can't predict the future, so you need to call it after inserting the text rather than before:

(defun insert-braces-macro ()
  (interactive)
  (insert "{")
  (newline) (indent-according-to-mode)
  (save-excursion
    (newline)
    (insert "}")
    (indent-according-to-mode)))


回答2:

Here's what I've been using for a long time:

(defun ins-c++-curly ()
  "Insert {}.
Treat it as a function body when from endline before )"
  (interactive)
  (if (looking-back "\\()\\|try\\|else\\|const\\|:\\)$")
      (progn
        (insert " {\n\n}")
        (indent-according-to-mode)
        (forward-line -1)
        (indent-according-to-mode))
    (insert "{}")
    (backward-char)))

This function:

  1. inserts a {} block when looking back at a place where it's appropriate, e.g. after a ).
  2. otherwise, inserts {} and goes backward one char. Useful for arrays and the new-style initialization.

This works for C++, where I have indentation set to 4 spaces, as well as for Java, where I have it at 2 spaces.