{-# LANGUAGE BangPatterns      #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE Safe              #-}


-- |
-- Copyright: © Herbert Valerio Riedel 2015-2018
-- SPDX-License-Identifier: GPL-2.0-or-later
--
-- Event-stream oriented YAML writer API
--
module Data.YAML.Event.Writer
    ( writeEvents
    , writeEventsText
    ) where

import           Data.YAML.Event.Internal

import qualified Data.ByteString.Lazy     as BS.L
import qualified Data.Char                as C
import qualified Data.Map                 as Map
import qualified Data.Text                as T
import           Text.Printf              (printf)

import qualified Data.Text.Lazy           as T.L
import qualified Data.Text.Lazy.Builder   as T.B
import qualified Data.Text.Lazy.Encoding  as T.L

import           Util


{- WARNING: the code that follows will make you cry; a safety pig is provided below for your benefit.

                         _
 _._ _..._ .-',     _.._(`))
'-. `     '  /-._.-'    ',/
   )         \            '.
  / _    _    |             \
 |  a    a    /              |
 \   .-.                     ;
  '-('' ).-'       ,'       ;
     '-;           |      .'
        \           \    /
        | 7  .__  _.-\   \
        | |  |  ``/  /`  /
       /,_|  |   /,_/   /
          /,_/      '`-'

-}

-- | Serialise 'Event's using specified UTF encoding to a lazy 'BS.L.ByteString'
--
-- __NOTE__: This function is only well-defined for valid 'Event' streams
--
-- @since 0.2.0.0
writeEvents :: Encoding -> [Event] -> BS.L.ByteString
writeEvents :: Encoding -> [Event] -> ByteString
writeEvents Encoding
UTF8    = Text -> ByteString
T.L.encodeUtf8    (Text -> ByteString) -> ([Event] -> Text) -> [Event] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Event] -> Text
writeEventsText
writeEvents Encoding
UTF16LE = Text -> ByteString
T.L.encodeUtf16LE (Text -> ByteString) -> ([Event] -> Text) -> [Event] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Text -> Text
T.L.cons Char
'\xfeff' (Text -> Text) -> ([Event] -> Text) -> [Event] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Event] -> Text
writeEventsText
writeEvents Encoding
UTF16BE = Text -> ByteString
T.L.encodeUtf16BE (Text -> ByteString) -> ([Event] -> Text) -> [Event] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Text -> Text
T.L.cons Char
'\xfeff' (Text -> Text) -> ([Event] -> Text) -> [Event] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Event] -> Text
writeEventsText
writeEvents Encoding
UTF32LE = Text -> ByteString
T.L.encodeUtf32LE (Text -> ByteString) -> ([Event] -> Text) -> [Event] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Text -> Text
T.L.cons Char
'\xfeff' (Text -> Text) -> ([Event] -> Text) -> [Event] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Event] -> Text
writeEventsText
writeEvents Encoding
UTF32BE = Text -> ByteString
T.L.encodeUtf32BE (Text -> ByteString) -> ([Event] -> Text) -> [Event] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Text -> Text
T.L.cons Char
'\xfeff' (Text -> Text) -> ([Event] -> Text) -> [Event] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Event] -> Text
writeEventsText

-- | Serialise 'Event's to lazy 'T.L.Text'
--
-- __NOTE__: This function is only well-defined for valid 'Event' streams
--
-- @since 0.2.0.0
writeEventsText :: [Event] -> T.L.Text
writeEventsText :: [Event] -> Text
writeEventsText [] = Text
forall a. Monoid a => a
mempty
writeEventsText (Event
StreamStart:[Event]
xs) = Builder -> Text
T.B.toLazyText (Builder -> Text) -> Builder -> Text
forall a b. (a -> b) -> a -> b
$ [Event] -> Any -> Builder
forall {t}. [Event] -> t -> Builder
goStream [Event]
xs (String -> Any
forall a. HasCallStack => String -> a
error String
"writeEvents: internal error")
  where
    -- goStream :: [Event] -> [Event] -> T.B.Builder
    goStream :: [Event] -> t -> Builder
goStream [Event
StreamEnd] t
_ = Builder
forall a. Monoid a => a
mempty
    goStream (Event
StreamEnd : Event
_ : [Event]
_ ) t
_cont = String -> Builder
forall a. HasCallStack => String -> a
error String
"writeEvents: events after StreamEnd"
    goStream (Comment Text
com: [Event]
rest) t
cont = Int -> Bool -> Context -> Text -> Builder -> Builder
goComment (Int
0 :: Int) Bool
True Context
BlockIn Text
com ([Event] -> t -> Builder
goStream [Event]
rest t
cont)
    goStream (DocumentStart Directives
marker : [Event]
rest) t
cont
      = case Directives
marker of
          Directives
NoDirEndMarker         -> Bool -> [Event] -> ([Event] -> Builder) -> Builder
putNode Bool
False [Event]
rest (\[Event]
zs -> [Event] -> t -> Builder
goDoc [Event]
zs t
cont)
          Directives
DirEndMarkerNoVersion  -> Builder
"---" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Bool -> [Event] -> ([Event] -> Builder) -> Builder
putNode Bool
True [Event]
rest (\[Event]
zs -> [Event] -> t -> Builder
goDoc [Event]
zs t
cont)
          DirEndMarkerVersion Word
mi -> Builder
"%YAML 1." Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> (String -> Builder
T.B.fromString (Word -> String
forall a. Show a => a -> String
show Word
mi)) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"\n---" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Bool -> [Event] -> ([Event] -> Builder) -> Builder
putNode Bool
True [Event]
rest (\[Event]
zs -> [Event] -> t -> Builder
goDoc [Event]
zs t
cont)
    goStream (Event
x:[Event]
_) t
_cont = String -> Builder
forall a. HasCallStack => String -> a
error (String
"writeEvents: unexpected " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Event -> String
forall a. Show a => a -> String
show Event
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" (expected DocumentStart or StreamEnd)")
    goStream [] t
_cont = String -> Builder
forall a. HasCallStack => String -> a
error (String
"writeEvents: unexpected end of stream (expected DocumentStart or StreamEnd)")

    goDoc :: [Event] -> t -> Builder
goDoc (DocumentEnd Bool
marker : [Event]
rest) t
cont
      = (if Bool
marker then Builder
"...\n" else Builder
forall a. Monoid a => a
mempty) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Event] -> t -> Builder
goStream [Event]
rest t
cont
    goDoc (Comment Text
com: [Event]
rest) t
cont = Int -> Bool -> Context -> Text -> Builder -> Builder
goComment (Int
0 :: Int) Bool
True Context
BlockIn Text
com ([Event] -> t -> Builder
goDoc [Event]
rest t
cont)
    goDoc [Event]
ys t
_ = String -> Builder
forall a. HasCallStack => String -> a
error ([Event] -> String
forall a. Show a => a -> String
show [Event]
ys)

    -- unexpected s l = error ("writeEvents: unexpected " ++ show l ++ " " ++ show s)

