【问题标题】:C++ Templates and Emacs: Customizing IndentationC++ 模板和 Emacs:自定义缩进
【发布时间】:2011-10-20 02:19:07
【问题描述】:

据我所知,在 emacs 中,没有办法自定义 C++ 中模板列表的结束“>”字符的缩进级别。目前我的emacs缩进方案是这样做的:

template <
    typename T1,
    typename T2,
    typename T3
    >
class X;

我想要的是这样的:

template <
    typename T1,
    typename T2,
    typename T3
>
class X;

将缩进变量 template-args-cont 设置为零将正确缩进 '>' 字符,但代价是取消缩进模板参数列表的实际正文。

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
        '+)))

然后在我的自定义主题中将 template-args-cont 设置为 indent-templates,ala:

(c-add-style "my-style"
             '("stroustrup"
                ;; ... Other stuff ...
                (template-args-cont . indent-templates))))

但它仍然很麻烦。它在大多数情况下都有效,但有时 emacs 会因为认为模板列表是 arglist 而感到困惑,然后就会产生欢闹。

【问题讨论】:

  • 我不确定是否可行,但如果可行,您可以在此页面上找到信息:gnu.org/software/emacs/manual/html_mono/…
  • 其实我觉得如果你自己写一个排队函数是可以的。我之前评论中的文档提供了更多信息。
  • 请注意,Emacs c++-mode 通常会定期对模板参数感到困惑,因此它实际上可能不是您的代码的问题... [公平地说,实际上很难正确, 因为 C++ 中 &lt;&gt; 的多重含义(有时作为平衡分隔符,有时作为运算符),除非你进行比 c++-mode 更多的实际解析...]

标签: c++ emacs


【解决方案1】:

我发现的最佳解决方案是编写一个自定义(并且相对简单)的缩进函数。

守则

(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 并调用通常的缩进函数。

【讨论】:

    【解决方案2】:

    评论

    我认为部分您遇到的问题是,当您实例化模板时,emacs CC 模式以相同的template-args-cont 结构查看它。因此,考虑到这一点,我扩展了您的原始想法并尝试使其符合我的喜好;我把代码写得很详细,希望每个人都能理解我的意图。 :) 这在您实例化时应该不会导致问题,而且它似乎也适用于模板模板参数!试试这个,直到有更多 Elisp 技能的人可以提供更好的解决方案!

    如果您遇到任何“冲突”(即交替或损坏的缩进),请尝试重新加载 cpp 文件 C-xC-vEnter 并再次缩进.有时使用模板模板参数,emacs 将内部参数显示为arglist-cont-nonempty,甚至与template-args-const 交替显示,但重新加载总是恢复状态。

    用法

    要执行您想要的操作,请使用下面的代码并在您的c-offsets-alist 中添加一个条目:

    (template-args-cont . brian-c-lineup-template-args)

    并设置变量

    (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 (e.g. 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)))))
    

    【讨论】:

    • 哇,谢谢。如果我有时间(正在搬家),我会在周末尝试一下。
    【解决方案3】:

    这是一种与更改选项卡不同的方法,但是使用像 Yasnippet 这样的 sn-p 系统怎么样(参见示例 here)。

    唯一的问题是,如果您重新格式化文档“M-x index-region”(或该部分),它可能会回到其他选项卡规则。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-24
      • 1970-01-01
      • 2011-04-26
      • 1970-01-01
      相关资源
      最近更新 更多