module Nixfmt
( errorBundlePretty
, ParseErrorBundle
, Width
, 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 :: Width -> FilePath -> Text -> Either String Text
format :: Width -> String -> Text -> Either String Text
format Width
width String
filename
= (ParseErrorBundle Text Void -> String)
-> (File -> Text)
-> Either (ParseErrorBundle Text Void) File
-> Either String Text
forall a b c d. (a -> b) -> (c -> d) -> Either a c -> Either b d
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap ParseErrorBundle Text Void -> String
forall s e.
(VisualStream s, TraversableStream s, ShowErrorComponent e) =>
ParseErrorBundle s e -> String
errorBundlePretty (Width -> File -> Text
forall a. Pretty a => Width -> a -> Text
layout Width
width)
(Either (ParseErrorBundle Text Void) File -> Either String Text)
-> (Text -> Either (ParseErrorBundle Text Void) File)
-> Text
-> Either String Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Parsec Void Text File
-> String -> Text -> Either (ParseErrorBundle Text Void) File
forall e s a.
Parsec e s a -> String -> s -> Either (ParseErrorBundle s e) a
Megaparsec.parse Parsec Void Text File
file String
filename
formatVerify :: Width -> FilePath -> Text -> Either String Text
formatVerify :: Width -> String -> Text -> Either String Text
formatVerify Width
width String
path Text
unformatted = do
File
unformattedParsed <- Text -> Either String File
parse Text
unformatted
let formattedOnce :: Text
formattedOnce = Width -> File -> Text
forall a. Pretty a => Width -> a -> Text
layout Width
width File
unformattedParsed
File
formattedOnceParsed <- Text -> Either String File
parse Text
formattedOnce
let formattedTwice :: Text
formattedTwice = Width -> File -> Text
forall a. Pretty a => Width -> a -> Text
layout Width
width File
formattedOnceParsed
if File
formattedOnceParsed File -> File -> Bool
forall a. Eq a => a -> a -> Bool
/= File
unformattedParsed
then String -> Either String Text
forall {b}. String -> Either String b
pleaseReport String
"Parses differently after formatting."
else if Text
formattedOnce Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
/= Text
formattedTwice
then String -> Either String Text
forall {b}. String -> Either String b
pleaseReport String
"Nixfmt is not idempotent."
else Text -> Either String Text
forall a b. b -> Either a b
Right Text
formattedOnce
where
parse :: Text -> Either String File
parse = (ParseErrorBundle Text Void -> String)
-> Either (ParseErrorBundle Text Void) File -> Either String File
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first ParseErrorBundle Text Void -> String
forall s e.
(VisualStream s, TraversableStream s, ShowErrorComponent e) =>
ParseErrorBundle s e -> String
errorBundlePretty (Either (ParseErrorBundle Text Void) File -> Either String File)
-> (Text -> Either (ParseErrorBundle Text Void) File)
-> Text
-> Either String File
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Parsec Void Text File
-> String -> Text -> Either (ParseErrorBundle Text Void) File
forall e s a.
Parsec e s a -> String -> s -> Either (ParseErrorBundle s e) a
Megaparsec.parse Parsec Void Text File
file String
path
pleaseReport :: String -> Either String b
pleaseReport String
x = String -> Either String b
forall a b. a -> Either a b
Left (String -> Either String b) -> String -> Either String b
forall a b. (a -> b) -> a -> b
$ String
path String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
": " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
x String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
" This is a bug in nixfmt. Please report it at https://github.com/serokell/nixfmt"