Uncrustifyのセッティング (3) インデント編 前編

はじめに
--------
Uncrustifyというツールは、ソースコード整形ツールの一つだ。
人気があるという点では、Artistic Style (AStyle)というコマンドラインツールが一番人気があるようだが、それはそもそもUncrustifyがあまりにも不親切にパワフル過ぎるからであると考えている。

今回はインデント設定である。ソースコード整形ツールは、Formatter、Beautifierなどとも呼ばれるとともに、Indenterとも呼ばれる。それほどにインデントというのは重要な設定なわけである。

ちなみに、uncrustifyの中では「インデント (indent)」という用語と「位置揃え (align)」という用語がある。インデントというのは、制御ブロック '{' と '}' で囲まれた中の段を深くすることである。位置揃えというのは、インデントと似ているが、行送りの後に段を深くすることとして使われている。行送りの位置揃えでも、インデントする場合、それ用のインデントオプションが設けられている。(例: indent_var_def_cont、indent_func_call_paramなど)

以下に、インデントと位置揃えの違いをコードで示しておく。

```cpp:indent_align.cpp
void func(void)
{
    // インデント (indent) の例
    if (foo) {
    ..../* this is an indent */
    }

    // 位置揃え (align) の例
    bar(var1,
    ....var2); /* this is an align */
}
```

インデント設定一覧
------------------
以下がインデント設定一覧だが、あまりにも長くて気が遠くなるぞ！行くぞ！

