{-# LANGUAGE NamedFieldPuns #-}

module CabalGild.Unstable.Type.Dependency where

import qualified CabalGild.Unstable.Type.VersionRange as VersionRange
import qualified Control.Monad as Monad
import qualified Data.List.NonEmpty as NonEmpty
import qualified Distribution.CabalSpecVersion as CabalSpecVersion
import qualified Distribution.Compat.CharParsing as Parse
import qualified Distribution.Parsec as Parsec
import qualified Distribution.Pretty as Pretty
import qualified Distribution.Types.PackageName as PackageName
import qualified Distribution.Types.UnqualComponentName as UnqualComponentName
import qualified Text.PrettyPrint as PrettyPrint

data Dependency = MkDependency
  { Dependency -> PackageName
packageName :: PackageName.PackageName,
    Dependency
-> Maybe
     (Either UnqualComponentName (NonEmpty UnqualComponentName))
libraryNames :: Maybe (Either UnqualComponentName.UnqualComponentName (NonEmpty.NonEmpty UnqualComponentName.UnqualComponentName)),
    Dependency -> Maybe VersionRange
versionRange :: Maybe VersionRange.VersionRange
  }
  deriving (Dependency -> Dependency -> Bool
(Dependency -> Dependency -> Bool)
-> (Dependency -> Dependency -> Bool) -> Eq Dependency
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Dependency -> Dependency -> Bool
== :: Dependency -> Dependency -> Bool
$c/= :: Dependency -> Dependency -> Bool
/= :: Dependency -> Dependency -> Bool
Eq, Eq Dependency
Eq Dependency =>
(Dependency -> Dependency -> Ordering)
-> (Dependency -> Dependency -> Bool)
-> (Dependency -> Dependency -> Bool)
-> (Dependency -> Dependency -> Bool)
-> (Dependency -> Dependency -> Bool)
-> (Dependency -> Dependency -> Dependency)
-> (Dependency -> Dependency -> Dependency)
-> Ord Dependency
Dependency -> Dependency -> Bool
Dependency -> Dependency -> Ordering
Dependency -> Dependency -> Dependency
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Dependency -> Dependency -> Ordering
compare :: Dependency -> Dependency -> Ordering
$c< :: Dependency -> Dependency -> Bool
< :: Dependency -> Dependency -> Bool
$c<= :: Dependency -> Dependency -> Bool
<= :: Dependency -> Dependency -> Bool
$c> :: Dependency -> Dependency -> Bool
> :: Dependency -> Dependency -> Bool
$c>= :: Dependency -> Dependency -> Bool
>= :: Dependency -> Dependency -> Bool
$cmax :: Dependency -> Dependency -> Dependency
max :: Dependency -> Dependency -> Dependency
$cmin :: Dependency -> Dependency -> Dependency
min :: Dependency -> Dependency -> Dependency
Ord, Int -> Dependency -> ShowS
[Dependency] -> ShowS
Dependency -> String
(Int -> Dependency -> ShowS)
-> (Dependency -> String)
-> ([Dependency] -> ShowS)
-> Show Dependency
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Dependency -> ShowS
showsPrec :: Int -> Dependency -> ShowS
$cshow :: Dependency -> String
show :: Dependency -> String
$cshowList :: [Dependency] -> ShowS
showList :: [Dependency] -> ShowS
Show)

instance Parsec.Parsec Dependency where
  parsec :: forall (m :: * -> *). CabalParsing m => m Dependency
parsec = do
    packageName <- m PackageName
forall a (m :: * -> *). (Parsec a, CabalParsing m) => m a
forall (m :: * -> *). CabalParsing m => m PackageName
Parsec.parsec
    libraryNames <- Parse.optional $ do
      Monad.void $ Parse.char ':'
      csv <- Parsec.askCabalSpecVersion
      Monad.guard $ csv >= CabalSpecVersion.CabalSpecV3_0
      Monad.msum
        [ Left <$> Parsec.parsec,
          Right
            <$> Parse.between
              (Parse.char '{' *> Parse.spaces)
              (Parse.spaces <* Parse.char '}')
              (Parsec.parsecCommaNonEmpty Parsec.parsec)
        ]
    Parse.spaces
    versionRange <- Parse.optional Parsec.parsec
    pure MkDependency {packageName, libraryNames, versionRange}

instance Pretty.Pretty Dependency where
  pretty :: Dependency -> Doc
pretty Dependency
dependency =
    let pkg :: Doc
pkg = PackageName -> Doc
forall a. Pretty a => a -> Doc
Pretty.pretty (PackageName -> Doc) -> PackageName -> Doc
forall a b. (a -> b) -> a -> b
$ Dependency -> PackageName
packageName Dependency
dependency
        libs :: Doc
libs = case Dependency
-> Maybe
     (Either UnqualComponentName (NonEmpty UnqualComponentName))
libraryNames Dependency
dependency of
          Maybe (Either UnqualComponentName (NonEmpty UnqualComponentName))
Nothing -> Doc
forall a. Monoid a => a
mempty
          Just Either UnqualComponentName (NonEmpty UnqualComponentName)
e ->
            Char -> Doc
PrettyPrint.char Char
':' Doc -> Doc -> Doc
forall a. Semigroup a => a -> a -> a
<> case Either UnqualComponentName (NonEmpty UnqualComponentName)
e of
              Left UnqualComponentName
ucn -> UnqualComponentName -> Doc
forall a. Pretty a => a -> Doc
Pretty.pretty UnqualComponentName
ucn
              Right NonEmpty UnqualComponentName
ucns ->
                Doc -> Doc
PrettyPrint.braces
                  (Doc -> Doc)
-> (NonEmpty UnqualComponentName -> Doc)
-> NonEmpty UnqualComponentName
-> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Doc] -> Doc
PrettyPrint.hsep
                  ([Doc] -> Doc)