writeEventsText (Event
x:[Event]
_) = String -> Text
forall a. HasCallStack => String -> a
error (String
"writeEvents: unexpected " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Event -> String
forall a. Show a => a -> String
show Event
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" (expected StreamStart)")

-- | Production context -- copied from Data.YAML.Token
data Context = BlockOut     -- ^ Outside block sequence.
             | BlockIn      -- ^ Inside block sequence.
             | BlockKey     -- ^ Implicit block key.
             | FlowOut      -- ^ Outside flow collection.
             | FlowIn       -- ^ Inside flow collection.
             | FlowKey      -- ^ Implicit flow key.
             deriving (Context -> Context -> Bool
(Context -> Context -> Bool)
-> (Context -> Context -> Bool) -> Eq Context
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Context -> Context -> Bool
== :: Context -> Context -> Bool
$c/= :: Context -> Context -> Bool
/= :: Context -> Context -> Bool
Eq,Int -> Context -> String -> String
[Context] -> String -> String
Context -> String
(Int -> Context -> String -> String)
-> (Context -> String)
-> ([Context] -> String -> String)
-> Show Context
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: Int -> Context -> String -> String
showsPrec :: Int -> Context -> String -> String
$cshow :: Context -> String
show :: Context -> String
$cshowList :: [Context] -> String -> String
showList :: [Context] -> String -> String
Show)

goComment :: Int -> Bool -> Context -> T.Text -> T.B.Builder -> T.B.Builder
goComment :: Int -> Bool -> Context -> Text -> Builder -> Builder
goComment !Int
n !Bool
sol Context
c Text
comment Builder
cont = Builder
doSol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"#" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> (Text -> Builder
T.B.fromText Text
comment) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
doEol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
doIndent Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
cont
  where
    doEol :: Builder
doEol
      | Bool -> Bool
not Bool
sol Bool -> Bool -> Bool
&& Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0  = Builder
forall a. Monoid a => a
mempty           -- "--- " case
      | Bool
sol Bool -> Bool -> Bool
&& Context
FlowIn Context -> Context -> Bool
forall a. Eq a => a -> a -> Bool
== Context
c = Builder
forall a. Monoid a => a
mempty
      | Bool
otherwise = Builder
eol

    doSol :: Builder
doSol
      | Bool -> Bool
not Bool
sol Bool -> Bool -> Bool
&& (Context
BlockOut Context -> Context -> Bool
forall a. Eq a => a -> a -> Bool
== Context
c Bool -> Bool -> Bool
|| Context
FlowOut Context -> Context -> Bool
forall a. Eq a => a -> a -> Bool
== Context
c) = Builder
ws
      | Bool
sol = Int -> Builder
mkInd Int
n'
      | Bool
otherwise = Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
mkInd Int
n'

    n' :: Int
n'
      | Context
BlockOut <- Context
c = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
      | Context
FlowOut  <- Context
c = Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
      | Bool
otherwise     = Int
n

    doIndent :: Builder
doIndent
      | Context
BlockOut <- Context
c = Int -> Builder
mkInd Int
n'
      | Context
FlowOut  <- Context
c = Int -> Builder
mkInd Int
n'
      | Bool
otherwise = Builder
forall a. Monoid a => a
mempty

putNode :: Bool -> [Event] -> ([Event] -> T.B.Builder) -> T.B.Builder
putNode :: Bool -> [Event] -> ([Event] -> Builder) -> Builder
putNode = \Bool
docMarker -> Int
-> Bool -> Context -> [Event] -> ([Event] -> Builder) -> Builder
go (-Int
1 :: Int) (Bool -> Bool
not Bool
docMarker) Context
BlockIn
  where

    {-  s-l+block-node(n,c)

        [196]   s-l+block-node(n,c)        ::=     s-l+block-in-block(n,c) | s-l+flow-in-block(n)

        [197]   s-l+flow-in-block(n)       ::=     s-separate(n+1,flow-out) ns-flow-node(n+1,flow-out) s-l-comments

        [198]   s-l+block-in-block(n,c)    ::=     s-l+block-scalar(n,c) | s-l+block-collection(n,c)

        [199]   s-l+block-scalar(n,c)      ::=     s-separate(n+1,c) ( c-ns-properties(n+1,c) s-separate(n+1,c) )?  ( c-l+literal(n) | c-l+folded(n) )

        [200]   s-l+block-collection(n,c)  ::=     ( s-separate(n+1,c) c-ns-properties(n+1,c) )? s-l-comments
                                                   ( l+block-sequence(seq-spaces(n,c)) | l+block-mapping(n) )

        [201]   seq-spaces(n,c)            ::=     c = block-out ⇒ n-1
                                                   c = block-in  ⇒ n

    -}

    go :: Int -> Bool -> Context -> [Event] -> ([Event] -> T.B.Builder) -> T.B.Builder
    go :: Int
-> Bool -> Context -> [Event] -> ([Event] -> Builder) -> Builder
go Int
_  Bool
_ Context
_  [] [Event] -> Builder
_cont = String -> Builder
forall a. HasCallStack => String -> a
error (String
"putNode: expected node-start event instead of end-of-stream")
    go !Int
n !Bool
sol Context
c (Event
t : [Event]
rest) [Event] -> Builder
cont = case Event
t of
        Scalar        Maybe Text
anc Tag
tag ScalarStyle
sty Text
t' -> Int
-> Bool
-> Context
-> Maybe Text
-> Tag
-> ScalarStyle
-> Text
-> Builder
-> Builder
goStr (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) Bool
sol Context
c Maybe Text
anc Tag
tag ScalarStyle
sty Text
t' ([Event] -> Builder
cont [Event]
rest)
        SequenceStart Maybe Text
anc Tag
tag NodeStyle
sty    -> Int
-> Bool
-> Context
-> Maybe Text
-> Tag
-> NodeStyle
-> [Event]
-> ([Event] -> Builder)
-> Builder
goSeq (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) Bool
sol (NodeStyle -> Context
chn NodeStyle
sty) Maybe Text
anc Tag
tag NodeStyle
sty [Event]
rest [Event] -> Builder
cont
        MappingStart  Maybe Text
anc Tag
tag NodeStyle
sty    -> Int
-> Bool
-> Context
-> Maybe Text
-> Tag
-> NodeStyle
-> [Event]
-> ([Event] -> Builder)
-> Builder
goMap (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) Bool
sol (NodeStyle -> Context
chn NodeStyle
sty) Maybe Text
anc Tag
tag NodeStyle
sty [Event]
rest [Event] -> Builder
cont
        Alias Text
a                      -> Builder
pfx Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Context -> Text -> Builder -> Builder
goAlias Context
c Text
a ([Event] -> Builder
cont [Event]
rest)
        Comment Text