| 項目                                 | 説明                                                                                                                                                                          |
|:-------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| indent_columns                       | インデントレベルのインデント幅 (半角空白数) (通常 2、3、4、8) { number }                                                                                                      |
| indent_continue                      | '('や'='の行送りの後のインデントを上書き。マイナスの場合はインデントを継続。 { number }                                                                                       |
| indent_with_tabs                     | コードをインデントする時にどのようにインデントするか。 { 0: 半角空白のみ 1: インデントはタブ、位置揃えは半角空白 2: インデントも位置揃えもタブ (タブストップ以外は半角空白) } |
| indent_cmt_with_tabs                 | コードのインデントレベルでないコメントをタブ位置までタブ文字でインデントするか。falseの場合、半角空白のみ。 (indent_with_tabs=2の場合のみ) { true, false }                    |
| indent_align_string                  | '\'-改行でされた文字列を位置揃えさせるかどうか。これ、いろいろ試したけど効かないな。 { true, false }                                                                          |
| indent_xml_string                    | 複数行のXML文字列をインデントするための半角空白の数 (indent_align_string=trueの場合のみ) { number }                                                                           |
| indent_brace                         | '{'をレベルからインデントさせる半角空白数 { number }                                                                                                                          |
| indent_braces                        | ボディレベルからブレースをインデントさせるかどうか { true, false }                                                                                                            |
| indent_braces_no_func                | 関数ブレースのインデントの無効化 (indent_bracesがtrueの時のみ) { true, false }                                                                                                |
| indent_braces_no_class               | クラスブレースのインデントの無効化 (indent_bracesがtrueの時のみ) { true, false }                                                                                              |
| indent_braces_no_struct              | 構造体ブレースのインデントの無効化 (indent_bracesがtrueの時のみ) { true, false }                                                                                              |
| indent_brace_parent                  | ブレースオーナーの文字数ベースでインデントする (例: 'if'なら空白3文字、'for'なら空白4文字) { true, false}                                                                     |
| indent_namespace                     | 'namespace'のボディをインデントさせるかどうか { true, false }                                                                                                                 |
| indent_namespace_level               | 名前空間ブロックをインデントさせる空白数 { number }                                                                                                                           |
| indent_namespace_limit               | 名前空間のボディがこの数字よりも長い場合、インデントしない。 (indent_namespace=trueの場合のみ) (0: 無制限) { number }                                                         |
| indent_extern                        | 'extern "C"'ボディをインデントさせるかどうか { true, false }                                                                                                                  |
| indent_class                         | 'class'ボディをインデントさせるかどうか { true, false }                                                                                                                       |
| indent_class_colon                   | クラス宣言の継承のコロンに続く文字をインデントさせるかどうか (indent_ctor_init_leading、indent_ctor_initと関連する) { true, false}                                            |
| indent_ctor_init_leading             | コンストラクタのメンバーイニシャライザの先頭の':'の (仮想的な) インデント幅。 (indent_class_colon=trueの場合のみ) (デフォルト:2) { number }                                   |
| indent_ctor_init                     | コンストラクタのメンバーイニシャライザの残りのリストに対する追加インデント (indent_class_colon=trueの場合のみ) { number }                                                     |
| indent_else_if                       | 'else\nif'の'if'をインデントするかどうか { true, false } |                                                                                                                    |
| indent_var_def_blk                   | '{'の後の行から始まる変数宣言のインデント幅の調整 (0: 調整なし、正値: カラム絶対値、負値: インデント相対値) { number }                                                        |
| indent_var_def_cont                  | 複数行に続く変数宣言を位置揃え (align) せずインデントする { true, false }                                                                                                     |
| indent_func_def_force_col1           | 関数定義のインデントを行頭から強制的に開始するかどうか { true, false }                                                                                                        |
| indent_func_call_param               | 複数行に続く関数コールの引数リストをインデントするか、位置揃えするか { true, false }                                                                                          |
| indent_func_def_param                | 複数行に続く関数定義の引数リストをインデントするか、位置揃えするか { true, false }                                                                                            |
| indent_func_proto_param              | 複数行に続くプロトタイプ宣言の引数リストをインデントするか、位置揃えするか { true, false }                                                                                    |
| indent_func_class_param              | 複数行に続くクラス宣言内のコンストラクタの引数リストをインデントするか、位置揃えするか { true, false }                                                                        |
| indent_func_ctor_var_param           | 複数行に続くクラスコンストラクタコールの引数リストをインデントするか、位置揃えするか { true, false }                                                                          |
| indent_template_param                | 複数行に続くテンプレートクラス宣言の引数リストをインデントするか、位置揃えするか { true, false }                                                                              |
| indent_func_param_double             | indent_func_xxx_paramオプションのインデント幅を2倍にする { true, false }                                                                                                      |
| indent_func_const                    | 関数宣言/プロトタイプの単独でぶら下がる'const'修飾子の絶対カラム位置 { number }                                                                                               |
| indent_func_throw                    | 関数宣言/プロトタイプの単独でぶら下がる'throw'修飾子の絶対カラム位置 { number }                                                                                               |
| indent_member                        | '->'もしくは'.'に続く位置揃えの半角空白数 (通常は0) { number }                                                                                                                |
| indent_sing_line_comments            | コード直前にある、1行以上の一行コメント ('//') を位置揃えするための半角空白数 { number }                                                                                      |
| indent_relative_single_line_comments | コードの後ろに続く一行コメント ('//') を相対的にインデントするかどうか { true, false }                                                                                        |
| indent_switch_case                   | 'switch'から'case'をインデントする半角空白数 (通常は、0か、indent_columnsで設定した値) { number }                                                                             |
| indent_case_shift                    | 'case'の中の他の行のインデントに影響を与えずに、'case'行だけを位置揃えするための半角空白数 (通常は0、インデント相対値) { number }                                             |
| indent_case_brace                    | 'case'の'{'をインデントする半角空白数 (通常は0、インデント相対値) { number }                                                                                                  |
| indent_col1_comment                  | 行頭に見つけたコメントをインデントさせるかどうか { true, false }                                                                                                              |
| indent_label                         | gotoラベルのインデント方法 (正値: カラム絶対値、負値: インデント相対値) { number }                                                                                            |
| indent_access_spec                   | コロンが続くアクセス指定子の場合 (正値: カラム絶対値、負値: インデント相対値) { number }                                                                                      |
| indent_access_spec_body              | アクセス指定子の後のコードを1レベルインデントするかどうか (indent_access_specは0に強制的に上書きされる) { true, false }                                                       |
| indent_paren_nl                      | '('に続けて改行されている時、次行からは'('の後に整列するよう位置揃えする (非推奨) { true, false }                                                                             |
| indent_paren_close                   | 改行後の')'のインデント方法 { 0: ボディレベルにインデントする 1: '('の位置に揃える 2: 直前の'{'レベルにインデントする }                                                       |
| indent_comma_paren                   | '()'内の改行直後の','のインデント方法 (trueの場合、'('の直下に位置揃えされる) { true, false }                                                                                 |
| indent_bool_paren                    | '()'内の改行直後のブール演算子のインデント方法 (trueの場合、'('の直下に位置揃えされる) { true, false }                                                                        |
| indent_first_bool_expr               | indent_bool_paren=true時の、最初の評価式のインデント方法 (trueなら次の行以降と位置揃えする) { true, false }                                                                   |
| indent_square_nl                     | '['に続けて改行されている時、次行からは'['の後に整列するよう位置揃えする (非推奨) { true, false }                                                                             |
| indent_preserve_sql                  | ESQL/Cの'EXEC SQL'ボディの相対インデントを変更しない { true, false }                                                                                                          |
| indent_align_assign                  | '='に続くステートメントをインデントするか、位置揃えするか (falseもしくは'='直後に改行場合、インデントする) { true, false }                                                    |
| indent_oc_block                      | Objective-Cブロックを通常ルールの代わりブレースレベルまでインデントするかどうか { true, false }                                                                               |
| indent_oc_block_msg                  | メッセージ内のObjective-Cブロックをパラメータ名に相対的にインデントする (0: indent_oc_blockルール >0: インデント半角空白数) { number }                                        |
| indent_oc_msg_colon                  | 継続するパラメータの最小インデント数 {number}                                                                                                                                 |

