module HsImport.ImportPos
( findImportPos
, ImportPos(..)
, matchingImports
, bestMatchingImport
) where
import qualified Language.Haskell.Exts as HS
import Data.List.Split (splitOn)
import Control.Lens
#if __GLASGOW_HASKELL__ < 710
import Control.Applicative ((<$>))
#endif
type ModuleName = String
data ImportPos = Before HS.ImportDecl
| After HS.ImportDecl
deriving (Show, Eq)
findImportPos :: HS.ImportDecl -> [HS.ImportDecl] -> Maybe ImportPos
findImportPos newImport imports = After <$> bestMatchingImport name imports
where
HS.ModuleName name = HS.importModule newImport
matchingImports :: ModuleName -> [HS.ImportDecl] -> [HS.ImportDecl]
matchingImports moduleName imports =
[ i
| i@HS.ImportDecl {HS.importModule = HS.ModuleName name} <- imports
, moduleName == name
]
bestMatchingImport :: ModuleName -> [HS.ImportDecl] -> Maybe HS.ImportDecl
bestMatchingImport _ [] = Nothing
bestMatchingImport moduleName imports =
case ifoldl' computeMatches Nothing splittedMods of
Just (idx, _) -> Just $ imports !! idx
_ -> Nothing
where
computeMatches :: Int -> Maybe (Int, Int) -> [String] -> Maybe (Int, Int)
computeMatches idx matches 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
]