packages feed

hstyle-0.2.0.3: src/HStyle.hs

{-# LANGUAGE OverloadedStrings, Rank2Types #-}
module HStyle
    ( FileState (..)
    , Options (..)
    , checkStyle
    ) where

import Control.Monad (foldM, when)
import Data.List (isPrefixOf)
import Data.Maybe (fromMaybe)

import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified Language.Haskell.Exts.Annotated as H

import HStyle.Block
import HStyle.Rule
import HStyle.Rules.AppSpacing
import HStyle.Rules.CaseAlignment
import HStyle.Rules.DataAlignment
import HStyle.Rules.EolComment
import HStyle.Rules.LineLength
import HStyle.Rules.Tabs
import HStyle.Rules.TrailingWhiteSpace
import HStyle.Rules.TypeSigAlignment

-- | Filter out lines which use CPP macros
unCPP :: String -> String
unCPP = unlines . map unCpp' . lines
  where
    unCpp' x
        | "#" `isPrefixOf` x = ""
        | otherwise          = x

checkStyle :: Options -> FilePath -> IO FileState
checkStyle options file = do
    contents <- readFile file
    let block     = fromText $ T.pack contents
        -- Determine the extensions used in the file, and update the parsing
        -- mode based upon those
        exts      = fromMaybe [] $ H.readExtensions contents
        mode      = H.defaultParseMode
            {H.extensions = exts, H.fixities = Nothing}
        -- Special handling for CPP, haskell-src-exts can't deal with it
        contents' = if H.CPP `elem` exts then unCPP contents else contents
        fs        = FileState block False True
    case H.parseModuleWithComments mode contents' of
        H.ParseOk x -> do
            fs' <- foldM (runRule options file x) fs
                [ typeSigAlignmentRule
                , tabsRule 4
                , lineLengthRule 78
                , trailingWhiteSpaceRule
                , eolCommentRule
                , dataAlignmentRule
                , appSpacingRule
                , caseAlignmentRule
                ]
            when (fileUpdated fs') $ T.writeFile file $ toText $ fileBlock fs'
            return fs'
        err         -> do
            putStrLn $ "HStyle.checkStyle: could not parse " ++
                file ++ ": " ++ show err
            return fs