{-# Language CPP #-}
module HsImport.ImportPos
( findImportPos
, ImportPos(..)
, matchingImports
, bestMatchingImport
) where
import qualified Language.Haskell.Exts as HS
import Data.List.Index (ifoldl')
import Data.List.Split (splitOn)
import HsImport.Types
#if __GLASGOW_HASKELL__ < 710
import Control.Applicative ((<$>))
#endif
data ImportPos = Before ImportDecl
| After ImportDecl
deriving (Show, Eq)
findImportPos :: ImportDecl -> [ImportDecl] -> Maybe ImportPos
findImportPos newImport imports = After <$> bestMatchingImport name imports
where
HS.ModuleName _ name = HS.importModule newImport
matchingImports :: ModuleName -> [ImportDecl] -> [ImportDecl]
matchingImports moduleName imports =
[ i
| i@HS.ImportDecl {HS.importModule = HS.ModuleName _ name} <- imports
, moduleName == name
]
bestMatchingImport :: ModuleName -> [ImportDecl] -> Maybe ImportDecl
bestMatchingImport _ [] = Nothing
bestMatchingImport moduleName imports =
case ifoldl' computeMatches Nothing splittedMods of
Just (idx, _) -> Just $ imports !! idx
_ -> Nothing
where
computeMatches :: Maybe (Int, Int) -> Int -> [String] -> Maybe (Int, Int)
computeMatches matches idx mod =
let num' = numMatches splittedMod mod
in case matches of
Just (_, num) | num' >= num -> Just (idx, num')
| otherwise -> matches
Nothing | num' > 0 -> Just (idx, num')
| otherwise -> Nothing
where
numMatches = loop 0
where
loop num (a:as) (b:bs)
| a == b = loop (num + 1) as bs
| otherwise = num
loop num [] _ = num
loop num _ [] = num
splittedMod = splitOn "." moduleName
splittedMods = [ splitOn "." name
| HS.ImportDecl {HS.importModule = HS.ModuleName _ name} <- imports
]