packages feed

hindent-6.3.0: src/HIndent/Ast/Import.hs

{-# LANGUAGE CPP #-}
{-# LANGUAGE RecordWildCards #-}

module HIndent.Ast.Import
  ( Import
  , mkImport
  , sortByName
  ) where

import Control.Monad
import Data.Function
import Data.List (sortBy)
import qualified GHC.Types.SourceText as GHC
import qualified GHC.Unit as GHC
import HIndent.Applicative
import HIndent.Ast.Import.Entry.Collection
import HIndent.Ast.Module.Name (ModuleName, mkModuleName)
import HIndent.Ast.NodeComments
import HIndent.Ast.WithComments
import qualified HIndent.GhcLibParserWrapper.GHC.Hs as GHC
import qualified HIndent.GhcLibParserWrapper.GHC.Hs.ImpExp as GHC
import HIndent.Pretty
import HIndent.Pretty.Combinators
import HIndent.Pretty.NodeComments

data QualificationPosition
  = Pre
  | Post
  deriving (Eq)

data Import = Import
  { moduleName :: WithComments ModuleName
  , isSafe :: Bool
  , isBoot :: Bool
  , qualifiedAs :: Maybe (WithComments ModuleName)
  , qualification :: Maybe QualificationPosition
  , packageName :: Maybe GHC.StringLiteral
  , importEntries :: Maybe (WithComments ImportEntryCollection)
  }

instance CommentExtraction Import where
  nodeComments Import {} = NodeComments [] [] []

instance Pretty Import where
  pretty' Import {..} = do
    string "import "
    when isBoot $ string "{-# SOURCE #-} "
    when isSafe $ string "safe "
    when (qualification == Just Pre) $ string "qualified "
    whenJust packageName $ \name -> pretty name >> space
    pretty moduleName
    when (qualification == Just Post) $ string " qualified"
    case qualifiedAs of
      Just name -> string " as " >> pretty name
      _ -> pure ()
    whenJust importEntries pretty

mkImport :: GHC.ImportDecl GHC.GhcPs -> Import
mkImport decl@GHC.ImportDecl {..} = Import {..}
  where
    moduleName = mkModuleName <$> fromGenLocated ideclName
    isSafe = ideclSafe
    isBoot = ideclSource == GHC.IsBoot
    qualification =
      case ideclQualified of
        GHC.NotQualified -> Nothing
        GHC.QualifiedPre -> Just Pre
        GHC.QualifiedPost -> Just Post
    qualifiedAs = fmap mkModuleName . fromGenLocated <$> ideclAs
    packageName = GHC.getPackageName decl
    importEntries = mkImportEntryCollection decl

sortByName :: [WithComments Import] -> [WithComments Import]
sortByName = fmap sortExplicitImportsInDecl . sortByModuleName

-- | This function sorts import declarations by their module names.
sortByModuleName :: [WithComments Import] -> [WithComments Import]
sortByModuleName = sortBy (compare `on` getNode . moduleName . getNode)

-- | This function sorts explicit imports in the given import declaration
-- by their names.
sortExplicitImportsInDecl :: WithComments Import -> WithComments Import
sortExplicitImportsInDecl = fmap f
  where
    f (Import {importEntries = Just xs, ..}) =
      Import {importEntries = Just sorted, ..}
      where
        sorted = fmap sortEntriesByName xs
    f x = x