com                  -> Int -> Bool -> Context -> Text -> Builder -> Builder
goComment (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) Bool
sol Context
c Text
com (Int
-> Bool -> Context -> [Event] -> ([Event] -> Builder) -> Builder
go Int
n Bool
sol Context
c [Event]
rest [Event] -> Builder
cont)
        Event
_ -> String -> Builder
forall a. HasCallStack => String -> a
error (String
"putNode: expected node-start event instead of " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Event -> String
forall a. Show a => a -> String
show Event
t)

      where
        pfx :: Builder
pfx | Bool
sol           = Builder
forall a. Monoid a => a
mempty
            | Context
BlockKey <- Context
c = Builder
forall a. Monoid a => a
mempty
            | Context
FlowKey  <- Context
c = Builder
forall a. Monoid a => a
mempty
            | Bool
otherwise     = Char -> Builder
T.B.singleton Char
' '

        chn :: NodeStyle -> Context
chn NodeStyle
sty
          | NodeStyle
Flow <-NodeStyle
sty, (Context
BlockIn Context -> Context -> Bool
forall a. Eq a => a -> a -> Bool
== Context
c Bool -> Bool -> Bool
|| Context
BlockOut Context -> Context -> Bool
forall a. Eq a => a -> a -> Bool
== Context
c) = Context
FlowOut
          | Bool
otherwise = Context
c


    goMap :: Int
-> Bool
-> Context
-> Maybe Text
-> Tag
-> NodeStyle
-> [Event]
-> ([Event] -> Builder)
-> Builder
goMap Int
_ Bool
sol Context
_ Maybe Text
anc Tag
tag NodeStyle
_ (Event
MappingEnd : [Event]
rest) [Event] -> Builder
cont = Builder -> Builder
pfx (Builder -> Builder) -> Builder -> Builder
forall a b. (a -> b) -> a -> b
$ Builder
"{}\n" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Event] -> Builder
cont [Event]
rest
      where
        pfx :: Builder -> Builder
pfx Builder
cont' = Bool -> Builder
wsSol Bool
sol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Either Builder Builder -> Maybe Text -> Tag -> Builder -> Builder
anchorTag'' (Builder -> Either Builder Builder
forall a b. b -> Either a b
Right Builder
ws) Maybe Text
anc Tag
tag Builder
cont'

    goMap Int
n Bool
sol Context
c Maybe Text
anc Tag
tag NodeStyle
Block [Event]
xs [Event] -> Builder
cont = case Context
c of
        Context
BlockIn | Bool -> Bool
not (Bool -> Bool
not Bool
sol Bool -> Bool -> Bool
&& Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0) -- avoid "--- " case
           ->  Bool -> Builder
wsSol Bool
sol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Either Builder Builder -> Maybe Text -> Tag -> Builder -> Builder
anchorTag'' (Builder -> Either Builder Builder
forall a b. b -> Either a b
Right (Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
mkInd Int
n)) Maybe Text
anc Tag
tag
               ([Event] -> ([Event] -> Builder) -> Builder
putKey [Event]
xs [Event] -> Builder
putValue')
        Context
_  ->  Either Builder Builder -> Maybe Text -> Tag -> Builder -> Builder
anchorTag'' (Builder -> Either Builder Builder
forall a b. a -> Either a b
Left Builder
ws) Maybe Text
anc Tag
tag (Builder -> Builder) -> Builder -> Builder
forall a b. (a -> b) -> a -> b
$ Builder
doEol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Event] -> Builder
g' [Event]
xs
      where
        g' :: [Event] -> Builder
g' (Event
MappingEnd : [Event]
rest) = [Event] -> Builder
cont [Event]
rest                    -- All comments should be part of the key
        g' [Event]
ys                  = Builder
pfx Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Event] -> ([Event] -> Builder) -> Builder
putKey [Event]
ys [Event] -> Builder
putValue'

        g :: [Event] -> Builder
g (Comment Text
com: [Event]
rest) = Int -> Bool -> Context -> Text -> Builder -> Builder
goComment Int
n Bool
True Context
c' Text
com ([Event] -> Builder
g [Event]
rest)  -- For trailing comments
        g (Event
MappingEnd : [Event]
rest) = [Event] -> Builder
cont [Event]
rest
        g [Event]
ys                  = Builder
pfx Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Event] -> ([Event] -> Builder) -> Builder
putKey [Event]
ys [Event] -> Builder
putValue'

        pfx :: Builder
pfx = if Context
c Context -> Context -> Bool
forall a. Eq a => a -> a -> Bool
== Context
BlockIn Bool -> Bool -> Bool
|| Context
c Context -> Context -> Bool
forall a. Eq a => a -> a -> Bool
== Context
BlockOut Bool -> Bool -> Bool
|| Context
c Context -> Context -> Bool
forall a. Eq a => a -> a -> Bool
== Context
BlockKey then Int -> Builder
mkInd Int
n else Builder
ws
        c' :: Context
c' = if Context
FlowIn Context -> Context -> Bool
forall a. Eq a => a -> a -> Bool
== Context
c then Context
FlowKey else Context
BlockKey

        doEol :: Builder
doEol = case Context
c of
          Context
FlowKey -> Builder
forall a. Monoid a => a
mempty
          Context
FlowIn  -> Builder
forall a. Monoid a => a
mempty
          Context
_       -> Builder
eol

        putKey :: [Event] -> ([Event] -> Builder) -> Builder
putKey [Event]
zs [Event] -> Builder
cont2
          | [Event] -> Bool
isSmallKey [Event]
zs = Int
-> Bool -> Context -> [Event] -> ([Event] -> Builder) -> Builder
go Int
n (Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0) Context
c' [Event]
zs (\[Event]
ys -> Builder
":" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Event] -> Builder
cont2 [Event]
ys)
          | Comment Text
com: [Event]
rest <- [Event]
zs = Builder
"?" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
ws Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Bool -> Context -> Text -> Builder -> Builder
goComment Int
0 Bool
True Context
BlockIn Text
com ([Event] -> ([Event] -> Builder) -> Builder
f [Event]
rest [Event] -> Builder
cont2)
          | Bool
otherwise     = Builder
"?" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int
-> Bool -> Context -> [Event] -> ([Event] -> Builder) -> Builder
go Int
n Bool
False Context
BlockIn [Event]
zs (([Event] -> Builder) -> [Event] -> Builder
forall {t}. (t -> Builder) -> t -> Builder
putValue [Event] -> Builder
cont2)

        f :: [Event] -> ([Event] -> Builder) -> Builder
