2011-10-20 15 views
44

私がemacsで知っている限り、C++のテンプレートリストの閉じる '>'文字のインデントレベルをカスタマイズする方法はありません。現在、私のEmacsのインデントスキームは、この処理を行います。私が欲しいものC++のテンプレートとEmacs:インデントのカスタマイズ

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

はこのようなものである:ゼロにインデント変数テンプレート引数-続きを設定

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

は、適切に「>」文字をインデントしますテンプレート引数リストの実際の本文をインデントしないでください。

emacs gurusの提案はありますか?

EDIT:

私はそれが多少以下のハックで作業しました:

(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で、テンプレートをインデントするために、テンプレート引数-CONTを設定:

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

しかし、まだかなりバグです。これはほとんどの場合動作しますが、時にはemacsが混乱してテンプレートリストがarglistであると思って、それからやっかいが起こると思います。

+1

もし可能であれば、私はこのページの情報を見つけることができません:http://www.gnu.org/software/emacs/manual/html_mono/ccmode.html#Customizing-Indentation – rve

+0

実際にあなた自身のラインアップ機能を書くことが可能かもしれないと思います。私の以前のコメントからの文書はこれに関するより多くの情報を提供します。 – rve

+6

EmacsのC++モードは、一般的にテンプレートの引数については定期的に混乱する傾向がありますので、実際にはあなたのコードには問題がないかもしれません... [公平には、実際にはかなり難しいです。 C++の '<' and '>'(時には平衡デリミタとして、時には演算子として)のように、実際の構文解析をC++よりも多くしなければ...] – snogglethorpe

答えて

2

私がカスタム(と比較的簡単)インデント機能を書いているを発見した最善の解決策。

コード

(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はそれらを順番にしようとすると、1が現在リターンnilを実行された場合、それは次のものを呼び出します。私が行ったことは、行の最初の空白以外の文字が '>'かどうかを検出する新しいインデント関数をリストの先頭に追加し、インデントが0の場合はインデントを設定しますオープニングテンプレートと一緒に)。

template < 
    template < 
    typename T, 
    typename U, 
    typename... Args 
    > class... CS 
> 

を、それが「>」の後に何を気にしないので、これはまた、次のようにテンプレートテンプレートパラメータを持つケースをカバーしています。インデント関数のリストがどのように動作するかの結果として、 '>'が最初の文字でない場合、関数はnilを返し、通常のインデント関数が呼び出されます。

0

タブを変更するのは別の方法ですが、Yasnippet(例hereを参照)のようなスニペットシステムを使用するのはどうでしょうか。

唯一の問題は、ドキュメント「M-xインデックス領域」(またはそのセクション)を再フォーマットすると、おそらく他のタブ規則に戻るということです。

1

コメント

私はあなたの経験はあなたがテンプレートをインスタンス化するとき、EmacsのCCモードは同じtemplate-args-cont構造でそれを見ていることである問題の一部だと思います。だから、これを考慮に入れて、私はあなたの元のアイデアを広げ、それを自分の好みに合わせようとしました。コードを冗長にして、誰もが私の意図を理解できるようにしました。 :)これは、インスタンス化するときに問題を起こすべきではなく、テンプレートテンプレートのパラメータとしても機能します。より多くのElispスキルを持つ人がより良い解決策を提供できるようになるまでこれを試してみてください!

あなたはどんな '戦い'(すなわち、交流または壊れインデントを)経験している場合、C-XC-Vを入力して、再度インデントのcppファイルをリロードしてみてください。ときどきテンプレートテンプレートのパラメータで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))))) 
+0

うわー、ありがとう。私は時間があるならば、週末に試してみるよ(家を動かす過程で)。 – bstamour

関連する問題