-- | Build span stream from AST. module Ormolu.Printer.SpanStream ( SpanStream (..), mkSpanStream, ) where import Data.Data (Data) import Data.Foldable (toList) import Data.Generics (everything, ext1Q, ext2Q) import Data.List (sortOn) import Data.Maybe (maybeToList) import Data.Sequence (Seq) import Data.Sequence qualified as Seq import Data.Typeable (cast) import GHC.Parser.Annotation import GHC.Types.SrcLoc -- | A stream of 'RealSrcSpan's in ascending order. This allows us to tell -- e.g. whether there is another \"located\" element of AST between current -- element and comment we're considering for printing. newtype SpanStream = SpanStream [RealSrcSpan] deriving (Eq, Show, Data, Semigroup, Monoid) -- | Create 'SpanStream' from a data structure containing \"located\" -- elements. mkSpanStream :: (Data a) => -- | Data structure to inspect (AST) a -> SpanStream mkSpanStream a = SpanStream . sortOn realSrcSpanStart . toList $ everything mappend (const mempty `ext2Q` queryLocated `ext1Q` querySrcSpanAnn) a where queryLocated :: (Data e0) => GenLocated e0 e1 -> Seq RealSrcSpan queryLocated (L mspn _) = maybe mempty srcSpanToRealSrcSpanSeq (cast mspn :: Maybe SrcSpan) querySrcSpanAnn :: SrcSpanAnn' a -> Seq RealSrcSpan querySrcSpanAnn = srcSpanToRealSrcSpanSeq . locA srcSpanToRealSrcSpanSeq = Seq.fromList . maybeToList . srcSpanToRealSrcSpan