僕の設定
--------

```bash:indent.cfg
indent_columns                          = 4
indent_continue                         = 0
indent_with_tabs                        = 0
indent_align_string                     = false
indent_brace                            = 0
indent_braces                           = false
indent_brace_parent                     = false
indent_namespace                        = false
indent_extern                           = false
indent_class                            = true
indent_class_colon                      = true
indent_ctor_init_leading                = 4
indent_ctor_init                        = 0
indent_else_if                          = true
indent_var_def_blk                      = 0
indent_var_def_cont                     = false
indent_func_def_force_col1              = false
indent_func_call_param                  = false
indent_func_def_param                   = false
indent_func_proto_param                 = false
indent_func_class_param                 = false
indent_func_ctor_var_param              = false
indent_template_param                   = false
indent_func_param_double                = false
indent_func_const                       = 0
indent_func_throw                       = 0
indent_member                           = 0
indent_sing_line_comments               = 0
indent_relative_single_line_comments    = false
indent_switch_case                      = 4
indent_case_shift                       = 0
indent_case_brace                       = 0
indent_col1_comment                     = false
indent_label                            = 1
indent_access_spec                      = -4
indent_access_spec_body                 = false
indent_paren_nl                         = false
indent_paren_close                      = 0
indent_comma_paren                      = true
indent_bool_paren                       = false
indent_first_bool_expr                  = false
indent_square_nl                        = false
indent_preserve_sql                     = false
indent_align_assign                     = true
indent_oc_block                         = false
indent_oc_block_msg                     = 0
indent_oc_msg_colon                     = 0
```

INDENT_COLUMNS
--------------
```cpp:indent_columns.cpp
// indent_columns=4
// インデント幅は空白4個分
void func(void)
{
    /* indent with 4 spaces */
}
```

INDENT_CONTINUE
---------------
```cpp:indent_continues.cpp
// indent_continue = -1
// '='-改行の後の行は、前の行のインデントをキープする。
float newvalue =
oldvalue * factor;

// indent_continue = 0
// '='-改行の後は位置揃えする。
float newvalue =
    oldvalue * factor;

// indent_continue = 2
// '='-改行の後の行を、半角空白2個分で位置揃えする。
float newvalue =
  oldvalue * factor;
```

