Help us understand the problem. What is going on with this article?

Delphi のソースコードフォーマッタ

はじめに

他人が書いた古いプロジェクトをマイグレーションする場合には、ソースコードをあらかじめソースコードフォーマッタで整形しておくといいと思います。

Delphi (Pascal) に不慣れな方、あるいはメインで Delphi を使っていない方が C++ とかの流儀で書いたコードは「気持ちは解るけどとても読みにくいんだ...」と思ってしまいます。逆もしかりなのでお互い様なんでしょうけどね...。

フォーマッタ

IDE ビルトインのソースコードフォーマッタは Delphi 2010 から実装されています。コマンドラインツール版 (formatter.exe) は Delphi XE から追加されています。

フォーマッタの使い方

DocWiki に詳細な記事があります。ざっくり言うと...

やりたい事 やり方
プロジェクトに含まれるすべてのソースコードファイルを整形する プロジェクトマネージャからプロジェクトを右クリックして [プロジェクトソースを整形...]
ソースコードファイル全体を整形する コードエディタ上で右クリックして [ソースの整形]
ソースコードファイルの一部を整形する コードエディタで整形したい部分をマウスで選択し、右クリックして [ソースの整形]

See also:

コマンドライン版フォーマッタ (formatter.exe) の使い方

コマンドライン版のフォーマッタもあります。DocWiki に詳細な記事があります。
image.png

See also:

フォーマッタの設定

フォーマッタの設定は [ツール | オプション] でオプションダイアログを出し、[言語 > フォーマッタ > Delphi] で設定できます。

[プロファイルと状態] では、設定をプロファイルとして保存する事もでき、標準で 3 つのプロファイルが用意されています。初期状態に戻すには Formatter_Default.config を指定して [適用] ボタンを押します。
image.png
標準で持っている 3 つのプロファイルの差異を調べてみました。

プロファイルファイル名
デフォルト Formatter_Default.config
コンパクト Formatter_Compact.config
ワイド Formatter_Wide.config

フォーマッタのプロファイルファイルは %AppData%\Embarcadero\BDS\nn.n にあります。
image.png
各設定項目の意味と凡例は下部に表示されているのですが、デフォルト状態では見切れているので、ガバッと広げましょう。

インデント

設定 Default Compact Wide
case ラベルのインデント はい いいえ はい
case 文の else のインデント いいえ いいえ はい
case 文の内容のインデント はい はい はい
ラベルのインデント 一段減らす 一段減らす 一段減らす
begin および end キーワードのインデント いいえ いいえ いいえ
begin と end で囲まれたブロックのインデント はい はい はい
interface セクション、implementation セクション、およびその他セクションのインデント いいえ いいえ いいえ
アセンブラ セクションのインデント はい はい はい
インデント位置の上限 40 40 40
クラス定義本体のインデント いいえ いいえ はい
コメントのインデント はい はい はい
コンパイラ指令のインデント いいえ いいえ いいえ
ネストした角かっこと丸かっこのインデント いいえ いいえ いいえ
関数本体のインデント いいえ いいえ はい
継続行のインデント 2 2 2
内部関数のインデント はい はい はい

スペース

