-- | Helper functions for dealing with import declarations.
module HIndent.Pretty.Import
  ( importsExist
  , extractImports
  , extractImportsSorted
  , groupImports
  ) where

import GHC.Hs
import GHC.Types.SrcLoc
import HIndent.Pretty.Import.Sort

-- | Returns if the module has import declarations.
importsExist :: HsModule -> Bool
importsExist :: HsModule -> Bool
importsExist = Bool -> Bool
not (Bool -> Bool) -> (HsModule -> Bool) -> HsModule -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [GenLocated SrcSpanAnnA (ImportDecl GhcPs)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([GenLocated SrcSpanAnnA (ImportDecl GhcPs)] -> Bool)
-> (HsModule -> [GenLocated SrcSpanAnnA (ImportDecl GhcPs)])
-> HsModule
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HsModule -> [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
HsModule -> [LImportDecl GhcPs]
hsmodImports

-- | Extracts import declarations from the given module. Adjacent import
-- declarations are grouped as a single list.
extractImports :: HsModule -> [[LImportDecl GhcPs]]
extractImports :: HsModule -> [[LImportDecl GhcPs]]
extractImports = [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
-> [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]]
[LImportDecl GhcPs] -> [[LImportDecl GhcPs]]
groupImports ([GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
 -> [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]])
-> (HsModule -> [GenLocated SrcSpanAnnA (ImportDecl GhcPs)])
-> HsModule
-> [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
-> [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
[LImportDecl GhcPs] -> [LImportDecl GhcPs]
sortImportsByLocation ([GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
 -> [GenLocated SrcSpanAnnA (ImportDecl GhcPs)])
-> (HsModule -> [GenLocated SrcSpanAnnA (ImportDecl GhcPs)])
-> HsModule
-> [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HsModule -> [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
HsModule -> [LImportDecl GhcPs]
hsmodImports

-- | Extracts import declarations from the given module and sorts them by
-- their names. Adjacent import declarations are grouped as a single list.
extractImportsSorted :: HsModule -> [[LImportDecl GhcPs]]
extractImportsSorted :: HsModule -> [[LImportDecl GhcPs]]
extractImportsSorted = ([GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
 -> [GenLocated SrcSpanAnnA (ImportDecl GhcPs)])
-> [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]]
-> [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
-> [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
[LImportDecl GhcPs] -> [LImportDecl GhcPs]
sortImportsByName ([[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]]
 -> [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]])
-> (HsModule -> [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]])
-> HsModule
-> [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HsModule -> [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]]
HsModule -> [[LImportDecl GhcPs]]
extractImports

-- | Combines adjacent import declarations into a single list.
groupImports :: [LImportDecl GhcPs] -> [[LImportDecl GhcPs]]
groupImports :: [LImportDecl GhcPs] -> [[LImportDecl GhcPs]]
groupImports = [[LImportDecl GhcPs]]
-> [LImportDecl GhcPs] -> [[LImportDecl GhcPs]]
groupImports' []
  where
    groupImports' ::
         [[LImportDecl GhcPs]] -> [LImportDecl GhcPs] -> [[LImportDecl GhcPs]]
    groupImports' :: [[LImportDecl GhcPs]]
-> [LImportDecl GhcPs] -> [[LImportDecl GhcPs]]
groupImports' [[LImportDecl GhcPs]]
xs [] = [[LImportDecl GhcPs]]
xs
    groupImports' [] (LImportDecl GhcPs
x:[LImportDecl GhcPs]
xs) = [[LImportDecl GhcPs]]
-> [LImportDecl GhcPs] -> [[LImportDecl GhcPs]]
groupImports' [[LImportDecl GhcPs
x]] [LImportDecl GhcPs]
xs
    groupImports' [[]] (LImportDecl GhcPs
x:[LImportDecl GhcPs]
xs) = [[LImportDecl GhcPs]]
-> [LImportDecl GhcPs] -> [[LImportDecl GhcPs]]
groupImports' [[LImportDecl GhcPs
x]] [LImportDecl GhcPs]
xs
    groupImports' ([]:[LImportDecl GhcPs]
x:[[LImportDecl GhcPs]]
xs) (LImportDecl GhcPs
y:[LImportDecl GhcPs]
ys) = [[LImportDecl GhcPs]]
-> [LImportDecl GhcPs] -> [[LImportDecl GhcPs]]
groupImports' ([GenLocated SrcSpanAnnA (ImportDecl GhcPs)
LImportDecl GhcPs
y] [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
-> [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]]
-> [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]]
forall a. a -> [a] -> [a]
: [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
[LImportDecl GhcPs]
x [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
-> [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]]
-> [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]]
forall a. a -> [a] -> [a]
: [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]]
[[LImportDecl GhcPs]]
xs) [LImportDecl GhcPs]
ys
    groupImports' ((LImportDecl GhcPs
