Ormolu

formatter

メモ

  • CPP を含むファイルには使えない

  • フォーマット形式のカスタマイズはできない。

  • フォーマット前と後でパーズが成功するかどうかチェックしている

  • オリジナルとフォーマット後の AST の diff をチェックしている

  • フォーマッターの冪等性をテストでチェックしている

  • 言語拡張を自動的に並べ替えてくれる (LANGUAGE が大文字・小文字問わずに処理可能)

  • nix を使えば Hackage にアップロードされているパッケージに対してフォーマッターを試すことができる

  • { ; } を使って書いているコードにも対応している。

  • VS Code の Plugin ができた

  • オンラインで試せるようになった

  • vim の Plugin ができた

適用事例

インストール方法

公式には nix推奨されていましたが、cabal を使います。

cabal-install
λ git clone https://github.com/tweag/ormolu.git
λ cd ormolu/

λ cabal build
λ cabal install

# テストを実行する
λ cabal test --enable-tests

フォーマット形式について

使い方

λ ormolu --help
Usage: ormolu [-v|--version] [--manual-exts] [-m|--mode MODE] [-o|--ghc-opt OPT]
              [-u|--unsafe] [-d|--debug] [-p|--tolerate-cpp]
              [-c|--check-idempotency] [FILE]

Available options:
  -h,--help                Show this help text
  -v,--version             Print version of the program
  --manual-exts            Display extensions that need to be enabled manually
  -m,--mode MODE           Mode of operation: 'stdout', 'inplace', or 'check'
  -o,--ghc-opt OPT         GHC options to enable (e.g. language extensions)
  -u,--unsafe              Do formatting faster but without automatic detection
                           of defects
  -d,--debug               Output information useful for debugging
  -p,--tolerate-cpp        Do not fail if CPP pragma is present
  -c,--check-idempotency   Fail if formatting is not idempotent.
  FILE                     Haskell source files to format or stdin (default)基本形
λ ormolu Test.hs

# 複数のファイルを指定することもできる
λ ormolu Test.hs Test2.hs

言語拡張を指定する場合は -o オプションを利用します。ただ、デフォルトで多くの言語拡張が有効になっているため、あまり使う機会は無いかもしれません。

しかし、Remove language extension whitelist #163 で議論されているように、-XPatternSynonyms-XViewPatterns を組み合わせると良く無いようで、そういうものはデフォルトの言語拡張リストから除外されているため、明示的に有効にする必要があります。

λ ormolu -o -XPatternSynonyms TestExts.hs

フォーマット結果でファイルを上書きする場合は以下のようにします。

λ ormolu --mode inplace Test.hs

手動で有効にする必要があるパッケージについて

--manual-exts オプションで確認できる。これらの拡張は、導入されるキーワードによって既存の識別子が使えなくなるため手動で有効にしなければならない。

λ ormolu --manual-exts
Arrows
Cpp
PatternSynonyms
RecursiveDo
StaticPointers
TransformListComp
UnboxedTuples
MagicHash
AlternativeLayoutRule
AlternativeLayoutRuleTransitional
MonadComprehensions
UnboxedSums
TemplateHaskellQuotes

Hackage のパッケージで試す

λ nix-build -A hackage.<package>

冪等チェック

λ ormolu -c File.hs

指定したディレクトリ以下に対して再帰的に適用する

# src ディレクトリを対象に実行した例
λ ormolu --mode inplace $(find src -type f -name "*.hs")

# src, app, test ディレクトリを対象に実行した例
λ ormolu --mode inplace $(find src app test -type f -name "*.hs")

# src, app, test ディレクトリを対象に実行した例 (特定のディレクトリを除外)
λ ormolu --mode inplace $(find src app test -type f -name "*.hs" -not -path '.git' -not -path '*.dist-newstyle' -not -path '*.stack-work*')

Config 型

Config 型は以下の実装になっており、内部で parseDynamicFilePragma を呼ぶため、DynFlags であれば何でも指定できます。

data Config = Config
  { cfgDynOptions :: ![DynOption]
    -- ^ Dynamic options to pass to GHC parser
  , cfgUnsafe :: !Bool
    -- ^ Do formatting faster but without automatic detection of defects
  , cfgDebug :: !Bool
    -- ^ Output information useful for debugging
  , cfgTolerateCpp :: !Bool
    -- ^ Do not fail if CPP pragma is present (still doesn't handle CPP but
    -- useful for formatting of files that enable the extension without
    -- actually containing CPP macros)
  } deriving (Eq, Show)

repl デバッグ

λ cabal new-run exe:ormolu

λ cabal new-repl
> ormoluFile defaultConfig "data/examples/other/language-pragma.hs"

> ormoluFile defaultConfig "data/examples/other/language-pragma.hs" >>= putStrLn . T.unpack

Last updated