据我所知,在emacs中,没有办法在C++中自定义模板列表的结束'>'字符的缩进级别.目前我的emacs缩进方案执行此操作:
template <
typename T1,
typename T2,
typename T3
>
class X;
Run Code Online (Sandbox Code Playgroud)
我想要的是这样的:
template <
typename T1,
typename T2,
typename T3
>
class X;
Run Code Online (Sandbox Code Playgroud)
将indent变量template-args-cont设置为零将正确缩进'>'字符,但代价是unindenting模板参数列表的实际主体.
来自emacs大师的任何建议吗?
编辑:
我有点使用以下hack:
(defun indent-templates (elem)
(c-langelem-col elem t)
(let ((current-line
(buffer-substring-no-properties
(point-at-bol) (point-at-eol))))
(if (string-match-p "^\\s-*>" current-line)
0
'+)))
Run Code Online (Sandbox Code Playgroud)
然后在我的自定义主题中将template-args-cont设置为indent-templates,ala:
(c-add-style "my-style"
'("stroustrup"
;; ... Other stuff ...
(template-args-cont . indent-templates))))
Run Code Online (Sandbox Code Playgroud)
但它仍然很漂亮.它大部分时间都可以工作,但有时emacs会因为认为模板列表是arglist而感到困惑,然后就会出现欢闹.
我发现的最佳解决方案是编写一个自定义(且相对简单)的缩进函数。
代码
(defun c++-template-args-cont (langelem)
"Control indentation of template parameters handling the special case of '>'.
Possible Values:
0 : The first non-ws character is '>'. Line it up under 'template'.
nil : Otherwise, return nil and run next lineup function."
(save-excursion
(beginning-of-line)
(if (re-search-forward "^[\t ]*>" (line-end-position) t)
0)))
(add-hook 'c++-mode-hook
(lambda ()
(c-set-offset 'template-args-cont
'(c++-template-args-cont c-lineup-template-args +))))
Run Code Online (Sandbox Code Playgroud)
这可以处理我遇到的所有情况,即使模板嵌套了几层深度。
怎么运行的
对于缩进代码,如果提供了缩进函数列表,那么 Emacs 将按顺序尝试它们,如果当前正在执行的函数返回nil,它将调用下一个。我所做的就是在列表的开头添加一个新的缩进函数,该函数检测该行上的第一个非空白字符是否为“>”,如果是,则将缩进设置为位置 0(这会将其对齐)与打开模板)。这也涵盖了具有模板-模板参数的情况,如下所示:
template <
template <
typename T,
typename U,
typename... Args
> class... CS
>
Run Code Online (Sandbox Code Playgroud)
因为它不关心“>”后面的内容。因此,根据缩进函数列表的工作原理,如果“>”不是第一个字符,该函数将返回nil并调用通常的缩进函数。