z:[LImportDecl GhcPs]
zs):[[LImportDecl GhcPs]]
xs) (LImportDecl GhcPs
y:[LImportDecl GhcPs]
ys)
      | GenLocated SrcSpanAnnA (ImportDecl GhcPs)
LImportDecl GhcPs
z GenLocated SrcSpanAnnA (ImportDecl GhcPs)
-> GenLocated SrcSpanAnnA (ImportDecl GhcPs) -> Bool
forall {a} {e} {a} {e}.
GenLocated (SrcSpanAnn' a) e
-> GenLocated (SrcSpanAnn' a) e -> Bool
`isAdjacentTo` GenLocated SrcSpanAnnA (ImportDecl GhcPs)
LImportDecl GhcPs
y = [[LImportDecl GhcPs]]
-> [LImportDecl GhcPs] -> [[LImportDecl GhcPs]]
groupImports' ((GenLocated SrcSpanAnnA (ImportDecl GhcPs)
LImportDecl GhcPs
y GenLocated SrcSpanAnnA (ImportDecl GhcPs)
-> [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
-> [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
forall a. a -> [a] -> [a]
: GenLocated SrcSpanAnnA (ImportDecl GhcPs)
LImportDecl GhcPs
z GenLocated SrcSpanAnnA (ImportDecl GhcPs)
-> [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
-> [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
forall a. a -> [a] -> [a]
: [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
[LImportDecl GhcPs]
zs) [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
-> [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]]
-> [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]]
forall a. a -> [a] -> [a]
: [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]]
[[LImportDecl GhcPs]]
xs) [LImportDecl GhcPs]
ys
      | Bool
otherwise = [[LImportDecl GhcPs]]
-> [LImportDecl GhcPs] -> [[LImportDecl GhcPs]]
groupImports' ([GenLocated SrcSpanAnnA (ImportDecl GhcPs)
LImportDecl GhcPs
y] [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
-> [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]]
-> [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]]
forall a. a -> [a] -> [a]
: (GenLocated SrcSpanAnnA (ImportDecl GhcPs)
LImportDecl GhcPs
z GenLocated SrcSpanAnnA (ImportDecl GhcPs)
-> [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
-> [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
forall a. a -> [a] -> [a]
: [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
[LImportDecl GhcPs]
zs) [GenLocated SrcSpanAnnA (ImportDecl GhcPs)]
-> [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]]
-> [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]]
forall a. a -> [a] -> [a]
: [[GenLocated SrcSpanAnnA (ImportDecl GhcPs)]]
[[LImportDecl GhcPs]]
xs) [LImportDecl GhcPs]
ys
    GenLocated (SrcSpanAnn' a) e
a isAdjacentTo :: GenLocated (SrcSpanAnn' a) e
-> GenLocated (SrcSpanAnn' a) e -> Bool
`isAdjacentTo` GenLocated (SrcSpanAnn' a) e
b =
      RealSrcSpan -> Int
srcSpanEndLine (GenLocated (SrcSpanAnn' a) e -> RealSrcSpan
forall {a} {e}. GenLocated (SrcSpanAnn' a) e -> RealSrcSpan
sp GenLocated (SrcSpanAnn' a) e
a) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== RealSrcSpan -> Int
srcSpanStartLine (GenLocated (SrcSpanAnn' a) e -> RealSrcSpan
forall {a} {e}. GenLocated (SrcSpanAnn' a) e -> RealSrcSpan
sp GenLocated (SrcSpanAnn' a) e
b) Bool -> Bool -> Bool
||
      RealSrcSpan -> Int
srcSpanEndLine (GenLocated (SrcSpanAnn' a) e -> RealSrcSpan
forall {a} {e}. GenLocated (SrcSpanAnn' a) e -> RealSrcSpan
sp GenLocated (SrcSpanAnn' a) e
b) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== RealSrcSpan -> Int
srcSpanStartLine (GenLocated (SrcSpanAnn' a) e -> RealSrcSpan
forall {a} {e}. GenLocated (SrcSpanAnn' a) e -> RealSrcSpan
sp GenLocated (SrcSpanAnn' a) e
a)
    sp :: GenLocated (SrcSpanAnn' a) e -> RealSrcSpan
sp GenLocated (SrcSpanAnn' a) e
x =
      case SrcSpanAnn' a -> SrcSpan
forall a. SrcSpanAnn' a -> SrcSpan
locA (SrcSpanAnn' a -> SrcSpan) -> SrcSpanAnn' a -> SrcSpan
forall a b. (a -> b) -> a -> b
$ GenLocated (SrcSpanAnn' a) e -> SrcSpanAnn' a
forall l e. GenLocated l e -> l
getLoc GenLocated (SrcSpanAnn' a) e
x of
        RealSrcSpan RealSrcSpan
x' Maybe BufSpan
_ -> RealSrcSpan
x'
        SrcSpan
_ -> [Char] -> RealSrcSpan
forall a. HasCallStack => [Char] -> a
error [Char]
"Src span unavailable."