Uncrustifyのセッティング (5) ポジション編

今回は
------
前回書いたアラインメントオプションとかインデントオプションとかが、非常にボリュームがあって、Qiitaで一つの記事をビューしようとしたら、途中で切れてたw。仕方がないので、前編と後編にそれぞれの記事を分割しました。まだ、空白オプションと改行オプションという地獄のようなオプションリストが残ってますが、まだバリエーションが少ないオプションの解説をしてきます。

今回、解説するのは、ポジショニングオプション。いくつかのトークン (プログラミング言語の構成要素) が行の先頭もしくは末尾に現れた時、行頭に置くべきか、それとも行末に置くべきか、悩んだりしますよね (しないかもしれませんが)。そんな時、ポジションがルール化されてたら嬉しいですよね。それを一つ一つ決めるのが、これらのオプションたちです。本当に、細かいところなので、別に設定する必要もないような気もします。プログラマの好みなど許さない！私のコーディング規約に従いなさいという人は、ここまで設定しちゃいましょう。

各ポジションオプションは、次の8種類の設定を選んでいきます。

- ignore <br/>
  この設定項目を無視します。すべてのポジションオプションのデフォルト値です。
- join <br />
  行頭もしくは行末に、そのトークンがあった場合、行と行をつなげます。
- lead <br />
  行末に、そのトークンがあった場合、そのトークンを次の行の行頭に挿入します。
- lead_break <br />
  行末に、そのトークンがあった場合、そのトークンを次の行の行頭に挿入します。
  また、そのトークンが、行中にある場合、そのトークンの直前で改行します。
- lead_force <br />
  行末に、そのトークンがあった場合、そのトークンを次の行の行頭に挿入します。
  また、そのトークンが、行中にある場合、そのトークンの直前で改行します。
  ただし、そのトークンしか行に存在しない場合、次の行の行頭に移動させます。
- trail <br />
  行頭に、そのトークンがあった場合、そのトークンを前の行の行末に挿入します。
- trail_break <br />
  行頭に、そのトークンがあった場合、そのトークンを前の行の行末に挿入します。
  また、そのトークンが、行中にある場合、そのトークンの直後で改行します。
- trail_force <br />
  行頭に、そのトークンがあった場合、そのトークンを前の行の行末に挿入します。
  また、そのトークンが、行中にある場合、そのトークンの直後で改行します。
  ただし、そのトークンしか行に存在しない場合、前の行の行末に移動させます。

leadとtrailの関係はこんな感じです。

```cpp:lead_trail.cpp
// こちらがleadである。'+'が行頭に置かれる。
int foo = bar
        + bar;

// こちらがtrailである。
int foo = bar +
          bar;
```

breakとforceの違いはこんな感じです。'+'が行末に置かれる。

```cpp:break_force.cpp
// 整形前
int foo = bar + bar +
bar
+
bar;

// こちらがbreakである。トークンごとに改行する。
int foo = bar +
          bar +
          bar
          +
          bar;


// こちらがforceである。トークン単独にならないようにする。
int foo = bar +
          bar +
          bar +
          bar;
```

それから、ポジション整形によって行頭や行末に移動されることとなったトークンのインデントやアラインメント、そして空白などは別のオプションによって決まります。特に、空白がない不格好なコードが生成されたりします。

そうやって結局設定していかなければ、気の利いたコード整形は実現されないということですかね。

ポジションオプション一覧
------------------------
ちなみに、私の環境では、pos_class_commaの設定がどうしても整形に反映されませんでした。

| 項目            | 説明                                                                                                                                        |
|:----------------|:--------------------------------------------------------------------------------------------------------------------------------------------|
| pos_arith       | 式が折り返す時の算術演算子の位置 { ignore, join, lead, lead_break, lead_force, trail, trail_break, trail_force }                            |
| pos_assign      | 式が折り返す時の代入演算子の位置 '{'が続く'='には影響しない { ignore, join, lead, lead_break, lead_force, trail, trail_break, trail_force } |
| pos_bool        | 式が折り返す時のブール演算子の位置 { ignore, join, lead, lead_break, lead_force, trail, trail_break, trail_force }                          |
| pos_compare     | 式が折り返す時の比較演算子の位置 { ignore, join, lead, lead_break, lead_force, trail, trail_break, trail_force }                            |
| pos_conditional | 式が折り返す時の三項演算子 (b ? t : f) の位置 { ignore, join, lead, lead_break, lead_force, trail, trail_break, trail_force }               |
| pos_comma       | 式が折り返す時の','の位置 { ignore, join, lead, lead_break, lead_force, trail, trail_break, trail_force }                                   |
| pos_class_comma | コンストラクタのメンバ初期化リストにおける','の位置 { ignore, join, lead, lead_break, lead_force, trail, trail_break, trail_force }         |
| pos_class_colon | コンストラクタとメンバ初期化の間の':'の位置 { ignore, join, lead, lead_break, lead_force, trail, trail_break, trail_force }                 |

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

```bash:position.cfg
pos_arith               = trail
pos_assign              = trail
pos_bool                = trail
pos_compare             = trail
pos_conditional         = trail
pos_comma               = trail
pos_class_comma         = trail
pos_class_colon         = lead
```

POS_ARITH
---------
```cpp:pos_arith.cpp
// pos_arith = lead
// '+'演算子は行頭に置かれる。
int foobar = foo + foo + foo
             + bar + bar + bar;
```

POS_ASSIGN
----------
```cpp:pos_assign.cpp
// pos_assign = lead
// '='演算子は行頭に置かれる。
int foobar
    = foo + bar;
```

POS_BOOL
--------
```cpp:pos_bool.cpp
// pos_bool = lead
// '&&'演算子は行頭に置かれる。
if (foo && foo && bar
    && bar)
```

POS_COMPARE
-----------
```cpp:pos_compare.cpp
// pos_compare = lead
// '>'演算子は行頭に置かれる。
if (foo + bar + foo
    > bar + bar + bar)
```

POS_CONDITIONAL
---------------
```cpp:pos_conditional.cpp
// pos_conditional = lead_break;
// '?' / ':'演算子は行頭に置かれる。
bool foo = (bar == boo)
           ? bee
           : bow;
```

POS_COMMA
---------
```cpp:pos_comma.cpp
// pos_comma = trail
// ','は行末に置かれる。
int foo1, foo2, foo3,
    bar1, bar2, bar3;
```

POS_CLASS_COMMA
---------------
```cpp:pos_class_comma.cpp
// pos_class_comma = lead
// クラスコンストラクタのメンバ初期化リストの','は行頭に置かれる。
class Foo
{
    Foo(int foo, int bar)
        : m_foo(foo)
        , m_foo(bar);
};
```

POS_CLASS_COLON
---------------
```cpp:pos_class_colon.cpp
// pos_class_colon = lead
// クラスコンストラクタのメンバ初期化リストの':'は行頭に置かれる。
class Foo
{
    Foo(int foo, int bar)
        : m_foo(foo)
        , m_foo(bar);
};
```