{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedLabels #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RecordWildCards #-} -- | Rendering of import and export lists. module Ormolu.Printer.Meat.ImportExport ( p_hsmodExports, p_hsmodImport, ) where import Control.Monad import Data.Choice (pattern Without) import Data.Foldable (for_, traverse_) import GHC.Hs import GHC.LanguageExtensions.Type import GHC.Types.PkgQual import GHC.Types.SrcLoc import Ormolu.Printer.Combinators import Ormolu.Printer.Meat.Common import Ormolu.Printer.Meat.Declaration.Warning import Ormolu.Utils (RelativePos (..), attachRelativePos) p_hsmodExports :: [LIE GhcPs] -> R () p_hsmodExports xs = parens N $ do layout <- getLayout sep breakpoint (\(p, l) -> sitcc (located (addDocSrcSpan l) (p_lie layout p))) (attachRelativePos xs) where -- In order to correctly set the layout when a doc comment is present. addDocSrcSpan lie@(L l ie) = case ieExportDoc ie of Nothing -> lie Just (L l' _) -> L (l <> noAnnSrcSpan l') ie p_hsmodImport :: ImportDecl GhcPs -> R () p_hsmodImport ImportDecl {..} = do useQualifiedPost <- isExtensionEnabled ImportQualifiedPost txt "import" space when (ideclSource == IsBoot) (txt "{-# SOURCE #-}") space when ideclSafe (txt "safe") space when (isImportDeclQualified ideclQualified && not useQualifiedPost) (txt "qualified") space case ideclPkgQual of NoRawPkgQual -> return () RawPkgQual slit -> atom slit space inci $ do located ideclName atom when (isImportDeclQualified ideclQualified && useQualifiedPost) (space >> txt "qualified") case ideclAs of Nothing -> return () Just l -> do space txt "as" space located l atom space case ideclImportList of Nothing -> return () Just (hiding, L _ xs) -> do case hiding of Exactly -> pure () EverythingBut -> txt "hiding" breakpoint parens N $ do layout <- getLayout sep breakpoint (\(p, l) -> sitcc (located l (p_lie layout p))) (attachRelativePos xs) newline p_lie :: Layout -> RelativePos -> IE GhcPs -> R () p_lie encLayout relativePos = \case IEVar mwarn l1 exportDoc -> do for_ mwarn $ \warnTxt -> do located warnTxt p_warningTxt breakpoint located l1 p_ieWrappedName p_comma p_exportDoc exportDoc IEThingAbs _ l1 exportDoc -> do located l1 p_ieWrappedName p_comma p_exportDoc exportDoc IEThingAll _ l1 exportDoc -> do located l1 p_ieWrappedName space txt "(..)" p_comma p_exportDoc exportDoc IEThingWith _ l1 w xs exportDoc -> do sitcc $ do located l1 p_ieWrappedName breakpoint inci $ do let names :: [R ()] names = located' p_ieWrappedName <$> xs parens N . sep commaDel sitcc $ case w of NoIEWildcard -> names IEWildcard n -> let (before, after) = splitAt n names in before ++ [txt ".."] ++ after p_comma p_exportDoc exportDoc IEModuleContents _ l1 -> do located l1 p_hsmodName p_comma IEGroup NoExtField n str -> do case relativePos of SinglePos -> return () FirstPos -> return () MiddlePos -> newline LastPos -> newline p_hsDoc (Asterisk n) (Without #endNewline) str IEDoc NoExtField str -> p_hsDoc Pipe (Without #endNewline) str IEDocNamed NoExtField str -> p_hsDocName str where p_comma = case encLayout of SingleLine -> case relativePos of SinglePos -> return () FirstPos -> comma MiddlePos -> comma LastPos -> return () MultiLine -> comma -- This is used to support `@since` annotations for (re)exported items. It -- /must/ use caret style comments, see -- https://gitlab.haskell.org/ghc/ghc/-/merge_requests/12098 and -- https://github.com/haskell/haddock/issues/1629#issuecomment-1931354411. p_exportDoc :: Maybe (ExportDoc GhcPs) -> R () p_exportDoc = traverse_ $ \exportDoc -> do breakpoint p_hsDoc Caret (Without #endNewline) exportDoc ieExportDoc :: IE GhcPs -> Maybe (ExportDoc GhcPs) ieExportDoc = \case IEVar _ _ doc -> doc IEThingAbs _ _ doc -> doc IEThingAll _ _ doc -> doc IEThingWith _ _ _ _ doc -> doc IEModuleContents {} -> Nothing IEGroup {} -> Nothing IEDoc {} -> Nothing IEDocNamed {} -> Nothing