Agda-2.3.2.2: src/fix-agda-whitespace/FixWhitespace.hs
import Control.Monad
import Data.Char as Char
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.IO as Text -- Strict IO.
import System.Environment
import System.Exit
import System.FilePath.Find
import System.IO
-- Configuration parameters.
extensions = [".hs", ".hs-boot", ".x", ".y", ".el"]
srcDir = "src"
-- Modes.
data Mode
= Fix -- ^ Fix whitespace issues.
| Check -- ^ Check if there are any whitespace issues.
deriving Eq
main = do
args <- getArgs
mode <- case args of
[] -> return Fix
["--check"] -> return Check
_ -> hPutStr stderr usage >> exitFailure
changes <-
mapM (fix mode) =<<
find always (foldr1 (||?) $ map (extension ==?) extensions) srcDir
when (or changes && mode == Check) exitFailure
-- | Usage info.
usage :: String
usage = unlines
[ "fix-agda-whitespace: Fixes whitespace issues for Agda sources."
, ""
, "Usage: fix-agda-whitespace [--check]"
, ""
, "This program should be run in the base directory."
, ""
, "By default the program does the following for every"
, list extensions ++ " file under " ++ srcDir ++ ":"
, "* Removes trailing whitespace."
, "* Removes trailing lines containing nothing but whitespace."
, "* Ensures that the file ends in a newline character."
, ""
, "With the --check flag the program does not change any files,"
, "it just checks if any files would have been changed. In this"
, "case it returns with a non-zero exit code."
, ""
, "Background: Agda was reported to fail to compile on Windows"
, "because a file did not end with a newline character (Agda"
, "uses -Werror)."
]
where
list [x] = x
list [x, y] = x ++ " and " ++ y
list (x : xs) = x ++ ", " ++ list xs
-- | Fix a file. Only performs changes if the mode is 'Fix'. Returns
-- 'True' iff any changes would have been performed in the 'Fix' mode.
fix :: Mode -> FilePath -> IO Bool
fix mode f = do
new <- withFile f ReadMode $ \h -> do
hSetEncoding h utf8
s <- Text.hGetContents h
let s' = transform s
return $ if s' == s then Nothing else Just s'
case new of
Nothing -> return False
Just s -> do
putStrLn $ "Whitespace violation " ++ (if mode == Fix then "fixed" else "detected") ++ " in " ++ f
when (mode == Fix) $
withFile f WriteMode $ \h -> do
hSetEncoding h utf8
Text.hPutStr h s
return True
-- | Transforms the contents of a file.
transform :: Text -> Text
transform =
Text.unlines .
removeFinalEmptyLinesExceptOne .
map removeTrailingWhitespace .
Text.lines
where
removeFinalEmptyLinesExceptOne =
reverse . dropWhile1 Text.null . reverse
removeTrailingWhitespace =
Text.dropWhileEnd Char.isSpace
-- | 'dropWhile' except keep the first of the dropped elements
dropWhile1 p [] = []
dropWhile1 p (x:xs)
| p x = x : dropWhile p xs
| otherwise = x : xs