設定 Default Compact Wide
// コメントのスペース設定 前後 前後 前後
{ および (* コメントのスペース設定 内側と外側 内側と外側 内側と外側
スペース競合の解消方法 スペース スペース スペース
代入演算子前後のスペース設定 前後 前後 前後
単項前置演算子前後のスペース設定 なし なし 前後
二項演算子前後のスペース設定 前後 前後 前後
ジェネリックスにおける山かっこの内側のスペース設定 いいえ いいえ はい
角かっこ前後のスペース設定 いいえ いいえ はい
丸かっこ内のスペース設定 いいえ いいえ はい
コロン前後のスペース設定 後のみ 後のみ 前後
コンマ前後のスペース設定 後のみ 後のみ 後のみ
セミコロン前後のスペース設定 後のみ 後のみ 後のみ
関数での丸かっこ前のスペース いいえ いいえ いいえ
書式内のコロン前後のスペース設定 なし なし なし

改行

設定 Default Compact Wide
begin キーワードの後で改行 はい はい はい
try-except ブロック内の単一命令文の前で改行 はい いいえ はい
メソッド定義の begin キーワードの後で改行 はい はい はい
制御文の begin キーワードの後で改行 はい はい はい
制御文の begin キーワードの前で改行 はい いいえ はい
制御文内の単一命令文の前で改行 はい いいえ はい
'else' と 'if' の間で改行 いいえ いいえ いいえ
'end else begin' 内での改行の削除 いいえ はい いいえ
'end else if' 内での改行の削除 いいえ はい いいえ
label 句、exports 句、requires 句、contains 句での改行 現状どおり いいえ はい
then キーワードの前で改行 いいえ いいえ はい
uses キーワードの後で改行 現状どおり いいえ はい
uses 句の中で改行 現状どおり いいえ はい
var セクションと const セクションの中で改行 はい いいえ はい
セミコロンの後で改行 はい はい はい
プロパティ宣言での改行 いいえ いいえ はい
ラベルの後で改行 はい いいえ はい
継承リストでの改行 いいえ いいえ いいえ
配列の初期化での改行 はい はい はい
無名関数使用時の改行 はい いいえ はい
無名関数の代入時の改行 いいえ いいえ はい
関数の戻り値型の改行 いいえ いいえ いいえ
関数呼び出しでパラメータごとに改行 いいえ いいえ いいえ
関数定義でパラメータごとに改行 いいえ いいえ はい
implementation セクションで区切り記号として使用される空行の数 1 1 1
interface セクションで区切り記号として使用される空行の数 1 1 1
type キーワード前の空行の数 1 0 1
コンパイラ指令前後の空行の数 0 0 0
サブセクション前の空行の数 1 1 1
セクション キーワード前後の空行の数 1 1 1
可視性修飾子前の空行の数 0 0 0
隣接する空行の最大数 1 1 1
ソースのトリミング はい はい はい
ユーザー入力の改行を保持 いいえ いいえ いいえ
右マージン 80 80 80
改行文字 システムのデフォルト値 システムのデフォルト値 システムのデフォルト値

大文字表記

設定 Default Compact Wide
コンパイラ指令の大文字表記 大文字で表記 大文字で表記 大文字で表記
その他の単語の大文字表記 最初の出現通り 最初の出現通り 最初の出現通り
数値の大文字表記 大文字で表記 大文字で表記 大文字で表記
予約語と指令の大文字表記 現状どおり 現状どおり 現状どおり

整列

設定 Default Compact Wide
パラメータ型の整列 いいえ いいえ はい
プロパティでのフィールドの整列 いいえ いいえ いいえ
型宣言での '=' の整列 いいえ いいえ いいえ
型名の整列 いいえ いいえ いいえ
行末コメントの整列 いいえ いいえ いいえ
初期化文での '=' の位置の整列 いいえ いいえ いいえ
代入演算子の整列 いいえ いいえ いいえ
定数宣言での '=' の整列 いいえ いいえ いいえ
型名の前での ':' の整列 いいえ いいえ いいえ
整列位置の上限 60 60 60
非整列行の最大数 0 0 0

個人的なオススメ設定

個人的なオススメ設定をデフォルトとの差異で書いてみたいと思います。理由も付記しておきます。

インデント

設定 オススメ
begin および end キーワードのインデント いいえ
コメントのインデント 1 いいえ
  • 個人的には begin および end キーワードのインデントはい にして J&W スタイル 2 にしたい所ですが、一般的ではないので。
  • コメントのインデントはそのままにしておかないと悲惨なことになります。

スペース

設定 オススメ
// コメントのスペース設定 1 スペースを保持
{ および (* コメントのスペース設定 1 スペースを保持
単項前置演算子前後のスペース設定 前後
  • コメントのスペースはそのままにしておかないと悲惨なことになります。
  • 10.1 Berlin 以前のフォーマッタは疑似プロパティ (Pseudo-Property) をブロックコメントとして認識してしまうバグがあるため、整形するとデータモジュールが壊れてしまいます。
  • 単項前置演算子というのは +, -, not です。個人的には not だけ前後にスペースが欲しいトコロですが、一緒になっているので仕方なく。前置の +, - ってそんなにないのでこれでいいかと。

See also:

改行

設定 オススメ

大文字表記

設定 オススメ
予約語と指令の大文字表記 小文字で表記
  • 予約語と指令は小文字に統一したい所。

整列

設定 オススメ
行末コメントの整列 はい
  • 狙った通りにならないかもしれませんが、整列しておくと後の編集が楽です。

個人的なイラッとポイント

■ 部分範囲型の .. の前後に強制的にスペースが入る

配列とかですね。

解決方法:
[SP]..[SP].. で全置換してしまえばいいと思います。全置換しても、問題が発生する事はそんなにないでしょう。

end. 行の前に必ず空行が入る

ユニットの時はいいですけど、プロジェクトソース / コンソールアプリケーション (*.dpr) だと違和感があります。

解決方法:
手動で削除しましょう。

■ フォーマッタはインライン変数宣言を知らない

10.3 Rio で実装されたインライン変数宣言を知りません。

解決方法:
なし。var セクションと const セクションの中で改行いいえ現状どおり に設定してもダメなときはダメみたいです。古いコードのマイグレーションでは問題にならないのでしょうけれど...。

See also:

■ フォーマッタはプログラマ定義の型 (New Type) を知らない

これは割と問題です。例えば次のようなレコード型は大丈夫なのですが、

type
  TRec = packed record
    ID: Integer;
    Password: string;
  end;

次のようなレコード型の配列は破綻します。

type
  TRecArr = array [1..10] of packed record
    ID: Integer;
    Password: string;
  end;

上記コードを実際に整形するとこうなります。

type
  TRecArr = array [1 .. 10] of packed record ID: Integer; // セミコロンで型定義の終わりだと思っている
Password:                                                 // ラベルだと思っている
string;                                                   // なにこれ?関数?
end;                                                      // 余剰の end; ができるので、以降の整形が破綻する

標準 Pascal でも可能な文法なのですが... 3

解決方法:
なし。あえていうなら事前にブロックコメントで保護するくらいでしょうか。
image.png

See also:

おわり

正直、コードフォーマッタにはバグがありますし、思った通りの結果は得られないかもしれません。それでも、大雑把に整形してあれば、その後の作業がかなり楽になると思うのでオススメです。

Delphi 2007? DelForExp を使えばいいんじゃないかな?
image.png


  1. これらをまとめて設定しておく事により、整形したくない場所をブロックコメントで保護できます。逆に言うと、コードをブロックコメントでコメントアウトしている場合、これらの設定をしないとブロックコメント内コードのインデントが破壊されます。 

  2. 詳しくはこちらを。 

  3. こういうのがあるから、Modula-2 のレコード型ではフィールドを | で区切るようになっているのでしょうね。 

ht_deko
とある熊本の障害復旧(トラブルシューター)
https://ht-deko.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away