    {-# LANGUAGE OverloadedStrings #-}
    {-# LANGUAGE RecordWildCards #-}

    -- | Printer for fixity maps.
    module Ormolu.Fixity.Printer
      ( printFixityMap,
      )
    where

    import qualified Data.Char as Char
    import qualified Data.Map.Strict as Map
    import Data.Text (Text)
    import qualified Data.Text as T
    import qualified Data.Text.Lazy as TL
    import Data.Text.Lazy.Builder (Builder)
    import qualified Data.Text.Lazy.Builder as B
    import qualified Data.Text.Lazy.Builder.Int as B
    import Ormolu.Fixity

    -- | Print out a textual representation of a 'FixityMap'.
    printFixityMap :: FixityMap -> Text
    printFixityMap :: FixityMap -> Text
    printFixityMap =
      Text -> Text
    TL.toStrict
        (Text -> Text) -> (FixityMap -> Text) -> FixityMap -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Builder -> Text
    B.toLazyText
        (Builder -> Text) -> (FixityMap -> Builder) -> FixityMap -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Builder] -> Builder
    forall a. Monoid a => [a] -> a
    mconcat
        ([Builder] -> Builder)
    -> (FixityMap -> [Builder]) -> FixityMap -> Builder
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ((FixityDirection, Int, OpName) -> Builder)
    -> [(FixityDirection, Int, OpName)] -> [Builder]
    forall a b. (a -> b) -> [a] -> [b]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (FixityDirection, Int, OpName) -> Builder
    renderOne
        ([(FixityDirection, Int, OpName)] -> [Builder])
    -> (FixityMap -> [(FixityDirection, Int, OpName)])
    -> FixityMap
    -> [Builder]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ((OpName, FixityInfo) -> [(FixityDirection, Int, OpName)])
    -> [(OpName, FixityInfo)] -> [(FixityDirection, Int, OpName)]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap (OpName, FixityInfo) -> [(FixityDirection, Int, OpName)]
    decompose
        ([(OpName, FixityInfo)] -> [(FixityDirection, Int, OpName)])
    -> (FixityMap -> [(OpName, FixityInfo)])
    -> FixityMap
    -> [(FixityDirection, Int, OpName)]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . FixityMap -> [(OpName, FixityInfo)]
    forall k a. Map k a -> [(k, a)]
    Map.toList
      where
        decompose :: (OpName, FixityInfo) -> [(FixityDirection, Int, OpName)]
        decompose :: (OpName, FixityInfo) -> [(FixityDirection, Int, OpName)]
    decompose (OpName
    operator, FixityInfo {Int
    Maybe FixityDirection
    fiDirection :: Maybe FixityDirection
    fiMinPrecedence :: Int
    fiMaxPrecedence :: Int
    fiDirection :: FixityInfo -> Maybe FixityDirection
    fiMinPrecedence :: FixityInfo -> Int
    fiMaxPrecedence :: FixityInfo -> Int
    ..}) =
          let forDirection :: a -> [(a, Int, OpName)]
    forDirection a
    dir =
                (a
    dir, Int
    fiMinPrecedence, OpName
    operator)
                  (a, Int, OpName) -> [(a, Int, OpName)] -> [(a, Int, OpName)]
    forall a. a -> [a] -> [a]
    : [ (a
    dir, Int
    fiMaxPrecedence, OpName
    operator)
                      | Int
    fiMinPrecedence Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Int
    fiMaxPrecedence
                    ]
           in case Maybe FixityDirection
    fiDirection of
                Maybe FixityDirection
    Nothing -> (FixityDirection -> [(FixityDirection, Int, OpName)])
    -> [FixityDirection] -> [(FixityDirection, Int, OpName)]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap FixityDirection -> [(FixityDirection, Int, OpName)]
    forall {a}. a -> [(a, Int, OpName)]
    forDirection [FixityDirection
    InfixL, FixityDirection
    InfixR]
                Just FixityDirection
    dir -> FixityDirection -> [(FixityDirection, Int, OpName)]
    forall {a}. a -> [(a, Int, OpName)]
    forDirection FixityDirection
    dir
        renderOne :: (FixityDirection, Int, OpName) -> Builder
        renderOne :: (FixityDirection, Int, OpName) -> Builder
    renderOne (FixityDirection
    fixityDirection, Int
    n, OpName Text
    operator) =
          [Builder] -> Builder
    forall a. Monoid a => [a] -> a
    mconcat
            [ case FixityDirection
    fixityDirection of
                FixityDirection
    InfixL -> Builder
    "infixl"
                FixityDirection
    InfixR -> Builder
    "infixr"
                FixityDirection
    InfixN -> Builder
    "infix",
              Builder
    " ",
              Int -> Builder
    forall a. Integral a => a -> Builder
    B.decimal Int
    n,
              Builder
    " ",
              if Text -> Bool
    isTickedOperator Text
    operator
                then Builder
    "`" Builder -> Builder -> Builder
    forall a. Semigroup a => a -> a -> a
    <> Text -> Builder
    B.fromText Text
    operator Builder -> Builder -> Builder
    forall a. Semigroup a => a -> a -> a
    <> Builder
    "`"
                else Text -> Builder
    B.fromText Text
    operator,
              Builder
    "\n"
            ]
        isTickedOperator :: Text -> Bool
    isTickedOperator = Bool -> ((Char, Text) -> Bool) -> Maybe (Char, Text) -> Bool
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe Bool
    True (Char -> Bool
    Char.isLetter (Char -> Bool) -> ((Char, Text) -> Char) -> (Char, Text) -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Char, Text) -> Char
    forall a b. (a, b) -> a
    fst) (Maybe (Char, Text) -> Bool)
    -> (Text -> Maybe (Char, Text)) -> Text -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> Maybe (Char, Text)
    T.uncons