content: -- | 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` queryEpAnn) a
    where
      queryLocated ::
        (Data e0) =>
        GenLocated e0 e1 ->
        Seq RealSrcSpan
      queryLocated (L mspn _) =
        maybe mempty srcSpanToRealSrcSpanSeq (cast mspn :: Maybe SrcSpan)
  
      queryEpAnn :: EpAnn ann -> Seq RealSrcSpan
      queryEpAnn = srcSpanToRealSrcSpanSeq . locA
  
      srcSpanToRealSrcSpanSeq =
        Seq.fromList . maybeToList . srcSpanToRealSrcSpan
  