2018-04-19 01:28:21 +02:00
|
|
|
{-# LANGUAGE CPP #-}
|
2018-04-11 06:11:46 +02:00
|
|
|
{-# LANGUAGE FlexibleInstances #-}
|
2018-04-23 19:06:49 +02:00
|
|
|
{-# LANGUAGE LambdaCase #-}
|
2018-04-07 21:02:50 +02:00
|
|
|
{-# LANGUAGE RankNTypes #-}
|
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
2018-04-26 05:30:44 +02:00
|
|
|
{-# LANGUAGE TupleSections #-}
|
2018-04-11 06:11:46 +02:00
|
|
|
{-# LANGUAGE TypeSynonymInstances #-}
|
2018-04-25 08:09:43 +02:00
|
|
|
{-# LANGUAGE ViewPatterns #-}
|
2018-04-07 21:02:50 +02:00
|
|
|
|
|
|
|
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
|
2018-04-11 06:11:46 +02:00
|
|
|
{-# OPTIONS_GHC -Wno-orphans #-}
|
2018-04-07 21:02:50 +02:00
|
|
|
|
|
|
|
module Nix.Pretty where
|
|
|
|
|
2018-04-08 07:46:05 +02:00
|
|
|
import Control.Monad
|
2018-04-07 21:02:50 +02:00
|
|
|
import Data.Fix
|
|
|
|
import Data.HashMap.Lazy (toList)
|
|
|
|
import qualified Data.HashMap.Lazy as M
|
|
|
|
import qualified Data.HashSet as HashSet
|
|
|
|
import Data.List (isPrefixOf, sort)
|
2018-04-17 21:46:41 +02:00
|
|
|
import Data.List.NonEmpty (NonEmpty(..))
|
|
|
|
import qualified Data.List.NonEmpty as NE
|
2018-04-07 21:02:50 +02:00
|
|
|
import Data.Maybe (isJust)
|
|
|
|
import Data.Text (pack, unpack, replace, strip)
|
|
|
|
import qualified Data.Text as Text
|
|
|
|
import Nix.Atoms
|
|
|
|
import Nix.Expr
|
2018-05-07 21:06:56 +02:00
|
|
|
import Nix.Parser
|
2018-05-08 22:47:50 +02:00
|
|
|
import Nix.NixString
|
2018-04-21 02:05:21 +02:00
|
|
|
import Nix.Strings
|
2018-04-07 21:02:50 +02:00
|
|
|
import Nix.Thunk
|
2018-04-19 01:28:21 +02:00
|
|
|
#if ENABLE_TRACING
|
|
|
|
import Nix.Utils
|
|
|
|
#else
|
2018-04-08 07:46:05 +02:00
|
|
|
import Nix.Utils hiding ((<$>))
|
2018-04-19 01:28:21 +02:00
|
|
|
#endif
|
2018-04-17 21:46:41 +02:00
|
|
|
import Nix.Value
|
2018-04-07 21:02:50 +02:00
|
|
|
import Prelude hiding ((<$>))
|
|
|
|
import Text.PrettyPrint.ANSI.Leijen
|
|
|
|
|
|
|
|
-- | This type represents a pretty printed nix expression
|
|
|
|
-- together with some information about the expression.
|
|
|
|
data NixDoc = NixDoc
|
|
|
|
{ -- | The rendered expression, without any parentheses.
|
|
|
|
withoutParens :: Doc
|
|
|
|
|
|
|
|
-- | The root operator is the operator at the root of
|
|
|
|
-- the expression tree. For example, in '(a * b) + c', '+' would be the root
|
|
|
|
-- operator. It is needed to determine if we need to wrap the expression in
|
|
|
|
-- parentheses.
|
|
|
|
, rootOp :: OperatorInfo
|
2018-05-06 00:56:56 +02:00
|
|
|
, wasPath :: Bool -- This is needed so that when a path is used in a selector path
|
|
|
|
-- we can add brackets appropiately
|
2018-04-07 21:02:50 +02:00
|
|
|
}
|
|
|
|
|
2018-05-06 00:56:56 +02:00
|
|
|
mkNixDoc :: Doc -> OperatorInfo -> NixDoc
|
|
|
|
mkNixDoc d o = NixDoc { withoutParens = d, rootOp = o, wasPath = False }
|
|
|
|
|
2018-04-07 21:02:50 +02:00
|
|
|
-- | A simple expression is never wrapped in parentheses. The expression
|
2018-04-19 09:21:30 +02:00
|
|
|
-- behaves as if its root operator had a precedence higher than all
|
|
|
|
-- other operators (including function application).
|
2018-04-07 21:02:50 +02:00
|
|
|
simpleExpr :: Doc -> NixDoc
|
2018-05-06 00:56:56 +02:00
|
|
|
simpleExpr d = mkNixDoc d (OperatorInfo minBound NAssocNone "simple expr")
|
|
|
|
|
|
|
|
pathExpr :: Doc -> NixDoc
|
|
|
|
pathExpr d = (simpleExpr d) { wasPath = True }
|
2018-04-07 21:02:50 +02:00
|
|
|
|
2018-04-19 09:21:30 +02:00
|
|
|
-- | An expression that behaves as if its root operator had a precedence lower
|
|
|
|
-- than all other operators. That ensures that the expression is wrapped in
|
|
|
|
-- parantheses in almost always, but it's still rendered without parentheses
|
|
|
|
-- in cases where parentheses are never required (such as in the LHS of a
|
|
|
|
-- binding).
|
2018-04-07 21:02:50 +02:00
|
|
|
leastPrecedence :: Doc -> NixDoc
|
2018-04-19 09:21:30 +02:00
|
|
|
leastPrecedence =
|
2018-05-06 00:56:56 +02:00
|
|
|
flip mkNixDoc $ OperatorInfo maxBound NAssocNone "least precedence"
|
2018-04-07 21:02:50 +02:00
|
|
|
|
2018-04-10 02:12:16 +02:00
|
|
|
appOp :: OperatorInfo
|
|
|
|
appOp = getBinaryOperator NApp
|
|
|
|
|
2018-04-07 21:02:50 +02:00
|
|
|
appOpNonAssoc :: OperatorInfo
|
2018-04-10 02:12:16 +02:00
|
|
|
appOpNonAssoc = (getBinaryOperator NApp) { associativity = NAssocNone }
|
|
|
|
|
|
|
|
selectOp :: OperatorInfo
|
|
|
|
selectOp = getSpecialOperator NSelectOp
|
|
|
|
|
|
|
|
hasAttrOp :: OperatorInfo
|
|
|
|
hasAttrOp = getSpecialOperator NHasAttrOp
|
2018-04-07 21:02:50 +02:00
|
|
|
|
|
|
|
wrapParens :: OperatorInfo -> NixDoc -> Doc
|
|
|
|
wrapParens op sub
|
2018-04-19 10:02:15 +02:00
|
|
|
| precedence (rootOp sub) < precedence op = withoutParens sub
|
2018-04-07 21:02:50 +02:00
|
|
|
| precedence (rootOp sub) == precedence op
|
|
|
|
&& associativity (rootOp sub) == associativity op
|
|
|
|
&& associativity op /= NAssocNone = withoutParens sub
|
|
|
|
| otherwise = parens $ withoutParens sub
|
|
|
|
|
2018-05-06 00:56:56 +02:00
|
|
|
-- Used in the selector case to print a path in a selector as
|
|
|
|
-- "${./abc}"
|
|
|
|
wrapPath :: OperatorInfo -> NixDoc -> Doc
|
|
|
|
wrapPath op sub =
|
|
|
|
if wasPath sub then dquotes (text "$" <> braces (withoutParens sub))
|
|
|
|
else wrapParens op sub
|
|
|
|
|
2018-04-07 21:02:50 +02:00
|
|
|
prettyString :: NString NixDoc -> Doc
|
|
|
|
prettyString (DoubleQuoted parts) = dquotes . hcat . map prettyPart $ parts
|
|
|
|
where prettyPart (Plain t) = text . concatMap escape . unpack $ t
|
2018-05-06 12:27:10 +02:00
|
|
|
prettyPart EscapedNewline = text "''\\n"
|
2018-04-07 21:02:50 +02:00
|
|
|
prettyPart (Antiquoted r) = text "$" <> braces (withoutParens r)
|
|
|
|
escape '"' = "\\\""
|
|
|
|
escape x = maybe [x] (('\\':) . (:[])) $ toEscapeCode x
|
2018-04-11 21:06:14 +02:00
|
|
|
prettyString (Indented _ parts)
|
2018-04-07 21:02:50 +02:00
|
|
|
= group $ nest 2 (squote <> squote <$$> content) <$$> squote <> squote
|
|
|
|
where
|
|
|
|
content = vsep . map prettyLine . stripLastIfEmpty . splitLines $ parts
|
|
|
|
stripLastIfEmpty = reverse . f . reverse where
|
|
|
|
f ([Plain t] : xs) | Text.null (strip t) = xs
|
|
|
|
f xs = xs
|
|
|
|
prettyLine = hcat . map prettyPart
|
|
|
|
prettyPart (Plain t) = text . unpack . replace "${" "''${" . replace "''" "'''" $ t
|
2018-05-06 12:27:10 +02:00
|
|
|
prettyPart EscapedNewline = text "\\n"
|
2018-04-07 21:02:50 +02:00
|
|
|
prettyPart (Antiquoted r) = text "$" <> braces (withoutParens r)
|
|
|
|
|
|
|
|
prettyParams :: Params NixDoc -> Doc
|
|
|
|
prettyParams (Param n) = text $ unpack n
|
|
|
|
prettyParams (ParamSet s v mname) = prettyParamSet s v <> case mname of
|
|
|
|
Nothing -> empty
|
2018-05-07 07:14:01 +02:00
|
|
|
Just name | Text.null name -> empty
|
|
|
|
| otherwise -> text "@" <> text (unpack name)
|
2018-04-07 21:02:50 +02:00
|
|
|
|
|
|
|
prettyParamSet :: ParamSet NixDoc -> Bool -> Doc
|
|
|
|
prettyParamSet args var =
|
2018-04-20 02:05:20 +02:00
|
|
|
encloseSep (lbrace <> space) (align (space <> rbrace)) sep (map prettySetArg args ++ prettyVariadic)
|
2018-04-07 21:02:50 +02:00
|
|
|
where
|
|
|
|
prettySetArg (n, maybeDef) = case maybeDef of
|
|
|
|
Nothing -> text (unpack n)
|
|
|
|
Just v -> text (unpack n) <+> text "?" <+> withoutParens v
|
2018-04-25 08:09:43 +02:00
|
|
|
prettyVariadic = [text "..." | var]
|
2018-04-07 21:02:50 +02:00
|
|
|
sep = align (comma <> space)
|
|
|
|
|
|
|
|
prettyBind :: Binding NixDoc -> Doc
|
|
|
|
prettyBind (NamedVar n v) =
|
|
|
|
prettySelector n <+> equals <+> withoutParens v <> semi
|
|
|
|
prettyBind (Inherit s ns)
|
|
|
|
= text "inherit" <+> scope <> align (fillSep (map prettyKeyName ns)) <> semi
|
|
|
|
where scope = maybe empty ((<> space) . parens . withoutParens) s
|
|
|
|
|
|
|
|
prettyKeyName :: NKeyName NixDoc -> Doc
|
|
|
|
prettyKeyName (StaticKey "" _) = dquotes $ text ""
|
|
|
|
prettyKeyName (StaticKey key _)
|
2018-04-10 02:12:16 +02:00
|
|
|
| HashSet.member key reservedNames = dquotes $ text $ unpack key
|
2018-04-07 21:02:50 +02:00
|
|
|
prettyKeyName (StaticKey key _) = text . unpack $ key
|
2018-04-11 03:45:57 +02:00
|
|
|
prettyKeyName (DynamicKey key) =
|
2018-04-19 10:20:17 +02:00
|
|
|
runAntiquoted (DoubleQuoted [Plain "\n"])
|
|
|
|
prettyString ((text "$" <>) . braces . withoutParens) key
|
2018-04-07 21:02:50 +02:00
|
|
|
|
|
|
|
prettySelector :: NAttrPath NixDoc -> Doc
|
2018-04-17 21:46:41 +02:00
|
|
|
prettySelector = hcat . punctuate dot . map prettyKeyName . NE.toList
|
2018-04-07 21:02:50 +02:00
|
|
|
|
|
|
|
prettyAtom :: NAtom -> NixDoc
|
|
|
|
prettyAtom atom = simpleExpr $ text $ unpack $ atomText atom
|
|
|
|
|
|
|
|
prettyNix :: NExpr -> Doc
|
2018-04-23 19:06:49 +02:00
|
|
|
prettyNix = withoutParens . cata exprFNixDoc
|
|
|
|
|
|
|
|
prettyOriginExpr :: NExprLocF (Maybe (NValue m)) -> Doc
|
|
|
|
prettyOriginExpr = withoutParens . go
|
|
|
|
where
|
|
|
|
go = exprFNixDoc . annotated . getCompose . fmap render
|
|
|
|
|
2018-04-25 08:09:43 +02:00
|
|
|
render Nothing = simpleExpr $ text "_"
|
2018-05-06 09:40:08 +02:00
|
|
|
render (Just (NValue (reverse -> p:_) _)) = go (_originExpr p)
|
2018-04-25 08:09:43 +02:00
|
|
|
render (Just (NValue _ _)) = simpleExpr $ text "?"
|
|
|
|
-- simpleExpr $ foldr ((<$>) . parens . indent 2 . withoutParens
|
|
|
|
-- . go . originExpr)
|
|
|
|
-- mempty (reverse ps)
|
2018-04-23 19:06:49 +02:00
|
|
|
|
|
|
|
exprFNixDoc :: NExprF NixDoc -> NixDoc
|
|
|
|
exprFNixDoc = \case
|
|
|
|
NConstant atom -> prettyAtom atom
|
|
|
|
NStr str -> simpleExpr $ prettyString str
|
|
|
|
NList [] -> simpleExpr $ lbracket <> rbracket
|
|
|
|
NList xs -> simpleExpr $ group $
|
|
|
|
nest 2 (vsep $ lbracket : map (wrapParens appOpNonAssoc) xs) <$> rbracket
|
|
|
|
NSet [] -> simpleExpr $ lbrace <> rbrace
|
|
|
|
NSet xs -> simpleExpr $ group $
|
|
|
|
nest 2 (vsep $ lbrace : map prettyBind xs) <$> rbrace
|
|
|
|
NRecSet [] -> simpleExpr $ recPrefix <> lbrace <> rbrace
|
|
|
|
NRecSet xs -> simpleExpr $ group $
|
|
|
|
nest 2 (vsep $ recPrefix <> lbrace : map prettyBind xs) <$> rbrace
|
|
|
|
NAbs args body -> leastPrecedence $
|
|
|
|
nest 2 ((prettyParams args <> colon) <$> withoutParens body)
|
|
|
|
NBinary NApp fun arg ->
|
2018-05-06 00:56:56 +02:00
|
|
|
mkNixDoc (wrapParens appOp fun <+> wrapParens appOpNonAssoc arg) appOp
|
|
|
|
NBinary op r1 r2 -> flip mkNixDoc opInfo $ hsep
|
2018-04-23 19:06:49 +02:00
|
|
|
[ wrapParens (f NAssocLeft) r1
|
|
|
|
, text $ unpack $ operatorName opInfo
|
|
|
|
, wrapParens (f NAssocRight) r2
|
|
|
|
]
|
|
|
|
where
|
|
|
|
opInfo = getBinaryOperator op
|
|
|
|
f x | associativity opInfo /= x = opInfo { associativity = NAssocNone }
|
|
|
|
| otherwise = opInfo
|
|
|
|
NUnary op r1 ->
|
2018-05-06 00:56:56 +02:00
|
|
|
mkNixDoc (text (unpack (operatorName opInfo)) <> wrapParens opInfo r1) opInfo
|
2018-04-23 19:06:49 +02:00
|
|
|
where opInfo = getUnaryOperator op
|
|
|
|
NSelect r attr o ->
|
2018-05-06 00:56:56 +02:00
|
|
|
(if isJust o then leastPrecedence else flip mkNixDoc selectOp) $
|
|
|
|
wrapPath selectOp r <> dot <> prettySelector attr <> ordoc
|
2018-04-23 19:06:49 +02:00
|
|
|
where ordoc = maybe empty (((space <> text "or") <+>) . wrapParens selectOp) o
|
|
|
|
NHasAttr r attr ->
|
2018-05-06 00:56:56 +02:00
|
|
|
mkNixDoc (wrapParens hasAttrOp r <+> text "?" <+> prettySelector attr) hasAttrOp
|
2018-04-23 19:06:49 +02:00
|
|
|
NEnvPath p -> simpleExpr $ text ("<" ++ p ++ ">")
|
2018-05-06 00:56:56 +02:00
|
|
|
NLiteralPath p -> pathExpr $ text $ case p of
|
2018-04-23 19:06:49 +02:00
|
|
|
"./" -> "./."
|
|
|
|
"../" -> "../."
|
|
|
|
".." -> "../."
|
|
|
|
txt | "/" `isPrefixOf` txt -> txt
|
|
|
|
| "~/" `isPrefixOf` txt -> txt
|
|
|
|
| "./" `isPrefixOf` txt -> txt
|
|
|
|
| "../" `isPrefixOf` txt -> txt
|
|
|
|
| otherwise -> "./" ++ txt
|
|
|
|
NSym name -> simpleExpr $ text (unpack name)
|
|
|
|
NLet binds body -> leastPrecedence $ group $ text "let" <$> indent 2 (
|
2018-04-19 08:42:13 +02:00
|
|
|
vsep (map prettyBind binds)) <$> text "in" <+> withoutParens body
|
2018-04-23 19:06:49 +02:00
|
|
|
NIf cond trueBody falseBody -> leastPrecedence $
|
|
|
|
group $ nest 2 $ (text "if" <+> withoutParens cond) <$>
|
|
|
|
( align (text "then" <+> withoutParens trueBody)
|
|
|
|
<$> align (text "else" <+> withoutParens falseBody)
|
|
|
|
)
|
|
|
|
NWith scope body -> leastPrecedence $
|
|
|
|
text "with" <+> withoutParens scope <> semi <$> align (withoutParens body)
|
|
|
|
NAssert cond body -> leastPrecedence $
|
|
|
|
text "assert" <+> withoutParens cond <> semi <$> align (withoutParens body)
|
|
|
|
where
|
|
|
|
recPrefix = text "rec" <> space
|
2018-04-07 21:02:50 +02:00
|
|
|
|
2018-04-28 05:08:47 +02:00
|
|
|
prettyNValueNF :: Functor m => NValueNF m -> Doc
|
|
|
|
prettyNValueNF = prettyNix . valueToExpr
|
2018-04-07 21:02:50 +02:00
|
|
|
where valueToExpr :: Functor m => NValueNF m -> NExpr
|
2018-04-08 07:46:05 +02:00
|
|
|
valueToExpr = transport go
|
|
|
|
|
2018-04-22 23:32:55 +02:00
|
|
|
go (NVConstantF a) = NConstant a
|
2018-05-08 22:47:50 +02:00
|
|
|
go (NVStrF ns) = NStr (DoubleQuoted [Plain (stringIntentionallyDropContext ns)])
|
2018-04-22 23:32:55 +02:00
|
|
|
go (NVListF l) = NList l
|
|
|
|
go (NVSetF s p) = NSet
|
2018-04-17 21:46:41 +02:00
|
|
|
[ NamedVar (StaticKey k (M.lookup k p) :| []) v
|
|
|
|
| (k, v) <- toList s ]
|
2018-04-22 23:32:55 +02:00
|
|
|
go (NVClosureF _ _) = NSym . pack $ "<closure>"
|
|
|
|
go (NVPathF p) = NLiteralPath p
|
|
|
|
go (NVBuiltinF name _) = NSym $ Text.pack $ "builtins." ++ name
|
2018-04-07 21:02:50 +02:00
|
|
|
|
|
|
|
printNix :: Functor m => NValueNF m -> String
|
|
|
|
printNix = cata phi
|
|
|
|
where phi :: NValueF m String -> String
|
2018-04-22 23:32:55 +02:00
|
|
|
phi (NVConstantF a) = unpack $ atomText a
|
2018-05-08 22:47:50 +02:00
|
|
|
phi (NVStrF ns) = show $ stringIntentionallyDropContext ns
|
2018-04-22 23:32:55 +02:00
|
|
|
phi (NVListF l) = "[ " ++ unwords l ++ " ]"
|
|
|
|
phi (NVSetF s _) =
|
2018-04-07 21:02:50 +02:00
|
|
|
"{ " ++ concat [ unpack k ++ " = " ++ v ++ "; "
|
|
|
|
| (k, v) <- sort $ toList s ] ++ "}"
|
2018-04-22 23:32:55 +02:00
|
|
|
phi NVClosureF {} = "<<lambda>>"
|
|
|
|
phi (NVPathF fp) = fp
|
|
|
|
phi (NVBuiltinF name _) = "<<builtin " ++ name ++ ">>"
|
2018-04-07 21:02:50 +02:00
|
|
|
|
2018-04-24 21:25:40 +02:00
|
|
|
removeEffects :: Functor m => NValueF m (NThunk m) -> NValueNF m
|
|
|
|
removeEffects = Fix . fmap dethunk
|
2018-04-07 21:02:50 +02:00
|
|
|
where
|
2018-05-06 09:40:08 +02:00
|
|
|
dethunk (NThunk _ (Value v)) = removeEffects (_baseValue v)
|
2018-05-08 22:47:50 +02:00
|
|
|
dethunk (NThunk _ _) = Fix $ NVStrF (makeNixStringWithoutContext "<thunk>")
|
2018-04-07 21:02:50 +02:00
|
|
|
|
2018-04-24 21:25:40 +02:00
|
|
|
removeEffectsM :: MonadVar m => NValueF m (NThunk m) -> m (NValueNF m)
|
|
|
|
removeEffectsM = fmap Fix . traverse dethunk
|
2018-04-23 19:06:49 +02:00
|
|
|
|
2018-04-28 05:08:47 +02:00
|
|
|
prettyNValueF :: MonadVar m => NValueF m (NThunk m) -> m Doc
|
|
|
|
prettyNValueF = fmap prettyNValueNF . removeEffectsM
|
2018-04-11 06:11:46 +02:00
|
|
|
|
2018-04-28 05:08:47 +02:00
|
|
|
prettyNValue :: MonadVar m => NValue m -> m Doc
|
|
|
|
prettyNValue (NValue _ v) = prettyNValueF v
|
2018-04-26 05:46:54 +02:00
|
|
|
|
2018-04-28 05:08:47 +02:00
|
|
|
prettyNValueProv :: MonadVar m => NValue m -> m Doc
|
|
|
|
prettyNValueProv = \case
|
|
|
|
NValue [] v -> prettyNValueF v
|
2018-04-25 08:09:43 +02:00
|
|
|
NValue ps v -> do
|
2018-04-28 05:08:47 +02:00
|
|
|
v' <- prettyNValueF v
|
2018-04-25 08:09:43 +02:00
|
|
|
pure $ v' </> indent 2 (parens (mconcat
|
2018-05-06 09:40:08 +02:00
|
|
|
(text "from: " : map (prettyOriginExpr . _originExpr) ps)))
|
2018-04-25 22:00:41 +02:00
|
|
|
|
2018-04-28 05:08:47 +02:00
|
|
|
prettyNThunk :: MonadVar m => NThunk m -> m Doc
|
|
|
|
prettyNThunk = \case
|
2018-04-25 22:00:41 +02:00
|
|
|
t@(NThunk ps _) -> do
|
2018-04-28 05:08:47 +02:00
|
|
|
v' <- fmap prettyNValueNF (dethunk t)
|
2018-04-25 22:00:41 +02:00
|
|
|
pure $ v' </> indent 2 (parens (mconcat
|
2018-05-06 09:40:08 +02:00
|
|
|
(text "thunk from: " : map (prettyOriginExpr . _originExpr) ps)))
|
2018-04-11 06:11:46 +02:00
|
|
|
|
2018-04-24 21:25:40 +02:00
|
|
|
dethunk :: MonadVar m => NThunk m -> m (NValueNF m)
|
|
|
|
dethunk = \case
|
2018-05-06 09:40:08 +02:00
|
|
|
NThunk _ (Value v) -> removeEffectsM (_baseValue v)
|
2018-04-30 19:15:57 +02:00
|
|
|
NThunk _ (Thunk _ active ref) -> do
|
2018-04-26 05:30:44 +02:00
|
|
|
nowActive <- atomicModifyVar active (True,)
|
|
|
|
if nowActive
|
2018-05-08 22:47:50 +02:00
|
|
|
then pure $ Fix $ NVStrF (makeNixStringWithoutContext "<thunk>")
|
2018-04-26 05:30:44 +02:00
|
|
|
else do
|
|
|
|
eres <- readVar ref
|
|
|
|
case eres of
|
2018-05-06 09:40:08 +02:00
|
|
|
Computed v -> removeEffectsM (_baseValue v)
|
2018-05-08 22:47:50 +02:00
|
|
|
_ -> pure $ Fix $ NVStrF (makeNixStringWithoutContext "<thunk>")
|