-> (NonEmpty UnqualComponentName -> [Doc])
-> NonEmpty UnqualComponentName
-> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Doc -> [Doc] -> [Doc]
PrettyPrint.punctuate Doc
PrettyPrint.comma
                  ([Doc] -> [Doc])
-> (NonEmpty UnqualComponentName -> [Doc])
-> NonEmpty UnqualComponentName
-> [Doc]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UnqualComponentName -> Doc) -> [UnqualComponentName] -> [Doc]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap UnqualComponentName -> Doc
forall a. Pretty a => a -> Doc
Pretty.pretty
                  ([UnqualComponentName] -> [Doc])
-> (NonEmpty UnqualComponentName -> [UnqualComponentName])
-> NonEmpty UnqualComponentName
-> [Doc]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty UnqualComponentName -> [UnqualComponentName]
forall a. NonEmpty a -> [a]
NonEmpty.toList
                  (NonEmpty UnqualComponentName -> Doc)
-> NonEmpty UnqualComponentName -> Doc
forall a b. (a -> b) -> a -> b
$ NonEmpty UnqualComponentName -> NonEmpty UnqualComponentName
forall a. Ord a => NonEmpty a -> NonEmpty a
NonEmpty.sort NonEmpty UnqualComponentName
ucns
        ver :: Doc
ver = (VersionRange -> Doc) -> Maybe VersionRange -> Doc
forall m a. Monoid m => (a -> m) -> Maybe a -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap VersionRange -> Doc
forall a. Pretty a => a -> Doc
Pretty.pretty (Maybe VersionRange -> Doc) -> Maybe VersionRange -> Doc
forall a b. (a -> b) -> a -> b
$ Dependency -> Maybe VersionRange
versionRange Dependency
dependency
     in [Doc] -> Doc
PrettyPrint.hsep [Doc
pkg Doc -> Doc -> Doc
forall a. Semigroup a => a -> a -> a
<> Doc
libs, Doc
ver]