packages feed

nixfmt-0.5.0: src/Nixfmt.hs

{- © 2019 Serokell <hi@serokell.io>
 - © 2019 Lars Jellema <lars.jellema@gmail.com>
 -
 - SPDX-License-Identifier: MPL-2.0
 -}

module Nixfmt
    ( errorBundlePretty
    , ParseErrorBundle
    , format
    , formatVerify
    ) where

import Data.Bifunctor (bimap, first)
import Data.Text (Text)
import qualified Text.Megaparsec as Megaparsec (parse)
import Text.Megaparsec.Error (errorBundlePretty)

import Nixfmt.Parser (file)
import Nixfmt.Predoc (layout)
import Nixfmt.Pretty ()
import Nixfmt.Types (ParseErrorBundle)

type Width = Int

-- | @format w filename source@ returns either a parsing error specifying a
-- failure in @filename@ or a formatted version of @source@ with a maximum width
-- of @w@ columns where possible.
format :: Width -> FilePath -> Text -> Either String Text
format width filename
    = bimap errorBundlePretty (layout width)
    . Megaparsec.parse file filename

formatVerify :: Width -> FilePath -> Text -> Either String Text
formatVerify width path unformatted = do
    unformattedParsed <- parse unformatted
    let formattedOnce = layout width unformattedParsed
    formattedOnceParsed <- parse formattedOnce
    let formattedTwice = layout width formattedOnceParsed
    if formattedOnceParsed /= unformattedParsed
    then pleaseReport "Parses differently after formatting."
    else if formattedOnce /= formattedTwice
    then pleaseReport "Nixfmt is not idempotent."
    else Right formattedOnce
    where
        parse = first errorBundlePretty . Megaparsec.parse file path
        pleaseReport x = Left $ path <> ": " <> x <> " This is a bug in nixfmt. Please report it at https://github.com/serokell/nixfmt"