C/C++/Java code indentation in Emacs
Problem
There are two styles when insert curly braces in C like languages.
Style 1:
if(true) {
printf("hello world\n");
}
Style 2:
if(true)
{
printf("hello world\n");
}
Whatever style I use, I expect Emacs will properly handle the indentation for me.
In "Style 1", when I press ENTER key after "{" at first line, I expect the new line will indent four spaces.
In "Style 2", when I press ENTER key after ")" at first line, I expect the new line will NOT indent.
Solution
Insert below code into ~/.emacs:
(defun fix-c-indent-offset-according-to-syntax-context (key val)
;; remove the old element
(setq c-offsets-alist (delq (assoc key c-offsets-alist) c-offsets-alist))
;; new value
(add-to-list 'c-offsets-alist '(key . val)))
(add-hook 'c-mode-common-hook
(lambda ()
(when (derived-mode-p 'c-mode 'c++-mode 'java-mode)
;; indent
(fix-c-indent-offset-according-to-syntax-context 'substatement 0)
(fix-c-indent-offset-according-to-syntax-context 'func-decl-cont 0))
))
That's it.
Explanation
When you press the ENTER key, the function c-indent-line will be called.
That function will do some simple syntax analysis and decide current syntactic context..
It will use that syntactic context to look up a global variable c-offsets-alist and decide how many spaces the new line will indent.
For example, the context substatement corresponds to the code like below:
if(true) // press ENTER here
And the context func-decl-cont corresponds to:
void fn () //press ENTER here
Technical details
When you press ENTER key, the new line will be inserted. Then the function indent-according-to-mode will always be called
indent-according-to-mode will call function object indent-line-function if it's not nil.
In C/C++/Java, that object is actually c-indent-line.
c-indent-line is defined in /usr/share/emacs/24.3/lisp/progmodes/cc-cmds.el (I use Emacs 24.3 on Gentoo Linux).
In that function, just below the code line:
(setq c-syntactic-context (c-guess-basic-syntax))
You can insert log code as below:
(message "c-syntactic-context=%s" c-syntactic-context)
You will know the current syntactic context when you press ENTER key through the output of log code.
EmacsWiki says you can run command "c-set-offset", whose hot key is "C-x C-o", in order to "see the syntax at point". As I tested, it does not work as expected. My way may seem a little bit intrusive but is reliable.
For example, the context statement-cont corresponds to the use case like this:
int a=3, // press ENTER here
Please note syntax analysis in c-indent-line is turned on if and only if the global flag c-syntactic-indentation is true.
Thanks for chengyi for reporting the issue and suggesting the fix.
BTW, EmacsWiki has a section to discuss the indenting in C. You may not need it if you have read this article and can read the Emacs lisp code.