C ++模板和Emacs:自定义缩进
据我所知,在Emacs中,没有办法自定义C ++中模板列表的结尾“>”字符的缩进级别。 目前我的emacs缩进scheme是这样的:
template < typename T1, typename T2, typename T3 > class X;
我想要的是这样的:
template < typename T1, typename T2, typename T3 > class X;
将缩进variablestemplate-args-cont设置为零将正确缩进“>”字符,但代价是取消缩进模板参数列表的实际主体。
任何build议从emacs的大师在那里?
编辑:
我有点用下面的黑客工作:
(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 '+)))
然后在我的自定义主题ala中将template-args-cont设置为缩进模板:
(c-add-style "my-style" '("stroustrup" ;; ... Other stuff ... (template-args-cont . indent-templates))))
但它仍然是非常错误的。 它大部分时间都在工作,但是有时候emacs会认为模板列表是一个arglist,然后就会出现闹剧。
我发现的最好的解决scheme是编写一个自定义(和相对简单)的缩进function。
代码
(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 +))))
这处理了我所遇到的所有情况,即使嵌套了几个级别的模板。
怎么运行的
对于缩进代码,如果提供了缩进函数列表,那么Emacs将按顺序尝试它们,如果当前正在执行的函数返回nil
,它将调用下一个。 我所做的是在列表的开始处添加一个新的缩进函数,用于检测行上的第一个非空白字符是否是“>”,如果是,则将缩进设置为位置0(将它排成一行与开放模板)。 这也包括你有如下模板参数的情况:
template < template < typename T, typename U, typename... Args > class... CS >
因为它不关心'>'后面的内容。 因此,由于缩进函数列表如何工作,如果“>”不是第一个字符,函数将返回nil
并调用通常的缩进函数。
注释
我认为您遇到的问题的一部分是,当您实例化模板时,emacs CC模式使用相同的template-args-cont
结构查看它。 所以,考虑到这一点,我扩大了你的原始想法,并试图使其符合我的喜好; 我使代码冗长,希望每个人都能理解我的意图。 :)这应该不会导致您实例化时出现问题,而且它似乎也适用于模板模板参数! 试试这个,直到有更多Elisp技能的人可以提供更好的解决scheme!
如果您遇到任何“战斗”(即交替或中断的缩进),请尝试重新加载cpp文件Cx Cv Enter和缩进。 有时使用模板模板参数emacs将内部参数显示为arglist-cont-nonempty
,甚至与template-args-const
来回交替,但重新加载始终处于恢复状态。
用法
做你想做的事情,试试下面的代码,并join你的c-offsets-alist
条目:
(template-args-cont . brian-c-lineup-template-args)
并设置variables
(setq brian-c-lineup-template-closebracket t)
我其实更喜欢稍微不同的路线:
(setq brian-c-lineup-template-closebracket 'under)
码
(defvar brian-c-lineup-template-closebracket 'under "Control the indentation of the closing template bracket, >. Possible values and consequences: 'under : Align directly under (same column) the opening bracket. t : Align at the beginning of the line (or current indentation level. nil : Align at the same column of previous types (eg col of class T).") (defun brian-c-lineup-template--closebracket-p () "Return t if the line contains only a template close bracket, >." (save-excursion (beginning-of-line) ;; Check if this line is empty except for the trailing bracket, > (looking-at (rx (zero-or-more blank) ">" (zero-or-more blank))))) (defun brian-c-lineup-template--pos-to-col (pos) (save-excursion (goto-char pos) (current-column))) (defun brian-c-lineup-template--calc-open-bracket-pos (langelem) "Calculate the position of a template declaration opening bracket via LANGELEM." (save-excursion (c-with-syntax-table c++-template-syntax-table (goto-char (c-langelem-pos langelem)) (1- (re-search-forward "<" (point-max) 'move))))) (defun brian-c-lineup-template--calc-indent-offset (ob-pos) "Calculate the indentation offset for lining up types given the opening bracket position, OB-POS." (save-excursion (c-with-syntax-table c++-template-syntax-table ;; Move past the opening bracket, and check for types (basically not space) ;; if types are on the same line, use their starting column for indentation. (goto-char (1+ ob-pos)) (cond ((re-search-forward (rx (or "class" "typename" (one-or-more (not blank)))) (c-point 'eol) 'move) (goto-char (match-beginning 0)) (current-column)) (t (back-to-indentation) (+ c-basic-offset (current-column))))))) (defun brian-c-lineup-template-args (langelem) "Align template arguments and the closing bracket in a semi-custom manner." (let* ((ob-pos (brian-c-lineup-template--calc-open-bracket-pos langelem)) (ob-col (brian-c-lineup-template--pos-to-col ob-pos)) (offset (brian-c-lineup-template--calc-indent-offset ob-pos))) ;; Optional check for a line consisting of only a closebracket and ;; line it up either at the start of indentation, or underneath the ;; column of the opening bracket (cond ((and brian-c-lineup-template-closebracket (brian-c-lineup-template--closebracket-p)) (cond ((eq brian-c-lineup-template-closebracket 'under) (vector ob-col)) (t 0))) (t (vector offset)))))
这是一个不同的方法,然后改变选项卡,但是使用像Yasnippet这样的片段系统怎么样(参见这里的例子)。
唯一的问题是,如果您重新格式化文档“Mx索引区域”(或该部分),它可能会回到其他选项卡规则。