INDENT_WITH_TABS
----------------
```cpp:indent_with_tabs.cpp
// indent_with_tabs = 0
// インデントも位置揃えも半角空白を用いる。
if (foo) {
..../* an indent with spaces */
}

bar(var1,
....var2); /* an align with spaces */

// indent_with_tabs = 1
// インデントはタブを、位置揃えは半角空白を用いる。
if (foo) {
--->/* an indent with tabs */
}

bar(var1,
....var2); /* an align with spaces */

// indent_with_tabs = 2
// インデントも位置揃えもタブを用いる。
if (foo) {
--->/* an indent with tabs */
}

bar(var1,
--->var2); /* an align with tabs */
```

INDENT_CMT_WITH_TABS
--------------------
```cpp:indent_cmt_with_tabs.cpp
// indent_cmt_with_tabs = true
// コメントまでのスペースをタブ位置までタブ文字でスペーシングする。
int foo;--->--->--->..// こんな感じ

// indent_cmt_with_tabs = false
// コメントまでのスペースをタブ位置まで半角空白でスペーシングする。
int foo;..............// こんな感じ
```

INDENT_ALIGN_STRING
-------------------
```cpp:indent_align_string.cpp
// indent_align_string = true
printf("hello \
    world");

// indent_align_string = false
printf("hello \
world");
```

INDENT_BRACE
------------
```cpp:indent_brace.cpp
// indent_brace = 0
// ボディレベルと同じインデント位置に'{'、'}'を配置する。
void func(void)
{
    if (true)
    {
        if (true)
        {
            /* do something */
        }
    }
}

// indent_brace = 2
// ボディレベルから+2のインデント位置に'{'、'}'を配置する。
void func(void)
{
    if (true)
      {
          if (true)
            {
                /* do something */
            }
      }
}
```

INDENT_BRACES
-------------
```cpp:indent_braces.cpp
// indent_braces = true
// ボディレベルからインデントして'{'、'}'を配置する。
void func(void)
    {
    if (true)
        {
        if (true)
            {
            /* do something */
            }
        }
    }

// indent_braces = false
// ボディレベルと同じレベルで'{'、'}'を配置する。
void func(void)
{
    if (true)
    {
        if (true)
        {
            /* do something */
        }
    }
}
```

INDENT_BRACES_NO_FUNC
---------------------
```cpp:indent_braces_no_func.cpp
// indent_braces_no_func = true && indent_braces = true
// 関数ブレースはボディレベルからインデントせずに'{'、'}'を配置する。
void func(void)
{
    if (true)
        {
        if (true)
            {
            /* do something */
            }
        }
}

// indent_braces_no_func = false && indent_braces = true
// indent_bracesと同じ。
void func(void)
    {
    if (true)
        {
        if (true)
            {
            /* do something */
            }
        }
    }
```

INDENT_BRACES_NO_CLASS
----------------------
```cpp:indent_braces_no_class.cpp
// indent_braces_no_class = true
// クラスブレースはボディレベルからインデントせずに'{'、'}'を配置する。
// (これ、僕の環境ではちゃんと整形の確認できてないけど)
class Foo
{
    class Bar
    {
    };
};

// indent_braces_no_class = false
// indent_bracesと同じ
class Foo
    {
    class Bar
        {
        };
    };

```

INDENT_BRACES_NO_STRUCT
-----------------------
```cpp:indent_braces_no_struct.cpp
// indent_braces_no_struct = true
// 構造体ブレースはボディレベルからインデントせずに'{'、'}'を配置する。
struct foo
{
    struct bar
    {
    };
};

// indent_braces_no_struct = false
// indent_bracesと同じ
struct foo
    {
    struct bar
        {
        };
    };

```

INDENT_BRACE_PARENT
-------------------
```cpp:indent_brace_parent.cpp
// indent_brace_parent = true
// ifやforの文字数に揃えてインデントする。
void func(void)
{
    if (true)
       {
       }

    for ( ; ; )
        {
        }
}
```