f (Comment Text
com: [Event]
rest) [Event] -> Builder
cont2 = Int -> Bool -> Context -> Text -> Builder -> Builder
goComment (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Bool
True Context
BlockIn Text
com ([Event] -> ([Event] -> Builder) -> Builder
f [Event]
rest [Event] -> Builder
cont2)   -- Comments should not change position in key
        f [Event]
zs [Event] -> Builder
cont2                  = Builder
ws Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
mkInd Int
n Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int
-> Bool -> Context -> [Event] -> ([Event] -> Builder) -> Builder
go Int
n Bool
False Context
BlockIn [Event]
zs (([Event] -> Builder) -> [Event] -> Builder
forall {t}. (t -> Builder) -> t -> Builder
putValue [Event] -> Builder
cont2)

        putValue :: (t -> Builder) -> t -> Builder
putValue t -> Builder
cont2 t
zs
          | Context
FlowIn <- Context
c   = Builder
ws Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
mkInd (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
":" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> t -> Builder
cont2 t
zs
          | Bool
otherwise     = Int -> Builder
mkInd Int
n Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
":" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> t -> Builder
cont2 t
zs

        putValue' :: [Event] -> Builder
putValue' (Comment Text
com: [Event]
rest) = Int -> Bool -> Context -> Text -> Builder -> Builder
goComment (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Bool
False Context
BlockOut Text
com (Builder
ws Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Event] -> Builder
putValue' [Event]
rest) -- Comments should not change position in value
        putValue' [Event]
zs = Int
-> Bool -> Context -> [Event] -> ([Event] -> Builder) -> Builder
go Int
n Bool
False (if Context
FlowIn Context -> Context -> Bool
forall a. Eq a => a -> a -> Bool
== Context
c then Context
FlowIn else Context
BlockOut) [Event]
zs [Event] -> Builder
g

    goMap Int
n Bool
sol Context
c Maybe Text
anc Tag
tag NodeStyle
Flow [Event]
xs [Event] -> Builder
cont =
        Bool -> Builder
wsSol Bool
sol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Either Builder Builder -> Maybe Text -> Tag -> Builder -> Builder
anchorTag'' (Builder -> Either Builder Builder
forall a b. b -> Either a b
Right Builder
ws) Maybe Text
anc Tag
tag (Builder
"{" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Event] -> Builder
f [Event]
xs)
          where
            f :: [Event] -> Builder
f (Comment Text
com: [Event]
rest) = Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Bool -> Builder
wsSol Bool
sol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Bool -> Context -> Text -> Builder -> Builder
goComment Int
n' Bool
True (Context -> Context
inFlow Context
c) Text
com ([Event] -> Builder
f [Event]
rest)
            f (Event
MappingEnd : [Event]
rest) = Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Bool -> Builder
wsSol Bool
sol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
mkInd (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"}" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
doEol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Event] -> Builder
cont [Event]
rest
            f [Event]
ys                  = Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
mkInd Int
n' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Event] -> ([Event] -> Builder) -> Builder
putKey [Event]
ys [Event] -> Builder
putValue'

            n' :: Int
n' = Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1

            doEol :: Builder
doEol = case Context
c of
              Context
FlowKey -> Builder
forall a. Monoid a => a
mempty
              Context
FlowIn  -> Builder
forall a. Monoid a => a
mempty
              Context
_       -> Builder
eol

            g :: [Event] -> Builder
g (Comment Text
com: [Event]
rest) = Builder
"," Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Bool -> Builder
wsSol Bool
sol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Bool -> Context -> Text -> Builder -> Builder
goComment Int
n' Bool
True (Context -> Context
inFlow Context
c) Text
com ([Event] -> Builder
f [Event]
rest)
            g (Event
MappingEnd : [Event]
rest) = Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Bool -> Builder
wsSol Bool
sol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
mkInd (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"}" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
doEol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Event] -> Builder
cont [Event]
rest
            g [Event]
ys                  = Builder
"," Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
mkInd Int
n' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Event] -> ([Event] -> Builder) -> Builder
putKey [Event]
ys [Event] -> Builder
putValue'

            putKey :: [Event] -> ([Event] -> Builder) -> Builder
putKey [Event]
zs [Event] -> Builder
cont2
              | (Comment Text
com: [Event]
rest) <- [Event]
zs = Int -> Bool -> Context -> Text -> Builder -> Builder
goComment Int
n' Bool
True Context
c Text
com (Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
mkInd Int
n' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Event] -> ([Event] -> Builder) -> Builder
putKey [Event]
rest [Event] -> Builder
cont2)
              | [Event] -> Bool
isSmallKey [Event]
zs =    Int
-> Bool -> Context -> [Event] -> ([Event] -> Builder) -> Builder
go Int
n' (Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0) Context
FlowKey [Event]
zs (if [Event] -> Bool
isComEv [Event]
zs then ([Event] -> Builder) -> [Event] -> Builder
putValue [Event] -> Builder
cont2 else (\[Event]
ys -> Builder
":" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Event] -> Builder
cont2 [Event]
ys))
              | Bool
otherwise     = Builder
"?" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int
-> Bool -> Context -> [Event] -> ([Event] -> Builder) -> Builder
go Int
n Bool
False Context
FlowIn [Event]
zs (([Event] -> Builder) -> [Event] -> Builder
putValue [Event] -> Builder
cont2)

            putValue :: ([Event] -> Builder) -> [Event] -> Builder
putValue [Event] -> Builder
cont2 [Event]
zs
              | Comment Text
com: [Event]
rest <- [Event]
zs =  Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Bool -> Builder
wsSol Bool
sol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Bool -> Context -> Text -> Builder -> Builder
goComment Int
n' Bool
True (Context -> Context
inFlow Context
c) Text
com (([Event] -> Builder) -> [Event] -> Builder
putValue [Event] -> Builder
cont2 [Event]
rest)
              | Bool
otherwise     = Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
mkInd Int
n' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
":" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Event] -> Builder
cont2 [Event]
zs

            putValue' :: [Event] -> Builder
putValue' [Event]
zs
              | Comment Text
com : [Event]
rest <- [Event]
zs = Int -> Bool -> Context -> Text -> Builder -> Builder
goComment Int
n' Bool
False Context
FlowOut Text
com ([Event] -> Builder
putValue' [Event]
rest)
              | Bool
otherwise = Int
-> Bool -> Context -> [Event] -> ([Event] -> Builder) -> Builder
go Int
n' Bool
False Context
FlowIn [Event]
zs [Event] -> Builder
g


    goSeq :: Int
-> Bool
-> Context
-> Maybe Text
-> Tag
-> NodeStyle
-> [Event]
-> ([Event] -> Builder)
-> Builder
goSeq Int
_ Bool
sol Context
_ Maybe Text
anc Tag
tag NodeStyle
_ (Event
SequenceEnd : [Event]
rest) [Event] -> Builder
cont = Builder -> Builder
pfx (Builder -> Builder) -> Builder -> Builder
forall a b. (a -> b) -> a -> b
$ Builder
"[]\n" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Event] -> Builder
cont [Event]
rest
      where
        pfx :: Builder -> Builder
pfx Builder
cont' = Bool -> Builder
wsSol Bool
sol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Either Builder Builder -> Maybe Text -> Tag -> Builder -> Builder
anchorTag'' (Builder -> Either Builder Builder
forall a b. b -> Either a b
Right Builder
ws) Maybe Text
anc Tag
tag Builder
cont'

    goSeq Int
