module Language.Haskell.Brittany.Internal.Layouters.Import (layoutImport) where #include "prelude.inc" import Language.Haskell.Brittany.Internal.Types import Language.Haskell.Brittany.Internal.LayouterBasics import Language.Haskell.Brittany.Internal.Layouters.IE import Language.Haskell.Brittany.Internal.Config.Types import GHC ( unLoc , GenLocated(L) , moduleNameString , Located ) import HsSyn import Name import FieldLabel import qualified FastString import BasicTypes import Language.Haskell.Brittany.Internal.Utils #if MIN_VERSION_ghc(8,2,0) prepPkg :: SourceText -> String prepPkg rawN = case rawN of SourceText n -> n -- This would be odd to encounter and the -- result will most certainly be wrong NoSourceText -> "" #else prepPkg :: String -> String prepPkg = id #endif #if MIN_VERSION_ghc(8,2,0) prepModName :: Located e -> e prepModName = unLoc #else prepModName :: e -> e prepModName = id #endif layoutImport :: ToBriDoc ImportDecl layoutImport limportD@(L _ importD) = docWrapNode limportD $ case importD of #if MIN_VERSION_ghc(8,6,0) ImportDecl _ _ (L _ modName) pkg src safe q False mas mllies -> do #else ImportDecl _ (L _ modName) pkg src safe q False mas mllies -> do #endif importCol <- mAsk <&> _conf_layout .> _lconfig_importColumn .> confUnpack importAsCol <- mAsk <&> _conf_layout .> _lconfig_importAsColumn .> confUnpack indentPolicy <- mAsk <&> _conf_layout .> _lconfig_indentPolicy .> confUnpack let compact = indentPolicy /= IndentPolicyFree modNameT = Text.pack $ moduleNameString modName pkgNameT = Text.pack . prepPkg . sl_st <$> pkg masT = Text.pack . moduleNameString . prepModName <$> mas hiding = maybe False fst mllies minQLength = length "import qualified " qLengthReal = let qualifiedPart = if q then length "qualified " else 0 safePart = if safe then length "safe " else 0 pkgPart = maybe 0 ((+ 1) . Text.length) pkgNameT srcPart = if src then length "{-# SOURCE #-} " else 0 in length "import " + srcPart + safePart + qualifiedPart + pkgPart qLength = max minQLength qLengthReal -- Cost in columns of importColumn asCost = length "as " hidingParenCost = if hiding then length "hiding ( " else length "( " nameCost = Text.length modNameT + qLength importQualifiers = docSeq [ appSep $ docLit $ Text.pack "import" , if src then appSep $ docLit $ Text.pack "{-# SOURCE #-}" else docEmpty , if safe then appSep $ docLit $ Text.pack "safe" else docEmpty , if q then appSep $ docLit $ Text.pack "qualified" else docEmpty , maybe docEmpty (appSep . docLit) pkgNameT ] indentName = if compact then id else docEnsureIndent (BrIndentSpecial qLength) modNameD = indentName $ appSep $ docLit modNameT hidDocCol = if hiding then importCol - hidingParenCost else importCol - 2 hidDocColDiff = importCol - 2 - hidDocCol hidDoc = if hiding then appSep $ docLit $ Text.pack "hiding" else docEmpty importHead = docSeq [importQualifiers, modNameD] bindingsD = case mllies of Nothing -> docEmpty Just (_, llies) -> do hasComments <- hasAnyCommentsBelow llies if compact then docAlt [ docSeq [hidDoc, docForceSingleline $ layoutLLIEs True llies] , let makeParIfHiding = if hiding then docAddBaseY BrIndentRegular . docPar hidDoc else id in makeParIfHiding (layoutLLIEs True llies) ] else do ieDs <- layoutAnnAndSepLLIEs llies docWrapNodeRest llies $ docEnsureIndent (BrIndentSpecial hidDocCol) $ case ieDs of -- ..[hiding].( ) [] -> if hasComments then docPar (docSeq [hidDoc, docParenLSep, docWrapNode llies docEmpty]) (docEnsureIndent (BrIndentSpecial hidDocColDiff) docParenR) else docSeq [hidDoc, docParenLSep, docSeparator, docParenR] -- ..[hiding].( b ) [ieD] -> runFilteredAlternative $ do addAlternativeCond (not hasComments) $ docSeq [ hidDoc , docParenLSep , docForceSingleline ieD , docSeparator , docParenR ] addAlternative $ docPar (docSeq [hidDoc, docParenLSep, docNonBottomSpacing ieD]) (docEnsureIndent (BrIndentSpecial hidDocColDiff) docParenR) -- ..[hiding].( b -- , b' -- ) (ieD:ieDs') -> docPar (docSeq [hidDoc, docSetBaseY $ docSeq [docParenLSep, ieD]]) ( docEnsureIndent (BrIndentSpecial hidDocColDiff) $ docLines $ ieDs' ++ [docParenR] ) makeAsDoc asT = docSeq [appSep $ docLit $ Text.pack "as", appSep $ docLit asT] if compact then let asDoc = maybe docEmpty makeAsDoc masT in docAlt [ docForceSingleline $ docSeq [importHead, asDoc, bindingsD] , docAddBaseY BrIndentRegular $ docPar (docSeq [importHead, asDoc]) bindingsD ] else case masT of Just n -> if enoughRoom then docLines [ docSeq [importHead, asDoc], bindingsD] else docLines [importHead, asDoc, bindingsD] where enoughRoom = nameCost < importAsCol - asCost asDoc = docEnsureIndent (BrIndentSpecial (importAsCol - asCost)) $ makeAsDoc n Nothing -> if enoughRoom then docSeq [importHead, bindingsD] else docLines [importHead, bindingsD] where enoughRoom = nameCost < importCol - hidingParenCost _ -> docEmpty