INDENT_NAMESPACE
----------------
```cpp:indent_namespace.cpp
// indnet_namespace = true
// 'namespace'のボディをインデントする。
namespace FOO
{
    namespace BAR
    {
    }
}

// indent_namespace = false
// 'namespace'のボディをインデントしない。
namespace FOO
{
namespace BAR
{
}
}
```

INDENT_NAMESPACE_LEVEL
----------------------
```cpp:indent_namespace_level.cpp
// indent_namespace_level = 0 && indent_namespace = true
// 名前空間をベースインデント幅でインデントする。
namespace FOO
{
    namespace BAR
    {
    }
}

// indent_namespace_level = 2 && indent_namespace = true
// 名前空間を半角空白2個でインデントする。
namespace FOO
{
  namespace BAR
  {
  }
}
```

INDENT_NAMESPACE_LIMIT
----------------------
```cpp:indent_namespace_limit.cpp
// indent_namespace_limit = 3
// ボディが3行で (body <= limit) なのでインデントされる。
namespace FOO
{
    namespace BAR
    {
    }
}

// indent_namespace_limit = 4
// ボディが3行で (body < limit) でないのでインデントされない。
namespace FOO
{
namespace BAR
{
}
}
```

INDENT_EXTERN
-------------
```cpp:indent_extern.cpp
// indent_extern = true
// extern "C" ボディをインデントする。
extern "C"
{
    void foo(void);
    void bar(void);
}

// indent_extern = false
// extern "C" ボディをインデントしない。
extern "C"
{
void foo(void);
void bar(void);
}
```

INDENT_CLASS
------------
```cpp:indent_class.cpp
// indent_class = true
// クラスボディをインデントする。
class MyClass
{
    void foo(void);
    void bar(void);
};

// indent_class = false
// クラスボディをインデントしない。
class MyClass
{
void foo(void);
void bar(void);
};
```

INDENT_CLASS_COLON
------------------
```cpp:indent_class_colon.cpp
// indent_class_colon = true
// コンストラクタのイニシャライザのインデントを細かく整形する。
MyClass::MyClass()
    : m_member1(NULL),
      m_member2(NULL),
      m_member3(NULL),
      ...

// indent_class_colon = true
// コンストラクタのイニシャライザを適当にインデントする。
MyClass::MyClass()
    : m_member1(NULL),
    m_member2(NULL),
    m_member3(NULL)
      ...
```

INDENT_CTOR_INIT_LEADING
------------------------
```cpp:indent_ctor_init_leading.cpp
// indent_ctor_init_leading = 2
// メンバー初期化の1行目のコロンに対して2行目以降はインデント幅が半角空白2個分インデントされる。
MyClass::MyClass()
    : m_member1(NULL),
      m_member2(NULL),
      m_member3(NULL),
      ...
```

INDENT_CTOR_INIT
----------------
```cpp:indent_ctor_init.cpp
// indent_ctor_init = 2
// メンバー初期化全体が普通のコードインデントのインデント幅(4個)に加えて、更に+2個インデントされる。
MyClass::MyClass()
    >>: m_member1(NULL),
    >>  m_member2(NULL),
    >>  m_member3(NULL),
    >>  ...
```

INDENT_ELSE_IF
--------------
```cpp:indent_else_if.cpp
// indent_else_if = true
// 'else\nif'の'if'をインデントする。
if (foo)
{
    /* ... */
}
else
    if (bar)
    {
        /* ... */
    }

// indent_else_if = false
// 'else\nif'を'if'をインデントしない。
if (foo)
{
    /* ... */
}
else
if (bar)
{
    /* ... */
}
```

INDENT_VAR_DEF_BLK
------------------
```cpp:indent_var_def_blk.cpp
// indent_var_def_blk = -2
// 変数宣言はインデント位置から-2個下がった場所に位置揃えされる。
void func(void)
{
    {
      int i;
      int j;
      int k;

        /*
         * actually, this is the brace level indent.
         */
    }
}

// indent_var_def_blk = 2
// 変数宣言は先頭から2桁目に位置揃えされる。
void func(void)
{
    {
 int i;
 int j;
 int k;
    }
}
```