n Bool
sol Context
c Maybe Text
anc Tag
tag NodeStyle
Block [Event]
xs [Event] -> Builder
cont = case Context
c of
        Context
BlockOut -> Either Builder Builder -> Maybe Text -> Tag -> Builder -> Builder
anchorTag'' (Builder -> Either Builder Builder
forall a b. a -> Either a b
Left Builder
ws) Maybe Text
anc Tag
tag (Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> if [Event] -> Bool
isComEv [Event]
xs then Builder
"-" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Event] -> Builder
f [Event]
xs else [Event] -> Builder
g [Event]
xs)

        Context
BlockIn
          | Bool -> Bool
not Bool
sol Bool -> Bool -> Bool
&& Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 {- "---" case -} -> Int
-> Bool
-> Context
-> Maybe Text
-> Tag
-> NodeStyle
-> [Event]
-> ([Event] -> Builder)
-> Builder
goSeq Int
n Bool
sol Context
BlockOut Maybe Text
anc Tag
tag NodeStyle
Block [Event]
xs [Event] -> Builder
cont
          | Comment Text
com: [Event]
rest <- [Event]
xs ->  Bool -> Builder
wsSol Bool
sol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Either Builder Builder -> Maybe Text -> Tag -> Builder -> Builder
anchorTag'' (Builder -> Either Builder Builder
forall a b. b -> Either a b
Right (Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
mkInd Int
n')) Maybe Text
anc Tag
tag (Builder
"-" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
ws Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Bool -> Context -> Text -> Builder -> Builder
goComment Int
0 Bool
True Context
BlockIn Text
com ([Event] -> Builder
f [Event]
rest))
          | Bool
otherwise -> Bool -> Builder
wsSol Bool
sol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Either Builder Builder -> Maybe Text -> Tag -> Builder -> Builder
anchorTag'' (Builder -> Either Builder Builder
forall a b. b -> Either a b
Right (Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
mkInd Int
n')) Maybe Text
anc Tag
tag (Builder
"-" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int
-> Bool -> Context -> [Event] -> ([Event] -> Builder) -> Builder
go Int
n' Bool
False Context
BlockIn [Event]
xs [Event] -> Builder
g)

        Context
BlockKey -> String -> Builder
forall a. HasCallStack => String -> a
error String
"sequence in block-key context not supported"

        Context
_ -> String -> Builder
forall a. HasCallStack => String -> a
error String
"Invalid Context in Block style"

      where
        n' :: Int
n' | Context
BlockOut <- Context
c = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
           | Bool
otherwise     = Int
n

        g :: [Event] -> Builder
g (Comment Text
com: [Event]
rest)  = Int -> Bool -> Context -> Text -> Builder -> Builder
goComment Int
n' Bool
True Context
BlockIn Text
com ([Event] -> Builder
g [Event]
rest)
        g (Event
SequenceEnd : [Event]
rest) = [Event] -> Builder
cont [Event]
rest
        g [Event]
ys                   = Int -> Builder
mkInd Int
n' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"-" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int
-> Bool -> Context -> [Event] -> ([Event] -> Builder) -> Builder
go Int
n' Bool
False Context
BlockIn [Event]
ys [Event] -> Builder
g

        f :: [Event] -> Builder
f (Comment Text
com: [Event]
rest)  = Int -> Bool -> Context -> Text -> Builder -> Builder
goComment Int
n' Bool
True Context
BlockIn Text
com ([Event] -> Builder
f [Event]
rest)
        f (Event
SequenceEnd : [Event]
rest) = [Event] -> Builder
cont [Event]
rest
        f [Event]
ys                   = Builder
ws Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
mkInd Int
n' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int
-> Bool -> Context -> [Event] -> ([Event] -> Builder) -> Builder
go Int
n' Bool
False Context
BlockIn [Event]
ys [Event] -> Builder
g

    goSeq Int
n Bool
sol Context
c Maybe Text
anc Tag
tag NodeStyle
Flow [Event]
xs [Event] -> Builder
cont =
      Bool -> Builder
wsSol Bool
sol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Either Builder Builder -> Maybe Text -> Tag -> Builder -> Builder
anchorTag'' (Builder -> Either Builder Builder
forall a b. b -> Either a b
Right Builder
ws) Maybe Text
anc Tag
tag (Builder
"[" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Event] -> Builder
f [Event]
xs)
        where
          f :: [Event] -> Builder
f (Comment Text
com: [Event]
rest)  = Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Bool -> Builder
wsSol Bool
sol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Bool -> Context -> Text -> Builder -> Builder
goComment Int
n' Bool
True (Context -> Context
inFlow Context
c) Text
com ([Event] -> Builder
f [Event]
rest)
          f (Event
SequenceEnd : [Event]
rest) = Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Bool -> Builder
wsSol Bool
sol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
mkInd (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"]" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
doEol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Event] -> Builder
cont [Event]
rest
          f [Event]
ys                   = Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
mkInd Int
n' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int
-> Bool -> Context -> [Event] -> ([Event] -> Builder) -> Builder
go Int
n' Bool
False (Context -> Context
inFlow Context
c) [Event]
ys [Event] -> Builder
g

          n' :: Int
n' = Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1

          doEol :: Builder
doEol = case Context
c of
            Context
FlowKey -> Builder
forall a. Monoid a => a
mempty
            Context
FlowIn  -> Builder
forall a. Monoid a => a
mempty
            Context
_       -> Builder
eol

          g :: [Event] -> Builder
g (Comment Text
com: [Event]
rest)  = Builder
"," Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Bool -> Builder
wsSol Bool
sol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Bool -> Context -> Text -> Builder -> Builder
goComment Int
n' Bool
True (Context -> Context
inFlow Context
c) Text
com ([Event] -> Builder
f [Event]
rest)
          g (Event
SequenceEnd : [Event]
rest) = Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Bool -> Builder
wsSol Bool
sol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
mkInd (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"]" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
doEol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Event] -> Builder
cont [Event]
rest
          g [Event]
ys                   = Builder
"," Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
mkInd Int
n' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int
-> Bool -> Context -> [Event] -> ([Event] -> Builder) -> Builder
go Int
n' Bool
False (Context -> Context
inFlow Context
c) [Event]
ys [Event] -> Builder
g


    goAlias :: Context -> Text -> Builder -> Builder
goAlias Context
c Text
a Builder
cont = Char -> Builder
T.B.singleton Char
'*' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
T.B.fromText Text
a Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
sep Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
cont
      where
        sep :: Builder
sep = case Context
c of
          Context
BlockIn  -> Builder
eol
          Context
BlockOut -> Builder
eol
          Context
BlockKey -> Char -> Builder
T.B.singleton Char
' '
          Context
FlowIn   -> Builder
forall a. Monoid a => a
mempty
          Context
FlowOut  -> Builder
eol
          Context
FlowKey  -> Char -> Builder
T.B.singleton Char
' '

    goStr :: Int -> Bool -> Context -> Maybe Anchor -> Tag -> ScalarStyle -> Text -> T.B.Builder -> T.B.Builder
    goStr :: Int
-> Bool
-> Context
-> Maybe Text
-> Tag
-> ScalarStyle
-> Text
-> Builder
-> Builder
goStr !Int
n !Bool
sol Context
c Maybe Text
anc Tag
tag ScalarStyle
sty Text
t Builder
cont = case ScalarStyle
sty of
      -- flow-style

      ScalarStyle
Plain -- empty scalars
        | Text
t Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
"" -> case () of
                      ()
_ | Maybe Text
Nothing <- Maybe Text
anc, Tag Maybe Text
Nothing <- Tag
tag  -> Builder
contEol -- not even node properties
                        | Bool
sol                                 -> Maybe Text -> Tag -> Builder -> Builder
anchorTag0 Maybe Text
anc Tag
tag (if Context
c Context -> Context -> Bool
forall a. Eq a => a -> a -> Bool
== Context
BlockKey Bool -> Bool -> Bool
|| Context
c Context -> Context -> Bool
forall a. Eq a => a -> a -> Bool
== Context
FlowKey then Builder
ws Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
cont else Builder
contEol)
                        | Context
BlockKey <- Context
c                       -> Maybe Text -> Tag -> Builder -> Builder
anchorTag0 Maybe Text
anc Tag
tag (Builder
ws Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
cont)
                        | Context
FlowKey <- Context
c                        -> Maybe Text -> Tag -> Builder -> Builder
anchorTag0 Maybe Text
anc Tag
tag (Builder
ws Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
cont)
                        | Bool
otherwise                           -> Either Builder Builder -> Maybe Text -> Tag -> Builder -> Builder
anchorTag'' (Builder -> Either Builder Builder
forall a b. a -> Either a b
Left Builder
ws) Maybe Text
anc Tag
tag Builder
contEol

      ScalarStyle
Plain           -> Builder -> Builder
pfx (Builder -> Builder) -> Builder -> Builder
forall a b. (a -> b) -> a -> b
$
                          let h :: [Text] -> Builder
h []     = Builder
contEol
                              h (Text
x:[Text]
xs) = Text -> Builder
T.B.fromText Text
x Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Text] -> Builder
f' [Text]
xs
                                where
                                  f' :: [Text] -> Builder
f' []     = Builder
contEol
                                  f' (Text
y:[Text]
ys) = Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
mkInd (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
T.B.fromText Text
y Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Text] -> Builder
f' [Text]
ys
                          in [Text] -> Builder
h ([Text] -> [Text]
insFoldNls (Text -> [Text]
T.lines Text
t)) -- FIXME: unquoted plain-strings can't handle leading/trailing whitespace properly

      ScalarStyle
SingleQuoted    -> Builder -> Builder
pfx (Builder -> Builder) -> Builder -> Builder
forall a b. (a -> b) -> a -> b
$ Char -> Builder
T.B.singleton Char
'\'' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Text] -> Builder -> Builder
f ([Text] -> [Text]
insFoldNls ([Text] -> [Text]) -> [Text] -> [Text]
forall a b. (a -> b) -> a -> b
$ Text -> [Text]
T.lines (HasCallStack => Text -> Text -> Text -> Text
Text -> Text -> Text -> Text
T.replace Text
"'" Text
"''" Text
t) [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ [ Text
forall a. Monoid a => a
mempty | Text -> Text -> Bool
T.isSuffixOf Text
"\n" Text
t]) (Char -> Builder
T.B.singleton Char
'\'' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
contEol) -- FIXME: leading white-space (i.e. SPC) before/after LF

      ScalarStyle
DoubleQuoted    -> Builder -> Builder
pfx (Builder -> Builder) -> Builder -> Builder
forall a b. (a -> b) -> a -> b
$ Char -> Builder
T.B.singleton Char
'"'  Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
T.B.fromText (Text -> Text
escapeDQ Text
t) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Char -> Builder
T.B.singleton Char
'"'  Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
contEol

      -- block style
      Folded Chomp
chm IndentOfs
iden -> Builder -> Builder
pfx (Builder -> Builder) -> Builder -> Builder
forall a b. (a -> b) -> a -> b
$ Builder
">" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Chomp -> Builder
goChomp Chomp
chm Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> IndentOfs -> Builder
goDigit IndentOfs
iden Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Text] -> Int -> Builder -> Builder
g ([Text] -> [Text]
insFoldNls' ([Text] -> [Text]) -> [Text] -> [Text]
forall a b. (a -> b) -> a -> b
$ Text -> [Text]
T.lines Text
t) (IndentOfs -> Int
forall a. Enum a => a -> Int
fromEnum IndentOfs
iden) Builder
cont

      Literal Chomp
