Reputation: 3176
The default Emacs C++ mode (cc-mode
) still does not recognize many C++11 features.
One annoying issue is that it applies too much indentation to lambda functions used
as function parameters:
std::vector<int> ar(4);
std::generate_n(std::begin(ar), 4, [] {
static int g_i;
return g_i++;
});
std::for_each(std::begin(ar), std::end(ar), [](int i) {
std::cout << " " << i;
});
bool b = std::is_sorted(std::begin(ar), std::end(ar), [&](int l, int r) {
return l<r;
});
std::cout << " " << b << "\n";
Ideally, one would prefer:
std::vector<int> ar(4);
std::generate_n(std::begin(ar), 4, [] {
static int g_i;
return g_i++;
});
std::for_each(std::begin(ar), std::end(ar), [](int i) {
std::cout << " " << i;
});
bool b = std::is_sorted(std::begin(ar), std::end(ar), [&](int l, int r) {
return l<r;
});
std::cout << " " << b << "\n";
Are there good solutions for this?
Upvotes: 18
Views: 4177
Reputation: 664
In Emacs26, the accepted answer doesn't work for me anymore. I just set the 'inlambda' to 0.
(c-offsets-alist . ((case-label . 0)
(inline-open . 0)
(substatement-open . 0)
(inlambda . 0) ; no extra indent for lambda
(block-open . 0) ; no space before {
(knr-argdecl-intro . -)))
Upvotes: 19
Reputation: 119
A slight rework of the Hugues' solution to also recognize lambda function as an argument nested in another lambda function, and lambda function as an in-class initialization value:
(defun vr-c++-looking-at-lambda_as_param ()
"Return t if text after point matches '[...](' or '[...]{'"
(looking-at ".*[,(][ \t]*\\[[^]]*\\][ \t]*[({][^}]*?[ \t]*[({][^}]*?$"))
(defun vr-c++-looking-at-lambda_in_uniform_init ()
"Return t if text after point matches '{[...](' or '{[...]{'"
(looking-at ".*{[ \t]*\\[[^]]*\\][ \t]*[({][^}]*?[ \t]*[({][^}]*?$"))
(defun vr-c++-indentation-examine (langelem looking-at-p)
(and (equal major-mode 'c++-mode)
(ignore-errors
(save-excursion
(goto-char (c-langelem-pos langelem))
(funcall looking-at-p)))))
(defun vr-c++-indentation-setup ()
(require 'google-c-style)
(google-set-c-style)
(c-set-offset
'block-close
(lambda (langelem)
(if (vr-c++-indentation-examine
langelem
#'vr-c++-looking-at-lambda_in_uniform_init)
'-
0)))
(c-set-offset
'statement-block-intro
(lambda (langelem)
(if (vr-c++-indentation-examine
langelem
#'vr-c++-looking-at-lambda_in_uniform_init)
0
'+)))
(defadvice c-lineup-arglist (around my activate)
"Improve indentation of continued C++11 lambda function opened as argument."
(setq ad-return-value
(if (vr-c++-indentation-examine
langelem
#'vr-c++-looking-at-lambda_as_param)
0
ad-do-it))))
Upvotes: 4
Reputation: 3176
The discussion in Emacs cc-mode indentation problem with C++0x enum class fixes the enum class
formatting issue.
This inspired the following advice function. It detects an open C++ lambda function in an open argument list, and cancels one level of indentation to produce the "ideal" result in the question:
(defadvice c-lineup-arglist (around my activate)
"Improve indentation of continued C++11 lambda function opened as argument."
(setq ad-return-value
(if (and (equal major-mode 'c++-mode)
(ignore-errors
(save-excursion
(goto-char (c-langelem-pos langelem))
;; Detect "[...](" or "[...]{". preceded by "," or "(",
;; and with unclosed brace.
(looking-at ".*[(,][ \t]*\\[[^]]*\\][ \t]*[({][^}]*$"))))
0 ; no additional indent
ad-do-it))) ; default behavior
Upvotes: 16