git-vogue-0.3.0.0: src/git-vogue-stylish.hs
--
-- Copyright © 2013-2015 Anchor Systems, Pty Ltd and Others
--
-- The code in this file, and the program it is a part of, is
-- made available to you by its authors as open source software:
-- you can redistribute it and/or modify it under the terms of
-- the 3-clause BSD licence.
--
-- | Description: Check and fix style differences with stylish-haskell
module Main where
import Control.Monad
import Data.Algorithm.Diff
import Data.Algorithm.DiffOutput
import Data.Foldable
import Data.List hiding (and)
import Data.Monoid hiding (First)
import Data.Traversable
import Git.Vogue.PluginCommon
import Language.Haskell.Stylish
import Prelude hiding (and)
import System.Exit
import System.IO hiding (hGetContents)
import System.IO.Strict (hGetContents)
main :: IO ()
main = do
cmd <- getPluginCommand
"Check your Haskell project for stylish-haskell-related problems."
"git-vogue-stylish - check for stylish-haskell problems"
cfg <- getConfig
f cfg cmd
where
hsFiles = filter (isSuffixOf ".hs")
f _ CmdName = putStrLn "stylish"
f cfg (CmdCheck check_fs_list _) = do
files <- read <$> readFile check_fs_list
rs <- traverse (stylishCheckFile cfg) (hsFiles files)
if and rs
then do
outputGood $ "Checked " <> show (length rs) <> " file(s)"
exitSuccess
else
exitFailure
f cfg (CmdFix check_fs_list _) = do
files <- read <$> readFile check_fs_list
let files' = hsFiles files
-- Fix all of the things first
traverse_ (stylishRunFile cfg) files'
-- Now double check they are fixed
rs <- traverse (stylishCheckFile cfg) files'
if and rs
then
outputGood "Style converged"
else do
outputBad "Style did not converge, bailing"
exitFailure
-- | Try various configuration locations as per stylish-haskell binary
getConfig
:: IO Config
getConfig =
-- Don't spew every file checked to stdout
let v = makeVerbose False
in do
config <- configFilePath v Nothing
loadConfig v config
-- | Checks whether running Stylish over a given file produces any differences.
-- Returns TRUE if there's nothing left to change.
-- Prints results and returns FALSE if there are things left to change.
stylishCheckFile
:: Config -- ^ Stylish Haskell config
-> FilePath -- ^ File to run through Stylish
-> IO Bool
stylishCheckFile cfg fp = stylishFile fp cfg (\original stylish ->
case getStyleDiffs original stylish of
[] -> return True
x -> do
outputBad $ "\x1b[33m" <> fp <> "\x1b[0m"
<> " has differing style:\n" <> ppDiff x
return False
)
-- | Runs Stylish over a given file. If there are changes, write them.
stylishRunFile
:: Config -- ^ Stylish Haskell config
-> FilePath -- ^ File to run through Stylish
-> IO ()
stylishRunFile cfg fp = stylishFile fp cfg $ \original stylish ->
unless (null $ getStyleDiffs original stylish) (writeFile fp stylish)
-- | Get diffs and filter out equivalent ones
getStyleDiffs
:: String
-> String
-> [Diff [String]]
getStyleDiffs original stylish = filter filterDiff $
getGroupedDiff (lines original) (lines stylish)
-- | Filters out equal diffs
filterDiff
:: (Eq a)
=> Diff a
-> Bool
filterDiff (Both a b) = a /= b
filterDiff _ = True
-- | Takes an original file, the Stylish version of the file, and does something
-- depending on the outcome of the Stylish transformation.
stylishFile
:: FilePath -- ^ File to run through Stylish
-> Config -- ^ Stylish Haskell config
-> (String -> String -> IO a)
-> IO a
stylishFile fp cfg fn = do
original <- readUTF8File fp
stylish <- stylishFile' (Just fp) cfg
fn original stylish
-- | Processes a single file, or stdin if no filepath is given
stylishFile'
:: Maybe FilePath -- ^ File to run through Stylish
-> Config -- ^ Stylish Haskell config
-> IO String
stylishFile' mfp conf = do
contents <- maybe getContents readUTF8File mfp
let result = runSteps (configLanguageExtensions conf)
mfp (configSteps conf) $ lines contents
case result of
Left err -> do
hPutStrLn stderr err
return contents
Right ok -> return $ unlines ok
-- | Loads a UTF8 file.
readUTF8File
:: FilePath -- ^ Filepath to read
-> IO String -- ^ File data
readUTF8File fp =
withFile fp ReadMode $ \h -> do
hSetEncoding h utf8
hGetContents h