chm IndentOfs
iden -> Builder -> Builder
pfx (Builder -> Builder) -> Builder -> Builder
forall a b. (a -> b) -> a -> b
$ Builder
"|" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Chomp -> Builder
goChomp Chomp
chm Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> IndentOfs -> Builder
goDigit IndentOfs
iden Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Text] -> Int -> Builder -> Builder
g (Text -> [Text]
T.lines Text
t) (IndentOfs -> Int
forall a. Enum a => a -> Int
fromEnum IndentOfs
iden) Builder
cont

      where
        goDigit :: IndentOfs -> T.B.Builder
        goDigit :: IndentOfs -> Builder
goDigit IndentOfs
iden = let ch :: Char
ch = Int -> Char
C.intToDigit(Int -> Char) -> (IndentOfs -> Int) -> IndentOfs -> Char
forall b c a. (b -> c) -> (a -> b) -> a -> c
.IndentOfs -> Int
forall a. Enum a => a -> Int
fromEnum (IndentOfs -> Char) -> IndentOfs -> Char
forall a b. (a -> b) -> a -> b
$ IndentOfs
iden
                       in if(Char
ch Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'0') then Builder
forall a. Monoid a => a
mempty else Char -> Builder
T.B.singleton Char
ch

        goChomp :: Chomp -> T.B.Builder
        goChomp :: Chomp -> Builder
goChomp Chomp
chm = case Chomp
chm of
           Chomp
Strip -> Char -> Builder
T.B.singleton Char
'-'
           Chomp
Clip  -> Builder
forall a. Monoid a => a
mempty
           Chomp
Keep  -> Char -> Builder
T.B.singleton Char
'+'

        pfx :: Builder -> Builder
pfx Builder
cont' = (if Bool
sol Bool -> Bool -> Bool
|| Context
c Context -> Context -> Bool
forall a. Eq a => a -> a -> Bool
== Context
BlockKey Bool -> Bool -> Bool
|| Context
c Context -> Context -> Bool
forall a. Eq a => a -> a -> Bool
== Context
FlowKey then Builder
forall a. Monoid a => a
mempty else Builder
ws) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Either Builder Builder -> Maybe Text -> Tag -> Builder -> Builder
anchorTag'' (Builder -> Either Builder Builder
forall a b. b -> Either a b
Right Builder
ws) Maybe Text
anc Tag
tag Builder
cont'

        doEol :: Bool
