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

{-# OPTIONS_GHC -Wno-orphans #-}

module Dhall.Syntax.Instances.Pretty
    ( pathCharacter
    ) where

import                Data.Text             (Text)
import {-# SOURCE #-} Dhall.Pretty.Internal
import                Dhall.Syntax.Const
import                Dhall.Syntax.Expr
import                Dhall.Syntax.Import
import                Dhall.Syntax.Var
import                Prettyprinter         (Doc, Pretty)

import qualified Data.Text
import qualified Network.URI   as URI
import qualified Prettyprinter as Pretty

instance Pretty Const where
    pretty :: Const -> Doc ann
pretty = Doc Ann -> Doc ann
forall ann xxx. Doc ann -> Doc xxx
Pretty.unAnnotate (Doc Ann -> Doc ann) -> (Const -> Doc Ann) -> Const -> Doc ann
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Const -> Doc Ann
prettyConst

instance Pretty Var where
    pretty :: Var -> Doc ann
pretty = Doc Ann -> Doc ann
forall ann xxx. Doc ann -> Doc xxx
Pretty.unAnnotate (Doc Ann -> Doc ann) -> (Var -> Doc Ann) -> Var -> Doc ann
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Var -> Doc Ann
prettyVar

-- | Generates a syntactically valid Dhall program
instance Pretty a => Pretty (Expr s a) where
    pretty :: Expr s a -> Doc ann
pretty = Doc Ann -> Doc ann
forall ann xxx. Doc ann -> Doc xxx
Pretty.unAnnotate (Doc Ann -> Doc ann)
-> (Expr s a -> Doc Ann) -> Expr s a -> Doc ann
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Expr s a -> Doc Ann
forall a s. Pretty a => Expr s a -> Doc Ann
prettyExpr

instance Pretty Directory where
    pretty :: Directory -> Doc ann
pretty (Directory {[Text]
components :: Directory -> [Text]
components :: [Text]
..}) = (Text -> Doc ann) -> [Text] -> Doc ann
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap Text -> Doc ann
forall ann. Text -> Doc ann
prettyPathComponent ([Text] -> [Text]
forall a. [a] -> [a]
reverse [Text]
components)

prettyPathComponent :: Text -> Doc ann
prettyPathComponent :: Text -> Doc ann
prettyPathComponent Text
text
    | (Char -> Bool) -> Text -> Bool
Data.Text.all Char -> Bool
pathCharacter Text
text =
        Doc ann
"/" Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
Pretty.pretty Text
text
    | Bool
otherwise =
        Doc ann
"/\"" Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
Pretty.pretty Text
text Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Doc ann
"\""

instance Pretty File where
    pretty :: File -> Doc ann
pretty (File {Text
Directory
file :: File -> Text
directory :: File -> Directory
file :: Text
directory :: Directory
..}) =
            Directory -> Doc ann
forall a ann. Pretty a => a -> Doc ann
Pretty.pretty Directory
directory
        Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<>  Text -> Doc ann
forall ann. Text -> Doc ann
prettyPathComponent Text
file

instance Pretty FilePrefix where
    pretty :: FilePrefix -> Doc ann
pretty FilePrefix
Absolute = Doc ann
""
    pretty FilePrefix
Here     = Doc ann
"."
    pretty FilePrefix
Parent   = Doc ann
".."
    pretty FilePrefix
Home     = Doc ann
"~"

instance Pretty URL where
    pretty :: URL -> Doc ann
pretty (URL {Maybe Text
Maybe (Expr Src Import)
Text
Scheme
File
headers :: URL -> Maybe (Expr Src Import)
query :: URL -> Maybe Text
path :: URL -> File
authority :: URL -> Text
scheme :: URL -> Scheme
headers :: Maybe (Expr Src Import)
query :: Maybe Text
path :: File
authority :: Text
scheme :: Scheme
..}) =
            Doc ann
schemeDoc
        Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<>  Doc ann
"://"
        Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<>  Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
Pretty.pretty Text
authority
        Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<>  Doc ann
forall ann. Doc ann
pathDoc
        Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<>  Doc ann
forall ann. Doc ann
queryDoc
        Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<>  (Expr Src Import -> Doc ann) -> Maybe (Expr Src Import) -> Doc ann
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap Expr Src Import -> Doc ann
forall a xxx. Pretty a => a -> Doc xxx
prettyHeaders Maybe (Expr Src Import)
headers
      where
        prettyHeaders :: a -> Doc xxx
prettyHeaders a
h =
          Doc xxx
" using (" Doc xxx -> Doc xxx -> Doc xxx
forall a. Semigroup a => a -> a -> a
<> Doc Any -> Doc xxx
forall ann xxx. Doc ann -> Doc xxx
Pretty.unAnnotate (a -> Doc Any
forall a ann. Pretty a => a -> Doc ann
Pretty.pretty a
h) Doc xxx -> Doc xxx -> Doc xxx
forall a. Semigroup a => a -> a -> a
<> Doc xxx
")"

        File {Text
Directory
file :: Text
directory :: Directory
file :: File -> Text
directory :: File -> Directory
..} = File
path

        Directory {[Text]
components :: [Text]
components :: Directory -> [Text]
..} = Directory
directory

        pathDoc :: Doc ann
pathDoc =
                (Text -> Doc ann) -> [Text] -> Doc ann
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap Text -> Doc ann
forall ann. Text -> Doc ann
prettyURIComponent ([Text] -> [Text]
forall a. [a] -> [a]
reverse [Text]
components)
            Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<>  Text -> Doc ann
forall ann. Text -> Doc ann
prettyURIComponent Text
file

        schemeDoc :: Doc ann
schemeDoc = case Scheme
scheme of
            Scheme
HTTP  -> Doc ann
"http"
            Scheme
HTTPS -> Doc ann
"https"

        queryDoc :: Doc ann
queryDoc = case Maybe Text
query of
            Maybe Text
Nothing -> Doc ann
""
            Just Text
q  -> Doc ann
"?" Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
Pretty.pretty Text
q

prettyURIComponent :: Text -> Doc ann
prettyURIComponent :: Text -> Doc ann
prettyURIComponent Text
text =
        String -> Doc ann
forall a ann. Pretty a => a -> Doc ann
Pretty.pretty (String -> Doc ann) -> String -> Doc ann
forall a b. (a -> b) -> a -> b
$ String -> String
URI.normalizeCase (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ String -> String
URI.normalizeEscape (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ String
"/" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Text -> String
Data.Text.unpack Text
text

instance Pretty ImportType where
    pretty :: ImportType -> Doc ann
pretty (Local FilePrefix
prefix File
file) =
        FilePrefix -> Doc ann
forall a ann. Pretty a => a -> Doc ann
Pretty.pretty FilePrefix
prefix Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> File -> Doc ann
forall a ann. Pretty a => a -> Doc ann
Pretty.pretty File
file

    pretty (Remote URL
url) = URL -> Doc ann
forall a ann. Pretty a => a -> Doc ann
Pretty.pretty URL
url

    pretty (Env Text
env) = Doc ann
"env:" Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Text -> Doc ann
forall ann. Text -> Doc ann
prettyEnvironmentVariable Text
env

    pretty ImportType
Missing = Doc ann
"missing"

instance Pretty ImportHashed where
    pretty :: ImportHashed -> Doc ann
pretty (ImportHashed  Maybe SHA256Digest
Nothing ImportType
p) =
      ImportType -> Doc ann
forall a ann. Pretty a => a -> Doc ann
Pretty.pretty ImportType
p
    pretty (ImportHashed (Just SHA256Digest
h) ImportType
p) =
      Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
Pretty.group (Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
Pretty.flatAlt Doc ann
forall ann. Doc ann
long Doc ann
forall ann. Doc ann
short)
      where
        long :: Doc ann
long =
            Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann
Pretty.align
                (   ImportType -> Doc ann
forall a ann. Pretty a => a -> Doc ann
Pretty.pretty ImportType
p Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Doc ann
forall ann. Doc ann
Pretty.hardline
                Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<>  Doc ann
"  sha256:" Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> String -> Doc ann
forall a ann. Pretty a => a -> Doc ann
Pretty.pretty (SHA256Digest -> String
forall a. Show a => a -> String
show SHA256Digest
h)
                )

        short :: Doc ann
short = ImportType -> Doc ann
forall a ann. Pretty a => a -> Doc ann
Pretty.pretty ImportType
p Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Doc ann
" sha256:" Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> String -> Doc ann
forall a ann. Pretty a => a -> Doc ann
Pretty.pretty (SHA256Digest -> String
forall a. Show a => a -> String
show SHA256Digest
h)

instance Pretty Import where
    pretty :: Import -> Doc ann
pretty (Import {ImportHashed
ImportMode
importMode :: Import -> ImportMode
importHashed :: Import -> ImportHashed
importMode :: ImportMode
importHashed :: ImportHashed
..}) = ImportHashed -> Doc ann
forall a ann. Pretty a => a -> Doc ann
Pretty.pretty ImportHashed
importHashed Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Text -> Doc ann
forall a ann. Pretty a => a -> Doc ann
Pretty.pretty Text
suffix
      where
        suffix :: Text
        suffix :: Text
suffix = case ImportMode
importMode of
            ImportMode
RawText  -> Text
" as Text"
            ImportMode
Location -> Text
" as Location"
            ImportMode
Code     -> Text
""
            ImportMode
RawBytes -> Text
" as Bytes"

{-| Returns `True` if the given `Char` is valid within an unquoted path
    component

    This is exported for reuse within the @"Dhall.Parser.Token"@ module
-}
pathCharacter :: Char -> Bool
pathCharacter :: Char -> Bool
pathCharacter Char
c =
         Char
'\x21' Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
c
    Bool -> Bool -> Bool
||  (Char
'\x24' Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'\x27')
    Bool -> Bool -> Bool
||  (Char
'\x2A' Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'\x2B')
    Bool -> Bool -> Bool
||  (Char
'\x2D' Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'\x2E')
    Bool -> Bool -> Bool
||  (Char
'\x30' Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'\x3B')
    Bool -> Bool -> Bool
||  Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\x3D'
    Bool -> Bool -> Bool
||  (Char
'\x40' Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'\x5A')
    Bool -> Bool -> Bool
||  (Char
'\x5E' Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'\x7A')
    Bool -> Bool -> Bool
||  Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\x7C'
    Bool -> Bool -> Bool
||  Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\x7E'