INDENT_VAR_DEF_CONT
-------------------
```cpp:indent_var_def_cont.cpp
// indent_var_def_cont = true
// 複数行の変数宣言を位置揃え (align) ではなくインデントする。
{
    const int integer1,
        integer2,
        integer3;
}

// indent_var_def_cont = false
// 複数行の変数宣言をインデントではなく位置揃え (align) する。
{
    const int integer1,
              integer2,
              integer3;
}
```

INDENT_FUNC_DEF_FORCE_COL1
----------------------
```cpp:indent_func_def_force_col1
// indent_func_def_force_col1 = true
// 関数定義のインテントを行頭にする。
class Foo
{
void bar(void);
};

// indent_func_def_force_col1 = false
// 関数定義を現在のコードのインデントレベルに合わせる。
class Foo
{
    void bar(void);
};
```

INDENT_FUNC_CALL_PARAM
----------------------
```cpp:indent_func_call_param.cpp
// indent_func_call_param = true
// 引数リストをインデントする。
{
    function(param1,
        param2,
        param3,
        param4);
}

// indent_func_call_param = false
// 引数リストを'('の下に位置揃えする。
{
    function(param1,
             param2,
             param3,
             param4);
}
```

INDENT_FUNC_DEF_PARAM
---------------------
```cpp:indent_func_def_param.cpp
// indent_func_def_param = true
// 引数リストをインデントする。
void function(int param1,
    int param2,
    int param3,
    int param4)
{
}

// indent_func_def_param = false
// 引数リストを'('の下に位置揃えする。
void function(int param1,
              int param2,
              int param3,
              int param4)
{
}
```

INDENT_FUNC_PROTO_PARAM
-----------------------
```cpp:indent_func_proto_param.cpp
// indent_func_proto_param = true
// 引数リストをインデントする。
void function(int param1,
    int param2,
    int param3,
    int param4);

// indent_func_proto_param = false
// 引数リストを'('の下に位置揃えする。
void function(int param1,
              int param2,
              int param3,
              int param4);
```

INDENT_FUNC_CLASS_PARAM
-----------------------
```cpp:indent_func_class_param.cpp
// indent_func_class_param = true
// 引数リストをインデントする。
class MyClass
{
    MyClass(int param1,
        int param2,
        int param3,
        int param4);
};

// indent_func_class_param = false
// 引数リストを'('の下に位置揃えする。
class MyClass
{
    MyClass(int param1,
            int param2,
            int param3,
            int param4);
};
```

INDENT_FUNC_CTOR_VAR_PARAM
--------------------------
```cpp:indent_func_ctor_var_param.cpp
// indent_func_ctor_var_param = true
// 引数リストをインデントする。
{
    MyClass object(param1,
        param2,
        param3,
        param4);
}

// indent_func_ctor_var_param = false
// 引数リストを'('の下に位置揃えする。
{
    MyClass object(param1,
                   param2,
                   param3,
                   param4);
}
```

INDENT_TEMPLATE_PARAM
---------------------
```cpp:indent_template_param.cpp
// indent_template_param = true
// 引数リストをインデントする。
template<typename T1,
    typename T2,
    typename T3,
    typename T4>
class Foo
{
};

// indent_template_param = false
// 引数リストを'<'の下に位置揃えする。
template<typename T1,
         typename T2,
         typename T3,
         typename T4>
class Foo
{
};
```

INDENT_FUNC_PARAM_DOUBLE
------------------------
```cpp:indent_func_param_double.cpp
// indent_func_param_double = false
// 引数リストをインデントする。
void function(int param1,
    int param2,
    int param3,
    int param4);

// indent_func_param_double = true
// 引数リストのインデントを倍にする。
void function(int param1,
        int param2,
        int param3,
        int param4);
```