doEol = case Context
c of
          Context
BlockKey -> Bool
False
          Context
FlowKey  -> Bool
False
          Context
FlowIn   -> Bool
False
          Context
_        -> Bool
True

        contEol :: Builder
contEol
          | Bool
doEol     = Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
cont
          | Bool
otherwise = Builder
cont

        g :: [Text] -> Int -> Builder -> Builder
g []     Int
_ Builder
cont' = Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
cont'
        g (Text
x:[Text]
xs) Int
dig Builder
cont'
          | Text -> Bool
T.null Text
x   = Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Text] -> Int -> Builder -> Builder
g [Text]
xs Int
dig Builder
cont'
          | Int
dig Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0   = Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> (if Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0 then Int -> Builder
mkInd Int
n else Int -> Builder
mkInd' Int
1) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
T.B.fromText Text
x Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Text] -> Int -> Builder -> Builder
g [Text]
xs Int
dig Builder
cont'
          | Bool
otherwise  = Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
mkInd (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
mkInd' Int
dig Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
T.B.fromText Text
x Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Text] -> Int -> Builder -> Builder
g [Text]
xs Int
dig Builder
cont'

        g' :: [Text] -> Builder -> Builder
g' []     Builder
cont' = Builder
cont'
        g' (Text
x:[Text]
xs) Builder
cont' = Builder
eol Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
mkInd (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
T.B.fromText Text
x Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Text] -> Builder -> Builder
g' [Text]
xs Builder
cont'

        f :: [Text] -> Builder -> Builder
f []     Builder
cont' = Builder
cont'
        f (Text
x:[Text]
xs) Builder
cont' = Text -> Builder
T.B.fromText Text
x Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Text] -> Builder -> Builder
g' [Text]
xs Builder
cont'


    isSmallKey :: [Event] -> Bool
isSmallKey (Alias Text
_ : [Event]
_)                   = Bool
True
    isSmallKey (Scalar Maybe Text
_ Tag
_ (Folded Chomp
_ IndentOfs
_) Text
_: [Event]
_)  = Bool
False
    isSmallKey (Scalar Maybe Text
_ Tag
_ (Literal Chomp
_ IndentOfs
_) Text
_: [Event]
_) = Bool
False
    isSmallKey (Scalar Maybe Text
_ Tag
_ ScalarStyle
_ Text
_ : [Event]
_)            = Bool
True
    isSmallKey (SequenceStart Maybe Text
_ Tag
_ NodeStyle
_ : [Event]
_)       = Bool
False
    isSmallKey (MappingStart Maybe Text
_ Tag
_ NodeStyle
_ : [Event]
_)        = Bool
False
    isSmallKey [Event]
_                               = Bool
False

    -- <https://yaml.org/spec/1.2/spec.html#in-flow(c) in-flow(c)>
    inFlow :: Context -> Context
inFlow Context
c = case Context
c of
      Context
FlowIn   -> Context
FlowIn
      Context
FlowOut  -> Context
FlowIn
      Context
BlockKey -> Context
FlowKey
      Context
FlowKey  -> Context
FlowKey
      Context
_        -> String -> Context
forall a. HasCallStack => String -> a
error String
"Invalid context in Flow style"


    putTag :: Text -> Builder -> Builder
putTag Text
t Builder
cont
      | Just Text
t' <- Text -> Text -> Maybe Text
T.stripPrefix Text
"tag:yaml.org,2002:" Text
t = Builder
"!!" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
T.B.fromText Text
t' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
cont
      | Text
"!" Text -> Text -> Bool
`T.isPrefixOf` Text
t = Text -> Builder
T.B.fromText Text
t Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
cont
      | Bool
otherwise            = Builder
"!<" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
T.B.fromText Text
t Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Char -> Builder
T.B.singleton Char
'>' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
cont

    anchorTag'' :: Either T.B.Builder T.B.Builder -> Maybe Anchor -> Tag -> T.B.Builder -> T.B.Builder
    anchorTag'' :: Either Builder Builder -> Maybe Text -> Tag -> Builder -> Builder
anchorTag'' Either Builder Builder
_ Maybe Text
Nothing (Tag Maybe Text
Nothing) Builder
cont = Builder
cont
    anchorTag'' (Right Builder
pad) Maybe Text
Nothing (Tag (Just Text
t)) Builder
cont  = Text -> Builder -> Builder
putTag Text
t (Builder
pad Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
cont)
    anchorTag'' (Right Builder
pad) (Just Text
a) (Tag Maybe Text
Nothing) Builder
cont  = Char -> Builder
T.B.singleton Char
'&' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
T.B.fromText Text
a Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
pad Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
cont
    anchorTag'' (Right Builder
pad) (Just Text
a) (Tag (Just Text
t)) Builder
cont = Char -> Builder
T.B.singleton Char
'&' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
T.B.fromText Text
a Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Char -> Builder
T.B.singleton Char
' ' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder -> Builder
putTag Text
t (Builder
pad Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
cont)
    anchorTag'' (Left Builder
pad)  Maybe Text
Nothing (Tag (Just Text
t)) Builder
cont  = Builder
pad Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder -> Builder
putTag Text
t Builder
cont
    anchorTag'' (Left Builder
pad)  (Just Text
a) (Tag Maybe Text
Nothing) Builder
cont  = Builder
pad Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Char -> Builder
T.B.singleton Char
'&' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
T.B.fromText Text
a Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
cont
    anchorTag'' (Left Builder
pad)  (Just Text
a) (Tag (Just Text
t)) Builder
cont = Builder
pad Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Char -> Builder
T.B.singleton Char
'&' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
T.B.fromText Text
a Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Char -> Builder
T.B.singleton Char
' ' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder -> Builder
putTag Text
t Builder
cont

    anchorTag0 :: Maybe Text -> Tag -> Builder -> Builder
anchorTag0 = Either Builder Builder -> Maybe Text -> Tag -> Builder -> Builder
anchorTag'' (Builder -> Either Builder Builder
forall a b. a -> Either a b
Left Builder
forall a. Monoid a => a
mempty)
    -- anchorTag  = anchorTag'' (Right (T.B.singleton ' '))
    -- anchorTag' = anchorTag'' (Left (T.B.singleton ' '))

isComEv :: [Event] -> Bool
isComEv :: [Event] -> Bool
isComEv (Comment Text
_: [Event]
_) = Bool
True
isComEv [Event]
_              = Bool
False

