content: {-# LANGUAGE TupleSections, OverloadedStrings #-}
  {-|
  Description: Additional functions that should probably be in @hnix@
  
  Nix generation helpers. No guarantee of stability (internal!).
  -}
  module Nix.Expr.Additions
  ( stringKey, ($$=), dynamicKey, inheritStatic
  , simpleParamSet, multiParam
  , (!!.)
  , StrQ(..), mkStrQ, mkStrQI
  ) where
  
  import Data.Fix (Fix(..))
  import Data.Text (Text)
  import Data.String (IsString(..))
  
  import Nix.Expr
  import Text.Regex.TDFA.Text ()
  import Text.Regex.TDFA ((=~))
  
  -- hnix helpers
  -- TODO submit upstream
  
  -- | Make a binding, but have the key be a string, not symbol.
  stringKey :: Text -> NExpr -> Binding NExpr
  stringKey k v = NamedVar (pure $ dynamicKey k) v nullPos
  -- | Infix version of 'stringKey'.
  ($$=) :: Text -> NExpr -> Binding NExpr
  ($$=) = stringKey
  infixr 2 $$=
  
  -- | Make a dynamic key name that is only enclosed in double quotes (no antiquotes).
  dynamicKey :: Text -> NKeyName NExpr
  dynamicKey k = DynamicKey $ Plain $ DoubleQuoted [Plain k]
  
  -- | Inherit the given list of symbols.
  inheritStatic :: [Text] -> Binding e
  inheritStatic names = inherit (map StaticKey names) nullPos
  
  -- | shortcut to create a list of closed params, like @{ foo, bar, baz }:@
  simpleParamSet :: [Text] -> Params NExpr
  simpleParamSet prms = mkParamset (fmap (, Nothing) prms) False
  
  -- | shortcut to create a list of multiple params, like @a: b: c:@
  multiParam :: [Text] -> NExpr -> NExpr
  multiParam ps expr = foldr mkFunction expr $ map Param ps
  
  -- TODO: switch over to !. when
  -- https://github.com/jwiegley/hnix/commit/8b4c137a3b125f52bb78039a9d201492032b38e8
  -- goes upstream
  -- | Like '!.', but automatically convert plain strings to static keys.
  (!!.) :: NExpr -> Text -> NExpr
  aset !!. k = Fix
    $ NSelect aset
        (pure $ (if isPlainSymbol k then StaticKey else dynamicKey) k) Nothing
    where
      -- the nix lexer regex for IDs (symbols) is 
      -- [a-zA-Z\_][a-zA-Z0-9\_\'\-]*
      isPlainSymbol :: Text -> Bool
      isPlainSymbol s = s =~ ("^[a-zA-Z_][a-zA-Z0-9_'-]*$" :: Text)
  infixl 8 !!.
  
  
  -- | String quotation, either a plain string (S) or antiquoted (A)
  data StrQ = StrQ !Text | AntiQ !NExpr
  instance IsString StrQ where
    fromString = StrQ . fromString
  
  -- 
  mkStrQtmpl :: ([Antiquoted Text NExpr] -> NString NExpr) -> [StrQ] -> NExpr
  mkStrQtmpl strtr = Fix . NStr . strtr . map trans
    where trans (StrQ t) = Plain t
          trans (AntiQ r) = Antiquoted r
  
  mkStrQ, mkStrQI :: [StrQ] -> NExpr
  -- | Create a double-quoted string from a list of antiquotes/plain strings.
  mkStrQ = mkStrQtmpl DoubleQuoted
  -- | Create a single-quoted string from a list of antiquotes/plain strings.
  mkStrQI = mkStrQtmpl (Indented 2)
  