-- indentation helper
mkInd :: Int -> T.B.Builder
mkInd :: Int -> Builder
mkInd (-1) = Builder
forall a. Monoid a => a
mempty
mkInd Int
0    = Builder
forall a. Monoid a => a
mempty
mkInd Int
1 = Builder
"  "
mkInd Int
2 = Builder
"    "
mkInd Int
3 = Builder
"      "
mkInd Int
4 = Builder
"        "
mkInd Int
l
  | Int
l Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0     = String -> Builder
forall a. HasCallStack => String -> a
error (Int -> String
forall a. Show a => a -> String
show Int
l)
  | Bool
otherwise = Text -> Builder
T.B.fromText (Int -> Text -> Text
T.replicate Int
l Text
"  ")

mkInd' :: Int -> T.B.Builder
mkInd' :: Int -> Builder
mkInd' Int
1 = Builder
" "
mkInd' Int
2 = Builder
"  "
mkInd' Int
3 = Builder
"   "
mkInd' Int
4 = Builder
"    "
mkInd' Int
5 = Builder
"     "
mkInd' Int
6 = Builder
"      "
mkInd' Int
7 = Builder
"       "
mkInd' Int
8 = Builder
"        "
mkInd' Int
9 = Builder
"         "
mkInd' Int
l = String -> Builder
forall a. HasCallStack => String -> a
error (String
"Impossible Indentation-level" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
l)

eol, ws:: T.B.Builder
eol :: Builder
eol = Char -> Builder
T.B.singleton Char
'\n'
ws :: Builder
ws  = Char -> Builder
T.B.singleton Char
' '

wsSol :: Bool -> T.B.Builder
wsSol :: Bool -> Builder
wsSol Bool
sol = if Bool
sol then Builder
forall a. Monoid a => a
mempty else Builder
ws

escapeDQ :: Text -> Text
escapeDQ :: Text -> Text
escapeDQ Text
t
  | (Char -> Bool) -> Text -> Bool
T.all (\Char
c -> Char -> Bool
C.isPrint Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'\\' Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'"') Text
t = Text
t
  | Bool
otherwise = (Char -> Text) -> Text -> Text
T.concatMap Char -> Text
escapeChar Text
t

escapeChar :: Char -> Text
escapeChar :: Char -> Text
escapeChar Char
c
  | Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\\'   = Text
"\\\\"
  | Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'"'    = Text
"\\\""
  | Char -> Bool
C.isPrint Char
c = Char -> Text
T.singleton Char
c
  | Just Text
e <- Char -> Map Char Text -> Maybe Text
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Char
c Map Char Text
emap = Text
e
  | Int
x Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0xff   = String -> Text
T.pack (String -> Int -> String
forall r. PrintfType r => String -> r
printf String
"\\x%02x" Int
x)
  | Int
x Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0xffff = String -> Text
T.pack (String -> Int -> String
forall r. PrintfType r => String -> r
printf String
"\\u%04x" Int
x)
  | Bool
otherwise   = String -> Text
T.pack (String -> Int -> String
forall r. PrintfType r => String -> r
printf String
"\\U%08x" Int
x)
  where
    x :: Int
x = Char -> Int
ord Char
c

    emap :: Map Char Text
emap = [(Char, Text)] -> Map Char Text
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [ (Char
v,String -> Text
T.pack [Char
'\\',Char
k]) | (Char
k,Char
v) <- [(Char, Char)]
escapes ]


escapes :: [(Char,Char)]
escapes :: [(Char, Char)]
escapes =
  [ (Char
'0',   Char
'\0')
  , (Char
'a',   Char
'\x7')
  , (Char
'b',   Char
'\x8')
  , (Char
'\x9', Char
'\x9')
  , (Char
't',   Char
'\x9')
  , (Char
'n',   Char
'\xa')
  , (Char
'v',   Char
'\xb')
  , (Char
'f',   Char
'\xc')
  , (Char
'r',   Char
'\xd')
  , (Char
'e',   Char
'\x1b')
  , (Char
' ',   Char
' ')
  , (Char
'"',   Char
'"')
  , (Char
'/',   Char
'/')
  , (Char
'\\',  Char
'\\')
  , (Char
'N',   Char
'\x85')
  , (Char
'_',   Char
'\xa0')
  , (Char
'L',   Char
'\x2028')
  , (Char
'P',   Char
'\x2029')
  ]


-- flow style line folding
-- FIXME: check single-quoted strings with leading '\n' or trailing '\n's
insFoldNls :: [Text] -> [Text]
insFoldNls :: [Text] -> [Text]
insFoldNls [] = []
insFoldNls z0 :: [Text]
z0@(Text
z:[Text]
zs)
  | (Text -> Bool) -> [Text] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Text -> Bool
T.null [Text]
z0     = Text
"" Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: [Text]
z0 -- HACK
  | Bool
otherwise         = Text
z Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: [Text] -> [Text]
go [Text]
zs
  where
    go :: [Text] -> [Text]
go [] = []
    go (Text
l:[Text]
ls)
      | Text -> Bool
T.null Text
l = Text
l Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: [Text] -> [Text]
go'  [Text]
ls
      | Bool
otherwise = Text
"" Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: Text
l Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: [Text] -> [Text]
go  [Text]
ls

    go' :: [Text] -> [Text]
go' [] = [Text
""]
    go' (Text
l:[Text]
ls)
      | Text -> Bool
T.null Text
l = Text
l Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: [Text] -> [Text]
go' [Text]
ls
      | Bool
otherwise = Text
"" Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: Text
l Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: [Text] -> [Text]
go  [Text]
ls

{- block style line folding

The combined effect of the block line folding rules is that each
“paragraph” is interpreted as a line, empty lines are interpreted as a
line feed, and the formatting of more-indented lines is preserved.

-}
insFoldNls' :: [Text] -> [Text]
insFoldNls' :: [Text] -> [Text]
insFoldNls' = [Text] -> [Text]
go'
  where
    go :: [Text] -> [Text]
go []                  = []
    go (Text
l:[Text]
ls)
      | Text -> Bool
T.null Text
l           = Text
l Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: [Text] -> [Text]
go  [Text]
ls
      | Char -> Bool
isWhite (HasCallStack => Text -> Char
Text -> Char
T.head Text
l) = Text
l Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: [Text] -> [Text]
go' [Text]
ls
      | Bool
otherwise          = Text
"" Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: Text
l Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: [Text] -> [Text]
go  [Text]
ls

    go' :: [Text] -> [Text]
go' []                 = []
    go' (Text
l:[Text]
ls)
      | Text -> Bool
T.null Text
l           = Text
l Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: [Text] -> [Text]
go' [Text]
ls
      | Char -> Bool
isWhite (HasCallStack => Text -> Char
Text -> Char
T.head Text
l) = Text
l Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: [Text] -> [Text]
go' [Text]
ls
      | Bool
otherwise          = Text
l Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: [Text] -> [Text]
go [Text]
ls

    -- @s-white@
    isWhite :: Char -> Bool
    isWhite :: Char -> Bool
isWhite Char
' '  = Bool
True
    isWhite Char
'\t' = Bool
True
    isWhite Char
_    = Bool
False